zenoamaro / react-quill

A Quill component for React.
https://zenoamaro.github.io/react-quill
MIT License
6.77k stars 922 forks source link

How to keep parent tag information after copying a portion of the inner text? #577

Closed DLMartin- closed 4 years ago

DLMartin- commented 4 years ago

I have defined a blot for a custom tag, <YUM>.

It works great when I paste in the whole thing, but if I copy some text from the middle of a <YUM> element and paste it somewhere else, the tag is not carried over (only the formatting).

Is there a way to keep the copied texts surrounding element(s)? For example, if I were to have this in the DOM: <em><strong><YUM>This is here</YUM> and it cannot be stopped.</strong></em> And I were to highlight and copy is is her, when I paste it, I would expect it to be wrapped up like this: <em><strong><YUM>is is her</YUM></strong></em>, instead of <span>is is her</span>, or at least <YUM>is is her</YUM>.

Here's my blot:

let Inline = Quill.import('blots/inline');
class YumBlot extends Inline {
  static create(value: { url: any }) {
    let node = super.create();
    node.setAttribute('style', 'font-size:150%; color: purple');
    node.setAttribute('src', value.url);
    return node;
  }

  static value(node: { getAttribute: (arg0: string) => any }) {
    return {
      alt: node.getAttribute('alt'),
      url: node.getAttribute('src'),
    };
  }
}

YumBlot.blotName = 'yEmp';
YumBlot.tagName = 'YUM';
YumBlot.className = 'YUMCLASS';
Quill.register('formats/em', YumBlot);

And I've set my editor up to give me a ref so I can set some sample text, as well as poke around for some information.

let Delta = Quill.import('delta');
const sampleData = `<em><strong><YUM>This is here</YUM> and it cannot be stopped.</strong></em>`;

export const RichTextEditor: React.FC = () => {
  const quillRef = React.useRef<ReactQuill | null>(null);

  const measuredRef = React.useCallback<any>((node) => {
    if (node !== null) {
      quillRef.current = node;

      //Add a matcher for the <YUM> tag
      quillRef
        .current!.getEditor()
        .clipboard.addMatcher('YUM', function(node, delta) {
          console.log(delta);
          return delta.compose(
            new Delta().retain(delta.length(), {yEmp: true})
          );
        });

        //Set the editor to the HTML string provided
        quillRef.current!.getEditor().clipboard.dangerouslyPasteHTML(sampleData);
    }
  }, []);

  return (
    <>
      <ReactQuill ref={measuredRef} />
      <button
        onClick={(_) => {
          if (quillRef.current) {
            console.log('Its here');
            quillRef.current.getEditor().insertText(0, 'Hello!');
            quillRef.current.getEditor().formatText(0, 4, 'yEmp', true);
          }
        }}
      />
    </>
  );
};

React-Quill version

alexkrolick commented 4 years ago

Is this also a problem when you use native Quill without React? Might be better to ask over on the parent repo because I think it has more to do with the parsing behavior than the React integration.

DLMartin- commented 4 years ago

I cross-posted in the Quill github repo, nobody has responded yet but I did make a discovery. If I create a custom clipboard and override the onPaste method with something simple (like a console.log), it works as I'd expect it to normally work.

var Clipboard = Quill.import('modules/clipboard');

class SampleClipboard extends Clipboard {
  onPaste(e) {
    if (e.defaultPrevented || !this.quill.isEnabled()) return;
  }
}

Quill.register('modules/clipboard', SampleClipboard, true);

It's interesting that Quills default behavior strips all formatting out, unless you copy the entire line.