slate: Internal copy paste is broken

Version 0.19.16 was the last version where copy and pasting internally in the document worked as expected (keeping the formatting intact). The .fragment document is now null, and there is only a .html part, thus it falls back to onPasteText by the default core plugin. I suspect it has something to do with #716.

If you try copying and pasting the contents of http://slatejs.org/#/rich-text?_k=952y37, you see what I mean.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 1
  • Comments: 19 (11 by maintainers)

Most upvoted comments

There are a hosts of problems relating to copy/paste in Chrome and Safari and they stem from a single problem:

Doing

    const r = window.document.createRange()
    r.selectNodeContents(div)
    native.removeAllRanges()
    native.addRange(r)

when the div has a single child node, on copy the content of the child node is copied instead of the entire child node (as it happens in Firefox), i.e. Webkit will copy the “inner HTML” while Firefox will copy the “outer HTML”. What this means in practice is that the fragment data, which resides on the outer HTML, will be lost to Webkit in a host of situations, and it has to fall back to the HTML content, which is a single, unstyled span.

A secondary problem is that any trailing whitespace is also lost in the process, but this can be fixed with a white-space: pre-wrap on the temporary div that gets created to hold the copy data.

I’m not sure if this behavior is intended (or what spec governs it), but I have not found a way yet to make the selection take the “outer html” in this situation. Selection.selectAllChildren() is different from Range.selectNodeContents in subtle ways but exhibits the same essential problems.

There is of course the possibility of always ensuring we have at least two child nodes by inserting a dummy node, but it needs to have non-empty content (a zero width space perhaps), and pasting into external apps will introduce these unwelcome artifacts.

Alternatively, we can theoretically use clipboardData.setData('text/plain') and clipboardData.setData('text/html') on the copy event and eschew the div thing entirely.

I’m not sure if this is a separate issue or not but when copy/pasting paragraph with inlines from a “hanging selection”, the inlines don’t make it through: inline bug