diff --git a/install/package.json b/install/package.json index ecb828a3eb..a5647b82f3 100644 --- a/install/package.json +++ b/install/package.json @@ -69,9 +69,9 @@ "nodebb-plugin-spam-be-gone": "0.5.1", "nodebb-rewards-essentials": "0.0.9", "nodebb-theme-lavender": "5.0.0", - "nodebb-theme-persona": "7.2.2", + "nodebb-theme-persona": "7.2.3", "nodebb-theme-slick": "1.1.2", - "nodebb-theme-vanilla": "8.1.1", + "nodebb-theme-vanilla": "8.1.2", "nodebb-widget-essentials": "4.0.1", "nodemailer": "4.4.0", "passport": "^0.4.0", diff --git a/public/language/en-GB/topic.json b/public/language/en-GB/topic.json index d206960156..40b9b84d09 100644 --- a/public/language/en-GB/topic.json +++ b/public/language/en-GB/topic.json @@ -6,6 +6,8 @@ "no_topics_found": "No topics found!", "no_posts_found": "No posts found!", + "no_topics_selected": "No topics selected!", + "post_is_deleted": "This post is deleted!", "topic_is_deleted": "This topic is deleted!", @@ -79,6 +81,8 @@ "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", "thread_tools.purge": "Purge Topic", "thread_tools.purge_confirm" : "Are you sure you want to purge this topic?", + "thread_tools.merge_topics": "Merge Topics", + "thread_tools.merge": "Merge", "topic_move_success": "This topic has been successfully moved to %1", @@ -105,6 +109,7 @@ "fork_pid_count": "%1 post(s) selected", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "delete_posts_instruction": "Click the posts you want to delete/purge", + "merge_topics_instruction": "Click the topics you want to merge", "composer.title_placeholder": "Enter your topic title here...", "composer.handle_placeholder": "Name", diff --git a/public/src/client/category/tools.js b/public/src/client/category/tools.js index 3f211400c4..c245dadc44 100644 --- a/public/src/client/category/tools.js +++ b/public/src/client/category/tools.js @@ -4,10 +4,11 @@ define('forum/category/tools', [ 'forum/topic/move', + 'forum/topic/merge', 'topicSelect', 'components', 'translator', -], function (move, topicSelect, components, translator) { +], function (move, merge, topicSelect, components, translator) { var CategoryTools = {}; CategoryTools.init = function (cid) { @@ -101,6 +102,8 @@ define('forum/category/tools', [ }); }); + merge.init(); + CategoryTools.removeListeners(); socket.on('event:topic_deleted', setDeleteState); socket.on('event:topic_restored', setDeleteState); diff --git a/public/src/client/topic/merge.js b/public/src/client/topic/merge.js new file mode 100644 index 0000000000..caaa01c3ed --- /dev/null +++ b/public/src/client/topic/merge.js @@ -0,0 +1,107 @@ +'use strict'; + + +define('forum/topic/merge', function () { + var Merge = {}; + var modal; + var mergeBtn; + + var selectedTids = {}; + + Merge.init = function () { + $('.category').on('click', '[component="topic/merge"]', onMergeTopicsClicked); + if (modal) { + $('[component="category/topic"]').on('click', 'a', onTopicClicked); + } + }; + + function onMergeTopicsClicked() { + if (modal) { + return; + } + app.parseAndTranslate('partials/merge_topics_modal', {}, function (html) { + modal = html; + + $('body').append(modal); + + mergeBtn = modal.find('#merge_topics_confirm'); + + modal.find('.close,#merge_topics_cancel').on('click', closeModal); + + $('[component="category/topic"]').on('click', 'a', onTopicClicked); + + showTopicsSelected(); + + mergeBtn.on('click', function () { + mergeTopics(mergeBtn); + }); + }); + } + + function onTopicClicked(ev) { + var tid = $(this).parents('[component="category/topic"]').attr('data-tid'); + var index = $(this).parents('[component="category/topic"]').attr('data-index'); + var title = ajaxify.data.topics[index] ? ajaxify.data.topics[index].title : 'No title'; + if (selectedTids[tid]) { + delete selectedTids[tid]; + } else { + selectedTids[tid] = title; + } + checkButtonEnable(); + showTopicsSelected(); + ev.preventDefault(); + ev.stopPropagation(); + return false; + } + + function mergeTopics(btn) { + btn.attr('disabled', true); + var tids = Object.keys(selectedTids); + socket.emit('topics.merge', tids, function (err) { + btn.removeAttr('disabled'); + if (err) { + return app.alertError(err.message); + } + ajaxify.go('/topic/' + tids[0]); + closeModal(); + }); + } + + function showTopicsSelected() { + var tids = Object.keys(selectedTids); + tids.sort(function (a, b) { + return a - b; + }); + + var topics = tids.map(function (tid) { + return { tid: tid, title: selectedTids[tid] }; + }); + + if (tids.length) { + app.parseAndTranslate('partials/merge_topics_modal', 'topics', { topics: topics }, function (html) { + modal.find('.topics-section').html(html); + }); + } else { + modal.find('.topics-section').translateHtml('[[topic:no_topics_selected]]'); + } + } + + function checkButtonEnable() { + if (Object.keys(selectedTids).length) { + mergeBtn.removeAttr('disabled'); + } else { + mergeBtn.attr('disabled', true); + } + } + + function closeModal() { + if (modal) { + modal.remove(); + modal = null; + } + selectedTids = {}; + $('[component="category/topic"]').off('click', 'a', onTopicClicked); + } + + return Merge; +}); diff --git a/src/meta/js.js b/src/meta/js.js index e3c988736b..e8b71cf6a3 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -49,6 +49,7 @@ JS.scripts = { 'public/src/client/unread.js', 'public/src/client/topic.js', 'public/src/client/topic/events.js', + 'public/src/client/topic/merge.js', 'public/src/client/topic/fork.js', 'public/src/client/topic/move.js', 'public/src/client/topic/posts.js', diff --git a/src/socket.io/topics/merge.js b/src/socket.io/topics/merge.js index 54275606e6..8b475f2ede 100644 --- a/src/socket.io/topics/merge.js +++ b/src/socket.io/topics/merge.js @@ -20,7 +20,7 @@ module.exports = function (SocketTopics) { if (allowed.includes(false)) { return next(new Error('[[error:no-privileges]]')); } - topics.merge(tids, next); + topics.merge(tids, socket.uid, next); }, ], callback); }; diff --git a/src/topics/merge.js b/src/topics/merge.js index 2c1df0df61..9fd97f60eb 100644 --- a/src/topics/merge.js +++ b/src/topics/merge.js @@ -3,7 +3,7 @@ var async = require('async'); module.exports = function (Topics) { - Topics.merge = function (tids, callback) { + Topics.merge = function (tids, uid, callback) { var mergeIntoTid = findOldestTopic(tids); var otherTids = tids.filter(function (tid) { @@ -23,6 +23,9 @@ module.exports = function (Topics) { function (next) { Topics.setTopicField(tid, 'mainPid', 0, next); }, + function (next) { + Topics.delete(tid, uid, next); + }, ], next); }, callback); }; diff --git a/test/topics.js b/test/topics.js index 15b839f996..f4d91ad763 100644 --- a/test/topics.js +++ b/test/topics.js @@ -1700,7 +1700,7 @@ describe('Topic\'s', function () { }); }); - describe('topic merge', function (done) { + describe('topic merge', function () { var uid; var topic1Data; var topic2Data; @@ -1774,12 +1774,13 @@ describe('Topic\'s', function () { function (results, next) { assert.equal(results.topic1.posts.length, 4); assert.equal(results.topic2.posts.length, 0); + assert.equal(results.topic2.deleted, true); assert.equal(results.topic1.posts[0].content, 'topic 1 OP'); assert.equal(results.topic1.posts[1].content, 'topic 2 OP'); assert.equal(results.topic1.posts[2].content, 'topic 1 reply'); assert.equal(results.topic1.posts[3].content, 'topic 2 reply'); - done(); + next(); }, ], done); });