1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-22 23:12:52 +02:00

fix selection marks

This commit is contained in:
Ian Storm Taylor
2016-08-29 18:30:06 -07:00
parent b0cf3d795f
commit 5b1793b116
5 changed files with 75 additions and 73 deletions

View File

@@ -1,42 +1,8 @@
import Operations from '../transforms/operations' import Operations from '../transforms/operations'
import Transforms from '../transforms' import Transforms from '../transforms'
import includes from 'lodash/includes'
import xor from 'lodash/xor'
import { List, Record } from 'immutable' 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. * Transform.
* *
@@ -53,9 +19,9 @@ class Transform {
constructor(properties) { constructor(properties) {
const { state } = properties const { state } = properties
this.initialState = state
this.state = state this.state = state
this.operations = [] this.operations = []
this.transforms = []
} }
/** /**
@@ -98,7 +64,7 @@ class Transform {
*/ */
apply(options = {}) { apply(options = {}) {
let { state, operations } = this let { initialState, state, operations } = this
let { history, selection } = state let { history, selection } = state
let { marks } = selection let { marks } = selection
let { undos, redos } = history let { undos, redos } = history
@@ -118,11 +84,11 @@ class Transform {
state = state.merge({ history }) state = state.merge({ history })
} }
// If there are cursor marks and they haven't changed, remove them. // Check whether to remove the cursor marks.
if (state.selection.marks && state.selection.marks == marks) { // if (options.snapshot !== false && initialState.selection.marks) {
selection = selection.merge({ marks: null }) // selection = selection.merge({ marks: null })
state = state.merge({ selection }) // state = state.merge({ selection })
} // }
// Apply the "isNative" flag, which is used to allow for natively-handled // Apply the "isNative" flag, which is used to allow for natively-handled
// content changes to skip rerendering the editor for performance. // content changes to skip rerendering the editor for performance.
@@ -140,35 +106,28 @@ class Transform {
*/ */
shouldSnapshot() { shouldSnapshot() {
const { state, transforms } = this const { state, operations } = this
const { history, selection } = state const { history, selection } = state
const { undos, redos } = history const { undos, redos } = history
const previous = undos.peek() 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 there isn't a previous state, snapshot.
if (!previous) return true if (!previous) return true
// If there is a previous state but the transforms are different, snapshot. // If the only operations applied are selection operations, don't snapshot.
const types = transforms.map(t => t.type) const onlySelections = operations.every(op => op.type == 'set_selection')
const prevTypes = previous.transforms.map(t => t.type) if (onlySelections) return false
const diff = xor(types, prevTypes)
if (diff.length) return true
// If the current transforms aren't one of the "combinable" types, snapshot. // If the current operations aren't one of the "combinable" types, snapshot.
const allCombinable = ( const onlyInsert = operations.every(op => op.type == 'insert_text')
transforms.every(t => t.type == 'insertText') || const onlyRemove = operations.every(op => op.type == 'remove_text')
transforms.every(t => t.type == 'deleteForward') || const onlyPrevInsert = previous.operations.every(op => op.type == 'insert_text')
transforms.every(t => t.type == 'deleteBackward') 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, snapshot.
return true
// Otherwise, don't snapshot.
return false
} }
/** /**
@@ -178,9 +137,9 @@ class Transform {
*/ */
snapshot() { snapshot() {
let { state, transforms, operations } = this let { initialState, operations } = this
let { document, selection } = state let { document, selection } = initialState
return { document, selection, transforms, operations } return { document, selection, operations }
} }
/** /**
@@ -261,13 +220,14 @@ class Transform {
Object.keys(Transforms).forEach((type) => { Object.keys(Transforms).forEach((type) => {
Transform.prototype[type] = function (...args) { Transform.prototype[type] = function (...args) {
this.transforms.push({ type, args })
return Transforms[type](this, ...args) return Transforms[type](this, ...args)
} }
}) })
/** /**
* Export. * Export.
*
* @type {Transform}
*/ */
export default Transform export default Transform

View File

@@ -15,13 +15,21 @@ export function addMark(transform, mark) {
const { state } = transform const { state } = transform
const { document, selection } = state const { document, selection } = state
if (selection.isCollapsed) { if (selection.isExpanded) {
const marks = document.getMarksAtRange(selection).add(mark) return transform.addMarkAtRange(selection, mark)
}
else if (selection.marks) {
const marks = selection.marks.add(mark)
const sel = selection.merge({ marks }) const sel = selection.merge({ marks })
return transform.setSelection(sel) 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 { state } = transform
const { document, selection } = state const { document, selection } = state
if (selection.isCollapsed) { if (selection.isExpanded) {
const marks = document.getMarksAtRange(selection).remove(mark) return transform.removeMarkAtRange(selection, mark)
}
else if (selection.marks) {
const marks = selection.marks.remove(mark)
const sel = selection.merge({ marks }) const sel = selection.merge({ marks })
return transform.setSelection(sel) 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)
}
} }
/** /**

View File

@@ -416,10 +416,15 @@ export function moveToRangeOf(transform, start, end) {
export function setSelection(transform, properties) { export function setSelection(transform, properties) {
properties = Normalize.selectionProperties(properties) properties = Normalize.selectionProperties(properties)
const { state } = transform const { state } = transform
const { selection } = state const { selection } = state
const prevProps = {} const prevProps = {}
if (properties.marks == selection.marks) {
properties.marks = null
}
for (const k in properties) { for (const k in properties) {
prevProps[k] = selection[k] prevProps[k] = selection[k]
} }

View File

@@ -1,6 +1,15 @@
import Debug from 'debug'
import uid from '../utils/uid' 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`. * 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) { function addMark(state, operation) {
debug('add_mark', operation)
const { path, offset, length, mark } = operation const { path, offset, length, mark } = operation
let { document } = state let { document } = state
let node = document.assertPath(path) let node = document.assertPath(path)
@@ -28,6 +38,7 @@ function addMark(state, operation) {
*/ */
function insertNode(state, operation) { function insertNode(state, operation) {
debug('insert_node', operation)
const { path, index, node } = operation const { path, index, node } = operation
let { document } = state let { document } = state
let parent = document.assertPath(path) let parent = document.assertPath(path)
@@ -48,6 +59,7 @@ function insertNode(state, operation) {
*/ */
function insertText(state, operation) { function insertText(state, operation) {
debug('insert_text', operation)
const { path, offset, text, marks } = operation const { path, offset, text, marks } = operation
let { document } = state let { document } = state
let node = document.assertPath(path) let node = document.assertPath(path)
@@ -66,6 +78,7 @@ function insertText(state, operation) {
*/ */
function moveNode(state, operation) { function moveNode(state, operation) {
debug('move_node', operation)
const { path, newPath, newIndex } = operation const { path, newPath, newIndex } = operation
let { document } = state let { document } = state
const node = document.assertPath(path) const node = document.assertPath(path)
@@ -94,6 +107,7 @@ function moveNode(state, operation) {
*/ */
function removeMark(state, operation) { function removeMark(state, operation) {
debug('remove_mark', operation)
const { path, offset, length, mark } = operation const { path, offset, length, mark } = operation
let { document } = state let { document } = state
let node = document.assertPath(path) let node = document.assertPath(path)
@@ -112,6 +126,7 @@ function removeMark(state, operation) {
*/ */
function removeNode(state, operation) { function removeNode(state, operation) {
debug('remove_node', operation)
const { path } = operation const { path } = operation
let { document } = state let { document } = state
const node = document.assertPath(path) const node = document.assertPath(path)
@@ -134,6 +149,7 @@ function removeNode(state, operation) {
*/ */
function removeText(state, operation) { function removeText(state, operation) {
debug('remove_text', operation)
const { path, offset, length } = operation const { path, offset, length } = operation
let { document } = state let { document } = state
let node = document.assertPath(path) let node = document.assertPath(path)
@@ -153,6 +169,7 @@ function removeText(state, operation) {
*/ */
function setMark(state, operation) { function setMark(state, operation) {
debug('set_mark', operation)
const { path, offset, length, mark, properties } = operation const { path, offset, length, mark, properties } = operation
let { document } = state let { document } = state
let node = document.assertPath(path) let node = document.assertPath(path)
@@ -171,6 +188,7 @@ function setMark(state, operation) {
*/ */
function setNode(state, operation) { function setNode(state, operation) {
debug('set_node', operation)
const { path, properties } = operation const { path, properties } = operation
let { document } = state let { document } = state
let node = document.assertPath(path) let node = document.assertPath(path)
@@ -190,6 +208,7 @@ function setNode(state, operation) {
*/ */
function setSelection(state, operation) { function setSelection(state, operation) {
debug('set_selection', operation)
let { properties } = operation let { properties } = operation
let { selection } = state let { selection } = state
selection = selection.merge(properties) selection = selection.merge(properties)
@@ -206,6 +225,7 @@ function setSelection(state, operation) {
*/ */
function splitNode(state, operation) { function splitNode(state, operation) {
debug('split_node', operation)
const { path, offset } = operation const { path, offset } = operation
let { document } = state let { document } = state
let node = document.assertPath(path) let node = document.assertPath(path)

View File

@@ -188,12 +188,13 @@ function selectionProperties(value = {}) {
switch (typeOf(value)) { switch (typeOf(value)) {
case 'object': { 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.anchorKey != null) ret.anchorKey = value.anchorKey
if (value.anchorOffset != null) ret.anchorOffset = value.anchorOffset if (value.anchorOffset != null) ret.anchorOffset = value.anchorOffset
if (value.focusKey != null) ret.focusKey = value.focusKey if (value.focusKey != null) ret.focusKey = value.focusKey
if (value.focusOffset != null) ret.focusOffset = value.focusOffset 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 break
} }
default: { default: {