diff --git a/.tx/config b/.tx/config index a7f7e2f98b..65d891131e 100644 --- a/.tx/config +++ b/.tx/config @@ -919,4 +919,50 @@ trans.tr = public/language/tr/groups.json trans.vi = public/language/vi/groups.json trans.zh_CN = public/language/zh_CN/groups.json trans.zh_TW = public/language/zh_TW/groups.json +type = KEYVALUEJSON + +[nodebb.uploads] +file_filter = public/language//uploads.json +source_file = public/language/en_GB/uploads.json +source_lang = en_GB +trans.ar = public/language/ar/uploads.json +trans.bn = public/language/bn/uploads.json +trans.bg = public/language/bg/uploads.json +trans.cs = public/language/cs/uploads.json +trans.da = public/language/da/uploads.json +trans.de = public/language/de/uploads.json +trans.el = public/language/el/uploads.json +trans.en_US = public/language/en_US/uploads.json +trans.en@pirate = public/language/en@pirate/uploads.json +trans.es = public/language/es/uploads.json +trans.et = public/language/et/uploads.json +trans.fa_IR = public/language/fa_IR/uploads.json +trans.fi = public/language/fi/uploads.json +trans.fr = public/language/fr/uploads.json +trans.gl = public/language/gl/uploads.json +trans.he = public/language/he/uploads.json +trans.hu = public/language/hu/uploads.json +trans.id = public/language/id/uploads.json +trans.it = public/language/it/uploads.json +trans.ja = public/language/ja/uploads.json +trans.ko = public/language/ko/uploads.json +trans.lt = public/language/lt/uploads.json +trans.ms = public/language/ms/uploads.json +trans.nb = public/language/nb/uploads.json +trans.nl = public/language/nl/uploads.json +trans.pl = public/language/pl/uploads.json +trans.pt_BR = public/language/pt_BR/uploads.json +trans.ru = public/language/ru/uploads.json +trans.ro = public/language/ro/uploads.json +trans.rw = public/language/rw/uploads.json +trans.sc = public/language/sc/uploads.json +trans.sk = public/language/sk/uploads.json +trans.sl = public/language/sl/uploads.json +trans.sr = public/language/sr/uploads.json +trans.sv = public/language/sv/uploads.json +trans.th = public/language/th/uploads.json +trans.tr = public/language/tr/uploads.json +trans.vi = public/language/vi/uploads.json +trans.zh_CN = public/language/zh_CN/uploads.json +trans.zh_TW = public/language/zh_TW/uploads.json type = KEYVALUEJSON \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index fa4ceed1e9..a6aca2083a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -57,19 +57,35 @@ module.exports = function(grunt) { grunt.initConfig({ watch: { lessUpdated_Client: { - files: ['public/*.less', 'node_modules/nodebb-*/*.less', 'node_modules/nodebb-*/*/*.less', 'node_modules/nodebb-*/*/*/*.less', 'node_modules/nodebb-*/*/*/*/*.less'] + files: [ + 'public/*.less', + 'node_modules/nodebb-*/*.less', 'node_modules/nodebb-*/**/*.less', + '!node_modules/nodebb-*/node_modules/**', + '!node_modules/nodebb-*/.git/**' + ] }, lessUpdated_Admin: { files: ['public/**/*.less'] }, clientUpdated: { - files: ['public/src/**/*.js', 'node_modules/nodebb-*/*.js', 'node_modules/nodebb-*/*/*.js', 'node_modules/nodebb-*/*/*/*.js', 'node_modules/nodebb-*/*/*/*/*.js', 'node_modules/templates.js/lib/templates.js'] + files: [ + 'public/src/**/*.js', + 'node_modules/nodebb-*/*.js', 'node_modules/nodebb-*/**/*.js', + '!node_modules/nodebb-*/node_modules/**', + 'node_modules/templates.js/lib/templates.js', + '!node_modules/nodebb-*/.git/**' + ] }, serverUpdated: { files: ['*.js', 'install/*.js', 'src/**/*.js'] }, templatesUpdated: { - files: ['src/views/**/*.tpl', 'node_modules/nodebb-*/*.tpl', 'node_modules/nodebb-*/*/*.tpl', 'node_modules/nodebb-*/*/*/*.tpl', 'node_modules/nodebb-*/*/*/*/*.tpl', 'node_modules/nodebb-*/*/*/*/*/*.tpl'] + files: [ + 'src/views/**/*.tpl', + 'node_modules/nodebb-*/*.tpl', 'node_modules/nodebb-*/**/*.tpl', + '!node_modules/nodebb-*/node_modules/**', + '!node_modules/nodebb-*/.git/**' + ] } } }); diff --git a/app.js b/app.js index c75c70f9cf..ed5238285e 100644 --- a/app.js +++ b/app.js @@ -149,9 +149,7 @@ function start() { meta.reload(); break; case 'js-propagate': - meta.js.target[message.target] = meta.js.target[message.target] || {}; - meta.js.target[message.target].cache = message.cache; - meta.js.target[message.target].map = message.map; + meta.js.target = message.data; emitter.emit('meta:js.compiled'); winston.verbose('[cluster] Client-side javascript and mapping propagated to worker %s', process.pid); break; diff --git a/loader.js b/loader.js index 5676a02bbd..b78abdc4a1 100644 --- a/loader.js +++ b/loader.js @@ -34,8 +34,9 @@ var pidFilePath = __dirname + '/pidfile', Loader.init = function(callback) { if (silent) { - console.log = function(value) { - output.write(value + '\n'); + console.log = function() { + var args = Array.prototype.slice.call(arguments); + output.write(args.join(' ') + '\n'); }; } @@ -122,15 +123,11 @@ Loader.addWorkerEvents = function(worker) { Loader.reload(); break; case 'js-propagate': - Loader.js.target[message.target] = Loader.js.target[message.target] || {}; - Loader.js.target[message.target].cache = message.cache; - Loader.js.target[message.target].map = message.map; + Loader.js.target = message.data; Loader.notifyWorkers({ action: 'js-propagate', - cache: message.cache, - map: message.map, - target: message.target + data: message.data }, worker.pid); break; case 'css-propagate': diff --git a/package.json b/package.json index 1776057690..b64c7e4fb9 100644 --- a/package.json +++ b/package.json @@ -53,9 +53,9 @@ "nodebb-plugin-spam-be-gone": "0.4.6", "nodebb-rewards-essentials": "0.0.8", "nodebb-theme-lavender": "3.0.9", - "nodebb-theme-persona": "4.0.114", + "nodebb-theme-persona": "4.0.115", "nodebb-theme-vanilla": "5.0.61", - "nodebb-widget-essentials": "2.0.8", + "nodebb-widget-essentials": "2.0.9", "nodemailer": "2.0.0", "nodemailer-sendmail-transport": "1.0.0", "nodemailer-smtp-transport": "^2.4.1", @@ -87,7 +87,7 @@ "devDependencies": { "mocha": "~1.13.0", "grunt": "~0.4.5", - "grunt-contrib-watch": "^0.6.1" + "grunt-contrib-watch": "^1.0.0" }, "bugs": { "url": "https://github.com/NodeBB/NodeBB/issues" @@ -112,4 +112,4 @@ "url": "https://github.com/barisusakli" } ] -} \ No newline at end of file +} diff --git a/public/language/ar/uploads.json b/public/language/ar/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/ar/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/bg/uploads.json b/public/language/bg/uploads.json new file mode 100644 index 0000000000..e262a56d6c --- /dev/null +++ b/public/language/bg/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Качване на файла…", + "select-file-to-upload": "Изберете файл за качване!", + "upload-success": "Файлът е качен успешно!", + "maximum-file-size": "Най-много %1 КБ" +} \ No newline at end of file diff --git a/public/language/bn/uploads.json b/public/language/bn/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/bn/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/cs/uploads.json b/public/language/cs/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/cs/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/da/uploads.json b/public/language/da/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/da/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/de/email.json b/public/language/de/email.json index d96a0b7b38..459cb40156 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -17,7 +17,7 @@ "reset.notify.text1": "Wir benachrichtigen dich, dass dein Passwort am %1 erfolgreich geändert wurde.", "reset.notify.text2": "Bitte benachrichtige umgehend einen Administrator, wenn du dies nicht autorisiert hast.", "digest.notifications": "Du hast ungelesene Benachrichtigungen von %1:", - "digest.latest_topics": "Neueste Themen vom %1", + "digest.latest_topics": "Neueste Themen auf %1", "digest.cta": "Klicke hier, um %1 zu besuchen", "digest.unsub.info": "Diese Zusammenfassung wurde dir aufgrund deiner Abonnement-Einstellungen gesendet.", "digest.no_topics": "Es gab keine aktiven Themen innerhalb %1", diff --git a/public/language/de/uploads.json b/public/language/de/uploads.json new file mode 100644 index 0000000000..2e0c183386 --- /dev/null +++ b/public/language/de/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Lade Datei hoch...", + "select-file-to-upload": "Wähle eine Datei zum Hochladen aus!", + "upload-success": "Datei erfolgreich hochgeladen!", + "maximum-file-size": "Maximal %1 kb" +} \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index addf47ab8f..e4fd8b8f8e 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -65,7 +65,7 @@ "show_email": "Zeige meine E-Mail Adresse an.", "show_fullname": "Zeige meinen kompletten Namen an", "restrict_chats": "Nur Chatnachrichten von Benutzern, denen ich folge, erlauben", - "digest_label": "Auszug abonnieren", + "digest_label": "Zusammenfassung abonnieren", "digest_description": "Abonniere E-Mail-Benachrichtigungen für dieses Forum (neue Benachrichtigungen und Themen) nach einem festen Zeitplan.", "digest_off": "Aus", "digest_daily": "Täglich", diff --git a/public/language/el/uploads.json b/public/language/el/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/el/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/en@pirate/uploads.json b/public/language/en@pirate/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/en@pirate/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/en_GB/email.json b/public/language/en_GB/email.json index 012270d2ab..e893709772 100644 --- a/public/language/en_GB/email.json +++ b/public/language/en_GB/email.json @@ -31,6 +31,7 @@ "digest.day": "day", "digest.week": "week", "digest.month": "month", + "digest.subject": "Digest for %1", "notif.chat.subject": "New chat message received from %1", "notif.chat.cta": "Click here to continue the conversation", diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index e9a4cbea7d..65e2c584df 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -109,6 +109,7 @@ "cant-remove-last-user": "You can't remove the last user", "cant-delete-chat-message": "You are not allowed to delete this message", + "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", diff --git a/public/language/en_US/uploads.json b/public/language/en_US/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/en_US/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/es/error.json b/public/language/es/error.json index 44a95c2cd6..630475a16f 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -14,7 +14,7 @@ "invalid-password": "Contraseña no válida", "invalid-username-or-password": "Por favor especifica tanto un usuario como contraseña", "invalid-search-term": "Término de búsqueda inválido", - "invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2", + "invalid-pagination-value": "Número de página inválido, debe estar entre %1 y %2", "username-taken": "Nombre de usuario ocupado", "email-taken": "Correo electrónico ocupado", "email-not-confirmed": "Su cuenta de correo electrónico no ha sido confirmada aún, por favor haga click aquí para confirmarla.", @@ -84,7 +84,7 @@ "chat-message-too-long": "Mensaje de Chat es demasiado largo", "cant-edit-chat-message": "No tienes permiso para editar este mensaje", "cant-remove-last-user": "No puedes eliminar el último usuario", - "cant-delete-chat-message": "You are not allowed to delete this message", + "cant-delete-chat-message": "No tienes permiso para eliminar este mensaje", "reputation-system-disabled": "El sistema de reputación está deshabilitado.", "downvoting-disabled": "La votación negativa está deshabilitada.", "not-enough-reputation-to-downvote": "No tienes suficiente reputación para votar negativo este post", @@ -97,7 +97,7 @@ "wrong-login-type-username": "Por favor introduce tu nombre de usuario para acceder", "invite-maximum-met": "Has alcanzado el número máximo de personas invitadas (%1 de %2).", "no-session-found": "¡No se ha encontrado ningún inicio de sesión!", - "not-in-room": "User not in room", - "no-users-in-room": "No users in this room", - "cant-kick-self": "You can't kick yourself from the group" + "not-in-room": "El usuario no está en la sala", + "no-users-in-room": "No hay usuarios en esta sala", + "cant-kick-self": "No te puedes expulsar a ti mismo del grupo" } \ No newline at end of file diff --git a/public/language/es/global.json b/public/language/es/global.json index 6e7c532fe9..d81c10ca88 100644 --- a/public/language/es/global.json +++ b/public/language/es/global.json @@ -65,7 +65,7 @@ "posted_in_ago_by": "publicado en %1 %2 por %3", "user_posted_ago": "%1 publicó %2", "guest_posted_ago": "Invitado publicó %1", - "last_edited_by": "last edited by %1", + "last_edited_by": "Última edición por %1", "norecentposts": "No hay publicaciones recientes", "norecenttopics": "No hay temas recientes", "recentposts": "Publicaciones recientes", @@ -87,8 +87,8 @@ "map": "Mapa", "sessions": "Inicios de sesión", "ip_address": "Direcciones IP", - "enter_page_number": "Enter page number", - "upload_file": "Upload file", - "upload": "Upload", - "allowed-file-types": "Allowed file types are %1" + "enter_page_number": "Escribe el número de página", + "upload_file": "Subir archivo", + "upload": "Subir", + "allowed-file-types": "Los tipos de archivos permitidos son: %1" } \ No newline at end of file diff --git a/public/language/es/groups.json b/public/language/es/groups.json index 1bcb9f23af..657fe67599 100644 --- a/public/language/es/groups.json +++ b/public/language/es/groups.json @@ -41,7 +41,7 @@ "details.hidden": "Oculto", "details.hidden_help": "Si está habilitado, este grupo no aparecerá en los listados de grupos, y los usuarios tendrán que ser invitados manualmente", "details.delete_group": "Eliminar grupo", - "details.private_system_help": "Private groups is disabled at system level, this option does not do anything", + "details.private_system_help": "Los grupos privados están desactivados a nivel de sistema, esta opción no cambiará nada.", "event.updated": "Los detalles del grupo han sido actualizados", "event.deleted": "El grupo \"%1\" ha sido eliminado", "membership.accept-invitation": "Aceptar Invitación", @@ -50,5 +50,5 @@ "membership.leave-group": "Dejar el grupo", "membership.reject": "Rechazar", "new-group.group_name": "Nombre de Grupo:", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "Cargar foto para el grupo" } \ No newline at end of file diff --git a/public/language/es/uploads.json b/public/language/es/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/es/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/et/uploads.json b/public/language/et/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/et/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/fa_IR/uploads.json b/public/language/fa_IR/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/fa_IR/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/fi/uploads.json b/public/language/fi/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/fi/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/fr/uploads.json b/public/language/fr/uploads.json new file mode 100644 index 0000000000..7cc22992da --- /dev/null +++ b/public/language/fr/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Envoi du fichier…", + "select-file-to-upload": "Sélectionnez un ficher à envoyer", + "upload-success": "Fichier envoyé", + "maximum-file-size": "%1 Ko maximum" +} \ No newline at end of file diff --git a/public/language/gl/uploads.json b/public/language/gl/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/gl/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/he/uploads.json b/public/language/he/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/he/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/hu/uploads.json b/public/language/hu/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/hu/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/id/uploads.json b/public/language/id/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/id/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/it/uploads.json b/public/language/it/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/it/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/ja/uploads.json b/public/language/ja/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/ja/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/ko/error.json b/public/language/ko/error.json index 026ba3dfb1..edb0a3a88d 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -27,7 +27,7 @@ "password-too-long": "패스워드가 너무 깁니다.", "user-banned": "차단된 사용자입니다.", "user-too-new": "죄송합니다, 첫 번째 게시물은 %1 초 후에 작성할 수 있습니다.", - "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "blacklisted-ip": "죄송하지만, 당신의 IP는 이 커뮤니티로부터 차단되었습니다. 만약 에러라는 생각이 드신다면 관리자에게 연락해주세요.", "no-category": "존재하지 않는 카테고리입니다.", "no-topic": "존재하지 않는 주제입니다.", "no-post": "존재하지 않는 게시물입니다.", @@ -99,5 +99,5 @@ "no-session-found": "로그인 세션을 찾을 수 없습니다.", "not-in-room": "없는 사용자입니다.", "no-users-in-room": "사용자가 없습니다.", - "cant-kick-self": "You can't kick yourself from the group" + "cant-kick-self": "스스로 이 그룹을 탈퇴할 수 없습니다." } \ No newline at end of file diff --git a/public/language/ko/groups.json b/public/language/ko/groups.json index aaba4f6565..18eb6a0b07 100644 --- a/public/language/ko/groups.json +++ b/public/language/ko/groups.json @@ -41,7 +41,7 @@ "details.hidden": "숨김", "details.hidden_help": "활성 시 그룹 목록에 노출되지 않습니다. 또한 구성원은 초대를 통해서만 가입이 가능합니다.", "details.delete_group": "그룹 삭제", - "details.private_system_help": "Private groups is disabled at system level, this option does not do anything", + "details.private_system_help": "비공개 그룹은 시스템에 의해 비활성화 되었으며, 이 옵션은 아무 기능도 하지 않습니다", "event.updated": "그룹 정보가 업데이트 되었습니다.", "event.deleted": "%1 그룹이 삭제되었습니다.", "membership.accept-invitation": "초대 수락", diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index f815b89ef4..99aea82699 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -6,7 +6,7 @@ "chat.user_typing": "%1님이 입력 중입니다.", "chat.user_has_messaged_you": "%1님이 메시지를 보냈습니다.", "chat.see_all": "모든 대화 보기", - "chat.mark_all_read": "Mark all chats read", + "chat.mark_all_read": "읽은 채팅 읽음으로 표시", "chat.no-messages": "대화 기록을 보려면 대화 상대를 선택하세요.", "chat.no-users-in-room": "사용자가 없습니다.", "chat.recent-chats": "최근 대화 내용", diff --git a/public/language/ko/uploads.json b/public/language/ko/uploads.json new file mode 100644 index 0000000000..3438b2ca03 --- /dev/null +++ b/public/language/ko/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "파일 업로드 중...", + "select-file-to-upload": "업로드할 파일을 선택해 주세요!", + "upload-success": "파일이 성공적으로 업로드 되었습니다!", + "maximum-file-size": "최대 %1 kb" +} \ No newline at end of file diff --git a/public/language/ko/user.json b/public/language/ko/user.json index 3ff7c3244e..b86ed76b19 100644 --- a/public/language/ko/user.json +++ b/public/language/ko/user.json @@ -39,7 +39,7 @@ "change_username": "사용자명 변경", "change_email": "이메일 변경", "edit": "프로필 수정", - "edit-profile": "Edit Profile", + "edit-profile": "프로필 수정하기", "default_picture": "기본 아이콘", "uploaded_picture": "사진 업로드", "upload_new_picture": "새 사진 업로드", @@ -92,7 +92,7 @@ "open_links_in_new_tab": "외부 링크를 새로운 탭을 사용하여 열람", "enable_topic_searching": "주제 내 검색 허용", "topic_search_help": "활성화 된후 브라우저의 기본 페이지 검색 기능을 연관 주제 검색 기능으로 대신하고 화면에 보여지는 것 뿐만 아니라 주제와 연관된 모든것을 검색합니다.", - "scroll_to_my_post": "After posting a reply, show the new post", + "scroll_to_my_post": "답글 게시 후 새 포스트 보여주기", "follow_topics_you_reply_to": "답글 단 게시물을 팔로우 합니다.", "follow_topics_you_create": "생성한 주제를 팔로우 합니다.", "grouptitle": "표시할 그룹 이름을 선택하세요.", diff --git a/public/language/lt/uploads.json b/public/language/lt/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/lt/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/ms/uploads.json b/public/language/ms/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/ms/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/nb/uploads.json b/public/language/nb/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/nb/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/nl/global.json b/public/language/nl/global.json index d1dc94a360..dfa27b416f 100644 --- a/public/language/nl/global.json +++ b/public/language/nl/global.json @@ -52,7 +52,7 @@ "best": "Beste", "upvoted": "Omhoog gestemd", "downvoted": "Omlaag gestemd", - "views": "Gezien", + "views": "Weergaven", "reputation": "Reputatie", "read_more": "Lees meer", "more": "Meer", diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index 90f6f2be90..5bff87a78c 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -104,9 +104,9 @@ "stale.title": "Een nieuw onderwerp maken in de plaats?", "stale.warning": "Het onderwerp waar je op antwoord is vrij oud. Zou je graag een nieuw onderwerp maken met een referentie naar dit onderwerp in je antwoord?", "stale.create": "Maak een nieuw onderwerp", - "stale.reply_anyway": "Antwoord toch op dit onderwerp", + "stale.reply_anyway": "Reageer toch op dit onderwerp", "link_back": "Re: [%1](%2)", "spam": "Spam", - "offensive": "Onbeleefd", + "offensive": "Aanstootgevend", "custom-flag-reason": "Geef een reden voor de melding." } \ No newline at end of file diff --git a/public/language/nl/uploads.json b/public/language/nl/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/nl/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/pl/uploads.json b/public/language/pl/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/pl/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/pt_BR/uploads.json b/public/language/pt_BR/uploads.json new file mode 100644 index 0000000000..232e568e92 --- /dev/null +++ b/public/language/pt_BR/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Fazendo upload do arquivo...", + "select-file-to-upload": "Escolha um arquivo para fazer upload!", + "upload-success": "Upload realizado com sucesso!", + "maximum-file-size": "No máximo %1 kb" +} \ No newline at end of file diff --git a/public/language/ro/uploads.json b/public/language/ro/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/ro/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/ru/uploads.json b/public/language/ru/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/ru/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/rw/uploads.json b/public/language/rw/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/rw/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/sc/uploads.json b/public/language/sc/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/sc/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/sk/uploads.json b/public/language/sk/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/sk/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/sl/uploads.json b/public/language/sl/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/sl/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/sr/uploads.json b/public/language/sr/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/sr/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/sv/uploads.json b/public/language/sv/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/sv/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/th/uploads.json b/public/language/th/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/th/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/tr/uploads.json b/public/language/tr/uploads.json new file mode 100644 index 0000000000..255eb420d7 --- /dev/null +++ b/public/language/tr/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Dosya yükleniyor...", + "select-file-to-upload": "Bir dosya seç!", + "upload-success": "Dosya yüklenmesi tamamlandı!", + "maximum-file-size": "Maksimum %1 kb" +} \ No newline at end of file diff --git a/public/language/vi/uploads.json b/public/language/vi/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/vi/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/language/zh_CN/error.json b/public/language/zh_CN/error.json index 3a96f6c556..4e8ec6a25f 100644 --- a/public/language/zh_CN/error.json +++ b/public/language/zh_CN/error.json @@ -27,7 +27,7 @@ "password-too-long": "密码太长", "user-banned": "用户已禁止", "user-too-new": "抱歉,您需要等待 %1 秒后,才可以发帖!", - "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", + "blacklisted-ip": "对不起,您的IP地址已被社区禁用。如果您认为这是一个错误,请与管理员联系。", "no-category": "版块不存在", "no-topic": "主题不存在", "no-post": "帖子不存在", @@ -99,5 +99,5 @@ "no-session-found": "未登录!", "not-in-room": "用户已不在聊天室中", "no-users-in-room": "这个聊天室中没有用户", - "cant-kick-self": "You can't kick yourself from the group" + "cant-kick-self": "你不能把自己踢出群组" } \ No newline at end of file diff --git a/public/language/zh_CN/groups.json b/public/language/zh_CN/groups.json index fd58e3308e..f988de4db6 100644 --- a/public/language/zh_CN/groups.json +++ b/public/language/zh_CN/groups.json @@ -41,7 +41,7 @@ "details.hidden": "隐藏", "details.hidden_help": "启用此选项后,小组将不在小组列表中展现,成员只能通过邀请加入。", "details.delete_group": "删除小组", - "details.private_system_help": "Private groups is disabled at system level, this option does not do anything", + "details.private_system_help": "系统禁用了私有群组,这个选项不起任何作用", "event.updated": "小组信息已更新", "event.deleted": "小组 \"%1\" 已被删除", "membership.accept-invitation": "接受邀请", diff --git a/public/language/zh_CN/modules.json b/public/language/zh_CN/modules.json index 50bdd2d042..bf50d3f496 100644 --- a/public/language/zh_CN/modules.json +++ b/public/language/zh_CN/modules.json @@ -6,7 +6,7 @@ "chat.user_typing": "%1 正在输入……", "chat.user_has_messaged_you": "%1 向您发送了消息。", "chat.see_all": "查看所有对话", - "chat.mark_all_read": "Mark all chats read", + "chat.mark_all_read": "将所有聊天标为已读", "chat.no-messages": "请选择接收人,以查看聊天消息历史", "chat.no-users-in-room": "此聊天室中没有用户", "chat.recent-chats": "最近聊天", diff --git a/public/language/zh_CN/uploads.json b/public/language/zh_CN/uploads.json new file mode 100644 index 0000000000..9c86a89605 --- /dev/null +++ b/public/language/zh_CN/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "正在上传文件...", + "select-file-to-upload": "请选择需要上传的文件!", + "upload-success": "文件上传成功!", + "maximum-file-size": "最大 %1 kb" +} \ No newline at end of file diff --git a/public/language/zh_CN/user.json b/public/language/zh_CN/user.json index f434a2f284..e713189b25 100644 --- a/public/language/zh_CN/user.json +++ b/public/language/zh_CN/user.json @@ -39,7 +39,7 @@ "change_username": "更改用户名", "change_email": "更改电子邮箱", "edit": "编辑", - "edit-profile": "Edit Profile", + "edit-profile": "编辑资料", "default_picture": "缺省图标", "uploaded_picture": "已有头像", "upload_new_picture": "上传新头像", @@ -92,7 +92,7 @@ "open_links_in_new_tab": "在新标签打开外部链接", "enable_topic_searching": "启用主题内搜索", "topic_search_help": "如果启用此项,主题内搜索会替代浏览器默认的页面搜索,您将可以在整个主题内搜索,而不仅仅只搜索页面上展现的内容。", - "scroll_to_my_post": "After posting a reply, show the new post", + "scroll_to_my_post": "在提交回复之后显示新帖子", "follow_topics_you_reply_to": "关注您回复的主题", "follow_topics_you_create": "关注您创建的主题", "grouptitle": "选择展示的小组称号", diff --git a/public/language/zh_TW/uploads.json b/public/language/zh_TW/uploads.json new file mode 100644 index 0000000000..1622cb5693 --- /dev/null +++ b/public/language/zh_TW/uploads.json @@ -0,0 +1,6 @@ +{ + "uploading-file": "Uploading the file...", + "select-file-to-upload": "Select a file to upload!", + "upload-success": "File uploaded successfully!", + "maximum-file-size": "Maximum %1 kb" +} \ No newline at end of file diff --git a/public/less/global.less b/public/less/global.less index 458fa4b8e6..d606b8221c 100644 --- a/public/less/global.less +++ b/public/less/global.less @@ -14,7 +14,7 @@ &[data-state="unloaded"], &[data-state="loading"] { display: inherit; - height: 2rem; + height: 0; opacity: 0; } diff --git a/public/src/admin/admin.js b/public/src/admin/admin.js index 22258d4f66..bed154107a 100644 --- a/public/src/admin/admin.js +++ b/public/src/admin/admin.js @@ -16,21 +16,21 @@ }); } - $(window).on('action:ajaxify.contentLoaded', function(ev, data) { - var url = data.url; - - selectMenuItem(data.url); - setupRestartLinks(); - - componentHandler.upgradeDom(); - }); - $('[component="logout"]').on('click', app.logout); app.alert = launchSnackbar; configureSlidemenu(); }); + $(window).on('action:ajaxify.contentLoaded', function(ev, data) { + var url = data.url; + + selectMenuItem(data.url); + setupRestartLinks(); + + componentHandler.upgradeDom(); + }); + function setupKeybindings() { Mousetrap.bind('ctrl+shift+a r', function() { require(['admin/modules/instance'], function(instance) { diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js index 289afa0de4..d37fac64b0 100644 --- a/public/src/admin/manage/category.js +++ b/public/src/admin/manage/category.js @@ -99,6 +99,48 @@ define('admin/manage/category', [ }); }); + $('.copy-settings').on('click', function(e) { + e.preventDefault(); + socket.emit('admin.categories.getNames', function(err, categories) { + if (err) { + return app.alertError(err.message); + } + + templates.parse('admin/partials/categories/select-category', { + categories: categories + }, function(html) { + function submit() { + var formData = modal.find('form').serializeObject(); + + socket.emit('admin.categories.copySettingsFrom', {fromCid: formData['select-cid'], toCid: ajaxify.data.category.cid}, function(err) { + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('Settings Copied!'); + ajaxify.refresh(); + }); + + modal.modal('hide'); + return false; + } + + var modal = bootbox.dialog({ + title: 'Select a Category', + message: html, + buttons: { + save: { + label: 'Copy', + className: 'btn-primary', + callback: submit + } + } + }); + + modal.find('form').on('submit', submit); + }); + }); + }); + $('.upload-button').on('click', function() { var inputEl = $(this); var cid = inputEl.attr('data-cid'); diff --git a/public/src/client/search.js b/public/src/client/search.js index c6bc30e44f..6ca5b8dc41 100644 --- a/public/src/client/search.js +++ b/public/src/client/search.js @@ -118,25 +118,25 @@ define('forum/search', ['search', 'autocomplete'], function(searchModule, autoco return; } - try { - var regexStr = searchQuery.replace(/^"/, '').replace(/"$/, '').trim().split(' ').join('|'); - var regex = new RegExp('(' + regexStr + ')', 'gi'); + var regexStr = searchQuery.replace(/^"/, '').replace(/"$/, '').trim().split(' ').join('|'); + var regex = new RegExp('(' + regexStr + ')', 'gi'); - $('.search-result-text').each(function() { - var result = $(this); + $('.search-result-text p, .search-result-text h4').each(function() { + var result = $(this), nested = []; - var text = result.html().replace(regex, '$1'); - result.html(text).find('img:not(.not-responsive)').addClass('img-responsive').each(function() { - $(this).attr('src', $(this).attr('src').replace(/([\s\S]*?)<\/strong>/gi, '$1')); - }); - - result.find('a').each(function() { - $(this).attr('href', $(this).attr('href').replace(/([\s\S]*?)<\/strong>/gi, '$1')); - }); + result.find('*').each(function() { + $(this).after(''); + nested.push($('
').append($(this))); }); - } catch(e) { - return; - } + + result.html(result.html().replace(regex, '$1')); + + for (var i = 0, ii = nested.length; i < ii; i++) { + result.html(result.html().replace('', nested[i].html())); + } + }); + + $('.search-result-text').find('img:not(.not-responsive)').addClass('img-responsive'); } function handleSavePreferences() { diff --git a/public/src/client/topic.js b/public/src/client/topic.js index cd0464e9aa..9d52262676 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -222,10 +222,10 @@ define('forum/topic', [ function updateTopicTitle() { var span = components.get('navbar/title').find('span'); - if ($(window).scrollTop() > 50) { - span.html(ajaxify.data.title).show(); - } else { - span.html('').hide(); + if ($(window).scrollTop() > 50 && span.hasClass('hidden')) { + span.html(ajaxify.data.title).removeClass('hidden'); + } else if ($(window).scrollTop() <= 50 && !span.hasClass('hidden')) { + span.html('').addClass('hidden'); } if ($(window).scrollTop() > 300) { app.removeAlert('bookmark'); diff --git a/public/src/client/topic/events.js b/public/src/client/topic/events.js index 6c8f58b55b..7f769f984b 100644 --- a/public/src/client/topic/events.js +++ b/public/src/client/topic/events.js @@ -118,6 +118,8 @@ define('forum/topic/events', [ editedPostEl.find('img:not(.not-responsive)').addClass('img-responsive'); app.replaceSelfLinks(editedPostEl.find('a')); posts.wrapImagesInLinks(editedPostEl.parent()); + posts.unloadImages(editedPostEl.parent()); + posts.loadImages(); editedPostEl.fadeIn(250); $(window).trigger('action:posts.edited', data); }); diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 35e7ec5d29..696b2f51ec 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -11,7 +11,7 @@ define('forum/topic/posts', [ ], function(pagination, infinitescroll, postTools, navigator, components) { var Posts = { - _threshold: 0 + _imageLoaderTimeout: undefined }; Posts.onNewPost = function(data) { @@ -181,10 +181,13 @@ define('forum/topic/posts', [ } Posts.loadMorePosts = function(direction) { - if (!components.get('topic').length || navigator.scrollActive) { + if (!components.get('topic').length || navigator.scrollActive || Posts._infiniteScrollTimeout) { return; } + Posts._infiniteScrollTimeout = setTimeout(function() { + delete Posts._infiniteScrollTimeout; + }, 1000); var replies = components.get('post').not('[data-index=0]').not('.new'); var afterEl = direction > 0 ? replies.last() : replies.first(); var after = parseInt(afterEl.attr('data-index'), 10) || 0; @@ -204,7 +207,6 @@ define('forum/topic/posts', [ after: after, direction: direction }, function (data, done) { - indicatorEl.fadeOut(); if (data && data.posts && data.posts.length) { @@ -235,78 +237,79 @@ define('forum/topic/posts', [ }; Posts.unloadImages = function(posts) { - var images = posts.find('[component="post/content"] img:not(.not-responsive)'), - scrollTop = $(window).scrollTop(), - height = $(document).height(); + var images = posts.find('[component="post/content"] img:not(.not-responsive)'); images.each(function() { $(this).attr('data-src', $(this).attr('src')); $(this).attr('data-state', 'unloaded'); - $(this).attr('src', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'); + $(this).attr('src', 'about:blank'); }); - - $(window).scrollTop(scrollTop + $(document).height() - height); }; Posts.loadImages = function(threshold) { - /* - If threshold is defined, images loaded above this threshold will modify - the user's scroll position so they are not scrolled away from content - they were reading. Images loaded below this threshold will push down content. + if (Posts._imageLoaderTimeout) { + clearTimeout(Posts._imageLoaderTimeout); + } - If no threshold is defined, loaded images will push down content, as per - default - */ - Posts._threshold = threshold; + Posts._imageLoaderTimeout = setTimeout(function() { + /* + If threshold is defined, images loaded above this threshold will modify + the user's scroll position so they are not scrolled away from content + they were reading. Images loaded below this threshold will push down content. - var images = components.get('post/content').find('img[data-state="unloaded"]'), - visible = images.filter(function() { - return utils.isElementInViewport(this); - }), - scrollTop = $(window).scrollTop(), - adjusting = false, - adjustQueue = [], - adjustPosition = function() { - adjusting = true; - oldHeight = document.body.clientHeight; + If no threshold is defined, loaded images will push down content, as per + default + */ - // Display the image - $(this).attr('data-state', 'loaded'); - newHeight = document.body.clientHeight; + var images = components.get('post/content').find('img[data-state="unloaded"]'), + visible = images.filter(function() { + return utils.isElementInViewport(this); + }), + scrollTop = $(window).scrollTop(), + adjusting = false, + adjustQueue = [], + adjustPosition = function() { + adjusting = true; + oldHeight = document.body.clientHeight; - var imageRect = this.getBoundingClientRect(); - if (imageRect.top < Posts._threshold) { - scrollTop = scrollTop + (newHeight - oldHeight); - $(window).scrollTop(scrollTop); - } - - if (adjustQueue.length) { - adjustQueue.pop()(); - } else { - adjusting = false; - } - }, - oldHeight, newHeight; - - // For each image, reset the source and adjust scrollTop when loaded - visible.attr('data-state', 'loading'); - visible.each(function(index, image) { - image = $(image); - - image.on('load', function() { - if (!adjusting) { - adjustPosition.call(this); - } else { - adjustQueue.push(adjustPosition.bind(this)); + // Display the image + $(this).attr('data-state', 'loaded'); + newHeight = document.body.clientHeight; + + var imageRect = this.getBoundingClientRect(); + if (imageRect.top < threshold) { + scrollTop = scrollTop + (newHeight - oldHeight); + $(window).scrollTop(scrollTop); + } + + if (adjustQueue.length) { + adjustQueue.pop()(); + } else { + adjusting = false; + } + }, + oldHeight, newHeight; + + // For each image, reset the source and adjust scrollTop when loaded + visible.attr('data-state', 'loading'); + visible.each(function(index, image) { + image = $(image); + + image.on('load', function() { + if (!adjusting) { + adjustPosition.call(this); + } else { + adjustQueue.push(adjustPosition.bind(this)); + } + }); + + image.attr('src', image.attr('data-src')); + if (image.parent().attr('href')) { + image.parent().attr('href', image.attr('data-src')); } + image.removeAttr('data-src'); }); - - image.attr('src', image.attr('data-src')); - if (image.parent().attr('href')) { - image.parent().attr('href', image.attr('data-src')); - } - image.removeAttr('data-src'); - }); + }, 250); }; Posts.wrapImagesInLinks = function(posts) { @@ -321,13 +324,10 @@ define('forum/topic/posts', [ Posts.showBottomPostBar = function() { var mainPost = components.get('post', 'index', 0); var posts = $('[component="post"]'); - var height = $(document).height(); if (!!mainPost.length && posts.length > 1 && $('.post-bar').length < 2) { $('.post-bar').clone().appendTo(mainPost); - $(window).scrollTop($(window).scrollTop() + $(document).height() - height); } else if (mainPost.length && posts.length < 2) { mainPost.find('.post-bar').remove(); - $(window).scrollTop($(window).scrollTop() - $(document).height() - height); } }; diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index dd15d0dab6..fda87711fb 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -1,6 +1,6 @@ ;(function(exports) { "use strict"; - /* globals define, utils */ + /* globals define, utils, config */ // export the class if we are in a Node-like system. if (typeof module === 'object' && module.exports === exports) { @@ -100,13 +100,15 @@ return style.join('; ') + ';'; }; - helpers.generateChildrenCategories = function(category, relative_path) { + helpers.generateChildrenCategories = function(category) { var html = ''; + var relative_path = (typeof config !== 'undefined' ? config.relative_path : require('nconf').get('relative_path')); + category.children.forEach(function(child) { if (!child) { return; } - var link = child.link ? child.link : ('/category/' + child.slug); + var link = child.link ? child.link : (relative_path + '/category/' + child.slug); html += '' + '' + '' + diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index 73ea9b8946..3d65f6b8a0 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -103,7 +103,10 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com index = parseInt(els.first().attr('data-index'), 10) + 1; } - var middleOfViewport = $(window).scrollTop() + $(window).height() / 2; + var scrollTop = $(window).scrollTop(); + var windowHeight = $(window).height(); + var documentHeight = $(document).height(); + var middleOfViewport = scrollTop + windowHeight / 2; var previousDistance = Number.MAX_VALUE; els.each(function() { var distanceToMiddle = Math.abs(middleOfViewport - $(this).offset().top); @@ -118,12 +121,24 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com } }); - // If a threshold is undefined, try to determine one based on new index - if (threshold === undefined && ajaxify.currentPage.startsWith('topic')) { - var anchorEl = components.get('post/anchor', index - 1), - anchorRect = anchorEl.get(0).getBoundingClientRect(); + var atTop = scrollTop === 0 && parseInt(els.first().attr('data-index'), 10) === 0, + nearBottom = scrollTop + windowHeight > documentHeight - 100 && parseInt(els.last().attr('data-index'), 10) === count - 1; - threshold = anchorRect.top; + if (atTop) { + index = 1; + } else if (nearBottom) { + index = count; + } + + // If a threshold is undefined, try to determine one based on new index + if (threshold === undefined) { + if (atTop) { + threshold = 0; + } else { + var anchorEl = components.get('post/anchor', index - 1); + var anchorRect = anchorEl.get(0).getBoundingClientRect(); + threshold = anchorRect.top; + } } if (typeof navigator.callback === 'function') { diff --git a/public/src/modules/uploader.js b/public/src/modules/uploader.js index 575508b2b9..6a0d7f161a 100644 --- a/public/src/modules/uploader.js +++ b/public/src/modules/uploader.js @@ -16,9 +16,10 @@ define('uploader', ['csrf', 'translator'], function(csrf, translator) { }; module.show = function(data, callback) { + var fileSize = data.hasOwnProperty('fileSize') && data.fileSize !== undefined ? parseInt(data.fileSize, 10) : false; parseModal({ showHelp: data.hasOwnProperty('showHelp') && data.showHelp !== undefined ? data.showHelp : true, - fileSize: data.hasOwnProperty('fileSize') && data.fileSize !== undefined ? parseInt(data.fileSize, 10) : false, + fileSize: fileSize, title: data.title || '[[global:upload_file]]', description: data.description || '', button: data.button || '[[global:upload]]', @@ -40,13 +41,17 @@ define('uploader', ['csrf', 'translator'], function(csrf, translator) { }); uploadForm.submit(function() { - onSubmit(uploadModal, callback); + onSubmit(uploadModal, fileSize, callback); return false; }); }); }; - function onSubmit(uploadModal, callback) { + module.hideAlerts = function(modal) { + $(modal).find('#alert-status, #alert-success, #alert-error, #upload-progress-box').addClass('hide'); + }; + + function onSubmit(uploadModal, fileSize, callback) { function showAlert(type, message) { module.hideAlerts(uploadModal); uploadModal.find('#alert-' + type).translateText(message).removeClass('hide'); @@ -57,9 +62,13 @@ define('uploader', ['csrf', 'translator'], function(csrf, translator) { uploadModal.find('#upload-progress-bar').css('width', '0%'); uploadModal.find('#upload-progress-box').show().removeClass('hide'); - if (!uploadModal.find('#fileInput').val()) { + var fileInput = uploadModal.find('#fileInput'); + if (!fileInput.val()) { return showAlert('error', '[[uploads:select-file-to-upload]]'); } + if (!hasValidFileSize(fileInput[0], fileSize)) { + return showAlert('error', '[[error:file-too-big, ' + fileSize + ']]'); + } uploadModal.find('#uploadForm').ajaxSubmit({ headers: { @@ -107,9 +116,12 @@ define('uploader', ['csrf', 'translator'], function(csrf, translator) { return response; } - module.hideAlerts = function(modal) { - $(modal).find('#alert-status, #alert-success, #alert-error, #upload-progress-box').addClass('hide'); - }; + function hasValidFileSize(fileElement, maxSize) { + if (window.FileReader && maxSize) { + return fileElement.files[0].size <= maxSize * 1000; + } + return true; + } return module; }); diff --git a/src/categories/create.js b/src/categories/create.js index 69d1f4dcd8..7f1f3955f7 100644 --- a/src/categories/create.js +++ b/src/categories/create.js @@ -1,10 +1,12 @@ 'use strict'; -var async = require('async'), - db = require('../database'), - privileges = require('../privileges'), - plugins = require('../plugins'), - utils = require('../../public/src/utils'); +var async = require('async'); + +var db = require('../database'); +var privileges = require('../privileges'); +var groups = require('../groups'); +var plugins = require('../plugins'); +var utils = require('../../public/src/utils'); module.exports = function(Categories) { @@ -17,6 +19,7 @@ module.exports = function(Categories) { db.incrObjectField('global', 'nextCid', next); }, function(cid, next) { + data.name = data.name || 'Category ' + cid; var slug = cid + '/' + utils.slugify(data.name); var order = data.order || cid; // If no order provided, place it at the end var colours = Categories.assignColours(); @@ -58,6 +61,12 @@ module.exports = function(Categories) { ], next); }, function(results, next) { + if (data.cloneFromCid && parseInt(data.cloneFromCid, 10)) { + return Categories.copySettingsFrom(data.cloneFromCid, category.cid, next); + } + next(null, category); + }, + function(category, next) { plugins.fireHook('action:category.create', category); next(null, category); } @@ -65,10 +74,94 @@ module.exports = function(Categories) { }; Categories.assignColours = function() { - var backgrounds = ['#AB4642', '#DC9656', '#F7CA88', '#A1B56C', '#86C1B9', '#7CAFC2', '#BA8BAF', '#A16946'], - text = ['#fff', '#fff', '#333', '#fff', '#333', '#fff', '#fff', '#fff'], - index = Math.floor(Math.random() * backgrounds.length); + var backgrounds = ['#AB4642', '#DC9656', '#F7CA88', '#A1B56C', '#86C1B9', '#7CAFC2', '#BA8BAF', '#A16946']; + var text = ['#fff', '#fff', '#333', '#fff', '#333', '#fff', '#fff', '#fff']; + var index = Math.floor(Math.random() * backgrounds.length); return [backgrounds[index], text[index]]; }; + + Categories.copySettingsFrom = function(fromCid, toCid, callback) { + var destination; + async.waterfall([ + function (next) { + async.parallel({ + source: async.apply(db.getObject, 'category:' + fromCid), + destination: async.apply(db.getObject, 'category:' + toCid) + }, next); + }, + function (results, next) { + if (!results.source) { + return next(new Error('[[error:invalid-cid]]')); + } + destination = results.destination; + + var tasks = []; + if (parseInt(results.source.parentCid, 10)) { + tasks.push(async.apply(db.sortedSetAdd, 'cid:' + results.source.parentCid + ':children', results.source.order, toCid)); + } + + if (destination && parseInt(destination.parentCid, 10)) { + tasks.push(async.apply(db.sortedSetRemove, 'cid:' + destination.parentCid + ':children', toCid)); + } + + destination.description = results.source.description; + destination.descriptionParsed = results.source.descriptionParsed; + destination.icon = results.source.icon; + destination.bgColor = results.source.bgColor; + destination.color = results.source.color; + destination.link = results.source.link; + destination.numRecentReplies = results.source.numRecentReplies; + destination.class = results.source.class; + destination.imageClass = results.source.imageClass; + destination.parentCid = results.source.parentCid || 0; + + tasks.push(async.apply(db.setObject, 'category:' + toCid, destination)); + + async.series(tasks, next); + }, + function (results, next) { + Categories.copyPrivilegesFrom(fromCid, toCid, next); + } + ], function(err) { + callback(err, destination); + }); + }; + + Categories.copyPrivilegesFrom = function(fromCid, toCid, callback) { + var privilegeList = [ + 'find', 'read', 'topics:create', 'topics:reply', 'purge', 'mods', + 'groups:find', 'groups:read', 'groups:topics:create', 'groups:topics:reply', 'groups:purge', 'groups:moderate' + ]; + + async.each(privilegeList, function(privilege, next) { + copyPrivilege(privilege, fromCid, toCid, next); + }, callback); + }; + + function copyPrivilege(privilege, fromCid, toCid, callback) { + async.waterfall([ + function (next) { + db.getSortedSetRange('group:cid:' + toCid + ':privileges:' + privilege + ':members', 0, -1, next); + }, + function (currentMembers, next) { + async.eachSeries(currentMembers, function(member, next) { + groups.leave('cid:' + toCid + ':privileges:' + privilege, member, next); + }, next); + }, + function (next) { + db.getSortedSetRange('group:cid:' + fromCid + ':privileges:' + privilege + ':members', 0, -1, next); + }, + function (members, next) { + if (!members || !members.length) { + return callback(); + } + + async.eachSeries(members, function(member, next) { + groups.join('cid:' + toCid + ':privileges:' + privilege, member, next); + }, next); + } + ], callback); + } + }; diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js index 0b180be686..b5b020c118 100644 --- a/src/controllers/accounts/settings.js +++ b/src/controllers/accounts/settings.js @@ -33,7 +33,7 @@ settingsController.get = function(req, res, callback) { user.getSettings(userData.uid, next); }, userGroups: function(next) { - groups.getUserGroups([userData.uid], next); + groups.getUserGroupsFromSet('groups:createtime', [userData.uid], next); }, languages: function(next) { languages.list(next); @@ -49,7 +49,9 @@ settingsController.get = function(req, res, callback) { }, function(results, next) { userData.settings = results.settings; - userData.userGroups = results.userGroups[0]; + userData.userGroups = results.userGroups[0].filter(function(group) { + return group && group.userTitleEnabled && !groups.isPrivilegeGroup(group.name) && group.name !== 'registered-users'; + }); userData.languages = results.languages; userData.homePageRoutes = results.homePageRoutes; userData.ips = results.ips; diff --git a/src/controllers/admin/users.js b/src/controllers/admin/users.js index 3651767153..7e5bd530d6 100644 --- a/src/controllers/admin/users.js +++ b/src/controllers/admin/users.js @@ -77,10 +77,17 @@ usersController.banned = function(req, res, next) { }; usersController.registrationQueue = function(req, res, next) { + var page = parseInt(req.query.page, 10) || 1; + var itemsPerPage = 20; + var start = (page - 1) * 20; + var stop = start + itemsPerPage - 1; var invitations; async.parallel({ + registrationQueueCount: function(next) { + db.sortedSetCard('registration:queue', next); + }, users: function(next) { - user.getRegistrationQueue(0, -1, next); + user.getRegistrationQueue(start, stop, next); }, invites: function(next) { async.waterfall([ @@ -118,6 +125,8 @@ usersController.registrationQueue = function(req, res, next) { if (err) { return next(err); } + var pageCount = Math.max(1, Math.ceil(data.registrationQueueCount / itemsPerPage)); + data.pagination = pagination.create(page, pageCount); res.render('admin/manage/registration', data); }); }; @@ -146,7 +155,7 @@ function getUsers(set, section, req, res, next) { var data = { users: results.users, page: page, - pageCount: Math.ceil(results.count / resultsPerPage) + pageCount: Math.max(1, Math.ceil(results.count / resultsPerPage)) }; data[section] = true; render(req, res, data); diff --git a/src/groups.js b/src/groups.js index 10d9137b8c..2df5dc3ce2 100644 --- a/src/groups.js +++ b/src/groups.js @@ -425,9 +425,13 @@ var utils = require('../public/src/utils'); }; Groups.getUserGroups = function(uids, callback) { + Groups.getUserGroupsFromSet('groups:visible:createtime', uids, callback); + }; + + Groups.getUserGroupsFromSet = function (set, uids, callback) { async.waterfall([ function(next) { - db.getSortedSetRevRange('groups:visible:createtime', 0, -1, next); + db.getSortedSetRevRange(set, 0, -1, next); }, function(groupNames, next) { var groupSets = groupNames.map(function(name) { diff --git a/src/groups/membership.js b/src/groups/membership.js index 18327579e5..747fa9d3d7 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -93,7 +93,8 @@ module.exports = function(Groups) { bodyShort: '[[groups:request.notification_title, ' + username + ']]', bodyLong: '[[groups:request.notification_text, ' + username + ', ' + groupName + ']]', nid: 'group:' + groupName + ':uid:' + uid + ':request', - path: '/groups/' + utils.slugify(groupName) + path: '/groups/' + utils.slugify(groupName), + from: uid }, next); }, owners: function(next) { diff --git a/src/meta.js b/src/meta.js index 716d90e9cb..ffc85c98bf 100644 --- a/src/meta.js +++ b/src/meta.js @@ -61,20 +61,16 @@ var async = require('async'), async.apply(plugins.clearRequireCache), async.apply(plugins.reload), async.apply(plugins.reloadRoutes), + async.apply(Meta.css.minify), + async.apply(Meta.js.minify, 'nodebb.min.js'), + async.apply(Meta.js.minify, 'acp.min.js'), + async.apply(Meta.sounds.init), + async.apply(Meta.templates.compile), + async.apply(auth.reloadRoutes), function(next) { - async.parallel([ - async.apply(Meta.js.minify, 'nodebb.min.js'), - async.apply(Meta.js.minify, 'acp.min.js'), - async.apply(Meta.css.minify), - async.apply(Meta.sounds.init), - async.apply(Meta.templates.compile), - async.apply(auth.reloadRoutes), - function(next) { - Meta.config['cache-buster'] = utils.generateUUID(); - templates.flush(); - next(); - } - ], next); + Meta.config['cache-buster'] = utils.generateUUID(); + templates.flush(); + next(); } ], function(err) { if (!err) { diff --git a/src/meta/css.js b/src/meta/css.js index 9dd9849d76..12c5d49c20 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -43,7 +43,8 @@ module.exports = function(Meta) { path.join(__dirname, '../../public/vendor/fontawesome/less'), path.join(__dirname, '../../public/vendor/bootstrap/less') ], - source = '@import "font-awesome";'; + source = '@import "font-awesome";', + acpSource = '@import "font-awesome";'; plugins.lessFiles = filterMissingFiles(plugins.lessFiles); plugins.cssFiles = filterMissingFiles(plugins.cssFiles); @@ -67,21 +68,21 @@ module.exports = function(Meta) { source += '\n@import (inline) "..' + path.sep + '..' + path.sep + 'public/vendor/jquery/css/smoothness/jquery-ui-1.10.4.custom.min.css";'; source += '\n@import (inline) "..' + path.sep + '..' + path.sep + 'public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";'; - source += '\n@import (inline) "..' + path.sep + '..' + path.sep + 'public/vendor/colorpicker/colorpicker.css";'; source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/flags.less";'; source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/blacklist.less";'; source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/generics.less";'; source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/mixins.less";'; source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/global.less";'; + source = '@import "./theme";\n' + source; - var acpSource = '\n@import "..' + path.sep + 'public/less/admin/admin";\n' + source; + acpSource += '\n@import "..' + path.sep + 'public/less/admin/admin";\n'; acpSource += '\n@import "..' + path.sep + 'public/less/generics.less";'; acpSource += '\n@import (inline) "..' + path.sep + 'public/vendor/colorpicker/colorpicker.css";'; - source = '@import "./theme";\n' + source; var fromFile = nconf.get('from-file') || ''; - async.parallel([ + + async.series([ function(next) { if (fromFile.match('clientLess')) { winston.info('[minifier] Compiling front-end LESS files skipped'); @@ -149,7 +150,7 @@ module.exports = function(Meta) { }); } - Meta.css.commitToFile = function(filename) { + Meta.css.commitToFile = function(filename, callback) { var file = (filename === 'acpCache' ? 'admin' : 'stylesheet') + '.css'; fs.writeFile(path.join(__dirname, '../../public/' + file), Meta.css[filename], function(err) { @@ -159,6 +160,8 @@ module.exports = function(Meta) { winston.error('[meta/css] ' + err.message); process.exit(0); } + + callback(); }); }; @@ -184,7 +187,6 @@ module.exports = function(Meta) { return; } - winston.verbose('[meta/css] Running PostCSS Plugins'); postcss([ autoprefixer ]).process(lessOutput.css).then(function (result) { result.warnings().forEach(function (warn) { winston.verbose(warn.toString()); @@ -194,7 +196,11 @@ module.exports = function(Meta) { // Save the compiled CSS in public/ so things like nginx can serve it if (nconf.get('isPrimary') === 'true') { - Meta.css.commitToFile(destination); + return Meta.css.commitToFile(destination, function() { + if (typeof callback === 'function') { + callback(null, result.css); + } + }); } if (typeof callback === 'function') { diff --git a/src/meta/js.js b/src/meta/js.js index f2fabac6ac..740b5e08ee 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -89,6 +89,8 @@ module.exports = function(Meta) { return; } + winston.verbose('[meta/js] Minifying ' + target); + var forkProcessParams = setupDebugging(); var minifier = Meta.js.minifierProc = fork('minifier.js', [], forkProcessParams); @@ -110,20 +112,19 @@ module.exports = function(Meta) { winston.verbose('[meta/js] ' + target + ' minification complete'); minifier.kill(); - if (process.send) { + if (process.send && Meta.js.target['nodebb.min.js'] && Meta.js.target['acp.min.js']) { process.send({ action: 'js-propagate', - cache: Meta.js.target[target].cache, - map: Meta.js.target[target].map, - target: target + data: Meta.js.target }); } - Meta.js.commitToFile(target); + Meta.js.commitToFile(target, function() { + if (typeof callback === 'function') { + callback(); + } + }); - if (typeof callback === 'function') { - callback(); - } break; case 'error': winston.error('[meta/js] Could not compile ' + target + ': ' + message.message); @@ -185,15 +186,15 @@ module.exports = function(Meta) { } }; - Meta.js.commitToFile = function(target) { + Meta.js.commitToFile = function(target, callback) { fs.writeFile(path.join(__dirname, '../../public/' + target), Meta.js.target[target].cache, function (err) { if (err) { winston.error('[meta/js] ' + err.message); process.exit(0); } - winston.verbose('[meta/js] ' + target + ' committed to disk.'); emitter.emit('meta:js.compiled'); + callback(); }); }; diff --git a/src/notifications.js b/src/notifications.js index 498337a7db..94cb5313b8 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -472,7 +472,7 @@ var async = require('async'), return true; } - return !(notifObj.mergeId === (mergeId + '|' + differentiator) && idx !== modifyIndex); + return !(notifObj.mergeId === (mergeId + (differentiator ? '|' + differentiator : '')) && idx !== modifyIndex); }); }); diff --git a/src/socket.io/admin/categories.js b/src/socket.io/admin/categories.js index 288e395837..3b35847366 100644 --- a/src/socket.io/admin/categories.js +++ b/src/socket.io/admin/categories.js @@ -1,16 +1,16 @@ "use strict"; -var async = require('async'), +var async = require('async'); - db = require('../../database'), - groups = require('../../groups'), - categories = require('../../categories'), - privileges = require('../../privileges'), - plugins = require('../../plugins'), - Categories = {}; +var db = require('../../database'); +var groups = require('../../groups'); +var categories = require('../../categories'); +var privileges = require('../../privileges'); +var plugins = require('../../plugins'); +var Categories = {}; Categories.create = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } @@ -46,7 +46,7 @@ Categories.purge = function(socket, cid, callback) { }; Categories.update = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } @@ -108,4 +108,8 @@ function copyPrivilegesToChildrenRecursive(category, privilegeGroups, callback) }); } +Categories.copySettingsFrom = function(socket, data, callback) { + categories.copySettingsFrom(data.fromCid, data.toCid, callback); +}; + module.exports = Categories; \ No newline at end of file diff --git a/src/user/approval.js b/src/user/approval.js index 41237043eb..94e0f097e5 100644 --- a/src/user/approval.js +++ b/src/user/approval.js @@ -158,7 +158,7 @@ module.exports = function(User) { return user; }).filter(Boolean); - async.mapLimit(users, 20, function(user, next) { + async.map(users, function(user, next) { if (!user) { return next(null, user); } diff --git a/src/user/digest.js b/src/user/digest.js index cc2c768b71..81b6ea0220 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -1,17 +1,16 @@ "use strict"; -var async = require('async'), - winston = require('winston'), - nconf = require('nconf'), +var async = require('async'); +var winston = require('winston'); +var nconf = require('nconf'); - db = require('../database'), - meta = require('../meta'), - user = require('../user'), - topics = require('../topics'), - batch = require('../batch'), - plugins = require('../plugins'), - emailer = require('../emailer'), - utils = require('../../public/src/utils'); +var db = require('../database'); +var meta = require('../meta'); +var user = require('../user'); +var topics = require('../topics'); +var plugins = require('../plugins'); +var emailer = require('../emailer'); +var utils = require('../../public/src/utils'); (function(Digest) { Digest.execute = function(interval) { @@ -100,7 +99,7 @@ var async = require('async'), } emailer.send('digest', userObj.uid, { - subject: '[' + meta.config.title + '] Digest for ' + now.getFullYear()+ '/' + (now.getMonth()+1) + '/' + now.getDate(), + subject: '[' + meta.config.title + '] [[email:digest.subject, ' + (now.getFullYear()+ '/' + (now.getMonth()+1) + '/' + now.getDate()) + ']]', username: userObj.username, userslug: userObj.userslug, url: nconf.get('url'), diff --git a/src/views/admin/manage/category.tpl b/src/views/admin/manage/category.tpl index ab7540d4fd..814b319913 100644 --- a/src/views/admin/manage/category.tpl +++ b/src/views/admin/manage/category.tpl @@ -105,7 +105,8 @@
- +
+
diff --git a/src/views/admin/manage/registration.tpl b/src/views/admin/manage/registration.tpl index f4dbe697ef..d293d8cfa4 100644 --- a/src/views/admin/manage/registration.tpl +++ b/src/views/admin/manage/registration.tpl @@ -55,6 +55,8 @@ + +
diff --git a/src/views/admin/partials/categories/create.tpl b/src/views/admin/partials/categories/create.tpl index 52e218fc0e..d4c551f1bf 100644 --- a/src/views/admin/partials/categories/create.tpl +++ b/src/views/admin/partials/categories/create.tpl @@ -12,4 +12,14 @@
+ +
+ + +
\ No newline at end of file diff --git a/src/views/admin/partials/categories/select-category.tpl b/src/views/admin/partials/categories/select-category.tpl new file mode 100644 index 0000000000..7e1f9f0d28 --- /dev/null +++ b/src/views/admin/partials/categories/select-category.tpl @@ -0,0 +1,10 @@ +
+
+ + +
+
\ No newline at end of file diff --git a/src/webserver.js b/src/webserver.js index 1db202e520..057c9a5e8a 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -85,7 +85,7 @@ function initializeNodeBB(callback) { plugins.init(app, middleware, next); }, function(next) { - async.parallel([ + async.series([ async.apply(meta.templates.compile), async.apply(!skipJS ? meta.js.minify : meta.js.getFromFile, 'nodebb.min.js'), async.apply(!skipJS ? meta.js.minify : meta.js.getFromFile, 'acp.min.js'),