From 07788eb2d945684ac8ca49b3136e37bdd17c016f Mon Sep 17 00:00:00 2001 From: Blake Embrey Date: Wed, 21 Feb 2018 12:38:56 -0800 Subject: [PATCH] Replace zero width blocks with newline before copy (#1644) * Replace zero width blocks with newline before copy * Fix linting issue * Fixing linting again, sorry Github --- packages/slate-react/src/components/leaf.js | 10 ++++++++-- packages/slate-react/src/utils/clone-fragment.js | 11 ++++++----- packages/slate-react/src/utils/find-point.js | 4 +++- .../test/rendering/fixtures/custom-block-void.js | 2 +- .../test/rendering/fixtures/custom-inline-multiple.js | 8 ++++---- .../test/rendering/fixtures/custom-inline-void.js | 6 +++--- .../test/rendering/fixtures/custom-inline.js | 4 ++-- .../rendering/fixtures/default-block-with-inline.js | 4 ++-- .../rendering/fixtures/empty-block-with-inline.js | 2 +- .../test/rendering/fixtures/empty-block.js | 2 +- .../rendering/fixtures/readonly-custom-inline-void.js | 4 ++-- 11 files changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/slate-react/src/components/leaf.js b/packages/slate-react/src/components/leaf.js index 2246f25c7..98df01b4b 100644 --- a/packages/slate-react/src/components/leaf.js +++ b/packages/slate-react/src/components/leaf.js @@ -116,14 +116,20 @@ class Leaf extends React.Component { renderText() { const { block, node, parent, text, index, leaves } = this.props + // COMPAT: If the text is empty and the only child, we need to render a + // line break when copying and pasting to support expected plain text. + if (text == '' && parent.kind == 'block' && parent.text == '') { + return {'\u200B'} + } + // COMPAT: Render text inside void nodes with a zero-width space. // So the node can contain selection but the text is not visible. - if (parent.isVoid) return {'\u200B'} + if (parent.isVoid) return {'\u200B'} // COMPAT: If the text is empty, it's because it's on the edge of an inline // void node, so we render a zero-width space so that the selection can be // inserted next to it still. - if (text == '') return {'\u200B'} + if (text == '') return {'\u200B'} // COMPAT: Browsers will collapse trailing new lines at the end of blocks, // so we need to add an extra trailing new lines to prevent that. diff --git a/packages/slate-react/src/utils/clone-fragment.js b/packages/slate-react/src/utils/clone-fragment.js index 64ae94fa4..2af482d91 100644 --- a/packages/slate-react/src/utils/clone-fragment.js +++ b/packages/slate-react/src/utils/clone-fragment.js @@ -1,7 +1,8 @@ import Base64 from 'slate-base64-serializer' -import findDOMNode from './find-dom-node' import getWindow from 'get-window' +import findDOMNode from './find-dom-node' +import { ZERO_WIDTH_SELECTOR, ZERO_WIDTH_ATTRIBUTE } from './find-point' import { IS_CHROME, IS_SAFARI } from '../constants/environment' /** @@ -62,10 +63,10 @@ function cloneFragment(event, value, fragment = value.fragment) { // Remove any zero-width space spans from the cloned DOM so that they don't // show up elsewhere when pasted. - const zws = [].slice.call( - contents.querySelectorAll('[data-slate-zero-width]') - ) - zws.forEach(zw => zw.parentNode.removeChild(zw)) + ;[].slice.call(contents.querySelectorAll(ZERO_WIDTH_SELECTOR)).forEach(zw => { + const isNewline = zw.getAttribute(ZERO_WIDTH_ATTRIBUTE) === 'n' + zw.textContent = isNewline ? '\n' : '' + }) // COMPAT: In Chrome and Safari, if the last element in the selection to // copy has `contenteditable="false"` the copy will fail, and nothing will diff --git a/packages/slate-react/src/utils/find-point.js b/packages/slate-react/src/utils/find-point.js index 3e8f24a79..75a27cf8a 100644 --- a/packages/slate-react/src/utils/find-point.js +++ b/packages/slate-react/src/utils/find-point.js @@ -8,6 +8,8 @@ import OffsetKey from './offset-key' * @type {String} */ +export const ZERO_WIDTH_ATTRIBUTE = 'data-slate-zero-width' +export const ZERO_WIDTH_SELECTOR = `[${ZERO_WIDTH_ATTRIBUTE}]` const OFFSET_KEY_ATTRIBUTE = 'data-offset-key' const RANGE_SELECTOR = `[${OFFSET_KEY_ATTRIBUTE}]` const TEXT_SELECTOR = `[data-key]` @@ -60,7 +62,7 @@ function findPoint(nativeNode, nativeOffset, value) { // from the offset to account for the zero-width space character. if ( offset == node.textContent.length && - parentNode.hasAttribute('data-slate-zero-width') + parentNode.hasAttribute(ZERO_WIDTH_ATTRIBUTE) ) { offset-- } diff --git a/packages/slate-react/test/rendering/fixtures/custom-block-void.js b/packages/slate-react/test/rendering/fixtures/custom-block-void.js index 6b70cfd77..cce0b0a4a 100644 --- a/packages/slate-react/test/rendering/fixtures/custom-block-void.js +++ b/packages/slate-react/test/rendering/fixtures/custom-block-void.js @@ -35,7 +35,7 @@ export const output = `
- +
diff --git a/packages/slate-react/test/rendering/fixtures/custom-inline-multiple.js b/packages/slate-react/test/rendering/fixtures/custom-inline-multiple.js index 57ae30128..08ddfb081 100644 --- a/packages/slate-react/test/rendering/fixtures/custom-inline-multiple.js +++ b/packages/slate-react/test/rendering/fixtures/custom-inline-multiple.js @@ -39,7 +39,7 @@ export const output = `
- + @@ -49,7 +49,7 @@ export const output = ` - + @@ -59,7 +59,7 @@ export const output = ` - + @@ -69,7 +69,7 @@ export const output = ` - +
diff --git a/packages/slate-react/test/rendering/fixtures/custom-inline-void.js b/packages/slate-react/test/rendering/fixtures/custom-inline-void.js index 7b36e0b18..89b7d5329 100644 --- a/packages/slate-react/test/rendering/fixtures/custom-inline-void.js +++ b/packages/slate-react/test/rendering/fixtures/custom-inline-void.js @@ -33,14 +33,14 @@ export const output = `
- + - + @@ -50,7 +50,7 @@ export const output = ` - +
diff --git a/packages/slate-react/test/rendering/fixtures/custom-inline.js b/packages/slate-react/test/rendering/fixtures/custom-inline.js index e35458dbe..3883844af 100644 --- a/packages/slate-react/test/rendering/fixtures/custom-inline.js +++ b/packages/slate-react/test/rendering/fixtures/custom-inline.js @@ -37,7 +37,7 @@ export const output = `
- + @@ -47,7 +47,7 @@ export const output = ` - +
diff --git a/packages/slate-react/test/rendering/fixtures/default-block-with-inline.js b/packages/slate-react/test/rendering/fixtures/default-block-with-inline.js index ad33b8cef..744d927e1 100644 --- a/packages/slate-react/test/rendering/fixtures/default-block-with-inline.js +++ b/packages/slate-react/test/rendering/fixtures/default-block-with-inline.js @@ -19,7 +19,7 @@ export const output = `
- + @@ -29,7 +29,7 @@ export const output = ` - +
diff --git a/packages/slate-react/test/rendering/fixtures/empty-block-with-inline.js b/packages/slate-react/test/rendering/fixtures/empty-block-with-inline.js index f2059e272..2fb474e01 100644 --- a/packages/slate-react/test/rendering/fixtures/empty-block-with-inline.js +++ b/packages/slate-react/test/rendering/fixtures/empty-block-with-inline.js @@ -19,7 +19,7 @@ export const output = `
- \u200B + \u200B
diff --git a/packages/slate-react/test/rendering/fixtures/empty-block.js b/packages/slate-react/test/rendering/fixtures/empty-block.js index 084bdb5a4..376bc092b 100644 --- a/packages/slate-react/test/rendering/fixtures/empty-block.js +++ b/packages/slate-react/test/rendering/fixtures/empty-block.js @@ -17,7 +17,7 @@ export const output = `
- \u200B + \u200B
diff --git a/packages/slate-react/test/rendering/fixtures/readonly-custom-inline-void.js b/packages/slate-react/test/rendering/fixtures/readonly-custom-inline-void.js index 13cbaf971..8d59a8d69 100644 --- a/packages/slate-react/test/rendering/fixtures/readonly-custom-inline-void.js +++ b/packages/slate-react/test/rendering/fixtures/readonly-custom-inline-void.js @@ -34,7 +34,7 @@ export const output = `
- + @@ -44,7 +44,7 @@ export const output = ` - +