Selaa lähdekoodia

Separate part of the logic to own class.

Mateusz Samsel 6 vuotta sitten
vanhempi
commit
8d7caa7d03

+ 20 - 31
packages/ckeditor5-link/src/linkediting.js

@@ -11,11 +11,13 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import LinkCommand from './linkcommand';
 import UnlinkCommand from './unlinkcommand';
 import { createLinkElement, ensureSafeUrl } from './utils';
+import AutomaticDispatchers from './utils/automaticdispatcher';
 import bindTwoStepCaretToAttribute from '@ckeditor/ckeditor5-engine/src/utils/bindtwostepcarettoattribute';
 import findLinkRange from './findlinkrange';
 import '../theme/link.css';
 
 const HIGHLIGHT_CLASS = 'ck-link_selected';
+const AUTO = 'automatic';
 
 /**
  * The link engine feature.
@@ -68,40 +70,27 @@ export default class LinkEditing extends Plugin {
 				}
 			} );
 
-		if ( editor.config.get( 'link.targetDecorator' ) ) {
-			const EXTERNAL_LINKS_REGEXP = /^(https?:)?\/\//;
-
-			editor.conversion.for( 'downcast' ).add( dispatcher => {
-				// Links are represented in the model as a "linkHref" attribute.
-				// Use the "low" listener priority to apply the changes after the Link feature.
-				dispatcher.on( 'attribute:linkHref', ( evt, data, conversionApi ) => {
-					if ( conversionApi.consumable.consume( data.item, 'attribute:linkHref' ) ) {
-						return;
-					}
-					const viewWriter = conversionApi.writer;
-					const viewSelection = viewWriter.document.selection;
-
-					const viewElement = viewWriter.createAttributeElement( 'a', {
-						target: '_blank'
-					}, {
-						priority: 5
-					} );
-
-					if ( !( EXTERNAL_LINKS_REGEXP.test( data.attributeNewValue ) ) ) {
-						viewWriter.unwrap( conversionApi.mapper.toViewRange( data.range ), viewElement );
-					} else {
-						if ( data.item.is( 'selection' ) ) {
-							viewWriter.wrap( viewSelection.getFirstRange(), viewElement );
-						} else {
-							viewWriter.wrap( conversionApi.mapper.toViewRange( data.range ), viewElement );
-						}
-					}
+		const automaticDispatcher = new AutomaticDispatchers();
 
-					evt.stop();
-				} );
-			}, { priority: 'low' } );
+		if ( editor.config.get( 'link.targetDecorator' ) ) {
+			automaticDispatcher.add( {
+				mode: AUTO,
+				callback: url => {
+					const EXTERNAL_LINKS_REGEXP = /^(https?:)?\/\//;
+					return EXTERNAL_LINKS_REGEXP.test( url );
+				},
+				attributes: {
+					target: '_blank',
+					rel: 'noopener noreferrer'
+				}
+			} );
 		}
 
+		const linkDecorators = editor.config.get( 'link.decorator' ) || [];
+		automaticDispatcher.add( linkDecorators.filter( item => item.mode === AUTO ) );
+
+		editor.conversion.for( 'downcast' ).add( automaticDispatcher.getCallback() );
+
 		// Create linking commands.
 		editor.commands.add( 'link', new LinkCommand( editor ) );
 		editor.commands.add( 'unlink', new UnlinkCommand( editor ) );

+ 54 - 0
packages/ckeditor5-link/src/utils/automaticdispatcher.js

@@ -0,0 +1,54 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module link/utils/automaticdispatcher
+ */
+
+export default class AutomaticDispatchers {
+	constructor() {
+		this._definitions = new Set();
+	}
+
+	add( item ) {
+		if ( Array.isArray( item ) ) {
+			item.forEach( item => this._definitions.add( item ) );
+		} else {
+			this._definitions.add( item );
+		}
+	}
+
+	getCallback() {
+		return dispatcher => {
+			dispatcher.on( 'attribute:linkHref', ( evt, data, conversionApi ) => {
+				// There is only test as this behavior decorates links and
+				// it is run before dispatcher which actually consumes this node.
+				// This allows on writing own dispatcher with highest priority,
+				// which blocks both native converter and this additional decoration.
+				if ( !conversionApi.consumable.test( data.item, 'attribute:linkHref' ) ) {
+					return;
+				}
+				const viewWriter = conversionApi.writer;
+				const viewSelection = viewWriter.document.selection;
+
+				for ( const item of this._definitions ) {
+					const viewElement = viewWriter.createAttributeElement( 'a', item.attributes, {
+						priority: 5
+					} );
+					viewWriter.setCustomProperty( 'link', true, viewElement );
+					if ( item.callback( data.attributeNewValue ) ) {
+						if ( data.item.is( 'selection' ) ) {
+							viewWriter.wrap( viewSelection.getFirstRange(), viewElement );
+						} else {
+							viewWriter.wrap( conversionApi.mapper.toViewRange( data.range ), viewElement );
+						}
+					} else {
+						viewWriter.unwrap( conversionApi.mapper.toViewRange( data.range ), viewElement );
+					}
+				}
+			}, { priority: 'high' } );
+		};
+	}
+}