From 3c96857123f4bebfcab4a6eacd6e4f194f26c610 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 3 May 2014 00:07:01 -0400 Subject: [PATCH 01/88] closes #1461 fixed disabled category grey out, added plural move topics string --- public/language/en_GB/topic.json | 1 + public/src/forum/topic/move.js | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/public/language/en_GB/topic.json b/public/language/en_GB/topic.json index 2af258a89d..8958beb1dc 100644 --- a/public/language/en_GB/topic.json +++ b/public/language/en_GB/topic.json @@ -82,6 +82,7 @@ "loading_more_posts": "Loading More Posts", "move_topic": "Move Topic", + "move_topics": "Move Topics", "move_post": "Move Post", "post_moved": "Post moved!", "fork_topic": "Fork Topic", diff --git a/public/src/forum/topic/move.js b/public/src/forum/topic/move.js index 937b072124..c1a0fe2d59 100644 --- a/public/src/forum/topic/move.js +++ b/public/src/forum/topic/move.js @@ -19,6 +19,13 @@ define(function() { modal.on('shown.bs.modal', onMoveModalShown); $('#move-confirm').hide(); + + if (tids.length > 1) { + translator.translate('[[topic:move_topics]]', function(translated) { + modal.find('.modal-header h3').text(translated); + }); + } + modal.modal('show'); }; @@ -93,9 +100,10 @@ define(function() { if(parseInt(info.cid, 10) === parseInt(Move.currentCid, 10)) { continue; } + $('
  • ') .css({background: info.bgColor, color: info.color || '#fff'}) - .addClass(info.disabled === '1' ? ' disabled' : '') + .toggleClass('disabled', info.disabled) .attr('data-cid', info.cid) .html(' ' + info.name) .appendTo(categoriesEl); From ec399d8b3b3e3dec47e51ebd41a2e3eff0e4ce49 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 3 May 2014 17:21:07 -0400 Subject: [PATCH 02/88] moved all account related files to account folder update nodebb-theme-vanilla too to get the update tpl files --- public/src/forum/{accountedit.js => account/edit.js} | 2 +- public/src/forum/{ => account}/favourites.js | 2 +- public/src/forum/{ => account}/followers.js | 2 +- public/src/forum/{ => account}/following.js | 2 +- public/src/forum/{accountheader.js => account/header.js} | 0 public/src/forum/{accountposts.js => account/posts.js} | 2 +- public/src/forum/{account.js => account/profile.js} | 2 +- public/src/forum/{accountsettings.js => account/settings.js} | 2 +- public/src/forum/{accounttopics.js => account/topics.js} | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename public/src/forum/{accountedit.js => account/edit.js} (98%) rename public/src/forum/{ => account}/favourites.js (96%) rename public/src/forum/{ => account}/followers.js (88%) rename public/src/forum/{ => account}/following.js (86%) rename public/src/forum/{accountheader.js => account/header.js} (100%) rename public/src/forum/{accountposts.js => account/posts.js} (96%) rename public/src/forum/{account.js => account/profile.js} (97%) rename public/src/forum/{accountsettings.js => account/settings.js} (96%) rename public/src/forum/{accounttopics.js => account/topics.js} (96%) diff --git a/public/src/forum/accountedit.js b/public/src/forum/account/edit.js similarity index 98% rename from public/src/forum/accountedit.js rename to public/src/forum/account/edit.js index e80ec94a0d..c1120432bc 100644 --- a/public/src/forum/accountedit.js +++ b/public/src/forum/account/edit.js @@ -2,7 +2,7 @@ /* globals define, ajaxify, socket, app, config, utils, translator */ -define(['forum/accountheader', 'uploader'], function(header, uploader) { +define(['forum/account/header', 'uploader'], function(header, uploader) { var AccountEdit = {}, gravatarPicture = '', uploadedPicture = '', diff --git a/public/src/forum/favourites.js b/public/src/forum/account/favourites.js similarity index 96% rename from public/src/forum/favourites.js rename to public/src/forum/account/favourites.js index c3810a316c..4ac57931d5 100644 --- a/public/src/forum/favourites.js +++ b/public/src/forum/account/favourites.js @@ -1,4 +1,4 @@ -define(['forum/accountheader'], function(header) { +define(['forum/account/header'], function(header) { var Favourites = {}, loadingMore = false; diff --git a/public/src/forum/followers.js b/public/src/forum/account/followers.js similarity index 88% rename from public/src/forum/followers.js rename to public/src/forum/account/followers.js index 40a2550ba6..9576ad4547 100644 --- a/public/src/forum/followers.js +++ b/public/src/forum/account/followers.js @@ -1,4 +1,4 @@ -define(['forum/accountheader'], function(header) { +define(['forum/account/header'], function(header) { var Followers = {}; Followers.init = function() { diff --git a/public/src/forum/following.js b/public/src/forum/account/following.js similarity index 86% rename from public/src/forum/following.js rename to public/src/forum/account/following.js index 4dd6636692..5bbce74d10 100644 --- a/public/src/forum/following.js +++ b/public/src/forum/account/following.js @@ -1,4 +1,4 @@ -define(['forum/accountheader'], function(header) { +define(['forum/account/header'], function(header) { var Following = {}; Following.init = function() { diff --git a/public/src/forum/accountheader.js b/public/src/forum/account/header.js similarity index 100% rename from public/src/forum/accountheader.js rename to public/src/forum/account/header.js diff --git a/public/src/forum/accountposts.js b/public/src/forum/account/posts.js similarity index 96% rename from public/src/forum/accountposts.js rename to public/src/forum/account/posts.js index 737cb41916..b7923cf0ba 100644 --- a/public/src/forum/accountposts.js +++ b/public/src/forum/account/posts.js @@ -2,7 +2,7 @@ /* globals define, app, socket, ajaxify, templates, translator, utils */ -define(['forum/accountheader'], function(header) { +define(['forum/account/header'], function(header) { var AccountPosts = {}, loadingMore = false; diff --git a/public/src/forum/account.js b/public/src/forum/account/profile.js similarity index 97% rename from public/src/forum/account.js rename to public/src/forum/account/profile.js index 74c8d25a98..140f3f53cd 100644 --- a/public/src/forum/account.js +++ b/public/src/forum/account/profile.js @@ -2,7 +2,7 @@ /* globals define, ajaxify, app, utils, socket, translator*/ -define(['forum/accountheader'], function(header) { +define(['forum/account/header'], function(header) { var Account = {}, yourid, theirid, diff --git a/public/src/forum/accountsettings.js b/public/src/forum/account/settings.js similarity index 96% rename from public/src/forum/accountsettings.js rename to public/src/forum/account/settings.js index 4945eb8abb..2c1f9508bf 100644 --- a/public/src/forum/accountsettings.js +++ b/public/src/forum/account/settings.js @@ -1,4 +1,4 @@ -define(['forum/accountheader'], function(header) { +define(['forum/account/header'], function(header) { var AccountSettings = {}; AccountSettings.init = function() { diff --git a/public/src/forum/accounttopics.js b/public/src/forum/account/topics.js similarity index 96% rename from public/src/forum/accounttopics.js rename to public/src/forum/account/topics.js index ae91e98df5..9b924aa474 100644 --- a/public/src/forum/accounttopics.js +++ b/public/src/forum/account/topics.js @@ -2,7 +2,7 @@ /* globals define, app, socket, ajaxify, templates, translator, utils */ -define(['forum/accountheader'], function(header) { +define(['forum/account/header'], function(header) { var AccountTopics = {}, loadingMore = false; From d43d363a7acf5257eb3b9c34d5e4f3b73964ccfc Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 3 May 2014 20:56:26 -0400 Subject: [PATCH 03/88] refactored topics.js removed ajaxify.register_events using removeListener now --- public/src/ajaxify.js | 11 - public/src/forum/admin/index.js | 4 +- public/src/forum/category.js | 12 +- public/src/forum/categoryTools.js | 10 + public/src/forum/popular.js | 6 + public/src/forum/recent.js | 51 ++- public/src/forum/topic.js | 568 +++++--------------------- public/src/forum/topic/browsing.js | 123 ++++++ public/src/forum/topic/events.js | 152 +++++++ public/src/forum/topic/postTools.js | 36 +- public/src/forum/topic/threadTools.js | 69 +++- public/src/forum/unread.js | 6 + src/favourites.js | 17 +- src/socket.io/index.js | 2 +- src/socket.io/modules.js | 4 +- src/socket.io/posts.js | 2 +- 16 files changed, 551 insertions(+), 522 deletions(-) create mode 100644 public/src/forum/topic/browsing.js create mode 100644 public/src/forum/topic/events.js diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 59807fa7a0..6513d305d3 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -11,17 +11,6 @@ var ajaxify = ajaxify || {}; availableTemplates = null, apiXHR = null; - var events = []; - - ajaxify.register_events = function (new_page_events) { - for (var i = 0, ii = events.length; i < ii; i++) { - socket.removeAllListeners(events[i]); // optimize this to user removeListener(event, listener) instead. - } - - events = new_page_events; - }; - - window.onpopstate = function (event) { if (event !== null && event.state && event.state.url !== undefined && !ajaxify.initialLoad) { ajaxify.go(event.state.url, function() { diff --git a/public/src/forum/admin/index.js b/public/src/forum/admin/index.js index 97af620e9c..4398dc3546 100644 --- a/public/src/forum/admin/index.js +++ b/public/src/forum/admin/index.js @@ -5,10 +5,11 @@ define(function() { var Admin = {}; Admin.init = function() { - ajaxify.register_events(['meta.rooms.getAll']); app.enterRoom('admin'); socket.emit('meta.rooms.getAll', Admin.updateRoomUsage); + + socket.removeListener('event:meta.rooms.update', Admin.updateRoomUsage); socket.on('event:meta.rooms.update', Admin.updateRoomUsage); $('#logout-link').on('click', function() { @@ -50,7 +51,6 @@ define(function() { uniqueVisitors.find('#' + key).text(data[key]); } } - }); }; diff --git a/public/src/forum/category.js b/public/src/forum/category.js index 1fa4d359ec..5b3358659a 100644 --- a/public/src/forum/category.js +++ b/public/src/forum/category.js @@ -9,9 +9,16 @@ define(['composer', 'forum/pagination', 'share', 'navigator', 'forum/categoryToo $(window).on('action:ajaxify.start', function(ev, data) { if(data && data.url.indexOf('category') !== 0) { navigator.hide(); + + removeListeners(); } }); + function removeListeners() { + socket.removeListener('event:new_topic', Category.onNewTopic); + categoryTools.removeListeners(); + } + Category.init = function() { var cid = ajaxify.variables.get('category_id'); @@ -23,11 +30,6 @@ define(['composer', 'forum/pagination', 'share', 'navigator', 'forum/categoryToo composer.newTopic(cid); }); - ajaxify.register_events([ - 'event:new_topic', 'event:topic_deleted', 'event:topic_restored', 'event:topic_locked', - 'event:topic_unlocked', 'event:topic_pinned', 'event:topic_unpinned', 'event:topic_moved' - ]); - socket.on('event:new_topic', Category.onNewTopic); categoryTools.init(cid); diff --git a/public/src/forum/categoryTools.js b/public/src/forum/categoryTools.js index b1fd02388f..4af8056bec 100644 --- a/public/src/forum/categoryTools.js +++ b/public/src/forum/categoryTools.js @@ -91,6 +91,16 @@ define(['forum/topic/move', 'topicSelect'], function(move, topicSelect) { socket.on('event:topic_moved', onTopicMoved); }; + CategoryTools.removeListeners = function() { + socket.removeListener('event:topic_deleted', setDeleteState); + socket.removeListener('event:topic_restored', setDeleteState); + socket.removeListener('event:topic_locked', setLockedState); + socket.removeListener('event:topic_unlocked', setLockedState); + socket.removeListener('event:topic_pinned', setPinnedState); + socket.removeListener('event:topic_unpinned', setPinnedState); + socket.removeListener('event:topic_moved', onTopicMoved); + }; + function closeDropDown() { $('.thread-tools.open').find('.dropdown-toggle').trigger('click'); } diff --git a/public/src/forum/popular.js b/public/src/forum/popular.js index e8b35729a4..fe0b9519fd 100644 --- a/public/src/forum/popular.js +++ b/public/src/forum/popular.js @@ -3,6 +3,12 @@ define(['forum/recent'], function(recent) { loadingMoreTopics = false, active = ''; + $(window).on('action:ajaxify.start', function(ev, data) { + if(data.url.indexOf('recent') !== 0) { + recent.removeListeners(); + } + }); + Popular.init = function() { app.enterRoom('recent_posts'); diff --git a/public/src/forum/recent.js b/public/src/forum/recent.js index 1af4e764a5..e73e3376c5 100644 --- a/public/src/forum/recent.js +++ b/public/src/forum/recent.js @@ -1,3 +1,7 @@ +'use strict'; + +/* globals define, app, socket, ajaxify, templates, translator, utils */ + define(function() { var Recent = {}; @@ -14,15 +18,19 @@ define(function() { return active; } + $(window).on('action:ajaxify.start', function(ev, data) { + if(data.url.indexOf('recent') !== 0) { + Recent.removeListeners(); + } + }); + Recent.init = function() { app.enterRoom('recent_posts'); Recent.watchForNewPosts(); - active = Recent.selectActivePill(); - $('#new-topics-alert').on('click', function() { $(this).addClass('hide'); }); @@ -48,29 +56,32 @@ define(function() { }); return active; - } + }; Recent.watchForNewPosts = function () { - newPostCount = 0; newTopicCount = 0; - ajaxify.register_events([ - 'event:new_topic', - 'event:new_post' - ]); + socket.on('event:new_topic', onNewTopic); + socket.on('event:new_post', onNewPost); + }; - socket.on('event:new_topic', function(data) { - ++newTopicCount; - Recent.updateAlertText(); - }); - - socket.on('event:new_post', function(data) { - ++newPostCount; - Recent.updateAlertText(); - }); + function onNewTopic(data) { + ++newTopicCount; + Recent.updateAlertText(); } + function onNewPost(data) { + ++newPostCount; + Recent.updateAlertText(); + } + + Recent.removeListeners = function() { + console.log('removing'); + socket.removeListener('event:new_topic', onNewTopic); + socket.removeListener('event:new_post', onNewPost); + }; + Recent.updateAlertText = function() { var text = 'There'; @@ -90,7 +101,7 @@ define(function() { $('#new-topics-alert').html(text).removeClass('hide').fadeIn('slow'); $('#category-no-topics').addClass('hide'); - } + }; Recent.loadMoreTopics = function() { if(!$('#topics-container').length) { @@ -113,7 +124,7 @@ define(function() { loadingMoreTopics = false; }); - } + }; Recent.onTopicsLoaded = function(templateName, topics, showSelect) { ajaxify.loadTemplate(templateName, function(template) { @@ -129,7 +140,7 @@ define(function() { utils.makeNumbersHumanReadable(html.find('.human-readable-number')); }); }); - } + }; return Recent; }); diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index d6fd2a697c..de564f00cb 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -3,23 +3,22 @@ /* globals define, app, templates, translator, socket, bootbox, config, ajaxify, RELATIVE_PATH, utils */ -define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', 'navigator'], function(pagination, threadTools, postTools, navigator) { +define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', 'forum/topic/events', 'navigator'], function(pagination, threadTools, postTools, events, navigator) { var Topic = {}, infiniteLoaderActive = false, scrollingToPost = false, currentUrl = ''; - function showBottomPostBar() { - if($('#post-container .post-row').length > 1 || !$('#post-container li[data-index="0"]').length) { - $('.bottom-post-bar').removeClass('hide'); - } - } $(window).on('action:ajaxify.start', function(ev, data) { if(data.url.indexOf('topic') !== 0) { navigator.hide(); $('.header-topic-title').find('span').text('').hide(); app.removeAlert('bookmark'); + + events.removeListeners(); + + socket.removeListener('event:new_post', onNewPost); } }); @@ -30,473 +29,122 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', deleted: ajaxify.variables.get('deleted'), pinned: ajaxify.variables.get('pinned') }, - currentPage = parseInt(ajaxify.variables.get('currentPage'), 10), - pageCount = parseInt(ajaxify.variables.get('pageCount'), 10); - - Topic.postCount = ajaxify.variables.get('postcount'); + postCount = ajaxify.variables.get('postcount'); $(window).trigger('action:topic.loading'); - function hidePostToolsForDeletedPosts() { - $('#post-container li.deleted').each(function() { - toggle_post_tools($(this).attr('data-pid'), true); - }); - } + utils.addCommasToNumbers($('.topic .formatted-number')); - $(function() { - utils.addCommasToNumbers($('.topic .formatted-number')); + app.enterRoom('topic_' + tid); - app.enterRoom('topic_' + tid); + showBottomPostBar(); - showBottomPostBar(); + postTools.init(tid, thread_state); + threadTools.init(tid, thread_state); + events.init(); - if (thread_state.locked === '1') { - set_locked_state(true); - } + hidePostToolsForDeletedPosts(); - if (thread_state.deleted === '1') { - set_delete_state(true); - } + enableInfiniteLoading(); - if (thread_state.pinned === '1') { - set_pinned_state(true); - } - - postTools.init(tid, thread_state); - threadTools.init(tid, thread_state); - - hidePostToolsForDeletedPosts(); - - enableInfiniteLoading(); - - var bookmark = localStorage.getItem('topic:' + tid + ':bookmark'); - if (window.location.hash) { - Topic.scrollToPost(window.location.hash.substr(1), true); - } else if (bookmark && (!config.usePagination || (config.usePagination && pagination.currentPage === 1)) && Topic.postCount > 1) { - app.alert({ - alert_id: 'bookmark', - message: '[[topic:bookmark_instructions]]', - timeout: 0, - type: 'info', - clickfn : function() { - Topic.scrollToPost(parseInt(bookmark, 10), true); - }, - closefn : function() { - localStorage.removeItem('topic:' + tid + ':bookmark'); - } - }); - } - - if (!config.usePagination) { - navigator.init('.posts > .post-row', Topic.postCount, Topic.navigatorCallback); - } - - $('#post-container').on('mouseenter', '.favourite-tooltip', function(e) { - if (!$(this).data('users-loaded')) { - $(this).data('users-loaded', "true"); - var pid = $(this).parents('.post-row').attr('data-pid'); - var el = $(this).attr('title', "Loading..."); - socket.emit('posts.getFavouritedUsers', pid, function(err, usernames) { - el.attr('title', usernames).tooltip('show'); - }); - } - }); - }); - - - function enableInfiniteLoading() { - if(!config.usePagination) { - - app.enableInfiniteLoading(function(direction) { - - if (!infiniteLoaderActive && $('#post-container').children().length) { - var after = 0; - var el = null; - if(direction > 0) { - el = $('#post-container .post-row').last(); - after = parseInt(el.attr('data-index'), 10) + 1; - } else { - el = $('#post-container .post-row').first(); - after = parseInt(el.attr('data-index'), 10); - after -= config.postsPerPage; - if(after < 0) { - after = 0; - } - } - - var offset = el.offset().top - $('#header-menu').offset().top + $('#header-menu').height(); - - loadMorePosts(tid, after, function() { - hidePostToolsForDeletedPosts(); - if(direction < 0 && el) { - Topic.scrollToPost(el.attr('data-pid'), false, 0, offset); - } - }); - } - }); - } else { - navigator.hide(); - - pagination.init(currentPage, pageCount); - } - } - - - ajaxify.register_events([ - 'event:voted', 'event:favourited', 'event:new_post', 'get_users_in_room', - 'event:topic_deleted', 'event:topic_restored', 'event:topic_locked', - 'event:topic_unlocked', 'event:topic_pinned', 'event:topic_unpinned', - 'event:topic_moved', 'event:post_edited', 'event:post_deleted', 'event:post_restored', - 'posts.favourite', 'user.isOnline', 'posts.upvote', 'posts.downvote', - 'event:topic.replyStart', 'event:topic.replyStop' - ]); - - function createUserIcon(uid, picture, userslug, username) { - if(!$('.thread_active_users').find('[data-uid="' + uid + '"]').length) { - return $('
    '); - } - } - - socket.on('get_users_in_room', function(data) { - if(data && data.room.indexOf('topic') !== -1) { - var activeEl = $('.thread_active_users'); - - // remove users that are no longer here - activeEl.find('a').each(function(index, element) { - if(element) { - var uid = $(element).attr('data-uid'); - var absent = data.users.every(function(user) { - return parseInt(user.uid, 10) !== parseInt(uid, 10); - }); - - if (absent) { - $(element).remove(); - } - } - }); - - var i=0, icon; - // add self - for(i = 0; i 8) { - break; - } - } - - activeEl.find('a[data-uid] img').tooltip({ - placement: 'top' - }); - - var remainingUsers = data.users.length - 9; - remainingUsers = remainingUsers < 0 ? 0 : remainingUsers; - var anonymousCount = parseInt(data.anonymousCount, 10); - activeEl.find('.anonymous-box').remove(); - if(anonymousCount || remainingUsers) { - - var anonLink = $('
    '); - activeEl.append(anonLink); - - var title = ''; - if(remainingUsers && anonymousCount) { - title = '[[topic:more_users_and_guests, ' + remainingUsers + ', ' + anonymousCount + ']]'; - } else if(remainingUsers) { - title = '[[topic:more_users, ' + remainingUsers + ']]'; - } else { - title = '[[topic:more_guests, ' + anonymousCount + ']]'; - } - - translator.translate(title, function(translated) { - $('.anonymous-box').tooltip({ - placement: 'top', - title: translated - }); - }); - } - - getReplyingUsers(); - } - - app.populateOnlineUsers(); - }); - - function getReplyingUsers() { - var activeEl = $('.thread_active_users'); - socket.emit('modules.composer.getUsersByTid', ajaxify.variables.get('topic_id'), function(err, uids) { - if (uids && uids.length) { - for(var x=0;x 1) { + app.alert({ + alert_id: 'bookmark', + message: '[[topic:bookmark_instructions]]', + timeout: 0, + type: 'info', + clickfn : function() { + Topic.scrollToPost(parseInt(bookmark, 10), true); + }, + closefn : function() { + localStorage.removeItem('topic:' + tid + ':bookmark'); } }); } - socket.on('user.isOnline', function(err, data) { - app.populateOnlineUsers(); - - updateActiveUsers(data); - }); - - function updateActiveUsers(data) { - var activeEl = $('.thread_active_users'); - var user = activeEl.find('a[data-uid="'+ data.uid + '"]'); - if (user.length && !data.online) { - user.parent().remove(); - } else if(!user.length && data.online) { - user = createUserIcon(data.uid, data.picture, data.userslug, data.username); - activeEl.append(user); - activeEl.find('a[data-uid] img').tooltip({ - placement: 'top' - }); - } + if (!config.usePagination) { + navigator.init('.posts > .post-row', postCount, Topic.navigatorCallback); } - socket.on('event:voted', function(data) { - updatePostVotesAndUserReputation(data); - }); - - socket.on('event:favourited', function(data) { - updateFavouriteCount(data.post.pid, data.post.reputation); - }); - - socket.on('event:new_post', function(data) { - if(data && data.posts && data.posts.length && data.posts[0].tid !== ajaxify.variables.get('topic_id')) { - return; - } - - if(config.usePagination) { - onNewPostPagination(data); - return; - } - - for (var i=0; i 0) { - ajaxify.go('topic/' + data.tid); - } - }); - - socket.on('event:post_edited', function(data) { - var editedPostEl = $('#content_' + data.pid), - editedPostTitle = $('#topic_title_' + data.pid); - - if (editedPostTitle.length) { - editedPostTitle.fadeOut(250, function() { - editedPostTitle.html(data.title); - editedPostTitle.fadeIn(250); - }); - } - - editedPostEl.fadeOut(250, function() { - editedPostEl.html(data.content); - editedPostEl.find('img').addClass('img-responsive'); - editedPostEl.fadeIn(250); - }); - }); - - socket.on('posts.upvote', function(pid) { - toggleUpvoteDownvote(pid, true, false); - }); - - socket.on('posts.downvote', function(pid) { - toggleUpvoteDownvote(pid, false, true); - }); - - socket.on('posts.unvote', function(pid) { - toggleUpvoteDownvote(pid, false, false); - }); - - function toggleUpvoteDownvote(pid, upvote, downvote) { - var post = $('li[data-pid="' + pid + '"]'); - - post.find('.upvote').toggleClass('btn-primary upvoted', upvote); - post.find('.downvote').toggleClass('btn-primary downvoted', downvote); - } - - socket.on('posts.favourite', function(pid) { - toggleFavourite(pid, true); - }); - - socket.on('posts.unfavourite', function(pid) { - toggleFavourite(pid, false); - }); - - function toggleFavourite(pid, isFavourited) { - var favBtn = $('li[data-pid="' + pid + '"] .favourite'); - if(favBtn.length) { - favBtn.addClass('btn-warning') - .attr('data-favourited', isFavourited); - - var icon = favBtn.find('i'); - var className = icon.attr('class'); - - if (isFavourited ? className.indexOf('-o') !== -1 : className.indexOf('-o') === -1) { - icon.attr('class', isFavourited ? className.replace('-o', '') : className + '-o'); - } - } - } - - socket.on('event:post_deleted', function(data) { - if (data.pid) { - toggle_post_delete_state(data.pid); - } - }); - - socket.on('event:post_restored', function(data) { - if (data.pid) { - toggle_post_delete_state(data.pid); - } - }); - - socket.on('event:topic.replyStart', function(uid) { - $('.thread_active_users [data-uid="' + uid + '"]').addClass('replying'); - }); - - socket.on('event:topic.replyStop', function(uid) { - $('.thread_active_users [data-uid="' + uid + '"]').removeClass('replying'); - }); - - function updatePostVotesAndUserReputation(data) { - var votes = $('li[data-pid="' + data.post.pid + '"] .votes'), - reputationElements = $('.reputation[data-uid="' + data.post.uid + '"]'); - - votes.html(data.post.votes).attr('data-votes', data.post.votes); - reputationElements.html(data.user.reputation).attr('data-reputation', data.user.reputation); - } - - function updateFavouriteCount(pid, value) { - $('li[data-pid="' + pid + '"] .favouriteCount').html(value).attr('data-favourites', value); - } - - function set_locked_state(locked, alert) { - translator.translate(' [[topic:thread_tools.' + (locked ? 'un': '') + 'lock]]', function(translated) { - $('.lock_thread').html(translated); - }); - - $('#post-container .post_reply').html(locked ? 'Locked ' : 'Reply '); - $('#post-container').find('.quote, .edit, .delete').toggleClass('none', locked); - $('.topic-main-buttons .post_reply').attr('disabled', locked).html(locked ? 'Locked ' : 'Reply'); - - if (alert) { - app.alertSuccess(locked ? '[[topic:topic_lock_success]]' : '[[topic:topic_unlock_success]]'); - } - - thread_state.locked = locked ? '1' : '0'; - } - - function set_delete_state(deleted) { - var threadEl = $('#post-container'); - - translator.translate(' [[topic:thread_tools.' + (deleted ? 'restore' : 'delete') + ']]', function(translated) { - $('.delete_thread span').html(translated); - }); - - threadEl.toggleClass('deleted', deleted); - thread_state.deleted = deleted ? '1' : '0'; - - if(deleted) { - translator.translate('[[topic:deleted_message]]', function(translated) { - $('
    ' + translated + '
    ').insertBefore(threadEl); - }); - } else { - $('#thread-deleted').remove(); - } - } - - function set_pinned_state(pinned, alert) { - translator.translate(' [[topic:thread_tools.' + (pinned ? 'unpin' : 'pin') + ']]', function(translated) { - $('.pin_thread').html(translated); - - if (alert) { - app.alertSuccess(pinned ? '[[topic:topic_pin_success]]' : '[[topic:topic_unpin_success]]'); - } - thread_state.pinned = pinned ? '1' : '0'; - }); - } - - function toggle_post_delete_state(pid) { - var postEl = $('#post-container li[data-pid="' + pid + '"]'); - - if (postEl.length) { - postEl.toggleClass('deleted'); - - toggle_post_tools(pid, postEl.hasClass('deleted')); - - updatePostCount(); - } - } - - function toggle_post_tools(pid, isDeleted) { - var postEl = $('#post-container li[data-pid="' + pid + '"]'); - - postEl.find('.quote, .favourite, .post_reply, .chat').toggleClass('none', isDeleted); - - translator.translate(isDeleted ? ' [[topic:restore]]' : ' [[topic:delete]]', function(translated) { - postEl.find('.delete').find('span').html(translated); - }); - } + socket.on('event:new_post', onNewPost); $(window).on('scroll', updateTopicTitle); $(window).trigger('action:topic.loaded'); }; + function showBottomPostBar() { + if($('#post-container .post-row').length > 1 || !$('#post-container li[data-index="0"]').length) { + $('.bottom-post-bar').removeClass('hide'); + } + } + + function onNewPost(data) { + var tid = ajaxify.variables.get('topic_id'); + if(data && data.posts && data.posts.length && data.posts[0].tid !== tid) { + return; + } + + if(config.usePagination) { + return onNewPostPagination(data); + } + + for (var i=0; i 0) { + el = $('#post-container .post-row').last(); + after = parseInt(el.attr('data-index'), 10) + 1; + } else { + el = $('#post-container .post-row').first(); + after = parseInt(el.attr('data-index'), 10); + after -= config.postsPerPage; + if(after < 0) { + after = 0; + } + } + + var offset = el.offset().top - $('#header-menu').offset().top + $('#header-menu').height(); + + loadMorePosts(ajaxify.variables.get('topic_id'), after, function() { + hidePostToolsForDeletedPosts(); + if(direction < 0 && el) { + Topic.scrollToPost(el.attr('data-pid'), false, 0, offset); + } + }); + } + }); + } else { + navigator.hide(); + + pagination.init(parseInt(ajaxify.variables.get('currentPage'), 10), parseInt(ajaxify.variables.get('pageCount'), 10)); + } + } + + function hidePostToolsForDeletedPosts() { + $('#post-container li.deleted').each(function() { + postTools.toggle($(this).attr('data-pid'), true); + }); + } + + function updateTopicTitle() { if($(window).scrollTop() > 50) { $('.header-topic-title').find('span').text(ajaxify.variables.get('topic_name')).show(); @@ -705,7 +353,7 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', if(err) { return app.alertError(err.message); } - toggle_mod_tools(html, privileges); + toggleModTools(html, privileges); }); } @@ -721,25 +369,15 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', utils.makeNumbersHumanReadable(html.find('.human-readable-number')); html.find('span.timeago').timeago(); html.find('.post-content img').addClass('img-responsive'); - updatePostCount(); + postTools.updatePostCount(); showBottomPostBar(); } - function toggle_mod_tools(postHtml, privileges) { + function toggleModTools(postHtml, privileges) { postHtml.find('.edit, .delete').toggleClass('none', !privileges.editable); postHtml.find('.move').toggleClass('none', !privileges.move); } - function updatePostCount() { - socket.emit('topics.postcount', ajaxify.variables.get('topic_id'), function(err, postcount) { - if(!err) { - Topic.postCount = postcount; - $('.topic-post-count').html(Topic.postCount); - navigator.setCount(Topic.postCount); - } - }); - } - function loadMorePosts(tid, after, callback) { var indicatorEl = $('.loading-indicator'); diff --git a/public/src/forum/topic/browsing.js b/public/src/forum/topic/browsing.js new file mode 100644 index 0000000000..812c60f6b9 --- /dev/null +++ b/public/src/forum/topic/browsing.js @@ -0,0 +1,123 @@ + + +'use strict'; + +/* globals define, app, translator, config, socket, ajaxify */ + +define(function() { + + var Browsing = {}; + + Browsing.onUpdateUsersInRoom = function(data) { + if(data && data.room.indexOf('topic') !== -1) { + var activeEl = $('.thread_active_users'); + + // remove users that are no longer here + activeEl.find('a').each(function(index, element) { + if(element) { + var uid = $(element).attr('data-uid'); + var absent = data.users.every(function(user) { + return parseInt(user.uid, 10) !== parseInt(uid, 10); + }); + + if (absent) { + $(element).remove(); + } + } + }); + + var i=0, icon; + // add self + for(i = 0; i 8) { + break; + } + } + + activeEl.find('a[data-uid] img').tooltip({ + placement: 'top' + }); + + var remainingUsers = data.users.length - 9; + remainingUsers = remainingUsers < 0 ? 0 : remainingUsers; + var anonymousCount = parseInt(data.anonymousCount, 10); + activeEl.find('.anonymous-box').remove(); + if(anonymousCount || remainingUsers) { + + var anonLink = $('
    '); + activeEl.append(anonLink); + + var title = ''; + if(remainingUsers && anonymousCount) { + title = '[[topic:more_users_and_guests, ' + remainingUsers + ', ' + anonymousCount + ']]'; + } else if(remainingUsers) { + title = '[[topic:more_users, ' + remainingUsers + ']]'; + } else { + title = '[[topic:more_guests, ' + anonymousCount + ']]'; + } + + translator.translate(title, function(translated) { + $('.anonymous-box').tooltip({ + placement: 'top', + title: translated + }); + }); + } + + getReplyingUsers(); + } + + app.populateOnlineUsers(); + }; + + Browsing.onUserOnline = function(err, data) { + app.populateOnlineUsers(); + + updateBrowsingUsers(data); + }; + + function updateBrowsingUsers(data) { + var activeEl = $('.thread_active_users'); + var user = activeEl.find('a[data-uid="'+ data.uid + '"]'); + if (user.length && !data.online) { + user.parent().remove(); + } else if(!user.length && data.online) { + user = createUserIcon(data.uid, data.picture, data.userslug, data.username); + activeEl.append(user); + activeEl.find('a[data-uid] img').tooltip({ + placement: 'top' + }); + } + } + + function createUserIcon(uid, picture, userslug, username) { + if(!$('.thread_active_users').find('[data-uid="' + uid + '"]').length) { + return $('
    '); + } + } + + + function getReplyingUsers() { + var activeEl = $('.thread_active_users'); + socket.emit('modules.composer.getUsersByTid', ajaxify.variables.get('topic_id'), function(err, uids) { + if (uids && uids.length) { + for(var x=0;x 0) { + ajaxify.go('topic/' + data.tid); + } + } + + function onPostEdited(data) { + var editedPostEl = $('#content_' + data.pid), + editedPostTitle = $('#topic_title_' + data.pid); + + if (editedPostTitle.length) { + editedPostTitle.fadeOut(250, function() { + editedPostTitle.html(data.title); + editedPostTitle.fadeIn(250); + }); + } + + editedPostEl.fadeOut(250, function() { + editedPostEl.html(data.content); + editedPostEl.find('img').addClass('img-responsive'); + editedPostEl.fadeIn(250); + }); + } + + function togglePostDeleteState(data) { + var postEl = $('#post-container li[data-pid="' + data.pid + '"]'); + + if (postEl.length) { + postEl.toggleClass('deleted'); + + postTools.toggle(data.pid, postEl.hasClass('deleted')); + + postTools.updatePostCount(); + } + } + + function togglePostFavourite(data) { + + var favBtn = $('li[data-pid="' + data.post.pid + '"] .favourite'); + if (favBtn.length) { + favBtn.addClass('btn-warning') + .attr('data-favourited', data.isFavourited); + + var icon = favBtn.find('i'); + var className = icon.attr('class'); + + if (data.isFavourited ? className.indexOf('-o') !== -1 : className.indexOf('-o') === -1) { + icon.attr('class', data.isFavourited ? className.replace('-o', '') : className + '-o'); + } + } + } + + function togglePostVote(data) { + var post = $('li[data-pid="' + data.post.pid + '"]'); + + post.find('.upvote').toggleClass('btn-primary upvoted', data.upvote); + post.find('.downvote').toggleClass('btn-primary downvoted', data.downvote); + } + + function toggleReply(data) { + $('.thread_active_users [data-uid="' + data.uid + '"]').toggleClass('replying', data.isReplying); + } + + return Events; + +}); \ No newline at end of file diff --git a/public/src/forum/topic/postTools.js b/public/src/forum/topic/postTools.js index 7b6452359b..347e7bd91e 100644 --- a/public/src/forum/topic/postTools.js +++ b/public/src/forum/topic/postTools.js @@ -2,7 +2,7 @@ /* globals define, app, translator, ajaxify, socket, bootbox */ -define(['composer', 'share'], function(composer, share) { +define(['composer', 'share', 'navigator'], function(composer, share, navigator) { var PostTools = {}, topicName; @@ -13,8 +13,42 @@ define(['composer', 'share'], function(composer, share) { addPostHandlers(tid, threadState); share.addShareHandlers(topicName); + + addFavouriteHandler(); }; + PostTools.toggle = function(pid, isDeleted) { + var postEl = $('#post-container li[data-pid="' + pid + '"]'); + + postEl.find('.quote, .favourite, .post_reply, .chat').toggleClass('none', isDeleted); + + translator.translate(isDeleted ? ' [[topic:restore]]' : ' [[topic:delete]]', function(translated) { + postEl.find('.delete').find('span').html(translated); + }); + }; + + PostTools.updatePostCount = function() { + socket.emit('topics.postcount', ajaxify.variables.get('topic_id'), function(err, postCount) { + if (!err) { + $('.topic-post-count').html(postCount); + navigator.setCount(postCount); + } + }); + }; + + function addFavouriteHandler() { + $('#post-container').on('mouseenter', '.favourite-tooltip', function(e) { + if (!$(this).data('users-loaded')) { + $(this).data('users-loaded', "true"); + var pid = $(this).parents('.post-row').attr('data-pid'); + var el = $(this).attr('title', "Loading..."); + socket.emit('posts.getFavouritedUsers', pid, function(err, usernames) { + el.attr('title', usernames).tooltip('show'); + }); + } + }); + } + function addPostHandlers(tid, threadState) { $('.topic').on('click', '.post_reply', function() { if (threadState.locked !== '1') { diff --git a/public/src/forum/topic/threadTools.js b/public/src/forum/topic/threadTools.js index 107d087bad..35dbf38a42 100644 --- a/public/src/forum/topic/threadTools.js +++ b/public/src/forum/topic/threadTools.js @@ -7,6 +7,19 @@ define(['forum/topic/fork', 'forum/topic/move'], function(fork, move) { var ThreadTools = {}; ThreadTools.init = function(tid, threadState) { + ThreadTools.threadState = threadState; + + if (threadState.locked === '1') { + ThreadTools.setLockedState({tid: tid, isLocked: true}); + } + + if (threadState.deleted === '1') { + ThreadTools.setDeleteState({tid: tid, isDelete: true}); + } + + if (threadState.pinned === '1') { + ThreadTools.setPinnedState({tid: tid, isPinned: true}); + } if (ajaxify.variables.get('expose_tools') === '1') { @@ -57,7 +70,7 @@ define(['forum/topic/fork', 'forum/topic/move'], function(fork, move) { } socket.emit('topics.followCheck', tid, function(err, state) { - setFollowState(state, false); + setFollowState(state); }); $('.posts').on('click', '.follow', function() { @@ -72,21 +85,63 @@ define(['forum/topic/fork', 'forum/topic/move'], function(fork, move) { }); } - setFollowState(state, true); + setFollowState(state); + + app.alertSuccess(state ? '[[topic:following_topic.message]]' : '[[topic:not_following_topic.message]]'); }); return false; }); - }; - function setFollowState(state, alert) { + ThreadTools.setLockedState = function(data) { + var threadEl = $('#post-container'); + if (parseInt(data.tid, 10) === parseInt(threadEl.attr('data-tid'), 10)) { + translator.translate(' [[topic:thread_tools.' + (data.isLocked ? 'un': '') + 'lock]]', function(translated) { + $('.lock_thread').html(translated); + }); - $('.posts .follow').toggleClass('btn-success', state).attr('title', state ? 'You are currently receiving updates to this topic' : 'Be notified of new replies in this topic'); + threadEl.find('.post_reply').html(data.isLocked ? 'Locked ' : 'Reply '); + threadEl.find('.quote, .edit, .delete').toggleClass('none', data.isLocked); + $('.topic-main-buttons .post_reply').attr('disabled', data.isLocked).html(data.isLocked ? 'Locked ' : 'Reply'); - if(alert) { - app.alertSuccess(state ? '[[topic:following_topic.message]]' : '[[topic:not_following_topic.message]]'); + ThreadTools.threadState.locked = data.isLocked ? '1' : '0'; } + }; + + ThreadTools.setDeleteState = function(data) { + var threadEl = $('#post-container'); + if (parseInt(data.tid, 10) === parseInt(threadEl.attr('data-tid'), 10)) { + translator.translate(' [[topic:thread_tools.' + (data.isDelete ? 'restore' : 'delete') + ']]', function(translated) { + $('.delete_thread span').html(translated); + }); + + threadEl.toggleClass('deleted', data.isDelete); + ThreadTools.threadState.deleted = data.isDelete ? '1' : '0'; + + if (data.isDelete) { + translator.translate('[[topic:deleted_message]]', function(translated) { + $('
    ' + translated + '
    ').insertBefore(threadEl); + }); + } else { + $('#thread-deleted').remove(); + } + } + }; + + ThreadTools.setPinnedState = function(data) { + var threadEl = $('#post-container'); + if (parseInt(data.tid, 10) === parseInt(threadEl.attr('data-tid'), 10)) { + translator.translate(' [[topic:thread_tools.' + (data.isPinned ? 'unpin' : 'pin') + ']]', function(translated) { + $('.pin_thread').html(translated); + + ThreadTools.threadState.pinned = data.isPinned ? '1' : '0'; + }); + } + } + + function setFollowState(state) { + $('.posts .follow').toggleClass('btn-success', state).attr('title', state ? 'You are currently receiving updates to this topic' : 'Be notified of new replies in this topic'); } diff --git a/public/src/forum/unread.js b/public/src/forum/unread.js index d7b31b7eec..a576a6ba23 100644 --- a/public/src/forum/unread.js +++ b/public/src/forum/unread.js @@ -6,6 +6,12 @@ define(['forum/recent', 'topicSelect'], function(recent, topicSelect) { var Unread = {}, loadingMoreTopics = false; + $(window).on('action:ajaxify.start', function(ev, data) { + if(data.url.indexOf('unread') !== 0) { + recent.removeListeners(); + } + }); + Unread.init = function() { app.enterRoom('recent_posts'); diff --git a/src/favourites.js b/src/favourites.js index b92d6ceea6..0398614b9f 100644 --- a/src/favourites.js +++ b/src/favourites.js @@ -48,7 +48,9 @@ var async = require('async'), user: { reputation: newreputation }, - post: postData + post: postData, + upvote: type === 'upvote' && !unvote, + downvote: type === 'downvote' && !unvote }); }); }); @@ -154,7 +156,7 @@ var async = require('async'), if (uid === 0) { return callback(new Error('[[error:not-logged-in]]')); } - + var isFavouriting = type === 'favourite'; posts.getPostFields(pid, ['pid', 'uid', 'timestamp'], function (err, postData) { if (err) { return callback(err); @@ -165,22 +167,22 @@ var async = require('async'), return callback(err); } - if (type === 'favourite' && hasFavourited) { + if (isFavouriting && hasFavourited) { return callback(new Error('[[error:already-favourited]]')); } - if (type === 'unfavourite' && !hasFavourited) { + if (!isFavouriting && !hasFavourited) { return callback(new Error('[[error:alrady-unfavourited]]')); } - if (type === 'favourite') { + if (isFavouriting) { db.sortedSetAdd('uid:' + uid + ':favourites', postData.timestamp, pid); } else { db.sortedSetRemove('uid:' + uid + ':favourites', pid); } - db[type === 'favourite' ? 'setAdd' : 'setRemove']('pid:' + pid + ':users_favourited', uid, function(err) { + db[isFavouriting ? 'setAdd' : 'setRemove']('pid:' + pid + ':users_favourited', uid, function(err) { if (err) { return callback(err); } @@ -192,7 +194,8 @@ var async = require('async'), postData.reputation = count; posts.setPostField(pid, 'reputation', count, function(err) { callback(err, { - post: postData + post: postData, + isFavourited: isFavouriting }); }); }); diff --git a/src/socket.io/index.js b/src/socket.io/index.js index b9abe1de6c..11c09936e9 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -286,7 +286,7 @@ function updateRoomBrowsingText(roomName) { return user.status !== 'offline'; }); - io.sockets.in(roomName).emit('get_users_in_room', { + io.sockets.in(roomName).emit('event:update_users_in_room', { users: users, anonymousCount: anonymousCount, room: roomName diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index bc243855ab..cf27156e76 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -29,7 +29,7 @@ var posts = require('../posts'), var stopTracking = function(replyObj) { if (isLast(replyObj.uid, replyObj.tid)) { - server.in('topic_' + replyObj.tid).emit('event:topic.replyStop', replyObj.uid); + server.in('topic_' + replyObj.tid).emit('event:topic.toggleReply', {uid: replyObj.uid, isReplying: false}); } clearInterval(replyObj.timer); @@ -106,7 +106,7 @@ SocketModules.composer.renderHelp = function(socket, data, callback) { SocketModules.composer.register = function(socket, data) { var now = Date.now(); - server.in('topic_' + data.tid).emit('event:topic.replyStart', data.uid); + server.in('topic_' + data.tid).emit('event:topic.toggleReply', {uid: data.uid, isReplying: true}); data.socket = socket; data.lastPing = now; diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 7398ea28cd..47653c7760 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -77,7 +77,7 @@ function favouriteCommand(command, eventName, socket, data, callback) { return callback(err); } - socket.emit('posts.' + command, data.pid); + socket.emit('posts.' + command, result); if(data.room_id && result && eventName) { websockets.in(data.room_id).emit('event:' + eventName, result); From aea8d502005b79cab31aaf5c20e07d5296929d8b Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 3 May 2014 20:59:38 -0400 Subject: [PATCH 04/88] removed console.log --- public/src/forum/recent.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/src/forum/recent.js b/public/src/forum/recent.js index e73e3376c5..84f3f26628 100644 --- a/public/src/forum/recent.js +++ b/public/src/forum/recent.js @@ -77,7 +77,6 @@ define(function() { } Recent.removeListeners = function() { - console.log('removing'); socket.removeListener('event:new_topic', onNewTopic); socket.removeListener('event:new_post', onNewPost); }; From c23df60e1b9cf09262e81e0448217075db973aa5 Mon Sep 17 00:00:00 2001 From: FrissDieGurke Date: Sun, 4 May 2014 12:34:22 +0200 Subject: [PATCH 05/88] removed unnecessary method + doc within Settings Framework --- public/src/modules/settings.js | 93 ---------------------------------- src/settings.js | 18 +------ 2 files changed, 1 insertion(+), 110 deletions(-) diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index 177a685137..af330fc598 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -13,79 +13,6 @@ define(function () { waitingJobs = 0, helper; - /* - * Attributes of HTML-tags that get used by default plugins: - * + data-key: the key to save/load the value within configuration-object - * + data-type: highest priority type-definition to determine what kind of element it is or which plugin to hook - * + type: normal priority type-definition - * + data-empty: if 'false' or '0' then values that are assumed as empty turn into null. data-empty of arrays affect - * their child-elements - * + data-trim: if not 'false' or '0' then values will get trimmed as defined by the elements type - * + data-split: if set and the element doesn't belong to any plugin, it's value will get split and joined by its - * value into the input-field - * array-elements: - * + data-split: separator (HTML allowed) between the elements, defaults to ', ' - * + data-new: value to insert into new created elements - * + data-attributes: an object to set the attributes of the child HTML-elements. tagName as special key will set - * the tag-name of the child HTML-elements - * key-fields: - * + data-trim: if 'false' or '0' then the value will get saved as string else as object providing following - * properties: ctrl, alt, shift, meta, code, char - * + data-split: separator between different modifiers and the key-code of the value that gets saved - * (only takes effect if trimming) - * + data-short: if not 'false' or '0' then modifier-keys get saved as first uppercase character - * (only takes effect if trimming) - * select: - * + data-options: an array of {"text":"Displayed Text","value":"some_value"}-like objects - * - * The name of the HTML-tag is lowest priority type-definition - * - * Examples-HTML: - No! -
    - Yes! -
    - An array of checkboxes that are selected by default: -

    - A simple input-field of any common type: -
    - A simple textarea: -
    - Array of textareas: -

    - 2D-Array of numbers that persist even when empty (but not empty rows): -

    - Same with persisting empty rows, but not empty numbers, if no row is given null will get saved: -

    - Array of Key-shortcuts (new: Ctrl+Shift+7): -

    - Array of numbers (new: 42, step: 21): -

    - Select with dynamic options: -
    - Select that loads faster: - - * - * Matching configuration: - { - cfg1: false, - cfg2: true, - cfg3: [false, false, true], - cfg4: 'hello world', - cfg5: 'some\nlong\ntext', - cfg6: ['some\nlong\ntexts', 'and another one'], - cfg7: [[]], - cfg8: [[]], - cfg9: [], - cfg10: [], - cfg11: 3, - cfg12: 2 - } - */ - /** Returns the hook of given name that matches the given type or element. @param type The type of the element to get the matching hook for, or the element itself. @@ -404,26 +331,6 @@ define(function () { }, /** Registers a new plugin and calls its use-hook. - A plugin is an object containing a types-property to define its default bindings. - A plugin may also provide the following properties of type function with [return-value] (parameters): - use [void] - gets called when the Settings initializes the plugin. - init [void] (element) - gets called on page-load and every time after the create-hook. - ; element: The element to initialize. - create [JQuery-Object] (type, tagName, data) - gets called when a new HTML-instance needs to get created. - ; type: A string that identifies the plugin itself within this Settings-instance if set as data-type. - ; tagName: The tag-name that gets requested. - ; data: Additional data, plugin-dependent meaning. - destruct [void] (element) - gets called after a HTML-instance got removed from DOM - ; element: The element that got removed. - set [void] (element, value, trim) - gets called when the value of the element should be set to the given value. - ; element: The element to set its value. - ; value: The value to set. - ; trim: Whether the value is considered as trimmed. - get [value] (element, trim, empty) - gets called when the value of the given instance is needed. - ; element: The element to get its value. - ; trim: Whether the result should be trimmed. - ; empty: Whether considered as empty values should get saved too. - All passed elements are JQuery-Objects. @param service The plugin to register. @param types The types to bind the plugin to. */ diff --git a/src/settings.js b/src/settings.js index a8d8594658..b18635d4ff 100644 --- a/src/settings.js +++ b/src/settings.js @@ -27,7 +27,7 @@ function trim(obj1, obj2) { function mergeSettings(cfg, defCfg) { if (typeof cfg._settings !== typeof defCfg || typeof defCfg !== 'object') { - return cfg._settings = defCfg; + cfg._settings = defCfg; } else { expandObjBy(cfg._settings, defCfg); trim(cfg._settings, defCfg); @@ -103,22 +103,6 @@ Settings.prototype.persist = function (callback) { return this; }; -/** - Persists the settings if no settings are saved. - @param callback Gets called when done. - */ -Settings.prototype.persistOnEmpty = function (callback) { - var _this = this; - meta.settings.get(this.hash, function (err, settings) { - if (!settings._settings) { - _this.persist(callback); - } else if (typeof callback === 'function') { - callback.call(_this); - } - }); - return this; -}; - /** Returns the setting of given key or default value if not set. @param key The key of the setting to return. From cbef92bb629ef19ae14d7daaa576b7a63f8695c0 Mon Sep 17 00:00:00 2001 From: FrissDieGurke Date: Sun, 4 May 2014 12:37:49 +0200 Subject: [PATCH 06/88] Added settings-framework documentation --- docs/index.rst | 1 + docs/plugins/settings.rst | 306 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+) create mode 100644 docs/plugins/settings.rst diff --git a/docs/index.rst b/docs/index.rst index d403812123..c48eb05adc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -73,6 +73,7 @@ Plugin System plugins/create plugins/hooks + plugins/settings Widgets System -------------- diff --git a/docs/plugins/settings.rst b/docs/plugins/settings.rst new file mode 100644 index 0000000000..ad1954d853 --- /dev/null +++ b/docs/plugins/settings.rst @@ -0,0 +1,306 @@ +Settings Framework +========================== + +If you want to make your plugin customizable you may use the Settings Framework NodeBB offers. + +Server-Side Access +------------------ + +First you need some default settings, just create a new object for this: + +.. code:: javascript + + var defaultSettings = { + booleans: { + someBool: true, + moreBools: [false, false, true] + }, + strings: { + someString: 'hello world', + multiLineString: 'some\nlong\ntext', + arrayOfStrings: ['some\nlong\ntexts', 'and another one'] + }, + numbers: { + multiArrayDimensions: [[42,42],[21,21]], + multiArrayDimensions2: [[42,42],[]], + justSomeNumbers: [], + oneNumber: 3, + anotherNumber: 2 + }, + someKeys: ['C+S+#13'] // Ctrl+Shift+Enter + }; + +Now you can use the server-side settings-module to access the saved settings like this: + +.. code:: javascript + + var Settings = module.parent.require('./settings'); + var mySettings = new Settings('myPlugin', '0.1', defaultSettings, function() { + // the settings are ready and can accessed. + console.log(mySettings === this); // true + console.log(this.get('someString') === mySettings.get().someString); // true + }); + +The second parameter should change at least every time the structure of default settings changes. Because of this it's +recommended to use your plugins version. + +To use the settings client-side you need to create a WebSocket that delivers the result of ``mySettings.get()``. + +The mySettings-object will cache the settings, so be sure to use methods like ``mySettings.sync(callback)`` when the +settings got changed from somewhere else and ``mySettings.persist(callback)`` when you finished +``mySettings.set(key, value)`` calls. + +You need to create a socket-listener like following to allow the admin to initiate a synchronization with the settings +stored within database: + +.. code:: javascript + + var SocketAdmin = module.parent.require('./socket.io/admin'); + SocketAdmin.settings.syncMyPlugin = function() { + mySettings.sync(); + }; + +If you want to add a reset-functionality you need to create another socket-listener: + +.. code:: javascript + + SocketAdmin.settings.getMyPluginDefaults = function (socket, data, callback) { + callback(null, mySettings.createDefaultWrapper()); + }; + +The methods of the ``mySettings`` object you probably want to use: + ++ ``constructor()`` ++ ``sync([callback])`` + Reloads the settings from database, overrides local changes. ++ ``persist([callback])`` + Saves the local changes within database. ++ ``get([key])`` + Returns the setting(s) identified by given key. If no key is provided the whole settings-object gets returned. If no + such setting is saved the default value gets returned. ++ ``set([key, ]value)`` + Sets the setting of given key to given value. Remember that it's just a local change, you need to call ``persist`` + in order to save the changes. ++ ``reset([callback])`` + Persists the default settings. ++ ``getWrapper()`` + Returns the local object as it would get saved within database. ++ ``createWrapper(version, settings)`` + Creates an object like it would get saved within database containing given information and settings. ++ ``createDefaultWrapper()`` + Creates an object like it would get saved within database containing the default settings. + +Client-Side Access +------------------ + +The next step is making the settings available to the admin. + +You need to use the :doc:`hooks ` ``filter:admin.header.build`` (to display a link to your page within ACP) and +``action:app.load`` (to create the needed route). + +Within your page you can access the client-side Settings API via + +.. code:: javascript + + require(['settings'], function (settings) { + var wrapper = $('#my_form_id'); + // [1] + settings.sync('myPlugin', wrapper); + // [2] + }); + +To make a button with the id ``save`` actually save the settings you can add the following at ``[2]``: + +.. code:: javascript + + $('#save').click(function(event) { + event.preventDefault(); + settings.persist('myPlugin', wrapper, function(){ + socket.emit('admin.settings.syncMyPlugin'); + }); + }); + +As said before the server-side settings-object caches the settings, so we emit a WebSocket to notify the server to +synchronize the settings after they got persisted. + +To use a reset-button you can add the following at ``[2]``: + +.. code:: javascript + + $('#reset').click(function(event) { + event.preventDefault(); + socket.emit('admin.settings.getMyPluginDefaults', null, function (err, data) { + settings.set('myPlugin', data, wrapper, function(){ + socket.emit('admin.settings.syncMyPlugin'); + }); + }); + }); + +There you go, the basic structure is done. +Now you need to add the form-fields. + +Each field needs an attribute ``data-key`` to reference its position within the settings. +The Framework does support any fields whose jQuery-object provides the value via the ``val()`` method. + +The plugin to use for a field gets determined by its ``data-type``, ``type`` or tag-name in this order. + +Additionally the following plugins are registered by default: + * array (types: div, array) + An Array of any other fields. + Uses the object within ``data-attributes`` to define the array-elements. + Uses ``data-new`` to define the value of new created elements. + * key (types: key) + A field to input keyboard-combinations. + * checkbox, select, textarea + Handle appropriate fields. + +A full list of all attributes that may influence the behavior of the default Framework: + + * data-key: the key to save/load the value within configuration-object + * data-type: highest priority type-definition to determine what kind of element it is or which plugin to associate + * type: normal priority type-definition + * data-empty: if ``false`` or ``0`` then values that are assumed as empty turn into null. data-empty of arrays affect their child-elements + * data-trim: if not ``false`` or ``0`` then values will get trimmed as defined by the elements type + * data-split: if set and the element doesn't belong to any plugin, it's value will get split and joined by its value into the field + * array-elements: + + data-split: separator (HTML allowed) between the elements, defaults to ``', '`` + + data-new: value to insert into new created elements + + data-attributes: an object to set the attributes of the child HTML-elements. tagName as special key will set the tag-name of the child HTML-elements + * key-fields: + + data-trim: if ``false`` or ``0`` then the value will get saved as string else as object providing following properties: ``ctrl``, ``alt``, ``shift``, ``meta``, ``code``, ``char`` + + data-split: separator between different modifiers and the key-code of the value that gets saved (only takes effect if trimming) + + data-short: if not ``false`` or ``0`` then modifier-keys get saved as first uppercase character (only takes effect if trimming) + * select: + + data-options: an array of objects containing ``text`` and ``value`` attributes. + +The methods of the ``settings`` module: + ++ ``registerPlugin(plugin[, types])`` + Registers the given plugin and associates it to the given types if any, otherwise the plugins default types will get + used. ++ ``get()`` + Returns the saved object. ++ ``set(hash, settings[, wrapper[, callback[, notify]]])`` + Refills the fields with given settings and persists them. + ``hash`` Identifies your plugins settings. + ``settings`` The object to save in database (settings-wrapper if you use server-side Settings Framework). + ``wrapper`` (default: 'form') The DOM-Element that contains all fields to fill. + ``callback`` (default: null) Gets called when done. + ``notify`` (default: true) Whether to display saved- and fail-notifications. ++ ``sync(hash[, wrapper[, callback]])`` + Resets the settings to saved ones and refills the fields. ++ ``persist(hash[, wrapper[, callback[, notify]]])`` + Reads the settings from given wrapper (default: 'form') and saves them within database. + +For Settings 2.0 support the methods ``load`` and ``save`` are still available but not recommended. + +Client-Side Example Template +------------------ + +An example template-file to use the same settings we already used server-side: + +.. code:: html + +

    My Plugin

    +
    + +
    +
    +

    +

    Settings

    + A boolean:
    + An array of checkboxes that are selected by default: +

    + + A simple input-field of any common type:
    + A simple textarea:
    + Array of textareas: +

    + + 2D-Array of numbers that persist even when empty (but not empty rows): +

    + Same with persisting empty rows, but not empty numbers, if no row is given null will get saved: +

    + Array of numbers (new: 42, step: 21): +

    + Select with dynamic options: +
    + Select that loads faster: + + + Array of Key-shortcuts (new: Ctrl+Shift+7): +

    +

    +
    + + +
    + + + +Custom Settings-Elements +------------------ + +If you want do define your own element-structure you can create a **plugin** for the Settings Framework. + +This allows you to use a whole object like a single field which - besides comfort in using multiple similar objects - +allows you to use them within arrays. + +A plugin is basically an object that contains at least an attribute ``types`` that contains an array of strings that +associate DOM-elements with your plugin. + +You can add a plugin at ``[1]`` using the method ``settings.registerPlugin``. + +To customize the way the associated fields get interpreted you may add the following methods to your plugin-object: + +All given elements are instances of JQuery. + +All methods get called within Settings-scope. + ++ ``use()`` + Gets called when the plugin gets registered. ++ ``[HTML-Element|JQuery] create(type, tagName, data)`` + Gets called when a new element should get created (eg. by expansion of an array). ++ ``destruct(element)`` + Gets called when the given element got removed from DOM (eg. by array-splice). ++ ``init(element)`` + Gets called when an element should get initialized (eg. after creation). ++ ``[value] get(element, trim, empty)`` + Gets called whenever the value of the given element is requested. + ``trim`` Whether the result should get trimmed. + ``empty`` Whether considered as empty values should get saved too. ++ ``set(element, value, trim)`` + Gets called whenever the value of the given element should be set to given one. + ``trim`` Whether the value is assumed as trimmed. + +For further impression take a look at the +`default plugins `_. + +You should also take a look at the helper-functions within +`Settings `_ in order to create +your own plugins. There are a few methods that take response to call the methods of other plugins when fittingly. \ No newline at end of file From c4606e7009f036ad9fe268e889d09d5801616ec9 Mon Sep 17 00:00:00 2001 From: FrissDieGurke Date: Sun, 4 May 2014 13:08:20 +0200 Subject: [PATCH 07/88] minified settings-framework wrapper-length --- public/src/modules/settings.js | 10 ++++----- src/settings.js | 37 ++++++++++++++++------------------ 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index af330fc598..fa9ac0ac3d 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -271,9 +271,9 @@ define(function () { @param callback The callback to call when done. */ persistSettings: function (hash, settings, notify, callback) { - if (settings != null && settings._settings != null && typeof settings._settings !== 'string') { + if (settings != null && settings._ != null && typeof settings._ !== 'string') { settings = helper.deepClone(settings); - settings._settings = JSON.stringify(settings._settings); + settings._ = JSON.stringify(settings._); } socket.emit('admin.settings.set', { hash: hash, @@ -307,7 +307,7 @@ define(function () { */ use: function (settings) { try { - settings._settings = JSON.parse(settings._settings); + settings._ = JSON.parse(settings._); } catch (_error) {} Settings.cfg = settings; } @@ -324,8 +324,8 @@ define(function () { @returns Object The settings. */ get: function () { - if (Settings.cfg != null && Settings.cfg._settings !== void 0) { - return Settings.cfg._settings; + if (Settings.cfg != null && Settings.cfg._ !== void 0) { + return Settings.cfg._; } return Settings.cfg; }, diff --git a/src/settings.js b/src/settings.js index b18635d4ff..2286f26b1d 100644 --- a/src/settings.js +++ b/src/settings.js @@ -26,16 +26,16 @@ function trim(obj1, obj2) { } function mergeSettings(cfg, defCfg) { - if (typeof cfg._settings !== typeof defCfg || typeof defCfg !== 'object') { - cfg._settings = defCfg; + if (typeof cfg._ !== typeof defCfg || typeof defCfg !== 'object') { + cfg._ = defCfg; } else { - expandObjBy(cfg._settings, defCfg); - trim(cfg._settings, defCfg); + expandObjBy(cfg._, defCfg); + trim(cfg._, defCfg); } } /** - A class to manage Objects saved in {@link meta.settings} within property "_settings". + A class to manage Objects saved in {@link meta.settings} within property "_". Constructor, synchronizes the settings and repairs them if version differs. @param hash The hash to use for {@link meta.settings}. @param version The version of the settings, used to determine whether the saved settings may be corrupt. @@ -71,8 +71,8 @@ Settings.prototype.sync = function (callback) { var _this = this; meta.settings.get(this.hash, function (err, settings) { try { - if (settings._settings) { - settings._settings = JSON.parse(settings._settings); + if (settings._) { + settings._ = JSON.parse(settings._); } } catch (_error) {} _this.cfg = settings; @@ -87,15 +87,12 @@ Settings.prototype.sync = function (callback) { @param callback Gets called when done. */ Settings.prototype.persist = function (callback) { - var conf = this.cfg._settings, + var conf = this.cfg._, _this = this; if (typeof conf === 'object') { conf = JSON.stringify(conf); } - meta.settings.set(this.hash, { - _settings: conf, - version: this.cfg.version - }, function () { + meta.settings.set(this.hash, this.createWrapper(this.cfg.v, conf), function () { if (typeof callback === 'function') { callback.apply(_this, arguments || []); } @@ -110,7 +107,7 @@ Settings.prototype.persist = function (callback) { @returns Object The setting to be used. */ Settings.prototype.get = function (key, def) { - var obj = this.cfg._settings, + var obj = this.cfg._, parts = (key || '').split('.'), part; for (var i = 0; i < parts.length; i++) { @@ -148,8 +145,8 @@ Settings.prototype.getWrapper = function () { */ Settings.prototype.createWrapper = function (version, settings) { return { - version: version, - _settings: settings + v: version, + _: settings }; }; @@ -168,11 +165,11 @@ Settings.prototype.createDefaultWrapper = function () { */ Settings.prototype.set = function (key, val) { var part, obj, parts; - this.cfg.version = this.version; + this.cfg.v = this.version; if (val == null || !key) { - this.cfg._settings = val || key; + this.cfg._ = val || key; } else { - obj = this.cfg._settings; + obj = this.cfg._; parts = key.split('.'); for (var i = 0, _len = parts.length - 1; i < _len; i++) { if (part = parts[i]) { @@ -202,13 +199,13 @@ Settings.prototype.reset = function (callback) { @param force Whether to update and persist the settings even if the versions ara equal. */ Settings.prototype.checkStructure = function (callback, force) { - if (!force && this.cfg.version === this.version) { + if (!force && this.cfg.v === this.version) { if (typeof callback === 'function') { callback(); } } else { mergeSettings(this.cfg, this.defCfg); - this.cfg.version = this.version; + this.cfg.v = this.version; this.persist(callback); } return this; From 6f40393b993491b8b94f6e49e58535b77c24ab5e Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 4 May 2014 14:33:12 -0400 Subject: [PATCH 08/88] added err check --- src/topics.js | 4 ++++ src/user/create.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/topics.js b/src/topics.js index 43dd9dadf2..63e2da86a7 100644 --- a/src/topics.js +++ b/src/topics.js @@ -63,6 +63,10 @@ var async = require('async'), } user.getNameSlugPicture(topic.uid, function(err, userData) { + if (err) { + return callback(err); + } + topic.user = userData; callback(err, topic); }); diff --git a/src/user/create.js b/src/user/create.js index 37cff32d72..dda4f1743d 100644 --- a/src/user/create.js +++ b/src/user/create.js @@ -126,10 +126,10 @@ module.exports = function(User) { }; db.setObject('user:' + uid, userData, function(err) { - if(err) { return callback(err); } + db.setObjectField('username:uid', userData.username, uid); db.setObjectField('userslug:uid', userData.userslug, uid); From ac9bd0859f2bc1dfa7229d7820ccc2997bf222f2 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 4 May 2014 16:46:09 -0400 Subject: [PATCH 09/88] fixed #1477 --- loader.js | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/loader.js b/loader.js index 749d3e619a..afce4daada 100644 --- a/loader.js +++ b/loader.js @@ -3,16 +3,10 @@ var nconf = require('nconf'), fs = require('fs'), pidFilePath = __dirname + '/pidfile', + output = fs.openSync(__dirname + '/logs/output.log', 'a'), start = function() { var fork = require('child_process').fork, - // output = fs.openSync(__dirname + '/logs/output.log', 'a'), - output = fs.createWriteStream(__dirname + '/logs/output.log', { - flags: 'a', - encoding: 'utf-8' - }), nbb_start = function() { - var silent = nconf.get('daemon') !== false; - if (timesStarted > 3) { console.log('\n[loader] Experienced three start attempts in 10 seconds, most likely an error on startup. Halting.'); return nbb_stop(); @@ -27,29 +21,13 @@ var nconf = require('nconf'), nbb = fork('./app', process.argv.slice(2), { env: { 'NODE_ENV': process.env.NODE_ENV - }, - silent: silent + } }); - - if (silent) { - nbb.stdout.pipe(output); - nbb.stderr.pipe(output); - } - nbb.on('message', function(message) { if (message && typeof message === 'object' && message.action) { if (message.action === 'restart') { nbb_restart(); - } else if (message.action === 'ready' && silent) { - // Output bind_address - process.stdout.write('\nNodeBB listening on ' + message.bind_address + '\n\n'); - - // Daemonize and record new pid - require('daemon')({ - stdout: output - }); - fs.writeFile(__dirname + '/pidfile', process.pid); } } }); @@ -105,13 +83,18 @@ if (nconf.get('daemon') !== false) { try { var pid = fs.readFileSync(pidFilePath, { encoding: 'utf-8' }); process.kill(pid, 0); - console.log('\n Error: Another NodeBB is already running!'); process.exit(); } catch (e) { fs.unlinkSync(pidFilePath); } } + // Daemonize and record new pid + require('daemon')({ + stdout: output + }); + fs.writeFile(__dirname + '/pidfile', process.pid); + start(); } else { start(); From 8afcf44732825e9069ce7c32e037984bda90e910 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 4 May 2014 17:26:56 -0400 Subject: [PATCH 10/88] gravatars will be generated on demand changing the setting in ACP will affect all default gravatars now. --- src/posts.js | 2 +- src/routes/authentication.js | 3 +- src/topics.js | 9 ++-- src/user.js | 97 +++++++++++++++++++++++------------- src/user/profile.js | 2 +- 5 files changed, 71 insertions(+), 42 deletions(-) diff --git a/src/posts.js b/src/posts.js index 8a90b0d9d8..5236ce1118 100644 --- a/src/posts.js +++ b/src/posts.js @@ -283,7 +283,7 @@ var db = require('./database'), async.parallel({ user: function(next) { - user.getNameSlugPicture(post.uid, next); + user.getUserFields(post.uid, ['username', 'userslug', 'picture'], next); }, topicCategory: function(next) { topics.getTopicFields(post.tid, ['title', 'cid', 'slug', 'deleted'], function(err, topicData) { diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 59896ca2b3..e557c49e83 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -10,6 +10,7 @@ meta = require('./../meta'), user = require('./../user'), plugins = require('./../plugins'), + db = require('../database'), utils = require('./../../public/src/utils'), login_strategies = []; @@ -174,7 +175,7 @@ return next(null, false, '[[error:no-user]]'); } - user.getUserFields(uid, ['password', 'banned'], function(err, userData) { + db.getObjectFields('user:' + uid, ['password', 'banned'], function(err, userData) { if (err) { return next(err); } diff --git a/src/topics.js b/src/topics.js index 63e2da86a7..37f5062df6 100644 --- a/src/topics.js +++ b/src/topics.js @@ -62,13 +62,13 @@ var async = require('async'), return callback(err || new Error('[[error:no-topic]]')); } - user.getNameSlugPicture(topic.uid, function(err, userData) { + user.getUserFields(topic.uid, ['username', 'userslug', 'picture'], function(err, userData) { if (err) { return callback(err); } topic.user = userData; - callback(err, topic); + callback(null, topic); }); }); }; @@ -211,8 +211,7 @@ var async = require('async'), if (userCache[topicData.uid]) { return next(null, userCache[topicData.uid]); } - - user.getNameSlugPicture(topicData.uid, next); + user.getUserFields(topicData.uid, ['username', 'userslug', 'picture'], next); } }, function(err, topicInfo) { if(err) { @@ -325,7 +324,7 @@ var async = require('async'), return callback(new Error('[[error:no-teaser]]')); } - user.getNameSlugPicture(postData.uid, function(err, userData) { + user.getUserFields(postData.uid, ['username', 'userslug', 'picture'], function(err, userData) { if (err) { return callback(err); } diff --git a/src/user.js b/src/user.js index a0eb7ed1c8..5d63582235 100644 --- a/src/user.js +++ b/src/user.js @@ -33,14 +33,25 @@ var bcrypt = require('bcryptjs'), require('./user/jobs')(User); User.getUserField = function(uid, field, callback) { - db.getObjectField('user:' + uid, field, callback); + User.getUserFields(uid, [field], function(err, user) { + callback(err, user ? user[field] : null); + }); }; User.getUserFields = function(uid, fields, callback) { - db.getObjectFields('user:' + uid, fields, callback); + User.getMultipleUserFields([uid], fields, function(err, users) { + callback(err, users ? users[0] : null); + }); }; User.getMultipleUserFields = function(uids, fields, callback) { + var fieldsToRemove = []; + function addField(field) { + if (fields.indexOf(field) === -1) { + fields.push(field); + fieldsToRemove.push(field); + } + } if (!Array.isArray(uids) || !uids.length) { return callback(null, []); @@ -50,7 +61,21 @@ var bcrypt = require('bcryptjs'), return 'user:' + uid; }); - db.getObjectsFields(keys, fields, callback); + addField('uid'); + + if (fields.indexOf('picture') !== -1) { + addField('email'); + addField('gravatarpicture'); + addField('uploadedpicture'); + } + + db.getObjectsFields(keys, fields, function(err, users) { + if (err) { + return callback(err); + } + + callback(null, modifyUserData(users, fieldsToRemove)); + }); }; User.getUserData = function(uid, callback) { @@ -74,25 +99,43 @@ var bcrypt = require('bcryptjs'), return callback(err); } - users.forEach(function(user) { - if (user) { - if (user.password) { - user.password = null; - user.hasPassword = true; - } else { - user.hasPassword = false; - } - - if (user.picture === user.uploadedpicture) { - user.picture = nconf.get('relative_path') + user.picture; - } - } - }); - - callback(null, users); + callback(null, modifyUserData(users, [])); }); }; + function modifyUserData(users, fieldsToRemove) { + users.forEach(function(user) { + if (!user) { + return; + } + + user.hasPassword = !!user.password; + if (user.password) { + user.password = null; + } + + if (parseInt(user.uid, 10) === 0) { + user.username = '[[global:guest]]'; + user.userslug = ''; + } + + if (user.picture) { + if (user.picture === user.uploadedpicture) { + user.picture = nconf.get('relative_path') + user.picture; + } else { + user.picture = User.createGravatarURLFromEmail(user.email); + } + } else { + user.picture = User.createGravatarURLFromEmail(''); + } + + for(var i=0; i Date: Mon, 5 May 2014 09:33:47 -0400 Subject: [PATCH 11/88] cleanup toggleFollow --- src/threadTools.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/threadTools.js b/src/threadTools.js index 0ffbea46d4..4ab1a165f4 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -210,17 +210,13 @@ var winston = require('winston'), ThreadTools.toggleFollow = function(tid, uid, callback) { topics.isFollowing(tid, uid, function(err, following) { - if(err) { + if (err) { return callback(err); } - db[following ? 'setRemove' : 'setAdd']('tid:' + tid + ':followers', uid, function(err, success) { - if (callback) { - if(err) { - return callback(err); - } - - callback(null, !following); + db[following ? 'setRemove' : 'setAdd']('tid:' + tid + ':followers', uid, function(err) { + if (typeof callback === 'function') { + callback(err, !following); } }); }); From 3934f2ec88f47ea01b86c20022ad61b8f37fbf65 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 5 May 2014 12:15:17 -0400 Subject: [PATCH 12/88] collapsible blockquotes, closes #1359 --- public/src/forum/topic.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index de564f00cb..cf2277a13e 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -47,6 +47,8 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', enableInfiniteLoading(); + addBlockquoteEllipses($('.topic .post-content > blockquote')); + var bookmark = localStorage.getItem('topic:' + tid + ':bookmark'); if (window.location.hash) { Topic.scrollToPost(window.location.hash.substr(1), true); @@ -101,6 +103,19 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', createNewPosts(data); } + function addBlockquoteEllipses(blockquotes) { + blockquotes.each(function() { + var $this = $(this); + if ($this.find(':hidden').length) { + $this.append(''); + } + }); + + $('blockquote .toggle').on('click', function() { + $(this).parent('blockquote').toggleClass('uncollapsed'); + }); + } + function enableInfiniteLoading() { if(!config.usePagination) { @@ -291,8 +306,12 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', var firstPid = parseInt(data.posts[0].pid, 10); $('#post-container li[data-pid]').each(function() { - if(firstPid > parseInt($(this).attr('data-pid'), 10)) { - after = $(this); + var $this = $(this); + + addBlockquoteEllipses($this.find('.post-content > blockquote')); + + if(firstPid > parseInt($this.attr('data-pid'), 10)) { + after = $this; if(after.next().length && after.next().hasClass('post-bar')) { after = after.next(); } From a51b357e671e9ce21aea83e79e1ae15c5a9ed662 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 5 May 2014 12:18:53 -0400 Subject: [PATCH 13/88] removed deprecated categories.background property --- src/categories.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/categories.js b/src/categories.js index 713ce64220..0b0e2dbe76 100644 --- a/src/categories.js +++ b/src/categories.js @@ -37,7 +37,6 @@ var db = require('./database'), description: data.description, icon: data.icon, bgColor: data.bgColor, - background: data.bgColor, color: data.color, slug: slug, topic_count: 0, From 38a3ab6365bb0a6bb9207ed214a5ecdfe39935fa Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 5 May 2014 12:59:27 -0400 Subject: [PATCH 14/88] fixes routes for https://github.com/designcreateplay/NodeBB/issues/1485 --- src/controllers/accounts.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 59ae4899f2..60bba47853 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -167,7 +167,7 @@ accountsController.getAccount = function(req, res, next) { postTools.parse(userData.signature, function (err, signature) { userData.signature = signature; - res.render('account', userData); + res.render('account/profile', userData); }); }); }); @@ -268,7 +268,7 @@ accountsController.getPosts = function(req, res, next) { userData.posts = userPosts.posts; userData.nextStart = userPosts.nextStart; - res.render('accountposts', userData); + res.render('account/posts', userData); }); }); }; @@ -296,7 +296,7 @@ accountsController.getTopics = function(req, res, next) { userData.topics = userTopics.topics; userData.nextStart = userTopics.nextStart; - res.render('accounttopics', userData); + res.render('account/topics', userData); }); }); }; @@ -319,7 +319,7 @@ accountsController.accountEdit = function(req, res, next) { return next(err); } - res.render('accountedit', userData); + res.render('account/edit', userData); }); }; @@ -371,7 +371,7 @@ accountsController.accountSettings = function(req, res, next) { languages: results.languages }; - res.render('accountsettings', results); + res.render('account/settings', results); }); }); }); From 7033fa7563ca32485e5b7fea7df6c2a1893c6536 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 5 May 2014 13:17:34 -0400 Subject: [PATCH 15/88] closes https://github.com/designcreateplay/NodeBB/issues/1474 --- public/src/forum/admin/plugins.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/public/src/forum/admin/plugins.js b/public/src/forum/admin/plugins.js index 6246c48851..733b01ba12 100644 --- a/public/src/forum/admin/plugins.js +++ b/public/src/forum/admin/plugins.js @@ -14,15 +14,14 @@ define(function() { pluginID = $(this).parents('li').attr('data-plugin-id'); var btn = $(this); socket.emit('admin.plugins.toggleActive', pluginID, function(err, status) { - - btn.html(' ' + (status.active ? 'Dea' : 'A') + 'ctivate'); + btn.html(' ' + status.active ? 'Deactivate' : 'Activate'); btn.toggleClass('btn-warning', status.active).toggleClass('btn-success', !status.active); app.alert({ alert_id: 'plugin_toggled', title: 'Plugin ' + (status.active ? 'Enabled' : 'Disabled'), - message: 'Please restart your NodeBB to fully ' + (status.active ? 'activate' : 'deactivate') + ' this plugin', - type: 'info', + message: status.active ? 'Please restart your NodeBB to fully activate this plugin' : 'Plugin successfully deactivated', + type: status.active ? 'warning' : 'success', timeout: 5000, clickfn: function() { socket.emit('admin.restart'); From 8fc818e07c24922c427e8c5f755a16603f65c887 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 5 May 2014 13:25:06 -0400 Subject: [PATCH 16/88] closes https://github.com/designcreateplay/NodeBB/issues/1473 --- src/plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins.js b/src/plugins.js index b66667f6a4..9be76bafe8 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -112,7 +112,7 @@ var fs = require('fs'), libraryPath, staticDir; if (pluginData.minver && semver.validRange(pluginData.minver)) { - if (!semver.gt(pkg.version, pluginData.minver)) { + if (!semver.gte(pkg.version, pluginData.minver)) { // If NodeBB is not new enough to run this plugin winston.warn('[plugins/' + pluginData.id + '] This plugin may not be compatible with your version of NodeBB. This may cause unintended behaviour or crashing.'); } From 14431f79132368dcf1f3e868f4ab6149b8bfaf73 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 5 May 2014 15:19:37 -0400 Subject: [PATCH 17/88] closes #1486 --- src/install.js | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/install.js b/src/install.js index b8a35fa572..851932d0a4 100644 --- a/src/install.js +++ b/src/install.js @@ -241,30 +241,29 @@ function setupDatabase(server_conf, next) { function setupDefaultConfigs(next) { winston.info('Populating database with default configs, if not already set...'); - var meta = require('./meta'); - - fs.readFile(path.join(__dirname, '../', 'install/data/defaults.json'), function (err, defaults) { - async.each(defaults, function (configObj, next) { - meta.configs.setOnEmpty(configObj.field, configObj.value, next); - }, function (err) { - meta.configs.init(next); - }); - - if (install.values) { - if (install.values['social:twitter:key'] && install.values['social:twitter:secret']) { - meta.configs.setOnEmpty('social:twitter:key', install.values['social:twitter:key']); - meta.configs.setOnEmpty('social:twitter:secret', install.values['social:twitter:secret']); - } - if (install.values['social:google:id'] && install.values['social:google:secret']) { - meta.configs.setOnEmpty('social:google:id', install.values['social:google:id']); - meta.configs.setOnEmpty('social:google:secret', install.values['social:google:secret']); - } - if (install.values['social:facebook:key'] && install.values['social:facebook:secret']) { - meta.configs.setOnEmpty('social:facebook:app_id', install.values['social:facebook:app_id']); - meta.configs.setOnEmpty('social:facebook:secret', install.values['social:facebook:secret']); - } - } + var meta = require('./meta'), + defaults = require(path.join(__dirname, '../', 'install/data/defaults.json')); + + async.each(defaults, function (configObj, next) { + meta.configs.setOnEmpty(configObj.field, configObj.value, next); + }, function (err) { + meta.configs.init(next); }); + + if (install.values) { + if (install.values['social:twitter:key'] && install.values['social:twitter:secret']) { + meta.configs.setOnEmpty('social:twitter:key', install.values['social:twitter:key']); + meta.configs.setOnEmpty('social:twitter:secret', install.values['social:twitter:secret']); + } + if (install.values['social:google:id'] && install.values['social:google:secret']) { + meta.configs.setOnEmpty('social:google:id', install.values['social:google:id']); + meta.configs.setOnEmpty('social:google:secret', install.values['social:google:secret']); + } + if (install.values['social:facebook:key'] && install.values['social:facebook:secret']) { + meta.configs.setOnEmpty('social:facebook:app_id', install.values['social:facebook:app_id']); + meta.configs.setOnEmpty('social:facebook:secret', install.values['social:facebook:secret']); + } + } } function enableDefaultTheme(next) { From dfe010d97dc30aeca8667a69fd276963f71ca1aa Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 5 May 2014 15:34:38 -0400 Subject: [PATCH 18/88] caps --- src/meta.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meta.js b/src/meta.js index 1fb8048fc7..a73de67c8d 100644 --- a/src/meta.js +++ b/src/meta.js @@ -15,7 +15,7 @@ var fs = require('fs'), translator = require('./../public/src/translator'), db = require('./database'), plugins = require('./plugins'), - User = require('./user'); + user = require('./user'); (function (Meta) { Meta.restartRequired = false; @@ -211,7 +211,7 @@ var fs = require('fs'), userslug = matches[1], subpage = matches[2]; - User.getUsernameByUserslug(userslug, function(err, username) { + user.getUsernameByUserslug(userslug, function(err, username) { if (subpage) { translator.translate('[[pages:user.' + subpage + ', ' + username + ']]', language, function(translated) { callback(null, translated); From 590082709fb73dcbab7fc502dbe79fa536722983 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 5 May 2014 16:25:20 -0400 Subject: [PATCH 19/88] fixed #1488 - emails are processed 100 at a time --- src/user/jobs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user/jobs.js b/src/user/jobs.js index c2e88e752f..2655b96a67 100644 --- a/src/user/jobs.js +++ b/src/user/jobs.js @@ -59,7 +59,7 @@ module.exports = function(User) { }); // Consider using eachLimit, but *only* if people complain about email relays choking -- otherwise we're ok. - async.each(users, function(userObj, next) { + async.eachLimit(users, 100, function(userObj, next) { user.notifications.getDailyUnread(userObj.uid, function(err, notifications) { // Turn relative URLs into absolute ones for(var i=0; i Date: Mon, 5 May 2014 16:48:09 -0400 Subject: [PATCH 20/88] closes #1487 ban and delete user admin actions takes an array of uids now. --- public/src/forum/admin/users.js | 194 ++++++++++++++++---------------- src/socket.io/admin/user.js | 69 ++++++++---- src/threadTools.js | 2 - src/user.js | 3 +- 4 files changed, 144 insertions(+), 124 deletions(-) diff --git a/public/src/forum/admin/users.js b/public/src/forum/admin/users.js index e52a8d78f9..a0116b2654 100644 --- a/public/src/forum/admin/users.js +++ b/public/src/forum/admin/users.js @@ -6,135 +6,136 @@ define(function() { Users.init = function() { var yourid = ajaxify.variables.get('yourid'); - function isUserAdmin(element) { - var parent = $(element).parents('.users-box'); - return (parent.attr('data-admin') !== "0"); + $('#users-container').on('click', '.select', function() { + var userBox = $(this).parents('.users-box'); + var isSelected = userBox.hasClass('selected'); + userBox.toggleClass('selected', !isSelected); + $(this).toggleClass('fa-square-o', isSelected); + $(this).toggleClass('fa-check-square-o', !isSelected); + }); + + function getSelectedUids() { + var uids = []; + $('#users-container .users-box.selected').each(function() { + uids.push($(this).attr('data-uid')); + }); + return uids; } - function isUserBanned(element) { - var parent = $(element).parents('.users-box'); - return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0"); - } - - function getUID(element) { - var parent = $(element).parents('.users-box'); - return parent.attr('data-uid'); - } - - function updateUserBanButtons(elements) { - elements.each(function(index, element) { - var banBtn = $(element); - var uid = getUID(banBtn); - - banBtn.toggleClass('disabled', isUserAdmin(banBtn) || uid === yourid); - banBtn.toggleClass('btn-warning', isUserBanned(banBtn)); + function update(className, state) { + $('#users-container .users-box.selected ' + className +'.label').each(function() { + $(this).toggleClass('hide', !state); }); } - function updateUserAdminButtons(elements) { - elements.each(function(index, element) { - var adminBtn = $(element); - var uid = getUID(adminBtn); - - adminBtn.toggleClass('disabled', (isUserAdmin(adminBtn) && uid === yourid) || isUserBanned(adminBtn)); - adminBtn.toggleClass('btn-success', isUserAdmin(adminBtn)); - }); + function unselectAll() { + $('#users-container .users-box.selected').removeClass('selected') + .find('.select').toggleClass('fa-square-o', true).toggleClass('fa-check-square-o', false); } - function updateButtons() { - updateUserBanButtons($('.ban-btn')); - updateUserAdminButtons($('.admin-btn')); + function removeSelected() { + $('#users-container .users-box.selected').remove(); } - $('#users-container').on('click', '.ban-btn', function() { - var banBtn = $(this); - var parent = banBtn.parents('.users-box'); - var uid = getUID(banBtn); + $('.ban-user').on('click', function() { + var uids = getSelectedUids(); + if (!uids.length) { + return; + } - if (!isUserAdmin(banBtn)) { - if (isUserBanned(banBtn)) { - socket.emit('admin.user.unbanUser', uid, function(err) { + bootbox.confirm('Do you really want to ban?', function(confirm) { + if (confirm) { + socket.emit('admin.user.banUsers', uids, function(err) { if (err) { return app.alertError(err.message); } - app.alertSuccess('This user is unbanned!'); - }); - - banBtn.removeClass('btn-warning'); - parent.attr('data-banned', 0); - updateUserAdminButtons($('.admin-btn')); - } else { - bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') + '"?', function(confirm) { - if (confirm) { - socket.emit('admin.user.banUser', uid, function(err) { - if (err) { - return app.alertError(err.message); - } - app.alertSuccess('This user is banned!'); - }); - banBtn.addClass('btn-warning'); - parent.attr('data-banned', 1); - updateUserAdminButtons($('.admin-btn')); - } + app.alertSuccess('User(s) banned!'); }); + update('.ban', true); + unselectAll(); } - } - - return false; + }); }); - $('#users-container').on('click', '.admin-btn', function() { - var adminBtn = $(this); - var parent = adminBtn.parents('.users-box'); - var uid = getUID(adminBtn); + $('.unban-user').on('click', function() { + var uids = getSelectedUids(); + if (!uids.length) { + return; + } - if(uid === yourid) { - app.alert({ - title: 'Error', - message: 'You can\'t remove yourself as Administrator!', - type: 'danger', - timeout: 5000 - }); - } else if (!isUserAdmin(adminBtn)) { - socket.emit('admin.user.makeAdmin', uid, function(err) { + socket.emit('admin.user.unbanUsers', uids, function(err) { + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('User(s) unbanned!'); + }); + + update('.ban', false); + unselectAll(); + }); + + $('.admin-user').on('click', function() { + var uids = getSelectedUids(); + if (!uids.length) { + return; + } + + if (uids.indexOf(yourid) !== -1) { + app.alertError('You can\'t remove yourself as Administrator!'); + } else { + socket.emit('admin.user.makeAdmins', uids, function(err) { if (err) { return app.alertError(err.message); } - app.alertSuccess('This user is now an administrator.'); + app.alertSuccess('User(s) are now administrators.'); }); - parent.attr('data-admin', 1); - updateUserBanButtons($('.ban-btn')); - updateUserAdminButtons($('.admin-btn')); - } else if(uid !== yourid) { - bootbox.confirm('Do you really want to remove this user as admin "' + parent.attr('data-username') + '"?', function(confirm) { + + update('.administrator', true); + unselectAll(); + } + }); + + $('.remove-admin-user').on('click', function() { + var uids = getSelectedUids(); + if (!uids.length) { + return; + } + + if (uids.indexOf(yourid) !== -1) { + app.alertError('You can\'t remove yourself as Administrator!'); + } else { + bootbox.confirm('Do you really want to remove admins?', function(confirm) { if (confirm) { - socket.emit('admin.user.removeAdmin', uid, function(err) { + socket.emit('admin.user.removeAdmins', uids, function(err) { if (err) { return app.alertError(err.message); } - app.alertSuccess('This user is no longer an administrator.'); + app.alertSuccess('User(s) are no longer administrators.'); }); - parent.attr('data-admin', 0); - updateUserBanButtons($('.ban-btn')); - updateUserAdminButtons($('.admin-btn')); + + update('.administrator', false); + unselectAll(); } }); } - return false; }); - $('#users-container').on('click', '.delete-btn', function() { - var deleteBtn = $(this); - var parent = deleteBtn.parents('.users-box'); - var uid = getUID(deleteBtn); - bootbox.confirm('Warning!
    Do you really want to delete this user "' + parent.attr('data-username') + '"?
    This action is not reversable, all user data and content will be erased!', function(confirm) { + $('.delete-user').on('click', function() { + var uids = getSelectedUids(); + if (!uids.length) { + return; + } + + bootbox.confirm('Warning!
    Do you really want to delete user(s)?
    This action is not reversable, all user data and content will be erased!', function(confirm) { if (confirm) { - socket.emit('admin.user.deleteUser', uid, function(err) { + socket.emit('admin.user.deleteUsers', uids, function(err) { if (err) { return app.alertError(err.message); } - parent.remove(); - app.alertSuccess('User Deleted!'); + + app.alertSuccess('User(s) Deleted!'); + removeSelected(); + unselectAll(); }); } }); @@ -179,7 +180,6 @@ define(function() { }); } - $('document').ready(function() { var timeoutId = 0, @@ -230,23 +230,17 @@ define(function() { .addClass('label-success') .removeClass('label-danger'); } - - updateButtons(); }); }); }, 250); }); - updateButtons(); - handleUserCreate(); function onUsersLoaded(users) { ajaxify.loadTemplate('admin/users', function(adminUsers) { var html = $(templates.parse(templates.getBlock(adminUsers, 'users'), {users: users})); $('#users-container').append(html); - updateUserBanButtons(html.find('.ban-btn')); - updateUserAdminButtons(html.find('.admin-btn')); }); } diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index 47ced5d63d..ec20007661 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -9,14 +9,24 @@ var groups = require('../../groups'), User = {}; -User.makeAdmin = function(socket, theirid, callback) { - groups.join('administrators', theirid, callback); +User.makeAdmins = function(socket, uids, callback) { + toggleAdmin(uids, true, callback); }; -User.removeAdmin = function(socket, theirid, callback) { - groups.leave('administrators', theirid, callback); +User.removeAdmins = function(socket, uids, callback) { + toggleAdmin(uids, false, callback); }; +function toggleAdmin(uids, isAdmin, callback) { + if(!Array.isArray(uids)) { + return callback(new Error('[[error:invalid-data]]')); + } + + async.each(uids, function(uid, next) { + groups[isAdmin ? 'join' : 'leave']('administrators', uid, next); + }, callback); +} + User.createUser = function(socket, userData, callback) { if (!userData) { return callback(new Error('[[error:invalid-data]]')); @@ -24,44 +34,61 @@ User.createUser = function(socket, userData, callback) { user.create(userData, callback); }; -User.banUser = function(socket, theirid, callback) { - user.isAdministrator(theirid, function(err, isAdmin) { +User.banUsers = function(socket, uids, callback) { + if(!Array.isArray(uids)) { + return callback(new Error('[[error:invalid-data]]')); + } + + async.each(uids, banUser, callback); +}; + +function banUser(uid, callback) { + user.isAdministrator(uid, function(err, isAdmin) { if (err || isAdmin) { return callback(err || new Error('[[error:cant-ban-other-admins]]')); } - user.ban(theirid, function(err) { + user.ban(uid, function(err) { if (err) { return callback(err); } - var sockets = websockets.getUserSockets(theirid); + var sockets = websockets.getUserSockets(uid); for(var i=0; i Date: Mon, 5 May 2014 16:56:01 -0400 Subject: [PATCH 21/88] enabling view cache, since we require server restart on theme changes it doesn't hurt --- src/middleware/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/middleware/index.js b/src/middleware/index.js index 1b42ab1f61..197f0a9c8d 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -189,6 +189,8 @@ module.exports = function(app, data) { app.set('view engine', 'tpl'); app.set('views', viewsPath); + app.enable('view cache'); + app.use(express.compress()); app.use(express.favicon(path.join(__dirname, '../../', 'public', meta.config['brand:favicon'] ? meta.config['brand:favicon'] : 'favicon.ico'))); From 7f6ae6df9f02a55047c9175e95da1fb6241ffce6 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 5 May 2014 18:17:08 -0400 Subject: [PATCH 22/88] possible fix to active users --- public/src/forum/admin/users.js | 3 +-- public/src/forum/topic/browsing.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/public/src/forum/admin/users.js b/public/src/forum/admin/users.js index a0116b2654..489e560fe2 100644 --- a/public/src/forum/admin/users.js +++ b/public/src/forum/admin/users.js @@ -10,8 +10,7 @@ define(function() { var userBox = $(this).parents('.users-box'); var isSelected = userBox.hasClass('selected'); userBox.toggleClass('selected', !isSelected); - $(this).toggleClass('fa-square-o', isSelected); - $(this).toggleClass('fa-check-square-o', !isSelected); + $(this).toggleClass('fa-square-o', isSelected).toggleClass('fa-check-square-o', !isSelected); }); function getSelectedUids() { diff --git a/public/src/forum/topic/browsing.js b/public/src/forum/topic/browsing.js index 812c60f6b9..dcd270beff 100644 --- a/public/src/forum/topic/browsing.js +++ b/public/src/forum/topic/browsing.js @@ -21,7 +21,7 @@ define(function() { }); if (absent) { - $(element).remove(); + $(element).parent().remove(); } } }); From 08cf6bc5e6db91150919843bf54c7a068e702eef Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 6 May 2014 10:22:55 -0400 Subject: [PATCH 23/88] fixed #1489 -- made checkReplace error-first, added missing callback, added missing object field to db query --- src/notifications.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index 2ec49ebc7e..4ea446d882 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -21,7 +21,6 @@ var async = require('async'), }; Notifications.get = function(nid, uid, callback) { - db.exists('notifications:' + nid, function(err, exists) { if (err) { winston.error('[notifications.get] Could not retrieve nid ' + nid + ': ' + err.message); @@ -117,7 +116,7 @@ var async = require('async'), Notifications.get(nid, null, function(notif_data) { async.each(uids, function(uid, next) { if (parseInt(uid, 10) > 0) { - checkReplace(notif_data.uniqueId, uid, notif_data, function(replace) { + checkReplace(notif_data.uniqueId, uid, notif_data, function(err, replace) { if (replace) { db.sortedSetAdd('uid:' + uid + ':notifications:unread', notif_data.datetime, nid); websockets.in('uid_' + uid).emit('event:new_notification', notif_data); @@ -145,7 +144,7 @@ var async = require('async'), return 'notifications:' + nid; }); - db.getObjectsFields(keys, ['uniqueId', 'importance'], function(err, nid_infos) { + db.getObjectsFields(keys, ['nid', 'uniqueId', 'importance'], function(err, nid_infos) { if (err) { return next(err); } @@ -158,7 +157,10 @@ var async = require('async'), db.sortedSetRemove(set, nid_info.nid); } } + }); + + next(); }); }); } @@ -176,7 +178,7 @@ var async = require('async'), replace = true; } - callback(replace); + callback(null, replace); } }); } From 89225c80ca7c620547431b677b5cc844f84054d3 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 6 May 2014 13:05:27 -0400 Subject: [PATCH 24/88] related to #1493 --- src/middleware/admin.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/middleware/admin.js b/src/middleware/admin.js index e04be5391b..cbe7b2ed16 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -16,6 +16,10 @@ var app, middleware.isAdmin = function(req, res, next) { user.isAdministrator((req.user && req.user.uid) ? req.user.uid : 0, function (err, isAdmin) { + if (err) { + return next(err); + } + if (!isAdmin) { res.status(403); res.redirect('/403'); @@ -26,6 +30,7 @@ middleware.isAdmin = function(req, res, next) { }; middleware.buildHeader = function(req, res, next) { + var uid = req.user ? req.user.uid : 0; async.parallel([ function(next) { var custom_header = { @@ -33,7 +38,7 @@ middleware.buildHeader = function(req, res, next) { 'authentication': [] }; - user.getUserFields(req.user.uid, ['username', 'userslug', 'picture'], function(err, userData) { + user.getUserFields(uid, ['username', 'userslug', 'picture'], function(err, userData) { async.parallel({ scripts: function(next) { plugins.fireHook('filter:admin.scripts.get', [], function(err, scripts) { From f89afd92b916385cf54619a547ed6b7e60d9a717 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 6 May 2014 13:12:19 -0400 Subject: [PATCH 25/88] fix for plugin page access issue closes #1493 --- src/routes/admin.js | 4 ---- src/routes/index.js | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index 6124f9beeb..1974c9e52b 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -74,10 +74,6 @@ function miscRoutes(app, middleware, controllers) { module.exports = function(app, middleware, controllers) { - app.all('/api/admin/*', middleware.admin.isAdmin, middleware.prepareAPI); - app.all('/admin/*', middleware.admin.isAdmin); - app.get('/admin', middleware.admin.isAdmin); - mainRoutes(app, middleware, controllers); userRoutes(app, middleware, controllers); forumRoutes(app, middleware, controllers); diff --git a/src/routes/index.js b/src/routes/index.js index ad48f0f580..71deb793df 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -129,6 +129,10 @@ module.exports = function(app, middleware) { app.namespace(nconf.get('relative_path'), function() { plugins.ready(function() { app.all('/api/*', middleware.updateLastOnlineTime, middleware.prepareAPI); + app.all('/api/admin/*', middleware.admin.isAdmin, middleware.prepareAPI); + app.all('/admin/*', middleware.admin.isAdmin); + app.get('/admin', middleware.admin.isAdmin); + plugins.fireHook('action:app.load', app, middleware, controllers); adminRoutes(app, middleware, controllers); From 3b7d222ec38bec60ea0b745e8329be5d61018ac9 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 6 May 2014 15:04:02 -0400 Subject: [PATCH 26/88] prevent duplicate blockquotes #1491 --- public/src/forum/topic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index cf2277a13e..b187049a43 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -106,7 +106,7 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', function addBlockquoteEllipses(blockquotes) { blockquotes.each(function() { var $this = $(this); - if ($this.find(':hidden').length) { + if ($this.find(':hidden').length && !$this.find('.toggle').length) { $this.append(''); } }); From f697b5a2b8896a471e8ade1a3086429653cb569a Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 6 May 2014 15:09:35 -0400 Subject: [PATCH 27/88] addBlockquoteEllipses to newly created posts #1491 --- public/src/forum/topic.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index b187049a43..9b50a2246a 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -308,8 +308,6 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', $('#post-container li[data-pid]').each(function() { var $this = $(this); - addBlockquoteEllipses($this.find('.post-content > blockquote')); - if(firstPid > parseInt($this.attr('data-pid'), 10)) { after = $this; if(after.next().length && after.next().hasClass('post-bar')) { @@ -350,6 +348,7 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', } translated.hide().fadeIn('slow'); + addBlockquoteEllipses(translated.find('.post-content > blockquote')); onNewPostsLoaded(translated, data.posts); From 14db999684f75c430062927b96d22184635cf4f2 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 6 May 2014 15:51:21 -0400 Subject: [PATCH 28/88] closes #1494 --- src/middleware/middleware.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 53ee5e3117..98b616a54e 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -45,7 +45,11 @@ middleware.updateLastOnlineTime = function(req, res, next) { middleware.redirectToAccountIfLoggedIn = function(req, res, next) { if (req.user) { user.getUserField(req.user.uid, 'userslug', function (err, userslug) { - res.redirect('/user/' + userslug); + if (res.locals.isAPI) { + return res.json(302, '/user/' + userslug); + } else { + res.redirect('/user/' + userslug); + } }); } else { next(); From 7a25f0bb3618a1f480e9a26e7e3a41fa3a7a8b46 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 6 May 2014 16:28:31 -0400 Subject: [PATCH 29/88] fix for #1496 --- src/controllers/accounts.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 60bba47853..bb5c6a0e05 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -175,14 +175,14 @@ accountsController.getAccount = function(req, res, next) { }; accountsController.getFollowing = function(req, res, next) { - getFollow('following', req, res, next); + getFollow('account/following', 'following', req, res, next); }; accountsController.getFollowers = function(req, res, next) { - getFollow('followers', req, res, next); + getFollow('account/followers', 'followers', req, res, next); }; -function getFollow(name, req, res, next) { +function getFollow(route, name, req, res, next) { var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; var userData; @@ -205,7 +205,7 @@ function getFollow(name, req, res, next) { userData[name] = users; userData[name + 'Count'] = users.length; - res.render(name, userData); + res.render(route, userData); }); } @@ -240,7 +240,7 @@ accountsController.getFavourites = function(req, res, next) { userData.posts = favourites.posts; userData.nextStart = favourites.nextStart; - res.render('favourites', userData); + res.render('account/favourites', userData); }); }); }); From 57f0ee8a38b212527addf371daa3d9c5c06e54c0 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 6 May 2014 17:28:42 -0400 Subject: [PATCH 30/88] removed whitespace --- src/routes/admin.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index 1974c9e52b..24bb7e76da 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -71,8 +71,6 @@ function miscRoutes(app, middleware, controllers) { app.get('/api/admin/logger', controllers.admin.logger.get); } - - module.exports = function(app, middleware, controllers) { mainRoutes(app, middleware, controllers); userRoutes(app, middleware, controllers); From 1f7fd51b40ad74bdea7d7ed7a6f75ce17ba3c4af Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 6 May 2014 17:46:34 -0400 Subject: [PATCH 31/88] some work for #1482 --- public/src/app.js | 7 ------- src/controllers/api.js | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index 6f768c2596..5221974efb 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -459,9 +459,6 @@ var socket, allowGuestSearching = (data.config || {}).allowGuestSearching === '1'; if (isLoggedIn) { - $('.nodebb-loggedin').show(); - $('.nodebb-loggedout').hide(); - $('#logged-out-menu').addClass('hide'); $('#logged-in-menu').removeClass('hide'); @@ -492,12 +489,8 @@ var socket, $('#mobile-search-button').addClass("hide").hide(); } - $('.nodebb-loggedin').hide(); - $('.nodebb-loggedout').show(); - $('#logged-out-menu').removeClass('hide'); $('#logged-in-menu').addClass('hide'); - } $('#main-nav a, #user-control-list a, #logged-out-menu li a, #logged-in-menu .visible-xs').off('click').on('click', function() { diff --git a/src/controllers/api.js b/src/controllers/api.js index 594dd2230b..03fdfa46c5 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -25,6 +25,7 @@ apiController.getConfig = function(req, res, next) { config.maximumSignatureLength = meta.config.maximumSignatureLength; config.useOutgoingLinksPage = parseInt(meta.config.useOutgoingLinksPage, 10) === 1; config.allowGuestPosting = parseInt(meta.config.allowGuestPosting, 10) === 1; + config.allowGuestSearching = parseInt(meta.config.allowGuestPosting, 10) === 1; config.allowFileUploads = parseInt(meta.config.allowFileUploads, 10) === 1; config.allowTopicsThumbnail = parseInt(meta.config.allowTopicsThumbnail, 10) === 1; config.privateUserInfo = parseInt(meta.config.privateUserInfo, 10) === 1; From 678f0f436eb018502cbd57649e1693733d7453c1 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 6 May 2014 17:50:01 -0400 Subject: [PATCH 32/88] importing latest templates.js @Schamper --- public/src/templates.js | 75 ++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/public/src/templates.js b/public/src/templates.js index 9ccc06b073..83931fb057 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -1,4 +1,5 @@ -"use strict"; +'use strict'; +/*global require, module*/ (function(module) { var templates = { @@ -53,7 +54,7 @@ }; templates.getBlock = function(template, block) { - return template.replace(new RegExp("[\\s\\S]*([\r\n]*[\\s\\S]*?[\r\n]*)[\\s\\S]*", 'g'), '$1'); + return template.replace(new RegExp('[\\s\\S]*([\r\n]*[\\s\\S]*?[\r\n]*)[\\s\\S]*', 'g'), '$1'); }; function express(filename, options, fn) { @@ -76,15 +77,19 @@ } function makeRegex(block) { - return new RegExp("[\\s\\S]*?", 'g'); + return new RegExp('[\\s\\S]*?'); + } + + function makeBlockRegex(block) { + return new RegExp('([\\n]?[\\n]?)|([\\n]?[\\n]?)', 'g'); } function makeConditionalRegex(block) { - return new RegExp("([\\s\\S]*?)", 'g'); + return new RegExp('([\\s\\S]*?)', 'g'); } function makeStatementRegex(key) { - return new RegExp("([\\s]*)|([\\s]*)", 'gi'); + return new RegExp('([\\s]*)|([\\s]*)', 'gi'); } function registerGlobals(obj) { @@ -168,41 +173,44 @@ template = checkConditional(template, namespace + 'length', array[key].length); template = checkConditional(template, '!' + namespace + 'length', !array[key].length); - var regex = makeRegex(key), - block = namespace.substring(0, namespace.length - 1).split('.').pop(); - - block = template.replace(new RegExp("[\\s\\S]*[\r\n]*([\\s\\S]*?)[\r\n]*[\\s\\S]*", 'g'), '$1'); + var regex = makeRegex(key), block; - if (typeof block === "undefined" || !array[key].length) { + if (!array[key].length) { return template; } - var numblocks = array[key].length - 1, - iterator = 0, - result = "", - parsedBlock; - - do { - parsedBlock = parse(block, array[key][iterator], bind, namespace, {iterator: iterator, total: numblocks}) + ((iterator < numblocks) ? '\r\n':''); + while (block = template.match(regex)) { + block = block[0].replace(makeBlockRegex(key), ''); - result += (!bind) ? parsedBlock : setBindContainer(parsedBlock, bind + namespace + iterator); - result = parseFunctions(block, result, { - data: array[key][iterator], - iterator: iterator, - numblocks: numblocks - }); + var numblocks = array[key].length - 1, + iterator = 0, + result = '', + parsedBlock; - result = checkConditional(result, '@first', iterator === 0); - result = checkConditional(result, '!@first', iterator !== 0); - result = checkConditional(result, '@last', iterator === numblocks); - result = checkConditional(result, '!@last', iterator !== numblocks); + do { + parsedBlock = parse(block, array[key][iterator], bind, namespace, {iterator: iterator, total: numblocks}) + ((iterator < numblocks) ? '\r\n':''); + + result += (!bind) ? parsedBlock : setBindContainer(parsedBlock, bind + namespace + iterator); + result = parseFunctions(block, result, { + data: array[key][iterator], + iterator: iterator, + numblocks: numblocks + }); - if (bind) { - array[key][iterator].__template = block; - } - } while (iterator++ < numblocks); + result = checkConditional(result, '@first', iterator === 0); + result = checkConditional(result, '!@first', iterator !== 0); + result = checkConditional(result, '@last', iterator === numblocks); + result = checkConditional(result, '!@last', iterator !== numblocks); - return template.replace(regex, result); + if (bind) { + array[key][iterator].__template = block; + } + } while (iterator++ < numblocks); + + template = template.replace(regex, result); + } + + return template; } function setBindContainer(block, namespace) { @@ -265,7 +273,6 @@ namespace = namespace || ''; originalObj = originalObj || obj; - template = checkConditionalHelper(template, obj); for (var key in obj) { @@ -296,7 +303,7 @@ } if (namespace) { - template = template.replace(new RegExp("{" + namespace + "\\.[\\s\\S]*?}", 'g'), ''); + template = template.replace(new RegExp('{' + namespace + '\\.[\\s\\S]*?}', 'g'), ''); namespace = ''; } else { // clean up all undefined conditionals From 883978007d1d925dc7a3def514e594021d98a9bd Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 6 May 2014 18:42:38 -0400 Subject: [PATCH 33/88] closes #1482 removed updateHeader, the header is using template values in from the api, update menu partial in vanilla theme as well --- public/src/app.js | 155 ++++++++++++------------------- public/src/forum/account/edit.js | 12 +-- public/src/forum/footer.js | 4 - src/middleware/middleware.js | 11 ++- src/plugins.js | 2 +- src/socket.io/meta.js | 31 ------- src/socket.io/user.js | 17 +--- 7 files changed, 76 insertions(+), 156 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index 5221974efb..720fb01d8c 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -58,10 +58,6 @@ var socket, reconnectEl.removeClass('active').addClass("hide"); }, 3000); } - - socket.emit('meta.updateHeader', { - fields: ['username', 'picture', 'userslug'] - }, app.updateHeader); } function onConfigLoad(data) { @@ -98,10 +94,6 @@ var socket, app.showLoginMessage(); - socket.emit('meta.updateHeader', { - fields: ['username', 'picture', 'userslug'] - }, app.updateHeader); - $(window).trigger('action:connected'); }); @@ -146,8 +138,6 @@ var socket, setTimeout(app.logout, 1000); }); - socket.on('meta.updateHeader', app.updateHeader); - app.enterRoom('global'); if (config.environment === 'development' && console && console.log) { @@ -289,7 +279,7 @@ var socket, app.replaceSelfLinks = function(selector) { selector = selector || $('a'); selector.each(function() { - var href = $(this).attr('href') + var href = $(this).attr('href'); if (href && app.userslug) { $(this).attr('href', href.replace(/\[self\]/g, app.userslug)); } @@ -430,86 +420,6 @@ var socket, }); } - - app.updateHeader = function(err, data) { - 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(); - - searchFields.removeClass('hide').show(); - $(this).hide(); - - searchInput.focus(); - - $('#search-form').on('submit', dismissSearch); - searchInput.on('blur', dismissSearch); - return false; - }); - - var loggedInMenu = $('#logged-in-menu'), - isLoggedIn = data.uid > 0, - allowGuestSearching = (data.config || {}).allowGuestSearching === '1'; - - if (isLoggedIn) { - $('#logged-out-menu').addClass('hide'); - $('#logged-in-menu').removeClass('hide'); - - searchButton.removeClass("hide").show(); - - var userLabel = loggedInMenu.find('#user_label'); - - if (data.userslug) { - userLabel.find('#user-profile-link').attr('href', RELATIVE_PATH + '/user/' + data.userslug); - } - if (data.picture) { - userLabel.find('img').attr('src', data.picture); - } - if (data.username) { - userLabel.find('#user-profile-link>span').html(' ' + data.username); - } - - $('#logout-link').on('click', app.logout); - - updateOnlineStatus(data.uid); - - } else { - if (allowGuestSearching) { - searchButton.removeClass("hide").show(); - $('#mobile-search-button').removeClass("hide").show(); - } else { - searchButton.addClass("hide").hide(); - $('#mobile-search-button').addClass("hide").hide(); - } - - $('#logged-out-menu').removeClass('hide'); - $('#logged-in-menu').addClass('hide'); - } - - $('#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')) { - $('.navbar-header button').click(); - } - }); - - $('#user-control-list .user-status').off('click').on('click', function(e) { - socket.emit('user.setStatus', $(this).attr('data-status'), function(err, data) { - if(err) { - return app.alertError(err.message); - } - updateOnlineStatus(data.uid); - }); - e.preventDefault(); - }); - }; - function exposeConfigToTemplates() { $(document).ready(function() { templates.setGlobal('relative_path', RELATIVE_PATH); @@ -540,6 +450,56 @@ var socket, }); } + function handleSearch() { + 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(); + + searchFields.removeClass('hide').show(); + $(this).hide(); + + searchInput.focus(); + + $('#search-form').on('submit', dismissSearch); + searchInput.on('blur', dismissSearch); + return false; + }); + + $('#search-form').on('submit', function () { + var input = $(this).find('input'); + ajaxify.go('search/' + input.val().replace(/^[ ?#]*/, '')); + input.val(''); + return false; + }); + } + + function collapseNavigationOnClick() { + $('#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')) { + $('.navbar-header button').click(); + } + }); + } + + function handleStatusChange() { + $('#user-control-list .user-status').off('click').on('click', function(e) { + socket.emit('user.setStatus', $(this).attr('data-status'), function(err, data) { + if(err) { + return app.alertError(err.message); + } + updateOnlineStatus(data.uid); + }); + e.preventDefault(); + }); + } app.load = function() { $('document').ready(function () { @@ -556,12 +516,13 @@ var socket, url: url }); - $('#search-form').on('submit', function () { - var input = $(this).find('input'); - ajaxify.go("search/" + input.val().replace(/^[ ?#]*/, '')); - input.val(''); - return false; - }); + collapseNavigationOnClick(); + + handleStatusChange(); + + handleSearch(); + + $('#logout-link').on('click', app.logout); $(window).blur(function(){ app.isFocused = false; diff --git a/public/src/forum/account/edit.js b/public/src/forum/account/edit.js index c1120432bc..acbe3275a6 100644 --- a/public/src/forum/account/edit.js +++ b/public/src/forum/account/edit.js @@ -26,6 +26,7 @@ define(['forum/account/header', 'uploader'], function(header, uploader) { handleImageUpload(); handlePasswordChange(); updateSignature(); + updateImages(); }; function updateProfile() { @@ -66,7 +67,7 @@ define(['forum/account/header', 'uploader'], function(header, uploader) { $('.account-username-box').attr('data-userslug', data.userslug); $('#user-profile-link').attr('href', config.relative_path + '/user/' + data.userslug); - $('#user-profile-link span').html(' ' + userData.username); + $('#user-header-name').text(userData.username); } }); @@ -106,8 +107,10 @@ define(['forum/account/header', 'uploader'], function(header, uploader) { if (selectedImageType === 'gravatar') { $('#user-current-picture').attr('src', gravatarPicture); + $('#user-header-picture').attr('src', gravatarPicture); } else if (selectedImageType === 'uploaded') { $('#user-current-picture').attr('src', uploadedPicture); + $('#user-header-picture').attr('src', uploadedPicture); } } }); @@ -126,12 +129,9 @@ define(['forum/account/header', 'uploader'], function(header, uploader) { $('#user-current-picture').attr('src', imageUrlOnServer); $('#user-uploaded-picture').attr('src', imageUrlOnServer); + $('#user-header-picture').attr('src', imageUrlOnServer); uploadedPicture = imageUrlOnServer; - - socket.emit('meta.updateHeader', { - fields: ['username', 'picture', 'userslug'] - }, app.updateHeader); }); return false; @@ -223,7 +223,7 @@ define(['forum/account/header', 'uploader'], function(header, uploader) { $('#gravatar-box').toggle(!!gravatarPicture); $('#uploaded-box').toggle(!!uploadedPicture); - $('#gravatar-box .fa-check').toggle(currentPicture === gravatarPicture); + $('#gravatar-box .fa-check').toggle(currentPicture !== uploadedPicture); $('#uploaded-box .fa-check').toggle(currentPicture === uploadedPicture); } diff --git a/public/src/forum/footer.js b/public/src/forum/footer.js index 585b9722c9..de0a25e81f 100644 --- a/public/src/forum/footer.js +++ b/public/src/forum/footer.js @@ -1,9 +1,5 @@ define(['notifications', 'chat'], function(Notifications, Chat) { - socket.emit('meta.updateHeader', { - fields: ['username', 'picture', 'userslug'] - }, app.updateHeader); - Notifications.prepareDOM(); Chat.prepareDOM(); translator.prepareDOM(); diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 98b616a54e..29b836035e 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -207,7 +207,7 @@ middleware.renderHeader = function(req, res, callback) { csrf: res.locals.csrf_token, navigation: custom_header.navigation, allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1, - searchEnabled: plugins.hasListeners('filter:search.query') ? true : false + searchEnabled: plugins.hasListeners('filter:search.query') && (uid || parseInt(meta.config.allowGuestSearching, 10) === 1) }, escapeList = { '&': '&', @@ -264,13 +264,22 @@ middleware.renderHeader = function(req, res, callback) { }, isAdmin: function(next) { user.isAdministrator(uid, next); + }, + user: function(next) { + if (uid) { + user.getUserFields(uid, ['username', 'userslug', 'picture', 'status'], next); + } else { + next(); + } } }, function(err, results) { if (err) { return next(err); } + templateValues.browserTitle = results.title; templateValues.isAdmin = results.isAdmin || false; + templateValues.user = results.user; app.render('header', templateValues, callback); }); diff --git a/src/plugins.js b/src/plugins.js index 9be76bafe8..c72420def7 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -291,7 +291,7 @@ var fs = require('fs'), }; Plugins.hasListeners = function(hook) { - return (Plugins.loadedHooks[hook] && Plugins.loadedHooks[hook].length > 0); + return !!(Plugins.loadedHooks[hook] && Plugins.loadedHooks[hook].length > 0); }; Plugins.fireHook = function(hook) { diff --git a/src/socket.io/meta.js b/src/socket.io/meta.js index 35039a9dd4..5ce1004971 100644 --- a/src/socket.io/meta.js +++ b/src/socket.io/meta.js @@ -44,37 +44,6 @@ SocketMeta.buildTitle = function(socket, text, callback) { } }; -SocketMeta.updateHeader = function(socket, data, callback) { - if(!data) { - return callback(new Error('[[error:invalid-data]]')); - } - - if (socket.uid) { - user.getUserFields(socket.uid, data.fields, function(err, fields) { - if(err) { - return callback(err); - } - - if (fields) { - fields.uid = socket.uid; - callback(null, fields); - } else { - callback(null, []); - } - }); - } else { - callback(null, { - uid: 0, - username: '[[global:guest]]', - email: '', - picture: user.createGravatarURLFromEmail(''), - config: { - allowGuestSearching: meta.config.allowGuestSearching - } - }); - } -}; - SocketMeta.getUsageStats = function(socket, data, callback) { module.parent.exports.emitTopicPostStats(callback); }; diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 4c564c18c9..c03b4cef13 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -87,21 +87,6 @@ SocketUser.changePicture = function(socket, data, callback) { var type = data.type; - function updateHeader(callback) { - user.getUserFields(socket.uid, ['picture'], function(err, fields) { - if(err) { - return callback(err); - } - - if (fields) { - fields.uid = socket.uid; - socket.emit('meta.updateHeader', null, fields); - } - - callback(); - }); - } - function changePicture(uid, callback) { user.getUserField(uid, type, function(err, picture) { if(err) { @@ -125,7 +110,7 @@ SocketUser.changePicture = function(socket, data, callback) { if(err) { return callback(err); } - updateHeader(callback); + }); return; } From b56df975e0a1175dac2f10c6f535f18eb554fed4 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 7 May 2014 11:46:24 -0400 Subject: [PATCH 34/88] fixed 1495 --- public/src/ajaxify.js | 4 +++- public/src/forum/login.js | 18 ++++++++++++------ src/controllers/index.js | 3 +++ src/middleware/admin.js | 4 ++++ src/middleware/middleware.js | 7 ++++++- src/routes/authentication.js | 2 +- 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 6513d305d3..d3f68e8fab 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -186,7 +186,9 @@ var ajaxify = ajaxify || {}; if (data && data.status === 404) { return ajaxify.go('404'); } else if (data && data.status === 403) { - return ajaxify.go('403'); + app.alertError('[[global:please_log_in]]'); + app.previousUrl = url; + return ajaxify.go('login'); } else if (data && data.status === 302) { return ajaxify.go(data.responseJSON.slice(1)); } else if (textStatus !== "abort") { diff --git a/public/src/forum/login.js b/public/src/forum/login.js index dd1ba7f22b..5741cb0079 100644 --- a/public/src/forum/login.js +++ b/public/src/forum/login.js @@ -1,3 +1,6 @@ +"use strict"; +/* global define, app, RELATIVE_PATH */ + define(function() { var Login = {}; @@ -6,11 +9,12 @@ define(function() { e.preventDefault(); var loginData = { - 'username': $('#username').val(), - 'password': $('#password').val(), - 'remember': $('#remember').prop('checked'), - '_csrf': $('#csrf-token').val() - }; + 'username': $('#username').val(), + 'password': $('#password').val(), + 'remember': $('#remember').prop('checked'), + '_csrf': $('#csrf-token').val() + }, + previousUrl = $('input[name="previousUrl"]').val(); $('#login').attr('disabled', 'disabled').html('Logging in...'); $('#login-error-notify').hide(); @@ -21,7 +25,9 @@ define(function() { data: loginData, success: function(data, textStatus, jqXHR) { $('#login').html('Redirecting...'); - if(!app.previousUrl) { + if (previousUrl) { + app.previousUrl = previousUrl; + } else if (!app.previousUrl) { app.previousUrl = '/'; } diff --git a/src/controllers/index.js b/src/controllers/index.js index eb0af56d65..d361fd85e7 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -176,6 +176,9 @@ Controllers.login = function(req, res, next) { data.token = res.locals.csrf_token; data.showResetLink = emailersPresent; data.allowLocalLogin = meta.config.allowLocalLogin === undefined || parseInt(meta.config.allowLocalLogin, 10) === 1; + if (req.query.next) { + data.previousUrl = req.query.next; + } res.render('login', data); }; diff --git a/src/middleware/admin.js b/src/middleware/admin.js index cbe7b2ed16..d9d36791ce 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -15,6 +15,10 @@ var app, middleware.isAdmin = function(req, res, next) { + if (!req.user) { + return res.redirect('/login?next=admin'); + } + user.isAdministrator((req.user && req.user.uid) ? req.user.uid : 0, function (err, isAdmin) { if (err) { return next(err); diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 29b836035e..8301e628c8 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -99,7 +99,7 @@ middleware.checkGlobalPrivacySettings = function(req, res, next) { if (res.locals.isAPI) { return res.json(403, 'not-allowed'); } else { - return res.redirect('403'); + return res.redirect('login?next=' + req.url); } } @@ -107,8 +107,13 @@ middleware.checkGlobalPrivacySettings = function(req, res, next) { }; middleware.checkAccountPermissions = function(req, res, next) { + // This middleware ensures that only the requested user and admins can pass var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; + if (callerUID === 0) { + return res.redirect('/login?next=' + req.url); + } + // this function requires userslug to be passed in. todo: /user/uploadpicture should pass in userslug I think user.getUidByUserslug(req.params.userslug, function (err, uid) { if (err) { diff --git a/src/routes/authentication.js b/src/routes/authentication.js index e557c49e83..53d1953bec 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -31,7 +31,7 @@ function login(req, res, next) { if(meta.config.allowLocalLogin !== undefined && parseInt(meta.config.allowLocalLogin, 10) === 0) { - return res.send(403); + return res.send(404); } passport.authenticate('local', function(err, userData, info) { From f714c713f34cd9d55c2a2f21b7b40bb8d4d61852 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 7 May 2014 12:30:58 -0400 Subject: [PATCH 35/88] fixes deactivate text on plugin buttons --- public/src/forum/admin/plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/forum/admin/plugins.js b/public/src/forum/admin/plugins.js index 733b01ba12..1ae5aa6dd5 100644 --- a/public/src/forum/admin/plugins.js +++ b/public/src/forum/admin/plugins.js @@ -14,7 +14,7 @@ define(function() { pluginID = $(this).parents('li').attr('data-plugin-id'); var btn = $(this); socket.emit('admin.plugins.toggleActive', pluginID, function(err, status) { - btn.html(' ' + status.active ? 'Deactivate' : 'Activate'); + btn.html(' ' + (status.active ? 'Deactivate' : 'Activate')); btn.toggleClass('btn-warning', status.active).toggleClass('btn-success', !status.active); app.alert({ From 62d487e0a8a6e5d5cecd3df6b96a8053b4e21a47 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 7 May 2014 12:46:58 -0400 Subject: [PATCH 36/88] use current user uid for feed generation --- src/routes/feeds.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 65b543f5ca..b42db1b3b3 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -40,8 +40,8 @@ function hasPrivileges(module, id, req, res, next) { function generateForTopic(req, res, next) { var tid = req.params.topic_id; - - topics.getTopicWithPosts(tid, 0, 0, 25, function (err, topicData) { + var uid = req.user ? req.user.uid : 0; + topics.getTopicWithPosts(tid, uid, 0, 25, function (err, topicData) { if (err) { return next(err); } @@ -85,8 +85,8 @@ function generateForTopic(req, res, next) { function generateForCategory(req, res, next) { var cid = req.params.category_id; - - categories.getCategoryById(cid, 0, 25, 0, function (err, categoryData) { + var uid = req.user ? req.user.uid : 0; + categories.getCategoryById(cid, 0, 25, uid, function (err, categoryData) { if (err) { return next(err); } @@ -108,7 +108,7 @@ function generateForRecent(req, res, next) { description: 'A list of topics that have been active within the past 24 hours', feed_url: '/recent.rss', site_url: '/recent' - }, 'topics:recent', res, next); + }, 'topics:recent', req, res, next); } function generateForPopular(req, res, next) { @@ -117,11 +117,12 @@ function generateForPopular(req, res, next) { description: 'A list of topics that are sorted by post count', feed_url: '/popular.rss', site_url: '/popular' - }, 'topics:posts', res, next); + }, 'topics:posts', req, res, next); } -function generateForTopics(options, set, res, next) { - topics.getTopicsFromSet(0, set, 0, 19, function (err, data) { +function generateForTopics(options, set, req, res, next) { + var uid = req.user ? req.user.uid : 0; + topics.getTopicsFromSet(uid, set, 0, 19, function (err, data) { if (err) { return next(err); } From 672bde70668be963b2b60ed3b4cbf2f656324e1a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 7 May 2014 13:27:11 -0400 Subject: [PATCH 37/88] removed ttl --- src/routes/feeds.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/feeds.js b/src/routes/feeds.js index b42db1b3b3..8bfad13bb2 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -135,7 +135,6 @@ function generateForTopics(options, set, req, res, next) { function generateTopicsFeed(feedOptions, topics) { - feedOptions.ttl = 60; feedOptions.feed_url = nconf.get('url') + feedOptions.feed_url; feedOptions.site_url = nconf.get('url') + feedOptions.site_url; From efaa1e62c1ddff39e1aefe479ef7e8c2678f90f3 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 7 May 2014 14:12:53 -0400 Subject: [PATCH 38/88] added back ttl :) --- src/routes/feeds.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 8bfad13bb2..b42db1b3b3 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -135,6 +135,7 @@ function generateForTopics(options, set, req, res, next) { function generateTopicsFeed(feedOptions, topics) { + feedOptions.ttl = 60; feedOptions.feed_url = nconf.get('url') + feedOptions.feed_url; feedOptions.site_url = nconf.get('url') + feedOptions.site_url; From 933aa5dfcbc9f7916d31290b7b1a3778fdb73229 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 7 May 2014 16:11:58 -0400 Subject: [PATCH 39/88] #1501 --- public/src/modules/navigator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index 648b3438b0..1f4e8beb50 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -76,7 +76,7 @@ define(function() { navigator.updateTextAndProgressBar = function() { $('#pagination').html(index + ' out of ' + count); - $('.progress-bar').width((index / count * 100) + '%'); + $('.pagination-block .progress-bar').width((index / count * 100) + '%'); }; navigator.scrollToTop = function () { From 4f5b3cc93443be2a6b04c1576b6f95383a1b881b Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 8 May 2014 00:50:44 -0400 Subject: [PATCH 40/88] changing update script to only directly update vanilla and lavender --- nodebb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nodebb b/nodebb index 8c98a30fcf..2d09f734db 100755 --- a/nodebb +++ b/nodebb @@ -80,8 +80,9 @@ case "$1" in upgrade) npm install - ls -d node_modules/nodebb* | xargs -n1 basename | xargs npm install - ls -d node_modules/nodebb* | xargs -n1 basename | xargs npm update + # ls -d node_modules/nodebb* | xargs -n1 basename | xargs npm install + # ls -d node_modules/nodebb* | xargs -n1 basename | xargs npm update + npm i nodebb-theme-vanilla nodebb-theme-lavender "$node" app --upgrade touch package.json echo -e "\n\e[00;32mNodeBB Dependencies up-to-date!\e[00;00m"; From ed57edde3b14151aa9f1999a2f8cb4539263e623 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 8 May 2014 01:03:03 -0400 Subject: [PATCH 41/88] fixed undefined next --- src/middleware/middleware.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 8301e628c8..bfa7f17a2d 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -279,7 +279,7 @@ middleware.renderHeader = function(req, res, callback) { } }, function(err, results) { if (err) { - return next(err); + return callback(err); } templateValues.browserTitle = results.title; From 7280567d219c49e29363fbd8fb059a5c4f3be6d6 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 8 May 2014 13:24:34 -0400 Subject: [PATCH 42/88] closes #1505 --- src/socket.io/posts.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 47653c7760..32ce86edaa 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -124,16 +124,26 @@ function sendNotificationToPostOwner(data, uid, notification) { } SocketPosts.getRawPost = function(socket, pid, callback) { - posts.getPostFields(pid, ['content', 'deleted'], function(err, data) { + async.waterfall([ + function(next) { + postTools.privileges(pid, socket.uid, next); + }, + function(privileges, next) { + if (!privileges || !privileges.read) { + return next(new Error('[[error:no-privileges]]')); + } + posts.getPostFields(pid, ['content', 'deleted'], next); + } + ], function(err, post) { if(err) { return callback(err); } - if(parseInt(data.deleted, 10) === 1) { + if(parseInt(post.deleted, 10) === 1) { return callback(new Error('[[error:no-post]]')); } - callback(null, data.content); + callback(null, post.content); }); }; From 10716c37d32bf27dd02cb70c07bed0a3296c5c9a Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 8 May 2014 14:16:40 -0400 Subject: [PATCH 43/88] closes #1376 --- public/language/en_GB/user.json | 5 ++++- public/src/ajaxify.js | 3 +++ src/controllers/api.js | 1 + src/user/settings.js | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/public/language/en_GB/user.json b/public/language/en_GB/user.json index 72cfc9bd02..ee6936147c 100644 --- a/public/language/en_GB/user.json +++ b/public/language/en_GB/user.json @@ -65,5 +65,8 @@ "topics_per_page": "Topics per Page", "posts_per_page": "Posts per Page", - "notification_sounds" : "Play a sound when you receive a notification." + "notification_sounds" : "Play a sound when you receive a notification.", + + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index d3f68e8fab..28781a865e 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -261,6 +261,9 @@ var ajaxify = ajaxify || {}; if (config.useOutgoingLinksPage) { ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); e.preventDefault(); + } else if (config.openOutgoingLinksInNewTab) { + window.open(this.href, '_blank'); + e.preventDefault(); } } } diff --git a/src/controllers/api.js b/src/controllers/api.js index 03fdfa46c5..648a5a70c6 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -62,6 +62,7 @@ apiController.getConfig = function(req, res, next) { config.postsPerPage = settings.postsPerPage; config.notificationSounds = settings.notificationSounds; config.defaultLang = settings.language || config.defaultLang; + config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab; if (res.locals.isAPI) { res.json(200, config); diff --git a/src/user/settings.js b/src/user/settings.js index 781b1934f5..73b51c241d 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -25,6 +25,7 @@ module.exports = function(User) { settings = data.settings; settings.showemail = settings.showemail ? parseInt(settings.showemail, 10) !== 0 : false; + settings.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab ? parseInt(settings.openOutgoingLinksInNewTab, 10) !== 0 : false; settings.dailyDigestFreq = settings.dailyDigestFreq || 'daily'; settings.usePagination = settings.usePagination ? parseInt(settings.usePagination, 10) === 1 : parseInt(meta.config.usePagination, 10) === 1; settings.topicsPerPage = settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : parseInt(meta.config.topicsPerPage, 10) || 20; @@ -72,6 +73,7 @@ module.exports = function(User) { plugins.fireHook('action:user.saveSettings', {uid: uid, settings: data}); db.setObject('user:' + uid + ':settings', { showemail: data.showemail, + openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab, dailyDigestFreq: data.dailyDigestFreq || 'daily', usePagination: data.usePagination, topicsPerPage: data.topicsPerPage, From a0fcdfe62972a7ddd3b07e9a0fb7d7c49bd2685a Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 8 May 2014 14:27:46 -0400 Subject: [PATCH 44/88] closes #1502 --- public/language/en_GB/global.json | 1 + public/src/modules/navigator.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/language/en_GB/global.json b/public/language/en_GB/global.json index 6ed0e914b1..d7bea3a7a1 100644 --- a/public/language/en_GB/global.json +++ b/public/language/en_GB/global.json @@ -23,6 +23,7 @@ "close": "Close", "pagination": "Pagination", + "pagination.out_of": "%1 out of %2", "header.admin": "Admin", "header.recent": "Recent", diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index 1f4e8beb50..044a586c68 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -75,7 +75,10 @@ define(function() { }; navigator.updateTextAndProgressBar = function() { - $('#pagination').html(index + ' out of ' + count); + translator.translate('[[global:pagination.out_of, ' + index + ', ' + count + ']]', function(translated) { + $('#pagination').html(translated); + }); + $('.pagination-block .progress-bar').width((index / count * 100) + '%'); }; From d1079c00bcb9f8f6928f2034c4a5c93643525227 Mon Sep 17 00:00:00 2001 From: Schamper Date: Thu, 8 May 2014 20:37:10 +0200 Subject: [PATCH 45/88] Fix Settings Framework example to display proper object path --- docs/plugins/settings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/settings.rst b/docs/plugins/settings.rst index ad1954d853..f761f8115d 100644 --- a/docs/plugins/settings.rst +++ b/docs/plugins/settings.rst @@ -38,7 +38,7 @@ Now you can use the server-side settings-module to access the saved settings lik var mySettings = new Settings('myPlugin', '0.1', defaultSettings, function() { // the settings are ready and can accessed. console.log(mySettings === this); // true - console.log(this.get('someString') === mySettings.get().someString); // true + console.log(this.get('strings.someString') === mySettings.get().strings.someString); // true }); The second parameter should change at least every time the structure of default settings changes. Because of this it's From 2ba2ef5320e2037cb9c9d7762afeb6920cbb8260 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 8 May 2014 14:38:46 -0400 Subject: [PATCH 46/88] closes #1498 --- public/src/modules/composer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index a6c6b0f830..7b3e0299fa 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -610,6 +610,8 @@ define(['taskbar'], function(taskbar) { thumbToggleBtnEl.removeClass('hide'); } }; + + postData.title = $('
    ').html(postData.title).text(); if (parseInt(postData.tid, 10) > 0) { translator.translate('[[topic:composer.replying_to, ' + postData.title + ']]', function(newTitle) { From 66abd206479c9ac6d4c13aa3cb9a9a7fdcaa0264 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 8 May 2014 19:17:31 -0400 Subject: [PATCH 47/88] moved add commas to process page --- public/src/app.js | 2 ++ public/src/forum/account/followers.js | 1 - public/src/forum/account/following.js | 2 -- public/src/forum/account/profile.js | 2 -- public/src/forum/topic.js | 4 +--- public/src/forum/users.js | 2 -- 6 files changed, 3 insertions(+), 10 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index 720fb01d8c..fa6c2a11d5 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -296,6 +296,8 @@ var socket, utils.makeNumbersHumanReadable($('.human-readable-number')); + utils.addCommasToNumbers($('.formatted-number')); + app.createUserTooltips(); app.createStatusTooltips(); diff --git a/public/src/forum/account/followers.js b/public/src/forum/account/followers.js index 9576ad4547..57e39fe54f 100644 --- a/public/src/forum/account/followers.js +++ b/public/src/forum/account/followers.js @@ -13,7 +13,6 @@ define(['forum/account/header'], function(header) { $('#no-followers-notice').removeClass('hide'); } - utils.addCommasToNumbers($('.account .formatted-number')); }; return Followers; diff --git a/public/src/forum/account/following.js b/public/src/forum/account/following.js index 5bbce74d10..0da72b8ccf 100644 --- a/public/src/forum/account/following.js +++ b/public/src/forum/account/following.js @@ -9,8 +9,6 @@ define(['forum/account/header'], function(header) { if (parseInt(followingCount, 10) === 0) { $('#no-following-notice').removeClass('hide'); } - - utils.addCommasToNumbers($('.account .formatted-number')); }; return Following; diff --git a/public/src/forum/account/profile.js b/public/src/forum/account/profile.js index 140f3f53cd..9c45bf6e7b 100644 --- a/public/src/forum/account/profile.js +++ b/public/src/forum/account/profile.js @@ -39,8 +39,6 @@ define(['forum/account/header'], function(header) { }; function processPage() { - utils.addCommasToNumbers($('.account .formatted-number')); - utils.makeNumbersHumanReadable($('.account .human-readable-number')); $('.user-recent-posts img').addClass('img-responsive'); } diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 9b50a2246a..460bfa43b6 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -33,8 +33,6 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', $(window).trigger('action:topic.loading'); - utils.addCommasToNumbers($('.topic .formatted-number')); - app.enterRoom('topic_' + tid); showBottomPostBar(); @@ -110,7 +108,7 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', $this.append(''); } }); - + $('blockquote .toggle').on('click', function() { $(this).parent('blockquote').toggleClass('uncollapsed'); }); diff --git a/public/src/forum/users.js b/public/src/forum/users.js index 898d6ac90c..2187e40ccf 100644 --- a/public/src/forum/users.js +++ b/public/src/forum/users.js @@ -16,8 +16,6 @@ define(function() { var lastSearch = null; - utils.addCommasToNumbers($('.users .formatted-number')); - $('.nav-pills li').removeClass('active'); $('.nav-pills li a').each(function() { var $this = $(this); From 2dd2d7a269ca615e56226e1fee12376b6211181e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 8 May 2014 20:54:00 -0400 Subject: [PATCH 48/88] defaulting daily digest frequency to null -- digests should be opt IN, not OUT. Bad idea on my part... re: #1499 --- src/user/jobs.js | 2 +- src/user/settings.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/user/jobs.js b/src/user/jobs.js index 2655b96a67..d522a8097b 100644 --- a/src/user/jobs.js +++ b/src/user/jobs.js @@ -48,7 +48,7 @@ module.exports = function(User) { // Find uids subscribed to daily digest emails subscribed = userSettings.filter(function(setting) { - return !setting.dailyDigestFreq || setting.dailyDigestFreq === 'daily'; + return setting.dailyDigestFreq === 'daily'; }).map(function(setting) { return setting.uid; }); diff --git a/src/user/settings.js b/src/user/settings.js index 73b51c241d..93dcf0b171 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -26,7 +26,7 @@ module.exports = function(User) { settings.showemail = settings.showemail ? parseInt(settings.showemail, 10) !== 0 : false; settings.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab ? parseInt(settings.openOutgoingLinksInNewTab, 10) !== 0 : false; - settings.dailyDigestFreq = settings.dailyDigestFreq || 'daily'; + settings.dailyDigestFreq = settings.dailyDigestFreq || 'off'; settings.usePagination = settings.usePagination ? parseInt(settings.usePagination, 10) === 1 : parseInt(meta.config.usePagination, 10) === 1; settings.topicsPerPage = settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : parseInt(meta.config.topicsPerPage, 10) || 20; settings.postsPerPage = settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : parseInt(meta.config.postsPerPage, 10) || 10; @@ -74,7 +74,7 @@ module.exports = function(User) { db.setObject('user:' + uid + ':settings', { showemail: data.showemail, openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab, - dailyDigestFreq: data.dailyDigestFreq || 'daily', + dailyDigestFreq: data.dailyDigestFreq || 'off', usePagination: data.usePagination, topicsPerPage: data.topicsPerPage, postsPerPage: data.postsPerPage, From c2fb4700de73adc8860e1823ef110142021c833f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 8 May 2014 22:44:29 -0400 Subject: [PATCH 49/88] fixes infinite scroll on account pages --- public/src/forum/account/favourites.js | 2 +- public/src/forum/account/posts.js | 2 +- public/src/forum/account/topics.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/src/forum/account/favourites.js b/public/src/forum/account/favourites.js index 4ac57931d5..487d0558ad 100644 --- a/public/src/forum/account/favourites.js +++ b/public/src/forum/account/favourites.js @@ -33,7 +33,7 @@ define(['forum/account/header'], function(header) { } function onTopicsLoaded(posts) { - ajaxify.loadTemplate('favourites', function(favouritesTemplate) { + ajaxify.loadTemplate('account/favourites', function(favouritesTemplate) { var html = templates.parse(templates.getBlock(favouritesTemplate, 'posts'), {posts: posts}); translator.translate(html, function(translatedHTML) { diff --git a/public/src/forum/account/posts.js b/public/src/forum/account/posts.js index b7923cf0ba..f3a9a0b0a8 100644 --- a/public/src/forum/account/posts.js +++ b/public/src/forum/account/posts.js @@ -38,7 +38,7 @@ define(['forum/account/header'], function(header) { } function onPostsLoaded(posts) { - ajaxify.loadTemplate('accountposts', function(accountposts) { + ajaxify.loadTemplate('account/posts', function(accountposts) { var html = templates.parse(templates.getBlock(accountposts, 'posts'), {posts: posts}); translator.translate(html, function(translatedHTML) { diff --git a/public/src/forum/account/topics.js b/public/src/forum/account/topics.js index 9b924aa474..6416412c64 100644 --- a/public/src/forum/account/topics.js +++ b/public/src/forum/account/topics.js @@ -36,7 +36,7 @@ define(['forum/account/header'], function(header) { } function onTopicsLoaded(topics) { - ajaxify.loadTemplate('accounttopics', function(accounttopics) { + ajaxify.loadTemplate('account/topics', function(accounttopics) { var html = templates.parse(templates.getBlock(accounttopics, 'topics'), {topics: topics}); translator.translate(html, function(translatedHTML) { From d304bab4f1b03565b78b751a50bf18a58e14cc1b Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 9 May 2014 11:41:41 -0400 Subject: [PATCH 50/88] dont change height if sizing horizontally #1508 --- public/src/modules/chat.js | 3 +++ src/socket.io/index.js | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 21588fbe4b..53fdba680b 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -172,6 +172,9 @@ define(['taskbar', 'string', 'sounds'], function(taskbar, S, sounds) { }); chatModal.find('.modal-content').on('resize', function(event, ui) { + if (ui.originalSize.height === ui.size.height) { + return; + } var totalHeight = chatModal.find('.modal-content').outerHeight() - chatModal.find('.modal-header').outerHeight(); var padding = parseInt(chatModal.find('.modal-body').css('padding-top'), 10) + parseInt(chatModal.find('.modal-body').css('padding-bottom'), 10); var contentMargin = parseInt(chatModal.find('#chat-content').css('margin-top'), 10) + parseInt(chatModal.find('#chat-content').css('margin-bottom'), 10); diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 11c09936e9..1de64d2a32 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -197,8 +197,12 @@ Sockets.in = function(room) { }; Sockets.getConnectedClients = function() { - var clients = io.sockets.clients(); var uids = []; + if (!io) { + return uids; + } + var clients = io.sockets.clients(); + clients.forEach(function(client) { if(client.uid && uids.indexOf(client.uid) === -1) { uids.push(client.uid); From f876ba91b8dbbaec004f0f10d1b241cf1a68315c Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 9 May 2014 11:50:46 -0400 Subject: [PATCH 51/88] Update heroku.rst --- docs/installing/cloud/heroku.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/installing/cloud/heroku.rst b/docs/installing/cloud/heroku.rst index 23ad0f0ee3..6787aecfee 100644 --- a/docs/installing/cloud/heroku.rst +++ b/docs/installing/cloud/heroku.rst @@ -13,6 +13,7 @@ Heroku 8. Enable WebSocket support (beta): ``heroku labs:enable websockets -a {APP_NAME}``, where ``{APP_NAME}`` is provided by Heroku, and looks something like ``adjective-noun-wxyz.herokuapp.com`` (NOTE: `See this doc `_): drop the `.herokuapp.com` when entering ``{APP_NAME}`` above. 9. Enable `Redis To Go `_ for your heroku account: ``heroku addons:add redistogo:nano`` 10. Run the NodeBB setup script: ``node app --setup`` (information for your Heroku server and Redis to Go instance can be found in your account page) + * Your server name is found in your Heroku app's "settings" page, and looks something like ``adjective-noun-wxyz.herokuapp.com`` * Use any port number. It will be ignored. * Specify "n" when asked if a port will be used. Heroku transparently proxies all requests. @@ -44,4 +45,4 @@ If you wish to pull the latest changes from the git repository to your Heroku ap 3. ``npm install`` 4. ``node app --upgrade`` 5. ``git commit -am "upgrading to latest nodebb"`` -6. ``git push heroku master`` \ No newline at end of file +6. ``git push heroku master`` From 43bbc00be8edd5d86ec30bf672d90fcbca135530 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 9 May 2014 11:50:49 -0400 Subject: [PATCH 52/88] closes #1512 spaces are required --- src/socket.io/modules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index cf27156e76..be71fb3c2b 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -194,7 +194,7 @@ SocketModules.chats.send = function(socket, data, callback) { function sendChatNotification(fromuid, touid, username) { if (!module.parent.exports.isUserOnline(touid)) { - var notifText = '[[notifications:new_message_from,' + username + ']]'; + var notifText = '[[notifications:new_message_from, ' + username + ']]'; notifications.create({ text: notifText, path: 'javascript:app.openChat('' + username + '', ' + fromuid + ');', From a5537cb8ae47d7e7b186dcde7a8d953820d4c4b3 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 9 May 2014 12:01:04 -0400 Subject: [PATCH 53/88] Update heroku.rst --- docs/installing/cloud/heroku.rst | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/installing/cloud/heroku.rst b/docs/installing/cloud/heroku.rst index 6787aecfee..6662d0b22b 100644 --- a/docs/installing/cloud/heroku.rst +++ b/docs/installing/cloud/heroku.rst @@ -21,17 +21,30 @@ Heroku * The server is ``fishyfish.redistogo.com`` * The port is ``12345`` * The password is ``h28h3wgh37fns7`` -11. Create a Procfile for Heroku: ``echo "web: node app.js" > Procfile`` -12. Commit the Procfile: + +12. Add the following two packages to the ``dependencies`` section of your ``package.json``: + +.. code:: json + + "dependencies": { + ... + "nodebb-plugin-dbsearch": "0.0.9", + "redis": "~0.10.1", + "connect-redis": "~1.4" + }, + "devDependencies": { + +13. Create a Procfile for Heroku: ``echo "web: node app.js" > Procfile`` +14. Commit the Procfile: .. code:: bash git add -f Procfile config.json public/config.json && git commit -am "adding Procfile and configs for Heroku" -13. Push to heroku: ``git push heroku master`` +15. Push to heroku: ``git push heroku master`` * Ensure that a proper SSH key was added to your account, otherwise the push will not succeed! -14. Initialise a single dyno: ``heroku ps:scale web=1`` -15. Visit your app! +16. Initialise a single dyno: ``heroku ps:scale web=1`` +17. Visit your app! If these instructions are unclear or if you run into trouble, please let us know by `filing an issue `_. From 025db831f4e8fba85faeb65efa75a9afa77daf1f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 9 May 2014 12:01:31 -0400 Subject: [PATCH 54/88] Update heroku.rst --- docs/installing/cloud/heroku.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installing/cloud/heroku.rst b/docs/installing/cloud/heroku.rst index 6662d0b22b..e6aaa6f27a 100644 --- a/docs/installing/cloud/heroku.rst +++ b/docs/installing/cloud/heroku.rst @@ -39,7 +39,7 @@ Heroku .. code:: bash - git add -f Procfile config.json public/config.json && git commit -am "adding Procfile and configs for Heroku" + git add -f Procfile config.json package.json && git commit -am "adding Procfile and configs for Heroku" 15. Push to heroku: ``git push heroku master`` * Ensure that a proper SSH key was added to your account, otherwise the push will not succeed! From 99b34d5990b99860912a99e9c195ee420124511f Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 9 May 2014 12:47:42 -0400 Subject: [PATCH 55/88] allow translator variables to not require a space, see #1512 --- public/src/translator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/translator.js b/public/src/translator.js index 52fc5a4f5d..59ba32cb9b 100644 --- a/public/src/translator.js +++ b/public/src/translator.js @@ -108,7 +108,7 @@ var key = keys[i]; key = '' + key; - var variables = key.split(/[,][?\s+]/); + var variables = key.split(/[,][\s]*/); var parsedKey = key.replace('[[', '').replace(']]', '').split(':'); if (!(parsedKey[0] && parsedKey[1])) { From 643dd74e43c5e8be6c71fb7114ad2b27cf2bd1f1 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 9 May 2014 12:56:51 -0400 Subject: [PATCH 56/88] initially hide the account setting menus (prevents the brief flashing of the buttons) https://github.com/designcreateplay/nodebb-theme-vanilla/commit/5589e1e148c6499b4e5005fd0c8b5b97882cfb8d --- public/src/forum/account/header.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/public/src/forum/account/header.js b/public/src/forum/account/header.js index c2d33546eb..687860554c 100644 --- a/public/src/forum/account/header.js +++ b/public/src/forum/account/header.js @@ -2,28 +2,26 @@ define(function() { var AccountHeader = {}; AccountHeader.init = function() { - - hideLinks(); - + displayAccountMenus(); selectActivePill(); }; - function hideLinks() { + function displayAccountMenus() { var yourid = ajaxify.variables.get('yourid'), theirid = ajaxify.variables.get('theirid'); - var editLink = $('#editLink'); - var settingsLink = $('#settingsLink'); - var favouritesLink = $('#favouritesLink'); + var editLink = $('#editLink'), + settingsLink = $('#settingsLink'), + favouritesLink = $('#favouritesLink'); - if (parseInt(yourid, 10) === 0 || parseInt(yourid, 10) !== parseInt(theirid, 10)) { - editLink.hide(); - settingsLink.hide(); - favouritesLink.hide(); + if (parseInt(yourid, 10) !== 0 && parseInt(yourid, 10) === parseInt(theirid, 10)) { + editLink.removeClass('hide'); + settingsLink.removeClass('hide'); + favouritesLink.removeClass('hide'); } if(app.isAdmin) { - editLink.show(); + editLink.removeClass('hide'); } } From 274acc8eece762a561552cd5eb117fa04c303a62 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 9 May 2014 13:47:29 -0400 Subject: [PATCH 57/88] moved base_templates_path to load config #1511 --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 11cfb82d0b..b2fc88cfc8 100644 --- a/app.js +++ b/app.js @@ -97,6 +97,7 @@ function loadConfig() { // Ensure themes_path is a full filepath nconf.set('themes_path', path.resolve(__dirname, nconf.get('themes_path'))); + nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-vanilla/templates')); } function start() { @@ -134,7 +135,6 @@ function start() { plugins.init(); nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path')); - nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-vanilla/templates')); plugins.ready(function() { webserver.init(); From 4c28de659c4e9fbe85388b872824dc268f761928 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 9 May 2014 17:46:10 -0400 Subject: [PATCH 58/88] closes #1504 --- public/src/app.js | 5 +++-- public/src/modules/chat.js | 11 +++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index fa6c2a11d5..c0cc527544 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -382,13 +382,15 @@ var socket, } if (title.length > 0 && !app.isFocused) { + if (!titleObj.titles[0]) { + titleObj.titles[0] = window.document.title; + } titleObj.titles[1] = title; if (titleObj.interval) { clearInterval(titleObj.interval); } titleObj.interval = setInterval(function() { var title = titleObj.titles[titleObj.titles.indexOf(window.document.title) ^ 1]; - if (title) { window.document.title = title; } @@ -532,7 +534,6 @@ var socket, $(window).focus(function(){ app.isFocused = true; - app.alternatingTitle(''); }); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 53fdba680b..46024ed3b0 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -53,7 +53,8 @@ define(['taskbar', 'string', 'sounds'], function(taskbar, S, sounds) { socket.on('event:chats.receive', function(data) { var username = data.message.fromUser.username; - if(parseInt(data.message.fromUser.uid, 10) === parseInt(app.uid, 10)) { + var isSelf = parseInt(data.message.fromUser.uid, 10) === parseInt(app.uid, 10); + if (isSelf) { username = data.message.toUser.username; } @@ -70,17 +71,19 @@ define(['taskbar', 'string', 'sounds'], function(taskbar, S, sounds) { module.toggleNew(modal.attr('UUID'), true); } - if (!modal.is(":visible") || !app.isFocused) { + if (!isSelf && (!modal.is(":visible") || !app.isFocused)) { app.alternatingTitle(username + ' has messaged you'); } } else { module.createModal(username, data.withUid, function(modal) { module.toggleNew(modal.attr('UUID'), true); - app.alternatingTitle(username + ' has messaged you'); + if (!isSelf) { + app.alternatingTitle(username + ' has messaged you'); + } }); } - if (parseInt(app.uid, 10) !== parseInt(data.message.fromuid, 10)) { + if (!isSelf) { sounds.play('chat-incoming'); } }); From 8ee866fc9dfb7d490064943f8a5fcec2d835a02d Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 9 May 2014 17:57:39 -0400 Subject: [PATCH 59/88] closes #1513 --- public/language/en_GB/modules.json | 3 ++- public/src/app.js | 22 +++++++++++++--------- public/src/modules/chat.js | 7 +++++-- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/public/language/en_GB/modules.json b/public/language/en_GB/modules.json index 8616bf0298..90ad8c6546 100644 --- a/public/language/en_GB/modules.json +++ b/public/language/en_GB/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "type chat message here, press enter to send", "chat.send": "Send", "chat.no_active": "You have no active chats.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/src/app.js b/public/src/app.js index c0cc527544..edf22a0c50 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -385,16 +385,20 @@ var socket, if (!titleObj.titles[0]) { titleObj.titles[0] = window.document.title; } - titleObj.titles[1] = title; - if (titleObj.interval) { - clearInterval(titleObj.interval); - } - titleObj.interval = setInterval(function() { - var title = titleObj.titles[titleObj.titles.indexOf(window.document.title) ^ 1]; - if (title) { - window.document.title = title; + + translator.translate(title, function(translated) { + titleObj.titles[1] = translated; + if (titleObj.interval) { + clearInterval(titleObj.interval); } - }, 2000); + + titleObj.interval = setInterval(function() { + var title = titleObj.titles[titleObj.titles.indexOf(window.document.title) ^ 1]; + if (title) { + window.document.title = title; + } + }, 2000); + }); } else { if (titleObj.interval) { clearInterval(titleObj.interval); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 46024ed3b0..93c2c93f7a 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -72,13 +72,13 @@ define(['taskbar', 'string', 'sounds'], function(taskbar, S, sounds) { } if (!isSelf && (!modal.is(":visible") || !app.isFocused)) { - app.alternatingTitle(username + ' has messaged you'); + app.alternatingTitle('[[modules:chat.user_has_messaged_you, ' + username + ']]'); } } else { module.createModal(username, data.withUid, function(modal) { module.toggleNew(modal.attr('UUID'), true); if (!isSelf) { - app.alternatingTitle(username + ' has messaged you'); + app.alternatingTitle('[[modules:chat.user_has_messaged_you, ' + username + ']]'); } }); } @@ -91,6 +91,9 @@ define(['taskbar', 'string', 'sounds'], function(taskbar, S, sounds) { socket.on('event:chats.userStartTyping', function(withUid) { var modal = module.getModal(withUid); var chatContent = modal.find('#chat-content'); + if (!chatContent.length) { + return; + } var atBottom = chatContent[0].scrollHeight - chatContent.scrollTop() === chatContent.innerHeight(); modal.find('.user-typing').removeClass('hide').appendTo(chatContent); From ab2c0cfa9f62b9b226269ac3ab0f64995bd17ccb Mon Sep 17 00:00:00 2001 From: FrissDieGurke Date: Sat, 10 May 2014 19:49:50 +0200 Subject: [PATCH 60/88] added number-type to settings framework. persist expanded object on server-side sync if changed --- public/src/modules/settings.js | 1 + public/src/modules/settings/number.js | 14 ++++++++++++++ src/settings.js | 12 +++++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 public/src/modules/settings/number.js diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index fa9ac0ac3d..2cb33163bb 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -2,6 +2,7 @@ define(function () { const DEFAULT_PLUGINS = [ 'settings/checkbox', + 'settings/number', 'settings/textarea', 'settings/select', 'settings/array', diff --git a/public/src/modules/settings/number.js b/public/src/modules/settings/number.js new file mode 100644 index 0000000000..5c98a86abc --- /dev/null +++ b/public/src/modules/settings/number.js @@ -0,0 +1,14 @@ +define(function () { + + return { + types: ['number'], + get: function (element, trim, empty) { + var value = element.val(); + if (!empty) { + return value ? +value : void 0; + } + return value ? +value : 0; + } + }; + +}); diff --git a/src/settings.js b/src/settings.js index 2286f26b1d..dfb65aaf9d 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1,16 +1,20 @@ var meta = require('./meta'); function expandObjBy(obj1, obj2) { - var key, val1, val2; + var key, val1, val2, changed = false; for (key in obj2) { val2 = obj2[key]; val1 = obj1[key]; if (!obj1.hasOwnProperty(key) || typeof val2 !== typeof val1) { obj1[key] = val2; + changed = true; } else if (typeof val2 === 'object') { - expandObjBy(val1, val2); + if (expandObjBy(val1, val2)) { + changed = true; + } } } + return changed; } function trim(obj1, obj2) { @@ -76,7 +80,9 @@ Settings.prototype.sync = function (callback) { } } catch (_error) {} _this.cfg = settings; - if (typeof callback === 'function') { + if (expandObjBy(_this.cfg._, _this.defCfg)) { + _this.persist(callback); + } else if (typeof callback === 'function') { callback.apply(_this, err); } }); From d0be73a4d4ca0b5c68e6b897a38bf161809ab3d3 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 10 May 2014 15:48:09 -0400 Subject: [PATCH 61/88] closes #1503 --- public/src/modules/alerts.js | 120 +++++++++++++++++------------------ 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/public/src/modules/alerts.js b/public/src/modules/alerts.js index 0c88017adb..3b103a1f18 100644 --- a/public/src/modules/alerts.js +++ b/public/src/modules/alerts.js @@ -7,88 +7,86 @@ define(function() { // use unique alert_id to have multiple alerts visible at a time, use the same alert_id to fade out the current instance // type : error, success, info, warning/notify - // title = bolded title text - // message = alert message content // timeout default = permanent - // location : alert_window (default) or content module.alert = function (params) { - var alert_id = 'alert_button_' + ((params.alert_id) ? params.alert_id : new Date().getTime()); - - var alert = $('#' + alert_id); - var title = params.title || ''; - - function fadeOut() { - alert.fadeOut(500, function () { - $(this).remove(); - }); - } - - function startTimeout(timeout) { - var timeoutId = setTimeout(function () { - fadeOut(); - }, timeout); - - alert.attr('timeoutId', timeoutId); - } + params.alert_id = 'alert_button_' + (params.alert_id ? params.alert_id : new Date().getTime()); + params.title = params.title || ''; + params.location = (params.location || 'right-top'); + var alert = $('#' + params.alert_id); if (alert.length) { - alert.find('strong').html(title); - alert.find('p').html(params.message); - alert.attr('class', 'alert alert-dismissable alert-' + params.type); - - clearTimeout(alert.attr('timeoutId')); - startTimeout(params.timeout); - - alert.children().fadeOut('100'); - translator.translate(templates.parse(alert.html(), {}), function(translatedHTML) { - alert.children().fadeIn('100'); - alert.html(translatedHTML); - }); + updateAlert(alert, params); } else { - alert = $('
    '); + createNew(params); + } + }; - alert.append($('')) - .append($('' + title + '')); + function createNew(params) { - if (params.message) { - alert.append($('

    ' + params.message + '

    ')); - } + templates.parse('alert', params, function(alertTpl) { - if (!params.location) { - params.location = 'alert_window'; - } + translator.translate(alertTpl, function(translatedHTML) { + var alert = $(translatedHTML); + alert.fadeIn(200); - translator.translate(templates.parse(alert.html(), {}), function(translatedHTML) { - alert.html(translatedHTML); - $('#' + params.location).prepend(alert.fadeIn('100')); + $('.alert-' + params.location).prepend(alert); if(typeof params.closefn === 'function') { alert.find('button').on('click', function() { params.closefn(); - fadeOut(); + fadeOut(alert); return false; }); } + + if (params.timeout) { + startTimeout(alert, params.timeout); + } + + if (typeof params.clickfn === 'function') { + alert.on('click', function (e) { + if(!$(e.target).is('.close')) { + params.clickfn(); + } + fadeOut(alert); + }); + } }); - - if (params.timeout) { - startTimeout(params.timeout); - } - - if (typeof params.clickfn === 'function') { - alert.on('click', function (e) { - if(!$(e.target).is('.close')) { - params.clickfn(); - } - fadeOut(); - }); - } - } - }; + }); + } module.remove = function(id) { $('#alert_button_' + id).remove(); }; + function updateAlert(alert, params) { + alert.find('strong').html(params.title); + alert.find('p').html(params.message); + alert.attr('class', 'alert alert-dismissable alert-' + params.type); + + clearTimeout(alert.attr('timeoutId')); + startTimeout(alert, params.timeout); + + alert.children().fadeOut(100); + translator.translate(alert.html(), function(translatedHTML) { + alert.children().fadeIn(100); + alert.html(translatedHTML); + }); + } + + function fadeOut(alert) { + alert.fadeOut(500, function () { + $(this).remove(); + }); + } + + function startTimeout(alert, timeout) { + var timeoutId = setTimeout(function () { + fadeOut(alert); + }, timeout); + + alert.attr('timeoutId', timeoutId); + } + return module; }); From db27a30005f1f0b48fe39dfde9495f5d97d691d7 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Sat, 10 May 2014 15:53:06 -0400 Subject: [PATCH 62/88] better alert for ban message --- public/language/en_GB/global.json | 2 +- public/language/en_US/global.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/language/en_GB/global.json b/public/language/en_GB/global.json index d7bea3a7a1..709e0bc94a 100644 --- a/public/language/en_GB/global.json +++ b/public/language/en_GB/global.json @@ -47,7 +47,7 @@ "alert.error": "Error", "alert.banned": "Banned", - "alert.banned.message": "You are banned you will be logged out!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "You are no longer following %1!", "alert.follow": "You are now following %1!", diff --git a/public/language/en_US/global.json b/public/language/en_US/global.json index 9673ee4afb..6e1c26500a 100644 --- a/public/language/en_US/global.json +++ b/public/language/en_US/global.json @@ -35,7 +35,7 @@ "alert.success": "Success", "alert.error": "Error", "alert.banned": "Banned", - "alert.banned.message": "You are banned you will be logged out!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "You are no longer following %1!", "alert.follow": "You are now following %1!", "online": "Online", From 74aabb9c601ba54a61e741bde00200eeaeadfba1 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Sat, 10 May 2014 16:16:35 -0400 Subject: [PATCH 63/88] modules documentation - alerts --- docs/index.rst | 1 + docs/modules/index.rst | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 docs/modules/index.rst diff --git a/docs/index.rst b/docs/index.rst index c48eb05adc..c086e5b737 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -64,6 +64,7 @@ Contributing to NodeBB :maxdepth: 2 contributing/style-guide + modules/index Plugin System ------------- diff --git a/docs/modules/index.rst b/docs/modules/index.rst new file mode 100644 index 0000000000..843548ee00 --- /dev/null +++ b/docs/modules/index.rst @@ -0,0 +1,42 @@ +Core Modules +================ + +.. note:: + + This section is under construction. Have a look at the modules folder for more information, located at: + + .. code:: bash + + public/src/modules + +Alerts +------- + +The alert module is a toaster notification that can be called via the following syntax: + +.. code:: javascript + + app.alert({ + title: 'Success!', + message: 'Here\'s an example of an alert!', + location: 'left-bottom', + timeout: 2500, + type: 'success', + image: 'https://i.imgur.com/dJBzcGT.jpg' + }); + +The above code will result in this notification (default styling): + +.. image:: http://i.imgur.com/jRD5GAI.png + +To style this, have a look at the vanilla theme's ``modules/alert.less`` and ``templates/alert.tpl``. + +**Parameters**: + +1. ``title`` - string, which can be a language string as well. Some core language strings that you can use here include: ``[[global:alert.success]]`` and ``[[global:alert.error]]`` +2. ``message`` - string, which can be a language string as well. +3. ``location`` (optional) - ``right-top`` (default), ``left-top``, ``right-bottom``, ``left-bottom`` +4. ``timeout`` (optional) - integer in milliseconds, default is permanent until closed. +5. ``type`` - error, success, info, warning/notify +6. ``image`` (optional) - string, URL to image. + From f7fe0aa680cb6e15c2ab4ebfa7e44e7becd43806 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Sat, 10 May 2014 16:16:56 -0400 Subject: [PATCH 64/88] moved documentation out of alerts --- public/src/modules/alerts.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/public/src/modules/alerts.js b/public/src/modules/alerts.js index 3b103a1f18..5f2518b8ce 100644 --- a/public/src/modules/alerts.js +++ b/public/src/modules/alerts.js @@ -5,9 +5,6 @@ define(function() { var module = {}; - // use unique alert_id to have multiple alerts visible at a time, use the same alert_id to fade out the current instance - // type : error, success, info, warning/notify - // timeout default = permanent module.alert = function (params) { params.alert_id = 'alert_button_' + (params.alert_id ? params.alert_id : new Date().getTime()); params.title = params.title || ''; @@ -22,9 +19,7 @@ define(function() { }; function createNew(params) { - templates.parse('alert', params, function(alertTpl) { - translator.translate(alertTpl, function(translatedHTML) { var alert = $(translatedHTML); alert.fadeIn(200); From 2649e6a385d9c62791bc2d9899b1ebf7f7179b72 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Sat, 10 May 2014 16:24:44 -0400 Subject: [PATCH 65/88] use secure image instead --- docs/modules/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/index.rst b/docs/modules/index.rst index 843548ee00..63531097a4 100644 --- a/docs/modules/index.rst +++ b/docs/modules/index.rst @@ -27,7 +27,7 @@ The alert module is a toaster notification that can be called via the following The above code will result in this notification (default styling): -.. image:: http://i.imgur.com/jRD5GAI.png +.. image:: https://i.imgur.com/jRD5GAI.png To style this, have a look at the vanilla theme's ``modules/alert.less`` and ``templates/alert.tpl``. From f65998f4c21a3b49b9fdace5b15f3a2089010020 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 10 May 2014 18:41:28 -0400 Subject: [PATCH 66/88] fixes guest name on home --- src/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user.js b/src/user.js index 041bdfc07c..029897383e 100644 --- a/src/user.js +++ b/src/user.js @@ -114,7 +114,7 @@ var bcrypt = require('bcryptjs'), user.password = null; } - if (parseInt(user.uid, 10) === 0) { + if (!parseInt(user.uid, 10)) { user.username = '[[global:guest]]'; user.userslug = ''; } From 65dd79c84ed3ef85abc830e5d5fbb9c972cc94f0 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sat, 10 May 2014 23:43:15 -0400 Subject: [PATCH 67/88] socket logic for #1149 -- handling of help tab in ACP --- public/src/modules/composer.js | 2 +- src/socket.io/modules.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 7b3e0299fa..ebe720c44c 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -819,7 +819,7 @@ define(['taskbar'], function(taskbar) { }); socket.emit('modules.composer.renderHelp', function(err, html) { - if (html && html.length > 0) { + if (!err && html && html.length > 0) { postContainer.find('.help').html(html); postContainer.find('[data-pane=".tab-help"]').parent().removeClass('hidden'); } diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index be71fb3c2b..74b5a4c280 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -100,7 +100,19 @@ SocketModules.composer.renderPreview = function(socket, content, callback) { }; SocketModules.composer.renderHelp = function(socket, data, callback) { - plugins.fireHook('filter:composer.help', '', callback); + var helpText = meta.config['composer:customHelpText'] || ''; + + if (meta.config['composer:showHelpTab'] === '0') { + return callback(new Error('help-hidden')); + } + + plugins.fireHook('filter:post.parse', helpText, function(err, helpText) { + if (!meta.config['composer:allowPluginHelp'] || meta.config['composer:allowPluginHelp'] === '1') { + plugins.fireHook('filter:composer.help', helpText, callback); + } else { + callback(null, helpText); + } + }); }; SocketModules.composer.register = function(socket, data) { From 4e0ccbf0c6c775f9e80f617d83751657e4389b77 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sat, 10 May 2014 23:56:45 -0400 Subject: [PATCH 68/88] fixed #1515 --- src/image.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/image.js b/src/image.js index 0d6fd8c75b..73bb85599d 100644 --- a/src/image.js +++ b/src/image.js @@ -15,10 +15,12 @@ image.resizeImage = function(path, extension, width, height, callback) { gm().in(path) .in('-coalesce') .in('-resize') - .in(width+'x'+height) + .in(width+'x'+height+'^') .write(path, done); } else { gm(path) + .in('-resize') + .in(width+'x'+height+'^') .gravity('Center') .crop(width, height) .write(path, done); From bab140c3969e53727d73c56558745918956bd07b Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 11 May 2014 10:31:32 -0400 Subject: [PATCH 69/88] added pexpire and pexpireAt methods for redis and mongo. Added emoticons for leveldb (as per existing implementation by @psychobunny LOL) --- src/database/level/main.js | 8 ++++++++ src/database/mongo/main.js | 8 ++++++++ src/database/redis/main.js | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/src/database/level/main.js b/src/database/level/main.js index 9f4736de44..a147803029 100644 --- a/src/database/level/main.js +++ b/src/database/level/main.js @@ -75,4 +75,12 @@ module.exports = function(db, module) { module.expireAt = function(key, timestamp, callback) { // <__< }; + + module.pexpire = function(key, ms, callback) { + // o_o + }; + + module.pexpireAt = function(key, timestamp, callback) { + // d-_-b + }; }; \ No newline at end of file diff --git a/src/database/mongo/main.js b/src/database/mongo/main.js index 1d3d13d388..834ad4e150 100644 --- a/src/database/mongo/main.js +++ b/src/database/mongo/main.js @@ -90,4 +90,12 @@ module.exports = function(db, module) { module.expireAt = function(key, timestamp, callback) { module.setObjectField(key, 'expireAt', new Date(timestamp * 1000), callback); }; + + module.pexpire = function(key, ms, callback) { + module.expireAt(key, Date.now() + parseInt(ms, 10), callback); + }; + + module.pexpireAt = function(key, timestamp, callback) { + module.setObjectField(key, 'expireAt', new Date(timestamp), callback); + }; }; \ No newline at end of file diff --git a/src/database/redis/main.js b/src/database/redis/main.js index 4e7ec1a5f4..2525b4972f 100644 --- a/src/database/redis/main.js +++ b/src/database/redis/main.js @@ -96,4 +96,12 @@ module.exports = function(redisClient, module) { module.expireAt = function(key, timestamp, callback) { redisClient.expireat(key, timestamp, callback); }; + + module.pexpire = function(key, ms, callback) { + redisClient.pexpire(key, ms, callback); + }; + + module.expireAt = function(key, timestamp, callback) { + redisClient.pexpireat(key, timestamp, callback); + }; }; \ No newline at end of file From e64c1bfec3749faa378d9cd5929538332242f8db Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 11 May 2014 11:45:20 -0400 Subject: [PATCH 70/88] closed #1453 --- public/language/en_GB/error.json | 1 + public/src/forum/login.js | 6 ++++- src/database/level/main.js | 4 +++ src/database/mongo/main.js | 4 +++ src/database/redis/main.js | 6 ++++- src/routes/authentication.js | 45 +++++++++++++++++++------------- src/user.js | 1 + src/user/auth.js | 32 +++++++++++++++++++++++ 8 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 src/user/auth.js diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index f44565d61d..d7e0d6e0d2 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -2,6 +2,7 @@ "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", diff --git a/public/src/forum/login.js b/public/src/forum/login.js index 5741cb0079..632844560d 100644 --- a/public/src/forum/login.js +++ b/public/src/forum/login.js @@ -45,7 +45,11 @@ define(function() { app.loadConfig(); }, error: function(data, textStatus, jqXHR) { - $('#login-error-notify').show(); + // Update error text + translator.translate(data.responseJSON, function(errorText) { + $('#login-error-notify').show().html(errorText); + }); + $('#login').removeAttr('disabled').html('Login'); }, dataType: 'json', diff --git a/src/database/level/main.js b/src/database/level/main.js index a147803029..bbde367fc9 100644 --- a/src/database/level/main.js +++ b/src/database/level/main.js @@ -64,6 +64,10 @@ module.exports = function(db, module) { } }; + module.increment = function(key, callback) { + // ^_^ + }; + module.rename = function(oldKey, newKey, callback) { // G__G }; diff --git a/src/database/mongo/main.js b/src/database/mongo/main.js index 834ad4e150..d7c41e4cb9 100644 --- a/src/database/mongo/main.js +++ b/src/database/mongo/main.js @@ -79,6 +79,10 @@ module.exports = function(db, module) { module.setObject(key, data, callback); }; + module.increment = function(key, callback) { + db.collection('objects').update({_key: key}, { $inc: { value: 1 } }, helpers.done(callback)); + }; + module.rename = function(oldKey, newKey, callback) { db.collection('objects').update({_key: oldKey}, {$set:{_key: newKey}}, helpers.done(callback)); }; diff --git a/src/database/redis/main.js b/src/database/redis/main.js index 2525b4972f..caeb6ab70b 100644 --- a/src/database/redis/main.js +++ b/src/database/redis/main.js @@ -85,6 +85,10 @@ module.exports = function(redisClient, module) { redisClient.set(key, value, callback); }; + module.increment = function(key, callback) { + redisClient.incr(key, callback); + }; + module.rename = function(oldKey, newKey, callback) { redisClient.rename(oldKey, newKey, callback); }; @@ -101,7 +105,7 @@ module.exports = function(redisClient, module) { redisClient.pexpire(key, ms, callback); }; - module.expireAt = function(key, timestamp, callback) { + module.pexpireAt = function(key, timestamp, callback) { redisClient.pexpireat(key, timestamp, callback); }; }; \ No newline at end of file diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 53d1953bec..131ab47ec0 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -171,35 +171,44 @@ } if(!uid) { - // Even if a user doesn't exist, compare passwords anyway, so we don't immediately return + // To-do: Even if a user doesn't exist, compare passwords anyway, so we don't immediately return return next(null, false, '[[error:no-user]]'); } - db.getObjectFields('user:' + uid, ['password', 'banned'], function(err, userData) { + user.auth.logAttempt(uid, function(err) { if (err) { - return next(err); + return next(null, false, err.message); } - if (!userData || !userData.password) { - return next(new Error('[[error:invalid-user-data]]')); - } - - if (userData.banned && parseInt(userData.banned, 10) === 1) { - return next(null, false, '[[error:user-banned]]'); - } - - bcrypt.compare(password, userData.password, function(err, res) { + db.getObjectFields('user:' + uid, ['password', 'banned'], function(err, userData) { if (err) { - return next(new Error('bcrypt compare error')); + return next(err); } - if (!res) { - return next(null, false, '[[error:invalid-password]]'); + if (!userData || !userData.password) { + return next(new Error('[[error:invalid-user-data]]')); } - next(null, { - uid: uid - }, '[[success:authentication-successful]]'); + if (userData.banned && parseInt(userData.banned, 10) === 1) { + return next(null, false, '[[error:user-banned]]'); + } + + bcrypt.compare(password, userData.password, function(err, res) { + if (err) { + return next(new Error('bcrypt compare error')); + } + + if (!res) { + return next(null, false, '[[error:invalid-password]]'); + } + + // Clear login attempts + user.auth.clearLoginAttempts(uid); + + next(null, { + uid: uid + }, '[[success:authentication-successful]]'); + }); }); }); }); diff --git a/src/user.js b/src/user.js index 029897383e..077a1e3d0f 100644 --- a/src/user.js +++ b/src/user.js @@ -23,6 +23,7 @@ var bcrypt = require('bcryptjs'), User.notifications = require('./user/notifications'); User.reset = require('./user/reset'); + require('./user/auth')(User); require('./user/create')(User); require('./user/follow')(User); require('./user/profile')(User); diff --git a/src/user/auth.js b/src/user/auth.js new file mode 100644 index 0000000000..71de297ca0 --- /dev/null +++ b/src/user/auth.js @@ -0,0 +1,32 @@ +var db = require('../database'), + meta = require('../meta'); + +module.exports = function(User) { + User.auth = {}; + + User.auth.logAttempt = function(uid, callback) { + db.exists('lockout:' + uid, function(err, exists) { + if (!exists) { + db.increment('loginAttempts:' + uid, function(err, attempts) { + if ((meta.config.loginAttempts || 5) < attempts) { + // Lock out the account + db.set('lockout:' + uid, '', function(err) { + db.delete('loginAttempts:' + uid); + db.pexpire('lockout:' + uid, 1000*60*(meta.config.lockoutDuration || 60)); + callback(new Error('account-locked')); + }); + } else { + db.pexpire('loginAttempts:' + uid, 1000*60*60); + callback(); + } + }); + } else { + callback(new Error('[[error:account-locked]]')); + } + }) + }; + + User.auth.clearLoginAttempts = function(uid) { + db.delete('loginAttempts:' + uid); + }; +}; \ No newline at end of file From f618a9405e679b6d5a5e60cec90d56623182c446 Mon Sep 17 00:00:00 2001 From: FrissDieGurke Date: Sun, 11 May 2014 18:58:01 +0200 Subject: [PATCH 71/88] added settings number-field to docs --- docs/plugins/settings.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/settings.rst b/docs/plugins/settings.rst index f761f8115d..7ab7febb53 100644 --- a/docs/plugins/settings.rst +++ b/docs/plugins/settings.rst @@ -151,7 +151,7 @@ Additionally the following plugins are registered by default: Uses ``data-new`` to define the value of new created elements. * key (types: key) A field to input keyboard-combinations. - * checkbox, select, textarea + * checkbox, number, select, textarea Handle appropriate fields. A full list of all attributes that may influence the behavior of the default Framework: @@ -303,4 +303,4 @@ For further impression take a look at the You should also take a look at the helper-functions within `Settings `_ in order to create -your own plugins. There are a few methods that take response to call the methods of other plugins when fittingly. \ No newline at end of file +your own plugins. There are a few methods that take response to call the methods of other plugins when fittingly. From d311995c1644dc2f054297c0a26f86396541e271 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 11 May 2014 14:06:15 -0400 Subject: [PATCH 72/88] closes #1516 --- public/src/forum/admin/settings.js | 56 ++++++++++++++++++------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/public/src/forum/admin/settings.js b/public/src/forum/admin/settings.js index 6bc5d782d0..b2315aa33e 100644 --- a/public/src/forum/admin/settings.js +++ b/public/src/forum/admin/settings.js @@ -53,11 +53,39 @@ define(['uploader', 'sounds'], function(uploader, sounds) { } } - saveBtn.on('click', function(e) { + saveBtn.off('click').on('click', function(e) { e.preventDefault(); + var done = 0, + error; for (x = 0; x < numFields; x++) { - saveField(fields[x]); + saveField(fields[x], onFieldSaved); + } + + function onFieldSaved(err) { + if (!error && err) { + error = err; + } + + done++; + if (done === numFields) { + if (error) { + return app.alert({ + alert_id: 'config_status', + timeout: 2500, + title: 'Changes Not Saved', + message: 'NodeBB encountered a problem saving your changes', + type: 'danger' + }); + } + app.alert({ + alert_id: 'config_status', + timeout: 2500, + title: 'Changes Saved', + message: 'Your changes to the NodeBB configuration have been saved.', + type: 'success' + }); + } } }); @@ -91,7 +119,7 @@ define(['uploader', 'sounds'], function(uploader, sounds) { socket.emit('admin.config.remove', key); }; - function saveField(field) { + function saveField(field, callback) { field = $(field); var key = field.attr('data-field'), value, inputType; @@ -118,28 +146,10 @@ define(['uploader', 'sounds'], function(uploader, sounds) { key: key, value: value }, function(err) { - if(err) { - return app.alert({ - alert_id: 'config_status', - timeout: 2500, - title: 'Changes Not Saved', - message: 'NodeBB encountered a problem saving your changes', - type: 'danger' - }); - } - - if(app.config[key] !== undefined) { + if(!err && app.config[key] !== undefined) { app.config[key] = value; } - - app.alert({ - alert_id: 'config_status', - timeout: 2500, - title: 'Changes Saved', - message: 'Your changes to the NodeBB configuration have been saved.', - type: 'success' - }); - + callback(err); }); } From c3e4c7dea1ea8ee594e5f1ac576c7497b9a6fa5b Mon Sep 17 00:00:00 2001 From: psychobunny Date: Sun, 11 May 2014 16:34:21 -0400 Subject: [PATCH 73/88] using var instead of const for < IE10 compatibility @frissdiegurke --- public/src/modules/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index 2cb33163bb..77aea5d342 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -1,6 +1,6 @@ define(function () { - const DEFAULT_PLUGINS = [ + var DEFAULT_PLUGINS = [ 'settings/checkbox', 'settings/number', 'settings/textarea', From f2a692add792fc9864d4611489cff4d9ff0fb3d1 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Sun, 11 May 2014 16:41:26 -0400 Subject: [PATCH 74/88] some linting of settings.js --- public/src/modules/settings.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index 77aea5d342..56636b9489 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -1,3 +1,6 @@ +"use strict"; +/*global define, app, socket*/ + define(function () { var DEFAULT_PLUGINS = [ @@ -58,7 +61,9 @@ define(function () { createElement: function (tagName, data, text) { var element = document.createElement(tagName); for (var k in data) { - element.setAttribute(k, data[k]); + if (data.hasOwnProperty(k)) { + element.setAttribute(k, data[k]); + } } if (text) { element.appendChild(document.createTextNode(text)); @@ -103,7 +108,7 @@ define(function () { if (type != null) { data.type = type; } - element = $(helper.createElement(tagName || 'input', data)) + element = $(helper.createElement(tagName || 'input', data)); } element.data('type', type); helper.initElement(element); From 78ccca4f636ac06c4034da83af665675d353d5cf Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 11 May 2014 18:57:18 -0400 Subject: [PATCH 75/88] removed comment --- src/routes/authentication.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 131ab47ec0..b203952b99 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -202,7 +202,6 @@ return next(null, false, '[[error:invalid-password]]'); } - // Clear login attempts user.auth.clearLoginAttempts(uid); next(null, { From 1a9ab9d1d2fc273eb7875a40e7bde6d9dec7ac5c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 11 May 2014 19:39:52 -0400 Subject: [PATCH 76/88] fixes default gravatar images if they are uploaded locally --- src/user.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/user.js b/src/user.js index 077a1e3d0f..43d30b353c 100644 --- a/src/user.js +++ b/src/user.js @@ -274,10 +274,14 @@ var bcrypt = require('bcryptjs'), }; User.createGravatarURLFromEmail = function(email) { + var customGravatarDefaultImage = meta.config.customGravatarDefaultImage; + if (customGravatarDefaultImage && customGravatarDefaultImage.indexOf('http') === -1) { + customGravatarDefaultImage = nconf.get('url') + meta.config.customGravatarDefaultImage; + } var options = { size: '128', - default: meta.config.customGravatarDefaultImage || meta.config.defaultGravatarImage || '', + default: customGravatarDefaultImage || meta.config.defaultGravatarImage || '', rating: 'pg' }; From 2bd15e155f1385426128c214250b4c2ca0260a0c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 11 May 2014 20:31:42 -0400 Subject: [PATCH 77/88] remove listener before adding --- public/src/forum/home.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/src/forum/home.js b/public/src/forum/home.js index 122b524b8b..3796b2ca6f 100644 --- a/public/src/forum/home.js +++ b/public/src/forum/home.js @@ -15,6 +15,7 @@ define(function() { home.init = function() { app.enterRoom('home'); + socket.removeListener('event:new_post', home.onNewPost); socket.on('event:new_post', home.onNewPost); $('.home .category-header').tooltip({ From 41c5a909149bb763d40189a1ed7b1f46c1482493 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 11 May 2014 23:08:28 -0400 Subject: [PATCH 78/88] latest language strings --- public/language/de/global.json | 8 ++++---- public/language/de/topic.json | 2 +- public/language/fr/topic.json | 2 +- public/language/pt_BR/global.json | 24 ++++++++++++------------ public/language/pt_BR/topic.json | 14 +++++++------- public/language/tr/topic.json | 2 +- public/language/vi/global.json | 6 +++--- public/language/vi/user.json | 2 +- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/public/language/de/global.json b/public/language/de/global.json index b4a3c84b07..2a9b0dab8e 100644 --- a/public/language/de/global.json +++ b/public/language/de/global.json @@ -45,12 +45,12 @@ "views": "Aufrufe", "reputation": "Reputation", "read_more": "weiterlesen", - "posted_ago_by_guest": "%1 verfasst von einem Gast", - "posted_ago_by": "Geposted %1 von %2", - "posted_ago": "schrieb %1", + "posted_ago_by_guest": "%1 von einem Gast geschrieben", + "posted_ago_by": "%1 von %2 geschrieben", + "posted_ago": "%1 geschrieben", "posted_in_ago_by_guest": "verfasst in %1 %2 von einem Gast", "posted_in_ago_by": "Verfasst in %1 %2 von %3", - "posted_in_ago": "posted in %1 %2", + "posted_in_ago": "Verfasst in %1 %2", "replied_ago": "antwortete %1", "user_posted_ago": "1% schrieb %2", "guest_posted_ago": "Gast schrieb %1", diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 28dc42c156..47d7a98fb9 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -7,7 +7,7 @@ "post_is_deleted": "Dieser Beitrag wurde gelöscht!", "profile": "Profil", "posted_by": "Geschrieben von %1", - "posted_by_guest": "Posted by Guest", + "posted_by_guest": "Verfasst von einem Gast", "chat": "Chat", "notify_me": "Werde bei neues Antworten auf dieses Thema benachrichtigt.", "quote": "zitieren", diff --git a/public/language/fr/topic.json b/public/language/fr/topic.json index 235603073a..7112846ed8 100644 --- a/public/language/fr/topic.json +++ b/public/language/fr/topic.json @@ -7,7 +7,7 @@ "post_is_deleted": "Ce message a été supprimé!", "profile": "Profil", "posted_by": "Posté par %1", - "posted_by_guest": "Posted by Guest", + "posted_by_guest": "Posté par un Invité", "chat": "Chat", "notify_me": "Être notifié des réponses dans ce sujet", "quote": "Citer", diff --git a/public/language/pt_BR/global.json b/public/language/pt_BR/global.json index bab2e65d8c..1f865ed750 100644 --- a/public/language/pt_BR/global.json +++ b/public/language/pt_BR/global.json @@ -45,16 +45,16 @@ "views": "Visualizações", "reputation": "Reputação", "read_more": "leia mais", - "posted_ago_by_guest": "posted %1 by Guest", - "posted_ago_by": "posted %1 by %2", - "posted_ago": "posted %1", - "posted_in_ago_by_guest": "posted in %1 %2 by Guest", - "posted_in_ago_by": "posted in %1 %2 by %3", - "posted_in_ago": "posted in %1 %2", - "replied_ago": "replied %1", - "user_posted_ago": "%1 posted %2", - "guest_posted_ago": "Guest posted %1", - "last_edited_by_ago": "last edited by %1 %2", + "posted_ago_by_guest": "postado %1 por Visitante", + "posted_ago_by": "postado %1 por %2", + "posted_ago": "postou %1", + "posted_in_ago_by_guest": "postado em %1 %2 por Visitante", + "posted_in_ago_by": "postado em %1 %2 por %3", + "posted_in_ago": "postado em %1 %2", + "replied_ago": "respondeu %1", + "user_posted_ago": "%1 postou %2", + "guest_posted_ago": "Visitante postou %1", + "last_edited_by_ago": "editado em %1 %2", "norecentposts": "Nenhum Post Recente", "norecenttopics": "Nenhum Tópico Recente", "recentposts": "Posts Recentes", @@ -65,6 +65,6 @@ "offline": "Offline", "email": "Email", "language": "Linguagem", - "guest": "Guest", - "guests": "Guests" + "guest": "Visitante", + "guests": "Visitantes" } \ No newline at end of file diff --git a/public/language/pt_BR/topic.json b/public/language/pt_BR/topic.json index daf029be0b..94e9a4a593 100644 --- a/public/language/pt_BR/topic.json +++ b/public/language/pt_BR/topic.json @@ -4,10 +4,10 @@ "topic_id_placeholder": "Digite o ID do tópico", "no_topics_found": "Nenhum tópico encontrado!", "no_posts_found": "Nenhum post encontrado!", - "post_is_deleted": "This post is deleted!", + "post_is_deleted": "Este post está excluído!", "profile": "Perfil", - "posted_by": "Posted by %1", - "posted_by_guest": "Posted by Guest", + "posted_by": "Postado por %1", + "posted_by_guest": "Postado por Visitante", "chat": "Bate Papo", "notify_me": "Ser notificado a cada nova resposta", "quote": "Citar", @@ -41,7 +41,7 @@ "thread_tools.lock": "Trancar Tópico", "thread_tools.unlock": "Destrancar Tópico", "thread_tools.move": "Mover Tópico", - "thread_tools.move_all": "Move All", + "thread_tools.move_all": "Mover todos", "thread_tools.fork": "Clonar Tópico", "thread_tools.delete": "Deletar Tópico", "thread_tools.delete_confirm": "Tem certeza que deseja deletar este tópico?", @@ -88,7 +88,7 @@ "composer.thumb_remove": "Limpar campos", "composer.drag_and_drop_images": "Clique e arraste imagens para este campo.", "composer.upload_instructions": "Mande suas imagens arrastando e soltando.", - "more_users_and_guests": "%1 more user(s) and %2 guest(s)", - "more_users": "%1 more user(s)", - "more_guests": "%1 more guest(s)" + "more_users_and_guests": "%1 mais usuário(s) e %2 visitante(s)", + "more_users": "%1 mais usuário(s)", + "more_guests": "%1 mais visitante(s)" } \ No newline at end of file diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json index 7a0758a998..6336a11268 100644 --- a/public/language/tr/topic.json +++ b/public/language/tr/topic.json @@ -7,7 +7,7 @@ "post_is_deleted": "Bu ileti silinmiş!", "profile": "Profil", "posted_by": "%1 tarafından gönderildi", - "posted_by_guest": "Posted by Guest", + "posted_by_guest": "Ziyaretçi tarafından yayımlandı", "chat": "Sohbet", "notify_me": "Bu konudaki cevaplardan haberdar ol", "quote": "Alıntı", diff --git a/public/language/vi/global.json b/public/language/vi/global.json index 92ccbe6b3d..3d50015d6c 100644 --- a/public/language/vi/global.json +++ b/public/language/vi/global.json @@ -34,7 +34,7 @@ "nextpage": "Trang kế tiếp", "alert.success": "Thành công", "alert.error": "Lỗi", - "alert.banned": "Bị ban", + "alert.banned": "Bị cấm", "alert.banned.message": "Bạn đã bị ban, giờ bạn sẽ đăng xuất", "alert.unfollow": "Bạn đã không còn theo dõi %1!", "alert.follow": "Bạn giờ đang theo dõi %1!", @@ -59,8 +59,8 @@ "norecenttopics": "Không có chủ đề gần đây", "recentposts": "Số bài viết gần đây", "recentips": "Các IP vừa mới đăng nhập", - "away": "Đang away", - "dnd": "Không được quấy rầy", + "away": "Đang đi vắng", + "dnd": "Đang bận", "invisible": "Ẩn", "offline": "Đang offline", "email": "Email", diff --git a/public/language/vi/user.json b/public/language/vi/user.json index fa9fc38c60..79bd0fa9dc 100644 --- a/public/language/vi/user.json +++ b/public/language/vi/user.json @@ -1,5 +1,5 @@ { - "banned": "Bị ban", + "banned": "Bị cấm", "offline": "Offline", "username": "Tên truy cập", "email": "Email", From b1257f6291519e3c2d66bdf4eb9551aa63eb1aec Mon Sep 17 00:00:00 2001 From: frissdiegurke Date: Mon, 12 May 2014 13:40:19 +0200 Subject: [PATCH 79/88] fix call of expandObjBy with undefined --- src/settings.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/settings.js b/src/settings.js index dfb65aaf9d..1c5992b945 100644 --- a/src/settings.js +++ b/src/settings.js @@ -8,10 +8,8 @@ function expandObjBy(obj1, obj2) { if (!obj1.hasOwnProperty(key) || typeof val2 !== typeof val1) { obj1[key] = val2; changed = true; - } else if (typeof val2 === 'object') { - if (expandObjBy(val1, val2)) { - changed = true; - } + } else if (typeof val2 === 'object' && expandObjBy(val1, val2)) { + changed = true; } } return changed; @@ -30,7 +28,10 @@ function trim(obj1, obj2) { } function mergeSettings(cfg, defCfg) { - if (typeof cfg._ !== typeof defCfg || typeof defCfg !== 'object') { + if (typeof defCfg !== 'object') { + return; + } + if (typeof cfg._ !== 'object') { cfg._ = defCfg; } else { expandObjBy(cfg._, defCfg); @@ -80,7 +81,10 @@ Settings.prototype.sync = function (callback) { } } catch (_error) {} _this.cfg = settings; - if (expandObjBy(_this.cfg._, _this.defCfg)) { + if (typeof _this.cfg._ !== 'object') { + _this.cfg._ = _this.defCfg; + _this.persist(callback); + } else if (expandObjBy(_this.cfg._, _this.defCfg)) { _this.persist(callback); } else if (typeof callback === 'function') { callback.apply(_this, err); From 3c7b433e3a5ca5e81f9b4639cab335a7f3273b99 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 12 May 2014 12:59:34 -0400 Subject: [PATCH 80/88] linting settings.js --- src/settings.js | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/settings.js b/src/settings.js index 1c5992b945..3d90dcfa84 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1,15 +1,19 @@ +"use strict"; + var meta = require('./meta'); function expandObjBy(obj1, obj2) { var key, val1, val2, changed = false; for (key in obj2) { - val2 = obj2[key]; - val1 = obj1[key]; - if (!obj1.hasOwnProperty(key) || typeof val2 !== typeof val1) { - obj1[key] = val2; - changed = true; - } else if (typeof val2 === 'object' && expandObjBy(val1, val2)) { - changed = true; + if (obj2.hasOwnProperty(key)) { + val2 = obj2[key]; + val1 = obj1[key]; + if (!obj1.hasOwnProperty(key) || typeof val2 !== typeof val1) { + obj1[key] = val2; + changed = true; + } else if (typeof val2 === 'object' && expandObjBy(val1, val2)) { + changed = true; + } } } return changed; @@ -18,12 +22,14 @@ function expandObjBy(obj1, obj2) { function trim(obj1, obj2) { var key, val1; for (key in obj1) { - val1 = obj1[key]; - if (!obj2.hasOwnProperty(key)) { - delete obj1[key]; - } else if (typeof val1 === 'object') { - trim(val1, obj2[key]); - } + if (obj1.hasOwnProperty(key)) { + val1 = obj1[key]; + if (!obj2.hasOwnProperty(key)) { + delete obj1[key]; + } else if (typeof val1 === 'object') { + trim(val1, obj2[key]); + } + } } } From 240932dd80a1f078e1fc9ec5f78efee404e06e4d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 12 May 2014 13:02:48 -0400 Subject: [PATCH 81/88] add cursor: pointer if alert's clickfn is defined --- public/src/modules/alerts.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/public/src/modules/alerts.js b/public/src/modules/alerts.js index 5f2518b8ce..6516dc48ea 100644 --- a/public/src/modules/alerts.js +++ b/public/src/modules/alerts.js @@ -39,12 +39,14 @@ define(function() { } if (typeof params.clickfn === 'function') { - alert.on('click', function (e) { - if(!$(e.target).is('.close')) { - params.clickfn(); - } - fadeOut(alert); - }); + alert + .addClass('pointer') + .on('click', function (e) { + if(!$(e.target).is('.close')) { + params.clickfn(); + } + fadeOut(alert); + }); } }); }); From 9efc3417720bda9cd18a63bb2ee8ab4da5620251 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 12 May 2014 13:03:49 -0400 Subject: [PATCH 82/88] updated docs for alert closefn/clickfn --- docs/modules/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/modules/index.rst b/docs/modules/index.rst index 63531097a4..d4fb3ad985 100644 --- a/docs/modules/index.rst +++ b/docs/modules/index.rst @@ -39,4 +39,5 @@ To style this, have a look at the vanilla theme's ``modules/alert.less`` and ``t 4. ``timeout`` (optional) - integer in milliseconds, default is permanent until closed. 5. ``type`` - error, success, info, warning/notify 6. ``image`` (optional) - string, URL to image. - +7. ``closefn`` (optional) - function. This is called when the user closes the alert via the (X) button. +8. ``clickfn`` (optional) - function. This is called when the user clicks on the alert. \ No newline at end of file From c7744d7a64f5c3bedf7049f5cde811a4768285bf Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 12 May 2014 14:51:39 -0400 Subject: [PATCH 83/88] closes #1483 --- src/notifications.js | 24 ++++++++++++++---------- src/socket.io/admin/user.js | 6 +++--- src/socket.io/posts.js | 36 +++++++++++++++++++++++++++++++----- src/user/admin.js | 1 + 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index 4ea446d882..183a4c34a7 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -115,17 +115,21 @@ var async = require('async'), Notifications.get(nid, null, function(notif_data) { async.each(uids, function(uid, next) { - if (parseInt(uid, 10) > 0) { - checkReplace(notif_data.uniqueId, uid, notif_data, function(err, replace) { - if (replace) { - db.sortedSetAdd('uid:' + uid + ':notifications:unread', notif_data.datetime, nid); - websockets.in('uid_' + uid).emit('event:new_notification', notif_data); - } + if (!parseInt(uid, 10)) { + next(); + } - if (callback) { - callback(true); - } - }); + checkReplace(notif_data.uniqueId, uid, notif_data, function(err, replace) { + if (replace) { + db.sortedSetAdd('uid:' + uid + ':notifications:unread', notif_data.datetime, nid); + websockets.in('uid_' + uid).emit('event:new_notification', notif_data); + } + next(); + }); + + }, function(err) { + if (callback) { + callback(true); } }); }); diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index ec20007661..a07cdc1be8 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -39,10 +39,10 @@ User.banUsers = function(socket, uids, callback) { return callback(new Error('[[error:invalid-data]]')); } - async.each(uids, banUser, callback); + async.each(uids, User.banUser, callback); }; -function banUser(uid, callback) { +User.banUser = function(uid, callback) { user.isAdministrator(uid, function(err, isAdmin) { if (err || isAdmin) { return callback(err || new Error('[[error:cant-ban-other-admins]]')); @@ -63,7 +63,7 @@ function banUser(uid, callback) { callback(); }); }); -} +}; User.unbanUsers = function(socket, uids, callback) { if(!Array.isArray(uids)) { diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 32ce86edaa..865c26a769 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -3,6 +3,7 @@ var async = require('async'), nconf = require('nconf'), + db = require('../database'), posts = require('../posts'), meta = require('../meta'), topics = require('../topics'), @@ -262,7 +263,8 @@ SocketPosts.flag = function(socket, pid, callback) { } var message = '', - path = ''; + path = '', + post; async.waterfall([ function(next) { @@ -270,10 +272,11 @@ SocketPosts.flag = function(socket, pid, callback) { }, function(username, next) { message = '[[notifications:user_flagged_post, ' + username + ']]'; - posts.getPostField(pid, 'tid', next); + posts.getPostFields(pid, ['tid', 'uid'], next); }, - function(tid, next) { - topics.getTopicField(tid, 'slug', next); + function(postData, next) { + post = postData; + topics.getTopicField(postData.tid, 'slug', next); }, function(topicSlug, next) { path = nconf.get('relative_path') + '/topic/' + topicSlug + '#' + pid; @@ -287,7 +290,30 @@ SocketPosts.flag = function(socket, pid, callback) { from: socket.uid }, function(nid) { notifications.push(nid, adminGroup.members, function() { - next(null); + next(); + }); + }); + }, + function(next) { + if (!parseInt(post.uid, 10)) { + return next(); + } + + db.setAdd('uid:' + post.uid + ':flagged_by', socket.uid, function(err) { + if (err) { + return next(err); + } + db.setCount('uid:' + post.uid + ':flagged_by', function(err, count) { + if (err) { + return next(err); + } + + if (count >= (meta.config.flagsForBan || 3)) { + var adminUser = require('./admin/user'); + adminUser.banUser(post.uid, next); + return; + } + next(); }); }); } diff --git a/src/user/admin.js b/src/user/admin.js index b6b97b2065..d489f16446 100644 --- a/src/user/admin.js +++ b/src/user/admin.js @@ -50,6 +50,7 @@ module.exports = function(User) { }; User.unban = function(uid, callback) { + db.delete('uid:' + uid + ':flagged_by'); User.setUserField(uid, 'banned', 0, callback); }; }; From fc00586f0e3a173cb73f439d16d7b435fdd2f427 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 12 May 2014 14:53:53 -0400 Subject: [PATCH 84/88] 0 disables flags for ban --- src/socket.io/posts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 865c26a769..30d7f018c1 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -308,7 +308,7 @@ SocketPosts.flag = function(socket, pid, callback) { return next(err); } - if (count >= (meta.config.flagsForBan || 3)) { + if (count >= (meta.config.flagsForBan || 3) && parseInt(meta.config.flagsForBan, 10) !== 0) { var adminUser = require('./admin/user'); adminUser.banUser(post.uid, next); return; From c5d9a68b4bb992b511cd82017626b62a949130da Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 12 May 2014 18:42:13 -0400 Subject: [PATCH 85/88] closes #1445 --- public/language/en_GB/modules.json | 3 ++- public/src/forum/chats.js | 16 ++++++++++++++++ public/src/modules/chat.js | 5 +++++ src/controllers/accounts.js | 15 ++++++++++++++- src/messaging.js | 4 ++-- src/routes/index.js | 3 +++ src/socket.io/modules.js | 2 +- 7 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 public/src/forum/chats.js diff --git a/public/language/en_GB/modules.json b/public/language/en_GB/modules.json index 90ad8c6546..b1d1903a79 100644 --- a/public/language/en_GB/modules.json +++ b/public/language/en_GB/modules.json @@ -4,5 +4,6 @@ "chat.send": "Send", "chat.no_active": "You have no active chats.", "chat.user_typing": "%1 is typing ...", - "chat.user_has_messaged_you": "%1 has messaged you." + "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.see_all": "See all Chats" } \ No newline at end of file diff --git a/public/src/forum/chats.js b/public/src/forum/chats.js new file mode 100644 index 0000000000..58a758d031 --- /dev/null +++ b/public/src/forum/chats.js @@ -0,0 +1,16 @@ +'use strict'; + +/* globals define, app*/ + +define(function() { + var Chats = {}; + + Chats.init = function() { + + $('.chats-list').on('click', 'li', function(e) { + app.openChat($(this).attr('data-username'), $(this).attr('data-uid')); + }); + }; + + return Chats; +}); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 93c2c93f7a..e68130519f 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -47,6 +47,11 @@ define(['taskbar', 'string', 'sounds'], function(taskbar, S, sounds) { userObj.username + '') .appendTo(chatsListEl); } + + var seeAll = '
  • '; + translator.translate(seeAll, function(translated) { + $(translated).appendTo(chatsListEl); + }); }); }); diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index bb5c6a0e05..dfeee5ae2b 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -11,6 +11,7 @@ var fs = require('fs'), user = require('./../user'), posts = require('./../posts'), topics = require('./../topics'), + messaging = require('../messaging'), postTools = require('../postTools'), utils = require('./../../public/src/utils'), meta = require('./../meta'), @@ -448,7 +449,7 @@ accountsController.uploadPicture = function (req, res, next) { }); } - if(err) { + if (err) { fs.unlink(req.files.userPhoto.path); return res.json({error:err.message}); } @@ -487,4 +488,16 @@ accountsController.getNotifications = function(req, res, next) { }); }; +accountsController.getChats = function(req, res, next) { + messaging.getRecentChats(req.user.uid, 0, -1, function(err, chats) { + if (err) { + return next(err); + } + + res.render('chats', { + chats: chats + }); + }); +}; + module.exports = accountsController; diff --git a/src/messaging.js b/src/messaging.js index 49426d971c..25bdeb9c51 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -121,8 +121,8 @@ var db = require('./database'), }); }; - Messaging.getRecentChats = function(uid, callback) { - db.getSortedSetRevRange('uid:' + uid + ':chats', 0, 9, function(err, uids) { + Messaging.getRecentChats = function(uid, start, end, callback) { + db.getSortedSetRevRange('uid:' + uid + ':chats', start, end, function(err, uids) { if(err) { return callback(err); } diff --git a/src/routes/index.js b/src/routes/index.js index 71deb793df..247350d77a 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -101,6 +101,9 @@ function accountRoutes(app, middleware, controllers) { app.get('/notifications', middleware.buildHeader, middleware.authenticate, controllers.accounts.getNotifications); app.get('/api/notifications', middleware.authenticate, controllers.accounts.getNotifications); + + app.get('/chats', middleware.buildHeader, middleware.authenticate, controllers.accounts.getChats); + app.get('/api/chats', middleware.authenticate, controllers.accounts.getChats); } function userRoutes(app, middleware, controllers) { diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 74b5a4c280..2a7159b0da 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -238,7 +238,7 @@ function sendTypingNotification(event, socket, data, callback) { } SocketModules.chats.list = function(socket, data, callback) { - Messaging.getRecentChats(socket.uid, callback); + Messaging.getRecentChats(socket.uid, 0, 9, callback); }; /* Notifications */ From 97d256c372dc4fa00b9b5e6b5690f3027020199a Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 13 May 2014 12:09:21 -0400 Subject: [PATCH 86/88] cleanup --- src/emitter.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/emitter.js b/src/emitter.js index 2d076613be..aa88cd5024 100644 --- a/src/emitter.js +++ b/src/emitter.js @@ -1,4 +1,6 @@ +"use strict"; + var events = require('events'), eventEmitter = new events.EventEmitter(); -module.exports = eventEmitter; +module.exports = eventEmitter; \ No newline at end of file From ea6576c6f3a174e4bd833ca22998f97155dcb02d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 13 May 2014 16:39:56 -0400 Subject: [PATCH 87/88] latest translations and fallbacks --- public/language/ar/error.json | 1 + public/language/ar/global.json | 3 +- public/language/ar/modules.json | 3 +- public/language/ar/topic.json | 1 + public/language/ar/user.json | 4 +- public/language/cs/error.json | 1 + public/language/cs/global.json | 3 +- public/language/cs/modules.json | 3 +- public/language/cs/topic.json | 1 + public/language/cs/user.json | 4 +- public/language/de/error.json | 1 + public/language/de/modules.json | 3 +- public/language/de/user.json | 4 +- public/language/en@pirate/error.json | 1 + public/language/en@pirate/global.json | 3 +- public/language/en@pirate/modules.json | 3 +- public/language/en@pirate/topic.json | 1 + public/language/en@pirate/user.json | 4 +- public/language/en_US/error.json | 1 + public/language/en_US/modules.json | 3 +- public/language/en_US/topic.json | 1 + public/language/en_US/user.json | 4 +- public/language/es/error.json | 95 +++++++++++++------------- public/language/es/global.json | 37 +++++----- public/language/es/modules.json | 3 +- public/language/es/success.json | 8 +-- public/language/es/topic.json | 25 +++---- public/language/es/unread.json | 8 +-- public/language/es/user.json | 6 +- public/language/et/error.json | 1 + public/language/et/global.json | 3 +- public/language/et/modules.json | 3 +- public/language/et/topic.json | 1 + public/language/et/user.json | 4 +- public/language/fa_IR/error.json | 1 + public/language/fa_IR/global.json | 3 +- public/language/fa_IR/modules.json | 3 +- public/language/fa_IR/topic.json | 1 + public/language/fa_IR/user.json | 4 +- public/language/fi/error.json | 1 + public/language/fi/global.json | 3 +- public/language/fi/modules.json | 3 +- public/language/fi/topic.json | 1 + public/language/fi/user.json | 4 +- public/language/fr/error.json | 1 + public/language/fr/global.json | 3 +- public/language/fr/modules.json | 3 +- public/language/fr/user.json | 4 +- public/language/he/error.json | 1 + public/language/he/global.json | 3 +- public/language/he/modules.json | 3 +- public/language/he/topic.json | 1 + public/language/he/user.json | 4 +- public/language/hu/error.json | 1 + public/language/hu/global.json | 3 +- public/language/hu/modules.json | 3 +- public/language/hu/topic.json | 1 + public/language/hu/user.json | 4 +- public/language/it/error.json | 1 + public/language/it/global.json | 3 +- public/language/it/modules.json | 3 +- public/language/it/topic.json | 1 + public/language/it/user.json | 4 +- public/language/ja/error.json | 1 + public/language/ja/global.json | 3 +- public/language/ja/modules.json | 3 +- public/language/ja/topic.json | 1 + public/language/ja/user.json | 4 +- public/language/lt/error.json | 1 + public/language/lt/global.json | 3 +- public/language/lt/modules.json | 3 +- public/language/lt/topic.json | 1 + public/language/lt/user.json | 4 +- public/language/ms/error.json | 1 + public/language/ms/global.json | 3 +- public/language/ms/modules.json | 3 +- public/language/ms/topic.json | 1 + public/language/ms/user.json | 4 +- public/language/nb/error.json | 1 + public/language/nb/global.json | 3 +- public/language/nb/modules.json | 3 +- public/language/nb/topic.json | 1 + public/language/nb/user.json | 4 +- public/language/nl/error.json | 1 + public/language/nl/global.json | 3 +- public/language/nl/modules.json | 3 +- public/language/nl/topic.json | 1 + public/language/nl/user.json | 4 +- public/language/pl/error.json | 1 + public/language/pl/global.json | 3 +- public/language/pl/modules.json | 3 +- public/language/pl/topic.json | 1 + public/language/pl/user.json | 4 +- public/language/pt_BR/error.json | 1 + public/language/pt_BR/modules.json | 3 +- public/language/pt_BR/user.json | 4 +- public/language/ru/error.json | 1 + public/language/ru/global.json | 3 +- public/language/ru/modules.json | 3 +- public/language/ru/topic.json | 1 + public/language/ru/user.json | 4 +- public/language/sc/error.json | 1 + public/language/sc/global.json | 3 +- public/language/sc/modules.json | 3 +- public/language/sc/topic.json | 1 + public/language/sc/user.json | 4 +- public/language/sk/error.json | 1 + public/language/sk/global.json | 3 +- public/language/sk/modules.json | 3 +- public/language/sk/topic.json | 1 + public/language/sk/user.json | 4 +- public/language/sv/error.json | 1 + public/language/sv/global.json | 3 +- public/language/sv/modules.json | 3 +- public/language/sv/topic.json | 1 + public/language/sv/user.json | 4 +- public/language/th/error.json | 1 + public/language/th/global.json | 3 +- public/language/th/modules.json | 3 +- public/language/th/topic.json | 1 + public/language/th/user.json | 4 +- public/language/tr/error.json | 1 + public/language/tr/global.json | 3 +- public/language/tr/modules.json | 3 +- public/language/tr/user.json | 4 +- public/language/vi/error.json | 1 + public/language/vi/modules.json | 3 +- public/language/vi/topic.json | 1 + public/language/zh_CN/error.json | 1 + public/language/zh_CN/global.json | 3 +- public/language/zh_CN/modules.json | 3 +- public/language/zh_CN/topic.json | 1 + public/language/zh_CN/user.json | 4 +- public/language/zh_TW/error.json | 1 + public/language/zh_TW/global.json | 3 +- public/language/zh_TW/modules.json | 3 +- public/language/zh_TW/topic.json | 1 + public/language/zh_TW/user.json | 4 +- 138 files changed, 331 insertions(+), 167 deletions(-) diff --git a/public/language/ar/error.json b/public/language/ar/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/ar/global.json b/public/language/ar/global.json index 638f37e5f5..7b464c9098 100644 --- a/public/language/ar/global.json +++ b/public/language/ar/global.json @@ -18,6 +18,7 @@ "save_changes": "حفظ التغييرات", "close": "أغلق", "pagination": "Pagination", + "pagination.out_of": "%1 out of %2", "header.admin": "مشرف", "header.recent": "حديث", "header.unread": "غير مقروء", @@ -35,7 +36,7 @@ "alert.success": "Success", "alert.error": "Error", "alert.banned": "Banned", - "alert.banned.message": "You are banned you will be logged out!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "You are no longer following %1!", "alert.follow": "You are now following %1!", "online": "Online", diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index 3807c7eed0..5d725f1837 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "اكتب رسالة دردشة هنا، وإضغط ENTER لإرسال", "chat.send": "أرسل", "chat.no_active": "لا يوجد لديك دردشات نشطة.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/ar/topic.json b/public/language/ar/topic.json index 851e1e0f7e..83ddde998d 100644 --- a/public/language/ar/topic.json +++ b/public/language/ar/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "ليس لديك أي ردود مفضلة. فضل بعد الردود لرؤيتهم هنا", "loading_more_posts": "تحميل المزيد من المشاركات", "move_topic": "نقل الموضوع", + "move_topics": "Move Topics", "move_post": "نقل الرد", "post_moved": "Post moved!", "fork_topic": "فرع الموضوع", diff --git a/public/language/ar/user.json b/public/language/ar/user.json index 3610171116..43764c322d 100644 --- a/public/language/ar/user.json +++ b/public/language/ar/user.json @@ -58,5 +58,7 @@ "paginate_description": "Paginate topics and posts instead of using infinite scroll.", "topics_per_page": "Topics per Page", "posts_per_page": "Posts per Page", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/cs/error.json b/public/language/cs/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/cs/global.json b/public/language/cs/global.json index eb9a0f0a8c..900c8ece9f 100644 --- a/public/language/cs/global.json +++ b/public/language/cs/global.json @@ -18,6 +18,7 @@ "save_changes": "Uložit změny", "close": "Zrušit", "pagination": "Pagination", + "pagination.out_of": "%1 out of %2", "header.admin": "Administrace", "header.recent": "Aktuality", "header.unread": "Nepřečtené", @@ -35,7 +36,7 @@ "alert.success": "Success", "alert.error": "Error", "alert.banned": "Banned", - "alert.banned.message": "You are banned you will be logged out!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "You are no longer following %1!", "alert.follow": "You are now following %1!", "online": "Online", diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index 246dc038af..d18979b634 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "napište zprávu sem a zmáčkněte enter pro odeslání", "chat.send": "Odeslat", "chat.no_active": "Nemáte žádné aktivní konverzace.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/cs/topic.json b/public/language/cs/topic.json index 4220fc9499..9fab09ff70 100644 --- a/public/language/cs/topic.json +++ b/public/language/cs/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Nemáte žádné oblíbené příspěvky, přidejte některý příspěvek k oblíbeným a uvidíte ho zde!", "loading_more_posts": "Načítání více příspěvků", "move_topic": "Přesunout téma", + "move_topics": "Move Topics", "move_post": "Přesunout příspěvek", "post_moved": "Post moved!", "fork_topic": "Rozdělit příspěvek", diff --git a/public/language/cs/user.json b/public/language/cs/user.json index f715deab17..f5cdff83dd 100644 --- a/public/language/cs/user.json +++ b/public/language/cs/user.json @@ -58,5 +58,7 @@ "paginate_description": "Paginate topics and posts instead of using infinite scroll.", "topics_per_page": "Topics per Page", "posts_per_page": "Posts per Page", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/de/error.json b/public/language/de/error.json index a9e4fc5e7a..ec0565eaed 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Daten ungültig", "not-logged-in": "Du bist nicht angemeldet", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Ungültige Kategorie-ID", "invalid-tid": "Ungültige Themen-ID", "invalid-pid": "Ungültige Beitrags-ID", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index c96be3d194..c1bc0fd5d0 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "Schreibe hier etwas, und drücke Enter zum absenden.", "chat.send": "Senden", "chat.no_active": "Du hast keine aktiven Chats.", - "chat.user_typing": "%1 tippt gerade ..." + "chat.user_typing": "%1 tippt gerade ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index e22d148bcd..319e7f16a6 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -58,5 +58,7 @@ "paginate_description": "Themen und Beiträge auf Seiten aufteilen statt unendliches Scrollen verweden", "topics_per_page": "Themen pro Seite", "posts_per_page": "Beiträge pro Seite", - "notification_sounds": "Ton abspielen, wenn ich eine Benachrichtigung erhalte." + "notification_sounds": "Ton abspielen, wenn ich eine Benachrichtigung erhalte.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/en@pirate/error.json b/public/language/en@pirate/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/en@pirate/error.json +++ b/public/language/en@pirate/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/en@pirate/global.json b/public/language/en@pirate/global.json index b6765d066e..90b4338269 100644 --- a/public/language/en@pirate/global.json +++ b/public/language/en@pirate/global.json @@ -18,6 +18,7 @@ "save_changes": "Save yer Changes", "close": "Shoot down", "pagination": "Pagination", + "pagination.out_of": "%1 out of %2", "header.admin": "Captains only", "header.recent": "Recent", "header.unread": "Undiscovered", @@ -35,7 +36,7 @@ "alert.success": "Success", "alert.error": "Somethin' broke", "alert.banned": "Exiled", - "alert.banned.message": "Ye be banned ye gunna be logged out!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Ye be no longer stalkin' %1!", "alert.follow": "Ye be stalkin' %1", "online": "Available", diff --git a/public/language/en@pirate/modules.json b/public/language/en@pirate/modules.json index ceabc625a8..4655d3b822 100644 --- a/public/language/en@pirate/modules.json +++ b/public/language/en@pirate/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "Yer message goes here, hit enter to send 'er off", "chat.send": "Send Parrot", "chat.no_active": "Ye be a lonely sailor.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/en@pirate/topic.json b/public/language/en@pirate/topic.json index e5c97c09f1..1b9c6a40f0 100644 --- a/public/language/en@pirate/topic.json +++ b/public/language/en@pirate/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "You don't have any favourites, favourite some posts to see them here!", "loading_more_posts": "Loading More Posts", "move_topic": "Move Topic", + "move_topics": "Move Topics", "move_post": "Move Post", "post_moved": "Post moved!", "fork_topic": "Fork Topic", diff --git a/public/language/en@pirate/user.json b/public/language/en@pirate/user.json index 989d39c6eb..76193ee06e 100644 --- a/public/language/en@pirate/user.json +++ b/public/language/en@pirate/user.json @@ -58,5 +58,7 @@ "paginate_description": "Paginate topics and posts instead of using infinite scroll.", "topics_per_page": "Topics per Page", "posts_per_page": "Posts per Page", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/en_US/error.json b/public/language/en_US/error.json index f3d428d08e..f85edb7658 100644 --- a/public/language/en_US/error.json +++ b/public/language/en_US/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/en_US/modules.json b/public/language/en_US/modules.json index d339c075eb..04b7d49faf 100644 --- a/public/language/en_US/modules.json +++ b/public/language/en_US/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "type chat message here, press enter to send", "chat.send": "Send", "chat.no_active": "You have no active chats.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/en_US/topic.json b/public/language/en_US/topic.json index ad4747ae31..b101a966c0 100644 --- a/public/language/en_US/topic.json +++ b/public/language/en_US/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "You don't have any favorites, favorite some posts to see them here!", "loading_more_posts": "Loading More Posts", "move_topic": "Move Topic", + "move_topics": "Move Topics", "move_post": "Move Post", "post_moved": "Post moved!", "fork_topic": "Fork Topic", diff --git a/public/language/en_US/user.json b/public/language/en_US/user.json index e2c9809197..5654f882f3 100644 --- a/public/language/en_US/user.json +++ b/public/language/en_US/user.json @@ -58,5 +58,7 @@ "paginate_description": "Paginate topics and posts instead of using infinite scroll.", "topics_per_page": "Topics per Page", "posts_per_page": "Posts per Page", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/es/error.json b/public/language/es/error.json index d536c24a73..6d3b447767 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -1,49 +1,50 @@ { - "invalid-data": "Invalid Data", - "not-logged-in": "You don't seem to be logged in.", - "invalid-cid": "Invalid Category ID", - "invalid-tid": "Invalid Topic ID", - "invalid-pid": "Invalid Post ID", - "invalid-uid": "Invalid User ID", - "invalid-username": "Invalid Username", - "invalid-email": "Invalid Email", - "invalid-title": "Invalid title", - "invalid-user-data": "Invalid User Data", - "invalid-password": "Invalid Password", - "invalid-pagination-value": "Invalid pagination value", - "username-taken": "Username taken", - "email-taken": "Email taken", - "user-banned": "User banned", - "no-category": "Category doesn't exist", - "no-topic": "Topic doesn't exist", - "no-post": "Post doesn't exist", - "no-group": "Group doesn't exist", - "no-user": "User doesn't exist", - "no-teaser": "Teaser doesn't exist", - "no-privileges": "You don't have enough privileges for this action.", - "category-disabled": "Category disabled", - "topic-locked": "Topic Locked", - "still-uploading": "Please wait for uploads to complete.", - "content-too-short": "Please enter a longer post. At least %1 characters.", - "title-too-short": "Please enter a longer title. At least %1 characters.", - "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", - "too-many-posts": "You can only post every %1 seconds.", - "file-too-big": "Maximum allowed file size is %1 kbs", - "cant-vote-self-post": "You cannot vote for your own post", - "already-favourited": "You already favourited this post", - "already-unfavourited": "You alread unfavourited this post", - "cant-ban-other-admins": "You can't ban other admins!", - "invalid-image-type": "Invalid image type", - "group-name-too-short": "Group name too short", - "group-already-exists": "Group already exists", - "group-name-change-not-allowed": "Group name change not allowed", - "post-already-deleted": "Post already deleted", - "post-already-restored": "Post already restored", - "topic-already-deleted": "Topic already deleted", - "topic-already-restored": "Topic already restored", - "topic-thumbnails-are-disabled": "Topic thumbnails are disabled.", - "invalid-file": "Invalid File", - "uploads-are-disabled": "Uploads are disabled", - "signature-too-long": "Signature can't be longer than %1 characters!", - "cant-chat-with-yourself": "You can't chat with yourself!" + "invalid-data": "Datos no válidos", + "not-logged-in": "No has iniciado sesión.", + "account-locked": "Tu cuenta ha sido bloqueada temporalmente.", + "invalid-cid": "Identificador de categoría no válido", + "invalid-tid": "Identificador de tema no válido", + "invalid-pid": "Identificador de publicación no válido", + "invalid-uid": "Identificador de usuario no válido", + "invalid-username": "Nombre de usuario no válido", + "invalid-email": "Correo electrónico no válido", + "invalid-title": "Título no válido", + "invalid-user-data": "Datos de Usuario no válidos", + "invalid-password": "Contraseña no válida", + "invalid-pagination-value": "Valor de paginación no válido.", + "username-taken": "Nombre de usuario ya escogido", + "email-taken": "El correo electrónico ya está escogido.", + "user-banned": "Usuario expulsado", + "no-category": "La categoría no existe", + "no-topic": "El tema no existe.", + "no-post": "La publicación no existe", + "no-group": "El grupo no existe", + "no-user": "El usuario no existe", + "no-teaser": "El extracto del tema no existe.", + "no-privileges": "No tienes los privilegios necesarios para esa acción.", + "category-disabled": "Categoría deshabilitada.", + "topic-locked": "Tema bloqueado.", + "still-uploading": "Por favor, espera a que terminen las subidas.", + "content-too-short": "Por favor, introduce una respuesta más larga, al menos de %1 caracteres.", + "title-too-short": "Por favor, introduce un título más largo, al menos de %1 caracteres.", + "title-too-long": "Por favor, introduce un título más corto, que no sobrepase los %1 caracteres.", + "too-many-posts": "Sólo puedes publicar cada %1 segundos.", + "file-too-big": "El tamaño máximo de archivo es de %1 KBs", + "cant-vote-self-post": "No puedes votar tus propios posts", + "already-favourited": "Ya has marcado esa publicación como favorita.", + "already-unfavourited": "Ya has desmarcado esta publicación como favorita.", + "cant-ban-other-admins": "No puedes expulsar a otros administradores!", + "invalid-image-type": "Tipo de imagen no válido.", + "group-name-too-short": "Nombre del grupo es demasiado corto.", + "group-already-exists": "El grupo ya existe.", + "group-name-change-not-allowed": "El nombre del grupo deseado no está permitido.", + "post-already-deleted": "La publicación ya ha sido eliminada.", + "post-already-restored": "La publicación ya ha sido recuperada.", + "topic-already-deleted": "El tema ya ha sido eliminado.", + "topic-already-restored": "El tema ya ha sido recuperado.", + "topic-thumbnails-are-disabled": "Las miniaturas de los temas están deshabilitadas.", + "invalid-file": "Archivo no válido.", + "uploads-are-disabled": "Las subidas están deshabilitadas.", + "signature-too-long": "Las firmas no pueden ser más largas de %1 caracteres!", + "cant-chat-with-yourself": "No puedes conversar contigo mismo!" } \ No newline at end of file diff --git a/public/language/es/global.json b/public/language/es/global.json index a70dfc51a0..aa6fd947bd 100644 --- a/public/language/es/global.json +++ b/public/language/es/global.json @@ -18,6 +18,7 @@ "save_changes": "Guardar Cambios", "close": "Cerrar", "pagination": "Paginación", + "pagination.out_of": "%1 out of %2", "header.admin": "Administración", "header.recent": "Recientes", "header.unread": "No Leídos", @@ -35,26 +36,26 @@ "alert.success": "Éxito!", "alert.error": "Error", "alert.banned": "Baneado", - "alert.banned.message": "Estás baneado, serás desconectado!", + "alert.banned.message": "Acabas de ser expulsado, a continuación tu sesión se desconectará.", "alert.unfollow": "Ya no estás siguiendo a %1!", "alert.follow": "Estás siguiendo a %1!", "online": "Conectado", - "users": "Users", - "topics": "Topics", + "users": "Usuarios", + "topics": "Temas", "posts": "Posts", "views": "Visitas", - "reputation": "Reputation", - "read_more": "read more", - "posted_ago_by_guest": "posted %1 by Guest", - "posted_ago_by": "posted %1 by %2", - "posted_ago": "posted %1", - "posted_in_ago_by_guest": "posted in %1 %2 by Guest", - "posted_in_ago_by": "posted in %1 %2 by %3", - "posted_in_ago": "posted in %1 %2", - "replied_ago": "replied %1", - "user_posted_ago": "%1 posted %2", - "guest_posted_ago": "Guest posted %1", - "last_edited_by_ago": "last edited by %1 %2", + "reputation": "Reputación", + "read_more": "leer más", + "posted_ago_by_guest": "publicado %1 por Invitado", + "posted_ago_by": "publicado hace %1 por %2", + "posted_ago": "publicado hace %1", + "posted_in_ago_by_guest": "publicado en %1 %2 por", + "posted_in_ago_by": "publicado en %1 hace %2 por %3", + "posted_in_ago": "publicado en %1 hace %2", + "replied_ago": "contestado hace %1", + "user_posted_ago": "%1 publicó %2", + "guest_posted_ago": "Invitado publicó %1", + "last_edited_by_ago": "última edición por %1 el %2", "norecentposts": "No hay publicaciones recientes", "norecenttopics": "No hay temas recientes", "recentposts": "Publicaciones Recientes", @@ -64,7 +65,7 @@ "invisible": "Invisible", "offline": "Desconectado", "email": "Email", - "language": "Language", - "guest": "Guest", - "guests": "Guests" + "language": "Lenguaje", + "guest": "Invitado", + "guests": "Invitados" } \ No newline at end of file diff --git a/public/language/es/modules.json b/public/language/es/modules.json index 58d86a1b28..6087aad83c 100644 --- a/public/language/es/modules.json +++ b/public/language/es/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "ingresa tu mensaje aquí, y presiona Intro para enviar", "chat.send": "Enviar", "chat.no_active": "No tiene conversaciones activas.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 está escribiendo ...", + "chat.user_has_messaged_you": "%1 te ha enviado un mensaje." } \ No newline at end of file diff --git a/public/language/es/success.json b/public/language/es/success.json index fde8a77044..ed5f88db31 100644 --- a/public/language/es/success.json +++ b/public/language/es/success.json @@ -1,6 +1,6 @@ { - "success": "Success", - "topic-post": "You have successfully posted.", - "authentication-successful": "Authentication Successful", - "settings-saved": "Settings saved!" + "success": "Exito!", + "topic-post": "Has publicado correctamente.", + "authentication-successful": "El inicio de sesión ha sido correcto!", + "settings-saved": "Su configuración ha sido guardada correctamente." } \ No newline at end of file diff --git a/public/language/es/topic.json b/public/language/es/topic.json index 3c3f9f753e..f3995eeb1d 100644 --- a/public/language/es/topic.json +++ b/public/language/es/topic.json @@ -4,10 +4,10 @@ "topic_id_placeholder": "Introducir ID tema", "no_topics_found": "No se encontraron temas!", "no_posts_found": "No se encontraron publicaciones!", - "post_is_deleted": "This post is deleted!", + "post_is_deleted": "Esta publicación está eliminada!", "profile": "Perfil", - "posted_by": "Posted by %1", - "posted_by_guest": "Posted by Guest", + "posted_by": "Publicado por %1", + "posted_by_guest": "Publicado por Invitado", "chat": "Chat", "notify_me": "Serás notificado cuando haya nuevas respuestas en este tema", "quote": "Citar", @@ -41,17 +41,17 @@ "thread_tools.lock": "Cerrar Tema", "thread_tools.unlock": "Abrir Tema", "thread_tools.move": "Mover Tema", - "thread_tools.move_all": "Move All", + "thread_tools.move_all": "Mover todo", "thread_tools.fork": "Bifurcar Tema", "thread_tools.delete": "Borrar Tema", "thread_tools.delete_confirm": "Estás seguro de que quieres eliminar este hilo?", "thread_tools.restore": "Restaurar Tema", "thread_tools.restore_confirm": "Estás seguro de que quieres restaurar este hilo?", - "topic_lock_success": "Topic has been successfully locked.", - "topic_unlock_success": "Topic has been successfully unlocked.", + "topic_lock_success": "El tema ha sido bloqueado correctamente.", + "topic_unlock_success": "El tema ha sido desbloqueado correctamente.", "topic_pin_success": "Topic has been successfully pinned.", "topic_unpin_success": "Topic has been successfully unpinned.", - "topic_move_success": "This topic has been successfully moved to %1", + "topic_move_success": "El tema ha sido movido correctamente a %1", "post_delete_confirm": "Estás seguro de que quieres eliminar esta respuesta?", "post_restore_confirm": "Estás seguro de que quieres restaurar esta respuesta?", "post_delete_error": "No se pudo borrar esta respuesta!", @@ -65,8 +65,9 @@ "favourites.has_no_favourites": "No tienes favoritos, puedes agregar alguno y volver a verlos aquí!", "loading_more_posts": "Cargando más publicaciones", "move_topic": "Mover Tema", + "move_topics": "Mover Temas", "move_post": "Mover Publicación", - "post_moved": "Post moved!", + "post_moved": "Publicación movida correctamente!", "fork_topic": "Bifurcar Tema", "topic_will_be_moved_to": "Este tema será movido a la categoría", "fork_topic_instruction": "Click en las publicaciones que quieres bifurcar", @@ -78,7 +79,7 @@ "composer.help": "Ayuda", "composer.discard": "Descartar", "composer.submit": "Enviar", - "composer.replying_to": "Replying to %1", + "composer.replying_to": "En respuesta a %1", "composer.new_topic": "Nuevo Tema", "composer.uploading": "cargando...", "composer.thumb_url_label": "Agregar imagen destacada a este tema.", @@ -88,7 +89,7 @@ "composer.thumb_remove": "Limpiar campos.", "composer.drag_and_drop_images": "Arrastra las imagenes aqui", "composer.upload_instructions": "Carga tus imagenes con solo arrastrarlas aqui.", - "more_users_and_guests": "%1 more user(s) and %2 guest(s)", - "more_users": "%1 more user(s)", - "more_guests": "%1 more guest(s)" + "more_users_and_guests": "%1 usuario(s) y %2 invitado(s) más", + "more_users": "%1 usuario(s) más", + "more_guests": "%1 invitado(s) más" } \ No newline at end of file diff --git a/public/language/es/unread.json b/public/language/es/unread.json index 29f15be5f2..fa029aafcc 100644 --- a/public/language/es/unread.json +++ b/public/language/es/unread.json @@ -2,8 +2,8 @@ "title": "No leído", "no_unread_topics": "No hay temas nuevos para leer.", "load_more": "Cargar más", - "mark_as_read": "Mark as Read", - "selected": "Selected", - "all": "All", - "topics_marked_as_read.success": "Topics marked as read!" + "mark_as_read": "Marcar como leído.", + "selected": "Seleccionado", + "all": "Todo", + "topics_marked_as_read.success": "Temas marcados como leídos correctamente!" } \ No newline at end of file diff --git a/public/language/es/user.json b/public/language/es/user.json index c524e1a121..6c01e86806 100644 --- a/public/language/es/user.json +++ b/public/language/es/user.json @@ -32,7 +32,7 @@ "change_password_error_wrong_current": "Su contraseña actual no es correcta!", "change_password_error_length": "La contraseña es demasiado corta!", "change_password_error_match": "Las contraseñas deben coincidir!", - "change_password_error_privileges": "You do not have the rights to change this password.", + "change_password_error_privileges": "No tienes los permisos suficientes para cambiar esta contraseña.", "change_password_success": "La contraseña ha sido actualizada correctamente!", "confirm_password": "Confirmar Contraseña", "password": "Contraseña", @@ -58,5 +58,7 @@ "paginate_description": "La paginación de los temas no es por página, ya que tiene scroll infinito.", "topics_per_page": "Temas por página", "posts_per_page": "Post por página", - "notification_sounds": "Reproducir un sonido al recibir una notificación" + "notification_sounds": "Reproducir un sonido al recibir una notificación", + "browsing": "Preferencias de navegación.", + "open_links_in_new_tab": "Abrir los enlaces externos en una nueva pestaña?" } \ No newline at end of file diff --git a/public/language/et/error.json b/public/language/et/error.json index 70d2e03d76..27b7a4a3b2 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Vigased andmed", "not-logged-in": "Sa ei ole sisse logitud", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Vigane kategooria ID", "invalid-tid": "Vigane teema ID", "invalid-pid": "Vigane postituse ID", diff --git a/public/language/et/global.json b/public/language/et/global.json index 27f3cefd89..adf78f86b8 100644 --- a/public/language/et/global.json +++ b/public/language/et/global.json @@ -18,6 +18,7 @@ "save_changes": "Salvesta muudatused", "close": "Sulge", "pagination": "Lehekülgede numeratsioon", + "pagination.out_of": "%1 out of %2", "header.admin": "Admin", "header.recent": "Hiljutised", "header.unread": "Lugemata", @@ -35,7 +36,7 @@ "alert.success": "Õnnestus", "alert.error": "Viga", "alert.banned": "Bannitud", - "alert.banned.message": "Oled bannitud!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Sa ei jälgi enam %1!", "alert.follow": "Sa jälgid nüüd %1!", "online": "Sees", diff --git a/public/language/et/modules.json b/public/language/et/modules.json index adaca465e6..1fe367b213 100644 --- a/public/language/et/modules.json +++ b/public/language/et/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "kirjuta oma sõnum siia ning sõnumi saatmiseks vajuta enterit", "chat.send": "Saada", "chat.no_active": "Sul ei ole hetkel aktiivseid vestlusi.", - "chat.user_typing": "%1 kirjutab sõnumit..." + "chat.user_typing": "%1 kirjutab sõnumit...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/et/topic.json b/public/language/et/topic.json index 05c614a960..5ed4cfb36b 100644 --- a/public/language/et/topic.json +++ b/public/language/et/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Sul pole lemmikuid postitusi. Märgi mõned postitused lemmikuks ning need ilmuvad automaatselt siia!", "loading_more_posts": "Laen postitusi", "move_topic": "Liiguta teemat", + "move_topics": "Move Topics", "move_post": "Liiguta postitust", "post_moved": "Postitus liigutatud!", "fork_topic": "Fork Topic", diff --git a/public/language/et/user.json b/public/language/et/user.json index 3b4633f26d..0c8851a496 100644 --- a/public/language/et/user.json +++ b/public/language/et/user.json @@ -58,5 +58,7 @@ "paginate_description": "Nummerda leheküljed ja postitused ning ära kasuta ''lõputut scrolli''.", "topics_per_page": "Teemasi ühe lehekülje kohta", "posts_per_page": "Postitusi ühe lehekülje kohta", - "notification_sounds": "Tee häält, kui saabub teade." + "notification_sounds": "Tee häält, kui saabub teade.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/fa_IR/error.json b/public/language/fa_IR/error.json index 8d75610b52..7eaf2ab9be 100644 --- a/public/language/fa_IR/error.json +++ b/public/language/fa_IR/error.json @@ -1,6 +1,7 @@ { "invalid-data": "به نظر نمی‌رسد که درون آمده باشید", "not-logged-in": "به نظر نمی‌رسد که درون آمده باشید.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "شناسهٔ (ID) دسته نامعتبر است", "invalid-tid": "شناسهٔ (ID) جستار نامعتبر است", "invalid-pid": "شناسهٔ (ID) دیدگاه نامعتبر است", diff --git a/public/language/fa_IR/global.json b/public/language/fa_IR/global.json index 75f5bc20fb..bf43458137 100644 --- a/public/language/fa_IR/global.json +++ b/public/language/fa_IR/global.json @@ -18,6 +18,7 @@ "save_changes": "اندوختن تغییرها", "close": "بستن", "pagination": "صفحه‌بندی", + "pagination.out_of": "%1 out of %2", "header.admin": "مدیر", "header.recent": "تازه‌ها", "header.unread": "نخوانده‌ها", @@ -35,7 +36,7 @@ "alert.success": "موفقیت", "alert.error": "خطا", "alert.banned": "مسدود", - "alert.banned.message": "شما بن شده‌اید، به بیرون هدایت خواهید شد.", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "شما دیگر %1 را دنبال نمی‌کنید!", "alert.follow": "اکنون %1 را دنبال می‌کنید.", "online": "حاضر", diff --git a/public/language/fa_IR/modules.json b/public/language/fa_IR/modules.json index 7ef1b32b9a..f441108977 100644 --- a/public/language/fa_IR/modules.json +++ b/public/language/fa_IR/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "متن را اینجا بنویسد و دکمهٔ‌ Enter را برای فرستادن بفشارید.", "chat.send": "فرستادن", "chat.no_active": "شما هیچ گفتگوی فعالی ندارید.", - "chat.user_typing": "%1 در حال نوشتن است..." + "chat.user_typing": "%1 در حال نوشتن است...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/fa_IR/topic.json b/public/language/fa_IR/topic.json index 4ffe102720..4cd89ca11c 100644 --- a/public/language/fa_IR/topic.json +++ b/public/language/fa_IR/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "شما هیچ پسندی ندارید، چندین دیدگاه را پسند کنید تا آن‌ها را در اینجا ببینید.", "loading_more_posts": "بارگذاری دیدگاه‌های بیش‌تر", "move_topic": "جابه‌جایی جستار", + "move_topics": "Move Topics", "move_post": "جابه‌جایی جستار", "post_moved": "دیدگاه جابه‌جا شد!", "fork_topic": "شاخه ساختن از جستار", diff --git a/public/language/fa_IR/user.json b/public/language/fa_IR/user.json index 295f5c824e..639fca48ca 100644 --- a/public/language/fa_IR/user.json +++ b/public/language/fa_IR/user.json @@ -58,5 +58,7 @@ "paginate_description": "محدود کردن شمار جستارها و دیدگاه‌ها در هر برگه به جای مرور بی‌پایان برگه‌ها", "topics_per_page": "شمار جستارها در هر برگه", "posts_per_page": "شمار دیدگاه‌ها در هر برگه", - "notification_sounds": "پخش صدا هنگامی که شما یک آگاه‌سازی دریافت می‌کنید." + "notification_sounds": "پخش صدا هنگامی که شما یک آگاه‌سازی دریافت می‌کنید.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/fi/error.json b/public/language/fi/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/fi/global.json b/public/language/fi/global.json index aa12108f0d..b574aa345c 100644 --- a/public/language/fi/global.json +++ b/public/language/fi/global.json @@ -18,6 +18,7 @@ "save_changes": "Tallenna muutokset", "close": "Sulje", "pagination": "Sivutus", + "pagination.out_of": "%1 out of %2", "header.admin": "Ylläpitäjä", "header.recent": "Viimeisimmät", "header.unread": "Lukemattomat", @@ -35,7 +36,7 @@ "alert.success": "Onnistui", "alert.error": "Virhe", "alert.banned": "Estetty", - "alert.banned.message": "Sinut on estetty ja kirjaudut ulos!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Et seuraa enää %1!", "alert.follow": "Seuraat nyt %1!", "online": "Online", diff --git a/public/language/fi/modules.json b/public/language/fi/modules.json index cd1f07c4ad..f399cea8cb 100644 --- a/public/language/fi/modules.json +++ b/public/language/fi/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "kirjoita viestisi tähän ja paina enter lähettääksesi", "chat.send": "Lähetä", "chat.no_active": "Sinulla ei ole aktiivisia keskusteluita.", - "chat.user_typing": "%1 kirjoittaa ..." + "chat.user_typing": "%1 kirjoittaa ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/fi/topic.json b/public/language/fi/topic.json index 0848103601..a391ab387d 100644 --- a/public/language/fi/topic.json +++ b/public/language/fi/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Sinulla ei ole yhtään suosikkiviestiä. Lisää joitakin viestejä suosikeiksi nähdäksesi ne täällä!", "loading_more_posts": "Ladataan lisää viestejä", "move_topic": "Siirrä aihe", + "move_topics": "Move Topics", "move_post": "Siirrä viesti", "post_moved": "Post moved!", "fork_topic": "Haaroita keskustelu", diff --git a/public/language/fi/user.json b/public/language/fi/user.json index e1fc5c3462..a4423c3490 100644 --- a/public/language/fi/user.json +++ b/public/language/fi/user.json @@ -58,5 +58,7 @@ "paginate_description": "Sivuta aiheet ja viestit loputtoman vierittämisen sijaan.", "topics_per_page": "Aihetta per sivu", "posts_per_page": "Viestiä per sivu", - "notification_sounds": "Soita merkkiääni ilmoituksen saapuessa." + "notification_sounds": "Soita merkkiääni ilmoituksen saapuessa.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/fr/error.json b/public/language/fr/error.json index 43ba8ec4f0..791d0344a0 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Données Invalides", "not-logged-in": "Vous ne semblez pas être connecté.", + "account-locked": "Votre compte a été temporairement suspendu.", "invalid-cid": "ID de Catégorie Invalide", "invalid-tid": "ID de Sujet Invalide", "invalid-pid": "ID de Message Invalide", diff --git a/public/language/fr/global.json b/public/language/fr/global.json index 945eaaa046..fdac0f2452 100644 --- a/public/language/fr/global.json +++ b/public/language/fr/global.json @@ -18,6 +18,7 @@ "save_changes": "Enregistrer les changements", "close": "Fermer", "pagination": "Pagination", + "pagination.out_of": "%1 sur %2", "header.admin": "Admin", "header.recent": "Récent", "header.unread": "Non Lu", @@ -35,7 +36,7 @@ "alert.success": "Succès", "alert.error": "Erreur", "alert.banned": "Bannis", - "alert.banned.message": "Vous avez été bannis, vous allez être déconnecté!", + "alert.banned.message": "Vous venez d'être banni, vous allez maintenant être déconnecté.", "alert.unfollow": "Vous ne suivez plus %1!", "alert.follow": "Vous suivez maintenant %1!", "online": "En ligne", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index 7cb60f52f3..6d67bbef49 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "taper le message ici, presser entrer pour envoyer", "chat.send": "Envoyer", "chat.no_active": "Vous n'avez aucune discussion active.", - "chat.user_typing": "%1 est en train d'écrire" + "chat.user_typing": "%1 est en train d'écrire", + "chat.user_has_messaged_you": "%1 vous a envoyé un message." } \ No newline at end of file diff --git a/public/language/fr/user.json b/public/language/fr/user.json index f2293424a5..32ecf7849f 100644 --- a/public/language/fr/user.json +++ b/public/language/fr/user.json @@ -58,5 +58,7 @@ "paginate_description": "Utiliser la pagination de sujets et messages au lieu du défilement infini.", "topics_per_page": "Sujets par Page", "posts_per_page": "Messages par Page", - "notification_sounds": "Emettre un son lors de la réception de notifications." + "notification_sounds": "Emettre un son lors de la réception de notifications.", + "browsing": "Paramètres de Naviguation.", + "open_links_in_new_tab": "Ouvrir les liens externes dans un nouvel onglet?" } \ No newline at end of file diff --git a/public/language/he/error.json b/public/language/he/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/he/global.json b/public/language/he/global.json index 74eb496719..23b18b37ff 100644 --- a/public/language/he/global.json +++ b/public/language/he/global.json @@ -18,6 +18,7 @@ "save_changes": "שמור שינויים", "close": "סגור", "pagination": "עימוד", + "pagination.out_of": "%1 out of %2", "header.admin": "ניהול", "header.recent": "פוסטים אחרונים", "header.unread": "לא נקרא", @@ -35,7 +36,7 @@ "alert.success": "הצלחה", "alert.error": "שגיאה", "alert.banned": "מורחק", - "alert.banned.message": "הורחקת וכעת תנותק מהאתר!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "אתה כבר לא עוקב אחרי %1!", "alert.follow": "אתה עכשיו עוקב אחרי %1", "online": "מחובר", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 5f993e23b8..043610ca6e 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "כתוב את הודעתך כאן, ולחץ על שלח", "chat.send": "שלח", "chat.no_active": "אין לך צ'אטים פעילים", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/he/topic.json b/public/language/he/topic.json index 1ae1536b88..4b4f19d40e 100644 --- a/public/language/he/topic.json +++ b/public/language/he/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "אין לך כרגע פוסטים מועדפים, סמן מספר פוסטים כמועדפים על מנת לראות אותם כאן!", "loading_more_posts": "טוען פוסטים נוספים", "move_topic": "הזז נושא", + "move_topics": "Move Topics", "move_post": "הזז פוסט", "post_moved": "Post moved!", "fork_topic": "שכפל נושא", diff --git a/public/language/he/user.json b/public/language/he/user.json index d20e9343da..adcdd183a9 100644 --- a/public/language/he/user.json +++ b/public/language/he/user.json @@ -58,5 +58,7 @@ "paginate_description": "צור עימוד לנושאים במקום לטעון את כל התוכן בעמוד אחד.", "topics_per_page": "כמות נושאים בעמוד", "posts_per_page": "כמות פוסטים בעמוד", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/hu/error.json b/public/language/hu/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/hu/global.json b/public/language/hu/global.json index dab6719892..765e81948e 100644 --- a/public/language/hu/global.json +++ b/public/language/hu/global.json @@ -18,6 +18,7 @@ "save_changes": "Változások mentése", "close": "Bezár", "pagination": "Lapszámozás", + "pagination.out_of": "%1 out of %2", "header.admin": "Admin", "header.recent": "Friss", "header.unread": "Olvasatlan", @@ -35,7 +36,7 @@ "alert.success": "Sikeres", "alert.error": "Hiba", "alert.banned": "Tiltva", - "alert.banned.message": "Ki vagy tiltva, ezért most ki leszel léptetve!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Nem követed tovább: %1!", "alert.follow": "Mostantól követed: %1!", "online": "Online", diff --git a/public/language/hu/modules.json b/public/language/hu/modules.json index f907fdc3f1..13fb95e507 100644 --- a/public/language/hu/modules.json +++ b/public/language/hu/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "írj be egy üzenetet, majd nyomj enter-t a küldéshez", "chat.send": "Küldés", "chat.no_active": "Nincs aktív csevegésed.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/hu/topic.json b/public/language/hu/topic.json index 141fdf8898..b7c87b0010 100644 --- a/public/language/hu/topic.json +++ b/public/language/hu/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Nincs egyetlen kedvenc hozzászólásod sem, jelölj meg párat hogy itt láthasd őket!", "loading_more_posts": "Hozzászólások betöltése", "move_topic": "Topik áthelyezése", + "move_topics": "Move Topics", "move_post": "Hozzászólás áthelyezése", "post_moved": "Post moved!", "fork_topic": "Topik szétszedése", diff --git a/public/language/hu/user.json b/public/language/hu/user.json index a0b098e386..e747ea389f 100644 --- a/public/language/hu/user.json +++ b/public/language/hu/user.json @@ -58,5 +58,7 @@ "paginate_description": "Oldalszámok használata a témáknál és hozzászólásoknál a végtelen görgetés helyett.", "topics_per_page": "Téma oldalanként", "posts_per_page": "Hozzászólás oldalanként", - "notification_sounds": "Hang lejátszása ha értesítés érkezett." + "notification_sounds": "Hang lejátszása ha értesítés érkezett.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/it/error.json b/public/language/it/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/it/global.json b/public/language/it/global.json index c408572d8f..a253c26e09 100644 --- a/public/language/it/global.json +++ b/public/language/it/global.json @@ -18,6 +18,7 @@ "save_changes": "Salva cambiamenti", "close": "Chiudi", "pagination": "Paginazione", + "pagination.out_of": "%1 out of %2", "header.admin": "Amministratore", "header.recent": "Recenti", "header.unread": "Non letti", @@ -35,7 +36,7 @@ "alert.success": "Riuscito", "alert.error": "Errore", "alert.banned": "Bannato", - "alert.banned.message": "Sei bannato e verrai disconnesso!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Non stai più seguendo %1!", "alert.follow": "Stai seguendo %1!", "online": "Online", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 48c4d95151..d0f15dc8aa 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "scrivi un messaggio qui, poi premi Invio", "chat.send": "Invia", "chat.no_active": "Non hai discussioni attive.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/it/topic.json b/public/language/it/topic.json index ecad017444..6739a53084 100644 --- a/public/language/it/topic.json +++ b/public/language/it/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Non hai ancun post preferito; aggiungi qualche post ai preferiti per vederli qui!", "loading_more_posts": "Caricamento altri post", "move_topic": "Sposta Discussione", + "move_topics": "Move Topics", "move_post": "Sposta Post", "post_moved": "Post moved!", "fork_topic": "Dividi il Topic", diff --git a/public/language/it/user.json b/public/language/it/user.json index 496913c8cb..2438a3a0e1 100644 --- a/public/language/it/user.json +++ b/public/language/it/user.json @@ -58,5 +58,7 @@ "paginate_description": "Dividi argomenti e post in pagine anziché usare lo scroll infinito.", "topics_per_page": "Argomenti per Pagina", "posts_per_page": "Post per Pagina", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/ja/error.json b/public/language/ja/error.json index a5a3c70da5..b04ad71b08 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -1,6 +1,7 @@ { "invalid-data": "無効なデータ", "not-logged-in": "ログインしていていないようです。", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "無効な板ID", "invalid-tid": "無効なスレッドID", "invalid-pid": "無効なポストID", diff --git a/public/language/ja/global.json b/public/language/ja/global.json index 1d2504bab7..eb83c18b85 100644 --- a/public/language/ja/global.json +++ b/public/language/ja/global.json @@ -18,6 +18,7 @@ "save_changes": "保存する", "close": "閉じる", "pagination": "ページ", + "pagination.out_of": "%1 out of %2", "header.admin": "管理", "header.recent": "最近", "header.unread": "未読", @@ -35,7 +36,7 @@ "alert.success": "成功", "alert.error": "エラー", "alert.banned": "停止した", - "alert.banned.message": "このアカウントが停止されました!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "%1へのフォローを停止しました!", "alert.follow": "%1をフォローしています!", "online": "オンライン", diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json index 507012d7a6..a89a067061 100644 --- a/public/language/ja/modules.json +++ b/public/language/ja/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "メッセージを入力する", "chat.send": "送信", "chat.no_active": "チャットはありません。", - "chat.user_typing": "%1 は入力中 ..." + "chat.user_typing": "%1 は入力中 ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/ja/topic.json b/public/language/ja/topic.json index 13fdba2593..9532b9e9a9 100644 --- a/public/language/ja/topic.json +++ b/public/language/ja/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "お気に入りはまだありません!", "loading_more_posts": "もっと見る", "move_topic": "スレッドを移動", + "move_topics": "Move Topics", "move_post": "ポストを移動", "post_moved": "ポストを移動しました!", "fork_topic": "スレッドをフォーク", diff --git a/public/language/ja/user.json b/public/language/ja/user.json index 68b6d79bc6..000668176a 100644 --- a/public/language/ja/user.json +++ b/public/language/ja/user.json @@ -58,5 +58,7 @@ "paginate_description": "スクロールでのページ自動ロードはしない", "topics_per_page": "ページ毎のスレッド数", "posts_per_page": "ページ毎のポスト数", - "notification_sounds": "通知が来たとき音を流す" + "notification_sounds": "通知が来たとき音を流す", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/lt/error.json b/public/language/lt/error.json index 840ef5b7c4..cfc857e254 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Klaidingi duomenys", "not-logged-in": "Atrodo, kad jūs neesate prisijungęs.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Klaidingas kategorijos ID", "invalid-tid": "Klaidingas temos ID", "invalid-pid": "Klaidingas pranešimo ID", diff --git a/public/language/lt/global.json b/public/language/lt/global.json index 54f12be8f1..5bca8410cf 100644 --- a/public/language/lt/global.json +++ b/public/language/lt/global.json @@ -18,6 +18,7 @@ "save_changes": "Išsaugoti pakeitimus", "close": "Uždaryti", "pagination": "Numeracija", + "pagination.out_of": "%1 out of %2", "header.admin": "Administratorius", "header.recent": "Naujausi", "header.unread": "Neskaityti", @@ -35,7 +36,7 @@ "alert.success": "Pavyko", "alert.error": "Klaida", "alert.banned": "Užblokuotas", - "alert.banned.message": "Jūs esate užblokuotas ir dabar atsijungsite!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Jūs jau nebesekate %1! ", "alert.follow": "Jūs sekate vartotoją %1!", "online": "Prisijungęs", diff --git a/public/language/lt/modules.json b/public/language/lt/modules.json index 736bfa1ab3..2461eecedf 100644 --- a/public/language/lt/modules.json +++ b/public/language/lt/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "žinutę rašykite čia, norėdami išsiųsti spauskite enter", "chat.send": "Siųsti", "chat.no_active": "Jūs neturite aktyvių susirašinėjimų.", - "chat.user_typing": "%1 dabar rašo..." + "chat.user_typing": "%1 dabar rašo...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/lt/topic.json b/public/language/lt/topic.json index 26efd59b6c..018bc3f0e0 100644 --- a/public/language/lt/topic.json +++ b/public/language/lt/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Neturite jokių mėgiamų pranešimų. Įtraukite pranešimą į mėgiamų sąrašą, kad pamatytumėte juos čia!", "loading_more_posts": "Įkeliama daugiau įrašų", "move_topic": "Perkelti temą", + "move_topics": "Move Topics", "move_post": "Perkelti įrašą", "post_moved": "Pranešimas perkeltas!", "fork_topic": "Išskaidyti temą", diff --git a/public/language/lt/user.json b/public/language/lt/user.json index 9947ae9eac..04c4c8668a 100644 --- a/public/language/lt/user.json +++ b/public/language/lt/user.json @@ -58,5 +58,7 @@ "paginate_description": "Temose ir kategorijose naudoti numeraciją puslapiams vietoje begalinės slinkties.", "topics_per_page": "Temų puslapyje", "posts_per_page": "Pranešimų puslapyje", - "notification_sounds": "Groti garsą kai gaunate pranešimą." + "notification_sounds": "Groti garsą kai gaunate pranešimą.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/ms/error.json b/public/language/ms/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/ms/global.json b/public/language/ms/global.json index c2b5744009..86610582f6 100644 --- a/public/language/ms/global.json +++ b/public/language/ms/global.json @@ -18,6 +18,7 @@ "save_changes": "simpan perubahan", "close": "Tutup", "pagination": "Mukasurat", + "pagination.out_of": "%1 out of %2", "header.admin": "Pentadbir", "header.recent": "terkini", "header.unread": "Belum dibaca", @@ -35,7 +36,7 @@ "alert.success": "berjaya", "alert.error": "ralat", "alert.banned": "Diharamkan", - "alert.banned.message": "Anda diharamkan, anda akan didaftar keluar", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Anda tidak lagi mengikuti %1", "alert.follow": "Anda sekarang mengikuti %1", "online": "dalam talian", diff --git a/public/language/ms/modules.json b/public/language/ms/modules.json index 7a90edc0eb..46a6cdf5b9 100644 --- a/public/language/ms/modules.json +++ b/public/language/ms/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "Taip pesanan disini, tekan enter untuk menghantar", "chat.send": "hantar", "chat.no_active": "Anda tiada pesanan yang aktif", - "chat.user_typing": "%1 menaip" + "chat.user_typing": "%1 menaip", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/ms/topic.json b/public/language/ms/topic.json index cb1eaf42e9..766f28a4e2 100644 --- a/public/language/ms/topic.json +++ b/public/language/ms/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Anda tiada sebarang kegemaran, tandakan kiriman yang digemari untuk dilihat disini", "loading_more_posts": "Memuatkan lagi kiriman ", "move_topic": "Pindahkan topik", + "move_topics": "Move Topics", "move_post": "Pindahkan kiriman", "post_moved": "Kiriman dipindahkan", "fork_topic": "Salin topik", diff --git a/public/language/ms/user.json b/public/language/ms/user.json index f4829fcb77..0fa57c6718 100644 --- a/public/language/ms/user.json +++ b/public/language/ms/user.json @@ -58,5 +58,7 @@ "paginate_description": "Pecahkan topik dan pesanan adalah lebih baik daripada menggunakan scroll berterusan", "topics_per_page": "Topik setiap muka", "posts_per_page": "Kiriman setiap muka", - "notification_sounds": "Mainkan muzik apabila anda menerima maklumbalas" + "notification_sounds": "Mainkan muzik apabila anda menerima maklumbalas", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/nb/error.json b/public/language/nb/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/nb/global.json b/public/language/nb/global.json index c4f58883e2..a95018b30a 100644 --- a/public/language/nb/global.json +++ b/public/language/nb/global.json @@ -18,6 +18,7 @@ "save_changes": "Lagre endringer", "close": "Steng", "pagination": "Paginering", + "pagination.out_of": "%1 out of %2", "header.admin": "Admin", "header.recent": "Seneste", "header.unread": "Uleste", @@ -35,7 +36,7 @@ "alert.success": "Suksess", "alert.error": "Feil", "alert.banned": "Utestengt", - "alert.banned.message": "Du er utestengt og vil bli logget ut!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Du følger ikke lenger %1!", "alert.follow": "Du følger nå %1!", "online": "Online", diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index 02739f5399..c50eeabc6a 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "skriv chat-melding her, trykk enter for å sende", "chat.send": "Send", "chat.no_active": "Du har ingen aktive chatter.", - "chat.user_typing": "%1 skriver ..." + "chat.user_typing": "%1 skriver ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 5ecd38e2fc..a9f785f37f 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Du har ingen favoritter, marker noen innlegg som favoritt for å se dem her!", "loading_more_posts": "Laster flere innlegg", "move_topic": "Flytt emne", + "move_topics": "Move Topics", "move_post": "Flytt innlegg", "post_moved": "Innlegg flyttet!", "fork_topic": "Del emne", diff --git a/public/language/nb/user.json b/public/language/nb/user.json index 82d7db5421..5cc898db36 100644 --- a/public/language/nb/user.json +++ b/public/language/nb/user.json @@ -58,5 +58,7 @@ "paginate_description": "Paginer tråder og innlegg istedet for å bruke uendelig skrolling.", "topics_per_page": "Tråd per side", "posts_per_page": "Innlegg per side", - "notification_sounds": "Spill av en lyd når du mottar ett varsel." + "notification_sounds": "Spill av en lyd når du mottar ett varsel.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/nl/error.json b/public/language/nl/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/nl/global.json b/public/language/nl/global.json index f5800b1abe..c25df8c135 100644 --- a/public/language/nl/global.json +++ b/public/language/nl/global.json @@ -18,6 +18,7 @@ "save_changes": "Aanpassingen Opslaan", "close": "Sluiten", "pagination": "Paginering", + "pagination.out_of": "%1 out of %2", "header.admin": "Admin", "header.recent": "Recent", "header.unread": "Ongelezen", @@ -35,7 +36,7 @@ "alert.success": "Succes", "alert.error": "Fout", "alert.banned": "Verbannen", - "alert.banned.message": "Je bent verbannen en zal uitgelogd worden!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Je volgt niet langer %1!", "alert.follow": "Je volgt nu %1!", "online": "Online", diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index b7a743d774..c54553dcb0 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "type chat bericht hier, druk op enter om te verzenden", "chat.send": "Verzenden", "chat.no_active": "Je hebt geen actieve chats.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index ff6a0d125d..baa5cea5f9 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Je hebt geen favorieten, sla een aantal berichten op als favoriet om ze hier te zien!", "loading_more_posts": "Meer Berichten Laden", "move_topic": "Onderwerp Verplaatsen", + "move_topics": "Move Topics", "move_post": "Bericht Verplaatsen", "post_moved": "Post moved!", "fork_topic": "Onderwerp Forken", diff --git a/public/language/nl/user.json b/public/language/nl/user.json index b05cd7368b..633b4f941d 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -58,5 +58,7 @@ "paginate_description": "Blader door onderwerpen en berichten in plaats van oneindig scrollen.", "topics_per_page": "Onderwerpen per Pagina", "posts_per_page": "Berichten per Pagina", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/pl/error.json b/public/language/pl/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/pl/global.json b/public/language/pl/global.json index f44cf2e0e0..c7939f4ee3 100644 --- a/public/language/pl/global.json +++ b/public/language/pl/global.json @@ -18,6 +18,7 @@ "save_changes": "Zapisz zmiany", "close": "Zamknij", "pagination": "Numerowanie stron", + "pagination.out_of": "%1 out of %2", "header.admin": "Administracja", "header.recent": "Ostatnie", "header.unread": "Nieprzeczytane", @@ -35,7 +36,7 @@ "alert.success": "Powodzenie", "alert.error": "Niepowodzenie", "alert.banned": "Ban", - "alert.banned.message": "Zostałeś zbanowany. Zostaniesz teraz wylogowany.", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Nie śledzisz już %1.", "alert.follow": "Śledzisz %1.", "online": "Online", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index 5b586de5ec..4f35382506 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "napisz wiadomość tutaj i naciśnij enter", "chat.send": "Wyślij", "chat.no_active": "Nie prowadzisz obecnie żadnych rozmów.", - "chat.user_typing": "%1 pisze..." + "chat.user_typing": "%1 pisze...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/pl/topic.json b/public/language/pl/topic.json index 18c68678cd..6ce7294a80 100644 --- a/public/language/pl/topic.json +++ b/public/language/pl/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Nie masz żadnych ulubionych. Polub kilka postów!", "loading_more_posts": "Załaduj więcej postów", "move_topic": "Przenieś wątek", + "move_topics": "Move Topics", "move_post": "Przenieś post", "post_moved": "Post moved!", "fork_topic": "Skopiuj wątek", diff --git a/public/language/pl/user.json b/public/language/pl/user.json index c0f56a6199..6f7c3696fb 100644 --- a/public/language/pl/user.json +++ b/public/language/pl/user.json @@ -58,5 +58,7 @@ "paginate_description": "Użyj klasycznego trybu paginacji zamiast nieskończonego przewijania.", "topics_per_page": "Wątków na stronę", "posts_per_page": "Postów na stronę", - "notification_sounds": "Odtwórz dźwięk po otrzymaniu powiadomienia." + "notification_sounds": "Odtwórz dźwięk po otrzymaniu powiadomienia.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/pt_BR/error.json b/public/language/pt_BR/error.json index 229c5f9e38..4bf7cd0d6d 100644 --- a/public/language/pt_BR/error.json +++ b/public/language/pt_BR/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Conteúdo inválido", "not-logged-in": "Você não parece estar logado.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "ID inválido de categoria", "invalid-tid": "ID inválido de tópico", "invalid-pid": "ID inválido de post", diff --git a/public/language/pt_BR/modules.json b/public/language/pt_BR/modules.json index 1fd4be8580..afec28a668 100644 --- a/public/language/pt_BR/modules.json +++ b/public/language/pt_BR/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "Digite sua mensagem aqui e pressione 'enter' para enviar", "chat.send": "Enviar", "chat.no_active": "Você não tem bate papos ativos.", - "chat.user_typing": "%1 está digitando..." + "chat.user_typing": "%1 está digitando...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/pt_BR/user.json b/public/language/pt_BR/user.json index ea8e46bc6c..10726aac74 100644 --- a/public/language/pt_BR/user.json +++ b/public/language/pt_BR/user.json @@ -58,5 +58,7 @@ "paginate_description": "Paginação de tópicos e posts ao invés de usar \"rolagem infinita\".", "topics_per_page": "Tópicos por Página", "posts_per_page": "Posts por Página", - "notification_sounds": "Tocar um som quando receber notificação." + "notification_sounds": "Tocar um som quando receber notificação.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/ru/error.json b/public/language/ru/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/ru/global.json b/public/language/ru/global.json index ba38a0cf7e..8178654d6a 100644 --- a/public/language/ru/global.json +++ b/public/language/ru/global.json @@ -18,6 +18,7 @@ "save_changes": "Сохранить изменения", "close": "Закрыть", "pagination": "Pagination", + "pagination.out_of": "%1 out of %2", "header.admin": "Админка", "header.recent": "Последние", "header.unread": "Непрочитанное", @@ -35,7 +36,7 @@ "alert.success": "Успешно", "alert.error": "Ошибка", "alert.banned": "Заблокирован", - "alert.banned.message": "Ваш аккаунт заблокирован сейчас будет произведен выход.", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Вы больше не читаете %1!", "alert.follow": "Вы теперь читаете %1!", "online": "В сети", diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index 5b1bdd600c..6e9da13ace 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "введите сообщение, нажмите enter для отправки", "chat.send": "Отправить", "chat.no_active": "У вас нет активных чатов.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/ru/topic.json b/public/language/ru/topic.json index fd97b8372e..080584f040 100644 --- a/public/language/ru/topic.json +++ b/public/language/ru/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "У вас нет избранного, добавьте несколько сообщений в избранное чтобы увидеть их здесь!", "loading_more_posts": "Загружаем еще сообщения", "move_topic": "Перенести тему", + "move_topics": "Move Topics", "move_post": "Перенести сообщение", "post_moved": "Post moved!", "fork_topic": "Ответвить Тему", diff --git a/public/language/ru/user.json b/public/language/ru/user.json index b5fd8458b3..cb731a7ecb 100644 --- a/public/language/ru/user.json +++ b/public/language/ru/user.json @@ -58,5 +58,7 @@ "paginate_description": "Paginate topics and posts instead of using infinite scroll.", "topics_per_page": "Topics per Page", "posts_per_page": "Posts per Page", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/sc/error.json b/public/language/sc/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/sc/global.json b/public/language/sc/global.json index 30c5548c40..8a538cb203 100644 --- a/public/language/sc/global.json +++ b/public/language/sc/global.json @@ -18,6 +18,7 @@ "save_changes": "Alloga Acontzos", "close": "Serra", "pagination": "Paginatzione", + "pagination.out_of": "%1 out of %2", "header.admin": "Amministradore", "header.recent": "Ùrtimos", "header.unread": "De lèghere", @@ -35,7 +36,7 @@ "alert.success": "Andat Bene", "alert.error": "Faddina", "alert.banned": "Blocadu", - "alert.banned.message": "Ses blocadu e as a èssere bogadu a foras!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Immoe non ses prus sighende %1!", "alert.follow": "Immoe ses sighende %1!", "online": "In lìnia", diff --git a/public/language/sc/modules.json b/public/language/sc/modules.json index 43369b42dc..c033d9863b 100644 --- a/public/language/sc/modules.json +++ b/public/language/sc/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "iscrie su messàgiu de tzarra inoghe, carca imbiu pro imbiare", "chat.send": "Imbia", "chat.no_active": "Non tenes tzarras ativas.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/sc/topic.json b/public/language/sc/topic.json index d164ab8480..d9e07dbd19 100644 --- a/public/language/sc/topic.json +++ b/public/language/sc/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Non tenes perunu preferidu, pone intre is preferidos carchi arresonu pro ddu bìdere inoghe!", "loading_more_posts": "Càrriga Prus Arresonos", "move_topic": "Move Arresonada", + "move_topics": "Move Topics", "move_post": "Move Arresonu", "post_moved": "Post moved!", "fork_topic": "Partzi Arresonada", diff --git a/public/language/sc/user.json b/public/language/sc/user.json index 06fa075aa9..dda846d7ff 100644 --- a/public/language/sc/user.json +++ b/public/language/sc/user.json @@ -58,5 +58,7 @@ "paginate_description": "Partzi is arresonadas e arresonos in pàginas a su postu de impreare su iscorrimentu infinidu.", "topics_per_page": "Arresonadas pro Pàgina", "posts_per_page": "Arresonos pro Pàgina", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/sk/error.json b/public/language/sk/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/sk/global.json b/public/language/sk/global.json index f0c7f6af18..736768d351 100644 --- a/public/language/sk/global.json +++ b/public/language/sk/global.json @@ -18,6 +18,7 @@ "save_changes": "Uložiť zmeny", "close": "Zrušiť", "pagination": "Stránkovanie", + "pagination.out_of": "%1 out of %2", "header.admin": "Administrácia", "header.recent": "Aktuality", "header.unread": "Neprečítané", @@ -35,7 +36,7 @@ "alert.success": "Úspešne", "alert.error": "Chyba", "alert.banned": "Zakázany", - "alert.banned.message": "Tvoj prístup bol zakázany a budeš odhlasená/ý!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Už nenasleduješ %!", "alert.follow": "Nasleduješ %1!", "online": "Online", diff --git a/public/language/sk/modules.json b/public/language/sk/modules.json index 422596b96d..70f6fbbe82 100644 --- a/public/language/sk/modules.json +++ b/public/language/sk/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "napíšte správu sem a stlačte enter pre odoslanie", "chat.send": "Odoslať", "chat.no_active": "Nemáte žiadne aktívne konverzácie.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/sk/topic.json b/public/language/sk/topic.json index f2d55ce1c2..e257895739 100644 --- a/public/language/sk/topic.json +++ b/public/language/sk/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Nemáte žiadne obľúbené príspevky, pridajte niektorý príspevok k obľúbeným a uvidíte ho tu!", "loading_more_posts": "Načítavanie viac príspevkov", "move_topic": "Presunúť tému", + "move_topics": "Move Topics", "move_post": "Presunúť príspevok", "post_moved": "Post moved!", "fork_topic": "Rozdeliť príspevok", diff --git a/public/language/sk/user.json b/public/language/sk/user.json index 5d78ced6cf..3725b62805 100644 --- a/public/language/sk/user.json +++ b/public/language/sk/user.json @@ -58,5 +58,7 @@ "paginate_description": "Stránkuj témy a príspevky miesto používania nekonečného posúvania.", "topics_per_page": "Témy na stranu", "posts_per_page": "Príspevkov na stranu", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/sv/error.json b/public/language/sv/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/sv/global.json b/public/language/sv/global.json index 441a1aabad..132652ba7e 100644 --- a/public/language/sv/global.json +++ b/public/language/sv/global.json @@ -18,6 +18,7 @@ "save_changes": "Spara ändringar", "close": "Stäng", "pagination": "Siduppdelning", + "pagination.out_of": "%1 out of %2", "header.admin": "Admin", "header.recent": "Senaste", "header.unread": "Olästa", @@ -35,7 +36,7 @@ "alert.success": "success", "alert.error": "Fel", "alert.banned": "Bannad", - "alert.banned.message": "Du är bannad och kommer loggas ut!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Du följer inte längre %1!", "alert.follow": "Du följer nu %1!", "online": "Online", diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index 1b9871a3e4..f2db88914a 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "skriv meddelanden här, tryck enter för att skicka", "chat.send": "Skicka", "chat.no_active": "Du har inte några aktiva chattar.", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/sv/topic.json b/public/language/sv/topic.json index 66ca248587..be7fa71576 100644 --- a/public/language/sv/topic.json +++ b/public/language/sv/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Du har inga favoriter, markera inlägg som favorit för att se dem här!", "loading_more_posts": "Laddar fler inlägg", "move_topic": "Flytta ämne", + "move_topics": "Move Topics", "move_post": "Flytta inlägg", "post_moved": "Post moved!", "fork_topic": "Grena ämne", diff --git a/public/language/sv/user.json b/public/language/sv/user.json index 6c05c40dd0..a0042f3a37 100644 --- a/public/language/sv/user.json +++ b/public/language/sv/user.json @@ -58,5 +58,7 @@ "paginate_description": "Gör så att ämnen och inlägg visas som sidor istället för oändlig scroll.", "topics_per_page": "Ämnen per sida", "posts_per_page": "Inlägg per sida", - "notification_sounds": "Spela ett ljud när du får en notis." + "notification_sounds": "Spela ett ljud när du får en notis.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/th/error.json b/public/language/th/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/th/global.json b/public/language/th/global.json index ea02312ad6..0e7647dfe1 100644 --- a/public/language/th/global.json +++ b/public/language/th/global.json @@ -18,6 +18,7 @@ "save_changes": "บันทึกการเปลี่ยนแปลง", "close": "ปิด", "pagination": "ให้เลขหน้า", + "pagination.out_of": "%1 out of %2", "header.admin": "ผู้ดูแลระบบ", "header.recent": "ล่าสุด", "header.unread": "ไม่ได้อ่าน", @@ -35,7 +36,7 @@ "alert.success": "สำเร็จ", "alert.error": "ผิดพลาด", "alert.banned": "เเบน", - "alert.banned.message": "คุณถูกเเบน คุณจะได้รับการดำเนินการให้ออกจากระบบ", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "คุณได้ยกเลิกติดตาม %1 !\n", "alert.follow": "คุณกำลังติดตาม %1 !", "online": "ออนไลน์", diff --git a/public/language/th/modules.json b/public/language/th/modules.json index 4b453f4243..5a2508e020 100644 --- a/public/language/th/modules.json +++ b/public/language/th/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "พิมพ์ข้อความการแชทที่นี่ กด Enter เพื่อส่ง", "chat.send": "ส่ง", "chat.no_active": "คุณไม่มีแชทที่คุยอยู่", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/th/topic.json b/public/language/th/topic.json index 187b74b496..1cacfcde26 100644 --- a/public/language/th/topic.json +++ b/public/language/th/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "คุณไม่ได้มีโพสต์ที่ชอบ รายการโพสต์ที่ชอบที่จะเห็นได้ที่นี่", "loading_more_posts": "โหลดโพสเพิ่มเติม", "move_topic": "ย้ายกระทู้", + "move_topics": "Move Topics", "move_post": "ย้ายโพส", "post_moved": "Post moved!", "fork_topic": "แยกกระทู้", diff --git a/public/language/th/user.json b/public/language/th/user.json index 4ba2d2ab02..08ee8d0cea 100644 --- a/public/language/th/user.json +++ b/public/language/th/user.json @@ -58,5 +58,7 @@ "paginate_description": "ให้เลขหน้ากระทู้และโพสต์แทนการใช้สกรอลล์ที่ไม่สิ้นสุด", "topics_per_page": "จำนวนกระทู้ต่อหน้า", "posts_per_page": "จำนวนโพสต์ต่อหน้า", - "notification_sounds": "Play a sound when you receive a notification." + "notification_sounds": "Play a sound when you receive a notification.", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/tr/error.json b/public/language/tr/error.json index 0e1ccbe34b..904d7d9583 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Geçersiz Veri", "not-logged-in": "Giriş yapmamış görünüyorsunuz.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Geçersiz Kategori ID", "invalid-tid": "Geçersiz Başlık ID", "invalid-pid": "Geçersiz İleti ID", diff --git a/public/language/tr/global.json b/public/language/tr/global.json index 1dd370bfe8..27b0e6140a 100644 --- a/public/language/tr/global.json +++ b/public/language/tr/global.json @@ -18,6 +18,7 @@ "save_changes": "Değişiklikleri kaydet", "close": "Yakın", "pagination": "Sayfalara numara koyma", + "pagination.out_of": "%1 out of %2", "header.admin": "Yönetim", "header.recent": "Yeni", "header.unread": "Okunmamış", @@ -35,7 +36,7 @@ "alert.success": "Başarılı", "alert.error": "Hata", "alert.banned": "Yasaklı", - "alert.banned.message": "Yasaklandınız, çıkışınız yapılıyor!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "Artık %1'i takip etmiyorsunuz!", "alert.follow": "%1'i takip ediyorsunuz!", "online": "Çevrimiçi", diff --git a/public/language/tr/modules.json b/public/language/tr/modules.json index 8886ab4151..b43aa97824 100644 --- a/public/language/tr/modules.json +++ b/public/language/tr/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "Sohbet mesajınızı yazın, göndermek için enter'a basın", "chat.send": "Gönder", "chat.no_active": "Aktif sohbet mevcut değil", - "chat.user_typing": "%1 yazıyor ..." + "chat.user_typing": "%1 yazıyor ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/tr/user.json b/public/language/tr/user.json index 13f09484d7..d319a6c663 100644 --- a/public/language/tr/user.json +++ b/public/language/tr/user.json @@ -58,5 +58,7 @@ "paginate_description": "Sonsuz yükleme yerine konu ve iletileri sayfalara böl.", "topics_per_page": "Sayfa başına Konular", "posts_per_page": "Sayfa başına İletiler", - "notification_sounds": "Bildirim alındığında ses çal" + "notification_sounds": "Bildirim alındığında ses çal", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/vi/error.json b/public/language/vi/error.json index 3612b00e3d..4a24b297d4 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Dữ liệu không hợp lệ", "not-logged-in": "Bạn không được đăng nhập.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Danh mục ID không hợp lệ", "invalid-tid": "ID chủ đề không hợp lệ", "invalid-pid": "ID bài viết không hợp lệ", diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json index 0f80e4414d..02de3260b9 100644 --- a/public/language/vi/modules.json +++ b/public/language/vi/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "đánh đoạn tin nhắn chat ở đây, nhấn phím enter để gửi đi", "chat.send": "Gửi đi", "chat.no_active": "Bạn hiện giờ không có cuộc chat nào", - "chat.user_typing": "%1b đang gõ" + "chat.user_typing": "%1b đang gõ", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/vi/topic.json b/public/language/vi/topic.json index 1847f66d39..c13f998e76 100644 --- a/public/language/vi/topic.json +++ b/public/language/vi/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "Bạn đang không có yêu thích nào. Hãy yêu thích một vài bài viết để thấy được chúng tại đây!", "loading_more_posts": "Tải thêm các bài gửi khác", "move_topic": "Chuyển chủ đề", + "move_topics": "Move Topics", "move_post": "Chuyển bài gửi", "post_moved": "Đã chuyển bài gửi!", "fork_topic": "Fork chủ đề", diff --git a/public/language/zh_CN/error.json b/public/language/zh_CN/error.json index dddbcdfc88..9e0f283216 100644 --- a/public/language/zh_CN/error.json +++ b/public/language/zh_CN/error.json @@ -1,6 +1,7 @@ { "invalid-data": "无效数据", "not-logged-in": "你看起来还没有登陆", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "无效的板块ID", "invalid-tid": "无效的话题ID", "invalid-pid": "无效的帖子ID", diff --git a/public/language/zh_CN/global.json b/public/language/zh_CN/global.json index d0012c0233..bf0ab19b35 100644 --- a/public/language/zh_CN/global.json +++ b/public/language/zh_CN/global.json @@ -18,6 +18,7 @@ "save_changes": "保存修改", "close": "关闭", "pagination": "分页", + "pagination.out_of": "%1 out of %2", "header.admin": "管理", "header.recent": "最近", "header.unread": "未读", @@ -35,7 +36,7 @@ "alert.success": "成功", "alert.error": "错误", "alert.banned": "禁止", - "alert.banned.message": "你被禁止了将会退出登录。", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "你不再是关注的那1%!", "alert.follow": "你现在属于关注的1%!", "online": " 在线", diff --git a/public/language/zh_CN/modules.json b/public/language/zh_CN/modules.json index 7ac44c4222..df2dba1187 100644 --- a/public/language/zh_CN/modules.json +++ b/public/language/zh_CN/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "在这里输入消息,按Enter发送", "chat.send": "发送", "chat.no_active": "暂无聊天", - "chat.user_typing": "%1 正在输入……" + "chat.user_typing": "%1 正在输入……", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/zh_CN/topic.json b/public/language/zh_CN/topic.json index d678314f6f..6a0c366e8f 100644 --- a/public/language/zh_CN/topic.json +++ b/public/language/zh_CN/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "你还没有任何收藏,收藏的帖子将会出现在这里!", "loading_more_posts": "载入更多帖子", "move_topic": "移动主题", + "move_topics": "Move Topics", "move_post": "移动帖子", "post_moved": "Post moved!", "fork_topic": "作为主题", diff --git a/public/language/zh_CN/user.json b/public/language/zh_CN/user.json index 383952d163..273fa7353f 100644 --- a/public/language/zh_CN/user.json +++ b/public/language/zh_CN/user.json @@ -58,5 +58,7 @@ "paginate_description": "使用分页方式显示话题和帖子,代替滚动显示", "topics_per_page": "每页话题数量设置", "posts_per_page": "每页帖子数量设置", - "notification_sounds": "通知时播放声音提示。" + "notification_sounds": "通知时播放声音提示。", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file diff --git a/public/language/zh_TW/error.json b/public/language/zh_TW/error.json index d536c24a73..659b74b30b 100644 --- a/public/language/zh_TW/error.json +++ b/public/language/zh_TW/error.json @@ -1,6 +1,7 @@ { "invalid-data": "Invalid Data", "not-logged-in": "You don't seem to be logged in.", + "account-locked": "Your account has been locked temporarily", "invalid-cid": "Invalid Category ID", "invalid-tid": "Invalid Topic ID", "invalid-pid": "Invalid Post ID", diff --git a/public/language/zh_TW/global.json b/public/language/zh_TW/global.json index 3222f72a1e..759ad4a67b 100644 --- a/public/language/zh_TW/global.json +++ b/public/language/zh_TW/global.json @@ -18,6 +18,7 @@ "save_changes": "保存修改", "close": "關閉", "pagination": "分頁", + "pagination.out_of": "%1 out of %2", "header.admin": "管理", "header.recent": "最近", "header.unread": "未讀", @@ -35,7 +36,7 @@ "alert.success": "成功", "alert.error": "錯誤", "alert.banned": "封鎖", - "alert.banned.message": "你已被封鎖並將登出!", + "alert.banned.message": "You have just been banned, you will now be logged out.", "alert.unfollow": "你已不再關注 %1!", "alert.follow": "你正在關注 %1!", "online": "在線", diff --git a/public/language/zh_TW/modules.json b/public/language/zh_TW/modules.json index 4ab5f03c30..574d8ecac7 100644 --- a/public/language/zh_TW/modules.json +++ b/public/language/zh_TW/modules.json @@ -3,5 +3,6 @@ "chat.placeholder": "在這裡輸入消息,按Enter發送", "chat.send": "發送", "chat.no_active": "暫無聊天", - "chat.user_typing": "%1 is typing ..." + "chat.user_typing": "%1 is typing ...", + "chat.user_has_messaged_you": "%1 has messaged you." } \ No newline at end of file diff --git a/public/language/zh_TW/topic.json b/public/language/zh_TW/topic.json index f403487fc0..53f63d1716 100644 --- a/public/language/zh_TW/topic.json +++ b/public/language/zh_TW/topic.json @@ -65,6 +65,7 @@ "favourites.has_no_favourites": "你還沒有任何收藏,收藏的帖子將會出現在這裡!", "loading_more_posts": "載入更多帖子", "move_topic": "移動主題", + "move_topics": "Move Topics", "move_post": "移動帖子", "post_moved": "帖子已移動!", "fork_topic": "作為主題", diff --git a/public/language/zh_TW/user.json b/public/language/zh_TW/user.json index 6641250c06..49e8258246 100644 --- a/public/language/zh_TW/user.json +++ b/public/language/zh_TW/user.json @@ -58,5 +58,7 @@ "paginate_description": "使用分頁取代瀏覽載入帖子模式.", "topics_per_page": "每頁的主題數", "posts_per_page": "每頁的帖子數", - "notification_sounds": "當收到新消息時播放提示音" + "notification_sounds": "當收到新消息時播放提示音", + "browsing": "Browsing Settings", + "open_links_in_new_tab": "Open outgoing links in new tab?" } \ No newline at end of file From 0e20350ca7aa227d1899fb70c807a6032685295e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 13 May 2014 16:40:19 -0400 Subject: [PATCH 88/88] 0.4.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c419ed9d12..64e9df2d6c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.4.2", + "version": "0.4.3", "homepage": "http://www.nodebb.org", "repository": { "type": "git",