slate-angular 1.7.3 → 1.9.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.
@@ -208,6 +208,33 @@ const getPlainText = (domNode) => {
208
208
  }
209
209
  return text;
210
210
  };
211
+ /**
212
+ * Get x-slate-fragment attribute from data-slate-fragment
213
+ */
214
+ const catchSlateFragment = /data-slate-fragment="(.+?)"/m;
215
+ const getSlateFragmentAttribute = (dataTransfer) => {
216
+ const htmlData = dataTransfer.getData('text/html');
217
+ const [, fragment] = htmlData.match(catchSlateFragment) || [];
218
+ return fragment;
219
+ };
220
+ /**
221
+ * Get the x-slate-fragment attribute that exist in text/html data
222
+ * and append it to the DataTransfer object
223
+ */
224
+ const getClipboardData = (dataTransfer, clipboardFormatKey = 'x-slate-fragment') => {
225
+ if (!dataTransfer.getData(`application/${clipboardFormatKey}`)) {
226
+ const fragment = getSlateFragmentAttribute(dataTransfer);
227
+ if (fragment) {
228
+ const clipboardData = new DataTransfer();
229
+ dataTransfer.types.forEach(type => {
230
+ clipboardData.setData(type, dataTransfer.getData(type));
231
+ });
232
+ clipboardData.setData(`application/${clipboardFormatKey}`, fragment);
233
+ return clipboardData;
234
+ }
235
+ }
236
+ return dataTransfer;
237
+ };
211
238
 
212
239
  /**
213
240
  * An auto-incrementing identifier for keys.
@@ -228,6 +255,7 @@ const IS_IOS = typeof navigator !== 'undefined' &&
228
255
  /iPad|iPhone|iPod/.test(navigator.userAgent) &&
229
256
  !window.MSStream;
230
257
  const IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent);
258
+ const IS_ANDROID = typeof navigator !== 'undefined' && /Android/.test(navigator.userAgent);
231
259
  const IS_FIREFOX = typeof navigator !== 'undefined' &&
232
260
  /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
233
261
  const IS_SAFARI = typeof navigator !== 'undefined' &&
@@ -239,6 +267,24 @@ const IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.u
239
267
  // Native beforeInput events don't work well with react on Chrome 75 and older, Chrome 76+ can use beforeInput
240
268
  const IS_CHROME_LEGACY = typeof navigator !== 'undefined' &&
241
269
  /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent);
270
+ // Firefox did not support `beforeInput` until `v87`.
271
+ const IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' &&
272
+ /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])).*/i.test(navigator.userAgent);
273
+ // qq browser
274
+ const IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent);
275
+ // UC mobile browser
276
+ const IS_UC_MOBILE = typeof navigator !== 'undefined' && /.*UCBrowser/.test(navigator.userAgent);
277
+ // Wechat browser
278
+ const IS_WECHATBROWSER = typeof navigator !== 'undefined' && /.*Wechat/.test(navigator.userAgent);
279
+ // COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
280
+ // Chrome Legacy doesn't support `beforeinput` correctly
281
+ const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
282
+ !IS_EDGE_LEGACY &&
283
+ // globalThis is undefined in older browsers
284
+ typeof globalThis !== 'undefined' &&
285
+ globalThis.InputEvent &&
286
+ // @ts-ignore The `getTargetRanges` property isn't recognized.
287
+ typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
242
288
 
243
289
  const FAKE_LEFT_BLOCK_CARD_OFFSET = -1;
244
290
  const FAKE_RIGHT_BLOCK_CARD_OFFSET = -2;
@@ -321,27 +367,16 @@ const AngularEditor = {
321
367
  throw new Error(`Unable to find the path for Slate node: ${JSON.stringify(node)}`);
322
368
  },
323
369
  /**
324
- * Find the DOM node that implements DocumentOrShadowRoot for the editor.
325
- */
370
+ * Find the DOM node that implements DocumentOrShadowRoot for the editor.
371
+ */
326
372
  findDocumentOrShadowRoot(editor) {
327
373
  const el = AngularEditor.toDOMNode(editor, editor);
328
374
  const root = el.getRootNode();
329
- // The below exception will always be thrown for iframes because the document inside an iframe
330
- // does not inherit it's prototype from the parent document, therefore we return early
331
- if (el.ownerDocument !== document) {
332
- return el.ownerDocument;
333
- }
334
- if (!(root instanceof Document || root instanceof ShadowRoot)) {
335
- throw new Error(`Unable to find DocumentOrShadowRoot for editor element: ${el}`);
336
- }
337
- // COMPAT: Only Chrome implements the DocumentOrShadowRoot mixin for
338
- // ShadowRoot; other browsers still implement it on the Document
339
- // interface. (2020/08/08)
340
- // https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot#Properties
341
- if (root.getSelection === undefined && el.ownerDocument !== null) {
342
- return el.ownerDocument;
343
- }
344
- return root;
375
+ if ((root instanceof Document || root instanceof ShadowRoot) &&
376
+ root.getSelection != null) {
377
+ return root;
378
+ }
379
+ return el.ownerDocument;
345
380
  },
346
381
  /**
347
382
  * Check if the editor is focused.
@@ -438,6 +473,18 @@ const AngularEditor = {
438
473
  insertData(editor, data) {
439
474
  editor.insertData(data);
440
475
  },
476
+ /**
477
+ * Insert fragment data from a `DataTransfer` into the editor.
478
+ */
479
+ insertFragmentData(editor, data) {
480
+ return editor.insertFragmentData(data);
481
+ },
482
+ /**
483
+ * Insert text data from a `DataTransfer` into the editor.
484
+ */
485
+ insertTextData(editor, data) {
486
+ return editor.insertTextData(data);
487
+ },
441
488
  /**
442
489
  * onKeydown hook.
443
490
  */
@@ -453,8 +500,8 @@ const AngularEditor = {
453
500
  /**
454
501
  * Sets data from the currently selected fragment on a `DataTransfer`.
455
502
  */
456
- setFragmentData(editor, data) {
457
- editor.setFragmentData(data);
503
+ setFragmentData(editor, data, originEvent) {
504
+ editor.setFragmentData(data, originEvent);
458
505
  },
459
506
  deleteCutData(editor) {
460
507
  editor.deleteCutData();
@@ -711,7 +758,9 @@ const AngularEditor = {
711
758
  // composition the ASCII characters will be prepended to the zero-width
712
759
  // space, so subtract 1 from the offset to account for the zero-width
713
760
  // space character.
714
- if (domNode && offset === domNode.textContent.length && parentNode && parentNode.hasAttribute('data-slate-zero-width')) {
761
+ if (domNode &&
762
+ offset === domNode.textContent.length &&
763
+ (parentNode && parentNode.hasAttribute('data-slate-zero-width'))) {
715
764
  offset--;
716
765
  }
717
766
  }
@@ -1125,7 +1174,7 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1125
1174
  // in the HTML, and can be used for intra-Slate pasting. If it's a text
1126
1175
  // node, wrap it in a `<span>` so we have something to set an attribute on.
1127
1176
  if (isDOMText(attach)) {
1128
- const span = document.createElement('span');
1177
+ const span = attach.ownerDocument.createElement('span');
1129
1178
  // COMPAT: In Chrome and Safari, if we don't add the `white-space` style
1130
1179
  // then leading and trailing spaces will be ignored. (2017/09/21)
1131
1180
  span.style.whiteSpace = 'pre';
@@ -1139,13 +1188,14 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1139
1188
  attach.setAttribute('data-slate-fragment', encoded);
1140
1189
  data.setData(`application/${clipboardFormatKey}`, encoded);
1141
1190
  // Add the content to a <div> so that we can get its inner HTML.
1142
- const div = document.createElement('div');
1191
+ const div = contents.ownerDocument.createElement('div');
1143
1192
  div.appendChild(contents);
1144
1193
  div.setAttribute('hidden', 'true');
1145
- document.body.appendChild(div);
1194
+ contents.ownerDocument.body.appendChild(div);
1146
1195
  data.setData('text/html', div.innerHTML);
1147
1196
  data.setData('text/plain', getPlainText(div));
1148
- document.body.removeChild(div);
1197
+ contents.ownerDocument.body.removeChild(div);
1198
+ return data;
1149
1199
  };
1150
1200
  e.deleteCutData = () => {
1151
1201
  const { selection } = editor;
@@ -1162,13 +1212,25 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1162
1212
  }
1163
1213
  };
1164
1214
  e.insertData = (data) => {
1165
- const fragment = data.getData(`application/${clipboardFormatKey}`);
1215
+ if (!e.insertFragmentData(data)) {
1216
+ e.insertTextData(data);
1217
+ }
1218
+ };
1219
+ e.insertFragmentData = (data) => {
1220
+ /**
1221
+ * Checking copied fragment from application/x-slate-fragment or data-slate-fragment
1222
+ */
1223
+ const fragment = data.getData(`application/${clipboardFormatKey}`) ||
1224
+ getSlateFragmentAttribute(data);
1166
1225
  if (fragment) {
1167
1226
  const decoded = decodeURIComponent(window.atob(fragment));
1168
1227
  const parsed = JSON.parse(decoded);
1169
1228
  e.insertFragment(parsed);
1170
- return;
1229
+ return true;
1171
1230
  }
1231
+ return false;
1232
+ };
1233
+ e.insertTextData = (data) => {
1172
1234
  const text = data.getData('text/plain');
1173
1235
  if (text) {
1174
1236
  const lines = text.split(/\r\n|\r|\n/);
@@ -1180,7 +1242,9 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1180
1242
  e.insertText(line);
1181
1243
  split = true;
1182
1244
  }
1245
+ return true;
1183
1246
  }
1247
+ return false;
1184
1248
  };
1185
1249
  e.onKeydown = () => { };
1186
1250
  e.onClick = () => { };
@@ -1551,12 +1615,16 @@ class SlateBlockCardComponent {
1551
1615
  get nativeElement() {
1552
1616
  return this.elementRef.nativeElement;
1553
1617
  }
1618
+ get centerContainerElement() {
1619
+ return this.centerContianer.nativeElement;
1620
+ }
1554
1621
  ngOnInit() {
1555
- const fragment = document.createDocumentFragment();
1556
- fragment.append(...this.centerRootNodes);
1557
- this.centerContianer.nativeElement.appendChild(fragment);
1622
+ this.append();
1558
1623
  this.nativeElement.classList.add(`slate-block-card`);
1559
1624
  }
1625
+ append() {
1626
+ this.centerRootNodes.forEach((rootNode) => !this.centerContainerElement.contains(rootNode) && this.centerContainerElement.appendChild(rootNode));
1627
+ }
1560
1628
  initializeCenter(rootNodes) {
1561
1629
  this.centerRootNodes = rootNodes;
1562
1630
  }
@@ -1662,6 +1730,11 @@ class ViewContainerItem {
1662
1730
  }
1663
1731
  }
1664
1732
  }
1733
+ appendBlockCardElement() {
1734
+ if (this.blockCardComponentRef) {
1735
+ this.blockCardComponentRef.instance.append();
1736
+ }
1737
+ }
1665
1738
  }
1666
1739
  ViewContainerItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.7", ngImport: i0, type: ViewContainerItem, deps: [{ token: i0.ViewContainerRef }, { token: i0.ComponentFactoryResolver }], target: i0.ɵɵFactoryTarget.Directive });
1667
1740
  ViewContainerItem.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.7", type: ViewContainerItem, inputs: { viewContext: "viewContext" }, ngImport: i0 });
@@ -1737,35 +1810,28 @@ class BaseLeafComponent extends BaseComponent {
1737
1810
  this.cdr.markForCheck();
1738
1811
  }
1739
1812
  renderPlaceholder() {
1740
- var _a, _b, _c;
1741
1813
  // issue-1: IME input was interrupted
1742
1814
  // issue-2: IME input focus jumping
1743
- // Issue occurs when the placeholder node is removed (in leaf span)
1744
- // So add a placeholder span to the block element root node
1815
+ // Issue occurs when the span node of the placeholder is before the slateString span node
1745
1816
  if (this.context.leaf['placeholder']) {
1746
1817
  if (!this.placeholderElement) {
1747
1818
  this.placeholderElement = document.createElement('span');
1748
1819
  this.placeholderElement.innerText = this.context.leaf['placeholder'];
1749
1820
  this.placeholderElement.contentEditable = 'false';
1750
1821
  this.placeholderElement.setAttribute('data-slate-placeholder', 'true');
1751
- (_a = this.nativeElement.closest('[data-slate-node="element"]')) === null || _a === void 0 ? void 0 : _a.classList.add('element-placeholder');
1752
- (_b = this.nativeElement.closest('[data-slate-node="element"]')) === null || _b === void 0 ? void 0 : _b.appendChild(this.placeholderElement);
1822
+ this.nativeElement.classList.add('leaf-with-placeholder');
1823
+ this.nativeElement.appendChild(this.placeholderElement);
1753
1824
  }
1754
1825
  }
1755
1826
  else {
1756
- if (this.placeholderElement) {
1757
- this.placeholderElement.remove();
1758
- this.placeholderElement = null;
1759
- (_c = this.nativeElement.closest('[data-slate-node="element"]')) === null || _c === void 0 ? void 0 : _c.classList.remove('element-placeholder');
1760
- }
1827
+ this.destroyPlaceholder();
1761
1828
  }
1762
1829
  }
1763
1830
  destroyPlaceholder() {
1764
- var _a, _b;
1765
1831
  if (this.placeholderElement) {
1766
1832
  this.placeholderElement.remove();
1767
1833
  this.placeholderElement = null;
1768
- (_b = (_a = this.nativeElement) === null || _a === void 0 ? void 0 : _a.closest('[data-slate-node="element"]')) === null || _b === void 0 ? void 0 : _b.classList.remove('element-placeholder');
1834
+ this.nativeElement.classList.remove('leaf-with-placeholder');
1769
1835
  }
1770
1836
  }
1771
1837
  }
@@ -1971,6 +2037,8 @@ class ViewContainer {
1971
2037
  });
1972
2038
  }
1973
2039
  }
2040
+ // Solve the block-card DOMElement loss when moving nodes
2041
+ record.item.appendBlockCardElement();
1974
2042
  }
1975
2043
  }
1976
2044
  ViewContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.7", ngImport: i0, type: ViewContainer, deps: [{ token: i0.ElementRef }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Directive });
@@ -2450,13 +2518,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.7", ngImpor
2450
2518
  }] } });
2451
2519
 
2452
2520
  const timeDebug = Debug('slate-angular-time');
2453
- // COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
2454
- // Chrome Legacy doesn't support `beforeinput` correctly
2455
- const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
2456
- !IS_EDGE_LEGACY &&
2457
- globalThis.InputEvent &&
2458
- // @ts-ignore The `getTargetRanges` property isn't recognized.
2459
- typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
2460
2521
  // not correctly clipboardData on beforeinput
2461
2522
  const forceOnDOMPaste = IS_SAFARI;
2462
2523
  class SlateEditableComponent {
@@ -2511,6 +2572,9 @@ class SlateEditableComponent {
2511
2572
  this.initializeContext();
2512
2573
  // remove unused DOM, just keep templateComponent instance
2513
2574
  this.templateElementRef.nativeElement.remove();
2575
+ // add browser class
2576
+ let browserClass = IS_FIREFOX ? 'firefox' : (IS_SAFARI ? 'safari' : '');
2577
+ browserClass && this.elementRef.nativeElement.classList.add(browserClass);
2514
2578
  }
2515
2579
  ngOnChanges(simpleChanges) {
2516
2580
  if (!this.initialized) {
@@ -2884,7 +2948,10 @@ class SlateEditableComponent {
2884
2948
  case 'insertFromYank':
2885
2949
  case 'insertReplacementText':
2886
2950
  case 'insertText': {
2887
- if (data instanceof DataTransfer) {
2951
+ // use a weak comparison instead of 'instanceof' to allow
2952
+ // programmatic access of paste events coming from external windows
2953
+ // like cypress where cy.window does not work realibly
2954
+ if ((data === null || data === void 0 ? void 0 : data.constructor.name) === 'DataTransfer') {
2888
2955
  AngularEditor.insertData(editor, data);
2889
2956
  }
2890
2957
  else if (typeof data === 'string') {
@@ -2996,13 +3063,13 @@ class SlateEditableComponent {
2996
3063
  const isOutsideSlate = !hasStringTarget(window.getSelection()) && isTargetInsideVoid(this.editor, event.target);
2997
3064
  if (!isOutsideSlate && hasTarget(this.editor, event.target) && !this.readonly && !this.isDOMEventHandled(event, this.copy)) {
2998
3065
  event.preventDefault();
2999
- AngularEditor.setFragmentData(this.editor, event.clipboardData);
3066
+ AngularEditor.setFragmentData(this.editor, event.clipboardData, 'copy');
3000
3067
  }
3001
3068
  }
3002
3069
  onDOMCut(event) {
3003
3070
  if (!this.readonly && hasEditableTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.cut)) {
3004
3071
  event.preventDefault();
3005
- AngularEditor.setFragmentData(this.editor, event.clipboardData);
3072
+ AngularEditor.setFragmentData(this.editor, event.clipboardData, 'cut');
3006
3073
  const { selection } = this.editor;
3007
3074
  if (selection) {
3008
3075
  AngularEditor.deleteCutData(this.editor);
@@ -3021,7 +3088,7 @@ class SlateEditableComponent {
3021
3088
  }
3022
3089
  }
3023
3090
  onDOMDragStart(event) {
3024
- if (hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragStart)) {
3091
+ if (!this.readonly && hasTarget(this.editor, event.target) && !this.isDOMEventHandled(event, this.dragStart)) {
3025
3092
  const node = AngularEditor.toSlateNode(this.editor, event.target);
3026
3093
  const path = AngularEditor.findPath(this.editor, node);
3027
3094
  const voidMatch = Editor.isVoid(this.editor, node) ||
@@ -3033,7 +3100,7 @@ class SlateEditableComponent {
3033
3100
  Transforms.select(this.editor, range);
3034
3101
  }
3035
3102
  this.isDraggingInternally = true;
3036
- AngularEditor.setFragmentData(this.editor, event.dataTransfer);
3103
+ AngularEditor.setFragmentData(this.editor, event.dataTransfer, 'drag');
3037
3104
  }
3038
3105
  }
3039
3106
  onDOMDrop(event) {
@@ -3576,5 +3643,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.7", ngImpor
3576
3643
  * Generated bundle index. Do not edit.
3577
3644
  */
3578
3645
 
3579
- 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, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_CLICKING, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_FOCUSED, IS_IOS, IS_READONLY, IS_SAFARI, KEY_TO_ELEMENT, Key, NODE_TO_ELEMENT, NODE_TO_INDEX, NODE_TO_KEY, NODE_TO_PARENT, PLACEHOLDER_SYMBOL, SlateChildrenComponent, SlateEditableComponent, SlateElementComponent, SlateErrorCode, SlateLeavesComponent, SlateModule, SlateStringComponent, check, getCardTargetAttribute, getDefaultView, getEditableChild, getEditableChildAndIndex, getPlainText, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hasShadowRoot, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isComponentType, isDOMComment, isDOMElement, isDOMNode, isDOMSelection, isDOMText, isDecoratorRangeListEqual, isPlainTextOnlyPaste, isTemplateRef, isValid, normalize, normalizeDOMPoint, shallowCompare, withAngular };
3646
+ export { AngularEditor, BaseComponent, BaseElementComponent, BaseLeafComponent, BaseTextComponent, DOMComment, DOMElement, DOMNode, DOMRange, DOMSelection, DOMStaticRange, DOMText, EDITOR_TO_ELEMENT, EDITOR_TO_ON_CHANGE, EDITOR_TO_PLACEHOLDER, EDITOR_TO_WINDOW, ELEMENT_TO_COMPONENT, ELEMENT_TO_NODE, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_CLICKING, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_FOCUSED, IS_IOS, IS_QQBROWSER, IS_READONLY, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, KEY_TO_ELEMENT, Key, NODE_TO_ELEMENT, NODE_TO_INDEX, NODE_TO_KEY, NODE_TO_PARENT, PLACEHOLDER_SYMBOL, SlateChildrenComponent, SlateEditableComponent, SlateElementComponent, SlateErrorCode, SlateLeavesComponent, SlateModule, SlateStringComponent, check, getCardTargetAttribute, getClipboardData, getDefaultView, getEditableChild, getEditableChildAndIndex, getPlainText, getSlateFragmentAttribute, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hasShadowRoot, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isComponentType, isDOMComment, isDOMElement, isDOMNode, isDOMSelection, isDOMText, isDecoratorRangeListEqual, isPlainTextOnlyPaste, isTemplateRef, isValid, normalize, normalizeDOMPoint, shallowCompare, withAngular };
3580
3647
  //# sourceMappingURL=slate-angular.js.map