@ckeditor/ckeditor5-clipboard 0.0.0-nightly-20231011.0 → 0.0.0-nightly-20231013.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-clipboard",
3
- "version": "0.0.0-nightly-20231011.0",
3
+ "version": "0.0.0-nightly-20231013.0",
4
4
  "description": "Clipboard integration feature for CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -12,11 +12,11 @@
12
12
  ],
13
13
  "main": "src/index.js",
14
14
  "dependencies": {
15
- "@ckeditor/ckeditor5-core": "0.0.0-nightly-20231011.0",
16
- "@ckeditor/ckeditor5-engine": "0.0.0-nightly-20231011.0",
17
- "@ckeditor/ckeditor5-ui": "0.0.0-nightly-20231011.0",
18
- "@ckeditor/ckeditor5-utils": "0.0.0-nightly-20231011.0",
19
- "@ckeditor/ckeditor5-widget": "0.0.0-nightly-20231011.0",
15
+ "@ckeditor/ckeditor5-core": "0.0.0-nightly-20231013.0",
16
+ "@ckeditor/ckeditor5-engine": "0.0.0-nightly-20231013.0",
17
+ "@ckeditor/ckeditor5-ui": "0.0.0-nightly-20231013.0",
18
+ "@ckeditor/ckeditor5-utils": "0.0.0-nightly-20231013.0",
19
+ "@ckeditor/ckeditor5-widget": "0.0.0-nightly-20231013.0",
20
20
  "lodash-es": "4.17.21"
21
21
  },
22
22
  "author": "CKSource (http://cksource.com/)",
package/src/dragdrop.js CHANGED
@@ -242,7 +242,7 @@ export default class DragDrop extends Plugin {
242
242
  return;
243
243
  }
244
244
  const { clientX, clientY } = data.domEvent;
245
- dragDropTarget.updateDropMarker(data.target, data.targetRanges, clientX, clientY, this._blockMode);
245
+ dragDropTarget.updateDropMarker(data.target, data.targetRanges, clientX, clientY, this._blockMode, this._draggedRange);
246
246
  // If this is content being dragged from another editor, moving out of current editor instance
247
247
  // is not possible until 'dragend' event case will be fixed.
248
248
  if (!this._draggedRange) {
@@ -274,7 +274,7 @@ export default class DragDrop extends Plugin {
274
274
  return;
275
275
  }
276
276
  const { clientX, clientY } = data.domEvent;
277
- const targetRange = dragDropTarget.getFinalDropRange(data.target, data.targetRanges, clientX, clientY, this._blockMode);
277
+ const targetRange = dragDropTarget.getFinalDropRange(data.target, data.targetRanges, clientX, clientY, this._blockMode, this._draggedRange);
278
278
  if (!targetRange) {
279
279
  this._finalizeDragging(false);
280
280
  evt.stop();
@@ -6,7 +6,7 @@
6
6
  * @module clipboard/dragdroptarget
7
7
  */
8
8
  import { Plugin } from '@ckeditor/ckeditor5-core';
9
- import { type Range, type ViewElement, type ViewRange } from '@ckeditor/ckeditor5-engine';
9
+ import { type Range, type LiveRange, type ViewElement, type ViewRange } from '@ckeditor/ckeditor5-engine';
10
10
  /**
11
11
  * Part of the Drag and Drop handling. Responsible for finding and displaying the drop target.
12
12
  *
@@ -56,13 +56,13 @@ export default class DragDropTarget extends Plugin {
56
56
  *
57
57
  * @internal
58
58
  */
59
- updateDropMarker(targetViewElement: ViewElement, targetViewRanges: Array<ViewRange> | null, clientX: number, clientY: number, blockMode: boolean): void;
59
+ updateDropMarker(targetViewElement: ViewElement, targetViewRanges: Array<ViewRange> | null, clientX: number, clientY: number, blockMode: boolean, draggedRange: LiveRange | null): void;
60
60
  /**
61
61
  * Finds the final drop target range.
62
62
  *
63
63
  * @internal
64
64
  */
65
- getFinalDropRange(targetViewElement: ViewElement, targetViewRanges: Array<ViewRange> | null, clientX: number, clientY: number, blockMode: boolean): Range | null;
65
+ getFinalDropRange(targetViewElement: ViewElement, targetViewRanges: Array<ViewRange> | null, clientX: number, clientY: number, blockMode: boolean, draggedRange: LiveRange | null): Range | null;
66
66
  /**
67
67
  * Removes the drop target marker.
68
68
  *
@@ -78,21 +78,26 @@ export default class DragDropTarget extends Plugin {
78
78
  *
79
79
  * @internal
80
80
  */
81
- updateDropMarker(targetViewElement, targetViewRanges, clientX, clientY, blockMode) {
81
+ updateDropMarker(targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
82
82
  this.removeDropMarkerDelayed.cancel();
83
- const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode);
84
- /* istanbul ignore else -- @preserve */
85
- if (targetRange) {
86
- this._updateDropMarkerThrottled(targetRange);
83
+ const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange);
84
+ /* istanbul ignore next -- @preserve */
85
+ if (!targetRange) {
86
+ return;
87
87
  }
88
+ if (draggedRange && draggedRange.containsRange(targetRange)) {
89
+ // Target range is inside the dragged range.
90
+ return this.removeDropMarker();
91
+ }
92
+ this._updateDropMarkerThrottled(targetRange);
88
93
  }
89
94
  /**
90
95
  * Finds the final drop target range.
91
96
  *
92
97
  * @internal
93
98
  */
94
- getFinalDropRange(targetViewElement, targetViewRanges, clientX, clientY, blockMode) {
95
- const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode);
99
+ getFinalDropRange(targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
100
+ const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange);
96
101
  // The dragging markers must be removed after searching for the target range because sometimes
97
102
  // the target lands on the marker itself.
98
103
  this.removeDropMarker();
@@ -246,7 +251,7 @@ export default class DragDropTarget extends Plugin {
246
251
  /**
247
252
  * Returns fixed selection range for given position and target element.
248
253
  */
249
- function findDropTargetRange(editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode) {
254
+ function findDropTargetRange(editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
250
255
  const model = editor.model;
251
256
  const mapper = editor.editing.mapper;
252
257
  const targetModelElement = getClosestMappedModelElement(editor, targetViewElement);
@@ -254,15 +259,20 @@ function findDropTargetRange(editor, targetViewElement, targetViewRanges, client
254
259
  while (modelElement) {
255
260
  if (!blockMode) {
256
261
  if (model.schema.checkChild(modelElement, '$text')) {
257
- const targetViewPosition = targetViewRanges ? targetViewRanges[0].start : null;
258
- const targetModelPosition = targetViewPosition ? mapper.toModelPosition(targetViewPosition) : null;
259
- if (targetModelPosition) {
260
- if (model.schema.checkChild(targetModelPosition, '$text')) {
261
- return model.createRange(targetModelPosition);
262
- }
263
- else if (targetViewPosition) {
264
- // This is the case of dropping inside a span wrapper of an inline image.
265
- return findDropTargetRangeForElement(editor, getClosestMappedModelElement(editor, targetViewPosition.parent), clientX, clientY);
262
+ if (targetViewRanges) {
263
+ const targetViewPosition = targetViewRanges[0].start;
264
+ const targetModelPosition = mapper.toModelPosition(targetViewPosition);
265
+ const canDropOnPosition = !draggedRange || Array
266
+ .from(draggedRange.getItems())
267
+ .every(item => model.schema.checkChild(targetModelPosition, item));
268
+ if (canDropOnPosition) {
269
+ if (model.schema.checkChild(targetModelPosition, '$text')) {
270
+ return model.createRange(targetModelPosition);
271
+ }
272
+ else if (targetViewPosition) {
273
+ // This is the case of dropping inside a span wrapper of an inline image.
274
+ return findDropTargetRangeForElement(editor, getClosestMappedModelElement(editor, targetViewPosition.parent), clientX, clientY);
275
+ }
266
276
  }
267
277
  }
268
278
  }
@@ -6,6 +6,7 @@
6
6
  // Most `view.ContainerElement` want to be separate by new-line, but some are creating one structure
7
7
  // together (like `<li>`) so it is better to separate them by only one "\n".
8
8
  const smallPaddingElements = ['figcaption', 'li'];
9
+ const listElements = ['ol', 'ul'];
9
10
  /**
10
11
  * Converts {@link module:engine/view/item~Item view item} and all of its children to plain text.
11
12
  *
@@ -13,38 +14,54 @@ const smallPaddingElements = ['figcaption', 'li'];
13
14
  * @returns Plain text representation of `viewItem`.
14
15
  */
15
16
  export default function viewToPlainText(viewItem) {
16
- let text = '';
17
17
  if (viewItem.is('$text') || viewItem.is('$textProxy')) {
18
- // If item is `Text` or `TextProxy` simple take its text data.
19
- text = viewItem.data;
20
- }
21
- else if (viewItem.is('element', 'img') && viewItem.hasAttribute('alt')) {
22
- // Special case for images - use alt attribute if it is provided.
23
- text = viewItem.getAttribute('alt');
24
- }
25
- else if (viewItem.is('element', 'br')) {
26
- // A soft break should be converted into a single line break (#8045).
27
- text = '\n';
28
- }
29
- else {
30
- // Other elements are document fragments, attribute elements or container elements.
31
- // They don't have their own text value, so convert their children.
32
- let prev = null;
33
- for (const child of viewItem.getChildren()) {
34
- const childText = viewToPlainText(child);
35
- // Separate container element children with one or more new-line characters.
36
- if (prev && (prev.is('containerElement') || child.is('containerElement'))) {
37
- if (smallPaddingElements.includes(prev.name) ||
38
- smallPaddingElements.includes(child.name)) {
39
- text += '\n';
40
- }
41
- else {
42
- text += '\n\n';
43
- }
44
- }
45
- text += childText;
46
- prev = child;
47
- }
18
+ return viewItem.data;
19
+ }
20
+ if (viewItem.is('element', 'img') && viewItem.hasAttribute('alt')) {
21
+ return viewItem.getAttribute('alt');
22
+ }
23
+ if (viewItem.is('element', 'br')) {
24
+ return '\n'; // Convert soft breaks to single line break (#8045).
25
+ }
26
+ /**
27
+ * Item is a document fragment, attribute element or container element. It doesn't
28
+ * have it's own text value, so we need to convert its children elements.
29
+ */
30
+ let text = '';
31
+ let prev = null;
32
+ for (const child of viewItem.getChildren()) {
33
+ text += newLinePadding(child, prev) + viewToPlainText(child);
34
+ prev = child;
48
35
  }
49
36
  return text;
50
37
  }
38
+ /**
39
+ * Returns new line padding to prefix the given elements with.
40
+ */
41
+ function newLinePadding(element, previous) {
42
+ if (!previous) {
43
+ // Don't add padding to first elements in a level.
44
+ return '';
45
+ }
46
+ if (element.is('element', 'li') && !element.isEmpty && element.getChild(0).is('containerElement')) {
47
+ // Separate document list items with empty lines.
48
+ return '\n\n';
49
+ }
50
+ if (listElements.includes(element.name) && listElements.includes(previous.name)) {
51
+ /**
52
+ * Because `<ul>` and `<ol>` are AttributeElements, two consecutive lists will not have any padding between
53
+ * them (see the `if` statement below). To fix this, we need to make an exception for this case.
54
+ */
55
+ return '\n\n';
56
+ }
57
+ if (!element.is('containerElement') && !previous.is('containerElement')) {
58
+ // Don't add padding between non-container elements.
59
+ return '';
60
+ }
61
+ if (smallPaddingElements.includes(element.name) || smallPaddingElements.includes(previous.name)) {
62
+ // Add small padding between selected container elements.
63
+ return '\n';
64
+ }
65
+ // Add empty lines between container elements.
66
+ return '\n\n';
67
+ }