diff --git a/public/language/es/global.json b/public/language/es/global.json index 7bb6ec6d41..21c502619a 100644 --- a/public/language/es/global.json +++ b/public/language/es/global.json @@ -44,12 +44,12 @@ "alert.banned.message": "Estás baneado, serás desconectado!", "alert.unfollow": "Ya no estás siguiendo a %1!", "alert.follow": "Estás siguiendo a %1!", - "posts": "Publicaciones", + "posts": "Posts", "views": "Visitas", "posted": "publicado", "in": "en", "recentposts": "Publicaciones Recientes", - "recentips": "Recently Logged In IPs", + "recentips": "Conexions recientes de estas IP's", "online": "Conectado", "away": "No disponible", "dnd": "No molestar", diff --git a/public/language/es/pages.json b/public/language/es/pages.json index 603c8ace7a..fab5dc5001 100644 --- a/public/language/es/pages.json +++ b/public/language/es/pages.json @@ -8,7 +8,7 @@ "user.edit": "Editando \"%1\"", "user.following": "Gente que sigue %1 ", "user.followers": "Seguidores de %1", - "user.posts": "Posts made by %1", + "user.posts": "Posteos de %1", "user.favourites": "Publicaciones favoritas de %1 ", "user.settings": "Preferencias del Usuario" } \ No newline at end of file diff --git a/public/language/es/topic.json b/public/language/es/topic.json index ce34ffa2a7..85e1488472 100644 --- a/public/language/es/topic.json +++ b/public/language/es/topic.json @@ -11,7 +11,7 @@ "reply": "Responder", "edit": "Editar", "delete": "Borrar", - "restore": "Restore", + "restore": "Restaurar", "move": "Mover", "fork": "Bifurcar", "banned": "baneado", @@ -19,15 +19,15 @@ "share": "Compartir", "tools": "Herramientas", "flag": "Reportar", - "bookmark_instructions": "Click here to return to your last position or close to discard.", + "bookmark_instructions": "Click aqui para restablecer la ultima posicion del post o cierralo para descartar cambios.", "flag_title": "Reportar esta publicación a los moderadores", "deleted_message": "Este tema ha sido borrado. Solo los miembros con privilegios pueden verlo.", "following_topic.title": "Siguendo tema", "following_topic.message": "Ahora recibiras notificaciones cuando alguien publique en este tema.", "not_following_topic.title": "No sigues este tema", "not_following_topic.message": "No recibiras notificaciones de este tema.", - "login_to_subscribe": "Please register or log in in order to subscribe to this topic.", - "markAsUnreadForAll.success": "Topic marked as unread for all.", + "login_to_subscribe": "Por favor, conectate para subscribirte a este tema.", + "markAsUnreadForAll.success": "Marcar todo como leeido.", "watch": "Seguir", "share_this_post": "Compartir este post", "thread_tools.title": "Herramientas del Tema", @@ -66,17 +66,17 @@ "composer.title_placeholder": "Ingresa el titulo de tu tema", "composer.write": "Escribe", "composer.preview": "Previsualización", - "composer.help": "Help", + "composer.help": "Ayuda", "composer.discard": "Descartar", "composer.submit": "Enviar", "composer.replying_to": "Respondiendo a", "composer.new_topic": "Nuevo Tema", - "composer.uploading": "uploading...", - "composer.thumb_url_label": "Paste a topic thumbnail URL", - "composer.thumb_title": "Add a thumbnail to this topic", - "composer.thumb_url_placeholder": "http://example.com/thumb.png", - "composer.thumb_file_label": "Or upload a file", - "composer.thumb_remove": "Clear fields", + "composer.uploading": "cargando...", + "composer.thumb_url_label": "Agregar imagen destacada a este tema.", + "composer.thumb_title": "Agregar miniatura a este tema.", + "composer.thumb_url_placeholder": "http://ejemplo.com/mini.png", + "composer.thumb_file_label": "Cargar una foto", + "composer.thumb_remove": "Limpiar campos.", "composer.drag_and_drop_images": "Arrastra las imagenes aqui", "composer.upload_instructions": "Carga tus imagenes con solo arrastrarlas aqui." } \ No newline at end of file diff --git a/public/language/fr/pages.json b/public/language/fr/pages.json index e20ff0444c..b30a1c004a 100644 --- a/public/language/fr/pages.json +++ b/public/language/fr/pages.json @@ -8,7 +8,7 @@ "user.edit": "Edite \"%1\"", "user.following": "Personnes que %1 suit", "user.followers": "Personnes qui suivent %1", - "user.posts": "Posts made by %1", + "user.posts": "Message écrit par %1", "user.favourites": "Messages favoris de %1", "user.settings": "Préférences Utilisateur" } \ No newline at end of file diff --git a/public/language/fr/topic.json b/public/language/fr/topic.json index cbe1843ca5..17b3be252d 100644 --- a/public/language/fr/topic.json +++ b/public/language/fr/topic.json @@ -11,7 +11,7 @@ "reply": "Répondre", "edit": "Editer", "delete": "Supprimer", - "restore": "Restore", + "restore": "Restaurer", "move": "Déplacer", "fork": "Scinder", "banned": "bannis", @@ -19,15 +19,15 @@ "share": "Partager", "tools": "Outils", "flag": "Signaler", - "bookmark_instructions": "Click here to return to your last position or close to discard.", + "bookmark_instructions": "Cliquer ici pour retourner à votre dernière position ou fermer pour ignorer.", "flag_title": "Signaler ce post pour modération", "deleted_message": "Ce sujet a été supprimé. Seuls les utilsateurs avec les droits d'administration peuvent le voir.", "following_topic.title": "Sujet suivi", "following_topic.message": "Vous recevrez désormais des notifications lorsque quelqu'un postera dans ce sujet.", "not_following_topic.title": "Sujet non suivi", "not_following_topic.message": "Vous ne recevrez plus de notifications pour ce sujet.", - "login_to_subscribe": "Please register or log in in order to subscribe to this topic.", - "markAsUnreadForAll.success": "Topic marked as unread for all.", + "login_to_subscribe": "Veuillez vous enregistrer ou vous connecter afin de souscrire à ce sujet.", + "markAsUnreadForAll.success": "Sujet marqué comme non lu pour tout le monde.", "watch": "Suivre", "share_this_post": "Partager ce message", "thread_tools.title": "Outils du Fil", @@ -66,17 +66,17 @@ "composer.title_placeholder": "Entrer le titre du sujet ici...", "composer.write": "Ecriture", "composer.preview": "Aperçu", - "composer.help": "Help", + "composer.help": "Aide", "composer.discard": "Abandon", "composer.submit": "Envoi", "composer.replying_to": "Répondre à", "composer.new_topic": "Nouveau Sujet", - "composer.uploading": "uploading...", - "composer.thumb_url_label": "Paste a topic thumbnail URL", - "composer.thumb_title": "Add a thumbnail to this topic", - "composer.thumb_url_placeholder": "http://example.com/thumb.png", - "composer.thumb_file_label": "Or upload a file", - "composer.thumb_remove": "Clear fields", + "composer.uploading": "téléchargement...", + "composer.thumb_url_label": "Coller une URL de vignette du sujet", + "composer.thumb_title": "Ajouter une vignette à ce sujet", + "composer.thumb_url_placeholder": "http://exemple.com/vignette.png", + "composer.thumb_file_label": "Ou télécharger un fichier", + "composer.thumb_remove": "Effacer les champs", "composer.drag_and_drop_images": "Glisser-déposer ici les images", "composer.upload_instructions": "Uploader des images par glisser-déposer." } \ No newline at end of file diff --git a/public/language/nb/global.json b/public/language/nb/global.json index d1773e9388..bd4292c02b 100644 --- a/public/language/nb/global.json +++ b/public/language/nb/global.json @@ -49,7 +49,7 @@ "posted": "skapt", "in": "i", "recentposts": "Seneste innlegg", - "recentips": "Recently Logged In IPs", + "recentips": "Seneste innloggede IP-er", "online": "Online", "away": "Borte", "dnd": "Ikke forsturr", diff --git a/public/language/nb/pages.json b/public/language/nb/pages.json index 1d7a489f5e..6a23fa2104 100644 --- a/public/language/nb/pages.json +++ b/public/language/nb/pages.json @@ -8,7 +8,7 @@ "user.edit": "Endrer \"%1\"", "user.following": "Personer %1 følger", "user.followers": "Personer som følger %1", - "user.posts": "Posts made by %1", + "user.posts": "Innlegg laget av %1", "user.favourites": "%1 sine favoritt-innlegg", "user.settings": "Brukerinnstillinger" } \ No newline at end of file diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 320f0b5002..4641564876 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -11,7 +11,7 @@ "reply": "Svar", "edit": "Endre", "delete": "Slett", - "restore": "Restore", + "restore": "Gjenopprett", "move": "Flytt", "fork": "Del", "banned": "utestengt", @@ -19,15 +19,15 @@ "share": "Del", "tools": "Verktøy", "flag": "Rapporter", - "bookmark_instructions": "Click here to return to your last position or close to discard.", + "bookmark_instructions": "Klikk her for å returnere til din siste posisjon eller lukk for å forkaste.", "flag_title": "Rapporter dette innlegget for granskning", "deleted_message": "Denne tråden har blitt slettet. Bare brukere med trådhåndterings-privilegier kan se den.", "following_topic.title": "Følger tråd", "following_topic.message": "Du vil nå motta varsler når noen skriver i denne tråden.", "not_following_topic.title": "Følger ikke tråd", "not_following_topic.message": "Du vil ikke lenger motta varsler fra denne tråden.", - "login_to_subscribe": "Please register or log in in order to subscribe to this topic.", - "markAsUnreadForAll.success": "Topic marked as unread for all.", + "login_to_subscribe": "Vennligst registrer deg eller logg inn for å abonnere på denne tråden.", + "markAsUnreadForAll.success": "Tråd markert som ulest for alle.", "watch": "Overvåk", "share_this_post": "Del ditt innlegg", "thread_tools.title": "Trådverktøy", @@ -66,17 +66,17 @@ "composer.title_placeholder": "Skriv din tråd-tittel her", "composer.write": "Skriv", "composer.preview": "Forhåndsvis", - "composer.help": "Help", + "composer.help": "Hjelp", "composer.discard": "Forkast", "composer.submit": "Send", "composer.replying_to": "Svarer til", "composer.new_topic": "Ny tråd", - "composer.uploading": "uploading...", - "composer.thumb_url_label": "Paste a topic thumbnail URL", - "composer.thumb_title": "Add a thumbnail to this topic", + "composer.uploading": "laster opp...", + "composer.thumb_url_label": "Lim inn som tråd-minatyr URL", + "composer.thumb_title": "Legg til minatyr til denne tråden", "composer.thumb_url_placeholder": "http://example.com/thumb.png", - "composer.thumb_file_label": "Or upload a file", - "composer.thumb_remove": "Clear fields", + "composer.thumb_file_label": "Eller last opp en fil", + "composer.thumb_remove": "Tøm felter", "composer.drag_and_drop_images": "Dra og slipp bilder her", "composer.upload_instructions": "Last opp bilder ved å dra og slippe dem." } \ No newline at end of file diff --git a/public/language/sv/category.json b/public/language/sv/category.json index 629829d720..33340fc2c2 100644 --- a/public/language/sv/category.json +++ b/public/language/sv/category.json @@ -2,7 +2,7 @@ "new_topic_button": "Nytt ämne", "no_topics": "Det finns inga ämnen i denna kategori.
Varför inte skapa ett?", "posts": "inlägg", - "views": "tittningar", + "views": "visningar", "posted": "skapad", "browsing": "läser", "no_replies": "Ingen har svarat", diff --git a/public/language/sv/global.json b/public/language/sv/global.json index 5896cf7d5c..a92a4b8d8f 100644 --- a/public/language/sv/global.json +++ b/public/language/sv/global.json @@ -10,16 +10,16 @@ "500.message": "Hoppsan! Verkar som att något gått snett!", "register": "Registrera", "login": "Logga in", - "please_log_in": "Please Log In", - "posting_restriction_info": "Posting is currently restricted to registered members only, click here to log in.", - "welcome_back": "Welcome Back ", - "you_have_successfully_logged_in": "You have successfully logged in", + "please_log_in": "Var god logga in", + "posting_restriction_info": "Man måste vara inloggad för att kunna skapa inlägg, klicka här för att logga in.", + "welcome_back": "Välkommen tillbaka", + "you_have_successfully_logged_in": "Inloggningen lyckades", "logout": "Logga ut", "logout.title": "Du är nu utloggad.", "logout.message": "Du är nu utloggad från NodeBB.", "save_changes": "Spara ändringar", "close": "Stäng", - "pagination": "Pagination", + "pagination": "Siduppdelning", "header.admin": "Admin", "header.recent": "Senaste", "header.unread": "Olästa", @@ -49,7 +49,7 @@ "posted": "svarade", "in": "i", "recentposts": "Senaste ämnena", - "recentips": "Recently Logged In IPs", + "recentips": "Nyligen inloggade IPn", "online": "Online", "away": "Borta", "dnd": "Stör ej", diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json index b97f8f5ae9..a480c7b77e 100644 --- a/public/language/sv/notifications.json +++ b/public/language/sv/notifications.json @@ -1,6 +1,6 @@ { "title": "Notiser", - "no_notifs": "You have no new notifications", + "no_notifs": "Du har inga nya notiser", "see_all": "Visa alla notiser", "back_to_home": "Tillbaka till NodeBB", "outgoing_link": "Utgående länk", diff --git a/public/language/sv/pages.json b/public/language/sv/pages.json index 39899ade4d..815fc336dd 100644 --- a/public/language/sv/pages.json +++ b/public/language/sv/pages.json @@ -1,14 +1,14 @@ { "home": "Hem", "unread": "Olästa ämnen", - "popular": "Popular Topics", + "popular": "Populära ämnen", "recent": "Senaste ämnena", "users": "Registrerade användare", "notifications": "Notiser", "user.edit": "Ändrar \"%1\"", "user.following": "Personer %1 Följer", "user.followers": "Personer som följer %1", - "user.posts": "Posts made by %1", + "user.posts": "Inlägg skapat av %1", "user.favourites": "%1's favorit-inlägg", "user.settings": "Avnändarinställningar" } \ No newline at end of file diff --git a/public/language/sv/topic.json b/public/language/sv/topic.json index 67e81513be..2f62fe568e 100644 --- a/public/language/sv/topic.json +++ b/public/language/sv/topic.json @@ -11,7 +11,7 @@ "reply": "Svara", "edit": "Ändra", "delete": "Ta bort", - "restore": "Restore", + "restore": "Återställ", "move": "Flytta", "fork": "Grena", "banned": "bannad", @@ -19,17 +19,17 @@ "share": "Dela", "tools": "Verktyg", "flag": "Rapportera", - "bookmark_instructions": "Click here to return to your last position or close to discard.", + "bookmark_instructions": "Klicka här för att återgå till den senaste positionen eller stäng för att kasta.", "flag_title": "Rapportera detta inlägg för granskning", "deleted_message": "Denna tråd har tagits bort. Endast användare med administrations-rättigheter kan se den.", - "following_topic.title": "Following Topic", - "following_topic.message": "You will now be receiving notifications when somebody posts to this topic.", - "not_following_topic.title": "Not Following Topic", - "not_following_topic.message": "You will no longer receive notifications from this topic.", - "login_to_subscribe": "Please register or log in in order to subscribe to this topic.", - "markAsUnreadForAll.success": "Topic marked as unread for all.", - "watch": "Watch", - "share_this_post": "Share this Post", + "following_topic.title": "Följer ämne", + "following_topic.message": "Du kommer nu få notiser när någon gör inlägg i detta ämne.", + "not_following_topic.title": "Du följer inte ämnet", + "not_following_topic.message": "Du kommer inte längre få notiser från detta ämne.", + "login_to_subscribe": "Var god registrera eller logga in för att kunna prenumerera på detta ämne.", + "markAsUnreadForAll.success": "Ämne markerat som oläst av alla.", + "watch": "Följ", + "share_this_post": "Dela detta inlägg", "thread_tools.title": "Trådverktyg", "thread_tools.markAsUnreadForAll": "Markera som oläst", "thread_tools.pin": "Fäst ämne", @@ -66,17 +66,17 @@ "composer.title_placeholder": "Skriv in ämnets titel här...", "composer.write": "Skriv", "composer.preview": "Förhandsgranska", - "composer.help": "Help", + "composer.help": "Hjälp", "composer.discard": "Avbryt", "composer.submit": "Spara", "composer.replying_to": "Svarar till", "composer.new_topic": "Nytt ämne", - "composer.uploading": "uploading...", - "composer.thumb_url_label": "Paste a topic thumbnail URL", - "composer.thumb_title": "Add a thumbnail to this topic", + "composer.uploading": "laddar upp...", + "composer.thumb_url_label": "Klistra in URL till tumnagel för ämnet", + "composer.thumb_title": "Lägg till tumnagel för detta ämne", "composer.thumb_url_placeholder": "http://example.com/thumb.png", - "composer.thumb_file_label": "Or upload a file", - "composer.thumb_remove": "Clear fields", - "composer.drag_and_drop_images": "Drag and Drop Images Here", - "composer.upload_instructions": "Upload images by dragging & dropping them." + "composer.thumb_file_label": "Eller ladda upp en fil", + "composer.thumb_remove": "Töm fält", + "composer.drag_and_drop_images": "Dra och släpp bilder här", + "composer.upload_instructions": "Ladda upp bilder genom att dra och släpp dem." } \ No newline at end of file diff --git a/public/language/sv/user.json b/public/language/sv/user.json index 13e77e3d00..a876a6f76d 100644 --- a/public/language/sv/user.json +++ b/public/language/sv/user.json @@ -19,20 +19,20 @@ "signature": "Signatur", "gravatar": "Gravatar", "birthday": "Födelsedag", - "chat": "Chat", - "follow": "Follow", - "unfollow": "Unfollow", + "chat": "Chatta", + "follow": "Följ", + "unfollow": "Sluta följ", "change_picture": "Ändra bild", "edit": "Ändra", "uploaded_picture": "Uppladdad bild", "upload_new_picture": "Ladda upp ny bild", - "current_password": "Current Password", + "current_password": "Nuvarande lösenord", "change_password": "Ändra lösenord", "confirm_password": "Bekräfta lösenord", "password": "Lösenord", "upload_picture": "Ladda upp bild", "upload_a_picture": "Ladda upp en bild", - "image_spec": "You may only upload PNG, JPG, or GIF files", + "image_spec": "Du får bara ladda upp PNG, JPG eller GIF-filer", "max": "max.", "settings": "Inställningar", "show_email": "Visa min epost", @@ -41,7 +41,7 @@ "has_no_posts": "Denna användare har inte gjort några inlägg än.", "email_hidden": "Epost dold", "hidden": "dold", - "paginate_description": "Paginate topics and posts instead of using infinite scroll.", - "topics_per_page": "Topics per Page", - "posts_per_page": "Posts per Page" + "paginate_description": "Gör så att ämnen och inlägg visas som sidor istället för oändlig scroll.", + "topics_per_page": "Ämnen per sida", + "posts_per_page": "Inlägg per sida" } \ No newline at end of file diff --git a/public/language/zh_CN/global.json b/public/language/zh_CN/global.json index 174386fd13..a56b080bc7 100644 --- a/public/language/zh_CN/global.json +++ b/public/language/zh_CN/global.json @@ -49,7 +49,7 @@ "posted": "发布", "in": "在", "recentposts": "最新发表", - "recentips": "Recently Logged In IPs", + "recentips": "最近登录ip", "online": " 在线", "away": "离开", "dnd": "不打扰", diff --git a/public/language/zh_CN/pages.json b/public/language/zh_CN/pages.json index 712bf602f1..59cfe38f1f 100644 --- a/public/language/zh_CN/pages.json +++ b/public/language/zh_CN/pages.json @@ -8,7 +8,7 @@ "user.edit": "编辑 \"%1\"", "user.following": "%1的人关注", "user.followers": "%1关注的人", - "user.posts": "Posts made by %1", + "user.posts": "%1 发表", "user.favourites": "%1 喜爱的帖子", "user.settings": "用户设置" } \ No newline at end of file diff --git a/public/language/zh_CN/topic.json b/public/language/zh_CN/topic.json index 4992fa4719..f3857aeadc 100644 --- a/public/language/zh_CN/topic.json +++ b/public/language/zh_CN/topic.json @@ -11,7 +11,7 @@ "reply": "回复", "edit": "编辑", "delete": "删除", - "restore": "Restore", + "restore": "恢复", "move": "移动", "fork": "作为主题", "banned": "禁止", @@ -19,15 +19,15 @@ "share": "分享", "tools": "工具", "flag": "标志", - "bookmark_instructions": "Click here to return to your last position or close to discard.", + "bookmark_instructions": "点击这里返回你最初的位置或退出。", "flag_title": "标志受限的帖子", "deleted_message": "这个帖子已经删除,只有帖子的拥有者才有权限去查看。", "following_topic.title": "关注该主题", "following_topic.message": "当有回复提交的时候你将会收到通知。", "not_following_topic.title": "非关注主题", "not_following_topic.message": "你将不再接受来自该帖子的通知。", - "login_to_subscribe": "Please register or log in in order to subscribe to this topic.", - "markAsUnreadForAll.success": "Topic marked as unread for all.", + "login_to_subscribe": "请注册或登录以订阅该主题。", + "markAsUnreadForAll.success": "标记所有未读主题", "watch": "查看", "share_this_post": "分享帖子", "thread_tools.title": "管理工具", @@ -66,17 +66,17 @@ "composer.title_placeholder": "在这里输入你的主题标题...", "composer.write": "书写", "composer.preview": "预览", - "composer.help": "Help", + "composer.help": "帮助", "composer.discard": "丢弃", "composer.submit": "提交", "composer.replying_to": "回复", "composer.new_topic": "新主题", - "composer.uploading": "uploading...", - "composer.thumb_url_label": "Paste a topic thumbnail URL", - "composer.thumb_title": "Add a thumbnail to this topic", + "composer.uploading": "上传中...", + "composer.thumb_url_label": "粘贴一个主题缩略图URL地址", + "composer.thumb_title": "为主题添加一个缩略图", "composer.thumb_url_placeholder": "http://example.com/thumb.png", - "composer.thumb_file_label": "Or upload a file", - "composer.thumb_remove": "Clear fields", + "composer.thumb_file_label": "或上传一个文件", + "composer.thumb_remove": "清除字段", "composer.drag_and_drop_images": "把图像拖到此处", "composer.upload_instructions": "拖拽图片以上传" } \ No newline at end of file diff --git a/public/src/forum/reset.js b/public/src/forum/reset.js index f67e1a28b8..b03007c74e 100644 --- a/public/src/forum/reset.js +++ b/public/src/forum/reset.js @@ -7,7 +7,7 @@ define(function() { successEl = $('#success'), errorTextEl = errorEl.find('p'); - $('#reset').onclick = function() { + $('#reset').on('click', function() { if (inputEl.val() && inputEl.val().indexOf('@') !== -1) { socket.emit('user.reset.send', { email: inputEl.val() @@ -26,7 +26,7 @@ define(function() { errorEl.removeClass('hide').show(); errorTextEl.html('Please enter a valid email'); } - }; + }); }; return ResetPassword; diff --git a/public/src/forum/reset_code.js b/public/src/forum/reset_code.js index 0afd3fc266..36af29de16 100644 --- a/public/src/forum/reset_code.js +++ b/public/src/forum/reset_code.js @@ -33,9 +33,8 @@ define(function() { $('#success').removeClass('hide').addClass('show').show(); }); } - }, false); + }); - // Enable the form if the code is valid socket.emit('user.reset.valid', { code: reset_code }, function(err, valid) { @@ -44,7 +43,7 @@ define(function() { } if (valid) { - resetEl.disabled = false; + resetEl.prop('disabled', false); } else { var formEl = $('#reset-form'); // Show error message diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 9a86aaec32..6a697f5849 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -613,7 +613,8 @@ define(['composer', 'forum/pagination'], function(composer, pagination) { 'event:topic_deleted', 'event:topic_restored', 'event:topic:locked', 'event:topic_unlocked', 'event:topic_pinned', 'event:topic_unpinned', 'event:topic_moved', 'event:post_edited', 'event:post_deleted', 'event:post_restored', - 'posts.favourite', 'user.isOnline', 'posts.upvote', 'posts.downvote' + 'posts.favourite', 'user.isOnline', 'posts.upvote', 'posts.downvote', + 'event:topic.replyStart', 'event:topic.replyStop' ]); socket.on('get_users_in_room', function(data) { @@ -622,17 +623,9 @@ define(['composer', 'forum/pagination'], function(composer, pagination) { var activeEl = $('li.post-bar[data-index="0"] .thread_active_users'); function createUserIcon(uid, picture, userslug, username) { - - if(!activeEl.find('[href="'+ RELATIVE_PATH +'/user/' + data.users[i].userslug + '"]').length) { - var userIcon = $(''); - - var userLink = $('').append(userIcon); - userLink.attr('data-uid', uid); - - var div = $('
'); - div.append(userLink); - - userLink.tooltip({ + if(!activeEl.find('[data-uid="' + uid + '"]').length) { + var div = $('
'); + div.find('a').tooltip({ placement: 'top', title: username }); @@ -642,15 +635,16 @@ define(['composer', 'forum/pagination'], function(composer, pagination) { } // remove users that are no longer here - activeEl.children().each(function(index, element) { + activeEl.find('a').each(function(index, element) { if(element) { var uid = $(element).attr('data-uid'); - for(var i=0; i [[topic:thread_tools.' + (locked ? 'un': '') + 'lock]]', function(translated) { @@ -934,7 +947,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) { } thread_state.locked = locked ? '1' : '0'; - } + }; function set_delete_state(deleted) { var threadEl = $('#post-container'); @@ -951,7 +964,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) { } else { $('#thread-deleted').remove(); } - } + }; function set_pinned_state(pinned, alert) { translator.translate(' [[topic:thread_tools.' + (pinned ? 'unpin' : 'pin') + ']]', function(translated) { @@ -968,7 +981,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) { } thread_state.pinned = pinned ? '1' : '0'; }); - } + }; function toggle_post_delete_state(pid) { var postEl = $('#post-container li[data-pid="' + pid + '"]'); @@ -980,7 +993,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) { updatePostCount(); } - } + }; function toggle_post_tools(pid, isDeleted) { var postEl = $('#post-container li[data-pid="' + pid + '"]'); @@ -990,7 +1003,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) { translator.translate(isDeleted ? ' [[topic:restore]]' : ' [[topic:delete]]', function(translated) { postEl.find('.delete').find('span').html(translated); }); - } + }; $(window).on('scroll', updateHeader); $(window).trigger('action:topic.loaded'); diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 55a0b1450b..c9457aa38a 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -4,6 +4,15 @@ define(['taskbar'], function(taskbar) { posts: {} }; + function initialise() { + socket.on('event:composer.ping', function(post_uuid) { + if (composer.active === post_uuid) { + socket.emit('modules.composer.pingActive', post_uuid); + } + }); + }; + initialise(); + function maybeParse(response) { if (typeof response == 'string') { try { @@ -380,6 +389,16 @@ define(['taskbar'], function(taskbar) { } else { composer.createNewComposer(post_uuid); } + + var postData = composer.posts[post_uuid]; + if (postData.tid) { + // Replying to a topic + socket.emit('modules.composer.register', { + uuid: post_uuid, + tid: postData.tid, + uid: app.uid + }); + } }; composer.createNewComposer = function(post_uuid) { @@ -813,6 +832,8 @@ define(['taskbar'], function(taskbar) { taskbar.discard('composer', post_uuid); $('body').css({'margin-bottom': 0}); $('.action-bar button').removeAttr('disabled'); + + socket.emit('modules.composer.unregister', post_uuid); } }; @@ -821,6 +842,8 @@ define(['taskbar'], function(taskbar) { postContainer.css('visibility', 'hidden'); composer.active = undefined; taskbar.minimize('composer', post_uuid); + + socket.emit('modules.composer.unregister', post_uuid); }; return { diff --git a/src/categories.js b/src/categories.js index 5a86d8532c..fb8e9b5990 100644 --- a/src/categories.js +++ b/src/categories.js @@ -1,3 +1,6 @@ + +'use strict'; + var db = require('./database'), posts = require('./posts'), utils = require('./../public/src/utils'), @@ -13,7 +16,6 @@ var db = require('./database'), nconf = require('nconf'); (function(Categories) { - "use strict"; Categories.create = function(data, callback) { db.incrObjectField('global', 'nextCid', function(err, cid) { @@ -102,12 +104,13 @@ var db = require('./database'), }); } - var indices = {}; - for(var i=0; i=0) { + /* If redis.host contains a path name character, use the unix dom sock connection. ie, /tmp/redis.sock */ + redisClient = redis.createClient(nconf.get('redis:host')); + } else { + /* Else, connect over tcp/ip */ + redisClient = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host')); + } - if (redis_socket_or_host && redis_socket_or_host.indexOf('/')>=0) { - /* If redis.host contains a path name character, use the unix dom sock connection. ie, /tmp/redis.sock */ - redisClient = redis.createClient(nconf.get('redis:host')); - } else { - /* Else, connect over tcp/ip */ - redisClient = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host')); - } - - if (nconf.get('redis:password')) { - redisClient.auth(nconf.get('redis:password')); - } else { - winston.warn('You have no redis password setup!'); - } - - redisClient.on('error', function (err) { - winston.error(err.message); - process.exit(); - }); + if (nconf.get('redis:password')) { + redisClient.auth(nconf.get('redis:password')); + } else { + winston.warn('You have no redis password setup!'); + } + redisClient.on('error', function (err) { + winston.error(err.message); + process.exit(); + }); - module.client = redisClient; + module.client = redisClient; - module.sessionStore = new connectRedis({ - client: redisClient, - ttl: 60 * 60 * 24 * 14 - }); + module.sessionStore = new connectRedis({ + client: redisClient, + ttl: 60 * 60 * 24 * 14 + }); - reds.createClient = function () { - return reds.client || (reds.client = redisClient); - }; + reds.createClient = function () { + return reds.client || (reds.client = redisClient); + }; - var userSearch = reds.createSearch('nodebbusersearch'), postSearch = reds.createSearch('nodebbpostsearch'), topicSearch = reds.createSearch('nodebbtopicsearch'); - var db = parseInt(nconf.get('redis:database'), 10); + var db = parseInt(nconf.get('redis:database'), 10); - if (db){ - redisClient.select(db, function(error) { - if(error) { - winston.error("NodeBB could not connect to your Redis database. Redis returned the following error: " + error.message); - process.exit(); - } - }); - } + if (db) { + redisClient.select(db, function(error) { + if(error) { + winston.error("NodeBB could not connect to your Redis database. Redis returned the following error: " + error.message); + process.exit(); + } + }); + } - module.init = function(callback) { - callback(null); - } + callback(); + }; module.close = function() { redisClient.quit(); - } + }; // // Exported functions // module.searchIndex = function(key, content, id) { - if(key === 'post') { + if (key === 'post') { postSearch.index(content, id); } else if(key === 'topic') { topicSearch.index(content, id); - } else if(key === 'user') { - userSearch.index(content, id); } - } + }; module.search = function(key, term, limit, callback) { function search(searchObj, callback) { @@ -102,55 +100,30 @@ search(postSearch, callback); } else if(key === 'topic') { search(topicSearch, callback); - } else if(key === 'user') { - search(userSearch, callback); } - } + }; module.searchRemove = function(key, id, callback) { if(key === 'post') { postSearch.remove(id); } else if(key === 'topic') { topicSearch.remove(id); - } else if(key === 'user') { - userSearch.remove(id); } if (typeof callback === 'function') { - callback() + callback(); } - } + }; module.flushdb = function(callback) { redisClient.send_command('flushdb', [], function(err) { - if(err){ - winston.error(error); - return callback(err); - } - callback(null); - }); - } - - module.getFileName = function(callback) { - var multi = redisClient.multi(); - - multi.config('get', 'dir'); - multi.config('get', 'dbfilename'); - multi.exec(function (err, results) { if (err) { + winston.error(err.message); return callback(err); } - - results = results.reduce(function (memo, config) { - memo[config[0]] = config[1]; - return memo; - }, {}); - - var dbFile = path.join(results.dir, results.dbfilename); - callback(null, dbFile); + callback(); }); - } - + }; module.info = function(callback) { redisClient.info(function (err, data) { @@ -172,7 +145,7 @@ callback(null, redisData); }); - } + }; // key @@ -180,35 +153,35 @@ redisClient.exists(key, function(err, exists) { callback(err, exists === 1); }); - } + }; module.delete = function(key, callback) { redisClient.del(key, callback); - } + }; module.get = function(key, callback) { redisClient.get(key, callback); - } + }; module.set = function(key, value, callback) { redisClient.set(key, value, callback); - } + }; module.keys = function(key, callback) { redisClient.keys(key, callback); - } + }; module.rename = function(oldKey, newKey, callback) { redisClient.rename(oldKey, newKey, callback); - } + }; module.expire = function(key, seconds, callback) { redisClient.expire(key, seconds, callback); - } + }; module.expireAt = function(key, timestamp, callback) { redisClient.expireat(key, timestamp, callback); - } + }; //hashes @@ -219,15 +192,15 @@ callback(err, res); } }); - } + }; module.setObjectField = function(key, field, value, callback) { redisClient.hset(key, field, value, callback); - } + }; module.getObject = function(key, callback) { redisClient.hgetall(key, callback); - } + }; module.getObjects = function(keys, callback) { var multi = redisClient.multi(); @@ -239,7 +212,7 @@ multi.exec(function (err, replies) { callback(err, replies); }); - } + }; module.getObjectField = function(key, field, callback) { module.getObjectFields(key, [field], function(err, data) { @@ -249,7 +222,7 @@ callback(null, data[field]); }); - } + }; module.getObjectFields = function(key, fields, callback) { redisClient.hmget(key, fields, function(err, data) { @@ -265,48 +238,48 @@ callback(null, returnData); }); - } + }; module.getObjectKeys = function(key, callback) { redisClient.hkeys(key, callback); - } + }; module.getObjectValues = function(key, callback) { redisClient.hvals(key, callback); - } + }; module.isObjectField = function(key, field, callback) { redisClient.hexists(key, field, function(err, exists) { callback(err, exists === 1); }); - } + }; module.deleteObjectField = function(key, field, callback) { redisClient.hdel(key, field, callback); - } + }; module.incrObjectField = function(key, field, callback) { redisClient.hincrby(key, field, 1, callback); - } + }; module.decrObjectField = function(key, field, callback) { redisClient.hincrby(key, field, -1, callback); - } + }; module.incrObjectFieldBy = function(key, field, value, callback) { redisClient.hincrby(key, field, value, callback); - } + }; // sets module.setAdd = function(key, value, callback) { redisClient.sadd(key, value, callback); - } + }; module.setRemove = function(key, value, callback) { redisClient.srem(key, value, callback); - } + }; module.isSetMember = function(key, value, callback) { redisClient.sismember(key, value, function(err, result) { @@ -316,7 +289,7 @@ callback(null, result === 1); }); - } + }; module.isMemberOfSets = function(sets, value, callback) { var batch = redisClient.multi(); @@ -326,67 +299,67 @@ } batch.exec(callback); - } + }; module.getSetMembers = function(key, callback) { redisClient.smembers(key, callback); - } + }; module.setCount = function(key, callback) { redisClient.scard(key, callback); - } + }; module.setRemoveRandom = function(key, callback) { redisClient.spop(key, callback); - } + }; // sorted sets module.sortedSetAdd = function(key, score, value, callback) { redisClient.zadd(key, score, value, callback); - } + }; module.sortedSetRemove = function(key, value, callback) { redisClient.zrem(key, value, callback); - } + }; module.getSortedSetRange = function(key, start, stop, callback) { redisClient.zrange(key, start, stop, callback); - } + }; module.getSortedSetRevRange = function(key, start, stop, callback) { redisClient.zrevrange(key, start, stop, callback); - } + }; module.getSortedSetRevRangeByScore = function(args, callback) { redisClient.zrevrangebyscore(args, callback); - } + }; module.sortedSetCount = function(key, min, max, callback) { redisClient.zcount(key, min, max, callback); - } + }; module.sortedSetCard = function(key, callback) { redisClient.zcard(key, callback); - } + }; module.sortedSetRank = function(key, value, callback) { redisClient.zrank(key, value, callback); - } + }; module.sortedSetRevRank = function(key, value, callback) { redisClient.zrevrank(key, value, callback); - } + }; module.sortedSetScore = function(key, value, callback) { redisClient.zscore(key, value, callback); - } + }; module.isSortedSetMember = function(key, value, callback) { module.sortedSetScore(key, value, function(err, score) { callback(err, !!score); }); - } + }; module.sortedSetsScore = function(keys, value, callback) { var multi = redisClient.multi(); @@ -396,31 +369,28 @@ } multi.exec(callback); - } + }; // lists module.listPrepend = function(key, value, callback) { redisClient.lpush(key, value, callback); - } + }; module.listAppend = function(key, value, callback) { redisClient.rpush(key, value, callback); - } + }; module.listRemoveLast = function(key, callback) { redisClient.rpop(key, callback); - } + }; module.listRemoveAll = function(key, value, callback) { redisClient.lrem(key, 0, value, callback); - } + }; module.getListRange = function(key, start, stop, callback) { redisClient.lrange(key, start, stop, callback); - } - - - + }; }(exports)); diff --git a/src/meta.js b/src/meta.js index 93f53e04d3..b8c12a0721 100644 --- a/src/meta.js +++ b/src/meta.js @@ -297,12 +297,6 @@ var fs = require('fs'), } }; - Meta.db = { - getFile: function (callback) { - db.getFileName(callback); - } - }; - Meta.css = { cache: undefined }; diff --git a/src/postTools.js b/src/postTools.js index b610e19415..814ea277a2 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -1,3 +1,5 @@ +'use strict'; + var winston = require('winston'), async = require('async'), nconf = require('nconf'), @@ -14,15 +16,20 @@ var winston = require('winston'), meta = require('./meta'); (function(PostTools) { + PostTools.isMain = function(pid, tid, callback) { db.getSortedSetRange('tid:' + tid + ':posts', 0, 0, function(err, pids) { if(err) { return callback(err); } + if(!Array.isArray(pids) || !pids.length) { + callback(null, false); + } + callback(null, parseInt(pids[0], 10) === parseInt(pid, 10)); }); - } + }; PostTools.privileges = function(pid, uid, callback) { async.parallel({ @@ -48,7 +55,6 @@ var winston = require('winston'), }); } } - // [getThreadPrivileges, isOwnPost, hasEnoughRep] }, function(err, results) { if(err) { return callback(err); @@ -61,71 +67,78 @@ var winston = require('winston'), move: results.topicPrivs.admin || results.topicPrivs.moderator }); }); - } + }; - PostTools.edit = function(uid, pid, title, content, options) { - options || (options = {}); + PostTools.edit = function(uid, pid, title, content, options, callback) { + options = options || {}; - var websockets = require('./socket.io'), - success = function() { - posts.setPostFields(pid, { - edited: Date.now(), - editor: uid, - content: content - }); + function success(postData) { + posts.setPostFields(pid, { + edited: Date.now(), + editor: uid, + content: postData.content + }); - events.logPostEdit(uid, pid); + events.logPostEdit(uid, pid); - async.parallel([ - function(next) { - posts.getPostField(pid, 'tid', function(err, tid) { - PostTools.isMain(pid, tid, function(err, isMainPost) { - if (isMainPost) { - title = title.trim(); - var slug = tid + '/' + utils.slugify(title); + async.parallel({ + topic: function(next) { + var tid = postData.tid; + PostTools.isMain(pid, tid, function(err, isMainPost) { + if (err) { + return next(err); + } + + if (isMainPost) { + title = title.trim(); + var slug = tid + '/' + utils.slugify(title); - topics.setTopicField(tid, 'title', title); - topics.setTopicField(tid, 'slug', slug); + topics.setTopicField(tid, 'title', title); + topics.setTopicField(tid, 'slug', slug); - topics.setTopicField(tid, 'thumb', options.topic_thumb); + topics.setTopicField(tid, 'thumb', options.topic_thumb); - plugins.fireHook('action:topic.edit', tid); - } + plugins.fireHook('action:topic.edit', tid); + } - posts.getPostData(pid, function(err, postData) { - plugins.fireHook('action:post.edit', postData); - }); + plugins.fireHook('action:post.edit', postData); - next(null, { - tid: tid, - isMainPost: isMainPost - }); - }); + next(null, { + tid: tid, + title: validator.escape(title), + isMainPost: isMainPost }); - }, - function(next) { - PostTools.parse(content, next); - } - ], function(err, results) { - websockets.in('topic_' + results[0].tid).emit('event:post_edited', { - pid: pid, - title: validator.escape(title), - isMainPost: results[0].isMainPost, - content: results[1] }); - }); - }; + + }, + content: function(next) { + PostTools.parse(postData.content, next); + } + }, callback); + } PostTools.privileges(pid, uid, function(err, privileges) { - if (privileges.editable) { - plugins.fireHook('filter:post.save', content, function(err, parsedContent) { - if (!err) content = parsedContent; - success(); - }); + if (err || !privileges.editable) { + return callback(err || new Error('not-privileges-to-edit')); } + + posts.getPostData(pid, function(err, postData) { + if (err) { + return callback(err); + } + + postData.content = content; + plugins.fireHook('filter:post.save', postData, function(err, postData) { + if (err) { + return callback(err); + } + + success(postData); + }); + }); }); - } + }; PostTools.delete = function(uid, pid, callback) { var success = function() { @@ -183,7 +196,7 @@ var winston = require('winston'), } }); }); - } + }; PostTools.restore = function(uid, pid, callback) { var success = function() { @@ -238,7 +251,7 @@ var winston = require('winston'), } }); }); - } + }; PostTools.parse = function(raw, callback) { raw = raw || ''; @@ -246,7 +259,7 @@ var winston = require('winston'), plugins.fireHook('filter:post.parse', raw, function(err, parsed) { callback(null, !err ? parsed : raw); }); - } + }; PostTools.parseSignature = function(raw, callback) { raw = raw || ''; @@ -254,5 +267,6 @@ var winston = require('winston'), plugins.fireHook('filter:post.parseSignature', raw, function(err, parsedSignature) { callback(null, !err ? parsedSignature : raw); }); - } + }; + }(exports)); diff --git a/src/posts.js b/src/posts.js index ac428870d0..ac4a3d5e5a 100644 --- a/src/posts.js +++ b/src/posts.js @@ -29,61 +29,49 @@ var db = require('./database'), toPid = data.toPid; if (uid === null) { - return callback(new Error('invalid-user'), null); + return callback(new Error('invalid-user')); } + var timestamp = Date.now(), + postData; + async.waterfall([ function(next) { - topics.isLocked(tid, next); - }, - function(locked, next) { - if(locked) { - return next(new Error('topic-locked')); - } - db.incrObjectField('global', 'nextPid', next); }, function(pid, next) { - plugins.fireHook('filter:post.save', content, function(err, newContent) { - next(err, pid, newContent); - }); - }, - function(pid, newContent, next) { - var timestamp = Date.now(), - postData = { - 'pid': pid, - 'uid': uid, - 'tid': tid, - 'content': newContent, - 'timestamp': timestamp, - 'reputation': '0', - 'votes': '0', - 'editor': '', - 'edited': 0, - 'deleted': 0 - }; + + postData = { + 'pid': pid, + 'uid': uid, + 'tid': tid, + 'content': content, + 'timestamp': timestamp, + 'reputation': 0, + 'votes': 0, + 'editor': '', + 'edited': 0, + 'deleted': 0 + }; if (toPid) { postData.toPid = toPid; } - db.setObject('post:' + pid, postData, function(err) { - if(err) { - return next(err); - } - - db.sortedSetAdd('posts:pid', timestamp, pid); + plugins.fireHook('filter:post.save', postData, next); + }, + function(postData, next) { + db.setObject('post:' + postData.pid, postData, next); + }, + function(result, next) { + db.sortedSetAdd('posts:pid', timestamp, postData.pid); - db.incrObjectField('global', 'postCount'); + db.incrObjectField('global', 'postCount'); - topics.onNewPostMade(tid, pid, timestamp); - categories.onNewPostMade(uid, tid, pid, timestamp); - user.onNewPostMade(uid, tid, pid, timestamp); + topics.onNewPostMade(tid, postData.pid, timestamp); + categories.onNewPostMade(uid, tid, postData.pid, timestamp); + user.onNewPostMade(uid, tid, postData.pid, timestamp); - next(null, postData); - }); - }, - function(postData, next) { plugins.fireHook('filter:post.get', postData, next); }, function(postData, next) { @@ -103,36 +91,34 @@ var db = require('./database'), }; Posts.getPostsByTid = function(tid, start, end, reverse, callback) { - if (typeof reverse === 'function') { - callback = reverse; - reverse = false; - } - db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange']('tid:' + tid + ':posts', start, end, function(err, pids) { if(err) { return callback(err); } - if(!pids.length) { + if(!Array.isArray(pids) || !pids.length) { return callback(null, []); } - plugins.fireHook('filter:post.getTopic', pids, function(err, posts) { + Posts.getPostsByPids(pids, function(err, posts) { if(err) { return callback(err); } - if(!posts.length) { + if(!Array.isArray(posts) || !posts.length) { return callback(null, []); } - - Posts.getPostsByPids(pids, function(err, posts) { + plugins.fireHook('filter:post.getPosts', {tid: tid, posts: posts}, function(err, data) { if(err) { return callback(err); } - plugins.fireHook('action:post.gotTopic', posts); - callback(null, posts); + + if(!data || !Array.isArray(data.posts)) { + return callback(null, []); + } + + callback(null, data.posts); }); }); }); diff --git a/src/routes/admin.js b/src/routes/admin.js index 1741f62c6f..d4cd723c21 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -347,28 +347,6 @@ var nconf = require('nconf'), res.json(data); }); }); - - // app.get('/export', function (req, res) { - // meta.db.getFile(function (err, dbFile) { - // if (!err) { - // res.download(dbFile, 'redis.rdb', function (err) { - // console.log(err); - // res.send(500); - // if (err) { - // res.send(500); - // switch (err.code) { - // case 'EACCES': - // res.send(500, 'Require permissions from Redis database file: ', dbFile); - // break; - // default: - // res.send(500); - // break; - // } - // } - // }); - // } else res.send(500); - // }); - // }); }); app.get('/events', function(req, res, next) { diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 551edac088..f135245009 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -235,7 +235,11 @@ function isUserOnline(uid) { Sockets.updateRoomBrowsingText = updateRoomBrowsingText; function updateRoomBrowsingText(roomName) { - function getUidsInRoom(room) { + if (!roomName) { + return; + } + + function getUidsInRoom() { var uids = []; var clients = io.sockets.clients(roomName); for(var i=0; i