diff --git a/public/language/en-GB/topic.json b/public/language/en-GB/topic.json index 4b30d84356..6e5fec66c6 100644 --- a/public/language/en-GB/topic.json +++ b/public/language/en-GB/topic.json @@ -73,6 +73,7 @@ "thread_tools.lock": "Lock Topic", "thread_tools.unlock": "Unlock Topic", "thread_tools.move": "Move Topic", + "thread_tools.move-posts": "Move Posts", "thread_tools.move_all": "Move All", "thread_tools.select_category": "Select Category", "thread_tools.fork": "Fork Topic", @@ -112,6 +113,7 @@ "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", + "move_posts_instruction": "Click the posts you want to move", "composer.title_placeholder": "Enter your topic title here...", "composer.handle_placeholder": "Name", diff --git a/public/src/client/topic/delete-posts.js b/public/src/client/topic/delete-posts.js index c2fde4ec25..fb2c9f7f43 100644 --- a/public/src/client/topic/delete-posts.js +++ b/public/src/client/topic/delete-posts.js @@ -77,17 +77,11 @@ define('forum/topic/delete-posts', ['components', 'postSelect'], function (compo } function closeModal() { - postSelect.pids.forEach(function (pid) { - components.get('post', 'pid', pid).toggleClass('bg-success', false); - }); - if (modal) { modal.remove(); modal = null; } - - components.get('topic').off('click', '[data-pid]'); - postSelect.enableClicksOnPosts(); + postSelect.disable(); } return DeletePosts; diff --git a/public/src/client/topic/fork.js b/public/src/client/topic/fork.js index b34d50d55f..f4190b61ac 100644 --- a/public/src/client/topic/fork.js +++ b/public/src/client/topic/fork.js @@ -89,17 +89,12 @@ define('forum/topic/fork', ['components', 'postSelect'], function (components, p } function closeForkModal() { - postSelect.pids.forEach(function (pid) { - components.get('post', 'pid', pid).toggleClass('bg-success', false); - }); - if (forkModal) { forkModal.remove(); forkModal = null; } - components.get('topic').off('click', '[data-pid]'); - postSelect.enableClicksOnPosts(); + postSelect.disable(); } return Fork; diff --git a/public/src/client/topic/move-post.js b/public/src/client/topic/move-post.js index 0c08e030da..c14361aa67 100644 --- a/public/src/client/topic/move-post.js +++ b/public/src/client/topic/move-post.js @@ -1,56 +1,95 @@ 'use strict'; -define('forum/topic/move-post', [], function () { +define('forum/topic/move-post', ['components', 'postSelect'], function (components, postSelect) { var MovePost = {}; - MovePost.openMovePostModal = function (button) { + var moveModal; + var moveCommit; + + MovePost.init = function () { + $('.topic').on('click', '[component="topic/move-posts"]', onMovePostsClicked); + $(window).on('action:ajaxify.start', onAjaxifyStart); + }; + + function onAjaxifyStart() { + closeMoveModal(); + $(window).off('action:ajaxify.start', onAjaxifyStart); + } + + function onMovePostsClicked() { + MovePost.openMovePostModal(); + } + + function showPostsSelected() { + if (postSelect.pids.length) { + moveModal.find('#pids').translateHtml('[[topic:fork_pid_count, ' + postSelect.pids.length + ']]'); + } else { + moveModal.find('#pids').translateHtml('[[topic:fork_no_pids]]'); + } + } + + function checkMoveButtonEnable() { + if (moveModal.find('#topicId').val().length && postSelect.pids.length) { + moveCommit.removeAttr('disabled'); + } else { + moveCommit.attr('disabled', true); + } + } + + MovePost.openMovePostModal = function (postEl) { app.parseAndTranslate('partials/move_post_modal', {}, function (html) { - var dialog = bootbox.dialog({ - title: '[[topic:move_post]]', - message: html, - show: true, - buttons: { - submit: { - label: '[[topic:confirm_move]]', - className: 'btn-primary submit-btn', - callback: function () { - var topicIdEl = dialog.find('#topicId'); - if (!topicIdEl.val()) { - return; - } - - movePost(button.parents('[data-pid]'), button.parents('[data-pid]').attr('data-pid'), topicIdEl.val(), function () { - topicIdEl.val(''); - }); - }, - }, - }, - }); - dialog.find('.submit-btn').attr('disabled', true); + moveModal = html; - dialog.find('#topicId').on('keyup change', function () { - dialog.find('.submit-btn').attr('disabled', !dialog.find('#topicId').val()); + moveCommit = moveModal.find('#move_posts_confirm'); + + $(document.body).append(moveModal); + + moveModal.find('.close,#move_posts_cancel').on('click', closeMoveModal); + moveModal.find('#topicId').on('keyup', checkMoveButtonEnable); + postSelect.init(onPostToggled); + showPostsSelected(); + + if (postEl) { + postSelect.togglePostSelection(postEl, onPostToggled); + } + + moveCommit.on('click', function () { + movePosts(); }); }); }; - function movePost(post, pid, tid, callback) { - socket.emit('posts.movePost', { pid: pid, tid: tid }, function (err) { + function onPostToggled() { + checkMoveButtonEnable(); + showPostsSelected(); + } + + function movePosts() { + var tid = moveModal.find('#topicId').val(); + socket.emit('posts.movePosts', { pids: postSelect.pids, tid: tid }, function (err) { if (err) { - app.alertError(err.message); - return callback(); + return app.alertError(err.message); } - - post.fadeOut(500, function () { - post.remove(); + postSelect.pids.forEach(function (pid) { + components.get('post', 'pid', pid).fadeOut(500, function () { + $(this).remove(); + }); }); - app.alertSuccess('[[topic:post_moved]]'); - callback(); + closeMoveModal(); }); } + function closeMoveModal() { + if (moveModal) { + moveModal.remove(); + moveModal = null; + } + + postSelect.disable(); + } + return MovePost; }); diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index a164f97ee2..5798386951 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -195,7 +195,7 @@ define('forum/topic/postTools', [ }); postContainer.on('click', '[component="post/move"]', function () { - movePost.openMovePostModal($(this)); + movePost.openMovePostModal($(this).parents('[data-pid]')); }); postContainer.on('click', '[component="post/ban-ip"]', function () { diff --git a/public/src/client/topic/threadTools.js b/public/src/client/topic/threadTools.js index e220e6305d..e8b6839d82 100644 --- a/public/src/client/topic/threadTools.js +++ b/public/src/client/topic/threadTools.js @@ -5,10 +5,11 @@ define('forum/topic/threadTools', [ 'forum/topic/fork', 'forum/topic/move', 'forum/topic/delete-posts', + 'forum/topic/move-post', 'components', 'translator', 'benchpress', -], function (fork, move, deletePosts, components, translator, Benchpress) { +], function (fork, move, deletePosts, movePosts, components, translator, Benchpress) { var ThreadTools = {}; ThreadTools.init = function (tid) { @@ -80,6 +81,7 @@ define('forum/topic/threadTools', [ deletePosts.init(); fork.init(); + movePosts.init(); $('.topic').on('click', '[component="topic/following"]', function () { changeWatching('follow'); diff --git a/public/src/modules/postSelect.js b/public/src/modules/postSelect.js index 5dae2995ea..a190e6fe50 100644 --- a/public/src/modules/postSelect.js +++ b/public/src/modules/postSelect.js @@ -9,13 +9,20 @@ define('postSelect', ['components'], function (components) { PostSelect.init = function (onSelect) { PostSelect.pids.length = 0; components.get('topic').on('click', '[data-pid]', function () { - togglePostSelection($(this), onSelect); + PostSelect.togglePostSelection($(this), onSelect); }); disableClicksOnPosts(); }; + PostSelect.disable = function () { + PostSelect.pids.forEach(function (pid) { + components.get('post', 'pid', pid).toggleClass('bg-success', false); + }); + components.get('topic').off('click', '[data-pid]'); + enableClicksOnPosts(); + }; - function togglePostSelection(post, callback) { + PostSelect.togglePostSelection = function (post, callback) { var newPid = post.attr('data-pid'); if (parseInt(post.attr('data-index'), 10) === 0) { @@ -37,7 +44,7 @@ define('postSelect', ['components'], function (components) { } callback(); } - } + }; function disableClicks() { @@ -48,7 +55,7 @@ define('postSelect', ['components'], function (components) { components.get('post').on('click', 'button,a', disableClicks); } - PostSelect.enableClicksOnPosts = function () { + function enableClicksOnPosts() { components.get('post').off('click', 'button,a', disableClicks); }; diff --git a/src/socket.io/posts/move.js b/src/socket.io/posts/move.js index 6ef596c1c2..fb1cc20756 100644 --- a/src/socket.io/posts/move.js +++ b/src/socket.io/posts/move.js @@ -7,29 +7,34 @@ var socketHelpers = require('../helpers'); module.exports = function (SocketPosts) { SocketPosts.movePost = function (socket, data, callback) { + SocketPosts.movePosts(socket, { pids: [data.pid], tid: data.tid }, callback); + }; + + SocketPosts.movePosts = function (socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:not-logged-in]]')); } - if (!data || !data.pid || !data.tid) { + if (!data || !Array.isArray(data.pids) || !data.tid) { return callback(new Error('[[error:invalid-data]]')); } + async.eachSeries(data.pids, function (pid, next) { + async.waterfall([ + function (next) { + privileges.posts.canMove(pid, socket.uid, next); + }, + function (canMove, next) { + if (!canMove) { + return next(new Error('[[error:no-privileges]]')); + } - async.waterfall([ - function (next) { - privileges.posts.canMove(data.pid, socket.uid, next); - }, - function (canMove, next) { - if (!canMove) { - return next(new Error('[[error:no-privileges]]')); - } - - topics.movePostToTopic(data.pid, data.tid, next); - }, - function (next) { - socketHelpers.sendNotificationToPostOwner(data.pid, socket.uid, 'move', 'notifications:moved_your_post'); - next(); - }, - ], callback); + topics.movePostToTopic(pid, data.tid, next); + }, + function (next) { + socketHelpers.sendNotificationToPostOwner(pid, socket.uid, 'move', 'notifications:moved_your_post'); + next(); + }, + ], next); + }, callback); }; };