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