mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +01:00 
			
		
		
		
	closes #2134
This commit is contained in:
		| @@ -59,6 +59,7 @@ | |||||||
| 	"thread_tools.move_all": "Move All", | 	"thread_tools.move_all": "Move All", | ||||||
| 	"thread_tools.fork": "Fork Topic", | 	"thread_tools.fork": "Fork Topic", | ||||||
| 	"thread_tools.delete": "Delete Topic", | 	"thread_tools.delete": "Delete Topic", | ||||||
|  | 	"thread_tools.delete-posts": "Delete Posts", | ||||||
| 	"thread_tools.delete_confirm": "Are you sure you want to delete this topic?", | 	"thread_tools.delete_confirm": "Are you sure you want to delete this topic?", | ||||||
| 	"thread_tools.restore": "Restore Topic", | 	"thread_tools.restore": "Restore Topic", | ||||||
| 	"thread_tools.restore_confirm": "Are you sure you want to restore this topic?", | 	"thread_tools.restore_confirm": "Are you sure you want to restore this topic?", | ||||||
| @@ -90,6 +91,7 @@ | |||||||
| 	"fork_topic_instruction": "Click the posts you want to fork", | 	"fork_topic_instruction": "Click the posts you want to fork", | ||||||
| 	"fork_no_pids": "No posts selected!", | 	"fork_no_pids": "No posts selected!", | ||||||
| 	"fork_success": "Successfully forked topic! Click here to go to the forked topic.", | 	"fork_success": "Successfully forked topic! Click here to go to the forked topic.", | ||||||
|  | 	"delete_posts_instruction": "Click the posts you want to delete/purge", | ||||||
|  |  | ||||||
| 	"composer.title_placeholder": "Enter your topic title here...", | 	"composer.title_placeholder": "Enter your topic title here...", | ||||||
| 	"composer.handle_placeholder": "Name", | 	"composer.handle_placeholder": "Name", | ||||||
|   | |||||||
							
								
								
									
										105
									
								
								public/src/client/topic/delete-posts.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								public/src/client/topic/delete-posts.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | /* globals define, app, ajaxify, socket, templates, translator */ | ||||||
|  |  | ||||||
|  | define('forum/topic/delete-posts', ['components', 'postSelect'], function(components, postSelect) { | ||||||
|  |  | ||||||
|  | 	var DeletePosts = {}, | ||||||
|  | 		modal, | ||||||
|  | 		deleteBtn, | ||||||
|  | 		purgeBtn; | ||||||
|  |  | ||||||
|  | 	DeletePosts.init = function() { | ||||||
|  | 		$('.topic').on('click', '[component="topic/delete/posts"]', onDeletePostsClicked); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	function onDeletePostsClicked() { | ||||||
|  | 		parseModal(function(html) { | ||||||
|  | 			modal = $(html); | ||||||
|  |  | ||||||
|  | 			modal.on('hidden.bs.modal', function() { | ||||||
|  | 				modal.remove(); | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			deleteBtn = modal.find('#delete_posts_confirm'); | ||||||
|  | 			purgeBtn = modal.find('#purge_posts_confirm'); | ||||||
|  |  | ||||||
|  | 			showModal(); | ||||||
|  |  | ||||||
|  | 			modal.find('.close,#delete_posts_cancel').on('click', closeModal); | ||||||
|  |  | ||||||
|  | 			postSelect.init(function() { | ||||||
|  | 				checkButtonEnable(); | ||||||
|  | 				showPostsSelected(); | ||||||
|  | 			}); | ||||||
|  | 			showPostsSelected(); | ||||||
|  |  | ||||||
|  | 			deleteBtn.on('click', function() { | ||||||
|  | 				deletePosts(deleteBtn, 'posts.deletePosts'); | ||||||
|  | 			}); | ||||||
|  | 			purgeBtn.on('click', function() { | ||||||
|  | 				deletePosts(purgeBtn, 'posts.purgePosts'); | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function parseModal(callback) { | ||||||
|  | 		templates.parse('partials/delete_posts_modal', {}, function(html) { | ||||||
|  | 			translator.translate(html, callback); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function showModal() { | ||||||
|  | 		modal.modal({backdrop: false, show: true}) | ||||||
|  | 			.css('position', 'fixed') | ||||||
|  | 			.css('left', Math.max(0, (($(window).width() - modal.outerWidth()) / 2) + $(window).scrollLeft()) + 'px') | ||||||
|  | 			.css('top', '0px') | ||||||
|  | 			.css('z-index', '2000'); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function deletePosts(btn, command) { | ||||||
|  | 		btn.attr('disabled', true); | ||||||
|  | 		socket.emit(command, { | ||||||
|  | 			tid: ajaxify.data.tid, | ||||||
|  | 			pids: postSelect.pids | ||||||
|  | 		}, function(err) { | ||||||
|  | 			btn.removeAttr('disabled'); | ||||||
|  | 			if (err) { | ||||||
|  | 				return app.alertError(err.message); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			closeModal(); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function showPostsSelected() { | ||||||
|  | 		if (postSelect.pids.length) { | ||||||
|  | 			modal.find('#pids').text(postSelect.pids.join(', ')); | ||||||
|  | 		} else { | ||||||
|  | 			modal.find('#pids').translateHtml('[[topic:fork_no_pids]]'); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function checkButtonEnable() { | ||||||
|  | 		if (postSelect.pids.length) { | ||||||
|  | 			deleteBtn.removeAttr('disabled'); | ||||||
|  | 			purgeBtn.removeAttr('disabled'); | ||||||
|  | 		} else { | ||||||
|  | 			deleteBtn.attr('disabled', true); | ||||||
|  | 			purgeBtn.attr('disabled', true); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function closeModal() { | ||||||
|  | 		postSelect.pids.forEach(function(pid) { | ||||||
|  | 			components.get('post', 'pid', pid).css('opacity', 1); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		modal.modal('hide'); | ||||||
|  |  | ||||||
|  | 		components.get('topic').off('click', '[data-pid]'); | ||||||
|  | 		postSelect.enableClicksOnPosts(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return DeletePosts; | ||||||
|  | }); | ||||||
| @@ -2,29 +2,16 @@ | |||||||
|  |  | ||||||
| /* globals define, app, ajaxify, socket, templates, translator */ | /* globals define, app, ajaxify, socket, templates, translator */ | ||||||
|  |  | ||||||
| define('forum/topic/fork', ['components'], function(components) { | define('forum/topic/fork', ['components', 'postSelect'], function(components, postSelect) { | ||||||
|  |  | ||||||
| 	var Fork = {}, | 	var Fork = {}, | ||||||
| 		forkModal, | 		forkModal, | ||||||
| 		forkCommit, | 		forkCommit; | ||||||
| 		pids = []; |  | ||||||
|  |  | ||||||
| 	Fork.init = function() { | 	Fork.init = function() { | ||||||
| 		$('.topic').on('click', '[component="topic/fork"]', onForkThreadClicked); | 		$('.topic').on('click', '[component="topic/fork"]', onForkThreadClicked); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	function disableClicks() { |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	function disableClicksOnPosts() { |  | ||||||
| 		components.get('post').on('click', 'button,a', disableClicks); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	function enableClicksOnPosts() { |  | ||||||
| 		components.get('post').off('click', 'button,a', disableClicks); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	function onForkThreadClicked() { | 	function onForkThreadClicked() { | ||||||
| 		parseModal(function(html) { | 		parseModal(function(html) { | ||||||
| 			forkModal = $(html); | 			forkModal = $(html); | ||||||
| @@ -34,21 +21,19 @@ define('forum/topic/fork', ['components'], function(components) { | |||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
| 			forkCommit = forkModal.find('#fork_thread_commit'); | 			forkCommit = forkModal.find('#fork_thread_commit'); | ||||||
| 			pids.length = 0; |  | ||||||
|  |  | ||||||
| 			showForkModal(); | 			showForkModal(); | ||||||
| 			showNoPostsSelected(); |  | ||||||
|  |  | ||||||
| 			forkModal.find('.close,#fork_thread_cancel').on('click', closeForkModal); | 			forkModal.find('.close,#fork_thread_cancel').on('click', closeForkModal); | ||||||
| 			forkModal.find('#fork-title').on('change', checkForkButtonEnable); | 			forkModal.find('#fork-title').on('change', checkForkButtonEnable); | ||||||
| 			components.get('topic').on('click', '[data-pid]', function() { |  | ||||||
| 				togglePostSelection($(this)); |  | ||||||
| 			}); |  | ||||||
|  |  | ||||||
| 			disableClicksOnPosts(); | 			postSelect.init(function() { | ||||||
|  | 				checkForkButtonEnable(); | ||||||
|  | 				showPostsSelected(); | ||||||
|  | 			}); | ||||||
|  | 			showPostsSelected(); | ||||||
|  |  | ||||||
| 			forkCommit.on('click', createTopicFromPosts); | 			forkCommit.on('click', createTopicFromPosts); | ||||||
|  |  | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -70,7 +55,7 @@ define('forum/topic/fork', ['components'], function(components) { | |||||||
| 		forkCommit.attr('disabled', true); | 		forkCommit.attr('disabled', true); | ||||||
| 		socket.emit('topics.createTopicFromPosts', { | 		socket.emit('topics.createTopicFromPosts', { | ||||||
| 			title: forkModal.find('#fork-title').val(), | 			title: forkModal.find('#fork-title').val(), | ||||||
| 			pids: pids | 			pids: postSelect.pids | ||||||
| 		}, function(err, newTopic) { | 		}, function(err, newTopic) { | ||||||
| 			function fadeOutAndRemove(pid) { | 			function fadeOutAndRemove(pid) { | ||||||
| 				components.get('post', 'pid', pid).fadeOut(500, function() { | 				components.get('post', 'pid', pid).fadeOut(500, function() { | ||||||
| @@ -92,46 +77,24 @@ define('forum/topic/fork', ['components'], function(components) { | |||||||
| 				} | 				} | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
| 			for(var i=0; i<pids.length; ++i) { | 			postSelect.pids.forEach(function(pid) { | ||||||
| 				fadeOutAndRemove(pids[i]); | 				fadeOutAndRemove(pid); | ||||||
| 			} | 			}); | ||||||
|  |  | ||||||
| 			closeForkModal(); | 			closeForkModal(); | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function togglePostSelection(post) { | 	function showPostsSelected() { | ||||||
| 		var newPid = post.attr('data-pid'); | 		if (postSelect.pids.length) { | ||||||
|  | 			forkModal.find('#fork-pids').text(postSelect.pids.join(', ')); | ||||||
| 		if (parseInt(post.attr('data-index'), 10) === 0) { | 		} else { | ||||||
| 			return; | 			forkModal.find('#fork-pids').translateHtml('[[topic:fork_no_pids]]'); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (newPid) { |  | ||||||
| 			var index = pids.indexOf(newPid); |  | ||||||
| 			if(index === -1) { |  | ||||||
| 				pids.push(newPid); |  | ||||||
| 				post.css('opacity', '0.5'); |  | ||||||
| 			} else { |  | ||||||
| 				pids.splice(index, 1); |  | ||||||
| 				post.css('opacity', '1.0'); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (pids.length) { |  | ||||||
| 				pids.sort(function(a,b) { return a - b; }); |  | ||||||
| 				forkModal.find('#fork-pids').text(pids.join(', ')); |  | ||||||
| 			} else { |  | ||||||
| 				showNoPostsSelected(); |  | ||||||
| 			} |  | ||||||
| 			checkForkButtonEnable(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	function showNoPostsSelected() { |  | ||||||
| 		forkModal.find('#fork-pids').translateHtml('[[topic:fork_no_pids]]'); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function checkForkButtonEnable() { | 	function checkForkButtonEnable() { | ||||||
| 		if (forkModal.find('#fork-title').length && pids.length) { | 		if (forkModal.find('#fork-title').length && postSelect.pids.length) { | ||||||
| 			forkCommit.removeAttr('disabled'); | 			forkCommit.removeAttr('disabled'); | ||||||
| 		} else { | 		} else { | ||||||
| 			forkCommit.attr('disabled', true); | 			forkCommit.attr('disabled', true); | ||||||
| @@ -139,14 +102,14 @@ define('forum/topic/fork', ['components'], function(components) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function closeForkModal() { | 	function closeForkModal() { | ||||||
| 		for (var i=0; i<pids.length; ++i) { | 		postSelect.pids.forEach(function(pid) { | ||||||
| 			components.get('post', 'pid', pids[i]).css('opacity', 1); | 			components.get('post', 'pid', pid).css('opacity', 1); | ||||||
| 		} | 		}); | ||||||
|  |  | ||||||
| 		forkModal.modal('hide'); | 		forkModal.modal('hide'); | ||||||
|  |  | ||||||
| 		components.get('topic').off('click', '[data-pid]'); | 		components.get('topic').off('click', '[data-pid]'); | ||||||
| 		enableClicksOnPosts(); | 		postSelect.enableClicksOnPosts(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return Fork; | 	return Fork; | ||||||
|   | |||||||
| @@ -2,7 +2,13 @@ | |||||||
|  |  | ||||||
| /* globals define, app, ajaxify, socket, bootbox, templates */ | /* globals define, app, ajaxify, socket, bootbox, templates */ | ||||||
|  |  | ||||||
| define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move', 'components', 'translator'], function(fork, move, components, translator) { | define('forum/topic/threadTools', [ | ||||||
|  | 	'forum/topic/fork', | ||||||
|  | 	'forum/topic/move', | ||||||
|  | 	'forum/topic/delete-posts', | ||||||
|  | 	'components', | ||||||
|  | 	'translator' | ||||||
|  | ], function(fork, move, deletePosts, components, translator) { | ||||||
|  |  | ||||||
| 	var ThreadTools = {}; | 	var ThreadTools = {}; | ||||||
|  |  | ||||||
| @@ -64,6 +70,7 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move', 'comp | |||||||
| 			return false; | 			return false; | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
|  | 		deletePosts.init(); | ||||||
| 		fork.init(); | 		fork.init(); | ||||||
|  |  | ||||||
| 		components.get('topic').on('click', '[component="topic/follow"], [component="topic/unfollow"]', follow); | 		components.get('topic').on('click', '[component="topic/follow"], [component="topic/unfollow"]', follow); | ||||||
|   | |||||||
							
								
								
									
										59
									
								
								public/src/modules/postSelect.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								public/src/modules/postSelect.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | /* globals define*/ | ||||||
|  |  | ||||||
|  | define('postSelect', ['components'], function(components) { | ||||||
|  | 	var PostSelect = {}; | ||||||
|  |  | ||||||
|  | 	PostSelect.pids = []; | ||||||
|  |  | ||||||
|  | 	PostSelect.init = function(onSelect) { | ||||||
|  | 		PostSelect.pids.length = 0; | ||||||
|  | 		components.get('topic').on('click', '[data-pid]', function() { | ||||||
|  | 			togglePostSelection($(this), onSelect); | ||||||
|  | 		}); | ||||||
|  | 		disableClicksOnPosts(); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	function togglePostSelection(post, callback) { | ||||||
|  | 		var newPid = post.attr('data-pid'); | ||||||
|  |  | ||||||
|  | 		if (parseInt(post.attr('data-index'), 10) === 0) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (newPid) { | ||||||
|  | 			var index = PostSelect.pids.indexOf(newPid); | ||||||
|  | 			if(index === -1) { | ||||||
|  | 				PostSelect.pids.push(newPid); | ||||||
|  | 				post.css('opacity', '0.5'); | ||||||
|  | 			} else { | ||||||
|  | 				PostSelect.pids.splice(index, 1); | ||||||
|  | 				post.css('opacity', '1.0'); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (PostSelect.pids.length) { | ||||||
|  | 				PostSelect.pids.sort(function(a,b) { return a - b; }); | ||||||
|  | 			} | ||||||
|  | 			callback(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	function disableClicks() { | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function disableClicksOnPosts() { | ||||||
|  | 		components.get('post').on('click', 'button,a', disableClicks); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	PostSelect.enableClicksOnPosts = function() { | ||||||
|  | 		components.get('post').off('click', 'button,a', disableClicks); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	return PostSelect; | ||||||
|  | }); | ||||||
| @@ -52,6 +52,24 @@ module.exports = function(SocketPosts) { | |||||||
| 		doPostAction('restore', 'event:post_restored', socket, data, callback); | 		doPostAction('restore', 'event:post_restored', socket, data, callback); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	SocketPosts.deletePosts = function(socket, data, callback) { | ||||||
|  | 		if (!data || !Array.isArray(data.pids)) { | ||||||
|  | 			return callback(new Error('[[error:invalid-data]]')); | ||||||
|  | 		} | ||||||
|  | 		async.each(data.pids, function(pid, next) { | ||||||
|  | 			SocketPosts.delete(socket, {pid: pid, tid: data.tid}, next); | ||||||
|  | 		}, callback); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	SocketPosts.purgePosts = function(socket, data, callback) { | ||||||
|  | 		if (!data || !Array.isArray(data.pids)) { | ||||||
|  | 			return callback(new Error('[[error:invalid-data]]')); | ||||||
|  | 		} | ||||||
|  | 		async.each(data.pids, function(pid, next) { | ||||||
|  | 			SocketPosts.purge(socket, {pid: pid, tid: data.tid}, next); | ||||||
|  | 		}, callback); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	function doPostAction(command, eventName, socket, data, callback) { | 	function doPostAction(command, eventName, socket, data, callback) { | ||||||
| 		if (!data) { | 		if (!data) { | ||||||
| 			return callback(new Error('[[error:invalid-data]]')); | 			return callback(new Error('[[error:invalid-data]]')); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user