From bdb8234b8ddf443f3fcd890f1fcc2b672ef21b58 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Wed, 6 Sep 2017 11:54:33 -0700 Subject: [PATCH] fix pasting plain text, fixes #586 fixes #795 (#1059) --- src/changes/at-current-range.js | 7 ++++--- src/plugins/core.js | 21 ++++++++++++++------- src/serializers/plain.js | 33 ++++++++++++++------------------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/changes/at-current-range.js b/src/changes/at-current-range.js index a385ee279..a60c3b7e6 100644 --- a/src/changes/at-current-range.js +++ b/src/changes/at-current-range.js @@ -117,13 +117,14 @@ Changes.insertFragment = (change, fragment) => { let { state } = change let { document, selection } = state - const { startText, endText } = state + const { startText, endText, startInline } = state const lastText = fragment.getLastText() const lastInline = fragment.getClosestInline(lastText.key) const keys = document.getTexts().map(text => text.key) const isAppending = ( - selection.hasEdgeAtEndOf(endText) || - selection.hasEdgeAtStartOf(startText) + !startInline || + selection.hasEdgeAtStartOf(startText) || + selection.hasEdgeAtEndOf(endText) ) change.insertFragmentAtRange(selection, fragment) diff --git a/src/plugins/core.js b/src/plugins/core.js index 17535f1f2..0c746eced 100644 --- a/src/plugins/core.js +++ b/src/plugins/core.js @@ -1,13 +1,14 @@ import Base64 from '../serializers/base-64' -import Content from '../components/content' import Block from '../models/block' import Character from '../models/character' -import Inline from '../models/inline' +import Content from '../components/content' import Debug from 'debug' -import getPoint from '../utils/get-point' +import Inline from '../models/inline' +import Plain from '../serializers/plain' import Placeholder from '../components/placeholder' import React from 'react' +import getPoint from '../utils/get-point' import getWindow from 'get-window' import findDOMNode from '../utils/find-dom-node' import { IS_CHROME, IS_MAC, IS_SAFARI } from '../constants/environment' @@ -840,10 +841,16 @@ function Plugin(options = {}) { function onPasteText(e, data, change) { debug('onPasteText', { data }) - data.text.split('\n').forEach((line, i) => { - if (i > 0) change.splitBlock() - change.insertText(line) - }) + + const { state } = change + const { document, selection, startBlock } = state + if (startBlock.isVoid) return + + const { text } = data + const defaultBlock = { type: startBlock.type, data: startBlock.data } + const defaultMarks = document.getMarksAtRange(selection.collapseToStart()) + const fragment = Plain.deserialize(text, { defaultBlock, defaultMarks }).document + change.insertFragment(fragment) } /** diff --git a/src/serializers/plain.js b/src/serializers/plain.js index d750b283f..3425ab2d2 100644 --- a/src/serializers/plain.js +++ b/src/serializers/plain.js @@ -7,25 +7,32 @@ import Raw from '../serializers/raw' * @param {String} string * @param {Object} options * @property {Boolean} toRaw + * @property {String|Object} defaultBlock + * @property {Array} defaultMarks * @return {State} */ function deserialize(string, options = {}) { + const { + defaultBlock = { type: 'line' }, + defaultMarks = [], + } = options + const raw = { kind: 'state', document: { kind: 'document', nodes: string.split('\n').map((line) => { return { + ...defaultBlock, kind: 'block', - type: 'line', nodes: [ { kind: 'text', ranges: [ { text: line, - marks: [], + marks: defaultMarks, } ] } @@ -38,21 +45,6 @@ function deserialize(string, options = {}) { return options.toRaw ? raw : Raw.deserialize(raw) } -/** - * Checks if the block has other blocks nested within - * @param {Node} node - * @return {Boolean} -*/ - -function hasNestedBlocks(node) { - return node && - node.nodes && - node.nodes.first() && - node.nodes.first().kind && - node.nodes.first().kind == 'block' -} - - /** * Serialize a `state` to plain text. * @@ -75,9 +67,12 @@ function serialize(state) { */ function serializeNode(node) { - if (node.kind == 'document' || (node.kind == 'block' && hasNestedBlocks(node))) { + if ( + (node.kind == 'document') || + (node.kind == 'block' && node.nodes.size > 0 && node.nodes.first().kind == 'block') + ) { return node.nodes - .map(childNode => serializeNode(childNode)) + .map(n => serializeNode(n)) .filter(text => text != '') .join('\n') } else {