@ckeditor/ckeditor5-clipboard 39.0.2 → 40.1.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/LICENSE.md +3 -3
- package/package.json +6 -6
- package/src/augmentation.d.ts +1 -2
- package/src/clipboardpipeline.d.ts +40 -1
- package/src/clipboardpipeline.js +28 -7
- package/src/dragdrop.d.ts +22 -20
- package/src/dragdrop.js +180 -258
- package/src/dragdropblocktoolbar.d.ts +1 -1
- package/src/dragdropblocktoolbar.js +13 -6
- package/src/dragdroptarget.d.ts +3 -3
- package/src/dragdroptarget.js +30 -19
- package/src/index.d.ts +1 -2
- package/src/index.js +0 -1
- package/src/utils/plaintexttohtml.js +2 -0
- package/src/utils/viewtoplaintext.js +48 -31
- package/src/dragdropexperimental.d.ts +0 -101
- package/src/dragdropexperimental.js +0 -522
package/src/dragdroptarget.d.ts
CHANGED
|
@@ -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
|
*
|
package/src/dragdroptarget.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @module clipboard/dragdroptarget
|
|
7
7
|
*/
|
|
8
|
-
/* istanbul ignore file -- @preserve */
|
|
9
8
|
import { Plugin } from '@ckeditor/ckeditor5-core';
|
|
10
9
|
import { global, Rect, DomEmitterMixin, delay, ResizeObserver } from '@ckeditor/ckeditor5-utils';
|
|
11
10
|
import LineView from './lineview';
|
|
@@ -79,21 +78,26 @@ export default class DragDropTarget extends Plugin {
|
|
|
79
78
|
*
|
|
80
79
|
* @internal
|
|
81
80
|
*/
|
|
82
|
-
updateDropMarker(targetViewElement, targetViewRanges, clientX, clientY, blockMode) {
|
|
81
|
+
updateDropMarker(targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
|
|
83
82
|
this.removeDropMarkerDelayed.cancel();
|
|
84
|
-
const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode);
|
|
85
|
-
/* istanbul ignore
|
|
86
|
-
if (targetRange) {
|
|
87
|
-
|
|
83
|
+
const targetRange = findDropTargetRange(this.editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange);
|
|
84
|
+
/* istanbul ignore next -- @preserve */
|
|
85
|
+
if (!targetRange) {
|
|
86
|
+
return;
|
|
88
87
|
}
|
|
88
|
+
if (draggedRange && draggedRange.containsRange(targetRange)) {
|
|
89
|
+
// Target range is inside the dragged range.
|
|
90
|
+
return this.removeDropMarker();
|
|
91
|
+
}
|
|
92
|
+
this._updateDropMarkerThrottled(targetRange);
|
|
89
93
|
}
|
|
90
94
|
/**
|
|
91
95
|
* Finds the final drop target range.
|
|
92
96
|
*
|
|
93
97
|
* @internal
|
|
94
98
|
*/
|
|
95
|
-
getFinalDropRange(targetViewElement, targetViewRanges, clientX, clientY, blockMode) {
|
|
96
|
-
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);
|
|
97
101
|
// The dragging markers must be removed after searching for the target range because sometimes
|
|
98
102
|
// the target lands on the marker itself.
|
|
99
103
|
this.removeDropMarker();
|
|
@@ -247,7 +251,7 @@ export default class DragDropTarget extends Plugin {
|
|
|
247
251
|
/**
|
|
248
252
|
* Returns fixed selection range for given position and target element.
|
|
249
253
|
*/
|
|
250
|
-
function findDropTargetRange(editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode) {
|
|
254
|
+
function findDropTargetRange(editor, targetViewElement, targetViewRanges, clientX, clientY, blockMode, draggedRange) {
|
|
251
255
|
const model = editor.model;
|
|
252
256
|
const mapper = editor.editing.mapper;
|
|
253
257
|
const targetModelElement = getClosestMappedModelElement(editor, targetViewElement);
|
|
@@ -255,15 +259,20 @@ function findDropTargetRange(editor, targetViewElement, targetViewRanges, client
|
|
|
255
259
|
while (modelElement) {
|
|
256
260
|
if (!blockMode) {
|
|
257
261
|
if (model.schema.checkChild(modelElement, '$text')) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
+
}
|
|
267
276
|
}
|
|
268
277
|
}
|
|
269
278
|
}
|
|
@@ -279,6 +288,9 @@ function findDropTargetRange(editor, targetViewElement, targetViewRanges, client
|
|
|
279
288
|
.filter((node) => node.is('element') && !isFloatingElement(editor, node));
|
|
280
289
|
let startIndex = 0;
|
|
281
290
|
let endIndex = childNodes.length;
|
|
291
|
+
if (endIndex == 0) {
|
|
292
|
+
return model.createRange(model.createPositionAt(modelElement, 'end'));
|
|
293
|
+
}
|
|
282
294
|
while (startIndex < endIndex - 1) {
|
|
283
295
|
const middleIndex = Math.floor((startIndex + endIndex) / 2);
|
|
284
296
|
const side = findElementSide(editor, childNodes[middleIndex], clientX, clientY);
|
|
@@ -293,7 +305,6 @@ function findDropTargetRange(editor, targetViewElement, targetViewRanges, client
|
|
|
293
305
|
}
|
|
294
306
|
modelElement = modelElement.parent;
|
|
295
307
|
}
|
|
296
|
-
console.warn('none:', targetModelElement.name);
|
|
297
308
|
return null;
|
|
298
309
|
}
|
|
299
310
|
/**
|
package/src/index.d.ts
CHANGED
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
* @module clipboard
|
|
7
7
|
*/
|
|
8
8
|
export { default as Clipboard } from './clipboard';
|
|
9
|
-
export { default as ClipboardPipeline, type ClipboardContentInsertionEvent, type ClipboardInputTransformationEvent, type ClipboardInputTransformationData, type ViewDocumentClipboardOutputEvent } from './clipboardpipeline';
|
|
9
|
+
export { default as ClipboardPipeline, type ClipboardContentInsertionEvent, type ClipboardInputTransformationEvent, type ClipboardInputTransformationData, type ClipboardOutputTransformationEvent, type ClipboardOutputTransformationData, type ViewDocumentClipboardOutputEvent } from './clipboardpipeline';
|
|
10
10
|
export type { ClipboardEventData } from './clipboardobserver';
|
|
11
11
|
export { default as DragDrop } from './dragdrop';
|
|
12
12
|
export { default as PastePlainText } from './pasteplaintext';
|
|
13
|
-
export { default as DragDropExperimental } from './dragdropexperimental';
|
|
14
13
|
export { default as DragDropTarget } from './dragdroptarget';
|
|
15
14
|
export { default as DragDropBlockToolbar } from './dragdropblocktoolbar';
|
|
16
15
|
export type { ViewDocumentClipboardInputEvent, ViewDocumentCopyEvent, ViewDocumentCutEvent } from './clipboardobserver';
|
package/src/index.js
CHANGED
|
@@ -9,7 +9,6 @@ export { default as Clipboard } from './clipboard';
|
|
|
9
9
|
export { default as ClipboardPipeline } from './clipboardpipeline';
|
|
10
10
|
export { default as DragDrop } from './dragdrop';
|
|
11
11
|
export { default as PastePlainText } from './pasteplaintext';
|
|
12
|
-
export { default as DragDropExperimental } from './dragdropexperimental';
|
|
13
12
|
export { default as DragDropTarget } from './dragdroptarget';
|
|
14
13
|
export { default as DragDropBlockToolbar } from './dragdropblocktoolbar';
|
|
15
14
|
import './augmentation';
|
|
@@ -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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
+
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* @module clipboard/dragdropexperimental
|
|
7
|
-
*/
|
|
8
|
-
import { Plugin } from '@ckeditor/ckeditor5-core';
|
|
9
|
-
import { Widget } from '@ckeditor/ckeditor5-widget';
|
|
10
|
-
import ClipboardPipeline from './clipboardpipeline';
|
|
11
|
-
import DragDropTarget from './dragdroptarget';
|
|
12
|
-
import '../theme/clipboard.css';
|
|
13
|
-
/**
|
|
14
|
-
* The drag and drop feature. It works on top of the {@link module:clipboard/clipboardpipeline~ClipboardPipeline}.
|
|
15
|
-
*
|
|
16
|
-
* Read more about the clipboard integration in the {@glink framework/deep-dive/clipboard clipboard deep-dive} guide.
|
|
17
|
-
*
|
|
18
|
-
* @internal
|
|
19
|
-
*/
|
|
20
|
-
export default class DragDropExperimental extends Plugin {
|
|
21
|
-
/**
|
|
22
|
-
* The live range over the original content that is being dragged.
|
|
23
|
-
*/
|
|
24
|
-
private _draggedRange;
|
|
25
|
-
/**
|
|
26
|
-
* The UID of current dragging that is used to verify if the drop started in the same editor as the drag start.
|
|
27
|
-
*
|
|
28
|
-
* **Note**: This is a workaround for broken 'dragend' events (they are not fired if the source text node got removed).
|
|
29
|
-
*/
|
|
30
|
-
private _draggingUid;
|
|
31
|
-
/**
|
|
32
|
-
* The reference to the model element that currently has a `draggable` attribute set (it is set while dragging).
|
|
33
|
-
*/
|
|
34
|
-
private _draggableElement;
|
|
35
|
-
/**
|
|
36
|
-
* A delayed callback removing draggable attributes.
|
|
37
|
-
*/
|
|
38
|
-
private _clearDraggableAttributesDelayed;
|
|
39
|
-
/**
|
|
40
|
-
* Whether the dragged content can be dropped only in block context.
|
|
41
|
-
*/
|
|
42
|
-
private _blockMode;
|
|
43
|
-
/**
|
|
44
|
-
* DOM Emitter.
|
|
45
|
-
*/
|
|
46
|
-
private _domEmitter;
|
|
47
|
-
/**
|
|
48
|
-
* The DOM element used to generate dragged preview image.
|
|
49
|
-
*/
|
|
50
|
-
private _previewContainer?;
|
|
51
|
-
/**
|
|
52
|
-
* @inheritDoc
|
|
53
|
-
*/
|
|
54
|
-
static get pluginName(): "DragDropExperimental";
|
|
55
|
-
/**
|
|
56
|
-
* @inheritDoc
|
|
57
|
-
*/
|
|
58
|
-
static get requires(): readonly [typeof ClipboardPipeline, typeof Widget, typeof DragDropTarget];
|
|
59
|
-
/**
|
|
60
|
-
* @inheritDoc
|
|
61
|
-
*/
|
|
62
|
-
init(): void;
|
|
63
|
-
/**
|
|
64
|
-
* @inheritDoc
|
|
65
|
-
*/
|
|
66
|
-
destroy(): void;
|
|
67
|
-
/**
|
|
68
|
-
* Drag and drop events handling.
|
|
69
|
-
*/
|
|
70
|
-
private _setupDragging;
|
|
71
|
-
/**
|
|
72
|
-
* Integration with the `clipboardInput` event.
|
|
73
|
-
*/
|
|
74
|
-
private _setupClipboardInputIntegration;
|
|
75
|
-
/**
|
|
76
|
-
* Integration with the `contentInsertion` event of the clipboard pipeline.
|
|
77
|
-
*/
|
|
78
|
-
private _setupContentInsertionIntegration;
|
|
79
|
-
/**
|
|
80
|
-
* Adds listeners that add the `draggable` attribute to the elements while the mouse button is down so the dragging could start.
|
|
81
|
-
*/
|
|
82
|
-
private _setupDraggableAttributeHandling;
|
|
83
|
-
/**
|
|
84
|
-
* Removes the `draggable` attribute from the element that was used for dragging.
|
|
85
|
-
*/
|
|
86
|
-
private _clearDraggableAttributes;
|
|
87
|
-
/**
|
|
88
|
-
* Deletes the dragged content from its original range and clears the dragging state.
|
|
89
|
-
*
|
|
90
|
-
* @param moved Whether the move succeeded.
|
|
91
|
-
*/
|
|
92
|
-
private _finalizeDragging;
|
|
93
|
-
/**
|
|
94
|
-
* Sets the dragged source range based on event target and document selection.
|
|
95
|
-
*/
|
|
96
|
-
private _prepareDraggedRange;
|
|
97
|
-
/**
|
|
98
|
-
* Updates the dragged preview image.
|
|
99
|
-
*/
|
|
100
|
-
private _updatePreview;
|
|
101
|
-
}
|