No meu tema, quando uma página de exibição de tópico é carregada, preciso obter o ID desse tópico (e o nome também, se possível, mas o ID seria suficiente).
Em seguida, uso essas informações no meu tema para fazer uma chamada de API e obter informações sobre o tópico (com uma chamada a um endpoint como forum-name/t/topic-name/id.json…)
Como posso obter o ID do tópico quando a página de exibição do tópico é carregada?
Os métodos óbvios não são suficientes
A solução óbvia é usar window.location.href ou window.location.pathname para obter informações da URL. O problema é que a URL da página de exibição do tópico pode assumir diferentes formas. Frequentemente, seria: forum-name/t/topic-name/topic-id
Se essa fosse sempre a forma, então usar window.location.pathname funcionaria bem — fornecendo-me “t/topic-name/topic-id”.
MAS, às vezes, a URL da página de exibição do tópico adiciona também a ordem da categoria do tópico, então a URL fica: forum-name/t/topic-name/topic-id/category-index
Portanto, usar window.location.pathname é insuficiente, porque não sei programaticamente se o último parâmetro será o topic-id ou o category-index.
Pode haver uma maneira de resolver isso usando regex, mas isso requer habilidades sérias com regex. Também pode haver uma maneira de resolver isso com jQuery, examinando elementos na página que possam fornecer o ID — mas ainda não consegui fazer isso funcionar.
No meu fórum, isso na verdade acontece na maioria das vezes quando você clica em um tópico. A última parte da URL será o número do tópico na categoria, caso você tenha clicado no tópico a partir de uma categoria. Talvez isso seja uma configuração no Discourse? Não parece acontecer no meta-, mas não acho que esteja fazendo nada especial para que isso ocorra no meu fórum.
No entanto, não posso sempre contar com isso, pois se um tópico for o primeiro da categoria, o índice da categoria não é anexado. Então, pelo que consigo ver, não há uma boa maneira, no momento, de eu saber se ele aparecerá ou não no índice da categoria.
Obter o ID de uma div é aceitável, mas, infelizmente, é bastante mais lento do que simplesmente obtê-lo diretamente da URL ou por algum outro meio direto. Caso não haja outra solução, você sabe qual é o jQuery para obter o valor desse Href?
Isso pode funcionar, mas não é muito eficiente, pois você está fazendo uma requisição AJAX extra para cada visualização de página de tópico por cada usuário — incluindo anônimos. Isso criará uma carga desnecessária no seu servidor.
Na verdade, não. A URL de um tópico se parece com isto:
Isso funciona! Muito obrigado. Entendo que, com o método match aqui, você está percorrendo a URL para obter, suponho, a 3ª ocorrência de “/”, pois o ID sempre aparecerá após a terceira “/” na URL, que retorna o formato “/t/nome/id/outra_coisa”. Você poderia fornecer algumas informações sobre como sua expressão regular faz isso? Seria muito útil na minha jornada com regex.
Obrigado pela informação. Então é o “numero_postagem_ligada” que aparece às vezes e atrapalha minha chamada de API. Você diz aqui que é “opcional” — há alguma maneira de ter certeza de que ele nunca será exibido?
Quando um usuário visita a página de exibição do tópico, eu quero:
Saber programaticamente todas as tags associadas a esse tópico. Observe que algumas tags estão ocultas da visualização do usuário.
Ter um botão na página do tópico que adicione uma determinada tag oculta ao tópico ao ser clicado (se a tag oculta ainda não estiver lá) e remova a tag oculta ao ser clicado (se a tag oculta já estiver lá).
Tudo isso é direto usando a API de Admin e javascript/jquery (assumindo que consiga a URL correta do tópico para usar nas chamadas de API).
Acredito que a única outra maneira de fazer esse tipo de coisa seria criar um plugin onde eu entraria profundamente em 1. ember, 2. rails e 3. a base de código do Discourse. Revisti os principais posts e documentações do Discourse sobre como fazer isso, mas achei o processo lento, pois realmente é necessário entender essas três partes. Então, por enquanto, foquei na abordagem via API.
Gostaria de saber se existe outra maneira de fazer isso que reduzisse a carga no servidor.
Certamente, eu poderia ter ajudado você com o código se fosse uma solução de um único passo, mas há várias etapas envolvidas. Se você precisar de ajuda na forma de consultoria para realizar o trabalho ou aprender a escrever componentes de tema por conta própria, por favor, publique no Marketplace e eu entrarei em contato.
Um objeto de tópico completo é carregado no lado do cliente ao abrir a página do tópico. Agora, se você quiser usá-lo, precisará adicionar seu próprio código ao modelo para acessar esses dados ou reabrir classes para aproveitar os dados carregados (ou seja, basicamente criar suas próprias propriedades computadas e utilizá-las no modelo). Ele contém a maioria dos dados que você precisa (provavelmente até mais do que o necessário), carregados no lado do cliente sem chamadas adicionais à API. Você também precisará de plugin-outlets para inserir seu próprio markup nos modelos existentes.
Agora, seria útil se você explorasse a base de código ou o meta para os termos que usei acima. Ficarei feliz em ajudar aqui se você ficar preso, dentro do meu limite de tempo disponível. Abraços.
Obrigado. Estou familiarizado com alguns dos conceitos básicos que você menciona, mas há um ponto que me deixa travado (e aposto que esse tipo de coisa trava muita gente):
Na página de exibição do tópico, ela carrega o template /templates/components/topic-category.hbs. É isso que exibe a categoria e também a tag abaixo do título do tópico.
No topic-category, ele lista topic.tags. Então, essa é a peça-chave de informação que preciso para fazer isso funcionar.
É aqui que estou travado: Como posso obter essas informações de topic.tags no meu JavaScript?
Por exemplo, se eu apenas quisesse fazer um console.log do conteúdo de topic.tags, como eu faria isso?
Sei como sobrescrever templates. Por exemplo, em um tema, eu poderia colocar um arquivo em discourse/templates/components/topic-category.hbs e reimprimir o template lá, adicionando as alterações que eu quisesse fazer na visualização. (Estou usando a estrutura de arquivos separados descrita aqui).
No meu tema, também sei como colocar JavaScript em theme/initializers/initializer-file.js.es6.
E consigo fazer os dois interagirem com um pouco de jQuery. Por exemplo, eu poderia colocar as topic.tags em uma div no template e acessá-las no meu inicializador com jQuery, obtendo o conteúdo dessa div.
Mas isso é indireto. Como posso obter essas informações de topic.tags diretamente para que eu possa analisá-las e manipulá-las?
Eu faria um console.log de todo o objeto topic e identificaria qual chave é necessária. Para interações com jQuery, elas devem ser feitas dentro dos componentes. didInsertElement é o hook do componente útil para esse caso.
Pelo que parece, você precisa de uma propriedade computada que dependa de topic.tags e retorne a manipulação desejada no controlador ou componente em questão. Ela pode ser usada diretamente no template. Além disso, não desista disso. Levará tempo, mas certamente valerá a pena de formas que você nem imaginava.
O que você quer dizer com “dentro dos componentes” — em qual arquivo devo colocar o código do jQuery? (no meu tema, posso usar jQuery no arquivo theme/intializers/intializer-file.js.es6, mas isso não parece estar “dentro” do componente)
Em qual arquivo deve ser colocado o código do didInsertElement?
Neste ponto, você deve realmente consultar os guias do Ember. Um componente é um pacote de funcionalidades que você pode implantar e anexar a outras coisas.
Obrigado, pessoal, todas essas informações são úteis. Estou analisando os guias e a documentação geral. Também seria muito útil saber o nome do arquivo onde devo colocar o código (i) jQuery e (ii) didInsertElement. Ter esse tipo de informação concreta será de grande ajuda para orientar a próxima revisão.
Você pode reopen (reabrir) vários tipos de classes do Ember e injetar seu código nelas. Você precisará pesquisar por plugins ou temas que façam isso para ter uma ideia melhor.
@JQ331 Como você provavelmente sabe, encontrei expressões regulares no Google e as tentei aqui! Você pode inserir variações para obter os melhores resultados.
Se as tags estão ocultas para o usuário comum, como uma chamada adicional ajudaria? O serializador, em qualquer caso, deve estar ocultando essas tags do usuário comum. Caso contrário, você está expondo uma brecha de segurança de conteúdo.
Se você está se dando ao trabalho de contornar as limitações de alterações apenas no front-end, sugiro que enfrente o problema e considere construir isso em um plugin, onde você poderia serializar de uma só vez, em vez de ter uma configuração confusa com chamadas adicionais.
Isso faz sentido. Gostaria de aprender mais sobre o uso do serializer — embora o serializer seja uma das etapas mais importantes em um plugin do Discourse, ainda não encontrei documentação que apresente exemplos básicos de como utilizá-lo. Você conhece essa documentação?
Quando você diz que um serializer deve ocultar essas tags, poderia fornecer algum pseudocódigo para ilustrar o que você quer dizer? (não precisa funcionar perfeitamente — estou apenas tentando entender o conceito).
Isso é como música jazz… as melhores práticas geralmente já estão disponíveis no ecossistema existente de plugins de código aberto, assim como todos os discos. Não espere um guia perfeito sobre como fazer tudo; na maioria das vezes, você precisa entrar no ritmo (hem) de aprender com trabalhos anteriores.
Encontre um plugin de #plugin que faça algo funcionalmente semelhante, ou um elemento do que você deseja fazer, e inspecione o código para ver como ele realiza as tarefas. O mesmo vale para o código-fonte do Discourse, que você pode usar como fonte definitiva de ‘melhores práticas’, especialmente em relação ao Discourse.
Clone um plugin existente localmente e tente alterar algumas coisas, experimente.
Serializadores apenas filtram o que é enviado dos Controladores/Modelos e também podem realizar algumas manipulações básicas.
def tags
# Chamar o método `pluck` junto com `includes` causa consultas N+1
tags = topic.tags.map(&:name)
if scope.is_staff?
tags
else
tags - scope.hidden_tag_names
end
end
Você pode ver aqui que as tags ocultas estão sendo excluídas para usuários que não são da equipe.