react-native-rich-editor icon indicating copy to clipboard operation
react-native-rich-editor copied to clipboard

How to get selected text

Open sizhe-eb opened this issue 2 years ago • 6 comments

How can I get the selected text in the editor? I checed the code, it call document.getSelection(), how can I get it manually.

sizhe-eb avatar Mar 11 '22 08:03 sizhe-eb

Having the ability to get both the selected text, surrounding html and character range would be very helpful.

For example: <p>NORMAL TEXT. <b>BOLD TEXT.</b></p>

If we select "BOLD TEXT" in the editor, it would be awesome to have a method that could return the selected text and even more helpful if there was a method that could return <b>BOLD TEXT.</b>.

React Native Quill editor has the ability to return the selection range. ItsonSelectionChange method will return data like this: {"oldRange": {"index": 19, "length": 6}, "range": {"index": 18, "length": 7}, "source": "user"}

NicholasBoccuzzi avatar Apr 27 '22 14:04 NicholasBoccuzzi

Looking for something similar to get text selection.

cristianoccazinsp avatar Apr 28 '22 18:04 cristianoccazinsp

Having the ability to get both the selected text, surrounding html and character range would be very helpful.

For example: <p>NORMAL TEXT. <b>BOLD TEXT.</b></p>

If we select "BOLD TEXT" in the editor, it would be awesome to have a method that could return the selected text and even more helpful if there was a method that could return <b>BOLD TEXT.</b>.

React Native Quill editor has the ability to return the selection range. ItsonSelectionChange method will return data like this: {"oldRange": {"index": 19, "length": 6}, "range": {"index": 18, "length": 7}, "source": "user"}

Thanks for your comment, i'll try this

sizhe-eb avatar Apr 29 '22 00:04 sizhe-eb

Hi Here is my workaround

import React, { useRef } from 'react';
import { StyleSheet, View } from 'react-native';
import { actions, RichEditor, RichToolbar } from 'react-native-pell-rich-editor';

const RichTextInput: React.FC = () => {
  const richText = useRef<RichEditor | null>(null);

  // Call this method to inject script and get selected text
  const onInjectJavascript = () => {
    const script = `(function() {
      var value = window.getSelection().toString() || '';
      window.ReactNativeWebView.postMessage(JSON.stringify({ data: {type: 'SELECTION_CHANGE', value } }));
      void(0);
    })();`;
    richText.current?.injectJavascript(script);
  };

  // Callback function to get selected text
  const handleOnMessage = (event: { type: string; id: string; data?: any }) => {
    if (event?.data?.type === 'SELECTION_CHANGE') {
      const selected = event?.data?.value;
      console.log('Selected text', selected);
    }
  };

  return (
    <>
      <View style={styles.toolbarContainer}>
        <RichToolbar
          style={styles.toolBar}
          unselectedButtonStyle={styles.toolbarIcon}
          selectedButtonStyle={styles.toolbarIcon}
          editor={richText}
          actions={[actions.setBold, actions.setItalic, actions.setUnderline, actions.insertLink]}
        />
      </View>
      <View style={styles.editorContainer}>
        <RichEditor
          placeholder={'Enter a message'}
          ref={richText}
          onMessage={handleOnMessage}
          androidHardwareAccelerationDisabled={true}
        />
      </View>
    </>
  );
};

const styles = StyleSheet.create({
});

export default RichTextInput;

injectJavascript method does not exist in node_modules/react-native-pell-rich-editor/src/RichEditor.js and you have to add in manually Add these lines in RichEditor.js

injectJavascript(script) {
    return this.webviewBridge.injectJavaScript(script);
}

To add injectJavascript automatically you can use postinstall script in package json

package.json

...
"postinstall": "./update_modules.sh"

Create update_modules.sh and add these lines

sed -i -e "s/render() {/injectJavascript(script) {\n\\t\\treturn this.webviewBridge.injectJavaScript(script);\n\\t}\n\n\\trender() {/g" node_modules/react-native-pell-rich-editor/src/RichEditor.js
 sed -i -e "s/preCode: (/injectJavascript: (script: string) => void;\n\n\\tpreCode: (/g" node_modules/react-native-pell-rich-editor/index.d.ts

gevgasparyan avatar Jun 28 '22 13:06 gevgasparyan

Hi Here is my workaround

import React, { useRef } from 'react';
import { StyleSheet, View } from 'react-native';
import { actions, RichEditor, RichToolbar } from 'react-native-pell-rich-editor';

const RichTextInput: React.FC = () => {
  const richText = useRef<RichEditor | null>(null);

  // Call this method to inject script and get selected text
  const onInjectJavascript = () => {
    const script = `(function() {
      var value = window.getSelection().toString() || '';
      window.ReactNativeWebView.postMessage(JSON.stringify({ data: {type: 'SELECTION_CHANGE', value } }));
      void(0);
    })();`;
    richText.current?.injectJavascript(script);
  };

  // Callback function to get selected text
  const handleOnMessage = (event: { type: string; id: string; data?: any }) => {
    if (event?.data?.type === 'SELECTION_CHANGE') {
      const selected = event?.data?.value;
      console.log('Selected text', selected);
    }
  };

  return (
    <>
      <View style={styles.toolbarContainer}>
        <RichToolbar
          style={styles.toolBar}
          unselectedButtonStyle={styles.toolbarIcon}
          selectedButtonStyle={styles.toolbarIcon}
          editor={richText}
          actions={[actions.setBold, actions.setItalic, actions.setUnderline, actions.insertLink]}
        />
      </View>
      <View style={styles.editorContainer}>
        <RichEditor
          placeholder={'Enter a message'}
          ref={richText}
          onMessage={handleOnMessage}
          androidHardwareAccelerationDisabled={true}
        />
      </View>
    </>
  );
};

const styles = StyleSheet.create({
});

export default RichTextInput;

injectJavascript method does not exist in node_modules/react-native-pell-rich-editor/src/RichEditor.js and you have to add in manually Add these lines in RichEditor.js

injectJavascript(script) {
    return this.webviewBridge.injectJavaScript(script);
}

To add injectJavascript automatically you can use postinstall script in package json

package.json

...
"postinstall": "./update_modules.sh"

Create update_modules.sh and add these lines

sed -i -e "s/render() {/injectJavascript(script) {\n\\t\\treturn this.webviewBridge.injectJavaScript(script);\n\\t}\n\n\\trender() {/g" node_modules/react-native-pell-rich-editor/src/RichEditor.js
 sed -i -e "s/preCode: (/injectJavascript: (script: string) => void;\n\n\\tpreCode: (/g" node_modules/react-native-pell-rich-editor/index.d.ts

Hi @gevgasparyan , thanks for your solution! but I have some questions:

  • Where should I call onInjectJavascript?
  • If I added injectJavascript in manually, do I still need to do postinstall?

For now, I just call onInjectJavascript when I click link icon, but the event in handleOnMessage is undefined. Wish for your reply, thanks!

sizhe-eb avatar Jun 29 '22 01:06 sizhe-eb

Hi @sizhe-eb

  1. Do it when you want to get selected text e.g. when onInsertLink is called.
const insertLink = () => {
    const script = `(function() {
      var value = window.getSelection().toString() || '';
      window.ReactNativeWebView.postMessage(JSON.stringify({ data: {type: 'SELECTION_CHANGE', value } }));
      void(0);
    })();`;
    richText.current?.injectJavascript(script);
  };
  
<RichToolbar
    ...
    onInsertLink={insertLink}
  />

No if you added it manually there is no need to do postinstall

Can you please try to register toolbar like this. It may solve the undefined event issue

if (richText.current) {
      richText.current.registerToolbar(() => {});
    }

gevgasparyan avatar Jun 30 '22 16:06 gevgasparyan

thank you @gevgasparyan

vitorguima avatar Jan 05 '23 20:01 vitorguima

All the above solutions will only give selected text but will not return selected text with the html. I need both for edit hyper link. I have a hyperlink Google. Is there any way to get selected text with the html?

vijay-dadhich09 avatar Feb 16 '23 20:02 vijay-dadhich09

You don't need to access the webviewBridge since it is a "private" ref used by the lib. You can execute the same command using the commandDOM function.

BalogunofAfrica avatar Apr 03 '23 07:04 BalogunofAfrica