diff --git a/package.json b/package.json index f237242210..c5f76cfd9a 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "mmmagic": "^0.4.0", "morgan": "^1.3.2", "nconf": "~0.8.2", - "nodebb-plugin-composer-default": "1.0.19", + "nodebb-plugin-composer-default": "1.0.20", "nodebb-plugin-dbsearch": "0.2.17", "nodebb-plugin-emoji-extended": "0.4.15", "nodebb-plugin-markdown": "4.0.6", @@ -48,10 +48,10 @@ "nodebb-plugin-soundpack-default": "0.1.4", "nodebb-plugin-spam-be-gone": "0.4.2", "nodebb-rewards-essentials": "0.0.5", - "nodebb-theme-lavender": "2.0.8", - "nodebb-theme-persona": "3.0.56", - "nodebb-theme-vanilla": "4.0.24", - "nodebb-widget-essentials": "2.0.2", + "nodebb-theme-lavender": "2.0.10", + "nodebb-theme-persona": "3.0.61", + "nodebb-theme-vanilla": "4.0.28", + "nodebb-widget-essentials": "2.0.3", "npm": "^2.1.4", "passport": "^0.3.0", "passport-local": "1.0.0", @@ -67,7 +67,7 @@ "socket.io-redis": "^0.1.3", "socketio-wildcard": "~0.1.1", "string": "^3.0.0", - "templates.js": "0.2.16", + "templates.js": "0.3.0", "uglify-js": "^2.4.24", "underscore": "~1.8.3", "underscore.deep": "^0.5.1", diff --git a/public/src/client/footer.js b/public/src/client/footer.js index 288123c8e1..6c8f4c5711 100644 --- a/public/src/client/footer.js +++ b/public/src/client/footer.js @@ -36,7 +36,7 @@ define('forum/footer', ['notifications', 'chat', 'components', 'translator'], fu function increaseUnreadCount() { var count = parseInt($('#unread-count i').attr('data-content'), 10) + 1; - updateUnreadTopicCount(null, count); + updateUnreadTopicCount(count); } function markTopicsUnread(tid) { diff --git a/public/src/client/topic/events.js b/public/src/client/topic/events.js index 47c7f2c328..7dfe57beed 100644 --- a/public/src/client/topic/events.js +++ b/public/src/client/topic/events.js @@ -81,7 +81,7 @@ define('forum/topic/events', [ $('[data-pid="' + data.post.pid + '"] .favouriteCount').html(data.post.reputation).attr('data-favourites', data.post.reputation); } - function onTopicPurged(data) { + function onTopicPurged() { if (ajaxify.data.category && ajaxify.data.category.slug) { ajaxify.go('category/' + ajaxify.data.category.slug, null, true); } @@ -162,6 +162,8 @@ define('forum/topic/events', [ function onPostPurged(pid) { components.get('post', 'pid', pid).fadeOut(500, function() { $(this).remove(); + ajaxify.data.postcount --; + postTools.updatePostCount(ajaxify.data.postcount); posts.showBottomPostBar(); }); diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 764ec7cd0a..c3e58d3db9 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -10,6 +10,8 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator PostTools.init = function(tid) { topicName = ajaxify.data.title; + renderMenu(); + addPostHandlers(tid); share.addShareHandlers(topicName); @@ -19,6 +21,30 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator PostTools.updatePostCount(ajaxify.data.postcount); }; + function renderMenu() { + $('[component="topic"]').on('show.bs.dropdown', '.moderator-tools', function() { + var $this = $(this); + var dropdownMenu = $this.find('.dropdown-menu'); + if (dropdownMenu.html()) { + return; + } + var postEl = $this.parents('[data-pid]'); + var pid = postEl.attr('data-pid'); + var index = parseInt(postEl.attr('data-index'), 10); + socket.emit('posts.loadPostTools', {pid: pid, cid: ajaxify.data.cid}, function(err, data) { + if (err) { + return app.alertError(err); + } + data.posts.display_move_tools = data.posts.display_move_tools && index !== 0; + templates.parse('partials/topic/post-menu-list', data, function(html) { + translator.translate(html, function(html) { + dropdownMenu.html(html); + }); + }); + }); + }); + } + PostTools.toggle = function(pid, isDeleted) { var postEl = components.get('post', 'pid', pid); diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 784a11c4a4..02fdfbc26f 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -211,6 +211,7 @@ define('forum/topic/posts', [ }; Posts.processPage = function(posts) { + Posts.showBottomPostBar(); app.createUserTooltips(posts); app.replaceSelfLinks(posts.find('a')); utils.addCommasToNumbers(posts.find('.formatted-number')); @@ -225,11 +226,16 @@ define('forum/topic/posts', [ addBlockquoteEllipses(posts.find('[component="post/content"] > blockquote > blockquote')); hidePostToolsForDeletedPosts(posts); - Posts.showBottomPostBar(); }; Posts.showBottomPostBar = function() { - $('.bottom-post-bar').toggleClass('hidden', components.get('post').length <= 1 && !!components.get('post', 'index', 0).length); + var mainPost = components.get('post', 'index', 0); + var posts = $('[component="post"]'); + if (!!mainPost.length && posts.length > 1 && $('.post-bar').length < 2) { + $('.post-bar').clone().appendTo(mainPost); + } else if (mainPost.length && posts.length < 2) { + mainPost.find('.post-bar').remove(); + } }; function hidePostToolsForDeletedPosts(posts) { diff --git a/public/src/client/topic/threadTools.js b/public/src/client/topic/threadTools.js index 82ee651ef9..69c8fad673 100644 --- a/public/src/client/topic/threadTools.js +++ b/public/src/client/topic/threadTools.js @@ -1,48 +1,53 @@ 'use strict'; -/* globals define, app, ajaxify, socket, bootbox */ +/* globals define, app, ajaxify, socket, bootbox, templates */ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move', 'components', 'translator'], function(fork, move, components, translator) { var ThreadTools = {}; ThreadTools.init = function(tid) { - components.get('topic/delete').on('click', function() { + + renderMenu(); + + var topicContainer = $('.topic'); + + topicContainer.on('click', '[component="topic/delete"]', function() { topicCommand('delete', tid); return false; }); - components.get('topic/restore').on('click', function() { + topicContainer.on('click', '[component="topic/restore"]', function() { topicCommand('restore', tid); return false; }); - components.get('topic/purge').on('click', function() { + topicContainer.on('click', '[component="topic/purge"]', function() { topicCommand('purge', tid); return false; }); - components.get('topic/lock').on('click', function() { + topicContainer.on('click', '[component="topic/lock"]', function() { socket.emit('topics.lock', {tids: [tid], cid: ajaxify.data.cid}); return false; }); - components.get('topic/unlock').on('click', function() { + topicContainer.on('click', '[component="topic/unlock"]', function() { socket.emit('topics.unlock', {tids: [tid], cid: ajaxify.data.cid}); return false; }); - components.get('topic/pin').on('click', function() { + topicContainer.on('click', '[component="topic/pin"]', function() { socket.emit('topics.pin', {tids: [tid], cid: ajaxify.data.cid}); return false; }); - components.get('topic/unpin').on('click', function() { + topicContainer.on('click', '[component="topic/unpin"]', function() { socket.emit('topics.unpin', {tids: [tid], cid: ajaxify.data.cid}); return false; }); - components.get('topic/mark-unread-for-all').on('click', function() { + topicContainer.on('click', '[component="topic/mark-unread-for-all"]', function() { var btn = $(this); socket.emit('topics.markAsUnreadForAll', [tid], function(err) { if (err) { @@ -54,7 +59,7 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move', 'comp return false; }); - components.get('topic/move').on('click', function(e) { + topicContainer.on('click', '[component="topic/move"]', function() { move.init([tid], ajaxify.data.cid); return false; }); @@ -91,6 +96,28 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move', 'comp } }; + function renderMenu() { + $('.topic').on('show.bs.dropdown', '.thread-tools', function () { + var $this = $(this); + var dropdownMenu = $this.find('.dropdown-menu'); + if (dropdownMenu.html()) { + return; + } + + socket.emit('topics.loadTopicTools', {tid: ajaxify.data.tid, cid: ajaxify.data.cid}, function(err, data) { + if (err) { + return app.alertError(err); + } + + templates.parse('partials/topic/topic-menu-list', data, function(html) { + translator.translate(html, function(html) { + dropdownMenu.html(html); + }); + }); + }); + }); + } + function topicCommand(command, tid) { translator.translate('[[topic:thread_tools.' + command + '_confirm]]', function(msg) { bootbox.confirm(msg, function(confirm) { diff --git a/src/posts/user.js b/src/posts/user.js index 4badf60650..baf6995d45 100644 --- a/src/posts/user.js +++ b/src/posts/user.js @@ -40,10 +40,12 @@ module.exports = function(Posts) { slug: group.slug, labelColor: group.labelColor, icon: group.icon, - userTitle: group.userTitle, - userTitleEnabled: group.userTitleEnabled, - selected: group.name === results.userSettings[i].groupTitle + userTitle: group.userTitle }; + + if (group.name === results.userSettings[i].groupTitle && group.userTitleEnabled) { + userData.selectedGroup = userData.groups[index]; + } }); userData.status = user.getStatus(userData.status, results.online[i]); }); diff --git a/src/socket.io/posts/tools.js b/src/socket.io/posts/tools.js index e5e04b8f5a..fc4491ea44 100644 --- a/src/socket.io/posts/tools.js +++ b/src/socket.io/posts/tools.js @@ -6,10 +6,44 @@ var posts = require('../../posts'); var events = require('../../events'); var websockets = require('../index'); var socketTopics = require('../topics'); +var privileges = require('../../privileges'); +var favourites = require('../../favourites'); module.exports = function(SocketPosts) { + SocketPosts.loadPostTools = function(socket, data, callback) { + if (!socket.uid) { + return; + } + if (!data) { + return callback(new Error('[[error:invalid-data]]')) + } + + async.parallel({ + posts: function(next) { + posts.getPostFields(data.pid, ['deleted', 'reputation', 'uid'], next); + }, + isAdminOrMod: function(next) { + privileges.categories.isAdminOrMod(data.cid, socket.uid, next); + }, + favourited: function(next) { + favourites.getFavouritesByPostIDs([data.pid], socket.uid, next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + results.posts.tools = []; // TODO: add filter for this + results.posts.deleted = parseInt(results.posts.deleted, 10) === 1; + results.posts.favourited = results.favourited[0]; + results.posts.selfPost = socket.uid === parseInt(results.posts.uid, 10); + results.posts.display_moderator_tools = results.isAdminOrMod || results.posts.selfPost; + results.posts.display_move_tools = results.isAdminOrMod; + callback(null, results); + }); + }; + SocketPosts.delete = function(socket, data, callback) { doPostAction('delete', 'event:post_deleted', socket, data, callback); }; diff --git a/src/socket.io/topics/tools.js b/src/socket.io/topics/tools.js index 19a1c393f1..38a80c356c 100644 --- a/src/socket.io/topics/tools.js +++ b/src/socket.io/topics/tools.js @@ -3,10 +3,39 @@ var async = require('async'); var topics = require('../../topics'); var events = require('../../events'); +var privileges = require('../../privileges'); var socketHelpers = require('../helpers'); module.exports = function(SocketTopics) { + SocketTopics.loadTopicTools = function(socket, data, callback) { + if (!socket.uid) { + return; + } + if (!data) { + return callback(new Error('[[error:invalid-data]]')) + } + + async.parallel({ + topic: function(next) { + topics.getTopicFields(data.tid, ['deleted', 'locked', 'pinned'], next); + }, + privileges: function(next) { + privileges.topics.get(data.tid, socket.uid, next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + + results.topic.deleted = parseInt(results.topic.deleted, 10) === 1; + results.topic.locked = parseInt(results.topic.locked, 10) === 1; + results.topic.pinned = parseInt(results.topic.pinned, 10) === 1; + results.topic.privileges = results.privileges; + + callback(null, results.topic); + }); + }; SocketTopics.delete = function(socket, data, callback) { SocketTopics.doTopicAction('delete', 'event:topic_deleted', socket, data, callback); diff --git a/src/user/notifications.js b/src/user/notifications.js index 7cc309d1a8..477a9cf53f 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -130,9 +130,9 @@ var async = require('async'), notification.path = pidToPaths[notification.pid] || notification.path || ''; if (notification.nid.startsWith('chat')) { - notification.path = nconf.get('relative_path') + '/chats/' + notification.user.userslug; + notification.path = '/chats/' + notification.user.userslug; } else if (notification.nid.startsWith('follow')) { - notification.path = nconf.get('relative_path') + '/user/' + notification.user.userslug; + notification.path = '/user/' + notification.user.userslug; } notification.datetimeISO = utils.toISOString(notification.datetime); @@ -176,7 +176,7 @@ var async = require('async'), var postIndex = utils.isNumber(results.indices[index]) ? parseInt(results.indices[index], 10) + 1 : null; if (slug && postIndex) { - pidToPaths[pid] = nconf.get('relative_path') + '/topic/' + slug + '/' + postIndex; + pidToPaths[pid] = '/topic/' + slug + '/' + postIndex; } }); diff --git a/src/views/admin/manage/category.tpl b/src/views/admin/manage/category.tpl index b68e7892ac..4d421757fe 100644 --- a/src/views/admin/manage/category.tpl +++ b/src/views/admin/manage/category.tpl @@ -94,7 +94,7 @@ - + diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 2b5ac35f2b..6557f5f6a3 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -31,7 +31,7 @@
No flagged posts! - +
diff --git a/src/views/admin/manage/group.tpl b/src/views/admin/manage/group.tpl index 99acd57b13..078da81b3e 100644 --- a/src/views/admin/manage/group.tpl +++ b/src/views/admin/manage/group.tpl @@ -31,7 +31,7 @@