@ckeditor/ckeditor5-clipboard 35.2.0 → 35.3.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 +32 -24
- package/src/clipboard.js +12 -17
- package/src/clipboardobserver.js +59 -89
- package/src/clipboardpipeline.js +135 -248
- package/src/dragdrop.js +572 -715
- package/src/index.js +0 -2
- package/src/pasteplaintext.js +61 -80
- package/src/utils/normalizeclipboarddata.js +12 -15
- package/src/utils/plaintexttohtml.js +21 -26
- package/src/utils/viewtoplaintext.js +36 -42
- package/src/datatransfer.js +0 -112
package/src/clipboardpipeline.js
CHANGED
|
@@ -2,20 +2,15 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
6
|
* @module clipboard/clipboardpipeline
|
|
8
7
|
*/
|
|
9
|
-
|
|
10
8
|
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
|
|
11
9
|
import EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';
|
|
12
|
-
|
|
13
10
|
import ClipboardObserver from './clipboardobserver';
|
|
14
|
-
|
|
15
11
|
import plainTextToHtml from './utils/plaintexttohtml';
|
|
16
12
|
import normalizeClipboardHtml from './utils/normalizeclipboarddata';
|
|
17
|
-
import viewToPlainText from './utils/viewtoplaintext
|
|
18
|
-
|
|
13
|
+
import viewToPlainText from './utils/viewtoplaintext';
|
|
19
14
|
// Input pipeline events overview:
|
|
20
15
|
//
|
|
21
16
|
// ┌──────────────────────┐ ┌──────────────────────┐
|
|
@@ -55,7 +50,6 @@ import viewToPlainText from './utils/viewtoplaintext.js';
|
|
|
55
50
|
// │ clipboardOutput │ and stores the results in data.dataTransfer.
|
|
56
51
|
// └──────────────────┘
|
|
57
52
|
//
|
|
58
|
-
|
|
59
53
|
/**
|
|
60
54
|
* The clipboard pipeline feature. It is responsible for intercepting the `paste` and `drop` events and
|
|
61
55
|
* passing the pasted content through a series of events in order to insert it into the editor's content.
|
|
@@ -120,245 +114,138 @@ import viewToPlainText from './utils/viewtoplaintext.js';
|
|
|
120
114
|
* @extends module:core/plugin~Plugin
|
|
121
115
|
*/
|
|
122
116
|
export default class ClipboardPipeline extends Plugin {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
data.preventDefault();
|
|
258
|
-
} else {
|
|
259
|
-
onCopyCut( evt, data );
|
|
260
|
-
}
|
|
261
|
-
}, { priority: 'low' } );
|
|
262
|
-
|
|
263
|
-
this.listenTo( viewDocument, 'clipboardOutput', ( evt, data ) => {
|
|
264
|
-
if ( !data.content.isEmpty ) {
|
|
265
|
-
data.dataTransfer.setData( 'text/html', this.editor.data.htmlProcessor.toData( data.content ) );
|
|
266
|
-
data.dataTransfer.setData( 'text/plain', viewToPlainText( data.content ) );
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if ( data.method == 'cut' ) {
|
|
270
|
-
editor.model.deleteContent( modelDocument.selection );
|
|
271
|
-
}
|
|
272
|
-
}, { priority: 'low' } );
|
|
273
|
-
}
|
|
117
|
+
/**
|
|
118
|
+
* @inheritDoc
|
|
119
|
+
*/
|
|
120
|
+
static get pluginName() {
|
|
121
|
+
return 'ClipboardPipeline';
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* @inheritDoc
|
|
125
|
+
*/
|
|
126
|
+
init() {
|
|
127
|
+
const editor = this.editor;
|
|
128
|
+
const view = editor.editing.view;
|
|
129
|
+
view.addObserver(ClipboardObserver);
|
|
130
|
+
this._setupPasteDrop();
|
|
131
|
+
this._setupCopyCut();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The clipboard paste pipeline.
|
|
135
|
+
*
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
_setupPasteDrop() {
|
|
139
|
+
const editor = this.editor;
|
|
140
|
+
const model = editor.model;
|
|
141
|
+
const view = editor.editing.view;
|
|
142
|
+
const viewDocument = view.document;
|
|
143
|
+
// Pasting and dropping is disabled when editor is in the read-only mode.
|
|
144
|
+
// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26.
|
|
145
|
+
this.listenTo(viewDocument, 'clipboardInput', evt => {
|
|
146
|
+
if (editor.isReadOnly) {
|
|
147
|
+
evt.stop();
|
|
148
|
+
}
|
|
149
|
+
}, { priority: 'highest' });
|
|
150
|
+
this.listenTo(viewDocument, 'clipboardInput', (evt, data) => {
|
|
151
|
+
const dataTransfer = data.dataTransfer;
|
|
152
|
+
let content;
|
|
153
|
+
// Some feature could already inject content in the higher priority event handler (i.e., codeBlock).
|
|
154
|
+
if (data.content) {
|
|
155
|
+
content = data.content;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
let contentData = '';
|
|
159
|
+
if (dataTransfer.getData('text/html')) {
|
|
160
|
+
contentData = normalizeClipboardHtml(dataTransfer.getData('text/html'));
|
|
161
|
+
}
|
|
162
|
+
else if (dataTransfer.getData('text/plain')) {
|
|
163
|
+
contentData = plainTextToHtml(dataTransfer.getData('text/plain'));
|
|
164
|
+
}
|
|
165
|
+
content = this.editor.data.htmlProcessor.toView(contentData);
|
|
166
|
+
}
|
|
167
|
+
const eventInfo = new EventInfo(this, 'inputTransformation');
|
|
168
|
+
this.fire(eventInfo, {
|
|
169
|
+
content,
|
|
170
|
+
dataTransfer,
|
|
171
|
+
targetRanges: data.targetRanges,
|
|
172
|
+
method: data.method
|
|
173
|
+
});
|
|
174
|
+
// If CKEditor handled the input, do not bubble the original event any further.
|
|
175
|
+
// This helps external integrations recognize this fact and act accordingly.
|
|
176
|
+
// https://github.com/ckeditor/ckeditor5-upload/issues/92
|
|
177
|
+
if (eventInfo.stop.called) {
|
|
178
|
+
evt.stop();
|
|
179
|
+
}
|
|
180
|
+
view.scrollToTheSelection();
|
|
181
|
+
}, { priority: 'low' });
|
|
182
|
+
this.listenTo(this, 'inputTransformation', (evt, data) => {
|
|
183
|
+
if (data.content.isEmpty) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const dataController = this.editor.data;
|
|
187
|
+
// Convert the pasted content into a model document fragment.
|
|
188
|
+
// The conversion is contextual, but in this case an "all allowed" context is needed
|
|
189
|
+
// and for that we use the $clipboardHolder item.
|
|
190
|
+
const modelFragment = dataController.toModel(data.content, '$clipboardHolder');
|
|
191
|
+
if (modelFragment.childCount == 0) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
evt.stop();
|
|
195
|
+
// Fire content insertion event in a single change block to allow other handlers to run in the same block
|
|
196
|
+
// without post-fixers called in between (i.e., the selection post-fixer).
|
|
197
|
+
model.change(() => {
|
|
198
|
+
this.fire('contentInsertion', {
|
|
199
|
+
content: modelFragment,
|
|
200
|
+
method: data.method,
|
|
201
|
+
dataTransfer: data.dataTransfer,
|
|
202
|
+
targetRanges: data.targetRanges
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}, { priority: 'low' });
|
|
206
|
+
this.listenTo(this, 'contentInsertion', (evt, data) => {
|
|
207
|
+
data.resultRange = model.insertContent(data.content);
|
|
208
|
+
}, { priority: 'low' });
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* The clipboard copy/cut pipeline.
|
|
212
|
+
*
|
|
213
|
+
* @private
|
|
214
|
+
*/
|
|
215
|
+
_setupCopyCut() {
|
|
216
|
+
const editor = this.editor;
|
|
217
|
+
const modelDocument = editor.model.document;
|
|
218
|
+
const view = editor.editing.view;
|
|
219
|
+
const viewDocument = view.document;
|
|
220
|
+
const onCopyCut = (evt, data) => {
|
|
221
|
+
const dataTransfer = data.dataTransfer;
|
|
222
|
+
data.preventDefault();
|
|
223
|
+
const content = editor.data.toView(editor.model.getSelectedContent(modelDocument.selection));
|
|
224
|
+
viewDocument.fire('clipboardOutput', {
|
|
225
|
+
dataTransfer,
|
|
226
|
+
content,
|
|
227
|
+
method: evt.name
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
this.listenTo(viewDocument, 'copy', onCopyCut, { priority: 'low' });
|
|
231
|
+
this.listenTo(viewDocument, 'cut', (evt, data) => {
|
|
232
|
+
// Cutting is disabled when editor is in the read-only mode.
|
|
233
|
+
// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26.
|
|
234
|
+
if (editor.isReadOnly) {
|
|
235
|
+
data.preventDefault();
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
onCopyCut(evt, data);
|
|
239
|
+
}
|
|
240
|
+
}, { priority: 'low' });
|
|
241
|
+
this.listenTo(viewDocument, 'clipboardOutput', (evt, data) => {
|
|
242
|
+
if (!data.content.isEmpty) {
|
|
243
|
+
data.dataTransfer.setData('text/html', this.editor.data.htmlProcessor.toData(data.content));
|
|
244
|
+
data.dataTransfer.setData('text/plain', viewToPlainText(data.content));
|
|
245
|
+
}
|
|
246
|
+
if (data.method == 'cut') {
|
|
247
|
+
editor.model.deleteContent(modelDocument.selection);
|
|
248
|
+
}
|
|
249
|
+
}, { priority: 'low' });
|
|
250
|
+
}
|
|
274
251
|
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Fired with the `content`, `dataTransfer`, `method`, and `targetRanges` properties:
|
|
278
|
-
*
|
|
279
|
-
* * The `content` which comes from the clipboard (it was pasted or dropped) should be processed in order to be inserted into the editor.
|
|
280
|
-
* * The `dataTransfer` object is available in case the transformation functions need access to the raw clipboard data.
|
|
281
|
-
* * The `method` indicates the original DOM event (for example `'drop'` or `'paste'`).
|
|
282
|
-
* * The `targetRanges` property is an array of view ranges (it is available only for `'drop'`).
|
|
283
|
-
*
|
|
284
|
-
* It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline clipboard input pipeline}.
|
|
285
|
-
*
|
|
286
|
-
* **Note**: You should not stop this event if you want to change the input data. You should modify the `content` property instead.
|
|
287
|
-
*
|
|
288
|
-
* @see module:clipboard/clipboardobserver~ClipboardObserver
|
|
289
|
-
* @see module:clipboard/clipboardpipeline~ClipboardPipeline
|
|
290
|
-
* @event module:clipboard/clipboardpipeline~ClipboardPipeline#event:inputTransformation
|
|
291
|
-
* @param {Object} data The event data.
|
|
292
|
-
* @param {module:engine/view/documentfragment~DocumentFragment} data.content The event data. The content to be inserted into the editor.
|
|
293
|
-
* It can be modified by event listeners. Read more about the clipboard pipelines in
|
|
294
|
-
* the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.
|
|
295
|
-
* @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance.
|
|
296
|
-
* @param {'paste'|'drop'} data.method Whether the event was triggered by a paste or drop operation.
|
|
297
|
-
* @param {Array.<module:engine/view/range~Range>} data.targetRanges The target drop ranges.
|
|
298
|
-
*/
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Fired with the `content`, `dataTransfer`, `method`, and `targetRanges` properties:
|
|
302
|
-
*
|
|
303
|
-
* * The `content` which comes from the clipboard (was pasted or dropped) should be processed in order to be inserted into the editor.
|
|
304
|
-
* * The `dataTransfer` object is available in case the transformation functions need access to the raw clipboard data.
|
|
305
|
-
* * The `method` indicates the original DOM event (for example `'drop'` or `'paste'`).
|
|
306
|
-
* * The `targetRanges` property is an array of view ranges (it is available only for `'drop'`).
|
|
307
|
-
*
|
|
308
|
-
* Event handlers can modify the content according to the final insertion position.
|
|
309
|
-
*
|
|
310
|
-
* It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline clipboard input pipeline}.
|
|
311
|
-
*
|
|
312
|
-
* **Note**: You should not stop this event if you want to change the input data. You should modify the `content` property instead.
|
|
313
|
-
*
|
|
314
|
-
* @see module:clipboard/clipboardobserver~ClipboardObserver
|
|
315
|
-
* @see module:clipboard/clipboardpipeline~ClipboardPipeline
|
|
316
|
-
* @see module:clipboard/clipboardpipeline~ClipboardPipeline#event:inputTransformation
|
|
317
|
-
* @event module:clipboard/clipboardpipeline~ClipboardPipeline#event:contentInsertion
|
|
318
|
-
* @param {Object} data The event data.
|
|
319
|
-
* @param {module:engine/model/documentfragment~DocumentFragment} data.content The event data. The content to be inserted into the editor.
|
|
320
|
-
* Read more about the clipboard pipelines in the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.
|
|
321
|
-
* @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance.
|
|
322
|
-
* @param {'paste'|'drop'} data.method Whether the event was triggered by a paste or drop operation.
|
|
323
|
-
* @param {Array.<module:engine/view/range~Range>} data.targetRanges The target drop ranges.
|
|
324
|
-
* @param {module:engine/model/range~Range} data.resultRange The result of the `model.insertContent()` call
|
|
325
|
-
* (inserted by the event handler at a low priority).
|
|
326
|
-
*/
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Fired on {@link module:engine/view/document~Document#event:copy} and {@link module:engine/view/document~Document#event:cut}
|
|
330
|
-
* with a copy of the selected content. The content can be processed before it ends up in the clipboard.
|
|
331
|
-
*
|
|
332
|
-
* It is a part of the {@glink framework/guides/deep-dive/clipboard#output-pipeline clipboard output pipeline}.
|
|
333
|
-
*
|
|
334
|
-
* @see module:clipboard/clipboardobserver~ClipboardObserver
|
|
335
|
-
* @see module:clipboard/clipboardpipeline~ClipboardPipeline
|
|
336
|
-
* @event module:engine/view/document~Document#event:clipboardOutput
|
|
337
|
-
* @param {module:clipboard/clipboardpipeline~ClipboardOutputEventData} data The event data.
|
|
338
|
-
*/
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* The value of the {@link module:engine/view/document~Document#event:clipboardOutput} event.
|
|
342
|
-
*
|
|
343
|
-
* @class module:clipboard/clipboardpipeline~ClipboardOutputEventData
|
|
344
|
-
*/
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* The data transfer instance.
|
|
348
|
-
*
|
|
349
|
-
* @readonly
|
|
350
|
-
* @member {module:clipboard/datatransfer~DataTransfer} module:clipboard/clipboardpipeline~ClipboardOutputEventData#dataTransfer
|
|
351
|
-
*/
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Content to be put into the clipboard. It can be modified by the event listeners.
|
|
355
|
-
* Read more about the clipboard pipelines in the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.
|
|
356
|
-
*
|
|
357
|
-
* @member {module:engine/view/documentfragment~DocumentFragment} module:clipboard/clipboardpipeline~ClipboardOutputEventData#content
|
|
358
|
-
*/
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Whether the event was triggered by a copy or cut operation.
|
|
362
|
-
*
|
|
363
|
-
* @member {'copy'|'cut'} module:clipboard/clipboardpipeline~ClipboardOutputEventData#method
|
|
364
|
-
*/
|