From 5b1793b11656f0d3122e4f612b00519a139ef9dd Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Mon, 29 Aug 2016 18:30:06 -0700 Subject: [PATCH] fix selection marks --- lib/models/transform.js | 90 +++++++++--------------------- lib/transforms/at-current-range.js | 28 ++++++++-- lib/transforms/on-selection.js | 5 ++ lib/transforms/operations.js | 20 +++++++ lib/utils/normalize.js | 5 +- 5 files changed, 75 insertions(+), 73 deletions(-) diff --git a/lib/models/transform.js b/lib/models/transform.js index a8809672e..ba662afd3 100644 --- a/lib/models/transform.js +++ b/lib/models/transform.js @@ -1,42 +1,8 @@ import Operations from '../transforms/operations' import Transforms from '../transforms' -import includes from 'lodash/includes' -import xor from 'lodash/xor' import { List, Record } from 'immutable' -/** - * Selection transforms. - */ - -const SELECTION_TRANSFORMS = [ - 'blur', - 'collapseToAnchor', - 'collapseToEnd', - 'collapseToEndOf', - 'collapseToFocus', - 'collapseToStart', - 'collapseToStartOf', - 'extendBackward', - 'extendForward', - 'extendToEndOf', - 'extendToStartOf', - 'focus', - 'moveBackward', - 'moveForward', - 'moveToOffsets', - 'moveToRangeOf', - 'collapseToEndOfNextBlock', - 'collapseToEndOfNextText', - 'collapseToEndOfPreviousBlock', - 'collapseToEndOfPreviousText', - 'collapseToStartOfNextBlock', - 'collapseToStartOfNextText', - 'collapseToStartOfPreviousBlock', - 'collapseToStartOfPreviousText', - 'moveTo', -] - /** * Transform. * @@ -53,9 +19,9 @@ class Transform { constructor(properties) { const { state } = properties + this.initialState = state this.state = state this.operations = [] - this.transforms = [] } /** @@ -98,7 +64,7 @@ class Transform { */ apply(options = {}) { - let { state, operations } = this + let { initialState, state, operations } = this let { history, selection } = state let { marks } = selection let { undos, redos } = history @@ -118,11 +84,11 @@ class Transform { state = state.merge({ history }) } - // If there are cursor marks and they haven't changed, remove them. - if (state.selection.marks && state.selection.marks == marks) { - selection = selection.merge({ marks: null }) - state = state.merge({ selection }) - } + // Check whether to remove the cursor marks. + // if (options.snapshot !== false && initialState.selection.marks) { + // selection = selection.merge({ marks: null }) + // state = state.merge({ selection }) + // } // Apply the "isNative" flag, which is used to allow for natively-handled // content changes to skip rerendering the editor for performance. @@ -140,35 +106,28 @@ class Transform { */ shouldSnapshot() { - const { state, transforms } = this + const { state, operations } = this const { history, selection } = state const { undos, redos } = history const previous = undos.peek() - // If the only transforms applied are selection transforms, don't snapshot. - const onlySelections = transforms.every(t => includes(SELECTION_TRANSFORMS, t.type)) - if (onlySelections) return false - // If there isn't a previous state, snapshot. if (!previous) return true - // If there is a previous state but the transforms are different, snapshot. - const types = transforms.map(t => t.type) - const prevTypes = previous.transforms.map(t => t.type) - const diff = xor(types, prevTypes) - if (diff.length) return true + // If the only operations applied are selection operations, don't snapshot. + const onlySelections = operations.every(op => op.type == 'set_selection') + if (onlySelections) return false - // If the current transforms aren't one of the "combinable" types, snapshot. - const allCombinable = ( - transforms.every(t => t.type == 'insertText') || - transforms.every(t => t.type == 'deleteForward') || - transforms.every(t => t.type == 'deleteBackward') - ) + // If the current operations aren't one of the "combinable" types, snapshot. + const onlyInsert = operations.every(op => op.type == 'insert_text') + const onlyRemove = operations.every(op => op.type == 'remove_text') + const onlyPrevInsert = previous.operations.every(op => op.type == 'insert_text') + const onlyPrevRemove = previous.operations.every(op => op.type == 'remove_text') + if (onlyInsert && onlyPrevInsert) return false + if (onlyRemove && onlyPrevRemove) return false - if (!allCombinable) return true - - // Otherwise, don't snapshot. - return false + // Otherwise, snapshot. + return true } /** @@ -178,9 +137,9 @@ class Transform { */ snapshot() { - let { state, transforms, operations } = this - let { document, selection } = state - return { document, selection, transforms, operations } + let { initialState, operations } = this + let { document, selection } = initialState + return { document, selection, operations } } /** @@ -261,13 +220,14 @@ class Transform { Object.keys(Transforms).forEach((type) => { Transform.prototype[type] = function (...args) { - this.transforms.push({ type, args }) return Transforms[type](this, ...args) } }) /** * Export. + * + * @type {Transform} */ export default Transform diff --git a/lib/transforms/at-current-range.js b/lib/transforms/at-current-range.js index 0d9da7ef0..1a02dfe3a 100644 --- a/lib/transforms/at-current-range.js +++ b/lib/transforms/at-current-range.js @@ -15,13 +15,21 @@ export function addMark(transform, mark) { const { state } = transform const { document, selection } = state - if (selection.isCollapsed) { - const marks = document.getMarksAtRange(selection).add(mark) + if (selection.isExpanded) { + return transform.addMarkAtRange(selection, mark) + } + + else if (selection.marks) { + const marks = selection.marks.add(mark) const sel = selection.merge({ marks }) return transform.setSelection(sel) } - return transform.addMarkAtRange(selection, mark) + else { + const marks = document.getMarksAtRange(selection).add(mark) + const sel = selection.merge({ marks }) + return transform.setSelection(sel) + } } /** @@ -445,13 +453,21 @@ export function removeMark(transform, mark) { const { state } = transform const { document, selection } = state - if (selection.isCollapsed) { - const marks = document.getMarksAtRange(selection).remove(mark) + if (selection.isExpanded) { + return transform.removeMarkAtRange(selection, mark) + } + + else if (selection.marks) { + const marks = selection.marks.remove(mark) const sel = selection.merge({ marks }) return transform.setSelection(sel) } - return transform.removeMarkAtRange(selection, mark) + else { + const marks = document.getMarksAtRange(selection).remove(mark) + const sel = selection.merge({ marks }) + return transform.setSelection(sel) + } } /** diff --git a/lib/transforms/on-selection.js b/lib/transforms/on-selection.js index c64d5f704..a9651bfab 100644 --- a/lib/transforms/on-selection.js +++ b/lib/transforms/on-selection.js @@ -416,10 +416,15 @@ export function moveToRangeOf(transform, start, end) { export function setSelection(transform, properties) { properties = Normalize.selectionProperties(properties) + const { state } = transform const { selection } = state const prevProps = {} + if (properties.marks == selection.marks) { + properties.marks = null + } + for (const k in properties) { prevProps[k] = selection[k] } diff --git a/lib/transforms/operations.js b/lib/transforms/operations.js index 972b1fe89..9a84cf51f 100644 --- a/lib/transforms/operations.js +++ b/lib/transforms/operations.js @@ -1,6 +1,15 @@ +import Debug from 'debug' import uid from '../utils/uid' +/** + * Debug. + * + * @type {Function} + */ + +const debug = Debug('slate:operation') + /** * Add mark to text at `offset` and `length` in node by `path`. * @@ -10,6 +19,7 @@ import uid from '../utils/uid' */ function addMark(state, operation) { + debug('add_mark', operation) const { path, offset, length, mark } = operation let { document } = state let node = document.assertPath(path) @@ -28,6 +38,7 @@ function addMark(state, operation) { */ function insertNode(state, operation) { + debug('insert_node', operation) const { path, index, node } = operation let { document } = state let parent = document.assertPath(path) @@ -48,6 +59,7 @@ function insertNode(state, operation) { */ function insertText(state, operation) { + debug('insert_text', operation) const { path, offset, text, marks } = operation let { document } = state let node = document.assertPath(path) @@ -66,6 +78,7 @@ function insertText(state, operation) { */ function moveNode(state, operation) { + debug('move_node', operation) const { path, newPath, newIndex } = operation let { document } = state const node = document.assertPath(path) @@ -94,6 +107,7 @@ function moveNode(state, operation) { */ function removeMark(state, operation) { + debug('remove_mark', operation) const { path, offset, length, mark } = operation let { document } = state let node = document.assertPath(path) @@ -112,6 +126,7 @@ function removeMark(state, operation) { */ function removeNode(state, operation) { + debug('remove_node', operation) const { path } = operation let { document } = state const node = document.assertPath(path) @@ -134,6 +149,7 @@ function removeNode(state, operation) { */ function removeText(state, operation) { + debug('remove_text', operation) const { path, offset, length } = operation let { document } = state let node = document.assertPath(path) @@ -153,6 +169,7 @@ function removeText(state, operation) { */ function setMark(state, operation) { + debug('set_mark', operation) const { path, offset, length, mark, properties } = operation let { document } = state let node = document.assertPath(path) @@ -171,6 +188,7 @@ function setMark(state, operation) { */ function setNode(state, operation) { + debug('set_node', operation) const { path, properties } = operation let { document } = state let node = document.assertPath(path) @@ -190,6 +208,7 @@ function setNode(state, operation) { */ function setSelection(state, operation) { + debug('set_selection', operation) let { properties } = operation let { selection } = state selection = selection.merge(properties) @@ -206,6 +225,7 @@ function setSelection(state, operation) { */ function splitNode(state, operation) { + debug('split_node', operation) const { path, offset } = operation let { document } = state let node = document.assertPath(path) diff --git a/lib/utils/normalize.js b/lib/utils/normalize.js index e6ef36c8d..a4b83e344 100644 --- a/lib/utils/normalize.js +++ b/lib/utils/normalize.js @@ -188,12 +188,13 @@ function selectionProperties(value = {}) { switch (typeOf(value)) { case 'object': { - if (value.isFocused != null) ret.isFocused = !!value.isFocused - if (value.isBackward != null) ret.isBackward = !!value.isBackward if (value.anchorKey != null) ret.anchorKey = value.anchorKey if (value.anchorOffset != null) ret.anchorOffset = value.anchorOffset if (value.focusKey != null) ret.focusKey = value.focusKey if (value.focusOffset != null) ret.focusOffset = value.focusOffset + if (value.isBackward != null) ret.isBackward = !!value.isBackward + if (value.isFocused != null) ret.isFocused = !!value.isFocused + if (value.marks !== undefined) ret.marks = value.marks break } default: {