Merge commit 'cdbe535e13557d57b37b84ad59c449e4fbbada04' into weekly

This commit is contained in:
NodeBB Misty
2016-04-04 16:00:17 -04:00
89 changed files with 737 additions and 227 deletions

View File

@@ -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/<lang>/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

View File

@@ -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/**'
]
}
}
});

4
app.js
View File

@@ -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;

View File

@@ -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':

View File

@@ -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"
}
]
}
}

View File

@@ -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"
}

View File

@@ -0,0 +1,6 @@
{
"uploading-file": "Качване на файла…",
"select-file-to-upload": "Изберете файл за качване!",
"upload-success": "Файлът е качен успешно!",
"maximum-file-size": "Най-много %1 КБ"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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",

View File

@@ -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"
}

View File

@@ -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",

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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": "스스로 이 그룹을 탈퇴할 수 없습니다."
}

View File

@@ -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": "초대 수락",

View File

@@ -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": "최근 대화 내용",

View File

@@ -0,0 +1,6 @@
{
"uploading-file": "파일 업로드 중...",
"select-file-to-upload": "업로드할 파일을 선택해 주세요!",
"upload-success": "파일이 성공적으로 업로드 되었습니다!",
"maximum-file-size": "최대 %1 kb"
}

View File

@@ -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": "표시할 그룹 이름을 선택하세요.",

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -52,7 +52,7 @@
"best": "Beste",
"upvoted": "Omhoog gestemd",
"downvoted": "Omlaag gestemd",
"views": "Gezien",
"views": "Weergaven",
"reputation": "Reputatie",
"read_more": "Lees meer",
"more": "Meer",

View File

@@ -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."
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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": "你不能把自己踢出群组"
}

View File

@@ -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": "接受邀请",

View File

@@ -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": "最近聊天",

View File

@@ -0,0 +1,6 @@
{
"uploading-file": "正在上传文件...",
"select-file-to-upload": "请选择需要上传的文件!",
"upload-success": "文件上传成功!",
"maximum-file-size": "最大 %1 kb"
}

View File

@@ -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": "选择展示的小组称号",

View File

@@ -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"
}

View File

@@ -14,7 +14,7 @@
&[data-state="unloaded"], &[data-state="loading"] {
display: inherit;
height: 2rem;
height: 0;
opacity: 0;
}

View File

@@ -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) {

View File

@@ -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');

View File

@@ -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, '<strong>$1</strong>');
result.html(text).find('img:not(.not-responsive)').addClass('img-responsive').each(function() {
$(this).attr('src', $(this).attr('src').replace(/<strong>([\s\S]*?)<\/strong>/gi, '$1'));
});
result.find('a').each(function() {
$(this).attr('href', $(this).attr('href').replace(/<strong>([\s\S]*?)<\/strong>/gi, '$1'));
});
result.find('*').each(function() {
$(this).after('<!-- ' + nested.length + ' -->');
nested.push($('<div />').append($(this)));
});
} catch(e) {
return;
}
result.html(result.html().replace(regex, '<strong>$1</strong>'));
for (var i = 0, ii = nested.length; i < ii; i++) {
result.html(result.html().replace('<!-- ' + i + ' -->', nested[i].html()));
}
});
$('.search-result-text').find('img:not(.not-responsive)').addClass('img-responsive');
}
function handleSavePreferences() {

View File

@@ -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');

View File

@@ -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);
});

View File

@@ -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);
}
};

View File

@@ -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 += '<a href="' + link + '">' +
'<span class="fa-stack fa-lg">' +
'<i style="color:' + child.bgColor + ';" class="fa fa-circle fa-stack-2x"></i>' +

View File

@@ -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') {

View File

@@ -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;
});

View File

@@ -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);
}
};

View File

@@ -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;

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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') {

View File

@@ -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();
});
};

View File

@@ -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);
});
});

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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'),

View File

@@ -105,7 +105,8 @@
<button type="button" class="btn btn-default btn-block <!-- IF category.parent.name -->hide<!-- ENDIF category.parent.name -->" data-action="setParent"><i class="fa fa-sitemap"></i> (None)</button>
</div>
</fieldset>
<hr/>
<button class="btn btn-info btn-block copy-settings"><i class="fa fa-files-o"></i> Copy Settings From</button>
<hr />
<button class="btn btn-danger btn-block purge"><i class="fa fa-eraser"></i> Purge Category</button>
</div>

View File

@@ -55,6 +55,8 @@
</tr>
<!-- END users -->
</table>
<!-- IMPORT partials/paginator.tpl -->
</div>
<div class="invitations panel panel-success">

View File

@@ -12,4 +12,14 @@
<!-- END categories -->
</select>
</div>
<div class="form-group">
<label for="cloneFromCid">(Optional) Clone Settings From Category</label>
<select class="form-control" name="cloneFromCid" id="cloneFromCid">
<option value=""></option>
<!-- BEGIN categories -->
<option value="{categories.cid}">{categories.name}</option>
<!-- END categories -->
</select>
</div>
</form>

View File

@@ -0,0 +1,10 @@
<form type="form">
<div class="form-group">
<label for="select-cid">Select Category</label>
<select class="form-control" name="select-cid" id="select-cid">
<!-- BEGIN categories -->
<option value="{categories.cid}">{categories.name}</option>
<!-- END categories -->
</select>
</div>
</form>

View File

@@ -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'),