From 948cd22e9c4d9f5c6f2ff13f2181dc965a697449 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 25 Feb 2015 09:49:08 -0500 Subject: [PATCH 001/143] triggering full-screen composer on short viewports as well as narrow, #2763 --- public/src/modules/composer/resize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/modules/composer/resize.js b/public/src/modules/composer/resize.js index 20048eb7e6..9d5d303df9 100644 --- a/public/src/modules/composer/resize.js +++ b/public/src/modules/composer/resize.js @@ -25,7 +25,7 @@ define('composer/resize', function() { } } - if (env === 'sm' || env === 'xs') { + if (env === 'sm' || env === 'xs' || window.innerHeight < 480) { app.toggleNavbar(false); postContainer.css('height', $(window).height()); } From ba7c873f0702767c007355deb3ba4c74a78709fe Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 25 Feb 2015 09:57:32 -0500 Subject: [PATCH 002/143] closed #2765 --- src/groups.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/groups.js b/src/groups.js index 54ff60a195..4d5d5fde0f 100644 --- a/src/groups.js +++ b/src/groups.js @@ -135,7 +135,19 @@ var async = require('async'), userObj.isOwner = isOwner; next(null, userObj); }); - }, next); + }, function(err, users) { + if (err) { + return next(); + } + + next(null, users.sort(function(a, b) { + if (a.isOwner === b.isOwner) { + return 0; + } else { + return a.isOwner && !b.isOwner ? -1 : 1; + } + })); + }); } ], next); } else { From ade12116a1586e248c2389e1ecd4b95cd17e6e99 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 25 Feb 2015 10:51:35 -0500 Subject: [PATCH 003/143] closed #2766 --- public/language/en_GB/groups.json | 1 + public/src/client/groups/details.js | 26 ++++++++++++++++++++++++-- src/groups.js | 6 +++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/public/language/en_GB/groups.json b/public/language/en_GB/groups.json index a72cf20110..09b1509171 100644 --- a/public/language/en_GB/groups.json +++ b/public/language/en_GB/groups.json @@ -29,6 +29,7 @@ "details.change_icon": "Change Icon", "details.change_colour": "Change Colour", "details.badge_text": "Badge Text", + "details.userTitleEnabled": "Show Badge", "details.private_help": "If enabled, joining of groups requires approval from a group owner", "details.hidden": "Hidden", "details.hidden_help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually", diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index f4f56a686e..bc1534f051 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -88,7 +88,9 @@ define('forum/groups/details', ['iconSelect', 'vendor/colorpicker/colorpicker', iconBtn = settingsFormEl.find('[data-action="icon-select"]'), previewEl = settingsFormEl.find('.label'), previewIcon = previewEl.find('i'), - previewValueEl = settingsFormEl.find('[name="icon"]'); + userTitleEl = settingsFormEl.find('[name="userTitle"]'), + userTitleEnabledEl = settingsFormEl.find('[name="userTitleEnabled"]'), + iconValueEl = settingsFormEl.find('[name="icon"]'); // Add color picker to settings form colorBtn.ColorPicker({ @@ -105,9 +107,29 @@ define('forum/groups/details', ['iconSelect', 'vendor/colorpicker/colorpicker', // Add icon selection interface iconBtn.on('click', function() { iconSelect.init(previewIcon, function() { - previewValueEl.val(previewIcon.val()); + iconValueEl.val(previewIcon.val()); }); }); + + // If the user title changes, update that too + userTitleEl.on('keyup', function() { + var icon = previewIcon.detach(); + previewEl.text(' ' + (this.value || settingsFormEl.find('#name').val())); + previewEl.prepend(icon); + }); + + // Disable user title customisation options if the the user title itself is disabled + userTitleEnabledEl.on('change', function() { + var customOpts = $('.user-title-option input, .user-title-option button'); + + if (this.checked) { + customOpts.removeAttr('disabled'); + previewEl.removeClass('hide'); + } else { + customOpts.attr('disabled', 'disabled'); + previewEl.addClass('hide'); + } + }); }; Details.update = function() { diff --git a/src/groups.js b/src/groups.js index 4d5d5fde0f..21575db866 100644 --- a/src/groups.js +++ b/src/groups.js @@ -228,6 +228,7 @@ var async = require('async'), results.base.description = validator.escape(results.base.description); results.base.descriptionParsed = descriptionParsed; results.base.userTitle = validator.escape(results.base.userTitle); + results.base.userTitleEnabled = results.base.userTitleEnabled ? !!parseInt(results.base.userTitleEnabled, 10) : true; results.base.createtimeISO = utils.toISOString(results.base.createtime); results.base.members = results.users.filter(Boolean); results.base.pending = results.pending.filter(Boolean); @@ -537,6 +538,7 @@ var async = require('async'), var payload = { userTitle: values.userTitle || '', + userTitleEnabled: values.userTitleEnabled === true ? '1' : '0', description: values.description || '', icon: values.icon || '', labelColor: values.labelColor || '#000000', @@ -891,6 +893,8 @@ var async = require('async'), } groupData = groupData.map(function(group) { if (group) { + group.userTitle = validator.escape(group.userTitle) || validator.escape(group.name); + group.userTitleEnabled = group.userTitleEnabled ? parseInt(group.userTitleEnabled, 10) === 1 : true; group.labelColor = group.labelColor || '#000000'; group.createtimeISO = utils.toISOString(group.createtime); group.hidden = parseInt(group.hidden, 10) === 1; @@ -925,7 +929,7 @@ var async = require('async'), } groupData = groupData.filter(function(group) { - return group && parseInt(group.hidden, 10) !== 1 && !!group.userTitle; + return group && parseInt(group.hidden, 10) !== 1; }); var groupSets = groupData.map(function(group) { From 29873f1c5c55a5b6328a7f9f811a74e9690845a2 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 25 Feb 2015 12:26:35 -0500 Subject: [PATCH 004/143] removed unused .getAll method, and sorting notifications client-side so that unread notifs don't all appear at the top, #2772 --- public/src/modules/notifications.js | 4 +++- src/user/notifications.js | 14 -------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/public/src/modules/notifications.js b/public/src/modules/notifications.js index 6e36cf7296..d0f92d0230 100644 --- a/public/src/modules/notifications.js +++ b/public/src/modules/notifications.js @@ -22,7 +22,9 @@ define('notifications', ['sounds'], function(sound) { return app.alertError(err.message); } - var notifs = data.unread.concat(data.read); + var notifs = data.unread.concat(data.read).sort(function(a, b) { + return parseInt(a.datetime, 10) > parseInt(b.datetime, 10) ? -1 : 1; + }); translator.toggleTimeagoShorthand(); for(var i=0; i Date: Wed, 25 Feb 2015 12:39:32 -0500 Subject: [PATCH 005/143] update tjs to 0.1.18 for conditional helper functionality --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 93c685afec..b2fbd45acf 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "socket.io-redis": "^0.1.3", "socketio-wildcard": "~0.1.1", "string": "^3.0.0", - "templates.js": "^0.1.15", + "templates.js": "^0.1.18", "uglify-js": "git+https://github.com/julianlam/UglifyJS2.git", "underscore": "~1.7.0", "validator": "^3.30.0", From e2b535dfaf79416078be7e763192b89094208767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 25 Feb 2015 12:43:56 -0500 Subject: [PATCH 006/143] closes #1973 --- src/search.js | 9 ++--- src/topics.js | 1 + src/topics/suggested.js | 74 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/topics/suggested.js diff --git a/src/search.js b/src/search.js index 190a764bf2..8ccdf77d78 100644 --- a/src/search.js +++ b/src/search.js @@ -58,14 +58,14 @@ function searchInContent(query, data, callback) { async.parallel({ pids: function(next) { if (data.searchIn === 'posts' || data.searchIn === 'titlesposts') { - searchQuery('post', query, next); + search.searchQuery('post', query, next); } else { next(null, []); } }, tids: function(next) { if (data.searchIn === 'titles' || data.searchIn === 'titlesposts') { - searchQuery('topic', query, next); + search.searchQuery('topic', query, next); } else { next(null, []); } @@ -93,6 +93,7 @@ function searchInContent(query, data, callback) { mainPids.push(pid); } }); + privileges.posts.filter('read', mainPids, data.uid, next); }, function(pids, next) { @@ -475,10 +476,10 @@ function getMainPids(tids, callback) { }); } -function searchQuery(index, query, callback) { +search.searchQuery = function(index, query, callback) { plugins.fireHook('filter:search.query', { index: index, query: query }, callback); -} +}; diff --git a/src/topics.js b/src/topics.js index a9514dabba..274ffbcf70 100644 --- a/src/topics.js +++ b/src/topics.js @@ -25,6 +25,7 @@ var async = require('async'), require('./topics/follow')(Topics); require('./topics/tags')(Topics); require('./topics/teaser')(Topics); + require('./topics/suggested')(Topics); Topics.exists = function(tid, callback) { db.isSortedSetMember('topics:tid', tid, callback); diff --git a/src/topics/suggested.js b/src/topics/suggested.js new file mode 100644 index 0000000000..3c18d50dbe --- /dev/null +++ b/src/topics/suggested.js @@ -0,0 +1,74 @@ + +'use strict'; + +var async = require('async'), + _ = require('underscore'), + + categories = require('../categories'), + search = require('../search'), + db = require('../database'); + + +module.exports = function(Topics) { + + Topics.getSuggestedTopics = function(tid, uid, start, end, callback) { + async.parallel({ + tagTids: function(next) { + getTidsWithSameTags(tid, next); + }, + searchTids: function(next) { + getSearchTids(tid, uid, next); + }, + categoryTids: function(next) { + getCategoryTids(tid, next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + var tids = results.tagTids.concat(results.searchTids).concat(results.categoryTids); + tids = tids.filter(function(_tid, index, array) { + return parseInt(_tid, 10) !== parseInt(tid, 10) && array.indexOf(_tid) === index; + }).slice(start, end + 1); + + Topics.getTopics(tids, uid, callback); + }); + }; + + function getTidsWithSameTags(tid, callback) { + async.waterfall([ + function(next) { + Topics.getTopicTags(tid, next); + }, + function(tags, next) { + async.map(tags, function(tag, next) { + Topics.getTagTids(tag, 0, -1, next); + }, next); + }, + function(data, next) { + next(null, _.unique(_.flatten(data))); + } + ], callback); + } + + function getSearchTids(tid, uid, callback) { + async.waterfall([ + function(next) { + Topics.getTopicField(tid, 'title', next); + }, + function(title, next) { + search.searchQuery('topic', title, next); + } + ], callback); + } + + function getCategoryTids(tid, callback) { + Topics.getTopicField(tid, 'cid', function(err, cid) { + if (err || !cid) { + return callback(err, []); + } + categories.getTopicIds('cid:' + cid + ':tids', true, 0, 9, callback); + }); + } + +}; \ No newline at end of file From 0c903672d0ae2a5a0f11abee91ecca9caa457b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 25 Feb 2015 12:46:00 -0500 Subject: [PATCH 007/143] uid not used #1973 --- src/topics/suggested.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/topics/suggested.js b/src/topics/suggested.js index 3c18d50dbe..fd3455f726 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -17,7 +17,7 @@ module.exports = function(Topics) { getTidsWithSameTags(tid, next); }, searchTids: function(next) { - getSearchTids(tid, uid, next); + getSearchTids(tid, next); }, categoryTids: function(next) { getCategoryTids(tid, next); @@ -51,7 +51,7 @@ module.exports = function(Topics) { ], callback); } - function getSearchTids(tid, uid, callback) { + function getSearchTids(tid, callback) { async.waterfall([ function(next) { Topics.getTopicField(tid, 'title', next); From 6dacaf6bb528eefbd28669e89a4d084656e55456 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 12:48:26 -0500 Subject: [PATCH 008/143] helpers.displayMenuItem --- public/src/modules/helpers.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index c4676a0e37..059e4445ab 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -13,6 +13,18 @@ return (config.loggedIn || !config.privateUserInfo); }; + helpers.displayMenuItem = function(data, index) { + var properties = data.navigation[index].properties; + + if (properties.loggedIn && !ldata.oggedIn || + properties.adminOnly && !data.isAdmin || + properties.installed && properties.installed.search && !data.searchEnabled) { + return false; + } + + return true; + }; + helpers.buildMetaTag = function(tag) { var name = tag.name ? 'name="' + tag.name + '" ' : '', property = tag.property ? 'property="' + tag.property + '" ' : '', From ecad9d54edf556d5cc1a4f7d236b399a35ba6f6f Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:08:55 -0500 Subject: [PATCH 009/143] tjs 0.1.19 for undefined key cleanups --- package.json | 2 +- public/src/modules/helpers.js | 5 +- src/middleware/middleware.js | 103 +++++++++++++++++++++++++++++++++- 3 files changed, 106 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b2fbd45acf..8cf75017d9 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "socket.io-redis": "^0.1.3", "socketio-wildcard": "~0.1.1", "string": "^3.0.0", - "templates.js": "^0.1.18", + "templates.js": "^0.1.19", "uglify-js": "git+https://github.com/julianlam/UglifyJS2.git", "underscore": "~1.7.0", "validator": "^3.30.0", diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index 059e4445ab..8842defb9c 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -16,9 +16,10 @@ helpers.displayMenuItem = function(data, index) { var properties = data.navigation[index].properties; - if (properties.loggedIn && !ldata.oggedIn || + if (properties.loggedIn && !data.loggedIn || properties.adminOnly && !data.isAdmin || - properties.installed && properties.installed.search && !data.searchEnabled) { + properties.installed && properties.installed.search && !data.searchEnabled || + properties.hideIfPrivate && data.privateUserInfo) { return false; } diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 349a227215..cc59c458d1 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -217,7 +217,108 @@ middleware.renderHeader = function(req, res, callback) { var custom_header = { uid: uid, - 'navigation': [] + 'navigation': [ + { + id: "unread-count", + class: "", + route: "/unread", + title: "[[global:header.unread]]", + iconClass: "fa-inbox", + textClass: "visible-xs-inline", + text: "[[global:header.unread]]", + properties: { + loggedIn: true + } + }, + { + id: "", + class: "", + route: "/recent", + title: "[[global:header.recent]]", + iconClass: "fa-clock-o", + textClass: "visible-xs-inline", + text: "[[global:]]", + properties: { + + } + }, + { + id: "", + class: "", + route: "/tags", + title: "[[global:header.tags]]", + iconClass: "fa-tags", + textClass: "visible-xs-inline", + text: "[[global:header.tags]]", + properties: { + + } + }, + { + id: "", + class: "", + route: "/popular", + title: "[[global:header.popular]]", + iconClass: "fa-fire", + textClass: "visible-xs-inline", + text: "[[global:header.popular]]", + properties: { + + } + }, + { + id: "", + class: "", + route: "/users", + title: "[[global:header.users]]", + iconClass: "fa-user", + textClass: "visible-xs-inline", + text: "[[global:header.users]]", + properties: { + loggedIn: true, + hideIfPrivate: true + } + }, + { + id: "", + class: "", + route: "/groups", + title: "[[global:header.groups]]", + iconClass: "fa-group", + textClass: "visible-xs-inline", + text: "[[global:header.groups]]", + properties: { + + } + }, + { + id: "", + class: "", + route: "/admin", + target: "_top", + title: "[[global:header.admin]]", + iconClass: "fa-cogs", + textClass: "visible-xs-inline", + text: "[[global:header.admin]]", + properties: { + adminOnly: true + } + }, + { + id: "", + class: "", + route: "/search", + title: "[[global:header.search]]", + iconClass: "fa-search", + textClass: "visible-xs-inline", + text: "[[global:header.search]]", + properties: { + installed: { + search: true + } + } + } + ] }; plugins.fireHook('filter:header.build', custom_header, function(err, custom_header) { From 738c27bf04f0abf8d765e962d2ceca48d52d2333 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:10:38 -0500 Subject: [PATCH 010/143] started dynamic sortable menu --- src/middleware/middleware.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index cc59c458d1..6e782a1002 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -220,7 +220,6 @@ middleware.renderHeader = function(req, res, callback) { 'navigation': [ { id: "unread-count", - class: "", route: "/unread", title: "[[global:header.unread]]", iconClass: "fa-inbox", @@ -231,8 +230,6 @@ middleware.renderHeader = function(req, res, callback) { } }, { - id: "", - class: "", route: "/recent", title: "[[global:header.recent]]", iconClass: "fa-clock-o", @@ -243,8 +240,6 @@ middleware.renderHeader = function(req, res, callback) { } }, { - id: "", - class: "", route: "/tags", title: "[[global:header.tags]]", iconClass: "fa-tags", @@ -255,8 +250,6 @@ middleware.renderHeader = function(req, res, callback) { } }, { - id: "", - class: "", route: "/popular", title: "[[global:header.popular]]", iconClass: "fa-fire", @@ -267,8 +260,6 @@ middleware.renderHeader = function(req, res, callback) { } }, { - id: "", - class: "", route: "/users", title: "[[global:header.users]]", iconClass: "fa-user", @@ -280,8 +271,6 @@ middleware.renderHeader = function(req, res, callback) { } }, { - id: "", - class: "", route: "/groups", title: "[[global:header.groups]]", iconClass: "fa-group", @@ -292,8 +281,6 @@ middleware.renderHeader = function(req, res, callback) { } }, { - id: "", - class: "", route: "/admin", target: "_top", title: "[[global:header.admin]]", @@ -305,8 +292,6 @@ middleware.renderHeader = function(req, res, callback) { } }, { - id: "", - class: "", route: "/search", title: "[[global:header.search]]", iconClass: "fa-search", From d754a6390ea9f053dbdd3295a50381aba076c168 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:25:56 -0500 Subject: [PATCH 011/143] navigation install data --- install/data/navigation.json | 87 ++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 install/data/navigation.json diff --git a/install/data/navigation.json b/install/data/navigation.json new file mode 100644 index 0000000000..873e466c03 --- /dev/null +++ b/install/data/navigation.json @@ -0,0 +1,87 @@ +[ + { + id: "unread-count", + route: "/unread", + title: "[[global:header.unread]]", + iconClass: "fa-inbox", + textClass: "visible-xs-inline", + text: "[[global:header.unread]]", + properties: { + loggedIn: true + } + }, + { + route: "/recent", + title: "[[global:header.recent]]", + iconClass: "fa-clock-o", + textClass: "visible-xs-inline", + text: "[[global:]]", + properties: { + + } + }, + { + route: "/tags", + title: "[[global:header.tags]]", + iconClass: "fa-tags", + textClass: "visible-xs-inline", + text: "[[global:header.tags]]", + properties: { + + } + }, + { + route: "/popular", + title: "[[global:header.popular]]", + iconClass: "fa-fire", + textClass: "visible-xs-inline", + text: "[[global:header.popular]]", + properties: { + + } + }, + { + route: "/users", + title: "[[global:header.users]]", + iconClass: "fa-user", + textClass: "visible-xs-inline", + text: "[[global:header.users]]", + properties: { + loggedIn: true, + hideIfPrivate: true + } + }, + { + route: "/groups", + title: "[[global:header.groups]]", + iconClass: "fa-group", + textClass: "visible-xs-inline", + text: "[[global:header.groups]]", + properties: { + + } + }, + { + route: "/admin", + target: "_top", + title: "[[global:header.admin]]", + iconClass: "fa-cogs", + textClass: "visible-xs-inline", + text: "[[global:header.admin]]", + properties: { + adminOnly: true + } + }, + { + route: "/search", + title: "[[global:header.search]]", + iconClass: "fa-search", + textClass: "visible-xs-inline", + text: "[[global:header.search]]", + properties: { + installed: { + search: true + } + } + } +] \ No newline at end of file From 7a4fc8e48b09fe47178542ac5e20f241e19e656d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:26:09 -0500 Subject: [PATCH 012/143] save default menu on installation --- src/install.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/install.js b/src/install.js index d3df90b267..b696c5cdf8 100644 --- a/src/install.js +++ b/src/install.js @@ -385,6 +385,13 @@ function createCategories(next) { }); } +function createMenuItems(next) { + var navigation = require('./navigation/admin'), + data = require('../install/data/navigation.json'); + + navigation.save(data, next); +} + function createWelcomePost(next) { var db = require('./database'), Topics = require('./topics'); @@ -463,6 +470,7 @@ install.setup = function (callback) { enableDefaultTheme, createAdministrator, createCategories, + createMenuItems, createWelcomePost, enableDefaultPlugins, setCopyrightWidget, From 58411a47642d14bc3447018eca821928b7479ade Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:26:42 -0500 Subject: [PATCH 013/143] deprecated filter:header.build, the equivalent hook (same output data) will be filter:navigation.available --- src/middleware/middleware.js | 96 ++---------------------------------- 1 file changed, 3 insertions(+), 93 deletions(-) diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 6e782a1002..5d06207dce 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -12,6 +12,7 @@ var app, nconf = require('nconf'), plugins = require('./../plugins'), + navigation = require('./../navigation'), meta = require('./../meta'), translator = require('./../../public/src/translator'), user = require('./../user'), @@ -215,98 +216,7 @@ middleware.buildHeader = function(req, res, next) { middleware.renderHeader = function(req, res, callback) { var uid = req.user ? parseInt(req.user.uid, 10) : 0; - var custom_header = { - uid: uid, - 'navigation': [ - { - id: "unread-count", - route: "/unread", - title: "[[global:header.unread]]", - iconClass: "fa-inbox", - textClass: "visible-xs-inline", - text: "[[global:header.unread]]", - properties: { - loggedIn: true - } - }, - { - route: "/recent", - title: "[[global:header.recent]]", - iconClass: "fa-clock-o", - textClass: "visible-xs-inline", - text: "[[global:]]", - properties: { - - } - }, - { - route: "/tags", - title: "[[global:header.tags]]", - iconClass: "fa-tags", - textClass: "visible-xs-inline", - text: "[[global:header.tags]]", - properties: { - - } - }, - { - route: "/popular", - title: "[[global:header.popular]]", - iconClass: "fa-fire", - textClass: "visible-xs-inline", - text: "[[global:header.popular]]", - properties: { - - } - }, - { - route: "/users", - title: "[[global:header.users]]", - iconClass: "fa-user", - textClass: "visible-xs-inline", - text: "[[global:header.users]]", - properties: { - loggedIn: true, - hideIfPrivate: true - } - }, - { - route: "/groups", - title: "[[global:header.groups]]", - iconClass: "fa-group", - textClass: "visible-xs-inline", - text: "[[global:header.groups]]", - properties: { - - } - }, - { - route: "/admin", - target: "_top", - title: "[[global:header.admin]]", - iconClass: "fa-cogs", - textClass: "visible-xs-inline", - text: "[[global:header.admin]]", - properties: { - adminOnly: true - } - }, - { - route: "/search", - title: "[[global:header.search]]", - iconClass: "fa-search", - textClass: "visible-xs-inline", - text: "[[global:header.search]]", - properties: { - installed: { - search: true - } - } - } - ] - }; - - plugins.fireHook('filter:header.build', custom_header, function(err, custom_header) { + navigation.get(function(err, menuItems) { if (err) { return callback(err); } @@ -344,7 +254,7 @@ middleware.renderHeader = function(req, res, callback) { 'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '', 'brand:logo': meta.config['brand:logo'] || '', 'brand:logo:display': meta.config['brand:logo']?'':'hide', - navigation: custom_header.navigation, + navigation: menuItems, allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1, searchEnabled: plugins.hasListeners('filter:search.query') }; From ba9bba1dd8ee9edce2694222ccc2d97c512a7d7a Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:27:25 -0500 Subject: [PATCH 014/143] navigation backbone --- src/navigation/admin.js | 12 ++++++++++++ src/navigation/index.js | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/navigation/admin.js create mode 100644 src/navigation/index.js diff --git a/src/navigation/admin.js b/src/navigation/admin.js new file mode 100644 index 0000000000..5158453aad --- /dev/null +++ b/src/navigation/admin.js @@ -0,0 +1,12 @@ +"use strict"; + + +var admin = {}; + + +admin.save = function(data, callback) { + +}; + + +module.exports = admin; \ No newline at end of file diff --git a/src/navigation/index.js b/src/navigation/index.js new file mode 100644 index 0000000000..4eb1080c25 --- /dev/null +++ b/src/navigation/index.js @@ -0,0 +1,13 @@ +"use strict"; + + +var navigation = {}, + plugins = require('../plugins'); + + +navigation.load = function(callback) { + callback(false, []); +}; + + +module.exports = navigation; \ No newline at end of file From 80116c3e300ce06a34f9897bc9bd48b510837cbb Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:42:14 -0500 Subject: [PATCH 015/143] fixed potential bug in rewards --- src/rewards/admin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rewards/admin.js b/src/rewards/admin.js index 6136e4f4b3..30bed9e0e8 100644 --- a/src/rewards/admin.js +++ b/src/rewards/admin.js @@ -15,7 +15,7 @@ rewards.save = function(data, callback) { data.id = id; - async.parallel([ + async.waterfall([ function(next) { rewards.delete(data, next); }, From 3202a52a6198688bb86d185ca48783e996889bd3 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 25 Feb 2015 13:43:21 -0500 Subject: [PATCH 016/143] refactored notif dropdown, #2771 --- public/src/modules/notifications.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/public/src/modules/notifications.js b/public/src/modules/notifications.js index d0f92d0230..c58287350e 100644 --- a/public/src/modules/notifications.js +++ b/public/src/modules/notifications.js @@ -58,10 +58,9 @@ define('notifications', ['sounds'], function(sound) { }); notifList.on('click', '.mark-read', function(e) { - var anchorEl = $(this.parentNode), - parentEl = anchorEl.parent(), - nid = anchorEl.attr('data-nid'), - unread = parentEl.hasClass('unread'); + var liEl = $(this.parentNode), + nid = liEl.siblings('a').attr('data-nid'), + unread = liEl.hasClass('unread'); e.preventDefault(); e.stopPropagation(); @@ -71,7 +70,7 @@ define('notifications', ['sounds'], function(sound) { app.alertError(err.message); } - parentEl.toggleClass('unread'); + liEl.toggleClass('unread'); increaseNotifCount(unread ? -1 : 1); }); }); From f1adddb775754523f02b38702f9a00a2298a39a6 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:45:49 -0500 Subject: [PATCH 017/143] navigation - basic save function --- src/navigation/admin.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/navigation/admin.js b/src/navigation/admin.js index 5158453aad..0cc25dcce1 100644 --- a/src/navigation/admin.js +++ b/src/navigation/admin.js @@ -1,12 +1,31 @@ "use strict"; -var admin = {}; +var admin = {}, + async = require('async'), + plugins = require('../plugins'), + db = require('../database'); admin.save = function(data, callback) { + var order = Object.keys(data), + items = data.map(function(item) { + return JSON.stringify(item); + }); + async.waterfall([ + function(next) { + db.delete('navigation:enabled', next); + }, + function(next) { + db.sortedSetAdd('navigation:enabled', order, items, next); + } + ], callback); }; +admin.getAvailable = function(data, callback) { + var core = require('../../install/data/navigation.json'); + plugins.fireHook('filter:navigation.available', core, callback); +}; module.exports = admin; \ No newline at end of file From 9a24110a375ce6df6004db5d710401f81f3e70f2 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:50:35 -0500 Subject: [PATCH 018/143] jsonlint --- install/data/navigation.json | 116 ++++++++++++++++------------------- 1 file changed, 52 insertions(+), 64 deletions(-) diff --git a/install/data/navigation.json b/install/data/navigation.json index 873e466c03..cdc05e51e7 100644 --- a/install/data/navigation.json +++ b/install/data/navigation.json @@ -1,86 +1,74 @@ [ { - id: "unread-count", - route: "/unread", - title: "[[global:header.unread]]", - iconClass: "fa-inbox", - textClass: "visible-xs-inline", - text: "[[global:header.unread]]", - properties: { - loggedIn: true + "id": "unread-count", + "route": "/unread", + "title": "[[global:header.unread]]", + "iconClass": "fa-inbox", + "textClass": "visible-xs-inline", + "text": "[[global:header.unread]]", + "properties": { + "loggedIn": true } }, { - route: "/recent", - title: "[[global:header.recent]]", - iconClass: "fa-clock-o", - textClass: "visible-xs-inline", - text: "[[global:]]", - properties: { - - } + "route": "/recent", + "title": "[[global:header.recent]]", + "iconClass": "fa-clock-o", + "textClass": "visible-xs-inline", + "text": "[[global:]]" }, { - route: "/tags", - title: "[[global:header.tags]]", - iconClass: "fa-tags", - textClass: "visible-xs-inline", - text: "[[global:header.tags]]", - properties: { - - } + "route": "/tags", + "title": "[[global:header.tags]]", + "iconClass": "fa-tags", + "textClass": "visible-xs-inline", + "text": "[[global:header.tags]]" }, { - route: "/popular", - title: "[[global:header.popular]]", - iconClass: "fa-fire", - textClass: "visible-xs-inline", - text: "[[global:header.popular]]", - properties: { - - } + "route": "/popular", + "title": "[[global:header.popular]]", + "iconClass": "fa-fire", + "textClass": "visible-xs-inline", + "text": "[[global:header.popular]]" }, { - route: "/users", - title: "[[global:header.users]]", - iconClass: "fa-user", - textClass: "visible-xs-inline", - text: "[[global:header.users]]", - properties: { - loggedIn: true, - hideIfPrivate: true + "route": "/users", + "title": "[[global:header.users]]", + "iconClass": "fa-user", + "textClass": "visible-xs-inline", + "text": "[[global:header.users]]", + "properties": { + "loggedIn": true, + "hideIfPrivate": true } }, { - route: "/groups", - title: "[[global:header.groups]]", - iconClass: "fa-group", - textClass: "visible-xs-inline", - text: "[[global:header.groups]]", - properties: { - - } + "route": "/groups", + "title": "[[global:header.groups]]", + "iconClass": "fa-group", + "textClass": "visible-xs-inline", + "text": "[[global:header.groups]]" }, { - route: "/admin", - target: "_top", - title: "[[global:header.admin]]", - iconClass: "fa-cogs", - textClass: "visible-xs-inline", - text: "[[global:header.admin]]", - properties: { - adminOnly: true + "route": "/admin", + "target": "_top", + "title": "[[global:header.admin]]", + "iconClass": "fa-cogs", + "textClass": "visible-xs-inline", + "text": "[[global:header.admin]]", + "properties": { + "adminOnly": true } }, { - route: "/search", - title: "[[global:header.search]]", - iconClass: "fa-search", - textClass: "visible-xs-inline", - text: "[[global:header.search]]", - properties: { - installed: { - search: true + "route": "/search", + "title": "[[global:header.search]]", + "iconClass": "fa-search", + "textClass": "visible-xs-inline", + "text": "[[global:header.search]]", + "properties": { + "installed": { + "search": true } } } From 3be5242aa1685e6c1b6805d3e6a3e29bf6bde2a4 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:50:41 -0500 Subject: [PATCH 019/143] navigation - upgrade script --- src/upgrade.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/upgrade.js b/src/upgrade.js index 13484b124e..7a9047d57c 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -21,7 +21,7 @@ var db = require('./database'), schemaDate, thisSchemaDate, // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema - latestSchema = Date.UTC(2015, 1, 24, 1); + latestSchema = Date.UTC(2015, 1, 25); Upgrade.check = function(callback) { db.get('schemaDate', function(err, value) { @@ -941,6 +941,25 @@ Upgrade.upgrade = function(callback) { winston.info('[2015/02/24] Upgrading privilege groups to system groups skipped'); next(); } + }, + function(next) { + thisSchemaDate = Date.UTC(2015, 1, 25); + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.info('[2015/02/25] Upgrading menu items to dynamic navigation system'); + + require('./navigation/admin').save(require('../install/data/navigation.json'), function(err) { + if (err) { + return next(err); + } + + winston.info('[2015/02/25] Upgrading menu items to dynamic navigation system done'); + Upgrade.update(thisSchemaDate, next); + }); + } else { + winston.info('[2015/02/25] Upgrading menu items to dynamic navigation system skipped'); + next(); + } } // Add new schema updates here From 6cea047518e963d6e23491ee284102b6c0b8832b Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 13:55:26 -0500 Subject: [PATCH 020/143] loading navigation, complete --- public/src/modules/helpers.js | 12 +++++++----- src/navigation/index.js | 13 ++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index 8842defb9c..71473d0d9a 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -16,11 +16,13 @@ helpers.displayMenuItem = function(data, index) { var properties = data.navigation[index].properties; - if (properties.loggedIn && !data.loggedIn || - properties.adminOnly && !data.isAdmin || - properties.installed && properties.installed.search && !data.searchEnabled || - properties.hideIfPrivate && data.privateUserInfo) { - return false; + if (properties) { + if (properties.loggedIn && !data.loggedIn || + properties.adminOnly && !data.isAdmin || + properties.installed && properties.installed.search && !data.searchEnabled || + properties.hideIfPrivate && data.privateUserInfo) { + return false; + } } return true; diff --git a/src/navigation/index.js b/src/navigation/index.js index 4eb1080c25..5411a8f052 100644 --- a/src/navigation/index.js +++ b/src/navigation/index.js @@ -2,11 +2,18 @@ var navigation = {}, - plugins = require('../plugins'); + plugins = require('../plugins'), + db = require('../database'); -navigation.load = function(callback) { - callback(false, []); +navigation.get = function(callback) { + db.getSortedSetRange('navigation:enabled', 0, -1, function(err, data) { + data = data.map(function(item) { + return JSON.parse(item); + }); + + callback(err, data); + }) }; From 431a7f3300ad20391c56812c5d1f19ff7bd747d7 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 14:02:33 -0500 Subject: [PATCH 021/143] tjs 0.1.20 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8cf75017d9..d638486c8e 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "socket.io-redis": "^0.1.3", "socketio-wildcard": "~0.1.1", "string": "^3.0.0", - "templates.js": "^0.1.19", + "templates.js": "^0.1.20", "uglify-js": "git+https://github.com/julianlam/UglifyJS2.git", "underscore": "~1.7.0", "validator": "^3.30.0", From 6c77adfd3ca471f65e4953ba798b1f4bba814847 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 14:05:16 -0500 Subject: [PATCH 022/143] tjs 0.1.21 * --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d638486c8e..54d4c2bc6c 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "socket.io-redis": "^0.1.3", "socketio-wildcard": "~0.1.1", "string": "^3.0.0", - "templates.js": "^0.1.20", + "templates.js": "^0.1.21", "uglify-js": "git+https://github.com/julianlam/UglifyJS2.git", "underscore": "~1.7.0", "validator": "^3.30.0", From 55262b399a441e2e39ad6e4f3e566d70b1e186df Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 25 Feb 2015 14:10:00 -0500 Subject: [PATCH 023/143] tweaks and refactoring for #2774 --- public/language/en_GB/error.json | 1 + public/language/en_GB/notifications.json | 1 - src/controllers/index.js | 7 ++++--- src/user/email.js | 17 +++++++---------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index b2f9a3b86b..6d64645c59 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -25,6 +25,7 @@ "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", + "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Username too short", "username-too-long": "Username too long", diff --git a/public/language/en_GB/notifications.json b/public/language/en_GB/notifications.json index 96aef60183..19de8e2c28 100644 --- a/public/language/en_GB/notifications.json +++ b/public/language/en_GB/notifications.json @@ -25,7 +25,6 @@ "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", - "email-confirm-error": "An error occurred...", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", "email-confirm-sent": "Confirmation email sent." } diff --git a/src/controllers/index.js b/src/controllers/index.js index d8ddf81735..7f4afeb4dc 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -119,9 +119,10 @@ Controllers.register = function(req, res, next) { Controllers.confirmEmail = function(req, res, next) { - user.email.confirm(req.params.code, function (data) { - data.status = data.status === 'ok'; - res.render('confirm', data); + user.email.confirm(req.params.code, function (err) { + res.render('confirm', { + error: err ? err.message : '' + }); }); }; diff --git a/src/user/email.js b/src/user/email.js index 74b86c0cfe..e7f56ed21a 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -87,21 +87,18 @@ var async = require('async'), UserEmail.confirm = function(code, callback) { db.getObject('confirm:' + code, function(err, confirmObj) { if (err) { - return callback({ - status:'error' - }); + return callback(new Error('[[error:parse-error]]')); } if (confirmObj && confirmObj.uid && confirmObj.email) { - user.setUserField(confirmObj.uid, 'email:confirmed', 1, function() { - callback({ - status: 'ok' - }); + async.series([ + async.apply(user.setUserField, confirmObj.uid, 'email:confirmed', 1), + async.apply(db.delete, 'confirm:' + code) + ], function(err) { + callback(err ? new Error('[[error:email-confirm-failed]]') : null); }); } else { - callback({ - status: 'not_ok' - }); + callback(new Error('[[error:invalid-data]]')); } }); }; From 307204fc38c5ea7206b3403358880d0312546dd0 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 14:12:16 -0500 Subject: [PATCH 024/143] nav - added enabled/disabled --- install/data/navigation.json | 8 ++++++++ src/navigation/index.js | 11 ++++++++--- src/upgrade.js | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/install/data/navigation.json b/install/data/navigation.json index cdc05e51e7..ffd670a0e5 100644 --- a/install/data/navigation.json +++ b/install/data/navigation.json @@ -3,6 +3,7 @@ "id": "unread-count", "route": "/unread", "title": "[[global:header.unread]]", + "enabled": true, "iconClass": "fa-inbox", "textClass": "visible-xs-inline", "text": "[[global:header.unread]]", @@ -13,6 +14,7 @@ { "route": "/recent", "title": "[[global:header.recent]]", + "enabled": true, "iconClass": "fa-clock-o", "textClass": "visible-xs-inline", "text": "[[global:]]" @@ -20,6 +22,7 @@ { "route": "/tags", "title": "[[global:header.tags]]", + "enabled": true, "iconClass": "fa-tags", "textClass": "visible-xs-inline", "text": "[[global:header.tags]]" @@ -27,6 +30,7 @@ { "route": "/popular", "title": "[[global:header.popular]]", + "enabled": true, "iconClass": "fa-fire", "textClass": "visible-xs-inline", "text": "[[global:header.popular]]" @@ -34,6 +38,7 @@ { "route": "/users", "title": "[[global:header.users]]", + "enabled": true, "iconClass": "fa-user", "textClass": "visible-xs-inline", "text": "[[global:header.users]]", @@ -45,6 +50,7 @@ { "route": "/groups", "title": "[[global:header.groups]]", + "enabled": true, "iconClass": "fa-group", "textClass": "visible-xs-inline", "text": "[[global:header.groups]]" @@ -53,6 +59,7 @@ "route": "/admin", "target": "_top", "title": "[[global:header.admin]]", + "enabled": true, "iconClass": "fa-cogs", "textClass": "visible-xs-inline", "text": "[[global:header.admin]]", @@ -63,6 +70,7 @@ { "route": "/search", "title": "[[global:header.search]]", + "enabled": true, "iconClass": "fa-search", "textClass": "visible-xs-inline", "text": "[[global:header.search]]", diff --git a/src/navigation/index.js b/src/navigation/index.js index 5411a8f052..b7ae3b2932 100644 --- a/src/navigation/index.js +++ b/src/navigation/index.js @@ -8,9 +8,14 @@ var navigation = {}, navigation.get = function(callback) { db.getSortedSetRange('navigation:enabled', 0, -1, function(err, data) { - data = data.map(function(item) { - return JSON.parse(item); - }); + + data = data + .filter(function(item) { + return item.enabled; + }) + .map(function(item) { + return JSON.parse(item); + }); callback(err, data); }) diff --git a/src/upgrade.js b/src/upgrade.js index 7a9047d57c..01ab47d01b 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -21,7 +21,7 @@ var db = require('./database'), schemaDate, thisSchemaDate, // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema - latestSchema = Date.UTC(2015, 1, 25); + latestSchema = Date.UTC(2015, 1, 25, 1); Upgrade.check = function(callback) { db.get('schemaDate', function(err, value) { @@ -943,7 +943,7 @@ Upgrade.upgrade = function(callback) { } }, function(next) { - thisSchemaDate = Date.UTC(2015, 1, 25); + thisSchemaDate = Date.UTC(2015, 1, 25, 1); if (schemaDate < thisSchemaDate) { updatesMade = true; winston.info('[2015/02/25] Upgrading menu items to dynamic navigation system'); From 8256d2b997e57cb5c8bd537e61c51b7b2311fa8d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 14:15:50 -0500 Subject: [PATCH 025/143] bugfix --- src/navigation/index.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/navigation/index.js b/src/navigation/index.js index b7ae3b2932..e11f845576 100644 --- a/src/navigation/index.js +++ b/src/navigation/index.js @@ -8,17 +8,13 @@ var navigation = {}, navigation.get = function(callback) { db.getSortedSetRange('navigation:enabled', 0, -1, function(err, data) { - - data = data - .filter(function(item) { - return item.enabled; - }) - .map(function(item) { - return JSON.parse(item); - }); - - callback(err, data); - }) + callback(err, data.map(function(item) { + return JSON.parse(item); + }) + .filter(function(item) { + return item.enabled; + })); + }); }; From 094cd6df32305d02d3aa37187928b994cdc6dc38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 25 Feb 2015 14:17:30 -0500 Subject: [PATCH 026/143] closes #2777 --- public/src/client/unread.js | 9 ++------- src/categories.js | 11 ++--------- src/privileges/categories.js | 7 +++++++ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/public/src/client/unread.js b/public/src/client/unread.js index 96c54e7536..994d4e1ddb 100644 --- a/public/src/client/unread.js +++ b/public/src/client/unread.js @@ -123,25 +123,20 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], } function createCategoryLinks(categories) { - categories = categories.filter(function(category) { - return !category.disabled; - }); - - for(var i=0; i'); + if (category.icon) { link.append(' ' + category.name); } else { link.append(category.name); } - $('') .append(link) .appendTo($('.markread .dropdown-menu')); diff --git a/src/categories.js b/src/categories.js index a4b6ce2092..87c540aaf1 100644 --- a/src/categories.js +++ b/src/categories.js @@ -121,13 +121,7 @@ var async = require('async'), }, function(cids, next) { Categories.getCategories(cids, uid, next); - }, - function(categories, next) { - categories = categories.filter(function(category) { - return !category.disabled; - }); - next(null, categories); - } + } ], callback); }; @@ -286,10 +280,9 @@ var async = require('async'), Categories.getCategoriesData(cids, next); }, function (categories, next) { - // Filter categories to isolate children, and remove disabled categories async.map(cids, function(cid, next) { next(null, categories.filter(function(category) { - return category && parseInt(category.parentCid, 10) === parseInt(cid, 10) && !category.disabled; + return category && parseInt(category.parentCid, 10) === parseInt(cid, 10); })); }, next); } diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 267c9e2c81..4a623eaa27 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -84,6 +84,9 @@ module.exports = function(privileges) { }); async.parallel({ + categories: function(next) { + categories.getMultipleCategoryFields(cids, ['disabled'], next); + }, allowedTo: function(next) { helpers.isUserAllowedTo(privilege, uid, cids, next); }, @@ -98,6 +101,10 @@ module.exports = function(privileges) { return callback(err); } + cids = cids.filter(function(cid, index) { + return !results.categories[index].disabled; + }); + if (results.isAdmin) { return callback(null, cids); } From 77d154bb8b9549523e35c323dcb62f811c27dfb6 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 22 Feb 2015 01:29:40 -0500 Subject: [PATCH 027/143] added ajaxify popstate cache, so back/forward will just put back the already loaded page --- public/src/ajaxify.js | 15 +++++++++++-- public/src/modules/ajaxifyCache.js | 35 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 public/src/modules/ajaxifyCache.js diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index cd87159420..8ba7fef1a6 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -1,9 +1,11 @@ "use strict"; -var ajaxify = ajaxify || {}; +var ajaxify = ajaxify || { + isPopState: false +}; $(document).ready(function() { - require(['templates'], function (templatesModule) { + require(['templates', 'ajaxifyCache'], function (templatesModule, cache) { /*global app, templates, utils, socket, translator, config, RELATIVE_PATH*/ var location = document.location || window.location, @@ -13,7 +15,9 @@ $(document).ready(function() { window.onpopstate = function (event) { if (event !== null && event.state && event.state.url !== undefined && !ajaxify.initialLoad) { + ajaxify.isPopState = true; ajaxify.go(event.state.url, function() { + ajaxify.isPopState = false; $(window).trigger('action:popstate', {url: event.state.url}); }, true); } @@ -55,6 +59,12 @@ $(document).ready(function() { // "quiet": If set to true, will not call pushState app.enterRoom(''); + // If the url is in the cache, load from cache instead + if (cache.get(url)) { return true; } + else { + cache.url = ajaxify.currentPage; + } + $(window).off('scroll'); if ($('#content').hasClass('ajaxifying') && apiXHR) { @@ -114,6 +124,7 @@ $(document).ready(function() { templates.parse(tpl_url, data, function(template) { translator.translate(template, function(translatedTemplate) { setTimeout(function() { + cache.set(); $('#content').html(translatedTemplate); ajaxify.variables.parse(); diff --git a/public/src/modules/ajaxifyCache.js b/public/src/modules/ajaxifyCache.js new file mode 100644 index 0000000000..eaa682b0da --- /dev/null +++ b/public/src/modules/ajaxifyCache.js @@ -0,0 +1,35 @@ +'use strict'; +/* globals define, app, ajaxify */ + +define('ajaxifyCache', function() { + var Cache = { + url: undefined, + DOM: undefined, + tempDOM: undefined + }; + + Cache.set = function() { + Cache.DOM = $('#content > *').detach(); + }; + + Cache.get = function(url) { + if (url === Cache.url && ajaxify.isPopState) { + // Swap DOM elements + setTimeout(function() { + Cache.tempDOM = $('#content > *').detach(); + $('#content').append(Cache.DOM); + Cache.DOM = Cache.tempDOM; + }, 100); // 100ms for realism! :sunglasses: + + // Set the values that normally get set on ajaxify + Cache.url = ajaxify.currentPage; + ajaxify.currentPage = url; + + return true; + } else { + return false; + } + }; + + return Cache; +}); \ No newline at end of file From d8c9ec0d406147b4ac9631fcc7687073ee71ea8e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 22 Feb 2015 21:10:06 -0500 Subject: [PATCH 028/143] on click, topics are marked read from the unread page. Also fixed an issue where isPopState kept getting set to true, causing issues --- public/src/ajaxify.js | 1 + public/src/client/unread.js | 27 ++++++++++++++++++++------- public/src/modules/ajaxifyCache.js | 4 ++-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 8ba7fef1a6..7f99f3d2be 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -63,6 +63,7 @@ $(document).ready(function() { if (cache.get(url)) { return true; } else { cache.url = ajaxify.currentPage; + ajaxify.isPopState = false; } $(window).off('scroll'); diff --git a/public/src/client/unread.js b/public/src/client/unread.js index 994d4e1ddb..8a6df4f9cd 100644 --- a/public/src/client/unread.js +++ b/public/src/client/unread.js @@ -12,6 +12,8 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], }); Unread.init = function() { + var topicsContainer = $('#topics-container'); + app.enterRoom('recent_posts'); $('#new-topics-alert').on('click', function() { @@ -42,7 +44,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], app.alertSuccess('[[unread:topics_marked_as_read.success]]'); - $('#topics-container').empty(); + topicsContainer.empty(); $('#category-no-topics').removeClass('hidden'); $('.markread').addClass('hidden'); }); @@ -68,11 +70,22 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], }); }); + topicsContainer.on('click', '.topic-title, .replies a', function(e) { + var tid = $(e.target).parents('[data-tid]').attr('data-tid'); + socket.emit('topics.markAsRead', [tid], function(err) { + if(err) { + return app.alertError(err.message); + } + + doneRemovingTids([tid]); + }); + }); + socket.emit('categories.get', onCategoriesLoaded); topicSelect.init(); - if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) { + if ($("body").height() <= $(window).height() && topicsContainer.children().length >= 20) { $('#load-more-btn').show(); } @@ -83,16 +96,16 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], infinitescroll.init(loadMoreTopics); function loadMoreTopics(direction) { - if(direction < 0 || !$('#topics-container').length) { + if(direction < 0 || !topicsContainer.length) { return; } infinitescroll.loadMore('topics.loadMoreUnreadTopics', { - after: $('#topics-container').attr('data-nextstart') + after: topicsContainer.attr('data-nextstart') }, function(data, done) { if (data.topics && data.topics.length) { recent.onTopicsLoaded('unread', data.topics, true, done); - $('#topics-container').attr('data-nextstart', data.nextStart); + topicsContainer.attr('data-nextstart', data.nextStart); } else { done(); $('#load-more-btn').hide(); @@ -101,10 +114,10 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], } }; - function doneRemovingTids(tids) { + function doneRemovingTids(tids, quiet) { removeTids(tids); - app.alertSuccess('[[unread:topics_marked_as_read.success]]'); + if (!quiet) { app.alertSuccess('[[unread:topics_marked_as_read.success]]'); } if (!$('#topics-container').children().length) { $('#category-no-topics').removeClass('hidden'); diff --git a/public/src/modules/ajaxifyCache.js b/public/src/modules/ajaxifyCache.js index eaa682b0da..1e5c63fa5c 100644 --- a/public/src/modules/ajaxifyCache.js +++ b/public/src/modules/ajaxifyCache.js @@ -15,11 +15,11 @@ define('ajaxifyCache', function() { Cache.get = function(url) { if (url === Cache.url && ajaxify.isPopState) { // Swap DOM elements - setTimeout(function() { + // setTimeout(function() { Cache.tempDOM = $('#content > *').detach(); $('#content').append(Cache.DOM); Cache.DOM = Cache.tempDOM; - }, 100); // 100ms for realism! :sunglasses: + // }, 100); // 100ms for realism! :sunglasses: // Set the values that normally get set on ajaxify Cache.url = ajaxify.currentPage; From e6701c5a1f5a87a526c860f8e25e68ca1a65492d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 23 Feb 2015 11:50:41 -0500 Subject: [PATCH 029/143] actually fixed isPopState error --- public/src/ajaxify.js | 7 ++----- public/src/modules/ajaxifyCache.js | 4 +++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 7f99f3d2be..adaef4cb8f 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -60,11 +60,8 @@ $(document).ready(function() { app.enterRoom(''); // If the url is in the cache, load from cache instead - if (cache.get(url)) { return true; } - else { - cache.url = ajaxify.currentPage; - ajaxify.isPopState = false; - } + if (cache.get(url, callback)) { return true; } + else { cache.url = ajaxify.currentPage; } $(window).off('scroll'); diff --git a/public/src/modules/ajaxifyCache.js b/public/src/modules/ajaxifyCache.js index 1e5c63fa5c..02313c3d68 100644 --- a/public/src/modules/ajaxifyCache.js +++ b/public/src/modules/ajaxifyCache.js @@ -12,7 +12,7 @@ define('ajaxifyCache', function() { Cache.DOM = $('#content > *').detach(); }; - Cache.get = function(url) { + Cache.get = function(url, callback) { if (url === Cache.url && ajaxify.isPopState) { // Swap DOM elements // setTimeout(function() { @@ -25,6 +25,8 @@ define('ajaxifyCache', function() { Cache.url = ajaxify.currentPage; ajaxify.currentPage = url; + if (typeof callback === 'function') { callback(); } + return true; } else { return false; From fbc0a11c879771386a2a53abc3e5cf50824342f8 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 14:50:45 -0500 Subject: [PATCH 030/143] nav - basic ACP setup --- install/data/navigation.json | 2 +- public/less/admin/admin.less | 1 + public/less/admin/general/navigation.less | 6 ++ src/controllers/admin.js | 39 ++++++++----- src/navigation/admin.js | 17 +++++- src/routes/admin.js | 1 + src/views/admin/general/navigation.tpl | 67 +++++++++++++++++++++++ src/views/admin/partials/menu.tpl | 1 + 8 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 public/less/admin/general/navigation.less create mode 100644 src/views/admin/general/navigation.tpl diff --git a/install/data/navigation.json b/install/data/navigation.json index ffd670a0e5..9d690fd415 100644 --- a/install/data/navigation.json +++ b/install/data/navigation.json @@ -17,7 +17,7 @@ "enabled": true, "iconClass": "fa-clock-o", "textClass": "visible-xs-inline", - "text": "[[global:]]" + "text": "[[global:header.recent]]" }, { "route": "/tags", diff --git a/public/less/admin/admin.less b/public/less/admin/admin.less index 1e4a10643d..528c9f7381 100644 --- a/public/less/admin/admin.less +++ b/public/less/admin/admin.less @@ -2,6 +2,7 @@ @import "./mixins"; @import "./general/dashboard"; +@import "./general/navigation"; @import "./manage/categories"; @import "./manage/groups"; @import "./manage/tags"; diff --git a/public/less/admin/general/navigation.less b/public/less/admin/general/navigation.less new file mode 100644 index 0000000000..3ae2c28c25 --- /dev/null +++ b/public/less/admin/general/navigation.less @@ -0,0 +1,6 @@ +#navigation { + ul { + list-style-type: none; + padding: 0; + } +} \ No newline at end of file diff --git a/src/controllers/admin.js b/src/controllers/admin.js index 33e86a383a..2f2d5cad52 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -37,6 +37,7 @@ var adminController = { settings: {}, logger: {}, sounds: {}, + navigation: {}, themes: {}, users: require('./admin/users'), uploads: require('./admin/uploads') @@ -230,6 +231,30 @@ adminController.languages.get = function(req, res, next) { }); }; +adminController.sounds.get = function(req, res, next) { + meta.sounds.getFiles(function(err, sounds) { + sounds = Object.keys(sounds).map(function(name) { + return { + name: name + }; + }); + + res.render('admin/general/sounds', { + sounds: sounds + }); + }); +}; + +adminController.navigation.get = function(req, res, next) { + require('../navigation/admin').get(function(err, data) { + if (err) { + return next(err); + } + + res.render('admin/general/navigation', data); + }); +}; + adminController.settings.get = function(req, res, next) { var term = req.params.term ? req.params.term : 'general'; @@ -340,20 +365,6 @@ adminController.groups.get = function(req, res, next) { }); }; -adminController.sounds.get = function(req, res, next) { - meta.sounds.getFiles(function(err, sounds) { - sounds = Object.keys(sounds).map(function(name) { - return { - name: name - }; - }); - - res.render('admin/general/sounds', { - sounds: sounds - }); - }); -}; - adminController.themes.get = function(req, res, next) { var themeDir = path.join(__dirname, '../../node_modules/' + req.params.theme); fs.exists(themeDir, function(exists) { diff --git a/src/navigation/admin.js b/src/navigation/admin.js index 0cc25dcce1..c60701e10d 100644 --- a/src/navigation/admin.js +++ b/src/navigation/admin.js @@ -23,9 +23,20 @@ admin.save = function(data, callback) { ], callback); }; -admin.getAvailable = function(data, callback) { - var core = require('../../install/data/navigation.json'); - plugins.fireHook('filter:navigation.available', core, callback); +admin.get = function(callback) { + async.parallel({ + enabled: require('./index').get, + available: getAvailable + }, callback); }; +function getAvailable(callback) { + var core = require('../../install/data/navigation.json').map(function(item) { + item.core = true; + return item; + }); + + plugins.fireHook('filter:navigation.available', core, callback); +} + module.exports = admin; \ No newline at end of file diff --git a/src/routes/admin.js b/src/routes/admin.js index 5175059493..a9c3ecc6ff 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -43,6 +43,7 @@ function addRoutes(router, middleware, controllers) { router.get('/general/dashboard', controllers.admin.home); router.get('/general/languages', controllers.admin.languages.get); router.get('/general/sounds', controllers.admin.sounds.get); + router.get('/general/navigation', controllers.admin.navigation.get); router.get('/manage/categories', controllers.admin.categories.active); router.get('/manage/categories/active', controllers.admin.categories.active); diff --git a/src/views/admin/general/navigation.tpl b/src/views/admin/general/navigation.tpl new file mode 100644 index 0000000000..2356309f06 --- /dev/null +++ b/src/views/admin/general/navigation.tpl @@ -0,0 +1,67 @@ + \ No newline at end of file diff --git a/src/views/admin/partials/menu.tpl b/src/views/admin/partials/menu.tpl index 597173be2e..37fbd6f017 100644 --- a/src/views/admin/partials/menu.tpl +++ b/src/views/admin/partials/menu.tpl @@ -4,6 +4,7 @@
  • Dashboard
  • Languages
  • Sounds
  • +
  • Navigation
  • @@ -51,6 +52,7 @@ coreplugin + From 1ae0a8a1bf72ec4a9381e0ca663ed28d60bb3819 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 15:01:45 -0500 Subject: [PATCH 032/143] typo --- public/src/admin/general/navigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/admin/general/navigation.js b/public/src/admin/general/navigation.js index 4bdb1973c6..a9452a9579 100644 --- a/public/src/admin/general/navigation.js +++ b/public/src/admin/general/navigation.js @@ -31,7 +31,7 @@ define('admin/general/navigation', function() { nav.push(data); }); - socket.emit('admin.navigation.save', activeRewards, function(err) { + socket.emit('admin.navigation.save', nav, function(err) { if (err) { app.alertError(err.message); } else { From a2e3179ea49c9342a958fc82fae33a234e76a8ba Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 25 Feb 2015 15:16:51 -0500 Subject: [PATCH 033/143] nav - enable / disable --- public/src/admin/general/navigation.js | 9 +++++++++ public/src/modules/helpers.js | 7 ++++++- src/navigation/index.js | 3 --- src/socket.io/admin.js | 1 + src/views/admin/general/navigation.tpl | 13 ++++++++----- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/public/src/admin/general/navigation.js b/public/src/admin/general/navigation.js index a9452a9579..6e2e36e66d 100644 --- a/public/src/admin/general/navigation.js +++ b/public/src/admin/general/navigation.js @@ -14,6 +14,15 @@ define('admin/general/navigation', function() { $(this).parents('li').remove(); }); + $('.toggle').on('click', function() { + var btn = $(this), + disabled = btn.html() === 'Enable'; + + btn.toggleClass('btn-warning').toggleClass('btn-success').html(!disabled ? 'Enable' : 'Disable'); + btn.parents('li').find('[name="enabled"]').val(disabled); + return false; + }); + $('#save').on('click', saveNavigation); }; diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index 71473d0d9a..14815c9811 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -14,7 +14,12 @@ }; helpers.displayMenuItem = function(data, index) { - var properties = data.navigation[index].properties; + var item = data.navigation[index], + properites = item.properties; + + if (!item.enabled) { + return false; + } if (properties) { if (properties.loggedIn && !data.loggedIn || diff --git a/src/navigation/index.js b/src/navigation/index.js index e11f845576..6a7ea1f638 100644 --- a/src/navigation/index.js +++ b/src/navigation/index.js @@ -10,9 +10,6 @@ navigation.get = function(callback) { db.getSortedSetRange('navigation:enabled', 0, -1, function(err, data) { callback(err, data.map(function(item) { return JSON.parse(item); - }) - .filter(function(item) { - return item.enabled; })); }); }; diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 30782f4d6e..dcbda783aa 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -26,6 +26,7 @@ var async = require('async'), groups: require('./admin/groups'), tags: require('./admin/tags'), rewards: require('./admin/rewards'), + navigation: require('./admin/navigation'), themes: {}, plugins: {}, widgets: {}, diff --git a/src/views/admin/general/navigation.tpl b/src/views/admin/general/navigation.tpl index e513c1b7a1..0f2890f855 100644 --- a/src/views/admin/general/navigation.tpl +++ b/src/views/admin/general/navigation.tpl @@ -13,11 +13,11 @@ -