v1.18.x
psychobunny 10 years ago
commit cb7c318377

@ -40,13 +40,13 @@
"nconf": "~0.7.1",
"nodebb-plugin-dbsearch": "^0.1.0",
"nodebb-plugin-emoji-extended": "^0.4.1-4",
"nodebb-plugin-markdown": "^0.8.0",
"nodebb-plugin-markdown": "^1.0.0",
"nodebb-plugin-mentions": "^0.9.0",
"nodebb-plugin-soundpack-default": "~0.1.1",
"nodebb-plugin-spam-be-gone": "^0.4.0",
"nodebb-theme-lavender": "^1.0.4",
"nodebb-theme-vanilla": "^1.0.5",
"nodebb-widget-essentials": "~0.2.11",
"nodebb-theme-lavender": "^1.0.6",
"nodebb-theme-vanilla": "^1.0.14",
"nodebb-widget-essentials": "~0.2.12",
"nodebb-rewards-essentials": "^0.0.1",
"npm": "^2.1.4",
"passport": "^0.2.1",

@ -1,5 +1,6 @@
{
"new_topic_button": "موضوع جديد",
"guest-login-post": "Log in to post",
"no_topics": "<strong>لا توجد مواضيع في هذه الفئة</strong>لم لا تحاول إنشاء موضوع؟<br />",
"browsing": "تصفح",
"no_replies": "لم يرد أحد",

@ -12,6 +12,7 @@
"notify_me": "تلق تنبيهات بالردود الجديدة في هذا الموضوع",
"quote": "اقتبس",
"reply": "رد",
"guest-login-reply": "Log in to reply",
"edit": "تعديل",
"delete": "حذف",
"purge": "تطهير",

@ -1,5 +1,6 @@
{
"new_topic_button": "নতুন টপিক",
"guest-login-post": "Log in to post",
"no_topics": "<strong>এই বিভাগে কোন টপিক নেই! </strong><br /> আপনি চাইলে একটি পোষ্ট করতে পারেন।",
"browsing": "ব্রাউজিং",
"no_replies": "কোন রিপ্লাই নেই",

@ -12,6 +12,7 @@
"notify_me": "এই টপিকে নতুন উত্তর আসলে জানুন",
"quote": "উদ্ধৃতি",
"reply": "উত্তর",
"guest-login-reply": "Log in to reply",
"edit": "সম্পাদণা",
"delete": "মুছে ফেলুন",
"purge": "পার্জ",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nové téma",
"guest-login-post": "Log in to post",
"no_topics": "<strong>V této kategorii zatím nejsou žádné příspěvky.</strong><br />Můžeš být první!",
"browsing": "prohlíží",
"no_replies": "Nikdo ještě neodpověděl",

@ -12,6 +12,7 @@
"notify_me": "Sledovat toto téma",
"quote": "Citovat",
"reply": "Odpovědět",
"guest-login-reply": "Log in to reply",
"edit": "Upravit",
"delete": "Smazat",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "Neues Thema",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Es gibt noch keine Themen in dieser Kategorie.</strong><br />Warum beginnst du nicht eins?",
"browsing": "Aktiv",
"no_replies": "Niemand hat geantwortet",

@ -12,6 +12,7 @@
"notify_me": "Erhalte eine Benachrichtigung bei neuen Antworten zu diesem Thema.",
"quote": "zitieren",
"reply": "antworten",
"guest-login-reply": "Log in to reply",
"edit": "bearbeiten",
"delete": "löschen",
"purge": "bereinigen",

@ -1,5 +1,6 @@
{
"new_topic_button": "Νέο Θέμα",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Δεν υπάρχουν θέματα σε αυτή την κατηγορία.</strong><br />Γιατί δεν δοκιμάζεις να δημοσιεύσεις ένα εσύ;",
"browsing": "περιηγούνται",
"no_replies": "Κανείς δεν έχει απαντήσει",

@ -12,6 +12,7 @@
"notify_me": "Να ειδοποιούμαι για νέες απαντήσεις σε αυτό το θέμα",
"quote": "Παράθεση",
"reply": "Απάντηση",
"guest-login-reply": "Log in to reply",
"edit": "Επεξεργασία",
"delete": "Διαγραφή",
"purge": "Εκκαθάριση",

@ -1,5 +1,6 @@
{
"new_topic_button": "New Topic",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Thar be no topics in 'tis category.</strong><br />Why don't ye give a go' postin' one?",
"browsing": "browsin'",
"no_replies": "No one has replied to ye message",

@ -12,6 +12,7 @@
"notify_me": "Be notified of new replies in this topic",
"quote": "Quote",
"reply": "Reply",
"guest-login-reply": "Log in to reply",
"edit": "Edit",
"delete": "Delete",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "New Topic",
"guest-login-post": "Log in to post",
"no_topics": "<strong>There are no topics in this category.</strong><br />Why don't you try posting one?",
"browsing": "browsing",

@ -15,6 +15,7 @@
"notify_me": "Be notified of new replies in this topic",
"quote": "Quote",
"reply": "Reply",
"guest-login-reply": "Log in to reply",
"edit": "Edit",
"delete": "Delete",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "New Topic",
"guest-login-post": "Log in to post",
"no_topics": "<strong>There are no topics in this category.</strong><br />Why don't you try posting one?",
"browsing": "browsing",
"no_replies": "No one has replied",

@ -12,6 +12,7 @@
"notify_me": "Be notified of new replies in this topic",
"quote": "Quote",
"reply": "Reply",
"guest-login-reply": "Log in to reply",
"edit": "Edit",
"delete": "Delete",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nuevo tema",
"guest-login-post": "Log in to post",
"no_topics": "<strong>No hay temas en esta categoría.</strong><br />¿Por que no te animas y publicas uno?",
"browsing": "viendo ahora",
"no_replies": "Nadie ha respondido aún",

@ -12,6 +12,7 @@
"notify_me": "Serás notificado cuando haya nuevas respuestas en este tema",
"quote": "Citar",
"reply": "Responder",
"guest-login-reply": "Log in to reply",
"edit": "Editar",
"delete": "Borrar",
"purge": "Purgar",

@ -1,5 +1,6 @@
{
"new_topic_button": "Uus teema",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Kahjuks ei leidu siin kategoorias ühtegi teemat.</strong><br />Soovid postitada?",
"browsing": "vaatab",
"no_replies": "Keegi pole vastanud",

@ -12,6 +12,7 @@
"notify_me": "Saa teateid uutest postitustest selles teemas",
"quote": "Tsiteeri",
"reply": "Vasta",
"guest-login-reply": "Log in to reply",
"edit": "Muuda",
"delete": "Kustuta",
"purge": "Kustuta",

@ -1,5 +1,6 @@
{
"new_topic_button": "جستار تازه",
"guest-login-post": "Log in to post",
"no_topics": "<strong>هیچ جستاری در این دسته نیست.</strong><br />چرا شما یکی نفرستید؟",
"browsing": "بیننده‌ها",
"no_replies": "هیچ کسی پاسخ نداده است.",

@ -12,6 +12,7 @@
"notify_me": "از پاسخ‌های تازه در جستار آگاه شوید",
"quote": "نقل قول",
"reply": "پاسخ",
"guest-login-reply": "Log in to reply",
"edit": "ویرایش",
"delete": "Delete",
"purge": "پاک کردن",

@ -1,5 +1,6 @@
{
"new_topic_button": "Uusi aihe",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Tällä aihealueella ei ole yhtään aihetta.</strong><br />Miksi et aloittaisi uutta?",
"browsing": "selaamassa",
"no_replies": "Kukaan ei ole vastannut",

@ -12,6 +12,7 @@
"notify_me": "Ilmoita, kun tähän keskusteluun tulee uusia viestejä",
"quote": "Lainaa",
"reply": "Vastaa",
"guest-login-reply": "Log in to reply",
"edit": "Muokkaa",
"delete": "Poista",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nouveau Sujet",
"new_topic_button": "Nouveau sujet",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Il n'y a aucun sujet dans cette catégorie.</strong><br />Pourquoi ne pas en créer un ?",
"browsing": "parcouru par",
"no_replies": "Personne n'a répondu",

@ -12,7 +12,8 @@
"notify_me": "Être notifié des réponses dans ce sujet",
"quote": "Citer",
"reply": "Répondre",
"edit": "Editer",
"guest-login-reply": "Log in to reply",
"edit": "Éditer",
"delete": "Supprimer",
"purge": "Supprimer définitivement",
"restore": "Restaurer",
@ -39,7 +40,7 @@
"share_this_post": "Partager ce message",
"thread_tools.title": "Outils pour sujets",
"thread_tools.markAsUnreadForAll": "Marquer comme non lu",
"thread_tools.pin": "Epingler le sujet",
"thread_tools.pin": "Épingler le sujet",
"thread_tools.unpin": "Désépingler le sujet",
"thread_tools.lock": "Verrouiller le sujet",
"thread_tools.unlock": "Déverouiller le sujet",
@ -60,9 +61,9 @@
"disabled_categories_note": "Les catégories désactivées sont grisées",
"confirm_move": "Déplacer",
"confirm_fork": "Scinder",
"favourite": "Favoris",
"favourite": "Favori",
"favourites": "Favoris",
"favourites.has_no_favourites": "Vous n'avez aucun favoris, mettez des messages en favoris pour les voir ici !",
"favourites.has_no_favourites": "Vous n'avez aucun favori, mettez des messages en favoris pour les voir ici !",
"loading_more_posts": "Charger plus de messages",
"move_topic": "Déplacer le sujet",
"move_topics": "Déplacer des sujets",

@ -1,5 +1,6 @@
{
"new_topic_button": "נושא חדש",
"guest-login-post": "Log in to post",
"no_topics": "<strong>קטגוריה זו ריקה מנושאים.</strong><br />למה שלא תנסה להוסיף נושא חדש?",
"browsing": "צופים בנושא זה כעת",
"no_replies": "אין תגובות",

@ -12,6 +12,7 @@
"notify_me": "קבל התראה כאשר יש תגובות חדשות בנושא זה",
"quote": "ציטוט",
"reply": "תגובה",
"guest-login-reply": "Log in to reply",
"edit": "עריכה",
"delete": "מחק",
"purge": "מחק הכל",

@ -1,5 +1,6 @@
{
"new_topic_button": "Új témakör",
"guest-login-post": "Log in to post",
"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",

@ -12,6 +12,7 @@
"notify_me": "Értesítést kérek az új hozzászólásokról ebben a topikban",
"quote": "Idéz",
"reply": "Válasz",
"guest-login-reply": "Log in to reply",
"edit": "Szerkeszt",
"delete": "Töröl",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "Topik Baru",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Tidak ada topik dikategori ini</strong><br/> Mengapa anda tidak mencoba membuat yang baru?",
"browsing": "penjelajahan",
"no_replies": "Belum ada orang yang menjawab",

@ -12,6 +12,7 @@
"notify_me": "Beritahukan balasan baru untuk topik ini",
"quote": "Kutip",
"reply": "Balas",
"guest-login-reply": "Log in to reply",
"edit": "Ubah",
"delete": "Hapus",
"purge": "Musnahkan",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nuova Discussione",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Non ci sono discussioni in questa categoria.</strong><br />Perché non ne inizi una?",
"browsing": "visualizzando",
"no_replies": "Nessuno ha risposto",

@ -12,6 +12,7 @@
"notify_me": "Ricevi notifiche di nuove risposte in questa discussione",
"quote": "Cita",
"reply": "Rispondi",
"guest-login-reply": "Log in to reply",
"edit": "Modifica",
"delete": "Cancella",
"purge": "Svuota",

@ -1,5 +1,6 @@
{
"new_topic_button": "新規スレッド",
"guest-login-post": "Log in to post",
"no_topics": "<strong>まだスレッドはありません.</strong><br />一番目のスレッドを書いてみないか?",
"browsing": "閲覧中",
"no_replies": "返事はまだありません",

@ -12,6 +12,7 @@
"notify_me": "このスレッドに新しいポストが投稿された際に通知する",
"quote": "引用",
"reply": "返答",
"guest-login-reply": "Log in to reply",
"edit": "編集",
"delete": "削除",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "새 주제 생성",
"guest-login-post": "Log in to post",
"no_topics": "<strong>이 카테고리에는 생성된 주제가 없습니다.</strong><br />먼저 주제를 생성해 보세요.",
"browsing": "이 주제를 읽고 있는 사용자",
"no_replies": "답글이 없습니다.",

@ -12,6 +12,7 @@
"notify_me": "이 주제의 새 답글 알리기",
"quote": "인용",
"reply": "답글",
"guest-login-reply": "Log in to reply",
"edit": "수정",
"delete": "삭제",
"purge": "폐기",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nauja tema",
"guest-login-post": "Log in to post",
"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ė",

@ -12,6 +12,7 @@
"notify_me": "Gauti pranešimus apie naujus atsakymus šioje temoje",
"quote": "Cituoti",
"reply": "Atsakyti",
"guest-login-reply": "Log in to reply",
"edit": "Redaguoti",
"delete": "Ištrinti",
"purge": "Išvalyti",

@ -1,5 +1,6 @@
{
"new_topic_button": "\nTopik Baru",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Tiada topik dalam kategori ini.</strong><br />Cuba menghantar topik yang baru?",
"browsing": "melihat",
"no_replies": "Tiada jawapan",

@ -12,6 +12,7 @@
"notify_me": "Kekal dimaklumkan berkenaan respon dalam topik ini",
"quote": "Petikan",
"reply": "Balas",
"guest-login-reply": "Log in to reply",
"edit": "Edit",
"delete": "Padamkan",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nytt emne",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Det er ingen emner i denne kategorien</strong><br />Hvorfor ikke lage ett?",
"browsing": "leser",
"no_replies": "Ingen har svart",

@ -12,6 +12,7 @@
"notify_me": "Bli varslet om nye svar i dette emnet",
"quote": "Siter",
"reply": "Svar",
"guest-login-reply": "Log in to reply",
"edit": "Endre",
"delete": "Slett",
"purge": "Tøm",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nieuw onderwerp",
"guest-login-post": "Log in to post",
"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",

@ -12,6 +12,7 @@
"notify_me": "Krijg notificaties van nieuwe reacties op dit onderwerp",
"quote": "Citeren",
"reply": "Reageren",
"guest-login-reply": "Log in to reply",
"edit": "Aanpassen",
"delete": "Verwijderen",
"purge": "weggooien",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nowy wątek",
"guest-login-post": "Log in to post",
"no_topics": "<strong>W tej kategorii nie ma jeszcze żadnych wątków.</strong><br />Dlaczego ty nie utworzysz jakiegoś?",
"browsing": "przegląda",
"no_replies": "Nikt jeszcze nie odpowiedział",

@ -12,6 +12,7 @@
"notify_me": "Powiadamiaj mnie o nowych odpowiedziach w tym wątku",
"quote": "Cytuj",
"reply": "Odpowiedz",
"guest-login-reply": "Log in to reply",
"edit": "Edytuj",
"delete": "Usuń",
"purge": "Wymaż",

@ -1,5 +1,6 @@
{
"new_topic_button": "Novo Tópico",
"guest-login-post": "Log in to post",
"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",

@ -12,6 +12,7 @@
"notify_me": "Seja notificado de novas respostas nesse tópico",
"quote": "Citar",
"reply": "Responder",
"guest-login-reply": "Log in to reply",
"edit": "Editar",
"delete": "Deletar",
"purge": "Expurgar",

@ -1,5 +1,6 @@
{
"new_topic_button": "Subiect Nou",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Nu există nici un subiect de discuție în această categorie.</strong><br />De ce nu încerci să postezi tu unul?",
"browsing": "navighează",
"no_replies": "Nu a răspuns nimeni",

@ -12,6 +12,7 @@
"notify_me": "Notică-mă de noi răspunsuri în acest subiect",
"quote": "Citează",
"reply": "Răspunde",
"guest-login-reply": "Log in to reply",
"edit": "Editează",
"delete": "Șterge",
"purge": "Curăță",

@ -1,5 +1,6 @@
{
"new_topic_button": "Создать тему",
"guest-login-post": "Log in to post",
"no_topics": "<strong>В этой категории еще нет тем.</strong><br />Почему бы вам не создать первую?",
"browsing": "просматривают",
"no_replies": "Нет ответов",

@ -7,11 +7,12 @@
"post_is_deleted": "Этот пост удален!",
"profile": "Профиль",
"posted_by": "Создано %1",
"posted_by_guest": "Опубликовано Гостем",
"posted_by_guest": "Опубликовано гостем",
"chat": "Чат",
"notify_me": "Сообщать мне об ответах в этой теме",
"quote": "Цитировать",
"reply": "Ответить",
"guest-login-reply": "Log in to reply",
"edit": "Редактировать",
"delete": "Удалить",
"purge": "Очистить",
@ -39,60 +40,60 @@
"share_this_post": "Поделиться этим Постом",
"thread_tools.title": "Опции темы",
"thread_tools.markAsUnreadForAll": "Отметить как непрочитанные",
"thread_tools.pin": "Прикрепить Тему",
"thread_tools.unpin": "Открепить Тему",
"thread_tools.lock": "Закрыть Тему",
"thread_tools.unlock": "Открыть Тему",
"thread_tools.move": "Переместить Тему",
"thread_tools.move_all": "Переместить Все",
"thread_tools.fork": "Ответвить Тему",
"thread_tools.delete": "Удалить Тему",
"thread_tools.pin": "Прикрепить тему",
"thread_tools.unpin": "Открепить тему",
"thread_tools.lock": "Закрыть тему",
"thread_tools.unlock": "Открыть тему",
"thread_tools.move": "Переместить тему",
"thread_tools.move_all": "Переместить все",
"thread_tools.fork": "Ответвить тему",
"thread_tools.delete": "Удалить тему",
"thread_tools.delete_confirm": "Вы уверены, что хотите удалить тему?",
"thread_tools.restore": "Восстановить Тему",
"thread_tools.restore": "Восстановить тему",
"thread_tools.restore_confirm": "Вы уверены, что хотите восстановить тему?",
"thread_tools.purge": "Очистить Тему",
"thread_tools.purge": "Очистить тему",
"thread_tools.purge_confirm": "Вы уверены, что хотите очистить эту тему?",
"topic_move_success": "Эта тема успешно перемещена в %1",
"post_delete_confirm": "Вы уверены, что хотите удалить этот пост?",
"post_restore_confirm": "Вы уверены, что хотите восстановить этот пост?",
"post_purge_confirm": "Вы уверены, что хотите очистить эту запись?",
"load_categories": "Загружаем Категории",
"disabled_categories_note": "Отключенные категории затемненны",
"load_categories": "Загружаем категории",
"disabled_categories_note": "Отключенные категории затемнены",
"confirm_move": "Перенести",
"confirm_fork": "Ответвление",
"favourite": "Избранное",
"favourites": "Избранные",
"favourites.has_no_favourites": "У вас нет избранного, добавьте несколько сообщений в избранное чтобы увидеть их здесь!",
"favourites.has_no_favourites": "У вас нет избранного, добавьте несколько сообщений в избранное, чтобы увидеть их здесь",
"loading_more_posts": "Загружаем еще сообщения",
"move_topic": "Перенести тему",
"move_topics": "Больше Тем",
"move_topics": "Перенести темы",
"move_post": "Перенести сообщение",
"post_moved": "Пост перемещен!",
"fork_topic": "Ответвить Тему",
"post_moved": "Пост перенесен",
"fork_topic": "Ответвить тему",
"topic_will_be_moved_to": "Эта тема будет перенесена в категорию",
"fork_topic_instruction": "Отметьте сообщения для ответвления",
"fork_no_pids": "Сообщения не отмечены!",
"fork_success": "Готово! Нажмите для перехода в отделённую тему.",
"composer.title_placeholder": "Введите название темы...",
"composer.handle_placeholder": "Name",
"composer.handle_placeholder": "Название",
"composer.discard": "Отменить",
"composer.submit": "Подтвердить",
"composer.replying_to": "Ответ %1",
"composer.new_topic": "Создать Тему",
"composer.new_topic": "Создать тему",
"composer.uploading": "загрузка...",
"composer.thumb_url_label": "Вставьте URL картинки с иконкой темы.",
"composer.thumb_title": "Добавить иконку к этой теме",
"composer.thumb_url_placeholder": "http://example.com/thumb.png",
"composer.thumb_file_label": "Или загрузите файл",
"composer.thumb_remove": "Очистить поля",
"composer.drag_and_drop_images": "Перетащите Изображения Сюда",
"composer.drag_and_drop_images": "Перетащите изображения сюда",
"more_users_and_guests": "еще %1 пользователя(ей) и %2 гостя(ей)",
"more_users": "еще %1 пользователя(ей)",
"more_guests": "еще %1 гостя(ей)",
"users_and_others": "%1 и %2 других",
"sort_by": "Сортировать",
"oldest_to_newest": "От Старых к Новым",
"newest_to_oldest": "От Новых к Старым",
"oldest_to_newest": "От старых к новым",
"newest_to_oldest": "От новых к старым",
"most_votes": "По голосам",
"most_posts": "Most posts"
"most_posts": "По количеству ответов"
}

@ -1,5 +1,6 @@
{
"new_topic_button": "Arresonada Noa",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Non bi sunt arresonadas in custa creze.</strong><br />Pro ite non nde pones una?",
"browsing": "navighende",
"no_replies": "Perunu at rispostu",

@ -12,6 +12,7 @@
"notify_me": "Imbia·mi notìficas pro is rispostas noas a custa arresonada",
"quote": "Mèntova",
"reply": "Risponde",
"guest-login-reply": "Log in to reply",
"edit": "Acontza",
"delete": "Contzella",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nová téma",
"guest-login-post": "Log in to post",
"no_topics": "<strong>V tejto kategórií zatiaľ nie sú žiadne príspevky.</strong><br />Môžeš byť prvý!",
"browsing": "prehliada",
"no_replies": "Nikdo ešte neodpovedal",

@ -12,6 +12,7 @@
"notify_me": "Sledovať túto tému",
"quote": "Citovať",
"reply": "Odpovedať",
"guest-login-reply": "Log in to reply",
"edit": "Upraviť",
"delete": "Zmazať",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "Nytt ämne",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Det finns inga ämnen i denna kategori.</strong><br />Varför skapar inte du ett ämne?",
"browsing": "läser",
"no_replies": "Ingen har svarat",

@ -12,6 +12,7 @@
"notify_me": "Få notiser om nya svar i detta ämne",
"quote": "Citera",
"reply": "Svara",
"guest-login-reply": "Log in to reply",
"edit": "Ändra",
"delete": "Ta bort",
"purge": "Rensa",

@ -1,5 +1,6 @@
{
"new_topic_button": "กระทู้",
"guest-login-post": "Log in to post",
"no_topics": "<strong>ยังไม่มีกระทู้ในหมวดนี้</strong><br />โพสต์กระทู้แรก?",
"browsing": "เรียกดู",
"no_replies": "ยังไม่มีใครตอบ",

@ -12,6 +12,7 @@
"notify_me": "แจ้งเตือนเมื่อการตอบใหม่ในกระทู้นี้",
"quote": "คำอ้างอิง",
"reply": "ตอบ",
"guest-login-reply": "Log in to reply",
"edit": "แก้ไข",
"delete": "ลบ",
"purge": "Purge",

@ -1,5 +1,6 @@
{
"new_topic_button": "Yeni Başlık",
"guest-login-post": "Log in to post",
"no_topics": "<strong> Bu kategoride hiç konu yok. </strong> <br /> Yeni bir konu açmak istemez misiniz?",
"browsing": "gözden geçiriliyor",
"no_replies": "Kimse yanıtlamadı",

@ -12,6 +12,7 @@
"notify_me": "Bu konudaki cevaplardan haberdar ol",
"quote": "Alıntı",
"reply": "Cevap",
"guest-login-reply": "Log in to reply",
"edit": "Düzenle",
"delete": "Sil",
"purge": "Temizle",

@ -1,5 +1,6 @@
{
"new_topic_button": "Chủ đề mới",
"guest-login-post": "Log in to post",
"no_topics": "<strong>Không có bài viết trong danh mục này.</strong><br />Hãy đăng một bài viết mới.",
"browsing": "đang xem",
"no_replies": "Chưa có bình luận nào",

@ -12,6 +12,7 @@
"notify_me": "Được thông báo khi có trả lời mới trong chủ đề này",
"quote": "Trích dẫn",
"reply": "Trả lời",
"guest-login-reply": "Log in to reply",
"edit": "Chỉnh sửa",
"delete": "Xóa",
"purge": "Xóa hẳn",

@ -1,5 +1,6 @@
{
"new_topic_button": "新主题",
"guest-login-post": "Log in to post",
"no_topics": "<strong>此版块还没有任何内容。</strong><br />赶紧来发帖吧!",
"browsing": "正在浏览",
"no_replies": "尚无回复",

@ -12,6 +12,7 @@
"notify_me": "此主题有新回复时通知我",
"quote": "引用",
"reply": "回复",
"guest-login-reply": "Log in to reply",
"edit": "编辑",
"delete": "删除",
"purge": "清除",

@ -1,5 +1,6 @@
{
"new_topic_button": "新主題",
"guest-login-post": "Log in to post",
"no_topics": "<strong>這個版面還沒有任何內容。</strong><br />趕緊來發文章吧!",
"browsing": "正在瀏覽",
"no_replies": "還沒有回覆",

@ -12,6 +12,7 @@
"notify_me": "該主題有新回覆時通知我",
"quote": "引用",
"reply": "回覆",
"guest-login-reply": "Log in to reply",
"edit": "編輯",
"delete": "刪除",
"purge": "清除",

@ -184,15 +184,18 @@
.box-header-font
}
#user_dropdown {
padding: 6px;
img {
width: 30px;
height: 30px;
vertical-align: -88%;
margin-right: 5px;
}
#user_label {
a {
padding-top: 13px;
padding-bottom: 13px;
img {
width: 24px;
height: 24px;
border-radius: 50%;
border: 1px solid #454;
}
}
}
.icon-container {
@ -214,24 +217,39 @@
}
}
.navbar {
padding: 0 5px;
.nav-home a, .nav-home a:hover {
width: 30px;
height: 30px;
padding: 5px;
text-align: center;
margin-top: 10px;
background: #DDD;
i {
color: black;
font-size: 17px;
}
}
}
.navbar-static-top, .navbar-fixed-top {
box-shadow: 0px -3px 12px rgba(0, 0, 0, 0.5);
}
.navbar-header > .navbar-toggle {
margin-right: 8px;
}
.navbar-nav {
margin-top: 0;
margin-bottom: 0;
>li {
>a {
padding-top: 15px;
padding-bottom: 15px;
}
>a:hover, >a:focus {
color: @gray-dark;
background-color: @gray-light;
}
>#reconnect {
color: @gray-light;
}
>#reconnect:focus, >#reconnect:hover {
color: @gray-light;
background-color: transparent;
}
}
}
#acp-search {
input {

@ -1,12 +1,21 @@
"use strict";
/*global define, socket, app, admin, utils, bootbox, RELATIVE_PATH*/
define('admin/manage/flags', ['forum/infinitescroll', 'admin/modules/selectable'], function(infinitescroll, selectable) {
define('admin/manage/flags', [
'forum/infinitescroll',
'admin/modules/selectable',
'autocomplete'
], function(infinitescroll, selectable, autocomplete) {
var Flags = {};
Flags.init = function() {
$('.post-container .content img').addClass('img-responsive');
var params = utils.params();
$('#flag-sort-by').val(params.sortBy);
autocomplete.user($('#byUsername'));
handleDismiss();
handleDismissAll();
handleDelete();
@ -69,8 +78,15 @@ define('admin/manage/flags', ['forum/infinitescroll', 'admin/modules/selectable'
if (direction < 0 && !$('.flags').length) {
return;
}
var params = utils.params();
var sortBy = params.sortBy || 'count';
var byUsername = params.byUsername || '';
infinitescroll.loadMore('admin.getMoreFlags', $('[data-next]').attr('data-next'), function(data, done) {
infinitescroll.loadMore('admin.getMoreFlags', {
byUsername: byUsername,
sortBy: sortBy,
after: $('[data-next]').attr('data-next')
}, function(data, done) {
if (data.posts && data.posts.length) {
infinitescroll.parseAndTranslate('admin/manage/flags', 'posts', {posts: data.posts}, function(html) {
$('[data-next]').attr('data-next', data.next);

@ -214,7 +214,7 @@ define('admin/manage/users', ['admin/modules/selectable'], function(selectable)
}
$('#create-modal').modal('hide');
$('#create-modal').on('hidden.bs.modal', function() {
ajaxify.go('admin/users');
ajaxify.refresh();
});
app.alertSuccess('User created!');
});

@ -339,7 +339,7 @@ define('forum/category', [
infinitescroll.loadMore('categories.loadMore', {
cid: ajaxify.variables.get('category_id'),
after: after,
author: utils.getQueryParams().author
author: utils.params().author
}, function (data, done) {
if (data.topics && data.topics.length) {

@ -2,7 +2,7 @@
/* globals app, define, utils, socket*/
define('forum/search', ['search'], function(searchModule) {
define('forum/search', ['search', 'autocomplete'], function(searchModule, autocomplete) {
var Search = {};
Search.init = function() {
@ -80,8 +80,8 @@ define('forum/search', ['search'], function(searchModule) {
$('#posted-by-user').val(params.by);
}
if ((params['categories[]'] || params.categories)) {
$('#posted-in-categories').val(params['categories[]'] || params.categories);
if (params.categories) {
$('#posted-in-categories').val(params.categories);
}
if (params.searchChildren) {
@ -156,25 +156,7 @@ define('forum/search', ['search'], function(searchModule) {
}
function enableAutoComplete() {
var input = $('#posted-by-user');
input.autocomplete({
delay: 100,
source: function(request, response) {
socket.emit('user.search', {query: request.term}, function(err, result) {
if (err) {
return app.alertError(err.message);
}
if (result && result.users) {
var names = result.users.map(function(user) {
return user && user.username;
});
response(names);
}
$('.ui-autocomplete a').attr('data-ajaxify', 'false');
});
}
});
autocomplete.user($('#posted-by-user'));
}
return Search;

@ -0,0 +1,31 @@
'use strict';
/* globals define, socket, app */
define('autocomplete', function() {
var module = {};
module.user = function (input) {
input.autocomplete({
delay: 100,
source: function(request, response) {
socket.emit('user.search', {query: request.term}, function(err, result) {
if (err) {
return app.alertError(err.message);
}
if (result && result.users) {
var names = result.users.map(function(user) {
return user && user.username;
});
response(names);
}
$('.ui-autocomplete a').attr('data-ajaxify', 'false');
});
}
});
};
return module;
});

@ -16,11 +16,17 @@ define('composer', [
var composer = {
active: undefined,
posts: {},
bsEnvironment: undefined
bsEnvironment: undefined,
formatting: []
};
$(window).off('resize', onWindowResize).on('resize', onWindowResize);
// Query server for formatting options
socket.emit('modules.composer.getFormattingOptions', function(err, options) {
composer.formatting = options;
});
function onWindowResize() {
if (composer.active !== undefined) {
resize.reposition($('#cmp-uuid-' + composer.active));
@ -232,7 +238,8 @@ define('composer', [
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
handle: composer.posts[post_uuid] ? composer.posts[post_uuid].handle || '' : undefined,
formatting: composer.formatting
};
parseAndTranslate(template, data, function(composerTemplate) {

@ -7,61 +7,15 @@ define('composer/formatting', ['composer/controls', 'composer/preview'], functio
var formatting = {};
var formattingDispatchTable = {
'fa fa-bold': function(textarea, selectionStart, selectionEnd){
if(selectionStart === selectionEnd){
controls.insertIntoTextarea(textarea, '**bolded text**');
controls.updateTextareaSelection(textarea, selectionStart + 2, selectionStart + 13);
} else {
controls.wrapSelectionInTextareaWith(textarea, '**');
controls.updateTextareaSelection(textarea, selectionStart + 2, selectionEnd + 2);
}
},
'fa fa-italic': function(textarea, selectionStart, selectionEnd){
if(selectionStart === selectionEnd){
controls.insertIntoTextarea(textarea, "*italicised text*");
controls.updateTextareaSelection(textarea, selectionStart + 1, selectionStart + 16);
} else {
controls.wrapSelectionInTextareaWith(textarea, '*');
controls.updateTextareaSelection(textarea, selectionStart + 1, selectionEnd + 1);
}
},
'fa fa-list': function(textarea, selectionStart, selectionEnd){
if(selectionStart === selectionEnd){
controls.insertIntoTextarea(textarea, "\n* list item");
// Highlight "list item"
controls.updateTextareaSelection(textarea, selectionStart + 3, selectionStart + 12);
} else {
controls.wrapSelectionInTextareaWith(textarea, '\n* ', '');
controls.updateTextareaSelection(textarea, selectionStart + 3, selectionEnd + 3);
}
},
'fa fa-link': function(textarea, selectionStart, selectionEnd){
if(selectionStart === selectionEnd){
controls.insertIntoTextarea(textarea, "[link text](link url)");
// Highlight "link url"
controls.updateTextareaSelection(textarea, selectionStart + 12, selectionEnd + 20);
} else {
controls.wrapSelectionInTextareaWith(textarea, '[', '](link url)');
// Highlight "link url"
controls.updateTextareaSelection(textarea, selectionEnd + 3, selectionEnd + 11);
}
},
'fa fa-picture-o': function(){
'picture-o': function(){
$('#files').click();
},
'fa fa-upload': function(){
upload: function(){
$('#files').click();
},
'fa fa-tags': function() {
tags: function() {
$('.tags-container').toggleClass('hidden');
}
};
@ -69,27 +23,32 @@ define('composer/formatting', ['composer/controls', 'composer/preview'], functio
var customButtons = [];
formatting.addComposerButtons = function() {
for (var button in customButtons) {
if (customButtons.hasOwnProperty(button)) {
$('.formatting-bar .btn-group form').before('<span class="btn btn-link" tabindex="-1"><i class="' + customButtons[button].iconClass + '"></i></span>');
}
for(var x=0,numButtons=customButtons.length;x<numButtons;x++) {
$('.formatting-bar .btn-group form').before('<span class="btn btn-link" tabindex="-1" data-format="' + customButtons[x].name + '"><i class="' + customButtons[x].iconClass + '"></i></span>');
}
}
};
formatting.addButton = function(iconClass, onClick) {
formattingDispatchTable[iconClass] = onClick;
var name = iconClass.replace('fa fa-', '');
formattingDispatchTable[name] = onClick;
customButtons.push({
name: name,
iconClass: iconClass
});
}
};
formatting.addButtonDispatch = function(name, onClick) {
formattingDispatchTable[name] = onClick;
};
formatting.addHandler = function(postContainer) {
postContainer.on('click', '.formatting-bar span', function () {
var iconClass = $(this).find('i').attr('class');
var textarea = $(this).parents('.composer').find('textarea')[0];
var format = $(this).attr('data-format'),
textarea = $(this).parents('.composer').find('textarea')[0];
if(formattingDispatchTable.hasOwnProperty(iconClass)){
formattingDispatchTable[iconClass](textarea, textarea.selectionStart, textarea.selectionEnd);
if(formattingDispatchTable.hasOwnProperty(format)){
formattingDispatchTable[format](textarea, textarea.selectionStart, textarea.selectionEnd);
preview.render(postContainer);
}
});

@ -270,9 +270,12 @@
value = options.skipToType[key] ? decodeURI(val[1]) : utils.toType(decodeURI(val[1]));
if (key) {
if (key.substr(-2, 2) === '[]') {
key = key.slice(0, -2);
}
if (!hash[key]) {
hash[key] = value;
} else {
} else {
if (!$.isArray(hash[key])) {
hash[key] = [hash[key]];
}
@ -293,24 +296,6 @@
return a;
},
getQueryParams: function() {
var search = window.location.search.slice(1),
data = {};
search = search.split('&');
for(var x=0,numParams=search.length,temp;x<numParams;x++) {
temp = search[x].split('=');
if (temp[0].substr(-2, 2) !== '[]') {
data[temp[0]] = temp[1];
} else {
data[temp[0].slice(0, -2)] = data[temp[0].slice(0, -2)] || [];
data[temp[0].slice(0, -2)].push(temp[1]);
}
}
return data;
},
// return boolean if string 'true' or string 'false', or if a parsable string which is a number
// also supports JSON object and/or arrays parsing
toType: function(str) {

@ -163,14 +163,24 @@ adminController.tags.get = function(req, res, next) {
};
adminController.flags.get = function(req, res, next) {
var uid = req.user ? parseInt(req.user.uid, 10) : 0;
posts.getFlags(uid, 0, 19, function(err, posts) {
function done(err, posts) {
if (err) {
return next(err);
}
res.render('admin/manage/flags', {posts: posts, next: 20});
});
res.render('admin/manage/flags', {posts: posts, next: end + 1, byUsername: byUsername});
}
var uid = req.user ? parseInt(req.user.uid, 10) : 0;
var sortBy = req.query.sortBy || 'count';
var byUsername = req.query.byUsername || '';
var start = 0;
var end = 19;
if (byUsername) {
posts.getUserFlags(byUsername, sortBy, uid, start, end, done);
} else {
var set = sortBy === 'count' ? 'posts:flags:count' : 'posts:flagged';
posts.getFlags(set, uid, start, end, done);
}
};
adminController.database.get = function(req, res, next) {

@ -5,6 +5,7 @@ var uploadsController = {},
fs = require('fs'),
path = require('path'),
async = require('async'),
validator = require('validator'),
meta = require('../meta'),
file = require('../file'),
@ -117,8 +118,10 @@ function uploadFile(uid, uploadedFile, callback) {
if (uploadedFile.size > parseInt(meta.config.maximumFileSize, 10) * 1024) {
return callback(new Error('[[error:file-too-big, ' + meta.config.maximumFileSize + ']]'));
}
var filename = uploadedFile.name || 'upload';
var filename = 'upload-' + utils.generateUUID() + path.extname(uploadedFile.name);
filename = Date.now() + '-' + validator.escape(filename).substr(0, 255);
file.saveFileToLocal(filename, 'files', uploadedFile.path, function(err, upload) {
if (err) {
return callback(err);

@ -825,40 +825,58 @@ var async = require('async'),
], callback);
};
Groups.getGroupsData = function(groupNames, callback) {
if (!Array.isArray(groupNames) || !groupNames.length) {
return callback(null, []);
}
var keys = groupNames.map(function(groupName) {
return 'group:' + groupName;
});
db.getObjects(keys, function(err, groupData) {
if (err) {
return callback(err);
}
groupData = groupData.map(function(group) {
if (group) {
group.labelColor = group.labelColor || '#000000';
group.createtimeISO = utils.toISOString(group.createtime);
group.hidden = parseInt(group.hidden, 10) === 1;
if (!group['cover:url']) {
group['cover:url'] = nconf.get('relative_path') + '/images/cover-default.png';
group['cover:position'] = '50% 50%';
}
}
return group;
});
plugins.fireHook('filter:groups.get', {groups: groupData}, function(err, data) {
callback(err, data ? data.groups : null);
});
});
};
Groups.getUserGroups = function(uids, callback) {
db.getSortedSetRevRange('groups:createtime', 0, -1, function(err, groupNames) {
if (err) {
return callback(err);
}
var groupKeys = groupNames.filter(function(groupName) {
groupNames = groupNames.filter(function(groupName) {
return groupName !== 'registered-users' && groupName.indexOf(':privileges:') === -1;
}).map(function(groupName) {
return 'group:' + groupName;
});
db.getObjects(groupKeys, function(err, groupData) {
Groups.getGroupsData(groupNames, function(err, groupData) {
if (err) {
return callback(err);
}
groupData = groupData.filter(function(group) {
return parseInt(group.hidden, 10) !== 1 && !!group.userTitle;
}).map(function(group) {
group.createtimeISO = utils.toISOString(group.createtime);
return group;
return group && parseInt(group.hidden, 10) !== 1 && !!group.userTitle;
});
var groupSets = groupData.map(function(group) {
group.labelColor = group.labelColor || '#000000';
group.createtimeISO = utils.toISOString(group.createtime);
if (!group['cover:url']) {
group['cover:url'] = nconf.get('relative_path') + '/images/cover-default.png';
group['cover:position'] = '50% 50%';
}
return 'group:' + group.name + ':members';
});

@ -320,33 +320,34 @@ var db = require('./database'),
};
function sendNotifications(fromuid, touid, messageObj, callback) {
if (!websockets.isUserOnline(touid)) {
notifications.create({
bodyShort: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
bodyLong: messageObj.content,
path: nconf.get('relative_path') + '/chats/' + utils.slugify(messageObj.fromUser.username),
nid: 'chat_' + fromuid + '_' + touid,
from: fromuid
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, [touid], callback);
}
});
user.getSettings(messageObj.toUser.uid, function(err, settings) {
if (settings.sendChatNotifications && !parseInt(meta.config.disableEmailSubscriptions, 10)) {
emailer.send('notif_chat', touid, {
subject: '[[email:notif.chat.subject, ' + messageObj.fromUser.username + ']]',
username: messageObj.toUser.username,
summary: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
message: messageObj,
site_title: meta.config.title || 'NodeBB',
url: nconf.get('url'),
fromUserslug: utils.slugify(messageObj.fromUser.username)
});
}
});
if (websockets.isUserOnline(touid)) {
return callback();
}
notifications.create({
bodyShort: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
bodyLong: messageObj.content,
nid: 'chat_' + fromuid + '_' + touid,
from: fromuid
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, [touid], callback);
}
});
user.getSettings(messageObj.toUser.uid, function(err, settings) {
if (settings.sendChatNotifications && !parseInt(meta.config.disableEmailSubscriptions, 10)) {
emailer.send('notif_chat', touid, {
subject: '[[email:notif.chat.subject, ' + messageObj.fromUser.username + ']]',
username: messageObj.toUser.username,
summary: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
message: messageObj,
site_title: meta.config.title || 'NodeBB',
url: nconf.get('url'),
fromUserslug: utils.slugify(messageObj.fromUser.username)
});
}
});
}
}(exports));

@ -55,11 +55,12 @@ var async = require('async'),
}
if (notification.from && !notification.image) {
User.getUserField(notification.from, 'picture', function(err, picture) {
User.getUserFields(notification.from, ['username', 'userslug', 'picture'], function(err, userData) {
if (err) {
return next(err);
}
notification.image = picture;
notification.image = userData.picture;
notification.user = userData;
next(null, notification);
});
return;

@ -29,7 +29,7 @@ module.exports = function(Posts) {
removeFromCategoryRecentPosts(pid, postData.tid, next);
},
function(next) {
db.sortedSetRemove('posts:flagged', pid, next);
Posts.dismissFlags(pid, next);
}
], function(err) {
callback(err, postData);
@ -125,6 +125,9 @@ module.exports = function(Posts) {
},
function(next) {
db.sortedSetsRemove(['posts:pid', 'posts:flagged'], pid, next);
},
function(next) {
Posts.dismissFlags(pid, next);
}
], function(err) {
if (err) {

@ -3,22 +3,52 @@
'use strict';
var async = require('async'),
db = require('../database');
db = require('../database'),
user = require('../user');
module.exports = function(Posts) {
Posts.flag = function(pid, callback) {
Posts.exists(pid, function(err, exists) {
if (err || !exists) {
Posts.flag = function(post, uid, callback) {
async.parallel({
hasFlagged: async.apply(hasFlagged, post.pid, uid),
exists: async.apply(Posts.exists, post.pid)
}, function(err, results) {
if (err || !results.exists) {
return callback(err || new Error('[[error:no-post]]'));
}
if (results.hasFlagged) {
return callback(new Error('[[error:already-flagged]]'));
}
var now = Date.now();
async.parallel([
function(next) {
db.sortedSetAdd('posts:flagged', Date.now(), pid, next);
db.sortedSetAdd('posts:flagged', now, post.pid, next);
},
function(next) {
db.sortedSetIncrBy('posts:flags:count', 1, post.pid, next);
},
function(next) {
db.incrObjectField('post:' + post.pid, 'flags', next);
},
function(next) {
db.sortedSetAdd('pid:' + post.pid + ':flag:uids', now, uid, next);
},
function(next) {
db.incrObjectField('post:' + pid, 'flags', next);
if (parseInt(post.uid, 10)) {
db.sortedSetAdd('uid:' + post.uid + ':flag:pids', now, post.pid, next);
} else {
next();
}
},
function(next) {
if (parseInt(post.uid, 10)) {
db.setAdd('uid:' + post.uid + ':flagged_by', uid, next);
} else {
next();
}
}
], function(err, results) {
callback(err);
@ -26,14 +56,31 @@ module.exports = function(Posts) {
});
};
function hasFlagged(pid, uid, callback) {
db.isSortedSetMember('pid:' + pid + ':flag:uids', uid, callback);
}
Posts.dismissFlag = function(pid, callback) {
async.parallel([
function(next) {
db.sortedSetRemove('posts:flagged', pid, next);
db.getObjectField('post:' + pid, 'uid', function(err, uid) {
if (err) {
return next(err);
}
db.sortedSetsRemove([
'posts:flagged',
'posts:flags:count',
'uid:' + uid + ':flag:pids'
], pid, next);
});
},
function(next) {
db.deleteObjectField('post:' + pid, 'flags', next);
}
},
function(next) {
db.delete('pid:' + pid + ':flag:uids', next);
}
], function(err, results) {
callback(err);
});
@ -43,8 +90,8 @@ module.exports = function(Posts) {
db.delete('posts:flagged', callback);
};
Posts.getFlags = function(uid, start, end, callback) {
db.getSortedSetRevRange('posts:flagged', start, end, function(err, pids) {
Posts.getFlags = function(set, uid, start, end, callback) {
db.getSortedSetRevRange(set, start, end, function(err, pids) {
if (err) {
return callback(err);
}
@ -52,4 +99,29 @@ module.exports = function(Posts) {
Posts.getPostSummaryByPids(pids, uid, {stripTags: false, extraFields: ['flags']}, callback);
});
};
Posts.getUserFlags = function(byUsername, sortBy, callerUID, start, end, callback) {
async.waterfall([
function(next) {
user.getUidByUsername(byUsername, next);
},
function(uid, next) {
if (!uid) {
return next(null, []);
}
db.getSortedSetRevRange('uid:' + uid + ':flag:pids', 0, -1, next);
},
function(pids, next) {
Posts.getPostSummaryByPids(pids, callerUID, {stripTags: false, extraFields: ['flags']}, next);
},
function(posts, next) {
if (sortBy === 'count') {
posts.sort(function(a, b) {
return b.flags - a.flags;
});
}
next(null, posts.slice(start, end));
}
], callback);
};
};

@ -365,47 +365,31 @@ function sortPosts(posts, data) {
if (isNumeric) {
if (data.sortDirection === 'desc') {
sortDescendingNumeric(posts, fields);
posts.sort(function(p1, p2) {
return p2[fields[0]][fields[1]] - p1[fields[0]][fields[1]];
});
} else {
sortAscendingNumeric(posts, fields);
posts.sort(function(p1, p2) {
return p1[fields[0]][fields[1]] - p2[fields[0]][fields[1]];
});
}
} else {
if (data.sortDirection === 'desc') {
sortDescendingAlpha(posts, fields);
posts.sort(function(p1, p2) {
if (p1[fields[0]][fields[1]] < p2[fields[0]][fields[1]]) return -1;
if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) return 1;
return 0;
});
} else {
sortAscendingAlpha(posts, fields);
posts.sort(function(p1, p2) {
if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) return -1;
if (p1[fields[0]][fields[1]] < p2[fields[0]][fields[1]]) return 1;
return 0;
});
}
}
}
function sortAscendingNumeric(posts, fields) {
posts.sort(function(p1, p2) {
return p1[fields[0]][fields[1]] - p2[fields[0]][fields[1]];
});
}
function sortDescendingNumeric(posts, fields) {
posts.sort(function(p1, p2) {
return p2[fields[0]][fields[1]] - p1[fields[0]][fields[1]];
});
}
function sortAscendingAlpha(posts, fields) {
posts.sort(function(p1, p2) {
if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) return -1;
if (p1[fields[0]][fields[1]] < p2[fields[0]][fields[1]]) return 1;
return 0;
});
}
function sortDescendingAlpha(posts, fields) {
posts.sort(function(p1, p2) {
if (p1[fields[0]][fields[1]] < p2[fields[0]][fields[1]]) return -1;
if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) return 1;
return 0;
});
}
function getSearchCategories(data, callback) {
if (!Array.isArray(data.categories) || !data.categories.length || data.categories.indexOf('all') !== -1) {
return callback(null, []);

@ -312,14 +312,24 @@ SocketAdmin.dismissAllFlags = function(socket, data, callback) {
posts.dismissAllFlags(callback);
};
SocketAdmin.getMoreFlags = function(socket, after, callback) {
if (!parseInt(after, 10)) {
SocketAdmin.getMoreFlags = function(socket, data, callback) {
if (!data || !parseInt(data.after, 10)) {
return callback('[[error:invalid-data]]');
}
after = parseInt(after, 10);
posts.getFlags(socket.uid, after, after + 19, function(err, posts) {
callback(err, {posts: posts, next: after + 20});
});
var sortBy = data.sortBy || 'count';
var byUsername = data.byUsername || '';
var start = parseInt(data.after, 10);
var end = start + 19;
if (byUsername) {
posts.getUserFlags(byUsername, sortBy, socket.uid, start, end, function(err, posts) {
callback(err, {posts: posts, next: end + 1});
});
} else {
var set = sortBy === 'count' ? 'posts:flags:count' : 'posts:flagged';
posts.getFlags(set, socket.uid, start, end, function(err, posts) {
callback(err, {posts: posts, next: end + 1});
});
}
};
SocketAdmin.takeHeapSnapshot = function(socket, data, callback) {

@ -114,6 +114,16 @@ SocketModules.composer.stopNotifyTyping = function(socket, data) {
server.in('topic_' + data.tid).emit('event:topic.stopNotifyTyping', data);
};
SocketModules.composer.getFormattingOptions = function(socket, data, callback) {
plugins.fireHook('filter:composer.formatting', {
options: [
// { className: 'fa fa-bold' } Just an example of what needs to be set via plugins
]
}, function(err, payload) {
callback(err, payload.options);
});
};
/* Chat */
SocketModules.chats.get = function(socket, data, callback) {

@ -422,14 +422,14 @@ SocketPosts.flag = function(socket, pid, callback) {
return next(new Error('[[error:not-enough-reputation-to-flag]]'));
}
userName = userData.username;
posts.getPostFields(pid, ['tid', 'uid', 'content', 'deleted'], next);
posts.getPostFields(pid, ['pid', 'tid', 'uid', 'content', 'deleted'], next);
},
function(postData, next) {
if (parseInt(postData.deleted, 10) === 1) {
return next(new Error('[[error:post-deleted]]'));
}
post = postData;
posts.flag(pid, next);
posts.flag(post, socket.uid, next);
},
function(next) {
topics.getTopicFields(post.tid, ['title', 'cid'], next);
@ -462,14 +462,7 @@ SocketPosts.flag = function(socket, pid, callback) {
}
notifications.push(notification, results.admins.concat(results.moderators), next);
});
},
function(next) {
if (!parseInt(post.uid, 10)) {
return next();
}
db.setAdd('uid:' + post.uid + ':flagged_by', socket.uid, next);
}
}
], callback);
};

@ -294,7 +294,6 @@ SocketUser.follow = function(socket, data, callback) {
notifications.create({
bodyShort: '[[notifications:user_started_following_you, ' + userData.username + ']]',
path: nconf.get('relative_path') + '/user/' + userData.userslug,
nid: 'follow:' + data.uid + ':uid:' + socket.uid,
from: socket.uid
}, function(err, notification) {

@ -250,11 +250,24 @@ Upgrade.upgrade = function(callback) {
}, next);
}
Groups.list({showSystemGroups: true}, function(err, groups) {
async.waterfall([
async.apply(db.getSetMembers, 'groups'),
function(groups, next) {
async.filter(groups, function(group, next) {
db.getObjectField('group:' + group, 'hidden', function(err, hidden) {
next(!parseInt(hidden, 10));
}, next);
}, function(groups) {
next(null, groups);
});
}
], function(err, groups) {
if (err) {
return next(err);
}
groups.push('administrators', 'registered-users');
async.eachLimit(cids, 50, function(cid, next) {
upgradePrivileges(cid, groups, next);
}, next);
@ -445,7 +458,7 @@ Upgrade.upgrade = function(callback) {
if (setting.dailyDigestFreq !== 'off') {
db.sortedSetAdd('digest:' + setting.dailyDigestFreq + ':uids', now, setting.uid, next);
} else {
next(false);
setImmediate(next);
}
}, function(err) {
if (err) {

@ -80,7 +80,7 @@ module.exports = function(User) {
'uid:' + uid + ':topics', 'uid:' + uid + ':posts',
'uid:' + uid + ':chats', 'uid:' + uid + ':chats:unread',
'uid:' + uid + ':upvote', 'uid:' + uid + ':downvote',
'uid:' + uid + ':ignored:cids'
'uid:' + uid + ':ignored:cids', 'uid:' + uid + ':flag:pids'
];
db.deleteAll(keys, next);
},

@ -124,6 +124,13 @@ var async = require('async'),
}
notification.path = pidToPaths[notification.pid] || notification.path || '';
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.datetimeISO = utils.toISOString(notification.datetime);
return notification;
});

@ -56,46 +56,55 @@
</head>
<body class="admin">
<div class="navbar navbar-inverse navbar-fixed-top header">
<nav class="navbar navbar-inverse navbar-fixed-top header">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand nodebb-logo" href="{relative_path}/admin/general/dashboard"><img src="{relative_path}/images/logo.png" alt="NodeBB ACP" /> Admin Control Panel <span id="breadcrumbs" class="hidden-xs"></span></a>
<ul class="nav navbar-nav pull-left">
<li>
<a href="#" id="reconnect"></a>
</li>
</ul>
</div>
<ul class="nav navbar-nav">
<li>
<a href="#" id="reconnect"></a>
</li>
</ul>
<ul id="logged-in-menu" class="nav navbar-nav navbar-right">
<form class="navbar-form navbar-left hidden-xs" role="search">
<div class="form-group" id="acp-search" >
<div class="dropdown" >
<input type="text" data-toggle="dropdown" class="form-control" placeholder="/">
<ul class="dropdown-menu" role="menu"></ul>
</div>
</div>
</form>
<li class="nav-home">
<a href="{relative_path}/" target="_blank" title="Open forum homepage"><i class="fa fa-home"></i></a>
</li>
<li id="user_label" class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="user_dropdown">
<img src="{userpicture}"/>
</a>
<ul id="user-control-list" class="dropdown-menu" aria-labelledby="user_dropdown">
<li>
<a id="user-profile-link" href="{relative_path}/user/{userslug}" target="_top"><span>Profile</span></a>
</li>
<li id="logout-link">
<a href="#">Log out</a>
</li>
</ul>
</li>
</ul>
<div class="navbar-collapse collapse">
<ul id="logged-in-menu" class="navbar-nav nav navbar-right pull-right">
<li style="float:left;">
<form class="navbar-form hidden-xs" role="search">
<div class="form-group" id="acp-search" >
<div class="dropdown" >
<input type="text" data-toggle="dropdown" class="form-control" placeholder="/">
<ul class="dropdown-menu" role="menu"></ul>
</div>
</div>
</form>
</li>
<li id="user_label" class="dropdown pull-right">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="user_dropdown">
<img src="{userpicture}"/>
</a>
<ul id="user-control-list" class="dropdown-menu" aria-labelledby="user_dropdown">
<li>
<a id="user-profile-link" href="{relative_path}/user/{userslug}" target="_top"><span>Profile</span></a>
</li>
<li id="logout-link">
<a href="#">Log out</a>
</li>
</ul>
</li>
<li class="nav-home pull-right">
<a href="{relative_path}/" target="_blank" title="Open forum homepage" data-original-title="Open forum homepage">
<i class="fa fa-home fa-fw"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
</nav>
<div class="wrapper">
<div id="main-menu" class="nano">

@ -2,42 +2,69 @@
<div class="col-lg-9">
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-flag"></i> Flags</div>
<div class="panel-body post-container" data-next="{next}">
<div class="panel-body" data-next="{next}">
<form id="flag-search" method="GET" action="flags">
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label>Flags by user</label>
<input type="text" class="form-control" id="byUsername" placeholder="Search flagged posts by username" name="byUsername" value="{byUsername}">
</div>
</div>
</div>
<!-- IF !posts.length -->
No flagged posts!
<!-- ENDIF !posts.length-->
<div class="form-group">
<label>Sort By</label>
<div class="row">
<div class="col-md-6">
<select id="flag-sort-by" class="form-control" name="sortBy">
<option value="count">Most Flags</option>
<option value="time">Most Recent</option>
</select>
</div>
</div>
</div>
<!-- BEGIN posts -->
<div>
<div class="panel panel-default" data-pid="{posts.pid}" data-tid="{posts.topic.tid}">
<div class="panel-body">
<a href="{relative_path}/user/{posts.user.userslug}">
<img title="{posts.user.username}" class="img-rounded user-img" src="{posts.user.picture}">
</a>
<button type="submit" class="btn btn-default">[[global:search]]</button>
</form>
<hr/>
<div class="post-container" data-next="{next}">
<!-- IF !posts.length -->
No flagged posts!
<!-- ENDIF !posts.length-->
<!-- BEGIN posts -->
<div>
<div class="panel panel-default" data-pid="{posts.pid}" data-tid="{posts.topic.tid}">
<div class="panel-body">
<a href="{relative_path}/user/{posts.user.userslug}">
<img title="{posts.user.username}" class="img-rounded user-img" src="{posts.user.picture}">
</a>
<a href="{relative_path}/user/{posts.user.userslug}">
<strong><span>{posts.user.username}</span></strong>
</a>
<div class="content">
<p>{posts.content}</p>
<p class="fade-out"></p>
<a href="{relative_path}/user/{posts.user.userslug}">
<strong><span>{posts.user.username}</span></strong>
</a>
<div class="content">
<p>{posts.content}</p>
<p class="fade-out"></p>
</div>
<small>
<span class="pull-right footer">
Posted in <a href="{relative_path}/category/{posts.category.slug}" target="_blank"><i class="fa {posts.category.icon}"></i> {posts.category.name}</a>, <span class="timeago" title="{posts.relativeTime}"></span> &bull;
<a href="{relative_path}/topic/{posts.topic.slug}/{posts.index}" target="_blank">Read More</a>
</span>
</small>
</div>
<small>
<span class="pull-right footer">
Posted in <a href="{relative_path}/category/{posts.category.slug}" target="_blank"><i class="fa {posts.category.icon}"></i> {posts.category.name}</a>, <span class="timeago" title="{posts.relativeTime}"></span> &bull;
<a href="{relative_path}/topic/{posts.topic.slug}/{posts.index}" target="_blank">Read More</a>
</span>
</small>
</div>
</div>
<span class="badge badge-warning"><i class="fa fa-flag"></i> {posts.flags}</span>
<button class="btn btn-warning dismiss">Dismiss</button>
<button class="btn btn-danger delete">Delete</button>
<br/><br/>
<span class="badge badge-warning"><i class="fa fa-flag"></i> {posts.flags}</span>
<button class="btn btn-warning dismiss">Dismiss</button>
<button class="btn btn-danger delete">Delete</button>
<br/><br/>
</div>
<!-- END posts -->
</div>
<!-- END posts -->
</div>
</div>
</div>

Loading…
Cancel
Save