1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-22 15:02:51 +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 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

View File

@@ -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)
}
}
/**

View File

@@ -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]
}

View File

@@ -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)

View File

@@ -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: {