Merge branch 'master' of github.com:designcreateplay/NodeBB

Conflicts:
	src/routes/api.js
v1.18.x
Julian Lam 11 years ago
commit 55b67ed735

@ -38,5 +38,14 @@
"motd.follow": "Follow", "motd.follow": "Follow",
"previouspage": "Previous Page", "previouspage": "Previous Page",
"nextpage": "Next Page" "nextpage": "Next Page",
"alert.success": "Success",
"alert.error": "Error",
"alert.banned": "Banned",
"alert.banned.message": "You are banned you will be logged out!",
"alert.unfollow": "You are no longer following %1!",
"alert.follow": "You are now following %1!"
} }

@ -113,8 +113,8 @@ var socket,
socket.on('event:banned', function() { socket.on('event:banned', function() {
app.alert({ app.alert({
title: 'Banned', title: '[[global:alert.banned]]',
message: 'You are banned you will be logged out!', message: '[[global:alert.banned.message]]',
type: 'warning', type: 'warning',
timeout: 1000 timeout: 1000
}); });
@ -125,6 +125,14 @@ var socket,
socket.on('meta.updateHeader', app.updateHeader); socket.on('meta.updateHeader', app.updateHeader);
app.enterRoom('global'); app.enterRoom('global');
if (config.environment === 'development' && console && console.log) {
var log = console.log;
console.log = function() {
log.apply(this, arguments);
socket.emit('tools.log', arguments);
}
}
} }
}, },
async: false async: false
@ -190,7 +198,10 @@ var socket,
if (params.location == null) if (params.location == null)
params.location = 'alert_window'; params.location = 'alert_window';
$('#' + params.location).prepend(div.fadeIn('100')); translator.translate(div.html(), function(translatedHTML) {
div.html(translatedHTML);
$('#' + params.location).prepend(div.fadeIn('100'));
});
if (params.timeout) { if (params.timeout) {
startTimeout(div, params.timeout); startTimeout(div, params.timeout);
@ -212,7 +223,7 @@ var socket,
timeout = 2000; timeout = 2000;
app.alert({ app.alert({
title: 'Success', title: '[[global:alert.success]]',
message: message, message: message,
type: 'success', type: 'success',
timeout: timeout timeout: timeout
@ -224,7 +235,7 @@ var socket,
timeout = 2000; timeout = 2000;
app.alert({ app.alert({
title: 'Error', title: '[[global:alert.error]]',
message: message, message: message,
type: 'danger', type: 'danger',
timeout: timeout timeout: timeout

@ -44,7 +44,7 @@ define(['forum/accountheader'], function(header) {
followBtn.addClass('hide'); followBtn.addClass('hide');
unfollowBtn.removeClass('hide'); unfollowBtn.removeClass('hide');
app.alertSuccess('You are now following ' + username + '!'); app.alertSuccess('[[global:alert.follow, ' + username + ']]');
}); });
return false; return false;
}); });
@ -59,7 +59,7 @@ define(['forum/accountheader'], function(header) {
followBtn.removeClass('hide'); followBtn.removeClass('hide');
unfollowBtn.addClass('hide'); unfollowBtn.addClass('hide');
app.alertSuccess('You are no longer following ' + username + '!'); app.alertSuccess('[[global:alert.unfollow, ' + username + ']]');
}); });
return false; return false;
}); });

@ -176,11 +176,11 @@ define(['taskbar', 'string'], function(taskbar, S) {
module.load = function(uuid) { module.load = function(uuid) {
var chatModal = $('div[UUID="'+uuid+'"]'); var chatModal = $('div[UUID="'+uuid+'"]');
chatModal.removeClass('hide'); chatModal.removeClass('hide');
module.bringModalToTop(chatModal);
checkOnlineStatus(chatModal); checkOnlineStatus(chatModal);
taskbar.updateActive(uuid); taskbar.updateActive(uuid);
scrollToBottom(chatModal.find('#chat-content')); scrollToBottom(chatModal.find('#chat-content'));
module.center(chatModal); module.center(chatModal);
module.bringModalToTop(chatModal);
} }
module.minimize = function(uuid) { module.minimize = function(uuid) {

@ -2,50 +2,37 @@ define(function() {
var Notifications = {}; var Notifications = {};
Notifications.prepareDOM = function() { Notifications.prepareDOM = function() {
// Notifications dropdown var notifContainer = $('.notifications'),
var notifContainer = document.getElementsByClassName('notifications')[0], notifTrigger = notifContainer.children('a'),
notifTrigger = notifContainer.querySelector('a'), notifList = $('#notif-list'),
notifList = document.getElementById('notif-list'),
notifIcon = $('.notifications a i'); notifIcon = $('.notifications a i');
notifTrigger.addEventListener('click', function(e) { notifTrigger.on('click', function(e) {
e.preventDefault(); e.preventDefault();
if (notifContainer.className.indexOf('open') === -1) { if (!notifContainer.hasClass('open')) {
socket.emit('notifications.get', null, function(err, data) { socket.emit('notifications.get', null, function(err, data) {
var notifFrag = document.createDocumentFragment(), var numRead = data.read.length,
notifEl = document.createElement('li'),
numRead = data.read.length,
numUnread = data.unread.length, numUnread = data.unread.length,
x; x;
notifList.innerHTML = ''; notifList.html('');
if (!err && (data.read.length + data.unread.length) > 0) { if (!err && (data.read.length + data.unread.length) > 0) {
for (x = 0; x < numUnread; x++) { for (x = 0; x < numUnread; x++) {
notifEl.setAttribute('data-nid', data.unread[x].nid); notifList.append($('<li class="' + data.unread[x].readClass + '"><a href="' + data.unread[x].path + '"><span class="pull-right">' + utils.relativeTime(data.unread[x].datetime, true) + '</span>' + data.unread[x].text + '</a></li>'));
notifEl.className = data.unread[x].readClass;
notifEl.innerHTML = '<a href="' + data.unread[x].path + '"><span class="pull-right">' + utils.relativeTime(data.unread[x].datetime, true) + '</span>' + data.unread[x].text + '</a>';
notifFrag.appendChild(notifEl.cloneNode(true));
} }
for (x = 0; x < numRead; x++) { for (x = 0; x < numRead; x++) {
notifEl.setAttribute('data-nid', data.read[x].nid); notifList.append($('<li class="' + data.read[x].readClass + '"><a href="' + data.read[x].path + '"><span class="pull-right">' + utils.relativeTime(data.read[x].datetime, true) + '</span>' + data.read[x].text + '</a></li>'));
notifEl.className = '';
notifEl.innerHTML = '<a href="' + data.read[x].path + '"><span class="pull-right">' + utils.relativeTime(data.read[x].datetime, true) + '</span>' + data.read[x].text + '</a>';
notifFrag.appendChild(notifEl.cloneNode(true));
} }
} else { } else {
notifEl.className = 'no-notifs'; notifList.append($('<li class="no-notifs"><a>You have no notifications</a></li>'));
notifEl.innerHTML = '<a>You have no notifications</a>';
notifFrag.appendChild(notifEl.cloneNode(true));
} }
// Add dedicated link to /notifications notifList.append($('<li class="pagelink"><a href="' + RELATIVE_PATH + '/notifications">See all Notifications</a></li>'));
notifEl.removeAttribute('data-nid');
notifEl.className = 'pagelink';
notifEl.innerHTML = '<a href="' + RELATIVE_PATH + '/notifications">See all Notifications</a>';
notifFrag.appendChild(notifEl.cloneNode(true));
notifList.appendChild(notifFrag);
updateNotifCount(data.unread.length); updateNotifCount(data.unread.length);
@ -58,27 +45,7 @@ define(function() {
} }
}); });
notifList.addEventListener('click', function(e) {
var target;
switch (e.target.nodeName) {
case 'SPAN':
target = e.target.parentNode.parentNode;
break;
case 'A':
target = e.target.parentNode;
break;
case 'li':
target = e.target;
break;
}
if (target) {
var nid = parseInt(target.getAttribute('data-nid'));
if (nid > 0) socket.emit('modules.notifications.mark_read', nid);
}
});
var updateNotifCount = function(count) { var updateNotifCount = function(count) {
// Update notification icon, if necessary
if (count > 0) { if (count > 0) {
notifIcon.removeClass('fa-bell-o').addClass('fa-bell'); notifIcon.removeClass('fa-bell-o').addClass('fa-bell');
} else { } else {
@ -88,7 +55,6 @@ define(function() {
notifIcon.toggleClass('unread-count', count > 0); notifIcon.toggleClass('unread-count', count > 0);
notifIcon.attr('data-content', count > 20 ? '20+' : count); notifIcon.attr('data-content', count > 20 ? '20+' : count);
// Update the favicon + saved local count
Tinycon.setBubble(count); Tinycon.setBubble(count);
localStorage.setItem('notifications:count', count); localStorage.setItem('notifications:count', count);
}; };
@ -116,7 +82,6 @@ define(function() {
ajaxify.refresh(); ajaxify.refresh();
} }
// Update the favicon + local storage
var savedCount = parseInt(localStorage.getItem('notifications:count'), 10) || 0; var savedCount = parseInt(localStorage.getItem('notifications:count'), 10) || 0;
updateNotifCount(savedCount + 1); updateNotifCount(savedCount + 1);
}); });

@ -323,6 +323,33 @@
template = ''; template = '';
} }
function checkConditional(key, value) {
var conditional = makeConditionalRegex(key),
matches = template.match(conditional);
if (matches !== null) {
for (var i = 0, ii = matches.length; i < ii; i++) {
var conditionalBlock = matches[i].split(/<!-- ELSE -->/);
if (conditionalBlock[1]) {
// there is an else statement
if (!value) {
template = template.replace(matches[i], conditionalBlock[1].replace(/<!-- ((\IF\b)|(\bENDIF\b))([^@]*?)-->/gi, ''));
} else {
template = template.replace(matches[i], conditionalBlock[0].replace(/<!-- ((\IF\b)|(\bENDIF\b))([^@]*?)-->/gi, ''));
}
} else {
// regular if statement
if (!value) {
template = template.replace(matches[i], '');
} else {
template = template.replace(matches[i], matches[i].replace(/<!-- ((\IF\b)|(\bENDIF\b))([^@]*?)-->/gi, ''));
}
}
}
}
}
for (var d in data) { for (var d in data) {
if (data.hasOwnProperty(d)) { if (data.hasOwnProperty(d)) {
if (typeof data[d] === 'undefined') { if (typeof data[d] === 'undefined') {
@ -330,6 +357,9 @@
} else if (data[d] === null) { } else if (data[d] === null) {
template = replace(namespace + d, '', template); template = replace(namespace + d, '', template);
} else if (data[d].constructor == Array) { } else if (data[d].constructor == Array) {
checkConditional(namespace + d + '.length', data[d].length);
checkConditional('!' + namespace + d + '.length', !data[d].length);
namespace += d + '.'; namespace += d + '.';
var regex = makeRegex(d), var regex = makeRegex(d),
@ -353,33 +383,6 @@
} else if (data[d] instanceof Object) { } else if (data[d] instanceof Object) {
template = parse(data[d], d + '.', template); template = parse(data[d], d + '.', template);
} else { } else {
function checkConditional(key, value) {
var conditional = makeConditionalRegex(key),
matches = template.match(conditional);
if (matches !== null) {
for (var i = 0, ii = matches.length; i < ii; i++) {
var conditionalBlock = matches[i].split(/<!-- ELSE -->/);
if (conditionalBlock[1]) {
// there is an else statement
if (!value) {
template = template.replace(matches[i], conditionalBlock[1].replace(/<!-- ((\IF\b)|(\bENDIF\b))([^@]*?)-->/gi, ''));
} else {
template = template.replace(matches[i], conditionalBlock[0].replace(/<!-- ((\IF\b)|(\bENDIF\b))([^@]*?)-->/gi, ''));
}
} else {
// regular if statement
if (!value) {
template = template.replace(matches[i], '');
} else {
template = template.replace(matches[i], matches[i].replace(/<!-- ((\IF\b)|(\bENDIF\b))([^@]*?)-->/gi, ''));
}
}
}
}
}
checkConditional(namespace + d, data[d]); checkConditional(namespace + d, data[d]);
checkConditional('!' + namespace + d, !data[d]); checkConditional('!' + namespace + d, !data[d]);

@ -112,16 +112,18 @@
<li><a href="{relative_path}/admin/events"><i class="fa fa-fw fa-calendar-o"></i> Events</a></li> <li><a href="{relative_path}/admin/events"><i class="fa fa-fw fa-calendar-o"></i> Events</a></li>
</ul> </ul>
</div> </div>
<!-- IF authentication.length -->
<div class="well sidebar-nav"> <div class="well sidebar-nav">
<ul class="nav nav-list"> <ul class="nav nav-list">
<li class="nav-header">Social Authentication</li> <li class="nav-header">Social Authentication</li>
<!-- BEGIN authentication --> <!-- BEGIN authentication -->
<li> <li>
<a href="{relative_path}/admin{authentication.route}"><i class="fa fa-fw {authentication.icon}"></i> {authentication.name}</a> <a href="{relative_path}/admin{authentication.route}"><i class="fa fa-fw {authentication.icon}"></i> {authentication.name}</a>
</li> </li>
<!-- END authentication --> <!-- END authentication -->
</ul> </ul>
</div> </div>
<!-- ENDIF authentication.length -->
<div class="well sidebar-nav"> <div class="well sidebar-nav">
<ul class="nav nav-list"> <ul class="nav nav-list">
<li class="nav-header">Plugins</li> <li class="nav-header">Plugins</li>

@ -134,11 +134,17 @@
<ul id="logged-out-menu" class="nav navbar-nav navbar-right"> <ul id="logged-out-menu" class="nav navbar-nav navbar-right">
<!-- IF allowRegistration --> <!-- IF allowRegistration -->
<li> <li>
<a href="{relative_path}/register">[[global:register]]</a> <a href="{relative_path}/register">
<i class="fa fa-pencil visible-xs-inline"></i>
<span>[[global:register]]</span>
</a>
</li> </li>
<!-- ENDIF allowRegistration --> <!-- ENDIF allowRegistration -->
<li> <li>
<a href="{relative_path}/login">[[global:login]]</a> <a href="{relative_path}/login">
<i class="fa fa-sign-in visible-xs-inline"></i>
<span>[[global:login]]</span>
</a>
</li> </li>
</ul> </ul>

@ -127,7 +127,9 @@
<div class="post-info"> <div class="post-info">
<span class="pull-left"> <span class="pull-left">
[[topic:reputation]]: <i class='fa fa-star'></i> <span class='formatted-number post_rep_{posts.uid}'>{posts.user_rep}</span>&nbsp;|&nbsp;[[topic:posts]]: <i class='fa fa-pencil'></i> <span class='formatted-number user_postcount_{posts.uid}'>{posts.user_postcount}</span> [[topic:reputation]]: <i class='fa fa-star'></i> <span class='formatted-number post_rep_{posts.uid}'>{posts.user_rep}</span>&nbsp;|&nbsp;[[topic:posts]]: <i class='fa fa-pencil'></i> <span class='formatted-number user_postcount_{posts.uid}'>{posts.user_postcount}</span>
{posts.additional_profile_info} <!-- BEGIN custom_profile_info -->
| {posts.custom_profile_info.content}
<!-- END custom_profile_info -->
</span> </span>
<span class="pull-right"> <span class="pull-right">
[[category:posted]] <span class="relativeTimeAgo timeago" title="{posts.relativeTime}"></span> [[category:posted]] <span class="relativeTimeAgo timeago" title="{posts.relativeTime}"></span>

@ -70,20 +70,6 @@
callback(null); callback(null);
} }
/*
* A possibly more efficient way of doing multiple sismember calls
*/
function sismembers(key, needles, callback) {
var tempkey = key + ':temp:' + utils.generateUUID();
redisClient.sadd(tempkey, needles, function() {
redisClient.sinter(key, tempkey, function(err, data) {
redisClient.del(tempkey);
callback(err, data);
});
});
};
// //
// Exported functions // Exported functions
// //

@ -4,7 +4,8 @@ var fs = require('fs'),
winston = require('winston'), winston = require('winston'),
nconf = require('nconf'), nconf = require('nconf'),
eventEmitter = require('events').EventEmitter, eventEmitter = require('events').EventEmitter,
db = require('./database'); db = require('./database'),
meta = require('./meta');
(function(Plugins) { (function(Plugins) {
@ -63,7 +64,9 @@ var fs = require('fs'),
db.getSetMembers('plugins:active', next); db.getSetMembers('plugins:active', next);
}, },
function(plugins, next) { function(plugins, next) {
if (plugins && Array.isArray(plugins) && plugins.length > 0) { if (plugins && Array.isArray(plugins)) {
plugins.push(meta.config['theme:id']);
async.each(plugins, function(plugin, next) { async.each(plugins, function(plugin, next) {
var modulePath = path.join(__dirname, '../node_modules/', plugin); var modulePath = path.join(__dirname, '../node_modules/', plugin);
if (fs.existsSync(modulePath)) { if (fs.existsSync(modulePath)) {
@ -94,7 +97,7 @@ var fs = require('fs'),
Plugins.loadPlugin = function(pluginPath, callback) { Plugins.loadPlugin = function(pluginPath, callback) {
fs.readFile(path.join(pluginPath, 'plugin.json'), function(err, data) { fs.readFile(path.join(pluginPath, 'plugin.json'), function(err, data) {
if (err) { if (err) {
return callback(err); return callback(pluginPath.match('nodebb-theme') ? null : err);
} }
var pluginData = JSON.parse(data), var pluginData = JSON.parse(data),

@ -206,11 +206,11 @@ var db = require('./database'),
} }
} }
plugins.fireHook('filter:posts.custom_profile_info', {profile: "", uid: post.uid, pid: post.pid}, function(err, profile_info) { plugins.fireHook('filter:posts.custom_profile_info', {profile: [], uid: post.uid, pid: post.pid}, function(err, profile_info) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
post.additional_profile_info = profile_info.profile; post.custom_profile_info = profile_info.profile;
if (post.editor !== '') { if (post.editor !== '') {
user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) { user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) {

@ -24,7 +24,9 @@ var path = require('path'),
app.namespace('/api', function () { app.namespace('/api', function () {
app.get('/get_templates_listing', function (req, res) { app.get('/get_templates_listing', function (req, res) {
utils.walk(path.join(__dirname, '../../', 'public/templates'), function (err, data) { utils.walk(path.join(__dirname, '../../', 'public/templates'), function (err, data) {
res.json(data); res.json(data.concat(app.get_custom_templates()).filter(function(value, index, self) {
return self.indexOf(value) === index;
}));
}); });
}); });
@ -48,6 +50,7 @@ var path = require('path'),
config.postsPerPage = meta.config.postsPerPage || 20; config.postsPerPage = meta.config.postsPerPage || 20;
config.maximumFileSize = meta.config.maximumFileSize; config.maximumFileSize = meta.config.maximumFileSize;
config.defaultLang = meta.config.defaultLang || 'en_GB'; config.defaultLang = meta.config.defaultLang || 'en_GB';
config.environment = process.env.NODE_ENV;
res.json(200, config); res.json(200, config);
}); });

@ -0,0 +1,9 @@
var winston = require('winston');
var SocketTools = {};
SocketTools.log = function(socket, data, callback) {
winston.info("captured console.log:", data)
};
module.exports = SocketTools;

@ -263,23 +263,36 @@ var winston = require('winston'),
}); });
} }
ThreadTools.notifyFollowers = function(tid, exceptUid) { ThreadTools.notifyFollowers = function(tid, pid, exceptUid) {
async.parallel([ async.parallel([
function(next) { function(next) {
topics.getTopicField(tid, 'title', function(err, title) { topics.getTopicFields(tid, ['title', 'slug'], function(err, topicData) {
topics.getTeaser(tid, function(err, teaser) { if(err) {
if (!err) { return next(err);
notifications.create('<strong>' + teaser.username + '</strong> has posted a reply to: "<strong>' + title + '</strong>"', nconf.get('relative_path') + '/topic/' + tid, 'topic:' + tid, function(nid) { }
next(null, nid);
}); user.getUserField(exceptUid, 'username', function(err, username) {
} else next(err); if(err) {
return next(err);
}
notifications.create('<strong>' + username + '</strong> has posted a reply to: "<strong>' + topicData.title + '</strong>"', nconf.get('relative_path') + '/topic/' + topicData.slug + '#' + pid, 'topic:' + tid, function(nid) {
next(null, nid);
});
}); });
}); });
}, },
function(next) { function(next) {
ThreadTools.getFollowers(tid, function(err, followers) { ThreadTools.getFollowers(tid, function(err, followers) {
if(err) {
return next(err);
}
exceptUid = parseInt(exceptUid, 10); exceptUid = parseInt(exceptUid, 10);
if (followers.indexOf(exceptUid) !== -1) followers.splice(followers.indexOf(exceptUid), 1); if (followers.indexOf(exceptUid) !== -1) {
followers.splice(followers.indexOf(exceptUid), 1);
}
next(null, followers); next(null, followers);
}); });
} }

@ -164,7 +164,7 @@ var async = require('async'),
}); });
feed.updateRecent(); feed.updateRecent();
threadTools.notifyFollowers(tid, uid); threadTools.notifyFollowers(tid, postData.pid, uid);
user.sendPostNotificationToFollowers(uid, tid, postData.pid); user.sendPostNotificationToFollowers(uid, tid, postData.pid);
Topics.markCategoryUnreadForAll(tid, function(err) { Topics.markCategoryUnreadForAll(tid, function(err) {

@ -911,6 +911,12 @@ module.exports.server = server;
'templates': [] 'templates': []
}; };
app.get_custom_templates = function() {
return custom_routes.templates.map(function(tpl) {
return tpl.template.split('.tpl')[0];
});
}
plugins.ready(function() { plugins.ready(function() {
plugins.fireHook('filter:server.create_routes', custom_routes, function(err, custom_routes) { plugins.fireHook('filter:server.create_routes', custom_routes, function(err, custom_routes) {
var routes = custom_routes.routes; var routes = custom_routes.routes;

Loading…
Cancel
Save