Browse Source

Working version of auto-embeding after tiemout (500ms).

Kamil Piechaczek 7 years ago
parent
commit
478835d035
1 changed files with 65 additions and 67 deletions
  1. 65 67
      packages/ckeditor5-media-embed/src/mediaembed.js

+ 65 - 67
packages/ckeditor5-media-embed/src/mediaembed.js

@@ -7,13 +7,16 @@
  * @module media-embed/mediaembed
  */
 
-import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-
 import MediaEmbedEditing from './mediaembedediting';
 import MediaEmbedUI from './mediaembedui';
-import Widget from '@ckeditor/ckeditor5-widget/src/widget';
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
-import Enter from '@ckeditor/ckeditor5-enter/src/enter';
+import Widget from '@ckeditor/ckeditor5-widget/src/widget';
+import Range from '@ckeditor/ckeditor5-engine/src/model/range';
+import Position from '@ckeditor/ckeditor5-engine/src/model/position';
+import LivePosition from '@ckeditor/ckeditor5-engine/src/model/liveposition';
+import TreeWalker from '@ckeditor/ckeditor5-engine/src/model/treewalker';
+import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 
 const URL_REGEXP = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=]+$/;
 
@@ -32,7 +35,7 @@ export default class MediaEmbed extends Plugin {
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ MediaEmbedEditing, MediaEmbedUI, Widget, Clipboard, Enter ];
+		return [ MediaEmbedEditing, MediaEmbedUI, Widget, Clipboard ];
 	}
 
 	/**
@@ -46,30 +49,59 @@ export default class MediaEmbed extends Plugin {
 	 * @inheritDoc
 	 */
 	init() {
+		this._attachAutoEmbedingEvents();
+	}
+
+	/**
+	 * Attach events required for "auto-embeding" feature.
+	 *
+	 * @private
+	 */
+	_attachAutoEmbedingEvents() {
 		const editor = this.editor;
 		const view = editor.editing.view;
-		const viewDocument = view.document;
 		const modelDocument = editor.model.document;
 		const mediaRegistry = editor.plugins.get( MediaEmbedEditing ).mediaRegistry;
 
-		this.listenTo( viewDocument, 'enter', ( evt, data ) => {
-			data.preventDefault();
+		let leftLivePosition, rightLivePosition;
 
-			// The soft enter key is handled by the ShiftEnter plugin.
-			if ( data.isSoft ) {
-				return;
-			}
+		// We need to listen on `Clipboard#inputTransformation` because we need to save positions of selection.
+		// After pasting a content, between those position can be located a URL that should be transformed to media.
+		this.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', () => {
+			const firstRange = modelDocument.selection.getFirstRange();
+
+			leftLivePosition = LivePosition.createFromPosition( firstRange.start );
+			leftLivePosition.stickiness = 'toPrevious';
 
-			const selectionWrapper = modelDocument.selection.getFirstPosition().parent;
+			rightLivePosition = LivePosition.createFromPosition( firstRange.end );
+			rightLivePosition.stickiness = 'toNext';
+		} );
 
-			if ( !selectionWrapper || !selectionWrapper.is( 'element', 'paragraph' ) ) {
+		// Detach the live positions after pasting the content.
+		this.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', () => {
+			leftLivePosition.detach();
+			rightLivePosition.detach();
+
+			leftLivePosition = null;
+			rightLivePosition = null;
+		}, { priority: 'lowest' } );
+
+		modelDocument.on( 'change:data', () => {
+			if ( !leftLivePosition ) {
 				return;
 			}
 
+			const urlRange = new Range( leftLivePosition, rightLivePosition );
+			const walker = new TreeWalker( { boundaries: urlRange } );
+
 			let url = '';
 
-			for ( const child of selectionWrapper.getChildren() ) {
-				url += child.data;
+			for ( const node of walker ) {
+				if ( !node.type === 'text' ) {
+					return;
+				}
+
+				url += node.item.data;
 			}
 
 			// If the url does not match to universal url regexp, let's skip that.
@@ -77,60 +109,26 @@ export default class MediaEmbed extends Plugin {
 				return;
 			}
 
-			// If the url is valid from MediaEmbed plugin, let's use it.
-			if ( mediaRegistry.hasMedia( url ) ) {
-				const model = this.editor.model;
+			// If the url is valid from MediaEmbed plugin point of view, let's use it.
+			if ( !mediaRegistry.hasMedia( url ) ) {
+				return;
+			}
+
+			// `leftLivePosition` won't be available in `setTimeout` function so let's clone it.
+			const positionToInsert = Position.createFromPosition( leftLivePosition );
 
-				model.change( writer => {
-					writer.remove( selectionWrapper );
-					editor.commands.execute( 'mediaEmbed', url );
-				} );
+			global.window.setTimeout( () => {
+				editor.model.change( writer => {
+					const mediaElement = writer.createElement( 'media', { url } );
 
-				evt.stop();
-				view.scrollToTheSelection();
-			}
-		} );
+					writer.remove( urlRange );
+					writer.insert( mediaElement, positionToInsert );
+					writer.setSelection( mediaElement, 'on' );
 
-		// this.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', ( evt, data ) => {
-		// 	// We assume that single node was pasted.
-		// 	if ( data.content.childCount > 1 ) {
-		// 		return;
-		// 	}
-		//
-		// 	const firstChild = data.content.getChild( 0 );
-		//
-		// 	// If the node is not a text, skip it.
-		// 	if ( !firstChild.is( 'text' ) ) {
-		// 		return;
-		// 	}
-		//
-		// 	const url = firstChild.data;
-		//
-		// 	// If the url does not match to universal url regexp, let's skip that.
-		// 	if ( !url.match( URL_REGEXP ) ) {
-		// 		return;
-		// 	}
-		//
-		// 	// If the url is valid from MediaEmbed plugin, let's use it.
-		// 	if ( mediaRegistry.hasMedia( url ) ) {
-		// 		const model = this.editor.model;
-		// 		let textNode;
-		//
-		// 		// Insert the URL as text...
-		// 		model.change( writer => {
-		// 			textNode = writer.createText( url );
-		// 			writer.insert( textNode, modelDocument.selection.getFirstPosition() );
-		// 		} );
-		//
-		// 		// ...then replace it with <media> element. Thanks to that auto-embeding is undoable.
-		// 		model.change( writer => {
-		// 			writer.remove( textNode );
-		// 			editor.commands.execute( 'mediaEmbed', url );
-		// 		} );
-		//
-		// 		evt.stop();
-		// 	}
-		// } );
+					view.scrollToTheSelection();
+				} );
+			}, 500 );
+		} );
 	}
 }