| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /**
- * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
- */
- /**
- * @module clipboard/clipboard
- */
- import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
- import ClipboardObserver from './clipboardobserver';
- import plainTextToHtml from './utils/plaintexttohtml';
- import normalizeClipboardHtml from './utils/normalizeclipboarddata';
- import viewToPlainText from './utils/viewtoplaintext.js';
- import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
- 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.
- *
- * Read more about the clipboard integration in {@glink framework/guides/deep-dive/clipboard "Clipboard" deep dive} guide.
- *
- * @extends module:core/plugin~Plugin
- */
- export default class Clipboard extends Plugin {
- /**
- * @inheritDoc
- */
- static get pluginName() {
- return 'Clipboard';
- }
- /**
- * @inheritDoc
- */
- init() {
- const editor = this.editor;
- const modelDocument = editor.model.document;
- const view = editor.editing.view;
- const viewDocument = view.document;
- /**
- * Data processor used to convert pasted HTML to a view structure.
- *
- * @private
- * @member {module:engine/dataprocessor/htmldataprocessor~HtmlDataProcessor} #_htmlDataProcessor
- */
- this._htmlDataProcessor = new HtmlDataProcessor( viewDocument );
- 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._htmlDataProcessor.toView( content );
- const eventInfo = new EventInfo( this, 'inputTransformation' );
- this.fire( eventInfo, { content, dataTransfer } );
- // 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.
- // 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.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._htmlDataProcessor.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 needs access to a 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.
- */
- /**
- * 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 copy or cut operation.
- *
- * @member {'copy'|'cut'} module:clipboard/clipboard~ClipboardOutputEventData#method
- */
|