slate-angular 19.0.0 → 19.1.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/editable/editable.component.d.ts +1 -5
- package/components/string/default-string.component.d.ts +1 -1
- package/fesm2022/slate-angular.mjs +461 -949
- package/fesm2022/slate-angular.mjs.map +1 -1
- package/package.json +7 -5
- package/plugins/angular-editor.d.ts +54 -122
- package/plugins/with-dom.d.ts +68 -0
- package/utils/block-card.d.ts +1 -1
- package/utils/dom.d.ts +3 -63
- package/utils/index.d.ts +1 -2
- package/utils/weak-maps.d.ts +1 -30
- package/utils/constants.d.ts +0 -1
- package/utils/key.d.ts +0 -11
- package/utils/lines.d.ts +0 -14
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Editor,
|
|
1
|
+
import { Editor, Range, Element, Transforms, Text as Text$1, Node, Path } from 'slate';
|
|
2
|
+
import { EDITOR_TO_ELEMENT, NODE_TO_ELEMENT, DOMEditor, normalizeDOMPoint, isDOMSelection, IS_CHROME as IS_CHROME$1, hasShadowRoot, isDOMElement, NODE_TO_PARENT, NODE_TO_INDEX, isDOMNode, withDOM, NODE_TO_KEY, ELEMENT_TO_NODE, getDefaultView, EDITOR_TO_WINDOW, IS_READ_ONLY, EDITOR_TO_ON_CHANGE, IS_FOCUSED, TRIPLE_CLICK, isPlainTextOnlyPaste } from 'slate-dom';
|
|
2
3
|
import { isKeyHotkey } from 'is-hotkey';
|
|
3
4
|
import * as i0 from '@angular/core';
|
|
4
5
|
import { TemplateRef, ViewChild, ChangeDetectionStrategy, Component, InjectionToken, ComponentRef, IterableDiffers, inject, ElementRef, ChangeDetectorRef, Input, Directive, HostBinding, ViewContainerRef, forwardRef, Inject, NgModule } from '@angular/core';
|
|
@@ -9,258 +10,6 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
|
9
10
|
import { HistoryEditor } from 'slate-history';
|
|
10
11
|
import { CommonModule } from '@angular/common';
|
|
11
12
|
|
|
12
|
-
/**
|
|
13
|
-
* Two weak maps that allow us rebuild a path given a node. They are populated
|
|
14
|
-
* at render time such that after a render occurs we can always backtrack.
|
|
15
|
-
*/
|
|
16
|
-
const EDITOR_TO_WINDOW = new WeakMap();
|
|
17
|
-
const NODE_TO_INDEX = new WeakMap();
|
|
18
|
-
const NODE_TO_PARENT = new WeakMap();
|
|
19
|
-
/**
|
|
20
|
-
* Weak maps that allow us to go between Slate nodes and DOM nodes. These
|
|
21
|
-
* are used to resolve DOM event-related logic into Slate actions.
|
|
22
|
-
*/
|
|
23
|
-
const EDITOR_TO_ELEMENT = new WeakMap();
|
|
24
|
-
const EDITOR_TO_PLACEHOLDER = new WeakMap();
|
|
25
|
-
const ELEMENT_TO_NODE = new WeakMap();
|
|
26
|
-
// Deprecated
|
|
27
|
-
const KEY_TO_ELEMENT = new WeakMap();
|
|
28
|
-
const NODE_TO_ELEMENT = new WeakMap();
|
|
29
|
-
const NODE_TO_KEY = new WeakMap();
|
|
30
|
-
/**
|
|
31
|
-
* Weak maps for storing editor-related state.
|
|
32
|
-
*/
|
|
33
|
-
const IS_READONLY = new WeakMap();
|
|
34
|
-
const IS_FOCUSED = new WeakMap();
|
|
35
|
-
const IS_DRAGGING = new WeakMap();
|
|
36
|
-
const IS_CLICKING = new WeakMap();
|
|
37
|
-
/**
|
|
38
|
-
* Weak map for associating the context `onChange` context with the plugin.
|
|
39
|
-
*/
|
|
40
|
-
const EDITOR_TO_ON_CHANGE = new WeakMap();
|
|
41
|
-
// export const NODE_TO_VIEWNODE = new WeakMap<Node, ViewNode>();
|
|
42
|
-
/**
|
|
43
|
-
* Symbols.
|
|
44
|
-
*/
|
|
45
|
-
const PLACEHOLDER_SYMBOL = Symbol('placeholder');
|
|
46
|
-
/**
|
|
47
|
-
* Weak map for associating the html element with the component.
|
|
48
|
-
*/
|
|
49
|
-
const ELEMENT_TO_COMPONENT = new WeakMap();
|
|
50
|
-
const EDITOR_TO_AFTER_VIEW_INIT_QUEUE = new WeakMap();
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Types.
|
|
54
|
-
*/
|
|
55
|
-
// COMPAT: This is required to prevent TypeScript aliases from doing some very
|
|
56
|
-
// weird things for Slate's types with the same name as globals. (2019/11/27)
|
|
57
|
-
// https://github.com/microsoft/TypeScript/issues/35002
|
|
58
|
-
var DOMNode = globalThis.Node;
|
|
59
|
-
var DOMComment = globalThis.Comment;
|
|
60
|
-
var DOMElement = globalThis.Element;
|
|
61
|
-
var DOMText = globalThis.Text;
|
|
62
|
-
var DOMRange = globalThis.Range;
|
|
63
|
-
var DOMSelection = globalThis.Selection;
|
|
64
|
-
var DOMStaticRange = globalThis.StaticRange;
|
|
65
|
-
/**
|
|
66
|
-
* Returns the host window of a DOM node
|
|
67
|
-
*/
|
|
68
|
-
const getDefaultView = (value) => {
|
|
69
|
-
return (value && value.ownerDocument && value.ownerDocument.defaultView) || null;
|
|
70
|
-
};
|
|
71
|
-
/**
|
|
72
|
-
* Check if a DOM node is a comment node.
|
|
73
|
-
*/
|
|
74
|
-
const isDOMComment = (value) => {
|
|
75
|
-
return isDOMNode(value) && value.nodeType === 8;
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Check if a DOM node is an element node.
|
|
79
|
-
*/
|
|
80
|
-
const isDOMElement = (value) => {
|
|
81
|
-
return isDOMNode(value) && value.nodeType === 1;
|
|
82
|
-
};
|
|
83
|
-
/**
|
|
84
|
-
* Check if a value is a DOM node.
|
|
85
|
-
*/
|
|
86
|
-
const isDOMNode = (value) => {
|
|
87
|
-
const window = getDefaultView(value);
|
|
88
|
-
return !!window && value instanceof window.Node;
|
|
89
|
-
};
|
|
90
|
-
/**
|
|
91
|
-
* Check if a value is a DOM selection.
|
|
92
|
-
*/
|
|
93
|
-
const isDOMSelection = (value) => {
|
|
94
|
-
const window = value && value.anchorNode && getDefaultView(value.anchorNode);
|
|
95
|
-
return !!window && value instanceof window.Selection;
|
|
96
|
-
};
|
|
97
|
-
/**
|
|
98
|
-
* Check if a DOM node is an element node.
|
|
99
|
-
*/
|
|
100
|
-
const isDOMText = (value) => {
|
|
101
|
-
return isDOMNode(value) && value.nodeType === 3;
|
|
102
|
-
};
|
|
103
|
-
/**
|
|
104
|
-
* Checks whether a paste event is a plaintext-only event.
|
|
105
|
-
*/
|
|
106
|
-
const isPlainTextOnlyPaste = (event) => {
|
|
107
|
-
return event.clipboardData && event.clipboardData.getData('text/plain') !== '' && event.clipboardData.types.length === 1;
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
* Normalize a DOM point so that it always refers to a text node.
|
|
111
|
-
*/
|
|
112
|
-
const normalizeDOMPoint = (domPoint) => {
|
|
113
|
-
let [node, offset] = domPoint;
|
|
114
|
-
// If it's an element node, its offset refers to the index of its children
|
|
115
|
-
// including comment nodes, so try to find the right text child node.
|
|
116
|
-
if (isDOMElement(node) && node.childNodes.length) {
|
|
117
|
-
let isLast = offset === node.childNodes.length;
|
|
118
|
-
let index = isLast ? offset - 1 : offset;
|
|
119
|
-
[node, index] = getEditableChildAndIndex(node, index, isLast ? 'backward' : 'forward');
|
|
120
|
-
// If the editable child found is in front of input offset, we instead seek to its end
|
|
121
|
-
isLast = index < offset;
|
|
122
|
-
// If the node has children, traverse until we have a leaf node. Leaf nodes
|
|
123
|
-
// can be either text nodes, or other void DOM nodes.
|
|
124
|
-
while (isDOMElement(node) && node.childNodes.length) {
|
|
125
|
-
const i = isLast ? node.childNodes.length - 1 : 0;
|
|
126
|
-
node = getEditableChild(node, i, isLast ? 'backward' : 'forward');
|
|
127
|
-
}
|
|
128
|
-
// Determine the new offset inside the text node.
|
|
129
|
-
offset = isLast && node.textContent != null ? node.textContent.length : 0;
|
|
130
|
-
}
|
|
131
|
-
// Return the node and offset.
|
|
132
|
-
return [node, offset];
|
|
133
|
-
};
|
|
134
|
-
/**
|
|
135
|
-
* Determines wether the active element is nested within a shadowRoot
|
|
136
|
-
*/
|
|
137
|
-
const hasShadowRoot = () => {
|
|
138
|
-
return !!(window.document.activeElement && window.document.activeElement.shadowRoot);
|
|
139
|
-
};
|
|
140
|
-
/**
|
|
141
|
-
* Get the nearest editable child and index at `index` in a `parent`, preferring
|
|
142
|
-
* `direction`.
|
|
143
|
-
*/
|
|
144
|
-
const getEditableChildAndIndex = (parent, index, direction) => {
|
|
145
|
-
const { childNodes } = parent;
|
|
146
|
-
let child = childNodes[index];
|
|
147
|
-
let i = index;
|
|
148
|
-
let triedForward = false;
|
|
149
|
-
let triedBackward = false;
|
|
150
|
-
// While the child is a comment node, or an element node with no children,
|
|
151
|
-
// keep iterating to find a sibling non-void, non-comment node.
|
|
152
|
-
while (isDOMComment(child) ||
|
|
153
|
-
(isDOMElement(child) && child.childNodes.length === 0) ||
|
|
154
|
-
(isDOMElement(child) && child.getAttribute('contenteditable') === 'false')) {
|
|
155
|
-
if (triedForward && triedBackward) {
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
if (i >= childNodes.length) {
|
|
159
|
-
triedForward = true;
|
|
160
|
-
i = index - 1;
|
|
161
|
-
direction = 'backward';
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
if (i < 0) {
|
|
165
|
-
triedBackward = true;
|
|
166
|
-
i = index + 1;
|
|
167
|
-
direction = 'forward';
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
child = childNodes[i];
|
|
171
|
-
index = i;
|
|
172
|
-
i += direction === 'forward' ? 1 : -1;
|
|
173
|
-
}
|
|
174
|
-
return [child, index];
|
|
175
|
-
};
|
|
176
|
-
/**
|
|
177
|
-
* Get the nearest editable child at `index` in a `parent`, preferring
|
|
178
|
-
* `direction`.
|
|
179
|
-
*/
|
|
180
|
-
const getEditableChild = (parent, index, direction) => {
|
|
181
|
-
const [child] = getEditableChildAndIndex(parent, index, direction);
|
|
182
|
-
return child;
|
|
183
|
-
};
|
|
184
|
-
/**
|
|
185
|
-
* Get a plaintext representation of the content of a node, accounting for block
|
|
186
|
-
* elements which get a newline appended.
|
|
187
|
-
*
|
|
188
|
-
* The domNode must be attached to the DOM.
|
|
189
|
-
*/
|
|
190
|
-
const getPlainText = (domNode) => {
|
|
191
|
-
let text = '';
|
|
192
|
-
if (isDOMText(domNode) && domNode.nodeValue) {
|
|
193
|
-
return domNode.nodeValue;
|
|
194
|
-
}
|
|
195
|
-
if (isDOMElement(domNode)) {
|
|
196
|
-
for (const childNode of Array.from(domNode.childNodes)) {
|
|
197
|
-
text += getPlainText(childNode);
|
|
198
|
-
}
|
|
199
|
-
const display = getComputedStyle(domNode).getPropertyValue('display');
|
|
200
|
-
if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {
|
|
201
|
-
text += '\n';
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return text;
|
|
205
|
-
};
|
|
206
|
-
const SlateFragmentAttributeKey = 'data-slate-angular-fragment';
|
|
207
|
-
/**
|
|
208
|
-
* Get x-slate-fragment attribute from data-slate-angular-fragment
|
|
209
|
-
*/
|
|
210
|
-
const catchSlateFragment = /data-slate-angular-fragment="(.+?)"/m;
|
|
211
|
-
const getSlateFragmentAttribute = (htmlData) => {
|
|
212
|
-
const [, fragment] = htmlData.match(catchSlateFragment) || [];
|
|
213
|
-
return fragment;
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* An auto-incrementing identifier for keys.
|
|
218
|
-
*/
|
|
219
|
-
let n = 0;
|
|
220
|
-
/**
|
|
221
|
-
* A class that keeps track of a key string. We use a full class here because we
|
|
222
|
-
* want to be able to use them as keys in `WeakMap` objects.
|
|
223
|
-
*/
|
|
224
|
-
class Key {
|
|
225
|
-
constructor() {
|
|
226
|
-
this.id = `${n++}`;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const IS_IOS = typeof navigator !== 'undefined' &&
|
|
231
|
-
typeof window !== 'undefined' &&
|
|
232
|
-
/iPad|iPhone|iPod/.test(navigator.userAgent) &&
|
|
233
|
-
!window.MSStream;
|
|
234
|
-
const IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent);
|
|
235
|
-
const IS_ANDROID = typeof navigator !== 'undefined' && /Android/.test(navigator.userAgent);
|
|
236
|
-
const IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
|
|
237
|
-
const IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent);
|
|
238
|
-
// "modern" Edge was released at 79.x
|
|
239
|
-
const IS_EDGE_LEGACY = typeof navigator !== 'undefined' && /Edge?\/(?:[0-6][0-9]|[0-7][0-8])(?:\.)/i.test(navigator.userAgent);
|
|
240
|
-
const IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.userAgent);
|
|
241
|
-
// Native beforeInput events don't work well with react on Chrome 75 and older, Chrome 76+ can use beforeInput
|
|
242
|
-
const IS_CHROME_LEGACY = typeof navigator !== 'undefined' &&
|
|
243
|
-
/Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent) &&
|
|
244
|
-
// Exclude Chrome version greater than 3 bits,Chrome releases v100 on 2022.03.29
|
|
245
|
-
!/Chrome?\/(?:\d{3,})/i.test(navigator.userAgent);
|
|
246
|
-
// Firefox did not support `beforeInput` until `v87`.
|
|
247
|
-
const IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])(?:\.)).*/i.test(navigator.userAgent);
|
|
248
|
-
// qq browser
|
|
249
|
-
const IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent);
|
|
250
|
-
// UC mobile browser
|
|
251
|
-
const IS_UC_MOBILE = typeof navigator !== 'undefined' && /.*UCBrowser/.test(navigator.userAgent);
|
|
252
|
-
// Wechat browser
|
|
253
|
-
const IS_WECHATBROWSER = typeof navigator !== 'undefined' && /.*Wechat/.test(navigator.userAgent);
|
|
254
|
-
// COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
|
|
255
|
-
// Chrome Legacy doesn't support `beforeinput` correctly
|
|
256
|
-
const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
|
|
257
|
-
!IS_EDGE_LEGACY &&
|
|
258
|
-
// globalThis is undefined in older browsers
|
|
259
|
-
typeof globalThis !== 'undefined' &&
|
|
260
|
-
globalThis.InputEvent &&
|
|
261
|
-
// @ts-ignore The `getTargetRanges` property isn't recognized.
|
|
262
|
-
typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
|
|
263
|
-
|
|
264
13
|
const FAKE_LEFT_BLOCK_CARD_OFFSET = -1;
|
|
265
14
|
const FAKE_RIGHT_BLOCK_CARD_OFFSET = -2;
|
|
266
15
|
function hasBlockCardWithNode(node) {
|
|
@@ -286,61 +35,251 @@ function isCardCenterByTargetAttr(targetAttr) {
|
|
|
286
35
|
return targetAttr && targetAttr.nodeValue === 'card-center';
|
|
287
36
|
}
|
|
288
37
|
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
38
|
+
const customToDOMNode = (editor, node) => {
|
|
39
|
+
const domNode = Editor.isEditor(node) ? EDITOR_TO_ELEMENT.get(editor) : NODE_TO_ELEMENT.get(node);
|
|
40
|
+
if (!domNode) {
|
|
41
|
+
throw new Error(`Cannot resolve a DOM node from Slate node: ${JSON.stringify(node)}`);
|
|
42
|
+
}
|
|
43
|
+
return domNode;
|
|
44
|
+
};
|
|
45
|
+
DOMEditor.toDOMNode = customToDOMNode;
|
|
46
|
+
const toDOMPointForBlockCard = (editor, point) => {
|
|
47
|
+
const [node] = Editor.node(editor, point.path);
|
|
48
|
+
const [parentNode] = Editor.parent(editor, point.path);
|
|
49
|
+
if (editor.isBlockCard(parentNode) || editor.isBlockCard(node)) {
|
|
50
|
+
if (point.offset < 0) {
|
|
51
|
+
if (point.offset === FAKE_LEFT_BLOCK_CARD_OFFSET) {
|
|
52
|
+
const cursorNode = CustomDOMEditor.getCardCursorNode(editor, node, { direction: 'left' });
|
|
53
|
+
return [cursorNode, 1];
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const cursorNode = CustomDOMEditor.getCardCursorNode(editor, node, { direction: 'right' });
|
|
57
|
+
return [cursorNode, 1];
|
|
58
|
+
}
|
|
297
59
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
60
|
+
if (editor.selection && Range.isExpanded(editor.selection)) {
|
|
61
|
+
const [start, end] = Range.edges(editor.selection);
|
|
62
|
+
if (start === point) {
|
|
63
|
+
const cursorNode = CustomDOMEditor.getCardCursorNode(editor, parentNode, { direction: 'left' });
|
|
64
|
+
return [cursorNode, 1];
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const cursorNode = CustomDOMEditor.getCardCursorNode(editor, parentNode, { direction: 'right' });
|
|
68
|
+
return [cursorNode, 1];
|
|
69
|
+
}
|
|
308
70
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const customToDOMPoint = (editor, point) => {
|
|
74
|
+
const [node] = Editor.node(editor, point.path);
|
|
75
|
+
const el = customToDOMNode(editor, node);
|
|
76
|
+
let domPoint;
|
|
77
|
+
const domPointForBlackCard = toDOMPointForBlockCard(editor, point);
|
|
78
|
+
if (domPointForBlackCard) {
|
|
79
|
+
return domPointForBlackCard;
|
|
80
|
+
}
|
|
81
|
+
// If we're inside a void node, force the offset to 0, otherwise the zero
|
|
82
|
+
// width spacing character will result in an incorrect offset of 1
|
|
83
|
+
if (Editor.void(editor, { at: point })) {
|
|
84
|
+
point = { path: point.path, offset: 0 };
|
|
85
|
+
}
|
|
86
|
+
// For each leaf, we need to isolate its content, which means filtering
|
|
87
|
+
// to its direct text and zero-width spans. (We have to filter out any
|
|
88
|
+
// other siblings that may have been rendered alongside them.)
|
|
89
|
+
const selector = `[data-slate-string], [data-slate-zero-width]`;
|
|
90
|
+
const texts = Array.from(el.querySelectorAll(selector));
|
|
91
|
+
let start = 0;
|
|
92
|
+
for (const text of texts) {
|
|
93
|
+
const domNode = text.childNodes[0];
|
|
94
|
+
if (domNode == null || domNode.textContent == null) {
|
|
95
|
+
continue;
|
|
317
96
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (Editor.isEditor(child) && child === editor) {
|
|
329
|
-
return path;
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
break;
|
|
333
|
-
}
|
|
97
|
+
const { length } = domNode.textContent;
|
|
98
|
+
const attr = text.getAttribute('data-slate-length');
|
|
99
|
+
const trueLength = attr == null ? length : parseInt(attr, 10);
|
|
100
|
+
const end = start + trueLength;
|
|
101
|
+
if (point.offset <= end) {
|
|
102
|
+
const offset = Math.min(length, Math.max(0, point.offset - start));
|
|
103
|
+
domPoint = [domNode, offset];
|
|
104
|
+
// fixed cursor position after zero width char
|
|
105
|
+
if (offset === 0 && length === 1 && domNode.textContent === '\uFEFF') {
|
|
106
|
+
domPoint = [domNode, offset + 1];
|
|
334
107
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
start = end;
|
|
111
|
+
}
|
|
112
|
+
if (!domPoint) {
|
|
113
|
+
throw new Error(`Cannot resolve a DOM point from Slate point: ${JSON.stringify(point)}`);
|
|
114
|
+
}
|
|
115
|
+
return domPoint;
|
|
116
|
+
};
|
|
117
|
+
DOMEditor.toDOMPoint = customToDOMPoint;
|
|
118
|
+
const toSlatePointForBlockCard = (editor, domPoint, nearestNode) => {
|
|
119
|
+
const [domNode] = domPoint;
|
|
120
|
+
const cardTargetAttr = getCardTargetAttribute(domNode);
|
|
121
|
+
if (cardTargetAttr) {
|
|
122
|
+
const domSelection = window.getSelection();
|
|
123
|
+
const blockCardEntry = CustomDOMEditor.toSlateCardEntry(editor, domNode) || CustomDOMEditor.toSlateCardEntry(editor, nearestNode);
|
|
124
|
+
const [, blockPath] = blockCardEntry;
|
|
125
|
+
if (domSelection.isCollapsed) {
|
|
126
|
+
if (isCardLeftByTargetAttr(cardTargetAttr)) {
|
|
127
|
+
return { path: blockPath, offset: -1 };
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
return { path: blockPath, offset: -2 };
|
|
338
131
|
}
|
|
339
|
-
path.unshift(i);
|
|
340
|
-
child = parent;
|
|
341
132
|
}
|
|
342
|
-
|
|
343
|
-
|
|
133
|
+
if (isCardLeftByTargetAttr(cardTargetAttr)) {
|
|
134
|
+
return Editor.start(editor, blockPath);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
return Editor.end(editor, blockPath);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const customToSlatePoint = (editor, domPoint, options) => {
|
|
142
|
+
const { exactMatch, suppressThrow } = options;
|
|
143
|
+
const [nearestNode, nearestOffset] = normalizeDOMPoint(domPoint);
|
|
144
|
+
let parentNode = nearestNode.parentNode;
|
|
145
|
+
let textNode = null;
|
|
146
|
+
let offset = 0;
|
|
147
|
+
const slatePointForBlockCard = toSlatePointForBlockCard(editor, domPoint, nearestNode);
|
|
148
|
+
if (slatePointForBlockCard) {
|
|
149
|
+
return slatePointForBlockCard;
|
|
150
|
+
}
|
|
151
|
+
if (parentNode) {
|
|
152
|
+
const voidNode = parentNode.closest('[data-slate-void="true"]');
|
|
153
|
+
let leafNode = parentNode.closest('[data-slate-leaf]');
|
|
154
|
+
let domNode = null;
|
|
155
|
+
// Calculate how far into the text node the `nearestNode` is, so that we
|
|
156
|
+
// can determine what the offset relative to the text node is.
|
|
157
|
+
if (leafNode && CustomDOMEditor.isLeafInEditor(editor, leafNode)) {
|
|
158
|
+
textNode = leafNode.closest('[data-slate-node="text"]');
|
|
159
|
+
const window = DOMEditor.getWindow(editor);
|
|
160
|
+
const range = window.document.createRange();
|
|
161
|
+
range.setStart(textNode, 0);
|
|
162
|
+
range.setEnd(nearestNode, nearestOffset);
|
|
163
|
+
const contents = range.cloneContents();
|
|
164
|
+
const removals = [
|
|
165
|
+
...Array.prototype.slice.call(contents.querySelectorAll('[data-slate-zero-width]')),
|
|
166
|
+
...Array.prototype.slice.call(contents.querySelectorAll('[contenteditable=false]'))
|
|
167
|
+
];
|
|
168
|
+
removals.forEach(el => {
|
|
169
|
+
el.parentNode.removeChild(el);
|
|
170
|
+
});
|
|
171
|
+
// COMPAT: Edge has a bug where Range.prototype.toString() will
|
|
172
|
+
// convert \n into \r\n. The bug causes a loop when slate-react
|
|
173
|
+
// attempts to reposition its cursor to match the native position. Use
|
|
174
|
+
// textContent.length instead.
|
|
175
|
+
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/
|
|
176
|
+
offset = contents.textContent.length;
|
|
177
|
+
domNode = textNode;
|
|
178
|
+
}
|
|
179
|
+
else if (voidNode) {
|
|
180
|
+
// For void nodes, the element with the offset key will be a cousin, not an
|
|
181
|
+
// ancestor, so find it by going down from the nearest void parent.
|
|
182
|
+
const spacer = voidNode.querySelector('[data-slate-spacer="true"]');
|
|
183
|
+
leafNode = spacer.firstElementChild;
|
|
184
|
+
parentNode = leafNode.firstElementChild;
|
|
185
|
+
textNode = spacer;
|
|
186
|
+
domNode = leafNode;
|
|
187
|
+
offset = domNode.textContent.length;
|
|
188
|
+
}
|
|
189
|
+
// COMPAT: If the parent node is a Slate zero-width space, editor is
|
|
190
|
+
// because the text node should have no characters. However, during IME
|
|
191
|
+
// composition the ASCII characters will be prepended to the zero-width
|
|
192
|
+
// space, so subtract 1 from the offset to account for the zero-width
|
|
193
|
+
// space character.
|
|
194
|
+
if (domNode && offset === domNode.textContent.length && parentNode && parentNode.hasAttribute('data-slate-zero-width')) {
|
|
195
|
+
offset--;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!textNode) {
|
|
199
|
+
if (suppressThrow) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
throw new Error(`Cannot resolve a Slate point from DOM point: ${domPoint}`);
|
|
203
|
+
}
|
|
204
|
+
// COMPAT: If someone is clicking from one Slate editor into another,
|
|
205
|
+
// the select event fires twice, once for the old editor's `element`
|
|
206
|
+
// first, and then afterwards for the correct `element`. (2017/03/03)
|
|
207
|
+
let slateNode = null;
|
|
208
|
+
try {
|
|
209
|
+
slateNode = CustomDOMEditor.toSlateNode(editor, textNode);
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
if (!suppressThrow) {
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!slateNode && suppressThrow) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const path = CustomDOMEditor.findPath(editor, slateNode);
|
|
220
|
+
return { path, offset };
|
|
221
|
+
};
|
|
222
|
+
DOMEditor.toSlatePoint = customToSlatePoint;
|
|
223
|
+
const customToSlateRange = (editor, domRange, options) => {
|
|
224
|
+
const { exactMatch, suppressThrow } = options || {};
|
|
225
|
+
const el = isDOMSelection(domRange) ? domRange.anchorNode : domRange.startContainer;
|
|
226
|
+
let anchorNode;
|
|
227
|
+
let anchorOffset;
|
|
228
|
+
let focusNode;
|
|
229
|
+
let focusOffset;
|
|
230
|
+
let isCollapsed;
|
|
231
|
+
if (el) {
|
|
232
|
+
if (isDOMSelection(domRange)) {
|
|
233
|
+
anchorNode = domRange.anchorNode;
|
|
234
|
+
anchorOffset = domRange.anchorOffset;
|
|
235
|
+
focusNode = domRange.focusNode;
|
|
236
|
+
focusOffset = domRange.focusOffset;
|
|
237
|
+
// COMPAT: There's a bug in chrome that always returns `true` for
|
|
238
|
+
// `isCollapsed` for a Selection that comes from a ShadowRoot.
|
|
239
|
+
// (2020/08/08)
|
|
240
|
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=447523
|
|
241
|
+
if (IS_CHROME$1 && hasShadowRoot(anchorNode)) {
|
|
242
|
+
isCollapsed = domRange.anchorNode === domRange.focusNode && domRange.anchorOffset === domRange.focusOffset;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
isCollapsed = domRange.isCollapsed;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
anchorNode = domRange.startContainer;
|
|
250
|
+
anchorOffset = domRange.startOffset;
|
|
251
|
+
focusNode = domRange.endContainer;
|
|
252
|
+
focusOffset = domRange.endOffset;
|
|
253
|
+
isCollapsed = domRange.collapsed;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (anchorNode == null || focusNode == null || anchorOffset == null || focusOffset == null) {
|
|
257
|
+
throw new Error(`Cannot resolve a Slate range from DOM range: ${domRange}`);
|
|
258
|
+
}
|
|
259
|
+
const anchor = DOMEditor.toSlatePoint(editor, [anchorNode, anchorOffset], { suppressThrow, exactMatch });
|
|
260
|
+
if (!anchor) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
const focus = isCollapsed ? anchor : DOMEditor.toSlatePoint(editor, [focusNode, focusOffset], { suppressThrow, exactMatch });
|
|
264
|
+
if (!focus) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
let range = { anchor: anchor, focus: focus };
|
|
268
|
+
// if the selection is a hanging range that ends in a void
|
|
269
|
+
// and the DOM focus is an Element
|
|
270
|
+
// (meaning that the selection ends before the element)
|
|
271
|
+
// unhang the range to avoid mistakenly including the void
|
|
272
|
+
if (Range.isExpanded(range) &&
|
|
273
|
+
Range.isForward(range) &&
|
|
274
|
+
isDOMElement(focusNode) &&
|
|
275
|
+
Editor.void(editor, { at: range.focus, mode: 'highest' })) {
|
|
276
|
+
range = Editor.unhangRange(editor, range, { voids: true });
|
|
277
|
+
}
|
|
278
|
+
return range;
|
|
279
|
+
};
|
|
280
|
+
DOMEditor.toSlateRange = customToSlateRange;
|
|
281
|
+
const CustomDOMEditor = {
|
|
282
|
+
...DOMEditor,
|
|
344
283
|
isNodeInEditor(editor, node) {
|
|
345
284
|
let child = node;
|
|
346
285
|
while (true) {
|
|
@@ -361,321 +300,14 @@ const AngularEditor = {
|
|
|
361
300
|
}
|
|
362
301
|
return false;
|
|
363
302
|
},
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
findDocumentOrShadowRoot(editor) {
|
|
368
|
-
const el = AngularEditor.toDOMNode(editor, editor);
|
|
369
|
-
const root = el.getRootNode();
|
|
370
|
-
if ((root instanceof Document || root instanceof ShadowRoot) && root.getSelection != null) {
|
|
371
|
-
return root;
|
|
372
|
-
}
|
|
373
|
-
return el.ownerDocument;
|
|
374
|
-
},
|
|
375
|
-
/**
|
|
376
|
-
* Check if the editor is focused.
|
|
377
|
-
*/
|
|
378
|
-
isFocused(editor) {
|
|
379
|
-
return !!IS_FOCUSED.get(editor);
|
|
380
|
-
},
|
|
381
|
-
/**
|
|
382
|
-
* Check if the editor is in read-only mode.
|
|
383
|
-
*/
|
|
384
|
-
isReadonly(editor) {
|
|
385
|
-
return !!IS_READONLY.get(editor);
|
|
386
|
-
},
|
|
387
|
-
/**
|
|
388
|
-
* Check if the editor is hanging right.
|
|
389
|
-
*/
|
|
390
|
-
isBlockHangingRight(editor) {
|
|
391
|
-
const { selection } = editor;
|
|
392
|
-
if (!selection) {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
if (Range.isCollapsed(selection)) {
|
|
396
|
-
return false;
|
|
397
|
-
}
|
|
398
|
-
const [start, end] = Range.edges(selection);
|
|
399
|
-
const endBlock = Editor.above(editor, {
|
|
400
|
-
at: end,
|
|
401
|
-
match: node => Element.isElement(node) && Editor.isBlock(editor, node)
|
|
402
|
-
});
|
|
403
|
-
return Editor.isStart(editor, end, endBlock[1]);
|
|
404
|
-
},
|
|
405
|
-
/**
|
|
406
|
-
* Blur the editor.
|
|
407
|
-
*/
|
|
408
|
-
blur(editor) {
|
|
409
|
-
const el = AngularEditor.toDOMNode(editor, editor);
|
|
410
|
-
const root = AngularEditor.findDocumentOrShadowRoot(editor);
|
|
411
|
-
IS_FOCUSED.set(editor, false);
|
|
412
|
-
if (root.activeElement === el) {
|
|
413
|
-
el.blur();
|
|
414
|
-
}
|
|
415
|
-
},
|
|
416
|
-
/**
|
|
417
|
-
* Focus the editor.
|
|
418
|
-
*/
|
|
419
|
-
focus(editor) {
|
|
420
|
-
const el = AngularEditor.toDOMNode(editor, editor);
|
|
421
|
-
IS_FOCUSED.set(editor, true);
|
|
422
|
-
const window = AngularEditor.getWindow(editor);
|
|
423
|
-
if (window.document.activeElement !== el) {
|
|
424
|
-
el.focus({ preventScroll: true });
|
|
425
|
-
}
|
|
426
|
-
},
|
|
427
|
-
/**
|
|
428
|
-
* Deselect the editor.
|
|
429
|
-
*/
|
|
430
|
-
deselect(editor) {
|
|
431
|
-
const { selection } = editor;
|
|
432
|
-
const root = AngularEditor.findDocumentOrShadowRoot(editor);
|
|
433
|
-
const domSelection = root.getSelection();
|
|
434
|
-
if (domSelection && domSelection.rangeCount > 0) {
|
|
435
|
-
domSelection.removeAllRanges();
|
|
436
|
-
}
|
|
437
|
-
if (selection) {
|
|
438
|
-
Transforms.deselect(editor);
|
|
439
|
-
}
|
|
440
|
-
},
|
|
441
|
-
/**
|
|
442
|
-
* Check if a DOM node is within the editor.
|
|
443
|
-
*/
|
|
444
|
-
hasDOMNode(editor, target, options = {}) {
|
|
445
|
-
const { editable = false } = options;
|
|
446
|
-
const editorEl = AngularEditor.toDOMNode(editor, editor);
|
|
447
|
-
let targetEl;
|
|
448
|
-
// COMPAT: In Firefox, reading `target.nodeType` will throw an error if
|
|
449
|
-
// target is originating from an internal "restricted" element (e.g. a
|
|
450
|
-
// stepper arrow on a number input). (2018/05/04)
|
|
451
|
-
// https://github.com/ianstormtaylor/slate/issues/1819
|
|
303
|
+
isLeafInEditor(editor, leafNode) {
|
|
304
|
+
const textNode = leafNode.closest('[data-slate-node="text"]');
|
|
305
|
+
let node = null;
|
|
452
306
|
try {
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
catch (err) {
|
|
456
|
-
if (!err.message.includes('Permission denied to access property "nodeType"')) {
|
|
457
|
-
throw err;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
if (!targetEl) {
|
|
461
|
-
return false;
|
|
462
|
-
}
|
|
463
|
-
return (targetEl.closest(`[data-slate-editor]`) === editorEl &&
|
|
464
|
-
(!editable || targetEl.isContentEditable || !!targetEl.getAttribute('data-slate-zero-width')));
|
|
465
|
-
},
|
|
466
|
-
/**
|
|
467
|
-
* Insert data from a `DataTransfer` into the editor.
|
|
468
|
-
*/
|
|
469
|
-
insertData(editor, data) {
|
|
470
|
-
editor.insertData(data);
|
|
471
|
-
},
|
|
472
|
-
/**
|
|
473
|
-
* Insert fragment data from a `DataTransfer` into the editor.
|
|
474
|
-
*/
|
|
475
|
-
insertFragmentData(editor, data) {
|
|
476
|
-
return editor.insertFragmentData(data);
|
|
477
|
-
},
|
|
478
|
-
/**
|
|
479
|
-
* Insert text data from a `DataTransfer` into the editor.
|
|
480
|
-
*/
|
|
481
|
-
insertTextData(editor, data) {
|
|
482
|
-
return editor.insertTextData(data);
|
|
483
|
-
},
|
|
484
|
-
/**
|
|
485
|
-
* onKeydown hook.
|
|
486
|
-
*/
|
|
487
|
-
onKeydown(editor, data) {
|
|
488
|
-
editor.onKeydown(data);
|
|
489
|
-
},
|
|
490
|
-
/**
|
|
491
|
-
* onClick hook.
|
|
492
|
-
*/
|
|
493
|
-
onClick(editor, data) {
|
|
494
|
-
editor.onClick(data);
|
|
495
|
-
},
|
|
496
|
-
/**
|
|
497
|
-
* Sets data from the currently selected fragment on a `DataTransfer`.
|
|
498
|
-
*/
|
|
499
|
-
setFragmentData(editor, data, originEvent) {
|
|
500
|
-
editor.setFragmentData(data, originEvent);
|
|
501
|
-
},
|
|
502
|
-
deleteCutData(editor) {
|
|
503
|
-
editor.deleteCutData();
|
|
504
|
-
},
|
|
505
|
-
/**
|
|
506
|
-
* Find the native DOM element from a Slate node.
|
|
507
|
-
*/
|
|
508
|
-
toDOMNode(editor, node) {
|
|
509
|
-
const domNode = Editor.isEditor(node) ? EDITOR_TO_ELEMENT.get(editor) : NODE_TO_ELEMENT.get(node);
|
|
510
|
-
if (!domNode) {
|
|
511
|
-
throw new Error(`Cannot resolve a DOM node from Slate node: ${JSON.stringify(node)}`);
|
|
512
|
-
}
|
|
513
|
-
return domNode;
|
|
514
|
-
},
|
|
515
|
-
/**
|
|
516
|
-
* Find a native DOM selection point from a Slate point.
|
|
517
|
-
*/
|
|
518
|
-
toDOMPoint(editor, point, options) {
|
|
519
|
-
const [node] = Editor.node(editor, point.path);
|
|
520
|
-
const el = AngularEditor.toDOMNode(editor, node);
|
|
521
|
-
let domPoint;
|
|
522
|
-
// block card
|
|
523
|
-
const [parentNode] = Editor.parent(editor, point.path);
|
|
524
|
-
if (editor.isBlockCard(parentNode) || editor.isBlockCard(node)) {
|
|
525
|
-
if (point.offset < 0) {
|
|
526
|
-
if (point.offset === FAKE_LEFT_BLOCK_CARD_OFFSET) {
|
|
527
|
-
const cursorNode = AngularEditor.getCardCursorNode(editor, node, { direction: 'left' });
|
|
528
|
-
return [cursorNode, 1];
|
|
529
|
-
}
|
|
530
|
-
else {
|
|
531
|
-
const cursorNode = AngularEditor.getCardCursorNode(editor, node, { direction: 'right' });
|
|
532
|
-
return [cursorNode, 1];
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
if (Range.isExpanded(options.range)) {
|
|
536
|
-
const [start, end] = Range.edges(options.range);
|
|
537
|
-
if (start === point) {
|
|
538
|
-
const cursorNode = AngularEditor.getCardCursorNode(editor, parentNode, { direction: 'left' });
|
|
539
|
-
return [cursorNode, 1];
|
|
540
|
-
}
|
|
541
|
-
else {
|
|
542
|
-
const cursorNode = AngularEditor.getCardCursorNode(editor, parentNode, { direction: 'right' });
|
|
543
|
-
return [cursorNode, 1];
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
// If we're inside a void node, force the offset to 0, otherwise the zero
|
|
548
|
-
// width spacing character will result in an incorrect offset of 1
|
|
549
|
-
if (Editor.void(editor, { at: point })) {
|
|
550
|
-
point = { path: point.path, offset: 0 };
|
|
551
|
-
}
|
|
552
|
-
// For each leaf, we need to isolate its content, which means filtering
|
|
553
|
-
// to its direct text and zero-width spans. (We have to filter out any
|
|
554
|
-
// other siblings that may have been rendered alongside them.)
|
|
555
|
-
const selector = `[data-slate-string], [data-slate-zero-width]`;
|
|
556
|
-
const texts = Array.from(el.querySelectorAll(selector));
|
|
557
|
-
let start = 0;
|
|
558
|
-
for (const text of texts) {
|
|
559
|
-
const domNode = text.childNodes[0];
|
|
560
|
-
if (domNode == null || domNode.textContent == null) {
|
|
561
|
-
continue;
|
|
562
|
-
}
|
|
563
|
-
const { length } = domNode.textContent;
|
|
564
|
-
const attr = text.getAttribute('data-slate-length');
|
|
565
|
-
const trueLength = attr == null ? length : parseInt(attr, 10);
|
|
566
|
-
const end = start + trueLength;
|
|
567
|
-
if (point.offset <= end) {
|
|
568
|
-
const offset = Math.min(length, Math.max(0, point.offset - start));
|
|
569
|
-
domPoint = [domNode, offset];
|
|
570
|
-
// fixed cursor position after zero width char
|
|
571
|
-
if (offset === 0 && length === 1 && domNode.textContent === '\uFEFF') {
|
|
572
|
-
domPoint = [domNode, offset + 1];
|
|
573
|
-
}
|
|
574
|
-
break;
|
|
575
|
-
}
|
|
576
|
-
start = end;
|
|
577
|
-
}
|
|
578
|
-
if (!domPoint) {
|
|
579
|
-
throw new Error(`Cannot resolve a DOM point from Slate point: ${JSON.stringify(point)}`);
|
|
580
|
-
}
|
|
581
|
-
return domPoint;
|
|
582
|
-
},
|
|
583
|
-
/**
|
|
584
|
-
* Find a native DOM range from a Slate `range`.
|
|
585
|
-
*/
|
|
586
|
-
toDOMRange(editor, range) {
|
|
587
|
-
const { anchor, focus } = range;
|
|
588
|
-
const isBackward = Range.isBackward(range);
|
|
589
|
-
const domAnchor = AngularEditor.toDOMPoint(editor, anchor, { range });
|
|
590
|
-
const domFocus = Range.isCollapsed(range) ? domAnchor : AngularEditor.toDOMPoint(editor, focus, { range });
|
|
591
|
-
const window = AngularEditor.getWindow(editor);
|
|
592
|
-
const domRange = window.document.createRange();
|
|
593
|
-
const [startNode, startOffset] = isBackward ? domFocus : domAnchor;
|
|
594
|
-
const [endNode, endOffset] = isBackward ? domAnchor : domFocus;
|
|
595
|
-
// A slate Point at zero-width Leaf always has an offset of 0 but a native DOM selection at
|
|
596
|
-
// zero-width node has an offset of 1 so we have to check if we are in a zero-width node and
|
|
597
|
-
// adjust the offset accordingly.
|
|
598
|
-
const startEl = (isDOMElement(startNode) ? startNode : startNode.parentElement);
|
|
599
|
-
const isStartAtZeroWidth = !!startEl.getAttribute('data-slate-zero-width');
|
|
600
|
-
const endEl = (isDOMElement(endNode) ? endNode : endNode.parentElement);
|
|
601
|
-
const isEndAtZeroWidth = !!endEl.getAttribute('data-slate-zero-width');
|
|
602
|
-
domRange.setStart(startNode, isStartAtZeroWidth ? 1 : startOffset);
|
|
603
|
-
domRange.setEnd(endNode, isEndAtZeroWidth ? 1 : endOffset);
|
|
604
|
-
return domRange;
|
|
605
|
-
},
|
|
606
|
-
/**
|
|
607
|
-
* Find a Slate node from a native DOM `element`.
|
|
608
|
-
*/
|
|
609
|
-
toSlateNode(editor, domNode, options) {
|
|
610
|
-
const { suppressThrow } = options || { suppressThrow: false };
|
|
611
|
-
let domEl = isDOMElement(domNode) ? domNode : domNode.parentElement;
|
|
612
|
-
if (domEl && !domEl.hasAttribute('data-slate-node')) {
|
|
613
|
-
domEl = domEl.closest(`[data-slate-node]`);
|
|
614
|
-
}
|
|
615
|
-
const node = domEl ? ELEMENT_TO_NODE.get(domEl) : null;
|
|
616
|
-
if (!node) {
|
|
617
|
-
if (suppressThrow) {
|
|
618
|
-
return null;
|
|
619
|
-
}
|
|
620
|
-
throw new Error(`Cannot resolve a Slate node from DOM node: ${domEl}`);
|
|
307
|
+
node = CustomDOMEditor.toSlateNode(editor, textNode);
|
|
621
308
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
/**
|
|
625
|
-
* Get the target range from a DOM `event`.
|
|
626
|
-
*/
|
|
627
|
-
findEventRange(editor, event) {
|
|
628
|
-
if ('nativeEvent' in event) {
|
|
629
|
-
event = event.nativeEvent;
|
|
630
|
-
}
|
|
631
|
-
const { clientX: x, clientY: y, target } = event;
|
|
632
|
-
if (x == null || y == null) {
|
|
633
|
-
throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`);
|
|
634
|
-
}
|
|
635
|
-
const node = AngularEditor.toSlateNode(editor, event.target, { suppressThrow: false });
|
|
636
|
-
const path = AngularEditor.findPath(editor, node);
|
|
637
|
-
// If the drop target is inside a void node, move it into either the
|
|
638
|
-
// next or previous node, depending on which side the `x` and `y`
|
|
639
|
-
// coordinates are closest to.
|
|
640
|
-
if (Element.isElement(node) && Editor.isVoid(editor, node)) {
|
|
641
|
-
const rect = target.getBoundingClientRect();
|
|
642
|
-
const isPrev = editor.isInline(node) ? x - rect.left < rect.left + rect.width - x : y - rect.top < rect.top + rect.height - y;
|
|
643
|
-
const edge = Editor.point(editor, path, {
|
|
644
|
-
edge: isPrev ? 'start' : 'end'
|
|
645
|
-
});
|
|
646
|
-
const point = isPrev ? Editor.before(editor, edge) : Editor.after(editor, edge);
|
|
647
|
-
if (point) {
|
|
648
|
-
return Editor.range(editor, point);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
// Else resolve a range from the caret position where the drop occured.
|
|
652
|
-
let domRange;
|
|
653
|
-
const window = AngularEditor.getWindow(editor);
|
|
654
|
-
const { document } = window;
|
|
655
|
-
// COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)
|
|
656
|
-
if (document.caretRangeFromPoint) {
|
|
657
|
-
domRange = document.caretRangeFromPoint(x, y);
|
|
658
|
-
}
|
|
659
|
-
else {
|
|
660
|
-
const position = document.caretPositionFromPoint(x, y);
|
|
661
|
-
if (position) {
|
|
662
|
-
domRange = document.createRange();
|
|
663
|
-
domRange.setStart(position.offsetNode, position.offset);
|
|
664
|
-
domRange.setEnd(position.offsetNode, position.offset);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
if (!domRange) {
|
|
668
|
-
throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`);
|
|
669
|
-
}
|
|
670
|
-
// Resolve a Slate range from the DOM range.
|
|
671
|
-
const range = AngularEditor.toSlateRange(editor, domRange, { suppressThrow: false });
|
|
672
|
-
return range;
|
|
673
|
-
},
|
|
674
|
-
isLeafInEditor(editor, leafNode, options) {
|
|
675
|
-
const { suppressThrow } = options;
|
|
676
|
-
const textNode = leafNode.closest('[data-slate-node="text"]');
|
|
677
|
-
const node = AngularEditor.toSlateNode(editor, textNode, { suppressThrow });
|
|
678
|
-
if (node && AngularEditor.isNodeInEditor(editor, node)) {
|
|
309
|
+
catch (error) { }
|
|
310
|
+
if (node && CustomDOMEditor.isNodeInEditor(editor, node)) {
|
|
679
311
|
return true;
|
|
680
312
|
}
|
|
681
313
|
else {
|
|
@@ -683,162 +315,22 @@ const AngularEditor = {
|
|
|
683
315
|
}
|
|
684
316
|
},
|
|
685
317
|
/**
|
|
686
|
-
*
|
|
687
|
-
*/
|
|
688
|
-
toSlatePoint(editor, domPoint, options) {
|
|
689
|
-
const { exactMatch, suppressThrow } = options;
|
|
690
|
-
const [domNode] = domPoint;
|
|
691
|
-
const [nearestNode, nearestOffset] = normalizeDOMPoint(domPoint);
|
|
692
|
-
let parentNode = nearestNode.parentNode;
|
|
693
|
-
let textNode = null;
|
|
694
|
-
let offset = 0;
|
|
695
|
-
// block card
|
|
696
|
-
const cardTargetAttr = getCardTargetAttribute(domNode);
|
|
697
|
-
if (cardTargetAttr) {
|
|
698
|
-
const domSelection = window.getSelection();
|
|
699
|
-
const isBackward = editor.selection && Range.isBackward(editor.selection);
|
|
700
|
-
const blockCardEntry = AngularEditor.toSlateCardEntry(editor, domNode) || AngularEditor.toSlateCardEntry(editor, nearestNode);
|
|
701
|
-
const [, blockPath] = blockCardEntry;
|
|
702
|
-
if (domSelection.isCollapsed) {
|
|
703
|
-
if (isCardLeftByTargetAttr(cardTargetAttr)) {
|
|
704
|
-
return { path: blockPath, offset: -1 };
|
|
705
|
-
}
|
|
706
|
-
else {
|
|
707
|
-
return { path: blockPath, offset: -2 };
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
if (isCardLeftByTargetAttr(cardTargetAttr)) {
|
|
711
|
-
return Editor.start(editor, blockPath);
|
|
712
|
-
}
|
|
713
|
-
else {
|
|
714
|
-
return Editor.end(editor, blockPath);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
if (parentNode) {
|
|
718
|
-
const voidNode = parentNode.closest('[data-slate-void="true"]');
|
|
719
|
-
let leafNode = parentNode.closest('[data-slate-leaf]');
|
|
720
|
-
let domNode = null;
|
|
721
|
-
// Calculate how far into the text node the `nearestNode` is, so that we
|
|
722
|
-
// can determine what the offset relative to the text node is.
|
|
723
|
-
if (leafNode && AngularEditor.isLeafInEditor(editor, leafNode, { suppressThrow: true })) {
|
|
724
|
-
textNode = leafNode.closest('[data-slate-node="text"]');
|
|
725
|
-
const window = AngularEditor.getWindow(editor);
|
|
726
|
-
const range = window.document.createRange();
|
|
727
|
-
range.setStart(textNode, 0);
|
|
728
|
-
range.setEnd(nearestNode, nearestOffset);
|
|
729
|
-
const contents = range.cloneContents();
|
|
730
|
-
const removals = [
|
|
731
|
-
...Array.prototype.slice.call(contents.querySelectorAll('[data-slate-zero-width]')),
|
|
732
|
-
...Array.prototype.slice.call(contents.querySelectorAll('[contenteditable=false]'))
|
|
733
|
-
];
|
|
734
|
-
removals.forEach(el => {
|
|
735
|
-
el.parentNode.removeChild(el);
|
|
736
|
-
});
|
|
737
|
-
// COMPAT: Edge has a bug where Range.prototype.toString() will
|
|
738
|
-
// convert \n into \r\n. The bug causes a loop when slate-react
|
|
739
|
-
// attempts to reposition its cursor to match the native position. Use
|
|
740
|
-
// textContent.length instead.
|
|
741
|
-
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/
|
|
742
|
-
offset = contents.textContent.length;
|
|
743
|
-
domNode = textNode;
|
|
744
|
-
}
|
|
745
|
-
else if (voidNode) {
|
|
746
|
-
// For void nodes, the element with the offset key will be a cousin, not an
|
|
747
|
-
// ancestor, so find it by going down from the nearest void parent.
|
|
748
|
-
const spacer = voidNode.querySelector('[data-slate-spacer="true"]');
|
|
749
|
-
leafNode = spacer.firstElementChild;
|
|
750
|
-
parentNode = leafNode.firstElementChild;
|
|
751
|
-
textNode = spacer;
|
|
752
|
-
domNode = leafNode;
|
|
753
|
-
offset = domNode.textContent.length;
|
|
754
|
-
}
|
|
755
|
-
// COMPAT: If the parent node is a Slate zero-width space, editor is
|
|
756
|
-
// because the text node should have no characters. However, during IME
|
|
757
|
-
// composition the ASCII characters will be prepended to the zero-width
|
|
758
|
-
// space, so subtract 1 from the offset to account for the zero-width
|
|
759
|
-
// space character.
|
|
760
|
-
if (domNode && offset === domNode.textContent.length && parentNode && parentNode.hasAttribute('data-slate-zero-width')) {
|
|
761
|
-
offset--;
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
if (!textNode) {
|
|
765
|
-
if (suppressThrow) {
|
|
766
|
-
return null;
|
|
767
|
-
}
|
|
768
|
-
throw new Error(`Cannot resolve a Slate point from DOM point: ${domPoint}`);
|
|
769
|
-
}
|
|
770
|
-
// COMPAT: If someone is clicking from one Slate editor into another,
|
|
771
|
-
// the select event fires twice, once for the old editor's `element`
|
|
772
|
-
// first, and then afterwards for the correct `element`. (2017/03/03)
|
|
773
|
-
const slateNode = AngularEditor.toSlateNode(editor, textNode, { suppressThrow });
|
|
774
|
-
if (!slateNode && suppressThrow) {
|
|
775
|
-
return null;
|
|
776
|
-
}
|
|
777
|
-
const path = AngularEditor.findPath(editor, slateNode);
|
|
778
|
-
return { path, offset };
|
|
779
|
-
},
|
|
780
|
-
/**
|
|
781
|
-
* Find a Slate range from a DOM range or selection.
|
|
318
|
+
* Check if the editor is hanging right.
|
|
782
319
|
*/
|
|
783
|
-
|
|
784
|
-
const {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
let anchorOffset;
|
|
788
|
-
let focusNode;
|
|
789
|
-
let focusOffset;
|
|
790
|
-
let isCollapsed;
|
|
791
|
-
if (el) {
|
|
792
|
-
if (isDOMSelection(domRange)) {
|
|
793
|
-
anchorNode = domRange.anchorNode;
|
|
794
|
-
anchorOffset = domRange.anchorOffset;
|
|
795
|
-
focusNode = domRange.focusNode;
|
|
796
|
-
focusOffset = domRange.focusOffset;
|
|
797
|
-
// COMPAT: There's a bug in chrome that always returns `true` for
|
|
798
|
-
// `isCollapsed` for a Selection that comes from a ShadowRoot.
|
|
799
|
-
// (2020/08/08)
|
|
800
|
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=447523
|
|
801
|
-
if (IS_CHROME && hasShadowRoot()) {
|
|
802
|
-
isCollapsed = domRange.anchorNode === domRange.focusNode && domRange.anchorOffset === domRange.focusOffset;
|
|
803
|
-
}
|
|
804
|
-
else {
|
|
805
|
-
isCollapsed = domRange.isCollapsed;
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
else {
|
|
809
|
-
anchorNode = domRange.startContainer;
|
|
810
|
-
anchorOffset = domRange.startOffset;
|
|
811
|
-
focusNode = domRange.endContainer;
|
|
812
|
-
focusOffset = domRange.endOffset;
|
|
813
|
-
isCollapsed = domRange.collapsed;
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
if (anchorNode == null || focusNode == null || anchorOffset == null || focusOffset == null) {
|
|
817
|
-
throw new Error(`Cannot resolve a Slate range from DOM range: ${domRange}`);
|
|
818
|
-
}
|
|
819
|
-
const anchor = AngularEditor.toSlatePoint(editor, [anchorNode, anchorOffset], { suppressThrow, exactMatch });
|
|
820
|
-
if (!anchor) {
|
|
821
|
-
return null;
|
|
320
|
+
isBlockHangingRight(editor) {
|
|
321
|
+
const { selection } = editor;
|
|
322
|
+
if (!selection) {
|
|
323
|
+
return false;
|
|
822
324
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
return null;
|
|
325
|
+
if (Range.isCollapsed(selection)) {
|
|
326
|
+
return false;
|
|
826
327
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
Range.isForward(range) &&
|
|
834
|
-
isDOMElement(focusNode) &&
|
|
835
|
-
Editor.void(editor, { at: range.focus, mode: 'highest' })) {
|
|
836
|
-
range = Editor.unhangRange(editor, range, { voids: true });
|
|
837
|
-
}
|
|
838
|
-
return range;
|
|
839
|
-
},
|
|
840
|
-
isLeafBlock(editor, node) {
|
|
841
|
-
return Element.isElement(node) && !editor.isInline(node) && Editor.hasInlines(editor, node);
|
|
328
|
+
const [start, end] = Range.edges(selection);
|
|
329
|
+
const endBlock = Editor.above(editor, {
|
|
330
|
+
at: end,
|
|
331
|
+
match: node => Element.isElement(node) && Editor.isBlock(editor, node)
|
|
332
|
+
});
|
|
333
|
+
return Editor.isStart(editor, end, endBlock[1]);
|
|
842
334
|
},
|
|
843
335
|
isBlockCardLeftCursor(editor) {
|
|
844
336
|
return (editor.selection?.anchor?.offset === FAKE_LEFT_BLOCK_CARD_OFFSET &&
|
|
@@ -849,15 +341,45 @@ const AngularEditor = {
|
|
|
849
341
|
editor.selection?.focus?.offset === FAKE_RIGHT_BLOCK_CARD_OFFSET);
|
|
850
342
|
},
|
|
851
343
|
getCardCursorNode(editor, blockCardNode, options) {
|
|
852
|
-
const blockCardElement =
|
|
344
|
+
const blockCardElement = DOMEditor.toDOMNode(editor, blockCardNode);
|
|
853
345
|
const cardCenter = blockCardElement.parentElement;
|
|
854
346
|
return options.direction === 'left' ? cardCenter.previousElementSibling.firstChild : cardCenter.nextElementSibling.firstChild;
|
|
855
347
|
},
|
|
856
348
|
toSlateCardEntry(editor, node) {
|
|
857
349
|
const element = node.parentElement.closest('.slate-block-card')?.querySelector('[card-target="card-center"]').firstElementChild;
|
|
858
|
-
const slateNode =
|
|
859
|
-
const path =
|
|
350
|
+
const slateNode = DOMEditor.toSlateNode(editor, element);
|
|
351
|
+
const path = DOMEditor.findPath(editor, slateNode);
|
|
860
352
|
return [slateNode, path];
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const AngularEditor = {
|
|
357
|
+
...CustomDOMEditor,
|
|
358
|
+
/**
|
|
359
|
+
* handle editor error.
|
|
360
|
+
*/
|
|
361
|
+
onError(errorData) {
|
|
362
|
+
if (errorData.nativeError) {
|
|
363
|
+
throw errorData.nativeError;
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
/**
|
|
367
|
+
* onKeydown hook.
|
|
368
|
+
*/
|
|
369
|
+
onKeydown(editor, data) {
|
|
370
|
+
editor.onKeydown(data);
|
|
371
|
+
},
|
|
372
|
+
/**
|
|
373
|
+
* onClick hook.
|
|
374
|
+
*/
|
|
375
|
+
onClick(editor, data) {
|
|
376
|
+
editor.onClick(data);
|
|
377
|
+
},
|
|
378
|
+
deleteCutData(editor) {
|
|
379
|
+
editor.deleteCutData();
|
|
380
|
+
},
|
|
381
|
+
isLeafBlock(editor, node) {
|
|
382
|
+
return Element.isElement(node) && !editor.isInline(node) && Editor.hasInlines(editor, node);
|
|
861
383
|
},
|
|
862
384
|
/**
|
|
863
385
|
* move native selection to card-left or card-right
|
|
@@ -883,13 +405,53 @@ const AngularEditor = {
|
|
|
883
405
|
offset: options.direction === 'left' ? FAKE_LEFT_BLOCK_CARD_OFFSET : FAKE_RIGHT_BLOCK_CARD_OFFSET
|
|
884
406
|
};
|
|
885
407
|
Transforms.select(editor, { anchor: cursor, focus: cursor });
|
|
886
|
-
},
|
|
887
|
-
hasRange(editor, range) {
|
|
888
|
-
const { anchor, focus } = range;
|
|
889
|
-
return Editor.hasPath(editor, anchor.path) && Editor.hasPath(editor, focus.path);
|
|
890
408
|
}
|
|
891
409
|
};
|
|
892
410
|
|
|
411
|
+
/**
|
|
412
|
+
* Symbols.
|
|
413
|
+
*/
|
|
414
|
+
const PLACEHOLDER_SYMBOL = Symbol('placeholder');
|
|
415
|
+
/**
|
|
416
|
+
* Weak map for associating the html element with the component.
|
|
417
|
+
*/
|
|
418
|
+
const ELEMENT_TO_COMPONENT = new WeakMap();
|
|
419
|
+
const EDITOR_TO_AFTER_VIEW_INIT_QUEUE = new WeakMap();
|
|
420
|
+
|
|
421
|
+
const IS_IOS = typeof navigator !== 'undefined' &&
|
|
422
|
+
typeof window !== 'undefined' &&
|
|
423
|
+
/iPad|iPhone|iPod/.test(navigator.userAgent) &&
|
|
424
|
+
!window.MSStream;
|
|
425
|
+
const IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent);
|
|
426
|
+
const IS_ANDROID = typeof navigator !== 'undefined' && /Android/.test(navigator.userAgent);
|
|
427
|
+
const IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
|
|
428
|
+
const IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent);
|
|
429
|
+
// "modern" Edge was released at 79.x
|
|
430
|
+
const IS_EDGE_LEGACY = typeof navigator !== 'undefined' && /Edge?\/(?:[0-6][0-9]|[0-7][0-8])(?:\.)/i.test(navigator.userAgent);
|
|
431
|
+
const IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.userAgent);
|
|
432
|
+
// Native beforeInput events don't work well with react on Chrome 75 and older, Chrome 76+ can use beforeInput
|
|
433
|
+
const IS_CHROME_LEGACY = typeof navigator !== 'undefined' &&
|
|
434
|
+
/Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent) &&
|
|
435
|
+
// Exclude Chrome version greater than 3 bits,Chrome releases v100 on 2022.03.29
|
|
436
|
+
!/Chrome?\/(?:\d{3,})/i.test(navigator.userAgent);
|
|
437
|
+
// Firefox did not support `beforeInput` until `v87`.
|
|
438
|
+
const IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])(?:\.)).*/i.test(navigator.userAgent);
|
|
439
|
+
// qq browser
|
|
440
|
+
const IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent);
|
|
441
|
+
// UC mobile browser
|
|
442
|
+
const IS_UC_MOBILE = typeof navigator !== 'undefined' && /.*UCBrowser/.test(navigator.userAgent);
|
|
443
|
+
// Wechat browser
|
|
444
|
+
const IS_WECHATBROWSER = typeof navigator !== 'undefined' && /.*Wechat/.test(navigator.userAgent);
|
|
445
|
+
// COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
|
|
446
|
+
// Chrome Legacy doesn't support `beforeinput` correctly
|
|
447
|
+
const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
|
|
448
|
+
!IS_EDGE_LEGACY &&
|
|
449
|
+
// globalThis is undefined in older browsers
|
|
450
|
+
typeof globalThis !== 'undefined' &&
|
|
451
|
+
globalThis.InputEvent &&
|
|
452
|
+
// @ts-ignore The `getTargetRanges` property isn't recognized.
|
|
453
|
+
typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
|
|
454
|
+
|
|
893
455
|
/**
|
|
894
456
|
* Hotkey mappings for each platform.
|
|
895
457
|
*/
|
|
@@ -1188,6 +750,44 @@ const getNavigatorClipboard = async () => {
|
|
|
1188
750
|
return clipboardData;
|
|
1189
751
|
};
|
|
1190
752
|
|
|
753
|
+
const SlateFragmentAttributeKey = 'data-slate-angular-fragment';
|
|
754
|
+
/**
|
|
755
|
+
* Get x-slate-fragment attribute from data-slate-angular-fragment
|
|
756
|
+
*/
|
|
757
|
+
const catchSlateFragment = /data-slate-angular-fragment="(.+?)"/m;
|
|
758
|
+
const getSlateFragmentAttribute = (htmlData) => {
|
|
759
|
+
const [, fragment] = htmlData.match(catchSlateFragment) || [];
|
|
760
|
+
return fragment;
|
|
761
|
+
};
|
|
762
|
+
/**
|
|
763
|
+
* Check if a DOM node is an element node.
|
|
764
|
+
*/
|
|
765
|
+
const isDOMText = (value) => {
|
|
766
|
+
return isDOMNode(value) && value.nodeType === 3;
|
|
767
|
+
};
|
|
768
|
+
/**
|
|
769
|
+
* Get a plaintext representation of the content of a node, accounting for block
|
|
770
|
+
* elements which get a newline appended.
|
|
771
|
+
*
|
|
772
|
+
* The domNode must be attached to the DOM.
|
|
773
|
+
*/
|
|
774
|
+
const getPlainText = (domNode) => {
|
|
775
|
+
let text = '';
|
|
776
|
+
if (isDOMText(domNode) && domNode.nodeValue) {
|
|
777
|
+
return domNode.nodeValue;
|
|
778
|
+
}
|
|
779
|
+
if (isDOMElement(domNode)) {
|
|
780
|
+
for (const childNode of Array.from(domNode.childNodes)) {
|
|
781
|
+
text += getPlainText(childNode);
|
|
782
|
+
}
|
|
783
|
+
const display = getComputedStyle(domNode).getPropertyValue('display');
|
|
784
|
+
if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {
|
|
785
|
+
text += '\n';
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return text;
|
|
789
|
+
};
|
|
790
|
+
|
|
1191
791
|
const buildHTMLText = (wrapper, attach, data) => {
|
|
1192
792
|
const stringObj = JSON.stringify(data);
|
|
1193
793
|
const encoded = window.btoa(encodeURIComponent(stringObj));
|
|
@@ -1262,128 +862,10 @@ const setClipboardData = async (clipboardData, wrapper, attach, dataTransfer) =>
|
|
|
1262
862
|
}
|
|
1263
863
|
};
|
|
1264
864
|
|
|
1265
|
-
/**
|
|
1266
|
-
* Utilities for single-line deletion
|
|
1267
|
-
*/
|
|
1268
|
-
const doRectsIntersect = (rect, compareRect) => {
|
|
1269
|
-
const middle = (compareRect.top + compareRect.bottom) / 2;
|
|
1270
|
-
return rect.top <= middle && rect.bottom >= middle;
|
|
1271
|
-
};
|
|
1272
|
-
const areRangesSameLine = (editor, range1, range2) => {
|
|
1273
|
-
const rect1 = AngularEditor.toDOMRange(editor, range1).getBoundingClientRect();
|
|
1274
|
-
const rect2 = AngularEditor.toDOMRange(editor, range2).getBoundingClientRect();
|
|
1275
|
-
return doRectsIntersect(rect1, rect2) && doRectsIntersect(rect2, rect1);
|
|
1276
|
-
};
|
|
1277
|
-
/**
|
|
1278
|
-
* A helper utility that returns the end portion of a `Range`
|
|
1279
|
-
* which is located on a single line.
|
|
1280
|
-
*
|
|
1281
|
-
* @param {Editor} editor The editor object to compare against
|
|
1282
|
-
* @param {Range} parentRange The parent range to compare against
|
|
1283
|
-
* @returns {Range} A valid portion of the parentRange which is one a single line
|
|
1284
|
-
*/
|
|
1285
|
-
const findCurrentLineRange = (editor, parentRange) => {
|
|
1286
|
-
const parentRangeBoundary = Editor.range(editor, Range.end(parentRange));
|
|
1287
|
-
const positions = Array.from(Editor.positions(editor, { at: parentRange }));
|
|
1288
|
-
let left = 0;
|
|
1289
|
-
let right = positions.length;
|
|
1290
|
-
let middle = Math.floor(right / 2);
|
|
1291
|
-
if (areRangesSameLine(editor, Editor.range(editor, positions[left]), parentRangeBoundary)) {
|
|
1292
|
-
return Editor.range(editor, positions[left], parentRangeBoundary);
|
|
1293
|
-
}
|
|
1294
|
-
if (positions.length < 2) {
|
|
1295
|
-
return Editor.range(editor, positions[positions.length - 1], parentRangeBoundary);
|
|
1296
|
-
}
|
|
1297
|
-
while (middle !== positions.length && middle !== left) {
|
|
1298
|
-
if (areRangesSameLine(editor, Editor.range(editor, positions[middle]), parentRangeBoundary)) {
|
|
1299
|
-
right = middle;
|
|
1300
|
-
}
|
|
1301
|
-
else {
|
|
1302
|
-
left = middle;
|
|
1303
|
-
}
|
|
1304
|
-
middle = Math.floor((left + right) / 2);
|
|
1305
|
-
}
|
|
1306
|
-
return Editor.range(editor, positions[right], parentRangeBoundary);
|
|
1307
|
-
};
|
|
1308
|
-
|
|
1309
865
|
const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
e
|
|
1313
|
-
if (unit !== 'line') {
|
|
1314
|
-
return deleteBackward(unit);
|
|
1315
|
-
}
|
|
1316
|
-
if (editor.selection && Range.isCollapsed(editor.selection)) {
|
|
1317
|
-
const parentBlockEntry = Editor.above(editor, {
|
|
1318
|
-
match: n => Element.isElement(n) && Editor.isBlock(editor, n),
|
|
1319
|
-
at: editor.selection
|
|
1320
|
-
});
|
|
1321
|
-
if (parentBlockEntry) {
|
|
1322
|
-
const [, parentBlockPath] = parentBlockEntry;
|
|
1323
|
-
const parentElementRange = Editor.range(editor, parentBlockPath, editor.selection.anchor);
|
|
1324
|
-
const currentLineRange = findCurrentLineRange(e, parentElementRange);
|
|
1325
|
-
if (!Range.isCollapsed(currentLineRange)) {
|
|
1326
|
-
Transforms.delete(editor, { at: currentLineRange });
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
};
|
|
1331
|
-
e.apply = (op) => {
|
|
1332
|
-
const matches = [];
|
|
1333
|
-
switch (op.type) {
|
|
1334
|
-
case 'insert_text':
|
|
1335
|
-
case 'remove_text':
|
|
1336
|
-
case 'set_node': {
|
|
1337
|
-
for (const [node, path] of Editor.levels(e, { at: op.path })) {
|
|
1338
|
-
const key = AngularEditor.findKey(e, node);
|
|
1339
|
-
matches.push([path, key]);
|
|
1340
|
-
}
|
|
1341
|
-
break;
|
|
1342
|
-
}
|
|
1343
|
-
case 'insert_node':
|
|
1344
|
-
case 'remove_node':
|
|
1345
|
-
case 'merge_node':
|
|
1346
|
-
case 'split_node': {
|
|
1347
|
-
for (const [node, path] of Editor.levels(e, {
|
|
1348
|
-
at: Path.parent(op.path)
|
|
1349
|
-
})) {
|
|
1350
|
-
const key = AngularEditor.findKey(e, node);
|
|
1351
|
-
matches.push([path, key]);
|
|
1352
|
-
}
|
|
1353
|
-
break;
|
|
1354
|
-
}
|
|
1355
|
-
case 'move_node': {
|
|
1356
|
-
const commonPath = Path.common(Path.parent(op.path), Path.parent(op.newPath));
|
|
1357
|
-
for (const [node, path] of Editor.levels(e, {
|
|
1358
|
-
at: Path.parent(op.path)
|
|
1359
|
-
})) {
|
|
1360
|
-
const key = AngularEditor.findKey(e, node);
|
|
1361
|
-
matches.push([Editor.pathRef(editor, path), key]);
|
|
1362
|
-
}
|
|
1363
|
-
for (const [node, path] of Editor.levels(e, {
|
|
1364
|
-
at: Path.parent(op.newPath)
|
|
1365
|
-
})) {
|
|
1366
|
-
if (path.length > commonPath.length) {
|
|
1367
|
-
const key = AngularEditor.findKey(e, node);
|
|
1368
|
-
matches.push([Editor.pathRef(editor, path), key]);
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
break;
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
apply(op);
|
|
1375
|
-
for (const [source, key] of matches) {
|
|
1376
|
-
const [node] = Editor.node(e, Path.isPath(source) ? source : source.current);
|
|
1377
|
-
NODE_TO_KEY.set(node, key);
|
|
1378
|
-
}
|
|
1379
|
-
};
|
|
1380
|
-
e.onChange = () => {
|
|
1381
|
-
const onContextChange = EDITOR_TO_ON_CHANGE.get(e);
|
|
1382
|
-
if (onContextChange) {
|
|
1383
|
-
onContextChange();
|
|
1384
|
-
}
|
|
1385
|
-
onChange();
|
|
1386
|
-
};
|
|
866
|
+
let e = editor;
|
|
867
|
+
let { apply } = e;
|
|
868
|
+
e = withDOM(e, clipboardFormatKey);
|
|
1387
869
|
e.setFragmentData = (dataTransfer, originEvent) => {
|
|
1388
870
|
const { selection } = e;
|
|
1389
871
|
if (!selection) {
|
|
@@ -1472,11 +954,11 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
|
1472
954
|
}
|
|
1473
955
|
};
|
|
1474
956
|
e.insertData = async (data) => {
|
|
1475
|
-
if (!(await e.
|
|
957
|
+
if (!(await e.customInsertFragmentData(data))) {
|
|
1476
958
|
e.insertTextData(data);
|
|
1477
959
|
}
|
|
1478
960
|
};
|
|
1479
|
-
e.
|
|
961
|
+
e.customInsertFragmentData = async (data) => {
|
|
1480
962
|
/**
|
|
1481
963
|
* Checking copied fragment from application/x-slate-fragment or data-slate-fragment
|
|
1482
964
|
*/
|
|
@@ -1487,7 +969,7 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
|
1487
969
|
}
|
|
1488
970
|
return false;
|
|
1489
971
|
};
|
|
1490
|
-
e.
|
|
972
|
+
e.customInsertTextData = async (data) => {
|
|
1491
973
|
const clipboardData = await getClipboardData(data);
|
|
1492
974
|
if (clipboardData && clipboardData.text) {
|
|
1493
975
|
const lines = clipboardData.text.split(/\r\n|\r|\n/);
|
|
@@ -1515,6 +997,56 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
|
1515
997
|
console.error(errorData);
|
|
1516
998
|
}
|
|
1517
999
|
};
|
|
1000
|
+
// exist issue for move operation in withDOM
|
|
1001
|
+
e.apply = (op) => {
|
|
1002
|
+
const matches = [];
|
|
1003
|
+
switch (op.type) {
|
|
1004
|
+
case 'insert_text':
|
|
1005
|
+
case 'remove_text':
|
|
1006
|
+
case 'set_node': {
|
|
1007
|
+
for (const [node, path] of Editor.levels(e, { at: op.path })) {
|
|
1008
|
+
const key = AngularEditor.findKey(e, node);
|
|
1009
|
+
matches.push([path, key]);
|
|
1010
|
+
}
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
case 'insert_node':
|
|
1014
|
+
case 'remove_node':
|
|
1015
|
+
case 'merge_node':
|
|
1016
|
+
case 'split_node': {
|
|
1017
|
+
for (const [node, path] of Editor.levels(e, {
|
|
1018
|
+
at: Path.parent(op.path)
|
|
1019
|
+
})) {
|
|
1020
|
+
const key = AngularEditor.findKey(e, node);
|
|
1021
|
+
matches.push([path, key]);
|
|
1022
|
+
}
|
|
1023
|
+
break;
|
|
1024
|
+
}
|
|
1025
|
+
case 'move_node': {
|
|
1026
|
+
const commonPath = Path.common(Path.parent(op.path), Path.parent(op.newPath));
|
|
1027
|
+
for (const [node, path] of Editor.levels(e, {
|
|
1028
|
+
at: Path.parent(op.path)
|
|
1029
|
+
})) {
|
|
1030
|
+
const key = AngularEditor.findKey(e, node);
|
|
1031
|
+
matches.push([Editor.pathRef(editor, path), key]);
|
|
1032
|
+
}
|
|
1033
|
+
for (const [node, path] of Editor.levels(e, {
|
|
1034
|
+
at: Path.parent(op.newPath)
|
|
1035
|
+
})) {
|
|
1036
|
+
if (path.length > commonPath.length) {
|
|
1037
|
+
const key = AngularEditor.findKey(e, node);
|
|
1038
|
+
matches.push([Editor.pathRef(editor, path), key]);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
break;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
apply(op);
|
|
1045
|
+
for (const [source, key] of matches) {
|
|
1046
|
+
const [node] = Editor.node(e, Path.isPath(source) ? source : source.current);
|
|
1047
|
+
NODE_TO_KEY.set(node, key);
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1518
1050
|
return e;
|
|
1519
1051
|
};
|
|
1520
1052
|
|
|
@@ -3118,8 +2650,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImpor
|
|
|
3118
2650
|
|
|
3119
2651
|
const SLATE_DEFAULT_LEAF_COMPONENT_TOKEN = new InjectionToken('slate-default-leaf-token');
|
|
3120
2652
|
|
|
3121
|
-
const TRIPLE_CLICK = 3;
|
|
3122
|
-
|
|
3123
2653
|
// not correctly clipboardData on beforeinput
|
|
3124
2654
|
const forceOnDOMPaste = IS_SAFARI;
|
|
3125
2655
|
class SlateEditable {
|
|
@@ -3170,7 +2700,7 @@ class SlateEditable {
|
|
|
3170
2700
|
EDITOR_TO_ELEMENT.set(this.editor, this.elementRef.nativeElement);
|
|
3171
2701
|
NODE_TO_ELEMENT.set(this.editor, this.elementRef.nativeElement);
|
|
3172
2702
|
ELEMENT_TO_NODE.set(this.elementRef.nativeElement, this.editor);
|
|
3173
|
-
|
|
2703
|
+
IS_READ_ONLY.set(this.editor, this.readonly);
|
|
3174
2704
|
EDITOR_TO_ON_CHANGE.set(this.editor, () => {
|
|
3175
2705
|
this.ngZone.run(() => {
|
|
3176
2706
|
this.onChange();
|
|
@@ -3202,7 +2732,7 @@ class SlateEditable {
|
|
|
3202
2732
|
}
|
|
3203
2733
|
const readonlyChange = simpleChanges['readonly'];
|
|
3204
2734
|
if (readonlyChange) {
|
|
3205
|
-
|
|
2735
|
+
IS_READ_ONLY.set(this.editor, this.readonly);
|
|
3206
2736
|
this.render();
|
|
3207
2737
|
this.toSlateSelection();
|
|
3208
2738
|
}
|
|
@@ -3276,7 +2806,10 @@ class SlateEditable {
|
|
|
3276
2806
|
}
|
|
3277
2807
|
// If the DOM selection is in the editor and the editor selection is already correct, we're done.
|
|
3278
2808
|
if (hasDomSelection && hasDomSelectionInEditor && selection && hasStringTarget(domSelection)) {
|
|
3279
|
-
const rangeFromDOMSelection = AngularEditor.toSlateRange(this.editor, domSelection, {
|
|
2809
|
+
const rangeFromDOMSelection = AngularEditor.toSlateRange(this.editor, domSelection, {
|
|
2810
|
+
exactMatch: false,
|
|
2811
|
+
suppressThrow: true
|
|
2812
|
+
});
|
|
3280
2813
|
if (rangeFromDOMSelection && Range.equals(rangeFromDOMSelection, selection)) {
|
|
3281
2814
|
return;
|
|
3282
2815
|
}
|
|
@@ -3290,7 +2823,7 @@ class SlateEditable {
|
|
|
3290
2823
|
// but Slate's value is not being updated through any operation
|
|
3291
2824
|
// and thus it doesn't transform selection on its own
|
|
3292
2825
|
if (selection && !AngularEditor.hasRange(this.editor, selection)) {
|
|
3293
|
-
this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection, { suppressThrow: false });
|
|
2826
|
+
this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection, { exactMatch: false, suppressThrow: false });
|
|
3294
2827
|
return;
|
|
3295
2828
|
}
|
|
3296
2829
|
// Otherwise the DOM selection is out of sync, so update it.
|
|
@@ -3514,14 +3047,14 @@ class SlateEditable {
|
|
|
3514
3047
|
let targetRange = null;
|
|
3515
3048
|
let [nativeTargetRange] = event.getTargetRanges();
|
|
3516
3049
|
if (nativeTargetRange) {
|
|
3517
|
-
targetRange = AngularEditor.toSlateRange(editor, nativeTargetRange);
|
|
3050
|
+
targetRange = AngularEditor.toSlateRange(editor, nativeTargetRange, { exactMatch: false, suppressThrow: false });
|
|
3518
3051
|
}
|
|
3519
3052
|
// COMPAT: SelectionChange event is fired after the action is performed, so we
|
|
3520
3053
|
// have to manually get the selection here to ensure it's up-to-date.
|
|
3521
3054
|
const window = AngularEditor.getWindow(editor);
|
|
3522
3055
|
const domSelection = window.getSelection();
|
|
3523
3056
|
if (!targetRange && domSelection) {
|
|
3524
|
-
targetRange = AngularEditor.toSlateRange(editor, domSelection);
|
|
3057
|
+
targetRange = AngularEditor.toSlateRange(editor, domSelection, { exactMatch: false, suppressThrow: false });
|
|
3525
3058
|
}
|
|
3526
3059
|
targetRange = targetRange ?? editor.selection;
|
|
3527
3060
|
if (type === 'insertCompositionText') {
|
|
@@ -3567,7 +3100,7 @@ class SlateEditable {
|
|
|
3567
3100
|
}
|
|
3568
3101
|
}
|
|
3569
3102
|
if (!this.readonly &&
|
|
3570
|
-
hasEditableTarget(editor, event.target) &&
|
|
3103
|
+
AngularEditor.hasEditableTarget(editor, event.target) &&
|
|
3571
3104
|
!isTargetInsideVoid(editor, activeElement) &&
|
|
3572
3105
|
!this.isDOMEventHandled(event, this.beforeInput)) {
|
|
3573
3106
|
try {
|
|
@@ -3668,7 +3201,7 @@ class SlateEditable {
|
|
|
3668
3201
|
onDOMBlur(event) {
|
|
3669
3202
|
if (this.readonly ||
|
|
3670
3203
|
this.isUpdatingSelection ||
|
|
3671
|
-
!hasEditableTarget(this.editor, event.target) ||
|
|
3204
|
+
!AngularEditor.hasEditableTarget(this.editor, event.target) ||
|
|
3672
3205
|
this.isDOMEventHandled(event, this.blur)) {
|
|
3673
3206
|
return;
|
|
3674
3207
|
}
|
|
@@ -3707,7 +3240,7 @@ class SlateEditable {
|
|
|
3707
3240
|
}
|
|
3708
3241
|
onDOMClick(event) {
|
|
3709
3242
|
if (!this.readonly &&
|
|
3710
|
-
hasTarget(this.editor, event.target) &&
|
|
3243
|
+
AngularEditor.hasTarget(this.editor, event.target) &&
|
|
3711
3244
|
!this.isDOMEventHandled(event, this.click) &&
|
|
3712
3245
|
isDOMNode(event.target)) {
|
|
3713
3246
|
const node = AngularEditor.toSlateNode(this.editor, event.target);
|
|
@@ -3747,7 +3280,7 @@ class SlateEditable {
|
|
|
3747
3280
|
this.forceRender();
|
|
3748
3281
|
}
|
|
3749
3282
|
}
|
|
3750
|
-
if (hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionStart)) {
|
|
3283
|
+
if (AngularEditor.hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionStart)) {
|
|
3751
3284
|
this.isComposing = true;
|
|
3752
3285
|
}
|
|
3753
3286
|
this.render();
|
|
@@ -3759,7 +3292,7 @@ class SlateEditable {
|
|
|
3759
3292
|
if (!event.data && !Range.isCollapsed(this.editor.selection)) {
|
|
3760
3293
|
Transforms.delete(this.editor);
|
|
3761
3294
|
}
|
|
3762
|
-
if (hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionEnd)) {
|
|
3295
|
+
if (AngularEditor.hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionEnd)) {
|
|
3763
3296
|
// COMPAT: In Chrome/Firefox, `beforeinput` events for compositions
|
|
3764
3297
|
// aren't correct and never fire the "insertFromComposition"
|
|
3765
3298
|
// type that we need. So instead, insert whenever a composition
|
|
@@ -3777,13 +3310,13 @@ class SlateEditable {
|
|
|
3777
3310
|
onDOMCopy(event) {
|
|
3778
3311
|
const window = AngularEditor.getWindow(this.editor);
|
|
3779
3312
|
const isOutsideSlate = !hasStringTarget(window.getSelection()) && isTargetInsideVoid(this.editor, event.target);
|
|
3780
|
-
if (!isOutsideSlate && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.copy)) {
|
|
3313
|
+
if (!isOutsideSlate && AngularEditor.hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.copy)) {
|
|
3781
3314
|
event.preventDefault();
|
|
3782
3315
|
AngularEditor.setFragmentData(this.editor, event.clipboardData, 'copy');
|
|
3783
3316
|
}
|
|
3784
3317
|
}
|
|
3785
3318
|
onDOMCut(event) {
|
|
3786
|
-
if (!this.readonly && hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.cut)) {
|
|
3319
|
+
if (!this.readonly && AngularEditor.hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.cut)) {
|
|
3787
3320
|
event.preventDefault();
|
|
3788
3321
|
AngularEditor.setFragmentData(this.editor, event.clipboardData, 'cut');
|
|
3789
3322
|
const { selection } = this.editor;
|
|
@@ -3793,7 +3326,7 @@ class SlateEditable {
|
|
|
3793
3326
|
}
|
|
3794
3327
|
}
|
|
3795
3328
|
onDOMDragOver(event) {
|
|
3796
|
-
if (hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragOver)) {
|
|
3329
|
+
if (AngularEditor.hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragOver)) {
|
|
3797
3330
|
// Only when the target is void, call `preventDefault` to signal
|
|
3798
3331
|
// that drops are allowed. Editable content is droppable by
|
|
3799
3332
|
// default, and calling `preventDefault` hides the cursor.
|
|
@@ -3804,7 +3337,7 @@ class SlateEditable {
|
|
|
3804
3337
|
}
|
|
3805
3338
|
}
|
|
3806
3339
|
onDOMDragStart(event) {
|
|
3807
|
-
if (!this.readonly && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragStart)) {
|
|
3340
|
+
if (!this.readonly && AngularEditor.hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragStart)) {
|
|
3808
3341
|
const node = AngularEditor.toSlateNode(this.editor, event.target);
|
|
3809
3342
|
const path = AngularEditor.findPath(this.editor, node);
|
|
3810
3343
|
const voidMatch = Element.isElement(node) && (Editor.isVoid(this.editor, node) || Editor.void(this.editor, { at: path, voids: true }));
|
|
@@ -3820,7 +3353,7 @@ class SlateEditable {
|
|
|
3820
3353
|
}
|
|
3821
3354
|
onDOMDrop(event) {
|
|
3822
3355
|
const editor = this.editor;
|
|
3823
|
-
if (!this.readonly && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.drop)) {
|
|
3356
|
+
if (!this.readonly && AngularEditor.hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.drop)) {
|
|
3824
3357
|
event.preventDefault();
|
|
3825
3358
|
// Keep a reference to the dragged range before updating selection
|
|
3826
3359
|
const draggedRange = editor.selection;
|
|
@@ -3847,7 +3380,7 @@ class SlateEditable {
|
|
|
3847
3380
|
onDOMDragEnd(event) {
|
|
3848
3381
|
if (!this.readonly &&
|
|
3849
3382
|
this.isDraggingInternally &&
|
|
3850
|
-
hasTarget(this.editor, event.target) &&
|
|
3383
|
+
AngularEditor.hasTarget(this.editor, event.target) &&
|
|
3851
3384
|
!this.isDOMEventHandled(event, this.dragEnd)) {
|
|
3852
3385
|
this.isDraggingInternally = false;
|
|
3853
3386
|
}
|
|
@@ -3855,7 +3388,7 @@ class SlateEditable {
|
|
|
3855
3388
|
onDOMFocus(event) {
|
|
3856
3389
|
if (!this.readonly &&
|
|
3857
3390
|
!this.isUpdatingSelection &&
|
|
3858
|
-
hasEditableTarget(this.editor, event.target) &&
|
|
3391
|
+
AngularEditor.hasEditableTarget(this.editor, event.target) &&
|
|
3859
3392
|
!this.isDOMEventHandled(event, this.focus)) {
|
|
3860
3393
|
const el = AngularEditor.toDOMNode(this.editor, this.editor);
|
|
3861
3394
|
const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
|
|
@@ -3875,7 +3408,7 @@ class SlateEditable {
|
|
|
3875
3408
|
const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
|
|
3876
3409
|
const { activeElement } = root;
|
|
3877
3410
|
if (!this.readonly &&
|
|
3878
|
-
hasEditableTarget(editor, event.target) &&
|
|
3411
|
+
AngularEditor.hasEditableTarget(editor, event.target) &&
|
|
3879
3412
|
!isTargetInsideVoid(editor, activeElement) && // stop fire keydown handle when focus void node
|
|
3880
3413
|
!this.isComposing &&
|
|
3881
3414
|
!this.isDOMEventHandled(event, this.keydown)) {
|
|
@@ -4097,7 +3630,7 @@ class SlateEditable {
|
|
|
4097
3630
|
if (!this.isDOMEventHandled(event, this.paste) &&
|
|
4098
3631
|
(!HAS_BEFORE_INPUT_SUPPORT || isPlainTextOnlyPaste(event) || forceOnDOMPaste) &&
|
|
4099
3632
|
!this.readonly &&
|
|
4100
|
-
hasEditableTarget(this.editor, event.target)) {
|
|
3633
|
+
AngularEditor.hasEditableTarget(this.editor, event.target)) {
|
|
4101
3634
|
event.preventDefault();
|
|
4102
3635
|
AngularEditor.insertData(this.editor, event.clipboardData);
|
|
4103
3636
|
}
|
|
@@ -4109,7 +3642,7 @@ class SlateEditable {
|
|
|
4109
3642
|
if (!HAS_BEFORE_INPUT_SUPPORT &&
|
|
4110
3643
|
!this.readonly &&
|
|
4111
3644
|
!this.isDOMEventHandled(event.nativeEvent, this.beforeInput) &&
|
|
4112
|
-
hasEditableTarget(this.editor, event.nativeEvent.target)) {
|
|
3645
|
+
AngularEditor.hasEditableTarget(this.editor, event.nativeEvent.target)) {
|
|
4113
3646
|
event.nativeEvent.preventDefault();
|
|
4114
3647
|
try {
|
|
4115
3648
|
const text = event.data;
|
|
@@ -4300,36 +3833,15 @@ const defaultScrollSelectionIntoView = (editor, domRange) => {
|
|
|
4300
3833
|
delete leafEl.getBoundingClientRect;
|
|
4301
3834
|
}
|
|
4302
3835
|
};
|
|
4303
|
-
/**
|
|
4304
|
-
* Check if the target is editable and in the editor.
|
|
4305
|
-
*/
|
|
4306
|
-
const hasEditableTarget = (editor, target) => {
|
|
4307
|
-
return isDOMNode(target) && AngularEditor.hasDOMNode(editor, target, { editable: true });
|
|
4308
|
-
};
|
|
4309
|
-
/**
|
|
4310
|
-
* Check if two DOM range objects are equal.
|
|
4311
|
-
*/
|
|
4312
|
-
const isRangeEqual = (a, b) => {
|
|
4313
|
-
return ((a.startContainer === b.startContainer &&
|
|
4314
|
-
a.startOffset === b.startOffset &&
|
|
4315
|
-
a.endContainer === b.endContainer &&
|
|
4316
|
-
a.endOffset === b.endOffset) ||
|
|
4317
|
-
(a.startContainer === b.endContainer &&
|
|
4318
|
-
a.startOffset === b.endOffset &&
|
|
4319
|
-
a.endContainer === b.startContainer &&
|
|
4320
|
-
a.endOffset === b.startOffset));
|
|
4321
|
-
};
|
|
4322
|
-
/**
|
|
4323
|
-
* Check if the target is in the editor.
|
|
4324
|
-
*/
|
|
4325
|
-
const hasTarget = (editor, target) => {
|
|
4326
|
-
return isDOMNode(target) && AngularEditor.hasDOMNode(editor, target);
|
|
4327
|
-
};
|
|
4328
3836
|
/**
|
|
4329
3837
|
* Check if the target is inside void and in the editor.
|
|
4330
3838
|
*/
|
|
4331
3839
|
const isTargetInsideVoid = (editor, target) => {
|
|
4332
|
-
|
|
3840
|
+
let slateNode = null;
|
|
3841
|
+
try {
|
|
3842
|
+
slateNode = AngularEditor.hasTarget(editor, target) && AngularEditor.toSlateNode(editor, target);
|
|
3843
|
+
}
|
|
3844
|
+
catch (error) { }
|
|
4333
3845
|
return slateNode && Element.isElement(slateNode) && Editor.isVoid(editor, slateNode);
|
|
4334
3846
|
};
|
|
4335
3847
|
const hasStringTarget = (domSelection) => {
|
|
@@ -4490,5 +4002,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImpor
|
|
|
4490
4002
|
* Generated bundle index. Do not edit.
|
|
4491
4003
|
*/
|
|
4492
4004
|
|
|
4493
|
-
export { AngularEditor, BaseComponent, BaseElementComponent, BaseLeafComponent, BaseTextComponent,
|
|
4005
|
+
export { AngularEditor, BaseComponent, BaseElementComponent, BaseLeafComponent, BaseTextComponent, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, ELEMENT_TO_COMPONENT, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, PLACEHOLDER_SYMBOL, SlateChildren, SlateChildrenOutlet, SlateDefaultString, SlateEditable, SlateElement, SlateErrorCode, SlateFragmentAttributeKey, SlateLeaves, SlateModule, SlateString, blobAsString, buildHTMLText, check, completeTable, createClipboardData, createThrottleRAF, defaultScrollSelectionIntoView, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getDataTransferClipboard, getDataTransferClipboardText, getNavigatorClipboard, getPlainText, getSlateFragmentAttribute, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDOMText, isDecoratorRangeListEqual, isEmpty, isInvalidTable, isTemplateRef, isValid, normalize, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
|
|
4494
4006
|
//# sourceMappingURL=slate-angular.mjs.map
|