{(card.get('description') || '').substring(0, 50)}
+{(card.get('description') || '').substring(0, maxDescription)}
{provider}From a345479de20bb508ef576af54427c35888deb0cc Mon Sep 17 00:00:00 2001
From: Masoud Abkenar Boas vindas, <%= @resource.email %>! Você acabou de criar uma conta no <%= @instance %>. Para confirmar o seu cadastro, por favor clique no link a seguir: Por favor, leia também os nossos <%= link_to 'termos de serviços', terms_url %>. Atenciosamente,
+
+ A equipe do <%= @instance %> Olá, <%= @resource.email %>! Estamos te contatando para te notificar que a senha senha no <%= @instance %> foi modificada. Olá, <%= @resource.email %>! Alguém solicitou um link para mudar a sua senha no <%= @instance %>. Você pode fazer isso através do link abaixo: <%= link_to 'Mudar a minha senha', edit_password_url(@resource, reset_password_token: @token) %> Se você não solicitou isso, por favor ignore este e-mail. A senha senha não será modificada até que você acesse o link acima e crie uma nova. A descrição extendida ainda não foi definida. Coletamos informações quando você se cadastra em nosso site e capturamos dados quando você participa do fórum lendo, escrevendo e analisando o conteúdo aqui compartilhado. Quando você se registrar em nosso site, será requisitado que você ceda seu nome e endereço de e-mail. Você pode, porém, visitar nosso site sem se cadastrar. Seu endereço de e-mail será verificado por uma mensagem contendo um link único. Se este link for visitado, saberemos que você controla este endereço de e-mail. Quando registrado e postando, nós gravamos o endereço de IP de onde a postagem se originou. Nós também podemos reter logs de serviores que incluem o endereço de IP em cada requisição para o nosso servidor. Quaisquer das informações que coletamos podem ser usadas das seguintes formas: Nós implementamos uma variedade de medidas de segurança para manter a segurança de suas informações pessoais quando você insere, submete ou acessa as suas informações pessoais. Faremos esforços de boa fé para: Sim. Cookies são pequenos arquivos que um site ou o provedor de serviço transfere para o armazenamento interno de seu computador através de seu navegador (se você permitir). Estes cookies habilitam o site para reconhecer o seu navegador e, se você ter um cadastro, associá-lo a esta conta. Nós usamos cookies para entender e salvar as suas preferências para futuras visitas e compilar dados agregados sobre o tráfego do site para que possamos oferecer melhores experiências e ferramentas no futuro. Nós podemos contratar serviços de terceiros para nos auxiliar a entender melhor nossos visitantes. Estes provedores de serviço não são autoriza usar as informações coletadas em nosso nome exceto para nos ajudar a conduzir e aprimorar nosso funcionamento. Nós não vendemos, tocamos ou transferimos para terceiros informações pessoais que te identificam. Isso não inclui partes em que confiamos para nos ajudar a operar nosso site, conduzir nosso funcionamento ou servir você desde que estes terceiros concordem em manter essas informações em segredo. Nós também podemos prover as suas informações para obedecer ordens judiciais, reforçar nossas políticas ou proteger nossos direitos ou de outrem, propriedades ou segurança. Entretanto, informações pessoais não identificáveis podem ser enviadas para outras partes para marketing, propaganda e outros usos. Ocasionalmente, à nossa discrição, podemos icluir ou oferecer produtos ou serviços de terceiros em nosso site. Estes terceiros têm políticas de privacidade separadas e independentes. Nós, portanto, não nos responsabilizamos pelo conteúdo e atividades destes sites de terceiros. Occasionally, at our discretion, we may include or offer third party products or services on our site. Não obstante, nós procuramos proteger a integridade de nosso site e todo feedback sobre estes sites de terceiros é bem-vindo. Nosso site, produtos e serviços são todos direcionados a pessoas que têm pelo menos 13 anos de idade. Se este servidor estiver nos EUA, e você tiver menos de 13 anos, pelos requerimentos da COPPA (Children's Online Privacy Protection Act) não use este site. Esta política de privacidade online se aplica somente a informações coletadas por nosso site e não a informações coletadas offline. Usando o nosso site, você concorda com a nossa política de privacidade. Se decidirmos mudar a nossa política de privacidade, publicaremos as mudanças nesta página. Este documento é CC-BY-SA. A sua última atualização aconteceu em 31 de maio de 2013. Originalmente adaptado da política de privacidade do Discourse. {(card.get('description') || '').substring(0, 50)} {(card.get('description') || '').substring(0, maxDescription)}
+<%= link_to 'Confirmar cadastro', confirmation_url(@resource, confirmation_token: @token) %>
+
+Um bom lugar para as regras
+
Você pode usar tags HTML
- title: Mensagem de registro fechados
+ desc_html: Exibido na página inicial quando cadastros estão fechados. Você pode usar tags HTML.
+ title: Mensagem de cadastros fechados
+ deletion:
+ desc_html: Permitir que qualquer um delete a sua conta
+ title: Exclusão aberta de contas
open:
- title: Aberto para registro
+ desc_html: Permitir que qualquer um crie uma conta
+ title: Cadastro aberto
site_description:
- desc_html: Mostrar como parágrafo e usado como meta tag.
Vôce pode usar tags HTML, em particular <a>
e <em>
.
- title: Descrição do site
+ desc_html: Parágrafo introdutório na página inicial e em meta tags. Você pode usar tags HTML, em especial <a>
e <em>
.
+ title: Descrição da instância
site_description_extended:
- desc_html: Mostrar na página de informação extendiada
Você pode usar tags HTML
- title: Descrição extendida do site
- site_title: Título do site
- title: Preferências do site
+ desc_html: Um ótimo lugar para seu código de conduta, regras, diretrizes e outras coisas para diferenciar a sua instância. Você pode usar tags HTML.
+ title: Informação estendida customizada
+ site_terms:
+ desc_html: Você pode escrever a sua própria política de privacidade, termos de serviço, entre outras coisas.Você pode usar tags HTML.
+ title: Termos de serviço customizados
+ site_title: Nome da instância
+ timeline_preview:
+ desc_html: Exibir a timeline pública na página inicial
+ title: Prévia da timeline
+ title: Configurações do site
+ statuses:
+ back_to_account: Voltar para página da conta
+ batch:
+ delete: Deletar
+ nsfw_off: NSFW OFF
+ nsfw_on: NSFW ON
+ execute: Executar
+ failed_to_execute: Falha em executar
+ media:
+ hide: Esconder mídia
+ show: Mostrar mídia
+ title: Mídia
+ no_media: Não há mídia
+ title: Postagens da conta
+ with_media: Com mídia
subscriptions:
- callback_url: URL de Callback
+ callback_url: Callback URL
confirmed: Confirmado
expires_in: Expira em
last_delivery: Última entrega
title: WebSub
topic: Tópico
title: Administração
+ admin_mailer:
+ new_report:
+ body: "%{reporter} reportou %{target}"
+ subject: Nova denúncia sobre %{instance} (#%{id})
application_mailer:
- settings: 'Mudar preferências de email: %{link}'
- signature: notificações Mastodon de %{instance}
- view: 'View:'
+ salutation: "%{name},"
+ settings: 'Change e-mail preferences: %{link}'
+ signature: Notificações do Mastodon de %{instance}
+ view: 'Visualizar:'
applications:
- invalid_url: URL dada é inválida
+ created: Aplicação criada com sucesso
+ destroyed: Aplicação excluída com sucesso
+ invalid_url: A URL provida é inválida
+ regenerate_token: Regenerar token de acesso
+ token_regenerated: Token de acesso renegerado com sucesso
+ warning: Tenha cuidado com estes dados. Nunca compartilhe com alguém!
+ your_token: Seu token de acesso
auth:
- change_password: Mudar senha
+ agreement_html: Cadastrando-se você concorda com nossos termos de serviço e política de privacidade.
+ change_password: Segurança
+ delete_account: Excluir conta
+ delete_account_html: Se você deseja excluir a sua conta, você pode prosseguir para cá. Uma confirmação será requisitada.
didnt_get_confirmation: Não recebeu instruções de confirmação?
- forgot_password: Esqueceu a senha?
+ forgot_password: Esqueceu a sua senha?
+ invalid_reset_password_token: Token de modificação de senha é inválido ou expirou. Por favor, requisite um novo.
login: Entrar
logout: Sair
- register: Registar
+ register: Cadastrar-se
resend_confirmation: Reenviar instruções de confirmação
- reset_password: Resetar senha
- set_new_password: Editar password
+ reset_password: Modificar senha
+ set_new_password: Definir uma nova senha
authorize_follow:
- error: Infelizmente houve um erro olhando uma conta remota
+ error: Infelizmente, ocorreu um erro quando visualizando a conta remota.
follow: Seguir
+ follow_request: 'Você mandou uma solicitação de seguidor para:'
+ following: 'Sucesso! Você agora está seguindo:'
+ post_follow:
+ close: Ou você pode simplesmente fechar esta janela.
+ return: Retornar ao perfil do usuário
+ web: Voltar para a página inicial
title: Seguir %{acct}
datetime:
distance_in_words:
about_x_hours: "%{count}h"
- about_x_months: "%{count}mo"
- about_x_years: "%{count}y"
- almost_x_years: "%{count}y"
+ about_x_months: "%{count} meses"
+ about_x_years: "%{count} anos"
+ almost_x_years: "%{count} anos"
half_a_minute: Agora
- less_than_x_minutes: "%{count}m"
+ less_than_x_minutes: "%{count} meses"
less_than_x_seconds: Agora
- over_x_years: "%{count}y"
- x_days: "%{count}d"
- x_minutes: "%{count}m"
- x_months: "%{count}mo"
- x_seconds: "%{count}s"
+ over_x_years: "%{count} anos"
+ x_days: "%{count} dias"
+ x_minutes: "%{count} minutos"
+ x_months: "%{count} meses"
+ x_seconds: "%{count} segundos"
+ deletes:
+ bad_password_msg: Boa tentativa, hackers! Senha incorreta.
+ confirm_password: Insira a sua senha atual para verificar a sua identidade
+ description_html: Isto vai permanente e irreversivelmente remover conteúdo de sua conta e desativá-la. O seu nome de usuário permanecerá reservado para previnir futuros roubos de identidade.
+ proceed: Excluir conta
+ success_msg: A sua conta foi excluída com sucesso
+ warning_html: Apenas a exclusão de conteúdo desta instância em particular é garantida. Conteúdo que tenha sido largamente compartilhado muito provavelmente deixará traços. Servidores offline e servidores que se desinscreveram de suas atualizações não irão atualizar as suas bases de dados.
+ warning_title: Disponibilidade de conteúdo disseminado
errors:
- '403': Você não tem permissão para ver essa página.
- '404': A página que você procura não existe.
- '410': A página que você procura não existe mais.
+ '403': Você não tem permissão para ver esta página.
+ '404': A página pela qual você está procurando não existe.
+ '410': A página pela qual você está procurando não existe mais.
'422':
- content: Verificação de segurança falhou. Você está bloqueando cookies?
- title: Verificação de segurança falhou
+ content: A verificação de segurança falhou. Você desativou o uso de cookies?
+ title: Falha na verificação de segurança
+ '429': Muitas requisições
+ noscript_html: Para usar o aplicativo web do Mastodon, por favor ative o JavaScript. Alternativamente, experimente um dos apps nativos para o Mastodon para a sua plataforma.
exports:
- blocks: Você bloqueia
+ blocks: Você bloqueou
csv: CSV
follows: Você segue
- mutes: Você selencia
- storage: Mídia de dados
+ mutes: Você silenciou
+ storage: Armazenamento de mídia
followers:
domain: Domínio
- explanation_html: Se você quer garantir a privacidade doe seu status, você precisa saber quem te segue. Seu status privado é enviado a todas as instancias que você tem seguidores. Você pode querer reavaliar e remover os seguidores que você não confia que sua privacidade vai ser mantida pelos administradores ou softwares de outras instancias.
- followers_count: Númbero de seguidores
- lock_link: Bloquear sua conta
- purge: Remove dos seguidores
+ explanation_html: Se você quer garantir a privacidade de suas postagens, você deve ficar atento a quem está te seguindo.Suas postagens privadas são enviadas para todas as instâncias em que você tem seguidores. Convém revisá-las e remover seguidores se você acredita que a sua privacidade não será respeitada pela equipe ou software destas instâncias.
+ followers_count: Número de seguidores
+ lock_link: Tranque a sua conta
+ purge: Remover de seus seguidores
success:
- one: Em processo de bloquear seguidores de um domínio...
- other: Em processo de bloqueio-leve dos seguidores de %{count} domínios...
- true_privacy_html: Saiba que privaicade de verdade só pode ser atingida com criptografia ponto-a-ponto.
- unlocked_warning_html: Qualquer um que te seguir para ver seus status privado imediatamente. %{lock_link} para poder rever e rejeitar seguidores.
- unlocked_warning_title: Sua conta não está bloqueada
+ one: No processo de bloqueio suave de seguidores de outro domínio...
+ other: No processo de bloqueio suave de seguidores de outros %{count} domínios...
+ true_privacy_html: Lembre-se de que a verdadeira privacidade só pode ser alcançada através de encriptação ponto-a-ponto.
+ unlocked_warning_html: Qualquer pessoa pode te seguir e ver as suas postagens privadas. %{lock_link} para ser capaz de revisar e rejeitar seguidores.
+ unlocked_warning_title: A sua conta não está trancada
generic:
- changes_saved_msg: Mudanças guardadas!
+ changes_saved_msg: Mudanças salvas com sucesso!
powered_by: powered by %{link}
- save_changes: Guardar alterações
+ save_changes: Salvar mudanças
validation_errors:
- one: Algo não está correto. Por favor reveja o erro abaixo
- other: Algo não está correto. Por favor reveja os %{count} erros abaixo
+ one: Algo não está certo! Por favor, reveja o erro abaixo
+ other: Algo não está certo! Por favor, reveja os %{count} erros abaixo
imports:
- preface: Você pode importar certos dados, como as pessoas que você segue ou estão bloqueadas para sua conta nessa instancia, de arquivos com dados criados por outra instancia.
- success: Seus dados foram carregados com sucesso and serão processados em algum tempo
+ preface: Você pode importar dados que você exportou de outra instância, como a lista de pessoas que você segue ou bloqueou.
+ success: Os seus dados foram enviados com sucesso e serão processados em instantes
types:
blocking: Lista de bloqueio
- following: Lista de seguidos
- muting: Lista de silenciados
- upload: Carregar
- landing_strip_html: "%{name} is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse."
- landing_strip_signup_html: If you don't, you can sign up here.
+ following: Pessoas que você segue
+ muting: Lista de silêncio
+ upload: Enviar
+ landing_strip_html: "%{name} é um usuário no %{link_to_root_path}. Você pode seguí-lo ou interagir com ele se você tiver uma conta em qualquer lugar no fediverso."
+ landing_strip_signup_html: Se não, você pode se cadastrar aqui.
media_attachments:
validations:
- images_and_video: Cannot attach a video to a status that already contains images
- too_many: Cannot attach more than 4 files
+ images_and_video: Não é possível anexar um vídeo a uma postagem que já contém imagens.
+ too_many: Não é possível anexar mais de quatro imagens.
notification_mailer:
digest:
- body: 'Isto é um resumo do que você perdeu em %{instance} desde sua última visita %{since}:'
- mention: "%{name} mencionou você em:"
+ body: 'Aqui está um resumo do que você perdeu no %{instance} desde o seu último acesso em %{since}:'
+ mention: "%{name} te mencionou em:"
new_followers_summary:
- one: Você tem um novo seguidor!
- other: Você conseguiu %{count} novos seguidores! Incrível
+ one: Você tem um novo seguidor! Yay!
+ other: Você tem %{count} novos seguidores! Maravilha!
subject:
- one: "1 nova notificação desde sua última visita \U0001F418"
- other: "%{count} novas notificações desde a última visita \U0001F418"
+ one: "Uma nova notificação desde o seu último acesso \U0001F418"
+ other: "%{count} novas notificações desde o seu último acesso \U0001F418"
favourite:
- body: 'O seu post foi favoritado por %{name}:'
- subject: "%{name} favouritou o seu post"
+ body: 'Sua postagem foi favoritada por %{name}:'
+ subject: "%{name} favoritou a sua postagem"
follow:
- body: "%{name} seguiu você!"
- subject: "%{name} segue você"
+ body: "%{name} está te seguindo!"
+ subject: "%{name} está te seguindo"
follow_request:
- body: "%{name} pediu para te seguir"
- subject: 'Seguidor pendente: %{name}'
+ body: "%{name} requisitou autorização para te seguir"
+ subject: 'Pending follower: %{name}'
mention:
body: 'Você foi mencionado por %{name} em:'
- subject: Foi mencionado por %{name}
+ subject: Você foi mencionado por %{name}
reblog:
- body: 'O seu post foi reblogado por %{name}:'
- subject: "%{name} reblogou o seu post"
+ body: 'Sua postagem foi compartilhada por %{name}:'
+ subject: "%{name} compartilhou a sua postagem"
number:
human:
decimal_units:
@@ -267,56 +368,190 @@ pt-BR:
trillion: T
unit: ''
pagination:
- next: Next
- prev: Prev
+ next: Próximo
+ prev: Anterior
truncate: "…"
+ push_notifications:
+ favourite:
+ title: "%{name} favoritou a sua postagem"
+ follow:
+ title: "%{name} está te seguindo"
+ group:
+ title: "%{count} notificações"
+ mention:
+ action_boost: Compartilhar
+ action_expand: Mostrar mais
+ action_favourite: Favoritar
+ title: "%{name} mencionou você"
+ reblog:
+ title: "%{name} compartilhou a sua postagem"
remote_follow:
- acct: Entre seu usuário@domínio do qual quer seguir
- missing_resource: Não foi possível achar a URL de redirecionamento para sua conta
- proceed: Prossiga para seguir
- prompt: 'Você vai seguir:'
+ acct: Insira o seu usuário@domínio do qual você quer seguir
+ missing_resource: Não foi possível encontrar a URL de direcionamento para a sua conta
+ proceed: Prosseguir para seguir
+ prompt: 'Você irá seguir:'
+ sessions:
+ activity: Última atividade
+ browser: Navegador
+ browsers:
+ alipay: Alipay
+ blackberry: Blackberry
+ chrome: Chrome
+ edge: Microsoft Edge
+ firefox: Firefox
+ generic: Unknown browser
+ ie: Internet Explorer
+ micro_messenger: MicroMessenger
+ nokia: Nokia S40 Ovi Browser
+ opera: Opera
+ phantom_js: PhantomJS
+ qq: QQ Browser
+ safari: Safari
+ uc_browser: UCBrowser
+ weibo: Weibo
+ current_session: Sessão atual
+ description: "%{browser} em %{platform}"
+ explanation: Estes são os navegadores que estão conectados com a sua conta do Mastodon.
+ ip: IP
+ platforms:
+ adobe_air: Adobe Air
+ android: Android
+ blackberry: Blackberry
+ chrome_os: ChromeOS
+ firefox_os: Firefox OS
+ ios: iOS
+ linux: Linux
+ mac: Mac
+ other: unknown platform
+ windows: Windows
+ windows_mobile: Windows Mobile
+ windows_phone: Windows Phone
+ revoke: Revogar
+ revoke_success: Sessão revogada com sucesso
+ title: Sessões
settings:
- authorized_apps: Aplicativos autorizados
- back: Voltar ao Mastodon
+ authorized_apps: Apps autorizados
+ back: Voltar para o Mastodon
+ delete: Exclusão de conta
+ development: Desenvolvimento
edit_profile: Editar perfil
- export: Importar dados
+ export: Exportar dados
followers: Seguidores autorizados
import: Importar
preferences: Preferências
- settings: Settings
- two_factor_authentication: Autenticação Two-factor
+ settings: Configurações
+ two_factor_authentication: Autenticação em dois passos
+ your_apps: Seus aplicativos
statuses:
- open_in_web: Abrir no browser
- over_character_limit: limite de caracter excedeu %{max}
+ open_in_web: Abrir na web
+ over_character_limit: limite de caracteres de %{max} excedido
+ pin_errors:
+ ownership: Toots de outras pessoas não podem ser fixados
+ private: Toot não-público não pode ser fixado
+ reblog: Um compartilhamento não pode ser fixado
show_more: Mostrar mais
visibilities:
- private: Seguidores-apenas
+ private: Apenas seguidores
private_long: Mostrar apenas para seguidores
public: Público
- public_long: Qualquer um pode ver
- unlisted: Público, mas não mostre no timeline público
- unlisted_long: Todo mundo pode ver mas não será listado nas timeline públicas
+ public_long: Todos podem ver
+ unlisted: Não listado
+ unlisted_long: Todos podem ver, porém não será postado nas timelines públicas
stream_entries:
- click_to_show: Clique pra mostrar
- reblogged: boosted
+ click_to_show: Clique para mostrar
+ pinned: Toot fixado
+ reblogged: compartilhado
sensitive_content: Conteúdo sensível
+ terms:
+ body_html: |
+ Política de privacidade
+
+ Que informações nós coletamos?
+
+ Para que usamos essas informações?
+
+
+
+
+ Como protegemos as suas informações?
+
+ Qual a sua política de retenção de dados?
+
+
+
+
+ Nós usamos cookies?
+
+ Nós revelamos informações para terceiros?
+
+ Links de terceiros
+
+ Obediência ao Ato de Proteção da Privacidade Online de Crianças
+
+ Política de Apenas Privacidade Online
+
+ Seu Consentimento
+
+ Mudanças em nossa Política de Privacidade
+
+
:coolcat::coolcat:<\/p>/) + end + end + + context 'with emoji at the end' do + let(:text) { '
Beep boop
:coolcat:
,
, etc.)
- // and replacing valid unicode strings
- // that _aren't_ within tags with an version.
- // The goal is to be the same as an emojione.regUnicode replacement, but faster.
- let i = -1;
- let insideTag = false;
- let insideShortname = false;
- let shortnameStartIndex = -1;
- let match;
- while (++i < str.length) {
- const char = str.charAt(i);
- if (insideShortname && char === ':') {
- const shortname = str.substring(shortnameStartIndex, i + 1);
- if (shortname in customEmojis) {
- const replacement = `
`;
- str = str.substring(0, shortnameStartIndex) + replacement + str.substring(i + 1);
- i += (replacement.length - shortname.length - 1); // jump ahead the length we've added to the string
+ let rtn = '';
+ for (;;) {
+ let match, i = 0, tag;
+ while (i < str.length && (tag = '<&:'.indexOf(str[i])) === -1 && !(match = trie.search(str.slice(i)))) {
+ i += str.codePointAt(i) < 65536 ? 1 : 2;
+ }
+ if (i === str.length)
+ break;
+ else if (tag >= 0) {
+ let tagend = str.indexOf('>;:'[tag], i + 1) + 1;
+ if (!tagend)
+ break;
+ if (str[i] === ':') {
+ const shortname = str.slice(i, tagend);
+ const lt = str.indexOf('<', i + 1);
+ if ((lt === -1 || lt >= tagend) && shortname in customEmojis) {
+ rtn += str.slice(0, i) + `
`;
+ str = str.slice(tagend);
+ } else {
+ rtn += str.slice(0, i + 1);
+ str = str.slice(i + 1);
+ }
} else {
- i--;
- }
- insideShortname = false;
- } else if (insideTag && char === '>') {
- insideTag = false;
- } else if (char === '<') {
- insideTag = true;
- insideShortname = false;
- } else if (!insideTag && char === ':') {
- insideShortname = true;
- shortnameStartIndex = i;
- } else if (!insideTag && (match = trie.search(str.substring(i)))) {
- const unicodeStr = match;
- if (unicodeStr in unicodeMapping) {
- const [filename, shortCode] = unicodeMapping[unicodeStr];
- const alt = unicodeStr;
- const replacement = `
`;
- str = str.substring(0, i) + replacement + str.substring(i + unicodeStr.length);
- i += (replacement.length - unicodeStr.length); // jump ahead the length we've added to the string
+ rtn += str.slice(0, tagend);
+ str = str.slice(tagend);
}
+ } else {
+ const [filename, shortCode] = unicodeMapping[match];
+ rtn += str.slice(0, i) + `
`;
+ str = str.slice(i + match.length);
}
}
- return str;
+ return rtn + str;
};
export default emojify;
--
cgit
From b35406b700e643c50ac9726e5f5e1650604e0879 Mon Sep 17 00:00:00 2001
From: Eugen Rochko
`;
- str = str.slice(tagend);
- } else {
- rtn += str.slice(0, i + 1);
- str = str.slice(i + 1);
+ str = str.slice(closeColon);
+ continue;
}
- } else {
- rtn += str.slice(0, tagend);
- str = str.slice(tagend);
- }
+ } catch (e) {}
+ // replacing :shortname: failed
+ rtn += str.slice(0, i + 1);
+ str = str.slice(i + 1);
} else {
const [filename, shortCode] = unicodeMapping[match];
rtn += str.slice(0, i) + `
`;
--
cgit
From 63819c848de8728fe3a0789213014c943588a5b1 Mon Sep 17 00:00:00 2001
From: syui
+ {items.map((option, i) => this.renderItem(option, i))}
+
+
- {items.map(this.renderItem)}
-
- );
+ setTargetRef = c => {
+ this.target = c;
+ }
- // No need to render the actual dropdown if we use the modal. If we
- // don't render anything `;
+ rtn += str.slice(0, i) + `
`;
str = str.slice(i + match.length);
}
}
diff --git a/app/javascript/mastodon/emojione_light.js b/app/javascript/mastodon/emojione_light.js
index 0d07d012f..ecba35d03 100644
--- a/app/javascript/mastodon/emojione_light.js
+++ b/app/javascript/mastodon/emojione_light.js
@@ -9,5 +9,5 @@ const excluded = ['®', '©', '™'];
module.exports.unicodeMapping = Object.keys(emojione.jsEscapeMap)
.filter(c => !excluded.includes(c))
.map(unicodeStr => [unicodeStr, mappedUnicode[emojione.jsEscapeMap[unicodeStr]]])
- .map(([unicodeStr, shortCode]) => ({ [unicodeStr]: [emojione.emojioneList[shortCode].fname, shortCode.slice(1, shortCode.length - 1)] }))
+ .map(([unicodeStr, shortCode]) => ({ [unicodeStr]: [emojione.emojioneList[shortCode].fname.replace(/^0+/g, ''), shortCode.slice(1, shortCode.length - 1)] }))
.reduce((x, y) => Object.assign(x, y), { });
diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js
index 413142d81..bb747b611 100644
--- a/app/javascript/mastodon/features/compose/components/compose_form.js
+++ b/app/javascript/mastodon/features/compose/components/compose_form.js
@@ -138,7 +138,7 @@ export default class ComposeForm extends ImmutablePureComponent {
handleEmojiPick = (data) => {
const position = this.autosuggestTextarea.textarea.selectionStart;
- const emojiChar = data.unicode.split('-').map(code => String.fromCodePoint(parseInt(code, 16))).join('');
+ const emojiChar = data.native;
this._restoreCaret = position + emojiChar.length + 1;
this.props.onPickEmoji(position, data);
}
diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
index 9d05b7a34..43e175be5 100644
--- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
@@ -1,12 +1,17 @@
import React from 'react';
-import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';
+import { Overlay } from 'react-overlays';
+import classNames from 'classnames';
const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
emoji_search: { id: 'emoji_button.search', defaultMessage: 'Search...' },
+ emoji_not_found: { id: 'emoji_button.not_found', defaultMessage: 'No emojos!! (╯°□°)╯︵ ┻━┻' },
+ custom: { id: 'emoji_button.custom', defaultMessage: 'Custom' },
+ recent: { id: 'emoji_button.recent', defaultMessage: 'Frequently used' },
+ search_results: { id: 'emoji_button.search_results', defaultMessage: 'Search results' },
people: { id: 'emoji_button.people', defaultMessage: 'People' },
nature: { id: 'emoji_button.nature', defaultMessage: 'Nature' },
food: { id: 'emoji_button.food', defaultMessage: 'Food & Drink' },
@@ -17,13 +22,234 @@ const messages = defineMessages({
flags: { id: 'emoji_button.flags', defaultMessage: 'Flags' },
});
-const settings = {
- imageType: 'png',
- sprites: false,
- imagePathPNG: '/emoji/',
-};
+const assetHost = process.env.CDN_HOST || '';
-let EmojiPicker; // load asynchronously
+let EmojiPicker, Emoji; // load asynchronously
+
+const backgroundImageFn = () => `${assetHost}/emoji/sheet.png`;
+
+class ModifierPickerMenu extends React.PureComponent {
+
+ static propTypes = {
+ active: PropTypes.bool,
+ onSelect: PropTypes.func.isRequired,
+ onClose: PropTypes.func.isRequired,
+ };
+
+ handleClick = (e) => {
+ const modifier = [].slice.call(e.currentTarget.parentNode.children).indexOf(e.target) + 1;
+ this.props.onSelect(modifier);
+ }
+
+ componentWillReceiveProps (nextProps) {
+ if (nextProps.active) {
+ this.attachListeners();
+ } else {
+ this.removeListeners();
+ }
+ }
+
+ componentWillUnmount () {
+ this.removeListeners();
+ }
+
+ handleDocumentClick = e => {
+ if (this.node && !this.node.contains(e.target)) {
+ this.props.onClose();
+ }
+ }
+
+ attachListeners () {
+ document.addEventListener('click', this.handleDocumentClick, false);
+ document.addEventListener('touchend', this.handleDocumentClick, false);
+ }
+
+ removeListeners () {
+ document.removeEventListener('click', this.handleDocumentClick, false);
+ document.removeEventListener('touchend', this.handleDocumentClick, false);
+ }
+
+ setRef = c => {
+ this.node = c;
+ }
+
+ render () {
+ const { active } = this.props;
+
+ return (
+
-
-
-
');
+ '
');
expect(emojify('\u2757#\uFE0F\u20E3')).to.equal(
- '
');
+ '
');
expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).to.equal(
- '
');
+ '
');
expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).to.equal(
- 'foo
bar');
+ 'foo
bar');
});
it('ignores unicode inside of tags', () => {
diff --git a/yarn.lock b/yarn.lock
index 1abf6a326..7b8328805 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2065,6 +2065,12 @@ elliptic@^6.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0"
+emoji-mart@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-1.0.1.tgz#0ef2fd2bf4b6762aab7486c26c574387f034e392"
+ dependencies:
+ measure-scrollbar "^0.1.0"
+
emoji-regex@^6.1.0:
version "6.4.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.4.3.tgz#6ac2ac58d4b78def5e39b33fcbf395688af3076c"
@@ -3857,6 +3863,10 @@ mathjs@^3.11.5:
tiny-emitter "2.0.0"
typed-function "0.10.5"
+measure-scrollbar@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/measure-scrollbar/-/measure-scrollbar-0.1.0.tgz#2bbfac6773bcbb98d814e6890554c0b92846fe6f"
+
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
--
cgit
From 66126f302167d21e4bf247e660f595ff0beaaf20 Mon Sep 17 00:00:00 2001
From: Eugen Rochko
+
+ {emoji.colons}
+
@@ -339,7 +315,6 @@ export default class EmojiPickerDropdown extends React.PureComponent {