-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
Copy pathLexicalNormalization.ts
124 lines (110 loc) · 3.11 KB
/
LexicalNormalization.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {RangeSelection, TextNode} from '.';
import type {PointType} from './LexicalSelection';
import {$isElementNode, $isTextNode} from '.';
import {getActiveEditor} from './LexicalUpdates';
function $canSimpleTextNodesBeMerged(
node1: TextNode,
node2: TextNode,
): boolean {
const node1Mode = node1.__mode;
const node1Format = node1.__format;
const node1Style = node1.__style;
const node2Mode = node2.__mode;
const node2Format = node2.__format;
const node2Style = node2.__style;
return (
(node1Mode === null || node1Mode === node2Mode) &&
(node1Format === null || node1Format === node2Format) &&
(node1Style === null || node1Style === node2Style)
);
}
function $mergeTextNodes(node1: TextNode, node2: TextNode): TextNode {
const writableNode1 = node1.mergeWithSibling(node2);
const normalizedNodes = getActiveEditor()._normalizedNodes;
normalizedNodes.add(node1.__key);
normalizedNodes.add(node2.__key);
return writableNode1;
}
export function $normalizeTextNode(textNode: TextNode): void {
let node = textNode;
if (node.__text === '' && node.isSimpleText() && !node.isUnmergeable()) {
node.remove();
return;
}
// Backward
let previousNode;
while (
(previousNode = node.getPreviousSibling()) !== null &&
$isTextNode(previousNode) &&
previousNode.isSimpleText() &&
!previousNode.isUnmergeable()
) {
if (previousNode.__text === '') {
previousNode.remove();
} else if ($canSimpleTextNodesBeMerged(previousNode, node)) {
node = $mergeTextNodes(previousNode, node);
break;
} else {
break;
}
}
// Forward
let nextNode;
while (
(nextNode = node.getNextSibling()) !== null &&
$isTextNode(nextNode) &&
nextNode.isSimpleText() &&
!nextNode.isUnmergeable()
) {
if (nextNode.__text === '') {
nextNode.remove();
} else if ($canSimpleTextNodesBeMerged(node, nextNode)) {
node = $mergeTextNodes(node, nextNode);
break;
} else {
break;
}
}
}
export function $normalizeSelection(selection: RangeSelection): RangeSelection {
$normalizePoint(selection.anchor);
$normalizePoint(selection.focus);
return selection;
}
function $normalizePoint(point: PointType): void {
while (point.type === 'element') {
const node = point.getNode();
const offset = point.offset;
let nextNode;
let nextOffsetAtEnd;
if (offset === node.getChildrenSize()) {
nextNode = node.getChildAtIndex(offset - 1);
nextOffsetAtEnd = true;
} else {
nextNode = node.getChildAtIndex(offset);
nextOffsetAtEnd = false;
}
if ($isTextNode(nextNode)) {
point.set(
nextNode.__key,
nextOffsetAtEnd ? nextNode.getTextContentSize() : 0,
'text',
);
break;
} else if (!$isElementNode(nextNode)) {
break;
}
point.set(
nextNode.__key,
nextOffsetAtEnd ? nextNode.getChildrenSize() : 0,
'element',
);
}
}