Incorpora widget nel testo di un argomento

Ciao!! :slight_smile:

Spero che questo possa interessare qualcun altro: sto cercando di creare un argomento “feed dei social media”, in cui vorrei incorporare i widget di diverse piattaforme in modo che gli utenti (e gli amministratori!) possano dare un’occhiata rapida a tutti in un’unica pagina, rimanendo così all’interno del forum ed evitando il sovraccarico che comporta dover passare da così tante piattaforme social solo per aggiornamenti rapidi (considerando anche che di solito condividono lo stesso contenuto), aumentando così la motivazione a utilizzare il forum come hub per lo sviluppo della comunità.

Un ottimo generatore di widget che ho trovato è Woxo, che è abbastanza pulito e semplice per lo scopo. Il problema ora è che non riesco a capire come incorporare il widget nell’argomento. Sto cercando di vedere se esiste qualche soluzione alternativa con gli iframe o qualcosa di simile, ma ora volevo chiedere se questo è possibile in assoluto.

Questo è il codice che ottengo da Woxo per il feed di Instagram:

<div data-mc-src="f4b43a8f-c188-4f80-8206-36d9f7529f13#instagram"></div>
        
<script 
  src="https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619" 
  async data-usrc>
</script>

Cosa ho provato finora:

  • Inserire lo <script> nella sezione <body>, <footer> e <header> (l’ho lasciato nell’header)
  • Assicurarmi che l’URL da cui proviene lo script sia nella whitelist (https://cdn2.woxo.tech/ in questo caso)
  • Aggiungere defer non aiuta (lo tengo comunque per sicurezza)

Se ispeziono la pagina, lo script appare in fondo alla sezione del body (all’interno) e, dato che l’origine è nella whitelist, dovrebbe avere effetto. Ho controllato se potesse essere colpa del mio browser, ma se eseguo l’HTML qui W3Schools Tryit Editor funziona perfettamente.

Ho ridotto l’errore a una funzione specifica all’interno dello script JS. La seguente chiamata restituisce un valore null. È l’unico errore a runtime:

e=document.querySelector("div[data-mc-src]")
e è null

Quel div è scritto nell’argomento (la parte <div data-mc-src="f4b43a8f-c188-4f80-8206-36d9f7529f13#instagram"></div>). Rimane come codice HTML puro, quindi dovrebbe essere leggibile. Per qualche motivo, lo script non riesce a individuarlo.

Con l’attributo defer e posizionato nel footer, lo script non genera errori (il fatto che prima generasse un errore dimostra che l’URL del file JS è effettivamente nella whitelist), quindi ora sono al buio sul perché non faccia nulla.

Qualsiasi suggerimento sarà più che apprezzato, grazie in anticipo per il vostro tempo! :slight_smile:
Lisandro

EDIT: alla fine ho dovuto desistere. Dato che sono supportati solo gli iframe, sto cercando un buon servizio web che ne fornisca uno. La maggior parte dei servizi gratuiti è troppo limitata, le versioni a pagamento costano più del doppio del servizio di hosting del forum. Scusate il lamento, dovevo sfogarmi qui ad alta voce per non essere riuscito a inserire semplicemente il codice HTML gratuito :cry:

2 Mi Piace

Discourse è un’applicazione a pagina singola. Il problema che stai riscontrando si verifica perché lo script che stai utilizzando non ne è a conoscenza. Quando visiti la home page o qualsiasi altra pagina in Discourse, ottieni qualcosa di simile a questo.

<html>
  <head>
    contenuto dell'head, incluso il tuo script
  </head>
  <body>
    <section id="main">
      contenuto della pagina
    </section>
  </body>
</html>

Quando navighi verso un’altra pagina, l’unica cosa che viene ricaricata è il contenuto all’interno di

<section id="main">

Quindi, il DOM è cambiato e il tuo script personalizzato non viene eseguito nuovamente. Se provi a visitare direttamente la pagina dell’argomento, vedrai che si carica correttamente.

.

Ora la domanda è: come farlo funzionare con Discourse?

Il plugin-api ha un metodo che puoi utilizzare per “decorare” i post.

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L282-L318

Puoi usarlo per eseguire script di terze parti quando un post viene renderizzato.

Ecco il codice di cui hai bisogno. Aggiungi questo alla scheda common > header del tuo tema.

<script type="text/discourse-plugin" version="0.8">
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";

const loadScript = require("discourse/lib/load-script").default;
const { iconHTML } = require("discourse-common/lib/icon-library");

const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
  class: "woxo-preview-icon"
});

const previewMarkup = () => {
  const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;
  return markup;
};

// crea un decoratore per i post
api.decorateCookedElement(
  post => {
    const woxoWidgets = post.querySelectorAll("div[data-mc-src]");

    if (woxoWidgets.length) {
      woxoWidgets.forEach(woxoWidget => {
        if (post.classList.contains("d-editor-preview")) {
          woxoWidget.innerHTML = previewMarkup();
          return;
        }

        loadScript(WOXO_SCRIPT_SRC).then(() => {
          const script = document.head.querySelector(
            `script[src*="cdn2.woxo.tech"]`
          );
          script.dataset.usrc = "";
          window.MC.Loader.init();
        });
      });
    }
  },
  { id: "render-woxo-widgets" }
);
</script>

Dovrai quindi aggiungere un paio di domini per CSP. Aggiungi questi alla tua

content_security_policy_script_src

impostazione del sito

https://*.woxo.tech/
https://us-central1-core-period-259421.cloudfunctions.net/availableComponentTracks

Infine, dovrai aggiungere un po’ di CSS per l’anteprima statica del compositore.

Questo va nella scheda common > CSS del tuo tema.

.woxo-preview {
  height: 400px;
  width: 100%;
  background: var(--primary-low);
  display: flex;
  align-items: center;
  justify-content: center;
  .woxo-preview-icon {
    font-size: var(--font-up-4);
    color: var(--primary-high);
  }
}

Poi puoi semplicemente aggiungere

<div data-mc-src="f4b43a8f-c188-4f80-8206-36d9f7529f13#instagram"></div>

a qualsiasi post e i widget verranno renderizzati e saranno pienamente funzionali.

Se osservi il JavaScript, noterai che ha due opzioni in cima.

const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";

Modifica WOXO_SCRIPT_SRC con l’URL fornito da Woxo. Dovrebbe essere lo stesso per tutti gli embed che crei.

Modifica PREVIEW_ICON con il nome dell’icona che desideri utilizzare nell’anteprima del compositore. L’esecuzione di questo codice nel compositore è piuttosto costosa, quindi il compositore ha un’anteprima statica che appare così.

L’icona che scegli verrà visualizzata al centro.

Ecco una copia commentata del codice, se vuoi seguire passo passo cosa sta accadendo.

codice commentato
<script type="text/discourse-plugin" version="0.8">
// opzioni
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";

// utilizziamo la libreria Discourse Load script per garantire che gli script
// vengano caricati correttamente. Non preoccuparti, è abbastanza intelligente
// da non duplicare lo script se è già stato caricato
const loadScript = require("discourse/lib/load-script").default;

// carichiamo la funzione HTML delle icone di Discourse per ottenere l'SVG dell'icona
// che vogliamo usare nell'anteprima statica del compositore
const { iconHTML } = require("discourse-common/lib/icon-library");

// impostiamo l'icona dell'anteprima del compositore
const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
  class: "woxo-preview-icon"
});

// creiamo una funzione di supporto per il markup dell'anteprima del compositore
const previewMarkup = () => {
  const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;

  return markup;
};

// creiamo un decoratore per i post
api.decorateCookedElement(
  post => {
    // questo post contiene widget Woxo?
    const woxoWidgets = post.querySelectorAll("div[data-mc-src]");

    // Sì, quindi procediamo con alcune operazioni.
    if (woxoWidgets.length) {
      // per ogni widget Woxo
      woxoWidgets.forEach(woxoWidget => {
        // se si tratta di un widget del compositore, sostituiscilo con un'anteprima statica e
        // esci subito
        if (post.classList.contains("d-editor-preview")) {
          woxoWidget.innerHTML = previewMarkup();
          return;
        }

        // se non è nel compositore, carica lo script Woxo.
        loadScript(WOXO_SCRIPT_SRC).then(() => {
          // Lo script Woxo è molto particolare. Non funzionerà a meno che il tag script
          // non abbia un attributo data-usrc vuoto. Quindi aggiungiamolo
          const script = document.head.querySelector(
            `script[src*="cdn2.woxo.tech"]`
          );
          script.dataset.usrc = "";

          // tutto è pronto, chiamiamo il metodo init nello script Woxo
          window.MC.Loader.init();
        });
      });
    }
  },
  // aggiungiamo un ID al decoratore per evitare perdite di memoria
  { id: "render-woxo-widgets" }
);

</script>
3 Mi Piace

Prima di tutto: O-M-G GRAZIE TANTISSIMO :exploding_head:
Sono rimasto stupefatto dal livello della risposta; l’unica consolazione nel vedere una tale quantità di lavoro è che è ovvio che sarà di grande aiuto per molti. Questo apre molte nuove possibilità, tutte a beneficio dello sviluppo di un forum come hub per una comunità.

Secondo: mi dispiace moltissimo per aver risposto così tardi, dato che hai risposto così velocemente. Innanzitutto non sono riuscito ad accedere al mio computer prima, e poi volevo rispondere solo dopo aver effettivamente esaminato il codice che hai gentilmente commentato (riga per riga :flushed:, mio Dio, grazie mille). Naturalmente, tutto ha funzionato perfettamente, l’intero feed si carica così velocemente… Sono in debito :pray:

Grazie ancora, Johan, spero davvero di poter contribuire con la mia esperienza :pray:

PD: Tengo assolutamente il cuore per l’anteprima statica.

1 Mi Piace

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.