mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-21 13:51:59 +02:00
Avoid transforming dirty paths if the op won't touch them (#4735)
* Avoid transforming dirty paths if the op won't touch them * Avoid the loop entirely if op doesn't affect path
This commit is contained in:
parent
ccafb6982f
commit
e5427dddfc
.changeset
packages/slate/src
5
.changeset/two-coins-enjoy.md
Normal file
5
.changeset/two-coins-enjoy.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'slate': patch
|
||||
---
|
||||
|
||||
Optimize path transforms during normalization
|
@ -13,7 +13,7 @@ import {
|
||||
Text,
|
||||
Transforms,
|
||||
} from './'
|
||||
import { DIRTY_PATHS, FLUSHING } from './utils/weak-maps'
|
||||
import { DIRTY_PATHS, DIRTY_PATH_KEYS, FLUSHING } from './utils/weak-maps'
|
||||
|
||||
/**
|
||||
* Create a new Slate `Editor` object.
|
||||
@ -42,33 +42,41 @@ export const createEditor = (): Editor => {
|
||||
RangeRef.transform(ref, op)
|
||||
}
|
||||
|
||||
const set = new Set()
|
||||
const dirtyPaths: Path[] = []
|
||||
const oldDirtyPaths = DIRTY_PATHS.get(editor) || []
|
||||
const oldDirtyPathKeys = DIRTY_PATH_KEYS.get(editor) || new Set()
|
||||
let dirtyPaths: Path[]
|
||||
let dirtyPathKeys: Set<string>
|
||||
|
||||
const add = (path: Path | null) => {
|
||||
if (path) {
|
||||
const key = path.join(',')
|
||||
|
||||
if (!set.has(key)) {
|
||||
set.add(key)
|
||||
if (!dirtyPathKeys.has(key)) {
|
||||
dirtyPathKeys.add(key)
|
||||
dirtyPaths.push(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const oldDirtyPaths = DIRTY_PATHS.get(editor) || []
|
||||
const newDirtyPaths = getDirtyPaths(op)
|
||||
|
||||
for (const path of oldDirtyPaths) {
|
||||
const newPath = Path.transform(path, op)
|
||||
add(newPath)
|
||||
if (Path.operationCanTransformPath(op)) {
|
||||
dirtyPaths = []
|
||||
dirtyPathKeys = new Set()
|
||||
for (const path of oldDirtyPaths) {
|
||||
const newPath = Path.transform(path, op)
|
||||
add(newPath)
|
||||
}
|
||||
} else {
|
||||
dirtyPaths = oldDirtyPaths
|
||||
dirtyPathKeys = oldDirtyPathKeys
|
||||
}
|
||||
|
||||
const newDirtyPaths = getDirtyPaths(op)
|
||||
for (const path of newDirtyPaths) {
|
||||
add(path)
|
||||
}
|
||||
|
||||
DIRTY_PATHS.set(editor, dirtyPaths)
|
||||
DIRTY_PATH_KEYS.set(editor, dirtyPathKeys)
|
||||
Transforms.transform(editor, op)
|
||||
editor.operations.push(op)
|
||||
Editor.normalize(editor)
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
} from '..'
|
||||
import {
|
||||
DIRTY_PATHS,
|
||||
DIRTY_PATH_KEYS,
|
||||
NORMALIZING,
|
||||
PATH_REFS,
|
||||
POINT_REFS,
|
||||
@ -979,13 +980,26 @@ export const Editor: EditorInterface = {
|
||||
return DIRTY_PATHS.get(editor) || []
|
||||
}
|
||||
|
||||
const getDirtyPathKeys = (editor: Editor) => {
|
||||
return DIRTY_PATH_KEYS.get(editor) || new Set()
|
||||
}
|
||||
|
||||
const popDirtyPath = (editor: Editor): Path => {
|
||||
const path = getDirtyPaths(editor).pop()!
|
||||
const key = path.join(',')
|
||||
getDirtyPathKeys(editor).delete(key)
|
||||
return path
|
||||
}
|
||||
|
||||
if (!Editor.isNormalizing(editor)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (force) {
|
||||
const allPaths = Array.from(Node.nodes(editor), ([, p]) => p)
|
||||
const allPathKeys = new Set(allPaths.map(p => p.join(',')))
|
||||
DIRTY_PATHS.set(editor, allPaths)
|
||||
DIRTY_PATH_KEYS.set(editor, allPathKeys)
|
||||
}
|
||||
|
||||
if (getDirtyPaths(editor).length === 0) {
|
||||
@ -1026,7 +1040,7 @@ export const Editor: EditorInterface = {
|
||||
`)
|
||||
}
|
||||
|
||||
const dirtyPath = getDirtyPaths(editor).pop()!
|
||||
const dirtyPath = popDirtyPath(editor)
|
||||
|
||||
// If the node doesn't exist in the tree, it does not need to be normalized.
|
||||
if (Node.has(editor, dirtyPath)) {
|
||||
|
@ -34,6 +34,7 @@ export interface PathInterface {
|
||||
}
|
||||
) => Path[]
|
||||
next: (path: Path) => Path
|
||||
operationCanTransformPath: (operation: Operation) => boolean
|
||||
parent: (path: Path) => Path
|
||||
previous: (path: Path) => Path
|
||||
relative: (path: Path, ancestor: Path) => Path
|
||||
@ -291,6 +292,26 @@ export const Path: PathInterface = {
|
||||
return path.slice(0, -1).concat(last + 1)
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether this operation can affect paths or not. Used as an
|
||||
* optimization when updating dirty paths during normalization
|
||||
*
|
||||
* NOTE: This *must* be kept in sync with the implementation of 'transform'
|
||||
* below
|
||||
*/
|
||||
operationCanTransformPath(operation: Operation): boolean {
|
||||
switch (operation.type) {
|
||||
case 'insert_node':
|
||||
case 'remove_node':
|
||||
case 'merge_node':
|
||||
case 'split_node':
|
||||
case 'move_node':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a path, return a new path referring to the parent node above it.
|
||||
*/
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Editor, Path, PathRef, PointRef, RangeRef } from '..'
|
||||
|
||||
export const DIRTY_PATHS: WeakMap<Editor, Path[]> = new WeakMap()
|
||||
export const DIRTY_PATH_KEYS: WeakMap<Editor, Set<string>> = new WeakMap()
|
||||
export const FLUSHING: WeakMap<Editor, boolean> = new WeakMap()
|
||||
export const NORMALIZING: WeakMap<Editor, boolean> = new WeakMap()
|
||||
export const PATH_REFS: WeakMap<Editor, Set<PathRef>> = new WeakMap()
|
||||
|
Loading…
x
Reference in New Issue
Block a user