@ckeditor/ckeditor5-clipboard 0.0.0-nightly-20240603.0 → 0.0.0-nightly-20240604.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,47 +3,39 @@
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
5
  import { Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
- import { EventInfo, uid, toUnit, delay, DomEmitterMixin, global, Rect, ResizeObserver, env, createElement } from '@ckeditor/ckeditor5-utils/dist/index.js';
6
+ import { EventInfo, uid, toUnit, global, Rect, ResizeObserver, delay, DomEmitterMixin, env, createElement } from '@ckeditor/ckeditor5-utils/dist/index.js';
7
7
  import { DomEventObserver, DataTransfer, Range, MouseObserver, LiveRange } from '@ckeditor/ckeditor5-engine/dist/index.js';
8
8
  import { mapValues, throttle } from 'lodash-es';
9
9
  import { Widget, isWidget } from '@ckeditor/ckeditor5-widget/dist/index.js';
10
10
  import { View } from '@ckeditor/ckeditor5-ui/dist/index.js';
11
11
 
12
- /**
13
- * Clipboard events observer.
14
- *
15
- * Fires the following events:
16
- *
17
- * * {@link module:engine/view/document~Document#event:clipboardInput},
18
- * * {@link module:engine/view/document~Document#event:paste},
19
- * * {@link module:engine/view/document~Document#event:copy},
20
- * * {@link module:engine/view/document~Document#event:cut},
21
- * * {@link module:engine/view/document~Document#event:drop},
22
- * * {@link module:engine/view/document~Document#event:dragover},
23
- * * {@link module:engine/view/document~Document#event:dragging},
24
- * * {@link module:engine/view/document~Document#event:dragstart},
25
- * * {@link module:engine/view/document~Document#event:dragend},
26
- * * {@link module:engine/view/document~Document#event:dragenter},
27
- * * {@link module:engine/view/document~Document#event:dragleave}.
28
- *
29
- * **Note**: This observer is not available by default (ckeditor5-engine does not add it on its own).
30
- * To make it available, it needs to be added to {@link module:engine/view/document~Document} by using
31
- * the {@link module:engine/view/view~View#addObserver `View#addObserver()`} method. Alternatively, you can load the
32
- * {@link module:clipboard/clipboard~Clipboard} plugin which adds this observer automatically (because it uses it).
33
- */ class ClipboardObserver extends DomEventObserver {
34
- domEventType = [
35
- 'paste',
36
- 'copy',
37
- 'cut',
38
- 'drop',
39
- 'dragover',
40
- 'dragstart',
41
- 'dragend',
42
- 'dragenter',
43
- 'dragleave'
44
- ];
12
+ class ClipboardObserver extends DomEventObserver {
13
+ onDomEvent(domEvent) {
14
+ const nativeDataTransfer = 'clipboardData' in domEvent ? domEvent.clipboardData : domEvent.dataTransfer;
15
+ const cacheFiles = domEvent.type == 'drop' || domEvent.type == 'paste';
16
+ const evtData = {
17
+ dataTransfer: new DataTransfer(nativeDataTransfer, {
18
+ cacheFiles
19
+ })
20
+ };
21
+ if (domEvent.type == 'drop' || domEvent.type == 'dragover') {
22
+ evtData.dropRange = getDropViewRange(this.view, domEvent);
23
+ }
24
+ this.fire(domEvent.type, domEvent, evtData);
25
+ }
45
26
  constructor(view){
46
27
  super(view);
28
+ this.domEventType = [
29
+ 'paste',
30
+ 'copy',
31
+ 'cut',
32
+ 'drop',
33
+ 'dragover',
34
+ 'dragstart',
35
+ 'dragend',
36
+ 'dragenter',
37
+ 'dragleave'
38
+ ];
47
39
  const viewDocument = this.document;
48
40
  this.listenTo(viewDocument, 'paste', handleInput('clipboardInput'), {
49
41
  priority: 'low'
@@ -77,19 +69,6 @@ import { View } from '@ckeditor/ckeditor5-ui/dist/index.js';
77
69
  };
78
70
  }
79
71
  }
80
- onDomEvent(domEvent) {
81
- const nativeDataTransfer = 'clipboardData' in domEvent ? domEvent.clipboardData : domEvent.dataTransfer;
82
- const cacheFiles = domEvent.type == 'drop' || domEvent.type == 'paste';
83
- const evtData = {
84
- dataTransfer: new DataTransfer(nativeDataTransfer, {
85
- cacheFiles
86
- })
87
- };
88
- if (domEvent.type == 'drop' || domEvent.type == 'dragover') {
89
- evtData.dropRange = getDropViewRange(this.view, domEvent);
90
- }
91
- this.fire(domEvent.type, domEvent, evtData);
92
- }
93
72
  }
94
73
  function getDropViewRange(view, domEvent) {
95
74
  const domDoc = domEvent.target.ownerDocument;
@@ -164,8 +143,6 @@ function getDropViewRange(view, domEvent) {
164
143
  /**
165
144
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
166
145
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
167
- */ /**
168
- * @module clipboard/utils/viewtoplaintext
169
146
  */ // Elements which should not have empty-line padding.
170
147
  // Most `view.ContainerElement` want to be separate by new-line, but some are creating one structure
171
148
  // together (like `<li>`) so it is better to separate them by only one "\n".
@@ -193,9 +170,9 @@ const listElements = [
193
170
  return '\n'; // Convert soft breaks to single line break (#8045).
194
171
  }
195
172
  /**
196
- * Item is a document fragment, attribute element or container element. It doesn't
197
- * have it's own text value, so we need to convert its children elements.
198
- */ let text = '';
173
+ * Item is a document fragment, attribute element or container element. It doesn't
174
+ * have it's own text value, so we need to convert its children elements.
175
+ */ let text = '';
199
176
  let prev = null;
200
177
  for (const child of viewItem.getChildren()){
201
178
  text += newLinePadding(child, prev) + viewToPlainText(child);
@@ -216,9 +193,9 @@ const listElements = [
216
193
  }
217
194
  if (listElements.includes(element.name) && listElements.includes(previous.name)) {
218
195
  /**
219
- * Because `<ul>` and `<ol>` are AttributeElements, two consecutive lists will not have any padding between
220
- * them (see the `if` statement below). To fix this, we need to make an exception for this case.
221
- */ return '\n\n';
196
+ * Because `<ul>` and `<ol>` are AttributeElements, two consecutive lists will not have any padding between
197
+ * them (see the `if` statement below). To fix this, we need to make an exception for this case.
198
+ */ return '\n\n';
222
199
  }
223
200
  if (!element.is('containerElement') && !previous.is('containerElement')) {
224
201
  // Don't add padding between non-container elements.
@@ -232,49 +209,39 @@ const listElements = [
232
209
  return '\n\n';
233
210
  }
234
211
 
235
- /**
236
- * Part of the clipboard logic. Responsible for collecting markers from selected fragments
237
- * and restoring them with proper positions in pasted elements.
238
- *
239
- * @internal
240
- */ class ClipboardMarkersUtils extends Plugin {
241
- /**
242
- * Map of marker names that can be copied.
243
- *
244
- * @internal
245
- */ _markersToCopy = new Map();
212
+ class ClipboardMarkersUtils extends Plugin {
246
213
  /**
247
- * @inheritDoc
248
- */ static get pluginName() {
214
+ * @inheritDoc
215
+ */ static get pluginName() {
249
216
  return 'ClipboardMarkersUtils';
250
217
  }
251
218
  /**
252
- * Registers marker name as copyable in clipboard pipeline.
253
- *
254
- * @param markerName Name of marker that can be copied.
255
- * @param config Configuration that describes what can be performed on specified marker.
256
- * @internal
257
- */ _registerMarkerToCopy(markerName, config) {
219
+ * Registers marker name as copyable in clipboard pipeline.
220
+ *
221
+ * @param markerName Name of marker that can be copied.
222
+ * @param config Configuration that describes what can be performed on specified marker.
223
+ * @internal
224
+ */ _registerMarkerToCopy(markerName, config) {
258
225
  this._markersToCopy.set(markerName, config);
259
226
  }
260
227
  /**
261
- * Performs copy markers on provided selection and paste it to fragment returned from `getCopiedFragment`.
262
- *
263
- * 1. Picks all markers in provided selection.
264
- * 2. Inserts fake markers to document.
265
- * 3. Gets copied selection fragment from document.
266
- * 4. Removes fake elements from fragment and document.
267
- * 5. Inserts markers in the place of removed fake markers.
268
- *
269
- * Due to selection modification, when inserting items, `getCopiedFragment` must *always* operate on `writer.model.document.selection'.
270
- * Do not use any other custom selection object within callback, as this will lead to out-of-bounds exceptions in rare scenarios.
271
- *
272
- * @param action Type of clipboard action.
273
- * @param writer An instance of the model writer.
274
- * @param selection Selection to be checked.
275
- * @param getCopiedFragment Callback that performs copy of selection and returns it as fragment.
276
- * @internal
277
- */ _copySelectedFragmentWithMarkers(action, selection, getCopiedFragment = (writer)=>writer.model.getSelectedContent(writer.model.document.selection)) {
228
+ * Performs copy markers on provided selection and paste it to fragment returned from `getCopiedFragment`.
229
+ *
230
+ * 1. Picks all markers in provided selection.
231
+ * 2. Inserts fake markers to document.
232
+ * 3. Gets copied selection fragment from document.
233
+ * 4. Removes fake elements from fragment and document.
234
+ * 5. Inserts markers in the place of removed fake markers.
235
+ *
236
+ * Due to selection modification, when inserting items, `getCopiedFragment` must *always* operate on `writer.model.document.selection'.
237
+ * Do not use any other custom selection object within callback, as this will lead to out-of-bounds exceptions in rare scenarios.
238
+ *
239
+ * @param action Type of clipboard action.
240
+ * @param writer An instance of the model writer.
241
+ * @param selection Selection to be checked.
242
+ * @param getCopiedFragment Callback that performs copy of selection and returns it as fragment.
243
+ * @internal
244
+ */ _copySelectedFragmentWithMarkers(action, selection, getCopiedFragment = (writer)=>writer.model.getSelectedContent(writer.model.document.selection)) {
278
245
  return this.editor.model.change((writer)=>{
279
246
  const oldSelection = writer.model.document.selection;
280
247
  // In some scenarios, such like in drag & drop, passed `selection` parameter is not actually
@@ -297,7 +264,7 @@ const listElements = [
297
264
  // This function checks special case of such problem. Markers that are orphaned at the start position
298
265
  // and end position in the same time. Basically it means that they overlaps whole element.
299
266
  for (const [markerName, elements] of Object.entries(sourceSelectionInsertedMarkers)){
300
- fakeMarkersRangesInsideRange[markerName] ||= writer.createRangeIn(fragment);
267
+ fakeMarkersRangesInsideRange[markerName] || (fakeMarkersRangesInsideRange[markerName] = writer.createRangeIn(fragment));
301
268
  for (const element of elements){
302
269
  writer.remove(element);
303
270
  }
@@ -312,24 +279,24 @@ const listElements = [
312
279
  });
313
280
  }
314
281
  /**
315
- * Performs paste of markers on already pasted element.
316
- *
317
- * 1. Inserts fake markers that are present in fragment element (such fragment will be processed in `getPastedDocumentElement`).
318
- * 2. Calls `getPastedDocumentElement` and gets element that is inserted into root model.
319
- * 3. Removes all fake markers present in transformed element.
320
- * 4. Inserts new markers with removed fake markers ranges into pasted fragment.
321
- *
322
- * There are multiple edge cases that have to be considered before calling this function:
323
- *
324
- * * `markers` are inserted into the same element that must be later transformed inside `getPastedDocumentElement`.
325
- * * Fake marker elements inside `getPastedDocumentElement` can be cloned, but their ranges cannot overlap.
326
- * * If `duplicateOnPaste` is `true` in marker config then associated marker ID is regenerated before pasting.
327
- *
328
- * @param action Type of clipboard action.
329
- * @param markers Object that maps marker name to corresponding range.
330
- * @param getPastedDocumentElement Getter used to get target markers element.
331
- * @internal
332
- */ _pasteMarkersIntoTransformedElement(markers, getPastedDocumentElement) {
282
+ * Performs paste of markers on already pasted element.
283
+ *
284
+ * 1. Inserts fake markers that are present in fragment element (such fragment will be processed in `getPastedDocumentElement`).
285
+ * 2. Calls `getPastedDocumentElement` and gets element that is inserted into root model.
286
+ * 3. Removes all fake markers present in transformed element.
287
+ * 4. Inserts new markers with removed fake markers ranges into pasted fragment.
288
+ *
289
+ * There are multiple edge cases that have to be considered before calling this function:
290
+ *
291
+ * * `markers` are inserted into the same element that must be later transformed inside `getPastedDocumentElement`.
292
+ * * Fake marker elements inside `getPastedDocumentElement` can be cloned, but their ranges cannot overlap.
293
+ * * If `duplicateOnPaste` is `true` in marker config then associated marker ID is regenerated before pasting.
294
+ *
295
+ * @param action Type of clipboard action.
296
+ * @param markers Object that maps marker name to corresponding range.
297
+ * @param getPastedDocumentElement Getter used to get target markers element.
298
+ * @internal
299
+ */ _pasteMarkersIntoTransformedElement(markers, getPastedDocumentElement) {
333
300
  const pasteMarkers = this._getPasteMarkersFromRangeMap(markers);
334
301
  return this.editor.model.change((writer)=>{
335
302
  // Inserts fake markers into source fragment / element that is later transformed inside `getPastedDocumentElement`.
@@ -356,13 +323,13 @@ const listElements = [
356
323
  });
357
324
  }
358
325
  /**
359
- * Pastes document fragment with markers to document.
360
- * If `duplicateOnPaste` is `true` in marker config then associated markers IDs
361
- * are regenerated before pasting to avoid markers duplications in content.
362
- *
363
- * @param fragment Document fragment that should contain already processed by pipeline markers.
364
- * @internal
365
- */ _pasteFragmentWithMarkers(fragment) {
326
+ * Pastes document fragment with markers to document.
327
+ * If `duplicateOnPaste` is `true` in marker config then associated markers IDs
328
+ * are regenerated before pasting to avoid markers duplications in content.
329
+ *
330
+ * @param fragment Document fragment that should contain already processed by pipeline markers.
331
+ * @internal
332
+ */ _pasteFragmentWithMarkers(fragment) {
366
333
  const pasteMarkers = this._getPasteMarkersFromRangeMap(fragment.markers);
367
334
  fragment.markers.clear();
368
335
  for (const copyableMarker of pasteMarkers){
@@ -371,17 +338,17 @@ const listElements = [
371
338
  return this.editor.model.insertContent(fragment);
372
339
  }
373
340
  /**
374
- * In some situations we have to perform copy on selected fragment with certain markers. This function allows to temporarily bypass
375
- * restrictions on markers that we want to copy.
376
- *
377
- * This function executes `executor()` callback. For the duration of the callback, if the clipboard pipeline is used to copy
378
- * content, markers with the specified name will be copied to the clipboard as well.
379
- *
380
- * @param markerName Which markers should be copied.
381
- * @param executor Callback executed.
382
- * @param config Optional configuration flags used to copy (such like partial copy flag).
383
- * @internal
384
- */ _forceMarkersCopy(markerName, executor, config = {
341
+ * In some situations we have to perform copy on selected fragment with certain markers. This function allows to temporarily bypass
342
+ * restrictions on markers that we want to copy.
343
+ *
344
+ * This function executes `executor()` callback. For the duration of the callback, if the clipboard pipeline is used to copy
345
+ * content, markers with the specified name will be copied to the clipboard as well.
346
+ *
347
+ * @param markerName Which markers should be copied.
348
+ * @param executor Callback executed.
349
+ * @param config Optional configuration flags used to copy (such like partial copy flag).
350
+ * @internal
351
+ */ _forceMarkersCopy(markerName, executor, config = {
385
352
  allowedActions: 'all',
386
353
  copyPartiallySelected: true,
387
354
  duplicateOnPaste: true
@@ -396,12 +363,12 @@ const listElements = [
396
363
  }
397
364
  }
398
365
  /**
399
- * Checks if marker can be copied.
400
- *
401
- * @param markerName Name of checked marker.
402
- * @param action Type of clipboard action. If null then checks only if marker is registered as copyable.
403
- * @internal
404
- */ _isMarkerCopyable(markerName, action) {
366
+ * Checks if marker can be copied.
367
+ *
368
+ * @param markerName Name of checked marker.
369
+ * @param action Type of clipboard action. If null then checks only if marker is registered as copyable.
370
+ * @internal
371
+ */ _isMarkerCopyable(markerName, action) {
405
372
  const config = this._getMarkerClipboardConfig(markerName);
406
373
  if (!config) {
407
374
  return false;
@@ -414,43 +381,43 @@ const listElements = [
414
381
  return allowedActions === 'all' || allowedActions.includes(action);
415
382
  }
416
383
  /**
417
- * Checks if marker has any clipboard copy behavior configuration.
418
- *
419
- * @param markerName Name of checked marker.
420
- */ _hasMarkerConfiguration(markerName) {
384
+ * Checks if marker has any clipboard copy behavior configuration.
385
+ *
386
+ * @param markerName Name of checked marker.
387
+ */ _hasMarkerConfiguration(markerName) {
421
388
  return !!this._getMarkerClipboardConfig(markerName);
422
389
  }
423
390
  /**
424
- * Returns marker's configuration flags passed during registration.
425
- *
426
- * @param markerName Name of marker that should be returned.
427
- * @internal
428
- */ _getMarkerClipboardConfig(markerName) {
391
+ * Returns marker's configuration flags passed during registration.
392
+ *
393
+ * @param markerName Name of marker that should be returned.
394
+ * @internal
395
+ */ _getMarkerClipboardConfig(markerName) {
429
396
  const [markerNamePrefix] = markerName.split(':');
430
397
  return this._markersToCopy.get(markerNamePrefix) || null;
431
398
  }
432
399
  /**
433
- * First step of copying markers. It looks for markers intersecting with given selection and inserts `$marker` elements
434
- * at positions where document markers start or end. This way `$marker` elements can be easily copied together with
435
- * the rest of the content of the selection.
436
- *
437
- * @param writer An instance of the model writer.
438
- * @param selection Selection to be checked.
439
- * @param action Type of clipboard action.
440
- */ _insertFakeMarkersIntoSelection(writer, selection, action) {
400
+ * First step of copying markers. It looks for markers intersecting with given selection and inserts `$marker` elements
401
+ * at positions where document markers start or end. This way `$marker` elements can be easily copied together with
402
+ * the rest of the content of the selection.
403
+ *
404
+ * @param writer An instance of the model writer.
405
+ * @param selection Selection to be checked.
406
+ * @param action Type of clipboard action.
407
+ */ _insertFakeMarkersIntoSelection(writer, selection, action) {
441
408
  const copyableMarkers = this._getCopyableMarkersFromSelection(writer, selection, action);
442
409
  return this._insertFakeMarkersElements(writer, copyableMarkers);
443
410
  }
444
411
  /**
445
- * Returns array of markers that can be copied in specified selection.
446
- *
447
- * If marker cannot be copied partially (according to `copyPartiallySelected` configuration flag) and
448
- * is not present entirely in any selection range then it will be skipped.
449
- *
450
- * @param writer An instance of the model writer.
451
- * @param selection Selection which will be checked.
452
- * @param action Type of clipboard action. If null then checks only if marker is registered as copyable.
453
- */ _getCopyableMarkersFromSelection(writer, selection, action) {
412
+ * Returns array of markers that can be copied in specified selection.
413
+ *
414
+ * If marker cannot be copied partially (according to `copyPartiallySelected` configuration flag) and
415
+ * is not present entirely in any selection range then it will be skipped.
416
+ *
417
+ * @param writer An instance of the model writer.
418
+ * @param selection Selection which will be checked.
419
+ * @param action Type of clipboard action. If null then checks only if marker is registered as copyable.
420
+ */ _getCopyableMarkersFromSelection(writer, selection, action) {
454
421
  const selectionRanges = Array.from(selection.getRanges());
455
422
  // Picks all markers in provided ranges. Ensures that there are no duplications if
456
423
  // there are multiple ranges that intersects with the same marker.
@@ -488,13 +455,13 @@ const listElements = [
488
455
  });
489
456
  }
490
457
  /**
491
- * Picks all markers from markers map that can be pasted.
492
- * If `duplicateOnPaste` is `true`, it regenerates their IDs to ensure uniqueness.
493
- * If marker is not registered, it will be kept in the array anyway.
494
- *
495
- * @param markers Object that maps marker name to corresponding range.
496
- * @param action Type of clipboard action. If null then checks only if marker is registered as copyable.
497
- */ _getPasteMarkersFromRangeMap(markers, action = null) {
458
+ * Picks all markers from markers map that can be pasted.
459
+ * If `duplicateOnPaste` is `true`, it regenerates their IDs to ensure uniqueness.
460
+ * If marker is not registered, it will be kept in the array anyway.
461
+ *
462
+ * @param markers Object that maps marker name to corresponding range.
463
+ * @param action Type of clipboard action. If null then checks only if marker is registered as copyable.
464
+ */ _getPasteMarkersFromRangeMap(markers, action = null) {
498
465
  const { model } = this.editor;
499
466
  const entries = markers instanceof Map ? Array.from(markers.entries()) : Object.entries(markers);
500
467
  return entries.flatMap(([markerName, range])=>{
@@ -523,13 +490,13 @@ const listElements = [
523
490
  });
524
491
  }
525
492
  /**
526
- * Inserts specified array of fake markers elements to document and assigns them `type` and `name` attributes.
527
- * Fake markers elements are used to calculate position of markers on pasted fragment that were transformed during
528
- * steps between copy and paste.
529
- *
530
- * @param writer An instance of the model writer.
531
- * @param markers Array of markers that will be inserted.
532
- */ _insertFakeMarkersElements(writer, markers) {
493
+ * Inserts specified array of fake markers elements to document and assigns them `type` and `name` attributes.
494
+ * Fake markers elements are used to calculate position of markers on pasted fragment that were transformed during
495
+ * steps between copy and paste.
496
+ *
497
+ * @param writer An instance of the model writer.
498
+ * @param markers Array of markers that will be inserted.
499
+ */ _insertFakeMarkersElements(writer, markers) {
533
500
  const mappedMarkers = {};
534
501
  const sortedMarkers = markers.flatMap((marker)=>{
535
502
  const { start, end } = marker.range;
@@ -562,17 +529,17 @@ const listElements = [
562
529
  return mappedMarkers;
563
530
  }
564
531
  /**
565
- * Removes all `$marker` elements from the given document fragment.
566
- *
567
- * Returns an object where keys are marker names, and values are ranges corresponding to positions
568
- * where `$marker` elements were inserted.
569
- *
570
- * If the document fragment had only one `$marker` element for given marker (start or end) the other boundary is set automatically
571
- * (to the end or start of the document fragment, respectively).
572
- *
573
- * @param writer An instance of the model writer.
574
- * @param rootElement The element to be checked.
575
- */ _removeFakeMarkersInsideElement(writer, rootElement) {
532
+ * Removes all `$marker` elements from the given document fragment.
533
+ *
534
+ * Returns an object where keys are marker names, and values are ranges corresponding to positions
535
+ * where `$marker` elements were inserted.
536
+ *
537
+ * If the document fragment had only one `$marker` element for given marker (start or end) the other boundary is set automatically
538
+ * (to the end or start of the document fragment, respectively).
539
+ *
540
+ * @param writer An instance of the model writer.
541
+ * @param rootElement The element to be checked.
542
+ */ _removeFakeMarkersInsideElement(writer, rootElement) {
576
543
  const fakeMarkersElements = this._getAllFakeMarkersFromElement(writer, rootElement);
577
544
  const fakeMarkersRanges = fakeMarkersElements.reduce((acc, fakeMarker)=>{
578
545
  const position = fakeMarker.markerElement && writer.createPositionBefore(fakeMarker.markerElement);
@@ -617,14 +584,14 @@ const listElements = [
617
584
  ]), range.end || writer.createPositionAt(rootElement, 'end')));
618
585
  }
619
586
  /**
620
- * Returns array that contains list of fake markers with corresponding `$marker` elements.
621
- *
622
- * For each marker, there can be two `$marker` elements or only one (if the document fragment contained
623
- * only the beginning or only the end of a marker).
624
- *
625
- * @param writer An instance of the model writer.
626
- * @param rootElement The element to be checked.
627
- */ _getAllFakeMarkersFromElement(writer, rootElement) {
587
+ * Returns array that contains list of fake markers with corresponding `$marker` elements.
588
+ *
589
+ * For each marker, there can be two `$marker` elements or only one (if the document fragment contained
590
+ * only the beginning or only the end of a marker).
591
+ *
592
+ * @param writer An instance of the model writer.
593
+ * @param rootElement The element to be checked.
594
+ */ _getAllFakeMarkersFromElement(writer, rootElement) {
628
595
  const foundFakeMarkers = Array.from(writer.createRangeIn(rootElement)).flatMap(({ item })=>{
629
596
  if (!item.is('element', '$marker')) {
630
597
  return [];
@@ -678,12 +645,12 @@ const listElements = [
678
645
  ];
679
646
  }
680
647
  /**
681
- * When copy of markers occurs we have to make sure that pasted markers have different names
682
- * than source markers. This functions helps with assigning unique part to marker name to
683
- * prevent duplicated markers error.
684
- *
685
- * @param name Name of marker
686
- */ _getUniqueMarkerName(name) {
648
+ * When copy of markers occurs we have to make sure that pasted markers have different names
649
+ * than source markers. This functions helps with assigning unique part to marker name to
650
+ * prevent duplicated markers error.
651
+ *
652
+ * @param name Name of marker
653
+ */ _getUniqueMarkerName(name) {
687
654
  const parts = name.split(':');
688
655
  const newId = uid().substring(1, 6);
689
656
  // It looks like the marker already is UID marker so in this scenario just swap
@@ -698,128 +665,32 @@ const listElements = [
698
665
  // example: comment => comment:{ newId }
699
666
  return `${parts.join(':')}:${newId}`;
700
667
  }
668
+ constructor(){
669
+ super(...arguments);
670
+ /**
671
+ * Map of marker names that can be copied.
672
+ *
673
+ * @internal
674
+ */ this._markersToCopy = new Map();
675
+ }
701
676
  }
702
677
 
703
- // Input pipeline events overview:
704
- //
705
- // ┌──────────────────────┐ ┌──────────────────────┐
706
- // │ view.Document │ │ view.Document │
707
- // │ paste │ │ drop │
708
- // └───────────┬──────────┘ └───────────┬──────────┘
709
- // │ │
710
- // └────────────────┌────────────────┘
711
- // │
712
- // ┌─────────V────────┐
713
- // │ view.Document │ Retrieves text/html or text/plain from data.dataTransfer
714
- // │ clipboardInput │ and processes it to view.DocumentFragment.
715
- // └─────────┬────────┘
716
- // │
717
- // ┌───────────V───────────┐
718
- // │ ClipboardPipeline │ Converts view.DocumentFragment to model.DocumentFragment.
719
- // │ inputTransformation │
720
- // └───────────┬───────────┘
721
- // │
722
- // ┌──────────V──────────┐
723
- // │ ClipboardPipeline │ Calls model.insertContent().
724
- // │ contentInsertion │
725
- // └─────────────────────┘
726
- //
727
- //
728
- // Output pipeline events overview:
729
- //
730
- // ┌──────────────────────┐ ┌──────────────────────┐
731
- // │ view.Document │ │ view.Document │ Retrieves the selected model.DocumentFragment
732
- // │ copy │ │ cut │ and fires the `outputTransformation` event.
733
- // └───────────┬──────────┘ └───────────┬──────────┘
734
- // │ │
735
- // └────────────────┌────────────────┘
736
- // │
737
- // ┌───────────V───────────┐
738
- // │ ClipboardPipeline │ Processes model.DocumentFragment and converts it to
739
- // │ outputTransformation │ view.DocumentFragment.
740
- // └───────────┬───────────┘
741
- // │
742
- // ┌─────────V────────┐
743
- // │ view.Document │ Processes view.DocumentFragment to text/html and text/plain
744
- // │ clipboardOutput │ and stores the results in data.dataTransfer.
745
- // └──────────────────┘
746
- //
747
- /**
748
- * The clipboard pipeline feature. It is responsible for intercepting the `paste` and `drop` events and
749
- * passing the pasted content through a series of events in order to insert it into the editor's content.
750
- * It also handles the `cut` and `copy` events to fill the native clipboard with the serialized editor's data.
751
- *
752
- * # Input pipeline
753
- *
754
- * The behavior of the default handlers (all at a `low` priority):
755
- *
756
- * ## Event: `paste` or `drop`
757
- *
758
- * 1. Translates the event data.
759
- * 2. Fires the {@link module:engine/view/document~Document#event:clipboardInput `view.Document#clipboardInput`} event.
760
- *
761
- * ## Event: `view.Document#clipboardInput`
762
- *
763
- * 1. If the `data.content` event field is already set (by some listener on a higher priority), it takes this content and fires the event
764
- * from the last point.
765
- * 2. Otherwise, it retrieves `text/html` or `text/plain` from `data.dataTransfer`.
766
- * 3. Normalizes the raw data by applying simple filters on string data.
767
- * 4. Processes the raw data to {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`} with the
768
- * {@link module:engine/controller/datacontroller~DataController#htmlProcessor `DataController#htmlProcessor`}.
769
- * 5. Fires the {@link module:clipboard/clipboardpipeline~ClipboardPipeline#event:inputTransformation
770
- * `ClipboardPipeline#inputTransformation`} event with the view document fragment in the `data.content` event field.
771
- *
772
- * ## Event: `ClipboardPipeline#inputTransformation`
773
- *
774
- * 1. Converts {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`} from the `data.content` field to
775
- * {@link module:engine/model/documentfragment~DocumentFragment `model.DocumentFragment`}.
776
- * 2. Fires the {@link module:clipboard/clipboardpipeline~ClipboardPipeline#event:contentInsertion `ClipboardPipeline#contentInsertion`}
777
- * event with the model document fragment in the `data.content` event field.
778
- * **Note**: The `ClipboardPipeline#contentInsertion` event is fired within a model change block to allow other handlers
779
- * to run in the same block without post-fixers called in between (i.e., the selection post-fixer).
780
- *
781
- * ## Event: `ClipboardPipeline#contentInsertion`
782
- *
783
- * 1. Calls {@link module:engine/model/model~Model#insertContent `model.insertContent()`} to insert `data.content`
784
- * at the current selection position.
785
- *
786
- * # Output pipeline
787
- *
788
- * The behavior of the default handlers (all at a `low` priority):
789
- *
790
- * ## Event: `copy`, `cut` or `dragstart`
791
- *
792
- * 1. Retrieves the selected {@link module:engine/model/documentfragment~DocumentFragment `model.DocumentFragment`} by calling
793
- * {@link module:engine/model/model~Model#getSelectedContent `model#getSelectedContent()`}.
794
- * 2. Converts the model document fragment to {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`}.
795
- * 3. Fires the {@link module:engine/view/document~Document#event:clipboardOutput `view.Document#clipboardOutput`} event
796
- * with the view document fragment in the `data.content` event field.
797
- *
798
- * ## Event: `view.Document#clipboardOutput`
799
- *
800
- * 1. Processes `data.content` to HTML and plain text with the
801
- * {@link module:engine/controller/datacontroller~DataController#htmlProcessor `DataController#htmlProcessor`}.
802
- * 2. Updates the `data.dataTransfer` data for `text/html` and `text/plain` with the processed data.
803
- * 3. For the `cut` method, calls {@link module:engine/model/model~Model#deleteContent `model.deleteContent()`}
804
- * on the current selection.
805
- *
806
- * Read more about the clipboard integration in the {@glink framework/deep-dive/clipboard clipboard deep-dive} guide.
807
- */ class ClipboardPipeline extends Plugin {
678
+ class ClipboardPipeline extends Plugin {
808
679
  /**
809
- * @inheritDoc
810
- */ static get pluginName() {
680
+ * @inheritDoc
681
+ */ static get pluginName() {
811
682
  return 'ClipboardPipeline';
812
683
  }
813
684
  /**
814
- * @inheritDoc
815
- */ static get requires() {
685
+ * @inheritDoc
686
+ */ static get requires() {
816
687
  return [
817
688
  ClipboardMarkersUtils
818
689
  ];
819
690
  }
820
691
  /**
821
- * @inheritDoc
822
- */ init() {
692
+ * @inheritDoc
693
+ */ init() {
823
694
  const editor = this.editor;
824
695
  const view = editor.editing.view;
825
696
  view.addObserver(ClipboardObserver);
@@ -827,10 +698,10 @@ const listElements = [
827
698
  this._setupCopyCut();
828
699
  }
829
700
  /**
830
- * Fires Clipboard `'outputTransformation'` event for given parameters.
831
- *
832
- * @internal
833
- */ _fireOutputTransformationEvent(dataTransfer, selection, method) {
701
+ * Fires Clipboard `'outputTransformation'` event for given parameters.
702
+ *
703
+ * @internal
704
+ */ _fireOutputTransformationEvent(dataTransfer, selection, method) {
834
705
  const clipboardMarkersUtils = this.editor.plugins.get('ClipboardMarkersUtils');
835
706
  this.editor.model.enqueueChange({
836
707
  isUndoable: method === 'cut'
@@ -844,8 +715,8 @@ const listElements = [
844
715
  });
845
716
  }
846
717
  /**
847
- * The clipboard paste pipeline.
848
- */ _setupPasteDrop() {
718
+ * The clipboard paste pipeline.
719
+ */ _setupPasteDrop() {
849
720
  const editor = this.editor;
850
721
  const model = editor.model;
851
722
  const view = editor.editing.view;
@@ -925,8 +796,8 @@ const listElements = [
925
796
  });
926
797
  }
927
798
  /**
928
- * The clipboard copy/cut pipeline.
929
- */ _setupCopyCut() {
799
+ * The clipboard copy/cut pipeline.
800
+ */ _setupCopyCut() {
930
801
  const editor = this.editor;
931
802
  const modelDocument = editor.model.document;
932
803
  const view = editor.editing.view;
@@ -974,13 +845,11 @@ const listElements = [
974
845
  }
975
846
  }
976
847
 
977
- const toPx = /* #__PURE__ */ toUnit('px');
978
- /**
979
- * The horizontal drop target line view.
980
- */ class LineView extends View {
848
+ const toPx = toUnit('px');
849
+ class LineView extends View {
981
850
  /**
982
- * @inheritDoc
983
- */ constructor(){
851
+ * @inheritDoc
852
+ */ constructor(){
984
853
  super();
985
854
  const bind = this.bindTemplate;
986
855
  this.set({
@@ -1007,48 +876,20 @@ const toPx = /* #__PURE__ */ toUnit('px');
1007
876
  }
1008
877
  }
1009
878
 
1010
- /**
1011
- * Part of the Drag and Drop handling. Responsible for finding and displaying the drop target.
1012
- *
1013
- * @internal
1014
- */ class DragDropTarget extends Plugin {
1015
- /**
1016
- * A delayed callback removing the drop marker.
1017
- *
1018
- * @internal
1019
- */ removeDropMarkerDelayed = delay(()=>this.removeDropMarker(), 40);
1020
- /**
1021
- * A throttled callback updating the drop marker.
1022
- */ _updateDropMarkerThrottled = throttle((targetRange)=>this._updateDropMarker(targetRange), 40);
1023
- /**
1024
- * A throttled callback reconverting the drop parker.
1025
- */ _reconvertMarkerThrottled = throttle(()=>{
1026
- if (this.editor.model.markers.has('drop-target')) {
1027
- this.editor.editing.reconvertMarker('drop-target');
1028
- }
1029
- }, 0);
1030
- /**
1031
- * The horizontal drop target line view.
1032
- */ _dropTargetLineView = new LineView();
879
+ class DragDropTarget extends Plugin {
1033
880
  /**
1034
- * DOM Emitter.
1035
- */ _domEmitter = new (DomEmitterMixin())();
1036
- /**
1037
- * Map of document scrollable elements.
1038
- */ _scrollables = new Map();
1039
- /**
1040
- * @inheritDoc
1041
- */ static get pluginName() {
881
+ * @inheritDoc
882
+ */ static get pluginName() {
1042
883
  return 'DragDropTarget';
1043
884
  }
1044
885
  /**
1045
- * @inheritDoc
1046
- */ init() {
886
+ * @inheritDoc
887
+ */ init() {
1047
888
  this._setupDropMarker();
1048
889
  }
1049
890
  /**
1050
- * @inheritDoc
1051
- */ destroy() {
891
+ * @inheritDoc
892
+ */ destroy() {
1052
893
  this._domEmitter.stopListening();
1053
894
  for (const { resizeObserver } of this._scrollables.values()){
1054
895
  resizeObserver.destroy();
@@ -1059,10 +900,10 @@ const toPx = /* #__PURE__ */ toUnit('px');
1059
900
  return super.destroy();
1060
901
  }
1061
902
  /**
1062
- * Finds the drop target range and updates the drop marker.
1063
- *
1064
- * @internal
1065
- */ updateDropMarker(targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
903
+ * Finds the drop target range and updates the drop marker.
904
+ *
905
+ * @internal
906
+ */ updateDropMarker(targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
1066
907
  this.removeDropMarkerDelayed.cancel();
1067
908
  const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange);
1068
909
  /* istanbul ignore next -- @preserve */ if (!targetRange) {
@@ -1075,10 +916,10 @@ const toPx = /* #__PURE__ */ toUnit('px');
1075
916
  this._updateDropMarkerThrottled(targetRange);
1076
917
  }
1077
918
  /**
1078
- * Finds the final drop target range.
1079
- *
1080
- * @internal
1081
- */ getFinalDropRange(targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
919
+ * Finds the final drop target range.
920
+ *
921
+ * @internal
922
+ */ getFinalDropRange(targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
1082
923
  const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange);
1083
924
  // The dragging markers must be removed after searching for the target range because sometimes
1084
925
  // the target lands on the marker itself.
@@ -1086,10 +927,10 @@ const toPx = /* #__PURE__ */ toUnit('px');
1086
927
  return targetRange;
1087
928
  }
1088
929
  /**
1089
- * Removes the drop target marker.
1090
- *
1091
- * @internal
1092
- */ removeDropMarker() {
930
+ * Removes the drop target marker.
931
+ *
932
+ * @internal
933
+ */ removeDropMarker() {
1093
934
  const model = this.editor.model;
1094
935
  this.removeDropMarkerDelayed.cancel();
1095
936
  this._updateDropMarkerThrottled.cancel();
@@ -1101,8 +942,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1101
942
  }
1102
943
  }
1103
944
  /**
1104
- * Creates downcast conversion for the drop target marker.
1105
- */ _setupDropMarker() {
945
+ * Creates downcast conversion for the drop target marker.
946
+ */ _setupDropMarker() {
1106
947
  const editor = this.editor;
1107
948
  editor.ui.view.body.add(this._dropTargetLineView);
1108
949
  // Drop marker conversion for hovering over widgets.
@@ -1133,10 +974,10 @@ const toPx = /* #__PURE__ */ toUnit('px');
1133
974
  });
1134
975
  }
1135
976
  /**
1136
- * Updates the drop target marker to the provided range.
1137
- *
1138
- * @param targetRange The range to set the marker to.
1139
- */ _updateDropMarker(targetRange) {
977
+ * Updates the drop target marker to the provided range.
978
+ *
979
+ * @param targetRange The range to set the marker to.
980
+ */ _updateDropMarker(targetRange) {
1140
981
  const editor = this.editor;
1141
982
  const markers = editor.model.markers;
1142
983
  editor.model.change((writer)=>{
@@ -1156,8 +997,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1156
997
  });
1157
998
  }
1158
999
  /**
1159
- * Creates the UI element for vertical (in-line) drop target.
1160
- */ _createDropTargetPosition(writer) {
1000
+ * Creates the UI element for vertical (in-line) drop target.
1001
+ */ _createDropTargetPosition(writer) {
1161
1002
  return writer.createUIElement('span', {
1162
1003
  class: 'ck ck-clipboard-drop-target-position'
1163
1004
  }, function(domDocument) {
@@ -1168,8 +1009,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1168
1009
  });
1169
1010
  }
1170
1011
  /**
1171
- * Updates the horizontal drop target line.
1172
- */ _updateDropTargetLine(range) {
1012
+ * Updates the horizontal drop target line.
1013
+ */ _updateDropTargetLine(range) {
1173
1014
  const editing = this.editor.editing;
1174
1015
  const nodeBefore = range.start.nodeBefore;
1175
1016
  const nodeAfter = range.start.nodeAfter;
@@ -1208,8 +1049,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1208
1049
  }
1209
1050
  }
1210
1051
  /**
1211
- * Finds the closest scrollable element rect for the given view element.
1212
- */ _getScrollableRect(viewElement) {
1052
+ * Finds the closest scrollable element rect for the given view element.
1053
+ */ _getScrollableRect(viewElement) {
1213
1054
  const rootName = viewElement.root.rootName;
1214
1055
  let domScrollable;
1215
1056
  if (this._scrollables.has(rootName)) {
@@ -1228,6 +1069,33 @@ const toPx = /* #__PURE__ */ toUnit('px');
1228
1069
  }
1229
1070
  return new Rect(domScrollable).excludeScrollbarsAndBorders();
1230
1071
  }
1072
+ constructor(){
1073
+ super(...arguments);
1074
+ /**
1075
+ * A delayed callback removing the drop marker.
1076
+ *
1077
+ * @internal
1078
+ */ this.removeDropMarkerDelayed = delay(()=>this.removeDropMarker(), 40);
1079
+ /**
1080
+ * A throttled callback updating the drop marker.
1081
+ */ this._updateDropMarkerThrottled = throttle((targetRange)=>this._updateDropMarker(targetRange), 40);
1082
+ /**
1083
+ * A throttled callback reconverting the drop parker.
1084
+ */ this._reconvertMarkerThrottled = throttle(()=>{
1085
+ if (this.editor.model.markers.has('drop-target')) {
1086
+ this.editor.editing.reconvertMarker('drop-target');
1087
+ }
1088
+ }, 0);
1089
+ /**
1090
+ * The horizontal drop target line view.
1091
+ */ this._dropTargetLineView = new LineView();
1092
+ /**
1093
+ * DOM Emitter.
1094
+ */ this._domEmitter = new (DomEmitterMixin())();
1095
+ /**
1096
+ * Map of document scrollable elements.
1097
+ */ this._scrollables = new Map();
1098
+ }
1231
1099
  }
1232
1100
  /**
1233
1101
  * Returns fixed selection range for given position and target element.
@@ -1342,25 +1210,15 @@ const toPx = /* #__PURE__ */ toUnit('px');
1342
1210
  return domElement;
1343
1211
  }
1344
1212
 
1345
- /**
1346
- * Integration of a block Drag and Drop support with the block toolbar.
1347
- *
1348
- * @internal
1349
- */ class DragDropBlockToolbar extends Plugin {
1213
+ class DragDropBlockToolbar extends Plugin {
1350
1214
  /**
1351
- * Whether current dragging is started by block toolbar button dragging.
1352
- */ _isBlockDragging = false;
1353
- /**
1354
- * DOM Emitter.
1355
- */ _domEmitter = new (DomEmitterMixin())();
1356
- /**
1357
- * @inheritDoc
1358
- */ static get pluginName() {
1215
+ * @inheritDoc
1216
+ */ static get pluginName() {
1359
1217
  return 'DragDropBlockToolbar';
1360
1218
  }
1361
1219
  /**
1362
- * @inheritDoc
1363
- */ init() {
1220
+ * @inheritDoc
1221
+ */ init() {
1364
1222
  const editor = this.editor;
1365
1223
  this.listenTo(editor, 'change:isReadOnly', (evt, name, isReadOnly)=>{
1366
1224
  if (isReadOnly) {
@@ -1391,14 +1249,14 @@ const toPx = /* #__PURE__ */ toUnit('px');
1391
1249
  }
1392
1250
  }
1393
1251
  /**
1394
- * @inheritDoc
1395
- */ destroy() {
1252
+ * @inheritDoc
1253
+ */ destroy() {
1396
1254
  this._domEmitter.stopListening();
1397
1255
  return super.destroy();
1398
1256
  }
1399
1257
  /**
1400
- * The `dragstart` event handler.
1401
- */ _handleBlockDragStart(domEvent) {
1258
+ * The `dragstart` event handler.
1259
+ */ _handleBlockDragStart(domEvent) {
1402
1260
  if (!this.isEnabled) {
1403
1261
  return;
1404
1262
  }
@@ -1413,8 +1271,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1413
1271
  view.getObserver(ClipboardObserver).onDomEvent(domEvent);
1414
1272
  }
1415
1273
  /**
1416
- * The `dragover` and `drop` event handler.
1417
- */ _handleBlockDragging(domEvent) {
1274
+ * The `dragover` and `drop` event handler.
1275
+ */ _handleBlockDragging(domEvent) {
1418
1276
  if (!this.isEnabled || !this._isBlockDragging) {
1419
1277
  return;
1420
1278
  }
@@ -1437,129 +1295,30 @@ const toPx = /* #__PURE__ */ toUnit('px');
1437
1295
  });
1438
1296
  }
1439
1297
  /**
1440
- * The `dragend` event handler.
1441
- */ _handleBlockDragEnd() {
1298
+ * The `dragend` event handler.
1299
+ */ _handleBlockDragEnd() {
1442
1300
  this._isBlockDragging = false;
1443
1301
  }
1302
+ constructor(){
1303
+ super(...arguments);
1304
+ /**
1305
+ * Whether current dragging is started by block toolbar button dragging.
1306
+ */ this._isBlockDragging = false;
1307
+ /**
1308
+ * DOM Emitter.
1309
+ */ this._domEmitter = new (DomEmitterMixin())();
1310
+ }
1444
1311
  }
1445
1312
 
1446
- // Drag and drop events overview:
1447
- //
1448
- // ┌──────────────────┐
1449
- // │ mousedown │ Sets the draggable attribute.
1450
- // └─────────┬────────┘
1451
- // │
1452
- // └─────────────────────┐
1453
- // │ │
1454
- // │ ┌─────────V────────┐
1455
- // │ │ mouseup │ Dragging did not start, removes the draggable attribute.
1456
- // │ └──────────────────┘
1457
- // │
1458
- // ┌─────────V────────┐ Retrieves the selected model.DocumentFragment
1459
- // │ dragstart │ and converts it to view.DocumentFragment.
1460
- // └─────────┬────────┘
1461
- // │
1462
- // ┌─────────V────────┐ Processes view.DocumentFragment to text/html and text/plain
1463
- // │ clipboardOutput │ and stores the results in data.dataTransfer.
1464
- // └─────────┬────────┘
1465
- // │
1466
- // │ DOM dragover
1467
- // ┌────────────┐
1468
- // │ │
1469
- // ┌─────────V────────┐ │
1470
- // │ dragging │ │ Updates the drop target marker.
1471
- // └─────────┬────────┘ │
1472
- // │ │
1473
- // ┌─────────────└────────────┘
1474
- // │ │ │
1475
- // │ ┌─────────V────────┐ │
1476
- // │ │ dragleave │ │ Removes the drop target marker.
1477
- // │ └─────────┬────────┘ │
1478
- // │ │ │
1479
- // ┌───│─────────────┘ │
1480
- // │ │ │ │
1481
- // │ │ ┌─────────V────────┐ │
1482
- // │ │ │ dragenter │ │ Focuses the editor view.
1483
- // │ │ └─────────┬────────┘ │
1484
- // │ │ │ │
1485
- // │ │ └────────────┘
1486
- // │ │
1487
- // │ └─────────────┐
1488
- // │ │ │
1489
- // │ │ ┌─────────V────────┐
1490
- // └───┐ │ drop │ (The default handler of the clipboard pipeline).
1491
- // │ └─────────┬────────┘
1492
- // │ │
1493
- // │ ┌─────────V────────┐ Resolves the final data.targetRanges.
1494
- // │ │ clipboardInput │ Aborts if dropping on dragged content.
1495
- // │ └─────────┬────────┘
1496
- // │ │
1497
- // │ ┌─────────V────────┐
1498
- // │ │ clipboardInput │ (The default handler of the clipboard pipeline).
1499
- // │ └─────────┬────────┘
1500
- // │ │
1501
- // │ ┌───────────V───────────┐
1502
- // │ │ inputTransformation │ (The default handler of the clipboard pipeline).
1503
- // │ └───────────┬───────────┘
1504
- // │ │
1505
- // │ ┌──────────V──────────┐
1506
- // │ │ contentInsertion │ Updates the document selection to drop range.
1507
- // │ └──────────┬──────────┘
1508
- // │ │
1509
- // │ ┌──────────V──────────┐
1510
- // │ │ contentInsertion │ (The default handler of the clipboard pipeline).
1511
- // │ └──────────┬──────────┘
1512
- // │ │
1513
- // │ ┌──────────V──────────┐
1514
- // │ │ contentInsertion │ Removes the content from the original range if the insertion was successful.
1515
- // │ └──────────┬──────────┘
1516
- // │ │
1517
- // └─────────────┐
1518
- // │
1519
- // ┌─────────V────────┐
1520
- // │ dragend │ Removes the drop marker and cleans the state.
1521
- // └──────────────────┘
1522
- //
1523
- /**
1524
- * The drag and drop feature. It works on top of the {@link module:clipboard/clipboardpipeline~ClipboardPipeline}.
1525
- *
1526
- * Read more about the clipboard integration in the {@glink framework/deep-dive/clipboard clipboard deep-dive} guide.
1527
- *
1528
- * @internal
1529
- */ class DragDrop extends Plugin {
1530
- /**
1531
- * The live range over the original content that is being dragged.
1532
- */ _draggedRange;
1533
- /**
1534
- * The UID of current dragging that is used to verify if the drop started in the same editor as the drag start.
1535
- *
1536
- * **Note**: This is a workaround for broken 'dragend' events (they are not fired if the source text node got removed).
1537
- */ _draggingUid;
1538
- /**
1539
- * The reference to the model element that currently has a `draggable` attribute set (it is set while dragging).
1540
- */ _draggableElement;
1541
- /**
1542
- * A delayed callback removing draggable attributes.
1543
- */ _clearDraggableAttributesDelayed = delay(()=>this._clearDraggableAttributes(), 40);
1313
+ class DragDrop extends Plugin {
1544
1314
  /**
1545
- * Whether the dragged content can be dropped only in block context.
1546
- */ // TODO handle drag from other editor instance
1547
- // TODO configure to use block, inline or both
1548
- _blockMode = false;
1549
- /**
1550
- * DOM Emitter.
1551
- */ _domEmitter = new (DomEmitterMixin())();
1552
- /**
1553
- * The DOM element used to generate dragged preview image.
1554
- */ _previewContainer;
1555
- /**
1556
- * @inheritDoc
1557
- */ static get pluginName() {
1315
+ * @inheritDoc
1316
+ */ static get pluginName() {
1558
1317
  return 'DragDrop';
1559
1318
  }
1560
1319
  /**
1561
- * @inheritDoc
1562
- */ static get requires() {
1320
+ * @inheritDoc
1321
+ */ static get requires() {
1563
1322
  return [
1564
1323
  ClipboardPipeline,
1565
1324
  Widget,
@@ -1568,8 +1327,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1568
1327
  ];
1569
1328
  }
1570
1329
  /**
1571
- * @inheritDoc
1572
- */ init() {
1330
+ * @inheritDoc
1331
+ */ init() {
1573
1332
  const editor = this.editor;
1574
1333
  const view = editor.editing.view;
1575
1334
  this._draggedRange = null;
@@ -1598,8 +1357,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1598
1357
  }
1599
1358
  }
1600
1359
  /**
1601
- * @inheritDoc
1602
- */ destroy() {
1360
+ * @inheritDoc
1361
+ */ destroy() {
1603
1362
  if (this._draggedRange) {
1604
1363
  this._draggedRange.detach();
1605
1364
  this._draggedRange = null;
@@ -1612,8 +1371,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1612
1371
  return super.destroy();
1613
1372
  }
1614
1373
  /**
1615
- * Drag and drop events handling.
1616
- */ _setupDragging() {
1374
+ * Drag and drop events handling.
1375
+ */ _setupDragging() {
1617
1376
  const editor = this.editor;
1618
1377
  const model = editor.model;
1619
1378
  const view = editor.editing.view;
@@ -1710,8 +1469,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1710
1469
  });
1711
1470
  }
1712
1471
  /**
1713
- * Integration with the `clipboardInput` event.
1714
- */ _setupClipboardInputIntegration() {
1472
+ * Integration with the `clipboardInput` event.
1473
+ */ _setupClipboardInputIntegration() {
1715
1474
  const editor = this.editor;
1716
1475
  const view = editor.editing.view;
1717
1476
  const viewDocument = view.document;
@@ -1751,8 +1510,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1751
1510
  });
1752
1511
  }
1753
1512
  /**
1754
- * Integration with the `contentInsertion` event of the clipboard pipeline.
1755
- */ _setupContentInsertionIntegration() {
1513
+ * Integration with the `contentInsertion` event of the clipboard pipeline.
1514
+ */ _setupContentInsertionIntegration() {
1756
1515
  const clipboardPipeline = this.editor.plugins.get(ClipboardPipeline);
1757
1516
  clipboardPipeline.on('contentInsertion', (evt, data)=>{
1758
1517
  if (!this.isEnabled || data.method !== 'drop') {
@@ -1781,8 +1540,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1781
1540
  });
1782
1541
  }
1783
1542
  /**
1784
- * Adds listeners that add the `draggable` attribute to the elements while the mouse button is down so the dragging could start.
1785
- */ _setupDraggableAttributeHandling() {
1543
+ * Adds listeners that add the `draggable` attribute to the elements while the mouse button is down so the dragging could start.
1544
+ */ _setupDraggableAttributeHandling() {
1786
1545
  const editor = this.editor;
1787
1546
  const view = editor.editing.view;
1788
1547
  const viewDocument = view.document;
@@ -1826,8 +1585,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1826
1585
  });
1827
1586
  }
1828
1587
  /**
1829
- * Removes the `draggable` attribute from the element that was used for dragging.
1830
- */ _clearDraggableAttributes() {
1588
+ * Removes the `draggable` attribute from the element that was used for dragging.
1589
+ */ _clearDraggableAttributes() {
1831
1590
  const editing = this.editor.editing;
1832
1591
  editing.view.change((writer)=>{
1833
1592
  // Remove 'draggable' attribute.
@@ -1838,10 +1597,10 @@ const toPx = /* #__PURE__ */ toUnit('px');
1838
1597
  });
1839
1598
  }
1840
1599
  /**
1841
- * Deletes the dragged content from its original range and clears the dragging state.
1842
- *
1843
- * @param moved Whether the move succeeded.
1844
- */ _finalizeDragging(moved) {
1600
+ * Deletes the dragged content from its original range and clears the dragging state.
1601
+ *
1602
+ * @param moved Whether the move succeeded.
1603
+ */ _finalizeDragging(moved) {
1845
1604
  const editor = this.editor;
1846
1605
  const model = editor.model;
1847
1606
  const dragDropTarget = editor.plugins.get(DragDropTarget);
@@ -1877,8 +1636,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1877
1636
  this._draggedRange = null;
1878
1637
  }
1879
1638
  /**
1880
- * Sets the dragged source range based on event target and document selection.
1881
- */ _prepareDraggedRange(target) {
1639
+ * Sets the dragged source range based on event target and document selection.
1640
+ */ _prepareDraggedRange(target) {
1882
1641
  const editor = this.editor;
1883
1642
  const model = editor.model;
1884
1643
  const selection = model.document.selection;
@@ -1918,8 +1677,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
1918
1677
  model.change((writer)=>writer.setSelection(this._draggedRange.toRange()));
1919
1678
  }
1920
1679
  /**
1921
- * Updates the dragged preview image.
1922
- */ _updatePreview({ dataTransfer, domTarget, clientX }) {
1680
+ * Updates the dragged preview image.
1681
+ */ _updatePreview({ dataTransfer, domTarget, clientX }) {
1923
1682
  const view = this.editor.editing.view;
1924
1683
  const editable = view.document.selection.editableElement;
1925
1684
  const domEditable = view.domConverter.mapViewToDom(editable);
@@ -1943,15 +1702,29 @@ const toPx = /* #__PURE__ */ toUnit('px');
1943
1702
  preview.style.width = computedStyle.width;
1944
1703
  preview.style.paddingLeft = `${domRect.left - clientX + domEditablePaddingLeft}px`;
1945
1704
  /**
1946
- * Set white background in drag and drop preview if iOS.
1947
- * Check: https://github.com/ckeditor/ckeditor5/issues/15085
1948
- */ if (env.isiOS) {
1705
+ * Set white background in drag and drop preview if iOS.
1706
+ * Check: https://github.com/ckeditor/ckeditor5/issues/15085
1707
+ */ if (env.isiOS) {
1949
1708
  preview.style.backgroundColor = 'white';
1950
1709
  }
1951
1710
  preview.innerHTML = dataTransfer.getData('text/html');
1952
1711
  dataTransfer.setDragImage(preview, 0, 0);
1953
1712
  this._previewContainer.appendChild(preview);
1954
1713
  }
1714
+ constructor(){
1715
+ super(...arguments);
1716
+ /**
1717
+ * A delayed callback removing draggable attributes.
1718
+ */ this._clearDraggableAttributesDelayed = delay(()=>this._clearDraggableAttributes(), 40);
1719
+ /**
1720
+ * Whether the dragged content can be dropped only in block context.
1721
+ */ // TODO handle drag from other editor instance
1722
+ // TODO configure to use block, inline or both
1723
+ this._blockMode = false;
1724
+ /**
1725
+ * DOM Emitter.
1726
+ */ this._domEmitter = new (DomEmitterMixin())();
1727
+ }
1955
1728
  }
1956
1729
  /**
1957
1730
  * Returns the drop effect that should be a result of dragging the content.
@@ -2022,26 +1795,22 @@ const toPx = /* #__PURE__ */ toUnit('px');
2022
1795
  return model.createRange(startPosition, endPosition);
2023
1796
  }
2024
1797
 
2025
- /**
2026
- * The plugin detects the user's intention to paste plain text.
2027
- *
2028
- * For example, it detects the <kbd>Ctrl/Cmd</kbd> + <kbd>Shift</kbd> + <kbd>V</kbd> keystroke.
2029
- */ class PastePlainText extends Plugin {
1798
+ class PastePlainText extends Plugin {
2030
1799
  /**
2031
- * @inheritDoc
2032
- */ static get pluginName() {
1800
+ * @inheritDoc
1801
+ */ static get pluginName() {
2033
1802
  return 'PastePlainText';
2034
1803
  }
2035
1804
  /**
2036
- * @inheritDoc
2037
- */ static get requires() {
1805
+ * @inheritDoc
1806
+ */ static get requires() {
2038
1807
  return [
2039
1808
  ClipboardPipeline
2040
1809
  ];
2041
1810
  }
2042
1811
  /**
2043
- * @inheritDoc
2044
- */ init() {
1812
+ * @inheritDoc
1813
+ */ init() {
2045
1814
  const editor = this.editor;
2046
1815
  const model = editor.model;
2047
1816
  const view = editor.editing.view;
@@ -2093,24 +1862,15 @@ const toPx = /* #__PURE__ */ toUnit('px');
2093
1862
  return Array.from(child.getAttributeKeys()).length == 0;
2094
1863
  }
2095
1864
 
2096
- /**
2097
- * The clipboard feature.
2098
- *
2099
- * Read more about the clipboard integration in the {@glink framework/deep-dive/clipboard clipboard deep-dive} guide.
2100
- *
2101
- * This is a "glue" plugin which loads the following plugins:
2102
- * * {@link module:clipboard/clipboardpipeline~ClipboardPipeline}
2103
- * * {@link module:clipboard/dragdrop~DragDrop}
2104
- * * {@link module:clipboard/pasteplaintext~PastePlainText}
2105
- */ class Clipboard extends Plugin {
1865
+ class Clipboard extends Plugin {
2106
1866
  /**
2107
- * @inheritDoc
2108
- */ static get pluginName() {
1867
+ * @inheritDoc
1868
+ */ static get pluginName() {
2109
1869
  return 'Clipboard';
2110
1870
  }
2111
1871
  /**
2112
- * @inheritDoc
2113
- */ static get requires() {
1872
+ * @inheritDoc
1873
+ */ static get requires() {
2114
1874
  return [
2115
1875
  ClipboardMarkersUtils,
2116
1876
  ClipboardPipeline,
@@ -2119,8 +1879,8 @@ const toPx = /* #__PURE__ */ toUnit('px');
2119
1879
  ];
2120
1880
  }
2121
1881
  /**
2122
- * @inheritDoc
2123
- */ init() {
1882
+ * @inheritDoc
1883
+ */ init() {
2124
1884
  const editor = this.editor;
2125
1885
  const t = this.editor.t;
2126
1886
  // Add the information about the keystrokes to the accessibility database.