|
|
@@ -39,105 +39,103 @@ export default class LinkImageEditing extends Plugin {
|
|
|
|
|
|
editor.model.schema.extend( 'image', { allowAttributes: [ 'linkHref' ] } );
|
|
|
|
|
|
- editor.conversion.for( 'upcast' ).add( this._upcastLink() );
|
|
|
- editor.conversion.for( 'downcast' ).add( this._downcastImageLink() );
|
|
|
+ editor.conversion.for( 'upcast' ).add( upcastLink() );
|
|
|
+ editor.conversion.for( 'downcast' ).add( downcastImageLink() );
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /**
|
|
|
- * Returns a converter that consumes the 'href' attribute if a link contains an image.
|
|
|
- *
|
|
|
- * @private
|
|
|
- * @returns {Function}
|
|
|
- */
|
|
|
- _upcastLink() {
|
|
|
- return dispatcher => {
|
|
|
- dispatcher.on( 'element:a', ( evt, data, conversionApi ) => {
|
|
|
- const viewLink = data.viewItem;
|
|
|
- const imageInLink = Array.from( viewLink.getChildren() ).find( child => child.name === 'img' );
|
|
|
-
|
|
|
- if ( !imageInLink ) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // There's an image inside an <a> element - we consume it so it won't be picked up by the Link plugin.
|
|
|
- const consumableAttributes = { attributes: [ 'href' ] };
|
|
|
-
|
|
|
- // Consume the `href` attribute so the default one will not convert it to $text attribute.
|
|
|
- if ( !conversionApi.consumable.consume( viewLink, consumableAttributes ) ) {
|
|
|
- // Might be consumed by something else - i.e. other converter with priority=highest - a standard check.
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const linkHref = viewLink.getAttribute( 'href' );
|
|
|
-
|
|
|
- // Missing the 'href' attribute.
|
|
|
- if ( !linkHref ) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // A full definition of the image feature.
|
|
|
- // figure > a > img: parent of the link element is an image element.
|
|
|
- let modelElement = data.modelCursor.parent;
|
|
|
-
|
|
|
- if ( !modelElement.is( 'image' ) ) {
|
|
|
- // a > img: parent of the link is not the image element. We need to convert it manually.
|
|
|
- const conversionResult = conversionApi.convertItem( imageInLink, data.modelCursor );
|
|
|
-
|
|
|
- // Set image range as conversion result.
|
|
|
- data.modelRange = conversionResult.modelRange;
|
|
|
-
|
|
|
- // Continue conversion where image conversion ends.
|
|
|
- data.modelCursor = conversionResult.modelCursor;
|
|
|
-
|
|
|
- modelElement = data.modelCursor.nodeBefore;
|
|
|
- }
|
|
|
-
|
|
|
- if ( modelElement && modelElement.is( 'image' ) ) {
|
|
|
- // Set the linkHref attribute from link element on model image element.
|
|
|
- conversionApi.writer.setAttribute( 'linkHref', linkHref, modelElement );
|
|
|
- }
|
|
|
- }, { priority: 'high' } );
|
|
|
- };
|
|
|
- }
|
|
|
+// Returns a converter that consumes the 'href' attribute if a link contains an image.
|
|
|
+//
|
|
|
+// @private
|
|
|
+// @returns {Function}
|
|
|
+//
|
|
|
+function upcastLink() {
|
|
|
+ return dispatcher => {
|
|
|
+ dispatcher.on( 'element:a', ( evt, data, conversionApi ) => {
|
|
|
+ const viewLink = data.viewItem;
|
|
|
+ const imageInLink = Array.from( viewLink.getChildren() ).find( child => child.name === 'img' );
|
|
|
+
|
|
|
+ if ( !imageInLink ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // There's an image inside an <a> element - we consume it so it won't be picked up by the Link plugin.
|
|
|
+ const consumableAttributes = { attributes: [ 'href' ] };
|
|
|
+
|
|
|
+ // Consume the `href` attribute so the default one will not convert it to $text attribute.
|
|
|
+ if ( !conversionApi.consumable.consume( viewLink, consumableAttributes ) ) {
|
|
|
+ // Might be consumed by something else - i.e. other converter with priority=highest - a standard check.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const linkHref = viewLink.getAttribute( 'href' );
|
|
|
+
|
|
|
+ // Missing the 'href' attribute.
|
|
|
+ if ( !linkHref ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // A full definition of the image feature.
|
|
|
+ // figure > a > img: parent of the link element is an image element.
|
|
|
+ let modelElement = data.modelCursor.parent;
|
|
|
+
|
|
|
+ if ( !modelElement.is( 'image' ) ) {
|
|
|
+ // a > img: parent of the link is not the image element. We need to convert it manually.
|
|
|
+ const conversionResult = conversionApi.convertItem( imageInLink, data.modelCursor );
|
|
|
+
|
|
|
+ // Set image range as conversion result.
|
|
|
+ data.modelRange = conversionResult.modelRange;
|
|
|
+
|
|
|
+ // Continue conversion where image conversion ends.
|
|
|
+ data.modelCursor = conversionResult.modelCursor;
|
|
|
+
|
|
|
+ modelElement = data.modelCursor.nodeBefore;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( modelElement && modelElement.is( 'image' ) ) {
|
|
|
+ // Set the linkHref attribute from link element on model image element.
|
|
|
+ conversionApi.writer.setAttribute( 'linkHref', linkHref, modelElement );
|
|
|
+ }
|
|
|
+ }, { priority: 'high' } );
|
|
|
+ };
|
|
|
+}
|
|
|
|
|
|
- /**
|
|
|
- * Return a converter that adds the `<a>` element to data.
|
|
|
- *
|
|
|
- * @private
|
|
|
- * @returns {Function}
|
|
|
- */
|
|
|
- _downcastImageLink() {
|
|
|
- return dispatcher => {
|
|
|
- dispatcher.on( 'attribute:linkHref:image', ( evt, data, conversionApi ) => {
|
|
|
- // The image will be already converted - so it will be present in the view.
|
|
|
- const viewFigure = conversionApi.mapper.toViewElement( data.item );
|
|
|
- const writer = conversionApi.writer;
|
|
|
-
|
|
|
- // But we need to check whether the link element exists.
|
|
|
- const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );
|
|
|
-
|
|
|
- // If so, update the attribute if it's defined or remove the entire link if the attribute is empty.
|
|
|
- if ( linkInImage ) {
|
|
|
- if ( data.attributeNewValue ) {
|
|
|
- writer.setAttribute( 'href', data.attributeNewValue, linkInImage );
|
|
|
- } else {
|
|
|
- const viewImage = Array.from( linkInImage.getChildren() ).find( child => child.name === 'img' );
|
|
|
-
|
|
|
- writer.move( writer.createRangeOn( viewImage ), writer.createPositionAt( viewFigure, 0 ) );
|
|
|
- writer.remove( linkInImage );
|
|
|
- }
|
|
|
+// Return a converter that adds the `<a>` element to data.
|
|
|
+//
|
|
|
+// @private
|
|
|
+// @returns {Function}
|
|
|
+//
|
|
|
+function downcastImageLink() {
|
|
|
+ return dispatcher => {
|
|
|
+ dispatcher.on( 'attribute:linkHref:image', ( evt, data, conversionApi ) => {
|
|
|
+ // The image will be already converted - so it will be present in the view.
|
|
|
+ const viewFigure = conversionApi.mapper.toViewElement( data.item );
|
|
|
+ const writer = conversionApi.writer;
|
|
|
+
|
|
|
+ // But we need to check whether the link element exists.
|
|
|
+ const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );
|
|
|
+
|
|
|
+ // If so, update the attribute if it's defined or remove the entire link if the attribute is empty.
|
|
|
+ if ( linkInImage ) {
|
|
|
+ if ( data.attributeNewValue ) {
|
|
|
+ writer.setAttribute( 'href', data.attributeNewValue, linkInImage );
|
|
|
} else {
|
|
|
- // But if it does not exist. Let's wrap already converted image by newly created link element.
|
|
|
- // 1. Create an empty link element.
|
|
|
- const linkElement = writer.createContainerElement( 'a', { href: data.attributeNewValue } );
|
|
|
-
|
|
|
- // 2. Insert link inside the associated image.
|
|
|
- writer.insert( writer.createPositionAt( viewFigure, 0 ), linkElement );
|
|
|
+ const viewImage = Array.from( linkInImage.getChildren() ).find( child => child.name === 'img' );
|
|
|
|
|
|
- // 3. Move the image to the link.
|
|
|
- writer.move( writer.createRangeOn( viewFigure.getChild( 1 ) ), writer.createPositionAt( linkElement, 0 ) );
|
|
|
+ writer.move( writer.createRangeOn( viewImage ), writer.createPositionAt( viewFigure, 0 ) );
|
|
|
+ writer.remove( linkInImage );
|
|
|
}
|
|
|
- } );
|
|
|
- };
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ // But if it does not exist. Let's wrap already converted image by newly created link element.
|
|
|
+ // 1. Create an empty link element.
|
|
|
+ const linkElement = writer.createContainerElement( 'a', { href: data.attributeNewValue } );
|
|
|
+
|
|
|
+ // 2. Insert link inside the associated image.
|
|
|
+ writer.insert( writer.createPositionAt( viewFigure, 0 ), linkElement );
|
|
|
+
|
|
|
+ // 3. Move the image to the link.
|
|
|
+ writer.move( writer.createRangeOn( viewFigure.getChild( 1 ) ), writer.createPositionAt( linkElement, 0 ) );
|
|
|
+ }
|
|
|
+ } );
|
|
|
+ };
|
|
|
}
|