如何为我的 markdown 扩展添加富文本编辑器支持?

我创建了一个扩展,它添加了一些bbcode标签来渲染snapblocks。当引入富文本编辑器时,我的扩展就坏了,或者至少在富文本编辑器中无法使用。我想添加对富文本编辑器的支持,所以我查看了损坏的扩展,看看它是如何实现的,并且目前已经取得了一些进展。我实际上可以在富文本编辑器中将snapblocks插入到帖子中,但我似乎无法让现有的snapblocks标签转换为富文本编辑器。

这是我目前所做的。

我现在专注于实际的转换。我对它的工作原理有一个基本的猜测,但到目前为止还没有取得任何成果。那么如何才能让解析工作呢?

1 个赞

经过大量的摸索和在 discourse 中添加许多 console.log(),我终于发现了它不起作用的原因以及如何让它起作用。

解析不是通过渲染后的 HTML 完成的,而是通过 markdownit 标记完成的。我一直在 replace() 函数中使用 state.push(html_raw) 来渲染我的 [snapblocks] bbcode 标签。

// 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>`
      },
    });
}

问题在于 html_raw 标记类型被富文本编辑器转换器忽略了。这意味着如果你想要富文本编辑器支持,就不能使用这个。

我发现通过使用 bbcode_opentextbbcode_close,我可以让它工作。

// 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']] // needed for later checks
      },
    });
}

完成这些之后,它将不再被忽略。

移动到 rich-text-editor-extension.js,然后执行此操作。

// 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*", // This is needed
      createGapCursor: true,
      parseDOM:[{ tag: "pre.snapblocks-blocks" }],
      toDOM: () => ["pre", { class: "snapblocks-blocks" }, 0],
    },
  },
  parse: {
    bbcode_open(state, token) {
      // The token here is the same `bbcode_open` token object
      // from the previous code
      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) {
      // This just converts it back to plain text markdown
      state.write("[snapblocks]\n");
      state.renderContent(node);
      state.write("\n[/snapblocks]\n\n");
    },
  },
}

parse 属性中的键是可用于 markdown 解析器的标记类型的解析器。

这肯定比这复杂得多,但至少这比以前清晰多了。

1 个赞

不完全是这样,但我们已经有了 html-block 扩展来处理 html_raw markdown-it 令牌,这是一种处理直通内容的通用方法。

你可以通过 registerRichEditorExtension 查看所有允许的扩展类型,并且有很多来自插件的扩展以及那些默认注册的扩展可以作为参考。

如果您有任何问题,请告诉我们。

3 个赞

感谢您的澄清。


我现在遇到了一个问题,切换块版本不起作用。我可以切换内联块,但不能切换块级节点。

在某个时候,我想让它在光标不在块上时渲染块,但我觉得这可以在它工作之后再处理。

抱歉,我没明白。您说的“切换块版本”是什么意思?

我的 bbcode 标签有 [snapblocks][sb],其中 [sb] 是行内标签,[snapblocks] 是块级标签。按下工具栏按钮时,它会切换行内标签,但在我选择一段文本时,它不会切换块级标签。