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 += '