Come aggiungo il supporto per l'editor di rich text alla mia estensione markdown?

Ho creato un’estensione che aggiunge alcuni tag bbcode per il rendering di snapblocks. Quando è stato introdotto l’editor di testo rich, questo tipo di estensione si è rotto, o almeno è inutilizzabile con l’editor di testo rich. Voglio aggiungere il supporto per l’editor di testo rich, quindi ho esaminato l’estensione rovinata per vedere come funziona e attualmente ci sono riuscito in parte. Posso effettivamente inserire gli snapblocks nel post nell’editor di testo rich, ma non riesco a far convertire i tag snapblocks esistenti nell’editor di testo rich.

Ecco cosa ho finora.

Al momento mi sto concentrando specificamente sulla conversione effettiva. Ho un’idea di base su come funziona, ma finora non ho ottenuto risultati. Quindi, come faccio a far funzionare il parsing?

1 Mi Piace

Dopo molte discussioni e l’aggiunta di molti console.log() a discourse, ho scoperto perché non funzionava e come farlo funzionare.

Il parsing non viene eseguito con l’HTML renderizzato, ma con i token di markdownit. Avevo usato state.push(html_raw) nella funzione replace() per renderizzare i miei tag bbcode [snapblocks].

// assets/javascripts/lib/discourse-markdown/snapblocks-discourse.js

export function(helper) {
  md.block.bbcode.ruler.push("snapblocks", {
      tag: "snapblocks",
      replace(state, tagInfo, content) {
        let token = state.push('html_raw', '', 0)
        token.content = `<pre class="snapblocks-blocks">${content}</pre>`
      },
    });
}

Il problema era che il tipo di token html_raw viene ignorato dal convertitore di editor di testo rich text. Ciò significa che non è possibile utilizzarlo se si desidera il supporto per l’editor di testo rich text.

Ho scoperto che utilizzando bbcode_open, text e bbcode_close, posso farlo funzionare.

// assets/javascripts/lib/discourse-markdown/snapblocks-discourse.js

export function(helper) {
  md.block.bbcode.ruler.push("snapblocks", {
      tag: "snapblocks",
      replace(state, tagInfo, content) {
        let token = state.push('bbcode_open', 'pre', 1)
        token.attrs = [['class', 'snapblocks-discourse']]

        token = state.push('text', '', 0)
        token.content = content

        token = token.push('bbcode_close', 'pre', -1)
        token.attrs = [['class', 'snapblocks-discourse']] // necessario per controlli successivi
      },
    });
}

Una volta fatto ciò, questo non verrà più ignorato.

Passando a rich-text-editor-extension.js, quindi fai questo.

// assets/javascripts/lib/rich-text-editor-extension.js

import { i18n } from "discourse-i18n";

const SNAPBLOCKS_NODES = ["inline_snapblocks", "snapblocks"];

/** @type {RichEditorExtension} */
const extension = {
    snapblocks: {
      attrs: { rendered: { default: true } },
      code: true,
      group: "block",
      content: "text*", // Questo è necessario
      createGapCursor: true,
      parseDOM:[{ tag: "pre.snapblocks-blocks" }],
      toDOM: () => ["pre", { class: "snapblocks-blocks" }, 0],
    },
  },
  parse: {
    bbcode_open(state, token) {
      // Il token qui è lo stesso oggetto token `bbcode_open`
      // dal codice precedente
      if (token.attrGet('class') === 'snapblocks-blocks') {
        state.openNode(state.schema.nodes.snapblocks, {
          open: token.attrGet("open") !== null,
        });
        return true;
      }
    },
    bbcode_close(state, token) {
      if (token.attrGet('class') === 'snapblocks-blocks') {
        state.closeNode();
        return true;
      }
    },
  },
  serializeNode: {
    snapblocks(state, node) {
      // Questo lo converte semplicemente di nuovo in markdown di testo normale
      state.write("[snapblocks]\n");
      state.renderContent(node);
      state.write("\n[/snapblocks]\n\n");
    },
  },
}

Le chiavi nella proprietà parse sono parser per il tipo di token che possono essere utilizzati nel parser markdown.

Ci sono sicuramente più cose da fare oltre a questo, ma almeno questo chiarisce molto di più rispetto a prima.

1 Mi Piace

Non esattamente, ma abbiamo già l’estensione html-block che gestisce i token html_raw di markdown-it, che è un modo generico per gestire un contenuto passthrough.

Puoi controllare tutti i tipi di estensioni consentite tramite registerRichEditorExtension, e ci sono molte estensioni dai plugin così come quelle che sono registrate di default che possono essere usate come ispirazione.

Fateci sapere se avete domande.

3 Mi Piace

Grazie per la precisazione.


Ora sto riscontrando un problema in cui l’attivazione della versione a blocco non funziona. Posso attivare i blocchi inline ma non il nodo a livello di blocco.

A un certo punto, vorrei che renderizzasse i blocchi quando il cursore non è su di essi, ma penso che questo possa venire dopo averlo semplicemente fatto funzionare.

Mi dispiace, non capisco. Cosa intendi per “attivare la versione a blocchi”?

Il mio tag bbcode ha [snapblocks] e [sb], dove [sb] è inline e [snapblocks] è a livello di blocco. Quando si preme il pulsante della barra degli strumenti, viene attivato e disattivato il tag inline, ma non viene attivato e disattivato il tag a livello di blocco quando si seleziona un blocco di testo.