diff --git a/app.js b/app.js
index 492faf9609..05ba01c22f 100644
--- a/app.js
+++ b/app.js
@@ -86,6 +86,7 @@
webserver = require('./src/webserver.js'),
SocketIO = require('socket.io').listen(global.server, { log: false, transports: ['websocket', 'xhr-polling', 'jsonp-polling', 'flashsocket']}),
websockets = require('./src/websockets.js'),
+ posts = require('./src/posts.js'),
plugins = require('./src/plugins'); // Don't remove this - plugins initializes itself
websockets.init(SocketIO);
diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js
index 2887b4a301..01b438b7b0 100644
--- a/public/src/ajaxify.js
+++ b/public/src/ajaxify.js
@@ -176,7 +176,7 @@ var ajaxify = {};
var scripts = [],
script,
- children_nodes = $(body_el).children(),
+ children_nodes = $(body_el).find('script'),
child,
i;
diff --git a/public/src/app.js b/public/src/app.js
index 9681e293f3..9098cce749 100644
--- a/public/src/app.js
+++ b/public/src/app.js
@@ -136,6 +136,7 @@ var socket,
var alert_id = 'alert_button_' + ((params.alert_id) ? params.alert_id : new Date().getTime());
var alert = $('#' + alert_id);
+ var title = params.title || '';
function startTimeout(div, timeout) {
var timeoutId = setTimeout(function () {
@@ -148,7 +149,7 @@ var socket,
}
if (alert.length > 0) {
- alert.find('strong').html(params.title);
+ alert.find('strong').html(title);
alert.find('p').html(params.message);
alert.attr('class', "alert toaster-alert " + "alert-" + params.type);
@@ -161,7 +162,7 @@ var socket,
p = document.createElement('p');
p.innerHTML = params.message;
- strong.innerHTML = params.title;
+ strong.innerHTML = title;
div.className = "alert toaster-alert " + "alert-" + params.type;
diff --git a/public/src/forum/admin/footer.js b/public/src/forum/admin/footer.js
index 22990fcf7b..8a99da7a74 100644
--- a/public/src/forum/admin/footer.js
+++ b/public/src/forum/admin/footer.js
@@ -16,9 +16,7 @@ jQuery('document').ready(function() {
});
socket.once('api:config.get', function(config) {
- require(['forum/admin/settings'], function(Settings) {
- Settings.config = config;
- });
+ app.config = config;
});
socket.emit('api:config.get');
diff --git a/public/src/forum/admin/settings.js b/public/src/forum/admin/settings.js
index 75f1a78c83..b6017af47e 100644
--- a/public/src/forum/admin/settings.js
+++ b/public/src/forum/admin/settings.js
@@ -1,18 +1,16 @@
define(function() {
var Settings = {};
- Settings.config = {};
-
Settings.init = function() {
Settings.prepare();
};
Settings.prepare = function() {
- // Come back in 500ms if the config isn't ready yet
- if (Settings.config === undefined) {
+ // Come back in 125ms if the config isn't ready yet
+ if (!app.config) {
setTimeout(function() {
Settings.prepare();
- }, 500);
+ }, 125);
return;
}
@@ -25,21 +23,21 @@ define(function() {
key = fields[x].getAttribute('data-field');
inputType = fields[x].getAttribute('type');
if (fields[x].nodeName === 'INPUT') {
- if (Settings.config[key]) {
+ if (app.config[key]) {
switch (inputType) {
case 'text':
case 'textarea':
case 'number':
- fields[x].value = Settings.config[key];
+ fields[x].value = app.config[key];
break;
case 'checkbox':
- fields[x].checked = Settings.config[key] === '1' ? true : false;
+ fields[x].checked = app.config[key] === '1' ? true : false;
break;
}
}
} else if (fields[x].nodeName === 'TEXTAREA') {
- if (Settings.config[key]) fields[x].value = Settings.config[key];
+ if (app.config[key]) fields[x].value = app.config[key];
}
}
diff --git a/public/templates/admin/header.tpl b/public/templates/admin/header.tpl
index 4135e135b0..ba2cdf32c7 100644
--- a/public/templates/admin/header.tpl
+++ b/public/templates/admin/header.tpl
@@ -76,35 +76,52 @@
+
+
+
diff --git a/public/templates/category.tpl b/public/templates/category.tpl
index b1894b4b9a..c9c0a06c1c 100644
--- a/public/templates/category.tpl
+++ b/public/templates/category.tpl
@@ -90,6 +90,16 @@
+
+
+
diff --git a/public/templates/topic.tpl b/public/templates/topic.tpl
index 1488af1e3a..5db4ea3fd2 100644
--- a/public/templates/topic.tpl
+++ b/public/templates/topic.tpl
@@ -66,6 +66,9 @@
{main_posts.content}
{main_posts.signature}
+
+ {main_posts.additional_profile_info}
+
posted
| last edited by {main_posts.editorname}
@@ -127,6 +130,9 @@
{posts.content}
{posts.signature}
+
+ {posts.additional_profile_info}
+
posted
| last edited by {posts.editorname}
diff --git a/src/categories.js b/src/categories.js
index b34eac86da..9ea879e140 100644
--- a/src/categories.js
+++ b/src/categories.js
@@ -55,9 +55,16 @@ var RDB = require('./redis.js'),
Categories.getActiveUsers(category_id, next);
}
- async.parallel([getTopicIds, getActiveUsers], function(err, results) {
+ function getSidebars(next) {
+ plugins.fireHook('filter:category.build_sidebars', [], function(err, sidebars) {
+ next(err, sidebars);
+ });
+ }
+
+ async.parallel([getTopicIds, getActiveUsers, getSidebars], function(err, results) {
var tids = results[0],
- active_users = results[1];
+ active_users = results[1],
+ sidebars = results[2];
var categoryData = {
'category_name': category_name,
@@ -72,7 +79,8 @@ var RDB = require('./redis.js'),
'topics': [],
'twitter-intent-url': 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug) + '&text=' + encodeURIComponent(category_name),
'facebook-share-url': 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug),
- 'google-share-url': 'https://plus.google.com/share?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug)
+ 'google-share-url': 'https://plus.google.com/share?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug),
+ 'sidebars': sidebars
};
function getTopics(next) {
diff --git a/src/plugins.js b/src/plugins.js
index 03332d5c2e..3adcbc90d7 100644
--- a/src/plugins.js
+++ b/src/plugins.js
@@ -274,7 +274,13 @@ var fs = require('fs'),
fs.readFile(path.join(file, 'plugin.json'), next);
},
function(configJSON, next) {
- var config = JSON.parse(configJSON);
+ try {
+ var config = JSON.parse(configJSON);
+ } catch (err) {
+ winston.warn("Plugin: " + file + " is corrupted or invalid. Please check plugin.json for errors.")
+ return next(err, null);
+ }
+
_self.isActive(config.id, function(err, active) {
if (err) next(new Error('no-active-state'));
diff --git a/src/posts.js b/src/posts.js
index 411610ee5e..60899e68c6 100644
--- a/src/posts.js
+++ b/src/posts.js
@@ -16,6 +16,7 @@ var RDB = require('./redis.js'),
winston = require('winston');
(function(Posts) {
+ var customUserInfo = {};
Posts.getPostsByTid = function(tid, start, end, callback) {
RDB.lrange('tid:' + tid + ':posts', start, end, function(err, pids) {
@@ -46,17 +47,27 @@ var RDB = require('./redis.js'),
post.picture = userData.picture || require('gravatar').url('', {}, https = nconf.get('https'));
post.signature = signature;
- if (post.editor !== '') {
- user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) {
- if (err) return callback();
-
- post.editorname = editorData.username;
- post.editorslug = editorData.userslug;
- callback();
- });
- } else {
- callback();
+ for (var info in customUserInfo) {
+ if (customUserInfo.hasOwnProperty(info)) {
+ post[info] = userData[info] || customUserInfo[info];
+ }
}
+
+ plugins.fireHook('filter:posts.custom_profile_info', {profile: "", uid: post.uid}, function(err, profile_info) {
+ post.additional_profile_info = profile_info.profile;
+
+ if (post.editor !== '') {
+ user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) {
+ if (err) return callback();
+
+ post.editorname = editorData.username;
+ post.editorslug = editorData.userslug;
+ callback();
+ });
+ } else {
+ callback();
+ }
+ });
});
});
};
diff --git a/src/routes/admin.js b/src/routes/admin.js
index 0fa581018c..28d0044849 100644
--- a/src/routes/admin.js
+++ b/src/routes/admin.js
@@ -18,10 +18,17 @@ var user = require('./../user.js'),
});
}
- Admin.build_header = function (res) {
- return templates['admin/header'].parse({
- csrf: res.locals.csrf_token,
- relative_path: nconf.get('relative_path')
+ Admin.build_header = function (res, callback) {
+ var custom_header = {
+ 'plugins': []
+ };
+
+ plugins.fireHook('filter:admin.header.build', custom_header, function(err, custom_header) {
+ callback(err, templates['admin/header'].parse({
+ csrf: res.locals.csrf_token,
+ relative_path: nconf.get('relative_path'),
+ plugins: custom_header.plugins
+ }));
});
}
@@ -38,7 +45,9 @@ var user = require('./../user.js'),
for (var i = 0, ii = routes.length; i < ii; i++) {
(function (route) {
app.get('/admin/' + route, Admin.isAdmin, function (req, res) {
- res.send(Admin.build_header(res) + app.create_route('admin/' + route) + templates['admin/footer']);
+ Admin.build_header(res, function(err, header) {
+ res.send(header + app.create_route('admin/' + route) + templates['admin/footer']);
+ });
});
}(routes[i]));
}
@@ -48,7 +57,9 @@ var user = require('./../user.js'),
for (var i = 0, ii = unit_tests.length; i < ii; i++) {
(function (route) {
app.get('/admin/testing/' + route, Admin.isAdmin, function (req, res) {
- res.send(Admin.build_header(res) + app.create_route('admin/testing/' + route) + templates['admin/footer']);
+ Admin.build_header(res, function(err, header) {
+ res.send(header + app.create_route('admin/testing/' + route) + templates['admin/footer']);
+ });
});
}(unit_tests[i]));
}
@@ -57,14 +68,42 @@ var user = require('./../user.js'),
app.namespace('/admin', function () {
app.get('/', Admin.isAdmin, function (req, res) {
- res.send(Admin.build_header(res) + app.create_route('admin/index') + templates['admin/footer']);
+ Admin.build_header(res, function(err, header) {
+ res.send(header + app.create_route('admin/index') + templates['admin/footer']);
+ });
});
app.get('/index', Admin.isAdmin, function (req, res) {
- res.send(Admin.build_header(res) + app.create_route('admin/index') + templates['admin/footer']);
+ Admin.build_header(res, function(err, header) {
+ res.send(header + app.create_route('admin/index') + templates['admin/footer']);
+ });
});
});
+
+ var custom_routes = {
+ 'routes': [],
+ 'api_methods': []
+ };
+
+ plugins.ready(function() {
+ plugins.fireHook('filter:admin.create_routes', custom_routes, function(err, custom_routes) {
+ var routes = custom_routes.routes;
+
+ for (var route in routes) {
+ if (routes.hasOwnProperty(route)) {
+ app[routes[route].method || 'get']('/admin' + routes[route].route, function(req, res) {
+ routes[route].options(req, res, function(options) {
+ Admin.build_header(res, function (err, header) {
+ res.send(header + options.content + templates['admin/footer']);
+ });
+ });
+ });
+ }
+ }
+ });
+ });
+
app.namespace('/api/admin', function () {
app.get('/index', function (req, res) {
res.json({
diff --git a/src/topics.js b/src/topics.js
index 98a53ae51e..7b87ae6325 100644
--- a/src/topics.js
+++ b/src/topics.js
@@ -1,5 +1,5 @@
-var RDB = require('./redis.js')
-schema = require('./schema.js'),
+var RDB = require('./redis.js'),
+ schema = require('./schema.js'),
posts = require('./posts.js'),
utils = require('./../public/src/utils.js'),
user = require('./user.js'),