Merge commit 'c3fc1347ec850d0b2f94b4e12db94f6dc1d4b808' into weekly

This commit is contained in:
NodeBB Misty
2016-08-01 16:00:18 -04:00
86 changed files with 577 additions and 719 deletions

View File

@@ -18,7 +18,7 @@
"autoprefixer": "^6.2.3",
"bcryptjs": "~2.3.0",
"body-parser": "^1.9.0",
"chart.js": "^1.0.2",
"chart.js": "^2.1.0",
"colors": "^1.1.0",
"compression": "^1.1.0",
"connect-ensure-login": "^0.1.1",
@@ -57,7 +57,7 @@
"nodebb-plugin-spam-be-gone": "0.4.9",
"nodebb-rewards-essentials": "0.0.9",
"nodebb-theme-lavender": "3.0.13",
"nodebb-theme-persona": "4.1.11",
"nodebb-theme-persona": "4.1.12",
"nodebb-theme-vanilla": "5.1.3",
"nodebb-widget-essentials": "2.0.10",
"nodemailer": "2.0.0",
@@ -117,4 +117,4 @@
"url": "https://github.com/barisusakli"
}
]
}
}

View File

@@ -10,11 +10,11 @@
"share_this_category": "انشر هذه الفئة",
"watch": "تابع",
"ignore": "تجاهل",
"watching": "Watching",
"ignoring": "Ignoring",
"watching.description": "Show topics in unread",
"ignoring.description": "Do not show topics in unread",
"watch.message": "أنت اﻷن متابع لتحديثات هذه الفئة",
"watching": "متابع",
"ignoring": "متجاهل",
"watching.description": "أظهر المواضيع في غير مقروء",
"ignoring.description": "لا تظهر المواضيع في غير مقروء",
"watch.message": "أنت اﻷن تتابع تحديثات هذه الفئة",
"ignore.message": "أنت اﻷن تتجاهل تحديثات هذه الفئة",
"watched-categories": "الفئات المراقبه"
"watched-categories": "الفئات المتابعة"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "Потребителят не е в стаята",
"no-users-in-room": "Няма потребители в тази стая",
"cant-kick-self": "Не можете да изритате себе си от групата",
"no-users-selected": "Няма избран(и) потребител(и)"
"no-users-selected": "Няма избран(и) потребител(и)",
"invalid-home-page-route": "Грешен път към началната страница"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "Nemůžete vyhodit sami sebe ze kupiny",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "Bruger er ikke i rummet",
"no-users-in-room": "Ingen brugere i rummet",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "Benutzer nicht im Raum",
"no-users-in-room": "In diesem Raum befinden sich keine Benutzer.",
"cant-kick-self": "Du kannst dich nicht selber aus der Gruppe entfernen.",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -25,6 +25,7 @@
"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, please click here to confirm your email.",
"email-not-confirmed-email-sent": "Your email has not been confirmed yet, please check your inbox for the confirmation 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.",
"confirm-email-already-sent": "Confirmation email already sent, please wait %1 minute(s) to send another one.",

View File

@@ -116,5 +116,7 @@
"enter_page_number": "Enter page number",
"upload_file": "Upload file",
"upload": "Upload",
"allowed-file-types": "Allowed file types are %1"
"allowed-file-types": "Allowed file types are %1",
"unsaved-changes": "You have unsaved changes. Are you sure you wish to navigate away?"
}

View File

@@ -7,5 +7,6 @@
"alternative_logins": "Alternative Logins",
"failed_login_attempt": "Login Unsuccessful",
"login_successful": "You have successfully logged in!",
"dont_have_account": "Don't have an account?"
"dont_have_account": "Don't have an account?",
"logged-out-due-to-inactivity": "You have been logged out due to inactivity"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "El usuario no está en la sala",
"no-users-in-room": "No hay usuarios en esta sala",
"cant-kick-self": "No te puedes expulsar a ti mismo del grupo",
"no-users-selected": "Ningun usuario(s) seleccionado"
"no-users-selected": "Ningun usuario(s) seleccionado",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "Kasutaja pole ruumis",
"no-users-in-room": "Ühtegi kasutajat ei leidu siit ruumist",
"cant-kick-self": "Sa ei saa ennast ära visata gruppist",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "هیچ کاربری در این گفتگو نیست",
"no-users-in-room": "هیچ کاربری در این گفتگو نیست",
"cant-kick-self": "شما نمی توانید خودتان را از گروه کیک کنید",
"no-users-selected": "هیچ کاربر(های) انتخاب نشده"
"no-users-selected": "هیچ کاربر(های) انتخاب نشده",
"invalid-home-page-route": "مسیر صفحه اصلی نامعتبر است"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "Käyttäjä ei ole huoneessa",
"no-users-in-room": "Ei käyttäjiä tässä huoneessa",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "L'utilisateur n'est pas dans cette salle",
"no-users-in-room": "Aucun utilisateur dans cette salle",
"cant-kick-self": "Vous ne pouvez pas vous exclure vous-même du groupe",
"no-users-selected": "Aucun utilisateur sélectionné"
"no-users-selected": "Aucun utilisateur sélectionné",
"invalid-home-page-route": "Route de page d'accueil invalide"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "O usuario non se encontra nesta sala",
"no-users-in-room": "Non hai usuarios nesta sala",
"cant-kick-self": "Non te podes expulsar a ti mesmo do grupo",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "משתמש זה לא בצ'אט",
"no-users-in-room": "אין משתמש בחדר הזה",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "없는 사용자입니다.",
"no-users-in-room": "사용자가 없습니다.",
"cant-kick-self": "스스로 이 그룹을 탈퇴할 수 없습니다.",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "Pengguna tiada dalam bilik",
"no-users-in-room": "Tiada pengguna dalam bilik ini",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -10,10 +10,10 @@
"share_this_category": "Deel deze categorie",
"watch": "Volgen",
"ignore": "Negeren",
"watching": "Watching",
"ignoring": "Ignoring",
"watching.description": "Show topics in unread",
"ignoring.description": "Do not show topics in unread",
"watching": "Volgend",
"ignoring": "Negerend",
"watching.description": "Toon ongelezen onderwerpen",
"ignoring.description": "Toon geen onderwerpen onder onder ongelezen onderwerpen",
"watch.message": "Van deze categorie worden nu meldingen ontvangen",
"ignore.message": "Er worden geen meldingen van deze categorie ontvangen",
"watched-categories": "Categorieën die bekeken zijn."

View File

@@ -119,5 +119,6 @@
"not-in-room": "Gebruiker niet in de chat",
"no-users-in-room": "Er zijn geen gebruikers in deze chat",
"cant-kick-self": "Je kunt jezelf niet uit een groep schoppen",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -31,8 +31,8 @@
"flag_success": "Dit bericht is gerapporteerd aan de beheerder.",
"deleted_message": "Dit onderwerp is verwijderd. Alleen gebruikers met beheerrechten op onderwerpniveau kunnen dit inzien.",
"following_topic.message": "Vanaf nu worden meldingen ontvangen zodra iemand een reactie op dit onderwerp geeft.",
"not_following_topic.message": "You will see this topic in the unread topics list, but you will not receive notifications when somebody posts to this topic.",
"ignoring_topic.message": "You will no longer see this topic in the unread topics list. You will be notified when you are mentioned or your post is up voted.",
"not_following_topic.message": "Dit onderwerp zal verschijnen in de lijst van ongelezen onderwerpen, maar er zullen geen meldingen ontvangen zodra iemand een reactie op dit onderwerp geeft.",
"ignoring_topic.message": "Dit onderwerp zal niet meer verschijnen in de lijst van ongelezen berichten. U zult enkel een melding ontvangen wanneer u wordt genoemd, of wanneer er een positieve stem op uw reactie wordt gegeven.",
"login_to_subscribe": "Log in or registreer om dit onderwerp te volgen.",
"markAsUnreadForAll.success": "Onderwerp is voor iedereen als ongelezen gemarkeerd.",
"mark_unread": "Ongelezen markeren",
@@ -45,9 +45,9 @@
"watching": "Gevolgd",
"not-watching": "Niet gevolgd",
"ignoring": "Genegeerd",
"watching.description": "Notify me of new replies.<br/>Show topic in unread.",
"not-watching.description": "Do not notify me of new replies.<br/>Show topic in unread if category is not ignored.",
"ignoring.description": "Do not notify me of new replies.<br/>Do not show topic in unread.",
"watching.description": "Stuur me een melding bij nieuwe reacties.<br/>Toon onderwerp bij de ongelezen onderwerpen.",
"not-watching.description": "Stuur me geen melding van nieuwe reacties.<br/>Toon onderwerp in ongelezen mits de categorie niet genegeerd wordt.",
"ignoring.description": "Stuur me geen melding van nieuwe reacties.<br/>Toon dit onderwerp niet onder de ongelezen onderwerpen.",
"thread_tools.title": "Acties",
"thread_tools.markAsUnreadForAll": "Ongelezen markeren",
"thread_tools.pin": "Onderwerp vastpinnen",

View File

@@ -119,5 +119,6 @@
"not-in-room": "Użytkownik nie jest w pokoju",
"no-users-in-room": "Brak użytkowników w pokoju",
"cant-kick-self": "Nie możesz wyrzucić samego siebie z grupy",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -10,10 +10,10 @@
"share_this_category": "Compartilhar esta categoria",
"watch": "Acompanhar",
"ignore": "Ignorar",
"watching": "Watching",
"ignoring": "Ignoring",
"watching.description": "Show topics in unread",
"ignoring.description": "Do not show topics in unread",
"watching": "Assistindo",
"ignoring": "Ignorando",
"watching.description": "Mostrar tópicos em não-lido",
"ignoring.description": "Não mostrar tópicos em não-lido",
"watch.message": "Agora você está acompanhando as atualizações desta categoria",
"ignore.message": "Agora você está ignorando as atualizações desta categoria",
"watched-categories": "Categorias acompanhadas"

View File

@@ -30,7 +30,7 @@
"user-banned": "Usuário banido",
"user-too-new": "Desculpe, é necessário que você aguarde %1 segundo(s) antes de fazer o seu primeiro post.",
"blacklisted-ip": "Desculpe, o seu endereço IP foi banido desta comunidade. Se você acha que isso é um engano, por favor contate um administrador.",
"ban-expiry-missing": "Please provide an end date for this ban",
"ban-expiry-missing": "Por favor forneça uma data para o fim deste banimento",
"no-category": "A categoria não existe",
"no-topic": "O tópico não existe",
"no-post": "O post não existe",
@@ -47,13 +47,13 @@
"post-edit-duration-expired-hours-minutes": "Você pode apenas editar posts por %1 hora(s) e %2 minuto(s) após postar",
"post-edit-duration-expired-days": "Você pode apenas editar posts por %1 dia(s) após postar",
"post-edit-duration-expired-days-hours": "Você pode apenas editar posts por %1 dia(s) e %2 hora(s) após postar",
"post-delete-duration-expired": "You are only allowed to delete posts for %1 second(s) after posting",
"post-delete-duration-expired-minutes": "You are only allowed to delete posts for %1 minute(s) after posting",
"post-delete-duration-expired-minutes-seconds": "You are only allowed to delete posts for %1 minute(s) %2 second(s) after posting",
"post-delete-duration-expired-hours": "You are only allowed to delete posts for %1 hour(s) after posting",
"post-delete-duration-expired-hours-minutes": "You are only allowed to delete posts for %1 hour(s) %2 minute(s) after posting",
"post-delete-duration-expired-days": "You are only allowed to delete posts for %1 day(s) after posting",
"post-delete-duration-expired-days-hours": "You are only allowed to delete posts for %1 day(s) %2 hour(s) after posting",
"post-delete-duration-expired": "Você só pode deletar posts por %1 segundo(s) depois de postar",
"post-delete-duration-expired-minutes": "Você só pode deletar posts por %1 minuto(s) depois de postar",
"post-delete-duration-expired-minutes-seconds": "Você só pode deletar posts por %1 minuto(s) e %2 segundo(s) depois de postar",
"post-delete-duration-expired-hours": "Você só pode deletar posts por %1 hora(s) depois de postar",
"post-delete-duration-expired-hours-minutes": "Você só pode deletar posts por %1 hora(s) e %2 minutos(s) depois de postar",
"post-delete-duration-expired-days": "Você só pode deletar posts por %1 dia(s) depois de postar",
"post-delete-duration-expired-days-hours": "Você só pode deletar posts por %1 dia(s) e %2 hora(s) depois de postar",
"content-too-short": "Por favor digite um post maior. Posts precisam conter ao menos %1 caractere(s).",
"content-too-long": "Por favor digite um post mais curto. Posts não podem ser maiores que %1 caractere(s)",
"title-too-short": "Por favor digite um título maior. Títulos devem conter no mínimo %1 caractere(s)",
@@ -71,12 +71,12 @@
"already-unfavourited": "Você já removeu este post dos favoritos",
"cant-ban-other-admins": "Você não pode banir outros administradores!",
"cant-remove-last-admin": "Você é o único administrador. Adicione outro usuário como administrador antes de remover a si mesmo como admin",
"cant-delete-admin": "Remove administrator privileges from this account before attempting to delete it.",
"cant-delete-admin": "Remova o privilégio de administrador desta conta antes de tentar deletá-la.",
"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": "Tipo de arquivo inválido. Os tipos permitidos são: %1",
"group-name-too-short": "Nome do grupo é muito curto",
"group-name-too-long": "Group name too long",
"group-name-too-long": "O nome do grupo é muito extenso",
"group-already-exists": "O grupo já existe",
"group-name-change-not-allowed": "Sem permissão para alterar nome do grupo",
"group-already-member": "Já faz parte deste grupo",
@@ -119,5 +119,6 @@
"not-in-room": "O usuário não está na sala",
"no-users-in-room": "Nenhum usuário nesta sala",
"cant-kick-self": "Você não pode kickar a si mesmo do grupo",
"no-users-selected": "No user(s) selected"
"no-users-selected": "Nenhuma escolha de usuário(s) foi feita",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -50,9 +50,9 @@
"topics": "Tópicos",
"posts": "Posts",
"best": "Melhor",
"upvoters": "Upvoters",
"upvoters": "Cimavotadores",
"upvoted": "Votado positivamente",
"downvoters": "Downvoters",
"downvoters": "Baixovotadores",
"downvoted": "Votado negativamente",
"views": "Visualizações",
"reputation": "Reputação",
@@ -80,7 +80,7 @@
"language": "Idioma",
"guest": "Visitante",
"guests": "Visitantes",
"updated.title": "Forum Updated",
"updated.title": "Fórum Atualizado",
"updated.message": "Este fórum foi atualizado para sua última versão. Clique aqui para atualizar a página.",
"privacy": "Privacidade",
"follow": "Seguir",

View File

@@ -12,7 +12,7 @@
"users/sort-posts": "Usuários com mais posts",
"users/sort-reputation": "Usuários com maior reputação",
"users/banned": "Usuários Banidos",
"users/most-flags": "Most flagged users",
"users/most-flags": "Usuários mais sinalizados",
"users/search": "Pesquisa de Usuários",
"notifications": "Notificações",
"tags": "Tags",
@@ -29,7 +29,7 @@
"account/edit/password": "Editando senha de \"%1\"",
"account/edit/username": "Editando nome de usuário de \"%1\"",
"account/edit/email": "Editando email de \"%1\"",
"account/info": "Account Info",
"account/info": "Informação da Conta",
"account/following": "Pessoas que %1 segue",
"account/followers": "Pessoas que seguem %1",
"account/posts": "Posts feitos por %1",

View File

@@ -1,6 +1,6 @@
{
"register": "Cadastrar",
"cancel_registration": "Cancel Registration",
"cancel_registration": "Cancelar Cadastro",
"help.email": "Por padrão seu email ficará invisível para o publico.",
"help.username_restrictions": "Um nome de usuário único entre %1 e %2 caracteres. Os outros poderão te mencionar digitando @<span id='yourUsername'>usuário</span>.",
"help.minimum_password_length": "Sua senha tem que ter no mínimo %1 caracteres.",
@@ -16,8 +16,8 @@
"alternative_registration": "Cadastro Alternativo",
"terms_of_use": "Termos de Uso",
"agree_to_terms_of_use": "Eu concordo com os Termos de Uso",
"terms_of_use_error": "You must agree to the Terms of Use",
"terms_of_use_error": "Você deve concordar com os Termos de Uso",
"registration-added-to-queue": "O seu cadastro foi adicionado à fila de aprovação. Você receberá um email quando ele for aceito por um administrador.",
"interstitial.intro": "We require some additional information before we can create your account.",
"interstitial.errors-found": "We could not complete your registration:"
"interstitial.intro": "Nós pedimos alguma informação adicional antes que você possa criar a sua conta.",
"interstitial.errors-found": "Nós não pudemos completar o seu cadastro:"
}

View File

@@ -31,7 +31,7 @@
"flag_success": "Este post foi sinalizado para ser moderado.",
"deleted_message": "Este tópico foi deletado. Apenas usuários com privilégios de moderação de tópico podem vê-lo.",
"following_topic.message": "Agora você receberá notificações quando alguém responder este tópico.",
"not_following_topic.message": "You will see this topic in the unread topics list, but you will not receive notifications when somebody posts to this topic.",
"not_following_topic.message": "Você verá este tópico na lista de tópicos não-lidos, mas você não receberá notificações quendo alguém posta no tópico.",
"ignoring_topic.message": "Você não verá mais este tópico na lista de tópicos não lidos. Você será notificado quando você for mencionado ou sua postagem for votada positivamente.",
"login_to_subscribe": "Por favor se cadastre ou entre para assinar à este tópico.",
"markAsUnreadForAll.success": "Tópico marcado como não lido para todos.",

View File

@@ -6,7 +6,7 @@
"postcount": "Número de Posts",
"email": "Email",
"confirm_email": "Confirmar Email",
"account_info": "Account Info",
"account_info": "Informação da Conta",
"ban_account": "Banir Conta",
"ban_account_confirm": "Você realmente quer banir esse usuario?",
"unban_account": "Desbanir Conta",
@@ -96,8 +96,8 @@
"delay_image_loading": "Aguardar para Carregar Imagens",
"image_load_delay_help": "Se habilitado, imagens em tópicos não serão carregadas até que eles sejam rolados à visão",
"scroll_to_my_post": "Após postar uma réplica, mostre o novo post",
"follow_topics_you_reply_to": "Watch topics that you reply to",
"follow_topics_you_create": "Watch topics you create",
"follow_topics_you_reply_to": "Assistir os tópicos que você responde",
"follow_topics_you_create": "Assistir aos tópicos que você cria",
"grouptitle": "Título do Grupo",
"no-group-title": "Sem título de grupo",
"select-skin": "Escolha uma Skin",
@@ -109,10 +109,10 @@
"sso.title": "Logar por outros Serviços",
"sso.associated": "Associado com",
"sso.not-associated": "Clique aqui para associar com",
"info.latest-flags": "Latest Flags",
"info.no-flags": "No Flagged Posts Found",
"info.ban-history": "Recent Ban History",
"info.no-ban-history": "This user has never been banned",
"info.banned-until": "Banned until %1",
"info.banned-permanently": "Banned permanently"
"info.latest-flags": "Últimas Sinalizações",
"info.no-flags": "Nenhum Post Sinalizado Encontrado",
"info.ban-history": "Histórico de Banimentos Recentes",
"info.no-ban-history": "Este usuário nunca foi banido",
"info.banned-until": "Banido até %1",
"info.banned-permanently": "Banido permanentemente"
}

View File

@@ -2,7 +2,7 @@
"latest_users": "Últimos Usuários",
"top_posters": "Principais Participantes",
"most_reputation": "Maior Reputação",
"most_flags": "Most Flags",
"most_flags": "Mais Sinalizações",
"search": "Pesquisar",
"enter_username": "Digite um nome de usuário para pesquisar",
"load_more": "Carregar Mais",

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "Пользователь не в комнате",
"no-users-in-room": "В этой комнате нет пользователей",
"cant-kick-self": "Вы не можете удалить себя сами из группы.",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "Nta muntu uri muri iki gikari",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "Användaren finns inte i rummet",
"no-users-in-room": "Inga användare i det här rummet",
"cant-kick-self": "Du kan inte sparka ut dig själv från gruppen",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "User not in room",
"no-users-in-room": "No users in this room",
"cant-kick-self": "You can't kick yourself from the group",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -10,10 +10,10 @@
"share_this_category": "Bu kategoriyi paylaş",
"watch": "İzle",
"ignore": "Yoksay",
"watching": "Watching",
"ignoring": "Ignoring",
"watching.description": "Show topics in unread",
"ignoring.description": "Do not show topics in unread",
"watching": "İzleniyor",
"ignoring": "Yoksayılıyor",
"watching.description": "Okunmamış başlıkları göster",
"ignoring.description": "Okunmamış başlıkları gösterme",
"watch.message": "Şuan bu kategorideki güncellemeleri izliyorsunuz",
"ignore.message": "Şuan bu kategoriden güncellemeleri gizliyorsunuz",
"watched-categories": "Takip edilen kategoriler"

View File

@@ -71,7 +71,7 @@
"already-unfavourited": "Bu iletiyi zaten yer imlerinizden çıkardınız",
"cant-ban-other-admins": "Başka yöneticileri yasaklayamazsınız!",
"cant-remove-last-admin": "Tek yönetici sizsiniz. Kendinizi adminlikten çıkarmadan önce başka bir kullanıcıyı admin olarak ekleyiniz",
"cant-delete-admin": "Remove administrator privileges from this account before attempting to delete it.",
"cant-delete-admin": "Öncelikle yönetici izinlerini kaldırman gerekiyor.",
"invalid-image-type": "Geçersiz resim uzantısı. Izin verilen uzantılar: %1",
"invalid-image-extension": "Geçersiz resim uzantısı",
"invalid-file-type": "Geçersiz dosya türü. İzin verilenler şunlar : %1",
@@ -119,5 +119,6 @@
"not-in-room": "Odada kullanıcı yok",
"no-users-in-room": "Bu odada kullanıcı yok",
"cant-kick-self": "Kendinizi gruptan atamazsınız.",
"no-users-selected": "Seçili kullanıcı(s) bulunamadı"
"no-users-selected": "Seçili kullanıcı(s) bulunamadı",
"invalid-home-page-route": "Geçersiz anasayfa yolu"
}

View File

@@ -50,9 +50,9 @@
"topics": "Başlık",
"posts": "İleti",
"best": "En İyi",
"upvoters": "Upvoters",
"upvoters": "Artı",
"upvoted": "Artı",
"downvoters": "Downvoters",
"downvoters": "Eksi",
"downvoted": "Eksi",
"views": "Görünüm",
"reputation": "Saygınlık",

View File

@@ -29,7 +29,7 @@
"account/edit/password": "\"%1\" parolayı düzenliyor",
"account/edit/username": "\"%1\" kullanıcı adını düzenliyor",
"account/edit/email": "\"%1\" email adresini düzenliyor",
"account/info": "Account Info",
"account/info": "Hesap Hakkında",
"account/following": "%1 tarafından takip edilenler",
"account/followers": "%1 takip edenler",
"account/posts": "%1 tarafından gönderilen iletiler",

View File

@@ -1,6 +1,6 @@
{
"register": "Kayıt Ol",
"cancel_registration": "Cancel Registration",
"cancel_registration": "Kaydı İptal Et",
"help.email": "E-posta adresiniz varsayılan olarak topluluktan gizlidir.",
"help.username_restrictions": "%1 ve %2 karakter arası bir kullanıcı ismi. Başkaları sizden @<span id='yourUsername'>isim</span> kullanarak bahsedebilir.",
"help.minimum_password_length": "Şifreniz en az %1 karakter olmalı",
@@ -16,8 +16,8 @@
"alternative_registration": "Alternatif Kayıt",
"terms_of_use": "Kullanım Şartları",
"agree_to_terms_of_use": "Kullanım Şartlarını kabul ediyorum",
"terms_of_use_error": "You must agree to the Terms of Use",
"terms_of_use_error": "Kullanım şartlarını kabul etmen gerekiyor",
"registration-added-to-queue": "Kayıt olma isteğiniz kabul listesine eklenmiştir. Yönetici tarafından kabul edildiğinizde mail alacaksınız.",
"interstitial.intro": "We require some additional information before we can create your account.",
"interstitial.errors-found": "We could not complete your registration:"
"interstitial.intro": "Hesabınızı yaratmadan önce bazı ekstra bilgiler gerekiyor.",
"interstitial.errors-found": "Kaydınınız tamamlanmadı:"
}

View File

@@ -31,7 +31,7 @@
"flag_success": "Bu ileti yöneticilere bildirildi.",
"deleted_message": "Bu başlık silindi. Sadece başlık düzenleme yetkisi olan kullanıcılar görebilir.",
"following_topic.message": "Artık bir kullanıcı bu başlığa ileti gönderdiğinde bildirim alacaksınız.",
"not_following_topic.message": "You will see this topic in the unread topics list, but you will not receive notifications when somebody posts to this topic.",
"not_following_topic.message": "Bu başlığı okunmamışlarda göreceksiniz ama biri bir şey yazdığında bildirim gelmeyecek.",
"ignoring_topic.message": "Bu başlığı okunmamış başlıklar alanında görmeyeceksin. Eğer bir iletide bahsedilirsen veya iletin oylanırsa bildiri alacaksın.",
"login_to_subscribe": "Lütfen bu iletiyi başlığa üye olmak için giriş yapın.",
"markAsUnreadForAll.success": "Başlık herkes için okunmadı olarak işaretlendi.",

View File

@@ -119,5 +119,6 @@
"not-in-room": "Thành viên không có trong phòng",
"no-users-in-room": "Không có ai trong phòng này",
"cant-kick-self": "Bạn không thể kick chính bạn ra khỏi nhóm",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "用户已不在聊天室中",
"no-users-in-room": "这个聊天室中没有用户",
"cant-kick-self": "你不能把自己踢出群组",
"no-users-selected": "尚未选择用户"
"no-users-selected": "尚未选择用户",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -119,5 +119,6 @@
"not-in-room": "使用者沒有在聊天室中",
"no-users-in-room": "沒有使用者在聊天室中",
"cant-kick-self": "你不能把自己從群組中踢出",
"no-users-selected": "No user(s) selected"
"no-users-selected": "No user(s) selected",
"invalid-home-page-route": "Invalid home page route"
}

View File

@@ -29,6 +29,11 @@
}
}
.fa-home {
margin-top: 12px;
font-size: 25px;
}
#user_dropdown {
font-size: 25px;
color: #eee;

View File

@@ -2,9 +2,23 @@
/*global config, translator, componentHandler, define, socket, app, ajaxify, utils, bootbox, Slideout, NProgress, RELATIVE_PATH*/
(function() {
var logoutTimer = 0;
function startLogoutTimer() {
if (logoutTimer) {
clearTimeout(logoutTimer);
}
logoutTimer = setTimeout(function() {
app.alert({
message: '[[login:logged-out-due-to-inactivity]]'
});
setTimeout(app.logout, 5000);
}, 3600000);
}
$(window).on('action:ajaxify.end', function() {
showCorrectNavTab();
startLogoutTimer();
});
function showCorrectNavTab() {

View File

@@ -16,6 +16,8 @@ define('admin/appearance/customise', ['admin/settings'], function(Settings) {
customCSS.getSession().setMode("ace/mode/css");
customCSS.on('change', function(e) {
app.flags = app.flags || {};
app.flags._unsaved = true;
$('#customCSS-holder').val(customCSS.getValue());
});
@@ -23,6 +25,8 @@ define('admin/appearance/customise', ['admin/settings'], function(Settings) {
customHTML.getSession().setMode("ace/mode/html");
customHTML.on('change', function(e) {
app.flags = app.flags || {};
app.flags._unsaved = true;
$('#customHTML-holder').val(customHTML.getValue());
});
});

View File

@@ -2,18 +2,18 @@
/*global define, ajaxify, app, socket, utils, bootbox, RELATIVE_PATH*/
define('admin/general/dashboard', ['semver', 'Chart'], function(semver, Chart) {
var Admin = {},
intervals = {
var Admin = {};
var intervals = {
rooms: false,
graphs: false
},
isMobile = false,
isPrerelease = /^v?\d+\.\d+\.\d+-.+$/,
graphData = {
};
var isMobile = false;
var isPrerelease = /^v?\d+\.\d+\.\d+-.+$/;
var graphData = {
rooms: {},
traffic: {}
},
currentGraph = {
};
var currentGraph = {
units: 'hours',
until: undefined
};
@@ -121,8 +121,8 @@ define('admin/general/dashboard', ['semver', 'Chart'], function(semver, Chart) {
topics: null
};
var topicColors = ["#bf616a","#5B90BF","#d08770","#ebcb8b","#a3be8c","#96b5b4","#8fa1b3","#b48ead","#ab7967","#46BFBD"],
usedTopicColors = [];
var topicColors = ["#bf616a","#5B90BF","#d08770","#ebcb8b","#a3be8c","#96b5b4","#8fa1b3","#b48ead","#ab7967","#46BFBD"];
var usedTopicColors = [];
// from chartjs.org
function lighten(col, amt) {
@@ -170,92 +170,103 @@ define('admin/general/dashboard', ['semver', 'Chart'], function(semver, Chart) {
}
var data = {
labels: trafficLabels,
datasets: [
{
label: "Page Views",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
},
{
label: "Unique Visitors",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
}
]
};
labels: trafficLabels,
datasets: [
{
label: "Page Views",
backgroundColor: "rgba(220,220,220,0.2)",
borderColor: "rgba(220,220,220,1)",
pointBackgroundColor: "rgba(220,220,220,1)",
pointHoverBackgroundColor: "#fff",
pointBorderColor: "#fff",
pointHoverBorderColor: "rgba(220,220,220,1)",
data: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
},
{
label: "Unique Visitors",
backgroundColor: "rgba(151,187,205,0.2)",
borderColor: "rgba(151,187,205,1)",
pointBackgroundColor: "rgba(151,187,205,1)",
pointHoverBackgroundColor: "#fff",
pointBorderColor: "#fff",
pointHoverBorderColor: "rgba(151,187,205,1)",
data: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
}
]
};
trafficCanvas.width = $(trafficCanvas).parent().width();
graphs.traffic = new Chart(trafficCtx).Line(data, {
responsive: true
graphs.traffic = new Chart(trafficCtx, {
type: 'line',
data: data,
options: {
responsive: true,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
graphs.registered = new Chart(registeredCtx, {
type: 'doughnut',
data: {
labels: ["Registered Users", "Anonymous Users"],
datasets: [{
data: [1, 1],
backgroundColor: ["#F7464A", "#46BFBD"],
hoverBackgroundColor: ["#FF5A5E", "#5AD3D1"]
}]
},
options: {
responsive: true,
legend: {
display: false
}
}
});
graphs.registered = new Chart(registeredCtx).Doughnut([{
value: 1,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Registered Users"
graphs.presence = new Chart(presenceCtx, {
type: 'doughnut',
data: {
labels: ["On categories list", "Reading posts", "Browsing topics", "Recent", "Unread"],
datasets: [{
data: [1, 1, 1, 1, 1],
backgroundColor: ["#F7464A", "#46BFBD", "#FDB45C", "#949FB1", "#9FB194"],
hoverBackgroundColor: ["#FF5A5E", "#5AD3D1", "#FFC870", "#A8B3C5", "#A8B3C5"]
}]
},
options: {
responsive: true,
legend: {
display: false
}
}
});
graphs.topics = new Chart(topicsCtx, {
type: 'doughnut',
data: {
labels: [],
datasets: [{
data: [],
backgroundColor: [],
hoverBackgroundColor: []
}]
},
{
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 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"
},
{
value: 1,
color: "#9FB194",
highlight: "#A8B3C5",
label: "Unread"
}
], {
responsive: true
});
graphs.topics = new Chart(topicsCtx).Doughnut([], {responsive: true});
topicsCanvas.onclick = function(evt){
var obj = graphs.topics.getSegmentsAtEvent(evt);
if (obj && obj[0]) {
window.open(RELATIVE_PATH + '/topic/' + obj[0].tid);
}
};
options: {
responsive: true,
legend: {
display: false
}
}
});
updateTrafficGraph();
@@ -302,15 +313,10 @@ define('admin/general/dashboard', ['semver', 'Chart'], function(semver, Chart) {
graphData.traffic = data;
// If new data set contains fewer points than currently shown, truncate
while(graphs.traffic.datasets[0].points.length > data.pageviews.length) {
graphs.traffic.removeData();
}
if (units === 'days') {
graphs.traffic.scale.xLabels = utils.getDaysArray(until);
graphs.traffic.data.xLabels = utils.getDaysArray(until);
} else {
graphs.traffic.scale.xLabels = utils.getHoursArray();
graphs.traffic.data.xLabels = utils.getHoursArray();
$('#pageViewsThisMonth').html(data.monthlyPageViews.thisMonth);
$('#pageViewsLastMonth').html(data.monthlyPageViews.lastMonth);
@@ -320,17 +326,9 @@ define('admin/general/dashboard', ['semver', 'Chart'], function(semver, Chart) {
utils.addCommasToNumbers($('#pageViewsPastDay'));
}
for (var i = 0, ii = data.pageviews.length; i < ii; i++) {
if (graphs.traffic.datasets[0].points[i]) {
graphs.traffic.datasets[0].points[i].value = data.pageviews[i];
graphs.traffic.datasets[0].points[i].label = graphs.traffic.scale.xLabels[i];
graphs.traffic.datasets[1].points[i].value = data.uniqueVisitors[i];
graphs.traffic.datasets[1].points[i].label = graphs.traffic.scale.xLabels[i];
} else {
// No points to replace? Add data.
graphs.traffic.addData([data.pageviews[i], data.uniqueVisitors[i]], graphs.traffic.scale.xLabels[i]);
}
}
graphs.traffic.data.datasets[0].data = data.pageviews;
graphs.traffic.data.datasets[1].data = data.uniqueVisitors;
graphs.traffic.data.labels = graphs.traffic.data.xLabels;
graphs.traffic.update();
currentGraph.units = units;
@@ -339,22 +337,21 @@ define('admin/general/dashboard', ['semver', 'Chart'], function(semver, Chart) {
}
function updateRegisteredGraph(registered, anonymous) {
graphs.registered.segments[0].value = registered;
graphs.registered.segments[1].value = anonymous;
graphs.registered.data.datasets[0].data[0] = registered;
graphs.registered.data.datasets[0].data[1] = anonymous;
graphs.registered.update();
}
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.unread;
graphs.presence.data.datasets[0].data[0] = users.categories;
graphs.presence.data.datasets[0].data[1] = users.topics;
graphs.presence.data.datasets[0].data[2] = users.category;
graphs.presence.data.datasets[0].data[3] = users.recent;
graphs.presence.data.datasets[0].data[4] = users.unread;
graphs.presence.update();
}
function updateTopicsGraph(topics) {
if (!Object.keys(topics).length) {
topics = {"0": {
@@ -363,88 +360,36 @@ define('admin/general/dashboard', ['semver', 'Chart'], function(semver, Chart) {
}};
}
var tids = Object.keys(topics),
segments = graphs.topics.segments;
function reassignExistingTopics() {
for (var i = segments.length - 1; i >= 0; i--) {
if (!segments[i]) {
continue;
}
var tid = segments[i].tid;
if ($.inArray(tid, tids) === -1) {
usedTopicColors.splice($.inArray(segments[i].fillColor, usedTopicColors), 1);
graphs.topics.removeData(i);
} else {
graphs.topics.segments[i].value = topics[tid].value;
delete topics[tid];
}
}
var tids = Object.keys(topics);
graphs.topics.data.labels = [];
graphs.topics.data.datasets[0].data = [];
graphs.topics.data.datasets[0].backgroundColor = [];
graphs.topics.data.datasets[0].hoverBackgroundColor = [];
for (var i = 0, ii = tids.length; i < ii; i++) {
graphs.topics.data.labels.push(topics[tids[i]].title);
graphs.topics.data.datasets[0].data.push(topics[tids[i]].value);
graphs.topics.data.datasets[0].backgroundColor.push(topicColors[i]);
graphs.topics.data.datasets[0].hoverBackgroundColor.push(lighten(topicColors[i], 10));
}
function assignNewTopics() {
while (segments.length < 10 && tids.length > 0) {
var tid = tids.pop(),
data = topics[tid],
color = null;
if (!data) {
continue;
}
if (tid === '0') {
color = '#4D5360';
} else {
do {
for (var i = 0, ii = topicColors.length; i < ii; i++) {
var chosenColor = topicColors[i];
if ($.inArray(chosenColor, usedTopicColors) === -1) {
color = chosenColor;
usedTopicColors.push(color);
break;
}
}
} while (color === null && usedTopicColors.length < topicColors.length);
}
if (color) {
graphs.topics.addData({
value: data.value,
color: color,
highlight: lighten(color, 10),
label: data.title
});
segments[segments.length - 1].tid = tid;
}
}
}
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>';
for (var i = 0, ii = tids.length; i < ii; i++) {
var topic = topics[tids[i]];
var label = topic.value === '0' ? topic.title : '<a title="' + topic.title + '"href="' + RELATIVE_PATH + '/topic/' + tids[i] + '" target="_blank"> ' + topic.title + '</a>';
legend.append(
'<li>' +
'<div style="background-color: ' + topic.highlightColor + '; border-color: ' + topic.strokeColor + '"></div>' +
'<span>' + label + '</span>' +
'<div style="background-color: ' + topicColors[i] + ';"></div>' +
'<span>' + label + '</span>' +
'</li>');
}
}
reassignExistingTopics();
assignNewTopics();
buildTopicsLegend();
graphs.topics.update();
}

View File

@@ -1,23 +1,23 @@
"use strict";
/*global config, define, app, socket, ajaxify, bootbox, templates, utils */
/*global define, ajaxify, utils */
define('admin/manage/category-analytics', ['Chart'], function(Chart) {
var CategoryAnalytics = {};
CategoryAnalytics.init = function() {
var hourlyCanvas = document.getElementById('pageviews:hourly'),
dailyCanvas = document.getElementById('pageviews:daily'),
topicsCanvas = document.getElementById('topics:daily'),
postsCanvas = document.getElementById('posts:daily'),
hourlyLabels = utils.getHoursArray().map(function(text, idx) {
var hourlyCanvas = document.getElementById('pageviews:hourly');
var dailyCanvas = document.getElementById('pageviews:daily');
var topicsCanvas = document.getElementById('topics:daily');
var postsCanvas = document.getElementById('posts:daily');
var hourlyLabels = utils.getHoursArray().map(function(text, idx) {
return idx % 3 ? '' : text;
}),
dailyLabels = utils.getDaysArray().map(function(text, idx) {
});
var dailyLabels = utils.getDaysArray().map(function(text, idx) {
return idx % 3 ? '' : text;
});
if (utils.isMobile()) {
Chart.defaults.global.showTooltips = false;
Chart.defaults.global.tooltips.enabled = false;
}
var data = {
@@ -26,12 +26,12 @@ define('admin/manage/category-analytics', ['Chart'], function(Chart) {
datasets: [
{
label: "",
fillColor: "rgba(186,139,175,0.2)",
strokeColor: "rgba(186,139,175,1)",
pointColor: "rgba(186,139,175,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(186,139,175,1)",
backgroundColor: "rgba(186,139,175,0.2)",
borderColor: "rgba(186,139,175,1)",
pointBackgroundColor: "rgba(186,139,175,1)",
pointHoverBackgroundColor: "#fff",
pointBorderColor: "#fff",
pointHoverBorderColor: "rgba(186,139,175,1)",
data: ajaxify.data.analytics['pageviews:hourly']
}
]
@@ -41,12 +41,12 @@ define('admin/manage/category-analytics', ['Chart'], function(Chart) {
datasets: [
{
label: "",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
backgroundColor: "rgba(151,187,205,0.2)",
borderColor: "rgba(151,187,205,1)",
pointBackgroundColor: "rgba(151,187,205,1)",
pointHoverBackgroundColor: "#fff",
pointBorderColor: "#fff",
pointHoverBorderColor: "rgba(151,187,205,1)",
data: ajaxify.data.analytics['pageviews:daily']
}
]
@@ -56,12 +56,12 @@ define('admin/manage/category-analytics', ['Chart'], function(Chart) {
datasets: [
{
label: "",
fillColor: "rgba(171,70,66,0.2)",
strokeColor: "rgba(171,70,66,1)",
pointColor: "rgba(171,70,66,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(171,70,66,1)",
backgroundColor: "rgba(171,70,66,0.2)",
borderColor: "rgba(171,70,66,1)",
pointBackgroundColor: "rgba(171,70,66,1)",
pointHoverBackgroundColor: "#fff",
pointBorderColor: "#fff",
pointHoverBorderColor: "rgba(171,70,66,1)",
data: ajaxify.data.analytics['topics:daily']
}
]
@@ -71,12 +71,12 @@ define('admin/manage/category-analytics', ['Chart'], function(Chart) {
datasets: [
{
label: "",
fillColor: "rgba(161,181,108,0.2)",
strokeColor: "rgba(161,181,108,1)",
pointColor: "rgba(161,181,108,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(161,181,108,1)",
backgroundColor: "rgba(161,181,108,0.2)",
borderColor: "rgba(161,181,108,1)",
pointBackgroundColor: "rgba(161,181,108,1)",
pointHoverBackgroundColor: "#fff",
pointBorderColor: "#fff",
pointHoverBorderColor: "rgba(161,181,108,1)",
data: ajaxify.data.analytics['posts:daily']
}
]
@@ -87,21 +87,81 @@ define('admin/manage/category-analytics', ['Chart'], function(Chart) {
dailyCanvas.width = $(dailyCanvas).parent().width();
topicsCanvas.width = $(topicsCanvas).parent().width();
postsCanvas.width = $(postsCanvas).parent().width();
new Chart(hourlyCanvas.getContext('2d')).Line(data['pageviews:hourly'], {
responsive: true,
animation: false
new Chart(hourlyCanvas.getContext('2d'), {
type: 'line',
data: data['pageviews:hourly'],
options: {
responsive: true,
animation: false,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
new Chart(dailyCanvas.getContext('2d')).Line(data['pageviews:daily'], {
responsive: true,
animation: false
new Chart(dailyCanvas.getContext('2d'), {
type: 'line',
data: data['pageviews:daily'],
options: {
responsive: true,
animation: false,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
new Chart(topicsCanvas.getContext('2d')).Line(data['topics:daily'], {
responsive: true,
animation: false
new Chart(topicsCanvas.getContext('2d'), {
type: 'line',
data: data['topics:daily'],
options: {
responsive: true,
animation: false,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
new Chart(postsCanvas.getContext('2d')).Line(data['posts:daily'], {
responsive: true,
animation: false
new Chart(postsCanvas.getContext('2d'), {
type: 'line',
data: data['posts:daily'],
options: {
responsive: true,
animation: false,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
};

View File

@@ -18,6 +18,9 @@ define('admin/manage/category', [
if (cid) {
modified_categories[cid] = modified_categories[cid] || {};
modified_categories[cid][$(el).attr('data-name')] = $(el).val();
app.flags = app.flags || {};
app.flags._unsaved = true;
}
}
@@ -31,6 +34,7 @@ define('admin/manage/category', [
}
if (result && result.length) {
app.flags._unsaved = false;
app.alert({
title: 'Updated Categories',
message: 'Category IDs ' + result.join(', ') + ' was successfully updated.',

View File

@@ -110,7 +110,7 @@ define('admin/manage/flags', [
});
if (utils.isMobile()) {
Chart.defaults.global.showTooltips = false;
Chart.defaults.global.tooltips.enabled = false;
}
var data = {
'flags:daily': {
@@ -118,26 +118,37 @@ define('admin/manage/flags', [
datasets: [
{
label: "",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
backgroundColor: "rgba(151,187,205,0.2)",
borderColor: "rgba(151,187,205,1)",
pointBackgroundColor: "rgba(151,187,205,1)",
pointHoverBackgroundColor: "#fff",
pointBorderColor: "#fff",
pointHoverBorderColor: "rgba(151,187,205,1)",
data: ajaxify.data.analytics
}
]
}
};
dailyCanvas.width = $(dailyCanvas).parent().width();
new Chart(dailyCanvas.getContext('2d')).Line(data['flags:daily'], {
responsive: true,
animation: false
new Chart(dailyCanvas.getContext('2d'), {
type: 'line',
data: data['flags:daily'],
options: {
responsive: true,
animation: false,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
return Flags;

View File

@@ -27,6 +27,12 @@ define('admin/settings', ['uploader'], function(uploader) {
revertBtn = $('#revert'),
x, key, inputType, field;
// Handle unsaved changes
$(fields).on('change', function() {
app.flags = app.flags || {};
app.flags._unsaved = true;
});
for (x = 0; x < numFields; x++) {
field = fields.eq(x);
key = field.attr('data-field');
@@ -77,6 +83,9 @@ define('admin/settings', ['uploader'], function(uploader) {
type: 'danger'
});
}
app.flags._unsaved = false;
app.alert({
alert_id: 'config_status',
timeout: 2500,

View File

@@ -1,11 +1,9 @@
"use strict";
/*global app, bootbox, templates, socket, config, RELATIVE_PATH*/
var ajaxify = ajaxify || {};
$(document).ready(function() {
/*global app, templates, socket, config, RELATIVE_PATH*/
var location = document.location || window.location;
var rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : '');
var apiXHR = null;
@@ -295,6 +293,32 @@ $(document).ready(function() {
// Enhancing all anchors to ajaxify...
$(document.body).on('click', 'a', function (e) {
var _self = this;
var process = function() {
if (!e.ctrlKey && !e.shiftKey && !e.metaKey && e.which === 1) {
if (internalLink) {
var pathname = this.href.replace(rootUrl + RELATIVE_PATH + '/', '');
// Special handling for urls with hashes
if (window.location.pathname === this.pathname && this.hash.length) {
window.location.hash = this.hash;
} else {
if (ajaxify.go(pathname)) {
e.preventDefault();
}
}
} else if (window.location.pathname !== '/outgoing') {
if (config.openOutgoingLinksInNewTab) {
window.open(this.href, '_blank');
e.preventDefault();
} else if (config.useOutgoingLinksPage) {
ajaxify.go('outgoing?url=' + encodeURIComponent(this.href));
e.preventDefault();
}
}
}
};
if (this.target !== '' || (this.protocol !== 'http:' && this.protocol !== 'https:')) {
return;
}
@@ -311,6 +335,7 @@ $(document).ready(function() {
}
}
// Default behaviour for rss feeds
if (internalLink && $(this).attr('href').endsWith('.rss')) {
return;
}
@@ -319,28 +344,19 @@ $(document).ready(function() {
return e.preventDefault();
}
if (!e.ctrlKey && !e.shiftKey && !e.metaKey && e.which === 1) {
if (internalLink) {
var pathname = this.href.replace(rootUrl + RELATIVE_PATH + '/', '');
// Special handling for urls with hashes
if (window.location.pathname === this.pathname && this.hash.length) {
window.location.hash = this.hash;
} else {
if (ajaxify.go(pathname)) {
e.preventDefault();
if (app.flags && app.flags.hasOwnProperty('_unsaved') && app.flags._unsaved === true) {
translator.translate('[[global:unsaved-changes]]', function(text) {
bootbox.confirm(text, function(navigate) {
if (navigate) {
app.flags._unsaved = false;
process.call(_self);
}
}
} else if (window.location.pathname !== '/outgoing') {
if (config.openOutgoingLinksInNewTab) {
window.open(this.href, '_blank');
e.preventDefault();
} else if (config.useOutgoingLinksPage) {
ajaxify.go('outgoing?url=' + encodeURIComponent(this.href));
e.preventDefault();
}
}
});
});
return e.preventDefault();
}
process.call(_self);
});
}

View File

@@ -473,33 +473,35 @@ app.cacheBuster = null;
if (!config.requireEmailConfirmation || !app.user.uid) {
return;
}
var msg = {
alert_id: 'email_confirm',
type: 'warning',
timeout: 0
};
if (!app.user.email) {
app.alert({
alert_id: 'email_confirm',
message: '[[error:no-email-to-confirm]]',
type: 'warning',
timeout: 0,
clickfn: function() {
app.removeAlert('email_confirm');
ajaxify.go('user/' + app.user.userslug + '/edit');
}
});
} else if (!app.user['email:confirmed']) {
app.alert({
alert_id: 'email_confirm',
message: err ? err.message : '[[error:email-not-confirmed]]',
type: 'warning',
timeout: 0,
clickfn: function() {
app.removeAlert('email_confirm');
socket.emit('user.emailConfirm', {}, function(err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[notifications:email-confirm-sent]]');
});
}
});
msg.message = '[[error:no-email-to-confirm]]';
msg.clickfn = function() {
app.removeAlert('email_confirm');
ajaxify.go('user/' + app.user.userslug + '/edit');
};
app.alert(msg);
} else if (!app.user['email:confirmed'] && !app.user.isEmailConfirmSent) {
msg.message = err ? err.message : '[[error:email-not-confirmed]]';
msg.clickfn = function() {
app.removeAlert('email_confirm');
socket.emit('user.emailConfirm', {}, function(err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[notifications:email-confirm-sent]]');
});
};
app.alert(msg);
} else if (!app.user['email:confirmed'] && app.user.isEmailConfirmSent) {
msg.message = '[[error:email-not-confirmed-email-sent]]';
app.alert(msg);
}
};

View File

@@ -196,7 +196,8 @@ define('forum/category', [
templates.parse('category', 'topics', {
privileges: {editable: editable},
showSelect: editable,
topics: [topic]
topics: [topic],
template: {category: true}
}, function(html) {
translator.translate(html, function(translatedHTML) {
var topic = $(translatedHTML),
@@ -347,4 +348,4 @@ define('forum/category', [
};
return Category;
});
});

View File

@@ -473,6 +473,12 @@ define('settings', function () {
});
$(window).trigger('action:admin.settingsLoaded');
// Handle unsaved changes
$(formEl).on('change', 'input, select, textarea', function() {
app.flags = app.flags || {};
app.flags._unsaved = true;
});
callback(null, values);
});
},
@@ -498,6 +504,9 @@ define('settings', function () {
hash: hash,
values: values
}, function (err) {
// Remove unsaved flag to re-enable ajaxify
app.flags._unsaved = false;
if (typeof callback === 'function') {
callback();
} else {

View File

@@ -1,254 +0,0 @@
/*!
Autosize 3.0.15
license: MIT
http://www.jacklmoore.com/autosize
*/
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
define('autosize', ['exports', 'module'], factory);
} else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
factory(exports, module);
} else {
var mod = {
exports: {}
};
factory(mod.exports, mod);
global.autosize = mod.exports;
}
})(this, function (exports, module) {
'use strict';
var set = typeof Set === 'function' ? new Set() : (function () {
var list = [];
return {
has: function has(key) {
return Boolean(list.indexOf(key) > -1);
},
add: function add(key) {
list.push(key);
},
'delete': function _delete(key) {
list.splice(list.indexOf(key), 1);
} };
})();
var createEvent = function createEvent(name) {
return new Event(name);
};
try {
new Event('test');
} catch (e) {
// IE does not support `new Event()`
createEvent = function (name) {
var evt = document.createEvent('Event');
evt.initEvent(name, true, false);
return evt;
};
}
function assign(ta) {
var _ref = arguments[1] === undefined ? {} : arguments[1];
var _ref$setOverflowX = _ref.setOverflowX;
var setOverflowX = _ref$setOverflowX === undefined ? true : _ref$setOverflowX;
var _ref$setOverflowY = _ref.setOverflowY;
var setOverflowY = _ref$setOverflowY === undefined ? true : _ref$setOverflowY;
if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || set.has(ta)) return;
var heightOffset = null;
var overflowY = null;
var clientWidth = ta.clientWidth;
function init() {
var style = window.getComputedStyle(ta, null);
overflowY = style.overflowY;
if (style.resize === 'vertical') {
ta.style.resize = 'none';
} else if (style.resize === 'both') {
ta.style.resize = 'horizontal';
}
if (style.boxSizing === 'content-box') {
heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
} else {
heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
}
// Fix when a textarea is not on document body and heightOffset is Not a Number
if (isNaN(heightOffset)) {
heightOffset = 0;
}
update();
}
function changeOverflow(value) {
{
// Chrome/Safari-specific fix:
// When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
// made available by removing the scrollbar. The following forces the necessary text reflow.
var width = ta.style.width;
ta.style.width = '0px';
// Force reflow:
/* jshint ignore:start */
ta.offsetWidth;
/* jshint ignore:end */
ta.style.width = width;
}
overflowY = value;
if (setOverflowY) {
ta.style.overflowY = value;
}
resize();
}
function resize() {
var htmlTop = window.pageYOffset;
var bodyTop = document.body.scrollTop;
var originalHeight = ta.style.height;
ta.style.height = 'auto';
var endHeight = ta.scrollHeight + heightOffset;
if (ta.scrollHeight === 0) {
// If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
ta.style.height = originalHeight;
return;
}
ta.style.height = endHeight + 'px';
// used to check if an update is actually necessary on window.resize
clientWidth = ta.clientWidth;
// prevents scroll-position jumping
document.documentElement.scrollTop = htmlTop;
document.body.scrollTop = bodyTop;
}
function update() {
var startHeight = ta.style.height;
resize();
var style = window.getComputedStyle(ta, null);
if (style.height !== ta.style.height) {
if (overflowY !== 'visible') {
changeOverflow('visible');
}
} else {
if (overflowY !== 'hidden') {
changeOverflow('hidden');
}
}
if (startHeight !== ta.style.height) {
var evt = createEvent('autosize:resized');
ta.dispatchEvent(evt);
}
}
var pageResize = function pageResize() {
if (ta.clientWidth !== clientWidth) {
update();
}
};
var destroy = (function (style) {
window.removeEventListener('resize', pageResize, false);
ta.removeEventListener('input', update, false);
ta.removeEventListener('keyup', update, false);
ta.removeEventListener('autosize:destroy', destroy, false);
ta.removeEventListener('autosize:update', update, false);
set['delete'](ta);
Object.keys(style).forEach(function (key) {
ta.style[key] = style[key];
});
}).bind(ta, {
height: ta.style.height,
resize: ta.style.resize,
overflowY: ta.style.overflowY,
overflowX: ta.style.overflowX,
wordWrap: ta.style.wordWrap });
ta.addEventListener('autosize:destroy', destroy, false);
// IE9 does not fire onpropertychange or oninput for deletions,
// so binding to onkeyup to catch most of those events.
// There is no way that I know of to detect something like 'cut' in IE9.
if ('onpropertychange' in ta && 'oninput' in ta) {
ta.addEventListener('keyup', update, false);
}
window.addEventListener('resize', pageResize, false);
ta.addEventListener('input', update, false);
ta.addEventListener('autosize:update', update, false);
set.add(ta);
if (setOverflowX) {
ta.style.overflowX = 'hidden';
ta.style.wordWrap = 'break-word';
}
init();
}
function destroy(ta) {
if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;
var evt = createEvent('autosize:destroy');
ta.dispatchEvent(evt);
}
function update(ta) {
if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;
var evt = createEvent('autosize:update');
ta.dispatchEvent(evt);
}
var autosize = null;
// Do nothing in Node.js environment and IE8 (or lower)
if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
autosize = function (el) {
return el;
};
autosize.destroy = function (el) {
return el;
};
autosize.update = function (el) {
return el;
};
} else {
autosize = function (el, options) {
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], function (x) {
return assign(x, options);
});
}
return el;
};
autosize.destroy = function (el) {
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], destroy);
}
return el;
};
autosize.update = function (el) {
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], update);
}
return el;
};
}
module.exports = autosize;
});

View File

@@ -91,7 +91,7 @@ module.exports = function(Messaging) {
userData: function(next) {
user.getUsersFields(uids, ['uid', 'username', 'userslug'], next);
},
settings: function(next) {
userSettings: function(next) {
user.getMultipleUserSettings(uids, next);
}
}, function(err, results) {

View File

@@ -30,7 +30,6 @@ module.exports = function(Meta) {
'public/vendor/tinycon/tinycon.js',
'public/vendor/xregexp/xregexp.js',
'public/vendor/xregexp/unicode/unicode-base.js',
'public/vendor/autosize.js',
'./node_modules/templates.js/lib/templates.js',
'public/src/utils.js',
'public/src/sockets.js',
@@ -79,7 +78,7 @@ module.exports = function(Meta) {
// modules listed below are routed through express (/src/modules) so they can be defined anonymously
modules: {
"Chart.js": './node_modules/chart.js/Chart.js',
"Chart.js": './node_modules/chart.js/dist/Chart.min.js',
"mousetrap.js": './node_modules/mousetrap/mousetrap.js',
"buzz.js": 'public/vendor/buzz/buzz.js'

View File

@@ -3,6 +3,7 @@
var async = require('async');
var nconf = require('nconf');
var db = require('../database');
var user = require('../user');
var meta = require('../meta');
var plugins = require('../plugins');
@@ -94,6 +95,12 @@ module.exports = function(app, middleware) {
next(null, userData);
}
},
isEmailConfirmSent: function(next) {
if (!meta.config.requireEmailConfirmation || !req.uid) {
return next(null, false);
}
db.get('uid:' + req.uid + ':confirm:email:sent', next);
},
navigation: async.apply(navigation.get),
tags: async.apply(meta.tags.parse, res.locals.metaTags, res.locals.linkTags)
}, function(err, results) {
@@ -110,6 +117,7 @@ module.exports = function(app, middleware) {
results.user.isGlobalMod = results.isGlobalMod;
results.user.uid = parseInt(results.user.uid, 10);
results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1;
results.user.isEmailConfirmSent = !!results.isEmailConfirmSent;
if (parseInt(meta.config.disableCustomUserSkins, 10) !== 1 && res.locals.config.bootswatchSkin !== 'default') {
templateValues.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + res.locals.config.bootswatchSkin + '/bootstrap.min.css';

View File

@@ -206,6 +206,7 @@ middleware.isAdmin = function(req, res, next) {
var loginTime = req.session.meta ? req.session.meta.datetime : 0;
if (loginTime && parseInt(loginTime, 10) > Date.now() - 3600000) {
req.session.meta.datetime += 300000;
return next();
}

View File

@@ -425,28 +425,4 @@ var middleware;
], next);
};
// function addLanguages(params, callback) {
// Plugins.customLanguages.forEach(function(lang) {
// console.log('route for', '/language/' + lang.route);
// params.router.get('/language' + lang.route, function(req, res, next) {
// res.json(lang.file);
// });
// var components = lang.route.split('/'),
// language = components[1],
// filename = components[2].replace('.json', '');
// translator.addTranslation(language, filename, lang.file);
// });
// for(var resource in Plugins.customLanguageFallbacks) {
// params.router.get('/language/:lang/' + resource + '.json', function(req, res, next) {
// winston.verbose('[translator] No resource file found for ' + req.params.lang + '/' + path.basename(req.path, '.json') + ', using provided fallback language file');
// res.sendFile(Plugins.customLanguageFallbacks[path.basename(req.path, '.json')]);
// });
// }
// callback(null);
// }
}(exports));

View File

@@ -14,13 +14,17 @@ module.exports = function(Plugins) {
`data.priority`, the relative priority of the method when it is eventually called (default: 10)
*/
Plugins.registerHook = function(id, data, callback) {
callback = callback || function() {};
function register() {
Plugins.loadedHooks[data.hook] = Plugins.loadedHooks[data.hook] || [];
Plugins.loadedHooks[data.hook].push(data);
if (typeof callback === 'function') {
callback();
}
callback();
}
if (!data.hook) {
winston.warn('[plugins/' + id + '] registerHook called with invalid data.hook', data);
return callback();
}
var method;
@@ -65,6 +69,7 @@ module.exports = function(Plugins) {
register();
} else {
winston.warn('[plugins/' + id + '] Hook method mismatch: ' + data.hook + ' => ' + data.method);
return callback();
}
}
};

View File

@@ -1,6 +1,6 @@
"use strict";
var SocketIO = require('socket.io');
var SocketIO = require('socket.io');
var socketioWildcard = require('socketio-wildcard')();
var async = require('async');
var nconf = require('nconf');

View File

@@ -28,8 +28,8 @@ var emailer = require('../emailer');
UserEmail.sendValidationEmail = function(uid, email, callback) {
callback = callback || function() {};
var confirm_code = utils.generateUUID(),
confirm_link = nconf.get('url') + '/confirm/' + confirm_code;
var confirm_code = utils.generateUUID();
var confirm_link = nconf.get('url') + '/confirm/' + confirm_code;
var emailInterval = meta.config.hasOwnProperty('emailConfirmInterval') ? parseInt(meta.config.emailConfirmInterval, 10) : 10;
@@ -97,6 +97,7 @@ var emailer = require('../emailer');
async.series([
async.apply(user.setUserField, confirmObj.uid, 'email:confirmed', 1),
async.apply(db.delete, 'confirm:' + code),
async.apply(db.delete, 'uid:' + confirmObj.uid + ':confirm:email:sent'),
function(next) {
db.sortedSetRemove('users:notvalidated', confirmObj.uid, next);
}

View File

@@ -25,6 +25,7 @@ module.exports = function(User) {
var updateUid = uid;
var imageDimension = parseInt(meta.config.profileImageDimension, 10) || 128;
var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1;
var keepAllVersions = parseInt(meta.config['profile:keepAllUserImages'], 10) === 1;
var uploadedImage;
async.waterfall([
@@ -42,7 +43,7 @@ module.exports = function(User) {
return plugins.fireHook('filter:uploadImage', {image: picture, uid: updateUid}, next);
}
var filename = updateUid + '-profileimg' + (convertToPNG ? '.png' : extension);
var filename = updateUid + '-profileimg' + (keepAllVersions ? '-' + Date.now() : '') + (convertToPNG ? '.png' : extension);
async.waterfall([
function(next) {
@@ -68,21 +69,7 @@ module.exports = function(User) {
});
},
function(next) {
User.getUserField(updateUid, 'uploadedpicture', next);
},
function(oldpicture, next) {
if (!oldpicture) {
return file.saveFileToLocal(filename, 'profile', picture.path, next);
}
var oldpicturePath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), 'profile', path.basename(oldpicture));
fs.unlink(oldpicturePath, function (err) {
if (err) {
winston.error(err);
}
file.saveFileToLocal(filename, 'profile', picture.path, next);
});
file.saveFileToLocal(filename, 'profile', picture.path, next);
},
], next);
},
@@ -134,6 +121,7 @@ module.exports = function(User) {
};
User.updateCoverPicture = function(data, callback) {
var keepAllVersions = parseInt(meta.config['profile:keepAllUserImages'], 10) === 1;
var url, md5sum;
if (!data.imageData && data.position) {
@@ -181,7 +169,7 @@ module.exports = function(User) {
return plugins.fireHook('filter:uploadImage', {image: image, uid: data.uid}, next);
}
var filename = data.uid + '-profilecover';
var filename = data.uid + '-profilecover' + (keepAllVersions ? '-' + Date.now() : '');
async.waterfall([
function (next) {
file.isFileTypeAllowed(data.file.path, next);

View File

@@ -15,7 +15,8 @@
var app = {
template: "{template.name}",
user: JSON.parse('{{userJSON}}'),
config: JSON.parse(decodeURIComponent("{{adminConfigJSON}}"))
config: JSON.parse(decodeURIComponent("{{adminConfigJSON}}")),
flags: {}
};
</script>

View File

@@ -118,15 +118,9 @@
<ul id="user_label" class="pull-right">
<li class="dropdown pull-right">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="user_dropdown">
<i class="fa fa-ellipsis-v"></i>
<i class="fa fa-fw fa-ellipsis-v"></i>
</a>
<ul id="user-control-list" class="dropdown-menu" aria-labelledby="user_dropdown">
<li>
<a href="{relative_path}/" target="_top" title="View Forum">
View Forum
</a>
</li>
<li role="presentation" class="divider"></li>
<li>
<a href="#" class="reload" title="Reload Forum">
Reload Forum
@@ -143,6 +137,13 @@
</li>
</ul>
</li>
<li class="pull-right">
<a href="{config.relative_path}/">
<i class="fa fa-fw fa-home" title="View Forum"></i>
</a>
</li>
<form class="pull-right hidden-sm hidden-xs" role="search">
<div class="" id="acp-search" >
<div class="dropdown">

View File

@@ -115,6 +115,13 @@
(in kilobytes, default: 2,048 KiB)
</p>
</div>
<div class="checkbox">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input class="mdl-switch__input" type="checkbox" data-field="profile:keepAllUserImages">
<span class="mdl-switch__label"><strong>Keep old versions of avatars and profile covers on the server</strong></span>
</label>
</div>
</form>
</div>
</div>
@@ -132,4 +139,4 @@
</div>
</div>
<!-- IMPORT admin/settings/footer.tpl -->
<!-- IMPORT admin/settings/footer.tpl -->

View File

@@ -85,6 +85,7 @@ function initializeNodeBB(callback) {
function(next) {
plugins.init(app, middleware, next);
},
async.apply(plugins.fireHook, 'static:assets.prepare', {}),
async.apply(meta.js.bridgeModules, app),
function(next) {
async.series([

View File

@@ -44,7 +44,7 @@ widgets.render = function(uid, area, req, res, callback) {
req: req,
res: res
}, function(err, html) {
if (err) {
if (err || html === null) {
return next(err);
}