TipTap/ProseMirror 使用任意文本换行选区

TipTap/ProseMirror wrap selection with arbitrary text

提问人:Tallboy 提问时间:10/27/2023 更新时间:11/19/2023 访问量:44

问:

赏金将在 3 天后到期。这个问题的答案有资格获得 +50 声望赏金。Tallboy 希望引起人们对这个问题的更多关注

我正在使用 TipTap 编写 markdown 文本(不是 html)。

我通过不使用任何扩展来做到这一点,只是自己做,然后使用该函数。BoldgetText()

所有这些都非常适合我的简单用例,尽管我确信如果不使用适当的扩展等,它并不理想。

(请注意,我希望所有 markdown 都是可见的,而不是由编辑器解释的,这就是我这样做的原因)

问题是我的包装/解包代码有一些错误,特别是与越界有关。

发生这种情况的主要时间是,如果只有一个单词被突出显示,以及多个单词但突出显示最后一个单词

TypeError: Cannot read properties of undefined (reading 'nodeSize')

有没有更简单的方法可以做到这一点,或者我目前的实现缺少什么?我发现很奇怪,如果我只突出显示一个单词,选择就不会开始0

    const wrapUnwrap = marker => {
      const { state, view } = toRaw(editor.value);
      const { from, to } = state.selection;
      const len = marker.length;

      // exit if nothing selected
      if (from === to) {
        return;
      }

      // there is a current bug here where there are "node size" errors if you
      // try to select a single word and make it bold... as well as the last word
      let textBefore, textAfter;
      try {
        textBefore = state.doc.textBetween(from - len, from);
        textAfter = state.doc.textBetween(to, to + len);
      } catch (e) {
        console.log(e);
        return;
      }
      let tr = state.tr;

      if (textBefore === marker && textAfter === marker) {
        tr.delete(to, to + len);
        tr.delete(from - len, from);
      } else {
        tr.insertText(marker, to, to);
        tr.insertText(marker, from, from);
      }
      view.dispatch(tr);
    };

    const makeBold = () => {
      wrapUnwrap("**");
    };

    const makeItalic = () => {
      wrapUnwrap("*");
    };
javascript 提示点 prose-mirror

评论


答:

0赞 Tallboy 11/30/2023 #1

我是这样解决的......

    const wrapUnwrap = marker => {
      const { state, view, from, to, tr } = buildTr();
      const len = marker.length;

      // exit if nothing selected
      if (from === to) {
        return;
      }

      let textBefore = "";
      let textAfter = "";

      if (from - len >= 1) {
        textBefore = state.doc.textBetween(from - len, from);
      }
      if (to + len <= state.doc.content.size) {
        textAfter = state.doc.textBetween(to, to + len);
      }

      if (textBefore === marker && textAfter === marker) {
        tr.delete(to, to + len);
        tr.delete(from - len, from);
      } else {
        tr.insertText(marker, to, to);
        tr.insertText(marker, from, from);
      }
      view.dispatch(tr);
    };

    const makeBold = () => {
      wrapUnwrap("**");
    };

    const makeItalic = () => {
      wrapUnwrap("*");
    };