简体   繁体   English

使 document.execCommand('insertText', false, 'message') 与 Draftjs 一起工作?

[英]make document.execCommand('insertText', false, 'message') work with draftjs?

I'm working on an application which needs to insert text into a contenteditable="true" div (a Draftjs based textfield to be precise).我正在开发一个需要将文本插入contenteditable="true" div( Draftjs基于Draftjs的文本字段)的应用程序。

Now I am aware that Draft.js uses react and that it should be used that way, but in this case, the application already exists and this is a third party electron app that works with it.现在我知道 Draft.js 使用 react 并且应该以这种方式使用它,但在这种情况下,该应用程序已经存在并且这是一个与它配合使用的第三方电子应用程序。

I'm working on in-line notification replying on macOS, so I need that reply text to be pasted inside the draftJS field, however, when I do so using:我正在 macOS 上处理在线通知回复,因此我需要将该回复文本粘贴到 DraftJS 字段中,但是,当我这样做时,使用:

document.querySelector('div[contenteditable="true"]').focus();
document.execCommand('insertText', false, 'message');

It throws an error:它抛出一个错误: 错误图像

I was able to make it work using:我能够使用以下方法使其工作:

const event = document.createEvent('TextEvent');
event.initTextEvent('textInput', true, true, window, 'message', 0, locale);

but this API is deprecated and doesn't work properly if the message contains an emoji.但如果消息包含表情符号,则此 API 已弃用且无法正常工作。

Is there any way to do this that doesn't cause an error?有没有办法做到这一点,不会导致错误? I found out that the new API that is supposed to replace initTextEvent is just new Event() (see docs ), but I can't find out if it supports textInput events.我发现应该替换 initTextEvent 的新 API 只是new Event() (请参阅文档),但我不知道它是否支持 textInput 事件。

To play around with it you can just go to https://draftjs.org/ and play with it in chrome dev tools.要使用它,您可以访问https://draftjs.org/并在 chrome 开发工具中使用它。

I would really appreciate some help here as I don't know what to do to make it work anymore.我真的很感激这里的一些帮助,因为我不知道该怎么做才能让它继续工作。 Also, I know people are a fan of jquery, but I'd prefer a native js solution (although any solution is welcome).另外,我知道人们是 jquery 的粉丝,但我更喜欢原生 js 解决方案(尽管欢迎任何解决方案)。

edit:编辑:

Please note: I'm not using react, the input field I want to modify (draftjs) is using react and I want to input text into it using native js.请注意:我没有使用 react,我要修改的输入字段 (draftjs) 使用的是 react,我想使用原生 js 向其中输入文本。

edit 2:编辑2:

For anyone else coming across this issue, I wanted to insert text into the Facebook messenger text field (which uses Draftjs).对于遇到此问题的其他人,我想将文本插入 Facebook 信使文本字段(使用 Draftjs)。

I managed to find a working workaround.我设法找到了一个可行的解决方法。 It does use the deprecated API ( event.initTextEvent ), but it's the only way that I've found that works, even with emoji.它确实使用了已弃用的 API ( event.initTextEvent ),但这是我发现的唯一有效方法,即使使用表情符号也是如此。 Please do post an answer if you have a better solution to this.如果您对此有更好的解决方案,请发布答案。 It works like this:它是这样工作的:

async function sendReply(message: string): Promise<void> {
       const inputField = document.querySelector('[contenteditable="true"]') as HTMLElement;
       if (inputField) {
               const previousMessage = inputField.textContent;
               // Send message
               inputField.focus();
               await insertMessageText(message, inputField);
               (await elementReady('._30yy._38lh._39bl')).click();
               // Restore (possible) previous message
               if (previousMessage) {
                       insertMessageText(previousMessage, inputField);
               }
       }
}

function insertMessageText(text: string, inputField: HTMLElement): void {
       // Workaround: insert placeholder value to get execCommand working
       if (!inputField.textContent) {
               const event = document.createEvent('TextEvent');
               event.initTextEvent('textInput', true, true, window, '_', 0, '');
               inputField.dispatchEvent(event);
       }

       document.execCommand('selectAll', false, undefined);
       document.execCommand('insertText', false, text);
}

This is typescript code, so you might want to change it up to use js.这是打字稿代码,因此您可能需要将其更改为使用 js。

It works by inserting a placeholder value inside the textField using event.initTextEvent , and then replacing that text with:它的工作原理是使用event.initTextEvent在 textField 中插入一个占位符值,然后将该文本替换为:

document.execCommand('selectAll', false, undefined);
document.execCommand('insertText', false, 'text');

tested in Chrome: Version 71.0.3578.98在 Chrome 中测试:版本 71.0.3578.98

Although the question was asked a long ago and @JoniVR found a workaround, this may help someone else.尽管很久以前就有人问过这个问题并且@JoniVR 找到了解决方法,但这可能对其他人有所帮助。

I was also having a similar problem while working on an extension.我在开发扩展时也遇到了类似的问题。 I also tried the method document.execCommand('insertText', false, text).我还尝试了方法 document.execCommand('insertText', false, text)。 It worked on LinkedIn but not on Facebook.它适用于 LinkedIn,但不适用于 Facebook。 It was inserting text in the wrong node.它在错误的节点中插入文本。 Although document.execCommand API works in some places, it's obsolete now.尽管document.execCommand API 在某些地方有效,但它现在已经过时了。

For Facebook and any other sites using drafjs editor, We need to dispatch a paste event using dataTransfer andclipBoardEvent APIs to make draftjs think that the text is pasted and process accordingly.对于 Facebook 和任何其他使用 drafjs 编辑器的站点,我们需要使用dataTransferclipBoardEvent API 调度一个 paste 事件,使 Draftjs 认为文本已粘贴并进行相应的处理。

const dataTransfer = new DataTransfer();

function dispatchPaste(target, text) {
  // this may be 'text/html' if it's required
  dataTransfer.setData('text/plain', text);

  target.dispatchEvent(
    new ClipboardEvent('paste', {
      clipboardData: dataTransfer,

      // need these for the event to reach Draft paste handler
      bubbles: true,
      cancelable: true
    })
  );

  // clear DataTransfer Data
  dataTransfer.clearData();
}

Check this link in case more info needed.如果需要更多信息,请检查此链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM