mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-30 02:25:55 +01:00 
			
		
		
		
	Merge branch 'code-quality' of https://github.com/miksago/NodeBB into miksago-code-quality
Conflicts: src/database.js
This commit is contained in:
		| @@ -13,11 +13,58 @@ var socket, | |||||||
|  |  | ||||||
| (function () { | (function () { | ||||||
| 	var showWelcomeMessage = false; | 	var showWelcomeMessage = false; | ||||||
|  | 	var reconnecting = false; | ||||||
|  |  | ||||||
| 	app.loadConfig = function() { | 	function onSocketConnect(data) { | ||||||
| 		$.ajax({ | 		if (reconnecting) { | ||||||
| 			url: RELATIVE_PATH + '/api/config', | 			var reconnectEl = $('#reconnect'); | ||||||
| 			success: function (data) { |  | ||||||
|  | 			reconnectEl.tooltip('destroy'); | ||||||
|  | 			reconnectEl.html('<i class="fa fa-check"></i>'); | ||||||
|  | 			reconnecting = false; | ||||||
|  |  | ||||||
|  | 			// Rejoin room that was left when we disconnected | ||||||
|  | 			var	url_parts = document.location.pathname.slice(RELATIVE_PATH.length).split('/').slice(1); | ||||||
|  | 			var room; | ||||||
|  |  | ||||||
|  | 			switch(url_parts[0]) { | ||||||
|  | 				case 'user': | ||||||
|  | 					room = 'user/' + ajaxify.variables.get('theirid'); | ||||||
|  | 				break; | ||||||
|  | 				case 'topic': | ||||||
|  | 					room = 'topic_' + url_parts[1]; | ||||||
|  | 				break; | ||||||
|  | 				case 'category': | ||||||
|  | 					room = 'category_' + url_parts[1]; | ||||||
|  | 				break; | ||||||
|  | 				case 'recent':	// intentional fall-through | ||||||
|  | 				case 'unread': | ||||||
|  | 					room = 'recent_posts'; | ||||||
|  | 				break; | ||||||
|  | 				case 'admin': | ||||||
|  | 					room = 'admin'; | ||||||
|  | 				break; | ||||||
|  | 				default: | ||||||
|  | 					room = 'global'; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			app.enterRoom(room, true); | ||||||
|  |  | ||||||
|  | 			socket.emit('meta.reconnected'); | ||||||
|  | 			$(window).trigger('action:reconnected'); | ||||||
|  |  | ||||||
|  | 			setTimeout(function() { | ||||||
|  | 				reconnectEl.removeClass('active').addClass("hide"); | ||||||
|  | 			}, 3000); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		socket.emit('meta.updateHeader', { | ||||||
|  | 			fields: ['username', 'picture', 'userslug'] | ||||||
|  | 		}, app.updateHeader); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function onConfigLoad(data) { | ||||||
| 		config = data; | 		config = data; | ||||||
|  |  | ||||||
| 		exposeConfigToTemplates(); | 		exposeConfigToTemplates(); | ||||||
| @@ -39,9 +86,7 @@ var socket, | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			socket = io.connect('', ioParams); | 			socket = io.connect('', ioParams); | ||||||
|  | 			reconnecting = false; | ||||||
| 					var reconnecting = false, |  | ||||||
| 						reconnectEl, reconnectTimer; |  | ||||||
|  |  | ||||||
| 			socket.on('event:connect', function (data) { | 			socket.on('event:connect', function (data) { | ||||||
| 				app.username = data.username; | 				app.username = data.username; | ||||||
| @@ -63,51 +108,7 @@ var socket, | |||||||
| 				app.alert(data); | 				app.alert(data); | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
| 					socket.on('connect', function (data) { | 			socket.on('connect', onSocketConnect); | ||||||
| 						if (reconnecting) { |  | ||||||
| 							reconnectEl.tooltip('destroy'); |  | ||||||
| 							reconnectEl.html('<i class="fa fa-check"></i>'); |  | ||||||
| 							reconnecting = false; |  | ||||||
|  |  | ||||||
| 							// Rejoin room that was left when we disconnected |  | ||||||
| 							var	url_parts = document.location.pathname.slice(RELATIVE_PATH.length).split('/').slice(1), |  | ||||||
| 								room; |  | ||||||
| 							switch(url_parts[0]) { |  | ||||||
| 								case 'user': |  | ||||||
| 									room = 'user/' + ajaxify.variables.get('theirid'); |  | ||||||
| 									break; |  | ||||||
| 								case 'topic': |  | ||||||
| 									room = 'topic_' + url_parts[1]; |  | ||||||
| 									break; |  | ||||||
| 								case 'category': |  | ||||||
| 									room = 'category_' + url_parts[1]; |  | ||||||
| 									break; |  | ||||||
| 								case 'recent':	// intentional fall-through |  | ||||||
| 								case 'unread': |  | ||||||
| 									room = 'recent_posts'; |  | ||||||
| 									break; |  | ||||||
| 								case 'admin': |  | ||||||
| 									room = 'admin'; |  | ||||||
| 									break; |  | ||||||
|  |  | ||||||
| 								default: |  | ||||||
| 									room = 'global'; |  | ||||||
| 									break; |  | ||||||
| 							} |  | ||||||
| 							app.enterRoom(room, true); |  | ||||||
|  |  | ||||||
| 							socket.emit('meta.reconnected'); |  | ||||||
| 							$(window).trigger('action:reconnected'); |  | ||||||
|  |  | ||||||
| 							setTimeout(function() { |  | ||||||
| 								reconnectEl.removeClass('active').addClass("hide"); |  | ||||||
| 							}, 3000); |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 						socket.emit('meta.updateHeader', { |  | ||||||
| 							fields: ['username', 'picture', 'userslug'] |  | ||||||
| 						}, app.updateHeader); |  | ||||||
| 					}); |  | ||||||
|  |  | ||||||
| 			socket.on('event:disconnect', function() { | 			socket.on('event:disconnect', function() { | ||||||
| 				$(window).trigger('action:disconnected'); | 				$(window).trigger('action:disconnected'); | ||||||
| @@ -121,8 +122,8 @@ var socket, | |||||||
| 					return; | 					return; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 						reconnectEl = reconnectEl || $('#reconnect'); |  | ||||||
| 				reconnecting = true; | 				reconnecting = true; | ||||||
|  | 				var reconnectEl = $('#reconnect'); | ||||||
|  |  | ||||||
| 				if (!reconnectEl.hasClass('active')) { | 				if (!reconnectEl.hasClass('active')) { | ||||||
| 					reconnectEl.html('<i class="fa fa-spinner fa-spin"></i>'); | 					reconnectEl.html('<i class="fa fa-spinner fa-spin"></i>'); | ||||||
| @@ -156,7 +157,12 @@ var socket, | |||||||
| 				}; | 				}; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 			}, | 	} | ||||||
|  |  | ||||||
|  | 	app.loadConfig = function() { | ||||||
|  | 		$.ajax({ | ||||||
|  | 			url: RELATIVE_PATH + '/api/config', | ||||||
|  | 			success: onConfigLoad, | ||||||
| 			async: false | 			async: false | ||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
| @@ -413,21 +419,25 @@ var socket, | |||||||
|  |  | ||||||
|  |  | ||||||
| 	app.updateHeader = function(err, data) { | 	app.updateHeader = function(err, data) { | ||||||
| 		$('#search-button').off().on('click', function(e) { | 		var searchButton = $("#search-button"), | ||||||
|  | 			searchFields = $("#search-fields"), | ||||||
|  | 			searchInput = $('#search-fields input'); | ||||||
|  |  | ||||||
|  | 		function dismissSearch(){ | ||||||
|  | 			searchFields.hide(); | ||||||
|  | 			searchButton.show(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		searchButton.off().on('click', function(e) { | ||||||
| 			e.stopPropagation(); | 			e.stopPropagation(); | ||||||
| 			$('#search-fields').removeClass('hide').show(); |  | ||||||
|  | 			searchFields.removeClass('hide').show(); | ||||||
| 			$(this).hide(); | 			$(this).hide(); | ||||||
| 			$('#search-fields input').focus(); |  | ||||||
|  |  | ||||||
| 			$('#search-form').on('submit', function() { | 			searchInput.focus(); | ||||||
| 				$('#search-fields').hide(); |  | ||||||
| 				$('#search-button').show(); |  | ||||||
| 			}); |  | ||||||
|  |  | ||||||
| 			$('#search-fields input').on('blur', function() { | 			$('#search-form').on('submit', dismissSearch); | ||||||
| 				$('#search-fields').hide(); | 			searchInput.on('blur', dismissSearch); | ||||||
| 				$('#search-button').show(); |  | ||||||
| 			}); |  | ||||||
| 			return false; | 			return false; | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
| @@ -442,7 +452,7 @@ var socket, | |||||||
| 			$('#logged-out-menu').addClass('hide'); | 			$('#logged-out-menu').addClass('hide'); | ||||||
| 			$('#logged-in-menu').removeClass('hide'); | 			$('#logged-in-menu').removeClass('hide'); | ||||||
|  |  | ||||||
| 			$('#search-button').removeClass("hide").show(); | 			searchButton.removeClass("hide").show(); | ||||||
|  |  | ||||||
| 			var userLabel = loggedInMenu.find('#user_label'); | 			var userLabel = loggedInMenu.find('#user_label'); | ||||||
|  |  | ||||||
| @@ -462,10 +472,10 @@ var socket, | |||||||
|  |  | ||||||
| 		} else { | 		} else { | ||||||
| 			if (allowGuestSearching) { | 			if (allowGuestSearching) { | ||||||
| 				$('#search-button').removeClass("hide").show(); | 				searchButton.removeClass("hide").show(); | ||||||
| 				$('#mobile-search-button').removeClass("hide").show(); | 				$('#mobile-search-button').removeClass("hide").show(); | ||||||
| 			} else { | 			} else { | ||||||
| 				$('#search-button').addClass("hide").hide(); | 				searchButton.addClass("hide").hide(); | ||||||
| 				$('#mobile-search-button').addClass("hide").hide(); | 				$('#mobile-search-button').addClass("hide").hide(); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -477,7 +487,7 @@ var socket, | |||||||
|  |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$('#main-nav a,#user-control-list a,#logged-out-menu li a,#logged-in-menu .visible-xs').off('click').on('click', function() { | 		$('#main-nav a, #user-control-list a, #logged-out-menu li a, #logged-in-menu .visible-xs').off('click').on('click', function() { | ||||||
| 			if($('.navbar .navbar-collapse').hasClass('in')) { | 			if($('.navbar .navbar-collapse').hasClass('in')) { | ||||||
| 				$('.navbar-header button').click(); | 				$('.navbar-header button').click(); | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -146,12 +146,12 @@ define(function() { | |||||||
|  |  | ||||||
| 		searchResults.on('click', 'li[data-uid]', function() { | 		searchResults.on('click', 'li[data-uid]', function() { | ||||||
| 			var userLabel = $(this), | 			var userLabel = $(this), | ||||||
| 				uid = parseInt(userLabel.attr('data-uid')), | 				uid = parseInt(userLabel.attr('data-uid'), 10), | ||||||
| 				groupName = detailsModal.attr('data-groupname'), | 				groupName = detailsModal.attr('data-groupname'), | ||||||
| 				members = []; | 				members = []; | ||||||
|  |  | ||||||
| 			groupMembersEl.find('li[data-uid]').each(function() { | 			groupMembersEl.find('li[data-uid]').each(function() { | ||||||
| 				members.push(parseInt($(this).attr('data-uid'))); | 				members.push(parseInt($(this).attr('data-uid'), 10)); | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
| 			if (members.indexOf(uid) === -1) { | 			if (members.indexOf(uid) === -1) { | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| /* global define, config, templates, app, ajaxify, socket, translator */ | /* global define, config, templates, app, utils, ajaxify, socket, translator */ | ||||||
|  |  | ||||||
| define(['composer', 'forum/pagination', 'share', 'navigator'], function(composer, pagination, share, navigator) { | define(['composer', 'forum/pagination', 'share', 'navigator'], function(composer, pagination, share, navigator) { | ||||||
| 	var Category = {}, | 	var Category = {}, | ||||||
|   | |||||||
| @@ -188,18 +188,17 @@ define(['taskbar'], function(taskbar) { | |||||||
| 		var draggingDocument = false; | 		var draggingDocument = false; | ||||||
|  |  | ||||||
| 		var postContainer = $('#cmp-uuid-' + post_uuid), | 		var postContainer = $('#cmp-uuid-' + post_uuid), | ||||||
| 			fileForm = postContainer.find('#fileForm'), |  | ||||||
| 			drop = postContainer.find('.imagedrop'), | 			drop = postContainer.find('.imagedrop'), | ||||||
| 			tabContent = postContainer.find('.tab-content'), | 			tabContent = postContainer.find('.tab-content'), | ||||||
| 			textarea = postContainer.find('textarea'); | 			textarea = postContainer.find('textarea'); | ||||||
|  |  | ||||||
| 		$(document).off('dragstart').on('dragstart', function(e) { | 		$(document).off('dragstart').on('dragstart', function() { | ||||||
| 			draggingDocument = true; | 			draggingDocument = true; | ||||||
| 		}).off('dragend').on('dragend', function(e) { | 		}).off('dragend').on('dragend', function() { | ||||||
| 			draggingDocument = false; | 			draggingDocument = false; | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
| 		textarea.on('dragenter', function(e) { | 		textarea.on('dragenter', function() { | ||||||
| 			if(draggingDocument) { | 			if(draggingDocument) { | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| @@ -208,7 +207,7 @@ define(['taskbar'], function(taskbar) { | |||||||
| 			drop.css('line-height', textarea.height() + 'px'); | 			drop.css('line-height', textarea.height() + 'px'); | ||||||
| 			drop.show(); | 			drop.show(); | ||||||
|  |  | ||||||
| 			drop.on('dragleave', function(ev) { | 			drop.on('dragleave', function() { | ||||||
| 				drop.hide(); | 				drop.hide(); | ||||||
| 				drop.off('dragleave'); | 				drop.off('dragleave'); | ||||||
| 			}); | 			}); | ||||||
| @@ -235,7 +234,6 @@ define(['taskbar'], function(taskbar) { | |||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				// fileForm[0].reset(); |  | ||||||
| 				uploadContentFiles({ | 				uploadContentFiles({ | ||||||
| 					files: files, | 					files: files, | ||||||
| 					post_uuid: post_uuid, | 					post_uuid: post_uuid, | ||||||
| @@ -264,7 +262,6 @@ define(['taskbar'], function(taskbar) { | |||||||
| 						fd.append('files[]', blob, blob.name); | 						fd.append('files[]', blob, blob.name); | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					// fileForm[0].reset(); |  | ||||||
| 					uploadContentFiles({ | 					uploadContentFiles({ | ||||||
| 						files: [blob], | 						files: [blob], | ||||||
| 						post_uuid: post_uuid, | 						post_uuid: post_uuid, | ||||||
| @@ -277,7 +274,7 @@ define(['taskbar'], function(taskbar) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function escapeRegExp(text) { | 	function escapeRegExp(text) { | ||||||
| 		return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); | 		return text.replace(/[\-\[\]\{\}\(\)\*\+\?\.\,\\\^\$\|\#\s]/g, "\\$&"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function uploadContentFiles(params) { | 	function uploadContentFiles(params) { | ||||||
| @@ -417,8 +414,95 @@ define(['taskbar'], function(taskbar) { | |||||||
| 		thumbForm.submit(); | 		thumbForm.submit(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	function handleFormattingBarClick() { | ||||||
|  | 		var iconClass = $(this).find('i').attr('class'); | ||||||
|  | 		var textarea = $(this).parents('.composer').find('textarea')[0]; | ||||||
|  |  | ||||||
|  | 		var textareaValue = $(textarea).val(); | ||||||
|  |  | ||||||
|  | 		var selectionStart = textarea.selectionStart, | ||||||
|  | 			selectionEnd = textarea.selectionEnd, | ||||||
|  | 			selectionLength = selectionEnd - selectionStart, | ||||||
|  | 			isSelectionAtEnd = selectionStart === selectionEnd; | ||||||
|  |  | ||||||
|  | 		function updateSelection(start, end){ | ||||||
|  | 			textarea.setSelectionRange(start, end); | ||||||
|  | 			textarea.focus(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		function insertIntoInput(value) { | ||||||
|  | 			$(textarea).val(textareaValue.slice(0, selectionStart) + value + textareaValue.slice(selectionStart)); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		function wrapSelectedWith(leading, trailing){ | ||||||
|  | 			if(trailing === undefined){ | ||||||
|  | 				trailing = leading; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$(textarea).val(textareaValue.slice(0, selectionStart) + leading + textareaValue.slice(selectionStart, selectionEnd) + trailing + textareaValue.slice(selectionEnd)); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if(iconClass === 'fa fa-bold') { | ||||||
|  | 			if (isSelectionAtEnd) { | ||||||
|  | 				insertIntoInput("**bolded text**"); | ||||||
|  |  | ||||||
|  | 				updateSelection(selectionStart + 2, selectionStart + 13); | ||||||
|  | 			} else { | ||||||
|  | 				wrapSelectedWith('**'); | ||||||
|  |  | ||||||
|  | 				// Highlight selection | ||||||
|  | 				updateSelection(selectionStart + 2, selectionEnd + 2); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if(iconClass === 'fa fa-italic') { | ||||||
|  | 			if (isSelectionAtEnd) { | ||||||
|  | 				insertIntoInput("*italicised text*"); | ||||||
|  |  | ||||||
|  | 				// Highlight selection | ||||||
|  | 				updateSelection(selectionStart + 1, selectionStart + 16); | ||||||
|  | 			} else { | ||||||
|  | 				wrapSelectedWith('*'); | ||||||
|  |  | ||||||
|  | 				// Highlight selection | ||||||
|  | 				updateSelection(selectionStart + 1, selectionEnd + 1); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (iconClass === 'fa fa-list'){ | ||||||
|  | 			if(isSelectionAtEnd){ | ||||||
|  | 				insertIntoInput("\n* list item"); | ||||||
|  |  | ||||||
|  | 				// Highlight "list item" | ||||||
|  | 				updateSelection(selectionStart + 3, selectionStart + 12); | ||||||
|  | 			} else { | ||||||
|  | 				wrapSelectedWith('\n* ', ''); | ||||||
|  |  | ||||||
|  | 				// Maintain selection: | ||||||
|  | 				updateSelection(selectionStart + 3, selectionEnd + 3); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (iconClass === 'fa fa-link') { | ||||||
|  | 			if (isSelectionAtEnd) { | ||||||
|  | 				insertIntoInput("[link text](link url)"); | ||||||
|  |  | ||||||
|  | 				// Highlight "link url" | ||||||
|  | 				updateSelection(selectionStart + 12, selectionEnd + 20); | ||||||
|  | 			} else { | ||||||
|  | 				wrapSelectedWith('[', '](link url)'); | ||||||
|  |  | ||||||
|  | 				// Highlight "link url" | ||||||
|  | 				updateSelection(selectionStart + selectionLength + 3, selectionEnd + 11); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	composer.newTopic = function(cid) { | 	composer.newTopic = function(cid) { | ||||||
| 		if(allowed()) { | 		if(!allowed()) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		push({ | 		push({ | ||||||
| 			cid: cid, | 			cid: cid, | ||||||
| 			title: '', | 			title: '', | ||||||
| @@ -426,13 +510,20 @@ define(['taskbar'], function(taskbar) { | |||||||
| 			modified: false, | 			modified: false, | ||||||
| 			isMain: true | 			isMain: true | ||||||
| 		}); | 		}); | ||||||
| 		} |  | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	composer.addQuote = function(tid, pid, title, username, text){ | 	composer.addQuote = function(tid, pid, title, username, text){ | ||||||
| 		if (allowed()) { | 		if (!allowed()) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		var uuid = composer.active; | 		var uuid = composer.active; | ||||||
| 			if(uuid !== undefined){ |  | ||||||
|  | 		if(uuid === undefined){ | ||||||
|  | 			composer.newReply(tid, pid, title, username + ' said:\n' + text); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		var bodyEl = $('#cmp-uuid-'+uuid).find('textarea'); | 		var bodyEl = $('#cmp-uuid-'+uuid).find('textarea'); | ||||||
| 		var prevText = bodyEl.val(); | 		var prevText = bodyEl.val(); | ||||||
| 		if(tid !== composer.posts[uuid].tid) { | 		if(tid !== composer.posts[uuid].tid) { | ||||||
| @@ -442,14 +533,13 @@ define(['taskbar'], function(taskbar) { | |||||||
| 		} | 		} | ||||||
| 		composer.posts[uuid].body = (prevText.length ? prevText + '\n\n' : '') + text; | 		composer.posts[uuid].body = (prevText.length ? prevText + '\n\n' : '') + text; | ||||||
| 		bodyEl.val(composer.posts[uuid].body); | 		bodyEl.val(composer.posts[uuid].body); | ||||||
| 			} else { |  | ||||||
| 				composer.newReply(tid, pid, title, username + ' said:\n' + text); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	composer.newReply = function(tid, pid, title, text) { | 	composer.newReply = function(tid, pid, title, text) { | ||||||
| 		if(allowed()) { | 		if(!allowed()) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		push({ | 		push({ | ||||||
| 			tid: tid, | 			tid: tid, | ||||||
| 			toPid: pid, | 			toPid: pid, | ||||||
| @@ -458,15 +548,18 @@ define(['taskbar'], function(taskbar) { | |||||||
| 			modified: false, | 			modified: false, | ||||||
| 			isMain: false | 			isMain: false | ||||||
| 		}); | 		}); | ||||||
| 		} |  | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	composer.editPost = function(pid) { | 	composer.editPost = function(pid) { | ||||||
| 		if(allowed()) { | 		if(!allowed()) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		socket.emit('modules.composer.push', pid, function(err, threadData) { | 		socket.emit('modules.composer.push', pid, function(err, threadData) { | ||||||
| 			if(err) { | 			if(err) { | ||||||
| 				return app.alertError(err.message); | 				return app.alertError(err.message); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			push({ | 			push({ | ||||||
| 				pid: pid, | 				pid: pid, | ||||||
| 				title: threadData.title, | 				title: threadData.title, | ||||||
| @@ -476,7 +569,6 @@ define(['taskbar'], function(taskbar) { | |||||||
| 				topic_thumb: threadData.topic_thumb | 				topic_thumb: threadData.topic_thumb | ||||||
| 			}); | 			}); | ||||||
| 		}); | 		}); | ||||||
| 		} |  | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	composer.load = function(post_uuid) { | 	composer.load = function(post_uuid) { | ||||||
| @@ -576,7 +668,7 @@ define(['taskbar'], function(taskbar) { | |||||||
| 					e.preventDefault(); | 					e.preventDefault(); | ||||||
| 				}); | 				}); | ||||||
|  |  | ||||||
| 				postContainer.on('paste change keypress', 'input#topic-thumb-url', function(e) { | 				postContainer.on('paste change keypress', 'input#topic-thumb-url', function() { | ||||||
| 					var urlEl = $(this); | 					var urlEl = $(this); | ||||||
| 					setTimeout(function(){ | 					setTimeout(function(){ | ||||||
| 						var url = urlEl.val(); | 						var url = urlEl.val(); | ||||||
| @@ -616,72 +708,7 @@ define(['taskbar'], function(taskbar) { | |||||||
| 					} | 					} | ||||||
| 				}); | 				}); | ||||||
|  |  | ||||||
| 				postContainer.on('click', '.formatting-bar span', function() { | 				postContainer.on('click', '.formatting-bar span', handleFormattingBarClick); | ||||||
| 					var postContentEl = postContainer.find('textarea'), |  | ||||||
| 						iconClass = $(this).find('i').attr('class'), |  | ||||||
| 						cursorEnd = postContentEl.val().length, |  | ||||||
| 						selectionStart = postContentEl[0].selectionStart, |  | ||||||
| 						selectionEnd = postContentEl[0].selectionEnd, |  | ||||||
| 						selectionLength = selectionEnd - selectionStart, |  | ||||||
| 						cursorPos; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 					function insertIntoInput(element, value) { |  | ||||||
| 						var start = postContentEl[0].selectionStart; |  | ||||||
| 						element.val(element.val().slice(0, start) + value + element.val().slice(start, element.val().length)); |  | ||||||
| 						postContentEl[0].selectionStart = postContentEl[0].selectionEnd = start + value.length; |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					switch(iconClass) { |  | ||||||
| 						case 'fa fa-bold': |  | ||||||
| 							if (selectionStart === selectionEnd) { |  | ||||||
| 								// Nothing selected |  | ||||||
| 								cursorPos = postContentEl[0].selectionStart; |  | ||||||
| 								insertIntoInput(postContentEl, "**bolded text**"); |  | ||||||
|  |  | ||||||
| 								// Highlight "link url" |  | ||||||
| 								postContentEl[0].selectionStart = cursorPos + 12; |  | ||||||
| 								postContentEl[0].selectionEnd = cursorPos + 20; |  | ||||||
| 							} else { |  | ||||||
| 								// Text selected |  | ||||||
| 								postContentEl.val(postContentEl.val().slice(0, selectionStart) + '**' + postContentEl.val().slice(selectionStart, selectionEnd) + '**' + postContentEl.val().slice(selectionEnd)); |  | ||||||
| 								postContentEl[0].selectionStart = selectionStart + 2; |  | ||||||
| 								postContentEl[0].selectionEnd = selectionEnd + 2; |  | ||||||
| 							} |  | ||||||
| 							break; |  | ||||||
| 						case 'fa fa-italic': |  | ||||||
| 							if (selectionStart === selectionEnd) { |  | ||||||
| 								// Nothing selected |  | ||||||
| 								insertIntoInput(postContentEl, "*italicised text*"); |  | ||||||
| 							} else { |  | ||||||
| 								// Text selected |  | ||||||
| 								postContentEl.val(postContentEl.val().slice(0, selectionStart) + '*' + postContentEl.val().slice(selectionStart, selectionEnd) + '*' + postContentEl.val().slice(selectionEnd)); |  | ||||||
| 								postContentEl[0].selectionStart = selectionStart + 1; |  | ||||||
| 								postContentEl[0].selectionEnd = selectionEnd + 1; |  | ||||||
| 							} |  | ||||||
| 							break; |  | ||||||
| 						case 'fa fa-list': |  | ||||||
| 							// Nothing selected |  | ||||||
| 							insertIntoInput(postContentEl, "\n* list item"); |  | ||||||
| 							break; |  | ||||||
| 						case 'fa fa-link': |  | ||||||
| 							if (selectionStart === selectionEnd) { |  | ||||||
| 								// Nothing selected |  | ||||||
| 								cursorPos = postContentEl[0].selectionStart; |  | ||||||
| 								insertIntoInput(postContentEl, "[link text](link url)"); |  | ||||||
|  |  | ||||||
| 								// Highlight "link url" |  | ||||||
| 								postContentEl[0].selectionStart = cursorPos + 12; |  | ||||||
| 								postContentEl[0].selectionEnd = cursorPos + 20; |  | ||||||
| 							} else { |  | ||||||
| 								// Text selected |  | ||||||
| 								postContentEl.val(postContentEl.val().slice(0, selectionStart) + '[' + postContentEl.val().slice(selectionStart, selectionEnd) + '](link url)' + postContentEl.val().slice(selectionEnd)); |  | ||||||
| 								postContentEl[0].selectionStart = selectionStart + selectionLength + 3; |  | ||||||
| 								postContentEl[0].selectionEnd = selectionEnd + 11; |  | ||||||
| 							} |  | ||||||
| 							break; |  | ||||||
| 					} |  | ||||||
| 				}); |  | ||||||
|  |  | ||||||
| 				postContainer.on('click', '.formatting-bar span .fa-picture-o, .formatting-bar span .fa-upload', function() { | 				postContainer.on('click', '.formatting-bar span .fa-picture-o, .formatting-bar span .fa-upload', function() { | ||||||
| 					$('#files').click(); | 					$('#files').click(); | ||||||
| @@ -871,11 +898,11 @@ define(['taskbar'], function(taskbar) { | |||||||
| 			titleEl = postContainer.find('.title'), | 			titleEl = postContainer.find('.title'), | ||||||
| 			bodyEl = postContainer.find('textarea'); | 			bodyEl = postContainer.find('textarea'); | ||||||
|  |  | ||||||
| 		if ((parseInt(postData.tid) || parseInt(postData.pid)) > 0) { | 		if ((parseInt(postData.tid, 10) || parseInt(postData.pid, 10)) > 0) { | ||||||
| 			bodyEl.focus(); | 			bodyEl.focus(); | ||||||
| 			bodyEl.selectionStart = bodyEl.val().length; | 			bodyEl.selectionStart = bodyEl.val().length; | ||||||
| 			bodyEl.selectionEnd = bodyEl.val().length; | 			bodyEl.selectionEnd = bodyEl.val().length; | ||||||
| 		} else if (parseInt(postData.cid) > 0) { | 		} else if (parseInt(postData.cid, 10) > 0) { | ||||||
| 			titleEl.focus(); | 			titleEl.focus(); | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|   | |||||||
| @@ -4,9 +4,31 @@ var	Groups = require('./groups'), | |||||||
| 	User = require('./user'), | 	User = require('./user'), | ||||||
|  |  | ||||||
| 	async = require('async'), | 	async = require('async'), | ||||||
| 	db = require('./database'), | 	db = require('./database'); | ||||||
|  |  | ||||||
| 	CategoryTools = {}; | var internals = { | ||||||
|  | 	isMember: function(key, candidate, next){ | ||||||
|  | 		Groups.exists(key, function(err, exists) { | ||||||
|  | 			if (exists) { | ||||||
|  | 				Groups.isMember(candidate, key, next); | ||||||
|  | 			} else { | ||||||
|  | 				next(null, null); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	isMemberOfGroupList: function(key, candidate, next){ | ||||||
|  | 		Groups.exists(key, function(err, exists) { | ||||||
|  | 			if (exists) { | ||||||
|  | 				Groups.isMemberOfGroupList(candidate, key, next); | ||||||
|  | 			} else { | ||||||
|  | 				next(null, null); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | var CategoryTools = {}; | ||||||
|  |  | ||||||
| CategoryTools.exists = function(cid, callback) { | CategoryTools.exists = function(cid, callback) { | ||||||
| 	db.isSortedSetMember('categories:cid', cid, callback); | 	db.isSortedSetMember('categories:cid', cid, callback); | ||||||
| @@ -15,44 +37,16 @@ CategoryTools.exists = function(cid, callback) { | |||||||
| CategoryTools.privileges = function(cid, uid, callback) { | CategoryTools.privileges = function(cid, uid, callback) { | ||||||
| 	async.parallel({ | 	async.parallel({ | ||||||
| 		"+r": function(next) { | 		"+r": function(next) { | ||||||
| 			var	key = 'cid:' + cid + ':privileges:+r'; | 			internals.isMember('cid:' + cid + ':privileges:+r', uid, next); | ||||||
| 			Groups.exists(key, function(err, exists) { |  | ||||||
| 				if (exists) { |  | ||||||
| 					Groups.isMember(uid, key, next); |  | ||||||
| 				} else { |  | ||||||
| 					next(null, null); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		}, | 		}, | ||||||
| 		"+w": function(next) { | 		"+w": function(next) { | ||||||
| 			var	key = 'cid:' + cid + ':privileges:+w'; | 			internals.isMember('cid:' + cid + ':privileges:+w', uid, next); | ||||||
| 			Groups.exists(key, function(err, exists) { |  | ||||||
| 				if (exists) { |  | ||||||
| 					Groups.isMember(uid, key, next); |  | ||||||
| 				} else { |  | ||||||
| 					next(null, null); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		}, | 		}, | ||||||
| 		"g+r": function(next) { | 		"g+r": function(next) { | ||||||
| 			var	key = 'cid:' + cid + ':privileges:g+r'; | 			internals.isMemberOfGroupList('cid:' + cid + ':privileges:g+r', uid, next); | ||||||
| 			Groups.exists(key, function(err, exists) { |  | ||||||
| 				if (exists) { |  | ||||||
| 					Groups.isMemberOfGroupList(uid, key, next); |  | ||||||
| 				} else { |  | ||||||
| 					next(null, null); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		}, | 		}, | ||||||
| 		"g+w": function(next) { | 		"g+w": function(next) { | ||||||
| 			var	key = 'cid:' + cid + ':privileges:g+w'; | 			internals.isMemberOfGroupList('cid:' + cid + ':privileges:g+w', uid, next); | ||||||
| 			Groups.exists(key, function(err, exists) { |  | ||||||
| 				if (exists) { |  | ||||||
| 					Groups.isMemberOfGroupList(uid, key, next); |  | ||||||
| 				} else { |  | ||||||
| 					next(null, null); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		}, | 		}, | ||||||
| 		moderator: function(next) { | 		moderator: function(next) { | ||||||
| 			User.isModerator(uid, cid, next); | 			User.isModerator(uid, cid, next); | ||||||
| @@ -93,23 +87,13 @@ CategoryTools.privileges = function(cid, uid, callback) { | |||||||
| CategoryTools.groupPrivileges = function(cid, groupName, callback) { | CategoryTools.groupPrivileges = function(cid, groupName, callback) { | ||||||
| 	async.parallel({ | 	async.parallel({ | ||||||
| 		"g+r": function(next) { | 		"g+r": function(next) { | ||||||
| 			var	key = 'cid:' + cid + ':privileges:g+r'; | 			internals.isMember('cid:' + cid + ':privileges:g+r', groupName, function(err, isMember){ | ||||||
| 			Groups.exists(key, function(err, exists) { | 				next(err, !!isMember); | ||||||
| 				if (exists) { |  | ||||||
| 					Groups.isMember(groupName, key, next); |  | ||||||
| 				} else { |  | ||||||
| 					next(null, false); |  | ||||||
| 				} |  | ||||||
| 			}); | 			}); | ||||||
| 		}, | 		}, | ||||||
| 		"g+w": function(next) { | 		"g+w": function(next) { | ||||||
| 			var	key = 'cid:' + cid + ':privileges:g+w'; | 			internals.isMember('cid:' + cid + ':privileges:g+w', groupName, function(err, isMember){ | ||||||
| 			Groups.exists(key, function(err, exists) { | 				next(err, !!isMember); | ||||||
| 				if (exists) { |  | ||||||
| 					Groups.isMember(groupName, key, next); |  | ||||||
| 				} else { |  | ||||||
| 					next(null, false); |  | ||||||
| 				} |  | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 	}, function(err, privileges) { | 	}, function(err, privileges) { | ||||||
|   | |||||||
| @@ -72,25 +72,21 @@ var fs = require('fs'), | |||||||
| 				db.getSetMembers('plugins:active', next); | 				db.getSetMembers('plugins:active', next); | ||||||
| 			}, | 			}, | ||||||
| 			function(plugins, next) { | 			function(plugins, next) { | ||||||
| 				if (plugins && Array.isArray(plugins)) { | 				if (!plugins || !Array.isArray(plugins)) { | ||||||
|  | 					next(); | ||||||
|  | 				} | ||||||
|  |  | ||||||
| 				plugins.push(meta.config['theme:id']); | 				plugins.push(meta.config['theme:id']); | ||||||
|  |  | ||||||
| 					async.each(plugins, function(plugin, next) { | 				plugins = plugins.filter(function(plugin){ | ||||||
| 						if (!plugin || typeof plugin !== 'string') { | 					return plugin && typeof plugin === 'string'; | ||||||
| 							return next(); | 				}).map(function(plugin){ | ||||||
| 						} | 					return path.join(__dirname, '../node_modules/', plugin); | ||||||
|  | 				}); | ||||||
|  |  | ||||||
| 						var modulePath = path.join(__dirname, '../node_modules/', plugin); | 				async.filter(plugins, fs.exists, function(plugins){ | ||||||
| 						if (fs.existsSync(modulePath)) { | 					async.each(plugins, Plugins.loadPlugin, next); | ||||||
| 							Plugins.loadPlugin(modulePath, next); | 				}); | ||||||
| 						} else { |  | ||||||
| 							if (global.env === 'development') { |  | ||||||
| 								winston.warn('[plugins] Plugin \'' + plugin + '\' not found'); |  | ||||||
| 							} |  | ||||||
| 							next(); // Ignore this plugin silently |  | ||||||
| 						} |  | ||||||
| 					}, next); |  | ||||||
| 				} else next(); |  | ||||||
| 			}, | 			}, | ||||||
| 			function(next) { | 			function(next) { | ||||||
| 				if (global.env === 'development') winston.info('[plugins] Sorting hooks to fire in priority sequence'); | 				if (global.env === 'development') winston.info('[plugins] Sorting hooks to fire in priority sequence'); | ||||||
| @@ -434,28 +430,31 @@ var fs = require('fs'), | |||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	Plugins.showInstalled = function(callback) { | 	Plugins.showInstalled = function(callback) { | ||||||
| 		npmPluginPath = path.join(__dirname, '../node_modules'); | 		var npmPluginPath = path.join(__dirname, '../node_modules'); | ||||||
|  |  | ||||||
| 		async.waterfall([ | 		async.waterfall([ | ||||||
| 			function(next) { | 			async.apply(fs.readdir, npmPluginPath), | ||||||
| 				fs.readdir(npmPluginPath, function(err, dirs) { |  | ||||||
| 					dirs = dirs.map(function(file) { |  | ||||||
| 						return path.join(npmPluginPath, file); |  | ||||||
| 					}).filter(function(file) { |  | ||||||
| 						if (fs.existsSync(file)) { |  | ||||||
| 							var stats = fs.statSync(file), |  | ||||||
| 								isPlugin =  file.substr(npmPluginPath.length + 1, 14) === 'nodebb-plugin-' || file.substr(npmPluginPath.length + 1, 14) === 'nodebb-widget-'; |  | ||||||
|  |  | ||||||
| 							if (stats.isDirectory() && isPlugin) return true; | 			function(dirs, next) { | ||||||
| 							else return false; | 				dirs = dirs.filter(function(dir){ | ||||||
| 						} else { | 					return dir.substr(0, 14) === 'nodebb-plugin-' || dir.substr(0, 14) === 'nodebb-widget-'; | ||||||
| 							return false; | 				}).map(function(dir){ | ||||||
| 						} | 					return path.join(npmPluginPath, dir); | ||||||
| 				}); | 				}); | ||||||
|  |  | ||||||
| 					next(err, dirs); | 				async.filter(dirs, function(dir, callback){ | ||||||
|  | 					fs.stat(dir, function(err, stats){ | ||||||
|  | 						if (err) { | ||||||
|  | 							return callback(false); | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						callback(stats.isDirectory()); | ||||||
|  | 					}) | ||||||
|  | 				}, function(plugins){ | ||||||
|  | 					next(null, plugins); | ||||||
| 				}); | 				}); | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
| 			function(files, next) { | 			function(files, next) { | ||||||
| 				var plugins = []; | 				var plugins = []; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -41,4 +41,3 @@ module.exports = function(User) { | |||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user