From 93b6b6ba5f49fd654cd72ed15730aa09be581a24 Mon Sep 17 00:00:00 2001 From: APXEOLOG Date: Thu, 2 Jul 2015 13:03:43 +0300 Subject: [PATCH 01/49] Fixed two bugs: 1. filename cannot contain ':' (at least on windows), nodebb crashes with such filename 2. lwip cannot define image type without file extension Also added image extension check to prevent security issues --- src/user/picture.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/user/picture.js b/src/user/picture.js index ada87589d6..852f575e07 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -90,7 +90,11 @@ module.exports = function(User) { }; User.uploadFromUrl = function(uid, url, callback) { - var filename = 'uid:' + uid + ':tmp-image'; + var extension = url.substring(url.lastIndexOf('.') + 1); + if (['png', 'jpeg', 'jpg', 'gif'].indexOf(extension) == -1) { + return callback('This image type is not allowed'); + } + var filename = 'uid_' + uid + '_tmp-image.' + extension; downloadFromUrl(url, filename, function(err, downloadedImage) { if (err) { return callback(err); From 1d7b2b577648dcf4b4c41dc98e28bea6ae352335 Mon Sep 17 00:00:00 2001 From: APXEOLOG Date: Thu, 2 Jul 2015 14:18:50 +0300 Subject: [PATCH 02/49] Branch for Pull Request From 1ae0077810074dc290ba6def6ca61ecd09a146e0 Mon Sep 17 00:00:00 2001 From: APXEOLOG Date: Thu, 2 Jul 2015 18:29:46 +0300 Subject: [PATCH 03/49] Change error message to localized one --- src/user/picture.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user/picture.js b/src/user/picture.js index 852f575e07..80b565217a 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -92,7 +92,7 @@ module.exports = function(User) { User.uploadFromUrl = function(uid, url, callback) { var extension = url.substring(url.lastIndexOf('.') + 1); if (['png', 'jpeg', 'jpg', 'gif'].indexOf(extension) == -1) { - return callback('This image type is not allowed'); + return callback('[[error:invalid-image-extension]]'); } var filename = 'uid_' + uid + '_tmp-image.' + extension; downloadFromUrl(url, filename, function(err, downloadedImage) { From 491d376fb42aa547e4373160d066d3c7c3f3151c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 3 Jul 2015 16:42:48 -0400 Subject: [PATCH 04/49] closes #2605 --- public/src/client/groups/details.js | 85 ++++++++++++++++++++++++++++- src/controllers/groups.js | 4 +- src/groups.js | 66 +++++++++++++--------- src/groups/ownership.js | 8 +++ src/groups/search.js | 43 ++++++++++++++- src/socket.io/groups.js | 14 +++++ 6 files changed, 192 insertions(+), 28 deletions(-) diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index 1f7bd3f2df..118dbcddda 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -1,11 +1,13 @@ "use strict"; /* globals define, socket, ajaxify, app, bootbox, RELATIVE_PATH, utils */ -define('forum/groups/details', ['iconSelect', 'components', 'vendor/colorpicker/colorpicker', 'vendor/jquery/draggable-background/backgroundDraggable'], function(iconSelect, components) { +define('forum/groups/details', ['iconSelect', 'components', 'forum/infinitescroll', 'vendor/colorpicker/colorpicker', 'vendor/jquery/draggable-background/backgroundDraggable'], function(iconSelect, components, infinitescroll) { var Details = { cover: {} }; + var searchInterval; + Details.init = function() { var detailsPage = components.get('groups/container'), settingsFormEl = detailsPage.find('form'); @@ -15,6 +17,9 @@ define('forum/groups/details', ['iconSelect', 'components', 'vendor/colorpicker/ Details.initialiseCover(); } + handleMemberSearch(); + handleMemberInfiniteScroll(); + components.get('groups/activity').find('.content img').addClass('img-responsive'); detailsPage.on('click', '[data-action]', function() { @@ -280,5 +285,83 @@ define('forum/groups/details', ['iconSelect', 'components', 'vendor/colorpicker/ }); }; + function handleMemberSearch() { + $('[component="groups/members/search"]').on('keyup', function() { + var query = $(this).val(); + if (searchInterval) { + clearInterval(searchInterval); + searchInterval = 0; + } + + searchInterval = setTimeout(function() { + socket.emit('groups.searchMembers', {groupName: ajaxify.variables.get('group_name'), query: query}, function(err, results) { + if (err) { + return app.alertError(err.message); + } + + infinitescroll.parseAndTranslate('groups/details', 'members', { + group: { + members: results.users, + isOwner: ajaxify.variables.get('is_owner') === 'true' + } + }, function(html) { + $('[component="groups/members"] tbody').html(html); + }); + }); + }, 250); + }) + } + + function handleMemberInfiniteScroll() { + $('[component="groups/members"] tbody').on('scroll', function() { + var $this = $(this); + var bottom = ($this[0].scrollHeight - $this.height()) * 0.9; + if ($this.scrollTop() > bottom) { + loadMoreMembers(); + } + }); + } + + function loadMoreMembers() { + var members = $('[component="groups/members"]'); + if (members.attr('loading')) { + return; + } + members.attr('loading', 1); + socket.emit('groups.loadMoreMembers', { + groupName: ajaxify.variables.get('group_name'), + after: members.attr('data-nextstart') + }, function(err, data) { + if (err) { + return app.alertError(err.message); + } + + if (data && data.users.length) { + onMembersLoaded(data.users, function() { + members.removeAttr('loading'); + members.attr('data-nextstart', data.nextStart); + }); + } else { + members.removeAttr('loading'); + } + }); + } + + function onMembersLoaded(users, callback) { + users = users.filter(function(user) { + return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length; + }); + + infinitescroll.parseAndTranslate('groups/details', 'members', { + group: { + members: users, + isOwner: ajaxify.variables.get('is_owner') === 'true' + } + }, function(html) { + $('[component="groups/members"] tbody').append(html); + callback(); + }); + } + return Details; }); \ No newline at end of file diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 8d7ddac3e2..84a3e25e2d 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -79,7 +79,9 @@ groupsController.details = function(req, res, next) { async.parallel({ group: function(next) { groups.get(res.locals.groupName, { - uid: req.uid + uid: req.uid, + truncateUserList: true, + userListCount: 20 }, next); }, posts: function(next) { diff --git a/src/groups.js b/src/groups.js index 8db9afe80b..b08c6eed3c 100644 --- a/src/groups.js +++ b/src/groups.js @@ -115,27 +115,18 @@ var async = require('async'), } options.escape = options.hasOwnProperty('escape') ? options.escape : true; + var stop = -1; async.parallel({ base: function (next) { db.getObject('group:' + groupName, next); }, - owners: function (next) { - async.waterfall([ - function(next) { - db.getSetMembers('group:' + groupName + ':owners', next); - }, - function(uids, next) { - user.getUsers(uids, options.uid, next); - } - ], next); - }, members: function (next) { - var stop = -1; if (options.truncateUserList) { stop = (parseInt(options.userListCount, 10) || 4) - 1; } - user.getUsersFromSet('group:' + groupName + ':members', options.uid, 0, stop, next); + + Groups.getOwnersAndMembers(groupName, options.uid, 0, stop, next); }, pending: function (next) { async.waterfall([ @@ -164,19 +155,6 @@ var async = require('async'), results.base['cover:position'] = '50% 50%'; } - var ownerUids = []; - results.owners.forEach(function(user) { - if (user) { - user.isOwner = true; - ownerUids.push(user.uid.toString()); - } - }); - - results.members = results.members.filter(function(user, index, array) { - return user && user.uid && ownerUids.indexOf(user.uid.toString()) === -1; - }); - results.members = results.owners.concat(results.members); - plugins.fireHook('filter:parse.raw', results.base.description, function(err, descriptionParsed) { if (err) { return callback(err); @@ -190,6 +168,7 @@ var async = require('async'), results.base.userTitleEnabled = results.base.userTitleEnabled ? !!parseInt(results.base.userTitleEnabled, 10) : true; results.base.createtimeISO = utils.toISOString(results.base.createtime); results.base.members = results.members; + results.base.membersNextStart = stop + 1; results.base.pending = results.pending.filter(Boolean); results.base.deleted = !!parseInt(results.base.deleted, 10); results.base.hidden = !!parseInt(results.base.hidden, 10); @@ -207,6 +186,43 @@ var async = require('async'), }); }; + Groups.getOwnersAndMembers = function(groupName, uid, start, stop, callback) { + async.parallel({ + owners: function (next) { + async.waterfall([ + function(next) { + db.getSetMembers('group:' + groupName + ':owners', next); + }, + function(uids, next) { + user.getUsers(uids, uid, next); + } + ], next); + }, + members: function (next) { + user.getUsersFromSet('group:' + groupName + ':members', uid, start, stop, next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + + var ownerUids = []; + results.owners.forEach(function(user) { + if (user) { + user.isOwner = true; + ownerUids.push(user.uid.toString()); + } + }); + + results.members = results.members.filter(function(user, index, array) { + return user && user.uid && ownerUids.indexOf(user.uid.toString()) === -1; + }); + results.members = results.owners.concat(results.members); + + callback(null, results.members); + }); + }; + Groups.escapeGroupData = function(group) { if (group) { group.nameEncoded = encodeURIComponent(group.name); diff --git a/src/groups/ownership.js b/src/groups/ownership.js index fa4beb70ba..4af6126aef 100644 --- a/src/groups/ownership.js +++ b/src/groups/ownership.js @@ -13,6 +13,14 @@ module.exports = function(Groups) { db.isSetMember('group:' + groupName + ':owners', uid, callback); }; + Groups.ownership.isOwners = function(uids, groupName, callback) { + if (!Array.isArray(uids)) { + return callback(null, []); + } + + db.isSetMembers('group:' + groupName + ':owners', uids, callback); + }; + Groups.ownership.grant = function(toUid, groupName, callback) { // Note: No ownership checking is done here on purpose! db.setAdd('group:' + groupName + ':owners', toUid, callback); diff --git a/src/groups/search.js b/src/groups/search.js index d674b29dba..1491129f30 100644 --- a/src/groups/search.js +++ b/src/groups/search.js @@ -87,7 +87,48 @@ module.exports = function(Groups) { ], callback); } + if (!data.query) { + Groups.getOwnersAndMembers(data.groupName, data.uid, 0, 19, function(err, users) { + if (err) { + return callback(err); + } + callback(null, {users: users}); + }); + return; + } + data.findUids = findUids; - user.search(data, callback); + var results; + async.waterfall([ + function(next) { + user.search(data, next); + }, + function(_results, next) { + results = _results; + var uids = results.users.map(function(user) { + return user && user.uid; + }); + Groups.ownership.isOwners(uids, data.groupName, next); + }, + function(isOwners, next) { + + results.users.forEach(function(user, index) { + if (user) { + user.isOwner = isOwners[index]; + } + }); + + results.users.sort(function(a,b) { + if (a.isOwner && !b.isOwner) { + return -1; + } else if (!a.isOwner && b.isOwner) { + return 1; + } else { + return 0; + } + }) + next(null, results); + } + ], callback); }; }; diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 69ce6a367c..671777ea95 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -244,6 +244,20 @@ SocketGroups.searchMembers = function(socket, data, callback) { groups.searchMembers(data, callback); }; +SocketGroups.loadMoreMembers = function(socket, data, callback) { + if (!data || !data.groupName || !parseInt(data.after, 10)) { + return callback(new Error('[[error:invalid-data]]')); + } + data.after = parseInt(data.after, 10); + user.getUsersFromSet('group:' + data.groupName + ':members', socket.uid, data.after, data.after + 9, function(err, users) { + if (err) { + return callback(err); + } + + callback(null, {users: users, nextStart: data.after + 10}); + }); +}; + SocketGroups.kick = function(socket, data, callback) { if (!data) { return callback(new Error('[[error:invalid-data]]')); From 48af82659ed16abd0f8d9df2ddd6b5d00b4807e3 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 3 Jul 2015 16:41:21 -0400 Subject: [PATCH 05/49] removing the composer from core, out to its own plugin: nodebb-plugin-composer-default, closes #3288 --- package.json | 3 +- public/src/app.js | 32 +- public/src/client/category.js | 3 +- public/src/client/topic/postTools.js | 90 +-- public/src/modules/composer.js | 595 -------------------- public/src/modules/composer/categoryList.js | 44 -- public/src/modules/composer/controls.js | 46 -- public/src/modules/composer/drafts.js | 69 --- public/src/modules/composer/formatting.js | 58 -- public/src/modules/composer/preview.js | 83 --- public/src/modules/composer/resize.js | 195 ------- public/src/modules/composer/tags.js | 92 --- public/src/modules/composer/uploads.js | 324 ----------- src/messaging.js | 3 +- src/upgrade.js | 28 +- 15 files changed, 99 insertions(+), 1566 deletions(-) delete mode 100644 public/src/modules/composer.js delete mode 100644 public/src/modules/composer/categoryList.js delete mode 100644 public/src/modules/composer/controls.js delete mode 100644 public/src/modules/composer/drafts.js delete mode 100644 public/src/modules/composer/formatting.js delete mode 100644 public/src/modules/composer/preview.js delete mode 100644 public/src/modules/composer/resize.js delete mode 100644 public/src/modules/composer/tags.js delete mode 100644 public/src/modules/composer/uploads.js diff --git a/package.json b/package.json index 60b101277c..38713a683c 100644 --- a/package.json +++ b/package.json @@ -28,18 +28,19 @@ "daemon": "~1.1.0", "express": "^4.9.5", "express-session": "^1.8.2", - "lwip": "0.0.7", "gravatar": "^1.1.0", "heapdump": "^0.3.0", "less": "^2.0.0", "logrotate-stream": "^0.2.3", "lru-cache": "^2.6.1", + "lwip": "0.0.7", "mime": "^1.3.4", "minimist": "^1.1.1", "mkdirp": "~0.5.0", "mmmagic": "^0.3.13", "morgan": "^1.3.2", "nconf": "~0.7.1", + "nodebb-plugin-composer-default": "^1.0.0", "nodebb-plugin-dbsearch": "^0.2.12", "nodebb-plugin-emoji-extended": "^0.4.8", "nodebb-plugin-markdown": "^3.0.0", diff --git a/public/src/app.js b/public/src/app.js index 74829543af..30a7d8bc68 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -466,21 +466,23 @@ app.cacheBuster = null; function handleNewTopic() { $('#content').on('click', '#new_topic', function() { - require(['composer'], function(composer) { - var cid = ajaxify.variables.get('category_id'); - if (cid) { - composer.newTopic(cid); - } else { - socket.emit('categories.getCategoriesByPrivilege', 'topics:create', function(err, categories) { - if (err) { - return app.alertError(err.message); - } - if (categories.length) { - composer.newTopic(categories[0].cid); - } - }); - } - }); + var cid = ajaxify.variables.get('category_id'); + if (cid) { + $(window).trigger('action:composer.topic.new', { + cid: cid + }); + } else { + socket.emit('categories.getCategoriesByPrivilege', 'topics:create', function(err, categories) { + if (err) { + return app.alertError(err.message); + } + if (categories.length) { + $(window).trigger('action:composer.topic.new', { + cid: categories[0].cid + }); + } + }); + } }); } diff --git a/public/src/client/category.js b/public/src/client/category.js index 777d3f808a..d60c643462 100644 --- a/public/src/client/category.js +++ b/public/src/client/category.js @@ -2,7 +2,6 @@ /* global define, config, templates, app, utils, ajaxify, socket */ define('forum/category', [ - 'composer', 'forum/pagination', 'forum/infinitescroll', 'share', @@ -11,7 +10,7 @@ define('forum/category', [ 'sort', 'components', 'translator' -], function(composer, pagination, infinitescroll, share, navigator, categoryTools, sort, components, translator) { +], function(pagination, infinitescroll, share, navigator, categoryTools, sort, components, translator) { var Category = {}; $(window).on('action:ajaxify.start', function(ev, data) { diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 4a227252a8..0ddeb8a700 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -108,9 +108,9 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator postContainer.on('click', '[component="post/edit"]', function(e) { var btn = $(this); - require(['composer'], function(composer) { - composer.editPost(getData(btn, 'data-pid')); - }); + $(window).trigger('action:composer.post.edit', { + pid: getData(btn, 'data-pid') + }) }); postContainer.on('click', '[component="post/delete"]', function(e) { @@ -135,51 +135,61 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator } function onReplyClicked(button, tid, topicName) { - require(['composer'], function(composer) { - var selectionText = '', - selection = window.getSelection ? window.getSelection() : document.selection.createRange(), - topicUUID = composer.findByTid(tid); + var selectionText = '', + selection = window.getSelection ? window.getSelection() : document.selection.createRange(); - if ($(selection.baseNode).parents('[component="post/content"]').length > 0) { - var snippet = selection.toString(); - if (snippet.length) { - selectionText = '> ' + snippet.replace(/\n/g, '\n> ') + '\n\n'; - } + if ($(selection.baseNode).parents('[component="post/content"]').length > 0) { + var snippet = selection.toString(); + if (snippet.length) { + selectionText = '> ' + snippet.replace(/\n/g, '\n> ') + '\n\n'; } + } - var username = getUserName(selectionText ? $(selection.baseNode) : button); - if (getData(button, 'data-uid') === '0') { - username = ''; - } - if (selectionText.length) { - composer.addQuote(tid, ajaxify.variables.get('topic_slug'), getData(button, 'data-index'), getData(button, 'data-pid'), topicName, username, selectionText, topicUUID); - } else { - composer.newReply(tid, getData(button, 'data-pid'), topicName, username ? username + ' ' : ''); - } - }); - + var username = getUserName(selectionText ? $(selection.baseNode) : button); + if (getData(button, 'data-uid') === '0') { + username = ''; + } + if (selectionText.length) { + $(window).trigger('action:composer.addQuote', { + tid: tid, + slug: ajaxify.variables.get('topic_slug'), + index: getData(button, 'data-index'), + pid: getData(button, 'data-pid'), + topicName: topicName, + username: username, + text: selectionText + }); + } else { + $(window).trigger('action:composer.post.new', { + tid: tid, + pid: ajaxify.variables.get('pid'), + topicName: topicName, + text: username + ' ' || '' + }); + } } function onQuoteClicked(button, tid, topicName) { - require(['composer'], function(composer) { - var username = getUserName(button), - pid = getData(button, 'data-pid'), - topicUUID = composer.findByTid(tid); + var username = getUserName(button), + pid = getData(button, 'data-pid'); - socket.emit('posts.getRawPost', pid, function(err, post) { - if(err) { - return app.alertError(err.message); - } - var quoted = ''; - if(post) { - quoted = '> ' + post.replace(/\n/g, '\n> ') + '\n\n'; - } + socket.emit('posts.getRawPost', pid, function(err, post) { + if(err) { + return app.alertError(err.message); + } + var quoted = ''; + if(post) { + quoted = '> ' + post.replace(/\n/g, '\n> ') + '\n\n'; + } - if(topicUUID) { - composer.addQuote(tid, ajaxify.variables.get('topic_slug'), getData(button, 'data-index'), pid, topicName, username, quoted, topicUUID); - } else { - composer.newReply(tid, pid, topicName, '[[modules:composer.user_said, ' + username + ']]\n' + quoted); - } + $(window).trigger('action:composer.addQuote', { + tid: tid, + slug: ajaxify.variables.get('topic_slug'), + index: getData(button, 'data-index'), + pid: pid, + username: username, + topicName: topicName, + text: quoted }); }); } diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js deleted file mode 100644 index 1e32892617..0000000000 --- a/public/src/modules/composer.js +++ /dev/null @@ -1,595 +0,0 @@ -'use strict'; - -/* globals define, socket, app, config, ajaxify, utils, templates, bootbox */ - -define('composer', [ - 'taskbar', - 'translator', - 'composer/controls', - 'composer/uploads', - 'composer/formatting', - 'composer/drafts', - 'composer/tags', - 'composer/categoryList', - 'composer/preview', - 'composer/resize' -], function(taskbar, translator, controls, uploads, formatting, drafts, tags, categoryList, preview, resize) { - var composer = { - active: undefined, - posts: {}, - bsEnvironment: undefined, - formatting: [] - }; - - $(window).off('resize', onWindowResize).on('resize', onWindowResize); - - $(window).on('action:composer.topics.post', function(ev, data) { - localStorage.removeItem('category:' + data.data.cid + ':bookmark'); - localStorage.removeItem('category:' + data.data.cid + ':bookmark:clicked'); - }); - - $(window).on('popstate', function(ev, data) { - var env = utils.findBootstrapEnvironment(); - - if (composer.active && (env === 'xs' || env ==='sm')) { - if (!composer.posts[composer.active].modified) { - discard(composer.active); - return; - } - - translator.translate('[[modules:composer.discard]]', function(translated) { - bootbox.confirm(translated, function(confirm) { - if (confirm) { - discard(composer.active); - } - }); - }); - } - }); - - function removeComposerHistory() { - var env = utils.findBootstrapEnvironment(); - if (env === 'xs' || env ==='sm') { - history.back(); - } - } - - // Query server for formatting options - socket.emit('modules.composer.getFormattingOptions', function(err, options) { - composer.formatting = options; - }); - - function onWindowResize() { - if (composer.active !== undefined) { - resize.reposition($('#cmp-uuid-' + composer.active)); - } - } - - function alreadyOpen(post) { - // If a composer for the same cid/tid/pid is already open, return the uuid, else return bool false - var type, id; - - if (post.hasOwnProperty('cid')) { - type = 'cid'; - } else if (post.hasOwnProperty('tid')) { - type = 'tid'; - } else if (post.hasOwnProperty('pid')) { - type = 'pid'; - } - - id = post[type]; - - // Find a match - for(var uuid in composer.posts) { - if (composer.posts[uuid].hasOwnProperty(type) && id === composer.posts[uuid][type]) { - return uuid; - } - } - - // No matches... - return false; - } - - function push(post) { - var uuid = utils.generateUUID(), - existingUUID = alreadyOpen(post); - - if (existingUUID) { - taskbar.updateActive(existingUUID); - return composer.load(existingUUID); - } - - translator.translate('[[topic:composer.new_topic]]', function(newTopicStr) { - taskbar.push('composer', uuid, { - title: post.title ? post.title : newTopicStr - }); - }); - - // Construct a save_id - if (0 !== parseInt(app.user.uid, 10)) { - if (post.hasOwnProperty('cid')) { - post.save_id = ['composer', app.user.uid, 'cid', post.cid].join(':'); - } else if (post.hasOwnProperty('tid')) { - post.save_id = ['composer', app.user.uid, 'tid', post.tid].join(':'); - } else if (post.hasOwnProperty('pid')) { - post.save_id = ['composer', app.user.uid, 'pid', post.pid].join(':'); - } - } - - composer.posts[uuid] = post; - composer.load(uuid); - } - - function composerAlert(post_uuid, message) { - $('#cmp-uuid-' + post_uuid).find('.composer-submit').removeAttr('disabled'); - app.alert({ - type: 'danger', - timeout: 3000, - title: '', - message: message, - alert_id: 'post_error' - }); - } - - composer.findByTid = function(tid) { - // Iterates through the initialised composers and returns the uuid of the matching composer - for(var uuid in composer.posts) { - if (composer.posts.hasOwnProperty(uuid) && composer.posts[uuid].hasOwnProperty('tid') && parseInt(composer.posts[uuid].tid, 10) === parseInt(tid, 10)) { - return uuid; - } - } - - return null; - }; - - composer.addButton = function(iconClass, onClick) { - formatting.addButton(iconClass, onClick); - }; - - composer.newTopic = function(cid) { - socket.emit('categories.isModerator', cid, function(err, isMod) { - if (err) { - return app.alertError(err.message); - } - push({ - cid: cid, - title: '', - body: '', - modified: false, - isMain: true, - isMod: isMod - }); - }); - }; - - composer.addQuote = function(tid, topicSlug, postIndex, pid, title, username, text, uuid) { - uuid = uuid || composer.active; - - if (uuid === undefined) { - composer.newReply(tid, pid, title, '[[modules:composer.user_said, ' + username + ']]\n' + text); - return; - } else if (uuid !== composer.active) { - // If the composer is not currently active, activate it - composer.load(uuid); - } - - var postContainer = $('#cmp-uuid-' + uuid); - var bodyEl = postContainer.find('textarea'); - var prevText = bodyEl.val(); - if (parseInt(tid, 10) !== parseInt(composer.posts[uuid].tid, 10)) { - var link = '[' + title + '](/topic/' + topicSlug + '/' + (parseInt(postIndex, 10) + 1) + ')'; - translator.translate('[[modules:composer.user_said_in, ' + username + ', ' + link + ']]\n', config.defaultLang, onTranslated); - } else { - translator.translate('[[modules:composer.user_said, ' + username + ']]\n', config.defaultLang, onTranslated); - } - - function onTranslated(translated) { - composer.posts[uuid].body = (prevText.length ? prevText + '\n\n' : '') + translated + text; - bodyEl.val(composer.posts[uuid].body); - focusElements(postContainer); - preview.render(postContainer); - } - }; - - composer.newReply = function(tid, pid, title, text) { - socket.emit('topics.isModerator', tid, function(err, isMod) { - if (err) { - return app.alertError(err.message); - } - translator.translate(text, config.defaultLang, function(translated) { - push({ - tid: tid, - toPid: pid, - title: $('
').text(title).html(), - body: translated, - modified: false, - isMain: false, - isMod: isMod - }); - }); - }); - }; - - composer.editPost = function(pid) { - socket.emit('modules.composer.push', pid, function(err, threadData) { - if(err) { - return app.alertError(err.message); - } - - push({ - pid: pid, - uid: threadData.uid, - handle: threadData.handle, - title: threadData.title, - body: threadData.body, - modified: false, - isMain: threadData.isMain, - topic_thumb: threadData.topic_thumb, - tags: threadData.tags - }); - }); - }; - - composer.load = function(post_uuid) { - var postContainer = $('#cmp-uuid-' + post_uuid); - if (postContainer.length) { - activate(post_uuid); - resize.reposition(postContainer); - focusElements(postContainer); - } else { - createNewComposer(post_uuid); - } - - startNotifyTyping(composer.posts[post_uuid]); - }; - - function startNotifyTyping(postData) { - function emit() { - socket.emit('modules.composer.notifyTyping', { - tid: postData.tid, - uid: app.user.uid - }); - } - - if (!parseInt(postData.tid, 10)) { - return; - } - - stopNotifyInterval(postData); - - emit(); - postData.notifyTypingIntervalId = setInterval(emit, 5000); - } - - function stopNotifyTyping(postData) { - if (!parseInt(postData.tid, 10)) { - return; - } - socket.emit('modules.composer.stopNotifyTyping', { - tid: postData.tid, - uid: app.user.uid - }); - } - - function stopNotifyInterval(postData) { - if (postData.notifyTypingIntervalId) { - clearInterval(postData.notifyTypingIntervalId); - postData.notifyTypingIntervalId = 0; - } - } - - function createNewComposer(post_uuid) { - var postData = composer.posts[post_uuid]; - - var allowTopicsThumbnail = config.allowTopicsThumbnail && postData.isMain && (config.hasImageUploadPlugin || config.allowFileUploads), - isTopic = postData ? !!postData.cid : false, - isMain = postData ? !!postData.isMain : false, - isEditing = postData ? !!postData.pid : false, - isGuestPost = postData ? parseInt(postData.uid, 10) === 0 : false; - - composer.bsEnvironment = utils.findBootstrapEnvironment(); - - // see - // https://github.com/NodeBB/NodeBB/issues/2994 and - // https://github.com/NodeBB/NodeBB/issues/1951 - // remove when 1951 is resolved - - var title = postData.title.replace(/%/g, '%').replace(/,/g, ','); - - var data = { - title: title, - mobile: composer.bsEnvironment === 'xs' || composer.bsEnvironment === 'sm', - allowTopicsThumbnail: allowTopicsThumbnail, - isTopicOrMain: isTopic || isMain, - minimumTagLength: config.minimumTagLength, - maximumTagLength: config.maximumTagLength, - isTopic: isTopic, - isEditing: isEditing, - showHandleInput: config.allowGuestHandles && (app.user.uid === 0 || (isEditing && isGuestPost && app.user.isAdmin)), - handle: postData ? postData.handle || '' : undefined, - formatting: composer.formatting, - isAdminOrMod: app.user.isAdmin || postData.isMod - }; - - if (data.mobile) { - var qs = '?p=' + window.location.pathname; - ajaxify.go('compose', function() { - renderComposer(); - }, false, qs); - } else { - renderComposer(); - } - - function renderComposer() { - parseAndTranslate('composer', data, function(composerTemplate) { - if ($('#cmp-uuid-' + post_uuid).length) { - return; - } - composerTemplate = $(composerTemplate); - - composerTemplate.attr('id', 'cmp-uuid-' + post_uuid); - - $(document.body).append(composerTemplate); - - var postContainer = $(composerTemplate[0]), - bodyEl = postContainer.find('textarea'), - draft = drafts.getDraft(postData.save_id), - submitBtn = postContainer.find('.composer-submit'); - - preview.handleToggler(postContainer); - tags.init(postContainer, composer.posts[post_uuid]); - categoryList.init(postContainer, composer.posts[post_uuid]); - - activate(post_uuid); - resize.reposition(postContainer); - - if (config.allowFileUploads || config.hasImageUploadPlugin) { - uploads.initialize(post_uuid); - } - - formatting.addHandler(postContainer); - - if (allowTopicsThumbnail) { - uploads.toggleThumbEls(postContainer, composer.posts[post_uuid].topic_thumb || ''); - } - - postContainer.on('change', 'input, textarea', function() { - composer.posts[post_uuid].modified = true; - }); - - submitBtn.on('click', function() { - var action = $(this).attr('data-action'); - - switch(action) { - case 'post-lock': - $(this).attr('disabled', true); - post(post_uuid, {lock: true}); - break; - - case 'post': // intentional fall-through - default: - $(this).attr('disabled', true); - post(post_uuid); - break; - } - }); - - postContainer.on('click', 'a[data-switch-action]', function() { - var action = $(this).attr('data-switch-action'), - label = $(this).html(); - - submitBtn.attr('data-action', action).html(label); - }); - - postContainer.find('.composer-discard').on('click', function() { - if (!composer.posts[post_uuid].modified) { - removeComposerHistory(); - discard(post_uuid); - return; - } - var btn = $(this).prop('disabled', true); - translator.translate('[[modules:composer.discard]]', function(translated) { - bootbox.confirm(translated, function(confirm) { - if (confirm) { - removeComposerHistory(); - discard(post_uuid); - } - btn.prop('disabled', false); - }); - }); - }); - - postContainer.on('click', function() { - if (!taskbar.isActive(post_uuid)) { - taskbar.updateActive(post_uuid); - } - }); - - bodyEl.on('input propertychange', function() { - preview.render(postContainer); - }); - - bodyEl.on('scroll', function() { - preview.matchScroll(postContainer); - }); - - bodyEl.val(draft ? draft : postData.body); - - preview.render(postContainer, function() { - preview.matchScroll(postContainer); - }); - - drafts.init(postContainer, postData); - - resize.handleResize(postContainer); - - handleHelp(postContainer); - - $(window).trigger('action:composer.loaded', { - post_uuid: post_uuid, - composerData: composer.posts[post_uuid] - }); - - formatting.addComposerButtons(); - focusElements(postContainer); - }); - } - } - - function parseAndTranslate(template, data, callback) { - templates.parse(template, data, function(composerTemplate) { - translator.translate(composerTemplate, callback); - }); - } - - function handleHelp(postContainer) { - var helpBtn = postContainer.find('.help'); - socket.emit('modules.composer.renderHelp', function(err, html) { - if (!err && html && html.length > 0) { - helpBtn.removeClass('hidden'); - helpBtn.on('click', function() { - bootbox.alert(html); - }); - } - }); - } - - function activate(post_uuid) { - if(composer.active && composer.active !== post_uuid) { - composer.minimize(composer.active); - } - - composer.active = post_uuid; - } - - function focusElements(postContainer) { - var title = postContainer.find('input.title'); - if (title.length) { - title.focus(); - } else { - postContainer.find('textarea').focus().putCursorAtEnd(); - } - } - - function post(post_uuid, options) { - var postData = composer.posts[post_uuid], - postContainer = $('#cmp-uuid-' + post_uuid), - handleEl = postContainer.find('.handle'), - titleEl = postContainer.find('.title'), - bodyEl = postContainer.find('textarea'), - thumbEl = postContainer.find('input#topic-thumb-url'); - - options = options || {}; - - titleEl.val(titleEl.val().trim()); - bodyEl.val(bodyEl.val().trim()); - if (thumbEl.length) { - thumbEl.val(thumbEl.val().trim()); - } - - var checkTitle = (parseInt(postData.cid, 10) || parseInt(postData.pid, 10)) && postContainer.find('input.title').length; - - if (uploads.inProgress[post_uuid] && uploads.inProgress[post_uuid].length) { - return composerAlert(post_uuid, '[[error:still-uploading]]'); - } else if (checkTitle && titleEl.val().length < parseInt(config.minimumTitleLength, 10)) { - return composerAlert(post_uuid, '[[error:title-too-short, ' + config.minimumTitleLength + ']]'); - } else if (checkTitle && titleEl.val().length > parseInt(config.maximumTitleLength, 10)) { - return composerAlert(post_uuid, '[[error:title-too-long, ' + config.maximumTitleLength + ']]'); - } else if (checkTitle && !utils.slugify(titleEl.val()).length) { - return composerAlert(post_uuid, '[[error:invalid-title]]'); - } else if (bodyEl.val().length < parseInt(config.minimumPostLength, 10)) { - return composerAlert(post_uuid, '[[error:content-too-short, ' + config.minimumPostLength + ']]'); - } else if (bodyEl.val().length > parseInt(config.maximumPostLength, 10)) { - return composerAlert(post_uuid, '[[error:content-too-long, ' + config.maximumPostLength + ']]'); - } - - var composerData = {}, action; - - if (parseInt(postData.cid, 10) > 0) { - action = 'topics.post'; - composerData = { - handle: handleEl ? handleEl.val() : undefined, - title: titleEl.val(), - content: bodyEl.val(), - topic_thumb: thumbEl.val() || '', - category_id: postData.cid, - tags: tags.getTags(post_uuid), - lock: options.lock || false - }; - } else if (parseInt(postData.tid, 10) > 0) { - action = 'posts.reply'; - composerData = { - tid: postData.tid, - handle: handleEl ? handleEl.val() : undefined, - content: bodyEl.val(), - toPid: postData.toPid, - lock: options.lock || false - }; - } else if (parseInt(postData.pid, 10) > 0) { - action = 'posts.edit'; - composerData = { - pid: postData.pid, - handle: handleEl ? handleEl.val() : undefined, - content: bodyEl.val(), - title: titleEl.val(), - topic_thumb: thumbEl.val() || '', - tags: tags.getTags(post_uuid) - }; - } - - socket.emit(action, composerData, function (err, data) { - postContainer.find('.composer-submit').removeAttr('disabled'); - if (err) { - if (err.message === '[[error:email-not-confirmed]]') { - return app.showEmailConfirmWarning(err); - } - - return app.alertError(err.message); - } - - discard(post_uuid); - drafts.removeDraft(postData.save_id); - - if (action === 'topics.post') { - ajaxify.go('topic/' + data.slug); - } else { - removeComposerHistory(); - } - - $(window).trigger('action:composer.' + action, {composerData: composerData, data: data}); - }); - } - - function discard(post_uuid) { - if (composer.posts[post_uuid]) { - $('#cmp-uuid-' + post_uuid).remove(); - drafts.removeDraft(composer.posts[post_uuid].save_id); - stopNotifyInterval(composer.posts[post_uuid]); - stopNotifyTyping(composer.posts[post_uuid]); - - delete composer.posts[post_uuid]; - composer.active = undefined; - taskbar.discard('composer', post_uuid); - $('body').css({'margin-bottom': 0}); - $('[data-action="post"]').removeAttr('disabled'); - - - $('html').removeClass('composing mobile'); - - } - } - - composer.minimize = function(post_uuid) { - var postContainer = $('#cmp-uuid-' + post_uuid); - postContainer.css('visibility', 'hidden'); - composer.active = undefined; - taskbar.minimize('composer', post_uuid); - - stopNotifyInterval(composer.posts[post_uuid]); - stopNotifyTyping(composer.posts[post_uuid]); - - $('body').css({'margin-bottom': '0px'}); - }; - - return composer; -}); diff --git a/public/src/modules/composer/categoryList.js b/public/src/modules/composer/categoryList.js deleted file mode 100644 index 1eb86051bf..0000000000 --- a/public/src/modules/composer/categoryList.js +++ /dev/null @@ -1,44 +0,0 @@ - -'use strict'; - -/*globals define, config, socket, app*/ - -define('composer/categoryList', function() { - var categoryList = {}; - - categoryList.init = function(postContainer, postData) { - var listEl = postContainer.find('.category-list'); - if (!listEl.length) { - return; - } - - socket.emit('categories.getCategoriesByPrivilege', 'topics:create', function(err, categories) { - if (err) { - return app.alertError(err.message); - } - - // Remove categories that are just external links - categories = categories.filter(function(category) { - return !category.link; - }); - - categories.forEach(function(category) { - $('').appendTo(listEl); - }); - - if (postData.cid) { - listEl.find('option[value="' + postData.cid + '"]').prop('selected', true); - } - }); - - listEl.on('change', function() { - if (postData.cid) { - postData.cid = this.value; - } - - $('[tabindex=' + (parseInt($(this).attr('tabindex'), 10) + 1) + ']').trigger('focus'); - }); - }; - - return categoryList; -}); diff --git a/public/src/modules/composer/controls.js b/public/src/modules/composer/controls.js deleted file mode 100644 index 05b6bdcf3c..0000000000 --- a/public/src/modules/composer/controls.js +++ /dev/null @@ -1,46 +0,0 @@ -"use strict"; - -/*global define*/ - -define('composer/controls', function() { - var controls = {}; - - /*************************************************/ - /* Rich Textarea Controls */ - /*************************************************/ - controls.insertIntoTextarea = function(textarea, value) { - var $textarea = $(textarea); - var currentVal = $textarea.val(); - - $textarea.val( - currentVal.slice(0, textarea.selectionStart) + - value + - currentVal.slice(textarea.selectionStart) - ); - }; - - controls.wrapSelectionInTextareaWith = function(textarea, leading, trailing){ - if(trailing === undefined){ - trailing = leading; - } - - var $textarea = $(textarea); - var currentVal = $textarea.val(); - - $textarea.val( - currentVal.slice(0, textarea.selectionStart) + - leading + - currentVal.slice(textarea.selectionStart, textarea.selectionEnd) + - trailing + - currentVal.slice(textarea.selectionEnd) - ); - }; - - controls.updateTextareaSelection = function(textarea, start, end){ - textarea.setSelectionRange(start, end); - $(textarea).focus(); - }; - - - return controls; -}); \ No newline at end of file diff --git a/public/src/modules/composer/drafts.js b/public/src/modules/composer/drafts.js deleted file mode 100644 index 27370607ca..0000000000 --- a/public/src/modules/composer/drafts.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -/* globals define */ - -define('composer/drafts', function() { - - var drafts = {}; - var saveThrottleId; - var saving = false; - - drafts.init = function(postContainer, postData) { - - var bodyEl = postContainer.find('textarea'); - bodyEl.on('keyup', function() { - resetTimeout(); - - saveThrottleId = setTimeout(function() { - saveDraft(postContainer, postData); - }, 1000); - }); - }; - - function resetTimeout() { - if (saveThrottleId) { - clearTimeout(saveThrottleId); - saveThrottleId = 0; - } - } - - drafts.getDraft = function(save_id) { - return localStorage.getItem(save_id); - }; - - function saveDraft(postContainer, postData) { - var raw; - - if (canSave() && postData && postData.save_id && postContainer.length) { - raw = postContainer.find('textarea').val(); - if (raw.length) { - localStorage.setItem(postData.save_id, raw); - } else { - drafts.removeDraft(postData.save_id); - } - } - } - - drafts.removeDraft = function(save_id) { - resetTimeout(); - return localStorage.removeItem(save_id); - }; - - function canSave() { - if (saving) { - return saving; - } - - try { - localStorage.setItem('test', 'test'); - localStorage.removeItem('test'); - saving = true; - return true; - } catch(e) { - saving = false; - return false; - } - } - - return drafts; -}); \ No newline at end of file diff --git a/public/src/modules/composer/formatting.js b/public/src/modules/composer/formatting.js deleted file mode 100644 index 05315a7edf..0000000000 --- a/public/src/modules/composer/formatting.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -/* globals define */ - -define('composer/formatting', ['composer/controls', 'composer/preview'], function(controls, preview) { - - var formatting = {}; - - var formattingDispatchTable = { - 'picture': function(){ - $('#files').click(); - }, - - upload: function(){ - $('#files').click(); - }, - - tags: function() { - $('.tags-container').toggleClass('hidden'); - } - }; - - var buttons = []; - - formatting.addComposerButtons = function() { - for(var x=0,numButtons=buttons.length;x'); - } - }; - - formatting.addButton = function(iconClass, onClick) { - var name = iconClass.replace('fa fa-', ''); - - formattingDispatchTable[name] = onClick; - buttons.push({ - name: name, - iconClass: iconClass - }); - }; - - formatting.addButtonDispatch = function(name, onClick) { - formattingDispatchTable[name] = onClick; - }; - - formatting.addHandler = function(postContainer) { - postContainer.on('click', '.formatting-bar span', function () { - var format = $(this).attr('data-format'), - textarea = $(this).parents('.composer').find('textarea')[0]; - - if(formattingDispatchTable.hasOwnProperty(format)){ - formattingDispatchTable[format](textarea, textarea.selectionStart, textarea.selectionEnd); - preview.render(postContainer); - } - }); - }; - - return formatting; -}); diff --git a/public/src/modules/composer/preview.js b/public/src/modules/composer/preview.js deleted file mode 100644 index e6bab0cb4e..0000000000 --- a/public/src/modules/composer/preview.js +++ /dev/null @@ -1,83 +0,0 @@ -'use strict'; - -/* globals define, socket*/ - -define('composer/preview', function() { - var preview = {}; - - var timeoutId = 0; - - preview.render = function(postContainer, callback) { - callback = callback || function() {}; - if (timeoutId) { - clearTimeout(timeoutId); - timeoutId = 0; - } - var textarea = postContainer.find('textarea'); - - timeoutId = setTimeout(function() { - socket.emit('modules.composer.renderPreview', textarea.val(), function(err, preview) { - timeoutId = 0; - if (err) { - return; - } - preview = $(preview); - preview.find('img').addClass('img-responsive'); - postContainer.find('.preview').html(preview); - $(window).trigger('action:composer.preview'); - callback(); - }); - }, 250); - }; - - preview.matchScroll = function(postContainer) { - var textarea = postContainer.find('textarea'); - var preview = postContainer.find('.preview'); - var diff = textarea[0].scrollHeight - textarea.height(); - - if (diff === 0) { - return; - } - - var scrollPercent = textarea.scrollTop() / diff; - - preview.scrollTop(Math.max(preview[0].scrollHeight - preview.height(), 0) * scrollPercent); - }; - - preview.handleToggler = function(postContainer) { - function hidePreview() { - togglePreview(false); - localStorage.setItem('composer:previewToggled', true); - } - - function showPreview() { - togglePreview(true); - localStorage.removeItem('composer:previewToggled'); - } - - function togglePreview(show) { - previewContainer.toggleClass('hide', !show); - writeContainer.toggleClass('maximized', !show); - showBtn.toggleClass('hide', show); - - $('.write').focus(); - preview.matchScroll(postContainer); - } - - var showBtn = postContainer.find('.write-container .toggle-preview'), - hideBtn = postContainer.find('.preview-container .toggle-preview'), - previewContainer = $('.preview-container'), - writeContainer = $('.write-container'); - - hideBtn.on('click', hidePreview); - showBtn.on('click', showPreview); - - if (localStorage.getItem('composer:previewToggled')) { - hidePreview(); - } else { - showPreview(); - } - }; - - return preview; -}); \ No newline at end of file diff --git a/public/src/modules/composer/resize.js b/public/src/modules/composer/resize.js deleted file mode 100644 index 23b5f67adb..0000000000 --- a/public/src/modules/composer/resize.js +++ /dev/null @@ -1,195 +0,0 @@ - -'use strict'; - -/* globals app, define, config, utils*/ - -define('composer/resize', ['autosize'], function(autosize) { - var resize = {}, - oldPercentage = 0; - - resize.reposition = function(postContainer) { - var percentage = localStorage.getItem('composer:resizePercentage') || 0.5; - - doResize(postContainer, percentage); - }; - - function doResize(postContainer, percentage) { - var env = utils.findBootstrapEnvironment(); - - - // todo, lump in browsers that don't support transform (ie8) here - // at this point we should use modernizr - if (env === 'sm' || env === 'xs' || window.innerHeight < 480) { - $('html').addClass('composing mobile'); - autosize(postContainer.find('textarea')[0]); - percentage = 1; - } else { - $('html').removeClass('composing mobile'); - } - - if (percentage) { - var max = getMaximumPercentage(); - - if (percentage < 0.25) { - percentage = 0.25; - } else if (percentage > max) { - percentage = max; - } - - if (env === 'md' || env === 'lg') { - var transform = 'translate(0, ' + (Math.abs(1-percentage) * 100) + '%)'; - postContainer.css({ - '-webkit-transform': transform, - '-moz-transform': transform, - '-ms-transform': transform, - '-o-transform': transform, - 'transform': transform - }); - } else { - postContainer.removeAttr('style'); - } - } - - postContainer.percentage = percentage; - - if (config.hasImageUploadPlugin) { - postContainer.find('.img-upload-btn').removeClass('hide'); - postContainer.find('#files.lt-ie9').removeClass('hide'); - } - - if (config.allowFileUploads) { - postContainer.find('.file-upload-btn').removeClass('hide'); - postContainer.find('#files.lt-ie9').removeClass('hide'); - } - - postContainer.css('visibility', 'visible'); - - // Add some extra space at the bottom of the body so that the user can still scroll to the last post w/ composer open - $('body').css({'margin-bottom': postContainer.css('height')}); - - resizeWritePreview(postContainer); - } - - resize.handleResize = function(postContainer) { - function resizeStart(e) { - var resizeRect = resizeEl[0].getBoundingClientRect(), - resizeCenterY = resizeRect.top + (resizeRect.height / 2); - - resizeOffset = (resizeCenterY - e.clientY) / 2; - resizeActive = true; - resizeDown = e.clientY; - - $(window).on('mousemove', resizeAction); - $(window).on('mouseup', resizeStop); - $('body').on('touchmove', resizeTouchAction); - } - - function resizeStop(e) { - resizeActive = false; - - postContainer.find('textarea').focus(); - $(window).off('mousemove', resizeAction); - $(window).off('mouseup', resizeStop); - $('body').off('touchmove', resizeTouchAction); - - var position = (e.clientY - resizeOffset), - newHeight = $(window).height() - position, - windowHeight = $(window).height(); - - if (newHeight > windowHeight - $('#header-menu').height() - (windowHeight / 15)) { - snapToTop = true; - } else { - snapToTop = false; - } - - toggleMaximize(e); - } - - function toggleMaximize(e) { - if (e.clientY - resizeDown === 0 || snapToTop) { - var newPercentage = getMaximumPercentage(); - - if (!postContainer.hasClass('maximized') || !snapToTop) { - oldPercentage = postContainer.percentage; - doResize(postContainer, newPercentage); - postContainer.addClass('maximized'); - } else { - doResize(postContainer, oldPercentage); - postContainer.removeClass('maximized'); - } - } - } - - function resizeTouchAction(e) { - e.preventDefault(); - resizeAction(e.touches[0]); - } - - function resizeAction(e) { - if (resizeActive) { - var position = (e.clientY - resizeOffset), - newHeight = $(window).height() - position; - - doResize(postContainer, newHeight / $(window).height()); - - resizeWritePreview(postContainer); - resizeSavePosition(newHeight); - - if (Math.abs(e.clientY - resizeDown) > 0) { - postContainer.removeClass('maximized'); - } - } - - e.preventDefault(); - return false; - } - - function resizeSavePosition(px) { - var percentage = px / $(window).height(), - max = getMaximumPercentage(); - localStorage.setItem('composer:resizePercentage', percentage < max ? percentage : max); - } - - var resizeActive = false, - resizeOffset = 0, - resizeDown = 0, - snapToTop = false, - resizeEl = postContainer.find('.resizer'); - - resizeEl - .on('mousedown', resizeStart) - .on('touchstart', function(e) { - e.preventDefault(); - resizeStart(e.touches[0]); - }) - .on('touchend', function(e) { - e.preventDefault(); - resizeStop(); - }); - }; - - function getMaximumPercentage() { - return ($(window).height() - $('#header-menu').height() - 1) / $(window).height(); - } - - function resizeWritePreview(postContainer) { - var total = getFormattingHeight(postContainer); - postContainer - .find('.write-preview-container') - .css('height', postContainer.percentage * $(window).height() - $('#header-menu').height() - total); - } - - function getFormattingHeight(postContainer) { - return [ - postContainer.find('.title-container').outerHeight(true), - postContainer.find('.formatting-bar').outerHeight(true), - postContainer.find('.topic-thumb-container').outerHeight(true), - $('.taskbar').height() - ].reduce(function(a, b) { - return a + b; - }); - } - - - return resize; -}); diff --git a/public/src/modules/composer/tags.js b/public/src/modules/composer/tags.js deleted file mode 100644 index 8e516e83b8..0000000000 --- a/public/src/modules/composer/tags.js +++ /dev/null @@ -1,92 +0,0 @@ - -'use strict'; - -/*globals define, config, socket, app*/ - -define('composer/tags', function() { - var tags = {}; - - tags.init = function(postContainer, postData) { - var tagEl = postContainer.find('.tags'); - if (!tagEl.length) { - return; - } - - tagEl.tagsinput({ - maxTags: config.tagsPerTopic, - maxChars: config.maximumTagLength, - confirmKeys: [13, 44], - trimValue: true - }); - - tagEl.on('beforeItemAdd', function(event) { - event.cancel = event.item.length < config.minimumTagLength || event.item.length > config.maximumTagLength; - if (event.item.length < config.minimumTagLength) { - app.alertError('[[error:tag-too-short, ' + config.minimumTagLength + ']]'); - } else if (event.item.length > config.maximumTagLength) { - app.alertError('[[error:tag-too-long, ' + config.maximumTagLength + ']]'); - } - }); - - tagEl.on('itemAdded', function(event) { - $(window).trigger('action:tag.added', {cid: postData.cid, tagEl: tagEl, tag: event.item}); - }); - - addTags(postData.tags, tagEl); - - var input = postContainer.find('.bootstrap-tagsinput input'); - - app.loadJQueryUI(function() { - input.autocomplete({ - delay: 100, - open: function() { - $(this).autocomplete('widget').css('z-index', 20000); - }, - source: function(request, response) { - socket.emit('topics.searchTags', {query: request.term, cid: postData.cid}, function(err, tags) { - if (err) { - return app.alertError(err.message); - } - if (tags) { - response(tags); - } - $('.ui-autocomplete a').attr('data-ajaxify', 'false'); - }); - }, - select: function(event, ui) { - // when autocomplete is selected from the dropdown simulate a enter key down to turn it into a tag - triggerEnter(input); - } - }); - }); - - input.attr('tabIndex', tagEl.attr('tabIndex')); - input.on('blur', function() { - triggerEnter(input); - }); - }; - - function triggerEnter(input) { - // http://stackoverflow.com/a/3276819/583363 - var e = jQuery.Event('keypress'); - e.which = 13; - e.keyCode = 13; - setTimeout(function() { - input.trigger(e); - }, 100); - } - - function addTags(tags, tagEl) { - if (tags && tags.length) { - for(var i=0; i').closest('form').get(0).reset(); - $el.unwrap(); - } - - function initializeDragAndDrop(post_uuid) { - - function onDragEnter() { - if(draggingDocument) { - return; - } - drop.css('top', postContainer.find('.write-preview-container').position().top + 'px'); - drop.css('height', textarea.height()); - drop.css('line-height', textarea.height() + 'px'); - drop.show(); - - drop.on('dragleave', function() { - drop.hide(); - drop.off('dragleave'); - }); - } - - function onDragDrop(e) { - e.preventDefault(); - var files = e.files || (e.dataTransfer || {}).files || (e.target.value ? [e.target.value] : []), - fd; - - if(files.length) { - if (window.FormData) { - fd = new FormData(); - for (var i = 0; i < files.length; ++i) { - fd.append('files[]', files[i], files[i].name); - } - } - - uploadContentFiles({ - files: files, - post_uuid: post_uuid, - route: '/api/post/upload', - formData: fd - }); - } - - drop.hide(); - return false; - } - - function cancel(e) { - e.preventDefault(); - return false; - } - - if($.event.props.indexOf('dataTransfer') === -1) { - $.event.props.push('dataTransfer'); - } - - var draggingDocument = false; - - var postContainer = $('#cmp-uuid-' + post_uuid), - drop = postContainer.find('.imagedrop'), - textarea = postContainer.find('textarea'); - - $(document).off('dragstart').on('dragstart', function() { - draggingDocument = true; - }).off('dragend').on('dragend', function() { - draggingDocument = false; - }); - - textarea.on('dragenter', onDragEnter); - - drop.on('dragover', cancel); - drop.on('dragenter', cancel); - drop.on('drop', onDragDrop); - } - - function initializePaste(post_uuid) { - $(window).off('paste').on('paste', function(event) { - - var items = (event.clipboardData || event.originalEvent.clipboardData || {}).items, - fd; - - if(items && items.length) { - - var blob = items[0].getAsFile(); - if(blob) { - blob.name = 'upload-' + utils.generateUUID(); - - if (window.FormData) { - fd = new FormData(); - fd.append('files[]', blob, blob.name); - } - - uploadContentFiles({ - files: [blob], - post_uuid: post_uuid, - route: '/api/post/upload', - formData: fd - }); - } - } - }); - } - - function escapeRegExp(text) { - return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); - } - - function maybeParse(response) { - if (typeof response === 'string') { - try { - return $.parseJSON(response); - } catch (e) { - return {status: 500, message: 'Something went wrong while parsing server response'}; - } - } - return response; - } - - function insertText(str, index, insert) { - return str.slice(0, index) + insert + str.slice(index); - } - - function uploadContentFiles(params) { - var files = params.files, - post_uuid = params.post_uuid, - formData = params.formData, - postContainer = $('#cmp-uuid-' + post_uuid), - textarea = postContainer.find('textarea'), - text = textarea.val(), - uploadForm = postContainer.find('#fileForm'); - - uploadForm.attr('action', config.relative_path + params.route); - - for(var i = 0; i < files.length; ++i) { - var isImage = files[i].type.match(/image./); - - text = insertText(text, textarea.getCursorPosition(), (isImage ? '!' : '') + '[' + files[i].name + '](uploading...) '); - - if(files[i].size > parseInt(config.maximumFileSize, 10) * 1024) { - uploadForm[0].reset(); - return app.alertError('[[error:file-too-big, ' + config.maximumFileSize + ']]'); - } - } - - textarea.val(text); - - uploadForm.off('submit').submit(function() { - function updateTextArea(filename, text) { - var current = textarea.val(); - var re = new RegExp(escapeRegExp(filename) + "]\\([^)]+\\)", 'g'); - textarea.val(current.replace(re, filename + '](' + text + ')')); - } - - uploads.inProgress[post_uuid] = uploads.inProgress[post_uuid] || []; - uploads.inProgress[post_uuid].push(1); - - $(this).ajaxSubmit({ - headers: { - 'x-csrf-token': csrf.get() - }, - resetForm: true, - clearForm: true, - formData: formData, - - error: onUploadError, - - uploadProgress: function(event, position, total, percent) { - for(var i=0; i < files.length; ++i) { - updateTextArea(files[i].name, 'uploading ' + percent + '%'); - } - }, - - success: function(uploads) { - uploads = maybeParse(uploads); - - if(uploads && uploads.length) { - for(var i=0; i Date: Fri, 3 Jul 2015 17:08:17 -0400 Subject: [PATCH 06/49] upping theme minimum versions --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 38713a683c..117f76b6d7 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,8 @@ "nodebb-plugin-spam-be-gone": "^0.4.0", "nodebb-rewards-essentials": "^0.0.1", "nodebb-theme-lavender": "^1.0.42", - "nodebb-theme-persona": "^0.2.0", - "nodebb-theme-vanilla": "^1.1.0", + "nodebb-theme-persona": "^1.0.0", + "nodebb-theme-vanilla": "^2.0.0", "nodebb-widget-essentials": "^1.0.2", "npm": "^2.1.4", "passport": "^0.2.1", From 5c35b2d96f42436d1fe166317e4062e509cafbd2 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 3 Jul 2015 17:21:14 -0400 Subject: [PATCH 07/49] fix composer redirect on relative path install --- src/controllers/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/controllers/index.js b/src/controllers/index.js index ae6cb5c497..7c56b55df6 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -135,6 +135,9 @@ Controllers.register = function(req, res, next) { Controllers.compose = function(req, res, next) { if (req.query.p && !res.locals.isAPI) { + if (req.query.p.startsWith(nconf.get('relative_path'))) { + req.query.p = req.query.p.replace(nconf.get('relative_path'), ''); + } return helpers.redirect(res, req.query.p); } From 619251143ddd4802ab573d337077dc1e0eef494c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 3 Jul 2015 18:19:02 -0400 Subject: [PATCH 08/49] reset inf scroll on search --- public/src/client/groups/details.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index 118dbcddda..d3e876bdb6 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -306,6 +306,7 @@ define('forum/groups/details', ['iconSelect', 'components', 'forum/infinitescrol } }, function(html) { $('[component="groups/members"] tbody').html(html); + $('[component="groups/members"]').attr('data-nextstart', 20); }); }); }, 250); From 773d88613571700338feae9e98b7394a98e08310 Mon Sep 17 00:00:00 2001 From: Nicolas Siver Date: Sat, 4 Jul 2015 10:11:11 +0300 Subject: [PATCH 09/49] ignore for JetBrains IDEs --- .gitignore | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2f966c4535..82ed213c66 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ public/css/*.css *.sublime-project *.sublime-workspace .project -.idea *.swp Vagrantfile .vagrant @@ -31,4 +30,14 @@ pidfile /public/stylesheet.css /public/admin.css /public/nodebb.min.js -/public/nodebb.min.js.map \ No newline at end of file +/public/nodebb.min.js.map + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio +*.iml + +## Directory-based project format: +.idea/ + +## File-based project format: +*.ipr +*.iws \ No newline at end of file From 1e2f4ae5e931654a7e6e5f2ea429204b15b94b32 Mon Sep 17 00:00:00 2001 From: Nicolas Siver Date: Sun, 5 Jul 2015 08:31:21 +0300 Subject: [PATCH 10/49] filter slug for category update --- src/categories/update.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/categories/update.js b/src/categories/update.js index f1d9ee773c..907def6875 100644 --- a/src/categories/update.js +++ b/src/categories/update.js @@ -16,7 +16,14 @@ module.exports = function(Categories) { return next(err); } - plugins.fireHook('filter:category.update', modified[cid], function(err, category) { + var modifiedFields = modified[cid]; + + if(modifiedFields.hasOwnProperty('name')){ + modifiedFields.slug = cid + '/' + utils.slugify(modifiedFields.name); + } + + plugins.fireHook('filter:category.update', {category:modifiedFields}, function(err, categoryData) { + var category = categoryData.category; var fields = Object.keys(category); async.each(fields, function(key, next) { updateCategoryField(cid, key, category[key], next); @@ -44,10 +51,7 @@ module.exports = function(Categories) { return callback(err); } - if (key === 'name') { - var slug = cid + '/' + utils.slugify(value); - db.setObjectField('category:' + cid, 'slug', slug, callback); - } else if (key === 'order') { + if (key === 'order') { db.sortedSetAdd('categories:cid', value, cid, callback); } else { callback(); From 4b1c9ce9a2a9e39f25d3e7c08dbe80b22bd56274 Mon Sep 17 00:00:00 2001 From: Fokke Zandbergen Date: Mon, 6 Jul 2015 11:58:17 +0200 Subject: [PATCH 11/49] Allow Winston's log level to be set via nconf Defaults to `info` for `production` and `verbose` otherwise, like it used to. --- app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 78afb10b9e..cd0a566fa4 100644 --- a/app.js +++ b/app.js @@ -43,7 +43,7 @@ winston.add(winston.transports.Console, { var date = new Date(); return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0,5) + ' [' + global.process.pid + ']'; }, - level: (global.env === 'production' || nconf.get('log-level') === 'info') ? 'info' : 'verbose' + level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose') }); if(os.platform() === 'linux') { @@ -403,4 +403,4 @@ function restart() { winston.error('[app] Could not restart server. Shutting down.'); shutdown(1); } -} \ No newline at end of file +} From ceb4de653db80d4be7ba47e0ea297db91e2266f9 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 6 Jul 2015 10:36:20 -0400 Subject: [PATCH 12/49] fixed #3295 --- public/src/admin/manage/category.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js index ac4b6a50cc..bdd219d80e 100644 --- a/public/src/admin/manage/category.js +++ b/public/src/admin/manage/category.js @@ -70,9 +70,9 @@ define('admin/manage/category', [ $this.addClass('hide'); target.removeClass('hide').on('blur', function() { - $this.removeClass('hide').children('span').html(this.value); + $this.removeClass('hide').children('span').text(this.value).html(); $(this).addClass('hide'); - }).val($this.children('span').html()); + }).val($this.children('span').html().text()); target.focus(); }); From 417a573f674aec4b815c3decdb415f27fccb9ca8 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 6 Jul 2015 12:14:27 -0400 Subject: [PATCH 13/49] closes #3260 --- src/controllers/accounts.js | 1 + src/user/profile.js | 19 ------------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 3fdb810c83..2455b5101b 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -90,6 +90,7 @@ function getUserDataByUserSlug(userslug, callerUID, callback) { userData.status = require('../socket.io').isUserOnline(userData.uid) ? (userData.status || 'online') : 'offline'; userData.banned = parseInt(userData.banned, 10) === 1; userData.website = validator.escape(userData.website); + userData.websiteLink = !userData.website.startsWith('http') ? 'http://' + userData.website : userData.website; userData.websiteName = userData.website.replace(validator.escape('http://'), '').replace(validator.escape('https://'), ''); userData.followingCount = parseInt(userData.followingCount, 10) || 0; userData.followerCount = parseInt(userData.followerCount, 10) || 0; diff --git a/src/user/profile.js b/src/user/profile.js index c5f693cee8..7a3f761edd 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -129,25 +129,6 @@ module.exports = function(User) { return updateFullname(uid, data.fullname, next); } else if (field === 'signature') { data[field] = S(data[field]).stripTags().s; - } else if (field === 'website') { - var urlObj; - if (data[field].length > 0) { - urlObj = url.parse(data[field], false, true); - if (!urlObj.protocol) { - urlObj.protocol = 'http'; - urlObj.slashes = true; - } - if (!urlObj.hostname && urlObj.pathname) { - urlObj.hostname = urlObj.pathname; - urlObj.pathname = null; - } - if (urlObj.pathname === '/') { - urlObj.pathname = null; - } - } - if (urlObj) { - data[field] = url.format(urlObj); - } } User.setUserField(uid, field, data[field], next); From e355c8cb1bf69de02c64f7d3df64b272d9316d99 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 6 Jul 2015 12:34:35 -0400 Subject: [PATCH 14/49] removed socket calls for composer out of core and into plugin, closes #3293 --- package.json | 2 +- src/socket.io/modules.js | 114 +-------------------------------------- 2 files changed, 2 insertions(+), 114 deletions(-) diff --git a/package.json b/package.json index 117f76b6d7..d6c37b900e 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "mmmagic": "^0.3.13", "morgan": "^1.3.2", "nconf": "~0.7.1", - "nodebb-plugin-composer-default": "^1.0.0", + "nodebb-plugin-composer-default": "^1.0.2", "nodebb-plugin-dbsearch": "^0.2.12", "nodebb-plugin-emoji-extended": "^0.4.8", "nodebb-plugin-markdown": "^3.0.0", diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index f160c9765a..fbdf2b0100 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -1,129 +1,17 @@ "use strict"; -var nconf = require('nconf'), - async = require('async'), - S = require('string'), - winston = require('winston'), - _ = require('underscore'), - - posts = require('../posts'), - postTools = require('../postTools'), - topics = require('../topics'), - meta = require('../meta'), +var meta = require('../meta'), Messaging = require('../messaging'), - user = require('../user'), - plugins = require('../plugins'), utils = require('../../public/src/utils'), - privileges = require('../privileges'), server = require('./'), - SocketModules = { - composer: {}, chats: {}, sounds: {}, settings: {} }; -/* Posts Composer */ - -SocketModules.composer.push = function(socket, pid, callback) { - privileges.posts.can('read', pid, socket.uid, function(err, canRead) { - if (err || !canRead) { - return callback(err || new Error('[[error:no-privileges]]')); - } - posts.getPostFields(pid, ['content', 'tid', 'uid', 'handle'], function(err, postData) { - if(err || (!postData && !postData.content)) { - return callback(err || new Error('[[error:invalid-pid]]')); - } - - async.parallel({ - topic: function(next) { - topics.getTopicDataByPid(pid, next); - }, - tags: function(next) { - topics.getTopicTags(postData.tid, next); - }, - isMain: function(next) { - posts.isMain(pid, next); - } - }, function(err, results) { - if(err) { - return callback(err); - } - - if (!results.topic) { - return callback(new Error('[[error:no-topic]]')); - } - - callback(null, { - pid: pid, - uid: postData.uid, - handle: parseInt(meta.config.allowGuestHandles, 10) ? postData.handle : undefined, - body: postData.content, - title: results.topic.title, - topic_thumb: results.topic.thumb, - tags: results.tags, - isMain: results.isMain - }); - }); - }); - }); -}; - -SocketModules.composer.editCheck = function(socket, pid, callback) { - posts.isMain(pid, function(err, isMain) { - callback(err, { - titleEditable: isMain - }); - }); -}; - -SocketModules.composer.renderPreview = function(socket, content, callback) { - plugins.fireHook('filter:parse.raw', content, callback); -}; - -SocketModules.composer.renderHelp = function(socket, data, callback) { - var helpText = meta.config['composer:customHelpText'] || ''; - - if (meta.config['composer:showHelpTab'] === '0') { - return callback(new Error('help-hidden')); - } - - plugins.fireHook('filter:parse.raw', 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.notifyTyping = function(socket, data) { - if (!socket.uid || !parseInt(data.tid, 10)) { - return; - } - server.in('topic_' + data.tid).emit('event:topic.notifyTyping', data); -}; - -SocketModules.composer.stopNotifyTyping = function(socket, data) { - if (!socket.uid || !parseInt(data.tid, 10)) { - return; - } - server.in('topic_' + data.tid).emit('event:topic.stopNotifyTyping', data); -}; - -SocketModules.composer.getFormattingOptions = function(socket, data, callback) { - plugins.fireHook('filter:composer.formatting', { - options: [ - { name: 'tags', className: 'fa fa-tags', mobile: true } - ] - }, function(err, payload) { - callback(err, payload.options); - }); -}; - /* Chat */ SocketModules.chats.get = function(socket, data, callback) { From 52f7e13a5c2bfb66c93afef9b989636a63cc5079 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 6 Jul 2015 12:39:05 -0400 Subject: [PATCH 15/49] closes #3289 --- public/src/client/topic/posts.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 3548e1bdf1..907f0da1b5 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -134,6 +134,7 @@ define('forum/topic/posts', [ findInsertionPoint(); data.title = $('
').text(ajaxify.variables.get('topic_name')).html(); + data.slug = ajaxify.variables.get('topic_slug'); data.viewcount = ajaxify.variables.get('viewcount'); infinitescroll.parseAndTranslate('topic', 'posts', data, function(html) { @@ -274,7 +275,7 @@ define('forum/topic/posts', [ function hidePostToolsForDeletedPosts(posts) { posts.each(function() { if ($(this).hasClass('deleted')) { - postTools.toggle($(this).attr('data-pid'), true); + postTools.toggle($(this).attr('data-pid'), true); } }); } From 5c44775c1f2688f84edcbc210c7b22f285dc71e8 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 6 Jul 2015 12:45:16 -0400 Subject: [PATCH 16/49] latest translations, wow. --- public/language/ar/category.json | 6 ++-- public/language/ar/email.json | 4 +-- public/language/ar/error.json | 14 ++++---- public/language/ar/global.json | 2 +- public/language/ar/modules.json | 2 +- public/language/ar/pages.json | 2 +- public/language/ar/reset_password.json | 6 ++-- public/language/ar/search.json | 12 +++---- public/language/ar/user.json | 2 +- public/language/ar/users.json | 2 +- public/language/de/error.json | 22 ++++++------ public/language/de/topic.json | 50 +++++++++++++------------- public/language/de/user.json | 2 +- public/language/es/category.json | 2 +- public/language/es/email.json | 10 +++--- public/language/es/user.json | 2 +- public/language/et/email.json | 8 ++--- public/language/et/global.json | 2 +- public/language/et/notifications.json | 2 +- public/language/ko/category.json | 4 +-- public/language/nb/category.json | 2 +- public/language/nb/email.json | 4 +-- public/language/nb/error.json | 36 +++++++++---------- public/language/nb/groups.json | 4 +-- public/language/nb/notifications.json | 2 +- public/language/nb/recent.json | 2 +- public/language/nb/reset_password.json | 6 ++-- public/language/nb/search.json | 8 ++--- public/language/nb/tags.json | 2 +- public/language/nb/topic.json | 4 +-- public/language/nb/user.json | 26 +++++++------- public/language/nb/users.json | 2 +- public/language/nl/error.json | 6 ++-- public/language/nl/topic.json | 2 +- public/language/nl/user.json | 2 +- public/language/sv/unread.json | 2 +- 36 files changed, 133 insertions(+), 133 deletions(-) diff --git a/public/language/ar/category.json b/public/language/ar/category.json index b1732ff8ba..430a82390d 100644 --- a/public/language/ar/category.json +++ b/public/language/ar/category.json @@ -3,10 +3,10 @@ "guest-login-post": "يجب عليك تسجيل الدخول للرد", "no_topics": "لا توجد مواضيع في هذه الفئةلم لا تحاول إنشاء موضوع؟
", "browsing": "تصفح", - "no_replies": "لم يرد أحد", + "no_replies": "لا توجد ردود.", "share_this_category": "انشر هذه الفئة", "watch": "متابعة", "ignore": "تجاهل", - "watch.message": "You are now watching updates from this category", - "ignore.message": "You are now ignoring updates from this category" + "watch.message": "أنت اﻷن متابع لتحديثات هذه الفئة", + "ignore.message": "أنت اﻷن تتجاهل تحديثات هذه الفئة" } \ No newline at end of file diff --git a/public/language/ar/email.json b/public/language/ar/email.json index 2eeef2c6cc..3970ae01c7 100644 --- a/public/language/ar/email.json +++ b/public/language/ar/email.json @@ -6,8 +6,8 @@ "welcome.text1": "شكرًا على تسجيلك في %1!", "welcome.text2": "لتفعيل حسابك، نحتاج إلى التأكد من صحة عنوان البريد الإلكتروني الذي تسجلت به.", "welcome.cta": "انقر هنا لتفعيل عنوان بريدك الإلكتروني", - "reset.text1": "لقد توصلنا بطلب إعادة تعيين كلمة السرالخاصة بك، ربما لكونك قد نسيتها, إن لم يكن الأمر كذلك، المرجو تجاهل هذه الرسالة.", - "reset.text2": "لمواصلة طلب إعاة تعيين كلمة السر، المرجو تتبع هذا الرابط.", + "reset.text1": "لقد توصلنا بطلب إعادة تعيين كلمة المرور الخاصة بك، ربما لكونك قد نسيتها, إن لم يكن الأمر كذلك، المرجو تجاهل هذه الرسالة.", + "reset.text2": "لمواصلة طلب إعاة تعيين كلمة المرور، الرجاء تتبع هذا الرابط.", "reset.cta": "انقر هنا لإعادة تعيين كلمة السر الخاصة بك.", "reset.notify.subject": "تم تغيير كلمة المرور بنجاح", "reset.notify.text1": "نحيطك علما أن كلمة مرورك قد تم تغييرها في %1", diff --git a/public/language/ar/error.json b/public/language/ar/error.json index 2e6908cbe4..055cd22c48 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -2,7 +2,7 @@ "invalid-data": "بيانات غير صالحة", "not-logged-in": "لم تقم بتسجيل الدخول", "account-locked": "تم حظر حسابك مؤقتًا.", - "search-requires-login": "Searching requires an account - please login or register.", + "search-requires-login": "البحث في المنتدى يتطلب حساب - الرجاء تسجيل الدخول أو التسجيل", "invalid-cid": "قائمة غير موجودة", "invalid-tid": "موضوع غير متواجد", "invalid-pid": "رد غير موجود", @@ -18,10 +18,10 @@ "username-taken": "اسم المستخدم مأخوذ", "email-taken": "البريد الالكتروني مأخوذ", "email-not-confirmed": "عنوان بريدك الإلكتروني غير مفعل بعد. انقر هنا لتفعيله من فضلك.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", + "email-not-confirmed-chat": "لا يمكنك الدردشة حتى تقوم بتأكيد بريدك الإلكتروني، الرجاء إضغط هنا لتأكيد بريدك اﻹلكتروني.", "no-email-to-confirm": "هذا المنتدى يستلزم تفعيل بريدك الإلكتروني، انقر هنا من فضلك لإدخاله.", "email-confirm-failed": "لم نستطع تفعيل بريدك الإلكتروني، المرجو المحاولة لاحقًا.", - "confirm-email-already-sent": "Confirmation email already sent, please wait %1 minute(s) to send another one.", + "confirm-email-already-sent": "لقد تم ارسال بريد التأكيد، الرجاء اﻹنتظار 1% دقائق لإعادة اﻹرسال", "username-too-short": "اسم المستخدم قصير.", "username-too-long": "اسم المستخدم طويل", "user-banned": "المستخدم محظور", @@ -57,8 +57,8 @@ "group-name-too-short": "اسم المجموعة قصير", "group-already-exists": "المجموعة موجودة مسبقا", "group-name-change-not-allowed": "لايسمح بتغيير أسماء المجموعات", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "أنت بالفعل عضو في هذه المجموعة ", + "group-needs-owner": "هذه المجموعة تتطلب مالك واحد على اﻷقل", "post-already-deleted": "سبق وتم حذف هذا الرد", "post-already-restored": "سبق وتم إلغاء حذف هذا الرد", "topic-already-deleted": "سبق وتم حذف هذا الموضوع", @@ -67,7 +67,7 @@ "topic-thumbnails-are-disabled": "الصور المصغرة غير مفعلة.", "invalid-file": "ملف غير مقبول", "uploads-are-disabled": "رفع الملفات غير مفعل", - "signature-too-long": "Sorry, your signature cannot be longer than %1 character(s).", + "signature-too-long": "عذرا، توقيعك يجب ألا يتجاوز %1 حرفًا.", "about-me-too-long": "Sorry, your about me cannot be longer than %1 character(s).", "cant-chat-with-yourself": "لايمكنك فتح محادثة مع نفسك", "chat-restricted": "هذا المستخدم عطل المحادثات الواردة عليه. يجب أن يتبعك حتى تتمكن من فتح محادثة معه.", @@ -78,7 +78,7 @@ "not-enough-reputation-to-flag": "ليس لديك سمعة تكفي للإشعار بموضوع مخل", "reload-failed": "المنتدى واجه مشكلة أثناء إعادة التحميل: \"%1\". سيواصل المنتدى خدمة العملاء السابقين لكن يجب عليك إلغاء أي تغيير قمت به قبل إعادة التحميل.", "registration-error": "حدث خطأ أثناء التسجيل", - "parse-error": "Something went wrong while parsing server response", + "parse-error": "حدث خطأ ما أثناء تحليل استجابة الخادم", "wrong-login-type-email": "الرجاء استعمال بريدك اﻹلكتروني للدخول", "wrong-login-type-username": "الرجاء استعمال اسم المستخدم الخاص بك للدخول" } \ No newline at end of file diff --git a/public/language/ar/global.json b/public/language/ar/global.json index 15275ddc39..9d99717966 100644 --- a/public/language/ar/global.json +++ b/public/language/ar/global.json @@ -3,7 +3,7 @@ "search": "بحث", "buttons.close": "أغلق", "403.title": "غير مسموح بالدخول", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", + "403.message": "يبدو أنك قد تعثرت على صفحة لا تمتلك الصلاحية للدخول إليها", "403.login": "Perhaps you should try logging in?", "404.title": "لم يتم العثور", "404.message": "You seem to have stumbled upon a page that does not exist. Return to the home page.", diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index 061fc4430c..56ff907b18 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -15,7 +15,7 @@ "chat.seven_days": "7 أيام", "chat.thirty_days": "30 يومًا", "chat.three_months": "3 أشهر", - "composer.compose": "Compose", + "composer.compose": "اكتب", "composer.show_preview": "عرض المعاينة", "composer.hide_preview": "إخفاء المعاينة", "composer.user_said_in": "%1 كتب في %2", diff --git a/public/language/ar/pages.json b/public/language/ar/pages.json index 4b4e1af182..cf230fc28a 100644 --- a/public/language/ar/pages.json +++ b/public/language/ar/pages.json @@ -12,7 +12,7 @@ "user.followers": "المستخدمون الذين يتبعون %1", "user.posts": "ردود %1", "user.topics": "مواضيع %1", - "user.groups": "%1's Groups", + "user.groups": "مجموعات %1", "user.favourites": "مفضلات %1", "user.settings": "خيارات المستخدم", "user.watched": "المواضيع المتابعة من قبل %1 ", diff --git a/public/language/ar/reset_password.json b/public/language/ar/reset_password.json index f6107ec45b..fe35f3569c 100644 --- a/public/language/ar/reset_password.json +++ b/public/language/ar/reset_password.json @@ -11,7 +11,7 @@ "enter_email_address": "ادخل عنوان البريد الإلكتروني", "password_reset_sent": "إعادة تعيين كلمة السر أرسلت", "invalid_email": "بريد إلكتروني غير صالح أو غير موجود", - "password_too_short": "The password entered is too short, please pick a different password.", - "passwords_do_not_match": "The two passwords you've entered do not match.", - "password_expired": "Your password has expired, please choose a new password" + "password_too_short": "كلمة المرور التي أدخلتها قصيرة، الرجاء اختر كلمة مرور مختلفة", + "passwords_do_not_match": "كلمتا السر التي أدخلتهما غير متطابقتان", + "password_expired": "لقد انتهت صلاحية كلمة المرور الخاصة بك، الرجاء اختيار كلمة مرور جديدة" } \ No newline at end of file diff --git a/public/language/ar/search.json b/public/language/ar/search.json index c126f78f86..39a6b89927 100644 --- a/public/language/ar/search.json +++ b/public/language/ar/search.json @@ -1,11 +1,11 @@ { - "results_matching": "%1 نتيجة (نتائج) موافقة ل \"%2\", (%3 ثواني)", - "no-matches": "No matches found", + "results_matching": "%1 نتيجة (نتائج) موافقة لـ \"%2\", (%3 ثواني)", + "no-matches": "لم يتم العثور على نتائج.", "advanced-search": "بحث متقدم", "in": "في", "titles": "العناوين", "titles-posts": "العناوين والمشاركات", - "posted-by": "Posted by", + "posted-by": "مشاركة من طرف", "in-categories": "في الفئات", "search-child-categories": "بحث في الفئات الفرعية", "reply-count": "عدد المشاركات", @@ -22,7 +22,7 @@ "three-months": "ثلاثة أشهر", "six-months": "ستة أشهر", "one-year": "عام", - "sort-by": "Sort by", + "sort-by": "عرض حسب", "last-reply-time": "تاريخ آخر رد", "topic-title": "عنوان الموضوع", "number-of-replies": "عدد الردود", @@ -30,8 +30,8 @@ "topic-start-date": "تاريخ بدأ الموضوع", "username": "اسم المستخدم", "category": "فئة", - "descending": "In descending order", - "ascending": "In ascending order", + "descending": "في ترتيب تنازلي", + "ascending": "في ترتيب تصاعدي", "save-preferences": "حفظ التفضيلات", "clear-preferences": "ازالة التفضيلات", "search-preferences-saved": "تم حفظ تفضيلات البحث", diff --git a/public/language/ar/user.json b/public/language/ar/user.json index f3a33a5c59..6d4e87c773 100644 --- a/public/language/ar/user.json +++ b/public/language/ar/user.json @@ -79,6 +79,6 @@ "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen", "follow_topics_you_reply_to": "متابعة المواضيع التي تقوم بالرد فيها", "follow_topics_you_create": "متابعة المواضيع التي تنشئها", - "grouptitle": "Select the group title you would like to display", + "grouptitle": "حدد عنوان المجموعة الذي تريد عرضه", "no-group-title": "لا يوجد عنوان للمجموعة" } \ No newline at end of file diff --git a/public/language/ar/users.json b/public/language/ar/users.json index e10ab98e61..1c08cd3176 100644 --- a/public/language/ar/users.json +++ b/public/language/ar/users.json @@ -5,7 +5,7 @@ "search": "بحث", "enter_username": "أدخل اسم مستخدم للبحث", "load_more": "حمل المزيد", - "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", + "users-found-search-took": "تم إيجاد %1 مستخدمـ(ين)! استغرق البحث %2 ثانية.", "filter-by": "Filter By", "online-only": "المتصلون فقط", "picture-only": "صورة فقط" diff --git a/public/language/de/error.json b/public/language/de/error.json index 61cb1fa3f9..30af2d7c65 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -2,7 +2,7 @@ "invalid-data": "Daten ungültig", "not-logged-in": "Du bist nicht angemeldet.", "account-locked": "Dein Account wurde vorübergehend gesperrt.", - "search-requires-login": "Searching requires an account - please login or register.", + "search-requires-login": "Die Suche erfordert ein Konto, bitte einloggen oder registrieren.", "invalid-cid": "Ungültige Kategorie-ID", "invalid-tid": "Ungültige Themen-ID", "invalid-pid": "Ungültige Beitrags-ID", @@ -21,11 +21,11 @@ "email-not-confirmed-chat": "Deine E-Mail wurde noch nicht bestätigt. Bitte klicke hier, um deine E-Mail zu bestätigen.", "no-email-to-confirm": "Dieses Forum setzt E-Mail-Bestätigung voraus, bitte klick hier um eine E-Mail-Adresse einzugeben", "email-confirm-failed": "Wir konnten deine E-Mail-Adresse nicht bestätigen, bitte versuch es später noch einmal", - "confirm-email-already-sent": "Confirmation email already sent, please wait %1 minute(s) to send another one.", + "confirm-email-already-sent": "Bestätigungsmail wurde verschickt, bitte warten %1 Minute(n) warten um eine weitere zu verschicken.", "username-too-short": "Benutzername ist zu kurz", "username-too-long": "Der Benutzername ist zu lang", "user-banned": "Der Benutzer ist gesperrt", - "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", + "user-too-new": "Entschuldigung, Sie müssen %1 Sekunde(n) warten, bevor Sie ihren ersten Beitrag schreiben können.", "no-category": "Die Kategorie existiert nicht", "no-topic": "Das Thema existiert nicht", "no-post": "Der Beitrag existiert nicht", @@ -36,17 +36,17 @@ "no-emailers-configured": "Es wurde keine E-Mail-Plugins geladen, weshalb eine Test-E-Mail nicht gesendet werden konnte.", "category-disabled": "Kategorie ist deaktiviert", "topic-locked": "Thema ist gesperrt", - "post-edit-duration-expired": "You are only allowed to edit posts for %1 second(s) after posting", + "post-edit-duration-expired": "Entschuldigung, Sie dürfen Beiträge nur %1 Sekunde(n) nach dem veröffentlichen editieren.", "still-uploading": "Bitte warte bis der Vorgang abgeschlossen ist.", - "content-too-short": "Please enter a longer post. Posts should contain at least %1 character(s).", - "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 character(s).", + "content-too-short": "Bitte schreiben Sie einen längeren Beitrag. Beiträge sollten mindestens %1 Zeichen enthalten.", + "content-too-long": "Bitte schreiben Sie einen kürzeren Beitrag. Beiträge können nicht länger als %1 Zeichen sein.", "title-too-short": "Please enter a longer title. Titles should contain at least %1 character(s).", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 character(s).", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", - "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", - "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", - "file-too-big": "Maximum allowed file size is %1 kB - please upload a smaller file", + "tag-too-short": "Bitte geben Sie ein längeres Schlagwort ein. Tags sollten mindestens %1 Zeichen enthalten.", + "tag-too-long": "Bitte geben Sie ein kürzeres Schlagwort ein. Tags können nicht länger als %1 Zeichen sein.", + "file-too-big": "Die maximale Dateigröße ist %1 kB, bitte laden Sie eine kleinere Datei hoch.", "cant-vote-self-post": "Du kannst deinen eigenen Beitrag nicht bewerten", "already-favourited": "Dieser Beitrag ist bereits in deinen Favoriten enthalten", "already-unfavourited": "Du hast diesen Beitrag bereits aus deinen Favoriten entfernt", @@ -67,8 +67,8 @@ "topic-thumbnails-are-disabled": "Vorschaubilder für Themen sind deaktiviert", "invalid-file": "Datei ungültig", "uploads-are-disabled": "Uploads sind deaktiviert", - "signature-too-long": "Sorry, your signature cannot be longer than %1 character(s).", - "about-me-too-long": "Sorry, your about me cannot be longer than %1 character(s).", + "signature-too-long": "Entschuldigung, Ihre Signatur kann nicht länger als %1 Zeichen sein.", + "about-me-too-long": "Entschuldigung, Ihr \"über mich\" kann nicht länger als %1 Zeichen sein.", "cant-chat-with-yourself": "Du kannst nicht mit dir selber chatten!", "chat-restricted": "Dieser Benutzer hat seine Chatfunktion eingeschränkt. Du kannst nur mit diesem Benutzer chatten, wenn er dir folgt.", "too-many-messages": "Du hast zu viele Nachrichten versandt, bitte warte eine Weile.", diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 43d59ecb73..5334700f39 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -1,37 +1,37 @@ { "topic": "Thema", - "topic_id": "Topic ID", - "topic_id_placeholder": "Topic ID eingeben", - "no_topics_found": "Keine passenden Themen gefunden.", + "topic_id": "Themen-ID", + "topic_id_placeholder": "Themen-ID eingeben", + "no_topics_found": "Keine passenden Themen gefunden!", "no_posts_found": "Keine Beiträge gefunden!", "post_is_deleted": "Dieser Beitrag wurde gelöscht!", - "topic_is_deleted": "This topic is deleted!", + "topic_is_deleted": "Dieses Thema wurde gelöscht!", "profile": "Profil", - "posted_by": "Geschrieben von %1", + "posted_by": "Verfasst von %1", "posted_by_guest": "Verfasst von einem Gast", "chat": "Chat", "notify_me": "Erhalte eine Benachrichtigung bei neuen Antworten zu diesem Thema.", - "quote": "zitieren", - "reply": "antworten", + "quote": "Zitieren", + "reply": "Antworten", "guest-login-reply": "Anmelden zum Antworten", - "edit": "bearbeiten", - "delete": "löschen", - "purge": "säubern", + "edit": "Bearbeiten", + "delete": "Löschen", + "purge": "Bereinigen", "restore": "Wiederherstellen", - "move": "verschieben", + "move": "Verschieben", "fork": "Aufspalten", "link": "Link", "share": "Teilen", - "tools": "Tools", + "tools": "Werkzeuge", "flag": "Markieren", "locked": "Gesperrt", - "bookmark_instructions": "Klicke hier um zur letzten Position zurückzukehren oder schließe zum Abbrechen.", + "bookmark_instructions": "Klicke hier, um zur letzten Position zurückzukehren oder schließe zum Abbrechen.", "flag_title": "Diesen Beitrag zur Moderation markieren", "flag_confirm": "Sind Sie sicher, dass Sie diesen Post markieren möchten?", "flag_success": "Dieser Beitrag wurde erfolgreich für die Moderation markiert.", "deleted_message": "Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.", "following_topic.message": "Du erhälst nun eine Benachrichtigung, wenn jemand einen Beitrag zu diesem Thema verfasst.", - "not_following_topic.message": "Du erhälst keine weiteren Benachrichtigungen zu diesem Thema.", + "not_following_topic.message": "Du erhälst keine weiteren Benachrichtigungen zu diesem Thema mehr.", "login_to_subscribe": "Bitte registrieren oder einloggen um dieses Thema zu abonnieren", "markAsUnreadForAll.success": "Thema für Alle als ungelesen markiert.", "watch": "Beobachten", @@ -39,10 +39,10 @@ "watch.title": "Bei neuen Antworten benachrichtigen", "unwatch.title": "Dieses Thema nicht mehr beobachten", "share_this_post": "Diesen Beitrag teilen", - "thread_tools.title": "Themen-Tools", + "thread_tools.title": "Themen-Werkzeuge", "thread_tools.markAsUnreadForAll": "Als ungelesen markieren", - "thread_tools.pin": "Thema anpinnen", - "thread_tools.unpin": "Thema nicht mehr anpinnen", + "thread_tools.pin": "Thema anheften", + "thread_tools.unpin": "Thema nicht mehr anheften", "thread_tools.lock": "Thema schließen", "thread_tools.unlock": "Thema öffnen", "thread_tools.move": "Thema verschieben", @@ -53,11 +53,11 @@ "thread_tools.restore": "Thema wiederherstellen", "thread_tools.restore_confirm": "Bist du sicher, dass du dieses Thema wiederherstellen möchtest?", "thread_tools.purge": "Thema säubern", - "thread_tools.purge_confirm": "Bist du sicher, dass du dieses Thema säubern möchtest?", - "topic_move_success": "Thema wurde erfolgreich zu %1 verschoben.", + "thread_tools.purge_confirm": "Bist du sicher, dass du dieses Thema bereinigen möchtest?", + "topic_move_success": "Thema wurde erfolgreich nach %1 verschoben.", "post_delete_confirm": "Sind Sie sicher, dass Sie diesen Beitrag löschen möchten?", "post_restore_confirm": "Sind Sie sicher, dass Sie diesen Beitrag wiederherstellen möchten?", - "post_purge_confirm": "Sind Sie sicher, das Sie diesen Beitrag säubern möchten?", + "post_purge_confirm": "Sind Sie sicher, das Sie diesen Beitrag bereinigen möchten?", "load_categories": "Kategorien laden", "disabled_categories_note": "Deaktivierte Kategorien sind ausgegraut.", "confirm_move": "Verschieben", @@ -72,29 +72,29 @@ "post_moved": "Beitrag wurde verschoben!", "fork_topic": "Thema aufspalten", "topic_will_be_moved_to": "Dieses Thema wird verschoben nach", - "fork_topic_instruction": "Klicke auf die Beiträge, die du aufspalten willst", + "fork_topic_instruction": "Klicke auf die Beiträge, die aufgespaltet werden sollen", "fork_no_pids": "Keine Beiträge ausgewählt!", - "fork_success": "Thema erfolgreich abgespalten! Klicke hier, um zum abgespalteten Thema zu gelangen.", + "fork_success": "Thema erfolgreich aufgespalten! Klicke hier, um zum aufgespalteten Thema zu gelangen.", "composer.title_placeholder": "Hier den Titel des Themas eingeben...", "composer.handle_placeholder": "Name", "composer.discard": "Verwerfen", "composer.submit": "Absenden", "composer.replying_to": "Antworte auf %1", "composer.new_topic": "Neues Thema", - "composer.uploading": "Upload läuft...", + "composer.uploading": "Lade hoch...", "composer.thumb_url_label": "Vorschaubild-URL hier einfügen", "composer.thumb_title": "Vorschaubild zu diesem Thema hinzufügen", "composer.thumb_url_placeholder": "http://example.com/thumb.png", "composer.thumb_file_label": "Oder eine Datei hochladen", "composer.thumb_remove": "Felder leeren", - "composer.drag_and_drop_images": "Bilder hier reinziehen", + "composer.drag_and_drop_images": "Bilder hierher ziehen", "more_users_and_guests": "%1 weitere(r) Nutzer und %2 Gäste", "more_users": "%1 weitere(r) Nutzer", "more_guests": "%1 weitere Gäste", "users_and_others": "%1 und %2 andere", "sort_by": "Sortieren nach", "oldest_to_newest": "Älteste zuerst", - "newest_to_oldest": "Neuster zuerst", + "newest_to_oldest": "Neuste zuerst", "most_votes": "Die meisten Stimmen", "most_posts": "Die meisten Beiträge" } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index d1677c7609..0e6d4e08c4 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -21,7 +21,7 @@ "watched": "Beobachtet", "followers": "Folger", "following": "Folgt", - "aboutme": "About me", + "aboutme": "Über mich", "signature": "Signatur", "gravatar": "Gravatar", "birthday": "Geburtstag", diff --git a/public/language/es/category.json b/public/language/es/category.json index dcb03b8ef3..edf0773adc 100644 --- a/public/language/es/category.json +++ b/public/language/es/category.json @@ -1,7 +1,7 @@ { "new_topic_button": "Nuevo tema", "guest-login-post": "Acceder para poder escribir un mensaje", - "no_topics": "No hay temas en esta categoría.
¿Por que no te animas y publicas uno?", + "no_topics": "No hay temas en esta categoría.
¿Por qué no te animas y publicas uno?", "browsing": "viendo ahora", "no_replies": "Nadie ha respondido aún", "share_this_category": "Compartir esta categoría", diff --git a/public/language/es/email.json b/public/language/es/email.json index fd42293e1b..cc9c02500c 100644 --- a/public/language/es/email.json +++ b/public/language/es/email.json @@ -5,18 +5,18 @@ "greeting_with_name": "Hola %1", "welcome.text1": "Gracias por registrarte con %1!", "welcome.text2": "Para activar completamente tu cuenta, necesitamos verificar que la dirección email con la que te registraste te pertenece.", - "welcome.cta": "Cliquea aquí para confirmar tu dirección email.", - "reset.text1": "Recibimos una solicitud para reiniciar tu contraseña, posiblemente porque la olvidaste. Si no es así, por favor ignora este email.", + "welcome.cta": "Cliquea aquí para confirmar tu dirección de email.", + "reset.text1": "Hemos recibido una solicitud para reiniciar tu contraseña, posiblemente porque la olvidaste. Si no es así, por favor, ignora este email.", "reset.text2": "Para continuar con el reinicio de contraseña, por favor cliquea en el siguiente vínculo:", "reset.cta": "Cliquea aquí para reiniciar tu contraseña", "reset.notify.subject": "Se ha modificado correctamente la contraseña.", - "reset.notify.text1": "Te estamos notificando que a a %1, tu contraseña ha sido cambiado correctamente.", - "reset.notify.text2": "Si no has sido tu, por favor notifica al administrador inmediatamente.", + "reset.notify.text1": "Te estamos notificando que en %1, tu contraseña ha sido cambiada correctamente.", + "reset.notify.text2": "Si no has sido tú, por favor notifica al administrador inmediatamente.", "digest.notifications": "Tiene notificaciones sin leer de %1:", "digest.latest_topics": "Últimos temas de %1", "digest.cta": "Cliquea aquí para visitar %1", "digest.unsub.info": "Este compendio te fue enviado debido a tus ajustes de subscripción.", - "digest.no_topics": "No han habido temas activos en el pasado %1", + "digest.no_topics": "No han habido temas activos anteriores %1", "notif.chat.subject": "Nuevo mensaje de chat recibido de %1", "notif.chat.cta": "Haz click aquí para continuar la conversación", "notif.chat.unsub.info": "Esta notificación de chat se te envió debido a tus ajustes de suscripción.", diff --git a/public/language/es/user.json b/public/language/es/user.json index be3ad91ed8..730b29bafa 100644 --- a/public/language/es/user.json +++ b/public/language/es/user.json @@ -77,7 +77,7 @@ "open_links_in_new_tab": "Abrir los enlaces externos en una nueva pestaña", "enable_topic_searching": "Activar la búsqueda \"in-topic\"", "topic_search_help": "Si está activada, la búsqueda 'in-topic' sustituirá el comportamiento por defecto del navegador y le permitirá buscar en el tema al completo, en vez de hacer una búsqueda únicamente sobre el contenido mostrado en pantalla", - "follow_topics_you_reply_to": "Seguir los temas en las que respondes", + "follow_topics_you_reply_to": "Seguir los temas en los que respondes", "follow_topics_you_create": "Seguir publicaciones que creas", "grouptitle": "Selecciona el título del grupo que deseas visualizar", "no-group-title": "Sin título de grupo" diff --git a/public/language/et/email.json b/public/language/et/email.json index 1f1c1e853a..6c89d2a386 100644 --- a/public/language/et/email.json +++ b/public/language/et/email.json @@ -1,16 +1,16 @@ { - "password-reset-requested": "Parooli muutmise taotlus - %1!", - "welcome-to": "Tere tulemast foorumisse %1", + "password-reset-requested": "Parooli muutmise taotlus - %1", + "welcome-to": "Tere tulemast %1 foorumisse", "greeting_no_name": "Tere", "greeting_with_name": "Tere %1", - "welcome.text1": "Täname et oled registreerinud foorumisse %1!", + "welcome.text1": "Täname et oled registreerinud %1 foorumisse!", "welcome.text2": "Konto täielikuks aktiveerimiseks peame me kinnitama, et registreerimisel kasutatud e-mail kuulub teile.", "welcome.cta": "Vajuta siia, et kinnitada oma e-maili aadress", "reset.text1": "Meile laekus päring parooli muutmiseks. Kui päring ei ole teie poolt esitatud või te ei soovi parooli muuta, siis võite antud kirja ignoreerida.", "reset.text2": "Selleks, et jätkata parooli muutmisega vajuta järgnevale lingile:", "reset.cta": "Vajuta siia, et taotleda uut parooli", "reset.notify.subject": "Parool edukalt muudetud", - "reset.notify.text1": "Teavitame sind, et sinu parool %1 foorumis on edukalt muudetud.", + "reset.notify.text1": "Teatame, et sinu parooli muutmine kuupäeval %1 oli edukas.", "reset.notify.text2": "Kui te ei ole lubanud seda, siis teavitage koheselt administraatorit.", "digest.notifications": "Sul on lugemata teateid %1 poolt:", "digest.latest_topics": "Viimased teemad %1 poolt", diff --git a/public/language/et/global.json b/public/language/et/global.json index b383959064..bc66223d36 100644 --- a/public/language/et/global.json +++ b/public/language/et/global.json @@ -45,7 +45,7 @@ "alert.follow": "Sa jälgid nüüd %1!", "online": "Sees", "users": "Kasutajad", - "topics": "Teemad", + "topics": "Teemat", "posts": "Postitust", "views": "Vaatamist", "reputation": "Reputatsioon", diff --git a/public/language/et/notifications.json b/public/language/et/notifications.json index 24c90fce91..720cd93bf7 100644 --- a/public/language/et/notifications.json +++ b/public/language/et/notifications.json @@ -21,7 +21,7 @@ "user_mentioned_you_in": "%1 mainis sind postituses %2", "user_started_following_you": "%1 hakkas sind jälgima.", "email-confirmed": "Emaili aadress kinnitatud", - "email-confirmed-message": "Täname, et kinnitasite oma emaili aadressi. Teie kasutaja omn nüüd täielikult aktiveeritud.", + "email-confirmed-message": "Täname, et kinnitasite oma emaili aadressi. Teie kasutaja on nüüd täielikult aktiveeritud.", "email-confirm-error-message": "Emaili aadressi kinnitamisel tekkis viga. Võibolla kinnituskood oli vale või aegunud.", "email-confirm-sent": "Kinnituskiri on saadetud." } \ No newline at end of file diff --git a/public/language/ko/category.json b/public/language/ko/category.json index f7ccdba720..e2a4059181 100644 --- a/public/language/ko/category.json +++ b/public/language/ko/category.json @@ -1,11 +1,11 @@ { "new_topic_button": "새 주제 생성", - "guest-login-post": "Log in to post", + "guest-login-post": "로그인", "no_topics": "이 카테고리에는 생성된 주제가 없습니다.
먼저 주제를 생성해 보세요.", "browsing": "이 주제를 읽고 있는 사용자", "no_replies": "답글이 없습니다.", "share_this_category": "이 카테고리를 공유", - "watch": "Watch", + "watch": "관심 주제", "ignore": "관심 해제", "watch.message": "You are now watching updates from this category", "ignore.message": "You are now ignoring updates from this category" diff --git a/public/language/nb/category.json b/public/language/nb/category.json index 673aec04c3..f4b2298a0d 100644 --- a/public/language/nb/category.json +++ b/public/language/nb/category.json @@ -1,7 +1,7 @@ { "new_topic_button": "Nytt emne", "guest-login-post": "Logg inn til innlegg", - "no_topics": "Det er ingen emner i denne kategorien
Hvorfor ikke lage ett?", + "no_topics": "Det er ingen emner i denne kategorien
Hvorfor ikke lage et?", "browsing": "leser", "no_replies": "Ingen har svart", "share_this_category": "Del denne kategorien", diff --git a/public/language/nb/email.json b/public/language/nb/email.json index 37b5df85d0..a51c87c7fc 100644 --- a/public/language/nb/email.json +++ b/public/language/nb/email.json @@ -4,8 +4,8 @@ "greeting_no_name": "Hallo", "greeting_with_name": "Hallo, %1", "welcome.text1": "Takk for at du registrerte deg hos %1!", - "welcome.text2": "For å aktivere kontoen din må vi verifisere at du eier epost-adressen du registrerte med.", - "welcome.cta": "Klikk her for å verifisere epost-adressen din", + "welcome.text2": "For å aktivere kontoen din må vi verifisere at du eier e-postadressen du registrerte med.", + "welcome.cta": "Klikk her for å verifisere e-postadressen din", "reset.text1": "Vi har blir bedt om å tilbakestille passordet ditt, muligens fordi du har glemt det. Hvis dette ikke stemmer kan du ignorere denne eposten.", "reset.text2": "For å fortsette med tilbakestillingen, vennligst klikk på følgende lenke:", "reset.cta": "Klikk her for å tilbakestille passordet ditt", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index fad46d11e6..e9c1e39447 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -1,8 +1,8 @@ { - "invalid-data": "Ugyldig data", + "invalid-data": "Ugyldige data", "not-logged-in": "Du ser ikke ut til å være logget inn.", "account-locked": "Kontoen din har blitt midlertidig låst", - "search-requires-login": "Searching requires an account - please login or register.", + "search-requires-login": "Søking krever en konto - vennligst logg inn eller registrer deg.", "invalid-cid": "Ugyldig kategori-ID", "invalid-tid": "Ugyldig emne-ID", "invalid-pid": "Ugyldig innlegg-ID", @@ -21,11 +21,11 @@ "email-not-confirmed-chat": "Du kan ikke chatte før e-posten din er bekreftet, vennligst klikk her for å bekrefte e-postadressen.", "no-email-to-confirm": "Dette forumet krever at e-postbekreftelse, vennligst klikk her for å skrive inn en e-post", "email-confirm-failed": "Vi kunne ikke godkjenne e-posten din, vennligst prøv igjen senere.", - "confirm-email-already-sent": "Confirmation email already sent, please wait %1 minute(s) to send another one.", + "confirm-email-already-sent": "Bekreftelsesepost allerede sendt, vennligst vent %1 minutt(er) for å sende enn til.", "username-too-short": "Brukernavnet er for kort", "username-too-long": "Brukernavnet er for langt", "user-banned": "Bruker utestengt", - "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", + "user-too-new": "Beklager, du må vente %1 sekund(er) før du lager ditt første innlegg", "no-category": "Kategorien eksisterer ikke.", "no-topic": "Emne eksisterer ikke", "no-post": "Innlegg eksisterer ikke", @@ -36,24 +36,24 @@ "no-emailers-configured": "Ingen e-post-tillegg er lastet, så ingen test e-post kunne bli sendt", "category-disabled": "Kategori deaktivert", "topic-locked": "Emne låst", - "post-edit-duration-expired": "You are only allowed to edit posts for %1 second(s) after posting", + "post-edit-duration-expired": "Du har bare lov til å redigere innlegg i %1 sekund(er) etter posting", "still-uploading": "Vennligst vent til opplastingene blir fullført.", - "content-too-short": "Please enter a longer post. Posts should contain at least %1 character(s).", - "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 character(s).", - "title-too-short": "Please enter a longer title. Titles should contain at least %1 character(s).", - "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 character(s).", - "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", - "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", - "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", - "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 character(s)", - "file-too-big": "Maximum allowed file size is %1 kB - please upload a smaller file", + "content-too-short": "Vennligst skriv et lengre innlegg. Innlegg må inneholde minst %1 tegn.", + "content-too-long": "Vennligst skriv et kortere innlegg. Innlegg kan ikke være lengre enn %1 tegn.", + "title-too-short": "Vennligst skriv en lengre tittel. Titler må inneholde minst %1 tegn.", + "title-too-long": "Vennligst skriv en kortere tittel. Tittel kan ikke være lengre enn %1 tegn.", + "too-many-posts": "Du kan bare poste hvert %1 sekund – vennligst vent før du poster igjen", + "too-many-posts-newbie": "Som en ny bruker kan du bare poste en gang hvert %1. sekund, før du har opparbeidet %2 rykte – vennligst vent før du poster igjen", + "tag-too-short": "Vennligst skriv en lengre tag. Tagger må være på minst %1 tegn", + "tag-too-long": "Vennligst skriv en kortere tag. Tagger kan ikke være lengre enn %1 tegn", + "file-too-big": "Største tillatte filstørrelse er %1 kB – vennligst last opp en mindre fil", "cant-vote-self-post": "Du kan ikke stemme på ditt eget innlegg", "already-favourited": "Du har allerede favorittmerket dette innlegget", "already-unfavourited": "Du har allerede avfavorisert dette innlegget", "cant-ban-other-admins": "Du kan ikke utestenge andre administratorer!", "invalid-image-type": "Ugyldig bildetype. Tilatte typer er: %1", "invalid-image-extension": "Ugyldig bildefiltype", - "invalid-file-type": "Invalid file type. Allowed types are: %1", + "invalid-file-type": "Ugyldig filtype. Tillatte typer er: %1", "group-name-too-short": "Gruppenavnet er for kort", "group-already-exists": "Gruppe eksisterer allerede", "group-name-change-not-allowed": "Gruppenavn ikke tillatt", @@ -63,12 +63,12 @@ "post-already-restored": "Dette innlegget har allerede blitt gjenopprettet", "topic-already-deleted": "Dette emnet har allerede blitt slettet", "topic-already-restored": "Dette emnet har allerede blitt gjenopprettet", - "cant-purge-main-post": "You can't purge the main post, please delete the topic instead", + "cant-purge-main-post": "Du kan ikke slette hovedinnlegget. Vennligst slett emnet i stedet.", "topic-thumbnails-are-disabled": "Emne-minatyrbilder har blitt deaktivert", "invalid-file": "Ugyldig fil", "uploads-are-disabled": "Opplastninger er deaktivert", - "signature-too-long": "Sorry, your signature cannot be longer than %1 character(s).", - "about-me-too-long": "Sorry, your about me cannot be longer than %1 character(s).", + "signature-too-long": "Beklager, din signatur kan ikke være lengre enn %1 tegn", + "about-me-too-long": "Beklager, din om meg kan ikke være lengre enn %1 tegn.", "cant-chat-with-yourself": "Du kan ikke chatte med deg selv!", "chat-restricted": "Denne brukeren har begrenset sine chat-meldinger. De må følge deg før du kan chatte med dem", "too-many-messages": "Du har sendt for mange meldinger, vennligst vent en stund.", diff --git a/public/language/nb/groups.json b/public/language/nb/groups.json index 0668648206..e9ab0aed41 100644 --- a/public/language/nb/groups.json +++ b/public/language/nb/groups.json @@ -20,8 +20,8 @@ "details.kick": "Kast ut", "details.owner_options": "Gruppeadministrasjon", "details.group_name": "Gruppenavn", - "details.member_count": "Member Count", - "details.creation_date": "Creation Date", + "details.member_count": "Antall medlemmer", + "details.creation_date": "Opprettelsesdato", "details.description": "Beskrivelse", "details.badge_preview": "Forhåndsvisning av skilt", "details.change_icon": "Endre ikon", diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json index 33ff86eff6..fdc6100309 100644 --- a/public/language/nb/notifications.json +++ b/public/language/nb/notifications.json @@ -2,7 +2,7 @@ "title": "Varsler", "no_notifs": "Du har ingen nye varsler", "see_all": "Se alle varsler", - "mark_all_read": "Mark all notifications read", + "mark_all_read": "Merk alle varsler som lest", "back_to_home": "Tilbake til %1", "outgoing_link": "Utgående link", "outgoing_link_message": "Du forlater nå %1.", diff --git a/public/language/nb/recent.json b/public/language/nb/recent.json index 3b980f6f02..bdee8a1f58 100644 --- a/public/language/nb/recent.json +++ b/public/language/nb/recent.json @@ -6,7 +6,7 @@ "year": "År", "alltime": "All tid", "no_recent_topics": "Det er ingen nye tråder.", - "no_popular_topics": "There are no popular topics.", + "no_popular_topics": "Det er ingen populære emner.", "there-is-a-new-topic": "Det finnes et nytt emne.", "there-is-a-new-topic-and-a-new-post": "Det finnes et nytt emne og et nytt innlegg.", "there-is-a-new-topic-and-new-posts": "Det finnes et nytt emne og %1 nye innlegg.", diff --git a/public/language/nb/reset_password.json b/public/language/nb/reset_password.json index f9cd7bdf72..bf51d99140 100644 --- a/public/language/nb/reset_password.json +++ b/public/language/nb/reset_password.json @@ -11,7 +11,7 @@ "enter_email_address": "Skriv e-post", "password_reset_sent": "Passord-tilbakestilling sendt", "invalid_email": "Ugyldig e-post / e-post eksisterer ikke", - "password_too_short": "The password entered is too short, please pick a different password.", - "passwords_do_not_match": "The two passwords you've entered do not match.", - "password_expired": "Your password has expired, please choose a new password" + "password_too_short": "Passordet du skrev inn er for kort, velg et lengre passord.", + "passwords_do_not_match": "Passordene du har skrevet inn stemmer ikke overens.", + "password_expired": "Passordet ditt er utgått, velg et nytt passord" } \ No newline at end of file diff --git a/public/language/nb/search.json b/public/language/nb/search.json index 51c3d113da..a62f2d9cb5 100644 --- a/public/language/nb/search.json +++ b/public/language/nb/search.json @@ -1,7 +1,7 @@ { "results_matching": "%1 resultat(er) samsvarer med \"%2\", (%3 sekunder)", "no-matches": "Ingen matcher funnet", - "advanced-search": "Advanced Search", + "advanced-search": "Avansert søk", "in": "I", "titles": "Titler", "titles-posts": "Titler og innlegg", @@ -30,11 +30,11 @@ "topic-start-date": "Starttid for emne", "username": "Brukernavn", "category": "Kategori", - "descending": "In descending order", - "ascending": "In ascending order", + "descending": "I synkende rekkefølge", + "ascending": "I stigende rekkefølge", "save-preferences": "Lagre innstillinger", "clear-preferences": "Tøm innstillinnger", "search-preferences-saved": "Søkeinnstillinger lagret", "search-preferences-cleared": "Søkeinnstillinger tømt", - "show-results-as": "Vis resultateter som" + "show-results-as": "Vis resultater som" } \ No newline at end of file diff --git a/public/language/nb/tags.json b/public/language/nb/tags.json index 5287b6125a..c9a6efbab7 100644 --- a/public/language/nb/tags.json +++ b/public/language/nb/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Det er ingen emnet med denne taggen.", "tags": "Tagger", - "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", + "enter_tags_here": "Skriv tagger her, mellom %1 og %2 tegn hver.", "enter_tags_here_short": "Skriv tagger...", "no_tags": "Det finnes ingen tagger enda." } \ No newline at end of file diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 3863fd48ae..49afb62941 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -5,7 +5,7 @@ "no_topics_found": "Ingen emner funnet!", "no_posts_found": "Ingen innlegg funnet!", "post_is_deleted": "Dette innlegget er slettet!", - "topic_is_deleted": "This topic is deleted!", + "topic_is_deleted": "Dette emnet er slettet!", "profile": "Profil", "posted_by": "Skapt av %1", "posted_by_guest": "Skapt av Gjest", @@ -13,7 +13,7 @@ "notify_me": "Bli varslet om nye svar i dette emnet", "quote": "Siter", "reply": "Svar", - "guest-login-reply": "Log in to reply", + "guest-login-reply": "Logg inn for å besvare", "edit": "Endre", "delete": "Slett", "purge": "Tøm", diff --git a/public/language/nb/user.json b/public/language/nb/user.json index be80c50470..e6cd7c41ed 100644 --- a/public/language/nb/user.json +++ b/public/language/nb/user.json @@ -21,14 +21,14 @@ "watched": "Overvåkede", "followers": "Følgere", "following": "Følger", - "aboutme": "About me", + "aboutme": "Om meg", "signature": "Signatur", "gravatar": "Gravatar", "birthday": "Bursdag", - "chat": "Chatt", + "chat": "Chat", "follow": "Følg", "unfollow": "Avfølg", - "more": "More", + "more": "Mer", "profile_update_success": "Profilen ble oppdatert!", "change_picture": "Bytt bilde", "edit": "Endre", @@ -60,8 +60,8 @@ "digest_weekly": "Ukentlig", "digest_monthly": "Månedlig", "send_chat_notifications": "Send en epost hvis jeg mottar en chat-melding når jeg ikke er pålogget", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", - "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", + "send_post_notifications": "Send en e-post når svar postes til emner jeg abonnerer på", + "settings-require-reload": "Noen innstillingsendringer krever at du laster siden på nytt. Klikk her for å laste på nytt.", "has_no_follower": "Denne brukeren har ingen følgere :(", "follows_no_one": "Denne brukeren følger ingen :(", "has_no_posts": "Denne brukeren har ikke skrevet noe enda.", @@ -69,16 +69,16 @@ "has_no_watched_topics": "Denne brukeren overvåker ingen innlegg foreløpig.", "email_hidden": "E-post skjult", "hidden": "skjult", - "paginate_description": "Paginate topics and posts instead of using infinite scroll", + "paginate_description": "Bruk sidevelger for emner og innlegg istedet for uendelig scrolling", "topics_per_page": "Tråd per side", "posts_per_page": "Innlegg per side", - "notification_sounds": "Play a sound when you receive a notification", + "notification_sounds": "Spill en lyd når du mottar et varsel", "browsing": "Surfeinnstillinger", - "open_links_in_new_tab": "Open outgoing links in new tab", + "open_links_in_new_tab": "Åpne utgående lenker i en ny fane", "enable_topic_searching": "Aktiver søk-i-emne", - "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen", - "follow_topics_you_reply_to": "Follow topics that you reply to", - "follow_topics_you_create": "Follow topics you create", - "grouptitle": "Select the group title you would like to display", - "no-group-title": "No group title" + "topic_search_help": "Hvis søk-i-emne er aktivert, overstyres nettleserens standard sidesøk og gir mulighet til å søke gjennom hele emnet, ikke bare det som vises på skjermen", + "follow_topics_you_reply_to": "Følg emner du besvarer", + "follow_topics_you_create": "Følg emner du oppretter", + "grouptitle": "Velg gruppetittelen du vil vise", + "no-group-title": "Ingen gruppetittel" } \ No newline at end of file diff --git a/public/language/nb/users.json b/public/language/nb/users.json index 661479fbf1..5f19a09507 100644 --- a/public/language/nb/users.json +++ b/public/language/nb/users.json @@ -5,7 +5,7 @@ "search": "Søk", "enter_username": "Skriv ett brukernavn for å søke", "load_more": "Last flere", - "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", + "users-found-search-took": "%1 bruker(e) funnet. Søket tok %2 sekunder.", "filter-by": "Filtrer etter", "online-only": "Bare påloggede", "picture-only": "Bare bilde" diff --git a/public/language/nl/error.json b/public/language/nl/error.json index 95f7d04f1d..686603759f 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -2,7 +2,7 @@ "invalid-data": "Ongeldige Data", "not-logged-in": "De account lijkt op dit moment niet aangemeld te zijn.", "account-locked": "De account is tijdelijk vergrendeld", - "search-requires-login": "Searching requires an account - please login or register.", + "search-requires-login": "Zoeken vereist een account - gelieve aan te melden of te registreren.", "invalid-cid": "Ongeldig categoriesleutel", "invalid-tid": "Ongeldig id voor onderwerp", "invalid-pid": "Ongeldig berichtkenmerk", @@ -67,8 +67,8 @@ "topic-thumbnails-are-disabled": "Miniatuurweergaven bij onderwerpen uitgeschakeld. ", "invalid-file": "Ongeldig bestand", "uploads-are-disabled": "Uploads zijn uitgeschakeld", - "signature-too-long": "Sorry, your signature cannot be longer than %1 character(s).", - "about-me-too-long": "Sorry, your about me cannot be longer than %1 character(s).", + "signature-too-long": "Sorry, je onderschrift kan niet langer zijn da %1 karakter(s).", + "about-me-too-long": "Sorry, je over mij kan niet langer zijn da %1 karakter(s).", "cant-chat-with-yourself": "Het is niet mogelijk met jezelf een chatgesprek te houden.", "chat-restricted": "Deze gebruiker heeft beperkingen aan de chatfunctie opgelegd waardoor deze eerst iemand moet volgen voordat deze persoon een nieuwe chat mag initiëren.", "too-many-messages": "Er zijn in korte tijd teveel berichten verzonden, een moment geduld.", diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index 38593ecca8..ab67cf9cb5 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -5,7 +5,7 @@ "no_topics_found": "Geen onderwerpen gevonden!", "no_posts_found": "Geen berichten gevonden!", "post_is_deleted": "Dit bericht is verwijderd!", - "topic_is_deleted": "This topic is deleted!", + "topic_is_deleted": "Dit onderwerp is verwijderd!", "profile": "Profiel", "posted_by": "Geplaatst door %1", "posted_by_guest": "Geplaatst door gast", diff --git a/public/language/nl/user.json b/public/language/nl/user.json index 4822209b05..d461f1b8a6 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -21,7 +21,7 @@ "watched": "Bekeken", "followers": "Volgers", "following": "Volgend", - "aboutme": "About me", + "aboutme": "Over mij", "signature": "Handtekening", "gravatar": "Gravatar", "birthday": "Verjaardag", diff --git a/public/language/sv/unread.json b/public/language/sv/unread.json index 583d912781..d9b02eabd0 100644 --- a/public/language/sv/unread.json +++ b/public/language/sv/unread.json @@ -1,6 +1,6 @@ { "title": "Olästa", - "no_unread_topics": "Det finns inga ilästa ämnen.", + "no_unread_topics": "Det finns inga olästa ämnen.", "load_more": "Ladda fler", "mark_as_read": "Markerad som läst", "selected": "Vald", From 4de5fde18d30e966c1aa6797cf3094ce4844966a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 6 Jul 2015 12:45:29 -0400 Subject: [PATCH 17/49] fixed link to maintenance mode in ACP/Dash --- src/views/admin/general/dashboard.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/admin/general/dashboard.tpl b/src/views/admin/general/dashboard.tpl index 6d6162f079..a3eeb464bb 100644 --- a/src/views/admin/general/dashboard.tpl +++ b/src/views/admin/general/dashboard.tpl @@ -99,7 +99,7 @@

- Maintenance Mode + Maintenance Mode

From 1d4efaee68e75dce75e2d207a27474a86f206ac4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 6 Jul 2015 13:01:26 -0400 Subject: [PATCH 18/49] fix indices if postsPerPage is an odd number --- src/controllers/topics.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/topics.js b/src/controllers/topics.js index b65b3b997a..2975c73cb3 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -89,9 +89,9 @@ topicsController.get = function(req, res, next) { } if (!settings.usePagination) { if (reverse) { - postIndex = Math.max(0, postCount - (req.params.post_index || postCount) - (settings.postsPerPage / 2)); + postIndex = Math.max(0, postCount - (req.params.post_index || postCount) - Math.ceil(settings.postsPerPage / 2)); } else { - postIndex = Math.max(0, (req.params.post_index || 1) - (settings.postsPerPage / 2)); + postIndex = Math.max(0, (req.params.post_index || 1) - Math.ceil(settings.postsPerPage / 2)); } } else if (!req.query.page) { var index = 0; From 2d70733fa5c0ff620102322fa5299d43595d3a38 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 6 Jul 2015 13:19:09 -0400 Subject: [PATCH 19/49] updated dependencies to use latest UglifyJS2, instead of my year-old fork --- minifier.js | 8 ++++++-- package.json | 2 +- src/meta/js.js | 1 + src/routes/meta.js | 11 +++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/minifier.js b/minifier.js index 3cd1c81ff8..bca79e68f1 100644 --- a/minifier.js +++ b/minifier.js @@ -30,9 +30,10 @@ Minifier.js.minify = function (scripts, minify, callback) { process.on('message', function(payload) { switch(payload.action) { case 'js': - Minifier.js.minify(payload.scripts, payload.minify, function(minified) { + Minifier.js.minify(payload.scripts, payload.minify, function(minified/*, sourceMap*/) { process.send({ type: 'end', + // sourceMap: sourceMap, minified: minified }); }); @@ -41,8 +42,11 @@ process.on('message', function(payload) { }); function minifyScripts(scripts, callback) { + // The portions of code involving the source map are commented out as they're broken in UglifyJS2 + // Follow along here: https://github.com/mishoo/UglifyJS2/issues/700 try { var minified = uglifyjs.minify(scripts, { + // outSourceMap: "nodebb.min.js.map", compress: false }), hasher = crypto.createHash('md5'), @@ -56,7 +60,7 @@ function minifyScripts(scripts, callback) { payload: hash.slice(0, 8) }); - callback(minified.code); + callback(minified.code/*, minified.map*/); } catch(err) { process.send({ type: 'error', diff --git a/package.json b/package.json index d6c37b900e..b84816767f 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "string": "^3.0.0", "templates.js": "^0.2.6", "touch": "0.0.3", - "uglify-js": "git+https://github.com/julianlam/UglifyJS2.git", + "uglify-js": "^2.4.23", "underscore": "~1.8.3", "underscore.deep": "^0.5.1", "validator": "^3.30.0", diff --git a/src/meta/js.js b/src/meta/js.js index 0384e8d36d..020611e7ce 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -141,6 +141,7 @@ module.exports = function(Meta) { switch(message.type) { case 'end': Meta.js.cache = message.minified; + Meta.js.map = message.sourceMap; onComplete(); break; case 'hash': diff --git a/src/routes/meta.js b/src/routes/meta.js index e028adf63d..03cf1cde24 100644 --- a/src/routes/meta.js +++ b/src/routes/meta.js @@ -8,6 +8,16 @@ function sendMinifiedJS(req, res, next) { res.type('text/javascript').send(meta.js.cache); } +// The portions of code involving the source map are commented out as they're broken in UglifyJS2 +// Follow along here: https://github.com/mishoo/UglifyJS2/issues/700 +// function sendJSSourceMap(req, res) { +// if (meta.js.hasOwnProperty('map')) { +// res.type('application/json').send(meta.js.map); +// } else { +// res.redirect(404); +// } +// }; + function sendStylesheet(req, res, next) { res.type('text/css').status(200).send(meta.css.cache); } @@ -20,6 +30,7 @@ module.exports = function(app, middleware, controllers) { app.get('/stylesheet.css', middleware.addExpiresHeaders, sendStylesheet); app.get('/admin.css', middleware.addExpiresHeaders, sendACPStylesheet); app.get('/nodebb.min.js', middleware.addExpiresHeaders, sendMinifiedJS); + // app.get('/nodebb.min.js.map', middleware.addExpiresHeaders, sendJSSourceMap); app.get('/sitemap.xml', controllers.sitemap); app.get('/robots.txt', controllers.robots); app.get('/css/previews/:theme', controllers.admin.themes.get); From ffd22f50ff8e291739032dd241c015eed7e50cd4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 6 Jul 2015 14:33:43 -0400 Subject: [PATCH 20/49] closes #1999 --- public/src/admin/admin.js | 9 -------- public/src/admin/extend/rewards.js | 14 +++++------ public/src/admin/general/navigation.js | 2 +- public/src/admin/manage/category.js | 14 +++++------ public/src/admin/manage/group.js | 2 +- public/src/admin/manage/users.js | 2 +- public/src/ajaxify.js | 2 +- public/src/app.js | 4 ++-- public/src/client/account/edit.js | 14 +++++------ public/src/client/account/header.js | 2 +- public/src/client/account/posts.js | 2 +- public/src/client/account/profile.js | 14 +++++------ public/src/client/account/settings.js | 4 ++-- public/src/client/account/topics.js | 2 +- public/src/client/account/watched.js | 2 +- public/src/client/category.js | 20 ++++++++-------- public/src/client/groups/details.js | 32 +++++++++++++------------- public/src/client/reset_code.js | 2 +- public/src/client/tag.js | 2 +- public/src/client/topic.js | 18 +++++++-------- public/src/client/topic/browsing.js | 2 +- public/src/client/topic/events.js | 4 ++-- public/src/client/topic/postTools.js | 14 +++++------ public/src/client/topic/posts.js | 10 ++++---- public/src/client/topic/threadTools.js | 12 +++++----- public/src/modules/search.js | 2 +- public/src/variables.js | 10 ++++++++ src/middleware/middleware.js | 4 ++-- 28 files changed, 111 insertions(+), 110 deletions(-) diff --git a/public/src/admin/admin.js b/public/src/admin/admin.js index fe411adeb3..f2919ada72 100644 --- a/public/src/admin/admin.js +++ b/public/src/admin/admin.js @@ -75,15 +75,6 @@ socket.emit('admin.restart'); }); - Mousetrap.bind('ctrl+shift+a d', function() { - var tid = ajaxify.variables.get('topic_id'), - cid = ajaxify.variables.get('category_id'); - - if (tid && cid) { - socket.emit('topics.delete', { tids: [tid], cid: cid }); - } - }); - Mousetrap.bind('/', function(e) { $('#acp-search input').focus(); diff --git a/public/src/admin/extend/rewards.js b/public/src/admin/extend/rewards.js index 967e098bf7..d93741d76b 100644 --- a/public/src/admin/extend/rewards.js +++ b/public/src/admin/extend/rewards.js @@ -11,10 +11,10 @@ define('admin/extend/rewards', function() { conditionals; rewards.init = function() { - available = JSON.parse(ajaxify.variables.get('rewards')); - active = JSON.parse(ajaxify.variables.get('active')); - conditions = JSON.parse(ajaxify.variables.get('conditions')); - conditionals = JSON.parse(ajaxify.variables.get('conditionals')); + available = ajaxify.data.rewards; + active = ajaxify.data.active; + conditions = ajaxify.data.conditions; + conditionals = ajaxify.data.conditionals; $('[data-selected]').each(function() { select($(this)); @@ -96,7 +96,7 @@ define('admin/extend/rewards', function() { inputs.forEach(function(input) { html += '