slate-angular 19.0.0-next.0 → 19.1.0-next.0
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 +462 -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/public-api.d.ts +1 -0
- package/utils/block-card.d.ts +1 -1
- package/utils/dom.d.ts +3 -63
- package/utils/index.d.ts +0 -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,6 @@
|
|
|
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';
|
|
3
|
+
export { NODE_TO_INDEX, NODE_TO_PARENT } from 'slate-dom';
|
|
2
4
|
import { isKeyHotkey } from 'is-hotkey';
|
|
3
5
|
import * as i0 from '@angular/core';
|
|
4
6
|
import { TemplateRef, ViewChild, ChangeDetectionStrategy, Component, InjectionToken, ComponentRef, IterableDiffers, inject, ElementRef, ChangeDetectorRef, Input, Directive, HostBinding, ViewContainerRef, forwardRef, Inject, NgModule } from '@angular/core';
|
|
@@ -9,258 +11,6 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
|
9
11
|
import { HistoryEditor } from 'slate-history';
|
|
10
12
|
import { CommonModule } from '@angular/common';
|
|
11
13
|
|
|
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
14
|
const FAKE_LEFT_BLOCK_CARD_OFFSET = -1;
|
|
265
15
|
const FAKE_RIGHT_BLOCK_CARD_OFFSET = -2;
|
|
266
16
|
function hasBlockCardWithNode(node) {
|
|
@@ -286,61 +36,251 @@ function isCardCenterByTargetAttr(targetAttr) {
|
|
|
286
36
|
return targetAttr && targetAttr.nodeValue === 'card-center';
|
|
287
37
|
}
|
|
288
38
|
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
39
|
+
const customToDOMNode = (editor, node) => {
|
|
40
|
+
const domNode = Editor.isEditor(node) ? EDITOR_TO_ELEMENT.get(editor) : NODE_TO_ELEMENT.get(node);
|
|
41
|
+
if (!domNode) {
|
|
42
|
+
throw new Error(`Cannot resolve a DOM node from Slate node: ${JSON.stringify(node)}`);
|
|
43
|
+
}
|
|
44
|
+
return domNode;
|
|
45
|
+
};
|
|
46
|
+
DOMEditor.toDOMNode = customToDOMNode;
|
|
47
|
+
const toDOMPointForBlockCard = (editor, point) => {
|
|
48
|
+
const [node] = Editor.node(editor, point.path);
|
|
49
|
+
const [parentNode] = Editor.parent(editor, point.path);
|
|
50
|
+
if (editor.isBlockCard(parentNode) || editor.isBlockCard(node)) {
|
|
51
|
+
if (point.offset < 0) {
|
|
52
|
+
if (point.offset === FAKE_LEFT_BLOCK_CARD_OFFSET) {
|
|
53
|
+
const cursorNode = CustomDOMEditor.getCardCursorNode(editor, node, { direction: 'left' });
|
|
54
|
+
return [cursorNode, 1];
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const cursorNode = CustomDOMEditor.getCardCursorNode(editor, node, { direction: 'right' });
|
|
58
|
+
return [cursorNode, 1];
|
|
59
|
+
}
|
|
297
60
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
61
|
+
if (editor.selection && Range.isExpanded(editor.selection)) {
|
|
62
|
+
const [start, end] = Range.edges(editor.selection);
|
|
63
|
+
if (start === point) {
|
|
64
|
+
const cursorNode = CustomDOMEditor.getCardCursorNode(editor, parentNode, { direction: 'left' });
|
|
65
|
+
return [cursorNode, 1];
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const cursorNode = CustomDOMEditor.getCardCursorNode(editor, parentNode, { direction: 'right' });
|
|
69
|
+
return [cursorNode, 1];
|
|
70
|
+
}
|
|
308
71
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const customToDOMPoint = (editor, point) => {
|
|
75
|
+
const [node] = Editor.node(editor, point.path);
|
|
76
|
+
const el = customToDOMNode(editor, node);
|
|
77
|
+
let domPoint;
|
|
78
|
+
const domPointForBlackCard = toDOMPointForBlockCard(editor, point);
|
|
79
|
+
if (domPointForBlackCard) {
|
|
80
|
+
return domPointForBlackCard;
|
|
81
|
+
}
|
|
82
|
+
// If we're inside a void node, force the offset to 0, otherwise the zero
|
|
83
|
+
// width spacing character will result in an incorrect offset of 1
|
|
84
|
+
if (Editor.void(editor, { at: point })) {
|
|
85
|
+
point = { path: point.path, offset: 0 };
|
|
86
|
+
}
|
|
87
|
+
// For each leaf, we need to isolate its content, which means filtering
|
|
88
|
+
// to its direct text and zero-width spans. (We have to filter out any
|
|
89
|
+
// other siblings that may have been rendered alongside them.)
|
|
90
|
+
const selector = `[data-slate-string], [data-slate-zero-width]`;
|
|
91
|
+
const texts = Array.from(el.querySelectorAll(selector));
|
|
92
|
+
let start = 0;
|
|
93
|
+
for (const text of texts) {
|
|
94
|
+
const domNode = text.childNodes[0];
|
|
95
|
+
if (domNode == null || domNode.textContent == null) {
|
|
96
|
+
continue;
|
|
317
97
|
}
|
|
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
|
-
}
|
|
98
|
+
const { length } = domNode.textContent;
|
|
99
|
+
const attr = text.getAttribute('data-slate-length');
|
|
100
|
+
const trueLength = attr == null ? length : parseInt(attr, 10);
|
|
101
|
+
const end = start + trueLength;
|
|
102
|
+
if (point.offset <= end) {
|
|
103
|
+
const offset = Math.min(length, Math.max(0, point.offset - start));
|
|
104
|
+
domPoint = [domNode, offset];
|
|
105
|
+
// fixed cursor position after zero width char
|
|
106
|
+
if (offset === 0 && length === 1 && domNode.textContent === '\uFEFF') {
|
|
107
|
+
domPoint = [domNode, offset + 1];
|
|
334
108
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
start = end;
|
|
112
|
+
}
|
|
113
|
+
if (!domPoint) {
|
|
114
|
+
throw new Error(`Cannot resolve a DOM point from Slate point: ${JSON.stringify(point)}`);
|
|
115
|
+
}
|
|
116
|
+
return domPoint;
|
|
117
|
+
};
|
|
118
|
+
DOMEditor.toDOMPoint = customToDOMPoint;
|
|
119
|
+
const toSlatePointForBlockCard = (editor, domPoint, nearestNode) => {
|
|
120
|
+
const [domNode] = domPoint;
|
|
121
|
+
const cardTargetAttr = getCardTargetAttribute(domNode);
|
|
122
|
+
if (cardTargetAttr) {
|
|
123
|
+
const domSelection = window.getSelection();
|
|
124
|
+
const blockCardEntry = CustomDOMEditor.toSlateCardEntry(editor, domNode) || CustomDOMEditor.toSlateCardEntry(editor, nearestNode);
|
|
125
|
+
const [, blockPath] = blockCardEntry;
|
|
126
|
+
if (domSelection.isCollapsed) {
|
|
127
|
+
if (isCardLeftByTargetAttr(cardTargetAttr)) {
|
|
128
|
+
return { path: blockPath, offset: -1 };
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
return { path: blockPath, offset: -2 };
|
|
338
132
|
}
|
|
339
|
-
path.unshift(i);
|
|
340
|
-
child = parent;
|
|
341
133
|
}
|
|
342
|
-
|
|
343
|
-
|
|
134
|
+
if (isCardLeftByTargetAttr(cardTargetAttr)) {
|
|
135
|
+
return Editor.start(editor, blockPath);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
return Editor.end(editor, blockPath);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const customToSlatePoint = (editor, domPoint, options) => {
|
|
143
|
+
const { exactMatch, suppressThrow } = options;
|
|
144
|
+
const [nearestNode, nearestOffset] = normalizeDOMPoint(domPoint);
|
|
145
|
+
let parentNode = nearestNode.parentNode;
|
|
146
|
+
let textNode = null;
|
|
147
|
+
let offset = 0;
|
|
148
|
+
const slatePointForBlockCard = toSlatePointForBlockCard(editor, domPoint, nearestNode);
|
|
149
|
+
if (slatePointForBlockCard) {
|
|
150
|
+
return slatePointForBlockCard;
|
|
151
|
+
}
|
|
152
|
+
if (parentNode) {
|
|
153
|
+
const voidNode = parentNode.closest('[data-slate-void="true"]');
|
|
154
|
+
let leafNode = parentNode.closest('[data-slate-leaf]');
|
|
155
|
+
let domNode = null;
|
|
156
|
+
// Calculate how far into the text node the `nearestNode` is, so that we
|
|
157
|
+
// can determine what the offset relative to the text node is.
|
|
158
|
+
if (leafNode && CustomDOMEditor.isLeafInEditor(editor, leafNode)) {
|
|
159
|
+
textNode = leafNode.closest('[data-slate-node="text"]');
|
|
160
|
+
const window = DOMEditor.getWindow(editor);
|
|
161
|
+
const range = window.document.createRange();
|
|
162
|
+
range.setStart(textNode, 0);
|
|
163
|
+
range.setEnd(nearestNode, nearestOffset);
|
|
164
|
+
const contents = range.cloneContents();
|
|
165
|
+
const removals = [
|
|
166
|
+
...Array.prototype.slice.call(contents.querySelectorAll('[data-slate-zero-width]')),
|
|
167
|
+
...Array.prototype.slice.call(contents.querySelectorAll('[contenteditable=false]'))
|
|
168
|
+
];
|
|
169
|
+
removals.forEach(el => {
|
|
170
|
+
el.parentNode.removeChild(el);
|
|
171
|
+
});
|
|
172
|
+
// COMPAT: Edge has a bug where Range.prototype.toString() will
|
|
173
|
+
// convert \n into \r\n. The bug causes a loop when slate-react
|
|
174
|
+
// attempts to reposition its cursor to match the native position. Use
|
|
175
|
+
// textContent.length instead.
|
|
176
|
+
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/
|
|
177
|
+
offset = contents.textContent.length;
|
|
178
|
+
domNode = textNode;
|
|
179
|
+
}
|
|
180
|
+
else if (voidNode) {
|
|
181
|
+
// For void nodes, the element with the offset key will be a cousin, not an
|
|
182
|
+
// ancestor, so find it by going down from the nearest void parent.
|
|
183
|
+
const spacer = voidNode.querySelector('[data-slate-spacer="true"]');
|
|
184
|
+
leafNode = spacer.firstElementChild;
|
|
185
|
+
parentNode = leafNode.firstElementChild;
|
|
186
|
+
textNode = spacer;
|
|
187
|
+
domNode = leafNode;
|
|
188
|
+
offset = domNode.textContent.length;
|
|
189
|
+
}
|
|
190
|
+
// COMPAT: If the parent node is a Slate zero-width space, editor is
|
|
191
|
+
// because the text node should have no characters. However, during IME
|
|
192
|
+
// composition the ASCII characters will be prepended to the zero-width
|
|
193
|
+
// space, so subtract 1 from the offset to account for the zero-width
|
|
194
|
+
// space character.
|
|
195
|
+
if (domNode && offset === domNode.textContent.length && parentNode && parentNode.hasAttribute('data-slate-zero-width')) {
|
|
196
|
+
offset--;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (!textNode) {
|
|
200
|
+
if (suppressThrow) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
throw new Error(`Cannot resolve a Slate point from DOM point: ${domPoint}`);
|
|
204
|
+
}
|
|
205
|
+
// COMPAT: If someone is clicking from one Slate editor into another,
|
|
206
|
+
// the select event fires twice, once for the old editor's `element`
|
|
207
|
+
// first, and then afterwards for the correct `element`. (2017/03/03)
|
|
208
|
+
let slateNode = null;
|
|
209
|
+
try {
|
|
210
|
+
slateNode = CustomDOMEditor.toSlateNode(editor, textNode);
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
if (!suppressThrow) {
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (!slateNode && suppressThrow) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
const path = CustomDOMEditor.findPath(editor, slateNode);
|
|
221
|
+
return { path, offset };
|
|
222
|
+
};
|
|
223
|
+
DOMEditor.toSlatePoint = customToSlatePoint;
|
|
224
|
+
const customToSlateRange = (editor, domRange, options) => {
|
|
225
|
+
const { exactMatch, suppressThrow } = options || {};
|
|
226
|
+
const el = isDOMSelection(domRange) ? domRange.anchorNode : domRange.startContainer;
|
|
227
|
+
let anchorNode;
|
|
228
|
+
let anchorOffset;
|
|
229
|
+
let focusNode;
|
|
230
|
+
let focusOffset;
|
|
231
|
+
let isCollapsed;
|
|
232
|
+
if (el) {
|
|
233
|
+
if (isDOMSelection(domRange)) {
|
|
234
|
+
anchorNode = domRange.anchorNode;
|
|
235
|
+
anchorOffset = domRange.anchorOffset;
|
|
236
|
+
focusNode = domRange.focusNode;
|
|
237
|
+
focusOffset = domRange.focusOffset;
|
|
238
|
+
// COMPAT: There's a bug in chrome that always returns `true` for
|
|
239
|
+
// `isCollapsed` for a Selection that comes from a ShadowRoot.
|
|
240
|
+
// (2020/08/08)
|
|
241
|
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=447523
|
|
242
|
+
if (IS_CHROME$1 && hasShadowRoot(anchorNode)) {
|
|
243
|
+
isCollapsed = domRange.anchorNode === domRange.focusNode && domRange.anchorOffset === domRange.focusOffset;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
isCollapsed = domRange.isCollapsed;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
anchorNode = domRange.startContainer;
|
|
251
|
+
anchorOffset = domRange.startOffset;
|
|
252
|
+
focusNode = domRange.endContainer;
|
|
253
|
+
focusOffset = domRange.endOffset;
|
|
254
|
+
isCollapsed = domRange.collapsed;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (anchorNode == null || focusNode == null || anchorOffset == null || focusOffset == null) {
|
|
258
|
+
throw new Error(`Cannot resolve a Slate range from DOM range: ${domRange}`);
|
|
259
|
+
}
|
|
260
|
+
const anchor = DOMEditor.toSlatePoint(editor, [anchorNode, anchorOffset], { suppressThrow, exactMatch });
|
|
261
|
+
if (!anchor) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const focus = isCollapsed ? anchor : DOMEditor.toSlatePoint(editor, [focusNode, focusOffset], { suppressThrow, exactMatch });
|
|
265
|
+
if (!focus) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
let range = { anchor: anchor, focus: focus };
|
|
269
|
+
// if the selection is a hanging range that ends in a void
|
|
270
|
+
// and the DOM focus is an Element
|
|
271
|
+
// (meaning that the selection ends before the element)
|
|
272
|
+
// unhang the range to avoid mistakenly including the void
|
|
273
|
+
if (Range.isExpanded(range) &&
|
|
274
|
+
Range.isForward(range) &&
|
|
275
|
+
isDOMElement(focusNode) &&
|
|
276
|
+
Editor.void(editor, { at: range.focus, mode: 'highest' })) {
|
|
277
|
+
range = Editor.unhangRange(editor, range, { voids: true });
|
|
278
|
+
}
|
|
279
|
+
return range;
|
|
280
|
+
};
|
|
281
|
+
DOMEditor.toSlateRange = customToSlateRange;
|
|
282
|
+
const CustomDOMEditor = {
|
|
283
|
+
...DOMEditor,
|
|
344
284
|
isNodeInEditor(editor, node) {
|
|
345
285
|
let child = node;
|
|
346
286
|
while (true) {
|
|
@@ -361,321 +301,14 @@ const AngularEditor = {
|
|
|
361
301
|
}
|
|
362
302
|
return false;
|
|
363
303
|
},
|
|
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
|
|
304
|
+
isLeafInEditor(editor, leafNode) {
|
|
305
|
+
const textNode = leafNode.closest('[data-slate-node="text"]');
|
|
306
|
+
let node = null;
|
|
452
307
|
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}`);
|
|
308
|
+
node = CustomDOMEditor.toSlateNode(editor, textNode);
|
|
621
309
|
}
|
|
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)) {
|
|
310
|
+
catch (error) { }
|
|
311
|
+
if (node && CustomDOMEditor.isNodeInEditor(editor, node)) {
|
|
679
312
|
return true;
|
|
680
313
|
}
|
|
681
314
|
else {
|
|
@@ -683,162 +316,22 @@ const AngularEditor = {
|
|
|
683
316
|
}
|
|
684
317
|
},
|
|
685
318
|
/**
|
|
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.
|
|
319
|
+
* Check if the editor is hanging right.
|
|
782
320
|
*/
|
|
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;
|
|
321
|
+
isBlockHangingRight(editor) {
|
|
322
|
+
const { selection } = editor;
|
|
323
|
+
if (!selection) {
|
|
324
|
+
return false;
|
|
822
325
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
return null;
|
|
326
|
+
if (Range.isCollapsed(selection)) {
|
|
327
|
+
return false;
|
|
826
328
|
}
|
|
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);
|
|
329
|
+
const [start, end] = Range.edges(selection);
|
|
330
|
+
const endBlock = Editor.above(editor, {
|
|
331
|
+
at: end,
|
|
332
|
+
match: node => Element.isElement(node) && Editor.isBlock(editor, node)
|
|
333
|
+
});
|
|
334
|
+
return Editor.isStart(editor, end, endBlock[1]);
|
|
842
335
|
},
|
|
843
336
|
isBlockCardLeftCursor(editor) {
|
|
844
337
|
return (editor.selection?.anchor?.offset === FAKE_LEFT_BLOCK_CARD_OFFSET &&
|
|
@@ -849,15 +342,45 @@ const AngularEditor = {
|
|
|
849
342
|
editor.selection?.focus?.offset === FAKE_RIGHT_BLOCK_CARD_OFFSET);
|
|
850
343
|
},
|
|
851
344
|
getCardCursorNode(editor, blockCardNode, options) {
|
|
852
|
-
const blockCardElement =
|
|
345
|
+
const blockCardElement = DOMEditor.toDOMNode(editor, blockCardNode);
|
|
853
346
|
const cardCenter = blockCardElement.parentElement;
|
|
854
347
|
return options.direction === 'left' ? cardCenter.previousElementSibling.firstChild : cardCenter.nextElementSibling.firstChild;
|
|
855
348
|
},
|
|
856
349
|
toSlateCardEntry(editor, node) {
|
|
857
350
|
const element = node.parentElement.closest('.slate-block-card')?.querySelector('[card-target="card-center"]').firstElementChild;
|
|
858
|
-
const slateNode =
|
|
859
|
-
const path =
|
|
351
|
+
const slateNode = DOMEditor.toSlateNode(editor, element);
|
|
352
|
+
const path = DOMEditor.findPath(editor, slateNode);
|
|
860
353
|
return [slateNode, path];
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const AngularEditor = {
|
|
358
|
+
...CustomDOMEditor,
|
|
359
|
+
/**
|
|
360
|
+
* handle editor error.
|
|
361
|
+
*/
|
|
362
|
+
onError(errorData) {
|
|
363
|
+
if (errorData.nativeError) {
|
|
364
|
+
throw errorData.nativeError;
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
/**
|
|
368
|
+
* onKeydown hook.
|
|
369
|
+
*/
|
|
370
|
+
onKeydown(editor, data) {
|
|
371
|
+
editor.onKeydown(data);
|
|
372
|
+
},
|
|
373
|
+
/**
|
|
374
|
+
* onClick hook.
|
|
375
|
+
*/
|
|
376
|
+
onClick(editor, data) {
|
|
377
|
+
editor.onClick(data);
|
|
378
|
+
},
|
|
379
|
+
deleteCutData(editor) {
|
|
380
|
+
editor.deleteCutData();
|
|
381
|
+
},
|
|
382
|
+
isLeafBlock(editor, node) {
|
|
383
|
+
return Element.isElement(node) && !editor.isInline(node) && Editor.hasInlines(editor, node);
|
|
861
384
|
},
|
|
862
385
|
/**
|
|
863
386
|
* move native selection to card-left or card-right
|
|
@@ -883,13 +406,53 @@ const AngularEditor = {
|
|
|
883
406
|
offset: options.direction === 'left' ? FAKE_LEFT_BLOCK_CARD_OFFSET : FAKE_RIGHT_BLOCK_CARD_OFFSET
|
|
884
407
|
};
|
|
885
408
|
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
409
|
}
|
|
891
410
|
};
|
|
892
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Symbols.
|
|
414
|
+
*/
|
|
415
|
+
const PLACEHOLDER_SYMBOL = Symbol('placeholder');
|
|
416
|
+
/**
|
|
417
|
+
* Weak map for associating the html element with the component.
|
|
418
|
+
*/
|
|
419
|
+
const ELEMENT_TO_COMPONENT = new WeakMap();
|
|
420
|
+
const EDITOR_TO_AFTER_VIEW_INIT_QUEUE = new WeakMap();
|
|
421
|
+
|
|
422
|
+
const IS_IOS = typeof navigator !== 'undefined' &&
|
|
423
|
+
typeof window !== 'undefined' &&
|
|
424
|
+
/iPad|iPhone|iPod/.test(navigator.userAgent) &&
|
|
425
|
+
!window.MSStream;
|
|
426
|
+
const IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent);
|
|
427
|
+
const IS_ANDROID = typeof navigator !== 'undefined' && /Android/.test(navigator.userAgent);
|
|
428
|
+
const IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
|
|
429
|
+
const IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent);
|
|
430
|
+
// "modern" Edge was released at 79.x
|
|
431
|
+
const IS_EDGE_LEGACY = typeof navigator !== 'undefined' && /Edge?\/(?:[0-6][0-9]|[0-7][0-8])(?:\.)/i.test(navigator.userAgent);
|
|
432
|
+
const IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.userAgent);
|
|
433
|
+
// Native beforeInput events don't work well with react on Chrome 75 and older, Chrome 76+ can use beforeInput
|
|
434
|
+
const IS_CHROME_LEGACY = typeof navigator !== 'undefined' &&
|
|
435
|
+
/Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent) &&
|
|
436
|
+
// Exclude Chrome version greater than 3 bits,Chrome releases v100 on 2022.03.29
|
|
437
|
+
!/Chrome?\/(?:\d{3,})/i.test(navigator.userAgent);
|
|
438
|
+
// Firefox did not support `beforeInput` until `v87`.
|
|
439
|
+
const IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])(?:\.)).*/i.test(navigator.userAgent);
|
|
440
|
+
// qq browser
|
|
441
|
+
const IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent);
|
|
442
|
+
// UC mobile browser
|
|
443
|
+
const IS_UC_MOBILE = typeof navigator !== 'undefined' && /.*UCBrowser/.test(navigator.userAgent);
|
|
444
|
+
// Wechat browser
|
|
445
|
+
const IS_WECHATBROWSER = typeof navigator !== 'undefined' && /.*Wechat/.test(navigator.userAgent);
|
|
446
|
+
// COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
|
|
447
|
+
// Chrome Legacy doesn't support `beforeinput` correctly
|
|
448
|
+
const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
|
|
449
|
+
!IS_EDGE_LEGACY &&
|
|
450
|
+
// globalThis is undefined in older browsers
|
|
451
|
+
typeof globalThis !== 'undefined' &&
|
|
452
|
+
globalThis.InputEvent &&
|
|
453
|
+
// @ts-ignore The `getTargetRanges` property isn't recognized.
|
|
454
|
+
typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
|
|
455
|
+
|
|
893
456
|
/**
|
|
894
457
|
* Hotkey mappings for each platform.
|
|
895
458
|
*/
|
|
@@ -1188,6 +751,44 @@ const getNavigatorClipboard = async () => {
|
|
|
1188
751
|
return clipboardData;
|
|
1189
752
|
};
|
|
1190
753
|
|
|
754
|
+
const SlateFragmentAttributeKey = 'data-slate-angular-fragment';
|
|
755
|
+
/**
|
|
756
|
+
* Get x-slate-fragment attribute from data-slate-angular-fragment
|
|
757
|
+
*/
|
|
758
|
+
const catchSlateFragment = /data-slate-angular-fragment="(.+?)"/m;
|
|
759
|
+
const getSlateFragmentAttribute = (htmlData) => {
|
|
760
|
+
const [, fragment] = htmlData.match(catchSlateFragment) || [];
|
|
761
|
+
return fragment;
|
|
762
|
+
};
|
|
763
|
+
/**
|
|
764
|
+
* Check if a DOM node is an element node.
|
|
765
|
+
*/
|
|
766
|
+
const isDOMText = (value) => {
|
|
767
|
+
return isDOMNode(value) && value.nodeType === 3;
|
|
768
|
+
};
|
|
769
|
+
/**
|
|
770
|
+
* Get a plaintext representation of the content of a node, accounting for block
|
|
771
|
+
* elements which get a newline appended.
|
|
772
|
+
*
|
|
773
|
+
* The domNode must be attached to the DOM.
|
|
774
|
+
*/
|
|
775
|
+
const getPlainText = (domNode) => {
|
|
776
|
+
let text = '';
|
|
777
|
+
if (isDOMText(domNode) && domNode.nodeValue) {
|
|
778
|
+
return domNode.nodeValue;
|
|
779
|
+
}
|
|
780
|
+
if (isDOMElement(domNode)) {
|
|
781
|
+
for (const childNode of Array.from(domNode.childNodes)) {
|
|
782
|
+
text += getPlainText(childNode);
|
|
783
|
+
}
|
|
784
|
+
const display = getComputedStyle(domNode).getPropertyValue('display');
|
|
785
|
+
if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {
|
|
786
|
+
text += '\n';
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return text;
|
|
790
|
+
};
|
|
791
|
+
|
|
1191
792
|
const buildHTMLText = (wrapper, attach, data) => {
|
|
1192
793
|
const stringObj = JSON.stringify(data);
|
|
1193
794
|
const encoded = window.btoa(encodeURIComponent(stringObj));
|
|
@@ -1262,128 +863,10 @@ const setClipboardData = async (clipboardData, wrapper, attach, dataTransfer) =>
|
|
|
1262
863
|
}
|
|
1263
864
|
};
|
|
1264
865
|
|
|
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
866
|
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
|
-
};
|
|
867
|
+
let e = editor;
|
|
868
|
+
let { apply } = e;
|
|
869
|
+
e = withDOM(e, clipboardFormatKey);
|
|
1387
870
|
e.setFragmentData = (dataTransfer, originEvent) => {
|
|
1388
871
|
const { selection } = e;
|
|
1389
872
|
if (!selection) {
|
|
@@ -1472,11 +955,11 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
|
1472
955
|
}
|
|
1473
956
|
};
|
|
1474
957
|
e.insertData = async (data) => {
|
|
1475
|
-
if (!(await e.
|
|
958
|
+
if (!(await e.customInsertFragmentData(data))) {
|
|
1476
959
|
e.insertTextData(data);
|
|
1477
960
|
}
|
|
1478
961
|
};
|
|
1479
|
-
e.
|
|
962
|
+
e.customInsertFragmentData = async (data) => {
|
|
1480
963
|
/**
|
|
1481
964
|
* Checking copied fragment from application/x-slate-fragment or data-slate-fragment
|
|
1482
965
|
*/
|
|
@@ -1487,7 +970,7 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
|
1487
970
|
}
|
|
1488
971
|
return false;
|
|
1489
972
|
};
|
|
1490
|
-
e.
|
|
973
|
+
e.customInsertTextData = async (data) => {
|
|
1491
974
|
const clipboardData = await getClipboardData(data);
|
|
1492
975
|
if (clipboardData && clipboardData.text) {
|
|
1493
976
|
const lines = clipboardData.text.split(/\r\n|\r|\n/);
|
|
@@ -1515,6 +998,56 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
|
1515
998
|
console.error(errorData);
|
|
1516
999
|
}
|
|
1517
1000
|
};
|
|
1001
|
+
// exist issue for move operation in withDOM
|
|
1002
|
+
e.apply = (op) => {
|
|
1003
|
+
const matches = [];
|
|
1004
|
+
switch (op.type) {
|
|
1005
|
+
case 'insert_text':
|
|
1006
|
+
case 'remove_text':
|
|
1007
|
+
case 'set_node': {
|
|
1008
|
+
for (const [node, path] of Editor.levels(e, { at: op.path })) {
|
|
1009
|
+
const key = AngularEditor.findKey(e, node);
|
|
1010
|
+
matches.push([path, key]);
|
|
1011
|
+
}
|
|
1012
|
+
break;
|
|
1013
|
+
}
|
|
1014
|
+
case 'insert_node':
|
|
1015
|
+
case 'remove_node':
|
|
1016
|
+
case 'merge_node':
|
|
1017
|
+
case 'split_node': {
|
|
1018
|
+
for (const [node, path] of Editor.levels(e, {
|
|
1019
|
+
at: Path.parent(op.path)
|
|
1020
|
+
})) {
|
|
1021
|
+
const key = AngularEditor.findKey(e, node);
|
|
1022
|
+
matches.push([path, key]);
|
|
1023
|
+
}
|
|
1024
|
+
break;
|
|
1025
|
+
}
|
|
1026
|
+
case 'move_node': {
|
|
1027
|
+
const commonPath = Path.common(Path.parent(op.path), Path.parent(op.newPath));
|
|
1028
|
+
for (const [node, path] of Editor.levels(e, {
|
|
1029
|
+
at: Path.parent(op.path)
|
|
1030
|
+
})) {
|
|
1031
|
+
const key = AngularEditor.findKey(e, node);
|
|
1032
|
+
matches.push([Editor.pathRef(editor, path), key]);
|
|
1033
|
+
}
|
|
1034
|
+
for (const [node, path] of Editor.levels(e, {
|
|
1035
|
+
at: Path.parent(op.newPath)
|
|
1036
|
+
})) {
|
|
1037
|
+
if (path.length > commonPath.length) {
|
|
1038
|
+
const key = AngularEditor.findKey(e, node);
|
|
1039
|
+
matches.push([Editor.pathRef(editor, path), key]);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
break;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
apply(op);
|
|
1046
|
+
for (const [source, key] of matches) {
|
|
1047
|
+
const [node] = Editor.node(e, Path.isPath(source) ? source : source.current);
|
|
1048
|
+
NODE_TO_KEY.set(node, key);
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1518
1051
|
return e;
|
|
1519
1052
|
};
|
|
1520
1053
|
|
|
@@ -3118,8 +2651,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImpor
|
|
|
3118
2651
|
|
|
3119
2652
|
const SLATE_DEFAULT_LEAF_COMPONENT_TOKEN = new InjectionToken('slate-default-leaf-token');
|
|
3120
2653
|
|
|
3121
|
-
const TRIPLE_CLICK = 3;
|
|
3122
|
-
|
|
3123
2654
|
// not correctly clipboardData on beforeinput
|
|
3124
2655
|
const forceOnDOMPaste = IS_SAFARI;
|
|
3125
2656
|
class SlateEditable {
|
|
@@ -3170,7 +2701,7 @@ class SlateEditable {
|
|
|
3170
2701
|
EDITOR_TO_ELEMENT.set(this.editor, this.elementRef.nativeElement);
|
|
3171
2702
|
NODE_TO_ELEMENT.set(this.editor, this.elementRef.nativeElement);
|
|
3172
2703
|
ELEMENT_TO_NODE.set(this.elementRef.nativeElement, this.editor);
|
|
3173
|
-
|
|
2704
|
+
IS_READ_ONLY.set(this.editor, this.readonly);
|
|
3174
2705
|
EDITOR_TO_ON_CHANGE.set(this.editor, () => {
|
|
3175
2706
|
this.ngZone.run(() => {
|
|
3176
2707
|
this.onChange();
|
|
@@ -3202,7 +2733,7 @@ class SlateEditable {
|
|
|
3202
2733
|
}
|
|
3203
2734
|
const readonlyChange = simpleChanges['readonly'];
|
|
3204
2735
|
if (readonlyChange) {
|
|
3205
|
-
|
|
2736
|
+
IS_READ_ONLY.set(this.editor, this.readonly);
|
|
3206
2737
|
this.render();
|
|
3207
2738
|
this.toSlateSelection();
|
|
3208
2739
|
}
|
|
@@ -3276,7 +2807,10 @@ class SlateEditable {
|
|
|
3276
2807
|
}
|
|
3277
2808
|
// If the DOM selection is in the editor and the editor selection is already correct, we're done.
|
|
3278
2809
|
if (hasDomSelection && hasDomSelectionInEditor && selection && hasStringTarget(domSelection)) {
|
|
3279
|
-
const rangeFromDOMSelection = AngularEditor.toSlateRange(this.editor, domSelection, {
|
|
2810
|
+
const rangeFromDOMSelection = AngularEditor.toSlateRange(this.editor, domSelection, {
|
|
2811
|
+
exactMatch: false,
|
|
2812
|
+
suppressThrow: true
|
|
2813
|
+
});
|
|
3280
2814
|
if (rangeFromDOMSelection && Range.equals(rangeFromDOMSelection, selection)) {
|
|
3281
2815
|
return;
|
|
3282
2816
|
}
|
|
@@ -3290,7 +2824,7 @@ class SlateEditable {
|
|
|
3290
2824
|
// but Slate's value is not being updated through any operation
|
|
3291
2825
|
// and thus it doesn't transform selection on its own
|
|
3292
2826
|
if (selection && !AngularEditor.hasRange(this.editor, selection)) {
|
|
3293
|
-
this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection, { suppressThrow: false });
|
|
2827
|
+
this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection, { exactMatch: false, suppressThrow: false });
|
|
3294
2828
|
return;
|
|
3295
2829
|
}
|
|
3296
2830
|
// Otherwise the DOM selection is out of sync, so update it.
|
|
@@ -3514,14 +3048,14 @@ class SlateEditable {
|
|
|
3514
3048
|
let targetRange = null;
|
|
3515
3049
|
let [nativeTargetRange] = event.getTargetRanges();
|
|
3516
3050
|
if (nativeTargetRange) {
|
|
3517
|
-
targetRange = AngularEditor.toSlateRange(editor, nativeTargetRange);
|
|
3051
|
+
targetRange = AngularEditor.toSlateRange(editor, nativeTargetRange, { exactMatch: false, suppressThrow: false });
|
|
3518
3052
|
}
|
|
3519
3053
|
// COMPAT: SelectionChange event is fired after the action is performed, so we
|
|
3520
3054
|
// have to manually get the selection here to ensure it's up-to-date.
|
|
3521
3055
|
const window = AngularEditor.getWindow(editor);
|
|
3522
3056
|
const domSelection = window.getSelection();
|
|
3523
3057
|
if (!targetRange && domSelection) {
|
|
3524
|
-
targetRange = AngularEditor.toSlateRange(editor, domSelection);
|
|
3058
|
+
targetRange = AngularEditor.toSlateRange(editor, domSelection, { exactMatch: false, suppressThrow: false });
|
|
3525
3059
|
}
|
|
3526
3060
|
targetRange = targetRange ?? editor.selection;
|
|
3527
3061
|
if (type === 'insertCompositionText') {
|
|
@@ -3567,7 +3101,7 @@ class SlateEditable {
|
|
|
3567
3101
|
}
|
|
3568
3102
|
}
|
|
3569
3103
|
if (!this.readonly &&
|
|
3570
|
-
hasEditableTarget(editor, event.target) &&
|
|
3104
|
+
AngularEditor.hasEditableTarget(editor, event.target) &&
|
|
3571
3105
|
!isTargetInsideVoid(editor, activeElement) &&
|
|
3572
3106
|
!this.isDOMEventHandled(event, this.beforeInput)) {
|
|
3573
3107
|
try {
|
|
@@ -3668,7 +3202,7 @@ class SlateEditable {
|
|
|
3668
3202
|
onDOMBlur(event) {
|
|
3669
3203
|
if (this.readonly ||
|
|
3670
3204
|
this.isUpdatingSelection ||
|
|
3671
|
-
!hasEditableTarget(this.editor, event.target) ||
|
|
3205
|
+
!AngularEditor.hasEditableTarget(this.editor, event.target) ||
|
|
3672
3206
|
this.isDOMEventHandled(event, this.blur)) {
|
|
3673
3207
|
return;
|
|
3674
3208
|
}
|
|
@@ -3707,7 +3241,7 @@ class SlateEditable {
|
|
|
3707
3241
|
}
|
|
3708
3242
|
onDOMClick(event) {
|
|
3709
3243
|
if (!this.readonly &&
|
|
3710
|
-
hasTarget(this.editor, event.target) &&
|
|
3244
|
+
AngularEditor.hasTarget(this.editor, event.target) &&
|
|
3711
3245
|
!this.isDOMEventHandled(event, this.click) &&
|
|
3712
3246
|
isDOMNode(event.target)) {
|
|
3713
3247
|
const node = AngularEditor.toSlateNode(this.editor, event.target);
|
|
@@ -3747,7 +3281,7 @@ class SlateEditable {
|
|
|
3747
3281
|
this.forceRender();
|
|
3748
3282
|
}
|
|
3749
3283
|
}
|
|
3750
|
-
if (hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionStart)) {
|
|
3284
|
+
if (AngularEditor.hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionStart)) {
|
|
3751
3285
|
this.isComposing = true;
|
|
3752
3286
|
}
|
|
3753
3287
|
this.render();
|
|
@@ -3759,7 +3293,7 @@ class SlateEditable {
|
|
|
3759
3293
|
if (!event.data && !Range.isCollapsed(this.editor.selection)) {
|
|
3760
3294
|
Transforms.delete(this.editor);
|
|
3761
3295
|
}
|
|
3762
|
-
if (hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionEnd)) {
|
|
3296
|
+
if (AngularEditor.hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionEnd)) {
|
|
3763
3297
|
// COMPAT: In Chrome/Firefox, `beforeinput` events for compositions
|
|
3764
3298
|
// aren't correct and never fire the "insertFromComposition"
|
|
3765
3299
|
// type that we need. So instead, insert whenever a composition
|
|
@@ -3777,13 +3311,13 @@ class SlateEditable {
|
|
|
3777
3311
|
onDOMCopy(event) {
|
|
3778
3312
|
const window = AngularEditor.getWindow(this.editor);
|
|
3779
3313
|
const isOutsideSlate = !hasStringTarget(window.getSelection()) && isTargetInsideVoid(this.editor, event.target);
|
|
3780
|
-
if (!isOutsideSlate && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.copy)) {
|
|
3314
|
+
if (!isOutsideSlate && AngularEditor.hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.copy)) {
|
|
3781
3315
|
event.preventDefault();
|
|
3782
3316
|
AngularEditor.setFragmentData(this.editor, event.clipboardData, 'copy');
|
|
3783
3317
|
}
|
|
3784
3318
|
}
|
|
3785
3319
|
onDOMCut(event) {
|
|
3786
|
-
if (!this.readonly && hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.cut)) {
|
|
3320
|
+
if (!this.readonly && AngularEditor.hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.cut)) {
|
|
3787
3321
|
event.preventDefault();
|
|
3788
3322
|
AngularEditor.setFragmentData(this.editor, event.clipboardData, 'cut');
|
|
3789
3323
|
const { selection } = this.editor;
|
|
@@ -3793,7 +3327,7 @@ class SlateEditable {
|
|
|
3793
3327
|
}
|
|
3794
3328
|
}
|
|
3795
3329
|
onDOMDragOver(event) {
|
|
3796
|
-
if (hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragOver)) {
|
|
3330
|
+
if (AngularEditor.hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragOver)) {
|
|
3797
3331
|
// Only when the target is void, call `preventDefault` to signal
|
|
3798
3332
|
// that drops are allowed. Editable content is droppable by
|
|
3799
3333
|
// default, and calling `preventDefault` hides the cursor.
|
|
@@ -3804,7 +3338,7 @@ class SlateEditable {
|
|
|
3804
3338
|
}
|
|
3805
3339
|
}
|
|
3806
3340
|
onDOMDragStart(event) {
|
|
3807
|
-
if (!this.readonly && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragStart)) {
|
|
3341
|
+
if (!this.readonly && AngularEditor.hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragStart)) {
|
|
3808
3342
|
const node = AngularEditor.toSlateNode(this.editor, event.target);
|
|
3809
3343
|
const path = AngularEditor.findPath(this.editor, node);
|
|
3810
3344
|
const voidMatch = Element.isElement(node) && (Editor.isVoid(this.editor, node) || Editor.void(this.editor, { at: path, voids: true }));
|
|
@@ -3820,7 +3354,7 @@ class SlateEditable {
|
|
|
3820
3354
|
}
|
|
3821
3355
|
onDOMDrop(event) {
|
|
3822
3356
|
const editor = this.editor;
|
|
3823
|
-
if (!this.readonly && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.drop)) {
|
|
3357
|
+
if (!this.readonly && AngularEditor.hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.drop)) {
|
|
3824
3358
|
event.preventDefault();
|
|
3825
3359
|
// Keep a reference to the dragged range before updating selection
|
|
3826
3360
|
const draggedRange = editor.selection;
|
|
@@ -3847,7 +3381,7 @@ class SlateEditable {
|
|
|
3847
3381
|
onDOMDragEnd(event) {
|
|
3848
3382
|
if (!this.readonly &&
|
|
3849
3383
|
this.isDraggingInternally &&
|
|
3850
|
-
hasTarget(this.editor, event.target) &&
|
|
3384
|
+
AngularEditor.hasTarget(this.editor, event.target) &&
|
|
3851
3385
|
!this.isDOMEventHandled(event, this.dragEnd)) {
|
|
3852
3386
|
this.isDraggingInternally = false;
|
|
3853
3387
|
}
|
|
@@ -3855,7 +3389,7 @@ class SlateEditable {
|
|
|
3855
3389
|
onDOMFocus(event) {
|
|
3856
3390
|
if (!this.readonly &&
|
|
3857
3391
|
!this.isUpdatingSelection &&
|
|
3858
|
-
hasEditableTarget(this.editor, event.target) &&
|
|
3392
|
+
AngularEditor.hasEditableTarget(this.editor, event.target) &&
|
|
3859
3393
|
!this.isDOMEventHandled(event, this.focus)) {
|
|
3860
3394
|
const el = AngularEditor.toDOMNode(this.editor, this.editor);
|
|
3861
3395
|
const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
|
|
@@ -3875,7 +3409,7 @@ class SlateEditable {
|
|
|
3875
3409
|
const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
|
|
3876
3410
|
const { activeElement } = root;
|
|
3877
3411
|
if (!this.readonly &&
|
|
3878
|
-
hasEditableTarget(editor, event.target) &&
|
|
3412
|
+
AngularEditor.hasEditableTarget(editor, event.target) &&
|
|
3879
3413
|
!isTargetInsideVoid(editor, activeElement) && // stop fire keydown handle when focus void node
|
|
3880
3414
|
!this.isComposing &&
|
|
3881
3415
|
!this.isDOMEventHandled(event, this.keydown)) {
|
|
@@ -4097,7 +3631,7 @@ class SlateEditable {
|
|
|
4097
3631
|
if (!this.isDOMEventHandled(event, this.paste) &&
|
|
4098
3632
|
(!HAS_BEFORE_INPUT_SUPPORT || isPlainTextOnlyPaste(event) || forceOnDOMPaste) &&
|
|
4099
3633
|
!this.readonly &&
|
|
4100
|
-
hasEditableTarget(this.editor, event.target)) {
|
|
3634
|
+
AngularEditor.hasEditableTarget(this.editor, event.target)) {
|
|
4101
3635
|
event.preventDefault();
|
|
4102
3636
|
AngularEditor.insertData(this.editor, event.clipboardData);
|
|
4103
3637
|
}
|
|
@@ -4109,7 +3643,7 @@ class SlateEditable {
|
|
|
4109
3643
|
if (!HAS_BEFORE_INPUT_SUPPORT &&
|
|
4110
3644
|
!this.readonly &&
|
|
4111
3645
|
!this.isDOMEventHandled(event.nativeEvent, this.beforeInput) &&
|
|
4112
|
-
hasEditableTarget(this.editor, event.nativeEvent.target)) {
|
|
3646
|
+
AngularEditor.hasEditableTarget(this.editor, event.nativeEvent.target)) {
|
|
4113
3647
|
event.nativeEvent.preventDefault();
|
|
4114
3648
|
try {
|
|
4115
3649
|
const text = event.data;
|
|
@@ -4300,36 +3834,15 @@ const defaultScrollSelectionIntoView = (editor, domRange) => {
|
|
|
4300
3834
|
delete leafEl.getBoundingClientRect;
|
|
4301
3835
|
}
|
|
4302
3836
|
};
|
|
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
3837
|
/**
|
|
4329
3838
|
* Check if the target is inside void and in the editor.
|
|
4330
3839
|
*/
|
|
4331
3840
|
const isTargetInsideVoid = (editor, target) => {
|
|
4332
|
-
|
|
3841
|
+
let slateNode = null;
|
|
3842
|
+
try {
|
|
3843
|
+
slateNode = AngularEditor.hasTarget(editor, target) && AngularEditor.toSlateNode(editor, target);
|
|
3844
|
+
}
|
|
3845
|
+
catch (error) { }
|
|
4333
3846
|
return slateNode && Element.isElement(slateNode) && Editor.isVoid(editor, slateNode);
|
|
4334
3847
|
};
|
|
4335
3848
|
const hasStringTarget = (domSelection) => {
|
|
@@ -4490,5 +4003,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImpor
|
|
|
4490
4003
|
* Generated bundle index. Do not edit.
|
|
4491
4004
|
*/
|
|
4492
4005
|
|
|
4493
|
-
export { AngularEditor, BaseComponent, BaseElementComponent, BaseLeafComponent, BaseTextComponent,
|
|
4006
|
+
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, SlateLeaves, SlateModule, SlateString, blobAsString, buildHTMLText, check, completeTable, createClipboardData, createThrottleRAF, defaultScrollSelectionIntoView, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getDataTransferClipboard, getDataTransferClipboardText, getNavigatorClipboard, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDecoratorRangeListEqual, isEmpty, isInvalidTable, isTemplateRef, isValid, normalize, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
|
|
4494
4007
|
//# sourceMappingURL=slate-angular.mjs.map
|