@ckeditor/ckeditor5-clipboard
Advanced tools
Comparing version 26.0.0 to 27.0.0
{ | ||
"name": "@ckeditor/ckeditor5-clipboard", | ||
"version": "26.0.0", | ||
"version": "27.0.0", | ||
"description": "Clipboard integration for CKEditor 5.", | ||
@@ -15,12 +15,26 @@ "keywords": [ | ||
"dependencies": { | ||
"@ckeditor/ckeditor5-core": "^26.0.0", | ||
"@ckeditor/ckeditor5-engine": "^26.0.0", | ||
"@ckeditor/ckeditor5-utils": "^26.0.0" | ||
"@ckeditor/ckeditor5-core": "^27.0.0", | ||
"@ckeditor/ckeditor5-engine": "^27.0.0", | ||
"@ckeditor/ckeditor5-utils": "^27.0.0", | ||
"@ckeditor/ckeditor5-widget": "^27.0.0", | ||
"lodash-es": "^4.17.11" | ||
}, | ||
"devDependencies": { | ||
"@ckeditor/ckeditor5-basic-styles": "^26.0.0", | ||
"@ckeditor/ckeditor5-block-quote": "^26.0.0", | ||
"@ckeditor/ckeditor5-editor-classic": "^26.0.0", | ||
"@ckeditor/ckeditor5-link": "^26.0.0", | ||
"@ckeditor/ckeditor5-paragraph": "^26.0.0" | ||
"@ckeditor/ckeditor5-alignment": "^27.0.0", | ||
"@ckeditor/ckeditor5-basic-styles": "^27.0.0", | ||
"@ckeditor/ckeditor5-block-quote": "^27.0.0", | ||
"@ckeditor/ckeditor5-cloud-services": "^27.0.0", | ||
"@ckeditor/ckeditor5-code-block": "^27.0.0", | ||
"@ckeditor/ckeditor5-easy-image": "^27.0.0", | ||
"@ckeditor/ckeditor5-editor-classic": "^27.0.0", | ||
"@ckeditor/ckeditor5-enter": "^27.0.0", | ||
"@ckeditor/ckeditor5-horizontal-line": "^27.0.0", | ||
"@ckeditor/ckeditor5-image": "^27.0.0", | ||
"@ckeditor/ckeditor5-link": "^27.0.0", | ||
"@ckeditor/ckeditor5-page-break": "^27.0.0", | ||
"@ckeditor/ckeditor5-paragraph": "^27.0.0", | ||
"@ckeditor/ckeditor5-paste-from-office": "^27.0.0", | ||
"@ckeditor/ckeditor5-remove-format": "^27.0.0", | ||
"@ckeditor/ckeditor5-table": "^27.0.0", | ||
"@ckeditor/ckeditor5-typing": "^27.0.0" | ||
}, | ||
@@ -27,0 +41,0 @@ "engines": { |
@@ -11,19 +11,17 @@ /** | ||
import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; | ||
import ClipboardPipeline from './clipboardpipeline'; | ||
import DragDrop from './dragdrop'; | ||
import PastePlainText from './pasteplaintext'; | ||
import ClipboardObserver from './clipboardobserver'; | ||
import plainTextToHtml from './utils/plaintexttohtml'; | ||
import normalizeClipboardHtml from './utils/normalizeclipboarddata'; | ||
import viewToPlainText from './utils/viewtoplaintext.js'; | ||
import EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo'; | ||
/** | ||
* The clipboard feature. It is responsible for intercepting the `paste` and `drop` events and | ||
* passing the pasted content through the clipboard pipeline in order to insert it into the editor's content. | ||
* It also handles the `cut` and `copy` events to fill the native clipboard with serialized editor's data. | ||
* The clipboard feature. | ||
* | ||
* Read more about the clipboard integration in {@glink framework/guides/deep-dive/clipboard "Clipboard" deep dive} guide. | ||
* | ||
* This is a "glue" plugin which loads the following plugins: | ||
* * {@link module:clipboard/clipboardpipeline~ClipboardPipeline} | ||
* * {@link module:clipboard/dragdrop~DragDrop} | ||
* * {@link module:clipboard/pasteplaintext~PastePlainText} | ||
* | ||
* @extends module:core/plugin~Plugin | ||
@@ -43,213 +41,4 @@ */ | ||
static get requires() { | ||
return [ PastePlainText ]; | ||
return [ ClipboardPipeline, DragDrop, PastePlainText ]; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
init() { | ||
const editor = this.editor; | ||
const modelDocument = editor.model.document; | ||
const view = editor.editing.view; | ||
const viewDocument = view.document; | ||
view.addObserver( ClipboardObserver ); | ||
// The clipboard paste pipeline. | ||
// Pasting and dropping is disabled when editor is read-only. | ||
// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26. | ||
this.listenTo( viewDocument, 'clipboardInput', evt => { | ||
if ( editor.isReadOnly ) { | ||
evt.stop(); | ||
} | ||
}, { priority: 'highest' } ); | ||
this.listenTo( viewDocument, 'clipboardInput', ( evt, data ) => { | ||
const dataTransfer = data.dataTransfer; | ||
let content = ''; | ||
if ( dataTransfer.getData( 'text/html' ) ) { | ||
content = normalizeClipboardHtml( dataTransfer.getData( 'text/html' ) ); | ||
} else if ( dataTransfer.getData( 'text/plain' ) ) { | ||
content = plainTextToHtml( dataTransfer.getData( 'text/plain' ) ); | ||
} | ||
content = this.editor.data.htmlProcessor.toView( content ); | ||
const eventInfo = new EventInfo( this, 'inputTransformation' ); | ||
this.fire( eventInfo, { | ||
content, | ||
dataTransfer, | ||
asPlainText: data.asPlainText | ||
} ); | ||
// If CKEditor handled the input, do not bubble the original event any further. | ||
// This helps external integrations recognize that fact and act accordingly. | ||
// https://github.com/ckeditor/ckeditor5-upload/issues/92 | ||
if ( eventInfo.stop.called ) { | ||
evt.stop(); | ||
} | ||
view.scrollToTheSelection(); | ||
}, { priority: 'low' } ); | ||
this.listenTo( this, 'inputTransformation', ( evt, data ) => { | ||
if ( !data.content.isEmpty ) { | ||
const dataController = this.editor.data; | ||
const model = this.editor.model; | ||
// Convert the pasted content to a model document fragment. | ||
// The conversion is contextual, but in this case we need an "all allowed" context | ||
// and for that we use the $clipboardHolder item. | ||
const modelFragment = dataController.toModel( data.content, '$clipboardHolder' ); | ||
if ( modelFragment.childCount == 0 ) { | ||
return; | ||
} | ||
model.change( writer => { | ||
const selection = model.document.selection; | ||
// Plain text can be determined based on event flag (#7799) or auto-detection (#1006). If detected, | ||
// preserve selection attributes on pasted items. | ||
if ( data.asPlainText || isPlainTextFragment( modelFragment, model.schema ) ) { | ||
// Formatting attributes should be preserved. | ||
const textAttributes = Array.from( selection.getAttributes() ) | ||
.filter( ( [ key ] ) => model.schema.getAttributeProperties( key ).isFormatting ); | ||
if ( !selection.isCollapsed ) { | ||
model.deleteContent( selection, { doNotAutoparagraph: true } ); | ||
} | ||
// Also preserve other attributes if they survived the content deletion (because they were not fully selected). | ||
// For example linkHref is not a formatting attribute but it should be preserved if pasted text was in the middle | ||
// of a link. | ||
textAttributes.push( ...selection.getAttributes() ); | ||
const range = writer.createRangeIn( modelFragment ); | ||
for ( const item of range.getItems() ) { | ||
if ( item.is( '$text' ) || item.is( '$textProxy' ) ) { | ||
writer.setAttributes( textAttributes, item ); | ||
} | ||
} | ||
} | ||
model.insertContent( modelFragment ); | ||
} ); | ||
evt.stop(); | ||
} | ||
}, { priority: 'low' } ); | ||
// The clipboard copy/cut pipeline. | ||
function onCopyCut( evt, data ) { | ||
const dataTransfer = data.dataTransfer; | ||
data.preventDefault(); | ||
const content = editor.data.toView( editor.model.getSelectedContent( modelDocument.selection ) ); | ||
viewDocument.fire( 'clipboardOutput', { dataTransfer, content, method: evt.name } ); | ||
} | ||
this.listenTo( viewDocument, 'copy', onCopyCut, { priority: 'low' } ); | ||
this.listenTo( viewDocument, 'cut', ( evt, data ) => { | ||
// Cutting is disabled when editor is read-only. | ||
// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26. | ||
if ( editor.isReadOnly ) { | ||
data.preventDefault(); | ||
} else { | ||
onCopyCut( evt, data ); | ||
} | ||
}, { priority: 'low' } ); | ||
this.listenTo( viewDocument, 'clipboardOutput', ( evt, data ) => { | ||
if ( !data.content.isEmpty ) { | ||
data.dataTransfer.setData( 'text/html', this.editor.data.htmlProcessor.toData( data.content ) ); | ||
data.dataTransfer.setData( 'text/plain', viewToPlainText( data.content ) ); | ||
} | ||
if ( data.method == 'cut' ) { | ||
editor.model.deleteContent( modelDocument.selection ); | ||
} | ||
}, { priority: 'low' } ); | ||
} | ||
} | ||
/** | ||
* Fired with a `content` and `dataTransfer` objects. The `content` which comes from the clipboard (was pasted or dropped) | ||
* should be processed in order to be inserted into the editor. The `dataTransfer` object is available | ||
* in case the transformation functions need access to raw clipboard data. | ||
* | ||
* It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline "clipboard input pipeline"}. | ||
* | ||
* @see module:clipboard/clipboardobserver~ClipboardObserver | ||
* @see module:clipboard/clipboard~Clipboard | ||
* @event module:clipboard/clipboard~Clipboard#event:inputTransformation | ||
* @param {Object} data Event data. | ||
* @param {module:engine/view/documentfragment~DocumentFragment} data.content Event data. Content to be inserted into the editor. | ||
* It can be modified by the event listeners. Read more about the clipboard pipelines in | ||
* {@glink framework/guides/deep-dive/clipboard "Clipboard" deep dive}. | ||
* @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer Data transfer instance. | ||
* @param {Boolean} data.asPlainText If set to `true`, the content is pasted as plain text. | ||
*/ | ||
/** | ||
* Fired on {@link module:engine/view/document~Document#event:copy} and {@link module:engine/view/document~Document#event:cut} | ||
* with a copy of selected content. The content can be processed before it ends up in the clipboard. | ||
* | ||
* It is a part of the {@glink framework/guides/deep-dive/clipboard#output-pipeline "clipboard output pipeline"}. | ||
* | ||
* @see module:clipboard/clipboardobserver~ClipboardObserver | ||
* @see module:clipboard/clipboard~Clipboard | ||
* @event module:engine/view/document~Document#event:clipboardOutput | ||
* @param {module:clipboard/clipboard~ClipboardOutputEventData} data Event data. | ||
*/ | ||
/** | ||
* The value of the {@link module:engine/view/document~Document#event:clipboardOutput} event. | ||
* | ||
* @class module:clipboard/clipboard~ClipboardOutputEventData | ||
*/ | ||
/** | ||
* Data transfer instance. | ||
* | ||
* @readonly | ||
* @member {module:clipboard/datatransfer~DataTransfer} module:clipboard/clipboard~ClipboardOutputEventData#dataTransfer | ||
*/ | ||
/** | ||
* Content to be put into the clipboard. It can be modified by the event listeners. | ||
* Read more about the clipboard pipelines in {@glink framework/guides/deep-dive/clipboard "Clipboard" deep dive}. | ||
* | ||
* @member {module:engine/view/documentfragment~DocumentFragment} module:clipboard/clipboard~ClipboardOutputEventData#content | ||
*/ | ||
/** | ||
* Whether the event was triggered by a copy or cut operation. | ||
* | ||
* @member {'copy'|'cut'} module:clipboard/clipboard~ClipboardOutputEventData#method | ||
*/ | ||
// Returns true if specified `documentFragment` represents a plain text. | ||
// | ||
// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment | ||
// @param {module:engine/model/schema~Schema} schema | ||
// @returns {Boolean} | ||
function isPlainTextFragment( documentFragment, schema ) { | ||
if ( documentFragment.childCount > 1 ) { | ||
return false; | ||
} | ||
const child = documentFragment.getChild( 0 ); | ||
if ( schema.isObject( child ) ) { | ||
return false; | ||
} | ||
return [ ...child.getAttributeKeys() ].length == 0; | ||
} |
@@ -19,12 +19,17 @@ /** | ||
* | ||
* * {@link module:engine/view/document~Document#event:clipboardInput} | ||
* * {@link module:engine/view/document~Document#event:dragover} | ||
* * {@link module:engine/view/document~Document#event:drop} | ||
* * {@link module:engine/view/document~Document#event:paste} | ||
* * {@link module:engine/view/document~Document#event:copy} | ||
* * {@link module:engine/view/document~Document#event:cut} | ||
* * {@link module:engine/view/document~Document#event:clipboardInput}, | ||
* * {@link module:engine/view/document~Document#event:paste}, | ||
* * {@link module:engine/view/document~Document#event:copy}, | ||
* * {@link module:engine/view/document~Document#event:cut}, | ||
* * {@link module:engine/view/document~Document#event:drop}, | ||
* * {@link module:engine/view/document~Document#event:dragover}, | ||
* * {@link module:engine/view/document~Document#event:dragging}, | ||
* * {@link module:engine/view/document~Document#event:dragstart}, | ||
* * {@link module:engine/view/document~Document#event:dragend}, | ||
* * {@link module:engine/view/document~Document#event:dragenter}, | ||
* * {@link module:engine/view/document~Document#event:dragleave}. | ||
* | ||
* Note that this observer is not available by default (it is not added by the engine). | ||
* To make it available, it needs to be added to {@link module:engine/view/document~Document} by | ||
* the {@link module:engine/view/view~View#addObserver `View#addObserver()`} method. You can also load the | ||
* **Note**: This observer is not available by default (ckeditor5-engine does not add it on its own). | ||
* To make it available, it needs to be added to {@link module:engine/view/document~Document} by using | ||
* the {@link module:engine/view/view~View#addObserver `View#addObserver()`} method. Alternatively, you can load the | ||
* {@link module:clipboard/clipboard~Clipboard} plugin which adds this observer automatically (because it uses it). | ||
@@ -40,25 +45,29 @@ * | ||
this.domEventType = [ 'paste', 'copy', 'cut', 'drop', 'dragover' ]; | ||
this.domEventType = [ 'paste', 'copy', 'cut', 'drop', 'dragover', 'dragstart', 'dragend', 'dragenter', 'dragleave' ]; | ||
this.listenTo( viewDocument, 'paste', handleInput, { priority: 'low' } ); | ||
this.listenTo( viewDocument, 'drop', handleInput, { priority: 'low' } ); | ||
this.listenTo( viewDocument, 'paste', handleInput( 'clipboardInput' ), { priority: 'low' } ); | ||
this.listenTo( viewDocument, 'drop', handleInput( 'clipboardInput' ), { priority: 'low' } ); | ||
this.listenTo( viewDocument, 'dragover', handleInput( 'dragging' ), { priority: 'low' } ); | ||
function handleInput( evt, data ) { | ||
data.preventDefault(); | ||
function handleInput( type ) { | ||
return ( evt, data ) => { | ||
data.preventDefault(); | ||
const targetRanges = data.dropRange ? [ data.dropRange ] : Array.from( viewDocument.selection.getRanges() ); | ||
const targetRanges = data.dropRange ? [ data.dropRange ] : null; | ||
const eventInfo = new EventInfo( viewDocument, type ); | ||
const eventInfo = new EventInfo( viewDocument, 'clipboardInput' ); | ||
viewDocument.fire( eventInfo, { | ||
dataTransfer: data.dataTransfer, | ||
method: evt.name, | ||
targetRanges, | ||
target: data.target | ||
} ); | ||
viewDocument.fire( eventInfo, { | ||
dataTransfer: data.dataTransfer, | ||
targetRanges | ||
} ); | ||
// If CKEditor handled the input, do not bubble the original event any further. | ||
// This helps external integrations recognize that fact and act accordingly. | ||
// https://github.com/ckeditor/ckeditor5-upload/issues/92 | ||
if ( eventInfo.stop.called ) { | ||
data.stopPropagation(); | ||
} | ||
// If CKEditor handled the input, do not bubble the original event any further. | ||
// This helps external integrations recognize that fact and act accordingly. | ||
// https://github.com/ckeditor/ckeditor5-upload/issues/92 | ||
if ( eventInfo.stop.called ) { | ||
data.stopPropagation(); | ||
} | ||
}; | ||
} | ||
@@ -72,3 +81,3 @@ } | ||
if ( domEvent.type == 'drop' ) { | ||
if ( domEvent.type == 'drop' || domEvent.type == 'dragover' ) { | ||
evtData.dropRange = getDropViewRange( this.view, domEvent ); | ||
@@ -100,5 +109,5 @@ } | ||
return view.domConverter.domRangeToView( domRange ); | ||
} else { | ||
return view.document.selection.getFirstRange(); | ||
} | ||
return null; | ||
} | ||
@@ -111,8 +120,9 @@ | ||
* | ||
* Fired with a `dataTransfer` which comes from the clipboard and whose content should be processed | ||
* This event carries a `dataTransfer` object which comes from the clipboard and which content should be processed | ||
* and inserted into the editor. | ||
* | ||
* Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method. | ||
* This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually. | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
@@ -124,5 +134,7 @@ * @see module:clipboard/clipboardobserver~ClipboardObserver | ||
* @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance. | ||
* @param {'paste'|'drop'} method Whether the event was triggered by a paste or drop operation. | ||
* @param {module:engine/view/element~Element} target The tree view element representing the target. | ||
* @param {Array.<module:engine/view/range~Range>} data.targetRanges Ranges which are the target of the operation | ||
* (usually – into which the content should be inserted). | ||
* If clipboard input was triggered by a paste operation, then these are the selection ranges. If by a drop operation, | ||
* If the clipboard input was triggered by a paste operation, then this property is not set. If by a drop operation, | ||
* then it is the drop position (which can be different than the selection at the moment of drop). | ||
@@ -132,9 +144,10 @@ */ | ||
/** | ||
* Fired when the user drags the content over one of the editables. | ||
* Fired when the user drags the content over one of the editing roots of the editor. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method. | ||
* This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually. | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
@@ -147,9 +160,10 @@ * @see module:engine/view/document~Document#event:clipboardInput | ||
/** | ||
* Fired when the user dropped the content into one of the editables. | ||
* Fired when the user dropped the content into one of the editing roots of the editor. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method. | ||
* This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually. | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
@@ -163,9 +177,10 @@ * @see module:engine/view/document~Document#event:clipboardInput | ||
/** | ||
* Fired when the user pasted the content into one of the editables. | ||
* Fired when the user pasted the content into one of the editing roots of the editor. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method. | ||
* This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually. | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
@@ -178,9 +193,10 @@ * @see module:engine/view/document~Document#event:clipboardInput | ||
/** | ||
* Fired when the user copied the content from one of the editables. | ||
* Fired when the user copied the content from one of the editing roots of the editor. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method. | ||
* This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually. | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
@@ -193,9 +209,10 @@ * @see module:clipboard/clipboardobserver~ClipboardObserver | ||
/** | ||
* Fired when the user cut the content from one of the editables. | ||
* Fired when the user cut the content from one of the editing roots of the editor. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method. | ||
* This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually. | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
@@ -223,1 +240,85 @@ * @see module:clipboard/clipboardobserver~ClipboardObserver | ||
*/ | ||
/** | ||
* Fired as a continuation of the {@link #event:dragover} event. | ||
* | ||
* It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline "clipboard input pipeline"}. | ||
* | ||
* This event carries a `dataTransfer` object which comes from the clipboard and which content should be processed | ||
* and inserted into the editor. | ||
* | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
* @see module:clipboard/clipboardobserver~ClipboardObserver | ||
* @see module:clipboard/clipboard~Clipboard | ||
* @event module:engine/view/document~Document#event:dragging | ||
* @param {Object} data Event data. | ||
* @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance. | ||
* @param {module:engine/view/element~Element} target The tree view element representing the target. | ||
* @param {Array.<module:engine/view/range~Range>} data.targetRanges Ranges which are the target of the operation | ||
* (usually – into which the content should be inserted). | ||
* It is the drop position (which can be different than the selection at the moment of drop). | ||
*/ | ||
/** | ||
* Fired when the user starts dragging the content in one of the editing roots of the editor. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
* @see module:engine/view/document~Document#event:clipboardInput | ||
* @event module:engine/view/document~Document#event:dragstart | ||
* @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data. | ||
*/ | ||
/** | ||
* Fired when the user ended dragging the content. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
* @see module:engine/view/document~Document#event:clipboardInput | ||
* @event module:engine/view/document~Document#event:dragend | ||
* @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data. | ||
*/ | ||
/** | ||
* Fired when the user drags the content into one of the editing roots of the editor. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
* @see module:engine/view/document~Document#event:clipboardInput | ||
* @event module:engine/view/document~Document#event:dragenter | ||
* @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data. | ||
*/ | ||
/** | ||
* Fired when the user drags the content out of one of the editing roots of the editor. | ||
* | ||
* Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}. | ||
* | ||
* **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver} | ||
* needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver} | ||
* method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded, | ||
* the observer must be added manually. | ||
* | ||
* @see module:engine/view/document~Document#event:clipboardInput | ||
* @event module:engine/view/document~Document#event:dragleave | ||
* @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data. | ||
*/ |
@@ -62,2 +62,37 @@ /** | ||
} | ||
/** | ||
* The effect that is allowed for a drag operation. | ||
* | ||
* @param {String} value | ||
*/ | ||
set effectAllowed( value ) { | ||
this._native.effectAllowed = value; | ||
} | ||
get effectAllowed() { | ||
return this._native.effectAllowed; | ||
} | ||
/** | ||
* The actual drop effect. | ||
* | ||
* @param {String} value | ||
*/ | ||
set dropEffect( value ) { | ||
this._native.dropEffect = value; | ||
} | ||
get dropEffect() { | ||
return this._native.dropEffect; | ||
} | ||
/** | ||
* Whether dragging operation was canceled. | ||
* | ||
* @returns {Boolean} | ||
*/ | ||
get isCanceled() { | ||
return this._native.dropEffect == 'none' || !!this._native.mozUserCancelled; | ||
} | ||
} | ||
@@ -64,0 +99,0 @@ |
@@ -11,3 +11,4 @@ /** | ||
export { default as Clipboard } from './clipboard'; | ||
export { default as ClipboardPipeline } from './clipboardpipeline'; | ||
export { default as DragDrop } from './dragdrop'; | ||
export { default as PastePlainText } from './pasteplaintext'; | ||
@@ -7,3 +7,3 @@ /** | ||
/** | ||
* @module clipboard/clipboard | ||
* @module clipboard/pasteplaintext | ||
*/ | ||
@@ -14,2 +14,3 @@ | ||
import ClipboardObserver from './clipboardobserver'; | ||
import ClipboardPipeline from './clipboardpipeline'; | ||
@@ -34,5 +35,16 @@ /** | ||
*/ | ||
static get requires() { | ||
return [ ClipboardPipeline ]; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
init() { | ||
const view = this.editor.editing.view; | ||
const editor = this.editor; | ||
const model = editor.model; | ||
const view = editor.editing.view; | ||
const viewDocument = view.document; | ||
const selection = model.document.selection; | ||
let shiftPressed = false; | ||
@@ -46,8 +58,52 @@ | ||
this.listenTo( viewDocument, 'clipboardInput', ( evt, data ) => { | ||
if ( shiftPressed ) { | ||
data.asPlainText = true; | ||
editor.plugins.get( ClipboardPipeline ).on( 'contentInsertion', ( evt, data ) => { | ||
// Plain text can be determined based on event flag (#7799) or auto-detection (#1006). If detected, | ||
// preserve selection attributes on pasted items. | ||
if ( !shiftPressed && !isPlainTextFragment( data.content, model.schema ) ) { | ||
return; | ||
} | ||
}, { priority: 'high' } ); | ||
model.change( writer => { | ||
// Formatting attributes should be preserved. | ||
const textAttributes = Array.from( selection.getAttributes() ) | ||
.filter( ( [ key ] ) => model.schema.getAttributeProperties( key ).isFormatting ); | ||
if ( !selection.isCollapsed ) { | ||
model.deleteContent( selection, { doNotAutoparagraph: true } ); | ||
} | ||
// Also preserve other attributes if they survived the content deletion (because they were not fully selected). | ||
// For example linkHref is not a formatting attribute but it should be preserved if pasted text was in the middle | ||
// of a link. | ||
textAttributes.push( ...selection.getAttributes() ); | ||
const range = writer.createRangeIn( data.content ); | ||
for ( const item of range.getItems() ) { | ||
if ( item.is( '$textProxy' ) ) { | ||
writer.setAttributes( textAttributes, item ); | ||
} | ||
} | ||
} ); | ||
} ); | ||
} | ||
} | ||
// Returns true if specified `documentFragment` represents a plain text. | ||
// | ||
// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment | ||
// @param {module:engine/model/schema~Schema} schema | ||
// @returns {Boolean} | ||
function isPlainTextFragment( documentFragment, schema ) { | ||
if ( documentFragment.childCount > 1 ) { | ||
return false; | ||
} | ||
const child = documentFragment.getChild( 0 ); | ||
if ( schema.isObject( child ) ) { | ||
return false; | ||
} | ||
return [ ...child.getAttributeKeys() ].length == 0; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
87367
15
1685
5
17
1
+ Addedlodash-es@^4.17.11
+ Added@ckeditor/ckeditor5-clipboard@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-core@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-engine@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-enter@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-paragraph@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-select-all@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-typing@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-ui@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-undo@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-upload@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-utils@27.1.0(transitive)
+ Added@ckeditor/ckeditor5-widget@27.1.0(transitive)
+ Addedckeditor5@27.1.0(transitive)
- Removed@ckeditor/ckeditor5-core@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-engine@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-enter@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-paragraph@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-select-all@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-typing@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-ui@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-undo@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-upload@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-utils@26.0.0(transitive)
- Removed@ckeditor/ckeditor5-widget@26.0.0(transitive)
- Removedckeditor5@26.0.0(transitive)