Disparar JavaScript ao clicar em qualquer link da página, mas antes do conteúdo da página carregar-se

Olá.
Quando mudamos de página no Discourse, os passos aparentes são:

  1. Clicamos no link
  2. O conteúdo atual desaparece e o carregador aparece
  3. A URL é atualizada e o novo conteúdo aparece

Isso é ligeiramente diferente quando vamos de uma página para a página inicial, pois a URL é alterada para a URL da página inicial quando o conteúdo atual desaparece, e não quando o novo conteúdo aparece.

Meu objetivo é ter um script que seja executado assim que clicarmos em qualquer link de página no Discourse.
api.onPageChange não serve para este caso, pois o código é executado quase ao mesmo tempo em que o conteúdo da nova página é carregado.

Existe algum método no Discourse para isso? Olhei para os gatilhos de eventos, mas não encontrei nenhum que corresponda ao que preciso.

1 curtida

Olá :wave:

Atualmente, não há nenhum método na Plugin-API que permita executar um script antes de uma transição de página, pois, até onde me lembro, isso nunca foi solicitado anteriormente.

Dito isso, você pode aproveitar a ação willTransition() na rota de aplicação (application route):

No seu tema ou componente, você usaria algo assim:

// isso é executado após a transição
api.onPageChange((url, title) => {
  console.log("after transition");
});

// isso é executado imediatamente antes da transição
api.modifyClass("route:application", {
  pluginId: "some-name",
  actions: {
    willTransition() {
      // execute o código principal primeiro
      this._super(...arguments);
      // depois faça algum trabalho
      console.log("before transition");
      // você também pode fazer algo assim para ver quais dados tem disponíveis
      // para trabalhar, como _router
      console.log(this)
    }
  }
});
6 curtidas

Exatamente o que eu precisava. Obrigado!

2 curtidas

Isso não parece ser acionado ao entrar em um Tópico a partir de uma Lista de Tópicos?

Eu também tentei adicionar um:

      api.modifyClass("route:topic", {
        pluginId: PLUGIN_ID,
        actions: {
          willTransition() {

mas isso também não é acionado.

Alguns motivos que podem estar impedindo o funcionamento:

  1. Colocar ações em um hash é uma sintaxe antiga que não usamos mais no Discourse. Teoricamente, deveria funcionar, mas a interoperabilidade com a nova sintaxe pode não ser perfeita. A maneira moderna seria

    api.modifyClass("route:application", (Superclass) => class extends Superclass {
      @action
      willTransition() {
        console.log("fazer algo");
        super.willTransition(...arguments);
      }
    });
    

    A isenção de responsabilidade padrão do modifyClass se aplica: isso é arriscado e pode quebrar a qualquer momento

  2. Não acho que willTransition seja garantido para disparar na rota de aplicação em todas as situações. (por exemplo, se uma rota filha tiver uma ação willTransition, ela não necessariamente subirá)

Eu recomendaria usar os eventos no serviço do roteador Ember em vez disso: RouterService | 5.12.0 | Ember API Documentation
por exemplo, algo como

const router = api.container.lookup("service:router");
router.on("routeWillChange", () => {
  console.log("route will change disparado");
});
2 curtidas

Legal, obrigado David, vou tentar isso em seguida!

Esta investigação foi acionada (ahem) porque eu precisava de uma maneira de disparar algo em cada mudança de página, e antes do Render.

O evento da API de mudança de página não parece garantir que dispare antes que os elementos da página sejam renderizados, aparentemente.

1 curtida

Acho que você terá dificuldade em fazer isso perfeitamente. O Ember espera ter controle total sobre a renderização, então tentar se conectar a pontos arbitrários será difícil e pode causar problemas (dependendo do que você está tentando fazer).

Obviamente, não sei qual é o seu objetivo final… então talvez a dificuldade seja justificada. Nesse caso: sinta-se à vontade para me ignorar :wink:

(claro, se você quiser abrir um tópico de Dev sobre o problema que está tentando resolver, ficarei feliz em dar uma olhada)

Feliz em ser explícito, pois o código é de código aberto:

Estou trabalhando com um provedor de anúncios terceirizado e eles têm uma função de reinicialização de página de anúncios em JavaScript que precisa ser executada antes que os anúncios da nova página sejam acionados.

Qualquer melhoria é bem-vinda e eu já percebi isso na Lista de Tópicos com o código de Johani. (em um PR aberto).

Mas isso deixou o Tópico… Tentarei sua sugestão em seguida e a adotarei em ambas as instâncias se isso melhorar ainda mais as coisas.

Ah, entendi, então você não está modificando o DOM diretamente :ok_hand:

Nesse caso, espero que routeWillChange funcione - ele certamente deve disparar antes que a próxima rota seja renderizada.

A ressalva é que… no caso de coisas como redirecionamentos, ele pode disparar duas vezes. Ou pode disparar, e então a transição acaba sendo abortada. Mas talvez isso esteja bom neste caso.

2 curtidas

Sim, nada dessa malandragem de modificação direta do DOM aqui na Merefield Technology Towers. :sweat_smile:

Sim, usarei o serviço, é para isso que ele serve! Retornarei com minha experiência, pois tenho certeza de que os resultados podem interessar a outros.

3 curtidas

Então sim, isso limpa e as coisas acontecem na ordem certa em ambas as rotas agora.

:rocket:

Obrigado pela sua ajuda!

2 curtidas