如何自动将选择范围扩展到Draft.js中的整个链接文本?

时间:2019-06-25 23:56:40

标签: reactjs draftjs

我正在使用Draft.js开发一个富文本编辑器(太好了!)。以下代码(允许用户编辑链接)在逻辑上可以正常工作,但我对用户体验感到不满意。

如果用户选择链接的一部分并运行此代码,则此代码会将该链接分为多个链接,这不是用户想要的。

例如,如果将“购买此书”阶段与URL-A链接,并且用户选择“购买此书”并将其更改为URL-B,则该部分将与URL-B链接,但是“书”仍与URL-A链接。

理想情况下,当用户选择链接文本的一部分时,我想自动将选择范围扩展到整个链接,然后执行此代码。

但是,我无法弄清楚该怎么做(将选择范围扩展到整个链接)。

editLink = () => {
    const { editorState } = this.state;
    const selection = editorState.getSelection();
    if (selection.isCollapsed()) {
      return;
    }

    let url = ''; // default
    const content = editorState.getCurrentContent();
    const startKey = selection.getStartKey();
    const startOffset = selection.getStartOffset();
    const blockWithLinkAtBeginning = content.getBlockForKey(startKey);
    const linkKey = blockWithLinkAtBeginning.getEntityAt(startOffset);
    if (linkKey) {
      const linkInstance = content.getEntity(linkKey);
      url = linkInstance.getData().url;
    }

    let link = window.prompt("Paste the link", url);
    if (!link) {
      console.log("removing link");
      const newEditorState = RichUtils.toggleLink(editorState, selection, null);
      this.setState({ editorState: newEditorState });
      return;
    }
    console.log("adding a link", link);
    const contentWithEntity = content.createEntity('LINK', 'MUTABLE', { url: link });
    const entityKey = contentWithEntity.getLastCreatedEntityKey();
    const newEditorState = EditorState.set(editorState, { currentContent: contentWithEntity });
    const yetNewEditorState = RichUtils.toggleLink(newEditorState, newEditorState.getSelection(), entityKey);

    this.setState({ editorState: yetNewEditorState} );
  }

非常感谢您的帮助或建议。

1 个答案:

答案 0 :(得分:0)

有两种方法可以做到这一点。第一个可能是您要尝试的操作-在当前链接的顶部应用一个新链接,从而覆盖它。这不是最好的方法,但是可以做到。

第二个更简单。在ContentState对象中,有一个方法replaceEntityData()。因此,您可以像这样实现它:

editLink = () => {
    const { editorState } = this.state;
    const selection = editorState.getSelection();
    if (selection.isCollapsed()) {
      return;
    }

    let url = ''; // default
    const content = editorState.getCurrentContent();
    const startKey = selection.getStartKey();
    const startOffset = selection.getStartOffset();
    const block = content.getBlockForKey(startKey);
    const linkKey = block.getEntityAt(startOffset);

    let link = window.prompt("Paste the link", url);
    if (!link) { //REMOVING LINK
        var contentWithRemovedLink = content;
        block.findEntityRanges(charData => { //You need to use block.findEntityRanges() API to get the whole range of link

            const entityKey = charData.getEntity();
            if (!entityKey) return false;
            return entityKey === linkKey //Need to return TRUE only for your specific link. 
        }, (start, end) => {
                const entitySelection = new SelectionState({
                    anchorKey: block.getKey(),  //You already have the block key
                    focusKey: block.getKey(),
                    anchorOffset: start,   //Just use the start/end provided by the API
                    focusOffset: end })
                contentWithRemovedLink = Modifier.applyEntity(content, entitySelection, null)

            return;
        })

        const newEditorState = EditorState.set(
            editorState, { currentContent: contentWithRemovedLink });
        return;
    }
    console.log("adding a link", link);

    //CHANGING LINK
    const contentWithUpdatedLink = content.replaceEntityData(linkKey, { url: link });
    const newEditorState = EditorState.set(editorState, { currentContent: contentWithUpdatedLink });
    //Now do as you please.
  }

删除链接:

ContentBlock api上,有一种称为findEntityRanges()的方法。该函数有两个参数:

  1. (char: CharacterMetadata) => boolean:characterMetadata对象的过滤器功能(每个连续的ENTITY + INLINE_STYLE组合都有一个唯一的CharacterMetatdata对象。您可以从此处通过characterMetadata.getEntity()进入实体。)如果此函数执行为TRUE,则将执行(2)。
  2. (start: number, end: number) => void。这使您可以访问执行TRUE的每个特定字符范围的开始和结束偏移量。现在,您可以开始和结束任何操作。

之后,您可以将NULL实体与包含整个链接的新SelectionState一起应用。这将删除链接实体。

更改链接:

您已经拥有linkKey。只需调用content.replaceEntityData(linkKey, {url: "MY NEW URL"})即可使用新的URL生成新的ContentState。此处定义的API:https://draftjs.org/docs/api-reference-content-state#replaceentitydata