Comment ajouter la prise en charge d'un éditeur de texte enrichi à mon extension markdown ?

J’ai créé une extension qui ajoute des balises bbcode pour rendre snapblocks. Lorsque l’éditeur de texte enrichi a été introduit, cela a en quelque sorte cassé mon extension, ou du moins elle est inutilisable avec l’éditeur de texte enrichi. Je veux ajouter la prise en charge de l’éditeur de texte enrichi, j’ai donc examiné l’extension corrompue pour voir comment elle fonctionne, et j’ai actuellement obtenu des résultats mitigés. Je peux effectivement insérer les snapblocks dans le message dans l’éditeur de texte enrichi, mais je n’arrive pas à faire convertir les balises snapblocks existantes dans l’éditeur de texte enrichi.

Voici ce que j’ai fait jusqu’à présent.

Pour l’instant, je me concentre spécifiquement sur la conversion proprement dite. J’ai une idée de base sur son fonctionnement, mais jusqu’à présent, je n’obtiens aucun résultat. Alors, comment faire fonctionner l’analyse ?

1 « J'aime »

Après beaucoup de frustration et l’ajout de nombreux console.log() dans discourse, j’ai découvert pourquoi cela ne fonctionnait pas et comment y remédier.

L’analyse n’est pas effectuée sur le HTML rendu, mais sur les tokens markdownit. J’utilisais state.push(html_raw) dans la fonction replace() pour rendre mes tags 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>`
      },
    });
}

Le problème était que le type de token html_raw est ignoré par le convertisseur d’éditeur de texte riche. Cela signifie que vous ne pouvez pas l’utiliser si vous souhaitez une prise en charge de l’éditeur de texte riche.

J’ai découvert qu’en utilisant bbcode_open, text et bbcode_close, je pouvais y parvenir.

// 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']] // nécessaire pour les vérifications ultérieures
      },
    });
}

Une fois cela fait, cela ne sera plus ignoré.

En passant à rich-text-editor-extension.js, vous faites ensuite ceci.

// 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*", // Ceci est nécessaire
      createGapCursor: true,
      parseDOM: [{ tag: "pre.snapblocks-blocks" }],
      toDOM: () => ["pre", { class: "snapblocks-blocks" }, 0],
    },
  },
  parse: {
    bbcode_open(state, token) {
      // Le token ici est le même objet token `bbcode_open`
      // que dans le code précédent
      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) {
      // Ceci convertit simplement en texte brut markdown
      state.write("[snapblocks]\n");
      state.renderContent(node);
      state.write("\n[/snapblocks]\n\n");
    },
  },
}

Les clés de la propriété parse sont des analyseurs pour le type de token qui peuvent être utilisés dans l’analyseur markdown.

Il y a certainement plus que cela, mais au moins cela clarifie beaucoup plus les choses qu’auparavant.

1 « J'aime »

Pas exactement, mais nous avons déjà l’extension html-block qui gère les tokens html_raw de markdown-it, ce qui est une manière générique de gérer un contenu passthrough.

Vous pouvez vérifier tous les types d’extensions autorisées via registerRichEditorExtension, et il existe de nombreuses extensions provenant de plugins ainsi que celles qui sont enregistrées par défaut qui peuvent servir d’inspiration.

N’hésitez pas à nous faire savoir si vous avez des questions.

3 « J'aime »

Merci pour la clarification.


Je rencontre maintenant un problème où le basculement de la version bloc ne fonctionne pas. Je peux basculer les blocs en ligne, mais pas le nœud de niveau bloc.

À un moment donné, j’aimerais qu’il affiche les blocs lorsque le curseur n’est pas dessus, mais je pense que cela peut venir après avoir simplement réussi à le faire fonctionner.

Désolé, je ne comprends pas. Que voulez-vous dire par « basculer la version de bloc » ?

Mon tag bbcode a [snapblocks] et [sb], où [sb] est en ligne, et [snapblocks] est de niveau bloc. Lorsque j’appuie sur le bouton de la barre d’outils, il bascule la balise en ligne, mais il ne bascule pas la balise de niveau bloc lorsque je sélectionne un bloc de texte.