Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy/paste between editors #787

Open
bryanph opened this issue Nov 16, 2016 · 15 comments
Open

Copy/paste between editors #787

bryanph opened this issue Nov 16, 2016 · 15 comments

Comments

@bryanph
Copy link

@bryanph bryanph commented Nov 16, 2016

How can I make sure custom blocks and entities are preserved if I copy from one Draft editor to another? Hence, I want the custom block/entity to be recreated in the new editor.

Take for example the entity example in the repo, when copying from one draft instance to another, the entities are not copied along, just the raw text. The same happens with custom blocks, for example in the media example

@bryanph
Copy link
Author

@bryanph bryanph commented Nov 16, 2016

I think one way to implement this is to set the required data for the blocks and entities in the ClipboardData object when the user triggers a copy event. Then on a paste event you check if the required data is set in the ClipboardData and if so, use that data to paste the entities and custom blocks into the second editor (by cloning the entities and inserting the blocks).

What do you think?

@StorytellerCZ
Copy link

@StorytellerCZ StorytellerCZ commented Nov 27, 2016

Yes, but won't that interfere with copying into non-draft editors?

@bryanph
Copy link
Author

@bryanph bryanph commented Nov 27, 2016

@StorytellerCZ It seems like you can just set arbitrary data in the DataTransfer object keyed by a "type", see https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData . No idea if this is an accepted practice though.

In the example below I do that. One thing to be cautious of though is that every time a user copies editor data, you must serialize the content state which is quite costly. No

<html>
    <script>
    function addExtraData(e) {
        var clipboardData = e.clipboardData;

        var someObj = {
            "test": { "test": "test" }
        }

        var selection = window.getSelection()

        console.log("called addExtraData")
        console.log(selection)

        e.clipboardData.setData('text/plain', selection)
        e.clipboardData.setData('test', JSON.stringify(someObj))

        e.preventDefault()
    }

    function getExtraData(e) {
        var data = e.clipboardData.getData('text/plain')
        var data2 = e.clipboardData.getData('test')
        console.log("called getExtraData")
        console.log(data)
        console.log(JSON.parse(data2))
    }

    document.addEventListener('copy', addExtraData);
    document.addEventListener('paste', getExtraData);

    </script>
    <body>
        <p>
            Text to Copy
        </p>
        <textarea rows="4" cols="50"></textarea>
    </body>
</html>

@mitermayer mitermayer self-assigned this Dec 16, 2016
@mitermayer
Copy link
Contributor

@mitermayer mitermayer commented Dec 16, 2016

We are currently working on a solution for this issue

@christophepas
Copy link

@christophepas christophepas commented Jan 13, 2017

Hey @mitermayer ! Glad to know this is wip, have you any update on a solution for this ?

Apart from mentions this is also a problem for nested lists, and in general an onCopy method added to the Editor API could help solve these issues.

@trevtrich
Copy link
Contributor

@trevtrich trevtrich commented Aug 30, 2017

@mitermayer has there been any movement on this? We could really use this functionality. Right now we're considering forking and working on a solution. Would you guys be open to a PR if we come up with something we're happy with?

Assuming dev on this has stopped and we start implementing a solution, would appreciate any guidance on major problems you ran into that we might hit as well.

@flarnie
Copy link
Contributor

@flarnie flarnie commented Sep 29, 2017

Just an update - I don't expect any support for this in the near future. It would be an interesting long term goal but we have shifted to have internal folks work on some other fixes and features for Draft.

@mzedeler
Copy link

@mzedeler mzedeler commented Mar 5, 2018

I am going to need this and expect to be working on a solution within a month or two.

@thibaudcolas
Copy link
Contributor

@thibaudcolas thibaudcolas commented Apr 18, 2018

I have been able to make this work a bit better by leveraging the internal Draft.js editor clipboard, at least if the copy-paste happens between editors that are on the same page (quite a common circumstance in a CMS that uses Draft.js).

The basic idea is:

  1. When editors mount (componentDidMount), register a ref to their DraftEditor component in a global object (eg. window.myEditorRefs). Associate the ref with the editor's getEditorKey (internal method related to the editorKey prop) – make sure these are unique between all editors if you set it manually.
  2. When editors unmount, un-register the ref.
  3. In handlePastedText, check whether the paste contains an editor key (data-editor) like Draft.js does internally:
    // If the editorKey is present in the pasted HTML, it should be safe to
    // assume this is an internal paste.
    html.indexOf(editor.getEditorKey()) !== -1 ||
    // The copy may have been made within a single block, in which case the
    // editor key won't be part of the paste. In this case, just check
    // whether the pasted text matches the internal clipboard.
    (textBlocks.length === 1 &&
    internalClipboard.size === 1 &&
    internalClipboard.first().getText() === text)
  4. If it does, find the corresponding editor in your registry of editor refs.
  5. Get the clipboard data from its internal clipboard, and insert it as a fragment.

I only put this together in half an hour so might be overlooking something (and the code is horrible): springload/draftail#148


Of course this would be much easier if there was a way to directly set the editor's clipboard on the copy data (

function editOnCopy(editor: DraftEditor, e: SyntheticClipboardEvent<>): void {
var editorState = editor._latestEditorState;
var selection = editorState.getSelection();
// No selection, so there's nothing to copy.
if (selection.isCollapsed()) {
e.preventDefault();
return;
}
editor.setClipboard(getFragmentFromSelection(editor._latestEditorState));
}
), and then retrieve it in the paste (like @bryanph shows above, except with Draft.js data). That said I'm not that familiar with clipboard data handling in browsers so don't know exactly if that would actually work.


I'll try this further over the next few days and report back with more findings.

@mzedeler
Copy link

@mzedeler mzedeler commented Apr 19, 2018

I've done some investigation and can see that I am forced to write my own replacement of the copy/paste-behavior, because I have extra data that isn't stored in any of the internal Draft data structures.

My plan is to ensure that Draft never tries to use the internal clipboard and then populate the normal clipboard with HTML fragments that have been enriched with the data that I keep outside the normal Draft data structures.

I think it could be a worthy long term goal to try to replace Drafts internal clipboard with a behavior where the data on the normal clipboard is sufficient for Draft when pasting. By doing this, we can remove a source of unpredictable behavior in Draft.

@thibaudcolas
Copy link
Contributor

@thibaudcolas thibaudcolas commented Jun 10, 2018

I've worked on this further since #787 (comment) and managed to fix the issue in my editor. Also submitted a similar fix for Draft.js itself over at #1784.

If you don't want to wait for that PR to be merged, the details on how to fix this in your own project are at the end of #1784.

@dav-sap
Copy link

@dav-sap dav-sap commented Nov 11, 2020

Is thing something that might be fixed soon? Its a common use case

@mzedeler
Copy link

@mzedeler mzedeler commented Nov 11, 2020

I think it is a relevant comment, @dav-sap, but the development of Draft.js is progressing extremely slowly. As you can see, the proposed fix by Thibaud has been open for more than two years.

@gorillatron
Copy link

@gorillatron gorillatron commented Sep 19, 2021

Currently building a rich text editor with alot of entity usage and copy pasting between documents is a huge use case. Any progress on getting this to prod?

@bryanph
Copy link
Author

@bryanph bryanph commented Sep 19, 2021

@gorillatron Honestly, I moved away from draft-js a long time ago and I feel there's no reason to start using this in a new project, there are much better alternatives out there. This project has been in maintenance mode for a long time now. Look into slate or prosemirror for better approaches to the rich text editing problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants