diff --git a/bcrypt.js b/bcrypt.js index 1445999a8a..ae81d09eb7 100644 --- a/bcrypt.js +++ b/bcrypt.js @@ -9,11 +9,10 @@ process.on('message', function(msg) { if (msg.type === 'hash') { hashPassword(msg.password, msg.rounds); } else if (msg.type === 'compare') { - compare(msg.password, msg.hash); + bcrypt.compare(msg.password, msg.hash, done); } }); - function hashPassword(password, rounds) { async.waterfall([ function(next) { @@ -22,23 +21,14 @@ function hashPassword(password, rounds) { function(salt, next) { bcrypt.hash(password, salt, next); } - ], function(err, hash) { - if (err) { - process.send({err: err.message}); - return process.disconnect(); - } - process.send({result: hash}); - process.disconnect(); - }); + ], done); } -function compare(password, hash) { - bcrypt.compare(password, hash, function(err, res) { - if (err) { - process.send({err: err.message}); - return process.disconnect(); - } - process.send({result: res}); - process.disconnect(); - }); +function done(err, result) { + if (err) { + process.send({err: err.message}); + return process.disconnect(); + } + process.send({result: result}); + process.disconnect(); } \ No newline at end of file diff --git a/package.json b/package.json index 1877079d6f..b4901f90e3 100644 --- a/package.json +++ b/package.json @@ -39,14 +39,14 @@ "mmmagic": "^0.3.13", "morgan": "^1.3.2", "nconf": "~0.7.1", - "nodebb-plugin-dbsearch": "^0.1.0", + "nodebb-plugin-dbsearch": "^0.2.1", "nodebb-plugin-emoji-extended": "^0.4.1-4", "nodebb-plugin-markdown": "^1.0.0", "nodebb-plugin-mentions": "^0.11.0", "nodebb-plugin-soundpack-default": "~0.1.1", "nodebb-plugin-spam-be-gone": "^0.4.0", - "nodebb-theme-lavender": "^1.0.6", - "nodebb-theme-vanilla": "^1.0.28", + "nodebb-theme-lavender": "^1.0.22", + "nodebb-theme-vanilla": "^1.0.80", "nodebb-widget-essentials": "~0.2.12", "nodebb-rewards-essentials": "^0.0.1", "npm": "^2.1.4", @@ -64,7 +64,7 @@ "socket.io-redis": "^0.1.3", "socketio-wildcard": "~0.1.1", "string": "^3.0.0", - "templates.js": "^0.1.28", + "templates.js": "^0.1.30", "uglify-js": "git+https://github.com/julianlam/UglifyJS2.git", "underscore": "~1.7.0", "validator": "^3.30.0", diff --git a/public/language/ar/error.json b/public/language/ar/error.json index e5d2f8c856..01c1aa7109 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -18,7 +18,7 @@ "username-taken": "اسم المستخدم مأخوذ", "email-taken": "البريد الالكتروني مأخوذ", "email-not-confirmed": "عنوان بريدك الإلكتروني غير مفعل بعد. انقر هنا لتفعيله من فضلك.", - "email-not-confirmed-chat": "لايمكنك الدردشة إلا بعد تفعيل بريدك الإلكتروني", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "هذا المنتدى يستلزم تفعيل بريدك الإلكتروني، انقر هنا من فضلك لإدخاله.", "email-confirm-failed": "لم نستطع تفعيل بريدك الإلكتروني، المرجو المحاولة لاحقًا.", "username-too-short": "اسم المستخدم قصير.", diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index 3d621333ba..4d644f6938 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 أشهر", "composer.user_said_in": "%1 كتب في %2", "composer.user_said": "%1 كتب:", - "composer.discard": "هل أنت متأكد أنك تريد التخلي عن التغييرات؟" + "composer.discard": "هل أنت متأكد أنك تريد التخلي عن التغييرات؟", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/ar/pages.json b/public/language/ar/pages.json index 15e8209928..e4183220a2 100644 --- a/public/language/ar/pages.json +++ b/public/language/ar/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "مفضلات %1", "user.settings": "خيارات المستخدم", + "user.watched": "Topics watched by %1", "maintenance.text": "جاري صيانة %1. المرجو العودة لاحقًا.", "maintenance.messageIntro": "بالإضافة إلى ذلك، قام مدبر النظام بترك هذه الرسالة:" } \ No newline at end of file diff --git a/public/language/ar/tags.json b/public/language/ar/tags.json index 004681a32a..f2eccbd1c0 100644 --- a/public/language/ar/tags.json +++ b/public/language/ar/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "لاوجود لمواضيع تحمل هذا الوسم.", "tags": "بطاقات", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "أدخل البطاقات...", "no_tags": "لاتوجد هناك بطاقات بعد." } \ No newline at end of file diff --git a/public/language/ar/user.json b/public/language/ar/user.json index 29094b2d39..11e27d0fdb 100644 --- a/public/language/ar/user.json +++ b/public/language/ar/user.json @@ -60,6 +60,7 @@ "digest_monthly": "شهريًّا", "send_chat_notifications": "استلام رسالة إلكترونية عند ورود محادثة وأنا غير متصل.", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "هذا المستخدم ليس لديه أي متابع :(", "follows_no_one": "هذا المستخدم لا يتابع أحد :(", "has_no_posts": "هذا المستخدم لم يكتب أي شيء بعد.", @@ -76,5 +77,6 @@ "enable_topic_searching": "تفعيل خاصية البحث داخل المواضيع", "topic_search_help": "في حالة تفعيلها، ستعوض خاصيةُ البحث داخل المواضيع خاصيةَ البحث الخاصة بالمتصفح، فتمكنك بالتالي بالبحث في الموضوع بأكمله دون الاقتصار على مايظهر في الشاشة فحسب.", "follow_topics_you_reply_to": "متابعة المشاركات التي ترد عليها", - "follow_topics_you_create": "متابعة المشاركات التي تكتبها" + "follow_topics_you_create": "متابعة المشاركات التي تكتبها", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/bn/error.json b/public/language/bn/error.json index 946b152345..71ff379ba6 100644 --- a/public/language/bn/error.json +++ b/public/language/bn/error.json @@ -18,7 +18,7 @@ "username-taken": "ইউজারনেম আগেই ব্যবহৃত", "email-taken": "ইমেইল আগেই ব্যবহৃত", "email-not-confirmed": "আপনার ইমেইল এড্রেস নিশ্চিত করা হয় নি, নিশ্চিত করতে এখানে ক্লিক করুন।", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "খুব ছোট ইউজারনেম", diff --git a/public/language/bn/modules.json b/public/language/bn/modules.json index cbd625d77a..3dd01df610 100644 --- a/public/language/bn/modules.json +++ b/public/language/bn/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "৩ মাস", "composer.user_said_in": "%1 বলেছেন %2:", "composer.user_said": "%1 বলেছেনঃ", - "composer.discard": "আপনি কি নিশ্চিত যে আপনি এই পোস্ট বাতিল করতে ইচ্ছুক?" + "composer.discard": "আপনি কি নিশ্চিত যে আপনি এই পোস্ট বাতিল করতে ইচ্ছুক?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/bn/pages.json b/public/language/bn/pages.json index 4ab90a11a2..0da3b3b4a7 100644 --- a/public/language/bn/pages.json +++ b/public/language/bn/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1'র প্রিয় পোস্টগুলো", "user.settings": "সদস্য সেটিংস", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/bn/tags.json b/public/language/bn/tags.json index e99c0f835d..86bbe70e75 100644 --- a/public/language/bn/tags.json +++ b/public/language/bn/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "এই ট্যাগ সম্বলিত কোন টপিক নেই", "tags": "ট্যাগসমূহ", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "ট্যাগ বসান", "no_tags": "এখন পর্যন্ত কোন ট্যাগ নেই" } \ No newline at end of file diff --git a/public/language/bn/user.json b/public/language/bn/user.json index 98f94c7936..b9acb70ad0 100644 --- a/public/language/bn/user.json +++ b/public/language/bn/user.json @@ -60,6 +60,7 @@ "digest_monthly": "মাসিক", "send_chat_notifications": "যদি আমি অনলাইনে না থাকি, সেক্ষেত্রে নতুন চ্যাট মেসেজ আসলে আমাকে ইমেইল করুন", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "এই সদস্যের কোন ফলোয়ার নেই :(", "follows_no_one": "এই সদস্য কাউকে ফলো করছেন না :(", "has_no_posts": "এই সদস্য এখনো কোন পোষ্ট করেন নি", @@ -76,5 +77,6 @@ "enable_topic_searching": "In-Topic সার্চ সক্রীয় করো", "topic_search_help": "যদি এনাবল করা হয়ে থাকে, In-topic সার্চিং ব্রাউজারের ডিফল্ট সার্চের বদলে পুরো টপিকজুড়ে সার্চ করার সুবিধা দিবে, যা কেবলমাত্র বর্তমান স্কৃণে দেখানো অংশের মধ্যে সীমাবদ্ধ থাকবে না। ", "follow_topics_you_reply_to": "আপনার উত্তর দেয়া টপিকগুলো ফলো করুন", - "follow_topics_you_create": "আপনার তৈরীকরা টপিকসমূহ ফলো করুন" + "follow_topics_you_create": "আপনার তৈরীকরা টপিকসমূহ ফলো করুন", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/cs/error.json b/public/language/cs/error.json index 6be7f9f69d..fdfdb5f6d3 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -18,7 +18,7 @@ "username-taken": "Uživatelské jméno je již použito", "email-taken": "Email je již použit", "email-not-confirmed": "Vaše emailová adresa zatím nebyla potvrzena. Kliknutím zde svůj email potvrdíte.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Uživatelské jméno je příliš krátké", diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index f3ea87a4ee..800f56a62a 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 měsíce", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/cs/pages.json b/public/language/cs/pages.json index 15386435af..1bcf760876 100644 --- a/public/language/cs/pages.json +++ b/public/language/cs/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1's Favourite Posts", "user.settings": "User Settings", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/cs/tags.json b/public/language/cs/tags.json index f2003f978a..8fc07c7da2 100644 --- a/public/language/cs/tags.json +++ b/public/language/cs/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Není zde žádné téma s tímto tagem.", "tags": "Tagy", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Vložte tagy ...", "no_tags": "Zatím tu není žádný tag." } \ No newline at end of file diff --git a/public/language/cs/user.json b/public/language/cs/user.json index 55c22b5b0b..46bf40cc1c 100644 --- a/public/language/cs/user.json +++ b/public/language/cs/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Monthly", "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Tohoto uživatele nikdo nesleduje :(", "follows_no_one": "Tento uživatel nikoho nesleduje :(", "has_no_posts": "This user didn't post anything yet.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_create": "Follow topics you create.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/de/email.json b/public/language/de/email.json index b60e620dd8..62c835cefd 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -1,9 +1,9 @@ { "password-reset-requested": "Zurücksetzung des Passworts beantragt - %1!", - "welcome-to": "Willkommen zu %1", + "welcome-to": "Willkommen bei %1", "greeting_no_name": "Hallo", "greeting_with_name": "Hallo %1", - "welcome.text1": "Vielen Dank für die Registrierung mit %1!", + "welcome.text1": "Vielen Dank für die Registrierung bei %1!", "welcome.text2": "Um dein Konto vollständig zu aktivieren, müssen wir überprüfen, ob du Besitzer der E-Mail-Adresse bist, mit der du dich registriert hast.", "welcome.cta": "Klicke hier, um deine E-Mail-Adresse zu bestätigen.", "reset.text1": "Wir haben eine Anfrage auf Zurücksetzung deines Passworts erhalten, wahrscheinlich, weil du es vergessen hast. Falls dies nicht der Fall ist, ignoriere bitte diese E-Mail.", @@ -13,7 +13,7 @@ "reset.notify.text1": "Wir benachrichtigen dich das am %1, dein Passwort erfolgreich geändert wurde.", "reset.notify.text2": "Wenn du das nicht autorisiert hast, bitte benachrichtige umgehend einen Administrator.", "digest.notifications": "Du hast ungelesene Benachrichtigungen von %1:", - "digest.latest_topics": "Aktuellste Themen vom %1", + "digest.latest_topics": "Neueste Themen vom %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 in den letzten %1", diff --git a/public/language/de/error.json b/public/language/de/error.json index f5c852c661..821060aa25 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -18,7 +18,7 @@ "username-taken": "Der Benutzername ist bereits vergeben", "email-taken": "Die E-Mail-Adresse ist bereits vergeben", "email-not-confirmed": "Deine E-Mail wurde noch nicht bestätigt. Bitte klicke hier, um deine E-Mail zu bestätigen.", - "email-not-confirmed-chat": "Der Chat ist deaktiviert bis Du deine E-Mail bestätigt hast", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "Dieses Forum setzt E-Mail-Bestätigung voraus, bitte klick hier um eine E-Mail-Adresse einzugeben", "email-confirm-failed": "Wir konnten deine E-Mail-Adresse nicht bestätigen, bitte versuch es später noch einmal", "username-too-short": "Benutzername ist zu kurz", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index e3ee1c334f..d1c1e61f4f 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Monate", "composer.user_said_in": "%1 sagte in %2:", "composer.user_said": "%1 sagte:", - "composer.discard": "Bist du sicher, dass du diesen Post verwerfen möchtest?" + "composer.discard": "Bist du sicher, dass du diesen Post verwerfen möchtest?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/de/pages.json b/public/language/de/pages.json index 78b7c7469d..1fee71d136 100644 --- a/public/language/de/pages.json +++ b/public/language/de/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Gruppen", "user.favourites": "Von %1 favorisierte Beiträge", "user.settings": "Benutzer-Einstellungen", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 befindet sich derzeit in der Wartung. Bitte komm später wieder.", "maintenance.messageIntro": "Zusätzlich hat der Administrator diese Nachricht hinterlassen:" } \ No newline at end of file diff --git a/public/language/de/tags.json b/public/language/de/tags.json index 9c40b9cc9e..dc1c643266 100644 --- a/public/language/de/tags.json +++ b/public/language/de/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Es gibt keine Themen mit diesem Stichwort.", "tags": "Stichwörter", - "enter_tags_here": "Gib hier Stichwörter ein. %1-%2 Zeichen. Drücke Enter nach jedem Stichwort.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Gib Stichwörter ein...", "no_tags": "Es gibt bisher keine Stichwörter." } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index dcc5a89332..5eaf971ab8 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Monatlich", "send_chat_notifications": "Sende eine E-Mail, wenn eine neue Chat-Nachricht eingeht und ich nicht online bin", "send_post_notifications": "Sende eine E-Mail wenn auf Themen die ich abonniert habe geantwortet wird", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Dieser User hat noch keine Follower.", "follows_no_one": "Dieser User folgt noch niemandem :(", "has_no_posts": "Dieser Nutzer hat noch nichts gepostet.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Suchen innerhalb von Themen aktivieren", "topic_search_help": "Falls aktiviert, wird die Suche im Thema das Standardsuchverhalten des Browsers überschreiben und es Ihnen erlauben, das ganze Thema statt dessen, was sich auf dem Bildschirm befindet, zu durchsuchen.", "follow_topics_you_reply_to": "Folge Themen, auf die du antwortest.", - "follow_topics_you_create": "Folge Themen, die du erstellst." + "follow_topics_you_create": "Folge Themen, die du erstellst.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/el/error.json b/public/language/el/error.json index 26ca6539ba..2d00c366d4 100644 --- a/public/language/el/error.json +++ b/public/language/el/error.json @@ -18,7 +18,7 @@ "username-taken": "Το όνομα χρήστη είναι πιασμένο", "email-taken": "Το email είναι πιασμένο", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Το όνομα χρήστη είναι πολύ μικρό", diff --git a/public/language/el/modules.json b/public/language/el/modules.json index 95dbfa73f2..5646e812eb 100644 --- a/public/language/el/modules.json +++ b/public/language/el/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Μήνες", "composer.user_said_in": "Ο/Η %1 είπε στο %2:", "composer.user_said": "Ο/Η %1 είπε:", - "composer.discard": "Είσαι σίγουρος/η πως θέλεις να πετάξεις αυτή την δημοσίευση;" + "composer.discard": "Είσαι σίγουρος/η πως θέλεις να πετάξεις αυτή την δημοσίευση;", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/el/pages.json b/public/language/el/pages.json index 0b9a89746e..1c2deb4489 100644 --- a/public/language/el/pages.json +++ b/public/language/el/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "Οι αγαπημένες δημοσιεύσεις του/της %1", "user.settings": "Επιλογές Χρήστη", + "user.watched": "Topics watched by %1", "maintenance.text": "Το %1 αυτή την στιγμή συντηρείται. Παρακαλώ έλα αργότερα.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/el/tags.json b/public/language/el/tags.json index 4264ed78aa..e3776579ed 100644 --- a/public/language/el/tags.json +++ b/public/language/el/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Δεν υπάρχουν θέματα με αυτή την ετικέτα.", "tags": "Ετικέτες", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Εισαγωγή ετικετών...", "no_tags": "Δεν υπάρχουν ακόμα ετικέτες." } \ No newline at end of file diff --git a/public/language/el/user.json b/public/language/el/user.json index 306604b44d..19a6d78974 100644 --- a/public/language/el/user.json +++ b/public/language/el/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Μηνιαία", "send_chat_notifications": "Αποστολή email αν μου έρθει μήνυμα συνομιλίας και δεν είμαι συνδεδεμένος", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Αυτός ο χρήστης δεν έχει κανέναν ακόλουθο :(", "follows_no_one": "Αυτός ο χρήστης δεν ακολουθεί κανέναν :(", "has_no_posts": "Αυτός ο χρήστης δεν έχει δημοσιεύσει τίποτα ακόμη.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Ακολούθα τα θέματα στα οποία απαντάς.", - "follow_topics_you_create": "Ακολούθα τα θέματα που δημιουργείς." + "follow_topics_you_create": "Ακολούθα τα θέματα που δημιουργείς.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/en@pirate/error.json b/public/language/en@pirate/error.json index e0700f76c4..17465a20a3 100644 --- a/public/language/en@pirate/error.json +++ b/public/language/en@pirate/error.json @@ -18,7 +18,7 @@ "username-taken": "Username taken", "email-taken": "Email taken", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Username too short", diff --git a/public/language/en@pirate/modules.json b/public/language/en@pirate/modules.json index 3f5fa58753..e43e497da3 100644 --- a/public/language/en@pirate/modules.json +++ b/public/language/en@pirate/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/en@pirate/pages.json b/public/language/en@pirate/pages.json index 15386435af..1bcf760876 100644 --- a/public/language/en@pirate/pages.json +++ b/public/language/en@pirate/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1's Favourite Posts", "user.settings": "User Settings", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/en@pirate/tags.json b/public/language/en@pirate/tags.json index aa9f14c70c..c416d8d4ec 100644 --- a/public/language/en@pirate/tags.json +++ b/public/language/en@pirate/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "There are no topics with this tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Enter tags...", "no_tags": "There are no tags yet." } \ No newline at end of file diff --git a/public/language/en@pirate/user.json b/public/language/en@pirate/user.json index 5fb6a30da2..f0467e46e3 100644 --- a/public/language/en@pirate/user.json +++ b/public/language/en@pirate/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Monthly", "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "This user doesn't have any followers :(", "follows_no_one": "This user isn't following anyone :(", "has_no_posts": "This user didn't post anything yet.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_create": "Follow topics you create.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/en_GB/modules.json b/public/language/en_GB/modules.json index 00a2ba412d..12eeb0f660 100644 --- a/public/language/en_GB/modules.json +++ b/public/language/en_GB/modules.json @@ -18,5 +18,6 @@ "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/en_GB/pages.json b/public/language/en_GB/pages.json index 4095ae38a3..74e24a2e79 100644 --- a/public/language/en_GB/pages.json +++ b/public/language/en_GB/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1's Favourite Posts", "user.settings": "User Settings", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" diff --git a/public/language/en_US/error.json b/public/language/en_US/error.json index e0700f76c4..17465a20a3 100644 --- a/public/language/en_US/error.json +++ b/public/language/en_US/error.json @@ -18,7 +18,7 @@ "username-taken": "Username taken", "email-taken": "Email taken", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Username too short", diff --git a/public/language/en_US/modules.json b/public/language/en_US/modules.json index 4388c738b1..7cdd9b4c48 100644 --- a/public/language/en_US/modules.json +++ b/public/language/en_US/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/en_US/pages.json b/public/language/en_US/pages.json index c6d577d2f5..ca0cb61e2e 100644 --- a/public/language/en_US/pages.json +++ b/public/language/en_US/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1's Favorite Posts", "user.settings": "User Settings", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/en_US/tags.json b/public/language/en_US/tags.json index aa9f14c70c..c416d8d4ec 100644 --- a/public/language/en_US/tags.json +++ b/public/language/en_US/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "There are no topics with this tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Enter tags...", "no_tags": "There are no tags yet." } \ No newline at end of file diff --git a/public/language/en_US/user.json b/public/language/en_US/user.json index 825cc3acae..b6209de55a 100644 --- a/public/language/en_US/user.json +++ b/public/language/en_US/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Monthly", "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "This user doesn't have any followers :(", "follows_no_one": "This user isn't following anyone :(", "has_no_posts": "This user didn't post anything yet.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_create": "Follow topics you create.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/es/error.json b/public/language/es/error.json index 8be673f77d..e7e9723169 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -18,7 +18,7 @@ "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.", - "email-not-confirmed-chat": "No puedes hacer uso del chat hasta que confirmes tu email", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "Este foro requiere confirmación de su email, por favor pulse aquí para introducir un email", "email-confirm-failed": "No se ha podido confirmar su email, por favor inténtelo de nuevo más tarde.", "username-too-short": "Nombre de usuario es demasiado corto", diff --git a/public/language/es/modules.json b/public/language/es/modules.json index 6c7642869b..a63418d2c6 100644 --- a/public/language/es/modules.json +++ b/public/language/es/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 meses", "composer.user_said_in": "%1 dijo en %2:", "composer.user_said": "%1 dijo:", - "composer.discard": "¿Estás seguro de que deseas descartar este mensaje?" + "composer.discard": "¿Estás seguro de que deseas descartar este mensaje?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/es/pages.json b/public/language/es/pages.json index 4cd102fdf0..f8beed5e43 100644 --- a/public/language/es/pages.json +++ b/public/language/es/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Grupos", "user.favourites": "Publicaciones favoritas de %1 ", "user.settings": "Preferencias de usuario", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 está en mantenimiento actualmente. Por favor vuelva en otro momento.", "maintenance.messageIntro": "Adicionalmente, la administración ha dejado este mensaje:" } \ No newline at end of file diff --git a/public/language/es/tags.json b/public/language/es/tags.json index dc1f26a0ba..260ff42eef 100644 --- a/public/language/es/tags.json +++ b/public/language/es/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "No hay temas con esta etiqueta.", "tags": "Etiquetas", - "enter_tags_here": "Introduce las etiquetas aquí. %1-%2 caracteres. Presiona enter después de cada etiqueta.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Introduzca las etiquetas...", "no_tags": "Aún no hay etiquetas." } \ No newline at end of file diff --git a/public/language/es/user.json b/public/language/es/user.json index add6981c5f..7accd46f09 100644 --- a/public/language/es/user.json +++ b/public/language/es/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Mensualmente", "send_chat_notifications": "Enviar un email si recibo un mensaje de chat cuando no esté en línea.", "send_post_notifications": "Enviarme un email cuando se realicen contestaciones en los temas en los que estoy subscrito", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Este usuario no tiene seguidores :(", "follows_no_one": "Este miembro no sigue a nadie :(", "has_no_posts": "Este usuario aún no ha publicado nada.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Activar la búsqueda \"in-topic\"", "topic_search_help": "Si está activada, la búsqueda 'in-topic' invalidará el comportamiento por defecto del navegador de buscar sólo en la página mostrada y le permitirá entonces buscar en el tema al completo, en vez de hacer una búsqueda únicamente sobre el contenido de la pantalla.", "follow_topics_you_reply_to": "Seguir los temas en las que respondes.", - "follow_topics_you_create": "Seguir publicaciones que creas." + "follow_topics_you_create": "Seguir publicaciones que creas.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/et/error.json b/public/language/et/error.json index 303197735f..0bbf35bd3a 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -18,7 +18,7 @@ "username-taken": "Kasutajanimi on juba võetud", "email-taken": "Email on võetud", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Kasutajanimi on liiga lühike", diff --git a/public/language/et/modules.json b/public/language/et/modules.json index a3ab106cf4..2ddda85058 100644 --- a/public/language/et/modules.json +++ b/public/language/et/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 ütles %2:", "composer.user_said": "%1 ütles:", - "composer.discard": "Oled kindel, et soovid selle postituse tühistada?" + "composer.discard": "Oled kindel, et soovid selle postituse tühistada?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/et/pages.json b/public/language/et/pages.json index 4a8ef6408f..d5cffc9d46 100644 --- a/public/language/et/pages.json +++ b/public/language/et/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1's lemmikud postitused", "user.settings": "Kasutaja sätted", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 foorumil on käimas hooldustööd. Palun külastage meid mõne aja pärast uuesti.", "maintenance.messageIntro": "Administraator on jätnud ka omaltpoolt sõnumi:" } \ No newline at end of file diff --git a/public/language/et/tags.json b/public/language/et/tags.json index 5f63e2b3e7..87b8332fad 100644 --- a/public/language/et/tags.json +++ b/public/language/et/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Teemasid, mis sisaldaksid seda märksõna, ei eksisteeri.", "tags": "Märksõnad", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Sisesta märksõnu...", "no_tags": "Siin ei ole veel ühtegi märksõna." } \ No newline at end of file diff --git a/public/language/et/user.json b/public/language/et/user.json index ebf69619dc..2e2b7a37fa 100644 --- a/public/language/et/user.json +++ b/public/language/et/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Iga kuu", "send_chat_notifications": "Saada mulle email kui mulle saabub uus sõnum ja ma ei ole antud hetkel online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Sellel kasutajal pole ühtegi jälgijat :(", "follows_no_one": "See kasutaja ei jälgi kedagi :(", "has_no_posts": "See kasutaja pole midagi postitanud veel.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Järgi teemasid millele vastuse kirjutad.", - "follow_topics_you_create": "Järgi teemasid, mis on sinu loodud." + "follow_topics_you_create": "Järgi teemasid, mis on sinu loodud.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/fa_IR/error.json b/public/language/fa_IR/error.json index 40ce45c9e0..cc32d1873e 100644 --- a/public/language/fa_IR/error.json +++ b/public/language/fa_IR/error.json @@ -18,7 +18,7 @@ "username-taken": "این نام کاربری گرفته شده است.", "email-taken": "این رایانامه گرفته شده است.", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "نام کاربری خیلی کوتاه است.", diff --git a/public/language/fa_IR/modules.json b/public/language/fa_IR/modules.json index 1b15e63d55..0456ff2842 100644 --- a/public/language/fa_IR/modules.json +++ b/public/language/fa_IR/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 در %2 گفته است:", "composer.user_said": "%1 گفته است:", - "composer.discard": "آیا از دور انداختن این دیدگاه اطمینان دارید؟" + "composer.discard": "آیا از دور انداختن این دیدگاه اطمینان دارید؟", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/fa_IR/pages.json b/public/language/fa_IR/pages.json index 42dacfa193..0daf56c95b 100644 --- a/public/language/fa_IR/pages.json +++ b/public/language/fa_IR/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "دیدگاههای پسندیدهٔ %1", "user.settings": "تنظیمات کاربر", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/fa_IR/tags.json b/public/language/fa_IR/tags.json index 82e477f4cc..26a393396b 100644 --- a/public/language/fa_IR/tags.json +++ b/public/language/fa_IR/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "جُستاری با این برچسب وجود ندارد.", "tags": "برچسبها", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Enter tags...", "no_tags": "هنوز برچسبی وجود ندارد." } \ No newline at end of file diff --git a/public/language/fa_IR/user.json b/public/language/fa_IR/user.json index 0b2a48667f..c2b90d3c4c 100644 --- a/public/language/fa_IR/user.json +++ b/public/language/fa_IR/user.json @@ -60,6 +60,7 @@ "digest_monthly": "ماهانه", "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "این کاربر هیچ دنبالکنندهای ندارد :(", "follows_no_one": "این کاربر هیچ کسی را دنبال نمیکند :(", "has_no_posts": "این کاربر هنوز هیچ دیدگاهی نگذاشته است.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_create": "Follow topics you create.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/fi/error.json b/public/language/fi/error.json index 9ca0ec4973..c343ca1345 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -18,7 +18,7 @@ "username-taken": "Käyttäjänimi varattu", "email-taken": "Sähköpostiosoite varattu", "email-not-confirmed": "Sähköpostiasi ei ole vielä vahvistettu, ole hyvä ja napsauta tätä vahvistaaksesi sen.", - "email-not-confirmed-chat": "Et voi käyttää chattia ennen kuin sähköpostisi on vahvistettu", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Käyttäjänimi on liian lyhyt", diff --git a/public/language/fi/modules.json b/public/language/fi/modules.json index cce7d25fbe..7823638f1b 100644 --- a/public/language/fi/modules.json +++ b/public/language/fi/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 kuukautta", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 sanoi:", - "composer.discard": "Oletko varma, että haluat hylätä viestin?" + "composer.discard": "Oletko varma, että haluat hylätä viestin?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/fi/pages.json b/public/language/fi/pages.json index 07d941a4dc..d2fc4993d6 100644 --- a/public/language/fi/pages.json +++ b/public/language/fi/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "Käyttäjän %1 suosikkiviestit", "user.settings": "Käyttäjän asetukset", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/fi/tags.json b/public/language/fi/tags.json index 3d1cf1271b..35903730b2 100644 --- a/public/language/fi/tags.json +++ b/public/language/fi/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Ei viimeisimpiä aiheita tällä tagilla.", "tags": "Tagit", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Syötä tagit...", "no_tags": "Ei vielä yhtään tagia." } \ No newline at end of file diff --git a/public/language/fi/user.json b/public/language/fi/user.json index 3f0768bf00..771ea13132 100644 --- a/public/language/fi/user.json +++ b/public/language/fi/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Kuukausittain", "send_chat_notifications": "Lähetä minulle sähköposti, jos uusi pikaviesti saapuu, kun en ole paikalla", "send_post_notifications": "Lähetä minulle sähköposti, kun tilaamiini aiheisiin tulee vastauksia", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Kukaan ei seuraa tätä käyttäjää :(", "follows_no_one": "Tämä käyttäjä ei seuraa ketään :(", "has_no_posts": "Tämä käyttäjä ei ole kirjoittanut vielä mitään.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Salli aiheen sisäiset haut", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Seuraa aiheita, joihin olen vastannut.", - "follow_topics_you_create": "Seuraa aloittamiani aiheita." + "follow_topics_you_create": "Seuraa aloittamiani aiheita.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/fr/error.json b/public/language/fr/error.json index 51f03aa33f..b2892fde19 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -18,7 +18,7 @@ "username-taken": "Nom d’utilisateur déjà utilisé", "email-taken": "Email déjà utilisé", "email-not-confirmed": "Votre adresse email n'est pas confirmée, cliquez ici pour la valider.", - "email-not-confirmed-chat": "Vous ne pouver discuter tant que votre email n'est pas confirmé", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "Ce forum requiert une vérification de votre adresse email. Veuillez cliquer ici pour entrer une adresse.", "email-confirm-failed": "Votre adresse email n'a pas pu être vérifiée. Veuillez ré-essayer plus tard.", "username-too-short": "Nom d'utilisateur trop court", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index c472c6b402..8589d50ca7 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Mois", "composer.user_said_in": "%1 a dit dans %2 :", "composer.user_said": "%1 a dit :", - "composer.discard": "Êtes-vous sûr de bien vouloir supprimer ce message ?" + "composer.discard": "Êtes-vous sûr de bien vouloir supprimer ce message ?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/fr/pages.json b/public/language/fr/pages.json index 7698a55986..9d57e1d68c 100644 --- a/public/language/fr/pages.json +++ b/public/language/fr/pages.json @@ -14,6 +14,7 @@ "user.groups": "Les Groupes de %1", "user.favourites": "Messages favoris de %1", "user.settings": "Préférences utilisateur", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 est en maintenance. Veuillez revenir un peu plus tard.", "maintenance.messageIntro": "De plus, l'administrateur a laissé ce message:" } \ No newline at end of file diff --git a/public/language/fr/tags.json b/public/language/fr/tags.json index ef226f2efe..477f1a0b56 100644 --- a/public/language/fr/tags.json +++ b/public/language/fr/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Il n'y a aucun sujet ayant ce mot-clé", "tags": "Mots-clés", - "enter_tags_here": "Entrez les mots-clés ici. %1-%2 caractères. Tapez sur \"Entrée\" après chaque mot-clé.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Entrez des mots-clés...", "no_tags": "Il n'y a pas encore de mots-clés." } \ No newline at end of file diff --git a/public/language/fr/user.json b/public/language/fr/user.json index 8786929c78..2f60041e7e 100644 --- a/public/language/fr/user.json +++ b/public/language/fr/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Mensuel", "send_chat_notifications": "Envoyer un e-mail si un nouveau message de chat arrive lorsque je ne suis pas en ligne", "send_post_notifications": "Envoyer un email lors de réponses envoyées aux sujets auxquels je suis abonné.", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Cet utilisateur n'est suivi par personne :(", "follows_no_one": "Cet utilisateur ne suit personne :(", "has_no_posts": "Ce membre n'a rien posté pour le moment", @@ -76,5 +77,6 @@ "enable_topic_searching": "Activer la recherche dans les sujets", "topic_search_help": "Une fois activé, la recherche dans les sujets va remplacer la recherche de page du navigateur et vous permettra de rechercher dans l'intégralité d'un sujet au lieu des seuls posts chargés.", "follow_topics_you_reply_to": "Suivre les sujets auxquels vous répondez.", - "follow_topics_you_create": "Suivre les sujets que vous créez." + "follow_topics_you_create": "Suivre les sujets que vous créez.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/he/error.json b/public/language/he/error.json index d6f29ea755..e210d21334 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -18,7 +18,7 @@ "username-taken": "שם משתמש תפוס", "email-taken": "כתובת אימייל תפוסה", "email-not-confirmed": "כתובת המייל שלך עוד לא אושרה, לחץ כאן על-מנת לאשר את המייל שלך.", - "email-not-confirmed-chat": "לא תוכל לדבר בצ'אט עד שלא תאשר את כתובת המייל שלך", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "שם משתמש קצר מדי", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 43bf264e7b..f4fe8cd0ef 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 חודשים", "composer.user_said_in": "%1 אמר ב%2:", "composer.user_said": "%1 אמר:", - "composer.discard": "האם למחוק פוסט זה?" + "composer.discard": "האם למחוק פוסט זה?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/he/pages.json b/public/language/he/pages.json index aaeb1fcac5..8a39e4fa58 100644 --- a/public/language/he/pages.json +++ b/public/language/he/pages.json @@ -14,6 +14,7 @@ "user.groups": "הקבוצות של %1", "user.favourites": "הפוסטים המועדפים על %1", "user.settings": "הגדרות משתמש", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 כרגע תחת עבודות תחזוקה. אנא חזור בזמן מאוחר יותר.", "maintenance.messageIntro": "בנוסף, המנהל השאיר את ההודעה הזו:" } \ No newline at end of file diff --git a/public/language/he/tags.json b/public/language/he/tags.json index 54ead310ad..3061057672 100644 --- a/public/language/he/tags.json +++ b/public/language/he/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "אין פוסטים עם תגית זו.", "tags": "תגיות", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "הכנס תגיות", "no_tags": "אין עדיין תגיות." } \ No newline at end of file diff --git a/public/language/he/user.json b/public/language/he/user.json index e8b3a5d3a7..61a45f3c5c 100644 --- a/public/language/he/user.json +++ b/public/language/he/user.json @@ -60,6 +60,7 @@ "digest_monthly": "חודשי", "send_chat_notifications": "שלח לי הודעה למייל כאשר הודעת צ'אט נשלחה אלי בזמן שאיני מחובר", "send_post_notifications": "שלח לי הודעה למייל כאשר תגובות חדשות פורסמו לנושאים שאני עוקב אחריהם", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "למשתמש זה אין עוקבים :(", "follows_no_one": "משתמש זה אינו עוקב אחרי אחרים :(", "has_no_posts": "המשתמש הזה עוד לא פרסם כלום.", @@ -76,5 +77,6 @@ "enable_topic_searching": "הפעל חיפוש בתוך נושא", "topic_search_help": "אם מופעל, חיפוש בתוך נושא יעקוף את מנגנון החיפוש הרגיל של הדפדפן שלך על מנת לאפשר לך לחפש בתוך כל הנושא ולא רק מה שמוצג כרגע בעמוד.", "follow_topics_you_reply_to": "עקוב אחר נושאים שהגבת עליהם.", - "follow_topics_you_create": "עקוב אחר נושאים שיצרת." + "follow_topics_you_create": "עקוב אחר נושאים שיצרת.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/hu/category.json b/public/language/hu/category.json index b36e9fc37a..2815eaab43 100644 --- a/public/language/hu/category.json +++ b/public/language/hu/category.json @@ -1,9 +1,9 @@ { "new_topic_button": "Új témakör", - "guest-login-post": "Log in to post", + "guest-login-post": "A hozzászóláshoz be kell lépni", "no_topics": "<strong>Nincs nyitva egy téma sem ebben a kategóriában.</strong>Hozzunk létre egyet.", "browsing": "böngészés", "no_replies": "Nem érkezett válasz", "share_this_category": "Kategória megosztása", - "ignore": "Figyelmen kívül hagyás" + "ignore": "Ignorálás" } \ No newline at end of file diff --git a/public/language/hu/email.json b/public/language/hu/email.json index 8430b8ff27..45c6be2630 100644 --- a/public/language/hu/email.json +++ b/public/language/hu/email.json @@ -9,20 +9,20 @@ "reset.text1": "Kaptunk egy kérést jelszava visszaállításához, valószínűleg azért, mert elfelejtette azt. Ha ez nem így van, hagyja figyelmen kívül ezt a levelet.", "reset.text2": "Ha szeretné, hogy továbbra alaphelyzetbe a jelszavát, kérjük kattintson az alábbi linkre:", "reset.cta": "Kattints ide a jelszavad visszaállításához", - "reset.notify.subject": "Password successfully changed", - "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", - "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "reset.notify.subject": "Jelszó sikeresen megváltoztatva", + "reset.notify.text1": "Értesítünk, hogy %1 névhez tartozó jelszavad sikeresen megváltozott.", + "reset.notify.text2": "Ha nem te voltál az, kérlek értesíts egy adminisztrátort azonnal.", "digest.notifications": "Olvasatlan értesítéseid vannak a következőtől: %1", "digest.latest_topics": "Legutóbbi témák a következőből: %1", "digest.cta": "Kattints ide, hogy meglátogasd a következőt: %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.info": "Ez a hírlevél a feliratkozási beállításaid miatt lett kiküldve.", "digest.no_topics": "Nem volt aktív témakör az elmúlt %1", "notif.chat.subject": "Új chat üzenet érkezett a következőtől: %1", "notif.chat.cta": "Kattints ide a beszélgetés folytatásához", - "notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "notif.chat.unsub.info": "Ez a chat-értesítés a feliratkozási beállításaid miatt lett kiküldve.", + "notif.post.cta": "Kattints ide a teljes téma olvasásához", + "notif.post.unsub.info": "Ez a hozzászólás-értesítés a feliratkozási beállításaid miatt lett kiküldve.", + "test.text1": "Ez egy teszt levél, ami által ellenőrizzük, hogy a levelező helyesen lett beállítva a fórumodon.", "unsub.cta": "Kattintson ide megváltoztatni ezeket a beállításokat", "closing": "Köszönjük!" } \ No newline at end of file diff --git a/public/language/hu/error.json b/public/language/hu/error.json index e03041b557..39ec76c011 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -1,7 +1,7 @@ { "invalid-data": "Érvénytelen adat", "not-logged-in": "Úgy tűnik, nem vagy bejelentkezve.", - "account-locked": "A fiókod ideiglenesen le lett zárva.", + "account-locked": "A fiókod ideiglenesen zárolva lett.", "search-requires-login": "A kereső használatához szükséges egy fiók! Kérlek jelenltkezz be vagy regisztrálj!", "invalid-cid": "Érvénytelen kategória azonosító", "invalid-tid": "Érvénytelen téma azonosító", @@ -18,9 +18,9 @@ "username-taken": "Foglalt felhasználónév", "email-taken": "Foglalt e-mail", "email-not-confirmed": "Az e-mail címed még nem lett ellenőrizve, kérlek kattints ide az e-mail címed ellenőrzéséhez!", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", - "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", - "email-confirm-failed": "We could not confirm your email, please try again later.", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", + "no-email-to-confirm": "Ez a fórum e-mail megerősítést kíván, kérlek kattints ide egy cím beírásához", + "email-confirm-failed": "Nem tudtuk ellenőrizni az e-mail címedet, kérlek próbálkozz később.", "username-too-short": "Túl rövid felhasználónév", "username-too-long": "Túl hosszú felhasználónév", "user-banned": "Kitiltott felhasználó", @@ -32,32 +32,32 @@ "no-user": "Nem létező felhasználó", "no-teaser": "Teaser does not exist", "no-privileges": "Nincs elég jogod ehhez a művelethez.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", + "no-emailers-configured": "Nincs levelező beállítva, ezért a teszt e-mail nem került kiküldésre.", "category-disabled": "Kategória kikapcsolva", "topic-locked": "Téma lezárva", - "post-edit-duration-expired": "You are only allowed to edit posts for %1 seconds after posting", - "still-uploading": "Please wait for uploads to complete.", - "content-too-short": "Please enter a longer post. Posts should contain at least %1 characters.", - "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", - "title-too-short": "Please enter a longer title. Titles should contain at least %1 characters.", - "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", - "too-many-posts": "You can only post once every %1 seconds - please wait before posting again", - "too-many-posts-newbie": "As a new user, you can only post once every %1 seconds until you have earned %2 reputation - please wait before posting again", - "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 characters", - "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 characters", - "file-too-big": "Maximum allowed file size is %1 kbs - please upload a smaller file", - "cant-vote-self-post": "You cannot vote for your own post", - "already-favourited": "You have already favourited this post", - "already-unfavourited": "You have already unfavourited this post", - "cant-ban-other-admins": "You can't ban other admins!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", - "invalid-file-type": "Invalid file type. Allowed types are: %1", + "post-edit-duration-expired": "A hozzászólásaidat %1 másodpercig szerkesztheted, miután beküldted azt", + "still-uploading": "Kérlek várj, amíg a feltöltés befejeződik.", + "content-too-short": "Kérlek hosszabb hozzászólást írj be. Legalább %1 karakternek kell lennie.", + "content-too-long": "Kérlek rövidebb hozzászólást írj be. Legfeljebb %1 karakter lehet.", + "title-too-short": "Kérlek hosszabb címet válassz. Legalább %1 karakternek kell lennie.", + "title-too-long": "Kérlek rövidebb címet válassz. Legfeljebb %1 karakter lehet.", + "too-many-posts": "%1 másodpercenként csak egy hozzászólást írhatsz - kérlek várj mielőtt újból hozzászólnál", + "too-many-posts-newbie": "Mint friss tag, csak egy hozzászólást küldhetsz be %1 másodpercenként, míg nem kapsz %2 jó hírnevet - kérlek várj mielőtt újból hozzászólnál", + "tag-too-short": "Kérlek hosszabb címkét válassz. Legalább %1 karakter hosszúnak kell lennie", + "tag-too-long": "Kérlek rövidebb címkét válassz. Legfeljebb %1 karakter lehet", + "file-too-big": "Maximális engedélyezett fájlméret %1 kbs - kérlek kisebb fájlt tölts fel", + "cant-vote-self-post": "Nem szavazhatsz a saját hozzászólásodra", + "already-favourited": "Már bejelölted Kedvencnek ezt a hozzászólást", + "already-unfavourited": "Már kivetted a Kedvenceid közül ezt a hozzászólást", + "cant-ban-other-admins": "Nem tilthatsz ki másik adminisztrátort!", + "invalid-image-type": "Érvénytelen a kép típusa. Engedett kiterjesztések: %1", + "invalid-image-extension": "Érvénytelen a kép kiterjesztése", + "invalid-file-type": "Érvénytelen a fájl típusa. Engedélyezett kiterjesztések: %1", "group-name-too-short": "A csoport név túl rövid", "group-already-exists": "A csoport nem létezik", "group-name-change-not-allowed": "A csoport névváltoztatás nem engedélyezett", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "Már a tagja vagy ennek a csoportnak", + "group-needs-owner": "Ennek a csoportnak lennie kell legalább egy tulajdonosnak.", "post-already-deleted": "Ez a bejegyzés mát törlésre került", "post-already-restored": "Ez a bejegyzés már visszaállításra került", "topic-already-deleted": "Ezt a témakör már törlésre került", @@ -66,16 +66,16 @@ "invalid-file": "Érvénytelen fájl", "uploads-are-disabled": "A feltöltés nem engedélyezett", "signature-too-long": "Sajnáljuk, az aláírás nem lehet hosszabb %1 karakternél.", - "cant-chat-with-yourself": "You can't chat with yourself!", - "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", - "too-many-messages": "You have sent too many messages, please wait awhile.", - "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", - "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", - "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", + "cant-chat-with-yourself": "Nem cseveghetsz magaddal!", + "chat-restricted": "Ez a felhasználó korlátozta a chat beállításait. Csak akkor cseveghetsz vele, miután felvett a követettek közé téged", + "too-many-messages": "Túl sok üzenetet küldtél, kérlek várj egy picit.", + "reputation-system-disabled": "Hírnév funkció kikapcsolva.", + "downvoting-disabled": "Leszavazás funkció kikapcsolva", + "not-enough-reputation-to-downvote": "Nem rendelkezel elég Hírnév ponttal, hogy leszavazhasd ezt a hozzászólást", + "not-enough-reputation-to-flag": "Nem rendelkezel elég Hírnév ponttal, hogy jelentsd ezt a hozzászólást", + "reload-failed": "NodeBB egy hibát észlelt újratöltés közben: \"% 1\". A fórum továbbra is kiszolgálja a kliens-oldali eszközöket, bár vissza kellene csinálnod amit az újratöltés előtt elállítottál.", "registration-error": "Regisztrációs hiba", - "parse-error": "Something went wrong while parsing server response", - "wrong-login-type-email": "Please use your email to login", - "wrong-login-type-username": "Please use your username to login" + "parse-error": "Hiba történt a szerver válaszának feldolgozása közben", + "wrong-login-type-email": "Kérlek az e-mail címedet használd a belépéshez", + "wrong-login-type-username": "Kérlek a felhasználónevedet használd a belépéshez" } \ No newline at end of file diff --git a/public/language/hu/global.json b/public/language/hu/global.json index 6f3926d6a5..ef775f0510 100644 --- a/public/language/hu/global.json +++ b/public/language/hu/global.json @@ -3,53 +3,53 @@ "search": "Keresés", "buttons.close": "Mégsem", "403.title": "Hozzáférés megtagadva", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should <a href='%1/login'>try logging in</a>?", + "403.message": "Úgy tűnik, hogy rábukkantál egy olyan oldalra, amihez nincs hozzáférésed.", + "403.login": "Talán meg kellene próbálnod <a href='%1/login'>belépni</a>?", "404.title": "Nincs találat", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the <a href='%1/'>home page</a>.", + "404.message": "Úgy tűnik, hogy rábukkantál egy olyan oldalra ami nem létezik. Visszatérés a <a href='%1/'>kezdőlapra</a>", "500.title": "Belső hiba.", "500.message": "Hoppá! Úgy tűnik valami hiba történt!", "register": "Regisztráció", "login": "Belépés", "please_log_in": "Jelentkezzünk be", "logout": "Kijelentkezés", - "posting_restriction_info": "Posting is currently restricted to registered members only, click here to log in.", + "posting_restriction_info": "A hozzászólás regisztrációhoz kötött, kérlek kattints ide a bejelentkezéshez.", "welcome_back": "Üdvözlet", "you_have_successfully_logged_in": "Sikeres bejelentkezés", "save_changes": "Változások mentése", "close": "Bezárás", "pagination": "Lapozás", "pagination.out_of": "%1 - %2", - "pagination.enter_index": "Enter index", + "pagination.enter_index": "Írj be egy számot", "header.admin": "Admin", "header.recent": "Friss", "header.unread": "Olvasatlan", - "header.tags": "Tags", + "header.tags": "Címkék", "header.popular": "Népszerű", "header.users": "Felhasználók", - "header.groups": "Groups", + "header.groups": "Csoportok", "header.chats": "Chat", "header.notifications": "Értesítések", "header.search": "Keresés", "header.profile": "Profil", "notifications.loading": "Értesítések Betöltése", - "chats.loading": "Chat-ek Betöltése", + "chats.loading": "Chat Betöltése", "motd.welcome": "Üdvözlet a NodeBB-n, a jövő fórum platformján.", "previouspage": "Előző Oldal", "nextpage": "Következő Oldal", "alert.success": "Sikeres", "alert.error": "Hiba", "alert.banned": "Tiltva", - "alert.banned.message": "You have just been banned, you will now be logged out.", + "alert.banned.message": "Kitiltottak, ezért most ki leszel léptetve.", "alert.unfollow": "Nem követed tovább: %1!", "alert.follow": "Mostantól követed: %1!", "online": "Online", - "users": "Users", - "topics": "Topics", - "posts": "Hozzászólás", - "views": "Megtekintés", - "reputation": "Reputation", - "read_more": "read more", + "users": "Felhasználók", + "topics": "Témák", + "posts": "Hozzászólások", + "views": "Megtekintések", + "reputation": "Hírnév", + "read_more": "tovább olvas", "posted_ago_by_guest": "posted %1 by Guest", "posted_ago_by": "posted %1 by %2", "posted_ago": "posted %1", @@ -63,19 +63,19 @@ "norecentposts": "Nincs legutóbbi hozzászólás", "norecenttopics": "Nincs friss téma", "recentposts": "Friss hozzászólások", - "recentips": "Utoljára bejelentkezett IP", + "recentips": "Utoljára bejelentkezett IP címek", "away": "Távol van", "dnd": "Elfoglalt", "invisible": "Láthatatlan", "offline": "Offline", "email": "Email", - "language": "Language", - "guest": "Guest", - "guests": "Guests", - "updated.title": "Forum Updated", - "updated.message": "This forum has just been updated to the latest version. Click here to refresh the page.", - "privacy": "Privacy", - "follow": "Follow", - "unfollow": "Unfollow", - "delete_all": "Delete All" + "language": "Nyelv", + "guest": "Vendég", + "guests": "Vendég", + "updated.title": "Fórum frissítve", + "updated.message": "A fórum frissítve lett a legutolsó verzióra. Kattints ide az oldal újratöltéséhez.", + "privacy": "Titoktartás", + "follow": "Követés", + "unfollow": "Nem követem", + "delete_all": "Összes törlése" } \ No newline at end of file diff --git a/public/language/hu/modules.json b/public/language/hu/modules.json index c339652efe..c708c09d98 100644 --- a/public/language/hu/modules.json +++ b/public/language/hu/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 hónap", "composer.user_said_in": "%1 válasza erre %2:", "composer.user_said": "%1 válasza:", - "composer.discard": "Biztosan elvetjük ezt a hozzászólást?" + "composer.discard": "Biztosan elvetjük ezt a hozzászólást?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/hu/pages.json b/public/language/hu/pages.json index 53b98e8562..547e924217 100644 --- a/public/language/hu/pages.json +++ b/public/language/hu/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's csoport", "user.favourites": "%1 Kedvenc Hozzászólásai", "user.settings": "Felhasználói Beállítások", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 jelenleg karbantartás alatt van. Kérlek nézz vissza késöbb!", "maintenance.messageIntro": "Ezenkívúl, az adminisztrátor ezt az üzenetet hagyta:" } \ No newline at end of file diff --git a/public/language/hu/tags.json b/public/language/hu/tags.json index aa7a02a772..baddf9f8d6 100644 --- a/public/language/hu/tags.json +++ b/public/language/hu/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Nem létezik témakör ezzel a címkével.", "tags": "Címkék", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Címke megadása...", "no_tags": "Nincs címke." } \ No newline at end of file diff --git a/public/language/hu/user.json b/public/language/hu/user.json index bacce74415..ba7f403c7c 100644 --- a/public/language/hu/user.json +++ b/public/language/hu/user.json @@ -18,7 +18,7 @@ "profile_views": "Megtekintések", "reputation": "Hírnév", "favourites": "Kedvencek", - "watched": "Megtekintve", + "watched": "Megfigyeli", "followers": "Követők", "following": "Követve", "signature": "Aláírás", @@ -33,17 +33,17 @@ "uploaded_picture": "Feltöltött kép", "upload_new_picture": "Új kép feltöltése", "upload_new_picture_from_url": "Új kép feltöltése adott URL-ről", - "current_password": "Current Password", + "current_password": "Jelenlegi jelszó", "change_password": "Jelszó megváltoztatása", "change_password_error": "Helytelen jelszó!", - "change_password_error_wrong_current": "Your current password is not correct!", + "change_password_error_wrong_current": "A jelenlegi jelszavad nem megfelelő!", "change_password_error_length": "A jelszó túl rövid!", "change_password_error_match": "A jelszavak nem egyeznek!", - "change_password_error_privileges": "You do not have the rights to change this password.", + "change_password_error_privileges": "Nincs jogod megváltoztatni ezt a jelszót.", "change_password_success": "A jelszavad frissítve!", "confirm_password": "Jelszó megerősítése", "password": "Jelszó", - "username_taken_workaround": "The username you requested was already taken, so we have altered it slightly. You are now known as <strong>%1</strong>", + "username_taken_workaround": "A kívánt felhasználónév már foglalt, így változtatnunk kellett rajta egy kicsit. Mostantól <strong>%1</strong> nicknév alatt vagy ismert.", "upload_picture": "Kép feltöltése", "upload_a_picture": "Egy kép feltöltése", "image_spec": "Csak PNG, JPG vagy GIF kiterjesztésű fájlokat tölthetsz fel", @@ -52,19 +52,20 @@ "show_email": "E-mail címem mutatása", "show_fullname": "A teljes nevem mutatása", "restrict_chats": "Csak olyanok tudjanak chat üzeneteket írni nekem, akiket követek", - "digest_label": "Subscribe to Digest", - "digest_description": "Subscribe to email updates for this forum (new notifications and topics) according to a set schedule", - "digest_off": "Off", - "digest_daily": "Daily", - "digest_weekly": "Weekly", - "digest_monthly": "Monthly", + "digest_label": "Feliratkozás a hírlevélre", + "digest_description": "E-mailben kapott frissítésekre (új értesítések, témák esetében) való feliratkozás, a beállított időintervallum szerint", + "digest_off": "Kikapcsolva", + "digest_daily": "Napi", + "digest_weekly": "Heti", + "digest_monthly": "Havi", "send_chat_notifications": "E-mail küldése, amennyiben chat üzenetem érkezett és nem vagyok aktív", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "E-mail küldése, amikor válasz érkezik azokhoz a témákhoz, amelyekre feliratkoztam", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Ezt a felhasználót nem követi senki :(", "follows_no_one": "Ez a felhasználó nem követ senkit :(", "has_no_posts": "Ennek a felhasználónak még nincsen hozzászólása.", - "has_no_topics": "This user didn't post any topics yet.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_topics": "Ez a felhasználó nem nyitott egyetlen témát sem még.", + "has_no_watched_topics": "Ez a felhasználó nem figyel egyetlen témát sem még.", "email_hidden": "E-mail rejtett", "hidden": "rejtett", "paginate_description": "Oldalszámok használata a témáknál és hozzászólásoknál a végtelen görgetés helyett.", @@ -72,9 +73,10 @@ "posts_per_page": "Hozzászólás oldalanként", "notification_sounds": "Hang lejátszása ha értesítés érkezett.", "browsing": "Browsing Settings", - "open_links_in_new_tab": "Open outgoing links in new tab?", + "open_links_in_new_tab": "Kívülre mutató linkek megnyitása új fülön?", "enable_topic_searching": "Témán belüli keresés bekapcsolása", - "topic_search_help": "Amennyiben be van kapcsolva, a témán belüli keresés fellül fogja írni a böngésző alapértelmezett oldalon belüli keresőjét és engedélyezni fogja neked, hogy a teljes témában kereshess, ne csak abban, ami jelenleg is megjelenik a képernyőn.", - "follow_topics_you_reply_to": "Minden olyan téma követése, amire válaszolsz.", - "follow_topics_you_create": "Minden általad létrehozott téma követése." + "topic_search_help": "Amennyiben be van kapcsolva, a témán belüli keresés felül fogja írni a böngésző alapértelmezett oldalon belüli keresőjét és engedélyezni fogja neked, hogy a teljes témában kereshess, ne csak abban, ami jelenleg is megjelenik a képernyőn.", + "follow_topics_you_reply_to": "Minden olyan téma követése, amihez hozzászóltál.", + "follow_topics_you_create": "Minden általad létrehozott téma követése.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/id/error.json b/public/language/id/error.json index d2ceed9a23..6f1e7b289f 100644 --- a/public/language/id/error.json +++ b/public/language/id/error.json @@ -18,7 +18,7 @@ "username-taken": "Username sudah terdaftar", "email-taken": "Email sudah terdaftar", "email-not-confirmed": "Email kamu belum dikonfirmasi, klik disini untuk mengkonfirmasi email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Username terlalu pendek", diff --git a/public/language/id/modules.json b/public/language/id/modules.json index 53320cf627..5bd4fe85c6 100644 --- a/public/language/id/modules.json +++ b/public/language/id/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Bulan", "composer.user_said_in": "%1 berkata di %2: ", "composer.user_said": "%1 berkata:", - "composer.discard": "Kamu yakin akan membuang posting ini?" + "composer.discard": "Kamu yakin akan membuang posting ini?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/id/pages.json b/public/language/id/pages.json index 83b55a2b22..08872d82de 100644 --- a/public/language/id/pages.json +++ b/public/language/id/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "Posting Favorit %1", "user.settings": "Pengaturan Pengguna", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 saat ini sedang dalam masa pemeliharaan. Silahkan kembali lain waktu.", "maintenance.messageIntro": "Tambahan, Administrator meninggalkan pesan ini:" } \ No newline at end of file diff --git a/public/language/id/tags.json b/public/language/id/tags.json index 647542884e..8485344416 100644 --- a/public/language/id/tags.json +++ b/public/language/id/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Tidak ada topik dengan tag ini.", "tags": "Tag", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Masukkan tag...", "no_tags": "Belum ada tag." } \ No newline at end of file diff --git a/public/language/id/user.json b/public/language/id/user.json index ce82e7888f..e7a7112465 100644 --- a/public/language/id/user.json +++ b/public/language/id/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Bulanan", "send_chat_notifications": "Kirimkan email jika menerima pesan percakapan dan saya sedang tidak online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "User ini tidak memiliki pengikut :(", "follows_no_one": "User ini tidak mengikuti seorangpun :(", "has_no_posts": "User ini belum pernah membuat posting.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Gunakan Pencarian Di dalam Topik", "topic_search_help": "Jika digunakan, pencarian di dalam topik akan mengambil alih tindakan pencarian default browser dan mengijinkan kamu untuk mencari keseluruhan topik sebagai pengganti pencarian hanya yang tampil pada layar saja.", "follow_topics_you_reply_to": "Ikuti topik yang kamu balas.", - "follow_topics_you_create": "Ikuti topik yang kamu buat." + "follow_topics_you_create": "Ikuti topik yang kamu buat.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/it/email.json b/public/language/it/email.json index be6567c1c2..e351a25036 100644 --- a/public/language/it/email.json +++ b/public/language/it/email.json @@ -11,7 +11,7 @@ "reset.cta": "Clicca qui per resettare la tua password", "reset.notify.subject": "Possword modificata con successo.", "reset.notify.text1": "Ti informiamo che in data %1, la password è stata cambiata con successo.", - "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "reset.notify.text2": "Se non hai autorizzato questo, per favore notifica immediatamente un amministratore.", "digest.notifications": "Hai una notifica non letta da %1:", "digest.latest_topics": "Ultimi argomenti su %1", "digest.cta": "Clicca qui per visitare %1", @@ -21,7 +21,7 @@ "notif.chat.cta": "Clicca qui per continuare la conversazione", "notif.chat.unsub.info": "Questa notifica di chat ti è stata inviata perché l'hai scelta nelle impostazioni.", "notif.post.cta": "Clicca qui per leggere il topic completo.", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.unsub.info": "Questo post ti è stato notificato in base alle tue impostazioni di sottoscrizione.", "test.text1": "Questa è una email di test per verificare che il servizio di invio email è configurato correttamente sul tuo NodeBB.", "unsub.cta": "Clicca qui per modificare queste impostazioni", "closing": "Grazie!" diff --git a/public/language/it/error.json b/public/language/it/error.json index 777c76856c..6858916193 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -18,9 +18,9 @@ "username-taken": "Nome utente già preso", "email-taken": "Email già esistente", "email-not-confirmed": "La tua Email deve essere ancora confermata, per favore clicca qui per confermare la tua Email.", - "email-not-confirmed-chat": "Non potrai chattare finchè non avrai confermato la tua email", - "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", - "email-confirm-failed": "We could not confirm your email, please try again later.", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", + "no-email-to-confirm": "Questo forum richiede la conferma dell'indirizzo email, per favore clicca qui per inserirne uno", + "email-confirm-failed": "Non possiamo confermare la tua email, per favore prova ancora più tardi.", "username-too-short": "Nome utente troppo corto", "username-too-long": "Nome utente troppo lungo", "user-banned": "Utente bannato", @@ -77,5 +77,5 @@ "registration-error": "Errore nella registrazione", "parse-error": "Qualcosa è andato storto durante l'analisi della risposta proveniente dal server", "wrong-login-type-email": "Please use your email to login", - "wrong-login-type-username": "Please use your username to login" + "wrong-login-type-username": "Per favore usa il tuo nome utente per accedere" } \ No newline at end of file diff --git a/public/language/it/modules.json b/public/language/it/modules.json index a049d581ae..dc6d3dcf78 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Mesi", "composer.user_said_in": "%1 ha detto in %2:", "composer.user_said": "%1 ha detto:", - "composer.discard": "Sei sicuro di voler scartare questo post?" + "composer.discard": "Sei sicuro di voler scartare questo post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json index a52aabb969..c3f067b0cf 100644 --- a/public/language/it/notifications.json +++ b/public/language/it/notifications.json @@ -2,7 +2,7 @@ "title": "Notifiche", "no_notifs": "Non hai nuove notifiche", "see_all": "Vedi tutte le Notifiche", - "mark_all_read": "Mark all notifications read", + "mark_all_read": "Segna tutte le notifiche come già lette", "back_to_home": "Indietro a %1", "outgoing_link": "Link in uscita", "outgoing_link_message": "Stai lasciando %1.", diff --git a/public/language/it/pages.json b/public/language/it/pages.json index 72d2a3e042..f7395c9d50 100644 --- a/public/language/it/pages.json +++ b/public/language/it/pages.json @@ -11,9 +11,10 @@ "user.followers": "Persone che seguono %1", "user.posts": "Post creati da %1", "user.topics": "Discussioni create da %1", - "user.groups": "%1's Groups", + "user.groups": "%1's Gruppi", "user.favourites": "Post Favoriti da %1", "user.settings": "Impostazioni Utente", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 è attualmente in manutenzione. Per favore ritorna più tardi.", "maintenance.messageIntro": "Inoltre, l'amministratore ha lasciato questo messaggio:" } \ No newline at end of file diff --git a/public/language/it/tags.json b/public/language/it/tags.json index c3364a0bbf..5fcdf9ff47 100644 --- a/public/language/it/tags.json +++ b/public/language/it/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Non ci sono discussioni con questo tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Inserisci i tags...", "no_tags": "Non ci sono ancora tags." } \ No newline at end of file diff --git a/public/language/it/user.json b/public/language/it/user.json index e93be01541..3dd7971b11 100644 --- a/public/language/it/user.json +++ b/public/language/it/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Mensile", "send_chat_notifications": "Invia una email se arriva un nuovo messaggio di chat e non sono online", "send_post_notifications": "Invia una email quando le risposte sono fatte a discussioni a cui sono sottoscritto", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Questo utente non è seguito da nessuno :(", "follows_no_one": "Questo utente non segue nessuno :(", "has_no_posts": "Questo utente non ha ancora postato nulla.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Abilita la ricerca negli argomenti", "topic_search_help": "Se abilitata, la ricerca negli argomenti sovrascriverà la pagina di ricerca preimpostata del browser per consentirti di cercare all'interno delle discussioni, anziché soltanto nel contenuto visibile a schermo.", "follow_topics_you_reply_to": "Segui le discussioni in cui rispondi.", - "follow_topics_you_create": "Segui le discussioni che crei." + "follow_topics_you_create": "Segui le discussioni che crei.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/ja/error.json b/public/language/ja/error.json index 95cf6728ac..d53e73b76e 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -18,7 +18,7 @@ "username-taken": "ユーザー名が取られた", "email-taken": "メールアドレスが使用された", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Username too short", diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json index 0b27bf28d1..1a30c49b7d 100644 --- a/public/language/ja/modules.json +++ b/public/language/ja/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/ja/pages.json b/public/language/ja/pages.json index eb5274c6f1..fda23c6d35 100644 --- a/public/language/ja/pages.json +++ b/public/language/ja/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1のお気に入りポスト", "user.settings": "ユーザー設定", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/ja/tags.json b/public/language/ja/tags.json index aa9f14c70c..c416d8d4ec 100644 --- a/public/language/ja/tags.json +++ b/public/language/ja/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "There are no topics with this tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Enter tags...", "no_tags": "There are no tags yet." } \ No newline at end of file diff --git a/public/language/ja/user.json b/public/language/ja/user.json index 0b2b065a94..9f94a46a32 100644 --- a/public/language/ja/user.json +++ b/public/language/ja/user.json @@ -60,6 +60,7 @@ "digest_monthly": "マンスリー", "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "フォロワーはまだいません :(", "follows_no_one": "フォロー中のユーザーはまだいません :(", "has_no_posts": "まだポストを投稿したことありません。", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_create": "Follow topics you create.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/ko/error.json b/public/language/ko/error.json index bf1eb8d8e4..2c9de646c5 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -18,7 +18,7 @@ "username-taken": "이미 사용 중인 사용자 이름입니다.", "email-taken": "이미 사용 중인 이메일입니다.", "email-not-confirmed": "아직 이메일이 인증되지 않았습니다. 여기를 누르면 인증 메일을 발송할 수 있습니다.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "사용자 이름이 너무 짧습니다.", diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index 2a9c765868..fbdd01a7ae 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3개월", "composer.user_said_in": "%1님이 %2에서 한 말:", "composer.user_said": "%1님의 말:", - "composer.discard": "이 게시물을 지우겠습니까?" + "composer.discard": "이 게시물을 지우겠습니까?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/ko/pages.json b/public/language/ko/pages.json index ce1f9e5a05..d5cd1ed4a4 100644 --- a/public/language/ko/pages.json +++ b/public/language/ko/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1님이 좋아하는 게시물", "user.settings": "설정", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 사이트는 현재 점검 중입니다. 나중에 다시 방문해주세요.", "maintenance.messageIntro": "다음은 관리자가 전하는 메시지입니다." } \ No newline at end of file diff --git a/public/language/ko/tags.json b/public/language/ko/tags.json index a50fc5e9e1..8e1011bd29 100644 --- a/public/language/ko/tags.json +++ b/public/language/ko/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "이 태그에 해당하는 주제가 없습니다.", "tags": "태그", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "태그 입력...", "no_tags": "아직 아무런 태그도 없습니다." } \ No newline at end of file diff --git a/public/language/ko/user.json b/public/language/ko/user.json index c656a64242..bf10413609 100644 --- a/public/language/ko/user.json +++ b/public/language/ko/user.json @@ -60,6 +60,7 @@ "digest_monthly": "매월", "send_chat_notifications": "오프라인일 때 채팅 메시지가 도착하면 알림 메일을 보냅니다.", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "아무도 이 사용자를 팔로우하지 않습니다.", "follows_no_one": "이 사용자는 아무도 팔로우하지 않습니다.", "has_no_posts": "이 사용자는 게시물을 작성하지 않았습니다.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "답글을 작성한 주제를 팔로우합니다.", - "follow_topics_you_create": "직접 작성한 주제를 팔로우합니다." + "follow_topics_you_create": "직접 작성한 주제를 팔로우합니다.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/lt/category.json b/public/language/lt/category.json index 149a102553..3694a767a7 100644 --- a/public/language/lt/category.json +++ b/public/language/lt/category.json @@ -1,9 +1,9 @@ { "new_topic_button": "Nauja tema", - "guest-login-post": "Log in to post", + "guest-login-post": "Prisijungti įrašų paskelbimui", "no_topics": "<strong>Šioje kategorijoje temų nėra.</strong><br/>Kodėl gi jums nesukūrus naujos?", "browsing": "naršo", "no_replies": "Niekas dar neatsakė", "share_this_category": "Pasidalinti šią kategoriją", - "ignore": "Ignore" + "ignore": "Nepaisyti" } \ No newline at end of file diff --git a/public/language/lt/email.json b/public/language/lt/email.json index f290435e75..af0968b55e 100644 --- a/public/language/lt/email.json +++ b/public/language/lt/email.json @@ -1,28 +1,28 @@ { "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", + "welcome-to": "Sveiki atvykę į %1", + "greeting_no_name": "Sveiki", + "greeting_with_name": "Sveiki %1", "welcome.text1": "Thank you for registering with %1!", "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", + "welcome.cta": "El. adreso patvirtinimui spauskite čia", "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "reset.notify.subject": "Password successfully changed", + "reset.cta": "Slaptažodžio atstatymui spauskite čia", + "reset.notify.subject": "Slaptažodis sėkmingai pakeistas", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", - "digest.notifications": "You have unread notifications from %1:", + "digest.notifications": "Turite neskaitytų pranešimų nuo %1:", "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", + "digest.cta": "Kad aplankyti %1, spauskite čia", "digest.unsub.info": "This digest was sent to you due to your subscription settings.", "digest.no_topics": "There have been no active topics in the past %1", "notif.chat.subject": "New chat message received from %1", - "notif.chat.cta": "Click here to continue the conversation", + "notif.chat.cta": "Pokalbio pratęsimui spauskite čia", "notif.chat.unsub.info": "This chat notification was sent to you due to your subscription settings.", - "notif.post.cta": "Click here to read the full topic", + "notif.post.cta": "Spauskite čia norėdami skaityti visą temą", "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "unsub.cta": "Click here to alter those settings", - "closing": "Thanks!" + "unsub.cta": "Spauskite čia norėdami pakeisti šiuos nustatymus", + "closing": "Ačiū!" } \ No newline at end of file diff --git a/public/language/lt/error.json b/public/language/lt/error.json index 295af44ce4..a1a25c65bc 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -12,26 +12,26 @@ "invalid-title": "Neteisingas pavadinimas!", "invalid-user-data": "Klaidingi vartotojo duomenys", "invalid-password": "Klaidingas slaptažodis", - "invalid-username-or-password": "Please specify both a username and password", - "invalid-search-term": "Invalid search term", + "invalid-username-or-password": "Prašome nurodyti tiek vartotojo vardą, tiek ir slaptažodį", + "invalid-search-term": "Neteisingas paieškos terminas", "invalid-pagination-value": "Klaidinga puslapiavimo reikšmė", "username-taken": "Vartotojo vardas jau užimtas", "email-taken": "El. pašto adresas jau užimtas", - "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", - "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", - "email-confirm-failed": "We could not confirm your email, please try again later.", + "email-not-confirmed": "Jūsų el. paštas nepatvirtintas, prašome paspausti čia norint jį patvirtinti.", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", + "no-email-to-confirm": "Šis forumas reikalauja patvirtinimo el. paštu prašome spausti čia el. adreso įrašymui", + "email-confirm-failed": "Negalime patvirtinti jūsų el. adreso, prašom bandyti vėliau.", "username-too-short": "Slapyvardis per trumpas", - "username-too-long": "Username too long", + "username-too-long": "Vartotojo vardas per ilgas", "user-banned": "Vartotojas užblokuotas", - "user-too-new": "Sorry, you are required to wait %1 seconds before making your first post", - "no-category": "Category does not exist", - "no-topic": "Topic does not exist", - "no-post": "Post does not exist", - "no-group": "Group does not exist", - "no-user": "User does not exist", + "user-too-new": "Atsiprašome, bet jums reikia laukti 1% sekundes prieš patalpinant savo pirmąjį įrašą", + "no-category": "Tokios kategorijos nėra", + "no-topic": "Tokios temos nėra", + "no-post": "Tokio įrašo nėra", + "no-group": "Grupė neegzistuoja", + "no-user": "Tokio vartotojo nėra", "no-teaser": "Teaser does not exist", - "no-privileges": "You do not have enough privileges for this action.", + "no-privileges": "Šiam veiksmui jūs neturite pakankamų privilegijų.", "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategorija išjungta", "topic-locked": "Tema užrakinta", @@ -50,32 +50,32 @@ "already-favourited": "You have already favourited this post", "already-unfavourited": "You have already unfavourited this post", "cant-ban-other-admins": "Jūs negalite užblokuoti kitų administratorių!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", - "invalid-file-type": "Invalid file type. Allowed types are: %1", + "invalid-image-type": "Neteisingas vaizdo tipas. Leidžiami tipai :%1", + "invalid-image-extension": "Neteisingas vaizdo plėtinys", + "invalid-file-type": "Neteisingas failo tipas. Leidžiami tipai: %1", "group-name-too-short": "Grupės pavadinimas per trumpas", "group-already-exists": "Tokia grupė jau egzistuoja", "group-name-change-not-allowed": "Grupės pavadinimas keitimas neleidžiamas", - "group-already-member": "You are already part of this group", + "group-already-member": "Jūs jau priklausote šiai grupei", "group-needs-owner": "This group requires at least one owner", - "post-already-deleted": "This post has already been deleted", - "post-already-restored": "This post has already been restored", - "topic-already-deleted": "This topic has already been deleted", - "topic-already-restored": "This topic has already been restored", + "post-already-deleted": "Šis įrašas jau buvo ištrintas", + "post-already-restored": "Šis įrašas jau atstatytas", + "topic-already-deleted": "Ši tema jau ištrinta", + "topic-already-restored": "Ši tema jau atkurta", "topic-thumbnails-are-disabled": "Temos paveikslėliai neleidžiami.", "invalid-file": "Klaidingas failas", "uploads-are-disabled": "Įkėlimai neleidžiami", "signature-too-long": "Sorry, your signature cannot be longer than %1 characters.", "cant-chat-with-yourself": "Jūs negalite susirašinėti su savimi!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", - "too-many-messages": "You have sent too many messages, please wait awhile.", - "reputation-system-disabled": "Reputation system is disabled.", + "too-many-messages": "Išsiuntėte per daug pranešimų, kurį laiką prašome palaukti.", + "reputation-system-disabled": "Reputacijos sistema išjungta.", "downvoting-disabled": "Downvoting is disabled", "not-enough-reputation-to-downvote": "Jūs neturite pakankamai reputacijos balsuoti prieš šį pranešimą", "not-enough-reputation-to-flag": "You do not have enough reputation to flag this post", "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading.", - "registration-error": "Registration Error", + "registration-error": "Registracijos klaida", "parse-error": "Something went wrong while parsing server response", - "wrong-login-type-email": "Please use your email to login", - "wrong-login-type-username": "Please use your username to login" + "wrong-login-type-email": "Prisijungimui prašom naudoti jūsų el. adresą", + "wrong-login-type-username": "Prisijungimui prašome naudoti vartotojo vardą" } \ No newline at end of file diff --git a/public/language/lt/global.json b/public/language/lt/global.json index c4bf81cf4b..8301db2346 100644 --- a/public/language/lt/global.json +++ b/public/language/lt/global.json @@ -27,7 +27,7 @@ "header.tags": "Žymos", "header.popular": "Populiarūs", "header.users": "Vartotojai", - "header.groups": "Groups", + "header.groups": "Grupės", "header.chats": "Susirašinėjimai", "header.notifications": "Pranešimai", "header.search": "Ieškoti", @@ -74,8 +74,8 @@ "guests": "Svečiai", "updated.title": "Forumas atnaujintas", "updated.message": "Forumas buvo atnaujintas iki naujausios versijos. Paspauskite čia norėdami perkrauti puslapį.", - "privacy": "Privacy", - "follow": "Follow", - "unfollow": "Unfollow", - "delete_all": "Delete All" + "privacy": "Privatumas", + "follow": "Sekti", + "unfollow": "Nebesekti", + "delete_all": "Viską ištrinti" } \ No newline at end of file diff --git a/public/language/lt/groups.json b/public/language/lt/groups.json index d2314fdc29..076154cf92 100644 --- a/public/language/lt/groups.json +++ b/public/language/lt/groups.json @@ -1,34 +1,34 @@ { - "groups": "Groups", - "view_group": "View Group", - "owner": "Group Owner", - "new_group": "Create New Group", + "groups": "Grupės", + "view_group": "Grupės peržiūra", + "owner": "Grupės savininkas", + "new_group": "Kurti naują grupę", "no_groups_found": "There are no groups to see", - "pending.accept": "Accept", - "pending.reject": "Reject", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit <strong>Save</strong>", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", - "details.title": "Group Details", - "details.members": "Member List", - "details.pending": "Pending Members", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts", - "details.private": "Private", + "pending.accept": "Priimti", + "pending.reject": "Atmesti", + "cover-instructions": "Vilkite čia nuotrauką, perkelkite į reikalingą poziciją ir spauskite <strong>Save</strong>", + "cover-change": "Keisti", + "cover-save": "Saugoti", + "cover-saving": "Išsaugoma", + "details.title": "Grupės detalės", + "details.members": "Narių sąrašas", + "details.pending": "Laukiantys nariai", + "details.has_no_posts": "Šios grupės nariai neatliko jokių įrašų.", + "details.latest_posts": "Vėliausi įrašai", + "details.private": "Asmeniška", "details.grant": "Grant/Rescind Ownership", "details.kick": "Kick", "details.owner_options": "Group Administration", - "details.group_name": "Group Name", - "details.description": "Description", + "details.group_name": "Grupės pavadinimas", + "details.description": "Aprašymas", "details.badge_preview": "Badge Preview", - "details.change_icon": "Change Icon", - "details.change_colour": "Change Colour", + "details.change_icon": "Pakeisti paveikslėlį", + "details.change_colour": "Pakeisti spalvą", "details.badge_text": "Badge Text", "details.userTitleEnabled": "Show Badge", "details.private_help": "If enabled, joining of groups requires approval from a group owner", - "details.hidden": "Hidden", + "details.hidden": "Paslėptas", "details.hidden_help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "event.updated": "Grupės informacija atnaujinta", + "event.deleted": "Grupė \"%1\" pašalinta" } \ No newline at end of file diff --git a/public/language/lt/login.json b/public/language/lt/login.json index ea6dab6e24..dd18d2949c 100644 --- a/public/language/lt/login.json +++ b/public/language/lt/login.json @@ -1,7 +1,7 @@ { - "username-email": "Username / Email", - "username": "Username", - "email": "Email", + "username-email": "Vartotojo vardas / El. paštas", + "username": "Vartotojo vardas", + "email": "El. paštas", "remember_me": "Prisiminti?", "forgot_password": "Užmiršote slaptažodį?", "alternative_logins": "Alternatyvūs prisijungimo būdai", diff --git a/public/language/lt/modules.json b/public/language/lt/modules.json index aefb40aed0..e6ddbe663e 100644 --- a/public/language/lt/modules.json +++ b/public/language/lt/modules.json @@ -12,10 +12,11 @@ "chat.message-history": "Žinučių istorija", "chat.pop-out": "Iššokančio lango pokalbiai", "chat.maximize": "Padininti", - "chat.seven_days": "7 Days", - "chat.thirty_days": "30 Days", - "chat.three_months": "3 Months", + "chat.seven_days": "7 dienos", + "chat.thirty_days": "30 dienų", + "chat.three_months": "3 mėnesiai", "composer.user_said_in": "%1 parašė į %2:", "composer.user_said": "%1 parašė:", - "composer.discard": "Ar tikrai norite sunaikinti šį pranešimą?" + "composer.discard": "Ar tikrai norite sunaikinti šį pranešimą?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/lt/notifications.json b/public/language/lt/notifications.json index 0a38999bff..e7deae258e 100644 --- a/public/language/lt/notifications.json +++ b/public/language/lt/notifications.json @@ -2,12 +2,12 @@ "title": "Pranešimai", "no_notifs": "Jūs neturite naujų pranešimų", "see_all": "Peržiūrėti visus pranešimus", - "mark_all_read": "Mark all notifications read", + "mark_all_read": "Žymėti visus perspėjimus kaip skaitytus", "back_to_home": "Atgal į %1", "outgoing_link": "Išeinanti nuoroda", "outgoing_link_message": "You are now leaving %1.", "continue_to": "Continue to %1", - "return_to": "Return to %1", + "return_to": "Grįžti į %1", "new_notification": "Naujas pranešimas", "you_have_unread_notifications": "Jūs turite neperskaitytų pranešimų.", "new_message_from": "Nauja žinutė nuo <strong>%1</strong>", @@ -17,7 +17,7 @@ "favourited_your_post_in": "<strong>%1</strong> has favourited your post in <strong>%2</strong>.", "user_flagged_post_in": "<strong>%1</strong> flagged a post in <strong>%2</strong>", "user_posted_to": "<strong>%1</strong> parašė atsaką <strong>%2</strong>", - "user_posted_topic": "<strong>%1</strong> has posted a new topic: <strong>%2</strong>", + "user_posted_topic": "<strong>%1</strong> paskelbė naują temą: <strong>%2</strong>", "user_mentioned_you_in": "<strong>%1</strong> paminėjo Jus <strong>%2</strong>", "user_started_following_you": "<strong>%1</strong> started following you.", "email-confirmed": "El. paštas patvirtintas", diff --git a/public/language/lt/pages.json b/public/language/lt/pages.json index 338cd346f5..c7cd3f490f 100644 --- a/public/language/lt/pages.json +++ b/public/language/lt/pages.json @@ -11,9 +11,10 @@ "user.followers": "Žmonės, kurie seka %1", "user.posts": "Pranešimai, kuriuos parašė %1", "user.topics": "Temos, kurias sukūrė %1", - "user.groups": "%1's Groups", + "user.groups": "%1's grupės", "user.favourites": "Vartotojo %1 mėgstami pranešimai", "user.settings": "Vartotojo nustatymai", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", - "maintenance.messageIntro": "Additionally, the administrator has left this message:" + "maintenance.messageIntro": "Be to, administratorius paliko šį pranešimą:" } \ No newline at end of file diff --git a/public/language/lt/recent.json b/public/language/lt/recent.json index ebb6269a19..bebb9353fa 100644 --- a/public/language/lt/recent.json +++ b/public/language/lt/recent.json @@ -4,16 +4,16 @@ "week": "Savaitė", "month": "Mėnesis", "year": "Metai", - "alltime": "All Time", + "alltime": "Per visą laiką", "no_recent_topics": "Paskutinių temų nėra", - "no_popular_topics": "There are no popular topics.", - "there-is-a-new-topic": "There is a new topic.", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "no_popular_topics": "Populiarių temų nėra.", + "there-is-a-new-topic": "Yra nauja tema.", + "there-is-a-new-topic-and-a-new-post": "Yra nauja tema ir naujas įrašas.", + "there-is-a-new-topic-and-new-posts": "Yra nauja tema ir %1 nauji įrašai.", + "there-are-new-topics": "Yra %1 naujos temos.", + "there-are-new-topics-and-a-new-post": "Yra %1 naujos temos ir naujas įrašas.", + "there-are-new-topics-and-new-posts": "Yra %1 naujos temos ir %2 nauji įrašai.", + "there-is-a-new-post": "Yra naujas įrašas.", + "there-are-new-posts": "Yra %1 naujas pranešimas.", + "click-here-to-reload": "Spauskite čia norėdami perkrauti." } \ No newline at end of file diff --git a/public/language/lt/reset_password.json b/public/language/lt/reset_password.json index 104f75e6e3..b95f3800be 100644 --- a/public/language/lt/reset_password.json +++ b/public/language/lt/reset_password.json @@ -11,6 +11,6 @@ "enter_email_address": "Įrašykite el. pašto adresą", "password_reset_sent": "Slaptažodžio atstatymas išsiųstas", "invalid_email": "Klaidingas arba neegzistuojantis el. pašto adresas!", - "password_too_short": "The password entered is too short, please pick a different password.", - "passwords_do_not_match": "The two passwords you've entered do not match." + "password_too_short": "Įvestas slaptažodis yra per trumpas, prašome pasirinkti kitą slaptažodį.", + "passwords_do_not_match": "Du slaptažodžiai, kuriuos įvedėte, nesutampa." } \ No newline at end of file diff --git a/public/language/lt/search.json b/public/language/lt/search.json index 9dad8b6eab..b31715a6b4 100644 --- a/public/language/lt/search.json +++ b/public/language/lt/search.json @@ -1,40 +1,40 @@ { "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)", - "no-matches": "No matches found", + "no-matches": "Atitikmenų nerasta", "in": "In", "by": "By", - "titles": "Titles", - "titles-posts": "Titles and Posts", - "posted-by": "Posted by", - "in-categories": "In Categories", + "titles": "Antraštės", + "titles-posts": "Antraštės ir įrašai", + "posted-by": "Parašė", + "in-categories": "Kategorijose", "search-child-categories": "Search child categories", "reply-count": "Reply Count", - "at-least": "At least", - "at-most": "At most", - "post-time": "Post time", - "newer-than": "Newer than", - "older-than": "Older than", - "any-date": "Any date", - "yesterday": "Yesterday", - "one-week": "One week", - "two-weeks": "Two weeks", - "one-month": "One month", - "three-months": "Three months", - "six-months": "Six months", - "one-year": "One year", - "sort-by": "Sort by", + "at-least": "Mažiausiai", + "at-most": "Daugiausia", + "post-time": "Įrašo laikas", + "newer-than": "Naujesni kaip", + "older-than": "Senesni kaip", + "any-date": "Bet kokia data", + "yesterday": "Vakar", + "one-week": "Viena savaitė", + "two-weeks": "Dvi savaitės", + "one-month": "Mėnuo", + "three-months": "Trys mėnesiai", + "six-months": "Šeši mėnesiai", + "one-year": "Vieneri metai", + "sort-by": "Rūšiuoti pagal", "last-reply-time": "Last reply time", - "topic-title": "Topic title", - "number-of-replies": "Number of replies", - "number-of-views": "Number of views", - "topic-start-date": "Topic start date", - "username": "Username", - "category": "Category", - "descending": "In descending order", - "ascending": "In ascending order", - "save-preferences": "Save preferences", - "clear-preferences": "Clear preferences", - "search-preferences-saved": "Search preferences saved", - "search-preferences-cleared": "Search preferences cleared", - "show-results-as": "Show results as" + "topic-title": "Temos pavadinimas", + "number-of-replies": "Atsakymų skaičius", + "number-of-views": "Peržiūrų skaičius", + "topic-start-date": "Temos pradžia", + "username": "Vartotojo vardas", + "category": "Kategorija", + "descending": "Mažėjančia tvarka", + "ascending": "Didėjančia tvarka", + "save-preferences": "Išsaugoti nustatymus", + "clear-preferences": "Išvalyti nustatymus", + "search-preferences-saved": "Paieškos nustatymai išsaugoti", + "search-preferences-cleared": "Paieškos nuostatos išvalytos", + "show-results-as": "Rodyti rezultatus kaip" } \ No newline at end of file diff --git a/public/language/lt/tags.json b/public/language/lt/tags.json index 2f2b9e11d2..2151f58d36 100644 --- a/public/language/lt/tags.json +++ b/public/language/lt/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Temų su šią žyma nėra.", "tags": "Žymos", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Enter tags...", "no_tags": "Žymų kolkas nėra." } \ No newline at end of file diff --git a/public/language/lt/topic.json b/public/language/lt/topic.json index 5138bc2766..e79c869a1b 100644 --- a/public/language/lt/topic.json +++ b/public/language/lt/topic.json @@ -12,7 +12,7 @@ "notify_me": "Gauti pranešimus apie naujus atsakymus šioje temoje", "quote": "Cituoti", "reply": "Atsakyti", - "guest-login-reply": "Log in to reply", + "guest-login-reply": "Norėdami atsakyti, prisijunkite", "edit": "Redaguoti", "delete": "Ištrinti", "purge": "Išvalyti", @@ -34,11 +34,11 @@ "login_to_subscribe": "Norėdami prenumeruoti šią temą, prašome prisiregistruoti arba prisijungti.", "markAsUnreadForAll.success": "Tema visiems vartotojams pažymėta kaip neskaityta.", "watch": "Žiūrėti", - "unwatch": "Unwatch", + "unwatch": "Nebesekti", "watch.title": "Gauti pranešimą apie naujus įrašus šioje temoje", - "unwatch.title": "Stop watching this topic", + "unwatch.title": "Baigti šios temos stebėjimą", "share_this_post": "Dalintis šiuo įrašu", - "thread_tools.title": "Topic Tools", + "thread_tools.title": "Temos priemonės", "thread_tools.markAsUnreadForAll": "Pažymėti kaip neskaitytą", "thread_tools.pin": "Prisegti temą", "thread_tools.unpin": "Atsegti temą", @@ -48,11 +48,11 @@ "thread_tools.move_all": "Perkelti visus", "thread_tools.fork": "Išskaidyti temą", "thread_tools.delete": "Ištrinti temą", - "thread_tools.delete_confirm": "Are you sure you want to delete this topic?", + "thread_tools.delete_confirm": "Ar jūs tikrai norite ištrinti šią temą?", "thread_tools.restore": "Atkurti temą", - "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", + "thread_tools.restore_confirm": "Ar jūs tikrai norite atkurti šią temą?", "thread_tools.purge": "Išvalyti temą", - "thread_tools.purge_confirm": "Are you sure you want to purge this topic?", + "thread_tools.purge_confirm": "Ar tikrai norite išvalyti šią temą?", "topic_move_success": "Ši tema buvo sėkmingai perkelta į %1", "post_delete_confirm": "Ar jūs tikrai norite ištrinti šį įrašą?", "post_restore_confirm": "Ar jūs tikrai norite atkurti šį įrašą?", @@ -75,7 +75,7 @@ "fork_no_pids": "Nepasirinktas joks įrašas!", "fork_success": "Successfully forked topic! Click here to go to the forked topic.", "composer.title_placeholder": "Įrašykite temos pavadinimą...", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "Vardas ir pavardė", "composer.discard": "Atšaukti", "composer.submit": "Patvirtinti", "composer.replying_to": "Atsakymas %1", @@ -90,10 +90,10 @@ "more_users_and_guests": "dar %1 vartotojai(-ų) ir %2 svečiai(-ių)", "more_users": "dar %1 vartotojai(-ų)", "more_guests": "dar %1 svečiai(-ių)", - "users_and_others": "%1 and %2 others", + "users_and_others": "%1 ir kiti %2", "sort_by": "Rūšiuoti pagal", "oldest_to_newest": "Nuo seniausių iki naujausių", "newest_to_oldest": "Nuo naujausių iki seniausių", "most_votes": "Daugiausiai balsų", - "most_posts": "Most posts" + "most_posts": "Daugiausia įrašų" } \ No newline at end of file diff --git a/public/language/lt/user.json b/public/language/lt/user.json index 7ec5d24423..3146ac252f 100644 --- a/public/language/lt/user.json +++ b/public/language/lt/user.json @@ -2,12 +2,12 @@ "banned": "Užblokuotas", "offline": "Atsijungęs", "username": "Vartotojo vardas", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "Prisijungimo data", + "postcount": "Įrašų kiekis", "email": "El. paštas", "confirm_email": "Patvirtinti el. paštą", - "delete_account": "Delete Account", - "delete_account_confirm": "Are you sure you want to delete your account? <br /><strong>This action is irreversible and you will not be able to recover any of your data</strong><br /><br />Enter your username to confirm that you wish to destroy this account.", + "delete_account": "Ištrinti paskyrą", + "delete_account_confirm": "Ar tikrai norite ištrinti savo paskyrą? <br /> <strong> Šis veiksmas yra negrįžtamas, ir jūs negalėsite susigrąžinti jokių duomenų </ strong> <br /> <br /> Įveskite savo vardą, kad patvirtintumėte, jog norite panaikinti šią paskyrą.", "fullname": "Vardas ir pavardė", "website": "Tinklalapis", "location": "Vieta", @@ -32,7 +32,7 @@ "edit": "Redaguoti", "uploaded_picture": "Įkeltas paveikslėlis", "upload_new_picture": "Įkelti naują paveikslėlį", - "upload_new_picture_from_url": "Upload New Picture From URL", + "upload_new_picture_from_url": "Įkelti naują paveikslėlį iš URL", "current_password": "Dabartinis slaptažodis", "change_password": "Pakeisti slaptažodį", "change_password_error": "Negalimas slaptažodis!", @@ -50,21 +50,22 @@ "max": "maks.", "settings": "Nustatymai", "show_email": "Rodyti mano el. paštą viešai", - "show_fullname": "Show My Full Name", - "restrict_chats": "Only allow chat messages from users I follow", + "show_fullname": "Rodyti mano vardą ir pavardę", + "restrict_chats": "Gauti pokalbių žinutes tik iš tų narių, kuriuos seku", "digest_label": "Prenumeruoti įvykių santrauką", "digest_description": "Gauti naujienas apie naujus pranešimus ir temas į el. paštą pagal nustatytą grafiką", "digest_off": "Išjungta", "digest_daily": "Kas dieną", "digest_weekly": "Kas savaitę", "digest_monthly": "Kas mėnesį", - "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_chat_notifications": "Jeigu gaunama nauja pokalbių žinutė ir aš neprisijungęs, siųsti el. laišką", + "send_post_notifications": "Atsiųsti el. laišką kai parašomi atsakymai į mano prenumeruojamas temas", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Šis vartotojas neturi jokių sekėjų :(", "follows_no_one": "Šis vartotojas nieko neseka :(", "has_no_posts": "Šis vartotojas dar neparašė nė vieno pranešimo.", "has_no_topics": "Šis vartotojas dar nesukūrė nė vienos temos.", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "Šis vartotojas dar neseka jokių temų", "email_hidden": "El. paštas paslėptas", "hidden": "paslėptas", "paginate_description": "Temose ir kategorijose naudoti numeraciją puslapiams vietoje begalinės slinkties.", @@ -75,6 +76,7 @@ "open_links_in_new_tab": "Atidaryti nuorodas naujame skirtuke?", "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", - "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_reply_to": "Sekite temas, į kurias jūs atsakėte.", + "follow_topics_you_create": "Sekite jūsų sukurtas temas.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/lt/users.json b/public/language/lt/users.json index 043ca55bcc..f4f4360022 100644 --- a/public/language/lt/users.json +++ b/public/language/lt/users.json @@ -5,8 +5,8 @@ "search": "Ieškoti", "enter_username": "Įrašykite vartotojo vardą paieškai", "load_more": "Įkelti daugiau", - "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", - "filter-by": "Filter By", + "users-found-search-took": "Rasta %1 vartotojas(-ai)! Paieška užtruko %2 sekundes.", + "filter-by": "Filtruoti pagal", "online-only": "Online only", - "picture-only": "Picture only" + "picture-only": "Tik paveikslėlis" } \ No newline at end of file diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 340e4e528b..23958cf5de 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -18,7 +18,7 @@ "username-taken": "Username taken", "email-taken": "Email taken", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Nama pengunna terlalu pendek", diff --git a/public/language/ms/modules.json b/public/language/ms/modules.json index dd206e5b24..9cae9f7b74 100644 --- a/public/language/ms/modules.json +++ b/public/language/ms/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/ms/pages.json b/public/language/ms/pages.json index dc7c0385e9..439217122f 100644 --- a/public/language/ms/pages.json +++ b/public/language/ms/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "Mesej Kegemaran %1", "user.settings": "Tetapan pengguna", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/ms/tags.json b/public/language/ms/tags.json index aa9f14c70c..c416d8d4ec 100644 --- a/public/language/ms/tags.json +++ b/public/language/ms/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "There are no topics with this tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Enter tags...", "no_tags": "There are no tags yet." } \ No newline at end of file diff --git a/public/language/ms/user.json b/public/language/ms/user.json index 5b44dfc707..89969347e8 100644 --- a/public/language/ms/user.json +++ b/public/language/ms/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Bulanan", "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Pengguna ini tiada pengikut :(", "follows_no_one": "Pengguna ini tidak mengikuti sesiapa :(", "has_no_posts": "Pengguna ini masih belum mengirim sebarang pos", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_create": "Follow topics you create.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/nb/category.json b/public/language/nb/category.json index 75f38d0df0..f8afafe14a 100644 --- a/public/language/nb/category.json +++ b/public/language/nb/category.json @@ -1,6 +1,6 @@ { "new_topic_button": "Nytt emne", - "guest-login-post": "Log in to post", + "guest-login-post": "Logg inn til innlegg", "no_topics": "<strong>Det er ingen emner i denne kategorien</strong><br />Hvorfor ikke lage ett?", "browsing": "leser", "no_replies": "Ingen har svart", diff --git a/public/language/nb/email.json b/public/language/nb/email.json index 65e1accaee..37b5df85d0 100644 --- a/public/language/nb/email.json +++ b/public/language/nb/email.json @@ -9,9 +9,9 @@ "reset.text1": "Vi har blir bedt om å tilbakestille passordet ditt, muligens fordi du har glemt det. Hvis dette ikke stemmer kan du ignorere denne eposten.", "reset.text2": "For å fortsette med tilbakestillingen, vennligst klikk på følgende lenke:", "reset.cta": "Klikk her for å tilbakestille passordet ditt", - "reset.notify.subject": "Password successfully changed", - "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", - "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "reset.notify.subject": "Passordet ble endret", + "reset.notify.text1": "Vi gir deg beskjed om at du endret passordet ditt den %1.", + "reset.notify.text2": "Hvis du ikke godkjenner dette, vennligst gi beskjed til en administrator omgående.", "digest.notifications": "Du har uleste varsler fra %1:", "digest.latest_topics": "Siste emner fra %1", "digest.cta": "Klikk her for å besøke %1", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index 2fe73f83a4..8706a9d569 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -18,9 +18,9 @@ "username-taken": "Brukernavn opptatt", "email-taken": "E-post opptatt", "email-not-confirmed": "E-posten din har ikke blitt bekreftet enda, vennligst klikk for å bekrefte din e-post.", - "email-not-confirmed-chat": "Du kan ikke chatte før e-posten din har blitt bekreftet", - "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", - "email-confirm-failed": "We could not confirm your email, please try again later.", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", + "no-email-to-confirm": "Dette forumet krever at e-postbekreftelse, vennligst klikk her for å skrive inn en e-post", + "email-confirm-failed": "Vi kunne ikke godkjenne e-posten din, vennligst prøv igjen senere.", "username-too-short": "Brukernavnet er for kort", "username-too-long": "Brukernavnet er for langt", "user-banned": "Bruker utestengt", @@ -35,7 +35,7 @@ "no-emailers-configured": "Ingen e-post-tillegg er lastet, så ingen test e-post kunne bli sendt", "category-disabled": "Kategori deaktivert", "topic-locked": "Emne låst", - "post-edit-duration-expired": "You are only allowed to edit posts for %1 seconds after posting", + "post-edit-duration-expired": "Du har bare lov til å endre innlegg i %1 sekunder etter at det ble skrevet", "still-uploading": "Vennligst vent til opplastingene blir fullført.", "content-too-short": "Vennligst skriv et lengere innlegg. Innlegg må inneholde minst %1 tegn.", "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", diff --git a/public/language/nb/groups.json b/public/language/nb/groups.json index e837ac8961..6ff3a9b71f 100644 --- a/public/language/nb/groups.json +++ b/public/language/nb/groups.json @@ -4,8 +4,8 @@ "owner": "Gruppe-eier", "new_group": "Opprett ny gruppe", "no_groups_found": "Det er ingen grupper å se", - "pending.accept": "Accept", - "pending.reject": "Reject", + "pending.accept": "Aksepter", + "pending.reject": "Avslå", "cover-instructions": "Dra og slipp et bilde, dra til posisjon, og trykk <strong>Lagre</strong>", "cover-change": "Endre", "cover-save": "Lagre", @@ -15,20 +15,20 @@ "details.pending": "Ventende meldemmer", "details.has_no_posts": "Medlemmene i denne gruppen har ikke skrevet noen innlegg.", "details.latest_posts": "Seneste innlegg", - "details.private": "Private", - "details.grant": "Grant/Rescind Ownership", - "details.kick": "Kick", + "details.private": "Privat", + "details.grant": "Gi/Opphev Eierskap", + "details.kick": "Kast ut", "details.owner_options": "Gruppeadministrasjon", - "details.group_name": "Group Name", - "details.description": "Description", - "details.badge_preview": "Badge Preview", - "details.change_icon": "Change Icon", - "details.change_colour": "Change Colour", - "details.badge_text": "Badge Text", - "details.userTitleEnabled": "Show Badge", - "details.private_help": "If enabled, joining of groups requires approval from a group owner", - "details.hidden": "Hidden", - "details.hidden_help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually", + "details.group_name": "Gruppenavn", + "details.description": "Beskrivelse", + "details.badge_preview": "Forhåndsvisning av skilt", + "details.change_icon": "Endre ikon", + "details.change_colour": "Endre farge", + "details.badge_text": "Skilt-tekst", + "details.userTitleEnabled": "Vis skilt", + "details.private_help": "Hvis aktivert, vil medlemskap i grupper kreve godkjennelse fra en gruppe-eier", + "details.hidden": "Skjult", + "details.hidden_help": "vis aktivert, vil denne gruppen ikke bli funnet i gruppelista, og brukere må inviteres manuellt", "event.updated": "Gruppedetaljer har blitt oppgradert", "event.deleted": "Gruppen \"%1\" har blitt slettet" } \ No newline at end of file diff --git a/public/language/nb/login.json b/public/language/nb/login.json index 2b51b10c6a..785a7defc4 100644 --- a/public/language/nb/login.json +++ b/public/language/nb/login.json @@ -1,7 +1,7 @@ { - "username-email": "Username / Email", - "username": "Username", - "email": "Email", + "username-email": "Brukernavn / E-post", + "username": "Brukernavn", + "email": "E-post", "remember_me": "Husk meg?", "forgot_password": "Glemt passord?", "alternative_logins": "Alternativ innlogging", diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index 83aae8d615..e5656f83d1 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 måneder", "composer.user_said_in": "%1 sa i %2: ", "composer.user_said": "%1 sa: ", - "composer.discard": "Er du sikker på at du vil forkaste dette innlegget?" + "composer.discard": "Er du sikker på at du vil forkaste dette innlegget?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/nb/pages.json b/public/language/nb/pages.json index 1d657bd759..4f424ec5d6 100644 --- a/public/language/nb/pages.json +++ b/public/language/nb/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1 sine favoritt-innlegg", "user.settings": "Brukerinnstillinger", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 er for tiden under vedlikehold. Kom tilbake en annen gang.", "maintenance.messageIntro": "I tillegg har administratoren skrevet denne meldingen:" } \ No newline at end of file diff --git a/public/language/nb/search.json b/public/language/nb/search.json index 74fdc462a6..2f06a88eb5 100644 --- a/public/language/nb/search.json +++ b/public/language/nb/search.json @@ -3,38 +3,38 @@ "no-matches": "Ingen matcher funnet", "in": "I", "by": "Av", - "titles": "Titles", - "titles-posts": "Titles and Posts", + "titles": "Titler", + "titles-posts": "Titler og innlegg", "posted-by": "Skapt av", - "in-categories": "In Categories", - "search-child-categories": "Search child categories", - "reply-count": "Reply Count", - "at-least": "At least", - "at-most": "At most", - "post-time": "Post time", - "newer-than": "Newer than", - "older-than": "Older than", - "any-date": "Any date", - "yesterday": "Yesterday", - "one-week": "One week", - "two-weeks": "Two weeks", - "one-month": "One month", - "three-months": "Three months", - "six-months": "Six months", - "one-year": "One year", - "sort-by": "Sort by", - "last-reply-time": "Last reply time", - "topic-title": "Topic title", - "number-of-replies": "Number of replies", - "number-of-views": "Number of views", - "topic-start-date": "Topic start date", - "username": "Username", - "category": "Category", + "in-categories": "I kategorier", + "search-child-categories": "Søk underkategorier", + "reply-count": "Mengde svar", + "at-least": "Minst", + "at-most": "Maks", + "post-time": "Innlegg-tid", + "newer-than": "Nyere enn", + "older-than": "Eldre en", + "any-date": "Alle datoer", + "yesterday": "I går", + "one-week": "En uke", + "two-weeks": "To uker", + "one-month": "En måned ", + "three-months": "Tre måneder", + "six-months": "Seks måneder", + "one-year": "Ett år", + "sort-by": "Sorter etter", + "last-reply-time": "Sise svartid", + "topic-title": "Emne-tittel", + "number-of-replies": "Antall svar", + "number-of-views": "Antall visninger", + "topic-start-date": "Starttid for emne", + "username": "Brukernavn", + "category": "Kategori", "descending": "In descending order", "ascending": "In ascending order", - "save-preferences": "Save preferences", - "clear-preferences": "Clear preferences", - "search-preferences-saved": "Search preferences saved", - "search-preferences-cleared": "Search preferences cleared", - "show-results-as": "Show results as" + "save-preferences": "Lagre innstillinger", + "clear-preferences": "Tøm innstillinnger", + "search-preferences-saved": "Søkeinnstillinger lagret", + "search-preferences-cleared": "Søkeinnstillinger tømt", + "show-results-as": "Vis resultateter som" } \ No newline at end of file diff --git a/public/language/nb/tags.json b/public/language/nb/tags.json index d38e00a025..5287b6125a 100644 --- a/public/language/nb/tags.json +++ b/public/language/nb/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Det er ingen emnet med denne taggen.", "tags": "Tagger", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Skriv tagger...", "no_tags": "Det finnes ingen tagger enda." } \ No newline at end of file diff --git a/public/language/nb/user.json b/public/language/nb/user.json index f3e6523e25..c64972929d 100644 --- a/public/language/nb/user.json +++ b/public/language/nb/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Månedlig", "send_chat_notifications": "Send en epost hvis jeg mottar en chat-melding når jeg ikke er pålogget", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Denne brukeren har ingen følgere :(", "follows_no_one": "Denne brukeren følger ingen :(", "has_no_posts": "Denne brukeren har ikke skrevet noe enda.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Aktiver søk-i-emne", "topic_search_help": "Hvis aktivert, vil i-emne-søk overstyre nettleseren sin standard sidesøk-oppførsel og tillate deg å søke gjennom hele emnet, i stedet for bare det som vises på skjermen.", "follow_topics_you_reply_to": "Følg emner du svarer i.", - "follow_topics_you_create": "Følg emner du oppretter." + "follow_topics_you_create": "Følg emner du oppretter.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/nl/category.json b/public/language/nl/category.json index bee6530395..fe05622fbb 100644 --- a/public/language/nl/category.json +++ b/public/language/nl/category.json @@ -1,6 +1,6 @@ { "new_topic_button": "Nieuw onderwerp", - "guest-login-post": "Log in to post", + "guest-login-post": "Log in om een reactie te plaatsen", "no_topics": "<strong>Er zijn geen onderwerpen in deze categorie.</strong><br />Waarom maak je er niet een aan?", "browsing": "verkennen", "no_replies": "Niemand heeft gereageerd", diff --git a/public/language/nl/email.json b/public/language/nl/email.json index a1f26cd2ea..18d7ab4a97 100644 --- a/public/language/nl/email.json +++ b/public/language/nl/email.json @@ -9,9 +9,9 @@ "reset.text1": "Wij ontvingen een verzoek van u om uw wachtwoord te resetten. Als dat niet het geval is, kunt u deze mail negeren ", "reset.text2": "Om uw wachtwoord te resetten, klik op de volgende link", "reset.cta": "Klik hier om u wachtwoord te resetten", - "reset.notify.subject": "Password successfully changed", - "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", - "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "reset.notify.subject": "Wachtwoord succesvol veranderd", + "reset.notify.text1": "Wij brengen u bij deze op de hoogte that uw wachtwoord succesvol is gewijzigd op %1.", + "reset.notify.text2": "Neem contact op met een administrator als u hier geen toestemming voor gegeven heeft.", "digest.notifications": "U heeft ongelezen notificaties van %1:", "digest.latest_topics": "De laatste onderwerpen van %1", "digest.cta": "Klik hier om deze website te bezoeken %1 ", @@ -20,8 +20,8 @@ "notif.chat.subject": "U heeft een chatbericht ontvangen van %1", "notif.chat.cta": "Klik hier om het gesprek te hervatten", "notif.chat.unsub.info": "Deze chat notificatie was verzonden naar jou vanwege je abbonement instellingen", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.cta": "Klik hier om het volledige bericht te lezen", + "notif.post.unsub.info": "Deze bericht notificatie werd naar u verstuurd wegens uw abonnement instellingen.", "test.text1": "Dit is een test email om te verifiëren dat de email service correct is opgezet voor jou NodeBB", "unsub.cta": "Klik hier om u instellingen te wijzigen", "closing": "Bedankt!" diff --git a/public/language/nl/error.json b/public/language/nl/error.json index de83d31255..e6be514a63 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -18,9 +18,9 @@ "username-taken": "Gebruikersnaam is al bezet", "email-taken": "Email adres is al gebruikt", "email-not-confirmed": "U email adres is niet bevestigd, Klik hier om uw email adres te bevestigen", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", - "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", - "email-confirm-failed": "We could not confirm your email, please try again later.", + "email-not-confirmed-chat": "U kunt helaas geen gebruik maken van chats tot uw email adres bevestigd is.", + "no-email-to-confirm": "Dit forum vereist email bevestiging, klikt u alstublieft hier om uw email te vermelden", + "email-confirm-failed": "Uw email kon helaas niet bevestigd worden, probeert u het alstublieft later nog eens.", "username-too-short": "Gebruikersnaam is te kort", "username-too-long": "Gebruikersnaam is te lang", "user-banned": "Gebruiker verbannen", @@ -35,29 +35,29 @@ "no-emailers-configured": "Er zijn geen email plugins geladen, een test email kan dus niet verzonden worden", "category-disabled": "Categorie uitgeschakeld", "topic-locked": "Onderwerp gesloten", - "post-edit-duration-expired": "You are only allowed to edit posts for %1 seconds after posting", + "post-edit-duration-expired": "Het is niet toegestaan om berichten aan te passen tot %1 seconden na het plaatsen", "still-uploading": "Heb even geduld totdat de alle bestanden geüpload zijn", - "content-too-short": "Maak de bericht alsjeblieft wat langer. Op z'n minst %1 karakters", - "content-too-long": "Please enter a shorter post. Posts can't be longer than %1 characters.", + "content-too-short": "Maak de bericht alstublieft wat langer. Op z'n minst %1 karakters", + "content-too-long": "Maakt u het bericht alstublieft wat korter. Berichten mogen niet langer zijn dan %1 karakters.", "title-too-short": "Maak de titel wat langer. Op z'n minst %1 karakters", "title-too-long": "Maak de titel wat korter. Het kan niet langer zijn dan %1 karakters", "too-many-posts": "Je kan eens in de %1 seconden een bericht aanmaken. Wacht alstublieft.", "too-many-posts-newbie": "Als een nieuwe gebruiker kan je maar om de %1 seconden een bericht plaatsen vanwege je reputatie. Uw moet deze level van reputatie verdienen %2. Wacht alstublieft met het plaatsen van uw bericht.", - "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 characters", - "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 characters", + "tag-too-short": "Maakt u alstublieft de tag iets langer. Tags dienen minimaal %1 karakters te bevatten", + "tag-too-long": "Maakt u alstublieft de tag iets korter. Tags mogen maximaal %1 karakters bevatten", "file-too-big": "De maximale bestandsgrootte is %1 kbs", "cant-vote-self-post": "Je kan niet op je eigen berichten stemmen", "already-favourited": "U heeft al dit bericht in uw favorieten staan", "already-unfavourited": "U heeft al dit bericht uit uw favorieten gehaald", "cant-ban-other-admins": "U kunt niet de andere admins bannen!", - "invalid-image-type": "Invalid image type. Allowed types are: %1", - "invalid-image-extension": "Invalid image extension", - "invalid-file-type": "Invalid file type. Allowed types are: %1", + "invalid-image-type": "Dit foto bestandstype is niet toegestaan. Toegestane foto bestandstypen zijn: %1", + "invalid-image-extension": "Ongeldige foto bestandsextensie", + "invalid-file-type": "Dit bestandstype is niet toegestaan. Toegestane bestandstypen zijn: %1", "group-name-too-short": "De groepsnaam is te kort", "group-already-exists": "Deze groep bestaat al", "group-name-change-not-allowed": "Het veranderen van de groepsnaam is niet toegestaan!", - "group-already-member": "You are already part of this group", - "group-needs-owner": "This group requires at least one owner", + "group-already-member": "U bent al lid van deze groep", + "group-needs-owner": "Deze groep vereist minimaal 1 eigenaar", "post-already-deleted": "Dit bericht is al verwijderd", "post-already-restored": "Dit bericht is al hersteld", "topic-already-deleted": "Deze topic is al verwijderd", @@ -68,14 +68,14 @@ "signature-too-long": "Sorry, maar deze handtekening kan niet groter zijn dan %1 karakters!", "cant-chat-with-yourself": "Je kan niet met jezelf chatten!", "chat-restricted": "Deze gebruiker heeft beperkingen gelegd op chatfunctie. Hun moeten jouw volgen voordat je met hun kan chatten", - "too-many-messages": "You have sent too many messages, please wait awhile.", + "too-many-messages": "U heeft teveel berichten verstuurd in een korte tijd. Wacht u alstublieft even.", "reputation-system-disabled": "Reputatie systeem is uitgeschakeld", "downvoting-disabled": "Downvoten is uitgeschakeld", "not-enough-reputation-to-downvote": "U heeft niet de benodigde reputatie om dit bericht te downvoten", "not-enough-reputation-to-flag": "U heeft niet de benodigde reputatie om dit bericht te melden aan de admins", "reload-failed": "NodeBB heeft een probleem geconstateerd tijdens het laden van: \"%1\".\nNodeBB blijft verder draaien. Het is wel verstandig om de actie wat u daarvoor heeft gedaan ongedaan te maken door te herladen.", "registration-error": "Registratie fout", - "parse-error": "Something went wrong while parsing server response", - "wrong-login-type-email": "Please use your email to login", - "wrong-login-type-username": "Please use your username to login" + "parse-error": "Er is iets fout gegaan tijdens het parsen van de server response", + "wrong-login-type-email": "Gebruikt u alstublieft uw email om in te loggen", + "wrong-login-type-username": "Gebruikt u alstublieft uw gebruikersnaam om in te loggen" } \ No newline at end of file diff --git a/public/language/nl/global.json b/public/language/nl/global.json index 84899903b0..bea96ad2b4 100644 --- a/public/language/nl/global.json +++ b/public/language/nl/global.json @@ -3,10 +3,10 @@ "search": "Zoeken", "buttons.close": "Sluiten", "403.title": "Toegang Geweigerd", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should <a href='%1/login'>try logging in</a>?", + "403.message": "Het lijkt er op dat u op een pagina bent beland waar u geen toegang tot heeft.", + "403.login": "Misschien moet u <a href='%1/login'>proberen in te loggen</a>?", "404.title": "Niet Gevonden", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the <a href='%1/'>home page</a>.", + "404.message": "Het lijkt er op dat u op een pagina bent beland die niet bestaat. Ga terug naar de <a href='%1/'>home pagina</a>.", "500.title": "Interne fout.", "500.message": "Oeps! Het lijkt erop dat iets is fout gegaan!", "register": "Registeren", @@ -27,7 +27,7 @@ "header.tags": "Tags", "header.popular": "Populair", "header.users": "Gebruikers", - "header.groups": "Groups", + "header.groups": "Groepen", "header.chats": "Chats", "header.notifications": "Notificaties", "header.search": "Zoeken", @@ -75,7 +75,7 @@ "updated.title": "Forum geüpdatet", "updated.message": "Dit forum is zojuist geüpdatet naar de laatste versie. Klik hier om de pagina te verversen", "privacy": "Privé", - "follow": "Follow", - "unfollow": "Unfollow", + "follow": "Volgen", + "unfollow": "Ontvolgen", "delete_all": "Alles verwijderen" } \ No newline at end of file diff --git a/public/language/nl/groups.json b/public/language/nl/groups.json index 9fe5c00975..67f21acd2b 100644 --- a/public/language/nl/groups.json +++ b/public/language/nl/groups.json @@ -3,32 +3,32 @@ "view_group": "Bekijk Groep", "owner": "Groep eigenaar", "new_group": "Maak een nieuwe groep", - "no_groups_found": "There are no groups to see", - "pending.accept": "Accept", - "pending.reject": "Reject", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit <strong>Save</strong>", - "cover-change": "Change", + "no_groups_found": "Er zijn geen groepen om weer te geven", + "pending.accept": "Accepteer", + "pending.reject": "Afwijzen", + "cover-instructions": "Sleep een foto, positioneer en klik op <strong>Opslaan</strong>", + "cover-change": "Aanpassen", "cover-save": "Opslaan", "cover-saving": "Bezig met opslaan", "details.title": "Groep Details", "details.members": "Ledenlijst", - "details.pending": "Pending Members", + "details.pending": "Afwachtende leden", "details.has_no_posts": "Deze groepleden hebben nog geen berichten geplaatst", "details.latest_posts": "Nieuwste Berichten", - "details.private": "Private", - "details.grant": "Grant/Rescind Ownership", - "details.kick": "Kick", - "details.owner_options": "Group Administration", - "details.group_name": "Group Name", - "details.description": "Description", - "details.badge_preview": "Badge Preview", - "details.change_icon": "Change Icon", - "details.change_colour": "Change Colour", - "details.badge_text": "Badge Text", - "details.userTitleEnabled": "Show Badge", - "details.private_help": "If enabled, joining of groups requires approval from a group owner", - "details.hidden": "Hidden", - "details.hidden_help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually", - "event.updated": "Group details have been updated", - "event.deleted": "The group \"%1\" has been deleted" + "details.private": "Prive", + "details.grant": "Toekennen/Herroepen van eigenaarschap", + "details.kick": "Verwijder", + "details.owner_options": "Groeps Administratie", + "details.group_name": "Groepsnaam", + "details.description": "Beschrijving", + "details.badge_preview": "Badge Voorvertoning", + "details.change_icon": "Icoon veranderen", + "details.change_colour": "Kleur veranderen", + "details.badge_text": "Badge tekst", + "details.userTitleEnabled": "Badge tonen", + "details.private_help": "Indien geactiveerd, zal er goedkeuring moeten worden verleend door een groepseigenaar voor het toetreden van groepen", + "details.hidden": "Verborgen", + "details.hidden_help": "Indien geactiveerd zal deze groep niet getoond worden in de groepslijst en zullen gebruikers handmatig uitgenodigd moeten worden.", + "event.updated": "Groepsdetails zijn geupdate", + "event.deleted": "De groep \"%1\" is verwijderd" } \ No newline at end of file diff --git a/public/language/nl/login.json b/public/language/nl/login.json index ec75667e86..fa1c5bf8eb 100644 --- a/public/language/nl/login.json +++ b/public/language/nl/login.json @@ -1,6 +1,6 @@ { - "username-email": "Username / Email", - "username": "Username", + "username-email": "Gebruikersnaam / Email", + "username": "Gebruikersnaam", "email": "Email", "remember_me": "Mij Onthouden?", "forgot_password": "Wachtwoord Vergeten?", diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index 18daffd434..4feffb4096 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Maanden", "composer.user_said_in": "%1 zegt in %2:", "composer.user_said": "%1 zegt:", - "composer.discard": "Weet u het zeker dat u dit bericht niet wilt plaatsen?" + "composer.discard": "Weet u het zeker dat u dit bericht niet wilt plaatsen?", + "composer.submit_and_lock": "Plaatsen en vergrendelen" } \ No newline at end of file diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json index f0dc76c27f..4e5a599896 100644 --- a/public/language/nl/notifications.json +++ b/public/language/nl/notifications.json @@ -2,7 +2,7 @@ "title": "Notificaties", "no_notifs": "Je hebt geen nieuwe notificaties", "see_all": "Bekijk alle Notificaties", - "mark_all_read": "Mark all notifications read", + "mark_all_read": "Markeer alle meldingen als gelezen", "back_to_home": "Terug naar %1", "outgoing_link": "Uitgaande Link", "outgoing_link_message": "Je verlaat nu %1", diff --git a/public/language/nl/pages.json b/public/language/nl/pages.json index 09cda815b9..3f6abeb9af 100644 --- a/public/language/nl/pages.json +++ b/public/language/nl/pages.json @@ -11,9 +11,10 @@ "user.followers": "Mensen die %1 Volgen", "user.posts": "Berichten geplaatst door %1", "user.topics": "Topics gecreëerd door %1", - "user.groups": "%1's Groups", + "user.groups": "%1's groepen", "user.favourites": "%1's Favoriete Berichten", "user.settings": "Gebruikersinstellingen", + "user.watched": "Berichten die worden bekeken door %1", "maintenance.text": "%1 is momenteel in onderhoud modus. Probeer later opnieuw", "maintenance.messageIntro": "daarnaast heeft de administrator het volgende bericht achtergelaten:" } \ No newline at end of file diff --git a/public/language/nl/recent.json b/public/language/nl/recent.json index e2f3471de6..887a149da0 100644 --- a/public/language/nl/recent.json +++ b/public/language/nl/recent.json @@ -6,14 +6,14 @@ "year": "Jaar", "alltime": "Intussen", "no_recent_topics": "Er zijn geen recente reacties.", - "no_popular_topics": "There are no popular topics.", + "no_popular_topics": "Er zijn geen populaire onderwerpen.", "there-is-a-new-topic": "Er is een nieuw onderwerp", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", + "there-is-a-new-topic-and-a-new-post": "Er is een nieuw onderwerp en een nieuw bericht.", "there-is-a-new-topic-and-new-posts": "Er is een nieuwe onderwerp en %1 nieuwe berichten", "there-are-new-topics": "Er zijn %1 nieuwe onderwerpen", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", - "click-here-to-reload": "Click here to reload." + "there-are-new-topics-and-a-new-post": "Er zijn %1 nieuwe onderwerpen en een nieuw bericht.", + "there-are-new-topics-and-new-posts": "Er zijn %1 nieuwe onderwerpen en %2 nieuwe berichten.", + "there-is-a-new-post": "Er is een nieuw bericht.", + "there-are-new-posts": "Er zijn %1 nieuwe berichten.", + "click-here-to-reload": "Klik hier om te herladen." } \ No newline at end of file diff --git a/public/language/nl/reset_password.json b/public/language/nl/reset_password.json index 2bac7d3849..1813eab2fe 100644 --- a/public/language/nl/reset_password.json +++ b/public/language/nl/reset_password.json @@ -11,6 +11,6 @@ "enter_email_address": "Vul uw Email Adres in", "password_reset_sent": "Wachtwoord Reset Verzonden", "invalid_email": "Fout Email Adres / Email Adres bestaat niet!", - "password_too_short": "The password entered is too short, please pick a different password.", - "passwords_do_not_match": "The two passwords you've entered do not match." + "password_too_short": "Het ingegeven wachtwoord is te kort. Kiest u alstublieft een ander wachtwoord.", + "passwords_do_not_match": "De twee wachtwoorden die u heeft ingegeven komen niet overeen." } \ No newline at end of file diff --git a/public/language/nl/search.json b/public/language/nl/search.json index 756a0ef3a7..c104ef95d3 100644 --- a/public/language/nl/search.json +++ b/public/language/nl/search.json @@ -3,38 +3,38 @@ "no-matches": "Geen matches gevonden", "in": "in", "by": "door", - "titles": "Titles", - "titles-posts": "Titles and Posts", - "posted-by": "Posted by", - "in-categories": "In Categories", - "search-child-categories": "Search child categories", - "reply-count": "Reply Count", - "at-least": "At least", - "at-most": "At most", - "post-time": "Post time", - "newer-than": "Newer than", - "older-than": "Older than", - "any-date": "Any date", - "yesterday": "Yesterday", - "one-week": "One week", - "two-weeks": "Two weeks", - "one-month": "One month", - "three-months": "Three months", - "six-months": "Six months", - "one-year": "One year", - "sort-by": "Sort by", - "last-reply-time": "Last reply time", - "topic-title": "Topic title", - "number-of-replies": "Number of replies", - "number-of-views": "Number of views", - "topic-start-date": "Topic start date", - "username": "Username", - "category": "Category", - "descending": "In descending order", - "ascending": "In ascending order", - "save-preferences": "Save preferences", - "clear-preferences": "Clear preferences", - "search-preferences-saved": "Search preferences saved", - "search-preferences-cleared": "Search preferences cleared", - "show-results-as": "Show results as" + "titles": "Titels", + "titles-posts": "Titels en Berichten", + "posted-by": "Geplaatst door", + "in-categories": "In categorieën", + "search-child-categories": "Doorzoek sub categorieën ", + "reply-count": "Aantal reacties", + "at-least": "Minimaal", + "at-most": "Maximaal", + "post-time": "Tijd van plaatsing", + "newer-than": "Nieuwer dan", + "older-than": "Ouder dan", + "any-date": "Iedere datum", + "yesterday": "Gisteren", + "one-week": "Eén week", + "two-weeks": "Twee weken", + "one-month": "Eén maand", + "three-months": "Drie maanden", + "six-months": "Zes maanden", + "one-year": "Eén jaar", + "sort-by": "Gesorteerd op", + "last-reply-time": "Laatste keer geantwoord", + "topic-title": "Onderwerp", + "number-of-replies": "Aantal antwoorden", + "number-of-views": "Aantal weergaven", + "topic-start-date": "Onderwerp aanmaakdatum", + "username": "Gebruikersnaam", + "category": "Categorie", + "descending": "In aflopende volgorde", + "ascending": "In oplopende volgorde", + "save-preferences": "Bewaar voorkeuren", + "clear-preferences": "Voorkeuren verwijderen", + "search-preferences-saved": "Zoek voorkeuren opgeslagen", + "search-preferences-cleared": "Zoek voorkeuren verwijderd", + "show-results-as": "Toon resultaten als" } \ No newline at end of file diff --git a/public/language/nl/tags.json b/public/language/nl/tags.json index 85c11b0476..ec028f3248 100644 --- a/public/language/nl/tags.json +++ b/public/language/nl/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Er zijn geen onderwerpen met deze tag", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Voegt u hier tags toe, tussen de %1 en %2 karakters per stuk.", "enter_tags_here_short": "Voer uw tags in...", "no_tags": "Er zijn nog geen tags te vinden" } \ No newline at end of file diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index 5f9250bea4..35679bccfd 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -12,7 +12,7 @@ "notify_me": "Krijg notificaties van nieuwe reacties op dit onderwerp", "quote": "Citeren", "reply": "Reageren", - "guest-login-reply": "Log in to reply", + "guest-login-reply": "Log in om een reactie te plaatsen", "edit": "Aanpassen", "delete": "Verwijderen", "purge": "weggooien", diff --git a/public/language/nl/user.json b/public/language/nl/user.json index 0cc9df6cbe..6726bf11ba 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -3,7 +3,7 @@ "offline": "Offline", "username": "Gebruikersnaam", "joindate": "Datum van registratie", - "postcount": "Post Count", + "postcount": "Aantal geplaatste berichten", "email": "Email", "confirm_email": "Bevestig uw email adres", "delete_account": "Account Verwijderen", @@ -18,7 +18,7 @@ "profile_views": "Profiel weergaven", "reputation": "Reputatie", "favourites": "Favorieten", - "watched": "Watched", + "watched": "Bekeken", "followers": "Volgers", "following": "Volgend", "signature": "Handtekening", @@ -59,12 +59,13 @@ "digest_weekly": "Weekelijks", "digest_monthly": "Maandelijks", "send_chat_notifications": "Verstuur mij een email als iemand een chatbericht stuurt terwijl ik niet online ben", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "Stuur een email als er een reactie wordt geplaatst in een topic waarop ik geabonneerd ben", + "settings-require-reload": "Sommige veranderingen vereisen het om de pagina te herladen. Klik hier om te herladen.", "has_no_follower": "Deze gebruiker heeft geen volgers :(", "follows_no_one": "Deze gebruiker volgt niemand :(", "has_no_posts": "Deze gebruiker heeft nog geen berichten geplaatst", "has_no_topics": "Deze gebruiker heeft nog geen berichten geplaatst", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "Deze gebruiker heeft nog geen berichten bekeken", "email_hidden": "Email Verborgen", "hidden": "verborgen", "paginate_description": "Blader door onderwerpen en berichten in plaats van oneindig scrollen.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Zet zoeken in het onderwerp aan", "topic_search_help": "Als het is ingeschakeld, dan zal het standaard zoeken overschrijven en zal je vanaf nu het gehele onderwerp kunnen doorzoeken ipv wat je standaard ziet.", "follow_topics_you_reply_to": "Volg de onderwerpen waarop u gereageerd heeft.", - "follow_topics_you_create": "Volg de onderwerpen die u gecreëerd heeft." + "follow_topics_you_create": "Volg de onderwerpen die u gecreëerd heeft.", + "grouptitle": "Selecteer de groepstitel die u wilt weergeven " } \ No newline at end of file diff --git a/public/language/nl/users.json b/public/language/nl/users.json index 315b86fe31..93e723d7b1 100644 --- a/public/language/nl/users.json +++ b/public/language/nl/users.json @@ -5,7 +5,7 @@ "search": "Zoeken", "enter_username": "Vul een gebruikersnaam in om te zoeken", "load_more": "Meer Laden", - "users-found-search-took": "%1 user(s) found! Search took %2 seconds.", + "users-found-search-took": "%1 gebruiker(s) gevonden! Zoekactie duurde %2 seconden.", "filter-by": "Filter op", "online-only": "Online ", "picture-only": "Alleen een afbeelding" diff --git a/public/language/pl/error.json b/public/language/pl/error.json index c967749eeb..e8f8f3dcdf 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -18,7 +18,7 @@ "username-taken": "Login zajęty.", "email-taken": "E-mail zajęty.", "email-not-confirmed": "Twój email nie został jeszcze potwierdzony. Proszę kliknąć tutaj by go potwierdzić.", - "email-not-confirmed-chat": "Nie możesz rozmawiać do czasu, gdy twój email zostanie potwierdzony.", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "To forum wymaga weryfikacji przez email. Proszę kliknąć tutaj, aby wprowadzić adres.", "email-confirm-failed": "Nie byliśmy w stanie potwierdzić twojego email-a. Proszę spróbować później.", "username-too-short": "Nazwa użytkownika za krótka.", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index af44c3ab51..f4a7f34c86 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 miesiące", "composer.user_said_in": "%1 powiedział w %2:", "composer.user_said": "%1 powiedział:", - "composer.discard": "Na pewno chcesz porzucić ten post?" + "composer.discard": "Na pewno chcesz porzucić ten post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/pl/pages.json b/public/language/pl/pages.json index 7f71ba388a..91e9e5efe4 100644 --- a/public/language/pl/pages.json +++ b/public/language/pl/pages.json @@ -14,6 +14,7 @@ "user.groups": "Grupy %1", "user.favourites": "Ulubione posty %1", "user.settings": "Ustawienia użytkownika", + "user.watched": "Topics watched by %1", "maintenance.text": "Obecnie trwają prace konserwacyjne nad %1. Proszę wrócić później.", "maintenance.messageIntro": "Dodatkowo, administrator zostawił wiadomość:" } \ No newline at end of file diff --git a/public/language/pl/tags.json b/public/language/pl/tags.json index 3036b34e62..a2247f39e7 100644 --- a/public/language/pl/tags.json +++ b/public/language/pl/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Nie ma tematów z tym tagiem", "tags": "Tagi", - "enter_tags_here": "Tutaj wpisz tagi. %1-%2 znaków. Naciśnij enter po każdym.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Wpisz tagi...", "no_tags": "Jeszcze nie ma tagów." } \ No newline at end of file diff --git a/public/language/pl/user.json b/public/language/pl/user.json index e28e3f637f..b0c031f94c 100644 --- a/public/language/pl/user.json +++ b/public/language/pl/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Co miesiąc", "send_chat_notifications": "Wyślij e-maila, jeśli dostanę nową wiadomość, a nie jestem on-line", "send_post_notifications": "Wyślij e-maila, kiedy wątki, które subskrybuję otrzymają odpowiedź", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Ten użytkownik nie ma jeszcze żadnych obserwujących", "follows_no_one": "Użytkownik jeszcze nikogo nie obsweruje.", "has_no_posts": "Użytkownik nie napisał jeszcze żadnych postów.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Odblokuj szukanie w wątku", "topic_search_help": "Jeśli odblokowane, szukanie w wątku zastąpi domyślną funkcję szukania przeglądarki, pozwalając na wyszukiwanie fraz tylko w wątku, a nie na całej stronie.", "follow_topics_you_reply_to": "Śledź tematy, w których piszesz.", - "follow_topics_you_create": "Śledź swoje tematy." + "follow_topics_you_create": "Śledź swoje tematy.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/pt_BR/category.json b/public/language/pt_BR/category.json index a781984e16..7dc608219f 100644 --- a/public/language/pt_BR/category.json +++ b/public/language/pt_BR/category.json @@ -1,6 +1,6 @@ { "new_topic_button": "Novo Tópico", - "guest-login-post": "Log in to post", + "guest-login-post": "Logue-se para postar", "no_topics": "<strong>Não tem nenhum tópico nesta categoria.</strong><br />Por que você não tenta postar o algum?", "browsing": "navegando", "no_replies": "Ninguém respondeu", diff --git a/public/language/pt_BR/error.json b/public/language/pt_BR/error.json index 359f3c654a..cb218a3d43 100644 --- a/public/language/pt_BR/error.json +++ b/public/language/pt_BR/error.json @@ -18,9 +18,9 @@ "username-taken": "Nome de usuário já existe", "email-taken": "Email já cadastrado", "email-not-confirmed": "O seu email ainda não foi confirmado, por favor clique aqui para confirmar seu email.", - "email-not-confirmed-chat": "Você não pode usar o chat até que seu email seja confirmado", - "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", - "email-confirm-failed": "We could not confirm your email, please try again later.", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", + "no-email-to-confirm": "Este fórum exige confirmação de email, por gentileza clique aqui para digitar um email", + "email-confirm-failed": "Nós não pudemos confirmar seu email, por gentileza tente novamente mais tarde.", "username-too-short": "Nome de usuário muito curto", "username-too-long": "Nome de usuário muito longo", "user-banned": "Usuário banido", @@ -35,7 +35,7 @@ "no-emailers-configured": "Nenhum plugin de email foi carregado, por isso um email de teste não pôde ser enviado", "category-disabled": "Categoria desativada", "topic-locked": "Tópico Trancado", - "post-edit-duration-expired": "You are only allowed to edit posts for %1 seconds after posting", + "post-edit-duration-expired": "Você pode editar posts por %1 segundos após postar", "still-uploading": "Aguarde a conclusão dos uploads.", "content-too-short": "Por favor digite um post mais longo. Posts devem conter no mínimo %1 caracteres.", "content-too-long": "Por favor entre com um post mais curto. Posts não podem ser maiores do que %1 caracteres.", @@ -43,8 +43,8 @@ "title-too-long": "Por favor entre com um título mais curto; Títulos não podem ser maiores que %1 caracteres.", "too-many-posts": "Você pode postar apenas uma vez a cada %1 segundos - por favor aguarde antes de postar novamente", "too-many-posts-newbie": "Como novo usuário, você pode postar apenas uma vez a cada %1 segundos até que você tenha recebido reputação de %2 - por favor aguarde antes de postar novamente", - "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 characters", - "tag-too-long": "Please enter a shorter tag. Tags can't be longer than %1 characters", + "tag-too-short": "Por favor digite uma tag mais longa. Tags devem conter pelo menos %1 caracteres", + "tag-too-long": "Por favor digite uma tag mais curta. Tags não podem ter mais do que %1 caracteres", "file-too-big": "O tamanho máximo permitido de arquivo é %1 kbs - por favor faça upload de um arquivo menor", "cant-vote-self-post": "Você não pode votar no seu próprio post", "already-favourited": "Você já adicionou este post aos favoritos", @@ -52,7 +52,7 @@ "cant-ban-other-admins": "Você não pode banir outros administradores!", "invalid-image-type": "Tipo inválido de imagem. Os tipos permitidos são: %1", "invalid-image-extension": "Extensão de imagem inválida", - "invalid-file-type": "Invalid file type. Allowed types are: %1", + "invalid-file-type": "Tipo de arquivo inválido. Os tipos permitidos são: %1", "group-name-too-short": "Nome do grupo é muito curto", "group-already-exists": "O grupo já existe", "group-name-change-not-allowed": "Sem permissão para alterar nome do grupo", @@ -76,6 +76,6 @@ "reload-failed": "O NodeBB encontrou um problema ao recarregar: \"%1\". O NodeBB continuará a servir os assets existentes no lado do cliente, apesar de que você deve desfazer o que você fez antes de recarregar.", "registration-error": "Erro de Cadastro", "parse-error": "Algo deu errado ao conseguir resposta do servidor", - "wrong-login-type-email": "Please use your email to login", - "wrong-login-type-username": "Please use your username to login" + "wrong-login-type-email": "Por favor use seu email para se logar", + "wrong-login-type-username": "Por favor use o seu nome de usuário para se logar" } \ No newline at end of file diff --git a/public/language/pt_BR/groups.json b/public/language/pt_BR/groups.json index a9e9efa321..2246818345 100644 --- a/public/language/pt_BR/groups.json +++ b/public/language/pt_BR/groups.json @@ -4,8 +4,8 @@ "owner": "Dono do Grupo", "new_group": "Criar Novo Grupo", "no_groups_found": "Não há grupos para ver", - "pending.accept": "Accept", - "pending.reject": "Reject", + "pending.accept": "Aceitar", + "pending.reject": "Rejeitar", "cover-instructions": "Arraste uma foto, arraste para a posição correta e clique em <strong>Salvar</strong>", "cover-change": "Alterar", "cover-save": "Salvar", @@ -15,20 +15,20 @@ "details.pending": "Membros Pendentes", "details.has_no_posts": "Os membros deste grupo não fizeram quaisquer posts.", "details.latest_posts": "Últimos Posts", - "details.private": "Private", + "details.private": "Particular", "details.grant": "Conceder/Retomar a Posse", "details.kick": "Chutar", "details.owner_options": "Administração do Grupo", - "details.group_name": "Group Name", - "details.description": "Description", - "details.badge_preview": "Badge Preview", - "details.change_icon": "Change Icon", - "details.change_colour": "Change Colour", - "details.badge_text": "Badge Text", - "details.userTitleEnabled": "Show Badge", - "details.private_help": "If enabled, joining of groups requires approval from a group owner", - "details.hidden": "Hidden", - "details.hidden_help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually", + "details.group_name": "Nome do Grupo", + "details.description": "Descrição", + "details.badge_preview": "Visualização do Distintivo", + "details.change_icon": "Mudar Ícone", + "details.change_colour": "Mudar Cor", + "details.badge_text": "Texto do Distintivo", + "details.userTitleEnabled": "Mostrar Distintivo", + "details.private_help": "Se habilitado, a entrada nos grupos requer aprovação de um dos donos do grupo", + "details.hidden": "Oculto", + "details.hidden_help": "Se habilitado, este grupo não se encontrará na listagem de grupos e os usuários terão de ser convivados manualmente", "event.updated": "Os detalhes do grupo foram atualizados", "event.deleted": "O grupo \"%1\" foi deletado" } \ No newline at end of file diff --git a/public/language/pt_BR/login.json b/public/language/pt_BR/login.json index 9b267d8d9c..7b8299af75 100644 --- a/public/language/pt_BR/login.json +++ b/public/language/pt_BR/login.json @@ -1,6 +1,6 @@ { - "username-email": "Username / Email", - "username": "Username", + "username-email": "Nome de usuário / Email", + "username": "Nome de usuário", "email": "Email", "remember_me": "Lembrar de Mim?", "forgot_password": "Esqueceu a Senha?", diff --git a/public/language/pt_BR/modules.json b/public/language/pt_BR/modules.json index 78dbe3d9d8..c899137cd6 100644 --- a/public/language/pt_BR/modules.json +++ b/public/language/pt_BR/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Meses", "composer.user_said_in": "%1 disse em %2:", "composer.user_said": "%1 disse:", - "composer.discard": "Tem certeza que deseja descartar essa postagem?" + "composer.discard": "Tem certeza que deseja descartar essa postagem?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/pt_BR/notifications.json b/public/language/pt_BR/notifications.json index 72b406d47b..cb3f217b47 100644 --- a/public/language/pt_BR/notifications.json +++ b/public/language/pt_BR/notifications.json @@ -2,7 +2,7 @@ "title": "Notificações", "no_notifs": "Você não tem nenhuma notificação nova", "see_all": "Ver todas as Notificações", - "mark_all_read": "Mark all notifications read", + "mark_all_read": "Marcas todas as notificações como lidas", "back_to_home": "Voltar para %1", "outgoing_link": "Link Externo", "outgoing_link_message": "Você deixou de seguir %1.", diff --git a/public/language/pt_BR/pages.json b/public/language/pt_BR/pages.json index 415f50c0fd..edcc280f4b 100644 --- a/public/language/pt_BR/pages.json +++ b/public/language/pt_BR/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Grupos", "user.favourites": "Posts Favoritos de %1", "user.settings": "Configurações de Usuário", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 está atualmente sob manutenção. Por favor retorne em outro momento.", "maintenance.messageIntro": "Adicionalmente, o administrador deixou esta mensagem:" } \ No newline at end of file diff --git a/public/language/pt_BR/recent.json b/public/language/pt_BR/recent.json index 2af16e248a..322ab84c1f 100644 --- a/public/language/pt_BR/recent.json +++ b/public/language/pt_BR/recent.json @@ -6,7 +6,7 @@ "year": "Ano", "alltime": "Todos os Tempos", "no_recent_topics": "Não há tópicos recentes.", - "no_popular_topics": "There are no popular topics.", + "no_popular_topics": "Não há tópicos populares.", "there-is-a-new-topic": "Há um novo tópico.", "there-is-a-new-topic-and-a-new-post": "Há um novo tópico e um novo post.", "there-is-a-new-topic-and-new-posts": "Há um novo tópico e %1 novos posts.", diff --git a/public/language/pt_BR/search.json b/public/language/pt_BR/search.json index 695d7795ce..9c48e1dfc0 100644 --- a/public/language/pt_BR/search.json +++ b/public/language/pt_BR/search.json @@ -32,9 +32,9 @@ "category": "Categoria", "descending": "Em ordem descendente", "ascending": "Em ordem ascendente", - "save-preferences": "Save preferences", - "clear-preferences": "Clear preferences", - "search-preferences-saved": "Search preferences saved", - "search-preferences-cleared": "Search preferences cleared", - "show-results-as": "Show results as" + "save-preferences": "Salvar preferências", + "clear-preferences": "Limpar preferências", + "search-preferences-saved": "Preferências de busca salvas", + "search-preferences-cleared": "Preferências de busca limpas", + "show-results-as": "Mostrar resultados como" } \ No newline at end of file diff --git a/public/language/pt_BR/tags.json b/public/language/pt_BR/tags.json index 267888cbfa..1150d12f7f 100644 --- a/public/language/pt_BR/tags.json +++ b/public/language/pt_BR/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Não há tópicos com esta tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Digite tags...", "no_tags": "Ainda não há tags." } \ No newline at end of file diff --git a/public/language/pt_BR/topic.json b/public/language/pt_BR/topic.json index a99468a79f..2c15fac095 100644 --- a/public/language/pt_BR/topic.json +++ b/public/language/pt_BR/topic.json @@ -12,7 +12,7 @@ "notify_me": "Seja notificado de novas respostas nesse tópico", "quote": "Citar", "reply": "Responder", - "guest-login-reply": "Log in to reply", + "guest-login-reply": "Logue-se para responder", "edit": "Editar", "delete": "Deletar", "purge": "Expurgar", diff --git a/public/language/pt_BR/user.json b/public/language/pt_BR/user.json index 86412afd5c..be3033d1c3 100644 --- a/public/language/pt_BR/user.json +++ b/public/language/pt_BR/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Mensalmente", "send_chat_notifications": "Enviar-me um email se uma nova mensagem de chat chegar quando eu não estiver online.", "send_post_notifications": "Enviar um email quando respostas forem dadas à tópicos que eu assino", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Este usuário não possui seguidores :(", "follows_no_one": "Este usuário não está seguindo ninguém :(", "has_no_posts": "Este usuário não postou nada ainda.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Habilitar Pesquisa dentro de Tópico", "topic_search_help": "Se habilitado, a pesquisa dentro de tópico irá substituir o funcionamento padrão de pesquisa de página do navegador e permitir que você pesquise pelo tópico todo, ao invés de apenas o que é mostrado na tela.", "follow_topics_you_reply_to": "Seguir tópicos que você responde.", - "follow_topics_you_create": "Seguir tópicos que você cria." + "follow_topics_you_create": "Seguir tópicos que você cria.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/ro/error.json b/public/language/ro/error.json index 51ad7c7cbc..1c60c0cf83 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -18,7 +18,7 @@ "username-taken": "Numele de utilizator este deja folosit", "email-taken": "Adresa de email este deja folostă", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Numele de utilizator este prea scurt", diff --git a/public/language/ro/modules.json b/public/language/ro/modules.json index 7c4f898389..585309d2ea 100644 --- a/public/language/ro/modules.json +++ b/public/language/ro/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Luni", "composer.user_said_in": "%1 a spus în %2:", "composer.user_said": "%1 a spus:", - "composer.discard": "Ești sigur că vrei să renunți la acest mesaj?" + "composer.discard": "Ești sigur că vrei să renunți la acest mesaj?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/ro/pages.json b/public/language/ro/pages.json index 141c5fb1df..86deca16e0 100644 --- a/public/language/ro/pages.json +++ b/public/language/ro/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "Mesajele favorite ale lui %1", "user.settings": "Setări Utilizator", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 este momentan în mentenanță. Întoarce-te în curând!", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/ro/tags.json b/public/language/ro/tags.json index 483efa66f6..59edbb0063 100644 --- a/public/language/ro/tags.json +++ b/public/language/ro/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Nu există nici un subiect cu acest tag.", "tags": "Taguri", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Introdu taguri...", "no_tags": "În acest moment nu există nici un tag." } \ No newline at end of file diff --git a/public/language/ro/user.json b/public/language/ro/user.json index 3fa30f4836..7c5abe0840 100644 --- a/public/language/ro/user.json +++ b/public/language/ro/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Lunar", "send_chat_notifications": "Trimite-mi un email dacă primesc un mesaj în chat si eu nu sunt online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Pe acest utilizator nu îl urmărește nimeni :(", "follows_no_one": "Acest utilizator nu urmărește pe nimeni :(", "has_no_posts": "Acest utilizator nu a postat nici un mesaj până acuma.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Urmărește subiectele în care ai răspuns.", - "follow_topics_you_create": "Urmărește subiectele care le creezi." + "follow_topics_you_create": "Urmărește subiectele care le creezi.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/ru/error.json b/public/language/ru/error.json index bca2535d19..e4be1447a2 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -18,7 +18,7 @@ "username-taken": "Имя пользователя занято", "email-taken": "Email занят", "email-not-confirmed": "Ваш email не подтвержден, нажмите для подтверждения.", - "email-not-confirmed-chat": "Вы не можете оставлять сообщения, пока Ваш email не подтверждён", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "Этот форум требует подтверждения по E-mail. Нажмите здесь для ввода E-mail.", "email-confirm-failed": "Мы не можем подтвердить Ваш E-mail, попробуйте позже.", "username-too-short": "Слишком короткое имя пользователя", diff --git a/public/language/ru/groups.json b/public/language/ru/groups.json index 8ef4e59089..87d1f1c98e 100644 --- a/public/language/ru/groups.json +++ b/public/language/ru/groups.json @@ -21,11 +21,11 @@ "details.owner_options": "Настройки группы", "details.group_name": "Имя группы", "details.description": "Описание", - "details.badge_preview": "Предпросмотр Бейджа", + "details.badge_preview": "Предпросмотр бейджа", "details.change_icon": "Сменить иконку", "details.change_colour": "Изменить цвет", - "details.badge_text": "Текст на Бейдже", - "details.userTitleEnabled": "Показать Бейдж", + "details.badge_text": "Текст на бейдже", + "details.userTitleEnabled": "Показать бейдж", "details.private_help": "Если включено, вступление в группы будет подтверждаться владельцем группы", "details.hidden": "Скрыто", "details.hidden_help": "Если включено, группа не будет показываться в списках, а пользователи должны приглашаться вручную", diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index 82611f15e7..c707341577 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 месяца", "composer.user_said_in": "%1 сказал %2:", "composer.user_said": "%1 сказал:", - "composer.discard": "Вы уверены, что хотите отказаться от этого поста?" + "composer.discard": "Вы уверены, что хотите отказаться от этого поста?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/ru/pages.json b/public/language/ru/pages.json index 9ad5cae0c2..b7b35fa25e 100644 --- a/public/language/ru/pages.json +++ b/public/language/ru/pages.json @@ -14,6 +14,7 @@ "user.groups": "Группы %1", "user.favourites": "Избранные сообщения %1", "user.settings": "Настройки", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 в настоящее время на обслуживании. Пожалуйста, возвращайтесь позже.", "maintenance.messageIntro": "Администратор оставил сообщение:" } \ No newline at end of file diff --git a/public/language/ru/search.json b/public/language/ru/search.json index 8fa2f31ebd..54886ccf15 100644 --- a/public/language/ru/search.json +++ b/public/language/ru/search.json @@ -34,7 +34,7 @@ "ascending": "В порядке убывания", "save-preferences": "Сохранить настройки", "clear-preferences": "Очистить настройки", - "search-preferences-saved": "Искать сохраненные настройки", - "search-preferences-cleared": "Search preferences cleared", + "search-preferences-saved": "Настройки поиска сохранены", + "search-preferences-cleared": "Настройки поиска очищены", "show-results-as": "Показать результаты как" } \ No newline at end of file diff --git a/public/language/ru/tags.json b/public/language/ru/tags.json index 8b78464be4..e923cccf2c 100644 --- a/public/language/ru/tags.json +++ b/public/language/ru/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Нет топиков с таким тегом.", "tags": "Теги", - "enter_tags_here": "Укажите тэги здесь. %1-%2 символов(а). Нажимайте Enter после каждого тэга.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Введите теги...", "no_tags": "Здесь еще нет тегов." } \ No newline at end of file diff --git a/public/language/ru/user.json b/public/language/ru/user.json index 99be44abd6..12797aef20 100644 --- a/public/language/ru/user.json +++ b/public/language/ru/user.json @@ -60,6 +60,7 @@ "digest_monthly": "За месяц", "send_chat_notifications": "Уведомлять на E-mail при поступлении нового сообщения чата, когда я оффлайн", "send_post_notifications": "Отправлять email, когда отвечают в темы, на которые я подписан(а)", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Этого пользователя никто не читает :(", "follows_no_one": "Этот пользователь никого не читает :(", "has_no_posts": "Этот пользователь еще ничего не написал.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Активировать поиск внутри тем", "topic_search_help": "Если включено, то стандартный \"Поиск на странице\" Вашего браузера будет осуществлять поиск по всей теме вместо одной её страницы.", "follow_topics_you_reply_to": "Следить за темами, в которых Вы отвечали.", - "follow_topics_you_create": "Следить за темами, которые Вы создали." + "follow_topics_you_create": "Следить за темами, которые Вы создали.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/sc/error.json b/public/language/sc/error.json index e0700f76c4..17465a20a3 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -18,7 +18,7 @@ "username-taken": "Username taken", "email-taken": "Email taken", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Username too short", diff --git a/public/language/sc/modules.json b/public/language/sc/modules.json index f24225a4ce..c34b686af0 100644 --- a/public/language/sc/modules.json +++ b/public/language/sc/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/sc/pages.json b/public/language/sc/pages.json index 0f846179c3..f087a77706 100644 --- a/public/language/sc/pages.json +++ b/public/language/sc/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "Arresonos Preferidos de %1", "user.settings": "Sèberos de Impitadore", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/sc/tags.json b/public/language/sc/tags.json index aa9f14c70c..c416d8d4ec 100644 --- a/public/language/sc/tags.json +++ b/public/language/sc/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "There are no topics with this tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Enter tags...", "no_tags": "There are no tags yet." } \ No newline at end of file diff --git a/public/language/sc/user.json b/public/language/sc/user.json index b083df5e52..01f88d738a 100644 --- a/public/language/sc/user.json +++ b/public/language/sc/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Monthly", "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Custu impitadore non tenet perunu sighidore :(", "follows_no_one": "Custu impitadore no est sighende nissunu :(", "has_no_posts": "Custu impitadore no at ancora publicadu nudda.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_create": "Follow topics you create.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/sk/error.json b/public/language/sk/error.json index 069d7b8deb..93c15ed553 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -18,7 +18,7 @@ "username-taken": "Užívateľske meno je obsadené", "email-taken": "Email je obsadený", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Username too short", diff --git a/public/language/sk/modules.json b/public/language/sk/modules.json index 335723bb7a..e8a242aba7 100644 --- a/public/language/sk/modules.json +++ b/public/language/sk/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/sk/pages.json b/public/language/sk/pages.json index c54ac7e71f..bbf7ebeebb 100644 --- a/public/language/sk/pages.json +++ b/public/language/sk/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1's obľubených príspevkov", "user.settings": "Užívatelské nadstavenie", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", "maintenance.messageIntro": "Additionally, the administrator has left this message:" } \ No newline at end of file diff --git a/public/language/sk/tags.json b/public/language/sk/tags.json index aa9f14c70c..c416d8d4ec 100644 --- a/public/language/sk/tags.json +++ b/public/language/sk/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "There are no topics with this tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Enter tags...", "no_tags": "There are no tags yet." } \ No newline at end of file diff --git a/public/language/sk/user.json b/public/language/sk/user.json index 48aa4ec144..db1541864f 100644 --- a/public/language/sk/user.json +++ b/public/language/sk/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Mesačne", "send_chat_notifications": "Send an email if a new chat message arrives and I am not online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Tohoto užívatela nikto nesleduje :(", "follows_no_one": "Tento užívateľ nikoho nesleduje :(", "has_no_posts": "Tento používateľ ešte nespravil príspevok", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "Follow topics that you reply to.", - "follow_topics_you_create": "Follow topics you create." + "follow_topics_you_create": "Follow topics you create.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/sv/error.json b/public/language/sv/error.json index 8f8c577d0d..99879a3388 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -18,7 +18,7 @@ "username-taken": "Användarnamn upptaget", "email-taken": "Epostadress upptagen", "email-not-confirmed": "Din epostadress är ännu inte bekräftad. Klicka här för att bekräfta din epostadress.", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Användarnamnet är för kort", diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index cb61fddae5..05d12e9247 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Månader", "composer.user_said_in": "%1 sa i %2:", "composer.user_said": "%1 sa:", - "composer.discard": "Är du säker på att du vill förkasta det här inlägget?" + "composer.discard": "Är du säker på att du vill förkasta det här inlägget?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/sv/pages.json b/public/language/sv/pages.json index f7a4904a84..61fb23b776 100644 --- a/public/language/sv/pages.json +++ b/public/language/sv/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "%1's favorit-inlägg", "user.settings": "Avnändarinställningar", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 genomgår underhåll just nu. Vänligen kom tillbaka lite senare.", "maintenance.messageIntro": "Ytterligare så lämnade administratören detta meddelande:" } \ No newline at end of file diff --git a/public/language/sv/tags.json b/public/language/sv/tags.json index fffe39ea0a..d846962ea4 100644 --- a/public/language/sv/tags.json +++ b/public/language/sv/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Det finns inga ämnen med detta märkord.", "tags": "Märkord", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Ange taggar...", "no_tags": "Det finns inga märkord ännu." } \ No newline at end of file diff --git a/public/language/sv/user.json b/public/language/sv/user.json index 6a773c45b4..14ceb0336a 100644 --- a/public/language/sv/user.json +++ b/public/language/sv/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Månadsvis", "send_chat_notifications": "Skicka ett epostmeddelande om nya chatt-meddelanden tas emot när jag inte är online.", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Denna användare har inga följare :(", "follows_no_one": "Denna användare följer ingen :(", "has_no_posts": "Denna användare har inte gjort några inlägg än.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Aktivera Sökning Inom Ämne", "topic_search_help": "Om aktiverat kommer sökning inom ämne överskrida webbläsarens vanliga sid-sökfunktion och tillåta dig att söka genom hela ämnet istället för det som endast visas på skärmen.", "follow_topics_you_reply_to": "Följ ämnen so du svarat på.", - "follow_topics_you_create": "Följ ämnen du skapat." + "follow_topics_you_create": "Följ ämnen du skapat.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/th/category.json b/public/language/th/category.json index 387458a0dd..e5d6b1e0fc 100644 --- a/public/language/th/category.json +++ b/public/language/th/category.json @@ -1,9 +1,9 @@ { "new_topic_button": "กระทู้", - "guest-login-post": "Log in to post", + "guest-login-post": "เข้าสู่ระบบเพื่อโพส", "no_topics": "<strong>ยังไม่มีกระทู้ในหมวดนี้</strong><br />โพสต์กระทู้แรก?", "browsing": "เรียกดู", "no_replies": "ยังไม่มีใครตอบ", - "share_this_category": "Share this category", - "ignore": "Ignore" + "share_this_category": "แชร์ Category นี้", + "ignore": "ไม่ต้องสนใจอีก" } \ No newline at end of file diff --git a/public/language/th/error.json b/public/language/th/error.json index 064bd1b530..7a46ebaa65 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -3,37 +3,37 @@ "not-logged-in": "คุณยังไม่ได้ลงชื่อเข้าระบบ", "account-locked": "บัญชีของคุณถูกระงับการใช้งานชั่วคราว", "search-requires-login": "ต้องลงทะเบียนบัญชีผู้ใช้สำหรับการค้นหา! โปรดลงชื่อเข้าระบบ หรือ ลงทะเบียน!", - "invalid-cid": "Invalid Category ID", - "invalid-tid": "Invalid Topic ID", - "invalid-pid": "Invalid Post ID", - "invalid-uid": "Invalid User ID", - "invalid-username": "Invalid Username", - "invalid-email": "Invalid Email", - "invalid-title": "Invalid title!", - "invalid-user-data": "Invalid User Data", - "invalid-password": "Invalid Password", - "invalid-username-or-password": "Please specify both a username and password", - "invalid-search-term": "Invalid search term", + "invalid-cid": "Category ID ไม่ถูกต้อง", + "invalid-tid": "Topic ID ไม่ถูกต้อง", + "invalid-pid": "Post ID ไม่ถูกต้อง", + "invalid-uid": "User ID ไม่ถูกต้อง", + "invalid-username": "ชื่อผู้ใช้ไม่ถูกต้อง", + "invalid-email": "อีเมลไม่ถูกต้อง", + "invalid-title": "คำนำหน้าชื่อไม่ถูกต้อง", + "invalid-user-data": "User Data ไม่ถูกต้อง", + "invalid-password": "รหัสผ่านไม่ถูกต้อง", + "invalid-username-or-password": "กรุณาระบุชื่อผู้ใช้และรหัสผ่าน", + "invalid-search-term": "ข้อความค้นหาไม่ถูกต้อง", "invalid-pagination-value": "Invalid pagination value", "username-taken": "ชื่อผู้ใช้นี้มีการใช้แล้ว", "email-taken": "อีเมลนี้มีการใช้แล้ว", "email-not-confirmed": "ยังไม่มีการยืนยันอีเมลของคุณ, โปรดกดยืนยันอีเมลของคุณตรงนี้", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", - "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", - "email-confirm-failed": "We could not confirm your email, please try again later.", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", + "no-email-to-confirm": "Forum นี้ต้องการการยืนยันอีเมล กรุณากดที่นี่เพื่อระบุอีเมล", + "email-confirm-failed": "เราไม่สามารถยืนยันอีเมลของคุณ ณ ขณะนี้ กรุณาลองใหม่อีกครั้งภายหลัง", "username-too-short": "ชื่อบัญชีผู้ใช้ สั้นเกินไป", "username-too-long": "ชื่อบัญชีผู้ใช้ ยาวเกินไป", "user-banned": "User banned", "user-too-new": "Sorry, you are required to wait %1 seconds before making your first post", - "no-category": "Category does not exist", - "no-topic": "Topic does not exist", - "no-post": "Post does not exist", - "no-group": "Group does not exist", - "no-user": "User does not exist", + "no-category": "ยังไม่มี Category นี้", + "no-topic": "ยังไม่มี Topic นี้", + "no-post": "ยังไม่มี Post นี้", + "no-group": "ยังไม่มี Group นี้", + "no-user": "ยังไม่มีผู้ใช้งานนี้", "no-teaser": "Teaser does not exist", - "no-privileges": "You do not have enough privileges for this action.", + "no-privileges": "คุณมีสิทธิ์ไม่เพียงพอที่จะทำรายการนี้", "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", - "category-disabled": "Category disabled", + "category-disabled": "Category นี้ถูกปิดการใช้งานแล้ว", "topic-locked": "Topic Locked", "post-edit-duration-expired": "You are only allowed to edit posts for %1 seconds after posting", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/th/global.json b/public/language/th/global.json index af4ff3bfd0..d81b58b8eb 100644 --- a/public/language/th/global.json +++ b/public/language/th/global.json @@ -14,20 +14,20 @@ "please_log_in": "กรุณาเข้าสู่ระบบ", "logout": "ออกจากระบบ", "posting_restriction_info": "คุณต้องต้องเป็นสมาชิกเพื่อทำการโพสต์ คลิกที่นี่เพื่อเข้าสู่ระบบ", - "welcome_back": "Welcome Back", + "welcome_back": "ยินดีต้อนรับ", "you_have_successfully_logged_in": "คุณได้เข้าสู่ระบบแล้ว", "save_changes": "บันทึกการเปลี่ยนแปลง", "close": "ปิด", "pagination": "ให้เลขหน้า", - "pagination.out_of": "%1 out of %2", + "pagination.out_of": "%1 จาก %2", "pagination.enter_index": "Enter index", "header.admin": "ผู้ดูแลระบบ", "header.recent": "ล่าสุด", "header.unread": "ไม่ได้อ่าน", - "header.tags": "Tags", + "header.tags": "Tag", "header.popular": "ฮิต", "header.users": "ผู้ใช้", - "header.groups": "Groups", + "header.groups": "Group", "header.chats": "สนทนา", "header.notifications": "แจ้งเตือน", "header.search": "ค้นหา", diff --git a/public/language/th/groups.json b/public/language/th/groups.json index d2314fdc29..be94efdf0b 100644 --- a/public/language/th/groups.json +++ b/public/language/th/groups.json @@ -1,34 +1,34 @@ { - "groups": "Groups", - "view_group": "View Group", - "owner": "Group Owner", - "new_group": "Create New Group", - "no_groups_found": "There are no groups to see", - "pending.accept": "Accept", - "pending.reject": "Reject", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit <strong>Save</strong>", - "cover-change": "Change", - "cover-save": "Save", - "cover-saving": "Saving", - "details.title": "Group Details", - "details.members": "Member List", - "details.pending": "Pending Members", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts", - "details.private": "Private", + "groups": "Group", + "view_group": "ดู Group", + "owner": "เจ้าของ Group", + "new_group": "สร้าง Group ใหม่", + "no_groups_found": "ยังไม่มี Group", + "pending.accept": "ยอมรับ", + "pending.reject": "ไม่ยอมรับ", + "cover-instructions": "ลากรูปภาพไปวางยังตำแหน่งที่ต้องการแล้วกดที่ปุ่ม <strong>บันทึก</strong>", + "cover-change": "ปรับปรุง", + "cover-save": "บันทึก", + "cover-saving": "กำลังบันทึก", + "details.title": "ข้อมูล Group", + "details.members": "รายชื่อสมาชิก", + "details.pending": "สมาชิกที่กำลังรอการตอบรับ", + "details.has_no_posts": "Group นี้ยังไม่มีโพสจากสมาชิก", + "details.latest_posts": "โพสล่าสุด", + "details.private": "ส่วนตัว", "details.grant": "Grant/Rescind Ownership", - "details.kick": "Kick", - "details.owner_options": "Group Administration", - "details.group_name": "Group Name", - "details.description": "Description", + "details.kick": "เตะออก", + "details.owner_options": "การจัดการ Group", + "details.group_name": "ชื่อ Group", + "details.description": "คำอธิบาย", "details.badge_preview": "Badge Preview", - "details.change_icon": "Change Icon", - "details.change_colour": "Change Colour", + "details.change_icon": "เปลี่ยนไอคอน", + "details.change_colour": "เปลี่ยนสี", "details.badge_text": "Badge Text", - "details.userTitleEnabled": "Show Badge", + "details.userTitleEnabled": "แสดง Badge", "details.private_help": "If enabled, joining of groups requires approval from a group owner", - "details.hidden": "Hidden", + "details.hidden": "ซ่อน", "details.hidden_help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually", - "event.updated": "Group details have been updated", + "event.updated": "ข้อมูล Group ได้รับการบันทึกแล้ว", "event.deleted": "The group \"%1\" has been deleted" } \ No newline at end of file diff --git a/public/language/th/login.json b/public/language/th/login.json index f0aff3c796..5eba336a39 100644 --- a/public/language/th/login.json +++ b/public/language/th/login.json @@ -1,7 +1,7 @@ { - "username-email": "Username / Email", - "username": "Username", - "email": "Email", + "username-email": "ชื่อผู้ใช้ / อีเมล", + "username": "ชื่อผู้ใช้", + "email": "อีเมล", "remember_me": "จำไว้ในระบบ?", "forgot_password": "ลืมรหัสผ่าน?", "alternative_logins": "เข้าสู่ระบบโดยทางอื่น", diff --git a/public/language/th/modules.json b/public/language/th/modules.json index c3ea23f0e2..21cb9a564d 100644 --- a/public/language/th/modules.json +++ b/public/language/th/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Months", "composer.user_said_in": "%1 said in %2:", "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "composer.discard": "Are you sure you wish to discard this post?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/th/pages.json b/public/language/th/pages.json index 44f8b127e1..91fe3f989a 100644 --- a/public/language/th/pages.json +++ b/public/language/th/pages.json @@ -5,15 +5,16 @@ "recent": "กระทู้ล่าสุด", "users": "ผู้ใช้ที่ลงทะเบียน", "notifications": "แจ้งเตือน", - "tags": "Topics tagged under \"%1\"", + "tags": "หัวข้อที่ถูก Tag อยู่ภายใต้ \"%1\"", "user.edit": "แก้ไข \"%1\"", "user.following": "ผู้ใช้ที่ %1 ติดตาม", "user.followers": "ผู้ใช้ที่ติดตาม %1", "user.posts": "กระทู้โดย %1", - "user.topics": "Topics created by %1", - "user.groups": "%1's Groups", + "user.topics": "หัวข้อที่ถูกสร้างโดย %1", + "user.groups": "กลุ่มของ %1", "user.favourites": "กระทู้ที่ %1 ชอบ", "user.settings": "ตั้งค่าผู้ใช้", - "maintenance.text": "%1 is currently undergoing maintenance. Please come back another time.", - "maintenance.messageIntro": "Additionally, the administrator has left this message:" + "user.watched": "Topics watched by %1", + "maintenance.text": "%1 กำลังอยู่ระหว่างการปิดปรับปรุงชั่วคราว กรุณาลองใหม่อีกครั้งในภายหลัง", + "maintenance.messageIntro": "ผู้ดูแลระบบได้ฝากข้อความต่อไปนี้เอาไว้" } \ No newline at end of file diff --git a/public/language/th/reset_password.json b/public/language/th/reset_password.json index 499f2f7136..1b66d7dd33 100644 --- a/public/language/th/reset_password.json +++ b/public/language/th/reset_password.json @@ -11,6 +11,6 @@ "enter_email_address": "ใส่อีเมล์", "password_reset_sent": "รหัสรีเซ็ตถูกส่งออกไปแล้ว", "invalid_email": "อีเมล์ไม่ถูกต้อง / อีเมล์ไม่มีอยู่!", - "password_too_short": "The password entered is too short, please pick a different password.", - "passwords_do_not_match": "The two passwords you've entered do not match." + "password_too_short": "รหัสผ่านที่คุณกำหนดยังสั้นเกินไป กรุณากำหนดรหัสผ่านของคุณใหม่", + "passwords_do_not_match": "รหัสผ่านทั้ง 2 ที่ใส่ไม่ตรงกัน" } \ No newline at end of file diff --git a/public/language/th/tags.json b/public/language/th/tags.json index d2d0ff6fe0..e8bf52df2e 100644 --- a/public/language/th/tags.json +++ b/public/language/th/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "ไม่มีหัวข้อสนทนาที่เกี่ยวข้องกับป้ายคำศัพท์นี้", "tags": "ป้ายคำศัพท์", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "ใส่ป้ายคำศัพท์ ...", "no_tags": "ยังไม่มีป้ายคำศัพท์" } \ No newline at end of file diff --git a/public/language/th/topic.json b/public/language/th/topic.json index 652ebe5db5..ea6a1a8998 100644 --- a/public/language/th/topic.json +++ b/public/language/th/topic.json @@ -4,15 +4,15 @@ "topic_id_placeholder": "Enter topic ID", "no_topics_found": "ไม่พบกระทู้", "no_posts_found": "ไม่พบโพส", - "post_is_deleted": "This post is deleted!", + "post_is_deleted": "ลบ Post นี้เรียบร้อยแล้ว!", "profile": "รายละเอียด", - "posted_by": "Posted by %1", - "posted_by_guest": "Posted by Guest", + "posted_by": "โพสโดย %1", + "posted_by_guest": "โพสโดย Guest", "chat": "แชท", "notify_me": "แจ้งเตือนเมื่อการตอบใหม่ในกระทู้นี้", "quote": "คำอ้างอิง", "reply": "ตอบ", - "guest-login-reply": "Log in to reply", + "guest-login-reply": "เข้าสู่ระบบเพื่อตอบกลับ", "edit": "แก้ไข", "delete": "ลบ", "purge": "Purge", @@ -26,31 +26,31 @@ "locked": "Locked", "bookmark_instructions": "คลิกที่นี่เพื่อกลับคืนสู่ฐานะสุดท้าย หรือ คลิกปิดเพื่อยกเลิก", "flag_title": "ปักธงโพสต์นี้เพื่อดำเนินการ", - "flag_confirm": "Are you sure you want to flag this post?", + "flag_confirm": "มั่นใจแล้วหรือไม่ที่จะ Flag Post นี้?", "flag_success": "This post has been flagged for moderation.", - "deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.", + "deleted_message": "Topic นี้ถูกลบไปแล้ว เฉพาะผู้ใช้งานที่มีสิทธิ์ในการจัดการ Topic เท่านั้นที่จะมีสิทธิ์ในการเข้าชม", "following_topic.message": "คุณจะได้รับการแจ้งเตือนเมื่อมีคนโพสต์ในกระทู้นี้", "not_following_topic.message": "คุณจะไม่รับการแจ้งเตือนจากกระทู้นี้", "login_to_subscribe": "กรุณาลงทะเบียนหรือเข้าสู่ระบบเพื่อที่จะติดตามกระทู้นี้", "markAsUnreadForAll.success": "ทำเครื่องหมายว่ายังไม่ได้อ่านทั้งหมด", "watch": "ติดตาม", - "unwatch": "Unwatch", - "watch.title": "Be notified of new replies in this topic", - "unwatch.title": "Stop watching this topic", + "unwatch": "ยังไม่ได้ติดตาม", + "watch.title": "ให้แจ้งเตือนเมื่อมีการตอบกลับ Topic นี้", + "unwatch.title": "ยกเลิกการติดตาม Topic นี้", "share_this_post": "แชร์โพสต์นี้", - "thread_tools.title": "Topic Tools", + "thread_tools.title": "เครื่องมือช่วยจัดการ Topic", "thread_tools.markAsUnreadForAll": "ทำหมายว่ายังไม่ได้อ่าน", "thread_tools.pin": "ปักหมุดกระทู้", "thread_tools.unpin": "เลิกปักหมุดกระทู้", "thread_tools.lock": "ล็อคกระทู้", "thread_tools.unlock": "ปลดล็อคกระทู้", "thread_tools.move": "ย้ายกระทู้", - "thread_tools.move_all": "Move All", + "thread_tools.move_all": "ย้ายทั้งหมด", "thread_tools.fork": "แยกกระทู้", "thread_tools.delete": "ลบกระทู้", - "thread_tools.delete_confirm": "Are you sure you want to delete this topic?", + "thread_tools.delete_confirm": "มั่นใจแล้วหรือไม่ที่จะลบ Topic นี้?", "thread_tools.restore": "กู้กระทู้", - "thread_tools.restore_confirm": "Are you sure you want to restore this topic?", + "thread_tools.restore_confirm": "มั่นใจแล้วหรือไม่ที่จะกู้คืน Topic นี้?", "thread_tools.purge": "Purge Topic", "thread_tools.purge_confirm": "Are you sure you want to purge this topic?", "topic_move_success": "This topic has been successfully moved to %1", diff --git a/public/language/th/unread.json b/public/language/th/unread.json index 37451a65ba..2595955dc7 100644 --- a/public/language/th/unread.json +++ b/public/language/th/unread.json @@ -2,8 +2,8 @@ "title": "ไม่ได้อ่าน", "no_unread_topics": "ไม่มีกระทู้ที่ยังไม่ได้อ่านเป็น", "load_more": "โหลดเพิ่มเติม", - "mark_as_read": "Mark as Read", - "selected": "Selected", - "all": "All", - "topics_marked_as_read.success": "Topics marked as read!" + "mark_as_read": "ทำเครื่องหมายว่าอ่านแล้ว", + "selected": "เลือก", + "all": "ทั้งหมด", + "topics_marked_as_read.success": "Topic ถูกทำเครื่องหมายว่าอ่านแล้วเรียบร้อย" } \ No newline at end of file diff --git a/public/language/th/user.json b/public/language/th/user.json index aaf5a74424..5fc906103c 100644 --- a/public/language/th/user.json +++ b/public/language/th/user.json @@ -2,8 +2,8 @@ "banned": "เเบน", "offline": "ออฟไลน์", "username": "ชื่อผู้ใช้", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "วันที่เข้าร่วม", + "postcount": "จำนวนโพส", "email": "อีเมล์", "confirm_email": "ยืนยันอีเมล", "delete_account": "ลบบัญชี", @@ -18,7 +18,7 @@ "profile_views": "ดูข้อมูลส่วนตัว", "reputation": "ชื่อเสียง", "favourites": "ชอบ", - "watched": "Watched", + "watched": "ดูแล้ว", "followers": "คนติดตาม", "following": "ติดตาม", "signature": "ลายเซ็น", @@ -59,12 +59,13 @@ "digest_weekly": "รายสัปดาห์", "digest_monthly": "รายเดือน", "send_chat_notifications": "ส่งอีเมลเมื่อมีข้อความใหม่เข้ามาขณะที่ฉันไม่ได้ออนไลน์", - "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "send_post_notifications": "ส่งอีเมลให้ฉันเมื่อมีการตอบกลับในหัวข้อที่ฉันเคยบอกรับเป็นสมาชิกไว้", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "ผู้ใช้รายนี้ไม่มีใครติดตาม :(", "follows_no_one": "ผู้ใช้รายนี้ไม่ติดตามใคร :(", "has_no_posts": "ผู้ใช้รายนี้ไม่ได้โพสต์อะไรเลย", "has_no_topics": "สมาชิกรายนี้ยังไม่ได้มีการโพสต์ข้อความ", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "ผู้ใช้นี้ยังไม่เคยเข้าชมในหัวข้อใดๆ", "email_hidden": "ซ่อนอีเมล์", "hidden": "ซ่อน", "paginate_description": "ให้เลขหน้ากระทู้และโพสต์แทนการใช้สกรอลล์ที่ไม่สิ้นสุด", @@ -73,8 +74,9 @@ "notification_sounds": "เตือนด้วยเสียงเมื่อมีข้อความแจ้งเตือน", "browsing": "เปิดดูการตั้งค่า", "open_links_in_new_tab": "เปิดลิงค์ในแท็บใหม่", - "enable_topic_searching": "Enable In-Topic Searching", - "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", + "enable_topic_searching": "เปิดใช้การค้นหาแบบ In-Topic", + "topic_search_help": "เมื่อการค้นหาแบบ In-Topic ถูกเปิดใช้งาน การค้นหาแบบ In-Topic จะทำงานแทนการค้นหาในรูปแบบเดิม ซึ่งช่วยให้คุณสามารถทำการค้นหาจาก Topic ทั้งหมด เพิ่มเติมจากที่คุณกำลังเห็นอยู่บนหน้าจอ", "follow_topics_you_reply_to": "ติดตามกระทู้ที่คุณตอบ", - "follow_topics_you_create": "ติดตามกระทู้ที่คุณตั้ง" + "follow_topics_you_create": "ติดตามกระทู้ที่คุณตั้ง", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/tr/error.json b/public/language/tr/error.json index d54bbce50a..475b93ac94 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -18,7 +18,7 @@ "username-taken": "Kullanıcı İsmi Alınmış", "email-taken": "E-posta Alınmış", "email-not-confirmed": "E-postanız onaylanmamış, onaylamak için lütfen buraya tıklayın.", - "email-not-confirmed-chat": "Email adresiniz doğrulanmadan sohbet edemezsiniz.", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "Bu forum e-posta doğrulaması gerektirir, lütfen buraya bir e-posta adresi girin", "email-confirm-failed": "E-posta adresinizi doğrulayamıyoruz. Lütfen daha sonra tekrar deneyin.", "username-too-short": "Kullanıcı ismi çok kısa", diff --git a/public/language/tr/modules.json b/public/language/tr/modules.json index 361e6deb48..af25aa3d20 100644 --- a/public/language/tr/modules.json +++ b/public/language/tr/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 Ay", "composer.user_said_in": "%1 %2 içinde söyledi:", "composer.user_said": "%1 söyledi:", - "composer.discard": "Bu iletiyi iptal etmek istediğinizden eminmisiniz?" + "composer.discard": "Bu iletiyi iptal etmek istediğinizden eminmisiniz?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/tr/pages.json b/public/language/tr/pages.json index 5171f4232f..84f3ef0148 100644 --- a/public/language/tr/pages.json +++ b/public/language/tr/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1 Kişisine Ait Gruplar", "user.favourites": "%1'in Favori İletileri", "user.settings": "Kullanıcı Ayarları", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 şu anda bakımda. Lütfen bir süre sonra tekrar deneyin.", "maintenance.messageIntro": "Ayrıca, yönetici şu mesaji bıraktı:" } \ No newline at end of file diff --git a/public/language/tr/tags.json b/public/language/tr/tags.json index 344a4bfff6..9f614ce38c 100644 --- a/public/language/tr/tags.json +++ b/public/language/tr/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Bu etiketli başlık yok.", "tags": "Etiketler", - "enter_tags_here": "Etiketleri buraya girin. %1-%2 karakter. Her etiketten sonra enter tuşuna basın.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Etiketleri gir...", "no_tags": "Henüz etiket yok." } \ No newline at end of file diff --git a/public/language/tr/user.json b/public/language/tr/user.json index 8fa7b4c5c9..cfca7130fb 100644 --- a/public/language/tr/user.json +++ b/public/language/tr/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Aylık", "send_chat_notifications": "Çevrimiçi değilken gelen iletileri e-posta olarak gönder", "send_post_notifications": "Abone olduğum konulara cevap gelince bana eposta yolla", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Bu kullanıcının hiç takipçisi yok :(", "follows_no_one": "Bu kullanıcı kimseyi takip etmiyor :(", "has_no_posts": "Bu kullanıcı henüz birşey göndermedi.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Konu içi aramayı aktive et", "topic_search_help": "Aktive edilirse, konu içi arama tarayıcının normal arama davranışını değiştirerek tüm konuyu aramanızı sağlar.", "follow_topics_you_reply_to": "İleti gönderdiğim konuları takip et.", - "follow_topics_you_create": "Kendi yarattığım konuları takip et." + "follow_topics_you_create": "Kendi yarattığım konuları takip et.", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/vi/error.json b/public/language/vi/error.json index 56d5a49788..5a9d22c3ee 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -18,7 +18,7 @@ "username-taken": "Tên đăng nhập đã tồn tại", "email-taken": "Email đã được đăng kí", "email-not-confirmed": "Email của bạn chưa được xác nhận, xin hãy nhấn vào đây để xác nhận địa chỉ này là của bạn", - "email-not-confirmed-chat": "Bạn không thể trò chuyện cho đến khi thư điện tử của bạn được xác nhận", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "Tên đăng nhập quá ngắn", diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json index 81ca0692b5..ecf53d1f0f 100644 --- a/public/language/vi/modules.json +++ b/public/language/vi/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3 tháng", "composer.user_said_in": "%1 đã nói trong %2:", "composer.user_said": "%1 đã nói:", - "composer.discard": "Bạn có chắc chắn hủy bỏ bài viết này?" + "composer.discard": "Bạn có chắc chắn hủy bỏ bài viết này?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/vi/pages.json b/public/language/vi/pages.json index 153a1f31d8..717907a267 100644 --- a/public/language/vi/pages.json +++ b/public/language/vi/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1's Groups", "user.favourites": "Các bài gửi yêu thích của %1", "user.settings": "Thiết lập cho người dùng", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 đang được bảo trì. Xin vui lòng quay lại sau.", "maintenance.messageIntro": "Ban quản lí để lại lời nhắn sau:" } \ No newline at end of file diff --git a/public/language/vi/tags.json b/public/language/vi/tags.json index 68f5639c02..7b8931883f 100644 --- a/public/language/vi/tags.json +++ b/public/language/vi/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "Không có bài viết nào với thẻ này.", "tags": "Thẻ", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "Tên thẻ...", "no_tags": "Chưa có thẻ nào." } \ No newline at end of file diff --git a/public/language/vi/user.json b/public/language/vi/user.json index a9ee90df9f..64fa5b6cdd 100644 --- a/public/language/vi/user.json +++ b/public/language/vi/user.json @@ -60,6 +60,7 @@ "digest_monthly": "Hàng tháng", "send_chat_notifications": "Gửi một email nếu có tin nhắn chat mới đến và tôi không online", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "Người dùng này hiện chưa có ai theo dõi :(", "follows_no_one": "Người dùng này hiện chưa theo dõi ai :(", "has_no_posts": "Người dùng này chưa viết bài nào", @@ -76,5 +77,6 @@ "enable_topic_searching": "Bật In-topic Searching", "topic_search_help": "Nếu được bật, in-topic searching sẽ thay thế tính năng tìm kiếu mặc định của trình duyệt và giúp bạn tìm trong toàn bộ nội dung bài viết, thay vì chỉ tìm trong những gì đang có trên màn hình.", "follow_topics_you_reply_to": "Theo dõi chủ đề mà bạn trả lời", - "follow_topics_you_create": "Theo dõi chủ đề bạn tạo" + "follow_topics_you_create": "Theo dõi chủ đề bạn tạo", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/zh_CN/email.json b/public/language/zh_CN/email.json index 9f0316ce3b..f25a53cd83 100644 --- a/public/language/zh_CN/email.json +++ b/public/language/zh_CN/email.json @@ -1,24 +1,24 @@ { - "password-reset-requested": "密码重置申请 - %1!", + "password-reset-requested": "密码重置申请 - %1!", "welcome-to": "欢迎来到 %1", "greeting_no_name": "您好", "greeting_with_name": "%1,您好", - "welcome.text1": "谢谢您注册 %1 帐户!", + "welcome.text1": "感谢您注册 %1 帐户!", "welcome.text2": "需要在校验您注册时填写的电子邮箱地址后,才能全面激活您的帐户。", "welcome.cta": "点击这里确认您的电子邮箱地址", - "reset.text1": "我们收到了重置您帐户密码的申请,可能是因为您遗忘了密码。如果不是,请忽略这封邮件。", + "reset.text1": "可能由于您忘记了密码,我们收到了重置您帐户密码的申请。 如果您没有提交密码重置的请求,请忽略这封邮件。", "reset.text2": "如需继续重置密码,请点击下面的链接:", "reset.cta": "点击这里重置您的密码", "reset.notify.subject": "更改密码成功", - "reset.notify.text1": "我们注意到你在 %1 上,成功修改了你的密码。", + "reset.notify.text1": "您在 %1 上的密码被成功修改。", "reset.notify.text2": "如果你没有授权此操作,请立即联系管理员。", "digest.notifications": "您有来自 %1 的未读通知:", "digest.latest_topics": "来自 %1 的最新主题", "digest.cta": "点击这里访问 %1", "digest.unsub.info": "根据您的订阅设置,为您发送此摘要。", - "digest.no_topics": "最近 %1,有一些未激活的主题", + "digest.no_topics": "最近 %1 没有活跃的主题", "notif.chat.subject": "收到来自 %1 的新聊天消息", - "notif.chat.cta": "点击这里恢复会话", + "notif.chat.cta": "点击这里继续会话", "notif.chat.unsub.info": "根据您的订阅设置,为您发送此聊天提醒。", "notif.post.cta": "点击这里阅读全主题。", "notif.post.unsub.info": "根据您的订阅设置,为您发送此回帖提醒。", diff --git a/public/language/zh_CN/error.json b/public/language/zh_CN/error.json index b156a96793..0488353541 100644 --- a/public/language/zh_CN/error.json +++ b/public/language/zh_CN/error.json @@ -18,7 +18,7 @@ "username-taken": "用户名已被占用", "email-taken": "电子邮箱已被占用", "email-not-confirmed": "您的电子邮箱尚未确认,请点击这里确认您的电子邮箱。", - "email-not-confirmed-chat": "在确认您的邮箱之前,您不能使用聊天功能", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "本论坛需要电子邮箱确认,请点击这里输入一个电子邮箱地址", "email-confirm-failed": "我们无法确认您的电子邮箱,请重试", "username-too-short": "用户名太短", diff --git a/public/language/zh_CN/groups.json b/public/language/zh_CN/groups.json index 39eb395078..b7a60f7813 100644 --- a/public/language/zh_CN/groups.json +++ b/public/language/zh_CN/groups.json @@ -4,8 +4,8 @@ "owner": "用户组组长", "new_group": "创建新用户组", "no_groups_found": "还没有用户组", - "pending.accept": "Accept", - "pending.reject": "Reject", + "pending.accept": "接受", + "pending.reject": "拒绝", "cover-instructions": "拖放照片,拖动位置,然后点击 <strong>保存</strong>", "cover-change": "变更", "cover-save": "保存", @@ -15,20 +15,20 @@ "details.pending": "预备成员", "details.has_no_posts": "此用户组的会员尚未发表任何帖子。", "details.latest_posts": "最新帖子", - "details.private": "Private", + "details.private": "私有", "details.grant": "授予/取消所有权", "details.kick": "踢", "details.owner_options": "用户组管理", - "details.group_name": "Group Name", - "details.description": "Description", - "details.badge_preview": "Badge Preview", - "details.change_icon": "Change Icon", - "details.change_colour": "Change Colour", - "details.badge_text": "Badge Text", - "details.userTitleEnabled": "Show Badge", - "details.private_help": "If enabled, joining of groups requires approval from a group owner", - "details.hidden": "Hidden", - "details.hidden_help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually", + "details.group_name": "用户组名", + "details.description": "描述", + "details.badge_preview": "标志预览", + "details.change_icon": "更改图标", + "details.change_colour": "更新颜色", + "details.badge_text": "标志文字", + "details.userTitleEnabled": "显示标志", + "details.private_help": "如果条件允许,必须得到群主批准才能加入该群。", + "details.hidden": "隐藏", + "details.hidden_help": "如果条件允许,这个群不再出现在此列表,所有用户要人工邀请加入。", "event.updated": "用户组信息已更新", "event.deleted": "用户组 \"%1\" 已被删除" } \ No newline at end of file diff --git a/public/language/zh_CN/login.json b/public/language/zh_CN/login.json index 3e8d54af50..9cf15f0e15 100644 --- a/public/language/zh_CN/login.json +++ b/public/language/zh_CN/login.json @@ -1,7 +1,7 @@ { - "username-email": "Username / Email", - "username": "Username", - "email": "Email", + "username-email": "用户名/电子邮箱", + "username": "用户名", + "email": "邮件", "remember_me": "记住我?", "forgot_password": "忘记密码?", "alternative_logins": "使用合作网站帐号登录", diff --git a/public/language/zh_CN/modules.json b/public/language/zh_CN/modules.json index 0049c202be..e309d83bbc 100644 --- a/public/language/zh_CN/modules.json +++ b/public/language/zh_CN/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3个月", "composer.user_said_in": "%1 在 %2 中说:", "composer.user_said": "%1 说:", - "composer.discard": "确定想要取消此帖?" + "composer.discard": "确定想要取消此帖?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/zh_CN/notifications.json b/public/language/zh_CN/notifications.json index f8a88ca3fe..f20ee0f1e4 100644 --- a/public/language/zh_CN/notifications.json +++ b/public/language/zh_CN/notifications.json @@ -2,7 +2,7 @@ "title": "通知", "no_notifs": "您没有新的通知", "see_all": "查看全部通知", - "mark_all_read": "Mark all notifications read", + "mark_all_read": "标记全部为已读", "back_to_home": "返回 %1", "outgoing_link": "站外链接", "outgoing_link_message": "您正在离开 %1。", diff --git a/public/language/zh_CN/pages.json b/public/language/zh_CN/pages.json index 6fde75dfe5..298f183f74 100644 --- a/public/language/zh_CN/pages.json +++ b/public/language/zh_CN/pages.json @@ -14,6 +14,7 @@ "user.groups": "%1 的用户组", "user.favourites": "%1 收藏的帖子", "user.settings": "用户设置", + "user.watched": "Topics watched by %1", "maintenance.text": "%1 正在进行维护。请稍后再来。", "maintenance.messageIntro": "此外,管理员留下的消息:" } \ No newline at end of file diff --git a/public/language/zh_CN/recent.json b/public/language/zh_CN/recent.json index c37b2c0557..1e76727b6a 100644 --- a/public/language/zh_CN/recent.json +++ b/public/language/zh_CN/recent.json @@ -6,14 +6,14 @@ "year": "年度热帖榜", "alltime": "总热帖榜", "no_recent_topics": "暂无主题。", - "no_popular_topics": "There are no popular topics.", - "there-is-a-new-topic": "这是个新主题。", - "there-is-a-new-topic-and-a-new-post": "There is a new topic and a new post.", - "there-is-a-new-topic-and-new-posts": "There is a new topic and %1 new posts.", - "there-are-new-topics": "There are %1 new topics.", - "there-are-new-topics-and-a-new-post": "There are %1 new topics and a new post.", - "there-are-new-topics-and-new-posts": "There are %1 new topics and %2 new posts.", - "there-is-a-new-post": "There is a new post.", - "there-are-new-posts": "There are %1 new posts.", + "no_popular_topics": "没有热门主题", + "there-is-a-new-topic": "有一个新主题", + "there-is-a-new-topic-and-a-new-post": "有一个新主题和一个新发表", + "there-is-a-new-topic-and-new-posts": "有一个新主题和 %1 新发表", + "there-are-new-topics": "有 %1 个新主题", + "there-are-new-topics-and-a-new-post": "有 %1个新主题和一个新发表", + "there-are-new-topics-and-new-posts": "有 %1个新主题和 %2个新发表", + "there-is-a-new-post": "有一个新发表", + "there-are-new-posts": "有 %1个新发表", "click-here-to-reload": "点击这里重新加载" } \ No newline at end of file diff --git a/public/language/zh_CN/search.json b/public/language/zh_CN/search.json index 68799a19f9..9df978a688 100644 --- a/public/language/zh_CN/search.json +++ b/public/language/zh_CN/search.json @@ -30,11 +30,11 @@ "topic-start-date": "主题开始日期", "username": "用户名", "category": "版面", - "descending": "逆序", + "descending": "倒序", "ascending": "顺序", - "save-preferences": "Save preferences", - "clear-preferences": "Clear preferences", - "search-preferences-saved": "Search preferences saved", - "search-preferences-cleared": "Search preferences cleared", - "show-results-as": "Show results as" + "save-preferences": "保存设置", + "clear-preferences": "清除设置", + "search-preferences-saved": "搜索设置已保存", + "search-preferences-cleared": "搜索设置已清除", + "show-results-as": "结果显示为" } \ No newline at end of file diff --git a/public/language/zh_CN/tags.json b/public/language/zh_CN/tags.json index a50705d3d6..9802f9c79a 100644 --- a/public/language/zh_CN/tags.json +++ b/public/language/zh_CN/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "此话题还没有主题帖。", "tags": "话题", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "输入话题...", "no_tags": "尚无话题。" } \ No newline at end of file diff --git a/public/language/zh_CN/topic.json b/public/language/zh_CN/topic.json index bd20fbdabc..9b113c0c90 100644 --- a/public/language/zh_CN/topic.json +++ b/public/language/zh_CN/topic.json @@ -12,7 +12,7 @@ "notify_me": "此主题有新回复时通知我", "quote": "引用", "reply": "回复", - "guest-login-reply": "Log in to reply", + "guest-login-reply": "登录后回复", "edit": "编辑", "delete": "删除", "purge": "清除", diff --git a/public/language/zh_CN/user.json b/public/language/zh_CN/user.json index 6c360a4d4e..6d29052981 100644 --- a/public/language/zh_CN/user.json +++ b/public/language/zh_CN/user.json @@ -60,6 +60,7 @@ "digest_monthly": "每月", "send_chat_notifications": "当我不在线,并受到新的聊天消息时给我发邮件", "send_post_notifications": "我订阅的主题有回复时发送邮件", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "此用户还没有粉丝 :(", "follows_no_one": "此用户尚未关注任何人 :(", "has_no_posts": "此用户尚未发布任何帖子。", @@ -76,5 +77,6 @@ "enable_topic_searching": "启用主题内搜索", "topic_search_help": "启用后,主题内搜索会替代浏览器默认的页面搜索,你可以在整个主题的全部内容进行搜索,而不是仅限于屏幕显示的内容。", "follow_topics_you_reply_to": "关注您回复的主题。", - "follow_topics_you_create": "关注您创建的主题。" + "follow_topics_you_create": "关注您创建的主题。", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/language/zh_TW/email.json b/public/language/zh_TW/email.json index 1062070b96..13f19de484 100644 --- a/public/language/zh_TW/email.json +++ b/public/language/zh_TW/email.json @@ -9,9 +9,9 @@ "reset.text1": "我們收到一個重設密碼的請求,你忘掉了密碼嗎?如果不是,請忽略這封郵件。", "reset.text2": "要繼續重置密碼,請點擊以下鏈接:", "reset.cta": "點擊這裡重置密碼", - "reset.notify.subject": "Password successfully changed", - "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", - "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "reset.notify.subject": "密碼修改成功", + "reset.notify.text1": "提醒您密碼已於 %1 修改成功", + "reset.notify.text2": "如果您未允許此動作, 請即刻通知系統管理者", "digest.notifications": "你有來自$1的未讀通知:", "digest.latest_topics": "來自%1的最新話題", "digest.cta": "點擊這裡訪問%1", @@ -20,8 +20,8 @@ "notif.chat.subject": "收到來自$1的聊天消息", "notif.chat.cta": "點擊此處繼續對話", "notif.chat.unsub.info": "本聊天通知按您的訂閱設置發送給您。", - "notif.post.cta": "Click here to read the full topic", - "notif.post.unsub.info": "This post notification was sent to you due to your subscription settings.", + "notif.post.cta": "按此以閱讀完整標題", + "notif.post.unsub.info": "本發文通知按您的訂閱設置發送給您。", "test.text1": "這是一個測試電郵,以確認您的NodeBB郵件器設置正確。", "unsub.cta": "點擊這裡更改這些設置", "closing": "謝謝!" diff --git a/public/language/zh_TW/error.json b/public/language/zh_TW/error.json index 9efb1e5ec1..3aae7dd5bc 100644 --- a/public/language/zh_TW/error.json +++ b/public/language/zh_TW/error.json @@ -18,7 +18,7 @@ "username-taken": "該使用者名稱已被使用", "email-taken": "該信箱已被使用", "email-not-confirmed": "您的電郵尚未得到確認,請點擊此處確認您的電子郵件。", - "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "email-not-confirmed-chat": "You are unable to chat until your email is confirmed, please click here to confirm your email.", "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "email-confirm-failed": "We could not confirm your email, please try again later.", "username-too-short": "用戶名太短", diff --git a/public/language/zh_TW/global.json b/public/language/zh_TW/global.json index 3dc23be905..f0a81aed7a 100644 --- a/public/language/zh_TW/global.json +++ b/public/language/zh_TW/global.json @@ -3,10 +3,10 @@ "search": "搜索", "buttons.close": "關閉", "403.title": "禁止存取", - "403.message": "You seem to have stumbled upon a page that you do not have access to.", - "403.login": "Perhaps you should <a href='%1/login'>try logging in</a>?", + "403.message": "你沒有該頁面的存取權限", + "403.login": "可能是因為你尚未<a href='%1/login'>登入</a>?", "404.title": "無法找到該頁", - "404.message": "You seem to have stumbled upon a page that does not exist. Return to the <a href='%1/'>home page</a>.", + "404.message": "你所查找的頁面並不存在,返回<a href='%1/'>主頁</a>。", "500.title": "內部錯誤", "500.message": "不好!看來是哪裡出錯了!", "register": "注冊", @@ -27,7 +27,7 @@ "header.tags": "標籤", "header.popular": "熱門", "header.users": "用戶", - "header.groups": "Groups", + "header.groups": "群組", "header.chats": "聊天", "header.notifications": "通知", "header.search": "搜索", @@ -75,7 +75,7 @@ "updated.title": "討論區更新完畢", "updated.message": "這個討論區最近被更新至最新的版本. 按此來重整這個頁面", "privacy": "隱私", - "follow": "Follow", - "unfollow": "Unfollow", + "follow": "追蹤", + "unfollow": "取消追蹤", "delete_all": "全部刪除" } \ No newline at end of file diff --git a/public/language/zh_TW/modules.json b/public/language/zh_TW/modules.json index ff6d2488f4..3e7d758914 100644 --- a/public/language/zh_TW/modules.json +++ b/public/language/zh_TW/modules.json @@ -17,5 +17,6 @@ "chat.three_months": "3個月", "composer.user_said_in": "%1在%2裡說:", "composer.user_said": "%1說:", - "composer.discard": "你確定要放棄這帖子嗎?" + "composer.discard": "你確定要放棄這帖子嗎?", + "composer.submit_and_lock": "Submit and Lock" } \ No newline at end of file diff --git a/public/language/zh_TW/notifications.json b/public/language/zh_TW/notifications.json index 6736c06584..660e984111 100644 --- a/public/language/zh_TW/notifications.json +++ b/public/language/zh_TW/notifications.json @@ -2,21 +2,21 @@ "title": "通知", "no_notifs": "沒有新消息", "see_all": "顯示全部", - "mark_all_read": "Mark all notifications read", + "mark_all_read": "所有訊息設為已讀", "back_to_home": "返回%1", - "outgoing_link": "站外鏈接", + "outgoing_link": "站外連結", "outgoing_link_message": "你正在離開 %1.", "continue_to": "繼續前往 %1", "return_to": "返回%1", "new_notification": "新訊息通知", "you_have_unread_notifications": "您有未讀的訊息!", "new_message_from": "來自 <strong>%1</strong> 的新訊息", - "upvoted_your_post_in": "<strong>%1</strong> upvote了您在 <strong>%2</strong>的帖子。", - "moved_your_post": "<strong>%1</strong> 移動了你的帖子。", + "upvoted_your_post_in": "<strong>%1</strong> upvote了您在 <strong>%2</strong>的post。", + "moved_your_post": "<strong>%1</strong> 移動了你的post。", "moved_your_topic": "<strong>%1</strong> 移動了你的主題。", - "favourited_your_post_in": "<strong>%1</strong> 收藏了你在 <strong>%2</strong>的帖子。", - "user_flagged_post_in": "<strong>%1</strong> 舉報了 <strong>%2</strong>裡的一個帖子。", - "user_posted_to": "<strong>%1</strong> has posted a reply to: <strong>%2</strong>", + "favourited_your_post_in": "<strong>%1</strong> 收藏了你在 <strong>%2</strong>的post。", + "user_flagged_post_in": "<strong>%1</strong> 舉報了 <strong>%2</strong>裡的一個post。", + "user_posted_to": "<strong>%1</strong> 發布一個回覆給: <strong>%2</strong>", "user_posted_topic": "<strong>%1</strong> 發布了一個新的主題: <strong>%2</strong>", "user_mentioned_you_in": "<strong>%1</strong> 在 <strong>%2</strong>提到你", "user_started_following_you": "<strong>%1</strong> 開始關注你。", diff --git a/public/language/zh_TW/pages.json b/public/language/zh_TW/pages.json index bcb655c3e2..20af148f85 100644 --- a/public/language/zh_TW/pages.json +++ b/public/language/zh_TW/pages.json @@ -11,9 +11,10 @@ "user.followers": "People who Follow %1", "user.posts": "文章由 %1 所張貼", "user.topics": "主題由 %1 所創建", - "user.groups": "%1's Groups", + "user.groups": "%1 的群組", "user.favourites": "%1's 最喜愛的文章", "user.settings": "使用者設定", + "user.watched": "Topics watched by %1", "maintenance.text": "%1目前正在進行維修。請稍後再來。", "maintenance.messageIntro": "此外,管理員有以下信息:" } \ No newline at end of file diff --git a/public/language/zh_TW/search.json b/public/language/zh_TW/search.json index 66fee75c1a..eef48e983e 100644 --- a/public/language/zh_TW/search.json +++ b/public/language/zh_TW/search.json @@ -1,40 +1,40 @@ { - "results_matching": "有%1個跟\"%2\"匹配的結果(%3秒)", - "no-matches": "沒有找到匹配的主題", - "in": "In", - "by": "By", - "titles": "Titles", - "titles-posts": "Titles and Posts", + "results_matching": "有%1個跟\"%2\"相符的結果(%3秒)", + "no-matches": "沒有找到相符的主題", + "in": "在", + "by": "由", + "titles": "標題", + "titles-posts": "標題與發布", "posted-by": "Posted by", - "in-categories": "In Categories", - "search-child-categories": "Search child categories", - "reply-count": "Reply Count", - "at-least": "At least", - "at-most": "At most", - "post-time": "Post time", - "newer-than": "Newer than", - "older-than": "Older than", - "any-date": "Any date", - "yesterday": "Yesterday", - "one-week": "One week", - "two-weeks": "Two weeks", - "one-month": "One month", - "three-months": "Three months", - "six-months": "Six months", - "one-year": "One year", - "sort-by": "Sort by", - "last-reply-time": "Last reply time", - "topic-title": "Topic title", - "number-of-replies": "Number of replies", - "number-of-views": "Number of views", - "topic-start-date": "Topic start date", - "username": "Username", - "category": "Category", - "descending": "In descending order", - "ascending": "In ascending order", - "save-preferences": "Save preferences", - "clear-preferences": "Clear preferences", - "search-preferences-saved": "Search preferences saved", - "search-preferences-cleared": "Search preferences cleared", - "show-results-as": "Show results as" + "in-categories": "在類別中", + "search-child-categories": "搜尋子類別", + "reply-count": "回覆數量", + "at-least": "最少", + "at-most": "最多", + "post-time": "發布時間", + "newer-than": "較新", + "older-than": "較舊", + "any-date": "任意日期", + "yesterday": "昨天", + "one-week": "一周", + "two-weeks": "兩周", + "one-month": "一個月", + "three-months": "三個月", + "six-months": "六個月", + "one-year": "一年", + "sort-by": "排序依據", + "last-reply-time": "最後回覆時間", + "topic-title": "主題", + "number-of-replies": "回覆數量", + "number-of-views": "閱讀數量", + "topic-start-date": "主題開始時間", + "username": "使用者名稱", + "category": "類別", + "descending": "降冪排序", + "ascending": "升冪排序", + "save-preferences": "存到我的最愛", + "clear-preferences": "清除我的最愛", + "search-preferences-saved": "搜尋我的最愛已儲存", + "search-preferences-cleared": "搜尋我的最愛已清除", + "show-results-as": "結果顯示" } \ No newline at end of file diff --git a/public/language/zh_TW/tags.json b/public/language/zh_TW/tags.json index dc5c1601ba..ce9de5c88b 100644 --- a/public/language/zh_TW/tags.json +++ b/public/language/zh_TW/tags.json @@ -1,7 +1,7 @@ { "no_tag_topics": "沒有此標籤的主題。", "tags": "標籤", - "enter_tags_here": "Enter tags here. %1-%2 characters. Press enter after each tag.", + "enter_tags_here": "Enter tags here, between %1 and %2 characters each.", "enter_tags_here_short": "輸入標籤...", "no_tags": "還沒有標籤呢。" } \ No newline at end of file diff --git a/public/language/zh_TW/topic.json b/public/language/zh_TW/topic.json index 41edd8828f..a65ccc6833 100644 --- a/public/language/zh_TW/topic.json +++ b/public/language/zh_TW/topic.json @@ -12,7 +12,7 @@ "notify_me": "該主題有新回覆時通知我", "quote": "引用", "reply": "回覆", - "guest-login-reply": "Log in to reply", + "guest-login-reply": "登入以回覆", "edit": "編輯", "delete": "刪除", "purge": "清除", @@ -75,7 +75,7 @@ "fork_no_pids": "尚未選擇文章!", "fork_success": "成功分叉成新的主題!點擊這裡進入新的主題。", "composer.title_placeholder": "輸入標題...", - "composer.handle_placeholder": "Name", + "composer.handle_placeholder": "名字", "composer.discard": "放棄", "composer.submit": "發表", "composer.replying_to": "回覆給 %1", @@ -95,5 +95,5 @@ "oldest_to_newest": "從舊到新", "newest_to_oldest": "從新到舊", "most_votes": "得票最多", - "most_posts": "Most posts" + "most_posts": "最多post" } \ No newline at end of file diff --git a/public/language/zh_TW/user.json b/public/language/zh_TW/user.json index 1752a45979..008808ae6f 100644 --- a/public/language/zh_TW/user.json +++ b/public/language/zh_TW/user.json @@ -2,8 +2,8 @@ "banned": "封鎖", "offline": "下線", "username": "使用者名稱", - "joindate": "Join Date", - "postcount": "Post Count", + "joindate": "加入時間", + "postcount": "Post數量", "email": "Email", "confirm_email": "確認電郵", "delete_account": "刪除帳戶", @@ -60,11 +60,12 @@ "digest_monthly": "每月", "send_chat_notifications": "如果有新的聊天消息而我不在線,發送郵件給我", "send_post_notifications": "Send an email when replies are made to topics I am subscribed to", + "settings-require-reload": "Some setting changes require a reload. Click here to reload the page.", "has_no_follower": "該用戶還沒有被任何人關注。", "follows_no_one": "該用戶還沒有關注過任何人。", "has_no_posts": "尚未有任何貼文.", "has_no_topics": "這位使用者尚未發表任何主題。", - "has_no_watched_topics": "This user didn't watch any topics yet.", + "has_no_watched_topics": "這位使用者尚未發表任何主題", "email_hidden": "郵箱被隱藏", "hidden": "隱藏", "paginate_description": "使用分頁取代瀏覽載入文章模式.", @@ -76,5 +77,6 @@ "enable_topic_searching": "Enable In-Topic Searching", "topic_search_help": "If enabled, in-topic searching will override the browser's default page search behaviour and allow you to search through the entire topic, instead of what is only shown on screen.", "follow_topics_you_reply_to": "關注您回复的主題。", - "follow_topics_you_create": "關注您創建的主題。" + "follow_topics_you_create": "關注您創建的主題。", + "grouptitle": "Select the group title you would like to display" } \ No newline at end of file diff --git a/public/less/admin/admin.less b/public/less/admin/admin.less index 528c9f7381..6d4dce3e43 100644 --- a/public/less/admin/admin.less +++ b/public/less/admin/admin.less @@ -3,7 +3,6 @@ @import "./general/dashboard"; @import "./general/navigation"; -@import "./manage/categories"; @import "./manage/groups"; @import "./manage/tags"; @import "./manage/flags"; @@ -296,3 +295,48 @@ max-width: calc( ~"(100% - 200px)/4" ); } } + +.category-settings-form { + h3 { + margin-top: 0; + .pointer; + } + + h4 { + .pointer; + } +} + +.category-preview { + .pointer; + width: 100%; + height: 100px; + text-align: center; + color: white; + margin-top: 0; + + .icon { + width: 30px; + height: 30px; + line-height: 40px; + display: inline-block; + margin: 35px 5px 0 5px; + } +} + +.table-reordering { + tr:hover { + cursor: move; + } +} + +.privilege-table { + th { + font-size: 10px; + } + + img { + max-width: 24px; + max-height: 24px; + } +} diff --git a/public/less/admin/general/dashboard.less b/public/less/admin/general/dashboard.less index 1001893ed7..71c2298d31 100644 --- a/public/less/admin/general/dashboard.less +++ b/public/less/admin/general/dashboard.less @@ -38,7 +38,7 @@ li { float: left; - width: 48%; + width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -90,7 +90,7 @@ border-color: #46BFBD; background-color: #5AD3D1; } - &.on-homepage { + &.on-categories { border-color: #F7464A; background-color: #FF5A5E; } @@ -98,10 +98,14 @@ border-color: #FDB45C; background-color: #FFC870; } - &.idle { + &.recent { border-color: #949FB1; background-color: #A8B3C5; } + &.tags { + border-color: #FDB45C; + background-color: #8FA633; + } } } } diff --git a/public/less/admin/manage/categories.less b/public/less/admin/manage/categories.less deleted file mode 100644 index 5982a108dd..0000000000 --- a/public/less/admin/manage/categories.less +++ /dev/null @@ -1,133 +0,0 @@ -.categories { - .entry-row { - border-radius: 10px; - cursor: move; - list-style-type: none; - } - - .fa-icons .col-md-3 { - padding-left: 0; - padding-right: 0; - } - - .admin-categories { - margin-top: 20px; - - > ul > li { - - label { - font-size: 12px; - font-weight: none; - } - - form { - .btn-group { - display: block; - } - } - h3 { - margin-top: 0; - } - - h3, h4 { - cursor: text; - .fa-edit { - cursor: pointer; - } - } - - h3, h4, .toggle-settings { - padding-left: 8px; - } - - .preview-box { - width: 100%; - height: 100px; - text-align: center; - color: white; - margin-top: 0; - - .icon { - width: 30px; - height: 30px; - line-height: 40px; - display: inline-block; - margin: 35px 5px 0 5px; - } - } - - .dropdown { - hr { - margin: 5px auto; - } - } - } - } - - .permissions-modal { - .search-results { - padding: 0; - - > li { - .zebra; - clear: both; - list-style-type: none; - padding: 0.5em; - min-height: 46px; - - a { - &:before { - font-family: "FontAwesome"; - content: "\f096"; - display: inline-block; - min-width: 20px; - } - - &.active:before { - content: "\f046"; - } - } - - img { - width: 32px; - margin-right: 1em; - } - } - } - - .members { - li { - list-style-type: none; - .inline-block; - .pointer; - - img { - width: 32px; - } - - &.empty { - font-size: 12px; - cursor: auto; - min-height: 28px; - } - } - } - } - - .category-list { - padding: 0; - - li { - .inline-block; - .pointer; - padding: 0.5em; - margin: 0.25em; - .border-radius(3px); - - &.disabled { - -webkit-filter: grayscale(30%); - .opacity(0.5); - } - } - } -} \ No newline at end of file diff --git a/public/less/generics.less b/public/less/generics.less new file mode 100644 index 0000000000..e44d5f0d72 --- /dev/null +++ b/public/less/generics.less @@ -0,0 +1,16 @@ +.category-list { + padding: 0; + + li { + .inline-block; + .pointer; + padding: 0.5em; + margin: 0.25em; + .border-radius(3px); + + &.disabled { + -webkit-filter: grayscale(30%); + .opacity(0.5); + } + } +} \ No newline at end of file diff --git a/public/src/admin/appearance/skins.js b/public/src/admin/appearance/skins.js index b67842b1b5..374b88a7b4 100644 --- a/public/src/admin/appearance/skins.js +++ b/public/src/admin/appearance/skins.js @@ -32,12 +32,9 @@ define('admin/appearance/skins', function() { app.alert({ alert_id: 'admin:theme', type: 'info', - title: 'Theme Changed', - message: 'Please restart your NodeBB to fully activate this theme', - timeout: 5000, - clickfn: function() { - socket.emit('admin.restart'); - } + title: 'Skin Updated', + message: themeId + ' skin was successfully applied', + timeout: 5000 }); }); } diff --git a/public/src/admin/general/dashboard.js b/public/src/admin/general/dashboard.js index 7a2243465d..a842c0d2af 100644 --- a/public/src/admin/general/dashboard.js +++ b/public/src/admin/general/dashboard.js @@ -141,10 +141,8 @@ define('admin/general/dashboard', ['semver'], function(semver) { '<div>Connections</div>' + '</div>'; - var idle = data.socketCount - (data.users.home + data.users.topics + data.users.category); - updateRegisteredGraph(data.onlineRegisteredCount, data.onlineGuestCount); - updatePresenceGraph(data.users.home, data.users.topics, data.users.category, idle); + updatePresenceGraph(data.users); updateTopicsGraph(data.topics); $('#active-users').html(html); @@ -248,46 +246,52 @@ define('admin/general/dashboard', ['semver'], function(semver) { }); graphs.registered = new Chart(registeredCtx).Doughnut([{ - value: 1, - color:"#F7464A", - highlight: "#FF5A5E", - label: "Registered Users" - }, - { - value: 1, - color: "#46BFBD", - highlight: "#5AD3D1", - label: "Anonymous Users" - }], { - responsive: true - }); + value: 1, + color:"#F7464A", + highlight: "#FF5A5E", + label: "Registered Users" + }, + { + value: 1, + color: "#46BFBD", + highlight: "#5AD3D1", + label: "Anonymous Users" + }], { + responsive: true + }); graphs.presence = new Chart(presenceCtx).Doughnut([{ - value: 1, - color:"#F7464A", - highlight: "#FF5A5E", - label: "On homepage" - }, - { - value: 1, - color: "#46BFBD", - highlight: "#5AD3D1", - label: "Reading posts" - }, - { - value: 1, - color: "#FDB45C", - highlight: "#FFC870", - label: "Browsing topics" - }, - { - value: 1, - color: "#949FB1", - highlight: "#A8B3C5", - label: "Idle" - }], { - responsive: true - }); + value: 1, + color:"#F7464A", + highlight: "#FF5A5E", + label: "On categories list" + }, + { + value: 1, + color: "#46BFBD", + highlight: "#5AD3D1", + label: "Reading posts" + }, + { + value: 1, + color: "#FDB45C", + highlight: "#FFC870", + label: "Browsing topics" + }, + { + value: 1, + color: "#949FB1", + highlight: "#A8B3C5", + label: "Recent/Unread" + }, + { + value: 1, + color: "#8FA633", + highlight: "#3FA7B8", + label: "Tags" + }], { + responsive: true + }); graphs.topics = new Chart(topicsCtx).Doughnut([], {responsive: true}); topicsCanvas.onclick = function(evt){ @@ -345,11 +349,13 @@ define('admin/general/dashboard', ['semver'], function(semver) { graphs.registered.update(); } - function updatePresenceGraph(homepage, posts, topics, idle) { - graphs.presence.segments[0].value = homepage; - graphs.presence.segments[1].value = posts; - graphs.presence.segments[2].value = topics; - graphs.presence.segments[3].value = idle; + function updatePresenceGraph(users) { + graphs.presence.segments[0].value = users.categories; + graphs.presence.segments[1].value = users.topics; + graphs.presence.segments[2].value = users.category; + graphs.presence.segments[3].value = users.recent; + graphs.presence.segments[4].value = users.tags; + graphs.presence.update(); } @@ -424,6 +430,9 @@ define('admin/general/dashboard', ['semver'], function(semver) { function buildTopicsLegend() { var legend = $('#topics-legend').html(''); + segments.sort(function(a, b) { + return b.value - a.value; + }); for (var i = 0, ii = segments.length; i < ii; i++) { var topic = segments[i], label = topic.tid === '0' ? topic.label : '<a title="' + topic.label + '"href="' + RELATIVE_PATH + '/topic/' + topic.tid + '" target="_blank"> ' + topic.label + '</a>'; diff --git a/public/src/admin/manage/categories.js b/public/src/admin/manage/categories.js index 52d13874ab..535d902dfe 100644 --- a/public/src/admin/manage/categories.js +++ b/public/src/admin/manage/categories.js @@ -1,88 +1,66 @@ "use strict"; /*global define, socket, app, bootbox, templates, ajaxify, RELATIVE_PATH*/ -define('admin/manage/categories', [ - 'uploader', - 'iconSelect', - 'admin/modules/colorpicker' -], function(uploader, iconSelect, colorpicker) { +define('admin/manage/categories', function() { var Categories = {}; Categories.init = function() { - var modified_categories = {}; + var bothEl = $('#active-categories, #disabled-categories'); - function modified(el) { - var cid = $(el).parents('li').attr('data-cid'); - if(cid) { - modified_categories[cid] = modified_categories[cid] || {}; - modified_categories[cid][$(el).attr('data-name')] = $(el).val(); - } - } + function updateCategoryOrders(evt, ui) { + var categories = $(evt.target).children(), + modified = {}, + cid; - function save() { - if(Object.keys(modified_categories).length) { - socket.emit('admin.categories.update', modified_categories, function(err, result) { - if (err) { - return app.alertError(err.message); - } - - if (result && result.length) { - app.alert({ - title: 'Updated Categories', - message: 'Category IDs ' + result.join(', ') + ' was successfully updated.', - type: 'success', - timeout: 2000 - }); - } - }); - modified_categories = {}; + for(var i=0;i<categories.length;i++) { + cid = $(categories[i]).attr('data-cid'); + modified[cid] = { + order: i+1 + }; } - return false; - } - function update_blockclass(el) { - el.parentNode.parentNode.className = 'entry-row ' + el.value; + socket.emit('admin.categories.update', modified); } - function updateCategoryOrders() { - var categories = $('.admin-categories #entry-container').children(); - for(var i = 0; i<categories.length; ++i) { - var input = $(categories[i]).find('input[data-name="order"]'); + bothEl.sortable({ + stop: updateCategoryOrders, + distance: 15 + }); - input.val(i+1).attr('data-value', i+1); - modified(input); - } - } + // Category enable/disable + bothEl.on('click', '[data-action="toggle"]', function(ev) { + var btnEl = $(this), + cid = btnEl.parents('tr').attr('data-cid'), + disabled = btnEl.attr('data-disabled') === 'false' ? '1' : '0', + payload = {}; - $('#entry-container').sortable({ - stop: function(event, ui) { - updateCategoryOrders(); - }, - distance: 10 - }); + payload[cid] = { + disabled: disabled + }; - $('.blockclass, .admin-categories form select').each(function() { - var $this = $(this); - $this.val($this.attr('data-value')); + socket.emit('admin.categories.update', payload, function(err, result) { + if (err) { + return app.alertError(err.message); + } else { + ajaxify.refresh(); + } + }); }); - function showCreateCategoryModal() { - $('#new-category-modal').modal(); - } - - function createNewCategory() { - var category = { - name: $('#inputName').val(), - description: $('#inputDescription').val(), - icon: $('#new-category-modal i').attr('value'), - order: $('.admin-categories #entry-container').children().length + 1 - }; + $('button[data-action="create"]').on('click', Categories.create); + }; - saveNew(category); - } + Categories.create = function() { + bootbox.prompt('Category Name', function(name) { + if (!name) { + return; + } - function saveNew(category) { - socket.emit('admin.categories.create', category, function(err, data) { + socket.emit('admin.categories.create', { + name: name, + description: '', + icon: 'fa-comments' + }, function(err, data) { if(err) { return app.alertError(err.message); } @@ -95,323 +73,9 @@ define('admin/manage/categories', [ timeout: 2000 }); - $('#new-category-modal').modal('hide'); - ajaxify.refresh(); - }); - } - - function enableColorPicker(idx, inputEl) { - var $inputEl = $(inputEl), - previewEl = $inputEl.parents('[data-cid]').find('.preview-box'); - - colorpicker.enable($inputEl, function(hsb, hex) { - if ($inputEl.attr('data-name') === 'bgColor') { - previewEl.css('background', '#' + hex); - } else if ($inputEl.attr('data-name') === 'color') { - previewEl.css('color', '#' + hex); - } - - modified($inputEl[0]); - }); - } - - function setupEditTargets() { - $('[data-edit-target]').on('click', function() { - var $this = $(this), - target = $($this.attr('data-edit-target')); - - $this.addClass('hide'); - target.removeClass('hide').on('blur', function() { - $this.removeClass('hide').children('span').html(this.value); - $(this).addClass('hide'); - }).val($this.children('span').html()); - - target.focus(); - }); - } - - $(function() { - var url = window.location.href, - parts = url.split('/'), - active = parts[parts.length - 1]; - - $('.nav-pills li').removeClass('active'); - $('.nav-pills li a').each(function() { - var $this = $(this); - if ($this.attr('href').match(active)) { - $this.parent().addClass('active'); - return false; - } - }); - - - $('#addNew').on('click', showCreateCategoryModal); - $('#create-category-btn').on('click', createNewCategory); - - $('#entry-container, #new-category-modal').on('click', '.icon', function(ev) { - iconSelect.init($(this).find('i'), modified); - }); - - $('.admin-categories form input, .admin-categories form select').on('change', function(ev) { - modified(ev.target); - }); - - $('.dropdown').on('click', '[data-disabled]', function(ev) { - var btn = $(this), - categoryRow = btn.parents('li'), - cid = categoryRow.attr('data-cid'), - disabled = btn.attr('data-disabled') === 'false' ? '1' : '0'; - - categoryRow.remove(); - modified_categories[cid] = modified_categories[cid] || {}; - modified_categories[cid].disabled = disabled; - - save(); - return false; - }); - - // Colour Picker - $('[data-name="bgColor"], [data-name="color"]').each(enableColorPicker); - - $('.admin-categories').on('click', '.save', save); - $('.admin-categories').on('click', '.purge', function() { - var categoryRow = $(this).parents('li[data-cid]'); - var cid = categoryRow.attr('data-cid'); - - bootbox.confirm('Do you really want to purge this category "' + categoryRow.find('#cid-' + cid + '-name').val() + '"?<br/><strong class="text-danger">Warning!</strong> All topics and posts in this category will be purged!', function(confirm) { - if (!confirm) { - return; - } - socket.emit('admin.categories.purge', cid, function(err) { - if (err) { - return app.alertError(err.message); - } - app.alertSuccess('Category purged!'); - categoryRow.remove(); - }); - }); - }); - - $('.admin-categories').on('click', '.duplicate', function() { - var inputs = $(this).parents('li[data-cid]').find('[data-name]'), - data = {}; - - inputs.each(function() { - var name = $(this).attr('data-name'); - switch (name) { - case 'icon': - data[name] = $(this).attr('value'); - break; - case 'name': - data[name] = $(this).val() + ' (copy)'; - break; - default: - data[name] = $(this).val(); - } - }); - - saveNew(data); - }); - - $('.admin-categories').on('click', '.permissions', function() { - var cid = $(this).parents('li[data-cid]').attr('data-cid'); - Categories.launchPermissionsModal(cid); - return false; - }); - - - $('.admin-categories').on('click', '.upload-button', function() { - var inputEl = $(this), - cid = inputEl.parents('li[data-cid]').attr('data-cid'); - - uploader.open(RELATIVE_PATH + '/api/admin/category/uploadpicture', { cid: cid }, 0, function(imageUrlOnServer) { - inputEl.val(imageUrlOnServer); - var previewBox = inputEl.parents('li[data-cid]').find('.preview-box'); - previewBox.css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')') - .css('background-size', 'cover'); - modified(inputEl[0]); - }); - }); - - $('.admin-categories').on('click', '.delete-image', function() { - var parent = $(this).parents('li[data-cid]'), - inputEl = parent.find('.upload-button'), - preview = parent.find('.preview-box'), - bgColor = parent.find('.category_bgColor').val(); - - inputEl.val(''); - modified(inputEl[0]); - - preview.css('background', bgColor); - - $(this).addClass('hide').hide(); - }); - - $('#revertChanges').on('click', function() { - ajaxify.refresh(); - }); - - setupEditTargets(); - - $('button[data-action="setParent"]').on('click', function() { - var cid = $(this).parents('[data-cid]').attr('data-cid'), - modal = $('#setParent'); - - modal.find('select').val($(this).attr('data-parentCid')); - modal.attr('data-cid', cid).modal(); - }); - - $('button[data-action="removeParent"]').on('click', function() { - var cid = $(this).parents('[data-cid]').attr('data-cid'); - var payload= {}; - payload[cid] = { - parentCid: 0 - }; - socket.emit('admin.categories.update', payload, function(err) { - if (err) { - return app.alertError(err.message); - } - ajaxify.go('admin/manage/categories/active'); - }); - }); - - $('#setParent [data-cid]').on('click', function() { - var modalEl = $('#setParent'), - parentCid = $(this).attr('data-cid'), - payload = {}; - - payload[modalEl.attr('data-cid')] = { - parentCid: parentCid - }; - - socket.emit('admin.categories.update', payload, function(err) { - modalEl.one('hidden.bs.modal', function() { - ajaxify.go('admin/manage/categories/active'); - }); - modalEl.modal('hide'); - }); - }); - }); - }; - - Categories.launchPermissionsModal = function(cid) { - var modal = $('#category-permissions-modal'), - searchEl = modal.find('#permission-search'), - resultsEl = modal.find('.search-results.users'), - groupsResultsEl = modal.find('.search-results.groups'), - searchDelay; - - // Clear the search field and results - searchEl.val(''); - resultsEl.html(''); - - searchEl.off().on('keyup', function() { - var searchEl = this, - liEl; - - clearTimeout(searchDelay); - - searchDelay = setTimeout(function() { - socket.emit('admin.categories.search', { - username: searchEl.value, - cid: cid - }, function(err, results) { - if(err) { - return app.alertError(err.message); - } - - templates.parse('admin/partials/categories/users', { - users: results - }, function(html) { - resultsEl.html(html); - }); - }); - }, 250); - }); - - Categories.refreshPrivilegeList(cid); - - resultsEl.off().on('click', '[data-priv]', function(e) { - var anchorEl = $(this), - uid = anchorEl.parents('li[data-uid]').attr('data-uid'), - privilege = anchorEl.attr('data-priv'); - e.preventDefault(); - e.stopPropagation(); - - socket.emit('admin.categories.setPrivilege', { - cid: cid, - uid: uid, - privilege: privilege, - set: !anchorEl.hasClass('active') - }, function(err) { - if (err) { - return app.alertError(err.message); - } - anchorEl.toggleClass('active', !anchorEl.hasClass('active')); - Categories.refreshPrivilegeList(cid); + ajaxify.go('admin/manage/categories/' + data.cid); }); }); - - modal.off().on('click', '.members li > img', function() { - searchEl.val($(this).attr('title')); - searchEl.keyup(); - }); - - // User Groups and privileges - socket.emit('admin.categories.groupsList', cid, function(err, results) { - if(err) { - return app.alertError(err.message); - } - - templates.parse('admin/partials/categories/groups', { - groups: results - }, function(html) { - groupsResultsEl.html(html); - }); - }); - - groupsResultsEl.off().on('click', '[data-priv]', function(e) { - var anchorEl = $(this), - name = anchorEl.parents('li[data-name]').attr('data-name'), - privilege = anchorEl.attr('data-priv'); - e.preventDefault(); - e.stopPropagation(); - - socket.emit('admin.categories.setGroupPrivilege', { - cid: cid, - name: name, - privilege: privilege, - set: !anchorEl.hasClass('active') - }, function(err) { - if (!err) { - anchorEl.toggleClass('active'); - } - }); - }); - - modal.modal(); - }; - - Categories.refreshPrivilegeList = function (cid) { - var modalEl = $('#category-permissions-modal'), - memberList = $('.members'); - - socket.emit('admin.categories.getPrivilegeSettings', cid, function(err, privilegeList) { - var membersLength = privilegeList.length, - liEl, x, userObj; - - memberList.html(''); - if (membersLength > 0) { - for(x = 0; x < membersLength; x++) { - userObj = privilegeList[x]; - liEl = $('<li/>').attr('data-uid', userObj.uid).html('<img src="' + userObj.picture + '" title="' + userObj.username + '" />'); - memberList.append(liEl); - } - } else { - liEl = $('<li/>').addClass('empty').html('None.'); - memberList.append(liEl); - } - }); }; return Categories; diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js new file mode 100644 index 0000000000..c51dba4a01 --- /dev/null +++ b/public/src/admin/manage/category.js @@ -0,0 +1,271 @@ +"use strict"; +/*global define, app, socket, ajaxify, RELATIVE_PATH, bootbox */ + +define('admin/manage/category', [ + 'uploader', + 'iconSelect', + 'admin/modules/colorpicker', + 'autocomplete' +], function(uploader, iconSelect, colorpicker, autocomplete) { + var Category = {}; + + Category.init = function() { + var modified_categories = {}; + + function modified(el) { + var cid = $(el).parents('form').attr('data-cid'); + + if (cid) { + modified_categories[cid] = modified_categories[cid] || {}; + modified_categories[cid][$(el).attr('data-name')] = $(el).val(); + } + } + + function save(e) { + e.preventDefault(); + + if(Object.keys(modified_categories).length) { + socket.emit('admin.categories.update', modified_categories, function(err, result) { + if (err) { + return app.alertError(err.message); + } + + if (result && result.length) { + app.alert({ + title: 'Updated Categories', + message: 'Category IDs ' + result.join(', ') + ' was successfully updated.', + type: 'success', + timeout: 2000 + }); + } + }); + modified_categories = {}; + } + } + + $('.blockclass, form.category select').each(function() { + var $this = $(this); + $this.val($this.attr('data-value')); + }); + + function enableColorPicker(idx, inputEl) { + var $inputEl = $(inputEl), + previewEl = $inputEl.parents('[data-cid]').find('.preview-box'); + + colorpicker.enable($inputEl, function(hsb, hex) { + if ($inputEl.attr('data-name') === 'bgColor') { + previewEl.css('background', '#' + hex); + } else if ($inputEl.attr('data-name') === 'color') { + previewEl.css('color', '#' + hex); + } + + modified($inputEl[0]); + }); + } + + function setupEditTargets() { + $('[data-edit-target]').on('click', function() { + var $this = $(this), + target = $($this.attr('data-edit-target')); + + $this.addClass('hide'); + target.removeClass('hide').on('blur', function() { + $this.removeClass('hide').children('span').html(this.value); + $(this).addClass('hide'); + }).val($this.children('span').html()); + + target.focus(); + }); + } + + // If any inputs have changed, prepare it for saving + $('form.category input, form.category select').on('change', function(ev) { + modified(ev.target); + }); + + // Colour Picker + $('[data-name="bgColor"], [data-name="color"]').each(enableColorPicker); + + $('.save').on('click', save); + $('.revert').on('click', ajaxify.refresh); + $('.purge').on('click', function(e) { + e.preventDefault(); + + bootbox.confirm('<p class="lead">Do you really want to purge this category "' + $('form.category').find('input[data-name="name"]').val() + '"?</p><p><strong class="text-danger">Warning!</strong> All topics and posts in this category will be purged!</p>', function(confirm) { + if (!confirm) { + return; + } + socket.emit('admin.categories.purge', ajaxify.variables.get('cid'), function(err) { + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('Category purged!'); + ajaxify.go('admin/manage/categories'); + }); + }); + }); + + // Image Uploader + $('.upload-button').on('click', function() { + var inputEl = $(this), + cid = inputEl.attr('data-cid'); + + uploader.open(RELATIVE_PATH + '/api/admin/category/uploadpicture', { cid: cid }, 0, function(imageUrlOnServer) { + inputEl.val(imageUrlOnServer); + var previewBox = inputEl.parent().parent().siblings('.category-preview'); + previewBox.css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')') + .css('background-size', 'cover'); + modified(inputEl[0]); + }); + }); + + // Image Remover + $('.delete-image').on('click', function(e) { + e.preventDefault(); + + var inputEl = $('.upload-button'), + previewBox = inputEl.parent().parent().siblings('.category-preview'); + + inputEl.val(''); + previewBox.css('background-image', ''); + modified(inputEl[0]); + $(this).parent().addClass('hide').hide(); + }); + + // Icon selection + $('.category-preview').on('click', function(ev) { + iconSelect.init($(this).find('i'), modified); + }); + + // Parent Category Selector + $('button[data-action="setParent"]').on('click', Category.launchParentSelector); + $('button[data-action="removeParent"]').on('click', function() { + var payload= {}; + payload[ajaxify.variables.get('cid')] = { + parentCid: 0 + }; + + socket.emit('admin.categories.update', payload, function(err) { + if (err) { + return app.alertError(err.message); + } + ajaxify.refresh(); + }); + }); + + setupEditTargets(); + Category.setupPrivilegeTable(); + }; + + Category.setupPrivilegeTable = function() { + var searchEl = $('.privilege-search'), + searchObj = autocomplete.user(searchEl); + + // User search + addition to table + searchObj.on('autocompleteselect', function(ev, ui) { + socket.emit('admin.categories.setPrivilege', { + cid: ajaxify.variables.get('cid'), + privilege: 'read', + set: true, + member: ui.item.user.uid + }, function(err) { + if (err) { + return app.alertError(err.message); + } + + Category.refreshPrivilegeTable(); + searchEl.val(''); + }); + }); + + // Checkbox event capture + $('.privilege-table-container').on('change', 'input[type="checkbox"]', function() { + var checkboxEl = $(this), + privilege = checkboxEl.parent().attr('data-privilege'), + state = checkboxEl.prop('checked'), + rowEl = checkboxEl.parents('tr'), + member = rowEl.attr('data-group-name') || rowEl.attr('data-uid'), + isPrivate = parseInt(rowEl.attr('data-private') || 0, 10), + isGroup = rowEl.attr('data-group-name') !== undefined; + + if (member) { + if (isGroup && privilege === 'groups:moderate' && !isPrivate && state) { + bootbox.confirm('<strong>Are you sure you wish to grant the moderation privilege to this user group?</strong> This group is public, and any users can join at will.', function(confirm) { + if (confirm) { + Category.setPrivilege(member, privilege, state, checkboxEl); + } else { + checkboxEl.prop('checked', checkboxEl.prop('checked') ^ 1); + } + }); + } else { + Category.setPrivilege(member, privilege, state, checkboxEl); + } + } else { + app.alertError('[[error:invalid-data]]'); + } + }) + }; + + Category.refreshPrivilegeTable = function() { + socket.emit('admin.categories.getPrivilegeSettings', ajaxify.variables.get('cid'), function(err, privileges) { + if (err) { + return app.alertError(err.message); + } + + templates.parse('admin/partials/categories/privileges', { + privileges: privileges + }, function(html) { + $('.privilege-table-container').html(html); + }); + }); + }; + + Category.setPrivilege = function(member, privilege, state, checkboxEl) { + socket.emit('admin.categories.setPrivilege', { + cid: ajaxify.variables.get('cid'), + privilege: privilege, + set: state, + member: member + }, function(err) { + if (err) { + return app.alertError(err.message); + } + + checkboxEl.replaceWith('<i class="fa fa-spin fa-spinner"></i>'); + Category.refreshPrivilegeTable(); + }); + }; + + Category.launchParentSelector = function() { + socket.emit('categories.get', function(err, categories) { + templates.parse('partials/category_list', { + categories: categories + }, function(html) { + var modal = bootbox.dialog({ + message: html, + title: 'Set Parent Category' + }); + + modal.find('li[data-cid]').on('click', function() { + var parentCid = $(this).attr('data-cid'), + payload = {}; + + payload[ajaxify.variables.get('cid')] = { + parentCid: parentCid + }; + + socket.emit('admin.categories.update', payload, function(err) { + if (err) { + return app.alertError(err.message); + } + + modal.modal('hide'); + ajaxify.refresh(); + }); + }); + }); + }); + }; + + return Category; +}); \ No newline at end of file diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 6178587423..ed5d3e8b69 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -25,6 +25,8 @@ $(document).ready(function() { ajaxify.go = function (url, callback, quiet) { if (ajaxify.handleACPRedirect(url)) { return true; + } else if (ajaxify.handleNonAPIRoutes(url)) { + return true; } app.enterRoom(''); @@ -39,8 +41,6 @@ $(document).ready(function() { $('#footer, #content').removeClass('hide').addClass('ajaxifying'); - var startTime = (new Date()).getTime(); - ajaxify.variables.flush(); ajaxify.loadData(url, function(err, data) { if (err) { @@ -51,7 +51,7 @@ $(document).ready(function() { translator.load(config.defaultLang, data.template.name); - renderTemplate(url, data.template.name, data, startTime, callback); + renderTemplate(url, data.template.name, data, callback); require(['search'], function(search) { search.topicDOM.end(); @@ -64,12 +64,21 @@ $(document).ready(function() { ajaxify.handleACPRedirect = function(url) { // If ajaxifying into an admin route from regular site, do a cold load. url = ajaxify.removeRelativePath(url.replace(/\/$/, '')); - if (url.indexOf('admin') === 0 && window.location.pathname.indexOf('/admin') !== 0) { + if (url.indexOf('admin') === 0 && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') !== 0) { window.open(RELATIVE_PATH + '/' + url, '_blank'); return true; } return false; - } + }; + + ajaxify.handleNonAPIRoutes = function(url) { + url = ajaxify.removeRelativePath(url.replace(/\/$/, '')); + if (url.indexOf('uploads') === 0) { + window.open(RELATIVE_PATH + '/' + url, '_blank'); + return true; + } + return false; + }; ajaxify.start = function(url, quiet, search) { url = ajaxify.removeRelativePath(url.replace(/\/$/, '')); @@ -118,25 +127,22 @@ $(document).ready(function() { } } - function renderTemplate(url, tpl_url, data, startTime, callback) { - var animationDuration = parseFloat($('#content').css('transition-duration')) || 0.2; + function renderTemplate(url, tpl_url, data, callback) { $(window).trigger('action:ajaxify.loadingTemplates', {}); templates.parse(tpl_url, data, function(template) { translator.translate(template, function(translatedTemplate) { - setTimeout(function() { - $('#content').html(translatedTemplate); + $('#content').html(translatedTemplate); - ajaxify.end(url, tpl_url); + ajaxify.end(url, tpl_url); - if (typeof callback === 'function') { - callback(); - } + if (typeof callback === 'function') { + callback(); + } - $('#content, #footer').removeClass('ajaxifying'); + $('#content, #footer').removeClass('ajaxifying'); - app.refreshTitle(url); - }, animationDuration * 1000 - ((new Date()).getTime() - startTime)); + app.refreshTitle(url); }); }); } @@ -162,7 +168,11 @@ $(document).ready(function() { return url; }; - ajaxify.refresh = function() { + ajaxify.refresh = function(e) { + if (e && e instanceof jQuery.Event) { + e.preventDefault(); + } + ajaxify.go(ajaxify.currentPage); }; diff --git a/public/src/app.js b/public/src/app.js index fdfe7856b3..dadf141702 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -105,8 +105,8 @@ app.cacheBuster = null; case 'admin': room = 'admin'; break; - case 'home': - room = 'home'; + case 'categories': + room = 'categories'; break; } app.currentRoom = ''; @@ -234,7 +234,7 @@ app.cacheBuster = null; app.processPage = function () { highlightNavigationLink(); - $('span.timeago').timeago(); + $('.timeago').timeago(); utils.makeNumbersHumanReadable($('.human-readable-number')); diff --git a/public/src/client/account/favourites.js b/public/src/client/account/favourites.js index 6a08a814a5..f73e1d4f20 100644 --- a/public/src/client/account/favourites.js +++ b/public/src/client/account/favourites.js @@ -34,7 +34,7 @@ define('forum/account/favourites', ['forum/account/header', 'forum/infinitescrol infinitescroll.parseAndTranslate('account/favourites', 'posts', {posts: posts}, function(html) { $('.user-favourite-posts').append(html); html.find('img').addClass('img-responsive'); - html.find('span.timeago').timeago(); + html.find('.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); callback(); diff --git a/public/src/client/account/posts.js b/public/src/client/account/posts.js index 70410e0819..c4759b9016 100644 --- a/public/src/client/account/posts.js +++ b/public/src/client/account/posts.js @@ -35,7 +35,7 @@ define('forum/account/posts', ['forum/account/header', 'forum/infinitescroll'], infinitescroll.parseAndTranslate('account/posts', 'posts', {posts: posts}, function(html) { $('.user-favourite-posts').append(html); html.find('img').addClass('img-responsive'); - html.find('span.timeago').timeago(); + html.find('.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); callback(); diff --git a/public/src/client/account/profile.js b/public/src/client/account/profile.js index 89a555a702..5bbf48fe85 100644 --- a/public/src/client/account/profile.js +++ b/public/src/client/account/profile.js @@ -116,7 +116,7 @@ define('forum/account/profile', ['forum/account/header', 'forum/infinitescroll'] infinitescroll.parseAndTranslate('account/profile', 'posts', {posts: posts}, function(html) { $('.user-recent-posts .loading-indicator').before(html); - html.find('span.timeago').timeago(); + html.find('.timeago').timeago(); callback(); }); diff --git a/public/src/client/account/topics.js b/public/src/client/account/topics.js index c556ef2891..c6c93f4262 100644 --- a/public/src/client/account/topics.js +++ b/public/src/client/account/topics.js @@ -18,12 +18,12 @@ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], infinitescroll.loadMore('topics.loadMoreFromSet', { set: 'uid:' + $('.account-username-box').attr('data-uid') + ':topics', - after: $('.user-topics').attr('data-nextstart') + after: $('[component="category"]').attr('data-nextstart') }, function(data, done) { if (data.topics && data.topics.length) { onTopicsLoaded(data.topics, done); - $('.user-topics').attr('data-nextstart', data.nextStart); + $('[component="category"]').attr('data-nextstart', data.nextStart); } else { done(); } @@ -32,8 +32,8 @@ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], function onTopicsLoaded(topics, callback) { infinitescroll.parseAndTranslate('account/topics', 'topics', {topics: topics}, function(html) { - $('#topics-container').append(html); - html.find('span.timeago').timeago(); + $('[component="category"]').append(html); + html.find('.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); $(window).trigger('action:topics.loaded'); diff --git a/public/src/client/account/watched.js b/public/src/client/account/watched.js index 9a502b1ee8..08feb89344 100644 --- a/public/src/client/account/watched.js +++ b/public/src/client/account/watched.js @@ -17,11 +17,11 @@ define('forum/account/watched', ['forum/account/header', 'forum/infinitescroll'] infinitescroll.loadMore('topics.loadMoreFromSet', { set: 'uid:' + $('.account-username-box').attr('data-uid') + ':followed_tids', - after: $('.user-topics').attr('data-nextstart') + after: $('[component="category"]').attr('data-nextstart') }, function(data, done) { if (data.topics && data.topics.length) { onTopicsLoaded(data.topics, done); - $('.user-topics').attr('data-nextstart', data.nextStart); + $('[component="category"]').attr('data-nextstart', data.nextStart); } else { done(); } @@ -30,8 +30,8 @@ define('forum/account/watched', ['forum/account/header', 'forum/infinitescroll'] function onTopicsLoaded(topics, callback) { infinitescroll.parseAndTranslate('account/watched', 'topics', {topics: topics}, function(html) { - $('#topics-container').append(html); - html.find('span.timeago').timeago(); + $('[component="category"]').append(html); + html.find('.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); $(window).trigger('action:topics.loaded'); diff --git a/public/src/client/categories.js b/public/src/client/categories.js index d3cf1cae43..e3882ff831 100644 --- a/public/src/client/categories.js +++ b/public/src/client/categories.js @@ -29,7 +29,7 @@ define('forum/categories', function() { }; function renderNewPost(cid, post) { - var category = $('.category-item[data-cid="' + cid + '"]'); + var category = components.get('category/topic', 'cid', cid); if (!category.length) { return; } @@ -67,7 +67,7 @@ define('forum/categories', function() { translator.translate(html, function(translatedHTML) { translatedHTML = $(translatedHTML); translatedHTML.find('img').addClass('img-responsive'); - translatedHTML.find('span.timeago').timeago(); + translatedHTML.find('.timeago').timeago(); callback(translatedHTML); }); }); diff --git a/public/src/client/category.js b/public/src/client/category.js index 3b6a0e69b9..1e6c0e94c4 100644 --- a/public/src/client/category.js +++ b/public/src/client/category.js @@ -20,12 +20,6 @@ define('forum/category', [ } }); - $(window).on('action:composer.topics.post', function(ev, data) { - localStorage.removeItem('category:' + data.data.cid + ':bookmark'); - localStorage.removeItem('category:' + data.data.cid + ':bookmark:clicked'); - ajaxify.go('topic/' + data.data.slug); - }); - function removeListeners() { socket.removeListener('event:new_topic', Category.onNewTopic); categoryTools.removeListeners(); @@ -52,12 +46,12 @@ define('forum/category', [ enableInfiniteLoadingOrPagination(); if (!config.usePagination) { - navigator.init('#topics-container > .category-item', ajaxify.variables.get('topic_count'), Category.toTop, Category.toBottom, Category.navigatorCallback); + navigator.init('[component="category/topic"]', ajaxify.variables.get('topic_count'), Category.toTop, Category.toBottom, Category.navigatorCallback); } - $('#topics-container').on('click', '.topic-title', function() { + $('[component="category"]').on('click', '[component="post/header"]', function() { var clickedIndex = $(this).parents('[data-index]').attr('data-index'); - $('#topics-container li.category-item').each(function(index, el) { + $('[component="category/topic"]').each(function(index, el) { if ($(el).offset().top - $(window).scrollTop() > 0) { localStorage.setItem('category:' + cid + ':bookmark', $(el).attr('data-index')); localStorage.setItem('category:' + cid + ':bookmark:clicked', clickedIndex); @@ -95,8 +89,8 @@ define('forum/category', [ }); }; - Category.navigatorCallback = function(element, elementCount) { - return parseInt(element.attr('data-index'), 10) + 1; + Category.navigatorCallback = function(topIndex, bottomIndex, elementCount) { + return bottomIndex; }; $(window).on('action:popstate', function(ev, data) { @@ -135,7 +129,7 @@ define('forum/category', [ bookmarkIndex = 0; } - $('#topics-container').empty(); + $('[component="category"]').empty(); loadTopicsAfter(bookmarkIndex, function() { Category.scrollToTopic(bookmarkIndex, clickedIndex, 0); @@ -145,7 +139,7 @@ define('forum/category', [ }); Category.highlightTopic = function(topicIndex) { - var highlight = $('#topics-container [data-index="' + topicIndex + '"]'); + var highlight = components.get('category/topic', 'index', topicIndex); if (highlight.length && !highlight.hasClass('highlight')) { highlight.addClass('highlight'); setTimeout(function() { @@ -163,7 +157,7 @@ define('forum/category', [ offset = 0; } - var scrollTo = $('#topics-container [data-index="' + bookmarkIndex + '"]'); + var scrollTo = components.get('category/topic', 'index', bookmarkIndex); var cid = ajaxify.variables.get('category_id'); if (scrollTo.length && cid) { $('html, body').animate({ @@ -198,11 +192,12 @@ define('forum/category', [ }, function(html) { translator.translate(html, function(translatedHTML) { var topic = $(translatedHTML), - container = $('#topics-container'), - topics = $('#topics-container').children('.category-item'), + container = $('[component="category"]'), + topics = $('[component="category/topic"]'), numTopics = topics.length; - $('#topics-container, .category-sidebar').removeClass('hidden'); + $('[component="category"]').removeClass('hidden'); + $('.category-sidebar').removeClass('hidden'); var noTopicsWarning = $('#category-no-topics'); if (noTopicsWarning.length) { @@ -228,7 +223,7 @@ define('forum/category', [ topic.hide().fadeIn('slow'); - topic.find('span.timeago').timeago(); + topic.find('.timeago').timeago(); app.createUserTooltips(); updateTopicCount(); @@ -253,7 +248,7 @@ define('forum/category', [ function removeAlreadyAddedTopics(topics) { return topics.filter(function(topic) { - return $('#topics-container li[data-tid="' + topic.tid +'"]').length === 0; + return components.get('category/topic', 'tid', topic.tid).length === 0; }); } @@ -261,16 +256,20 @@ define('forum/category', [ before = null; function findInsertionPoint() { - if (!$('#topics-container .category-item[data-tid]').length) { + var topics = components.get('category/topic'); + + if (!topics.length) { return; } - var last = $('#topics-container .category-item[data-tid]').last(); - var lastIndex = last.attr('data-index'); - var firstIndex = data.topics[data.topics.length - 1].index; + + var last = topics.last(), + lastIndex = last.attr('data-index'), + firstIndex = data.topics[data.topics.length - 1].index; + if (firstIndex > lastIndex) { after = last; } else { - before = $('#topics-container .category-item[data-tid]').first(); + before = topics.first(); } } @@ -283,10 +282,12 @@ define('forum/category', [ templates.parse('category', 'topics', data, function(html) { translator.translate(html, function(translatedHTML) { - var container = $('#topics-container'), + var container = $('[component="category"]'), html = $(translatedHTML); - $('#topics-container, .category-sidebar').removeClass('hidden'); + $('[component="category"]').removeClass('hidden'); + $('.category-sidebar').removeClass('hidden'); + $('#category-no-topics').remove(); if(config.usePagination) { @@ -304,7 +305,7 @@ define('forum/category', [ if (typeof callback === 'function') { callback(); } - html.find('span.timeago').timeago(); + html.find('.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); }); @@ -312,11 +313,11 @@ define('forum/category', [ }; Category.loadMoreTopics = function(direction) { - if (!$('#topics-container').length || !$('#topics-container').children().length) { + if (!$('[component="category"]').length || !$('[component="category"]').children().length) { return; } - infinitescroll.calculateAfter(direction, '#topics-container .category-item[data-tid]', config.topicsPerPage, false, function(after, offset, el) { + infinitescroll.calculateAfter(direction, components.get('category/topic'), config.topicsPerPage, false, function(after, offset, el) { loadTopicsAfter(after, function() { if (direction < 0 && el) { Category.scrollToTopic(el.attr('data-index'), null, 0, offset); @@ -326,7 +327,7 @@ define('forum/category', [ }; function loadTopicsAfter(after, callback) { - if(!utils.isNumber(after) || (after === 0 && $('#topics-container li.category-item[data-index="0"]').length)) { + if(!utils.isNumber(after) || (after === 0 && components.get('category/topic', 'index', 0).length)) { return; } @@ -342,7 +343,7 @@ define('forum/category', [ done(); callback(); }); - $('#topics-container').attr('data-nextstart', data.nextStart); + $('[component="category"]').attr('data-nextstart', data.nextStart); } else { done(); } diff --git a/public/src/client/categoryTools.js b/public/src/client/categoryTools.js index 0e9bae608b..e711bce436 100644 --- a/public/src/client/categoryTools.js +++ b/public/src/client/categoryTools.js @@ -173,26 +173,26 @@ define('forum/categoryTools', ['forum/topic/move', 'topicSelect'], function(move } function getTopicEl(tid) { - return $('#topics-container li[data-tid="' + tid + '"]'); + return components.get('category/topic', 'tid', tid); } function setDeleteState(data) { var topic = getTopicEl(data.tid); topic.toggleClass('deleted', data.isDeleted); - topic.find('.fa-lock').toggleClass('hide', !data.isDeleted); + topic.find('[component="topic/locked"]').toggleClass('hide', !data.isDeleted); } function setPinnedState(data) { var topic = getTopicEl(data.tid); topic.toggleClass('pinned', data.isPinned); - topic.find('.fa-thumb-tack').toggleClass('hide', !data.isPinned); + topic.find('[component="topic/pinned"]').toggleClass('hide', !data.isPinned); ajaxify.refresh(); } function setLockedState(data) { var topic = getTopicEl(data.tid); topic.toggleClass('locked', data.isLocked); - topic.find('.fa-lock').toggleClass('hide', !data.isLocked); + topic.find('[component="topic/locked"]').toggleClass('hide', !data.isLocked); } function onTopicMoved(data) { diff --git a/public/src/client/chats.js b/public/src/client/chats.js index cde94aa71a..9ea8beea57 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -122,7 +122,7 @@ define('forum/chats', ['string', 'sounds', 'forum/infinitescroll'], function(S, function onMessagesParsed(html) { var newMessage = $(html); newMessage.insertBefore($('.user-typing')); - newMessage.find('span.timeago').timeago(); + newMessage.find('.timeago').timeago(); newMessage.find('img:not(".chat-user-image")').addClass('img-responsive'); Chats.scrollToBottom($('.expanded-chat .chat-content')); } diff --git a/public/src/client/footer.js b/public/src/client/footer.js index 6462e3e39a..4e7c2fa9ee 100644 --- a/public/src/client/footer.js +++ b/public/src/client/footer.js @@ -22,7 +22,7 @@ define('forum/footer', ['notifications', 'chat'], function(Notifications, Chat) return console.warn('Error updating unread count', err); } - $('#chat-count') + components.get('chat/icon') .toggleClass('unread-count', count > 0) .attr('data-content', count > 20 ? '20+' : count); } diff --git a/public/src/client/notifications.js b/public/src/client/notifications.js index fb778ec18f..4e7244f83f 100644 --- a/public/src/client/notifications.js +++ b/public/src/client/notifications.js @@ -16,7 +16,7 @@ define('forum/notifications', function() { }); }); - $('span.timeago').timeago(); + $('.timeago').timeago(); $('.notifications .delete').on('click', function() { socket.emit('notifications.markAllRead', function(err) { diff --git a/public/src/client/recent.js b/public/src/client/recent.js index 05e936a577..30d635ea0d 100644 --- a/public/src/client/recent.js +++ b/public/src/client/recent.js @@ -94,17 +94,17 @@ define('forum/recent', ['forum/infinitescroll', 'composer'], function(infinitesc }; Recent.loadMoreTopics = function(direction) { - if(direction < 0 || !$('#topics-container').length) { + if(direction < 0 || !$('[component="category"]').length) { return; } infinitescroll.loadMore('topics.loadMoreFromSet', { - after: $('#topics-container').attr('data-nextstart'), + after: $('[component="category"]').attr('data-nextstart'), set: 'topics:recent' }, function(data, done) { if (data.topics && data.topics.length) { Recent.onTopicsLoaded('recent', data.topics, false, done); - $('#topics-container').attr('data-nextstart', data.nextStart); + $('[component="category"]').attr('data-nextstart', data.nextStart); } else { done(); } @@ -114,7 +114,7 @@ define('forum/recent', ['forum/infinitescroll', 'composer'], function(infinitesc Recent.onTopicsLoaded = function(templateName, topics, showSelect, callback) { topics = topics.filter(function(topic) { - return !$('#topics-container li[data-tid=' + topic.tid + ']').length; + return !components.get('category/topic', 'tid', topic.tid).length; }); if (!topics.length) { @@ -124,8 +124,8 @@ define('forum/recent', ['forum/infinitescroll', 'composer'], function(infinitesc infinitescroll.parseAndTranslate(templateName, 'topics', {topics: topics, showSelect: showSelect}, function(html) { $('#category-no-topics').remove(); - $('#topics-container').append(html); - html.find('span.timeago').timeago(); + $('[component="category"]').append(html); + html.find('.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); $(window).trigger('action:topics.loaded'); diff --git a/public/src/client/reset.js b/public/src/client/reset.js index 7e272c3284..568d0739a1 100644 --- a/public/src/client/reset.js +++ b/public/src/client/reset.js @@ -24,6 +24,7 @@ define('forum/reset', function() { successEl.addClass('hide').hide(); errorEl.removeClass('hide').show(); } + return false; }); }; diff --git a/public/src/client/reset_code.js b/public/src/client/reset_code.js index c0f46dc356..846feffb42 100644 --- a/public/src/client/reset_code.js +++ b/public/src/client/reset_code.js @@ -31,22 +31,8 @@ define('forum/reset_code', function() { window.location.href = RELATIVE_PATH + '/login'; }); } + return false; }); - - // socket.emit('user.reset.valid', reset_code, function(err, valid) { - // if(err) { - // return app.alertError(err.message); - // } - - // if (valid) { - // resetEl.prop('disabled', false); - // } else { - // var formEl = $('#reset-form'); - // // Show error message - // $('#error').show(); - // formEl.remove(); - // } - // }); }; return ResetCode; diff --git a/public/src/client/tag.js b/public/src/client/tag.js index 3565c7e151..7328934e2d 100644 --- a/public/src/client/tag.js +++ b/public/src/client/tag.js @@ -8,7 +8,7 @@ define('forum/tag', ['forum/recent', 'forum/infinitescroll'], function(recent, i Tag.init = function() { app.enterRoom('tags'); - if ($('body').height() <= $(window).height() && $('#topics-container').children().length >= 20) { + if ($('body').height() <= $(window).height() && $('[component="category"]').children().length >= 20) { $('#load-more-btn').show(); } @@ -19,17 +19,17 @@ define('forum/tag', ['forum/recent', 'forum/infinitescroll'], function(recent, i infinitescroll.init(loadMoreTopics); function loadMoreTopics(direction) { - if(direction < 0 || !$('#topics-container').length) { + if(direction < 0 || !$('[component="category"]').length) { return; } infinitescroll.loadMore('topics.loadMoreFromSet', { set: 'tag:' + ajaxify.variables.get('tag') + ':topics', - after: $('#topics-container').attr('data-nextstart') + after: $('[component="category"]').attr('data-nextstart') }, function(data, done) { if (data.topics && data.topics.length) { recent.onTopicsLoaded('tag', data.topics, false, done); - $('#topics-container').attr('data-nextstart', data.nextStart); + $('[component="category"]').attr('data-nextstart', data.nextStart); } else { done(); $('#load-more-btn').hide(); diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 9acd1a4d73..f28a9097c8 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -1,7 +1,7 @@ 'use strict'; -/* globals define, app, templates, translator, socket, bootbox, config, ajaxify, RELATIVE_PATH, utils */ +/* globals define, app, components, templates, translator, socket, bootbox, config, ajaxify, RELATIVE_PATH, utils */ define('forum/topic', [ 'forum/pagination', @@ -20,7 +20,7 @@ define('forum/topic', [ $(window).on('action:ajaxify.start', function(ev, data) { if (ajaxify.currentPage !== data.url) { navigator.hide(); - $('.header-topic-title').find('span').text('').hide(); + components.get('navbar/title').find('span').text('').hide(); app.removeAlert('bookmark'); events.removeListeners(); @@ -53,7 +53,7 @@ define('forum/topic', [ handleBookmark(tid); - navigator.init('.posts > .post-row', ajaxify.variables.get('postcount'), Topic.toTop, Topic.toBottom, Topic.navigatorCallback, Topic.calculateIndex); + navigator.init('[component="post"]', ajaxify.variables.get('postcount'), Topic.toTop, Topic.toBottom, Topic.navigatorCallback, Topic.calculateIndex); $(window).on('scroll', updateTopicTitle); @@ -112,7 +112,7 @@ define('forum/topic', [ } function addBlockQuoteHandler() { - $('#post-container').on('click', 'blockquote .toggle', function() { + components.get('topic').on('click', 'blockquote .toggle', function() { var blockQuote = $(this).parent('blockquote'); var toggle = $(this); blockQuote.toggleClass('uncollapsed'); @@ -124,7 +124,7 @@ define('forum/topic', [ function enableInfiniteLoadingOrPagination() { if(!config.usePagination) { - infinitescroll.init(posts.loadMorePosts, $('#post-container .post-row[data-index="0"]').height()); + infinitescroll.init(posts.loadMorePosts, components.get('post', 'index', 0).height()); } else { navigator.hide(); @@ -135,9 +135,9 @@ define('forum/topic', [ function updateTopicTitle() { if($(window).scrollTop() > 50) { - $('.header-topic-title').find('span').text(ajaxify.variables.get('topic_name')).show(); + components.get('navbar/title').find('span').text(ajaxify.variables.get('topic_name')).show(); } else { - $('.header-topic-title').find('span').text('').hide(); + components.get('navbar/title').find('span').text('').hide(); } } @@ -148,18 +148,18 @@ define('forum/topic', [ return index; }; - Topic.navigatorCallback = function(element, elementCount) { + Topic.navigatorCallback = function(topPostIndex, bottomPostIndex, elementCount) { var path = ajaxify.removeRelativePath(window.location.pathname.slice(1)); if (!path.startsWith('topic')) { return 1; } - var postIndex = parseInt(element.attr('data-index'), 10); - var index = postIndex + 1; + var postIndex = topPostIndex; + var index = bottomPostIndex; if (config.topicPostSort !== 'oldest_to_newest') { - if (postIndex === 0) { + if (bottomPostIndex === 0) { index = 1; } else { - index = Math.max(elementCount - postIndex + 1, 1); + index = Math.max(elementCount - bottomPostIndex + 2, 1); } } @@ -175,8 +175,8 @@ define('forum/topic', [ var topicId = parts[1], slug = parts[2]; var newUrl = 'topic/' + topicId + '/' + (slug ? slug : ''); - if (postIndex > 0) { - newUrl += '/' + (postIndex + 1); + if (postIndex > 1) { + newUrl += '/' + postIndex; } if (newUrl !== currentUrl) { diff --git a/public/src/client/topic/browsing.js b/public/src/client/topic/browsing.js index 935439fa88..7c14fab158 100644 --- a/public/src/client/topic/browsing.js +++ b/public/src/client/topic/browsing.js @@ -10,7 +10,7 @@ define('forum/topic/browsing', function() { Browsing.onUpdateUsersInRoom = function(data) { if (data && data.room.indexOf('topic_' + ajaxify.variables.get('topic_id')) !== -1) { - $('.browsing-users').toggleClass('hidden', !data.users.length); + $('[component="topic/browsing/list"]').parent().toggleClass('hidden', !data.users.length); for(var i=0; i<data.users.length; ++i) { addUserIcon(data.users[i]); } @@ -20,7 +20,7 @@ define('forum/topic/browsing', function() { }; Browsing.onUserEnter = function(data) { - var activeEl = $('.thread_active_users'); + var activeEl = $('[component="topic/browsing/list"]'); var user = activeEl.find('a[data-uid="' + data.uid + '"]'); if (!user.length && activeEl.first().children().length < 10) { addUserIcon(data); @@ -35,7 +35,7 @@ define('forum/topic/browsing', function() { if (app.user.uid === parseInt(uid, 10)) { return; } - var user = $('.thread_active_users').find('a[data-uid="' + uid + '"]'); + var user = $('[component="topic/browsing/list"]').find('a[data-uid="' + uid + '"]'); if (user.length) { var count = Math.max(0, parseInt(user.attr('data-count'), 10) - 1); user.attr('data-count', count); @@ -63,7 +63,7 @@ define('forum/topic/browsing', function() { } function updateBrowsingUsers(data) { - var activeEl = $('.thread_active_users'); + var activeEl = $('[component="topic/browsing/list"]'); var user = activeEl.find('a[data-uid="'+ data.uid + '"]'); if (user.length && data.status === 'offline') { user.parent().remove(); @@ -74,7 +74,7 @@ define('forum/topic/browsing', function() { if (!user.userslug) { return; } - var activeEl = $('.thread_active_users'); + var activeEl = $('[component="topic/browsing/list"]'); var userEl = createUserIcon(user.uid, user.picture, user.userslug, user.username); var isSelf = parseInt(user.uid, 10) === parseInt(app.user.uid, 10); if (isSelf) { @@ -89,7 +89,7 @@ define('forum/topic/browsing', function() { } function createUserIcon(uid, picture, userslug, username) { - if(!$('.thread_active_users').find('[data-uid="' + uid + '"]').length) { + if(!$('[component="topic/browsing/list"]').find('[data-uid="' + uid + '"]').length) { return $('<div class="inline-block"><a data-uid="' + uid + '" data-count="1" href="' + config.relative_path + '/user/' + userslug + '"><img title="' + username + '" src="'+ picture +'"/></a></div>'); } } @@ -99,11 +99,11 @@ define('forum/topic/browsing', function() { if (!count || count < 0) { count = 0; } - $('.user-count').text(count).parent().toggleClass('hidden', count === 0); + $('[component="topic/browsing/count"]').text(count).parent().toggleClass('hidden', count === 0); } function increaseUserCount(incr) { - updateUserCount(parseInt($('.user-count').first().text(), 10) + incr); + updateUserCount(parseInt($('[component="topic/browsing/count"]').first().text(), 10) + incr); } return Browsing; diff --git a/public/src/client/topic/events.js b/public/src/client/topic/events.js index c90dd149b5..c3ecf6d29a 100644 --- a/public/src/client/topic/events.js +++ b/public/src/client/topic/events.js @@ -1,7 +1,7 @@ 'use strict'; -/* globals app, ajaxify, define, socket, translator, templates */ +/* globals app, ajaxify, components, define, socket, translator, templates */ define('forum/topic/events', [ 'forum/topic/browsing', @@ -69,7 +69,7 @@ define('forum/topic/events', [ }; function updatePostVotesAndUserReputation(data) { - var votes = $('[data-pid="' + data.post.pid + '"] .votes'), + var votes = components.get('post/vote-count', data.post.pid), reputationElements = $('.reputation[data-uid="' + data.post.uid + '"]'); votes.html(data.post.votes).attr('data-votes', data.post.votes); @@ -96,12 +96,12 @@ define('forum/topic/events', [ } function onPostEdited(data) { - var editedPostEl = $('#content_' + data.pid), - editedPostTitle = $('#topic_title_' + data.pid); + var editedPostEl = components.get('post/content', data.pid), + editedPostHeader = components.get('post/header', data.pid); - if (editedPostTitle.length) { - editedPostTitle.fadeOut(250, function() { - editedPostTitle.html(data.title).fadeIn(250); + if (editedPostHeader.length) { + editedPostHeader.fadeOut(250, function() { + editedPostHeader.html(data.title).fadeIn(250); }); } @@ -139,14 +139,15 @@ define('forum/topic/events', [ } function onPostPurged(pid) { - $('#post-container [data-pid="' + pid + '"]').fadeOut(500, function() { + components.get('post', 'pid', pid).fadeOut(500, function() { $(this).remove(); }); + postTools.updatePostCount(); } function togglePostDeleteState(data) { - var postEl = $('#post-container [data-pid="' + data.pid + '"]'); + var postEl = components.get('post', 'pid', data.pid); if (!postEl.length) { return; @@ -158,9 +159,9 @@ define('forum/topic/events', [ if (!app.user.isAdmin && parseInt(data.uid, 10) !== parseInt(app.user.uid, 10)) { if (isDeleted) { - postEl.find('.post-content').translateHtml('[[topic:post_is_deleted]]'); + postEl.find('[component="post/content"]').translateHtml('[[topic:post_is_deleted]]'); } else { - postEl.find('.post-content').html(data.content); + postEl.find('[component="post/content"]').html(data.content); } } } diff --git a/public/src/client/topic/fork.js b/public/src/client/topic/fork.js index 216cc63f9f..91ec8a2be9 100644 --- a/public/src/client/topic/fork.js +++ b/public/src/client/topic/fork.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals define, app, ajaxify, translator, socket */ +/* globals define, app, ajaxify, components, translator, socket */ define('forum/topic/fork', function() { @@ -10,7 +10,7 @@ define('forum/topic/fork', function() { pids = []; Fork.init = function() { - $('.fork_thread').on('click', onForkThreadClicked); + components.get('topic/fork').on('click', onForkThreadClicked); }; function disableClicks() { @@ -18,11 +18,11 @@ define('forum/topic/fork', function() { } function disableClicksOnPosts() { - $('.post-row').on('click', 'button,a', disableClicks); + components.get('post').on('click', 'button,a', disableClicks); } function enableClicksOnPosts() { - $('.post-row').off('click', 'button,a', disableClicks); + components.get('post').off('click', 'button,a', disableClicks); } function onForkThreadClicked() { @@ -35,7 +35,7 @@ define('forum/topic/fork', function() { forkModal.find('.close,#fork_thread_cancel').on('click', closeForkModal); forkModal.find('#fork-title').on('change', checkForkButtonEnable); - $('#post-container').on('click', '[data-pid]', function() { + components.get('topic').on('click', '[data-pid]', function() { togglePostSelection($(this)); }); @@ -58,7 +58,7 @@ define('forum/topic/fork', function() { pids: pids }, function(err, newTopic) { function fadeOutAndRemove(pid) { - $('#post-container [data-pid="' + pid + '"]').fadeOut(500, function() { + components.get('post', 'pid', pid).fadeOut(500, function() { $(this).remove(); }); } @@ -125,10 +125,11 @@ define('forum/topic/fork', function() { function closeForkModal() { for(var i=0; i<pids.length; ++i) { - $('#post-container [data-pid="' + pids[i] + '"]').css('opacity', 1); + components.get('post', 'pid', pids[i]).css('opacity', 1); } + forkModal.addClass('hide'); - $('#post-container').off('click', '[data-pid]'); + components.get('topic').off('click', '[data-pid]'); enableClicksOnPosts(); } diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 5e6df47e8b..4e561b036c 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals define, app, utils, templates, translator, ajaxify, socket, bootbox */ +/* globals define, app, ajaxify, bootbox, components, socket, templates, translator, utils */ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(composer, share, navigator) { @@ -18,12 +18,14 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com }; PostTools.toggle = function(pid, isDeleted) { - var postEl = $('#post-container li[data-pid="' + pid + '"]'); + var postEl = components.get('post', 'pid', pid); - postEl.find('.quote, .favourite, .post_reply, .chat, .flag').toggleClass('hidden', isDeleted); - postEl.find('.purge').toggleClass('hidden', !isDeleted); - postEl.find('.delete .i').toggleClass('fa-trash-o', !isDeleted).toggleClass('fa-history', isDeleted); - postEl.find('.delete span').translateHtml(isDeleted ? ' [[topic:restore]]' : ' [[topic:delete]]'); + postEl.find('[component="post/quote"], [component="post/favourite"], [component="post/reply"], [component="post/flag"], [component="user/chat"]') + .toggleClass('hidden', isDeleted); + + postEl.find('[component="post/purge"]').toggleClass('hidden', !isDeleted); + postEl.find('[component="post/delete"] .i').toggleClass('fa-trash-o', !isDeleted).toggleClass('fa-history', isDeleted); + postEl.find('[component="post/delete"] span').translateHtml(isDeleted ? ' [[topic:restore]]' : ' [[topic:delete]]'); }; PostTools.updatePostCount = function() { @@ -38,13 +40,13 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com }; function addVoteHandler() { - $('#post-container').on('mouseenter', '.post-row .votes', function() { + components.get('topic').on('mouseenter', '[data-pid] .votes', function() { loadDataAndCreateTooltip($(this)); }); } function loadDataAndCreateTooltip(el) { - var pid = el.parents('.post-row').attr('data-pid'); + var pid = el.parents('[data-pid]').attr('data-pid'); socket.emit('posts.getUpvoters', [pid], function(err, data) { if (!err && data.length) { createTooltip(el, data[0]); @@ -70,57 +72,67 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com } function addPostHandlers(tid, threadState) { - $('.topic').on('click', '.post_reply', function() { - if (!threadState.locked) { - onReplyClicked($(this), tid, topicName); + function canPost() { + return !threadState.locked || app.user.isAdmin; + } + + var postContainer = components.get('topic'); + + postContainer.on('click', '[component="post/quote"]', function() { + if (canPost()) { + onQuoteClicked($(this), tid, topicName); } }); - var postContainer = $('#post-container'); + postContainer.on('click', '[component="post/reply"]', function() { + if (canPost()) { + onReplyClicked($(this), tid, topicName); + } + }); - postContainer.on('click', '.quote', function() { - if (!threadState.locked) { - onQuoteClicked($(this), tid, topicName); + components.get('topic/reply').on('click', function() { + if (canPost()) { + onReplyClicked($(this), tid, topicName); } }); - postContainer.on('click', '.favourite', function() { + postContainer.on('click', '[component="post/favourite"]', function() { favouritePost($(this), getData($(this), 'data-pid')); }); - postContainer.on('click', '.upvote', function() { + postContainer.on('click', '[component="post/upvote"]', function() { return toggleVote($(this), '.upvoted', 'posts.upvote'); }); - postContainer.on('click', '.downvote', function() { + postContainer.on('click', '[component="post/downvote"]', function() { return toggleVote($(this), '.downvoted', 'posts.downvote'); }); - postContainer.on('click', '.votes', function() { + postContainer.on('click', '[component="post/vote-count"]', function() { showVotes(getData($(this), 'data-pid')); }); - postContainer.on('click', '.flag', function() { + postContainer.on('click', '[component="post/flag"]', function() { flagPost(getData($(this), 'data-pid')); }); - postContainer.on('click', '.edit', function(e) { + postContainer.on('click', '[component="post/edit"]', function(e) { composer.editPost(getData($(this), 'data-pid')); }); - postContainer.on('click', '.delete', function(e) { + postContainer.on('click', '[component="post/delete"]', function(e) { deletePost($(this), tid); }); - postContainer.on('click', '.purge', function(e) { + postContainer.on('click', '[component="post/purge"]', function(e) { purgePost($(this), tid); }); - postContainer.on('click', '.move', function(e) { + postContainer.on('click', '[component="post/move"]', function(e) { openMovePostModal($(this)); }); - postContainer.on('click', '.chat', function(e) { + postContainer.on('click', '[component="user/chat"]', function(e) { openChat($(this)); }); } @@ -129,7 +141,7 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com var selectionText = '', selection = window.getSelection ? window.getSelection() : document.selection.createRange(); - if ($(selection.baseNode).parents('.post-content').length > 0) { + if ($(selection.baseNode).parents('[component="post/content"]').length > 0) { var snippet = selection.toString(); if (snippet.length) { selectionText = '> ' + snippet.replace(/\n/g, '\n> ') + '\n\n'; @@ -185,7 +197,7 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com } function toggleVote(button, className, method) { - var post = button.parents('.post-row'), + var post = button.parents('[data-pid]'), currentState = post.find(className).length; socket.emit(currentState ? 'posts.unvote' : method , { @@ -222,7 +234,7 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com } function getData(button, data) { - return button.parents('.post-row').attr(data); + return button.parents('[data-pid]').attr(data); } function getUserName(button) { @@ -241,7 +253,7 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com function deletePost(button, tid) { var pid = getData(button, 'data-pid'), - postEl = $('#post-container li[data-pid="' + pid + '"]'), + postEl = components.get('post', 'pid', pid), action = !postEl.hasClass('deleted') ? 'delete' : 'restore'; postAction(action, pid, tid); @@ -290,7 +302,7 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com }); moveBtn.on('click', function() { - movePost(button.parents('.post-row'), getData(button, 'data-pid'), topicId.val()); + movePost(button.parents('[data-pid]'), getData(button, 'data-pid'), topicId.val()); }); } @@ -338,7 +350,7 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com } function openChat(button) { - var post = button.parents('li.post-row'); + var post = button.parents('data-pid'); app.openChat(post.attr('data-username'), post.attr('data-uid')); button.parents('.btn-group').find('.dropdown-toggle').click(); diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 8731121de1..070a97fa5b 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals config, app, ajaxify, define, socket, utils */ +/* globals config, app, ajaxify, components, define, socket, utils */ define('forum/topic/posts', [ 'forum/pagination', @@ -22,11 +22,12 @@ define('forum/topic/posts', [ } for (var i=0; i<data.posts.length; ++i) { - var postcount = $('.user_postcount_' + data.posts[i].uid); - postcount.html(parseInt(postcount.html(), 10) + 1); + var cmp = components.get('user/postcount', data.posts[i].uid); + cmp.html(parseInt(cmp.attr('data-postcount'), 10) + 1); + utils.addCommasToNumbers(cmp); } - createNewPosts(data, '.post-row[data-index!="0"]', function(html) { + createNewPosts(data, components.get('post').not('[data-index=0]'), function(html) { if (html) { html.addClass('new'); } @@ -43,7 +44,7 @@ define('forum/topic/posts', [ pagination.pageCount = Math.max(1, Math.ceil((posts[0].topic.postcount - 1) / config.postsPerPage)); if (pagination.currentPage === pagination.pageCount) { - createNewPosts(data, '.post-row[data-index!="0"]', scrollToPost); + createNewPosts(data, components.get('post').not('[data-index=0]'), scrollToPost); } else if (parseInt(posts[0].uid, 10) === parseInt(app.user.uid, 10)) { pagination.loadPage(pagination.pageCount, scrollToPost); } @@ -56,9 +57,34 @@ define('forum/topic/posts', [ } function removeAlreadyAddedPosts() { - data.posts = data.posts.filter(function(post) { - return $('#post-container [data-pid="' + post.pid +'"]').length === 0; - }); + var newPosts = components.get('topic').find('[data-index][data-index!="0"].new'); + + if (newPosts.length === data.posts.length) { + var allSamePids = true; + newPosts.each(function(index, el) { + if (parseInt($(el).attr('data-pid'), 10) !== parseInt(data.posts[index].pid, 10)) { + allSamePids = false; + } + }); + + if (allSamePids) { + newPosts.each(function() { + $(this).removeClass('new'); + }); + data.posts.length = 0; + return; + } + } + + if (newPosts.length && data.posts.length > 1) { + data.posts.forEach(function(post) { + components.get('post', 'pid', post.pid).remove(); + }); + } else { + data.posts = data.posts.filter(function(post) { + return components.get('post', 'pid', post.pid).length === 0; + }); + } } var after = null, @@ -116,7 +142,7 @@ define('forum/topic/posts', [ // Save document height and position for future reference (about 5 lines down) var height = $(document).height(), scrollTop = $(document).scrollTop(), - originalPostEl = $('.post-row[data-index="0"]'); + originalPostEl = components.get('post', 'index', 0); // Insert the new post html.insertBefore(before); @@ -127,7 +153,7 @@ define('forum/topic/posts', [ $(document).scrollTop(scrollTop + ($(document).height() - height)); } } else { - $('#post-container').append(html); + components.get('topic').append(html); } html.hide().fadeIn('slow'); @@ -164,34 +190,35 @@ define('forum/topic/posts', [ } function toggleModTools(pid, privileges) { - var postEl = $('.post-row[data-pid="' + pid + '"]'); + var postEl = components.get('post', 'pid', pid), + isSelfPost = parseInt(postEl.attr('data-uid'), 10) === parseInt(app.user.uid, 10); if (!privileges.editable) { - postEl.find('.edit, .delete, .purge').remove(); + postEl.find('[component="post/edit"], [component="post/delete"], [component="post/purge"]').remove(); } + if (!privileges.move) { - postEl.find('.move').remove(); + postEl.find('[component="post/move"]').remove(); } - postEl.find('.reply, .quote').toggleClass('hidden', !$('.post_reply').length); - var isSelfPost = parseInt(postEl.attr('data-uid'), 10) === parseInt(app.user.uid, 10); - postEl.find('.chat, .flag').toggleClass('hidden', isSelfPost || !app.user.uid); + + postEl.find('[component="user/chat"], [component="post/flag"]').toggleClass('hidden', isSelfPost || !app.user.uid); } Posts.loadMorePosts = function(direction) { - if (!$('#post-container').length || navigator.scrollActive) { + if (!components.get('topic').length || navigator.scrollActive) { return; } var reverse = config.topicPostSort === 'newest_to_oldest' || config.topicPostSort === 'most_votes'; - infinitescroll.calculateAfter(direction, '#post-container .post-row[data-index!="0"]:not(.new)', config.postsPerPage, reverse, function(after, offset, el) { + infinitescroll.calculateAfter(direction, components.get('topic').find('[data-index][data-index!="0"]:not(.new)'), config.postsPerPage, reverse, function(after, offset, el) { loadPostsAfter(after); }); }; function loadPostsAfter(after) { var tid = ajaxify.variables.get('topic_id'); - if (!utils.isNumber(tid) || !utils.isNumber(after) || (after === 0 && $('#post-container .post-row[data-index="1"]').length)) { + if (!utils.isNumber(tid) || !utils.isNumber(after) || (after === 0 && components.get('post', 'index', 1).length)) { return; } @@ -208,7 +235,7 @@ define('forum/topic/posts', [ indicatorEl.fadeOut(); if (data && data.posts && data.posts.length) { - createNewPosts(data, '.post-row[data-index!="0"]:not(.new)', done); + createNewPosts(data, components.get('post').not('[data-index=0]').not('.new'), done); } else { if (app.user.uid) { socket.emit('topics.markAsRead', [tid]); @@ -224,27 +251,27 @@ define('forum/topic/posts', [ app.replaceSelfLinks(element.find('a')); utils.addCommasToNumbers(element.find('.formatted-number')); utils.makeNumbersHumanReadable(element.find('.human-readable-number')); - element.find('span.timeago').timeago(); - element.find('.post-content img:not(.emoji)').addClass('img-responsive').each(function() { + element.find('.timeago').timeago(); + element.find('[component="post/content"] img:not(.emoji)').addClass('img-responsive').each(function() { var $this = $(this); if (!$this.parent().is('a')) { $this.wrap('<a href="' + $this.attr('src') + '" target="_blank">'); } }); postTools.updatePostCount(); - addBlockquoteEllipses(element.find('.post-content > blockquote')); + addBlockquoteEllipses(element.find('[component="post/content"] > blockquote')); hidePostToolsForDeletedPosts(element); showBottomPostBar(); }; function showBottomPostBar() { - if($('#post-container .post-row').length > 1 || !$('#post-container [data-index="0"]').length) { + if(components.get('post').length > 1 || !components.get('post', 'index', 0).length) { $('.bottom-post-bar').removeClass('hide'); } } function hidePostToolsForDeletedPosts(element) { - element.find('.post-row.deleted').each(function() { + element.find('[data-pid].deleted').each(function() { postTools.toggle($(this).attr('data-pid'), true); }); } diff --git a/public/src/client/topic/threadTools.js b/public/src/client/topic/threadTools.js index c3923e2720..fe8bc1fcfb 100644 --- a/public/src/client/topic/threadTools.js +++ b/public/src/client/topic/threadTools.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals define, app, translator, ajaxify, socket, bootbox */ +/* globals define, app, components, translator, ajaxify, socket, bootbox */ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], function(fork, move) { @@ -21,27 +21,27 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], func ThreadTools.setPinnedState({tid: tid, isPinned: true}); } - $('.delete_thread').on('click', function() { + components.get('topic/delete').on('click', function() { topicCommand(threadState.deleted ? 'restore' : 'delete', tid); return false; }); - $('.purge_thread').on('click', function() { + components.get('topic/purge').on('click', function() { topicCommand('purge', tid); return false; }); - $('.lock_thread').on('click', function() { + components.get('topic/lock').on('click', function() { socket.emit(threadState.locked ? 'topics.unlock' : 'topics.lock', {tids: [tid], cid: ajaxify.variables.get('category_id')}); return false; }); - $('.pin_thread').on('click', function() { + components.get('topic/pin').on('click', function() { socket.emit(threadState.pinned ? 'topics.unpin' : 'topics.pin', {tids: [tid], cid: ajaxify.variables.get('category_id')}); return false; }); - $('.markAsUnreadForAll').on('click', function() { + components.get('topic/mark-unread-for-all').on('click', function() { var btn = $(this); socket.emit('topics.markAsUnreadForAll', [tid], function(err) { if(err) { @@ -53,14 +53,17 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], func return false; }); - $('.move_thread').on('click', function(e) { + components.get('topic/move').on('click', function(e) { move.init([tid], ajaxify.variables.get('category_id')); return false; }); fork.init(); - $('.posts').on('click', '.follow', function() { + components.get('topic').on('click', '[component="topic/follow"]', follow); + components.get('topic/follow').off('click').on('click', follow); + + function follow() { socket.emit('topics.toggleFollow', tid, function(err, state) { if(err) { return app.alert({ @@ -83,7 +86,7 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], func }); return false; - }); + } }; function topicCommand(command, tid) { @@ -97,35 +100,36 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], func } ThreadTools.setLockedState = function(data) { - var threadEl = $('#post-container'); + var threadEl = components.get('topic'); if (parseInt(data.tid, 10) === parseInt(threadEl.attr('data-tid'), 10)) { var isLocked = data.isLocked && !app.user.isAdmin; - $('.lock_thread').translateHtml('<i class="fa fa-fw fa-' + (data.isLocked ? 'un': '') + 'lock"></i> [[topic:thread_tools.' + (data.isLocked ? 'un': '') + 'lock]]'); + components.get('topic/lock').translateHtml('<i class="fa fa-fw fa-' + (data.isLocked ? 'un': '') + 'lock"></i> [[topic:thread_tools.' + (data.isLocked ? 'un': '') + 'lock]]'); translator.translate(isLocked ? '[[topic:locked]]' : '[[topic:reply]]', function(translated) { var className = isLocked ? 'fa-lock' : 'fa-reply'; - threadEl.find('.post_reply').html('<i class="fa ' + className + '"></i> ' + translated); - $('.topic-main-buttons .post_reply').attr('disabled', isLocked).html(isLocked ? '<i class="fa fa-lock"></i> ' + translated : translated); + threadEl.find('[component="post/reply"]').html('<i class="fa ' + className + '"></i> ' + translated).attr('disabled', isLocked); + $('[component="topic/reply"]').attr('disabled', isLocked).html(isLocked ? '<i class="fa fa-lock"></i> ' + translated : translated); }); - threadEl.find('.quote, .edit, .delete').toggleClass('hidden', isLocked); - $('.topic-title i.fa-lock').toggleClass('hide', !data.isLocked); + threadEl.find('[component="post/quote"], [component="post/edit"], [component="post/delete"]').toggleClass('hidden', isLocked); + $('[component="post/header"] i.fa-lock').toggleClass('hide', !data.isLocked); ThreadTools.threadState.locked = data.isLocked; } }; ThreadTools.setDeleteState = function(data) { - var threadEl = $('#post-container'); + var threadEl = components.get('topic'); if (parseInt(data.tid, 10) !== parseInt(threadEl.attr('data-tid'), 10)) { return; } - $('.delete_thread span').translateHtml('<i class="fa fa-fw ' + (data.isDelete ? 'fa-history' : 'fa-trash-o') + '"></i> [[topic:thread_tools.' + (data.isDelete ? 'restore' : 'delete') + ']]'); + components.get('topic/delete').translateHtml('<i class="fa fa-fw ' + (data.isDelete ? 'fa-history' : 'fa-trash-o') + '"></i> [[topic:thread_tools.' + (data.isDelete ? 'restore' : 'delete') + ']]'); threadEl.toggleClass('deleted', data.isDelete); ThreadTools.threadState.deleted = data.isDelete; - $('.purge_thread').toggleClass('hidden', !data.isDelete); + + components.get('topic/purge').toggleClass('hidden', !data.isDelete); if (data.isDelete) { translator.translate('[[topic:deleted_message]]', function(translated) { @@ -137,13 +141,13 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], func }; ThreadTools.setPinnedState = function(data) { - var threadEl = $('#post-container'); + var threadEl = components.get('topic'); if (parseInt(data.tid, 10) === parseInt(threadEl.attr('data-tid'), 10)) { translator.translate('<i class="fa fa-fw fa-thumb-tack"></i> [[topic:thread_tools.' + (data.isPinned ? 'unpin' : 'pin') + ']]', function(translated) { - $('.pin_thread').html(translated); + components.get('topic/pin').html(translated); ThreadTools.threadState.pinned = data.isPinned; }); - $('.topic-title i.fa-thumb-tack').toggleClass('hide', !data.isPinned); + $('[component="post/header"] i.fa-thumb-tack').toggleClass('hide', !data.isPinned); } }; @@ -152,7 +156,7 @@ define('forum/topic/threadTools', ['forum/topic/fork', 'forum/topic/move'], func var iconClass = state ? 'fa fa-eye-slash' : 'fa fa-eye'; var text = state ? '[[topic:unwatch]]' : '[[topic:watch]]'; - var followEl = $('.posts .follow'); + var followEl = components.get('topic/follow'); translator.translate(title, function(titleTranslated) { followEl.attr('title', titleTranslated).find('i').attr('class', iconClass); diff --git a/public/src/client/unread.js b/public/src/client/unread.js index 7e08037f5a..c8c1c96de9 100644 --- a/public/src/client/unread.js +++ b/public/src/client/unread.js @@ -42,7 +42,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], app.alertSuccess('[[unread:topics_marked_as_read.success]]'); - $('#topics-container').empty(); + $('[component="category"]').empty(); $('#category-no-topics').removeClass('hidden'); $('.markread').addClass('hidden'); }); @@ -51,7 +51,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], $('.markread').on('click', '.category', function() { function getCategoryTids(cid) { var tids = []; - $('#topics-container .category-item[data-cid="' + cid + '"]').each(function() { + components.get('category/topic', 'cid', cid).each(function() { tids.push($(this).attr('data-tid')); }); return tids; @@ -72,7 +72,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], topicSelect.init(); - if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) { + if ($("body").height() <= $(window).height() && $('[component="category"]').children().length >= 20) { $('#load-more-btn').show(); } @@ -83,16 +83,16 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], infinitescroll.init(loadMoreTopics); function loadMoreTopics(direction) { - if(direction < 0 || !$('#topics-container').length) { + if(direction < 0 || !$('[component="category"]').length) { return; } infinitescroll.loadMore('topics.loadMoreUnreadTopics', { - after: $('#topics-container').attr('data-nextstart') + after: $('[component="category"]').attr('data-nextstart') }, function(data, done) { if (data.topics && data.topics.length) { recent.onTopicsLoaded('unread', data.topics, true, done); - $('#topics-container').attr('data-nextstart', data.nextStart); + $('[component="category"]').attr('data-nextstart', data.nextStart); } else { done(); $('#load-more-btn').hide(); @@ -106,7 +106,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], app.alertSuccess('[[unread:topics_marked_as_read.success]]'); - if (!$('#topics-container').children().length) { + if (!$('[component="category"]').children().length) { $('#category-no-topics').removeClass('hidden'); $('.markread').addClass('hidden'); } @@ -114,7 +114,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], function removeTids(tids) { for(var i=0; i<tids.length; ++i) { - $('#topics-container .category-item[data-tid="' + tids[i] + '"]').remove(); + components.get('category/topic', 'tid', tids[i]).remove(); } } diff --git a/public/src/components.js b/public/src/components.js new file mode 100644 index 0000000000..bef3c95117 --- /dev/null +++ b/public/src/components.js @@ -0,0 +1,47 @@ +"use strict"; + +var components = components || {}; + +(function() { + components.core = { + 'post': function(name, value) { + return $('[data-' + name + '="' + value + '"]'); + }, + 'post/content': function(pid) { + return components.core.post('pid', pid).find('[component="post/content"]'); + }, + 'post/header': function(pid) { + return components.core.post('pid', pid).find('[component="post/header"]'); + }, + 'post/anchor': function(index) { + return components.core.post('index', index).find('[component="post/anchor"]'); + }, + 'post/vote-count': function(pid) { + return components.core.post('pid', pid).find('[component="post/vote-count"]'); + }, + 'post/favourite-count': function(pid) { + return components.core.post('pid', pid).find('[component="post/favourite-count"]'); + }, + + 'user/postcount': function(uid) { + return $('[component="user/postcount"][data-uid="' + uid + '"]'); + }, + 'user/reputation': function(uid) { + return $('[component="user/reputation"][data-uid="' + uid + '"]'); + }, + + 'category/topic': function(name, value) { + return $('[data-' + name + '="' + value + '"]'); + } + }; + + components.get = function() { + var args = Array.prototype.slice.call(arguments, 1); + + if (components.core[arguments[0]] && args.length) { + return components.core[arguments[0]].apply(this, args); + } else { + return $('[component="' + arguments[0] + '"]'); + } + }; +}()); \ No newline at end of file diff --git a/public/src/modules/autocomplete.js b/public/src/modules/autocomplete.js index d8b2311b98..55c15b8686 100644 --- a/public/src/modules/autocomplete.js +++ b/public/src/modules/autocomplete.js @@ -7,7 +7,7 @@ define('autocomplete', function() { var module = {}; module.user = function (input) { - input.autocomplete({ + return input.autocomplete({ delay: 100, source: function(request, response) { socket.emit('user.search', {query: request.term}, function(err, result) { @@ -17,7 +17,15 @@ define('autocomplete', function() { if (result && result.users) { var names = result.users.map(function(user) { - return user && user.username; + return user && { + label: user.username, + value: user.username, + user: { + uid: user.uid, + name: user.username, + slug: user.userslug + } + }; }); response(names); } diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 5d60f2d411..760f19ca20 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -406,7 +406,7 @@ define('chat', ['taskbar', 'string', 'sounds', 'forum/chats'], function(taskbar, Chats.parseMessage(data, function(html) { var message = $(html); message.find('img:not(".chat-user-image")').addClass('img-responsive'); - message.find('span.timeago').timeago(); + message.find('.timeago').timeago(); message.insertBefore(typingNotif); Chats.scrollToBottom(chatContent); diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 71706704cb..9545759395 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -43,6 +43,12 @@ define('composer', [ } }); + $(window).on('action:composer.topics.post', function(ev, data) { + localStorage.removeItem('category:' + data.data.cid + ':bookmark'); + localStorage.removeItem('category:' + data.data.cid + ':bookmark:clicked'); + ajaxify.go('topic/' + data.data.slug); + }); + // Query server for formatting options socket.emit('modules.composer.getFormattingOptions', function(err, options) { composer.formatting = options; @@ -115,8 +121,8 @@ define('composer', [ } } - function composerAlert(message) { - $('[data-action="post"]').removeAttr('disabled'); + function composerAlert(post_uuid, message) { + $('#cmp-uuid-' + post_uuid).find('.composer-submit').removeAttr('disabled'); app.alert({ type: 'danger', timeout: 3000, @@ -131,12 +137,18 @@ define('composer', [ }; composer.newTopic = function(cid) { - push({ - cid: cid, - title: '', - body: '', - modified: false, - isMain: true + socket.emit('categories.isModerator', cid, function(err, isMod) { + if (err) { + return app.alertError(err.message); + } + push({ + cid: cid, + title: '', + body: '', + modified: false, + isMain: true, + isMod: isMod + }); }); }; @@ -166,14 +178,20 @@ define('composer', [ }; composer.newReply = function(tid, pid, title, text) { - translator.translate(text, config.defaultLang, function(translated) { - push({ - tid: tid, - toPid: pid, - title: title, - body: translated, - modified: false, - isMain: false + socket.emit('topics.isModerator', tid, function(err, isMod) { + if (err) { + return app.alertError(err.message); + } + translator.translate(text, config.defaultLang, function(translated) { + push({ + tid: tid, + toPid: pid, + title: title, + body: translated, + modified: false, + isMain: false, + isMod: isMod + }); }); }); }; @@ -247,11 +265,13 @@ define('composer', [ } function createNewComposer(post_uuid) { - var allowTopicsThumbnail = config.allowTopicsThumbnail && composer.posts[post_uuid].isMain && (config.hasImageUploadPlugin || config.allowFileUploads), - isTopic = composer.posts[post_uuid] ? !!composer.posts[post_uuid].cid : false, - isMain = composer.posts[post_uuid] ? !!composer.posts[post_uuid].isMain : false, - isEditing = composer.posts[post_uuid] ? !!composer.posts[post_uuid].pid : false, - isGuestPost = composer.posts[post_uuid] ? parseInt(composer.posts[post_uuid].uid, 10) === 0 : null; + var postData = composer.posts[post_uuid]; + + var allowTopicsThumbnail = config.allowTopicsThumbnail && postData.isMain && (config.hasImageUploadPlugin || config.allowFileUploads), + isTopic = postData ? !!postData.cid : false, + isMain = postData ? !!postData.isMain : false, + isEditing = postData ? !!postData.pid : false, + isGuestPost = postData ? parseInt(postData.uid, 10) === 0 : false; composer.bsEnvironment = utils.findBootstrapEnvironment(); @@ -262,9 +282,11 @@ define('composer', [ minimumTagLength: config.minimumTagLength, maximumTagLength: config.maximumTagLength, isTopic: isTopic, - showHandleInput: (app.user.uid === 0 || (isEditing && isGuestPost && app.user.isAdmin)) && config.allowGuestHandles, - handle: composer.posts[post_uuid] ? composer.posts[post_uuid].handle || '' : undefined, - formatting: composer.formatting + isEditing: isEditing, + showHandleInput: config.allowGuestHandles && (app.user.uid === 0 || (isEditing && isGuestPost && app.user.isAdmin)), + handle: postData ? postData.handle || '' : undefined, + formatting: composer.formatting, + isAdminOrMod: app.user.isAdmin || postData.isMod }; parseAndTranslate('composer', data, function(composerTemplate) { @@ -278,9 +300,9 @@ define('composer', [ $(document.body).append(composerTemplate); var postContainer = $(composerTemplate[0]), - postData = composer.posts[post_uuid], bodyEl = postContainer.find('textarea'), - draft = drafts.getDraft(postData.save_id); + draft = drafts.getDraft(postData.save_id), + submitBtn = postContainer.find('.composer-submit'); tags.init(postContainer, composer.posts[post_uuid]); categoryList.init(postContainer, composer.posts[post_uuid]); @@ -304,12 +326,31 @@ define('composer', [ composer.posts[post_uuid].modified = true; }); - postContainer.on('click', '[data-action="post"]', function() { - $(this).attr('disabled', true); - post(post_uuid); + submitBtn.on('click', function() { + var action = $(this).attr('data-action'); + + switch(action) { + case 'post-lock': + $(this).attr('disabled', true); + post(post_uuid, {lock: true}); + break; + + case 'post': // intentional fall-through + default: + $(this).attr('disabled', true); + post(post_uuid); + break; + } + }); + + postContainer.on('click', 'a[data-switch-action]', function() { + var action = $(this).attr('data-switch-action'), + label = $(this).html(); + + submitBtn.attr('data-action', action).html(label); }); - postContainer.on('click', '[data-action="discard"]', function() { + postContainer.find('.composer-discard').on('click', function() { if (!composer.posts[post_uuid].modified) { discard(post_uuid); return; @@ -438,7 +479,7 @@ define('composer', [ } } - function post(post_uuid) { + function post(post_uuid, options) { var postData = composer.posts[post_uuid], postContainer = $('#cmp-uuid-' + post_uuid), handleEl = postContainer.find('.handle'), @@ -446,6 +487,8 @@ define('composer', [ bodyEl = postContainer.find('textarea'), thumbEl = postContainer.find('input#topic-thumb-url'); + options = options || {}; + titleEl.val(titleEl.val().trim()); bodyEl.val(bodyEl.val().trim()); if (thumbEl.length) { @@ -455,44 +498,43 @@ define('composer', [ var checkTitle = parseInt(postData.cid, 10) || parseInt(postData.pid, 10); if (uploads.inProgress[post_uuid] && uploads.inProgress[post_uuid].length) { - return composerAlert('[[error:still-uploading]]'); + return composerAlert(post_uuid, '[[error:still-uploading]]'); } else if (checkTitle && titleEl.val().length < parseInt(config.minimumTitleLength, 10)) { - return composerAlert('[[error:title-too-short, ' + config.minimumTitleLength + ']]'); + return composerAlert(post_uuid, '[[error:title-too-short, ' + config.minimumTitleLength + ']]'); } else if (checkTitle && titleEl.val().length > parseInt(config.maximumTitleLength, 10)) { - return composerAlert('[[error:title-too-long, ' + config.maximumTitleLength + ']]'); + return composerAlert(post_uuid, '[[error:title-too-long, ' + config.maximumTitleLength + ']]'); } else if (checkTitle && !utils.slugify(titleEl.val()).length) { - return composerAlert('[[error:invalid-title]]'); + return composerAlert(post_uuid, '[[error:invalid-title]]'); } else if (bodyEl.val().length < parseInt(config.minimumPostLength, 10)) { - return composerAlert('[[error:content-too-short, ' + config.minimumPostLength + ']]'); + return composerAlert(post_uuid, '[[error:content-too-short, ' + config.minimumPostLength + ']]'); } else if (bodyEl.val().length > parseInt(config.maximumPostLength, 10)) { - return composerAlert('[[error:content-too-long, ' + config.maximumPostLength + ']]'); + return composerAlert(post_uuid, '[[error:content-too-long, ' + config.maximumPostLength + ']]'); } var composerData = {}, action; if (parseInt(postData.cid, 10) > 0) { + action = 'topics.post'; composerData = { handle: handleEl ? handleEl.val() : undefined, title: titleEl.val(), content: bodyEl.val(), topic_thumb: thumbEl.val() || '', category_id: postData.cid, - tags: tags.getTags(post_uuid) + tags: tags.getTags(post_uuid), + lock: options.lock || false }; - - action = 'topics.post'; - socket.emit(action, composerData, done); } else if (parseInt(postData.tid, 10) > 0) { + action = 'posts.reply'; composerData = { tid: postData.tid, handle: handleEl ? handleEl.val() : undefined, content: bodyEl.val(), - toPid: postData.toPid + toPid: postData.toPid, + lock: options.lock || false }; - - action = 'posts.reply'; - socket.emit(action, composerData, done); } else if (parseInt(postData.pid, 10) > 0) { + action = 'posts.edit'; composerData = { pid: postData.pid, handle: handleEl ? handleEl.val() : undefined, @@ -501,13 +543,10 @@ define('composer', [ topic_thumb: thumbEl.val() || '', tags: tags.getTags(post_uuid) }; - - action = 'posts.edit'; - socket.emit(action, composerData, done); } - function done(err, data) { - $('[data-action="post"]').removeAttr('disabled'); + socket.emit(action, composerData, function (err, data) { + postContainer.find('.composer-submit').removeAttr('disabled'); if (err) { if (err.message === '[[error:email-not-confirmed]]') { return app.showEmailConfirmWarning(err); @@ -520,7 +559,7 @@ define('composer', [ drafts.removeDraft(postData.save_id); $(window).trigger('action:composer.' + action, {composerData: composerData, data: data}); - } + }); } function discard(post_uuid) { diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index 9f643d8736..04937895c5 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -1,6 +1,6 @@ ;(function(exports) { "use strict"; - /* globals define */ + /* globals define, utils */ // export the class if we are in a Node-like system. if (typeof module === 'object' && module.exports === exports) { @@ -43,6 +43,56 @@ return JSON.stringify(obj).replace(/&/gm,"&").replace(/</gm,"<").replace(/>/gm,">").replace(/"/g, '"'); }; + helpers.escape = function(str) { + var utils = utils || require('../utils'); + return utils.escapeHTML(str); + }; + + helpers.stripTags = function(str) { + var S = S || require('string'); + return S(str).stripTags().s; + }; + + helpers.generateCategoryBackground = function(category) { + var style = []; + + if (category.backgroundImage) { + style.push('background-image: url(' + category.backgroundImage + ')'); + } + + if (category.bgColor) { + style.push('background-color: ' + category.bgColor + ';'); + } + + if (category.color) { + style.push('color: ' + category.color + ';'); + } + + return style.join(' '); + }; + + helpers.generateTopicClass = function(topic) { + var style = []; + + if (topic.locked) { + style.push('locked'); + } + + if (topic.pinned) { + style.push('pinned'); + } + + if (topic.deleted) { + style.push('deleted'); + } + + if (topic.unread) { + style.push('unread'); + } + + return style.join(' '); + }; + // Groups helpers helpers.membershipBtn = function(groupObj) { if (groupObj.isMember) { @@ -58,6 +108,21 @@ } }; + helpers.spawnPrivilegeStates = function(member, privileges) { + var states = []; + for(var priv in privileges) { + if (privileges.hasOwnProperty(priv)) { + states.push({ + name: priv, + state: privileges[priv] + }); + } + } + return states.map(function(priv) { + return '<td class="text-center" data-privilege="' + priv.name + '"><input type="checkbox"' + (priv.state ? ' checked' : '') + (member === 'guests' && priv.name === 'groups:moderate' ? ' disabled="disabled"' : '') + ' /></td>'; + }).join(''); + }; + exports.register = function() { var templates; diff --git a/public/src/modules/iconSelect.js b/public/src/modules/iconSelect.js index f21bd76e1f..5dea30c189 100644 --- a/public/src/modules/iconSelect.js +++ b/public/src/modules/iconSelect.js @@ -16,31 +16,41 @@ define('iconSelect', function() { selected = 'fa-doesnt-exist'; } if (selected) { - $('#icons .fa-icons .fa.' + selected).parent().addClass('selected'); + $('#icons .fa-icons .fa.' + selected).addClass('selected'); } - bootbox.confirm('<h2>Select an icon.</h2>' + $('#icons').html(), function(confirm) { - if (confirm) { - var iconClass = $('.bootbox .selected').attr('class'); - var categoryIconClass = $('<div/>').addClass(iconClass).removeClass('fa').removeClass('selected').attr('class'); - if (categoryIconClass === 'fa-doesnt-exist') { - categoryIconClass = ''; - } - - el.attr('class', 'fa ' + (doubleSize ? 'fa-2x ' : '') + categoryIconClass); - el.val(categoryIconClass); - el.attr('value', categoryIconClass); - - onModified(el); - } - }); - - setTimeout(function() { - $('.bootbox .fa-icons i').on('click', function() { - $('.bootbox .selected').removeClass('selected'); - $(this).addClass('selected'); + templates.parse('partials/fontawesome', {}, function(html) { + var picker = bootbox.dialog({ + message: html, + title: 'Select an Icon', + buttons: { + success: { + label: 'Save', + callback: function(confirm) { + var iconClass = $('.bootbox .selected').attr('class'); + var categoryIconClass = $('<div/>').addClass(iconClass).removeClass('fa').removeClass('selected').attr('class'); + if (categoryIconClass === 'fa-doesnt-exist') { + categoryIconClass = ''; + } + + el.attr('class', 'fa ' + (doubleSize ? 'fa-2x ' : '') + categoryIconClass); + el.val(categoryIconClass); + el.attr('value', categoryIconClass); + + onModified(el); + } + } + } + }); + + picker.on('shown.bs.modal', function() { + var modalEl = $(this); + modalEl.find('.icon-container').on('click', 'i', function() { + modalEl.find('.icon-container i').removeClass('selected'); + $(this).addClass('selected'); + }); }); - }, 500); + }); }; return iconSelect; diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index e7f78c980f..f4f4d74a59 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -1,7 +1,7 @@ 'use strict'; -/* globals app, define, ajaxify, utils, translator, config */ +/* globals app, components, define, ajaxify, utils, translator, config */ define('navigator', ['forum/pagination'], function(pagination) { @@ -90,18 +90,26 @@ define('navigator', ['forum/pagination'], function(pagination) { navigator.update = function() { toggle(!!count); - $($(navigator.selector).get().reverse()).each(function() { + var topIndex = 0; + var bottomIndex = 0; + $(navigator.selector).each(function() { var el = $(this); if (elementInView(el)) { - if (typeof navigator.callback === 'function') { - index = navigator.callback(el, count); - navigator.updateTextAndProgressBar(); + if (!topIndex) { + topIndex = parseInt(el.attr('data-index'), 10) + 1; + } else { + bottomIndex = parseInt(el.attr('data-index'), 10) + 1; } - + } else if (topIndex && bottomIndex) { return false; } }); + + if (typeof navigator.callback === 'function' && topIndex && bottomIndex) { + index = navigator.callback(topIndex, bottomIndex, count); + navigator.updateTextAndProgressBar(); + } }; navigator.updateTextAndProgressBar = function() { @@ -153,7 +161,7 @@ define('navigator', ['forum/pagination'], function(pagination) { } navigator.scrollToPost = function(postIndex, highlight, duration, offset) { - if (!utils.isNumber(postIndex) || !$('#post-container').length) { + if (!utils.isNumber(postIndex) || !components.get('topic').length) { return; } @@ -161,7 +169,7 @@ define('navigator', ['forum/pagination'], function(pagination) { duration = duration !== undefined ? duration : 400; navigator.scrollActive = true; - if($('#post_anchor_' + postIndex).length) { + if(components.get('post/anchor', postIndex).length) { return scrollToPid(postIndex, highlight, duration, offset); } @@ -188,7 +196,7 @@ define('navigator', ['forum/pagination'], function(pagination) { }; function scrollToPid(postIndex, highlight, duration, offset) { - var scrollTo = $('#post_anchor_' + postIndex); + var scrollTo = components.get('post/anchor', postIndex); if (!scrollTo) { navigator.scrollActive = false; @@ -215,14 +223,14 @@ define('navigator', ['forum/pagination'], function(pagination) { function highlightPost() { if (highlight) { - scrollTo.parent().find('.topic-item').addClass('highlight'); + scrollTo.parents('[component="post"]').addClass('highlight'); setTimeout(function() { - scrollTo.parent().find('.topic-item').removeClass('highlight'); + scrollTo.parents('[component="post"]').removeClass('highlight'); }, 3000); } } - if ($('#post-container').length) { + if (components.get('topic').length) { animateScroll(); } } diff --git a/public/src/modules/notifications.js b/public/src/modules/notifications.js index 52e4c42c8c..43ba05ed1b 100644 --- a/public/src/modules/notifications.js +++ b/public/src/modules/notifications.js @@ -48,7 +48,7 @@ define('notifications', ['sounds'], function(sound) { }); }); - notifList.on('click', '.mark-all-read', function() { + notifContainer.on('click', '.mark-all-read', function() { socket.emit('notifications.markAllRead', function(err) { if (err) { app.alertError(err.message); diff --git a/public/src/modules/share.js b/public/src/modules/share.js index 3f26ebb9f8..6665a30b8c 100644 --- a/public/src/modules/share.js +++ b/public/src/modules/share.js @@ -50,7 +50,7 @@ define('share', function() { function getPostUrl(clickedElement) { var parts = window.location.pathname.split('/'); - var postIndex = parseInt(clickedElement.parents('.post-row').attr('data-index'), 10); + var postIndex = parseInt(clickedElement.parents('[data-index]').attr('data-index'), 10); return '/' + parts[1] + '/' + parts[2] + (parts[3] ? '/' + parts[3] : '') + (postIndex ? '/' + (postIndex + 1) : ''); } diff --git a/public/src/modules/topicSelect.js b/public/src/modules/topicSelect.js index 75f32f80be..3e3ae58d46 100644 --- a/public/src/modules/topicSelect.js +++ b/public/src/modules/topicSelect.js @@ -9,7 +9,7 @@ define('topicSelect', function() { var topicsContainer; TopicSelect.init = function(onSelect) { - topicsContainer = $('#topics-container'); + topicsContainer = $('[component="category"]'); topicsContainer.on('selectstart', function() { return false; }); @@ -18,7 +18,7 @@ define('topicSelect', function() { var select = $(this); if (ev.shiftKey) { - selectRange($(this).parents('.category-item').attr('data-tid')); + selectRange($(this).parents('[component="category/topic"]').attr('data-tid')); lastSelected = select; return false; } @@ -35,32 +35,32 @@ define('topicSelect', function() { function toggleSelect(select, isSelected) { select.toggleClass('fa-check-square-o', isSelected); select.toggleClass('fa-square-o', !isSelected); - select.parents('.category-item').toggleClass('selected', isSelected); + select.parents('[component="category/topic"]').toggleClass('selected', isSelected); } TopicSelect.getSelectedTids = function() { var tids = []; - topicsContainer.find('.category-item.selected').each(function() { + topicsContainer.find('[component="category/topic"].selected').each(function() { tids.push($(this).attr('data-tid')); }); return tids; }; TopicSelect.unselectAll = function() { - topicsContainer.find('.category-item.selected').removeClass('selected'); + topicsContainer.find('[component="category/topic"].selected').removeClass('selected'); topicsContainer.find('.select').toggleClass('fa-check-square-o', false).toggleClass('fa-square-o', true); }; function selectRange(clickedTid) { if(!lastSelected) { - lastSelected = $('.category-item[data-tid]').first().find('.select'); + lastSelected = $('[component="category/topic"]').first().find('.select'); } - var isClickedSelected = $('.category-item[data-tid="' + clickedTid + '"]').hasClass('selected'); + var isClickedSelected = components.get('category/topic', 'tid', clickedTid).hasClass('selected'); var clickedIndex = getIndex(clickedTid); - var lastIndex = getIndex(lastSelected.parents('.category-item[data-tid]').attr('data-tid')); + var lastIndex = getIndex(lastSelected.parents('[component="category/topic"]').attr('data-tid')); selectIndexRange(clickedIndex, lastIndex, !isClickedSelected); } @@ -72,13 +72,13 @@ define('topicSelect', function() { } for(var i=start; i<=end; ++i) { - var topic = $('.category-item[data-tid]').eq(i); + var topic = $('[component="category/topic"]').eq(i); toggleSelect(topic.find('.select'), isSelected); } } function getIndex(tid) { - return $('.category-item[data-tid="' + tid + '"]').index('#topics-container .category-item'); + return components.get('category/topic', 'tid', tid).index('[component="category/topic"]'); } return TopicSelect; diff --git a/public/src/translator.js b/public/src/translator.js index a6f4027faf..d1b85e300c 100644 --- a/public/src/translator.js +++ b/public/src/translator.js @@ -79,7 +79,7 @@ } $.getScript(RELATIVE_PATH + '/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '.js').success(function() { - $('span.timeago').timeago(); + $('.timeago').timeago(); }).fail(function() { $.getScript(RELATIVE_PATH + '/vendor/jquery/timeago/locales/jquery.timeago.en.js'); }); diff --git a/public/src/utils.js b/public/src/utils.js index 0c58817411..930e03501f 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -367,6 +367,20 @@ }; } + if (typeof String.prototype.endsWith != 'function') { + String.prototype.endsWith = function(suffix) { + if (this.length < suffix.length) { + return false; + } + var len = this.length; + var suffixLen = suffix.length; + for (var i=1; (i <= suffixLen && this[len - i] === suffix[suffixLen - i]); ++i) { + continue; + } + return i > suffixLen; + }; + } + if ('undefined' !== typeof window) { window.utils = module.exports; } diff --git a/public/src/widgets.js b/public/src/widgets.js index 990a42c6f0..e83353ec1b 100644 --- a/public/src/widgets.js +++ b/public/src/widgets.js @@ -71,7 +71,7 @@ var widgetAreas = $('#content [widget-area]'); widgetAreas.find('img:not(.user-img)').addClass('img-responsive'); - widgetAreas.find('span.timeago').timeago(); + widgetAreas.find('.timeago').timeago(); widgetAreas.find('img[title].teaser-pic,img[title].user-img').each(function() { $(this).tooltip({ placement: 'top', diff --git a/src/categories.js b/src/categories.js index 87c540aaf1..3061ef8425 100644 --- a/src/categories.js +++ b/src/categories.js @@ -62,7 +62,6 @@ var async = require('async'), category.nextStart = results.topics.nextStart; category.pageCount = results.pageCount; category.isIgnored = results.isIgnored[0]; - category.topic_row_size = 'col-md-9'; plugins.fireHook('filter:category.get', {category: category, uid: data.uid}, function(err, data) { callback(err, data ? data.category : null); diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index 596bd6882e..bd6871ce99 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -61,7 +61,8 @@ module.exports = function(Categories) { function assignPostsToCategory(category, posts) { category.posts = posts.filter(function(post) { - return post.category && parseInt(post.category.cid, 10) === parseInt(category.cid, 10); + return post.category && (parseInt(post.category.cid, 10) === parseInt(category.cid, 10) + || parseInt(post.category.parentCid, 10) === parseInt(category.cid, 10)); }).sort(function(a, b) { return b.timestamp - a.timestamp; }).slice(0, parseInt(category.numRecentReplies, 10)); diff --git a/src/categories/topics.js b/src/categories/topics.js index 50dba67bbd..805ab30c4a 100644 --- a/src/categories/topics.js +++ b/src/categories/topics.js @@ -74,37 +74,29 @@ module.exports = function(Categories) { }); }; - Categories.onNewPostMade = function(postData, callback) { - topics.getTopicFields(postData.tid, ['cid', 'pinned'], function(err, topicData) { - if (err) { - return callback(err); - } - - if (!topicData || !topicData.cid) { - return callback(); - } - - var cid = topicData.cid; + Categories.onNewPostMade = function(cid, pinned, postData, callback) { + if (!cid || !postData) { + return callback(); + } - async.parallel([ - function(next) { - db.sortedSetAdd('cid:' + cid + ':pids', postData.timestamp, postData.pid, next); - }, - function(next) { - db.incrObjectField('category:' + cid, 'post_count', next); - }, - function(next) { - if (parseInt(topicData.pinned, 10) === 1) { - next(); - } else { - db.sortedSetAdd('cid:' + cid + ':tids', postData.timestamp, postData.tid, next); - } - }, - function(next) { - db.sortedSetIncrBy('cid:' + cid + ':tids:posts', 1, postData.tid, next); + async.parallel([ + function(next) { + db.sortedSetAdd('cid:' + cid + ':pids', postData.timestamp, postData.pid, next); + }, + function(next) { + db.incrObjectField('category:' + cid, 'post_count', next); + }, + function(next) { + if (parseInt(pinned, 10) === 1) { + next(); + } else { + db.sortedSetAdd('cid:' + cid + ':tids', postData.timestamp, postData.tid, next); } - ], callback); - }); + }, + function(next) { + db.sortedSetIncrBy('cid:' + cid + ':tids:posts', 1, postData.tid, next); + } + ], callback); }; }; diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 8b966fbd26..51cc3daf82 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -356,7 +356,7 @@ accountsController.accountSettings = function(req, res, next) { }, userGroups: function(next) { groups.getUserGroups([userData.uid], next); - }, + }, languages: function(next) { languages.list(next); } @@ -434,7 +434,7 @@ accountsController.uploadPicture = function (req, res, next) { user.setUserFields(updateUid, {uploadedpicture: image.url, picture: image.url}); - res.json([{name: userPhoto.name, url: nconf.get('relative_path') + image.url}]); + res.json([{name: userPhoto.name, url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url}]); } if (err) { diff --git a/src/controllers/admin.js b/src/controllers/admin.js index e0912a668c..24332866f9 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -6,6 +6,7 @@ var async = require('async'), user = require('../user'), categories = require('../categories'), + privileges = require('../privileges'), posts = require('../posts'), topics = require('../topics'), meta = require('../meta'), @@ -126,33 +127,42 @@ function getGlobalField(field, callback) { }); } -adminController.categories.active = function(req, res, next) { - filterAndRenderCategories(req, res, next, true); -}; +adminController.categories.get = function(req, res, next) { + async.parallel({ + category: async.apply(categories.getCategories, [req.params.category_id], req.user.uid), + privileges: async.apply(privileges.categories.list, req.params.category_id) + }, function(err, data) { + if (err) { + return next(err); + } -adminController.categories.disabled = function(req, res, next) { - filterAndRenderCategories(req, res, next, false); + res.render('admin/manage/category', { + category: data.category[0], + privileges: data.privileges + }); + }); }; -function filterAndRenderCategories(req, res, next, active) { - var uid = req.user ? parseInt(req.user.uid, 10) : 0; +adminController.categories.getAll = function(req, res, next) { + var uid = req.user ? parseInt(req.user.uid, 10) : 0, + active = [], + disabled = []; + categories.getAllCategories(uid, function (err, categoryData) { if (err) { return next(err); } - categoryData = categoryData.filter(function (category) { - if (!category) { - return false; - } - return active ? !category.disabled : category.disabled; + categoryData.filter(Boolean).forEach(function(category) { + (category.disabled ? disabled : active).push(category); }); res.render('admin/manage/categories', { - categories: categoryData + active: active, + disabled: disabled }); }); -} +}; adminController.tags.get = function(req, res, next) { topics.getTags(0, 199, function(err, tags) { diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 18bbd57f8b..8896894680 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -4,6 +4,8 @@ var categoriesController = {}, async = require('async'), nconf = require('nconf'), validator = require('validator'), + + db = require('../database'), privileges = require('../privileges'), user = require('../user'), categories = require('../categories'), @@ -249,6 +251,11 @@ categoriesController.get = function(req, res, next) { categories.getCategoryById(payload, next); }, function(categoryData, next) { + if (categoryData.link) { + db.incrObjectField('category:' + categoryData.cid, 'timesClicked'); + return res.redirect(categoryData.link); + } + var breadcrumbs = [ { text: categoryData.name, @@ -264,16 +271,13 @@ categoriesController.get = function(req, res, next) { }); }, function(categoryData, next) { - if (categoryData.link) { - return res.redirect(categoryData.link); - } - categories.getRecentTopicReplies(categoryData.children, uid, function(err) { next(err, categoryData); }); }, function (categoryData, next) { categoryData.privileges = userPrivileges; + categoryData.showSelect = categoryData.privileges.editable; res.locals.metaTags = [ { diff --git a/src/controllers/index.js b/src/controllers/index.js index 6aba26bb1f..74cce358e5 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -26,7 +26,7 @@ var Controllers = { accounts: require('./accounts'), static: require('./static'), api: require('./api'), - admin: require('./admin'), + admin: require('./admin') }; @@ -52,15 +52,18 @@ Controllers.home = function(req, res, next) { Controllers.reset = function(req, res, next) { if (req.params.code) { user.reset.validate(req.params.code, function(err, valid) { + if (err) { + return next(err); + } res.render('reset_code', { valid: valid, - reset_code: req.params.code ? req.params.code : null, + code: req.params.code ? req.params.code : null, breadcrumbs: helpers.buildBreadcrumbs([{text: '[[reset_password:reset_password]]', url: '/reset'}, {text: '[[reset_password:update_password]]'}]) }); }); } else { res.render('reset', { - reset_code: req.params.code ? req.params.code : null, + code: req.params.code ? req.params.code : null, breadcrumbs: helpers.buildBreadcrumbs([{text: '[[reset_password:reset_password]]'}]) }); } diff --git a/src/controllers/search.js b/src/controllers/search.js index 7ed16d8bb8..7c1d20262b 100644 --- a/src/controllers/search.js +++ b/src/controllers/search.js @@ -23,26 +23,6 @@ searchController.search = function(req, res, next) { return next(err); } - if (!req.params.term) { - var results = { - time: 0, - search_query: '', - posts: [], - users: [], - tags: [], - categories: categories, - breadcrumbs: breadcrumbs, - expandSearch: true - }; - plugins.fireHook('filter:search.build', {data: {}, results: results}, function(err, data) { - if (err) { - return next(err); - } - res.render('search', data.results); - }); - return; - } - req.params.term = validator.escape(req.params.term); var page = Math.max(1, parseInt(req.query.page, 10)) || 1; if (req.query.categories && !Array.isArray(req.query.categories)) { @@ -76,8 +56,8 @@ searchController.search = function(req, res, next) { results.showAsTopics = req.query.showAs === 'topics'; results.breadcrumbs = breadcrumbs; results.categories = categories; - results.expandSearch = false; - + results.expandSearch = !req.params.term; + plugins.fireHook('filter:search.build', {data: data, results: results}, function(err, data) { if (err) { return next(err); diff --git a/src/database/mongo.js b/src/database/mongo.js index 0e69c12380..e420f003b9 100644 --- a/src/database/mongo.js +++ b/src/database/mongo.js @@ -45,7 +45,7 @@ mongoClient = require('mongodb').MongoClient; if (!nconf.get('redis')) { - sessionStore = require('connect-mongo')({session: session}); + sessionStore = require('connect-mongo')(session); } else { sessionStore = require('connect-redis')(session); } @@ -59,6 +59,17 @@ usernamePassword = nconf.get('mongo:username') + ':' + nconf.get('mongo:password') + '@'; } + // Sensible defaults for Mongo, if not set + if (!nconf.get('mongo:host')) { + nconf.set('mongo:host', '127.0.0.1'); + } + if (!nconf.get('mongo:port')) { + nconf.set('mongo:port', 27017); + } + if (!nconf.get('mongo:database')) { + nconf.set('mongo:database', '0'); + } + var connString = 'mongodb://' + usernamePassword + nconf.get('mongo:host') + ':' + nconf.get('mongo:port') + '/' + nconf.get('mongo:database'); var connOptions = { server: { @@ -74,8 +85,10 @@ db = _db; module.client = db; - + if (!nconf.get('redis')) { + // TEMP: to fix connect-mongo, see https://github.com/kcbanner/connect-mongo/issues/161 + db.openCalled = true module.sessionStore = new sessionStore({ db: db }); @@ -110,8 +123,14 @@ createIndex('objects', {_key: 1, value: -1}, {background:true}); createIndex('objects', {expireAt: 1}, {expireAfterSeconds:0, background:true}); - createIndex('search', {content:'text'}, {background:true}); - createIndex('search', {key: 1, id: 1}, {background:true}); + + createIndex('searchtopic', {content: 'text', uid: 1, cid: 1}, {background:true}); + createIndex('searchtopic', {id: 1}, {background:true}); + + + createIndex('searchpost', {content: 'text', uid: 1, cid: 1}, {background:true}); + createIndex('searchpost', {id: 1}, {background:true}); + if (typeof callback === 'function') { callback(); diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index da1d2483d9..65157d8cb9 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -242,7 +242,7 @@ module.exports = function(db, module) { data[field] = value; db.collection('objects').findAndModify({_key: key}, {}, {$inc: data}, {new: true, upsert: true}, function(err, result) { - callback(err, result ? result[field] : null); + callback(err, result && result.value ? result.value[field] : null); }); }; }; \ No newline at end of file diff --git a/src/database/mongo/main.js b/src/database/mongo/main.js index 029b8f1fee..eba0b3b14b 100644 --- a/src/database/mongo/main.js +++ b/src/database/mongo/main.js @@ -5,15 +5,18 @@ var winston = require('winston'); module.exports = function(db, module) { var helpers = module.helpers.mongo; - module.searchIndex = function(key, content, id, callback) { + module.searchIndex = function(key, data, id, callback) { callback = callback || function() {}; - var data = { - id: id, - key: key, - content: content + var setData = { + id: id }; + for(var field in data) { + if (data.hasOwnProperty(field) && data[field]) { + setData[field] = data[field].toString(); + } + } - db.collection('search').update({key:key, id:id}, {$set:data}, {upsert:true, w: 1}, function(err) { + db.collection('search' + key).update({id: id}, {$set: setData}, {upsert:true, w: 1}, function(err) { if(err) { winston.error('Error indexing ' + err.message); } @@ -21,13 +24,35 @@ module.exports = function(db, module) { }); }; - module.search = function(key, term, limit, callback) { - db.collection('search').find({ $text: { $search: term }, key: key}, {limit: limit}).toArray(function(err, results) { - if(err) { + module.search = function(key, data, limit, callback) { + var searchQuery = {}; + + if (data.content) { + searchQuery.$text = {$search: data.content}; + } + + if (Array.isArray(data.cid) && data.cid.length) { + if (data.cid.length > 1) { + searchQuery.cid = {$in: data.cid.map(String)}; + } else { + searchQuery.cid = data.cid[0].toString(); + } + } + + if (Array.isArray(data.uid) && data.uid.length) { + if (data.uid.length > 1) { + searchQuery.uid = {$in: data.uid.map(String)}; + } else { + searchQuery.uid = data.uid[0].toString(); + } + } + + db.collection('search' + key).find(searchQuery, {limit: limit}).toArray(function(err, results) { + if (err) { return callback(err); } - if(!results || !results.length) { + if (!results || !results.length) { return callback(null, []); } @@ -44,7 +69,9 @@ module.exports = function(db, module) { if (!id) { return callback(); } - db.collection('search').remove({key: key, id: id}, callback); + db.collection('search' + key).remove({id: id}, function(err, res) { + callback(err); + }); }; module.flushdb = function(callback) { @@ -121,7 +148,7 @@ module.exports = function(db, module) { return callback(); } db.collection('objects').findAndModify({_key: key}, {}, {$inc: {value: 1}}, {new: true, upsert: true}, function(err, result) { - callback(err, result ? result.value : null); + callback(err, result && result.value ? result.value.value : null); }); }; diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 5b06e22cfb..a056de991f 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -502,7 +502,7 @@ module.exports = function(db, module) { data.score = parseInt(increment, 10); db.collection('objects').findAndModify({_key: key, value: value}, {}, {$inc: data}, {new: true, upsert: true}, function(err, result) { - callback(err, result ? result.score : null); + callback(err, result && result.value ? result.value.score : null); }); }; }; \ No newline at end of file diff --git a/src/database/redis.js b/src/database/redis.js index 727705c130..716a8fd715 100644 --- a/src/database/redis.js +++ b/src/database/redis.js @@ -9,7 +9,7 @@ utils = require('./../../public/src/utils.js'), redis, connectRedis, - reds, + redisSearch, redisClient, postSearch, topicSearch; @@ -41,7 +41,7 @@ try { redis = require('redis'); connectRedis = require('connect-redis')(session); - reds = require('reds'); + redisSearch = require('redisearch'); } catch (err) { winston.error('Unable to initialize Redis! Is Redis installed? Error :' + err.message); process.exit(); @@ -56,12 +56,8 @@ ttl: 60 * 60 * 24 * 14 }); - reds.createClient = function () { - return reds.client || (reds.client = redisClient); - }; - - module.postSearch = reds.createSearch('nodebbpostsearch'); - module.topicSearch = reds.createSearch('nodebbtopicsearch'); + module.postSearch = redisSearch.createSearch('nodebbpostsearch', redisClient); + module.topicSearch = redisSearch.createSearch('nodebbtopicsearch', redisClient); require('./redis/main')(redisClient, module); require('./redis/hash')(redisClient, module); diff --git a/src/database/redis/main.js b/src/database/redis/main.js index 094fa3b695..b09574e10f 100644 --- a/src/database/redis/main.js +++ b/src/database/redis/main.js @@ -1,28 +1,18 @@ "use strict"; module.exports = function(redisClient, module) { - module.searchIndex = function(key, content, id, callback) { - if (key === 'post') { - module.postSearch.index(content, id, callback); - } else if(key === 'topic') { - module.topicSearch.index(content, id, callback); - } + module.searchIndex = function(key, data, id, callback) { + var method = key === 'post' ? module.postSearch : module.topicSearch; + + method.index(data, id, function(err, res) { + callback(err); + }); }; - module.search = function(key, term, limit, callback) { - function search(searchObj, callback) { - searchObj - .query(term) - .between(0, limit - 1) - .type('or') - .end(callback); - } + module.search = function(key, data, limit, callback) { + var method = key === 'post' ? module.postSearch : module.topicSearch; - if(key === 'post') { - search(module.postSearch, callback); - } else if(key === 'topic') { - search(module.topicSearch, callback); - } + method.query(data, 0, limit - 1, callback); }; module.searchRemove = function(key, id, callback) { @@ -30,12 +20,11 @@ module.exports = function(redisClient, module) { if (!id) { return callback(); } + var method = key === 'post' ? module.postSearch : module.topicSearch; - if (key === 'post') { - module.postSearch.remove(id, callback); - } else if(key === 'topic') { - module.topicSearch.remove(id, callback); - } + method.remove(id, function(err, res) { + callback(err); + }); }; module.flushdb = function(callback) { diff --git a/src/emailer.js b/src/emailer.js index b358e170fb..aeca1ecab8 100644 --- a/src/emailer.js +++ b/src/emailer.js @@ -62,7 +62,8 @@ var fs = require('fs'), plaintext: translated[1], template: template, uid: uid, - pid: params.pid + pid: params.pid, + fromUid: params.fromUid }); callback(); } else { diff --git a/src/favourites.js b/src/favourites.js index 0c9c81dc46..e38e11298e 100644 --- a/src/favourites.js +++ b/src/favourites.js @@ -10,6 +10,8 @@ var async = require('async'), (function (Favourites) { + var votesInProgress = {}; + function vote(type, unvote, pid, uid, callback) { uid = parseInt(uid, 10); @@ -41,7 +43,9 @@ var async = require('async'), return callback(err); } - db.sortedSetAdd('users:reputation', newreputation, postData.uid); + if (parseInt(postData.uid, 10)) { + db.sortedSetAdd('users:reputation', newreputation, postData.uid); + } adjustPostVotes(pid, uid, type, unvote, function(err, votes) { postData.votes = votes; @@ -127,13 +131,41 @@ var async = require('async'), }); }; + function voteInProgress(pid, uid) { + return Array.isArray(votesInProgress[uid]) && votesInProgress[uid].indexOf(parseInt(pid, 10)) !== -1; + } + + function putVoteInProgress(pid, uid) { + votesInProgress[uid] = votesInProgress[uid] || []; + votesInProgress[uid].push(parseInt(pid, 10)); + } + + function clearVoteProgress(pid, uid) { + if (Array.isArray(votesInProgress[uid])) { + var index = votesInProgress[uid].indexOf(parseInt(pid, 10)); + if (index !== -1) { + votesInProgress[uid].splice(index, 1); + } + } + } + function toggleVote(type, pid, uid, callback) { + function done(err, data) { + clearVoteProgress(pid, uid); + callback(err, data); + } + + if (voteInProgress(pid, uid)) { + return callback(new Error('[[error:already-voting-for-this-post]]')); + } + putVoteInProgress(pid, uid); + unvote(pid, uid, type, function(err) { if (err) { - return callback(err); + return done(err); } - vote(type, false, pid, uid, callback); + vote(type, false, pid, uid, done); }); } diff --git a/src/file.js b/src/file.js index 543c5011fa..6be1cd37c8 100644 --- a/src/file.js +++ b/src/file.js @@ -8,11 +8,20 @@ var fs = require('fs'), Magic = mmmagic.Magic, mime = require('mime'), - meta= require('./meta'); + meta = require('./meta'), + utils = require('../public/src/utils'); var file = {}; file.saveFileToLocal = function(filename, folder, tempPath, callback) { + /* + * remarkable doesn't allow spaces in hyperlinks, once that's fixed, remove this. + */ + filename = filename.split('.'); + filename.forEach(function(name, idx) { + filename[idx] = utils.slugify(name); + }); + filename = filename.join('.'); var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), folder, filename); diff --git a/src/groups.js b/src/groups.js index 25c8ff1bdc..c2257c9935 100644 --- a/src/groups.js +++ b/src/groups.js @@ -47,6 +47,7 @@ var async = require('async'), getEphemeralGroup: function(groupName) { return { name: groupName, + slug: utils.slugify(groupName), description: '', deleted: '0', hidden: '0', @@ -66,6 +67,10 @@ var async = require('async'), isPrivilegeGroup: /^cid:\d+:privileges:[\w:]+$/ }; + Groups.getEphemeralGroups = function() { + return ephemeralGroups; + }; + Groups.list = function(options, callback) { db.getSortedSetRevRange('groups:createtime', 0, -1, function (err, groupNames) { if (err) { @@ -121,7 +126,7 @@ var async = require('async'), if (options.expand) { async.waterfall([ - async.apply(async.map, uids, user.getUserData), + async.apply(user.getUsers, uids, options.uid || 0), function(users, next) { // Filter out non-matches users = users.filter(Boolean); @@ -226,9 +231,9 @@ var async = require('async'), return callback(err); } results.base.name = !options.unescape ? validator.escape(results.base.name) : results.base.name; - results.base.description = options.unescape ? validator.escape(results.base.description) : results.base.description; + results.base.description = !options.unescape ? validator.escape(results.base.description) : results.base.description; results.base.descriptionParsed = descriptionParsed; - results.base.userTitle = options.unescape ? validator.escape(results.base.userTitle) : results.base.userTitle; + results.base.userTitle = !options.unescape ? validator.escape(results.base.userTitle) : results.base.userTitle; results.base.userTitleEnabled = results.base.userTitleEnabled ? !!parseInt(results.base.userTitleEnabled, 10) : true; results.base.createtimeISO = utils.toISOString(results.base.createtime); results.base.members = results.users.filter(Boolean); @@ -271,7 +276,15 @@ var async = require('async'), }; Groups.getGroupFields = function(groupName, fields, callback) { - db.getObjectFields('group:' + groupName, fields, callback); + Groups.getMultipleGroupFields([groupName], fields, function(err, groups) { + callback(err, groups ? groups[0] : null); + }); + }; + + Groups.getMultipleGroupFields = function(groups, fields, callback) { + db.getObjectsFields(groups.map(function(group) { + return 'group:' + group; + }), fields, callback); }; Groups.setGroupField = function(groupName, field, value, callback) { @@ -306,6 +319,12 @@ var async = require('async'), db.getSortedSetRevRange('group:' + groupName + ':members', start, end, callback); }; + Groups.getMembersOfGroups = function(groupNames, callback) { + db.getSortedSetsMembers(groupNames.map(function(name) { + return 'group:' + name + ':members'; + }), callback); + }; + Groups.isMember = function(uid, groupName, callback) { if (!uid || parseInt(uid, 10) <= 0) { return callback(null, false); @@ -440,7 +459,6 @@ var async = require('async'), return ephemeralGroups.indexOf(slug) !== -1; })); }, - async.apply(db.isObjectFields, 'groupslug:groupname', slugs), async.apply(db.isSortedSetMembers, 'groups:createtime', name) ], function(err, results) { if (err) { @@ -448,7 +466,7 @@ var async = require('async'), } callback(null, results.map(function(result) { - return result[0] || result[1] || result[2]; + return result[0] || result[1]; })); }); } else { @@ -457,16 +475,19 @@ var async = require('async'), function(next) { next(null, ephemeralGroups.indexOf(slug) !== -1); }, - async.apply(db.isObjectField, 'groupslug:groupname', slug), async.apply(db.isSortedSetMember, 'groups:createtime', name) ], function(err, results) { - callback(err, !err ? (results[0] || results[1] || results[2]) : null); + callback(err, !err ? (results[0] || results[1]) : null); }); } }; Groups.existsBySlug = function(slug, callback) { - db.isObjectField('groupslug:groupname', slug, callback); + if (Array.isArray(slug)) { + db.isObjectFields('groupslug:groupName', slug, callback); + } else { + db.isObjectField('groupslug:groupname', slug, callback); + } }; Groups.create = function(data, callback) { @@ -499,7 +520,7 @@ var async = require('async'), deleted: '0', hidden: data.hidden || '0', system: system ? '1' : '0', - 'private': data.private || '1' + private: data.private || '1' }, tasks = [ async.apply(db.sortedSetAdd, 'groups:createtime', now, data.name), @@ -538,14 +559,26 @@ var async = require('async'), } var payload = { - userTitle: values.userTitle || '', - userTitleEnabled: values.userTitleEnabled === true ? '1' : '0', - description: values.description || '', - icon: values.icon || '', - labelColor: values.labelColor || '#000000', - hidden: values.hidden === true ? '1' : '0', - 'private': values.private === false ? '0' : '1' - }; + description: values.description || '', + icon: values.icon || '', + labelColor: values.labelColor || '#000000' + }; + + if (values.hasOwnProperty('userTitle')) { + payload.userTitle = values.userTitle || ''; + } + + if (values.hasOwnProperty('userTitleEnabled')) { + payload.userTitleEnabled = values.userTitleEnabled ? '1' : '0'; + } + + if (values.hasOwnProperty('hidden')) { + payload.hidden = values.hidden ? '1' : '0'; + } + + if (values.hasOwnProperty('private')) { + payload.private = values.private ? '1' : '0'; + } async.series([ async.apply(updatePrivacy, groupName, values.private), @@ -566,9 +599,15 @@ var async = require('async'), }; function updatePrivacy(groupName, newValue, callback) { - // Grab the group's current privacy value + if (!newValue) { + return callback(); + } + Groups.getGroupFields(groupName, ['private'], function(err, currentValue) { - currentValue = currentValue.private === '1'; // Now a Boolean + if (err) { + return callback(err); + } + currentValue = currentValue.private === '1'; if (currentValue !== newValue && currentValue === true) { // Group is now public, so all pending users are automatically considered members diff --git a/src/install.js b/src/install.js index b696c5cdf8..be1c322267 100644 --- a/src/install.js +++ b/src/install.js @@ -13,7 +13,7 @@ var async = require('async'), "dependencies": ["redis@~0.10.1", "connect-redis@~2.0.0"] }, "mongo": { - "dependencies": ["mongodb", "connect-mongo"] + "dependencies": ["mongodb@~2.0.0", "connect-mongo"] } }; @@ -234,13 +234,13 @@ function setupDefaultConfigs(next) { }); if (install.values) { - setOnEmpty('social:twitter:key', 'social:twitter:secret'); - setOnEmpty('social:google:id', 'social:google:secret'); - setOnEmpty('social:facebook:app_id', 'social:facebook:secret'); + setIfPaired('social:twitter:key', 'social:twitter:secret'); + setIfPaired('social:google:id', 'social:google:secret'); + setIfPaired('social:facebook:app_id', 'social:facebook:secret'); } } -function setOnEmpty(key1, key2) { +function setIfPaired(key1, key2) { var meta = require('./meta'); if (install.values[key1] && install.values[key2]) { meta.configs.setOnEmpty(key1, install.values[key1]); @@ -468,8 +468,8 @@ install.setup = function (callback) { setupConfig, setupDefaultConfigs, enableDefaultTheme, - createAdministrator, createCategories, + createAdministrator, createMenuItems, createWelcomePost, enableDefaultPlugins, @@ -479,7 +479,7 @@ install.setup = function (callback) { } ], function (err) { if (err) { - winston.warn('NodeBB Setup Aborted. ' + err.message); + winston.warn('NodeBB Setup Aborted.\n ' + err.stack); process.exit(); } else { callback(); diff --git a/src/meta.js b/src/meta.js index b58ac1a9b2..4aa65f6719 100644 --- a/src/meta.js +++ b/src/meta.js @@ -29,7 +29,7 @@ var async = require('async'), Meta.userOrGroupExists = function(slug, callback) { async.parallel([ async.apply(user.exists, slug), - async.apply(groups.exists, slug) + async.apply(groups.existsBySlug, slug) ], function(err, results) { callback(err, results ? results.some(function(result) { return result; }) : false); }); diff --git a/src/meta/css.js b/src/meta/css.js index d45b61f280..50369f89fb 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -10,7 +10,8 @@ var winston = require('winston'), plugins = require('../plugins'), emitter = require('../emitter'), - db = require('../database'); + db = require('../database'), + utils = require('../../public/src/utils'); module.exports = function(Meta) { @@ -21,38 +22,56 @@ module.exports = function(Meta) { Meta.css.defaultBranding = {}; Meta.css.minify = function(callback) { - if (nconf.get('isPrimary') === 'true') { - winston.verbose('[meta/css] Minifying LESS/CSS'); - db.getObjectFields('config', ['theme:type', 'theme:id'], function(err, themeData) { - var themeId = (themeData['theme:id'] || 'nodebb-theme-vanilla'), - baseThemePath = path.join(nconf.get('themes_path'), (themeData['theme:type'] && themeData['theme:type'] === 'local' ? themeId : 'nodebb-theme-vanilla')), - paths = [ - baseThemePath, - path.join(__dirname, '../../node_modules'), - path.join(__dirname, '../../public/vendor/fontawesome/less'), - path.join(__dirname, '../../public/vendor/bootstrap/less') - ], - source = '@import "font-awesome";', - acpSource, - x; - - - plugins.lessFiles = filterMissingFiles(plugins.lessFiles); - for(x=0; x<plugins.lessFiles.length; ++x) { - source += '\n@import ".' + path.sep + plugins.lessFiles[x] + '";'; - } + callback = callback || function() {}; + if (nconf.get('isPrimary') !== 'true') { + winston.verbose('[meta/css] Cluster worker ' + process.pid + ' skipping LESS/CSS compilation'); + return callback(); + } + + winston.verbose('[meta/css] Minifying LESS/CSS'); + db.getObjectFields('config', ['theme:type', 'theme:id'], function(err, themeData) { + if (err) { + return callback(err); + } - plugins.cssFiles = filterMissingFiles(plugins.cssFiles); - for(x=0; x<plugins.cssFiles.length; ++x) { - source += '\n@import (inline) ".' + path.sep + plugins.cssFiles[x] + '";'; + var themeId = (themeData['theme:id'] || 'nodebb-theme-vanilla'), + baseThemePath = path.join(nconf.get('themes_path'), (themeData['theme:type'] && themeData['theme:type'] === 'local' ? themeId : 'nodebb-theme-vanilla')), + paths = [ + baseThemePath, + path.join(__dirname, '../../node_modules'), + path.join(__dirname, '../../public/vendor/fontawesome/less'), + path.join(__dirname, '../../public/vendor/bootstrap/less') + ], + source = '@import "font-awesome";'; + + plugins.lessFiles = filterMissingFiles(plugins.lessFiles); + plugins.cssFiles = filterMissingFiles(plugins.cssFiles); + + async.waterfall([ + function(next) { + getStyleSource(plugins.lessFiles, '\n@import ".', '.less', next); + }, + function(src, next) { + source += src; + getStyleSource(plugins.cssFiles, '\n@import (inline) ".', '.css', next); + }, + function(src, next) { + source += src; + next(); + } + ], function(err) { + if (err) { + return callback(err); } 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/jquery/textcomplete/jquery.textcomplete.css";'; source += '\n@import (inline) "..' + path.sep + '..' + path.sep + 'public/vendor/colorpicker/colorpicker.css";'; + source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/generics.less";'; - acpSource = '\n@import "..' + path.sep + 'public/less/admin/admin";\n' + source; + var acpSource = '\n@import "..' + path.sep + 'public/less/admin/admin";\n' + source; + 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; @@ -65,6 +84,10 @@ module.exports = function(Meta) { minify(acpSource, paths, 'acpCache', next); } ], function(err, minified) { + if (err) { + return callback(err); + } + // Propagate to other workers if (process.send) { process.send({ @@ -77,19 +100,41 @@ module.exports = function(Meta) { emitter.emit('meta:css.compiled'); - if (typeof callback === 'function') { - callback(); - } + callback(); }); }); - } else { - winston.verbose('[meta/css] Cluster worker ' + process.pid + ' skipping LESS/CSS compilation'); - if (typeof callback === 'function') { - callback(); - } - } + }); }; + function getStyleSource(files, prefix, extension, callback) { + var pluginDirectories = [], + source = ''; + + files.forEach(function(styleFile) { + if (styleFile.endsWith(extension)) { + source += prefix + path.sep + styleFile + '";'; + } else { + pluginDirectories.push(styleFile); + } + }); + + async.each(pluginDirectories, function(directory, next) { + utils.walk(directory, function(err, styleFiles) { + if (err) { + return next(err); + } + + styleFiles.forEach(function(styleFile) { + source += prefix + path.sep + styleFile + '";'; + }); + + next(); + }); + }, function(err) { + callback(err, source); + }); + } + Meta.css.commitToFile = function(filename) { var file = (filename === 'acpCache' ? 'admin' : 'stylesheet') + '.css'; diff --git a/src/meta/js.js b/src/meta/js.js index 4373d21a1d..85188ab3f7 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -44,10 +44,11 @@ module.exports = function(Meta) { 'public/src/utils.js', 'public/src/app.js', 'public/src/ajaxify.js', - 'public/src/variables.js', - 'public/src/widgets.js', + 'public/src/components.js', + 'public/src/overrides.js', 'public/src/translator.js', - 'public/src/overrides.js' + 'public/src/variables.js', + 'public/src/widgets.js' ], rjs: [] } @@ -93,7 +94,7 @@ module.exports = function(Meta) { clientScripts = []; pluginsScripts = plugins.clientScripts.filter(function(path) { - if (path.indexOf('.js') !== -1) { + if (path.endsWith('.js')) { return true; } else { pluginDirectories.push(path); diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index c4c4e6d792..b46376f590 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -378,6 +378,11 @@ middleware.processRender = function(req, res, next) { } render.call(self, template, options, function(err, str) { + if (err) { + winston.error(err); + return fn(err); + } + // str = str + '<input type="hidden" ajaxify-data="' + encodeURIComponent(JSON.stringify(options)) + '" />'; str = (res.locals.postHeader ? res.locals.postHeader : '') + str + (res.locals.preFooter ? res.locals.preFooter : ''); @@ -513,6 +518,21 @@ middleware.exposeGroupName = function(req, res, next) { }); }; +middleware.exposeUid = function(req, res, next) { + if (req.params.hasOwnProperty('userslug')) { + user.getUidByUserslug(req.params.userslug, function(err, uid) { + if (err) { + return next(err); + } + + res.locals.uid = uid; + next(); + }) + } else { + next(); + } +}; + module.exports = function(webserver) { app = webserver; middleware.admin = require('./admin')(webserver); diff --git a/src/postTools.js b/src/postTools.js index 3e9712699e..cb3b1da938 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -19,7 +19,7 @@ var winston = require('winston'), var cache = LRU({ max: 1048576, - length: function (n) { return n.length }, + length: function (n) { return n.length; }, maxAge: 1000 * 60 * 60 }); @@ -63,22 +63,32 @@ var cache = LRU({ }, topic: function(next) { var tid = postData.tid; - posts.isMain(data.pid, function(err, isMainPost) { + async.parallel({ + cid: function(next) { + topics.getTopicField(tid, 'cid', next); + }, + isMain: function(next) { + posts.isMain(data.pid, next); + } + }, function(err, results) { if (err) { return next(err); } options.tags = options.tags || []; - if (!isMainPost) { + if (!results.isMain) { return next(null, { tid: tid, + cid: results.cid, isMainPost: false }); } var topicData = { tid: tid, + cid: results.cid, + uid: postData.uid, mainPid: data.pid, title: title, slug: tid + '/' + utils.slugify(title) @@ -98,8 +108,10 @@ var cache = LRU({ topics.getTopicTagsObjects(tid, function(err, tags) { next(err, { tid: tid, + cid: results.cid, + uid: postData.uid, title: validator.escape(title), - isMainPost: isMainPost, + isMainPost: results.isMain, tags: tags }); }); @@ -108,12 +120,13 @@ var cache = LRU({ }, postData: function(next) { cache.del(postData.pid); - PostTools.parsePost(postData, data.uid, next); + PostTools.parsePost(postData, next); } }, function(err, results) { if (err) { return callback(err); } + postData.cid = results.topic.cid; results.content = results.postData.content; plugins.fireHook('action:post.edit', postData); @@ -163,7 +176,7 @@ var cache = LRU({ if (err) { return callback(err); } - PostTools.parsePost(postData, uid, callback); + PostTools.parsePost(postData, callback); }); } }); @@ -179,7 +192,7 @@ var cache = LRU({ }); }; - PostTools.parsePost = function(postData, uid, callback) { + PostTools.parsePost = function(postData, callback) { postData.content = postData.content || ''; var cachedContent = cache.get(postData.pid); @@ -188,7 +201,7 @@ var cache = LRU({ return callback(null, postData); } - plugins.fireHook('filter:parse.post', {postData: postData, uid: uid}, function(err, data) { + plugins.fireHook('filter:parse.post', {postData: postData}, function(err, data) { if (err) { return callback(err); } diff --git a/src/posts.js b/src/posts.js index 2c7ca82737..53931d75f7 100644 --- a/src/posts.js +++ b/src/posts.js @@ -52,7 +52,7 @@ var async = require('async'), postData.relativeTime = utils.toISOString(postData.timestamp); postData.relativeEditTime = parseInt(postData.edited, 10) !== 0 ? utils.toISOString(postData.edited) : ''; - postTools.parsePost(postData, uid, next); + postTools.parsePost(postData, next); }, function(err, posts) { if (err) { return callback(err); diff --git a/src/posts/create.js b/src/posts/create.js index a235b2f3f0..1bce6e69c7 100644 --- a/src/posts/create.js +++ b/src/posts/create.js @@ -68,7 +68,13 @@ module.exports = function(Posts) { topics.onNewPostMade(postData, next); }, function(next) { - categories.onNewPostMade(postData, next); + topics.getTopicFields(tid, ['cid', 'pinned'], function(err, topicData) { + if (err) { + return next(err); + } + postData.cid = topicData.cid; + categories.onNewPostMade(topicData.cid, topicData.pinned, postData, next); + }); }, function(next) { db.sortedSetAdd('posts:pid', timestamp, postData.pid, next); diff --git a/src/posts/delete.js b/src/posts/delete.js index bd130ade46..f47ff28e88 100644 --- a/src/posts/delete.js +++ b/src/posts/delete.js @@ -9,16 +9,19 @@ var async = require('async'), module.exports = function(Posts) { Posts.delete = function(pid, callback) { - Posts.setPostField(pid, 'deleted', 1, function(err) { - if (err) { - return callback(err); - } - - Posts.getPostFields(pid, ['pid', 'tid', 'uid', 'timestamp'], function(err, postData) { - if (err) { - return callback(err); - } - + var postData; + async.waterfall([ + function(next) { + Posts.setPostField(pid, 'deleted', 1, next); + }, + function(next) { + Posts.getPostFields(pid, ['pid', 'tid', 'uid', 'timestamp'], next); + }, + function(_post, next) { + postData = _post; + topics.getTopicField(_post.tid, 'cid', next); + }, + function(cid, next) { plugins.fireHook('action:post.delete', pid); async.parallel([ @@ -26,7 +29,7 @@ module.exports = function(Posts) { updateTopicTimestamp(postData.tid, next); }, function(next) { - removeFromCategoryRecentPosts(pid, postData.tid, next); + db.sortedSetRemove('cid:' + cid + ':pids', pid, next); }, function(next) { Posts.dismissFlag(pid, next); @@ -34,21 +37,25 @@ module.exports = function(Posts) { ], function(err) { callback(err, postData); }); - }); - }); + } + ], callback); }; Posts.restore = function(pid, callback) { - Posts.setPostField(pid, 'deleted', 0, function(err) { - if (err) { - return callback(err); - } - - Posts.getPostFields(pid, ['pid', 'tid', 'uid', 'content', 'timestamp'], function(err, postData) { - if (err) { - return callback(err); - } - + var postData; + async.waterfall([ + function(next) { + Posts.setPostField(pid, 'deleted', 0, next); + }, + function(next) { + Posts.getPostFields(pid, ['pid', 'tid', 'uid', 'content', 'timestamp'], next); + }, + function(_post, next) { + postData = _post; + topics.getTopicField(_post.tid, 'cid', next); + }, + function(cid, next) { + postData.cid = cid; plugins.fireHook('action:post.restore', postData); async.parallel([ @@ -56,13 +63,13 @@ module.exports = function(Posts) { updateTopicTimestamp(postData.tid, next); }, function(next) { - addToCategoryRecentPosts(pid, postData.tid, postData.timestamp, next); + db.sortedSetAdd('cid:' + cid + ':pids', postData.timestamp, pid, next); } ], function(err) { callback(err, postData); }); - }); - }); + } + ], callback); }; function updateTopicTimestamp(tid, callback) { @@ -84,26 +91,6 @@ module.exports = function(Posts) { }); } - function removeFromCategoryRecentPosts(pid, tid, callback) { - topics.getTopicField(tid, 'cid', function(err, cid) { - if (err) { - return callback(err); - } - - db.sortedSetRemove('cid:' + cid + ':pids', pid, callback); - }); - } - - function addToCategoryRecentPosts(pid, tid, timestamp, callback) { - topics.getTopicField(tid, 'cid', function(err, cid) { - if (err) { - return callback(err); - } - - db.sortedSetAdd('cid:' + cid + ':pids', timestamp, pid, callback); - }); - } - Posts.purge = function(pid, callback) { Posts.exists(pid, function(err, exists) { if (err || !exists) { diff --git a/src/posts/summary.js b/src/posts/summary.js index 962a51aaa6..15f2f645ad 100644 --- a/src/posts/summary.js +++ b/src/posts/summary.js @@ -86,7 +86,7 @@ module.exports = function(Posts) { return next(null, post); } - postTools.parsePost(post, uid, function(err, post) { + postTools.parsePost(post, function(err, post) { if (err) { return next(err); } @@ -120,7 +120,7 @@ module.exports = function(Posts) { return topic && array.indexOf(topic) === index; }); - categories.getMultipleCategoryFields(cids, ['cid', 'name', 'icon', 'slug'], function(err, categories) { + categories.getMultipleCategoryFields(cids, ['cid', 'name', 'icon', 'slug', 'parentCid'], function(err, categories) { callback(err, {topics: topics, categories: categories}); }); }); diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 4a623eaa27..59b2f79a1d 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -13,6 +13,138 @@ module.exports = function(privileges) { privileges.categories = {}; + privileges.categories.list = function(cid, callback) { + // Method used in admin/category controller to show all users with privs in that given cid + async.parallel({ + labels: function(next) { + async.parallel({ + users: async.apply(plugins.fireHook, 'filter:privileges.list_human', + ['Find category', 'Access & Read', 'Create Topics', 'Reply to Topics', 'Moderate'].map(function(name) { + return { + name: name + }; + }) + ), + groups: async.apply(plugins.fireHook, 'filter:privileges.groups.list_human', + ['Find category', 'Access & Read', 'Create Topics', 'Reply to Topics', 'Moderate'].map(function(name) { + return { + name: name + }; + }) + ) + }, next); + }, + users: function(next) { + var privileges; + async.waterfall([ + async.apply(plugins.fireHook, 'filter:privileges.list', [ + 'find', 'read', 'topics:create', 'topics:reply', 'mods' + ]), + function(privs, next) { + privileges = privs; + groups.getMembersOfGroups(privs.map(function(privilege) { + return 'cid:' + cid + ':privileges:' + privilege; + }), function(err, memberSets) { + if (err) { + return next(err); + } + + next(null, memberSets.map(function(set) { + return set.map(function(uid) { + return parseInt(uid, 10); + }); + })); + }); + }, + function(memberSets, next) { + // Reduce into a single array + var members = memberSets.reduce(function(combined, curMembers) { + return combined.concat(curMembers); + }).filter(function(member, index, combined) { + return combined.indexOf(member) === index; + }); + + user.getMultipleUserFields(members, ['picture', 'username'], function(err, memberData) { + memberData = memberData.map(function(member) { + member.privileges = {}; + for(var x=0,numPrivs=privileges.length;x<numPrivs;x++) { + member.privileges[privileges[x]] = memberSets[x].indexOf(parseInt(member.uid, 10)) !== -1; + } + + return member; + }); + + next(null, memberData); + }); + } + ], next); + }, + groups: function(next) { + var privileges; + async.waterfall([ + async.apply(plugins.fireHook, 'filter:privileges.groups.list', [ + 'groups:find', 'groups:read', 'groups:topics:create', 'groups:topics:reply', 'groups:moderate' + ]), + function(privs, next) { + privileges = privs; + groups.getMembersOfGroups(privs.map(function(privilege) { + return 'cid:' + cid + ':privileges:' + privilege; + }), next); + }, + function(memberSets, next) { + groups.getGroups(0, -1, function(err, groupNames) { + if (err) { + return next(err); + } + + groupNames = groups.getEphemeralGroups().concat(groupNames); + groupNames.splice(0, 0, groupNames.splice(groupNames.indexOf('registered-users'), 1)[0]); + groupNames.splice(groupNames.indexOf('administrators'), 1); + + var memberData = groupNames.filter(function(member) { + return member.indexOf(':privileges:') === -1; + }).map(function(member) { + var memberPrivs = {}; + for(var x=0,numPrivs=privileges.length;x<numPrivs;x++) { + memberPrivs[privileges[x]] = memberSets[x].indexOf(member) !== -1; + } + + return { + name: member, + privileges: memberPrivs, + }; + }); + + next(null, memberData); + }); + }, + function(memberData, next) { + // Grab privacy info for the groups as well + async.map(memberData, function(member, next) { + groups.isPrivate(member.name, function(err, isPrivate) { + if (err) { + return next(err); + } + + member.isPrivate = isPrivate; + next(null, member); + }); + }, next); + } + ], next); + } + }, function(err, payload) { + if (err) { + return callback(err); + } + + // This is a hack because I can't do {labels.users.length} to echo the count in templates.js + payload.columnCount = payload.labels.users.length + 2; + + callback(null, payload); + }); + }; + privileges.categories.get = function(cid, uid, callback) { async.parallel({ 'topics:create': function(next) { @@ -102,17 +234,11 @@ module.exports = function(privileges) { } cids = cids.filter(function(cid, index) { - return !results.categories[index].disabled; + return !results.categories[index].disabled && + (results.allowedTo[index] || results.isAdmin || results.isModerators[index]); }); - - if (results.isAdmin) { - return callback(null, cids); - } - cids = cids.filter(function(cid, index) { - return results.allowedTo[index] || results.isModerators[index]; - }); - callback(null, cids); + callback(null, cids.filter(Boolean)); }); }; diff --git a/src/routes/admin.js b/src/routes/admin.js index 4a7e7ef460..c84758a1cd 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -45,9 +45,8 @@ function addRoutes(router, middleware, controllers) { router.get('/general/navigation', controllers.admin.navigation.get); router.get('/general/homepage', controllers.admin.homepage.get); - router.get('/manage/categories', controllers.admin.categories.active); - router.get('/manage/categories/active', controllers.admin.categories.active); - router.get('/manage/categories/disabled', controllers.admin.categories.disabled); + router.get('/manage/categories', controllers.admin.categories.getAll); + router.get('/manage/categories/:category_id', controllers.admin.categories.get); router.get('/manage/tags', controllers.admin.tags.get); diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 0f2f6082b6..86d9cbb82d 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -84,8 +84,8 @@ function generateForTopic(req, res, next) { feed.item({ title: 'Reply to ' + topicData.title + ' on ' + dateStamp, description: postData.content, - url: nconf.get('url') + '/topic/' + topicData.slug + '#' + postData.pid, - author: postData.username, + url: nconf.get('url') + '/topic/' + topicData.slug + (postData.index ? '/' + (postData.index + 1) : ''), + author: postData.user ? postData.user.username : '', date: dateStamp }); } @@ -144,8 +144,8 @@ function generateForCategory(req, res, next) { if (err) { return next(err); } - sendFeed(feed, res); - }); + sendFeed(feed, res); + }); }); } @@ -183,8 +183,8 @@ function generateForPopular(req, res, next) { return next(err); } sendFeed(feed, res); - }); - }); + }); + }); } function disabledRSS(req, res, next) { @@ -201,58 +201,41 @@ function generateForTopics(options, set, req, res, next) { if (err) { return next(err); } - + generateTopicsFeed(options, data.topics, function(err, feed) { if (err) { return next(err); } - sendFeed(feed, res); - }); + sendFeed(feed, res); + }); }); } function generateTopicsFeed(feedOptions, feedTopics, callback) { - var tids = feedTopics.map(function(topic) { - return topic ? topic.tid : null; - }); - - topics.getMainPids(tids, function(err, pids) { - if (err) { - return callback(err); - } - posts.getPostsFields(pids, ['content'], function(err, posts) { - if (err) { - return callback(err); - } - - feedTopics.forEach(function(topic, index) { - if (topic && posts[index]) { - topic.mainPost = posts[index].content; - } - }); - feedOptions.ttl = 60; - feedOptions.feed_url = nconf.get('url') + feedOptions.feed_url; - feedOptions.site_url = nconf.get('url') + feedOptions.site_url; + feedOptions.ttl = 60; + feedOptions.feed_url = nconf.get('url') + feedOptions.feed_url; + feedOptions.site_url = nconf.get('url') + feedOptions.site_url; - var feed = new rss(feedOptions); + var feed = new rss(feedOptions); - if (feedTopics.length > 0) { - feed.pubDate = new Date(parseInt(feedTopics[0].lastposttime, 10)).toUTCString(); - } + if (feedTopics.length > 0) { + feed.pubDate = new Date(parseInt(feedTopics[0].lastposttime, 10)).toUTCString(); + } - feedTopics.forEach(function(topicData) { - feed.item({ - title: topicData.title, - description: topicData.mainPost, - url: nconf.get('url') + '/topic/' + topicData.slug, - author: topicData.username, - date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString() - }); + feedTopics.forEach(function(topicData) { + if (topicData && topicData.teaser && topicData.teaser.user) { + feed.item({ + title: topicData.title, + description: topicData.teaser.content, + url: nconf.get('url') + '/topic/' + topicData.slug, + author: topicData.teaser.user.username, + date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString() }); - callback(null, feed); - }); - }); + } + }); + callback(null, feed); + } function generateForRecentPosts(req, res, next) { diff --git a/src/search.js b/src/search.js index e44dedc216..063ebfa142 100644 --- a/src/search.js +++ b/src/search.js @@ -43,7 +43,7 @@ search.search = function(data, callback) { }; if (searchIn === 'posts' || searchIn === 'titles' || searchIn === 'titlesposts') { - searchInContent(query, data, done); + searchInContent(data, done); } else if (searchIn === 'users') { searchInUsers(query, data.uid, done); } else if (searchIn === 'tags') { @@ -53,89 +53,87 @@ search.search = function(data, callback) { } }; -function searchInContent(query, data, callback) { +function searchInContent(data, callback) { data.uid = data.uid || 0; async.parallel({ - pids: function(next) { - if (data.searchIn === 'posts' || data.searchIn === 'titlesposts') { - search.searchQuery('post', query, next); - } else { - next(null, []); - } - }, - tids: function(next) { - if (data.searchIn === 'titles' || data.searchIn === 'titlesposts') { - search.searchQuery('topic', query, next); - } else { - next(null, []); - } + searchCids: function(next) { + getSearchCids(data, next); }, - searchCategories: function(next) { - getSearchCategories(data, next); + searchUids: function(next) { + getSearchUids(data, next); } - }, function (err, results) { + }, function(err, results) { if (err) { return callback(err); } - var matchCount = 0; - if (!results || (!results.pids.length && !results.tids.length)) { - return callback(null, {matches: [], matchCount: matchCount}); - } - - async.waterfall([ - function(next) { - topics.getMainPids(results.tids, next); - }, - function(mainPids, next) { - results.pids = mainPids.concat(results.pids).filter(function(pid, index, array) { - return pid && array.indexOf(pid) === index; - }); - - privileges.posts.filter('read', results.pids, data.uid, next); - }, - function(pids, next) { - filterAndSort(pids, data, results.searchCategories, next); + async.parallel({ + pids: function(next) { + if (data.searchIn === 'posts' || data.searchIn === 'titlesposts') { + search.searchQuery('post', data.query, results.searchCids, results.searchUids, next); + } else { + next(null, []); + } }, - function(pids, next) { - matchCount = pids.length; - if (data.page) { - var start = Math.max(0, (data.page - 1)) * 10; - pids = pids.slice(start, start + 10); + tids: function(next) { + if (data.searchIn === 'titles' || data.searchIn === 'titlesposts') { + search.searchQuery('topic', data.query, results.searchCids, results.searchUids, next); + } else { + next(null, []); } + } + }, function (err, results) { + if (err) { + return callback(err); + } - posts.getPostSummaryByPids(pids, data.uid, {stripTags: true, parse: false}, next); - }, - function(posts, next) { - next(null, {matches: posts, matchCount: matchCount}); + var matchCount = 0; + if (!results || (!results.pids.length && !results.tids.length)) { + return callback(null, {matches: [], matchCount: matchCount}); } - ], callback); + + async.waterfall([ + function(next) { + topics.getMainPids(results.tids, next); + }, + function(mainPids, next) { + results.pids = mainPids.concat(results.pids).filter(function(pid, index, array) { + return pid && array.indexOf(pid) === index; + }); + + privileges.posts.filter('read', results.pids, data.uid, next); + }, + function(pids, next) { + filterAndSort(pids, data, next); + }, + function(pids, next) { + matchCount = pids.length; + if (data.page) { + var start = Math.max(0, (data.page - 1)) * 10; + pids = pids.slice(start, start + 10); + } + + posts.getPostSummaryByPids(pids, data.uid, {stripTags: true, parse: false}, next); + }, + function(posts, next) { + next(null, {matches: posts, matchCount: matchCount}); + } + ], callback); + }); }); } -function filterAndSort(pids, data, searchCategories, callback) { - async.parallel({ - posts: function(next) { - getMatchedPosts(pids, data, searchCategories, next); - }, - postedByUid: function(next) { - if (data.postedBy) { - user.getUidByUsername(data.postedBy, next); - } else { - next(); - } - } - }, function(err, results) { +function filterAndSort(pids, data, callback) { + getMatchedPosts(pids, data, function(err, posts) { if (err) { return callback(err); } - if (!results.posts) { + + if (!Array.isArray(posts) || !posts.length) { return callback(null, pids); } - var posts = results.posts.filter(Boolean); + posts = posts.filter(Boolean); - posts = filterByUser(posts, results.postedByUid); - posts = filterByCategories(posts, searchCategories); posts = filterByPostcount(posts, data.replies, data.repliesFilter); posts = filterByTimerange(posts, data.timeRange, data.timeFilter); @@ -149,25 +147,19 @@ function filterAndSort(pids, data, searchCategories, callback) { }); } -function getMatchedPosts(pids, data, searchCategories, callback) { +function getMatchedPosts(pids, data, callback) { var postFields = ['pid', 'tid', 'timestamp']; var topicFields = []; var categoryFields = []; - if (data.postedBy) { - postFields.push('uid'); - } - - if (searchCategories.length || (data.sortBy && data.sortBy.startsWith('category.'))) { - topicFields.push('cid'); - } - if (data.replies) { topicFields.push('postcount'); } if (data.sortBy) { - if (data.sortBy.startsWith('topic.')) { + if (data.sortBy.startsWith('category')) { + topicFields.push('cid'); + } else if (data.sortBy.startsWith('topic.')) { topicFields.push(data.sortBy.split('.')[1]); } else if (data.sortBy.startsWith('user.')) { postFields.push('uid'); @@ -280,25 +272,6 @@ function getMatchedPosts(pids, data, searchCategories, callback) { ], callback); } -function filterByUser(posts, postedByUid) { - if (postedByUid) { - postedByUid = parseInt(postedByUid, 10); - posts = posts.filter(function(post) { - return parseInt(post.uid, 10) === postedByUid; - }); - } - return posts; -} - -function filterByCategories(posts, searchCategories) { - if (searchCategories.length) { - posts = posts.filter(function(post) { - return post.topic && searchCategories.indexOf(post.topic.cid) !== -1; - }); - } - return posts; -} - function filterByPostcount(posts, postCount, repliesFilter) { postCount = parseInt(postCount, 10); if (postCount) { @@ -389,7 +362,7 @@ function sortPosts(posts, data) { } } -function getSearchCategories(data, callback) { +function getSearchCids(data, callback) { if (!Array.isArray(data.categories) || !data.categories.length || data.categories.indexOf('all') !== -1) { return callback(null, []); } @@ -439,6 +412,14 @@ function getChildrenCids(cids, uid, callback) { }); } +function getSearchUids(data, callback) { + if (data.postedBy) { + user.getUidsByUsernames(Array.isArray(data.postedBy) ? data.postedBy : [data.postedBy], callback); + } else { + callback(null, []); + } +} + function searchInUsers(query, uid, callback) { user.search({query: query, uid: uid}, function(err, results) { if (err) { @@ -458,10 +439,12 @@ function searchInTags(query, callback) { }); } -search.searchQuery = function(index, query, callback) { +search.searchQuery = function(index, content, cids, uids, callback) { plugins.fireHook('filter:search.query', { index: index, - query: query + content: content, + cid: cids, + uid: uids }, callback); }; diff --git a/src/socket.io/admin/categories.js b/src/socket.io/admin/categories.js index 5659b8aca9..4db4445d4d 100644 --- a/src/socket.io/admin/categories.js +++ b/src/socket.io/admin/categories.js @@ -59,83 +59,11 @@ Categories.setPrivilege = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } - groups[data.set ? 'join' : 'leave']('cid:' + data.cid + ':privileges:' + data.privilege, data.uid, callback); + groups[data.set ? 'join' : 'leave']('cid:' + data.cid + ':privileges:' + data.privilege, data.member, callback); }; Categories.getPrivilegeSettings = function(socket, cid, callback) { - var privileges = ['find', 'read', 'topics:create', 'topics:reply', 'mods']; - - async.reduce(privileges, [], function(members, privilege, next) { - groups.get('cid:' + cid + ':privileges:' + privilege, { expand: true }, function(err, groupObj) { - if (err || !groupObj) { - return next(null, members); - } - - members = members.concat(groupObj.members); - - next(null, members); - }); - }, function(err, members) { - if (err) { - return callback(err); - } - // Remove duplicates - var present = [], - x = members.length, - uid; - while(x--) { - uid = parseInt(members[x].uid, 10); - if (present.indexOf(uid) !== -1) { - members.splice(x, 1); - } else { - present.push(uid); - } - } - - callback(err, members); - }); -}; - -Categories.setGroupPrivilege = function(socket, data, callback) { - if(!data) { - return callback(new Error('[[error:invalid-data]]')); - } - - groups[data.set ? 'join' : 'leave']('cid:' + data.cid + ':privileges:' + data.privilege, data.name, function (err) { - if (err) { - return callback(err); - } - - groups.hide('cid:' + data.cid + ':privileges:' + data.privilege, callback); - }); -}; - -Categories.groupsList = function(socket, cid, callback) { - groups.list({ - expand: false, - isAdmin: true, - showSystemGroups: true - }, function(err, data) { - if(err) { - return callback(err); - } - - // Remove privilege groups - data = data.filter(function(groupObj) { - return groupObj.name.indexOf(':privileges:') === -1; - }); - - async.map(data, function(groupObj, next) { - privileges.categories.groupPrivileges(cid, groupObj.name, function(err, privileges) { - if(err) { - return next(err); - } - - groupObj.privileges = privileges; - next(null, groupObj); - }); - }, callback); - }); + privileges.categories.list(cid, callback); }; module.exports = Categories; \ No newline at end of file diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 9f20697ef9..d98cb0c21f 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -118,4 +118,8 @@ SocketCategories.ignore = function(socket, cid, callback) { }); }; +SocketCategories.isModerator = function(socket, cid, callback) { + user.isModerator(socket.uid, cid, callback); +}; + module.exports = SocketCategories; diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 337320e226..a2cc3a241e 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -12,6 +12,7 @@ var SocketIO = require('socket.io'), user = require('../user'), logger = require('../logger'), ratelimit = require('../middleware/ratelimit'), + rooms = require('./rooms'), Sockets = {}, Namespaces = {}; @@ -63,8 +64,8 @@ function onConnection(socket) { function onConnect(socket) { if (socket.uid) { - socket.join('uid_' + socket.uid); - socket.join('online_users'); + rooms.enter(socket, 'uid_' + socket.uid); + rooms.enter(socket, 'online_users'); user.getUserFields(socket.uid, ['status'], function(err, userData) { if (err || !userData) { @@ -77,7 +78,7 @@ function onConnect(socket) { } }); } else { - socket.join('online_guests'); + rooms.enter(socket, 'online_guests'); socket.emit('event:connect'); } } @@ -85,7 +86,7 @@ function onConnect(socket) { function onDisconnect(socket, data) { if (socket.uid) { var socketCount = Sockets.getUserSocketCount(socket.uid); - if (socketCount <= 0) { + if (socketCount <= 1) { socket.broadcast.emit('event:user_status_change', {uid: socket.uid, status: 'offline'}); } @@ -96,6 +97,7 @@ function onDisconnect(socket, data) { } }); } + rooms.leaveAll(socket, data.rooms); } function onMessage(socket, payload) { @@ -149,17 +151,12 @@ function onMessage(socket, payload) { } function requireModules() { - fs.readdir(__dirname, function(err, files) { - files.splice(files.indexOf('index.js'), 1); + var modules = ['admin', 'categories', 'groups', 'meta', 'modules', + 'notifications', 'plugins', 'posts', 'topics', 'user' + ]; - async.each(files, function(lib, next) { - if (lib.substr(lib.length - 3) === '.js') { - lib = lib.slice(0, -3); - Namespaces[lib] = require('./' + lib); - } - - next(); - }); + modules.forEach(function(module) { + Namespaces[module] = require('./' + module); }); } @@ -183,7 +180,7 @@ function authorize(socket, callback) { socket.uid = parseInt(sessionData.passport.user, 10); } else { socket.uid = 0; - } + } next(); }); } @@ -218,27 +215,25 @@ Sockets.in = function(room) { }; Sockets.getSocketCount = function() { - // TODO: io.sockets.adapter.sids is local to this worker - // use redis-adapter - - var clients = Object.keys(io.sockets.adapter.sids || {}); - return Array.isArray(clients) ? clients.length : 0; + return rooms.socketCount(); }; Sockets.getUserSocketCount = function(uid) { - // TODO: io.sockets.adapter.rooms is local to this worker - // use .clients('uid_' + uid, fn) + return rooms.clients('uid_' + uid).length; +}; - var roomClients = Object.keys(io.sockets.adapter.rooms['uid_' + uid] || {}); - return Array.isArray(roomClients) ? roomClients.length : 0; +Sockets.getOnlineUserCount = function() { + var count = 0; + Object.keys(rooms.roomClients()).forEach(function(roomName) { + if (roomName.startsWith('uid_')) { + ++ count; + } + }); + return count; }; Sockets.getOnlineAnonCount = function () { - // TODO: io.sockets.adapter.rooms is local to this worker - // use .clients() - - var guestSocketIds = Object.keys(io.sockets.adapter.rooms.online_guests || {}); - return Array.isArray(guestSocketIds) ? guestSocketIds.length : 0; + return rooms.clients('online_guests').length; }; Sockets.reqFromSocket = function(socket) { @@ -258,9 +253,7 @@ Sockets.reqFromSocket = function(socket) { }; Sockets.isUserOnline = function(uid) { - // TODO: io.sockets.adapter.rooms is local to this worker - // use .clients('uid_' + uid, fn) - return io ? !!io.sockets.adapter.rooms['uid_' + uid] : false; + return !!rooms.clients('uid_' + uid).length; }; Sockets.isUsersOnline = function(uids, callback) { @@ -301,26 +294,29 @@ Sockets.getUsersInRoom = function (uid, roomName, callback) { Sockets.getUidsInRoom = function(roomName, callback) { callback = callback || function() {}; - // TODO : doesnt work in cluster var uids = []; - var socketids = Object.keys(io.sockets.adapter.rooms[roomName] || {}); + var socketids = rooms.clients(roomName); if (!Array.isArray(socketids) || !socketids.length) { callback(null, []); return []; } for(var i=0; i<socketids.length; ++i) { - var socketRooms = Object.keys(io.sockets.adapter.sids[socketids[i]]); + var socketRooms = rooms.clientRooms(socketids[i]); if (Array.isArray(socketRooms)) { socketRooms.forEach(function(roomName) { - if (roomName.indexOf('uid_') === 0 ) { - uids.push(roomName.split('_')[1]); + if (roomName.startsWith('uid_')) { + var uid = roomName.split('_')[1]; + if (uids.indexOf(uid) === -1) { + uids.push(uid); + } } }); } } + callback(null, uids); return uids; }; diff --git a/src/socket.io/meta.js b/src/socket.io/meta.js index c801381a1f..60bb51bd4e 100644 --- a/src/socket.io/meta.js +++ b/src/socket.io/meta.js @@ -12,6 +12,7 @@ var nconf = require('nconf'), logger = require('../logger'), plugins = require('../plugins'), emitter = require('../emitter'), + rooms = require('./rooms'), websockets = require('./'), @@ -58,7 +59,7 @@ SocketMeta.rooms.enter = function(socket, data, callback) { } if (socket.currentRoom) { - socket.leave(socket.currentRoom); + rooms.leave(socket, socket.currentRoom); if (socket.currentRoom.indexOf('topic') !== -1) { websockets.in(socket.currentRoom).emit('event:user_leave', socket.uid); } @@ -66,79 +67,80 @@ SocketMeta.rooms.enter = function(socket, data, callback) { } if (data.enter) { - socket.join(data.enter); + rooms.enter(socket, data.enter); socket.currentRoom = data.enter; if (data.enter.indexOf('topic') !== -1) { data.uid = socket.uid; + data.picture = validator.escape(data.picture); + data.username = validator.escape(data.username); + data.userslug = validator.escape(data.userslug); + websockets.in(data.enter).emit('event:user_enter', data); } } }; SocketMeta.rooms.getAll = function(socket, data, callback) { - var now = Date.now(); - db.sortedSetCount('users:online', now - 300000, now, function(err, onlineRegisteredCount) { - if (err) { - return callback(err); - } - - var rooms = {}; // TODO: websockets.server.sockets.manager.rooms; doesnt work in socket.io 1.x - var socketData = { - onlineGuestCount: websockets.getOnlineAnonCount(), - onlineRegisteredCount: onlineRegisteredCount, - socketCount: websockets.getSocketCount(), - users: { - home: rooms['/home'] ? rooms['/home'].length : 0, - topics: 0, - category: 0 - }, - topics: {} - }; - - var scores = {}, - topTenTopics = [], - tid; - - for (var room in rooms) { - if (rooms.hasOwnProperty(room)) { - if (tid = room.match(/^\/topic_(\d+)/)) { - var length = rooms[room].length; - socketData.users.topics += length; - - if (scores[length]) { - scores[length].push(tid[1]); - } else { - scores[length] = [tid[1]]; - } - } else if (room.match(/^\/category/)) { - socketData.users.category += rooms[room].length; + var roomClients = rooms.roomClients(); + var socketData = { + onlineGuestCount: websockets.getOnlineAnonCount(), + onlineRegisteredCount: websockets.getOnlineUserCount(), + socketCount: websockets.getSocketCount(), + users: { + categories: roomClients.categories ? roomClients.categories.length : 0, + recent: roomClients.recent_posts ? roomClients.recent_posts.length : 0, + tags: roomClients.tags ? roomClients.tags.length : 0, + topics: 0, + category: 0 + }, + topics: {} + }; + + var scores = {}, + topTenTopics = [], + tid; + + for (var room in roomClients) { + if (roomClients.hasOwnProperty(room)) { + tid = room.match(/^topic_(\d+)/); + if (tid) { + var length = roomClients[room].length; + socketData.users.topics += length; + + if (scores[length]) { + scores[length].push(tid[1]); + } else { + scores[length] = [tid[1]]; } + } else if (room.match(/^category/)) { + socketData.users.category += roomClients[room].length; } } + } - var scoreKeys = Object.keys(scores), - mostActive = scoreKeys.sort(); + var scoreKeys = Object.keys(scores), + mostActive = scoreKeys.sort(); - while(topTenTopics.length < 10 && mostActive.length > 0) { - topTenTopics = topTenTopics.concat(scores[mostActive.pop()]); - } + while(topTenTopics.length < 10 && mostActive.length > 0) { + topTenTopics = topTenTopics.concat(scores[mostActive.pop()]); + } - topTenTopics = topTenTopics.slice(0, 10); + topTenTopics = topTenTopics.slice(0, 10); - topics.getTopicsFields(topTenTopics, ['title'], function(err, titles) { - if (err) { - return callback(err); - } - topTenTopics.forEach(function(tid, id) { - socketData.topics[tid] = { - value: rooms['/topic_' + tid].length, - title: validator.escape(titles[id].title) - }; - }); - - callback(null, socketData); + topics.getTopicsFields(topTenTopics, ['title'], function(err, titles) { + if (err) { + return callback(err); + } + topTenTopics.forEach(function(tid, id) { + socketData.topics[tid] = { + value: Array.isArray(roomClients['topic_' + tid]) ? roomClients['topic_' + tid].length : 0, + title: validator.escape(titles[id].title) + }; }); + + callback(null, socketData); }); + }; /* Exports */ diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index e8f5ef9a63..2fdf4425b5 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -49,7 +49,13 @@ SocketPosts.reply = function(socket, data, callback) { socket.emit('event:new_post', result); + user.updateOnlineUsers(socket.uid); + SocketPosts.notifyOnlineUsers(socket.uid, result); + + if (data.lock) { + socketTopics.doTopicAction('lock', 'event:topic_locked', socket, {tids: [postData.topic.tid], cid: postData.topic.cid}); + } }); }; @@ -228,7 +234,7 @@ SocketPosts.sendNotificationToPostOwner = function(pid, fromuid, notification) { async.parallel({ username: async.apply(user.getUserField, fromuid, 'username'), topicTitle: async.apply(topics.getTopicField, postData.tid, 'title'), - postObj: async.apply(postTools.parsePost, postData, postData.uid) + postObj: async.apply(postTools.parsePost, postData) }, function(err, results) { if (err) { return; @@ -362,9 +368,9 @@ SocketPosts.purge = function(socket, data, callback) { }); callback(); - }); + }); } - + if (!data || !parseInt(data.pid, 10)) { return callback(new Error('[[error:invalid-data]]')); } @@ -475,7 +481,7 @@ SocketPosts.flag = function(socket, pid, callback) { function(topic, next) { post.topic = topic; message = '[[notifications:user_flagged_post_in, ' + userName + ', ' + topic.title + ']]'; - postTools.parsePost(post, socket.uid, next); + postTools.parsePost(post, next); }, function(post, next) { async.parallel({ @@ -500,7 +506,7 @@ SocketPosts.flag = function(socket, pid, callback) { } notifications.push(notification, results.admins.concat(results.moderators), next); }); - } + } ], callback); }; diff --git a/src/socket.io/rooms.js b/src/socket.io/rooms.js new file mode 100644 index 0000000000..e392abf3f9 --- /dev/null +++ b/src/socket.io/rooms.js @@ -0,0 +1,95 @@ +'use strict'; + + +// Temp solution until +// https://github.com/NodeBB/NodeBB/issues/2486 +// and +// https://github.com/Automattic/socket.io/issues/1945 +// are closed. +// Once they are closed switch to .clients() and async calls + + +var pubsub = require('../pubsub'); + +var rooms = {}; + +var clientRooms = {}; +var roomClients = {}; + +rooms.enter = function(socket, room) { + socket.join(room); + pubsub.publish('socket:join', {id: socket.id, room: room}); +}; + +rooms.leave = function(socket, room) { + socket.leave(room); + pubsub.publish('socket:leave', {id: socket.id, room: room}); +}; + +rooms.leaveAll = function(socket, roomsToLeave) { + roomsToLeave.forEach(function(room) { + rooms.leave(socket, room); + }); +}; + +pubsub.on('socket:join', onSocketJoin); +pubsub.on('socket:leave', onSocketLeave); + +function onSocketJoin(data) { + clientRooms[data.id] = clientRooms[data.id] || []; + if (clientRooms[data.id].indexOf(data.room) === -1) { + clientRooms[data.id].push(data.room); + } + + roomClients[data.room] = roomClients[data.room] || []; + if (roomClients[data.room].indexOf(data.id) === -1) { + roomClients[data.room].push(data.id); + } +} + + +function onSocketLeave(data) { + var index; + if (Array.isArray(clientRooms[data.id])) { + index = clientRooms[data.id].indexOf(data.room); + if (index !== -1) { + clientRooms[data.id].splice(index, 1); + if (!clientRooms[data.id].length) { + delete clientRooms[data.id]; + } + } + } + + if (Array.isArray(roomClients[data.room])) { + index = roomClients[data.room].indexOf(data.id); + if (index !== -1) { + roomClients[data.room].splice(index, 1); + if (!roomClients[data.room].length) { + delete roomClients[data.room]; + } + } + } +} + + +rooms.clients = function(room) { + return Array.isArray(roomClients[room]) ? roomClients[room] : []; +}; + +rooms.clientRooms = function(id) { + return Array.isArray(clientRooms[id]) ? clientRooms[id] : []; +}; + +rooms.socketCount = function() { + return Object.keys(clientRooms || {}).length; +}; + +rooms.roomClients = function() { + return roomClients; +}; + + + + +module.exports = rooms; + diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index b0f9d3b8c7..c270082953 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -41,6 +41,10 @@ SocketTopics.post = function(socket, data, callback) { return callback(err); } + if (data.lock) { + SocketTopics.doTopicAction('lock', 'event:topic_locked', socket, {tids: [result.topicData.tid], cid: result.topicData.cid}); + } + callback(null, result.topicData); socket.emit('event:new_post', {posts: [result.postData]}); socket.emit('event:new_topic', result.topicData); @@ -233,6 +237,7 @@ SocketTopics.unpin = function(socket, data, callback) { }; SocketTopics.doTopicAction = function(action, event, socket, data, callback) { + callback = callback || function() {}; if (!socket.uid) { return; } @@ -550,4 +555,13 @@ SocketTopics.loadMoreTags = function(socket, data, callback) { }); }; +SocketTopics.isModerator = function(socket, tid, callback) { + topics.getTopicField(tid, 'cid', function(err, cid) { + if (err) { + return callback(err); + } + user.isModerator(socket.uid, cid, callback); + }); +}; + module.exports = SocketTopics; diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 7170cf27d0..807666ff18 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -281,7 +281,7 @@ SocketUser.follow = function(socket, data, callback) { if (!socket.uid || !data) { return; } - + var userData; async.waterfall([ function(next) { toggleFollow('follow', socket.uid, data.uid, next); @@ -289,7 +289,8 @@ SocketUser.follow = function(socket, data, callback) { function(next) { user.getUserFields(socket.uid, ['username', 'userslug'], next); }, - function(userData, next) { + function(_userData, next) { + userData = _userData; notifications.create({ bodyShort: '[[notifications:user_started_following_you, ' + userData.username + ']]', nid: 'follow:' + data.uid + ':uid:' + socket.uid, @@ -297,6 +298,7 @@ SocketUser.follow = function(socket, data, callback) { }, next); }, function(notification, next) { + notification.user = userData; notifications.push(notification, [data.uid], next); } ], callback); diff --git a/src/threadTools.js b/src/threadTools.js index 96d8198291..76ea84c9df 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -21,7 +21,7 @@ var async = require('async'), }; function toggleDelete(tid, uid, isDelete, callback) { - topics.getTopicFields(tid, ['tid', 'cid', 'deleted', 'title', 'mainPid'], function(err, topicData) { + topics.getTopicFields(tid, ['tid', 'cid', 'uid', 'deleted', 'title', 'mainPid'], function(err, topicData) { if (err) { return callback(err); } @@ -183,13 +183,16 @@ var async = require('async'), categories.moveRecentReplies(tid, oldCid, cid); - topics.setTopicField(tid, 'cid', cid, callback); - - plugins.fireHook('action:topic.move', { - tid: tid, - fromCid: oldCid, - toCid: cid, - uid: uid + topics.setTopicField(tid, 'cid', cid, function(err) { + if (err) { + return callback(err); + } + plugins.fireHook('action:topic.move', { + tid: tid, + fromCid: oldCid, + toCid: cid, + uid: uid + }); }); }); }; diff --git a/src/topics/create.js b/src/topics/create.js index 36a73948d7..f7af1d0c5e 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -93,7 +93,6 @@ module.exports = function(Topics) { Topics.post = function(data, callback) { var uid = data.uid, - handle = data.handle, title = data.title, content = data.content, cid = data.cid; @@ -135,7 +134,7 @@ module.exports = function(Topics) { Topics.create({uid: uid, title: title, cid: cid, thumb: data.thumb, tags: data.tags}, next); }, function(tid, next) { - Topics.reply({uid:uid, tid:tid, handle: handle, content:content, req: data.req}, next); + Topics.reply({uid:uid, tid:tid, handle: data.handle, content:content, req: data.req}, next); }, function(postData, next) { async.parallel({ @@ -185,30 +184,23 @@ module.exports = function(Topics) { Topics.reply = function(data, callback) { var tid = data.tid, uid = data.uid, - toPid = data.toPid, - handle = data.handle, content = data.content, postData; async.waterfall([ function(next) { async.parallel({ - exists: function(next) { - Topics.exists(tid, next); - }, - locked: function(next) { - Topics.isLocked(tid, next); - }, - canReply: function(next) { - privileges.topics.can('topics:reply', tid, uid, next); - } + exists: async.apply(Topics.exists, tid), + locked: async.apply(Topics.isLocked, tid), + canReply: async.apply(privileges.topics.can, 'topics:reply', tid, uid), + isAdmin: async.apply(user.isAdministrator, uid) }, next); }, function(results, next) { if (!results.exists) { return next(new Error('[[error:no-topic]]')); } - if (results.locked) { + if (results.locked && !results.isAdmin) { return next(new Error('[[error:topic-locked]]')); } if (!results.canReply) { @@ -229,7 +221,7 @@ module.exports = function(Topics) { checkContentLength(content, next); }, function(next) { - posts.create({uid: uid, tid: tid, handle: handle, content: content, toPid: toPid, ip: data.req ? data.req.ip : null}, next); + posts.create({uid: uid, tid: tid, handle: data.handle, content: content, toPid: data.toPid, ip: data.req ? data.req.ip : null}, next); }, function(data, next) { postData = data; @@ -253,7 +245,7 @@ module.exports = function(Topics) { posts.getPidIndex(postData.pid, uid, next); }, content: function(next) { - postTools.parsePost(postData, uid, next); + postTools.parsePost(postData, next); } }, next); }, diff --git a/src/topics/teaser.js b/src/topics/teaser.js index 87e2baa86f..5946eef988 100644 --- a/src/topics/teaser.js +++ b/src/topics/teaser.js @@ -3,10 +3,13 @@ 'use strict'; var async = require('async'), + S = require('string'), db = require('../database'), user = require('../user'), posts = require('../posts'), + plugins = require('../plugins'), + postTools = require('../postTools'), utils = require('../../public/src/utils'); @@ -27,7 +30,7 @@ module.exports = function(Topics) { } }); - posts.getPostsFields(teaserPids, ['pid', 'uid', 'timestamp', 'tid'], function(err, postData) { + posts.getPostsFields(teaserPids, ['pid', 'uid', 'timestamp', 'tid', 'content'], function(err, postData) { if (err) { return callback(err); } @@ -48,20 +51,31 @@ module.exports = function(Topics) { users[user.uid] = user; }); var tidToPost = {}; - postData.forEach(function(post) { + + async.each(postData, function(post, next) { post.user = users[post.uid]; post.timestamp = utils.toISOString(post.timestamp); tidToPost[post.tid] = post; - }); - - var teasers = topics.map(function(topic, index) { - if (tidToPost[topic.tid]) { - tidToPost[topic.tid].index = counts[index]; + postTools.parsePost(post, next); + }, function(err) { + if (err) { + return callback(err); } - return tidToPost[topic.tid]; + var teasers = topics.map(function(topic, index) { + if (tidToPost[topic.tid]) { + tidToPost[topic.tid].index = counts[index]; + if (tidToPost[topic.tid].content) { + var s = S(tidToPost[topic.tid].content); + tidToPost[topic.tid].content = s.stripTags.apply(s, utils.stripTags).s; + } + } + return tidToPost[topic.tid]; + }); + + plugins.fireHook('filter:teasers.get', {teasers: teasers}, function(err, data) { + callback(err, data ? data.teasers : null); + }); }); - - callback(null, teasers); }); }); }; diff --git a/src/topics/unread.js b/src/topics/unread.js index e6910b9b5a..b9392d3eda 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -12,6 +12,8 @@ var async = require('async'), module.exports = function(Topics) { + var unreadCutoff = 86400000; + Topics.getTotalUnread = function(uid, callback) { Topics.getUnreadTids(uid, 0, 20, function(err, tids) { callback(err, tids ? tids.length : 0); @@ -54,17 +56,17 @@ module.exports = function(Topics) { return callback(null, []); } - var yesterday = Date.now() - 86400000; + var cutoff = Date.now() - unreadCutoff; async.parallel({ ignoredCids: function(next) { user.getIgnoredCategories(uid, next); }, recentTids: function(next) { - db.getSortedSetRevRangeByScoreWithScores('topics:recent', 0, -1, '+inf', yesterday, next); + db.getSortedSetRevRangeByScoreWithScores('topics:recent', 0, -1, '+inf', cutoff, next); }, userScores: function(next) { - db.getSortedSetRevRangeByScoreWithScores('uid:' + uid + ':tids_read', 0, -1, '+inf', yesterday, next); + db.getSortedSetRevRangeByScoreWithScores('uid:' + uid + ':tids_read', 0, -1, '+inf', cutoff, next); } }, function(err, results) { if (err) { @@ -178,7 +180,7 @@ module.exports = function(Topics) { } var now = Date.now(); - var scores = tids.map(function(tid) { + var scores = tids.map(function() { return now; }); @@ -247,8 +249,9 @@ module.exports = function(Topics) { if (err) { return callback(err); } + var cutoff = Date.now() - unreadCutoff; var result = tids.map(function(tid, index) { - return !!(results.userScores[index] && results.userScores[index] >= results.recentScores[index]); + return results.recentScores[index] < cutoff || !!(results.userScores[index] && results.userScores[index] >= results.recentScores[index]); }); callback(null, result); diff --git a/src/user.js b/src/user.js index 109e67a3f0..86e0d904be 100644 --- a/src/user.js +++ b/src/user.js @@ -120,7 +120,7 @@ var async = require('async'), if (user.picture) { if (user.picture === user.uploadedpicture) { - user.picture = user.uploadedpicture = user.picture.indexOf('http') === -1 ? nconf.get('relative_path') + user.picture : user.picture; + user.picture = user.uploadedpicture = user.picture.startsWith('http') ? user.picture : nconf.get('relative_path') + user.picture; } else { user.picture = User.createGravatarURLFromEmail(user.email); } @@ -158,7 +158,7 @@ var async = require('async'), if (now - parseInt(userOnlineTime, 10) < 300000) { return callback(); } - db.sortedSetAdd('users:online', now, uid, next); + db.sortedSetAdd('users:online', now, uid, next); }, function(next) { topics.pushUnreadCount(uid); @@ -334,6 +334,18 @@ var async = require('async'), db.getObjectField('username:uid', username, callback); }; + User.getUidsByUsernames = function(usernames, callback) { + db.getObjectFields('username:uid', usernames, function(err, users) { + if (err) { + return callback(err); + } + var uids = usernames.map(function(username) { + return users[username]; + }); + callback(null, uids); + }); + }; + User.getUidByUserslug = function(userslug, callback) { if (!userslug) { return callback(); @@ -403,15 +415,25 @@ var async = require('async'), }); var groupNames = uniqueCids.map(function(cid) { - return 'cid:' + cid + ':privileges:mods'; - }); + return 'cid:' + cid + ':privileges:mods'; // At some point we should *probably* change this to "moderate" as well + }), + groupListNames = uniqueCids.map(function(cid) { + return 'cid:' + cid + ':privileges:groups:moderate'; + }); - groups.isMemberOfGroups(uid, groupNames, function(err, isMembers) { + async.parallel({ + user: async.apply(groups.isMemberOfGroups, uid, groupNames), + group: async.apply(groups.isMemberOfGroupsList, uid, groupListNames) + }, function(err, checks) { if (err) { return callback(err); } - var map = {}; + var isMembers = checks.user.map(function(isMember, idx) { + return isMember || checks.group[idx] + }), + map = {}; + uniqueCids.forEach(function(cid, index) { map[cid] = isMembers[index]; }); @@ -422,9 +444,23 @@ var async = require('async'), }); } else { if (Array.isArray(uid)) { - groups.isMembers(uid, 'cid:' + cid + ':privileges:mods', filterIsModerator); + async.parallel([ + async.apply(groups.isMembers, uid, 'cid:' + cid + ':privileges:mods'), + async.apply(groups.isMembers, uid, 'cid:' + cid + ':privileges:groups:moderate') + ], function(err, checks) { + var isModerator = checks[0].map(function(isMember, idx) { + return isMember || checks[1][idx] + }); + filterIsModerator(null, isModerator); + }); } else { - groups.isMember(uid, 'cid:' + cid + ':privileges:mods', filterIsModerator); + async.parallel([ + async.apply(groups.isMember, uid, 'cid:' + cid + ':privileges:mods'), + async.apply(groups.isMember, uid, 'cid:' + cid + ':privileges:groups:moderate') + ], function(err, checks) { + var isModerator = checks[0] || checks[1]; + filterIsModerator(null, isModerator); + }); } } }; diff --git a/src/user/digest.js b/src/user/digest.js index 06ea1aa967..02799c0bf3 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -46,7 +46,6 @@ var async = require('async'), return topicObj; }); - return; data.interval = interval; diff --git a/src/user/notifications.js b/src/user/notifications.js index c3ea4b9c23..fe9ffc80b8 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -109,34 +109,38 @@ var async = require('async'), return callback(err); } - var pids = notifications.map(function(notification) { - return notification ? notification.pid : null; - }); + UserNotifications.generateNotificationPaths(notifications, uid, callback); + }); + }; - generatePostPaths(pids, uid, function(err, pidToPaths) { - if (err) { - return callback(err); - } + UserNotifications.generateNotificationPaths = function (notifications, uid, callback) { + var pids = notifications.map(function(notification) { + return notification ? notification.pid : null; + }); - notifications = notifications.map(function(notification, index) { - if (!notification) { - return null; - } + generatePostPaths(pids, uid, function(err, pidToPaths) { + if (err) { + return callback(err); + } - notification.path = pidToPaths[notification.pid] || notification.path || ''; + notifications = notifications.map(function(notification, index) { + if (!notification) { + return null; + } - if (notification.nid.startsWith('chat')) { - notification.path = nconf.get('relative_path') + '/chats/' + notification.user.userslug; - } else if (notification.nid.startsWith('follow')) { - notification.path = nconf.get('relative_path') + '/user/' + notification.user.userslug; - } + notification.path = pidToPaths[notification.pid] || notification.path || ''; - notification.datetimeISO = utils.toISOString(notification.datetime); - return notification; - }); + if (notification.nid.startsWith('chat')) { + notification.path = nconf.get('relative_path') + '/chats/' + notification.user.userslug; + } else if (notification.nid.startsWith('follow')) { + notification.path = nconf.get('relative_path') + '/user/' + notification.user.userslug; + } - callback(null, notifications); + notification.datetimeISO = utils.toISOString(notification.datetime); + return notification; }); + + callback(null, notifications); }); }; diff --git a/src/user/posts.js b/src/user/posts.js index 10b6a581ba..c7d8e230be 100644 --- a/src/user/posts.js +++ b/src/user/posts.js @@ -84,6 +84,9 @@ module.exports = function(User) { if (err) { return callback(err); } + if (!parseInt(uid, 10)) { + return callback(); + } db.sortedSetAdd('users:postcount', newpostcount, uid, callback); }); }; diff --git a/src/user/profile.js b/src/user/profile.js index 829c143505..f16046ee4a 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -15,14 +15,15 @@ var async = require('async'), module.exports = function(User) { User.updateProfile = function(uid, data, callback) { + var fields = ['username', 'email', 'fullname', 'website', 'location', 'birthday', 'signature']; - plugins.fireHook('filter:user.updateProfile', {uid: uid, settings: data}, function(err, data) { - if(err) { + plugins.fireHook('filter:user.updateProfile', {uid: uid, data: data, fields: fields}, function(err, data) { + if (err) { return callback(err); } - data = data.settings; - var fields = ['username', 'email', 'fullname', 'website', 'location', 'birthday', 'signature']; + fields = data.fields; + data = data.data; function isSignatureValid(next) { if (data.signature !== undefined && data.signature.length > meta.config.maximumSignatureLength) { diff --git a/src/views/admin/advanced/events.tpl b/src/views/admin/advanced/events.tpl index d5942f4225..747f9e03db 100644 --- a/src/views/admin/advanced/events.tpl +++ b/src/views/admin/advanced/events.tpl @@ -10,7 +10,7 @@ <!-- BEGIN events --> <div> <span>#{events.eid} </span><span class="label label-info">{events.type}</span> - <a href="{config.relative_path}/user/{events.user.userslug}" target="_blank"><img class="user-img" src="{events.user.picture}"/></a> <a href="{config.relative_path}/user/{events.user.userslug}">{events.user.username}</a> (uid {events.user.uid}) (IP {events.ip}) + <a href="{config.relative_path}/user/{events.user.userslug}" target="_blank"><img class="user-img" src="{events.user.picture}"/></a> <a href="{config.relative_path}/user/{events.user.userslug}" target="_blank">{events.user.username}</a> (uid {events.user.uid}) (IP {events.ip}) <span class="pull-right">{events.timestampISO}</span> <br/><br/> <pre>{events.jsonString}</pre> diff --git a/src/views/admin/general/dashboard.tpl b/src/views/admin/general/dashboard.tpl index 759144152d..db18b7cf02 100644 --- a/src/views/admin/general/dashboard.tpl +++ b/src/views/admin/general/dashboard.tpl @@ -1,6 +1,5 @@ <div class="row dashboard"> - <!-- Override for now, until the right sidebar graphs are fixed (pending socket.io resolution) --> - <div class="col-lg-12"> + <div class="col-lg-9"> <div class="panel panel-default"> <div class="panel-heading">Forum Traffic</div> <div class="panel-body"> @@ -88,8 +87,8 @@ </div> </div> </div> - <!-- Override for now, until the right sidebar graphs are fixed (pending socket.io resolution) --> - <div class="col-lg-3 hide"> + + <div class="col-lg-3"> <div class="panel panel-default"> <div class="panel-heading">Anonymous vs Registered Users</div> <div class="panel-body"> @@ -108,10 +107,11 @@ <div class="panel-body"> <div class="graph-container pie-chart legend-up"> <ul class="graph-legend"> - <li><div class="on-homepage"></div><span>On Homepage</span></li> + <li><div class="on-categories"></div><span>On categories list</span></li> <li><div class="reading-posts"></div><span>Reading posts</span></li> <li><div class="browsing-topics"></div><span>Browsing topics</span></li> - <li><div class="idle"></div><span>Idle</span></li> + <li><div class="recent"></div><span>Recent / Unread</span></li> + <li><div class="tags"></div><span>Tags</span></li> </ul> <canvas id="analytics-presence"></canvas> </div> diff --git a/src/views/admin/manage/categories.tpl b/src/views/admin/manage/categories.tpl index 8d4367bb2e..69526e86b4 100644 --- a/src/views/admin/manage/categories.tpl +++ b/src/views/admin/manage/categories.tpl @@ -1,156 +1,119 @@ -<div class="categories"> +<div class="row"> <div class="col-lg-9"> <div class="panel panel-default"> <div class="panel-heading"><i class="fa fa-folder"></i> Categories</div> <div class="panel-body"> - <ul class="nav nav-pills"> - <li class='active'><a href='/admin/manage/categories/active'>Active</a></li> - <li class=''><a href='/admin/manage/categories/disabled'>Disabled</a></li> - </ul> - - <div class="row admin-categories"> - <ul class="col-md-12" id="entry-container"> - <!-- BEGIN categories --> - <li data-cid="{categories.cid}" class="entry-row"> - <div class="well"> - <form class="form"> - <div class="row"> - <div class="col-sm-2 hidden-xs text-center"> - <div class="preview-box" style=" - <!-- IF categories.backgroundImage -->background-image: url({categories.backgroundImage});<!-- ENDIF categories.backgroundImage --> - <!-- IF categories.bgColor -->background-color: {categories.bgColor};<!-- ENDIF categories.bgColor --> - color: {categories.color}; - background-size:cover; - "> - <div class="icon"> - <i data-name="icon" value="{categories.icon}" class="fa {categories.icon} fa-2x"></i> - </div> - </div><br /> - <button type="button" data-name="image" data-value="{categories.image}" class="btn btn-default upload-button"><i class="fa fa-upload"></i> Image</button> - <!-- IF categories.image --> - <br/> - <small class="pointer delete-image"><i data-name="icon" value="fa-times" class="fa fa-times"></i> Delete Image</small> - <!-- ENDIF categories.image --> - </div> - <div class="col-sm-10"> - <div class="pull-right text-right"> - <div class="form-group"> - <div class="dropdown"> - <button type="button" class="btn btn-default" data-toggle="dropdown"><i class="fa fa-cogs"></i> Options</button> - <ul class="dropdown-menu" role="menu"> - <li class="permissions"><a href="#"><i class="fa fa-ban"></i> Access Control</a></li> - <hr /> - <li data-disabled="{categories.disabled}"> - <!-- IF categories.disabled --> - <a href="#"><i class="fa fa-power-off"></i> Enable</a> - <!-- ELSE --> - <a href="#"><i class="fa fa-power-off"></i> Disable</a> - <!-- ENDIF categories.disabled --> - </li> - <li><a href="#" class="purge"><i class="fa fa-eraser"></i> Purge</a></li> - <li><a href="#" class="duplicate"><i class="fa fa-copy"></i> Duplicate</a></li> - </ul> - - - <button class="btn btn-primary save">Save</button> - - </div> - </div> - </div> - <h3 data-edit-target="#cid-{categories.cid}-name"><span>{categories.name}</span> <small><i class="fa fa-edit"></i></small></h3> - <input id="cid-{categories.cid}-name" type="text" class="form-control hide" placeholder="Category Name" data-name="name" value="{categories.name}" /> - <h4 data-edit-target="#cid-{categories.cid}-description"><span>{categories.description}</span> <small><i class="fa fa-edit"></i></small></h4> - <input id="cid-{categories.cid}-description" data-name="description" placeholder="Category Description" value="{categories.description}" class="form-control category_description input-sm description hide"></input> - - <fieldset> - <div class="col-xs-12"> - <div class="form-group"> - <label for="cid-{categories.cid}-parentCid">Parent Category</label> - <!-- IF categories.parent.name --> - <div class="btn-group"> - <button type="button" class="btn btn-default" data-action="setParent" data-parentCid="{categories.parent.cid}"><i class="fa {categories.parent.icon}"></i> {categories.parent.name}</button> - <button type="button" class="btn btn-warning" data-action="removeParent" data-parentCid="{categories.parent.cid}"><i class="fa fa-times"></i></button> - </div> - <!-- ELSE --> - <button type="button" class="btn btn-default form-control" data-action="setParent"><i class="fa fa-sitemap"></i> (None)</button> - <!-- ENDIF categories.parent.name --> - </div> - </div> - </fieldset> - <fieldset> - <div class="col-sm-4 col-xs-12"> - <div class="form-group"> - <label for="cid-{categories.cid}-bgColor">Background Colour</label> - <input id="cid-{categories.cid}-bgColor" placeholder="#0059b2" data-name="bgColor" value="{categories.bgColor}" class="form-control category_bgColor" /> - </div> - </div> - <div class="col-sm-4 col-xs-12"> - <div class="form-group"> - <label for="cid-{categories.cid}-color">Text Colour</label> - <input id="cid-{categories.cid}-color" placeholder="#fff" data-name="color" value="{categories.color}" class="form-control category_color" /> - </div> - </div> - <div class="col-sm-4 col-xs-12"> - <div class="form-group"> - <label for="cid-{categories.cid}-imageClass">Image Class</label> - <select id="cid-{categories.cid}-imageClass" class="form-control" data-name="imageClass" data-value="{categories.imageClass}"> - <option value="auto">auto</option> - <option value="cover">cover</option> - <option value="contain">contain</option> - </select> - </div> - </div> - <div class="col-sm-4 col-xs-12"> - <div class="form-group"> - <label for="cid-{categories.cid}-class">Custom Class</label> - <input id="cid-{categories.cid}-class" type="text" class="form-control" placeholder="col-md-6 col-xs-6" data-name="class" value="{categories.class}" /> - </div> - </div> - <div class="col-sm-4 col-xs-12"> - <div class="form-group"> - <label for="cid-{categories.cid}-numRecentReplies"># of Recent Replies Displayed</label> - <input id="cid-{categories.cid}-numRecentReplies" type="text" class="form-control" placeholder="2" data-name="numRecentReplies" value="{categories.numRecentReplies}" /> - </div> - </div> - <div class="col-sm-4 col-xs-12"> - <div class="form-group"> - <label for="cid-{categories.cid}-link">External Link</label> - <input id="cid-{categories.cid}-link" type="text" class="form-control" placeholder="http://domain.com" data-name="link" value="{categories.link}" /> - </div> - </div> - </fieldset> - - <input type="hidden" data-name="order" data-value="{categories.order}"></input> - </div> - </div> - </form> - </div> - </li> - <!-- END categories --> - </ul> - </div> + <table class="table table-striped table-hover table-reordering"> + <thead> + <tr> + <th></th> + <th>Name</th> + <th>Description</th> + <th class="text-center">Topics</th> + <th class="text-center">Posts</th> + <th></th> + </tr> + </thead> + <tbody id="active-categories"> + <!-- IF active.length --> + <!-- BEGIN active --> + <tr data-cid="{active.cid}"> + <td> + <span class="label" style=" + <!-- IF active.backgroundImage -->background-image: url({active.backgroundImage});<!-- ENDIF active.backgroundImage --> + <!-- IF active.bgColor -->background-color: {active.bgColor};<!-- ENDIF active.bgColor --> + color: {active.color}; + background-size:cover; + "> + <i data-name="icon" value="{active.icon}" class="fa fa-fw {active.icon}"></i> + </span> + </td> + <td>{active.name}</td> + <td>{active.description}</td> + <td class="text-center">{active.topic_count}</td> + <td class="text-center">{active.post_count}</td> + <td> + <div class="btn-group"> + <a href="./categories/{active.cid}" class="btn btn-default btn-xs">Edit</a> + <button data-action="toggle" data-disabled="{active.disabled}" class="btn btn-default btn-xs">Disable</button> + </div> + </td> + </tr> + <!-- END active --> + <!-- ELSE --> + <tr> + <td colspan="6"> + <div class="alert alert-info text-center"> + You have no active categories. + </div> + </td> + </tr> + <!-- ENDIF active.length --> + </tbody> + </table> </div> </div> - </div> - <div class="col-lg-3 acp-sidebar"> <div class="panel panel-default"> - <div class="panel-heading">Categories Control Panel</div> + <div class="panel-heading"><i class="fa fa-folder"></i> Categories</div> <div class="panel-body"> - <button class="btn btn-primary" id="addNew">Create New Category</button> - <button class="btn btn-default" id="revertChanges">Revert Changes</button> + <table class="table table-striped table-hover table-reordering"> + <thead> + <tr> + <th></th> + <th>Name</th> + <th>Description</th> + <th class="text-center">Topics</th> + <th class="text-center">Posts</th> + <th></th> + </tr> + </thead> + <tbody id="disabled-categories"> + <!-- IF disabled.length --> + <!-- BEGIN disabled --> + <tr data-cid="{disabled.cid}"> + <td> + <span class="label" style=" + <!-- IF disabled.backgroundImage -->background-image: url({disabled.backgroundImage});<!-- ENDIF disabled.backgroundImage --> + <!-- IF disabled.bgColor -->background-color: {disabled.bgColor};<!-- ENDIF disabled.bgColor --> + color: {disabled.color}; + background-size:cover; + "> + <i data-name="icon" value="{disabled.icon}" class="fa fa-fw {disabled.icon}"></i> + </span> + </td> + <td>{disabled.name}</td> + <td>{disabled.description}</td> + <td class="text-center">{disabled.topic_count}</td> + <td class="text-center">{disabled.post_count}</td> + <td> + <div class="btn-group"> + <a href="./categories/{disabled.cid}" class="btn btn-default btn-xs">Edit</a> + <button data-action="toggle" data-disabled="{disabled.disabled}" class="btn btn-default btn-xs">Enable</button> + </div> + </td> + </tr> + <!-- END disabled --> + <!-- ELSE --> + <tr> + <td colspan="6"> + <div class="alert alert-info text-center"> + You have no disabled categories. + </div> + </td> + </tr> + <!-- ENDIF disabled.length --> + </tbody> + </table> </div> </div> </div> - - <!-- IMPORT admin/partials/categories/new.tpl --> - <!-- IMPORT admin/partials/categories/permissions.tpl --> - <!-- IMPORT admin/partials/categories/setParent.tpl --> - <div id="icons" style="display:none;"> - <div class="icon-container"> - <div class="row fa-icons"> - <i class="fa fa-doesnt-exist"></i> - <!-- IMPORT partials/fontawesome.tpl --> + + <div class="col-lg-3 acp-sidebar"> + <div class="panel panel-default"> + <div class="panel-heading">Categories Control Panel</div> + <div class="panel-body"> + <button type="button" class="btn btn-primary btn-block" data-action="create">Create New Category</button> </div> </div> </div> diff --git a/src/views/admin/manage/category.tpl b/src/views/admin/manage/category.tpl new file mode 100644 index 0000000000..80b5dbe694 --- /dev/null +++ b/src/views/admin/manage/category.tpl @@ -0,0 +1,146 @@ +<div class="row"> + <form role="form" class="category" data-cid="{category.cid}"> + <div class="col-md-9"> + <div class="panel panel-default"> + <div class="panel-heading"><i class="fa fa-folder"></i> Category Settings</div> + <div class="panel-body category-settings-form"> + <fieldset> + <div class="col-xs-12"> + <h3 data-edit-target="#cid-{category.cid}-name"><span>{category.name}</span> <small><i class="fa fa-edit"></i></small></h3> + <input id="cid-{category.cid}-name" type="text" class="form-control hide" placeholder="Category Name" data-name="name" value="{category.name}" /> + <h4 data-edit-target="#cid-{category.cid}-description"><span>{category.description}</span> <small><i class="fa fa-edit"></i></small></h4> + <input id="cid-{category.cid}-description" data-name="description" placeholder="Category Description" value="{category.description}" class="form-control category_description input-sm description hide"></input> + </div> + </fieldset> + + <fieldset> + <div class="col-xs-12"> + <div class="form-group"> + <label for="cid-{category.cid}-parentCid">Parent Category</label> + <!-- IF category.parent.name --> + <br /> + <div class="btn-group"> + <button type="button" class="btn btn-default" data-action="setParent" data-parentCid="{category.parent.cid}"><i class="fa {category.parent.icon}"></i> {category.parent.name}</button> + <button type="button" class="btn btn-warning" data-action="removeParent" data-parentCid="{category.parent.cid}"><i class="fa fa-times"></i></button> + </div> + <!-- ELSE --> + <button type="button" class="btn btn-default form-control" data-action="setParent"><i class="fa fa-sitemap"></i> (None)</button> + <!-- ENDIF category.parent.name --> + </div> + </div> + </fieldset> + <fieldset> + <div class="col-sm-4 col-xs-12"> + <div class="form-group"> + <label for="cid-{category.cid}-bgColor">Background Colour</label> + <input id="cid-{category.cid}-bgColor" placeholder="#0059b2" data-name="bgColor" value="{category.bgColor}" class="form-control category_bgColor" /> + </div> + </div> + <div class="col-sm-4 col-xs-12"> + <div class="form-group"> + <label for="cid-{category.cid}-color">Text Colour</label> + <input id="cid-{category.cid}-color" placeholder="#fff" data-name="color" value="{category.color}" class="form-control category_color" /> + </div> + </div> + <div class="col-sm-4 col-xs-12"> + <div class="form-group"> + <label for="cid-{category.cid}-imageClass">Image Class</label> + <select id="cid-{category.cid}-imageClass" class="form-control" data-name="imageClass" data-value="{category.imageClass}"> + <option value="auto">auto</option> + <option value="cover">cover</option> + <option value="contain">contain</option> + </select> + </div> + </div> + <div class="col-sm-4 col-xs-12"> + <div class="form-group"> + <label for="cid-{category.cid}-class">Custom Class</label> + <input id="cid-{category.cid}-class" type="text" class="form-control" placeholder="col-md-6 col-xs-6" data-name="class" value="{category.class}" /> + </div> + </div> + <div class="col-sm-4 col-xs-12"> + <div class="form-group"> + <label for="cid-{category.cid}-numRecentReplies"># of Recent Replies</label> + <input id="cid-{category.cid}-numRecentReplies" type="text" class="form-control" placeholder="2" data-name="numRecentReplies" value="{category.numRecentReplies}" /> + </div> + </div> + <div class="col-sm-4 col-xs-12"> + <div class="form-group"> + <label for="cid-{category.cid}-link">External Link</label> + <input id="cid-{category.cid}-link" type="text" class="form-control" placeholder="http://domain.com" data-name="link" value="{category.link}" /> + </div> + </div> + </fieldset> + </div> + </div> + + <div class="panel panel-default"> + <div class="panel-heading"><i class="fa fa-key"></i> Privileges / Access Control</div> + <div class="panel-body"> + <p> + You can configure the access control privileges for this category in this section. Privileges can be granted on a per-user or + a per-group basis. You can add a new user to this table by searching for them in the form below. + </p> + <p class="text-warning"> + <strong>Note</strong>: Privilege settings take effect immediately. It is not necessary to save the category after adjusting + these settings. + </p> + <hr /> + <input class="form-control privilege-search" type="text" placeholder="Add a user or group to this list..." /> + <hr /> + <!-- IMPORT admin/partials/categories/privileges.tpl --> + </div> + </div> + </div> + + <div class="col-md-3 options acp-sidebar"> + <div class="panel panel-default hidden-sm"> + <div class="panel-heading">Preview</div> + <div class="panel-body"> + <div class="category-preview" style=" + <!-- IF category.backgroundImage -->background-image: url({category.backgroundImage});<!-- ENDIF category.backgroundImage --> + <!-- IF category.bgColor -->background-color: {category.bgColor};<!-- ENDIF category.bgColor --> + color: {category.color}; + background-size:cover; + "> + <div class="icon"> + <i data-name="icon" value="{category.icon}" class="fa {category.icon} fa-2x"></i> + </div> + </div> + <div class="btn-group btn-group-justified"> + <div class="btn-group"> + <button type="button" data-cid="{category.cid}" data-name="image" data-value="{category.image}" class="btn btn-default upload-button"><i class="fa fa-upload"></i> Upload</button> + </div> + <!-- IF category.image --> + <div class="btn-group"> + <button class="btn btn-warning delete-image"><i data-name="icon" value="fa-times" class="fa fa-times"></i> Remove</button> + </div> + <!-- ENDIF category.image --> + </div> + </div> + </div> + + <div class="panel panel-default"> + <div class="panel-heading">Categories Control Panel</div> + <div class="panel-body"> + <div class="btn-group btn-group-justified"> + <div class="btn-group"> + <button class="btn btn-primary save">Save</button> + </div> + <div class="btn-group"> + <button class="btn btn-default revert">Revert</button> + </div> + </div> + <hr /> + <button class="btn btn-danger btn-block btn-xs purge"><i class="fa fa-eraser"></i> Purge Category</button> + <p class="help-block"> + Purging a category will remove all topics and posts, and delete the category from the database. If you want to + remove a category <em>temporarily</em>, you'll want to "disable" the category instead. + </p> + </div> + </div> + </div> + </form> +</div> + +<input type="hidden" template-variable="cid" value="{category.cid}" /> \ No newline at end of file diff --git a/src/views/admin/partials/categories/new.tpl b/src/views/admin/partials/categories/new.tpl deleted file mode 100644 index e45d87f3bf..0000000000 --- a/src/views/admin/partials/categories/new.tpl +++ /dev/null @@ -1,41 +0,0 @@ - <div id="new-category-modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="Add New Modal" aria-hidden="true"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> - <h3>Create New Category</h3> - </div> - <div class="modal-body"> - <div> - <form class='form-horizontal'> - <div class="control-group"> - <label class="control-label" for="inputName">Name</label> - <div class="controls"> - <input class="form-control" type="text" id="inputName" placeholder="Name" value=""> - </div> - </div> - - <div class="control-group"> - <label class="control-label" for="inputDescription">Description</label> - <div class="controls"> - <input class="form-control" type="text" id="inputDescription" placeholder="Description" value=""> - </div> - </div> - - <div class="control-group"> - <label class="control-label" for="inputIcon">Icon</label> - <div class="controls"> - <div class="icon"> - <i data-name="icon" value="fa-pencil" class="fa fa-pencil fa-2x"></i> - </div> - </div> - </div> - </form> - </div> - </div> - <div class="modal-footer"> - <button type="button" id="create-category-btn" href="#" class="btn btn-primary btn-lg btn-block">Create</button> - </div> - </div><!-- /.modal-content --> - </div><!-- /.modal-dialog --> - </div><!-- /.modal --> \ No newline at end of file diff --git a/src/views/admin/partials/categories/permissions.tpl b/src/views/admin/partials/categories/permissions.tpl deleted file mode 100644 index a8077e2aa4..0000000000 --- a/src/views/admin/partials/categories/permissions.tpl +++ /dev/null @@ -1,32 +0,0 @@ - <div id="category-permissions-modal" class="modal permissions-modal fade" tabindex="-1" role="dialog" aria-labelledby="Category Permissions" aria-hidden="true"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> - <h3>Category Permissions</h3> - </div> - <div class="modal-body"> - <p>The following users have access control permissions in this Category</p> - <ul class="members"></ul> - - <hr /> - <form role="form"> - <div class="form-group"> - <label for="permission-search">User Search</label> - <input class="form-control" type="text" id="permission-search" /> - </div> - </form> - <ul class="search-results users"></ul> - - <hr /> - <form role="form"> - <div class="form-group"> - <label for="permission-group-pick">User Groups</label> - </div> - </form> - <ul class="search-results groups"></ul> - - </div> - </div> - </div> - </div> \ No newline at end of file diff --git a/src/views/admin/partials/categories/privileges.tpl b/src/views/admin/partials/categories/privileges.tpl new file mode 100644 index 0000000000..b6b33ac42b --- /dev/null +++ b/src/views/admin/partials/categories/privileges.tpl @@ -0,0 +1,45 @@ + <div class="privilege-table-container"> + <table class="table table-striped table-hover privilege-table"> + <tr> + <th colspan="2">User</th> + <!-- BEGIN privileges.labels.users --> + <th class="text-center">{privileges.labels.users.name}</th> + <!-- END privileges.labels.users --> + </tr> + <!-- IF privileges.users.length --> + <!-- BEGIN privileges.users --> + <tr data-uid="{uid}"> + <td><img src="{picture}" title="{username}" /></td> + <td>{username}</td> + {function.spawnPrivilegeStates, username, privileges} + </tr> + <!-- END privileges.users --> + <!-- ELSE --> + <tr> + <td colspan="{privileges.columnCount}"> + <div class="alert alert-info">No user-specific privileges in this category.</div> + </td> + </tr> + <!-- ENDIF privileges.users.length --> + </table> + + <table class="table table-striped table-hover privilege-table"> + <tr> + <th colspan="1">Group</th> + <!-- BEGIN privileges.labels.groups --> + <th class="text-center">{privileges.labels.groups.name}</th> + <!-- END privileges.labels.groups --> + </tr> + <!-- BEGIN privileges.groups --> + <tr data-group-name="{privileges.groups.name}" data-private="<!-- IF privileges.groups.isPrivate -->1<!-- ELSE -->0<!-- ENDIF privileges.groups.isPrivate -->"> + <td> + <!-- IF privileges.groups.isPrivate --> + <i class="fa fa-lock text-muted" title="This group is private"></i> + <!-- ENDIF privileges.groups.isPrivate --> + {privileges.groups.name} + </td> + {function.spawnPrivilegeStates, name, privileges} + </tr> + <!-- END privileges.groups --> + </table> + </div> \ No newline at end of file diff --git a/src/views/admin/settings/post.tpl b/src/views/admin/settings/post.tpl index 2ec28c23a1..4f4314228d 100644 --- a/src/views/admin/settings/post.tpl +++ b/src/views/admin/settings/post.tpl @@ -54,7 +54,7 @@ <input type="number" class="form-control" value="8" data-field="minimumPostLength"> </div> <div class="form-group"> - <label>Minimum Post Length</label> + <label>Maximum Post Length</label> <input type="number" class="form-control" value="32767" data-field="maximumPostLength"> </div> <div class="checkbox"> diff --git a/src/views/partials/data/category.tpl b/src/views/partials/data/category.tpl new file mode 100644 index 0000000000..2144c8a84c --- /dev/null +++ b/src/views/partials/data/category.tpl @@ -0,0 +1 @@ +data-tid="{topics.tid}" data-index="{topics.index}" data-cid="{topics.cid}" itemprop="itemListElement" \ No newline at end of file diff --git a/src/views/partials/data/topic.tpl b/src/views/partials/data/topic.tpl new file mode 100644 index 0000000000..125926e94f --- /dev/null +++ b/src/views/partials/data/topic.tpl @@ -0,0 +1 @@ +data-pid="{posts.pid}" data-uid="{posts.uid}" data-username="{posts.user.username}" data-userslug="{posts.user.userslug}" data-index="{posts.index}" data-timestamp="{posts.timestamp}" data-votes="{posts.votes}" itemscope itemtype="http://schema.org/Comment" \ No newline at end of file diff --git a/src/views/partials/fontawesome.tpl b/src/views/partials/fontawesome.tpl new file mode 100644 index 0000000000..c5c768fc42 --- /dev/null +++ b/src/views/partials/fontawesome.tpl @@ -0,0 +1,6 @@ +<div class="icon-container"> + <div class="row fa-icons"> + <i class="fa fa-doesnt-exist"></i> + <i class="fa fa-adjust"></i><i class="fa fa-adn"></i><i class="fa fa-align-center"></i><i class="fa fa-align-justify"></i><i class="fa fa-align-left"></i><i class="fa fa-align-right"></i><i class="fa fa-ambulance"></i><i class="fa fa-anchor"></i><i class="fa fa-android"></i><i class="fa fa-angellist"></i><i class="fa fa-angle-double-down"></i><i class="fa fa-angle-double-left"></i><i class="fa fa-angle-double-right"></i><i class="fa fa-angle-double-up"></i><i class="fa fa-angle-down"></i><i class="fa fa-angle-left"></i><i class="fa fa-angle-right"></i><i class="fa fa-angle-up"></i><i class="fa fa-apple"></i><i class="fa fa-archive"></i><i class="fa fa-area-chart"></i><i class="fa fa-arrow-circle-down"></i><i class="fa fa-arrow-circle-left"></i><i class="fa fa-arrow-circle-o-down"></i><i class="fa fa-arrow-circle-o-left"></i><i class="fa fa-arrow-circle-o-right"></i><i class="fa fa-arrow-circle-o-up"></i><i class="fa fa-arrow-circle-right"></i><i class="fa fa-arrow-circle-up"></i><i class="fa fa-arrow-down"></i><i class="fa fa-arrow-left"></i><i class="fa fa-arrow-right"></i><i class="fa fa-arrow-up"></i><i class="fa fa-arrows"></i><i class="fa fa-arrows-alt"></i><i class="fa fa-arrows-h"></i><i class="fa fa-arrows-v"></i><i class="fa fa-asterisk"></i><i class="fa fa-at"></i><i class="fa fa-backward"></i><i class="fa fa-ban"></i><i class="fa fa-bar-chart"></i><i class="fa fa-barcode"></i><i class="fa fa-bars"></i><i class="fa fa-beer"></i><i class="fa fa-behance"></i><i class="fa fa-behance-square"></i><i class="fa fa-bell"></i><i class="fa fa-bell-o"></i><i class="fa fa-bell-slash"></i><i class="fa fa-bell-slash-o"></i><i class="fa fa-bicycle"></i><i class="fa fa-binoculars"></i><i class="fa fa-birthday-cake"></i><i class="fa fa-bitbucket"></i><i class="fa fa-bitbucket-square"></i><i class="fa fa-bold"></i><i class="fa fa-bolt"></i><i class="fa fa-bomb"></i><i class="fa fa-book"></i><i class="fa fa-bookmark"></i><i class="fa fa-bookmark-o"></i><i class="fa fa-briefcase"></i><i class="fa fa-btc"></i><i class="fa fa-bug"></i><i class="fa fa-building"></i><i class="fa fa-building-o"></i><i class="fa fa-bullhorn"></i><i class="fa fa-bullseye"></i><i class="fa fa-bus"></i><i class="fa fa-calculator"></i><i class="fa fa-calendar"></i><i class="fa fa-calendar-o"></i><i class="fa fa-camera"></i><i class="fa fa-camera-retro"></i><i class="fa fa-car"></i><i class="fa fa-caret-down"></i><i class="fa fa-caret-left"></i><i class="fa fa-caret-right"></i><i class="fa fa-caret-square-o-down"></i><i class="fa fa-caret-square-o-left"></i><i class="fa fa-caret-square-o-right"></i><i class="fa fa-caret-square-o-up"></i><i class="fa fa-caret-up"></i><i class="fa fa-cc"></i><i class="fa fa-cc-amex"></i><i class="fa fa-cc-discover"></i><i class="fa fa-cc-mastercard"></i><i class="fa fa-cc-paypal"></i><i class="fa fa-cc-stripe"></i><i class="fa fa-cc-visa"></i><i class="fa fa-certificate"></i><i class="fa fa-chain-broken"></i><i class="fa fa-check"></i><i class="fa fa-check-circle"></i><i class="fa fa-check-circle-o"></i><i class="fa fa-check-square"></i><i class="fa fa-check-square-o"></i><i class="fa fa-chevron-circle-down"></i><i class="fa fa-chevron-circle-left"></i><i class="fa fa-chevron-circle-right"></i><i class="fa fa-chevron-circle-up"></i><i class="fa fa-chevron-down"></i><i class="fa fa-chevron-left"></i><i class="fa fa-chevron-right"></i><i class="fa fa-chevron-up"></i><i class="fa fa-child"></i><i class="fa fa-circle"></i><i class="fa fa-circle-o"></i><i class="fa fa-circle-o-notch"></i><i class="fa fa-circle-thin"></i><i class="fa fa-clipboard"></i><i class="fa fa-clock-o"></i><i class="fa fa-cloud"></i><i class="fa fa-cloud-download"></i><i class="fa fa-cloud-upload"></i><i class="fa fa-code"></i><i class="fa fa-code-fork"></i><i class="fa fa-codepen"></i><i class="fa fa-coffee"></i><i class="fa fa-cog"></i><i class="fa fa-cogs"></i><i class="fa fa-columns"></i><i class="fa fa-comment"></i><i class="fa fa-comment-o"></i><i class="fa fa-comments"></i><i class="fa fa-comments-o"></i><i class="fa fa-compass"></i><i class="fa fa-compress"></i><i class="fa fa-copyright"></i><i class="fa fa-credit-card"></i><i class="fa fa-crop"></i><i class="fa fa-crosshairs"></i><i class="fa fa-css3"></i><i class="fa fa-cube"></i><i class="fa fa-cubes"></i><i class="fa fa-cutlery"></i><i class="fa fa-database"></i><i class="fa fa-delicious"></i><i class="fa fa-desktop"></i><i class="fa fa-deviantart"></i><i class="fa fa-digg"></i><i class="fa fa-dot-circle-o"></i><i class="fa fa-download"></i><i class="fa fa-dribbble"></i><i class="fa fa-dropbox"></i><i class="fa fa-drupal"></i><i class="fa fa-eject"></i><i class="fa fa-ellipsis-h"></i><i class="fa fa-ellipsis-v"></i><i class="fa fa-empire"></i><i class="fa fa-envelope"></i><i class="fa fa-envelope-o"></i><i class="fa fa-envelope-square"></i><i class="fa fa-eraser"></i><i class="fa fa-eur"></i><i class="fa fa-exchange"></i><i class="fa fa-exclamation"></i><i class="fa fa-exclamation-circle"></i><i class="fa fa-exclamation-triangle"></i><i class="fa fa-expand"></i><i class="fa fa-external-link"></i><i class="fa fa-external-link-square"></i><i class="fa fa-eye"></i><i class="fa fa-eye-slash"></i><i class="fa fa-eyedropper"></i><i class="fa fa-facebook"></i><i class="fa fa-facebook-square"></i><i class="fa fa-fast-backward"></i><i class="fa fa-fast-forward"></i><i class="fa fa-fax"></i><i class="fa fa-female"></i><i class="fa fa-fighter-jet"></i><i class="fa fa-file"></i><i class="fa fa-file-archive-o"></i><i class="fa fa-file-audio-o"></i><i class="fa fa-file-code-o"></i><i class="fa fa-file-excel-o"></i><i class="fa fa-file-image-o"></i><i class="fa fa-file-o"></i><i class="fa fa-file-pdf-o"></i><i class="fa fa-file-powerpoint-o"></i><i class="fa fa-file-text"></i><i class="fa fa-file-text-o"></i><i class="fa fa-file-video-o"></i><i class="fa fa-file-word-o"></i><i class="fa fa-files-o"></i><i class="fa fa-film"></i><i class="fa fa-filter"></i><i class="fa fa-fire"></i><i class="fa fa-fire-extinguisher"></i><i class="fa fa-flag"></i><i class="fa fa-flag-checkered"></i><i class="fa fa-flag-o"></i><i class="fa fa-flask"></i><i class="fa fa-flickr"></i><i class="fa fa-floppy-o"></i><i class="fa fa-folder"></i><i class="fa fa-folder-o"></i><i class="fa fa-folder-open"></i><i class="fa fa-folder-open-o"></i><i class="fa fa-font"></i><i class="fa fa-forward"></i><i class="fa fa-foursquare"></i><i class="fa fa-frown-o"></i><i class="fa fa-futbol-o"></i><i class="fa fa-gamepad"></i><i class="fa fa-gavel"></i><i class="fa fa-gbp"></i><i class="fa fa-gift"></i><i class="fa fa-git"></i><i class="fa fa-git-square"></i><i class="fa fa-github"></i><i class="fa fa-github-alt"></i><i class="fa fa-github-square"></i><i class="fa fa-gittip"></i><i class="fa fa-glass"></i><i class="fa fa-globe"></i><i class="fa fa-google"></i><i class="fa fa-google-plus"></i><i class="fa fa-google-plus-square"></i><i class="fa fa-google-wallet"></i><i class="fa fa-graduation-cap"></i><i class="fa fa-h-square"></i><i class="fa fa-hacker-news"></i><i class="fa fa-hand-o-down"></i><i class="fa fa-hand-o-left"></i><i class="fa fa-hand-o-right"></i><i class="fa fa-hand-o-up"></i><i class="fa fa-hdd-o"></i><i class="fa fa-header"></i><i class="fa fa-headphones"></i><i class="fa fa-heart"></i><i class="fa fa-heart-o"></i><i class="fa fa-history"></i><i class="fa fa-home"></i><i class="fa fa-hospital-o"></i><i class="fa fa-html5"></i><i class="fa fa-ils"></i><i class="fa fa-inbox"></i><i class="fa fa-indent"></i><i class="fa fa-info"></i><i class="fa fa-info-circle"></i><i class="fa fa-inr"></i><i class="fa fa-instagram"></i><i class="fa fa-ioxhost"></i><i class="fa fa-italic"></i><i class="fa fa-joomla"></i><i class="fa fa-jpy"></i><i class="fa fa-jsfiddle"></i><i class="fa fa-key"></i><i class="fa fa-keyboard-o"></i><i class="fa fa-krw"></i><i class="fa fa-language"></i><i class="fa fa-laptop"></i><i class="fa fa-lastfm"></i><i class="fa fa-lastfm-square"></i><i class="fa fa-leaf"></i><i class="fa fa-lemon-o"></i><i class="fa fa-level-down"></i><i class="fa fa-level-up"></i><i class="fa fa-life-ring"></i><i class="fa fa-lightbulb-o"></i><i class="fa fa-line-chart"></i><i class="fa fa-link"></i><i class="fa fa-linkedin"></i><i class="fa fa-linkedin-square"></i><i class="fa fa-linux"></i><i class="fa fa-list"></i><i class="fa fa-list-alt"></i><i class="fa fa-list-ol"></i><i class="fa fa-list-ul"></i><i class="fa fa-location-arrow"></i><i class="fa fa-lock"></i><i class="fa fa-long-arrow-down"></i><i class="fa fa-long-arrow-left"></i><i class="fa fa-long-arrow-right"></i><i class="fa fa-long-arrow-up"></i><i class="fa fa-magic"></i><i class="fa fa-magnet"></i><i class="fa fa-male"></i><i class="fa fa-map-marker"></i><i class="fa fa-maxcdn"></i><i class="fa fa-meanpath"></i><i class="fa fa-medkit"></i><i class="fa fa-meh-o"></i><i class="fa fa-microphone"></i><i class="fa fa-microphone-slash"></i><i class="fa fa-minus"></i><i class="fa fa-minus-circle"></i><i class="fa fa-minus-square"></i><i class="fa fa-minus-square-o"></i><i class="fa fa-mobile"></i><i class="fa fa-money"></i><i class="fa fa-moon-o"></i><i class="fa fa-music"></i><i class="fa fa-newspaper-o"></i><i class="fa fa-openid"></i><i class="fa fa-outdent"></i><i class="fa fa-pagelines"></i><i class="fa fa-paint-brush"></i><i class="fa fa-paper-plane"></i><i class="fa fa-paper-plane-o"></i><i class="fa fa-paperclip"></i><i class="fa fa-paragraph"></i><i class="fa fa-pause"></i><i class="fa fa-paw"></i><i class="fa fa-paypal"></i><i class="fa fa-pencil"></i><i class="fa fa-pencil-square"></i><i class="fa fa-pencil-square-o"></i><i class="fa fa-phone"></i><i class="fa fa-phone-square"></i><i class="fa fa-picture-o"></i><i class="fa fa-pie-chart"></i><i class="fa fa-pied-piper"></i><i class="fa fa-pied-piper-alt"></i><i class="fa fa-pinterest"></i><i class="fa fa-pinterest-square"></i><i class="fa fa-plane"></i><i class="fa fa-play"></i><i class="fa fa-play-circle"></i><i class="fa fa-play-circle-o"></i><i class="fa fa-plug"></i><i class="fa fa-plus"></i><i class="fa fa-plus-circle"></i><i class="fa fa-plus-square"></i><i class="fa fa-plus-square-o"></i><i class="fa fa-power-off"></i><i class="fa fa-print"></i><i class="fa fa-puzzle-piece"></i><i class="fa fa-qq"></i><i class="fa fa-qrcode"></i><i class="fa fa-question"></i><i class="fa fa-question-circle"></i><i class="fa fa-quote-left"></i><i class="fa fa-quote-right"></i><i class="fa fa-random"></i><i class="fa fa-rebel"></i><i class="fa fa-recycle"></i><i class="fa fa-reddit"></i><i class="fa fa-reddit-square"></i><i class="fa fa-refresh"></i><i class="fa fa-renren"></i><i class="fa fa-repeat"></i><i class="fa fa-reply"></i><i class="fa fa-reply-all"></i><i class="fa fa-retweet"></i><i class="fa fa-road"></i><i class="fa fa-rocket"></i><i class="fa fa-rss"></i><i class="fa fa-rss-square"></i><i class="fa fa-rub"></i><i class="fa fa-scissors"></i><i class="fa fa-search"></i><i class="fa fa-search-minus"></i><i class="fa fa-search-plus"></i><i class="fa fa-share"></i><i class="fa fa-share-alt"></i><i class="fa fa-share-alt-square"></i><i class="fa fa-share-square"></i><i class="fa fa-share-square-o"></i><i class="fa fa-shield"></i><i class="fa fa-shopping-cart"></i><i class="fa fa-sign-in"></i><i class="fa fa-sign-out"></i><i class="fa fa-signal"></i><i class="fa fa-sitemap"></i><i class="fa fa-skype"></i><i class="fa fa-slack"></i><i class="fa fa-sliders"></i><i class="fa fa-slideshare"></i><i class="fa fa-smile-o"></i><i class="fa fa-sort"></i><i class="fa fa-sort-alpha-asc"></i><i class="fa fa-sort-alpha-desc"></i><i class="fa fa-sort-amount-asc"></i><i class="fa fa-sort-amount-desc"></i><i class="fa fa-sort-asc"></i><i class="fa fa-sort-desc"></i><i class="fa fa-sort-numeric-asc"></i><i class="fa fa-sort-numeric-desc"></i><i class="fa fa-soundcloud"></i><i class="fa fa-space-shuttle"></i><i class="fa fa-spinner"></i><i class="fa fa-spoon"></i><i class="fa fa-spotify"></i><i class="fa fa-square"></i><i class="fa fa-square-o"></i><i class="fa fa-stack-exchange"></i><i class="fa fa-stack-overflow"></i><i class="fa fa-star"></i><i class="fa fa-star-half"></i><i class="fa fa-star-half-o"></i><i class="fa fa-star-o"></i><i class="fa fa-steam"></i><i class="fa fa-steam-square"></i><i class="fa fa-step-backward"></i><i class="fa fa-step-forward"></i><i class="fa fa-stethoscope"></i><i class="fa fa-stop"></i><i class="fa fa-strikethrough"></i><i class="fa fa-stumbleupon"></i><i class="fa fa-stumbleupon-circle"></i><i class="fa fa-subscript"></i><i class="fa fa-suitcase"></i><i class="fa fa-sun-o"></i><i class="fa fa-superscript"></i><i class="fa fa-table"></i><i class="fa fa-tablet"></i><i class="fa fa-tachometer"></i><i class="fa fa-tag"></i><i class="fa fa-tags"></i><i class="fa fa-tasks"></i><i class="fa fa-taxi"></i><i class="fa fa-tencent-weibo"></i><i class="fa fa-terminal"></i><i class="fa fa-text-height"></i><i class="fa fa-text-width"></i><i class="fa fa-th"></i><i class="fa fa-th-large"></i><i class="fa fa-th-list"></i><i class="fa fa-thumb-tack"></i><i class="fa fa-thumbs-down"></i><i class="fa fa-thumbs-o-down"></i><i class="fa fa-thumbs-o-up"></i><i class="fa fa-thumbs-up"></i><i class="fa fa-ticket"></i><i class="fa fa-times"></i><i class="fa fa-times-circle"></i><i class="fa fa-times-circle-o"></i><i class="fa fa-tint"></i><i class="fa fa-toggle-off"></i><i class="fa fa-toggle-on"></i><i class="fa fa-trash"></i><i class="fa fa-trash-o"></i><i class="fa fa-tree"></i><i class="fa fa-trello"></i><i class="fa fa-trophy"></i><i class="fa fa-truck"></i><i class="fa fa-try"></i><i class="fa fa-tty"></i><i class="fa fa-tumblr"></i><i class="fa fa-tumblr-square"></i><i class="fa fa-twitch"></i><i class="fa fa-twitter"></i><i class="fa fa-twitter-square"></i><i class="fa fa-umbrella"></i><i class="fa fa-underline"></i><i class="fa fa-undo"></i><i class="fa fa-university"></i><i class="fa fa-unlock"></i><i class="fa fa-unlock-alt"></i><i class="fa fa-upload"></i><i class="fa fa-usd"></i><i class="fa fa-user"></i><i class="fa fa-user-md"></i><i class="fa fa-users"></i><i class="fa fa-video-camera"></i><i class="fa fa-vimeo-square"></i><i class="fa fa-vine"></i><i class="fa fa-vk"></i><i class="fa fa-volume-down"></i><i class="fa fa-volume-off"></i><i class="fa fa-volume-up"></i><i class="fa fa-weibo"></i><i class="fa fa-weixin"></i><i class="fa fa-wheelchair"></i><i class="fa fa-wifi"></i><i class="fa fa-windows"></i><i class="fa fa-wordpress"></i><i class="fa fa-wrench"></i><i class="fa fa-xing"></i><i class="fa fa-xing-square"></i><i class="fa fa-yahoo"></i><i class="fa fa-yelp"></i><i class="fa fa-youtube"></i><i class="fa fa-youtube-play"></i><i class="fa fa-youtube-square"></i> + </div> +</div> \ No newline at end of file diff --git a/src/views/partials/requirejs-config.tpl b/src/views/partials/requirejs-config.tpl new file mode 100644 index 0000000000..932c571f4a --- /dev/null +++ b/src/views/partials/requirejs-config.tpl @@ -0,0 +1,12 @@ +<script> + require.config({ + baseUrl: "{relative_path}/src/modules", + waitSeconds: 3, + urlArgs: "{cache-buster}", + paths: { + 'forum': '../forum', + 'vendor': '../../vendor', + 'mousetrap': '../../bower/mousetrap/mousetrap' + } + }); +</script> \ No newline at end of file diff --git a/src/views/partials/variables/account.tpl b/src/views/partials/variables/account.tpl new file mode 100644 index 0000000000..cc63770339 --- /dev/null +++ b/src/views/partials/variables/account.tpl @@ -0,0 +1,2 @@ +<input type="hidden" template-variable="yourid" value="{yourid}" /> +<input type="hidden" template-variable="theirid" value="{theirid}" /> \ No newline at end of file diff --git a/src/views/partials/variables/account/edit.tpl b/src/views/partials/variables/account/edit.tpl new file mode 100644 index 0000000000..d8e5d259cc --- /dev/null +++ b/src/views/partials/variables/account/edit.tpl @@ -0,0 +1,3 @@ +<input type="hidden" template-variable="userslug" value="{userslug}" /> +<input type="hidden" template-variable="gravatarpicture" value="{gravatarpicture}" /> +<input type="hidden" template-variable="uploadedpicture" value="{uploadedpicture}" /> \ No newline at end of file diff --git a/src/views/partials/variables/account/profile.tpl b/src/views/partials/variables/account/profile.tpl new file mode 100644 index 0000000000..be91685112 --- /dev/null +++ b/src/views/partials/variables/account/profile.tpl @@ -0,0 +1 @@ +<input type="hidden" template-type="boolean" template-variable="isFollowing" value="{isFollowing}" /> \ No newline at end of file diff --git a/src/views/partials/variables/category.tpl b/src/views/partials/variables/category.tpl new file mode 100644 index 0000000000..984002411a --- /dev/null +++ b/src/views/partials/variables/category.tpl @@ -0,0 +1,6 @@ +<input type="hidden" template-variable="category_id" value="{cid}" /> +<input type="hidden" template-variable="category_name" value="{name}" /> +<input type="hidden" template-variable="category_slug" value="{slug}" /> +<input type="hidden" template-variable="topic_count" value="{topic_count}" /> +<input type="hidden" template-variable="currentPage" value="{currentPage}" /> +<input type="hidden" template-variable="pageCount" value="{pageCount}" /> \ No newline at end of file diff --git a/src/views/partials/variables/groups/details.tpl b/src/views/partials/variables/groups/details.tpl new file mode 100644 index 0000000000..0cefdde305 --- /dev/null +++ b/src/views/partials/variables/groups/details.tpl @@ -0,0 +1,2 @@ +<input type="hidden" template-variable="group_name" value="{group.name}" /> +<input type="hidden" template-variable="is_owner" value="{group.isOwner}" /> \ No newline at end of file diff --git a/src/views/partials/variables/reset_code.tpl b/src/views/partials/variables/reset_code.tpl new file mode 100644 index 0000000000..ab630d7cff --- /dev/null +++ b/src/views/partials/variables/reset_code.tpl @@ -0,0 +1 @@ +<input type="hidden" template-variable="reset_code" value="{code}" /> \ No newline at end of file diff --git a/src/views/partials/variables/tag.tpl b/src/views/partials/variables/tag.tpl new file mode 100644 index 0000000000..486ba8245c --- /dev/null +++ b/src/views/partials/variables/tag.tpl @@ -0,0 +1 @@ +<input type="hidden" template-variable="tag" value="{tag}" /> \ No newline at end of file diff --git a/src/views/partials/variables/topic.tpl b/src/views/partials/variables/topic.tpl new file mode 100644 index 0000000000..4f3c15180d --- /dev/null +++ b/src/views/partials/variables/topic.tpl @@ -0,0 +1,11 @@ +<input type="hidden" template-variable="topic_id" value="{tid}" /> +<input type="hidden" template-variable="topic_slug" value="{slug}" /> +<input type="hidden" template-variable="category_id" value="{category.cid}" /> +<input type="hidden" template-variable="currentPage" value="{currentPage}" /> +<input type="hidden" template-variable="pageCount" value="{pageCount}" /> +<input type="hidden" template-variable="locked" template-type="boolean" value="{locked}" /> +<input type="hidden" template-variable="deleted" template-type="boolean" value="{deleted}" /> +<input type="hidden" template-variable="pinned" template-type="boolean" value="{pinned}" /> +<input type="hidden" template-variable="topic_name" value="{title}" /> +<input type="hidden" template-variable="postcount" value="{postcount}" /> +<input type="hidden" template-variable="viewcount" value="{viewcount}" /> \ No newline at end of file diff --git a/src/webserver.js b/src/webserver.js index 849be56879..bd4acb231f 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -110,7 +110,7 @@ if(nconf.get('ssl')) { emitter.emit('nodebb:ready'); }); - server.setTimeout(10000); + server.setTimout && server.setTimeout(10000); module.exports.listen = function(callback) { logger.init(app); diff --git a/tests/groups.js b/tests/groups.js index 0025000828..a4d5c9da30 100644 --- a/tests/groups.js +++ b/tests/groups.js @@ -186,13 +186,22 @@ describe('Groups', function() { }); describe('.update()', function() { + before(function(done) { + Groups.create({ + name: 'updateTestGroup', + description: 'bar', + system: 0, + hidden: 0 + }, done); + }); + it('should change an aspect of a group', function(done) { - Groups.update('foo', { + Groups.update('updateTestGroup', { description: 'baz' }, function(err) { if (err) return done(err); - Groups.get('foo', {}, function(err, groupObj) { + Groups.get('updateTestGroup', {}, function(err, groupObj) { if (err) return done(err); assert.strictEqual('baz', groupObj.description); @@ -203,16 +212,16 @@ describe('Groups', function() { }); it('should rename a group if the name was updated', function(done) { - Groups.update('foo', { - name: 'foobar?' + Groups.update('updateTestGroup', { + name: 'updateTestGroup?' }, function(err) { if (err) return done(err); - Groups.get('foobar?', {}, function(err, groupObj) { + Groups.get('updateTestGroup?', {}, function(err, groupObj) { if (err) return done(err); - assert.strictEqual('foobar?', groupObj.name); - assert.strictEqual('foobar', groupObj.slug); + assert.strictEqual('updateTestGroup?', groupObj.name); + assert.strictEqual('updatetestgroup', groupObj.slug); done(); });