slate-angular 1.9.3 → 13.0.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.
Files changed (63) hide show
  1. package/components/descendant/descendant.component.d.ts +2 -3
  2. package/{esm2015/components/block-card/block-card.component.js → esm2020/components/block-card/block-card.component.mjs} +5 -8
  3. package/{esm2015/components/children/children.component.js → esm2020/components/children/children.component.mjs} +3 -3
  4. package/esm2020/components/descendant/descendant.component.mjs +183 -0
  5. package/esm2020/components/editable/editable.component.mjs +1057 -0
  6. package/{esm2015/components/element/default-element.component.js → esm2020/components/element/default-element.component.mjs} +3 -3
  7. package/{esm2015/components/element/default-element.component.token.js → esm2020/components/element/default-element.component.token.mjs} +0 -0
  8. package/{esm2015/components/element/element.component.js → esm2020/components/element/element.component.mjs} +3 -3
  9. package/{esm2015/components/leaf/default-leaf.component.js → esm2020/components/leaf/default-leaf.component.mjs} +3 -3
  10. package/{esm2015/components/leaf/leaf.component.js → esm2020/components/leaf/leaf.component.mjs} +3 -3
  11. package/{esm2015/components/leaves/leaves.component.js → esm2020/components/leaves/leaves.component.mjs} +3 -3
  12. package/esm2020/components/string/string.component.mjs +73 -0
  13. package/esm2020/components/string/template.component.mjs +26 -0
  14. package/{esm2015/components/text/default-text.component.js → esm2020/components/text/default-text.component.mjs} +3 -3
  15. package/{esm2015/components/text/void-text.component.js → esm2020/components/text/void-text.component.mjs} +3 -3
  16. package/{esm2015/custom-event/BeforeInputEventPlugin.js → esm2020/custom-event/BeforeInputEventPlugin.mjs} +0 -0
  17. package/{esm2015/custom-event/DOMTopLevelEventTypes.js → esm2020/custom-event/DOMTopLevelEventTypes.mjs} +0 -0
  18. package/{esm2015/custom-event/FallbackCompositionState.js → esm2020/custom-event/FallbackCompositionState.mjs} +0 -0
  19. package/{esm2015/custom-event/before-input-polyfill.js → esm2020/custom-event/before-input-polyfill.mjs} +0 -0
  20. package/{esm2015/module.js → esm2020/module.mjs} +5 -6
  21. package/esm2020/plugins/angular-editor.mjs +565 -0
  22. package/{esm2015/plugins/with-angular.js → esm2020/plugins/with-angular.mjs} +0 -0
  23. package/{esm2015/public-api.js → esm2020/public-api.mjs} +0 -0
  24. package/{esm2015/slate-angular.js → esm2020/slate-angular.mjs} +0 -0
  25. package/{esm2015/types/error.js → esm2020/types/error.mjs} +0 -0
  26. package/{esm2015/types/feature.js → esm2020/types/feature.mjs} +0 -0
  27. package/{esm2015/types/index.js → esm2020/types/index.mjs} +1 -1
  28. package/{esm2015/types/view.js → esm2020/types/view.mjs} +0 -0
  29. package/esm2020/utils/block-card.mjs +25 -0
  30. package/{esm2015/utils/dom.js → esm2020/utils/dom.mjs} +0 -0
  31. package/{esm2015/utils/environment.js → esm2020/utils/environment.mjs} +0 -0
  32. package/{esm2015/utils/global-normalize.js → esm2020/utils/global-normalize.mjs} +0 -0
  33. package/{esm2015/utils/hotkeys.js → esm2020/utils/hotkeys.mjs} +0 -0
  34. package/{esm2015/utils/index.js → esm2020/utils/index.mjs} +0 -0
  35. package/{esm2015/utils/key.js → esm2020/utils/key.mjs} +0 -0
  36. package/{esm2015/utils/lines.js → esm2020/utils/lines.mjs} +0 -0
  37. package/esm2020/utils/range-list.mjs +29 -0
  38. package/{esm2015/utils/view.js → esm2020/utils/view.mjs} +0 -0
  39. package/{esm2015/utils/weak-maps.js → esm2020/utils/weak-maps.mjs} +0 -0
  40. package/{esm2015/view/base.js → esm2020/view/base.mjs} +12 -12
  41. package/{esm2015/view/before-context-change.js → esm2020/view/before-context-change.mjs} +0 -0
  42. package/esm2020/view/container-item.mjs +102 -0
  43. package/{esm2015/view/container.js → esm2020/view/container.mjs} +3 -3
  44. package/{esm2015/view/context.js → esm2020/view/context.mjs} +0 -0
  45. package/fesm2015/{slate-angular.js → slate-angular.mjs} +81 -98
  46. package/fesm2015/slate-angular.mjs.map +1 -0
  47. package/fesm2020/slate-angular.mjs +3643 -0
  48. package/fesm2020/slate-angular.mjs.map +1 -0
  49. package/package.json +26 -6
  50. package/styles/index.scss +1 -1
  51. package/types/index.d.ts +1 -0
  52. package/view/container-item.d.ts +2 -3
  53. package/bundles/slate-angular.umd.js +0 -4298
  54. package/bundles/slate-angular.umd.js.map +0 -1
  55. package/esm2015/components/descendant/descendant.component.js +0 -179
  56. package/esm2015/components/editable/editable.component.js +0 -1063
  57. package/esm2015/components/string/string.component.js +0 -73
  58. package/esm2015/components/string/template.component.js +0 -30
  59. package/esm2015/plugins/angular-editor.js +0 -565
  60. package/esm2015/utils/block-card.js +0 -25
  61. package/esm2015/utils/range-list.js +0 -30
  62. package/esm2015/view/container-item.js +0 -105
  63. package/fesm2015/slate-angular.js.map +0 -1
@@ -0,0 +1,3643 @@
1
+ import { Editor, Range, Transforms, Path, Element, Text as Text$1, Node } from 'slate';
2
+ import { isKeyHotkey } from 'is-hotkey';
3
+ import * as i0 from '@angular/core';
4
+ import { TemplateRef, Component, ViewChild, Directive, Input, HostBinding, ChangeDetectionStrategy, ViewChildren, InjectionToken, Inject, forwardRef, ElementRef, NgModule } from '@angular/core';
5
+ import getDirection from 'direction';
6
+ import { Subject } from 'rxjs';
7
+ import Debug from 'debug';
8
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
9
+ import { HistoryEditor } from 'slate-history';
10
+ import * as i2 from '@angular/common';
11
+ import { CommonModule } from '@angular/common';
12
+
13
+ /**
14
+ * Two weak maps that allow us rebuild a path given a node. They are populated
15
+ * at render time such that after a render occurs we can always backtrack.
16
+ */
17
+ const EDITOR_TO_WINDOW = new WeakMap();
18
+ const NODE_TO_INDEX = new WeakMap();
19
+ const NODE_TO_PARENT = new WeakMap();
20
+ /**
21
+ * Weak maps that allow us to go between Slate nodes and DOM nodes. These
22
+ * are used to resolve DOM event-related logic into Slate actions.
23
+ */
24
+ const EDITOR_TO_ELEMENT = new WeakMap();
25
+ const EDITOR_TO_PLACEHOLDER = new WeakMap();
26
+ const ELEMENT_TO_NODE = new WeakMap();
27
+ // Deprecated
28
+ const KEY_TO_ELEMENT = new WeakMap();
29
+ const NODE_TO_ELEMENT = new WeakMap();
30
+ const NODE_TO_KEY = new WeakMap();
31
+ /**
32
+ * Weak maps for storing editor-related state.
33
+ */
34
+ const IS_READONLY = new WeakMap();
35
+ const IS_FOCUSED = new WeakMap();
36
+ const IS_DRAGGING = new WeakMap();
37
+ const IS_CLICKING = new WeakMap();
38
+ /**
39
+ * Weak map for associating the context `onChange` context with the plugin.
40
+ */
41
+ const EDITOR_TO_ON_CHANGE = new WeakMap();
42
+ // export const NODE_TO_VIEWNODE = new WeakMap<Node, ViewNode>();
43
+ /**
44
+ * Symbols.
45
+ */
46
+ const PLACEHOLDER_SYMBOL = Symbol('placeholder');
47
+ /**
48
+ * Weak map for associating the html element with the component.
49
+ */
50
+ const ELEMENT_TO_COMPONENT = 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 &&
108
+ event.clipboardData.getData('text/plain') !== '' &&
109
+ event.clipboardData.types.length === 1);
110
+ };
111
+ /**
112
+ * Normalize a DOM point so that it always refers to a text node.
113
+ */
114
+ const normalizeDOMPoint = (domPoint) => {
115
+ let [node, offset] = domPoint;
116
+ // If it's an element node, its offset refers to the index of its children
117
+ // including comment nodes, so try to find the right text child node.
118
+ if (isDOMElement(node) && node.childNodes.length) {
119
+ let isLast = offset === node.childNodes.length;
120
+ let index = isLast ? offset - 1 : offset;
121
+ ;
122
+ [node, index] = getEditableChildAndIndex(node, index, isLast ? 'backward' : 'forward');
123
+ // If the editable child found is in front of input offset, we instead seek to its end
124
+ isLast = index < offset;
125
+ // If the node has children, traverse until we have a leaf node. Leaf nodes
126
+ // can be either text nodes, or other void DOM nodes.
127
+ while (isDOMElement(node) && node.childNodes.length) {
128
+ const i = isLast ? node.childNodes.length - 1 : 0;
129
+ node = getEditableChild(node, i, isLast ? 'backward' : 'forward');
130
+ }
131
+ // Determine the new offset inside the text node.
132
+ offset =
133
+ isLast && node.textContent != null ? node.textContent.length : 0;
134
+ }
135
+ // Return the node and offset.
136
+ return [node, offset];
137
+ };
138
+ /**
139
+ * Determines wether the active element is nested within a shadowRoot
140
+ */
141
+ const hasShadowRoot = () => {
142
+ return !!(window.document.activeElement && window.document.activeElement.shadowRoot);
143
+ };
144
+ /**
145
+ * Get the nearest editable child and index at `index` in a `parent`, preferring
146
+ * `direction`.
147
+ */
148
+ const getEditableChildAndIndex = (parent, index, direction) => {
149
+ const { childNodes } = parent;
150
+ let child = childNodes[index];
151
+ let i = index;
152
+ let triedForward = false;
153
+ let triedBackward = false;
154
+ // While the child is a comment node, or an element node with no children,
155
+ // keep iterating to find a sibling non-void, non-comment node.
156
+ while (isDOMComment(child) ||
157
+ (isDOMElement(child) && child.childNodes.length === 0) ||
158
+ (isDOMElement(child) && child.getAttribute('contenteditable') === 'false')) {
159
+ if (triedForward && triedBackward) {
160
+ break;
161
+ }
162
+ if (i >= childNodes.length) {
163
+ triedForward = true;
164
+ i = index - 1;
165
+ direction = 'backward';
166
+ continue;
167
+ }
168
+ if (i < 0) {
169
+ triedBackward = true;
170
+ i = index + 1;
171
+ direction = 'forward';
172
+ continue;
173
+ }
174
+ child = childNodes[i];
175
+ index = i;
176
+ i += direction === 'forward' ? 1 : -1;
177
+ }
178
+ return [child, index];
179
+ };
180
+ /**
181
+ * Get the nearest editable child at `index` in a `parent`, preferring
182
+ * `direction`.
183
+ */
184
+ const getEditableChild = (parent, index, direction) => {
185
+ const [child] = getEditableChildAndIndex(parent, index, direction);
186
+ return child;
187
+ };
188
+ /**
189
+ * Get a plaintext representation of the content of a node, accounting for block
190
+ * elements which get a newline appended.
191
+ *
192
+ * The domNode must be attached to the DOM.
193
+ */
194
+ const getPlainText = (domNode) => {
195
+ let text = '';
196
+ if (isDOMText(domNode) && domNode.nodeValue) {
197
+ return domNode.nodeValue;
198
+ }
199
+ if (isDOMElement(domNode)) {
200
+ for (const childNode of Array.from(domNode.childNodes)) {
201
+ text += getPlainText(childNode);
202
+ }
203
+ const display = getComputedStyle(domNode).getPropertyValue('display');
204
+ if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {
205
+ text += '\n';
206
+ }
207
+ }
208
+ return text;
209
+ };
210
+ /**
211
+ * Get x-slate-fragment attribute from data-slate-fragment
212
+ */
213
+ const catchSlateFragment = /data-slate-fragment="(.+?)"/m;
214
+ const getSlateFragmentAttribute = (dataTransfer) => {
215
+ const htmlData = dataTransfer.getData('text/html');
216
+ const [, fragment] = htmlData.match(catchSlateFragment) || [];
217
+ return fragment;
218
+ };
219
+ /**
220
+ * Get the x-slate-fragment attribute that exist in text/html data
221
+ * and append it to the DataTransfer object
222
+ */
223
+ const getClipboardData = (dataTransfer, clipboardFormatKey = 'x-slate-fragment') => {
224
+ if (!dataTransfer.getData(`application/${clipboardFormatKey}`)) {
225
+ const fragment = getSlateFragmentAttribute(dataTransfer);
226
+ if (fragment) {
227
+ const clipboardData = new DataTransfer();
228
+ dataTransfer.types.forEach(type => {
229
+ clipboardData.setData(type, dataTransfer.getData(type));
230
+ });
231
+ clipboardData.setData(`application/${clipboardFormatKey}`, fragment);
232
+ return clipboardData;
233
+ }
234
+ }
235
+ return dataTransfer;
236
+ };
237
+
238
+ /**
239
+ * An auto-incrementing identifier for keys.
240
+ */
241
+ let n = 0;
242
+ /**
243
+ * A class that keeps track of a key string. We use a full class here because we
244
+ * want to be able to use them as keys in `WeakMap` objects.
245
+ */
246
+ class Key {
247
+ constructor() {
248
+ this.id = `${n++}`;
249
+ }
250
+ }
251
+
252
+ const IS_IOS = typeof navigator !== 'undefined' &&
253
+ typeof window !== 'undefined' &&
254
+ /iPad|iPhone|iPod/.test(navigator.userAgent) &&
255
+ !window.MSStream;
256
+ const IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent);
257
+ const IS_ANDROID = typeof navigator !== 'undefined' && /Android/.test(navigator.userAgent);
258
+ const IS_FIREFOX = typeof navigator !== 'undefined' &&
259
+ /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
260
+ const IS_SAFARI = typeof navigator !== 'undefined' &&
261
+ /Version\/[\d\.]+.*Safari/.test(navigator.userAgent);
262
+ // "modern" Edge was released at 79.x
263
+ const IS_EDGE_LEGACY = typeof navigator !== 'undefined' &&
264
+ /Edge?\/(?:[0-6][0-9]|[0-7][0-8])/i.test(navigator.userAgent);
265
+ const IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.userAgent);
266
+ // Native beforeInput events don't work well with react on Chrome 75 and older, Chrome 76+ can use beforeInput
267
+ const IS_CHROME_LEGACY = typeof navigator !== 'undefined' &&
268
+ /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent) &&
269
+ // Exclude Chrome version greater than 3 bits,Chrome releases v100 on 2022.03.29
270
+ !/Chrome?\/(?:\d{3,})/i.test(navigator.userAgent);
271
+ // Firefox did not support `beforeInput` until `v87`.
272
+ const IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' &&
273
+ /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])).*/i.test(navigator.userAgent);
274
+ // qq browser
275
+ const IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent);
276
+ // UC mobile browser
277
+ const IS_UC_MOBILE = typeof navigator !== 'undefined' && /.*UCBrowser/.test(navigator.userAgent);
278
+ // Wechat browser
279
+ const IS_WECHATBROWSER = typeof navigator !== 'undefined' && /.*Wechat/.test(navigator.userAgent);
280
+ // COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
281
+ // Chrome Legacy doesn't support `beforeinput` correctly
282
+ const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
283
+ !IS_EDGE_LEGACY &&
284
+ // globalThis is undefined in older browsers
285
+ typeof globalThis !== 'undefined' &&
286
+ globalThis.InputEvent &&
287
+ // @ts-ignore The `getTargetRanges` property isn't recognized.
288
+ typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
289
+
290
+ const FAKE_LEFT_BLOCK_CARD_OFFSET = -1;
291
+ const FAKE_RIGHT_BLOCK_CARD_OFFSET = -2;
292
+ function hasBlockCardWithNode(node) {
293
+ return node && (node.parentElement.hasAttribute('card-target') || (node instanceof HTMLElement && node.hasAttribute('card-target')));
294
+ }
295
+ function hasBlockCard(selection) {
296
+ return hasBlockCardWithNode(selection?.anchorNode) || hasBlockCardWithNode(selection?.focusNode);
297
+ }
298
+ function getCardTargetAttribute(node) {
299
+ return node.parentElement.attributes['card-target'] || (node instanceof HTMLElement && node.attributes['card-target']);
300
+ }
301
+ function isCardLeft(node) {
302
+ const cardTarget = getCardTargetAttribute(node);
303
+ return cardTarget && cardTarget.nodeValue === 'card-left';
304
+ }
305
+ function isCardLeftByTargetAttr(targetAttr) {
306
+ return targetAttr && targetAttr.nodeValue === 'card-left';
307
+ }
308
+ function isCardRightByTargetAttr(targetAttr) {
309
+ return targetAttr && targetAttr.nodeValue === 'card-right';
310
+ }
311
+ function isCardCenterByTargetAttr(targetAttr) {
312
+ return targetAttr && targetAttr.nodeValue === 'card-center';
313
+ }
314
+
315
+ const AngularEditor = {
316
+ /**
317
+ * Return the host window of the current editor.
318
+ */
319
+ getWindow(editor) {
320
+ const window = EDITOR_TO_WINDOW.get(editor);
321
+ if (!window) {
322
+ throw new Error('Unable to find a host window element for this editor');
323
+ }
324
+ return window;
325
+ },
326
+ /**
327
+ * Find a key for a Slate node.
328
+ */
329
+ findKey(editor, node) {
330
+ let key = NODE_TO_KEY.get(node);
331
+ if (!key) {
332
+ key = new Key();
333
+ NODE_TO_KEY.set(node, key);
334
+ }
335
+ return key;
336
+ },
337
+ /**
338
+ * handle editor error.
339
+ */
340
+ onError(errorData) {
341
+ if (errorData.nativeError) {
342
+ throw errorData.nativeError;
343
+ }
344
+ },
345
+ /**
346
+ * Find the path of Slate node.
347
+ */
348
+ findPath(editor, node) {
349
+ const path = [];
350
+ let child = node;
351
+ while (true) {
352
+ const parent = NODE_TO_PARENT.get(child);
353
+ if (parent == null) {
354
+ if (Editor.isEditor(child)) {
355
+ return path;
356
+ }
357
+ else {
358
+ break;
359
+ }
360
+ }
361
+ const i = NODE_TO_INDEX.get(child);
362
+ if (i == null) {
363
+ break;
364
+ }
365
+ path.unshift(i);
366
+ child = parent;
367
+ }
368
+ throw new Error(`Unable to find the path for Slate node: ${JSON.stringify(node)}`);
369
+ },
370
+ /**
371
+ * Find the DOM node that implements DocumentOrShadowRoot for the editor.
372
+ */
373
+ findDocumentOrShadowRoot(editor) {
374
+ const el = AngularEditor.toDOMNode(editor, editor);
375
+ const root = el.getRootNode();
376
+ if ((root instanceof Document || root instanceof ShadowRoot) &&
377
+ root.getSelection != null) {
378
+ return root;
379
+ }
380
+ return el.ownerDocument;
381
+ },
382
+ /**
383
+ * Check if the editor is focused.
384
+ */
385
+ isFocused(editor) {
386
+ return !!IS_FOCUSED.get(editor);
387
+ },
388
+ /**
389
+ * Check if the editor is in read-only mode.
390
+ */
391
+ isReadonly(editor) {
392
+ return !!IS_READONLY.get(editor);
393
+ },
394
+ /**
395
+ * Check if the editor is hanging right.
396
+ */
397
+ isBlockHangingRight(editor) {
398
+ const { selection } = editor;
399
+ if (!selection) {
400
+ return false;
401
+ }
402
+ if (Range.isCollapsed(selection)) {
403
+ return false;
404
+ }
405
+ const [start, end] = Range.edges(selection);
406
+ const endBlock = Editor.above(editor, { at: end, match: (node) => Editor.isBlock(editor, node) });
407
+ return Editor.isStart(editor, end, endBlock[1]);
408
+ },
409
+ /**
410
+ * Blur the editor.
411
+ */
412
+ blur(editor) {
413
+ const el = AngularEditor.toDOMNode(editor, editor);
414
+ const root = AngularEditor.findDocumentOrShadowRoot(editor);
415
+ IS_FOCUSED.set(editor, false);
416
+ if (root.activeElement === el) {
417
+ el.blur();
418
+ }
419
+ },
420
+ /**
421
+ * Focus the editor.
422
+ */
423
+ focus(editor) {
424
+ const el = AngularEditor.toDOMNode(editor, editor);
425
+ IS_FOCUSED.set(editor, true);
426
+ const window = AngularEditor.getWindow(editor);
427
+ if (window.document.activeElement !== el) {
428
+ el.focus({ preventScroll: true });
429
+ }
430
+ },
431
+ /**
432
+ * Deselect the editor.
433
+ */
434
+ deselect(editor) {
435
+ const { selection } = editor;
436
+ const root = AngularEditor.findDocumentOrShadowRoot(editor);
437
+ const domSelection = root.getSelection();
438
+ if (domSelection && domSelection.rangeCount > 0) {
439
+ domSelection.removeAllRanges();
440
+ }
441
+ if (selection) {
442
+ Transforms.deselect(editor);
443
+ }
444
+ },
445
+ /**
446
+ * Check if a DOM node is within the editor.
447
+ */
448
+ hasDOMNode(editor, target, options = {}) {
449
+ const { editable = false } = options;
450
+ const editorEl = AngularEditor.toDOMNode(editor, editor);
451
+ let targetEl;
452
+ // COMPAT: In Firefox, reading `target.nodeType` will throw an error if
453
+ // target is originating from an internal "restricted" element (e.g. a
454
+ // stepper arrow on a number input). (2018/05/04)
455
+ // https://github.com/ianstormtaylor/slate/issues/1819
456
+ try {
457
+ targetEl = (isDOMElement(target) ? target : target.parentElement);
458
+ }
459
+ catch (err) {
460
+ if (!err.message.includes('Permission denied to access property "nodeType"')) {
461
+ throw err;
462
+ }
463
+ }
464
+ if (!targetEl) {
465
+ return false;
466
+ }
467
+ return targetEl.closest(`[data-slate-editor]`) === editorEl &&
468
+ (!editable || targetEl.isContentEditable ||
469
+ !!targetEl.getAttribute('data-slate-zero-width'));
470
+ },
471
+ /**
472
+ * Insert data from a `DataTransfer` into the editor.
473
+ */
474
+ insertData(editor, data) {
475
+ editor.insertData(data);
476
+ },
477
+ /**
478
+ * Insert fragment data from a `DataTransfer` into the editor.
479
+ */
480
+ insertFragmentData(editor, data) {
481
+ return editor.insertFragmentData(data);
482
+ },
483
+ /**
484
+ * Insert text data from a `DataTransfer` into the editor.
485
+ */
486
+ insertTextData(editor, data) {
487
+ return editor.insertTextData(data);
488
+ },
489
+ /**
490
+ * onKeydown hook.
491
+ */
492
+ onKeydown(editor, data) {
493
+ editor.onKeydown(data);
494
+ },
495
+ /**
496
+ * onClick hook.
497
+ */
498
+ onClick(editor, data) {
499
+ editor.onClick(data);
500
+ },
501
+ /**
502
+ * Sets data from the currently selected fragment on a `DataTransfer`.
503
+ */
504
+ setFragmentData(editor, data, originEvent) {
505
+ editor.setFragmentData(data, originEvent);
506
+ },
507
+ deleteCutData(editor) {
508
+ editor.deleteCutData();
509
+ },
510
+ /**
511
+ * Find the native DOM element from a Slate node.
512
+ */
513
+ toDOMNode(editor, node) {
514
+ const domNode = Editor.isEditor(node)
515
+ ? EDITOR_TO_ELEMENT.get(editor)
516
+ : NODE_TO_ELEMENT.get(node);
517
+ if (!domNode) {
518
+ throw new Error(`Cannot resolve a DOM node from Slate node: ${JSON.stringify(node)}`);
519
+ }
520
+ return domNode;
521
+ },
522
+ /**
523
+ * Find a native DOM selection point from a Slate point.
524
+ */
525
+ toDOMPoint(editor, point) {
526
+ const [node] = Editor.node(editor, point.path);
527
+ const el = AngularEditor.toDOMNode(editor, node);
528
+ let domPoint;
529
+ // block card
530
+ const cardTargetAttr = getCardTargetAttribute(el);
531
+ if (cardTargetAttr) {
532
+ if (point.offset === FAKE_LEFT_BLOCK_CARD_OFFSET) {
533
+ const cursorNode = AngularEditor.getCardCursorNode(editor, node, { direction: 'left' });
534
+ return [cursorNode, 1];
535
+ }
536
+ else {
537
+ const cursorNode = AngularEditor.getCardCursorNode(editor, node, { direction: 'right' });
538
+ return [cursorNode, 1];
539
+ }
540
+ }
541
+ // If we're inside a void node, force the offset to 0, otherwise the zero
542
+ // width spacing character will result in an incorrect offset of 1
543
+ if (Editor.void(editor, { at: point })) {
544
+ point = { path: point.path, offset: 0 };
545
+ }
546
+ // For each leaf, we need to isolate its content, which means filtering
547
+ // to its direct text and zero-width spans. (We have to filter out any
548
+ // other siblings that may have been rendered alongside them.)
549
+ const selector = `[data-slate-string], [data-slate-zero-width]`;
550
+ const texts = Array.from(el.querySelectorAll(selector));
551
+ let start = 0;
552
+ for (const text of texts) {
553
+ const domNode = text.childNodes[0];
554
+ if (domNode == null || domNode.textContent == null) {
555
+ continue;
556
+ }
557
+ const { length } = domNode.textContent;
558
+ const attr = text.getAttribute('data-slate-length');
559
+ const trueLength = attr == null ? length : parseInt(attr, 10);
560
+ const end = start + trueLength;
561
+ if (point.offset <= end) {
562
+ const offset = Math.min(length, Math.max(0, point.offset - start));
563
+ domPoint = [domNode, offset];
564
+ // fixed cursor position after zero width char
565
+ if (offset === 0 && length === 1 && domNode.textContent === '\uFEFF') {
566
+ domPoint = [domNode, offset + 1];
567
+ }
568
+ break;
569
+ }
570
+ start = end;
571
+ }
572
+ if (!domPoint) {
573
+ throw new Error(`Cannot resolve a DOM point from Slate point: ${JSON.stringify(point)}`);
574
+ }
575
+ return domPoint;
576
+ },
577
+ /**
578
+ * Find a native DOM range from a Slate `range`.
579
+ */
580
+ toDOMRange(editor, range) {
581
+ const { anchor, focus } = range;
582
+ const isBackward = Range.isBackward(range);
583
+ const domAnchor = AngularEditor.toDOMPoint(editor, anchor);
584
+ const domFocus = Range.isCollapsed(range) ? domAnchor : AngularEditor.toDOMPoint(editor, focus);
585
+ const window = AngularEditor.getWindow(editor);
586
+ const domRange = window.document.createRange();
587
+ const [startNode, startOffset] = isBackward ? domFocus : domAnchor;
588
+ const [endNode, endOffset] = isBackward ? domAnchor : domFocus;
589
+ // A slate Point at zero-width Leaf always has an offset of 0 but a native DOM selection at
590
+ // zero-width node has an offset of 1 so we have to check if we are in a zero-width node and
591
+ // adjust the offset accordingly.
592
+ const startEl = (isDOMElement(startNode)
593
+ ? startNode
594
+ : startNode.parentElement);
595
+ const isStartAtZeroWidth = !!startEl.getAttribute('data-slate-zero-width');
596
+ const endEl = (isDOMElement(endNode)
597
+ ? endNode
598
+ : endNode.parentElement);
599
+ const isEndAtZeroWidth = !!endEl.getAttribute('data-slate-zero-width');
600
+ domRange.setStart(startNode, isStartAtZeroWidth ? 1 : startOffset);
601
+ domRange.setEnd(endNode, isEndAtZeroWidth ? 1 : endOffset);
602
+ return domRange;
603
+ },
604
+ /**
605
+ * Find a Slate node from a native DOM `element`.
606
+ */
607
+ toSlateNode(editor, domNode) {
608
+ let domEl = isDOMElement(domNode) ? domNode : domNode.parentElement;
609
+ if (domEl && !domEl.hasAttribute('data-slate-node')) {
610
+ domEl = domEl.closest(`[data-slate-node]`);
611
+ }
612
+ const node = domEl ? ELEMENT_TO_NODE.get(domEl) : null;
613
+ if (!node) {
614
+ throw new Error(`Cannot resolve a Slate node from DOM node: ${domEl}`);
615
+ }
616
+ return node;
617
+ },
618
+ /**
619
+ * Get the target range from a DOM `event`.
620
+ */
621
+ findEventRange(editor, event) {
622
+ if ('nativeEvent' in event) {
623
+ event = event.nativeEvent;
624
+ }
625
+ const { clientX: x, clientY: y, target } = event;
626
+ if (x == null || y == null) {
627
+ throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`);
628
+ }
629
+ const node = AngularEditor.toSlateNode(editor, event.target);
630
+ const path = AngularEditor.findPath(editor, node);
631
+ // If the drop target is inside a void node, move it into either the
632
+ // next or previous node, depending on which side the `x` and `y`
633
+ // coordinates are closest to.
634
+ if (Editor.isVoid(editor, node)) {
635
+ const rect = target.getBoundingClientRect();
636
+ const isPrev = editor.isInline(node)
637
+ ? x - rect.left < rect.left + rect.width - x
638
+ : y - rect.top < rect.top + rect.height - y;
639
+ const edge = Editor.point(editor, path, {
640
+ edge: isPrev ? 'start' : 'end'
641
+ });
642
+ const point = isPrev ? Editor.before(editor, edge) : Editor.after(editor, edge);
643
+ if (point) {
644
+ return Editor.range(editor, point);
645
+ }
646
+ }
647
+ // Else resolve a range from the caret position where the drop occured.
648
+ let domRange;
649
+ const window = AngularEditor.getWindow(editor);
650
+ const { document } = window;
651
+ // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)
652
+ if (document.caretRangeFromPoint) {
653
+ domRange = document.caretRangeFromPoint(x, y);
654
+ }
655
+ else {
656
+ const position = document.caretPositionFromPoint(x, y);
657
+ if (position) {
658
+ domRange = document.createRange();
659
+ domRange.setStart(position.offsetNode, position.offset);
660
+ domRange.setEnd(position.offsetNode, position.offset);
661
+ }
662
+ }
663
+ if (!domRange) {
664
+ throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`);
665
+ }
666
+ // Resolve a Slate range from the DOM range.
667
+ const range = AngularEditor.toSlateRange(editor, domRange);
668
+ return range;
669
+ },
670
+ /**
671
+ * Find a Slate point from a DOM selection's `domNode` and `domOffset`.
672
+ */
673
+ toSlatePoint(editor, domPoint) {
674
+ const [domNode] = domPoint;
675
+ const [nearestNode, nearestOffset] = normalizeDOMPoint(domPoint);
676
+ let parentNode = nearestNode.parentNode;
677
+ let textNode = null;
678
+ let offset = 0;
679
+ // block card
680
+ const cardTargetAttr = getCardTargetAttribute(domNode);
681
+ if (cardTargetAttr) {
682
+ const domSelection = window.getSelection();
683
+ const isBackward = editor.selection && Range.isBackward(editor.selection);
684
+ const blockCardEntry = AngularEditor.toSlateCardEntry(editor, domNode) || AngularEditor.toSlateCardEntry(editor, nearestNode);
685
+ const [, blockPath] = blockCardEntry;
686
+ if (domSelection.isCollapsed) {
687
+ if (isCardLeftByTargetAttr(cardTargetAttr)) {
688
+ return { path: blockPath, offset: -1 };
689
+ }
690
+ else {
691
+ return { path: blockPath, offset: -2 };
692
+ }
693
+ }
694
+ // forward
695
+ // and to the end of previous node
696
+ if (isCardLeftByTargetAttr(cardTargetAttr) && !isBackward) {
697
+ const endPath = blockPath[blockPath.length - 1] <= 0
698
+ ? blockPath
699
+ : Path.previous(blockPath);
700
+ return Editor.end(editor, endPath);
701
+ }
702
+ // to the of current node
703
+ if ((isCardCenterByTargetAttr(cardTargetAttr) ||
704
+ isCardRightByTargetAttr(cardTargetAttr)) &&
705
+ !isBackward) {
706
+ return Editor.end(editor, blockPath);
707
+ }
708
+ // backward
709
+ // and to the start of next node
710
+ if (isCardRightByTargetAttr(cardTargetAttr) && isBackward) {
711
+ return Editor.start(editor, Path.next(blockPath));
712
+ }
713
+ // and to the start of current node
714
+ if ((isCardCenterByTargetAttr(cardTargetAttr) ||
715
+ isCardLeftByTargetAttr(cardTargetAttr)) &&
716
+ isBackward) {
717
+ return Editor.start(editor, blockPath);
718
+ }
719
+ }
720
+ if (parentNode) {
721
+ const voidNode = parentNode.closest('[data-slate-void="true"]');
722
+ let leafNode = parentNode.closest('[data-slate-leaf]');
723
+ let domNode = null;
724
+ // Calculate how far into the text node the `nearestNode` is, so that we
725
+ // can determine what the offset relative to the text node is.
726
+ if (leafNode) {
727
+ textNode = leafNode.closest('[data-slate-node="text"]');
728
+ const window = AngularEditor.getWindow(editor);
729
+ const range = window.document.createRange();
730
+ range.setStart(textNode, 0);
731
+ range.setEnd(nearestNode, nearestOffset);
732
+ const contents = range.cloneContents();
733
+ const removals = [
734
+ ...Array.prototype.slice.call(contents.querySelectorAll('[data-slate-zero-width]')),
735
+ ...Array.prototype.slice.call(contents.querySelectorAll('[contenteditable=false]')),
736
+ ];
737
+ removals.forEach(el => {
738
+ el.parentNode.removeChild(el);
739
+ });
740
+ // COMPAT: Edge has a bug where Range.prototype.toString() will
741
+ // convert \n into \r\n. The bug causes a loop when slate-react
742
+ // attempts to reposition its cursor to match the native position. Use
743
+ // textContent.length instead.
744
+ // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/
745
+ offset = contents.textContent.length;
746
+ domNode = textNode;
747
+ }
748
+ else if (voidNode) {
749
+ // For void nodes, the element with the offset key will be a cousin, not an
750
+ // ancestor, so find it by going down from the nearest void parent.
751
+ leafNode = voidNode.querySelector('[data-slate-leaf]');
752
+ parentNode = voidNode.querySelector('[data-slate-length="0"]');
753
+ textNode = leafNode.closest('[data-slate-node="text"]');
754
+ domNode = leafNode;
755
+ offset = domNode.textContent.length;
756
+ }
757
+ // COMPAT: If the parent node is a Slate zero-width space, editor is
758
+ // because the text node should have no characters. However, during IME
759
+ // composition the ASCII characters will be prepended to the zero-width
760
+ // space, so subtract 1 from the offset to account for the zero-width
761
+ // space character.
762
+ if (domNode &&
763
+ offset === domNode.textContent.length &&
764
+ (parentNode && parentNode.hasAttribute('data-slate-zero-width'))) {
765
+ offset--;
766
+ }
767
+ }
768
+ if (!textNode) {
769
+ throw new Error(`Cannot resolve a Slate point from DOM point: ${domPoint}`);
770
+ }
771
+ // COMPAT: If someone is clicking from one Slate editor into another,
772
+ // the select event fires twice, once for the old editor's `element`
773
+ // first, and then afterwards for the correct `element`. (2017/03/03)
774
+ const slateNode = AngularEditor.toSlateNode(editor, textNode);
775
+ const path = AngularEditor.findPath(editor, slateNode);
776
+ return { path, offset };
777
+ },
778
+ /**
779
+ * Find a Slate range from a DOM range or selection.
780
+ */
781
+ toSlateRange(editor, domRange) {
782
+ const el = isDOMSelection(domRange) ? domRange.anchorNode : domRange.startContainer;
783
+ let anchorNode;
784
+ let anchorOffset;
785
+ let focusNode;
786
+ let focusOffset;
787
+ let isCollapsed;
788
+ if (el) {
789
+ if (isDOMSelection(domRange)) {
790
+ anchorNode = domRange.anchorNode;
791
+ anchorOffset = domRange.anchorOffset;
792
+ focusNode = domRange.focusNode;
793
+ focusOffset = domRange.focusOffset;
794
+ // COMPAT: There's a bug in chrome that always returns `true` for
795
+ // `isCollapsed` for a Selection that comes from a ShadowRoot.
796
+ // (2020/08/08)
797
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=447523
798
+ if (IS_CHROME && hasShadowRoot()) {
799
+ isCollapsed =
800
+ domRange.anchorNode === domRange.focusNode &&
801
+ domRange.anchorOffset === domRange.focusOffset;
802
+ }
803
+ else {
804
+ isCollapsed = domRange.isCollapsed;
805
+ }
806
+ }
807
+ else {
808
+ anchorNode = domRange.startContainer;
809
+ anchorOffset = domRange.startOffset;
810
+ focusNode = domRange.endContainer;
811
+ focusOffset = domRange.endOffset;
812
+ isCollapsed = domRange.collapsed;
813
+ }
814
+ }
815
+ if (anchorNode == null || focusNode == null || anchorOffset == null || focusOffset == null) {
816
+ throw new Error(`Cannot resolve a Slate range from DOM range: ${domRange}`);
817
+ }
818
+ const anchor = AngularEditor.toSlatePoint(editor, [anchorNode, anchorOffset]);
819
+ const focus = isCollapsed ? anchor : AngularEditor.toSlatePoint(editor, [focusNode, focusOffset]);
820
+ return { anchor, focus };
821
+ },
822
+ isLeafBlock(editor, node) {
823
+ return Element.isElement(node) && !editor.isInline(node) && Editor.hasInlines(editor, node);
824
+ },
825
+ isBlockCardLeftCursor(editor) {
826
+ return editor.selection.anchor.offset === FAKE_LEFT_BLOCK_CARD_OFFSET && editor.selection.focus.offset === FAKE_LEFT_BLOCK_CARD_OFFSET;
827
+ },
828
+ isBlockCardRightCursor(editor) {
829
+ return editor.selection.anchor.offset === FAKE_RIGHT_BLOCK_CARD_OFFSET && editor.selection.focus.offset === FAKE_RIGHT_BLOCK_CARD_OFFSET;
830
+ },
831
+ getCardCursorNode(editor, blockCardNode, options) {
832
+ const blockCardElement = AngularEditor.toDOMNode(editor, blockCardNode);
833
+ const cardCenter = blockCardElement.parentElement;
834
+ return options.direction === 'left'
835
+ ? cardCenter.previousElementSibling
836
+ : cardCenter.nextElementSibling;
837
+ },
838
+ toSlateCardEntry(editor, node) {
839
+ const element = node.parentElement
840
+ .closest('.slate-block-card')?.querySelector('[card-target="card-center"]')
841
+ .firstElementChild;
842
+ const slateNode = AngularEditor.toSlateNode(editor, element);
843
+ const path = AngularEditor.findPath(editor, slateNode);
844
+ return [slateNode, path];
845
+ },
846
+ /**
847
+ * move native selection to card-left or card-right
848
+ * @param editor
849
+ * @param blockCardNode
850
+ * @param options
851
+ */
852
+ moveBlockCard(editor, blockCardNode, options) {
853
+ const cursorNode = AngularEditor.getCardCursorNode(editor, blockCardNode, options);
854
+ const window = AngularEditor.getWindow(editor);
855
+ const domSelection = window.getSelection();
856
+ domSelection.setBaseAndExtent(cursorNode, 1, cursorNode, 1);
857
+ },
858
+ /**
859
+ * move slate selection to card-left or card-right
860
+ * @param editor
861
+ * @param path
862
+ * @param options
863
+ */
864
+ moveBlockCardCursor(editor, path, options) {
865
+ const cursor = { path, offset: options.direction === 'left' ? FAKE_LEFT_BLOCK_CARD_OFFSET : FAKE_RIGHT_BLOCK_CARD_OFFSET };
866
+ Transforms.select(editor, { anchor: cursor, focus: cursor });
867
+ },
868
+ hasRange(editor, range) {
869
+ const { anchor, focus } = range;
870
+ return (Editor.hasPath(editor, anchor.path) && Editor.hasPath(editor, focus.path));
871
+ },
872
+ };
873
+
874
+ /**
875
+ * Hotkey mappings for each platform.
876
+ */
877
+ const HOTKEYS = {
878
+ bold: 'mod+b',
879
+ compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'],
880
+ moveBackward: 'left',
881
+ moveForward: 'right',
882
+ moveUp: 'up',
883
+ moveDown: 'down',
884
+ moveWordBackward: 'ctrl+left',
885
+ moveWordForward: 'ctrl+right',
886
+ deleteBackward: 'shift?+backspace',
887
+ deleteForward: 'shift?+delete',
888
+ extendBackward: 'shift+left',
889
+ extendForward: 'shift+right',
890
+ italic: 'mod+i',
891
+ splitBlock: 'shift?+enter',
892
+ undo: 'mod+z'
893
+ };
894
+ const APPLE_HOTKEYS = {
895
+ moveLineBackward: 'opt+up',
896
+ moveLineForward: 'opt+down',
897
+ moveWordBackward: 'opt+left',
898
+ moveWordForward: 'opt+right',
899
+ deleteBackward: ['ctrl+backspace', 'ctrl+h'],
900
+ deleteForward: ['ctrl+delete', 'ctrl+d'],
901
+ deleteLineBackward: 'cmd+shift?+backspace',
902
+ deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'],
903
+ deleteWordBackward: 'opt+shift?+backspace',
904
+ deleteWordForward: 'opt+shift?+delete',
905
+ extendLineBackward: 'opt+shift+up',
906
+ extendLineForward: 'opt+shift+down',
907
+ redo: 'cmd+shift+z',
908
+ transposeCharacter: 'ctrl+t'
909
+ };
910
+ const WINDOWS_HOTKEYS = {
911
+ deleteWordBackward: 'ctrl+shift?+backspace',
912
+ deleteWordForward: 'ctrl+shift?+delete',
913
+ redo: ['ctrl+y', 'ctrl+shift+z']
914
+ };
915
+ /**
916
+ * Create a platform-aware hotkey checker.
917
+ */
918
+ const create = (key) => {
919
+ const generic = HOTKEYS[key];
920
+ const apple = APPLE_HOTKEYS[key];
921
+ const windows = WINDOWS_HOTKEYS[key];
922
+ const isGeneric = generic && isKeyHotkey(generic);
923
+ const isApple = apple && isKeyHotkey(apple);
924
+ const isWindows = windows && isKeyHotkey(windows);
925
+ return (event) => {
926
+ if (isGeneric && isGeneric(event)) {
927
+ return true;
928
+ }
929
+ if (IS_APPLE && isApple && isApple(event)) {
930
+ return true;
931
+ }
932
+ if (!IS_APPLE && isWindows && isWindows(event)) {
933
+ return true;
934
+ }
935
+ return false;
936
+ };
937
+ };
938
+ /**
939
+ * Hotkeys.
940
+ */
941
+ const hotkeys = {
942
+ isBold: create('bold'),
943
+ isCompose: create('compose'),
944
+ isMoveBackward: create('moveBackward'),
945
+ isMoveForward: create('moveForward'),
946
+ isMoveUp: create('moveUp'),
947
+ isMoveDown: create('moveDown'),
948
+ isDeleteBackward: create('deleteBackward'),
949
+ isDeleteForward: create('deleteForward'),
950
+ isDeleteLineBackward: create('deleteLineBackward'),
951
+ isDeleteLineForward: create('deleteLineForward'),
952
+ isDeleteWordBackward: create('deleteWordBackward'),
953
+ isDeleteWordForward: create('deleteWordForward'),
954
+ isExtendBackward: create('extendBackward'),
955
+ isExtendForward: create('extendForward'),
956
+ isExtendLineBackward: create('extendLineBackward'),
957
+ isExtendLineForward: create('extendLineForward'),
958
+ isItalic: create('italic'),
959
+ isMoveLineBackward: create('moveLineBackward'),
960
+ isMoveLineForward: create('moveLineForward'),
961
+ isMoveWordBackward: create('moveWordBackward'),
962
+ isMoveWordForward: create('moveWordForward'),
963
+ isRedo: create('redo'),
964
+ isSplitBlock: create('splitBlock'),
965
+ isTransposeCharacter: create('transposeCharacter'),
966
+ isUndo: create('undo')
967
+ };
968
+
969
+ function isTemplateRef(value) {
970
+ return value && value instanceof TemplateRef;
971
+ }
972
+ function isComponentType(value) {
973
+ return !isTemplateRef(value);
974
+ }
975
+
976
+ const shallowCompare = (obj1, obj2) => Object.keys(obj1).length === Object.keys(obj2).length &&
977
+ Object.keys(obj1).every(key => obj2.hasOwnProperty(key) && obj1[key] === obj2[key]);
978
+ /**
979
+ * Check if a list of decorator ranges are equal to another.
980
+ *
981
+ * PERF: this requires the two lists to also have the ranges inside them in the
982
+ * same order, but this is an okay constraint for us since decorations are
983
+ * kept in order, and the odd case where they aren't is okay to re-render for.
984
+ */
985
+ const isDecoratorRangeListEqual = (list, another) => {
986
+ if (list.length !== another.length) {
987
+ return false;
988
+ }
989
+ for (let i = 0; i < list.length; i++) {
990
+ const range = list[i];
991
+ const other = another[i];
992
+ const { anchor: rangeAnchor, focus: rangeFocus, ...rangeOwnProps } = range;
993
+ const { anchor: otherAnchor, focus: otherFocus, ...otherOwnProps } = other;
994
+ if (!Range.equals(range, other) ||
995
+ range[PLACEHOLDER_SYMBOL] !== other[PLACEHOLDER_SYMBOL] ||
996
+ !shallowCompare(rangeOwnProps, otherOwnProps)) {
997
+ return false;
998
+ }
999
+ }
1000
+ return true;
1001
+ };
1002
+
1003
+ const isValid = (value) => (Element.isElement(value) &&
1004
+ value.children.length > 0 &&
1005
+ value.children.every((child) => isValid(child))) ||
1006
+ Text$1.isText(value);
1007
+ const check = (document) => {
1008
+ return document.every((value) => Element.isElement(value) && isValid(value));
1009
+ ;
1010
+ };
1011
+ function normalize(document) {
1012
+ return document.filter((value) => Element.isElement(value) && isValid(value));
1013
+ }
1014
+
1015
+ /**
1016
+ * Utilities for single-line deletion
1017
+ */
1018
+ const doRectsIntersect = (rect, compareRect) => {
1019
+ const middle = (compareRect.top + compareRect.bottom) / 2;
1020
+ return rect.top <= middle && rect.bottom >= middle;
1021
+ };
1022
+ const areRangesSameLine = (editor, range1, range2) => {
1023
+ const rect1 = AngularEditor.toDOMRange(editor, range1).getBoundingClientRect();
1024
+ const rect2 = AngularEditor.toDOMRange(editor, range2).getBoundingClientRect();
1025
+ return doRectsIntersect(rect1, rect2) && doRectsIntersect(rect2, rect1);
1026
+ };
1027
+ /**
1028
+ * A helper utility that returns the end portion of a `Range`
1029
+ * which is located on a single line.
1030
+ *
1031
+ * @param {Editor} editor The editor object to compare against
1032
+ * @param {Range} parentRange The parent range to compare against
1033
+ * @returns {Range} A valid portion of the parentRange which is one a single line
1034
+ */
1035
+ const findCurrentLineRange = (editor, parentRange) => {
1036
+ const parentRangeBoundary = Editor.range(editor, Range.end(parentRange));
1037
+ const positions = Array.from(Editor.positions(editor, { at: parentRange }));
1038
+ let left = 0;
1039
+ let right = positions.length;
1040
+ let middle = Math.floor(right / 2);
1041
+ if (areRangesSameLine(editor, Editor.range(editor, positions[left]), parentRangeBoundary)) {
1042
+ return Editor.range(editor, positions[left], parentRangeBoundary);
1043
+ }
1044
+ if (positions.length < 2) {
1045
+ return Editor.range(editor, positions[positions.length - 1], parentRangeBoundary);
1046
+ }
1047
+ while (middle !== positions.length && middle !== left) {
1048
+ if (areRangesSameLine(editor, Editor.range(editor, positions[middle]), parentRangeBoundary)) {
1049
+ right = middle;
1050
+ }
1051
+ else {
1052
+ left = middle;
1053
+ }
1054
+ middle = Math.floor((left + right) / 2);
1055
+ }
1056
+ return Editor.range(editor, positions[right], parentRangeBoundary);
1057
+ };
1058
+
1059
+ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1060
+ const e = editor;
1061
+ const { apply, onChange, deleteBackward } = e;
1062
+ e.deleteBackward = unit => {
1063
+ if (unit !== 'line') {
1064
+ return deleteBackward(unit);
1065
+ }
1066
+ if (editor.selection && Range.isCollapsed(editor.selection)) {
1067
+ const parentBlockEntry = Editor.above(editor, {
1068
+ match: n => Editor.isBlock(editor, n),
1069
+ at: editor.selection,
1070
+ });
1071
+ if (parentBlockEntry) {
1072
+ const [, parentBlockPath] = parentBlockEntry;
1073
+ const parentElementRange = Editor.range(editor, parentBlockPath, editor.selection.anchor);
1074
+ const currentLineRange = findCurrentLineRange(e, parentElementRange);
1075
+ if (!Range.isCollapsed(currentLineRange)) {
1076
+ Transforms.delete(editor, { at: currentLineRange });
1077
+ }
1078
+ }
1079
+ }
1080
+ };
1081
+ e.apply = (op) => {
1082
+ const matches = [];
1083
+ switch (op.type) {
1084
+ case 'insert_text':
1085
+ case 'remove_text':
1086
+ case 'set_node': {
1087
+ for (const [node, path] of Editor.levels(e, { at: op.path })) {
1088
+ const key = AngularEditor.findKey(e, node);
1089
+ matches.push([path, key]);
1090
+ }
1091
+ break;
1092
+ }
1093
+ case 'insert_node':
1094
+ case 'remove_node':
1095
+ case 'merge_node':
1096
+ case 'split_node': {
1097
+ for (const [node, path] of Editor.levels(e, {
1098
+ at: Path.parent(op.path),
1099
+ })) {
1100
+ const key = AngularEditor.findKey(e, node);
1101
+ matches.push([path, key]);
1102
+ }
1103
+ break;
1104
+ }
1105
+ case 'move_node': {
1106
+ const commonPath = Path.common(Path.parent(op.path), Path.parent(op.newPath));
1107
+ for (const [node, path] of Editor.levels(e, { at: Path.parent(op.path) })) {
1108
+ const key = AngularEditor.findKey(e, node);
1109
+ matches.push([Editor.pathRef(editor, path), key]);
1110
+ }
1111
+ for (const [node, path] of Editor.levels(e, { at: Path.parent(op.newPath) })) {
1112
+ if (path.length > commonPath.length) {
1113
+ const key = AngularEditor.findKey(e, node);
1114
+ matches.push([Editor.pathRef(editor, path), key]);
1115
+ }
1116
+ }
1117
+ break;
1118
+ }
1119
+ }
1120
+ apply(op);
1121
+ for (const [source, key] of matches) {
1122
+ const [node] = Editor.node(e, Path.isPath(source) ? source : source.current);
1123
+ NODE_TO_KEY.set(node, key);
1124
+ }
1125
+ };
1126
+ e.onChange = () => {
1127
+ const onContextChange = EDITOR_TO_ON_CHANGE.get(e);
1128
+ if (onContextChange) {
1129
+ onContextChange();
1130
+ }
1131
+ onChange();
1132
+ };
1133
+ e.setFragmentData = (data) => {
1134
+ const { selection } = e;
1135
+ if (!selection) {
1136
+ return;
1137
+ }
1138
+ const [start, end] = Range.edges(selection);
1139
+ const startVoid = Editor.void(e, { at: start.path });
1140
+ const endVoid = Editor.void(e, { at: end.path });
1141
+ if (Range.isCollapsed(selection) && !startVoid) {
1142
+ return;
1143
+ }
1144
+ // Create a fake selection so that we can add a Base64-encoded copy of the
1145
+ // fragment to the HTML, to decode on future pastes.
1146
+ const domRange = AngularEditor.toDOMRange(e, selection);
1147
+ let contents = domRange.cloneContents();
1148
+ let attach = contents.childNodes[0];
1149
+ // Make sure attach is non-empty, since empty nodes will not get copied.
1150
+ const contentsArray = Array.from(contents.children);
1151
+ contentsArray.forEach(node => {
1152
+ if (node.textContent && node.textContent.trim() !== '') {
1153
+ attach = node;
1154
+ }
1155
+ });
1156
+ // COMPAT: If the end node is a void node, we need to move the end of the
1157
+ // range from the void node's spacer span, to the end of the void node's
1158
+ // content, since the spacer is before void's content in the DOM.
1159
+ if (endVoid) {
1160
+ const [voidNode] = endVoid;
1161
+ const r = domRange.cloneRange();
1162
+ const domNode = AngularEditor.toDOMNode(e, voidNode);
1163
+ r.setEndAfter(domNode);
1164
+ contents = r.cloneContents();
1165
+ }
1166
+ // COMPAT: If the start node is a void node, we need to attach the encoded
1167
+ // fragment to the void node's content node instead of the spacer, because
1168
+ // attaching it to empty `<div>/<span>` nodes will end up having it erased by
1169
+ // most browsers. (2018/04/27)
1170
+ if (startVoid) {
1171
+ attach = contents.querySelector('[data-slate-spacer]');
1172
+ }
1173
+ // Remove any zero-width space spans from the cloned DOM so that they don't
1174
+ // show up elsewhere when pasted.
1175
+ Array.from(contents.querySelectorAll('[data-slate-zero-width]')).forEach(zw => {
1176
+ const isNewline = zw.getAttribute('data-slate-zero-width') === 'n';
1177
+ zw.textContent = isNewline ? '\n' : '';
1178
+ });
1179
+ // Set a `data-slate-fragment` attribute on a non-empty node, so it shows up
1180
+ // in the HTML, and can be used for intra-Slate pasting. If it's a text
1181
+ // node, wrap it in a `<span>` so we have something to set an attribute on.
1182
+ if (isDOMText(attach)) {
1183
+ const span = attach.ownerDocument.createElement('span');
1184
+ // COMPAT: In Chrome and Safari, if we don't add the `white-space` style
1185
+ // then leading and trailing spaces will be ignored. (2017/09/21)
1186
+ span.style.whiteSpace = 'pre';
1187
+ span.appendChild(attach);
1188
+ contents.appendChild(span);
1189
+ attach = span;
1190
+ }
1191
+ const fragment = e.getFragment();
1192
+ const stringObj = JSON.stringify(fragment);
1193
+ const encoded = window.btoa(encodeURIComponent(stringObj));
1194
+ attach.setAttribute('data-slate-fragment', encoded);
1195
+ data.setData(`application/${clipboardFormatKey}`, encoded);
1196
+ // Add the content to a <div> so that we can get its inner HTML.
1197
+ const div = contents.ownerDocument.createElement('div');
1198
+ div.appendChild(contents);
1199
+ div.setAttribute('hidden', 'true');
1200
+ contents.ownerDocument.body.appendChild(div);
1201
+ data.setData('text/html', div.innerHTML);
1202
+ data.setData('text/plain', getPlainText(div));
1203
+ contents.ownerDocument.body.removeChild(div);
1204
+ return data;
1205
+ };
1206
+ e.deleteCutData = () => {
1207
+ const { selection } = editor;
1208
+ if (selection) {
1209
+ if (Range.isExpanded(selection)) {
1210
+ Editor.deleteFragment(editor);
1211
+ }
1212
+ else {
1213
+ const node = Node.parent(editor, selection.anchor.path);
1214
+ if (Editor.isVoid(editor, node)) {
1215
+ Transforms.delete(editor);
1216
+ }
1217
+ }
1218
+ }
1219
+ };
1220
+ e.insertData = (data) => {
1221
+ if (!e.insertFragmentData(data)) {
1222
+ e.insertTextData(data);
1223
+ }
1224
+ };
1225
+ e.insertFragmentData = (data) => {
1226
+ /**
1227
+ * Checking copied fragment from application/x-slate-fragment or data-slate-fragment
1228
+ */
1229
+ const fragment = data.getData(`application/${clipboardFormatKey}`) ||
1230
+ getSlateFragmentAttribute(data);
1231
+ if (fragment) {
1232
+ const decoded = decodeURIComponent(window.atob(fragment));
1233
+ const parsed = JSON.parse(decoded);
1234
+ e.insertFragment(parsed);
1235
+ return true;
1236
+ }
1237
+ return false;
1238
+ };
1239
+ e.insertTextData = (data) => {
1240
+ const text = data.getData('text/plain');
1241
+ if (text) {
1242
+ const lines = text.split(/\r\n|\r|\n/);
1243
+ let split = false;
1244
+ for (const line of lines) {
1245
+ if (split) {
1246
+ Transforms.splitNodes(e, { always: true });
1247
+ }
1248
+ e.insertText(line);
1249
+ split = true;
1250
+ }
1251
+ return true;
1252
+ }
1253
+ return false;
1254
+ };
1255
+ e.onKeydown = () => { };
1256
+ e.onClick = () => { };
1257
+ e.isBlockCard = (element) => false;
1258
+ e.onError = (errorData) => {
1259
+ if (errorData.nativeError) {
1260
+ console.error(errorData.nativeError);
1261
+ }
1262
+ else {
1263
+ console.error(errorData);
1264
+ }
1265
+ };
1266
+ return e;
1267
+ };
1268
+
1269
+ const TOP_BLUR = 'blur';
1270
+ const TOP_COMPOSITION_END = 'compositionend';
1271
+ const TOP_COMPOSITION_START = 'compositionstart';
1272
+ const TOP_COMPOSITION_UPDATE = 'compositionupdate';
1273
+ const TOP_KEY_DOWN = 'keydown';
1274
+ const TOP_KEY_PRESS = 'keypress';
1275
+ const TOP_KEY_UP = 'keyup';
1276
+ const TOP_MOUSE_DOWN = 'mousedown';
1277
+ const TOP_MOUSE_MOVE = 'mousemove';
1278
+ const TOP_MOUSE_OUT = 'mouseout';
1279
+ const TOP_TEXT_INPUT = 'textInput';
1280
+ const TOP_PASTE = 'paste';
1281
+
1282
+ /**
1283
+ * Copyright (c) Facebook, Inc. and its affiliates.
1284
+ *
1285
+ * This source code is licensed under the MIT license found in the
1286
+ * LICENSE file in the root directory of this source tree.
1287
+ */
1288
+ /**
1289
+ * These variables store information about text content of a target node,
1290
+ * allowing comparison of content before and after a given event.
1291
+ *
1292
+ * Identify the node where selection currently begins, then observe
1293
+ * both its text content and its current position in the DOM. Since the
1294
+ * browser may natively replace the target node during composition, we can
1295
+ * use its position to find its replacement.
1296
+ *
1297
+ *
1298
+ */
1299
+ let root = null;
1300
+ let startText = null;
1301
+ let fallbackText = null;
1302
+ function initialize(nativeEventTarget) {
1303
+ root = nativeEventTarget;
1304
+ startText = getText();
1305
+ return true;
1306
+ }
1307
+ function reset() {
1308
+ root = null;
1309
+ startText = null;
1310
+ fallbackText = null;
1311
+ }
1312
+ function getData() {
1313
+ if (fallbackText) {
1314
+ return fallbackText;
1315
+ }
1316
+ let start;
1317
+ const startValue = startText;
1318
+ const startLength = startValue.length;
1319
+ let end;
1320
+ const endValue = getText();
1321
+ const endLength = endValue.length;
1322
+ for (start = 0; start < startLength; start++) {
1323
+ if (startValue[start] !== endValue[start]) {
1324
+ break;
1325
+ }
1326
+ }
1327
+ const minEnd = startLength - start;
1328
+ for (end = 1; end <= minEnd; end++) {
1329
+ if (startValue[startLength - end] !== endValue[endLength - end]) {
1330
+ break;
1331
+ }
1332
+ }
1333
+ const sliceTail = end > 1 ? 1 - end : undefined;
1334
+ fallbackText = endValue.slice(start, sliceTail);
1335
+ return fallbackText;
1336
+ }
1337
+ function getText() {
1338
+ if ('value' in root) {
1339
+ return root.value;
1340
+ }
1341
+ return root.textContent;
1342
+ }
1343
+
1344
+ /**
1345
+ * Copyright (c) Facebook, Inc. and its affiliates.
1346
+ *
1347
+ * This source code is licensed under the MIT license found in the
1348
+ * LICENSE file in the root directory of this source tree.
1349
+ */
1350
+ const canUseDOM = !!(typeof window !== 'undefined' &&
1351
+ typeof window.document !== 'undefined' &&
1352
+ typeof window.document.createElement !== 'undefined');
1353
+ const END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
1354
+ const START_KEYCODE = 229;
1355
+ const canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window;
1356
+ let documentMode = null;
1357
+ if (canUseDOM && 'documentMode' in document) {
1358
+ documentMode = document.documentMode;
1359
+ }
1360
+ // Webkit offers a very useful `textInput` event that can be used to
1361
+ // directly represent `beforeInput`. The IE `textinput` event is not as
1362
+ // useful, so we don't use it.
1363
+ const canUseTextInputEvent = canUseDOM && 'TextEvent' in window && !documentMode;
1364
+ // In IE9+, we have access to composition events, but the data supplied
1365
+ // by the native compositionend event may be incorrect. Japanese ideographic
1366
+ // spaces, for instance (\u3000) are not recorded correctly.
1367
+ const useFallbackCompositionData = canUseDOM && (!canUseCompositionEvent || (documentMode && documentMode > 8 && documentMode <= 11));
1368
+ const SPACEBAR_CODE = 32;
1369
+ const SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
1370
+ // Events and their corresponding property names.
1371
+ const eventTypes = {
1372
+ beforeInput: {
1373
+ phasedRegistrationNames: {
1374
+ bubbled: 'onBeforeInput',
1375
+ captured: 'onBeforeInputCapture'
1376
+ },
1377
+ dependencies: [TOP_COMPOSITION_END, TOP_KEY_PRESS, TOP_TEXT_INPUT, TOP_PASTE]
1378
+ }
1379
+ };
1380
+ // Track whether we've ever handled a keypress on the space key.
1381
+ let hasSpaceKeypress = false;
1382
+ /**
1383
+ * Return whether a native keypress event is assumed to be a command.
1384
+ * This is required because Firefox fires `keypress` events for key commands
1385
+ * (cut, copy, select-all, etc.) even though no character is inserted.
1386
+ */
1387
+ function isKeypressCommand(nativeEvent) {
1388
+ return ((nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
1389
+ // ctrlKey && altKey is equivalent to AltGr, and is not a command.
1390
+ !(nativeEvent.ctrlKey && nativeEvent.altKey));
1391
+ }
1392
+ /**
1393
+ * Does our fallback mode think that this event is the end of composition?
1394
+ *
1395
+ */
1396
+ function isFallbackCompositionEnd(topLevelType, nativeEvent) {
1397
+ switch (topLevelType) {
1398
+ case TOP_KEY_UP:
1399
+ // Command keys insert or clear IME input.
1400
+ return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
1401
+ case TOP_KEY_DOWN:
1402
+ // Expect IME keyCode on each keydown. If we get any other
1403
+ // code we must have exited earlier.
1404
+ return nativeEvent.keyCode !== START_KEYCODE;
1405
+ case TOP_KEY_PRESS:
1406
+ case TOP_MOUSE_DOWN:
1407
+ case TOP_BLUR:
1408
+ // Events are not possible without cancelling IME.
1409
+ return true;
1410
+ default:
1411
+ return false;
1412
+ }
1413
+ }
1414
+ /**
1415
+ * Google Input Tools provides composition data via a CustomEvent,
1416
+ * with the `data` property populated in the `detail` object. If this
1417
+ * is available on the event object, use it. If not, this is a plain
1418
+ * composition event and we have nothing special to extract.
1419
+ *
1420
+ */
1421
+ function getDataFromCustomEvent(nativeEvent) {
1422
+ const detail = nativeEvent.detail;
1423
+ if (typeof detail === 'object' && 'data' in detail) {
1424
+ return detail.data;
1425
+ }
1426
+ return null;
1427
+ }
1428
+ /**
1429
+ * Check if a composition event was triggered by Korean IME.
1430
+ * Our fallback mode does not work well with IE's Korean IME,
1431
+ * so just use native composition events when Korean IME is used.
1432
+ * Although CompositionEvent.locale property is deprecated,
1433
+ * it is available in IE, where our fallback mode is enabled.
1434
+ *
1435
+ */
1436
+ function isUsingKoreanIME(nativeEvent) {
1437
+ return nativeEvent.locale === 'ko';
1438
+ }
1439
+ // Track the current IME composition status, if any.
1440
+ let isComposing = false;
1441
+ function getNativeBeforeInputChars(topLevelType, nativeEvent) {
1442
+ switch (topLevelType) {
1443
+ case TOP_COMPOSITION_END:
1444
+ return getDataFromCustomEvent(nativeEvent);
1445
+ case TOP_KEY_PRESS:
1446
+ /**
1447
+ * If native `textInput` events are available, our goal is to make
1448
+ * use of them. However, there is a special case: the spacebar key.
1449
+ * In Webkit, preventing default on a spacebar `textInput` event
1450
+ * cancels character insertion, but it *also* causes the browser
1451
+ * to fall back to its default spacebar behavior of scrolling the
1452
+ * page.
1453
+ *
1454
+ * Tracking at:
1455
+ * https://code.google.com/p/chromium/issues/detail?id=355103
1456
+ *
1457
+ * To avoid this issue, use the keypress event as if no `textInput`
1458
+ * event is available.
1459
+ */
1460
+ const which = nativeEvent.which;
1461
+ if (which !== SPACEBAR_CODE) {
1462
+ return null;
1463
+ }
1464
+ hasSpaceKeypress = true;
1465
+ return SPACEBAR_CHAR;
1466
+ case TOP_TEXT_INPUT:
1467
+ // Record the characters to be added to the DOM.
1468
+ const chars = nativeEvent.data;
1469
+ // If it's a spacebar character, assume that we have already handled
1470
+ // it at the keypress level and bail immediately. Android Chrome
1471
+ // doesn't give us keycodes, so we need to ignore it.
1472
+ if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
1473
+ return null;
1474
+ }
1475
+ return chars;
1476
+ default:
1477
+ // For other native event types, do nothing.
1478
+ return null;
1479
+ }
1480
+ }
1481
+ /**
1482
+ * For browsers that do not provide the `textInput` event, extract the
1483
+ * appropriate string to use for SyntheticInputEvent.
1484
+ *
1485
+ */
1486
+ function getFallbackBeforeInputChars(topLevelType, nativeEvent) {
1487
+ // If we are currently composing (IME) and using a fallback to do so,
1488
+ // try to extract the composed characters from the fallback object.
1489
+ // If composition event is available, we extract a string only at
1490
+ // compositionevent, otherwise extract it at fallback events.
1491
+ if (isComposing) {
1492
+ if (topLevelType === TOP_COMPOSITION_END || (!canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent))) {
1493
+ const chars = getData();
1494
+ reset();
1495
+ isComposing = false;
1496
+ return chars;
1497
+ }
1498
+ return null;
1499
+ }
1500
+ switch (topLevelType) {
1501
+ case TOP_PASTE:
1502
+ // If a paste event occurs after a keypress, throw out the input
1503
+ // chars. Paste events should not lead to BeforeInput events.
1504
+ return null;
1505
+ case TOP_KEY_PRESS:
1506
+ /**
1507
+ * As of v27, Firefox may fire keypress events even when no character
1508
+ * will be inserted. A few possibilities:
1509
+ *
1510
+ * - `which` is `0`. Arrow keys, Esc key, etc.
1511
+ *
1512
+ * - `which` is the pressed key code, but no char is available.
1513
+ * Ex: 'AltGr + d` in Polish. There is no modified character for
1514
+ * this key combination and no character is inserted into the
1515
+ * document, but FF fires the keypress for char code `100` anyway.
1516
+ * No `input` event will occur.
1517
+ *
1518
+ * - `which` is the pressed key code, but a command combination is
1519
+ * being used. Ex: `Cmd+C`. No character is inserted, and no
1520
+ * `input` event will occur.
1521
+ */
1522
+ if (!isKeypressCommand(nativeEvent)) {
1523
+ // IE fires the `keypress` event when a user types an emoji via
1524
+ // Touch keyboard of Windows. In such a case, the `char` property
1525
+ // holds an emoji character like `\uD83D\uDE0A`. Because its length
1526
+ // is 2, the property `which` does not represent an emoji correctly.
1527
+ // In such a case, we directly return the `char` property instead of
1528
+ // using `which`.
1529
+ if (nativeEvent.char && nativeEvent.char.length > 1) {
1530
+ return nativeEvent.char;
1531
+ }
1532
+ else if (nativeEvent.which) {
1533
+ return String.fromCharCode(nativeEvent.which);
1534
+ }
1535
+ }
1536
+ return null;
1537
+ case TOP_COMPOSITION_END:
1538
+ return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) ? null : nativeEvent.data;
1539
+ default:
1540
+ return null;
1541
+ }
1542
+ }
1543
+ /**
1544
+ * Extract a SyntheticInputEvent for `beforeInput`, based on either native
1545
+ * `textInput` or fallback behavior.
1546
+ *
1547
+ */
1548
+ function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
1549
+ let chars;
1550
+ if (canUseTextInputEvent) {
1551
+ chars = getNativeBeforeInputChars(topLevelType, nativeEvent);
1552
+ }
1553
+ else {
1554
+ chars = getFallbackBeforeInputChars(topLevelType, nativeEvent);
1555
+ }
1556
+ // If no characters are being inserted, no BeforeInput event should
1557
+ // be fired.
1558
+ if (!chars) {
1559
+ return null;
1560
+ }
1561
+ const beforeInputEvent = new BeforeInputEvent();
1562
+ beforeInputEvent.data = chars;
1563
+ beforeInputEvent.nativeEvent = nativeEvent;
1564
+ return beforeInputEvent;
1565
+ }
1566
+ /**
1567
+ * Create an `onBeforeInput` event to match
1568
+ * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
1569
+ *
1570
+ * This event plugin is based on the native `textInput` event
1571
+ * available in Chrome, Safari, Opera, and IE. This event fires after
1572
+ * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
1573
+ *
1574
+ * `beforeInput` is spec'd but not implemented in any browsers, and
1575
+ * the `input` event does not provide any useful information about what has
1576
+ * actually been added, contrary to the spec. Thus, `textInput` is the best
1577
+ * available event to identify the characters that have actually been inserted
1578
+ * into the target node.
1579
+ *
1580
+ * This plugin is also responsible for emitting `composition` events, thus
1581
+ * allowing us to share composition fallback code for both `beforeInput` and
1582
+ * `composition` event types.
1583
+ */
1584
+ const BeforeInputEventPlugin = {
1585
+ extractEvents: (topLevelType, targetInst, nativeEvent, nativeEventTarget) => {
1586
+ return extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget);
1587
+ }
1588
+ };
1589
+ class BeforeInputEvent {
1590
+ }
1591
+
1592
+ const BEFORE_INPUT_EVENTS = [
1593
+ // { name: 'blur', handler: 'onBlur', isTriggerBeforeInput: true },
1594
+ // { name: 'compositionstart', handler: 'onCompositionStart', isTriggerBeforeInput: true },
1595
+ { name: 'compositionupdate', handler: null, isTriggerBeforeInput: true },
1596
+ // { name: 'compositionend', handler: 'onCompositionEnd', isTriggerBeforeInput: false },
1597
+ // { name: 'keydown', handler: 'onKeyDown', isTriggerBeforeInput: true },
1598
+ { name: 'keypress', handler: null, isTriggerBeforeInput: true },
1599
+ { name: 'keyup', handler: 'onKeyUp', isTriggerBeforeInput: true },
1600
+ { name: 'mousedown', handler: 'onMouseDown', isTriggerBeforeInput: true },
1601
+ { name: 'textInput', handler: null, isTriggerBeforeInput: true },
1602
+ // { name: 'paste', handler: 'onPaste', isTriggerBeforeInput: true }
1603
+ ];
1604
+
1605
+ var SlateErrorCode;
1606
+ (function (SlateErrorCode) {
1607
+ SlateErrorCode[SlateErrorCode["ToNativeSelectionError"] = 2100] = "ToNativeSelectionError";
1608
+ SlateErrorCode[SlateErrorCode["ToSlateSelectionError"] = 2101] = "ToSlateSelectionError";
1609
+ SlateErrorCode[SlateErrorCode["OnDOMBeforeInputError"] = 2102] = "OnDOMBeforeInputError";
1610
+ SlateErrorCode[SlateErrorCode["OnSyntheticBeforeInputError"] = 2103] = "OnSyntheticBeforeInputError";
1611
+ SlateErrorCode[SlateErrorCode["OnDOMKeydownError"] = 2104] = "OnDOMKeydownError";
1612
+ SlateErrorCode[SlateErrorCode["GetStartPointError"] = 2105] = "GetStartPointError";
1613
+ SlateErrorCode[SlateErrorCode["NotFoundPreviousRootNodeError"] = 3100] = "NotFoundPreviousRootNodeError";
1614
+ SlateErrorCode[SlateErrorCode["InvalidValueError"] = 4100] = "InvalidValueError";
1615
+ })(SlateErrorCode || (SlateErrorCode = {}));
1616
+
1617
+ class SlateBlockCardComponent {
1618
+ constructor(elementRef) {
1619
+ this.elementRef = elementRef;
1620
+ }
1621
+ get nativeElement() {
1622
+ return this.elementRef.nativeElement;
1623
+ }
1624
+ get centerContainerElement() {
1625
+ return this.centerContianer.nativeElement;
1626
+ }
1627
+ ngOnInit() {
1628
+ this.append();
1629
+ this.nativeElement.classList.add(`slate-block-card`);
1630
+ }
1631
+ append() {
1632
+ this.centerRootNodes.forEach((rootNode) => !this.centerContainerElement.contains(rootNode) && this.centerContainerElement.appendChild(rootNode));
1633
+ }
1634
+ initializeCenter(rootNodes) {
1635
+ this.centerRootNodes = rootNodes;
1636
+ }
1637
+ }
1638
+ SlateBlockCardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateBlockCardComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1639
+ SlateBlockCardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateBlockCardComponent, selector: "slate-block-card, [slateBlockCard]", viewQueries: [{ propertyName: "centerContianer", first: true, predicate: ["centerContianer"], descendants: true, static: true }], ngImport: i0, template: "<span card-target=\"card-left\" class=\"card-left\">{{ '\\uFEFF' }}</span>\n<div card-target=\"card-center\" #centerContianer></div>\n<span card-target=\"card-right\" class=\"card-right\">{{ '\\uFEFF' }}</span>" });
1640
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateBlockCardComponent, decorators: [{
1641
+ type: Component,
1642
+ args: [{ selector: 'slate-block-card, [slateBlockCard]', template: "<span card-target=\"card-left\" class=\"card-left\">{{ '\\uFEFF' }}</span>\n<div card-target=\"card-center\" #centerContianer></div>\n<span card-target=\"card-right\" class=\"card-right\">{{ '\\uFEFF' }}</span>" }]
1643
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { centerContianer: [{
1644
+ type: ViewChild,
1645
+ args: ['centerContianer', { static: true }]
1646
+ }] } });
1647
+
1648
+ /**
1649
+ * Dynamically create/update components or templates
1650
+ * Provide rootNodes for the view container
1651
+ * If the dynamically created component uses onpush mode, then it must call markForCheck when setting the context
1652
+ */
1653
+ class ViewContainerItem {
1654
+ constructor(viewContainerRef) {
1655
+ this.viewContainerRef = viewContainerRef;
1656
+ this.initialized = false;
1657
+ }
1658
+ get rootNodes() {
1659
+ return this.getRootNodes();
1660
+ }
1661
+ getRootNodes() {
1662
+ if (this.embeddedViewRef) {
1663
+ return this.embeddedViewRef.rootNodes.filter((rootNode) => isDOMElement(rootNode));
1664
+ }
1665
+ if (this.componentRef) {
1666
+ return [this.componentRef.instance.nativeElement];
1667
+ }
1668
+ return [];
1669
+ }
1670
+ destroyView() {
1671
+ if (this.embeddedViewRef) {
1672
+ this.embeddedViewRef.destroy();
1673
+ this.embeddedViewRef = null;
1674
+ }
1675
+ if (this.componentRef) {
1676
+ this.componentRef.destroy();
1677
+ this.componentRef = null;
1678
+ }
1679
+ }
1680
+ createView() {
1681
+ this.initialized = true;
1682
+ this.viewType = this.getViewType();
1683
+ const context = this.getContext();
1684
+ if (isTemplateRef(this.viewType)) {
1685
+ this.embeddedViewContext = { context, viewContext: this.viewContext };
1686
+ const embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.viewType, this.embeddedViewContext);
1687
+ this.embeddedViewRef = embeddedViewRef;
1688
+ }
1689
+ if (isComponentType(this.viewType)) {
1690
+ const componentRef = this.viewContainerRef.createComponent(this.viewType);
1691
+ componentRef.instance.context = context;
1692
+ componentRef.instance.viewContext = this.viewContext;
1693
+ this.componentRef = componentRef;
1694
+ }
1695
+ }
1696
+ updateView() {
1697
+ const viewType = this.getViewType();
1698
+ const context = this.getContext();
1699
+ if (this.viewType === viewType) {
1700
+ if (this.componentRef) {
1701
+ if (this.memoizedContext(this.componentRef.instance.context, context)) {
1702
+ return;
1703
+ }
1704
+ this.componentRef.instance.context = context;
1705
+ }
1706
+ if (this.embeddedViewRef) {
1707
+ if (this.memoizedContext(this.embeddedViewContext.context, context)) {
1708
+ return;
1709
+ }
1710
+ this.embeddedViewContext.context = context;
1711
+ }
1712
+ }
1713
+ else {
1714
+ this.viewType = viewType;
1715
+ const firstRootNode = this.rootNodes[0];
1716
+ if (isTemplateRef(this.viewType)) {
1717
+ this.embeddedViewContext = { context, viewContext: this.viewContext };
1718
+ const embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.viewType, this.embeddedViewContext);
1719
+ firstRootNode.replaceWith(...embeddedViewRef.rootNodes.filter((rootNode) => isDOMElement(rootNode)));
1720
+ this.destroyView();
1721
+ this.embeddedViewRef = embeddedViewRef;
1722
+ }
1723
+ if (isComponentType(this.viewType)) {
1724
+ const componentRef = this.viewContainerRef.createComponent(this.viewType);
1725
+ componentRef.instance.context = context;
1726
+ componentRef.instance.viewContext = this.viewContext;
1727
+ firstRootNode.replaceWith(componentRef.instance.nativeElement);
1728
+ this.destroyView();
1729
+ this.componentRef = componentRef;
1730
+ }
1731
+ }
1732
+ }
1733
+ appendBlockCardElement() {
1734
+ if (this.blockCardComponentRef) {
1735
+ this.blockCardComponentRef.instance.append();
1736
+ }
1737
+ }
1738
+ }
1739
+ ViewContainerItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: ViewContainerItem, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive });
1740
+ ViewContainerItem.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: ViewContainerItem, inputs: { viewContext: "viewContext" }, ngImport: i0 });
1741
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: ViewContainerItem, decorators: [{
1742
+ type: Directive
1743
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; }, propDecorators: { viewContext: [{
1744
+ type: Input
1745
+ }] } });
1746
+
1747
+ function hasBeforeContextChange(value) {
1748
+ if (value.beforeContextChange) {
1749
+ return true;
1750
+ }
1751
+ return false;
1752
+ }
1753
+
1754
+ /**
1755
+ * base class for custom element component or text component
1756
+ */
1757
+ class BaseComponent {
1758
+ constructor(elementRef, cdr) {
1759
+ this.elementRef = elementRef;
1760
+ this.cdr = cdr;
1761
+ }
1762
+ set context(value) {
1763
+ if (hasBeforeContextChange(this)) {
1764
+ this.beforeContextChange(value);
1765
+ }
1766
+ this._context = value;
1767
+ this.onContextChange();
1768
+ }
1769
+ get context() {
1770
+ return this._context;
1771
+ }
1772
+ get editor() {
1773
+ return this.viewContext && this.viewContext.editor;
1774
+ }
1775
+ get nativeElement() {
1776
+ return this.elementRef.nativeElement;
1777
+ }
1778
+ }
1779
+ BaseComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: BaseComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
1780
+ BaseComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: BaseComponent, inputs: { context: "context", viewContext: "viewContext" }, ngImport: i0 });
1781
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: BaseComponent, decorators: [{
1782
+ type: Directive
1783
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { context: [{
1784
+ type: Input
1785
+ }], viewContext: [{
1786
+ type: Input
1787
+ }] } });
1788
+ /**
1789
+ * base class for custom leaf component
1790
+ */
1791
+ class BaseLeafComponent extends BaseComponent {
1792
+ constructor() {
1793
+ super(...arguments);
1794
+ this.initialized = false;
1795
+ this.isSlateLeaf = true;
1796
+ }
1797
+ get text() {
1798
+ return this.context && this.context.text;
1799
+ }
1800
+ get leaf() {
1801
+ return this.context && this.context.leaf;
1802
+ }
1803
+ ngOnInit() {
1804
+ this.initialized = true;
1805
+ }
1806
+ onContextChange() {
1807
+ if (!this.initialized) {
1808
+ return;
1809
+ }
1810
+ this.cdr.markForCheck();
1811
+ }
1812
+ renderPlaceholder() {
1813
+ // issue-1: IME input was interrupted
1814
+ // issue-2: IME input focus jumping
1815
+ // Issue occurs when the span node of the placeholder is before the slateString span node
1816
+ if (this.context.leaf['placeholder']) {
1817
+ if (!this.placeholderElement) {
1818
+ this.placeholderElement = document.createElement('span');
1819
+ this.placeholderElement.innerText = this.context.leaf['placeholder'];
1820
+ this.placeholderElement.contentEditable = 'false';
1821
+ this.placeholderElement.setAttribute('data-slate-placeholder', 'true');
1822
+ this.nativeElement.classList.add('leaf-with-placeholder');
1823
+ this.nativeElement.appendChild(this.placeholderElement);
1824
+ }
1825
+ }
1826
+ else {
1827
+ this.destroyPlaceholder();
1828
+ }
1829
+ }
1830
+ destroyPlaceholder() {
1831
+ if (this.placeholderElement) {
1832
+ this.placeholderElement.remove();
1833
+ this.placeholderElement = null;
1834
+ this.nativeElement.classList.remove('leaf-with-placeholder');
1835
+ }
1836
+ }
1837
+ }
1838
+ BaseLeafComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: BaseLeafComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1839
+ BaseLeafComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: BaseLeafComponent, host: { properties: { "attr.data-slate-leaf": "this.isSlateLeaf" } }, usesInheritance: true, ngImport: i0 });
1840
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: BaseLeafComponent, decorators: [{
1841
+ type: Directive
1842
+ }], propDecorators: { isSlateLeaf: [{
1843
+ type: HostBinding,
1844
+ args: ['attr.data-slate-leaf']
1845
+ }] } });
1846
+ /**
1847
+ * base class for custom element component
1848
+ */
1849
+ class BaseElementComponent extends BaseComponent {
1850
+ constructor() {
1851
+ super(...arguments);
1852
+ this.initialized = false;
1853
+ }
1854
+ get element() {
1855
+ return this._context && this._context.element;
1856
+ }
1857
+ get selection() {
1858
+ return this._context && this._context.selection;
1859
+ }
1860
+ get decorations() {
1861
+ return this._context && this._context.decorations;
1862
+ }
1863
+ get children() {
1864
+ return this._context && this._context.element.children;
1865
+ }
1866
+ get isCollapsed() {
1867
+ return this.selection && Range.isCollapsed(this.editor.selection);
1868
+ }
1869
+ get readonly() {
1870
+ return this._context && this._context.readonly;
1871
+ }
1872
+ ngOnInit() {
1873
+ this.updateWeakMap();
1874
+ for (const key in this._context.attributes) {
1875
+ this.nativeElement.setAttribute(key, this._context.attributes[key]);
1876
+ }
1877
+ this.initialized = true;
1878
+ }
1879
+ updateWeakMap() {
1880
+ NODE_TO_ELEMENT.set(this.element, this.nativeElement);
1881
+ ELEMENT_TO_NODE.set(this.nativeElement, this.element);
1882
+ ELEMENT_TO_COMPONENT.set(this.element, this);
1883
+ }
1884
+ ngOnDestroy() {
1885
+ if (NODE_TO_ELEMENT.get(this.element) === this.nativeElement) {
1886
+ NODE_TO_ELEMENT.delete(this.element);
1887
+ }
1888
+ if (ELEMENT_TO_COMPONENT.get(this.element) === this) {
1889
+ ELEMENT_TO_COMPONENT.delete(this.element);
1890
+ }
1891
+ }
1892
+ onContextChange() {
1893
+ this.childrenContext = this.getChildrenContext();
1894
+ if (!this.initialized) {
1895
+ return;
1896
+ }
1897
+ this.cdr.markForCheck();
1898
+ this.updateWeakMap();
1899
+ }
1900
+ getChildrenContext() {
1901
+ return {
1902
+ parent: this._context.element,
1903
+ selection: this._context.selection,
1904
+ decorations: this._context.decorations,
1905
+ decorate: this._context.decorate,
1906
+ readonly: this._context.readonly
1907
+ };
1908
+ }
1909
+ }
1910
+ BaseElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: BaseElementComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1911
+ BaseElementComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: BaseElementComponent, usesInheritance: true, ngImport: i0 });
1912
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: BaseElementComponent, decorators: [{
1913
+ type: Directive
1914
+ }] });
1915
+ /**
1916
+ * base class for custom text component
1917
+ */
1918
+ class BaseTextComponent extends BaseComponent {
1919
+ constructor() {
1920
+ super(...arguments);
1921
+ this.initialized = false;
1922
+ }
1923
+ get text() {
1924
+ return this._context && this._context.text;
1925
+ }
1926
+ ngOnInit() {
1927
+ this.updateWeakMap();
1928
+ this.initialized = true;
1929
+ }
1930
+ updateWeakMap() {
1931
+ ELEMENT_TO_NODE.set(this.nativeElement, this.text);
1932
+ NODE_TO_ELEMENT.set(this.text, this.nativeElement);
1933
+ }
1934
+ ngOnDestroy() {
1935
+ if (NODE_TO_ELEMENT.get(this.text) === this.nativeElement) {
1936
+ NODE_TO_ELEMENT.delete(this.text);
1937
+ }
1938
+ }
1939
+ onContextChange() {
1940
+ if (!this.initialized) {
1941
+ return;
1942
+ }
1943
+ this.cdr.markForCheck();
1944
+ this.updateWeakMap();
1945
+ }
1946
+ }
1947
+ BaseTextComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: BaseTextComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1948
+ BaseTextComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: BaseTextComponent, usesInheritance: true, ngImport: i0 });
1949
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: BaseTextComponent, decorators: [{
1950
+ type: Directive
1951
+ }] });
1952
+
1953
+ /**
1954
+ * the sepcial container for angular template
1955
+ * Add the rootNodes of each child component to the parentElement
1956
+ * Remove useless DOM elements, eg: comment...
1957
+ */
1958
+ class ViewContainer {
1959
+ constructor(elementRef, differs) {
1960
+ this.elementRef = elementRef;
1961
+ this.differs = differs;
1962
+ }
1963
+ ngAfterViewInit() {
1964
+ const differ = this.differs.find(this.childrenComponent).create((index, item) => {
1965
+ return item;
1966
+ });
1967
+ // first diff
1968
+ differ.diff(this.childrenComponent);
1969
+ const parentElement = this.elementRef.nativeElement.parentElement;
1970
+ if (this.childrenComponent.length > 0) {
1971
+ parentElement.insertBefore(this.createFragment(), this.elementRef.nativeElement);
1972
+ this.elementRef.nativeElement.remove();
1973
+ }
1974
+ this.childrenComponent.changes.subscribe((value) => {
1975
+ const iterableChanges = differ.diff(this.childrenComponent);
1976
+ if (iterableChanges) {
1977
+ iterableChanges.forEachOperation((record, previousIndex, currentIndex) => {
1978
+ // removed
1979
+ if (currentIndex === null) {
1980
+ return;
1981
+ }
1982
+ // added or moved
1983
+ this.handleContainerItemChange(record, parentElement);
1984
+ });
1985
+ }
1986
+ });
1987
+ }
1988
+ getPreviousRootNode(currentIndex) {
1989
+ if (currentIndex === 0) {
1990
+ return null;
1991
+ }
1992
+ const previousComponent = this.childrenComponent.find((item, index) => index === currentIndex - 1);
1993
+ let previousRootNode = previousComponent.rootNodes[previousComponent.rootNodes.length - 1];
1994
+ if (previousRootNode) {
1995
+ return previousRootNode;
1996
+ }
1997
+ else {
1998
+ return this.getPreviousRootNode(currentIndex - 1);
1999
+ }
2000
+ }
2001
+ createFragment() {
2002
+ const fragment = document.createDocumentFragment();
2003
+ this.childrenComponent.forEach((component, index) => {
2004
+ fragment.append(...component.rootNodes);
2005
+ });
2006
+ return fragment;
2007
+ }
2008
+ handleContainerItemChange(record, parentElement) {
2009
+ // first insert
2010
+ if (this.elementRef.nativeElement.parentElement && this.elementRef.nativeElement.parentElement === parentElement) {
2011
+ const fragment = document.createDocumentFragment();
2012
+ fragment.append(...record.item.rootNodes);
2013
+ parentElement.insertBefore(fragment, this.elementRef.nativeElement);
2014
+ this.elementRef.nativeElement.remove();
2015
+ return;
2016
+ }
2017
+ // insert at start location
2018
+ if (record.currentIndex === 0) {
2019
+ const fragment = document.createDocumentFragment();
2020
+ fragment.append(...record.item.rootNodes);
2021
+ parentElement.prepend(fragment);
2022
+ }
2023
+ else {
2024
+ // insert afterend of previous component end
2025
+ let previousRootNode = this.getPreviousRootNode(record.currentIndex);
2026
+ if (previousRootNode) {
2027
+ record.item.rootNodes.forEach((rootNode) => {
2028
+ previousRootNode.insertAdjacentElement('afterend', rootNode);
2029
+ previousRootNode = rootNode;
2030
+ });
2031
+ }
2032
+ else {
2033
+ this.viewContext.editor.onError({
2034
+ code: SlateErrorCode.NotFoundPreviousRootNodeError,
2035
+ name: 'not found previous rootNode',
2036
+ nativeError: null
2037
+ });
2038
+ }
2039
+ }
2040
+ // Solve the block-card DOMElement loss when moving nodes
2041
+ record.item.appendBlockCardElement();
2042
+ }
2043
+ }
2044
+ ViewContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: ViewContainer, deps: [{ token: i0.ElementRef }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Directive });
2045
+ ViewContainer.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: ViewContainer, inputs: { viewContext: "viewContext" }, ngImport: i0 });
2046
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: ViewContainer, decorators: [{
2047
+ type: Directive
2048
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.IterableDiffers }]; }, propDecorators: { viewContext: [{
2049
+ type: Input
2050
+ }] } });
2051
+
2052
+ class SlateStringComponent extends ViewContainerItem {
2053
+ constructor(elementRef, viewContainerRef) {
2054
+ super(viewContainerRef);
2055
+ this.elementRef = elementRef;
2056
+ this.viewContainerRef = viewContainerRef;
2057
+ }
2058
+ ngOnInit() {
2059
+ this.createView();
2060
+ }
2061
+ ngOnChanges() {
2062
+ if (!this.initialized) {
2063
+ return;
2064
+ }
2065
+ this.updateView();
2066
+ }
2067
+ ngAfterViewInit() {
2068
+ this.elementRef.nativeElement.remove();
2069
+ }
2070
+ getViewType() {
2071
+ const path = AngularEditor.findPath(this.viewContext.editor, this.context.text);
2072
+ const parentPath = Path.parent(path);
2073
+ // COMPAT: Render text inside void nodes with a zero-width space.
2074
+ // So the node can contain selection but the text is not visible.
2075
+ if (this.viewContext.editor.isVoid(this.context.parent)) {
2076
+ return this.viewContext.templateComponent.emptyStringTemplate;
2077
+ }
2078
+ // COMPAT: If this is the last text node in an empty block, render a zero-
2079
+ // width space that will convert into a line break when copying and pasting
2080
+ // to support expected plain text.
2081
+ if (this.context.leaf.text === '' &&
2082
+ this.context.parent.children[this.context.parent.children.length - 1] === this.context.text &&
2083
+ !this.viewContext.editor.isInline(this.context.parent) &&
2084
+ Editor.string(this.viewContext.editor, parentPath) === '') {
2085
+ return this.viewContext.templateComponent.lineBreakEmptyStringTemplate;
2086
+ }
2087
+ // COMPAT: If the text is empty, it's because it's on the edge of an inline
2088
+ // node, so we render a zero-width space so that the selection can be
2089
+ // inserted next to it still.
2090
+ if (this.context.leaf.text === '') {
2091
+ return this.viewContext.templateComponent.emptyTextTemplate;
2092
+ }
2093
+ // COMPAT: Browsers will collapse trailing new lines at the end of blocks,
2094
+ // so we need to add an extra trailing new lines to prevent that.
2095
+ if (this.context.isLast && this.context.leaf.text.slice(-1) === '\n') {
2096
+ return this.viewContext.templateComponent.compatStringTemplate;
2097
+ }
2098
+ return this.viewContext.templateComponent.stringTemplate;
2099
+ }
2100
+ getContext() {
2101
+ return { text: this.context.leaf.text, elementStringLength: Node.string(this.context.parent).length };
2102
+ }
2103
+ memoizedContext(prev, next) {
2104
+ return false;
2105
+ }
2106
+ }
2107
+ SlateStringComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateStringComponent, deps: [{ token: i0.ElementRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
2108
+ SlateStringComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateStringComponent, selector: "span[slateString]", inputs: { context: "context" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
2109
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateStringComponent, decorators: [{
2110
+ type: Component,
2111
+ args: [{
2112
+ selector: 'span[slateString]',
2113
+ template: '',
2114
+ changeDetection: ChangeDetectionStrategy.OnPush
2115
+ }]
2116
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { context: [{
2117
+ type: Input
2118
+ }] } });
2119
+
2120
+ class SlateDefaultLeafComponent extends BaseLeafComponent {
2121
+ onContextChange() {
2122
+ super.onContextChange();
2123
+ this.renderPlaceholder();
2124
+ }
2125
+ ngOnDestroy() {
2126
+ // Because the placeholder span is not in the current component, it is destroyed along with the current component
2127
+ this.destroyPlaceholder();
2128
+ }
2129
+ }
2130
+ SlateDefaultLeafComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateDefaultLeafComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2131
+ SlateDefaultLeafComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateDefaultLeafComponent, selector: "span[slateDefaultLeaf]", host: { attributes: { "data-slate-leaf": "true" } }, usesInheritance: true, ngImport: i0, template: `<span slateString [context]="context" [viewContext]="viewContext"><span>`, isInline: true, components: [{ type: SlateStringComponent, selector: "span[slateString]", inputs: ["context"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2132
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateDefaultLeafComponent, decorators: [{
2133
+ type: Component,
2134
+ args: [{
2135
+ selector: 'span[slateDefaultLeaf]',
2136
+ template: `<span slateString [context]="context" [viewContext]="viewContext"><span>`,
2137
+ changeDetection: ChangeDetectionStrategy.OnPush,
2138
+ host: {
2139
+ 'data-slate-leaf': 'true'
2140
+ }
2141
+ }]
2142
+ }] });
2143
+
2144
+ class SlateLeafComponent extends ViewContainerItem {
2145
+ ngOnInit() {
2146
+ this.createView();
2147
+ }
2148
+ getContext() {
2149
+ return this.context;
2150
+ }
2151
+ getViewType() {
2152
+ return this.viewContext.renderLeaf && this.viewContext.renderLeaf(this.context.leaf) || SlateDefaultLeafComponent;
2153
+ }
2154
+ memoizedContext(prev, next) {
2155
+ return false;
2156
+ }
2157
+ ngOnChanges(simpleChanges) {
2158
+ if (!this.initialized) {
2159
+ return;
2160
+ }
2161
+ this.updateView();
2162
+ }
2163
+ }
2164
+ SlateLeafComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateLeafComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2165
+ SlateLeafComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateLeafComponent, selector: "slate-leaf", inputs: { context: "context" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
2166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateLeafComponent, decorators: [{
2167
+ type: Component,
2168
+ args: [{
2169
+ selector: 'slate-leaf',
2170
+ template: '',
2171
+ changeDetection: ChangeDetectionStrategy.OnPush,
2172
+ }]
2173
+ }], propDecorators: { context: [{
2174
+ type: Input
2175
+ }] } });
2176
+
2177
+ class SlateLeavesComponent extends ViewContainer {
2178
+ constructor() {
2179
+ super(...arguments);
2180
+ this.initialized = false;
2181
+ }
2182
+ ngOnInit() {
2183
+ this.leaves = Text$1.decorations(this.context.text, this.context.decorations);
2184
+ this.leafContexts = this.getLeafCotexts();
2185
+ this.initialized = true;
2186
+ }
2187
+ getLeafCotexts() {
2188
+ return this.leaves.map((leaf, index) => {
2189
+ return {
2190
+ leaf,
2191
+ text: this.context.text,
2192
+ parent: this.context.parent,
2193
+ index,
2194
+ isLast: this.context.isLast && index === this.leaves.length - 1
2195
+ };
2196
+ });
2197
+ }
2198
+ ngOnChanges(simpleChanges) {
2199
+ if (!this.initialized) {
2200
+ return;
2201
+ }
2202
+ const context = simpleChanges['context'];
2203
+ const previousValue = context.previousValue;
2204
+ const currentValue = context.currentValue;
2205
+ if (previousValue.text !== currentValue.text || !isDecoratorRangeListEqual(previousValue.decorations, currentValue.decorations)) {
2206
+ this.leaves = Text$1.decorations(this.context.text, this.context.decorations);
2207
+ }
2208
+ this.leafContexts = this.getLeafCotexts();
2209
+ }
2210
+ trackBy(index, item) {
2211
+ return index;
2212
+ }
2213
+ }
2214
+ SlateLeavesComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateLeavesComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2215
+ SlateLeavesComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateLeavesComponent, selector: "slate-leaves", inputs: { context: "context" }, viewQueries: [{ propertyName: "childrenComponent", predicate: SlateLeafComponent, descendants: true, read: SlateLeafComponent }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `<slate-leaf
2216
+ [context]="context" [viewContext]="viewContext"
2217
+ [viewContext]="viewContext"
2218
+ *ngFor="let context of leafContexts; trackBy: trackBy"></slate-leaf>
2219
+ `, isInline: true, components: [{ type: SlateLeafComponent, selector: "slate-leaf", inputs: ["context"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2220
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateLeavesComponent, decorators: [{
2221
+ type: Component,
2222
+ args: [{
2223
+ selector: 'slate-leaves',
2224
+ template: `<slate-leaf
2225
+ [context]="context" [viewContext]="viewContext"
2226
+ [viewContext]="viewContext"
2227
+ *ngFor="let context of leafContexts; trackBy: trackBy"></slate-leaf>
2228
+ `,
2229
+ changeDetection: ChangeDetectionStrategy.OnPush
2230
+ }]
2231
+ }], propDecorators: { context: [{
2232
+ type: Input
2233
+ }], childrenComponent: [{
2234
+ type: ViewChildren,
2235
+ args: [SlateLeafComponent, { read: SlateLeafComponent }]
2236
+ }] } });
2237
+
2238
+ class SlateDefaultTextComponent extends BaseTextComponent {
2239
+ }
2240
+ SlateDefaultTextComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateDefaultTextComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2241
+ SlateDefaultTextComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateDefaultTextComponent, selector: "span[slateDefaultText]", host: { attributes: { "data-slate-node": "text" } }, usesInheritance: true, ngImport: i0, template: `<slate-leaves [context]="context" [viewContext]="viewContext" [viewContext]="viewContext"></slate-leaves>`, isInline: true, components: [{ type: SlateLeavesComponent, selector: "slate-leaves", inputs: ["context"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2242
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateDefaultTextComponent, decorators: [{
2243
+ type: Component,
2244
+ args: [{
2245
+ selector: 'span[slateDefaultText]',
2246
+ template: `<slate-leaves [context]="context" [viewContext]="viewContext" [viewContext]="viewContext"></slate-leaves>`,
2247
+ changeDetection: ChangeDetectionStrategy.OnPush,
2248
+ host: {
2249
+ 'data-slate-node': 'text'
2250
+ }
2251
+ }]
2252
+ }] });
2253
+
2254
+ class SlateVoidTextComponent extends BaseTextComponent {
2255
+ ngOnInit() {
2256
+ this.isLeafBlock = AngularEditor.isLeafBlock(this.viewContext.editor, this.context.parent);
2257
+ super.ngOnInit();
2258
+ }
2259
+ ngOnChanges() {
2260
+ if (!this.initialized) {
2261
+ return;
2262
+ }
2263
+ this.isLeafBlock = AngularEditor.isLeafBlock(this.viewContext.editor, this.context.parent);
2264
+ }
2265
+ }
2266
+ SlateVoidTextComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateVoidTextComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2267
+ SlateVoidTextComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateVoidTextComponent, selector: "span[slateVoidText]", host: { attributes: { "data-slate-spacer": "true", "data-slate-node": "text" }, properties: { "attr.contenteditable": "isLeafBlock" }, classAttribute: "slate-spacer" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `<slate-leaves [context]="context" [viewContext]="viewContext" [viewContext]="viewContext"></slate-leaves>`, isInline: true, components: [{ type: SlateLeavesComponent, selector: "slate-leaves", inputs: ["context"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2268
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateVoidTextComponent, decorators: [{
2269
+ type: Component,
2270
+ args: [{
2271
+ selector: 'span[slateVoidText]',
2272
+ template: `<slate-leaves [context]="context" [viewContext]="viewContext" [viewContext]="viewContext"></slate-leaves>`,
2273
+ changeDetection: ChangeDetectionStrategy.OnPush,
2274
+ host: {
2275
+ '[attr.contenteditable]': 'isLeafBlock',
2276
+ 'data-slate-spacer': "true",
2277
+ 'class': 'slate-spacer',
2278
+ 'data-slate-node': 'text'
2279
+ }
2280
+ }]
2281
+ }] });
2282
+
2283
+ const SLATE_DEFAULT_ELEMENT_COMPONENT_TOKEN = new InjectionToken('slate-default-element-token');
2284
+
2285
+ class SlateDescendantComponent extends ViewContainerItem {
2286
+ constructor(viewContainerRef, defaultElementComponentType) {
2287
+ super(viewContainerRef);
2288
+ this.viewContainerRef = viewContainerRef;
2289
+ this.defaultElementComponentType = defaultElementComponentType;
2290
+ }
2291
+ get rootNodes() {
2292
+ if (this.blockCardComponentRef) {
2293
+ return [this.blockCardComponentRef.instance.nativeElement];
2294
+ }
2295
+ return super.getRootNodes();
2296
+ }
2297
+ get isBlockCard() {
2298
+ return this.viewContext.editor.isBlockCard(this.descendant);
2299
+ }
2300
+ ngOnInit() {
2301
+ NODE_TO_INDEX.set(this.descendant, this.index);
2302
+ NODE_TO_PARENT.set(this.descendant, this.context.parent);
2303
+ this.createView();
2304
+ if (this.isBlockCard) {
2305
+ this.createBlockCard();
2306
+ }
2307
+ }
2308
+ destroyView() {
2309
+ super.destroyView();
2310
+ this.destroyBlockCard();
2311
+ }
2312
+ ngOnChanges() {
2313
+ if (!this.initialized) {
2314
+ return;
2315
+ }
2316
+ NODE_TO_INDEX.set(this.descendant, this.index);
2317
+ NODE_TO_PARENT.set(this.descendant, this.context.parent);
2318
+ this.updateView();
2319
+ if (this.isBlockCard) {
2320
+ this.updateBlockCard();
2321
+ }
2322
+ }
2323
+ destroyBlockCard() {
2324
+ if (this.blockCardComponentRef) {
2325
+ this.blockCardComponentRef.destroy();
2326
+ this.blockCardComponentRef = null;
2327
+ }
2328
+ }
2329
+ createBlockCard() {
2330
+ const rootNodes = this.rootNodes;
2331
+ this.blockCardComponentRef = this.viewContainerRef.createComponent(SlateBlockCardComponent);
2332
+ this.blockCardComponentRef.instance.initializeCenter(rootNodes);
2333
+ }
2334
+ updateBlockCard() {
2335
+ if (this.blockCardComponentRef) {
2336
+ return;
2337
+ }
2338
+ const rootNodes = this.rootNodes;
2339
+ this.createBlockCard();
2340
+ const firstRootNode = rootNodes[0];
2341
+ firstRootNode.replaceWith(this.blockCardComponentRef.instance.nativeElement);
2342
+ }
2343
+ getCommonContext() {
2344
+ const path = AngularEditor.findPath(this.viewContext.editor, this.context.parent);
2345
+ const p = path.concat(this.index);
2346
+ try {
2347
+ const range = Editor.range(this.viewContext.editor, p);
2348
+ const sel = this.context.selection && Range.intersection(range, this.context.selection);
2349
+ const ds = this.context.decorate([this.descendant, p]);
2350
+ for (const dec of this.context.decorations) {
2351
+ const d = Range.intersection(dec, range);
2352
+ if (d) {
2353
+ ds.push(d);
2354
+ }
2355
+ }
2356
+ return { selection: sel, decorations: ds };
2357
+ }
2358
+ catch (error) {
2359
+ this.viewContext.editor.onError({ code: SlateErrorCode.GetStartPointError, nativeError: error });
2360
+ return { selection: null, decorations: [] };
2361
+ }
2362
+ }
2363
+ getContext() {
2364
+ if (Element.isElement(this.descendant)) {
2365
+ const computedContext = this.getCommonContext();
2366
+ const key = AngularEditor.findKey(this.viewContext.editor, this.descendant);
2367
+ const isInline = this.viewContext.editor.isInline(this.descendant);
2368
+ const isVoid = this.viewContext.editor.isVoid(this.descendant);
2369
+ const elementContext = {
2370
+ element: this.descendant,
2371
+ ...computedContext,
2372
+ attributes: {
2373
+ 'data-slate-node': 'element',
2374
+ 'data-slate-key': key.id
2375
+ },
2376
+ decorate: this.context.decorate,
2377
+ readonly: this.context.readonly
2378
+ };
2379
+ if (isInline) {
2380
+ elementContext.attributes['data-slate-inline'] = true;
2381
+ }
2382
+ if (isVoid) {
2383
+ elementContext.attributes['data-slate-void'] = true;
2384
+ elementContext.attributes.contenteditable = false;
2385
+ }
2386
+ return elementContext;
2387
+ }
2388
+ else {
2389
+ const computedContext = this.getCommonContext();
2390
+ const isLeafBlock = AngularEditor.isLeafBlock(this.viewContext.editor, this.context.parent);
2391
+ const textContext = {
2392
+ decorations: computedContext.decorations,
2393
+ isLast: isLeafBlock && this.index === this.context.parent.children.length - 1,
2394
+ parent: this.context.parent,
2395
+ text: this.descendant
2396
+ };
2397
+ return textContext;
2398
+ }
2399
+ }
2400
+ getViewType() {
2401
+ if (Element.isElement(this.descendant)) {
2402
+ return (this.viewContext.renderElement && this.viewContext.renderElement(this.descendant)) || this.defaultElementComponentType;
2403
+ }
2404
+ else {
2405
+ const isVoid = this.viewContext.editor.isVoid(this.context.parent);
2406
+ return isVoid ? SlateVoidTextComponent : (this.viewContext.renderText && this.viewContext.renderText(this.descendant)) || SlateDefaultTextComponent;
2407
+ }
2408
+ }
2409
+ memoizedElementContext(prev, next) {
2410
+ return (prev.element === next.element &&
2411
+ (!this.viewContext.isStrictDecorate || prev.decorate === next.decorate) &&
2412
+ prev.readonly === next.readonly &&
2413
+ isDecoratorRangeListEqual(prev.decorations, next.decorations) &&
2414
+ (prev.selection === next.selection ||
2415
+ (!!prev.selection &&
2416
+ !!next.selection &&
2417
+ Range.equals(prev.selection, next.selection))));
2418
+ }
2419
+ memoizedTextContext(prev, next) {
2420
+ return (next.parent === prev.parent &&
2421
+ next.isLast === prev.isLast &&
2422
+ next.text === prev.text &&
2423
+ isDecoratorRangeListEqual(next.decorations, prev.decorations));
2424
+ }
2425
+ memoizedContext(prev, next) {
2426
+ if (Element.isElement(this.descendant)) {
2427
+ return this.memoizedElementContext(prev, next);
2428
+ }
2429
+ else {
2430
+ return this.memoizedTextContext(prev, next);
2431
+ }
2432
+ }
2433
+ }
2434
+ SlateDescendantComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateDescendantComponent, deps: [{ token: i0.ViewContainerRef }, { token: SLATE_DEFAULT_ELEMENT_COMPONENT_TOKEN }], target: i0.ɵɵFactoryTarget.Component });
2435
+ SlateDescendantComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateDescendantComponent, selector: "slate-descendant", inputs: { descendant: "descendant", context: "context", viewContext: "viewContext", index: "index" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
2436
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateDescendantComponent, decorators: [{
2437
+ type: Component,
2438
+ args: [{
2439
+ selector: 'slate-descendant',
2440
+ template: '',
2441
+ changeDetection: ChangeDetectionStrategy.OnPush
2442
+ }]
2443
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: undefined, decorators: [{
2444
+ type: Inject,
2445
+ args: [SLATE_DEFAULT_ELEMENT_COMPONENT_TOKEN]
2446
+ }] }]; }, propDecorators: { descendant: [{
2447
+ type: Input
2448
+ }], context: [{
2449
+ type: Input
2450
+ }], viewContext: [{
2451
+ type: Input
2452
+ }], index: [{
2453
+ type: Input
2454
+ }] } });
2455
+
2456
+ class SlateChildrenComponent extends ViewContainer {
2457
+ constructor() {
2458
+ super(...arguments);
2459
+ this.trackBy = (index, node) => {
2460
+ return this.viewContext.trackBy(node) || AngularEditor.findKey(this.viewContext.editor, node);
2461
+ };
2462
+ }
2463
+ ngOnInit() {
2464
+ }
2465
+ }
2466
+ SlateChildrenComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateChildrenComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2467
+ SlateChildrenComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateChildrenComponent, selector: "slate-children", inputs: { children: "children", context: "context", viewContext: "viewContext" }, viewQueries: [{ propertyName: "childrenComponent", predicate: SlateDescendantComponent, descendants: true, read: SlateDescendantComponent }], usesInheritance: true, ngImport: i0, template: `<slate-descendant
2468
+ [descendant]="descendant"
2469
+ [context]="context" [viewContext]="viewContext"
2470
+ [viewContext]="viewContext"
2471
+ [index]="index"
2472
+ *ngFor="let descendant of children;let index = index; trackBy: trackBy"></slate-descendant>`, isInline: true, components: [{ type: SlateDescendantComponent, selector: "slate-descendant", inputs: ["descendant", "context", "viewContext", "index"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2473
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateChildrenComponent, decorators: [{
2474
+ type: Component,
2475
+ args: [{
2476
+ selector: 'slate-children',
2477
+ template: `<slate-descendant
2478
+ [descendant]="descendant"
2479
+ [context]="context" [viewContext]="viewContext"
2480
+ [viewContext]="viewContext"
2481
+ [index]="index"
2482
+ *ngFor="let descendant of children;let index = index; trackBy: trackBy"></slate-descendant>`,
2483
+ changeDetection: ChangeDetectionStrategy.OnPush
2484
+ }]
2485
+ }], propDecorators: { children: [{
2486
+ type: Input
2487
+ }], context: [{
2488
+ type: Input
2489
+ }], viewContext: [{
2490
+ type: Input
2491
+ }], childrenComponent: [{
2492
+ type: ViewChildren,
2493
+ args: [SlateDescendantComponent, { read: SlateDescendantComponent }]
2494
+ }] } });
2495
+
2496
+ class SlateStringTemplateComponent {
2497
+ }
2498
+ SlateStringTemplateComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateStringTemplateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2499
+ SlateStringTemplateComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateStringTemplateComponent, selector: "slate-string-template", viewQueries: [{ propertyName: "stringTemplate", first: true, predicate: ["stringTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "compatStringTemplate", first: true, predicate: ["compatStringTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "emptyStringTemplate", first: true, predicate: ["emptyStringTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "emptyTextTemplate", first: true, predicate: ["emptyTextTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "lineBreakEmptyStringTemplate", first: true, predicate: ["lineBreakEmptyStringTemplate"], descendants: true, read: TemplateRef, static: true }], ngImport: i0, template: "<ng-template #stringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-string=\"true\">{{ context.text }}</span>\n</ng-template>\n<ng-template #compatStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <!-- Compatible with Chinese input in Chrome with \\n -->\n <span editable-text data-slate-string=\"true\">{{ context.text }}<span data-slate-zero-width>{{'\\uFEFF'}}</span></span>\n</ng-template>\n<ng-template #emptyStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #emptyTextTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" data-slate-length=\"0\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #lineBreakEmptyStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"n\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF'\n }}<br /></span>\n</ng-template>", changeDetection: i0.ChangeDetectionStrategy.OnPush });
2500
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateStringTemplateComponent, decorators: [{
2501
+ type: Component,
2502
+ args: [{ selector: 'slate-string-template', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #stringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-string=\"true\">{{ context.text }}</span>\n</ng-template>\n<ng-template #compatStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <!-- Compatible with Chinese input in Chrome with \\n -->\n <span editable-text data-slate-string=\"true\">{{ context.text }}<span data-slate-zero-width>{{'\\uFEFF'}}</span></span>\n</ng-template>\n<ng-template #emptyStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #emptyTextTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" data-slate-length=\"0\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #lineBreakEmptyStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"n\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF'\n }}<br /></span>\n</ng-template>" }]
2503
+ }], propDecorators: { stringTemplate: [{
2504
+ type: ViewChild,
2505
+ args: ['stringTemplate', { read: TemplateRef, static: true }]
2506
+ }], compatStringTemplate: [{
2507
+ type: ViewChild,
2508
+ args: ['compatStringTemplate', { read: TemplateRef, static: true }]
2509
+ }], emptyStringTemplate: [{
2510
+ type: ViewChild,
2511
+ args: ['emptyStringTemplate', { read: TemplateRef, static: true }]
2512
+ }], emptyTextTemplate: [{
2513
+ type: ViewChild,
2514
+ args: ['emptyTextTemplate', { read: TemplateRef, static: true }]
2515
+ }], lineBreakEmptyStringTemplate: [{
2516
+ type: ViewChild,
2517
+ args: ['lineBreakEmptyStringTemplate', { read: TemplateRef, static: true }]
2518
+ }] } });
2519
+
2520
+ const timeDebug = Debug('slate-angular-time');
2521
+ // not correctly clipboardData on beforeinput
2522
+ const forceOnDOMPaste = IS_SAFARI;
2523
+ class SlateEditableComponent {
2524
+ constructor(elementRef, renderer2, cdr, ngZone, injector) {
2525
+ this.elementRef = elementRef;
2526
+ this.renderer2 = renderer2;
2527
+ this.cdr = cdr;
2528
+ this.ngZone = ngZone;
2529
+ this.injector = injector;
2530
+ this.destroy$ = new Subject();
2531
+ this.isComposing = false;
2532
+ this.isDraggingInternally = false;
2533
+ this.isUpdatingSelection = false;
2534
+ this.latestElement = null;
2535
+ this.manualListeners = [];
2536
+ this.onTouchedCallback = () => { };
2537
+ this.onChangeCallback = () => { };
2538
+ this.decorate = () => [];
2539
+ this.isStrictDecorate = true;
2540
+ this.trackBy = () => null;
2541
+ this.readonly = false;
2542
+ //#endregion
2543
+ //#region DOM attr
2544
+ this.spellCheck = false;
2545
+ this.autoCorrect = false;
2546
+ this.autoCapitalize = false;
2547
+ this.dataSlateEditor = true;
2548
+ this.dataSlateNode = 'value';
2549
+ this.dataGramm = false;
2550
+ }
2551
+ get hasBeforeInputSupport() {
2552
+ return HAS_BEFORE_INPUT_SUPPORT;
2553
+ }
2554
+ ngOnInit() {
2555
+ this.editor.injector = this.injector;
2556
+ this.editor.children = [];
2557
+ let window = getDefaultView(this.elementRef.nativeElement);
2558
+ EDITOR_TO_WINDOW.set(this.editor, window);
2559
+ EDITOR_TO_ELEMENT.set(this.editor, this.elementRef.nativeElement);
2560
+ NODE_TO_ELEMENT.set(this.editor, this.elementRef.nativeElement);
2561
+ ELEMENT_TO_NODE.set(this.elementRef.nativeElement, this.editor);
2562
+ IS_READONLY.set(this.editor, this.readonly);
2563
+ EDITOR_TO_ON_CHANGE.set(this.editor, () => {
2564
+ this.ngZone.run(() => {
2565
+ this.onChange();
2566
+ });
2567
+ });
2568
+ this.ngZone.runOutsideAngular(() => {
2569
+ this.initialize();
2570
+ });
2571
+ this.initializeViewContext();
2572
+ this.initializeContext();
2573
+ // remove unused DOM, just keep templateComponent instance
2574
+ this.templateElementRef.nativeElement.remove();
2575
+ // add browser class
2576
+ let browserClass = IS_FIREFOX ? 'firefox' : (IS_SAFARI ? 'safari' : '');
2577
+ browserClass && this.elementRef.nativeElement.classList.add(browserClass);
2578
+ }
2579
+ ngOnChanges(simpleChanges) {
2580
+ if (!this.initialized) {
2581
+ return;
2582
+ }
2583
+ const decorateChange = simpleChanges['decorate'];
2584
+ if (decorateChange) {
2585
+ this.forceFlush();
2586
+ }
2587
+ const readonlyChange = simpleChanges['readonly'];
2588
+ if (readonlyChange) {
2589
+ IS_READONLY.set(this.editor, this.readonly);
2590
+ this.detectContext();
2591
+ this.toSlateSelection();
2592
+ }
2593
+ }
2594
+ registerOnChange(fn) {
2595
+ this.onChangeCallback = fn;
2596
+ }
2597
+ registerOnTouched(fn) {
2598
+ this.onTouchedCallback = fn;
2599
+ }
2600
+ writeValue(value) {
2601
+ if (value && value.length) {
2602
+ if (check(value)) {
2603
+ this.editor.children = value;
2604
+ }
2605
+ else {
2606
+ this.editor.onError({
2607
+ code: SlateErrorCode.InvalidValueError,
2608
+ name: 'initialize invalid data',
2609
+ data: value
2610
+ });
2611
+ this.editor.children = normalize(value);
2612
+ }
2613
+ this.initializeContext();
2614
+ this.cdr.markForCheck();
2615
+ }
2616
+ }
2617
+ initialize() {
2618
+ this.initialized = true;
2619
+ const window = AngularEditor.getWindow(this.editor);
2620
+ this.addEventListener('selectionchange', event => {
2621
+ this.toSlateSelection();
2622
+ }, window.document);
2623
+ if (HAS_BEFORE_INPUT_SUPPORT) {
2624
+ this.addEventListener('beforeinput', this.onDOMBeforeInput.bind(this));
2625
+ }
2626
+ this.addEventListener('blur', this.onDOMBlur.bind(this));
2627
+ this.addEventListener('click', this.onDOMClick.bind(this));
2628
+ this.addEventListener('compositionend', this.onDOMCompositionEnd.bind(this));
2629
+ this.addEventListener('compositionstart', this.onDOMCompositionStart.bind(this));
2630
+ this.addEventListener('copy', this.onDOMCopy.bind(this));
2631
+ this.addEventListener('cut', this.onDOMCut.bind(this));
2632
+ this.addEventListener('dragover', this.onDOMDragOver.bind(this));
2633
+ this.addEventListener('dragstart', this.onDOMDragStart.bind(this));
2634
+ this.addEventListener('dragend', this.onDOMDragEnd.bind(this));
2635
+ this.addEventListener('drop', this.onDOMDrop.bind(this));
2636
+ this.addEventListener('focus', this.onDOMFocus.bind(this));
2637
+ this.addEventListener('keydown', this.onDOMKeydown.bind(this));
2638
+ this.addEventListener('paste', this.onDOMPaste.bind(this));
2639
+ BEFORE_INPUT_EVENTS.forEach(event => {
2640
+ this.addEventListener(event.name, () => { });
2641
+ });
2642
+ }
2643
+ toNativeSelection() {
2644
+ try {
2645
+ const { selection } = this.editor;
2646
+ const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
2647
+ const domSelection = root.getSelection();
2648
+ if (this.isComposing || !domSelection || !AngularEditor.isFocused(this.editor)) {
2649
+ return;
2650
+ }
2651
+ const hasDomSelection = domSelection.type !== 'None';
2652
+ // If the DOM selection is properly unset, we're done.
2653
+ if (!selection && !hasDomSelection) {
2654
+ return;
2655
+ }
2656
+ // If the DOM selection is already correct, we're done.
2657
+ // verify that the dom selection is in the editor
2658
+ const editorElement = EDITOR_TO_ELEMENT.get(this.editor);
2659
+ let hasDomSelectionInEditor = false;
2660
+ if (editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode)) {
2661
+ hasDomSelectionInEditor = true;
2662
+ }
2663
+ // If the DOM selection is in the editor and the editor selection is already correct, we're done.
2664
+ if (hasDomSelection &&
2665
+ hasDomSelectionInEditor &&
2666
+ selection &&
2667
+ hasStringTarget(domSelection) &&
2668
+ Range.equals(AngularEditor.toSlateRange(this.editor, domSelection), selection)) {
2669
+ return;
2670
+ }
2671
+ // when <Editable/> is being controlled through external value
2672
+ // then its children might just change - DOM responds to it on its own
2673
+ // but Slate's value is not being updated through any operation
2674
+ // and thus it doesn't transform selection on its own
2675
+ if (selection && !AngularEditor.hasRange(this.editor, selection)) {
2676
+ this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection);
2677
+ return;
2678
+ }
2679
+ // Otherwise the DOM selection is out of sync, so update it.
2680
+ const el = AngularEditor.toDOMNode(this.editor, this.editor);
2681
+ this.isUpdatingSelection = true;
2682
+ const newDomRange = selection && AngularEditor.toDOMRange(this.editor, selection);
2683
+ if (newDomRange) {
2684
+ // COMPAT: Since the DOM range has no concept of backwards/forwards
2685
+ // we need to check and do the right thing here.
2686
+ if (Range.isBackward(selection)) {
2687
+ // eslint-disable-next-line max-len
2688
+ domSelection.setBaseAndExtent(newDomRange.endContainer, newDomRange.endOffset, newDomRange.startContainer, newDomRange.startOffset);
2689
+ }
2690
+ else {
2691
+ // eslint-disable-next-line max-len
2692
+ domSelection.setBaseAndExtent(newDomRange.startContainer, newDomRange.startOffset, newDomRange.endContainer, newDomRange.endOffset);
2693
+ }
2694
+ }
2695
+ else {
2696
+ domSelection.removeAllRanges();
2697
+ }
2698
+ setTimeout(() => {
2699
+ // COMPAT: In Firefox, it's not enough to create a range, you also need
2700
+ // to focus the contenteditable element too. (2016/11/16)
2701
+ if (newDomRange && IS_FIREFOX) {
2702
+ el.focus();
2703
+ }
2704
+ this.isUpdatingSelection = false;
2705
+ });
2706
+ }
2707
+ catch (error) {
2708
+ this.editor.onError({ code: SlateErrorCode.ToNativeSelectionError, nativeError: error });
2709
+ }
2710
+ }
2711
+ onChange() {
2712
+ this.forceFlush();
2713
+ this.onChangeCallback(this.editor.children);
2714
+ }
2715
+ ngAfterViewChecked() {
2716
+ timeDebug('editable ngAfterViewChecked');
2717
+ }
2718
+ ngDoCheck() {
2719
+ timeDebug('editable ngDoCheck');
2720
+ }
2721
+ forceFlush() {
2722
+ timeDebug('start data sync');
2723
+ this.detectContext();
2724
+ this.cdr.detectChanges();
2725
+ // repair collaborative editing when Chinese input is interrupted by other users' cursors
2726
+ // when the DOMElement where the selection is located is removed
2727
+ // the compositionupdate and compositionend events will no longer be fired
2728
+ // so isComposing needs to be corrected
2729
+ // need exec after this.cdr.detectChanges() to render HTML
2730
+ // need exec before this.toNativeSelection() to correct native selection
2731
+ if (this.isComposing) {
2732
+ // Composition input text be not rendered when user composition input with selection is expanded
2733
+ // At this time, the following matching conditions are met, assign isComposing to false, and the status is wrong
2734
+ // this time condition is true and isComposiing is assigned false
2735
+ // Therefore, need to wait for the composition input text to be rendered before performing condition matching
2736
+ setTimeout(() => {
2737
+ const textNode = Node.get(this.editor, this.editor.selection.anchor.path);
2738
+ const textDOMNode = AngularEditor.toDOMNode(this.editor, textNode);
2739
+ let textContent = '';
2740
+ // skip decorate text
2741
+ textDOMNode.querySelectorAll('[editable-text]').forEach((stringDOMNode) => {
2742
+ let text = stringDOMNode.textContent;
2743
+ const zeroChar = '\uFEFF';
2744
+ // remove zero with char
2745
+ if (text.startsWith(zeroChar)) {
2746
+ text = text.slice(1);
2747
+ }
2748
+ if (text.endsWith(zeroChar)) {
2749
+ text = text.slice(0, text.length - 1);
2750
+ }
2751
+ textContent += text;
2752
+ });
2753
+ if (Node.string(textNode).endsWith(textContent)) {
2754
+ this.isComposing = false;
2755
+ }
2756
+ }, 0);
2757
+ }
2758
+ this.toNativeSelection();
2759
+ timeDebug('end data sync');
2760
+ }
2761
+ initializeContext() {
2762
+ this.context = {
2763
+ parent: this.editor,
2764
+ selection: this.editor.selection,
2765
+ decorations: this.generateDecorations(),
2766
+ decorate: this.decorate,
2767
+ readonly: this.readonly
2768
+ };
2769
+ }
2770
+ initializeViewContext() {
2771
+ this.viewContext = {
2772
+ editor: this.editor,
2773
+ renderElement: this.renderElement,
2774
+ renderLeaf: this.renderLeaf,
2775
+ renderText: this.renderText,
2776
+ trackBy: this.trackBy,
2777
+ isStrictDecorate: this.isStrictDecorate,
2778
+ templateComponent: this.templateComponent
2779
+ };
2780
+ }
2781
+ detectContext() {
2782
+ const decorations = this.generateDecorations();
2783
+ if (this.context.selection !== this.editor.selection ||
2784
+ this.context.decorate !== this.decorate ||
2785
+ this.context.readonly !== this.readonly ||
2786
+ !isDecoratorRangeListEqual(this.context.decorations, decorations)) {
2787
+ this.context = {
2788
+ parent: this.editor,
2789
+ selection: this.editor.selection,
2790
+ decorations: decorations,
2791
+ decorate: this.decorate,
2792
+ readonly: this.readonly
2793
+ };
2794
+ }
2795
+ }
2796
+ composePlaceholderDecorate(editor) {
2797
+ if (this.placeholderDecorate) {
2798
+ return this.placeholderDecorate(editor) || [];
2799
+ }
2800
+ if (this.placeholder &&
2801
+ editor.children.length === 1 &&
2802
+ Array.from(Node.texts(editor)).length === 1 &&
2803
+ Node.string(editor) === '') {
2804
+ const start = Editor.start(editor, []);
2805
+ return [
2806
+ {
2807
+ placeholder: this.placeholder,
2808
+ anchor: start,
2809
+ focus: start,
2810
+ },
2811
+ ];
2812
+ }
2813
+ else {
2814
+ return [];
2815
+ }
2816
+ }
2817
+ generateDecorations() {
2818
+ const decorations = this.decorate([this.editor, []]);
2819
+ const placeholderDecorations = this.isComposing
2820
+ ? []
2821
+ : this.composePlaceholderDecorate(this.editor);
2822
+ decorations.push(...placeholderDecorations);
2823
+ return decorations;
2824
+ }
2825
+ //#region event proxy
2826
+ addEventListener(eventName, listener, target = this.elementRef.nativeElement) {
2827
+ this.manualListeners.push(this.renderer2.listen(target, eventName, (event) => {
2828
+ const beforeInputEvent = extractBeforeInputEvent(event.type, null, event, event.target);
2829
+ if (beforeInputEvent) {
2830
+ this.onFallbackBeforeInput(beforeInputEvent);
2831
+ }
2832
+ listener(event);
2833
+ }));
2834
+ }
2835
+ toSlateSelection() {
2836
+ if (!this.readonly && !this.isComposing && !this.isUpdatingSelection && !this.isDraggingInternally) {
2837
+ try {
2838
+ const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
2839
+ const { activeElement } = root;
2840
+ const el = AngularEditor.toDOMNode(this.editor, this.editor);
2841
+ const domSelection = root.getSelection();
2842
+ if (activeElement === el || hasEditableTarget(this.editor, activeElement)) {
2843
+ this.latestElement = activeElement;
2844
+ IS_FOCUSED.set(this.editor, true);
2845
+ }
2846
+ else {
2847
+ IS_FOCUSED.delete(this.editor);
2848
+ }
2849
+ if (!domSelection) {
2850
+ return Transforms.deselect(this.editor);
2851
+ }
2852
+ const editorElement = EDITOR_TO_ELEMENT.get(this.editor);
2853
+ const hasDomSelectionInEditor = editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode);
2854
+ if (!hasDomSelectionInEditor) {
2855
+ Transforms.deselect(this.editor);
2856
+ return;
2857
+ }
2858
+ // try to get the selection directly, because some terrible case can be normalize for normalizeDOMPoint
2859
+ // for example, double-click the last cell of the table to select a non-editable DOM
2860
+ const range = AngularEditor.toSlateRange(this.editor, domSelection);
2861
+ if (this.editor.selection && Range.equals(range, this.editor.selection) && !hasStringTarget(domSelection)) {
2862
+ // force adjust DOMSelection
2863
+ this.toNativeSelection();
2864
+ }
2865
+ else {
2866
+ Transforms.select(this.editor, range);
2867
+ }
2868
+ }
2869
+ catch (error) {
2870
+ this.editor.onError({ code: SlateErrorCode.ToSlateSelectionError, nativeError: error });
2871
+ }
2872
+ }
2873
+ }
2874
+ onDOMBeforeInput(event) {
2875
+ const editor = this.editor;
2876
+ if (!this.readonly && hasEditableTarget(editor, event.target) && !this.isDOMEventHandled(event, this.beforeInput)) {
2877
+ try {
2878
+ const { selection } = editor;
2879
+ const { inputType: type } = event;
2880
+ const data = event.dataTransfer || event.data || undefined;
2881
+ event.preventDefault();
2882
+ // COMPAT: If the selection is expanded, even if the command seems like
2883
+ // a delete forward/backward command it should delete the selection.
2884
+ if (selection && Range.isExpanded(selection) && type.startsWith('delete')) {
2885
+ const direction = type.endsWith('Backward') ? 'backward' : 'forward';
2886
+ Editor.deleteFragment(editor, { direction });
2887
+ return;
2888
+ }
2889
+ switch (type) {
2890
+ case 'deleteByComposition':
2891
+ case 'deleteByCut':
2892
+ case 'deleteByDrag': {
2893
+ Editor.deleteFragment(editor);
2894
+ break;
2895
+ }
2896
+ case 'deleteContent':
2897
+ case 'deleteContentForward': {
2898
+ Editor.deleteForward(editor);
2899
+ break;
2900
+ }
2901
+ case 'deleteContentBackward': {
2902
+ Editor.deleteBackward(editor);
2903
+ break;
2904
+ }
2905
+ case 'deleteEntireSoftLine': {
2906
+ Editor.deleteBackward(editor, { unit: 'line' });
2907
+ Editor.deleteForward(editor, { unit: 'line' });
2908
+ break;
2909
+ }
2910
+ case 'deleteHardLineBackward': {
2911
+ Editor.deleteBackward(editor, { unit: 'block' });
2912
+ break;
2913
+ }
2914
+ case 'deleteSoftLineBackward': {
2915
+ Editor.deleteBackward(editor, { unit: 'line' });
2916
+ break;
2917
+ }
2918
+ case 'deleteHardLineForward': {
2919
+ Editor.deleteForward(editor, { unit: 'block' });
2920
+ break;
2921
+ }
2922
+ case 'deleteSoftLineForward': {
2923
+ Editor.deleteForward(editor, { unit: 'line' });
2924
+ break;
2925
+ }
2926
+ case 'deleteWordBackward': {
2927
+ Editor.deleteBackward(editor, { unit: 'word' });
2928
+ break;
2929
+ }
2930
+ case 'deleteWordForward': {
2931
+ Editor.deleteForward(editor, { unit: 'word' });
2932
+ break;
2933
+ }
2934
+ case 'insertLineBreak':
2935
+ case 'insertParagraph': {
2936
+ Editor.insertBreak(editor);
2937
+ break;
2938
+ }
2939
+ case 'insertFromComposition': {
2940
+ // COMPAT: in safari, `compositionend` event is dispatched after
2941
+ // the beforeinput event with the inputType "insertFromComposition" has been dispatched.
2942
+ // https://www.w3.org/TR/input-events-2/
2943
+ // so the following code is the right logic
2944
+ // because DOM selection in sync will be exec before `compositionend` event
2945
+ // isComposing is true will prevent DOM selection being update correctly.
2946
+ this.isComposing = false;
2947
+ preventInsertFromComposition(event, this.editor);
2948
+ }
2949
+ case 'insertFromDrop':
2950
+ case 'insertFromPaste':
2951
+ case 'insertFromYank':
2952
+ case 'insertReplacementText':
2953
+ case 'insertText': {
2954
+ // use a weak comparison instead of 'instanceof' to allow
2955
+ // programmatic access of paste events coming from external windows
2956
+ // like cypress where cy.window does not work realibly
2957
+ if (data?.constructor.name === 'DataTransfer') {
2958
+ AngularEditor.insertData(editor, data);
2959
+ }
2960
+ else if (typeof data === 'string') {
2961
+ Editor.insertText(editor, data);
2962
+ }
2963
+ break;
2964
+ }
2965
+ }
2966
+ }
2967
+ catch (error) {
2968
+ this.editor.onError({ code: SlateErrorCode.OnDOMBeforeInputError, nativeError: error });
2969
+ }
2970
+ }
2971
+ }
2972
+ onDOMBlur(event) {
2973
+ if (this.readonly ||
2974
+ this.isUpdatingSelection ||
2975
+ !hasEditableTarget(this.editor, event.target) ||
2976
+ this.isDOMEventHandled(event, this.blur)) {
2977
+ return;
2978
+ }
2979
+ const window = AngularEditor.getWindow(this.editor);
2980
+ // COMPAT: If the current `activeElement` is still the previous
2981
+ // one, this is due to the window being blurred when the tab
2982
+ // itself becomes unfocused, so we want to abort early to allow to
2983
+ // editor to stay focused when the tab becomes focused again.
2984
+ const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
2985
+ if (this.latestElement === root.activeElement) {
2986
+ return;
2987
+ }
2988
+ const { relatedTarget } = event;
2989
+ const el = AngularEditor.toDOMNode(this.editor, this.editor);
2990
+ // COMPAT: The event should be ignored if the focus is returning
2991
+ // to the editor from an embedded editable element (eg. an <input>
2992
+ // element inside a void node).
2993
+ if (relatedTarget === el) {
2994
+ return;
2995
+ }
2996
+ // COMPAT: The event should be ignored if the focus is moving from
2997
+ // the editor to inside a void node's spacer element.
2998
+ if (isDOMElement(relatedTarget) && relatedTarget.hasAttribute('data-slate-spacer')) {
2999
+ return;
3000
+ }
3001
+ // COMPAT: The event should be ignored if the focus is moving to a
3002
+ // non- editable section of an element that isn't a void node (eg.
3003
+ // a list item of the check list example).
3004
+ if (relatedTarget != null && isDOMNode(relatedTarget) && AngularEditor.hasDOMNode(this.editor, relatedTarget)) {
3005
+ const node = AngularEditor.toSlateNode(this.editor, relatedTarget);
3006
+ if (Element.isElement(node) && !this.editor.isVoid(node)) {
3007
+ return;
3008
+ }
3009
+ }
3010
+ IS_FOCUSED.delete(this.editor);
3011
+ }
3012
+ onDOMClick(event) {
3013
+ if (!this.readonly &&
3014
+ hasTarget(this.editor, event.target) &&
3015
+ !this.isDOMEventHandled(event, this.click) &&
3016
+ isDOMNode(event.target)) {
3017
+ const node = AngularEditor.toSlateNode(this.editor, event.target);
3018
+ const path = AngularEditor.findPath(this.editor, node);
3019
+ const start = Editor.start(this.editor, path);
3020
+ const end = Editor.end(this.editor, path);
3021
+ const startVoid = Editor.void(this.editor, { at: start });
3022
+ const endVoid = Editor.void(this.editor, { at: end });
3023
+ if (startVoid && endVoid && Path.equals(startVoid[1], endVoid[1])) {
3024
+ const range = Editor.range(this.editor, start);
3025
+ Transforms.select(this.editor, range);
3026
+ }
3027
+ }
3028
+ }
3029
+ onDOMCompositionEnd(event) {
3030
+ if (!event.data && !Range.isCollapsed(this.editor.selection)) {
3031
+ Transforms.delete(this.editor);
3032
+ }
3033
+ if (hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionEnd)) {
3034
+ // COMPAT: In Chrome/Firefox, `beforeinput` events for compositions
3035
+ // aren't correct and never fire the "insertFromComposition"
3036
+ // type that we need. So instead, insert whenever a composition
3037
+ // ends since it will already have been committed to the DOM.
3038
+ if (this.isComposing === true && !IS_SAFARI && event.data) {
3039
+ preventInsertFromComposition(event, this.editor);
3040
+ Editor.insertText(this.editor, event.data);
3041
+ }
3042
+ // COMPAT: In Firefox 87.0 CompositionEnd fire twice
3043
+ // so we need avoid repeat isnertText by isComposing === true,
3044
+ this.isComposing = false;
3045
+ }
3046
+ this.detectContext();
3047
+ this.cdr.detectChanges();
3048
+ }
3049
+ onDOMCompositionStart(event) {
3050
+ const { selection } = this.editor;
3051
+ if (selection) {
3052
+ // solve the problem of cross node Chinese input
3053
+ if (Range.isExpanded(selection)) {
3054
+ Editor.deleteFragment(this.editor);
3055
+ this.forceFlush();
3056
+ }
3057
+ }
3058
+ if (hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.compositionStart)) {
3059
+ this.isComposing = true;
3060
+ }
3061
+ this.detectContext();
3062
+ this.cdr.detectChanges();
3063
+ }
3064
+ onDOMCopy(event) {
3065
+ const window = AngularEditor.getWindow(this.editor);
3066
+ const isOutsideSlate = !hasStringTarget(window.getSelection()) && isTargetInsideVoid(this.editor, event.target);
3067
+ if (!isOutsideSlate && hasTarget(this.editor, event.target) && !this.readonly && !this.isDOMEventHandled(event, this.copy)) {
3068
+ event.preventDefault();
3069
+ AngularEditor.setFragmentData(this.editor, event.clipboardData, 'copy');
3070
+ }
3071
+ }
3072
+ onDOMCut(event) {
3073
+ if (!this.readonly && hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.cut)) {
3074
+ event.preventDefault();
3075
+ AngularEditor.setFragmentData(this.editor, event.clipboardData, 'cut');
3076
+ const { selection } = this.editor;
3077
+ if (selection) {
3078
+ AngularEditor.deleteCutData(this.editor);
3079
+ }
3080
+ }
3081
+ }
3082
+ onDOMDragOver(event) {
3083
+ if (hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragOver)) {
3084
+ // Only when the target is void, call `preventDefault` to signal
3085
+ // that drops are allowed. Editable content is droppable by
3086
+ // default, and calling `preventDefault` hides the cursor.
3087
+ const node = AngularEditor.toSlateNode(this.editor, event.target);
3088
+ if (Editor.isVoid(this.editor, node)) {
3089
+ event.preventDefault();
3090
+ }
3091
+ }
3092
+ }
3093
+ onDOMDragStart(event) {
3094
+ if (!this.readonly && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragStart)) {
3095
+ const node = AngularEditor.toSlateNode(this.editor, event.target);
3096
+ const path = AngularEditor.findPath(this.editor, node);
3097
+ const voidMatch = Editor.isVoid(this.editor, node) ||
3098
+ Editor.void(this.editor, { at: path, voids: true });
3099
+ // If starting a drag on a void node, make sure it is selected
3100
+ // so that it shows up in the selection's fragment.
3101
+ if (voidMatch) {
3102
+ const range = Editor.range(this.editor, path);
3103
+ Transforms.select(this.editor, range);
3104
+ }
3105
+ this.isDraggingInternally = true;
3106
+ AngularEditor.setFragmentData(this.editor, event.dataTransfer, 'drag');
3107
+ }
3108
+ }
3109
+ onDOMDrop(event) {
3110
+ const editor = this.editor;
3111
+ if (!this.readonly && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.drop)) {
3112
+ event.preventDefault();
3113
+ // Keep a reference to the dragged range before updating selection
3114
+ const draggedRange = editor.selection;
3115
+ // Find the range where the drop happened
3116
+ const range = AngularEditor.findEventRange(editor, event);
3117
+ const data = event.dataTransfer;
3118
+ Transforms.select(editor, range);
3119
+ if (this.isDraggingInternally) {
3120
+ if (draggedRange) {
3121
+ Transforms.delete(editor, {
3122
+ at: draggedRange,
3123
+ });
3124
+ }
3125
+ this.isDraggingInternally = false;
3126
+ }
3127
+ AngularEditor.insertData(editor, data);
3128
+ // When dragging from another source into the editor, it's possible
3129
+ // that the current editor does not have focus.
3130
+ if (!AngularEditor.isFocused(editor)) {
3131
+ AngularEditor.focus(editor);
3132
+ }
3133
+ }
3134
+ }
3135
+ onDOMDragEnd(event) {
3136
+ if (!this.readonly && this.isDraggingInternally && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragEnd)) {
3137
+ this.isDraggingInternally = false;
3138
+ }
3139
+ }
3140
+ onDOMFocus(event) {
3141
+ if (!this.readonly &&
3142
+ !this.isUpdatingSelection &&
3143
+ hasEditableTarget(this.editor, event.target) &&
3144
+ !this.isDOMEventHandled(event, this.focus)) {
3145
+ const el = AngularEditor.toDOMNode(this.editor, this.editor);
3146
+ const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
3147
+ this.latestElement = root.activeElement;
3148
+ // COMPAT: If the editor has nested editable elements, the focus
3149
+ // can go to them. In Firefox, this must be prevented because it
3150
+ // results in issues with keyboard navigation. (2017/03/30)
3151
+ if (IS_FIREFOX && event.target !== el) {
3152
+ el.focus();
3153
+ return;
3154
+ }
3155
+ IS_FOCUSED.set(this.editor, true);
3156
+ }
3157
+ }
3158
+ onDOMKeydown(event) {
3159
+ const editor = this.editor;
3160
+ if (!this.readonly &&
3161
+ hasEditableTarget(editor, event.target) &&
3162
+ !this.isComposing &&
3163
+ !this.isDOMEventHandled(event, this.keydown)) {
3164
+ const nativeEvent = event;
3165
+ const { selection } = editor;
3166
+ const element = editor.children[selection !== null ? selection.focus.path[0] : 0];
3167
+ const isRTL = getDirection(Node.string(element)) === 'rtl';
3168
+ try {
3169
+ // COMPAT: Since we prevent the default behavior on
3170
+ // `beforeinput` events, the browser doesn't think there's ever
3171
+ // any history stack to undo or redo, so we have to manage these
3172
+ // hotkeys ourselves. (2019/11/06)
3173
+ if (hotkeys.isRedo(nativeEvent)) {
3174
+ event.preventDefault();
3175
+ if (HistoryEditor.isHistoryEditor(editor)) {
3176
+ editor.redo();
3177
+ }
3178
+ return;
3179
+ }
3180
+ if (hotkeys.isUndo(nativeEvent)) {
3181
+ event.preventDefault();
3182
+ if (HistoryEditor.isHistoryEditor(editor)) {
3183
+ editor.undo();
3184
+ }
3185
+ return;
3186
+ }
3187
+ // COMPAT: Certain browsers don't handle the selection updates
3188
+ // properly. In Chrome, the selection isn't properly extended.
3189
+ // And in Firefox, the selection isn't properly collapsed.
3190
+ // (2017/10/17)
3191
+ if (hotkeys.isMoveLineBackward(nativeEvent)) {
3192
+ event.preventDefault();
3193
+ Transforms.move(editor, { unit: 'line', reverse: true });
3194
+ return;
3195
+ }
3196
+ if (hotkeys.isMoveLineForward(nativeEvent)) {
3197
+ event.preventDefault();
3198
+ Transforms.move(editor, { unit: 'line' });
3199
+ return;
3200
+ }
3201
+ if (hotkeys.isExtendLineBackward(nativeEvent)) {
3202
+ event.preventDefault();
3203
+ Transforms.move(editor, {
3204
+ unit: 'line',
3205
+ edge: 'focus',
3206
+ reverse: true
3207
+ });
3208
+ return;
3209
+ }
3210
+ if (hotkeys.isExtendLineForward(nativeEvent)) {
3211
+ event.preventDefault();
3212
+ Transforms.move(editor, { unit: 'line', edge: 'focus' });
3213
+ return;
3214
+ }
3215
+ // COMPAT: If a void node is selected, or a zero-width text node
3216
+ // adjacent to an inline is selected, we need to handle these
3217
+ // hotkeys manually because browsers won't be able to skip over
3218
+ // the void node with the zero-width space not being an empty
3219
+ // string.
3220
+ if (hotkeys.isMoveBackward(nativeEvent)) {
3221
+ event.preventDefault();
3222
+ if (selection && Range.isCollapsed(selection)) {
3223
+ Transforms.move(editor, { reverse: !isRTL });
3224
+ }
3225
+ else {
3226
+ Transforms.collapse(editor, { edge: 'start' });
3227
+ }
3228
+ return;
3229
+ }
3230
+ if (hotkeys.isMoveForward(nativeEvent)) {
3231
+ event.preventDefault();
3232
+ if (selection && Range.isCollapsed(selection)) {
3233
+ Transforms.move(editor, { reverse: isRTL });
3234
+ }
3235
+ else {
3236
+ Transforms.collapse(editor, { edge: 'end' });
3237
+ }
3238
+ return;
3239
+ }
3240
+ if (hotkeys.isMoveWordBackward(nativeEvent)) {
3241
+ event.preventDefault();
3242
+ if (selection && Range.isExpanded(selection)) {
3243
+ Transforms.collapse(editor, { edge: 'focus' });
3244
+ }
3245
+ Transforms.move(editor, { unit: 'word', reverse: !isRTL });
3246
+ return;
3247
+ }
3248
+ if (hotkeys.isMoveWordForward(nativeEvent)) {
3249
+ event.preventDefault();
3250
+ if (selection && Range.isExpanded(selection)) {
3251
+ Transforms.collapse(editor, { edge: 'focus' });
3252
+ }
3253
+ Transforms.move(editor, { unit: 'word', reverse: isRTL });
3254
+ return;
3255
+ }
3256
+ // COMPAT: Certain browsers don't support the `beforeinput` event, so we
3257
+ // fall back to guessing at the input intention for hotkeys.
3258
+ // COMPAT: In iOS, some of these hotkeys are handled in the
3259
+ if (!HAS_BEFORE_INPUT_SUPPORT) {
3260
+ // We don't have a core behavior for these, but they change the
3261
+ // DOM if we don't prevent them, so we have to.
3262
+ if (hotkeys.isBold(nativeEvent) || hotkeys.isItalic(nativeEvent) || hotkeys.isTransposeCharacter(nativeEvent)) {
3263
+ event.preventDefault();
3264
+ return;
3265
+ }
3266
+ if (hotkeys.isSplitBlock(nativeEvent)) {
3267
+ event.preventDefault();
3268
+ Editor.insertBreak(editor);
3269
+ return;
3270
+ }
3271
+ if (hotkeys.isDeleteBackward(nativeEvent)) {
3272
+ event.preventDefault();
3273
+ if (selection && Range.isExpanded(selection)) {
3274
+ Editor.deleteFragment(editor, { direction: 'backward' });
3275
+ }
3276
+ else {
3277
+ Editor.deleteBackward(editor);
3278
+ }
3279
+ return;
3280
+ }
3281
+ if (hotkeys.isDeleteForward(nativeEvent)) {
3282
+ event.preventDefault();
3283
+ if (selection && Range.isExpanded(selection)) {
3284
+ Editor.deleteFragment(editor, { direction: 'forward' });
3285
+ }
3286
+ else {
3287
+ Editor.deleteForward(editor);
3288
+ }
3289
+ return;
3290
+ }
3291
+ if (hotkeys.isDeleteLineBackward(nativeEvent)) {
3292
+ event.preventDefault();
3293
+ if (selection && Range.isExpanded(selection)) {
3294
+ Editor.deleteFragment(editor, { direction: 'backward' });
3295
+ }
3296
+ else {
3297
+ Editor.deleteBackward(editor, { unit: 'line' });
3298
+ }
3299
+ return;
3300
+ }
3301
+ if (hotkeys.isDeleteLineForward(nativeEvent)) {
3302
+ event.preventDefault();
3303
+ if (selection && Range.isExpanded(selection)) {
3304
+ Editor.deleteFragment(editor, { direction: 'forward' });
3305
+ }
3306
+ else {
3307
+ Editor.deleteForward(editor, { unit: 'line' });
3308
+ }
3309
+ return;
3310
+ }
3311
+ if (hotkeys.isDeleteWordBackward(nativeEvent)) {
3312
+ event.preventDefault();
3313
+ if (selection && Range.isExpanded(selection)) {
3314
+ Editor.deleteFragment(editor, { direction: 'backward' });
3315
+ }
3316
+ else {
3317
+ Editor.deleteBackward(editor, { unit: 'word' });
3318
+ }
3319
+ return;
3320
+ }
3321
+ if (hotkeys.isDeleteWordForward(nativeEvent)) {
3322
+ event.preventDefault();
3323
+ if (selection && Range.isExpanded(selection)) {
3324
+ Editor.deleteFragment(editor, { direction: 'forward' });
3325
+ }
3326
+ else {
3327
+ Editor.deleteForward(editor, { unit: 'word' });
3328
+ }
3329
+ return;
3330
+ }
3331
+ }
3332
+ else {
3333
+ if (IS_CHROME || IS_SAFARI) {
3334
+ // COMPAT: Chrome and Safari support `beforeinput` event but do not fire
3335
+ // an event when deleting backwards in a selected void inline node
3336
+ if (selection &&
3337
+ (hotkeys.isDeleteBackward(nativeEvent) ||
3338
+ hotkeys.isDeleteForward(nativeEvent)) &&
3339
+ Range.isCollapsed(selection)) {
3340
+ const currentNode = Node.parent(editor, selection.anchor.path);
3341
+ if (Element.isElement(currentNode) &&
3342
+ Editor.isVoid(editor, currentNode) &&
3343
+ Editor.isInline(editor, currentNode)) {
3344
+ event.preventDefault();
3345
+ Editor.deleteBackward(editor, { unit: 'block' });
3346
+ return;
3347
+ }
3348
+ }
3349
+ }
3350
+ }
3351
+ }
3352
+ catch (error) {
3353
+ this.editor.onError({ code: SlateErrorCode.OnDOMKeydownError, nativeError: error });
3354
+ }
3355
+ }
3356
+ }
3357
+ onDOMPaste(event) {
3358
+ // COMPAT: Certain browsers don't support the `beforeinput` event, so we
3359
+ // fall back to React's `onPaste` here instead.
3360
+ // COMPAT: Firefox, Chrome and Safari are not emitting `beforeinput` events
3361
+ // when "paste without formatting" option is used.
3362
+ // This unfortunately needs to be handled with paste events instead.
3363
+ if (!this.isDOMEventHandled(event, this.paste) &&
3364
+ (!HAS_BEFORE_INPUT_SUPPORT || isPlainTextOnlyPaste(event) || forceOnDOMPaste) &&
3365
+ !this.readonly &&
3366
+ hasEditableTarget(this.editor, event.target)) {
3367
+ event.preventDefault();
3368
+ AngularEditor.insertData(this.editor, event.clipboardData);
3369
+ }
3370
+ }
3371
+ onFallbackBeforeInput(event) {
3372
+ // COMPAT: Certain browsers don't support the `beforeinput` event, so we
3373
+ // fall back to React's leaky polyfill instead just for it. It
3374
+ // only works for the `insertText` input type.
3375
+ if (!HAS_BEFORE_INPUT_SUPPORT &&
3376
+ !this.readonly &&
3377
+ !this.isDOMEventHandled(event.nativeEvent, this.beforeInput) &&
3378
+ hasEditableTarget(this.editor, event.nativeEvent.target)) {
3379
+ event.nativeEvent.preventDefault();
3380
+ try {
3381
+ const text = event.data;
3382
+ if (!Range.isCollapsed(this.editor.selection)) {
3383
+ Editor.deleteFragment(this.editor);
3384
+ }
3385
+ // just handle Non-IME input
3386
+ if (!this.isComposing) {
3387
+ Editor.insertText(this.editor, text);
3388
+ }
3389
+ }
3390
+ catch (error) {
3391
+ this.editor.onError({ code: SlateErrorCode.ToNativeSelectionError, nativeError: error });
3392
+ }
3393
+ }
3394
+ }
3395
+ isDOMEventHandled(event, handler) {
3396
+ if (!handler) {
3397
+ return false;
3398
+ }
3399
+ handler(event);
3400
+ return event.defaultPrevented;
3401
+ }
3402
+ //#endregion
3403
+ ngOnDestroy() {
3404
+ NODE_TO_ELEMENT.delete(this.editor);
3405
+ this.manualListeners.forEach(manualListener => {
3406
+ manualListener();
3407
+ });
3408
+ this.destroy$.complete();
3409
+ EDITOR_TO_ON_CHANGE.delete(this.editor);
3410
+ }
3411
+ }
3412
+ SlateEditableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateEditableComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
3413
+ SlateEditableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateEditableComponent, selector: "slate-editable", inputs: { editor: "editor", renderElement: "renderElement", renderLeaf: "renderLeaf", renderText: "renderText", decorate: "decorate", placeholderDecorate: "placeholderDecorate", isStrictDecorate: "isStrictDecorate", trackBy: "trackBy", readonly: "readonly", placeholder: "placeholder", beforeInput: "beforeInput", blur: "blur", click: "click", compositionEnd: "compositionEnd", compositionStart: "compositionStart", copy: "copy", cut: "cut", dragOver: "dragOver", dragStart: "dragStart", dragEnd: "dragEnd", drop: "drop", focus: "focus", keydown: "keydown", paste: "paste", spellCheck: "spellCheck", autoCorrect: "autoCorrect", autoCapitalize: "autoCapitalize" }, host: { properties: { "attr.contenteditable": "readonly ? undefined : true", "attr.role": "readonly ? undefined : 'textbox'", "attr.spellCheck": "!hasBeforeInputSupport ? false : spellCheck", "attr.autoCorrect": "!hasBeforeInputSupport ? 'false' : autoCorrect", "attr.autoCapitalize": "!hasBeforeInputSupport ? 'false' : autoCapitalize", "attr.data-slate-editor": "this.dataSlateEditor", "attr.data-slate-node": "this.dataSlateNode", "attr.data-gramm": "this.dataGramm" }, classAttribute: "slate-editable-container" }, providers: [{
3414
+ provide: NG_VALUE_ACCESSOR,
3415
+ useExisting: forwardRef(() => SlateEditableComponent),
3416
+ multi: true
3417
+ }], viewQueries: [{ propertyName: "templateComponent", first: true, predicate: ["templateComponent"], descendants: true, static: true }, { propertyName: "templateElementRef", first: true, predicate: ["templateComponent"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: "<slate-children [children]=\"editor.children\" [context]=\"context\" [viewContext]=\"viewContext\"></slate-children>\n<slate-string-template #templateComponent></slate-string-template>", components: [{ type: SlateChildrenComponent, selector: "slate-children", inputs: ["children", "context", "viewContext"] }, { type: SlateStringTemplateComponent, selector: "slate-string-template" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3418
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateEditableComponent, decorators: [{
3419
+ type: Component,
3420
+ args: [{ selector: 'slate-editable', host: {
3421
+ class: 'slate-editable-container',
3422
+ '[attr.contenteditable]': 'readonly ? undefined : true',
3423
+ '[attr.role]': `readonly ? undefined : 'textbox'`,
3424
+ '[attr.spellCheck]': `!hasBeforeInputSupport ? false : spellCheck`,
3425
+ '[attr.autoCorrect]': `!hasBeforeInputSupport ? 'false' : autoCorrect`,
3426
+ '[attr.autoCapitalize]': `!hasBeforeInputSupport ? 'false' : autoCapitalize`
3427
+ }, changeDetection: ChangeDetectionStrategy.OnPush, providers: [{
3428
+ provide: NG_VALUE_ACCESSOR,
3429
+ useExisting: forwardRef(() => SlateEditableComponent),
3430
+ multi: true
3431
+ }], template: "<slate-children [children]=\"editor.children\" [context]=\"context\" [viewContext]=\"viewContext\"></slate-children>\n<slate-string-template #templateComponent></slate-string-template>" }]
3432
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i0.Injector }]; }, propDecorators: { editor: [{
3433
+ type: Input
3434
+ }], renderElement: [{
3435
+ type: Input
3436
+ }], renderLeaf: [{
3437
+ type: Input
3438
+ }], renderText: [{
3439
+ type: Input
3440
+ }], decorate: [{
3441
+ type: Input
3442
+ }], placeholderDecorate: [{
3443
+ type: Input
3444
+ }], isStrictDecorate: [{
3445
+ type: Input
3446
+ }], trackBy: [{
3447
+ type: Input
3448
+ }], readonly: [{
3449
+ type: Input
3450
+ }], placeholder: [{
3451
+ type: Input
3452
+ }], beforeInput: [{
3453
+ type: Input
3454
+ }], blur: [{
3455
+ type: Input
3456
+ }], click: [{
3457
+ type: Input
3458
+ }], compositionEnd: [{
3459
+ type: Input
3460
+ }], compositionStart: [{
3461
+ type: Input
3462
+ }], copy: [{
3463
+ type: Input
3464
+ }], cut: [{
3465
+ type: Input
3466
+ }], dragOver: [{
3467
+ type: Input
3468
+ }], dragStart: [{
3469
+ type: Input
3470
+ }], dragEnd: [{
3471
+ type: Input
3472
+ }], drop: [{
3473
+ type: Input
3474
+ }], focus: [{
3475
+ type: Input
3476
+ }], keydown: [{
3477
+ type: Input
3478
+ }], paste: [{
3479
+ type: Input
3480
+ }], spellCheck: [{
3481
+ type: Input
3482
+ }], autoCorrect: [{
3483
+ type: Input
3484
+ }], autoCapitalize: [{
3485
+ type: Input
3486
+ }], dataSlateEditor: [{
3487
+ type: HostBinding,
3488
+ args: ['attr.data-slate-editor']
3489
+ }], dataSlateNode: [{
3490
+ type: HostBinding,
3491
+ args: ['attr.data-slate-node']
3492
+ }], dataGramm: [{
3493
+ type: HostBinding,
3494
+ args: ['attr.data-gramm']
3495
+ }], templateComponent: [{
3496
+ type: ViewChild,
3497
+ args: ['templateComponent', { static: true }]
3498
+ }], templateElementRef: [{
3499
+ type: ViewChild,
3500
+ args: ['templateComponent', { static: true, read: ElementRef }]
3501
+ }] } });
3502
+ /**
3503
+ * Check if the target is editable and in the editor.
3504
+ */
3505
+ const hasEditableTarget = (editor, target) => {
3506
+ return isDOMNode(target) && AngularEditor.hasDOMNode(editor, target, { editable: true });
3507
+ };
3508
+ /**
3509
+ * Check if two DOM range objects are equal.
3510
+ */
3511
+ const isRangeEqual = (a, b) => {
3512
+ return ((a.startContainer === b.startContainer &&
3513
+ a.startOffset === b.startOffset &&
3514
+ a.endContainer === b.endContainer &&
3515
+ a.endOffset === b.endOffset) ||
3516
+ (a.startContainer === b.endContainer &&
3517
+ a.startOffset === b.endOffset &&
3518
+ a.endContainer === b.startContainer &&
3519
+ a.endOffset === b.startOffset));
3520
+ };
3521
+ /**
3522
+ * Check if the target is in the editor.
3523
+ */
3524
+ const hasTarget = (editor, target) => {
3525
+ return isDOMNode(target) && AngularEditor.hasDOMNode(editor, target);
3526
+ };
3527
+ /**
3528
+ * Check if the target is inside void and in the editor.
3529
+ */
3530
+ const isTargetInsideVoid = (editor, target) => {
3531
+ const slateNode = hasTarget(editor, target) && AngularEditor.toSlateNode(editor, target);
3532
+ return Editor.isVoid(editor, slateNode);
3533
+ };
3534
+ const hasStringTarget = (domSelection) => {
3535
+ return (domSelection.anchorNode.parentElement.hasAttribute('data-slate-string') || domSelection.anchorNode.parentElement.hasAttribute('data-slate-zero-width')) &&
3536
+ (domSelection.focusNode.parentElement.hasAttribute('data-slate-string') || domSelection.focusNode.parentElement.hasAttribute('data-slate-zero-width'));
3537
+ };
3538
+ /**
3539
+ * remove default insert from composition
3540
+ * @param text
3541
+ */
3542
+ const preventInsertFromComposition = (event, editor) => {
3543
+ const types = ['compositionend', 'insertFromComposition'];
3544
+ if (!types.includes(event.type)) {
3545
+ return;
3546
+ }
3547
+ const insertText = event.data;
3548
+ const window = AngularEditor.getWindow(editor);
3549
+ const domSelection = window.getSelection();
3550
+ // ensure text node insert composition input text
3551
+ if (insertText && domSelection.anchorNode instanceof Text && domSelection.anchorNode.textContent.endsWith(insertText)) {
3552
+ const textNode = domSelection.anchorNode;
3553
+ textNode.splitText(textNode.length - insertText.length).remove();
3554
+ }
3555
+ };
3556
+
3557
+ class SlateElementComponent extends BaseElementComponent {
3558
+ }
3559
+ SlateElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateElementComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
3560
+ SlateElementComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateElementComponent, selector: "[slateElement]", usesInheritance: true, ngImport: i0, template: '<slate-children [children]="children" [context]="childrenContext" [viewContext]="viewContext"></slate-children><ng-content></ng-content>', isInline: true, components: [{ type: SlateChildrenComponent, selector: "slate-children", inputs: ["children", "context", "viewContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3561
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateElementComponent, decorators: [{
3562
+ type: Component,
3563
+ args: [{
3564
+ selector: '[slateElement]',
3565
+ template: '<slate-children [children]="children" [context]="childrenContext" [viewContext]="viewContext"></slate-children><ng-content></ng-content>',
3566
+ changeDetection: ChangeDetectionStrategy.OnPush
3567
+ }]
3568
+ }] });
3569
+
3570
+ class SlateDefaultElementComponent extends BaseElementComponent {
3571
+ }
3572
+ SlateDefaultElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateDefaultElementComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
3573
+ SlateDefaultElementComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: SlateDefaultElementComponent, selector: "div[slateDefaultElement]", usesInheritance: true, ngImport: i0, template: `<slate-children [children]="children" [context]="childrenContext" [viewContext]="viewContext"></slate-children>`, isInline: true, components: [{ type: SlateChildrenComponent, selector: "slate-children", inputs: ["children", "context", "viewContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3574
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateDefaultElementComponent, decorators: [{
3575
+ type: Component,
3576
+ args: [{
3577
+ selector: 'div[slateDefaultElement]',
3578
+ template: `<slate-children [children]="children" [context]="childrenContext" [viewContext]="viewContext"></slate-children>`,
3579
+ changeDetection: ChangeDetectionStrategy.OnPush
3580
+ }]
3581
+ }] });
3582
+
3583
+ class SlateModule {
3584
+ }
3585
+ SlateModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
3586
+ SlateModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateModule, declarations: [SlateEditableComponent,
3587
+ SlateDefaultElementComponent,
3588
+ SlateElementComponent,
3589
+ SlateVoidTextComponent,
3590
+ SlateDefaultTextComponent,
3591
+ SlateStringComponent,
3592
+ SlateStringTemplateComponent,
3593
+ SlateDescendantComponent,
3594
+ SlateChildrenComponent,
3595
+ SlateBlockCardComponent,
3596
+ SlateLeafComponent,
3597
+ SlateLeavesComponent,
3598
+ SlateDefaultLeafComponent], imports: [CommonModule], exports: [SlateEditableComponent, SlateChildrenComponent, SlateElementComponent, SlateLeavesComponent, SlateStringComponent] });
3599
+ SlateModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateModule, providers: [
3600
+ {
3601
+ provide: SLATE_DEFAULT_ELEMENT_COMPONENT_TOKEN,
3602
+ useValue: SlateDefaultElementComponent
3603
+ },
3604
+ ], imports: [[CommonModule]] });
3605
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: SlateModule, decorators: [{
3606
+ type: NgModule,
3607
+ args: [{
3608
+ declarations: [
3609
+ SlateEditableComponent,
3610
+ SlateDefaultElementComponent,
3611
+ SlateElementComponent,
3612
+ SlateVoidTextComponent,
3613
+ SlateDefaultTextComponent,
3614
+ SlateStringComponent,
3615
+ SlateStringTemplateComponent,
3616
+ SlateDescendantComponent,
3617
+ SlateChildrenComponent,
3618
+ SlateBlockCardComponent,
3619
+ SlateLeafComponent,
3620
+ SlateLeavesComponent,
3621
+ SlateDefaultLeafComponent
3622
+ ],
3623
+ imports: [CommonModule],
3624
+ exports: [SlateEditableComponent, SlateChildrenComponent, SlateElementComponent, SlateLeavesComponent, SlateStringComponent],
3625
+ providers: [
3626
+ {
3627
+ provide: SLATE_DEFAULT_ELEMENT_COMPONENT_TOKEN,
3628
+ useValue: SlateDefaultElementComponent
3629
+ },
3630
+ ]
3631
+ }]
3632
+ }] });
3633
+
3634
+ /*
3635
+ * Public API Surface of slate-angular
3636
+ */
3637
+
3638
+ /**
3639
+ * Generated bundle index. Do not edit.
3640
+ */
3641
+
3642
+ export { AngularEditor, BaseComponent, BaseElementComponent, BaseLeafComponent, BaseTextComponent, DOMComment, DOMElement, DOMNode, DOMRange, DOMSelection, DOMStaticRange, DOMText, EDITOR_TO_ELEMENT, EDITOR_TO_ON_CHANGE, EDITOR_TO_PLACEHOLDER, EDITOR_TO_WINDOW, ELEMENT_TO_COMPONENT, ELEMENT_TO_NODE, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_CLICKING, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_FOCUSED, IS_IOS, IS_QQBROWSER, IS_READONLY, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, KEY_TO_ELEMENT, Key, NODE_TO_ELEMENT, NODE_TO_INDEX, NODE_TO_KEY, NODE_TO_PARENT, PLACEHOLDER_SYMBOL, SlateChildrenComponent, SlateEditableComponent, SlateElementComponent, SlateErrorCode, SlateLeavesComponent, SlateModule, SlateStringComponent, check, getCardTargetAttribute, getClipboardData, getDefaultView, getEditableChild, getEditableChildAndIndex, getPlainText, getSlateFragmentAttribute, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hasShadowRoot, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isComponentType, isDOMComment, isDOMElement, isDOMNode, isDOMSelection, isDOMText, isDecoratorRangeListEqual, isPlainTextOnlyPaste, isTemplateRef, isValid, normalize, normalizeDOMPoint, shallowCompare, withAngular };
3643
+ //# sourceMappingURL=slate-angular.mjs.map