Come eseguire un'azione ad ogni caricamento del footer (o caricamento della pagina?)

Sto cercando di caricare un modulo JavaScript in un footer.

Nel header ho questo:

<script type="text/discourse-plugin" version="0.8">
  let loadScript = require("discourse/lib/load-script").default;

  api.onPageChange(() => {
    loadScript("//js.hsforms.net/forms/current.js").then(() => {
      console.log("doing the thing");
      hbspt.forms.create({
        portalId: "229276",
        formId: "a86ca9cc",
        submitButtonClass: "button orange-button hubspot-button",
        target: ".subscription-form"
      });
    });
  });
</script>

E nel footer c’è questo:

<div class="subscription-form clearfix">
  <h5>Iscriviti al nostro blog</h5>
</div>

La prima volta che la pagina viene caricata, funziona correttamente. Nelle pagine successive (la maggior parte di esse, almeno), il modulo non viene caricato e viene visualizzato questo errore:

Couldn't find target container .subscription-form for HubSpot Form a86ca9cc. Not rendering form onto the page

Penso che forse il footer venga caricato dopo che lo script viene eseguito?

Quindi devo in qualche modo ritardare l’esecuzione dello script fino a quando il footer non è stato caricato.

plugin-api.js dice:

//  Listen for a triggered `AppEvent` from Discourse.

api.onAppEvent("inserted-custom-html", () => {
  console.log("a custom footer was rendered");
});

Forse devo solo sapere quale AppEvent monitorare?

C’è un po’ di informazione a riguardo qui.

Javascripts targeting the footer doesn't work after page transitions - #4 by Johani

Quando usi questo

api.onAppEvent("inserted-custom-html", () => {
  // some code
});

devi specificare quale HTML personalizzato vuoi prendere di mira: diversi eventi vengono attivati in base a questo.

In questo caso, vuoi prendere di mira il footer. Puoi provare questo e vedere se funziona per te?

api.onAppEvent("inserted-custom-html:footer", () => {
  // some code
});

Ehi! Ci siamo! (Ovviamente, è successo dopo averli convinti che quello che stavano cercando di fare nel footer non valeva la pena di essere fatto in primo luogo). Sono entusiasta di aver risolto il problema e apprezzo molto il tuo aiuto; sto gradualmente arrivando a capire queste cose. (E penso che ora cancelleranno completamente il footer.)

Aha! Non sono sicuro del perché non mi sia venuto in mente di cercare “footer”! :man_shrugging:

Quindi inserted-custom-html si riferisce a qualsiasi cosa nei temi? E poi potrei aggiungere :footer o :header o forse :head_tag? È questa la magia? Sono solo io, o

https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/lib/plugin-api.js#L516

sarebbe stato più utile se invece avesse detto

   api.onAppEvent('inserted-custom-html:footer', () => {

Javascript ed Ember sono le cose più difficili per me da capire da quando… forse quando ho imparato Lisp a metà degli anni '80, quindi ancora non riesco a capire cosa sia considerato “ovvio”.

Non esattamente. Quel evento viene attivato solo quando viene renderizzato il componente ember custom-html.

Quindi, dove utilizziamo quel componente ember e cosa fa?

Lo utilizziamo principalmente nel modello dell’applicazione principale per renderizzare due campi del tema.

Scheda after_header del tema

Scheda footer del tema

Nota che lo usiamo anche in altri punti, ma in questo contesto non sono rilevanti.

Notate come anche il footer abbia triggerAppEvent="true"

Ecco perché puoi usare

api.onAppEvent("inserted-custom-html:footer", () => {
  // qualche codice
});

Non puoi fare lo stesso con la scheda after_header. Discourse non attiva un evento per quella. Quindi, questo non funzionerà.

api.onAppEvent("inserted-custom-html:top", () => {
  // qualche codice
});

Ora, perché usiamo quel componente ember per renderizzare alcuni campi del tema?

La risposta semplice è che ci dà molto più controllo su quando viene renderizzato.

Due esempi di questo… La lista degli argomenti e la pagina di amministrazione.

Non vogliamo renderizzare il footer nella lista degli argomenti mentre ci sono ancora argomenti da caricare tramite lo scroll infinito.

Non vogliamo nemmeno renderizzare banner o markup di branding del sito aggiunti nella scheda after_header nella pagina di amministrazione.

Quindi, usare il componente ember custom-html ci dà un controllo più granulare su cose come queste.

Ora, torniamo alla tua domanda. Se devi eseguire qualche operazione quando il footer viene renderizzato, questo è il wrapper di cui hai bisogno,

api.onAppEvent("inserted-custom-html:footer", () => {
  // qualche codice
});

Quel metodo API funziona per tutti gli eventi dell’app. Quindi, anche se l’esempio lì non è davvero completo, è solo un esempio. Ci sono molti altri AppEvents che puoi usare in quel metodo. Ad esempio, puoi controllare qui.

Code search results · GitHub

per vedere i nomi di alcuni eventi che vengono attivati.

this.appEvents.trigger("EVENT_NAME")

e come ci agganchiamo ad essi per apportare altre modifiche

this.appEvents.on("EVENT_NAME")

Puoi agganciarti a qualsiasi evento attivato dal core di Discourse nel tuo tema. Quindi, se voglio eseguire del codice subito prima che si apra il compositore.

discourse/app/assets/javascripts/discourse/app/components/composer-editor.js at 1c38b4abf1fab8d67aaaa4b9f2810add64b709c4 · discourse/discourse · GitHub.

Posso aggiungere qualcosa del genere al mio tema.

api.onAppEvent("composer:will-open", () => {
  console.log("questo viene eseguito subito prima che il compositore si apra");
});

Detto questo, sono d’accordo con te. Dovremmo usare un esempio diverso per quel metodo nel file API. Ho preso nota per migliorare quell’esempio.

Questa è una risposta eccellente e così chiara che persino io sono riuscito a capirla.

La questione su “come far scattare una cosa” si presenta abbastanza spesso. Forse le persone la troveranno qui, ma il tuo ultimo post potrebbe benissimo essere un argomento a sé stante e magari aggiunto o collegato nelle guide sui temi e/o sui plugin.

E ora che per “tema” si intende principalmente “Ember” e per “plugin” principalmente “Rails”, potrebbe avere senso che qualcuno pensi a una loro leggera rifattorizzazione. Sembra che, quando tutto era appena iniziato, c’era una serie di funzionalità Ember che richiedevano un plugin e che ora possono essere realizzate in un componente del tema, giusto? E ora puoi gestire le funzionalità Ember in un plugin o in un componente del tema.

Ciao @Johani, un’altra versione di questo problema su “come attivare o essere attivati” è che sto utilizzando una versione di Custom Header Links all’interno di un plugin. Questo collega alcuni elementi (“server”) creati in un modello separato che il mio plugin aggiunge. Quando viene creato un server, voglio ricostruire i link dell’intestazione per puntare ai due server più recenti. Attualmente lo sto facendo in un inizializzatore e funziona bene, tranne che per aggiornarlo dopo l’aggiunta di un server è necessario ricaricare la pagina.

Mi hai spiegato come aggiungere e monitorare i trigger, quindi pensavo di poter risolvere il problema, ma la pagina che esegue il lavoro si trova in discourse-subscriptions. Forse quello che voglio fare è inviare una PR a discourse-subscriptions che aggiunga

 this.appEvents.trigger("purchase-complete")

dopo il completamento dell’acquisto (e l’acquisto attiva l’aggiunta a un gruppo, che a sua volta attiva la creazione di un server e la rimozione dell’utente dal gruppo). Oppure, se potessi semplicemente attivare un ricaricamento dopo il completamento dell’acquisto o quando si clicca su “OK” nella finestra modale “acquisto completato”, sarebbe comunque accettabile, ma non so come farlo (quello che ho provato ha ricaricato la pagina all’infinito…)

Quindi forse qui:

https://github.com/discourse/discourse-subscriptions/blob/main/assets/javascripts/discourse/controllers/s-show.js.es6#L71-L81

Vorrei aggiungere

 this.appEvents.trigger("successful-transaction")

dopo aver impostato loading su false, e poi potrei far sì che il mio inizializzatore aggiunga

 this.appEvents.on("successful-transaction")

per eseguire la manipolazione dell’intestazione?

Penso che, una volta fatto questo, dovrò fare qualcosa di diverso perché temo che

      api.decorateWidget("header-buttons:before", (helper) => {
        return helper.h("ul.pfaffmanager-header-links", headerLinks);
      });

aggiunga a header-buttons:before invece di sostituirli, così otterrò più link ogni volta che viene attivato?

Questo mi ha aiutato di nuovo! Quello che dovevo fare era caricare uno script quando il flusso di post veniva aggiornato. Tutti gli esempi che ho trovato erano in componenti che avevano accesso a appEvent tramite this. Ho finalmente trovato questo e ora in un apiInitializer posso

  api.onAppEvent('post-stream:refresh', args => {
   // do some stuff!!!
  });

E ora quelle pubblicità si caricano quando ogni batch di post viene caricato. Ho già messo :heart: al tuo post, quindi ho dovuto scrivere un ringraziamento più esteso. :wink:

Questo è uno dei miei argomenti preferiti :heart: Torno qui di tanto in tanto :sweat_smile: Lo apprezzo molto! :hugs: