浏览代码

#value and #isEnabled attributes for Link and Unlink Command work properly with images.

Kamil Piechaczek 5 年之前
父节点
当前提交
0adf7d8f0c

+ 2 - 2
packages/ckeditor5-link/package.json

@@ -13,6 +13,7 @@
     "@ckeditor/ckeditor5-core": "^19.0.1",
     "@ckeditor/ckeditor5-engine": "^19.0.1",
     "@ckeditor/ckeditor5-ui": "^19.0.1",
+    "@ckeditor/ckeditor5-utils": "^19.0.1",
     "lodash-es": "^4.17.15"
   },
   "devDependencies": {
@@ -25,8 +26,7 @@
     "@ckeditor/ckeditor5-paragraph": "^19.1.0",
     "@ckeditor/ckeditor5-theme-lark": "^19.1.0",
     "@ckeditor/ckeditor5-typing": "^19.0.1",
-    "@ckeditor/ckeditor5-undo": "^19.0.1",
-    "@ckeditor/ckeditor5-utils": "^19.0.1"
+    "@ckeditor/ckeditor5-undo": "^19.0.1"
   },
   "engines": {
     "node": ">=12.0.0",

+ 12 - 3
packages/ckeditor5-link/src/linkcommand.js

@@ -11,6 +11,7 @@ import Command from '@ckeditor/ckeditor5-core/src/command';
 import findLinkRange from './findlinkrange';
 import toMap from '@ckeditor/ckeditor5-utils/src/tomap';
 import Collection from '@ckeditor/ckeditor5-utils/src/collection';
+import first from '@ckeditor/ckeditor5-utils/src/first';
 
 /**
  * The link command. It is used by the {@link module:link/link~Link link feature}.
@@ -57,13 +58,21 @@ export default class LinkCommand extends Command {
 		const model = this.editor.model;
 		const doc = model.document;
 
-		this.value = doc.selection.getAttribute( 'linkHref' );
+		const selectedElement = first( doc.selection.getSelectedBlocks() );
+
+		// A check for the `LinkImage` plugin. If the selection contains an element, get values from the element.
+		// Currently the selection reads attributes from text nodes only. See #7429.
+		if ( selectedElement && selectedElement.name === 'image' ) {
+			this.value = selectedElement.getAttribute( 'linkHref' );
+			this.isEnabled = model.schema.checkAttribute( selectedElement, 'linkHref' );
+		} else {
+			this.value = doc.selection.getAttribute( 'linkHref' );
+			this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'linkHref' );
+		}
 
 		for ( const manualDecorator of this.manualDecorators ) {
 			manualDecorator.value = this._getDecoratorStateFromModel( manualDecorator.id );
 		}
-
-		this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'linkHref' );
 	}
 
 	/**

+ 13 - 1
packages/ckeditor5-link/src/unlinkcommand.js

@@ -9,6 +9,7 @@
 
 import Command from '@ckeditor/ckeditor5-core/src/command';
 import findLinkRange from './findlinkrange';
+import first from '@ckeditor/ckeditor5-utils/src/first';
 
 /**
  * The unlink command. It is used by the {@link module:link/link~Link link plugin}.
@@ -20,7 +21,18 @@ export default class UnlinkCommand extends Command {
 	 * @inheritDoc
 	 */
 	refresh() {
-		this.isEnabled = this.editor.model.document.selection.hasAttribute( 'linkHref' );
+		const model = this.editor.model;
+		const doc = model.document;
+
+		const selectedImage = first( doc.selection.getSelectedBlocks() );
+
+		// A check for the `LinkImage` plugin. If the selection contains an image element, get values from the element.
+		// Currently the selection reads attributes from text nodes only. See #7429.
+		if ( selectedImage && selectedImage.name === 'image' ) {
+			this.isEnabled = model.schema.checkAttribute( selectedImage, 'linkHref' );
+		} else {
+			this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'linkHref' );
+		}
 	}
 
 	/**

+ 101 - 18
packages/ckeditor5-link/tests/linkcommand.js

@@ -67,6 +67,56 @@ describe( 'LinkCommand', () => {
 				setData( model, '<x>[foo]</x>' );
 				expect( command.isEnabled ).to.be.false;
 			} );
+
+			describe( 'for images', () => {
+				beforeEach( () => {
+					model.schema.register( 'image', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
+				} );
+
+				it( 'should be true when an image is selected', () => {
+					setData( model, '[<image linkHref="foo"></image>]' );
+
+					expect( command.isEnabled ).to.be.true;
+				} );
+
+				it( 'should be true when an image and a text are selected', () => {
+					setData( model, '[<image linkHref="foo"></image>Foo]' );
+
+					expect( command.isEnabled ).to.be.true;
+				} );
+
+				it( 'should be true when a text and an image are selected', () => {
+					setData( model, '[Foo<image linkHref="foo"></image>]' );
+
+					expect( command.isEnabled ).to.be.true;
+				} );
+
+				it( 'should be true when two images are selected', () => {
+					setData( model, '[<image linkHref="foo"></image><image linkHref="foo"></image>]' );
+
+					expect( command.isEnabled ).to.be.true;
+				} );
+
+				it( 'should be false when a fake image is selected', () => {
+					model.schema.register( 'fake', { isBlock: true, allowWhere: '$text' } );
+
+					setData( model, '[<fake></fake>]' );
+
+					expect( command.isEnabled ).to.be.false;
+				} );
+
+				it( 'should be false if an image does not accept the `linkHref` attribute in given context', () => {
+					model.schema.addAttributeCheck( ( ctx, attributeName ) => {
+						if ( ctx.endsWith( '$root image' ) && attributeName == 'linkHref' ) {
+							return false;
+						}
+					} );
+
+					setData( model, '[<image></image>]' );
+
+					expect( command.isEnabled ).to.be.false;
+				} );
+			} );
 		} );
 	} );
 
@@ -98,6 +148,38 @@ describe( 'LinkCommand', () => {
 				expect( command.value ).to.be.undefined;
 			} );
 		} );
+
+		describe( 'for images', () => {
+			beforeEach( () => {
+				model.schema.register( 'image', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
+			} );
+
+			it( 'should read the value from a selected image', () => {
+				setData( model, '[<image linkHref="foo"></image>]' );
+
+				expect( command.value ).to.be.equal( 'foo' );
+			} );
+
+			it( 'should read the value from a selected image and ignore a text node', () => {
+				setData( model, '[<image linkHref="foo"></image><p><$text linkHref="bar">bar</$text>]</p>' );
+
+				expect( command.value ).to.be.equal( 'foo' );
+			} );
+
+			it( 'should read the value from a selected text node and ignore an image', () => {
+				setData( model, '<p>[<$text linkHref="bar">bar</$text></p><image linkHref="foo"></image>]' );
+
+				expect( command.value ).to.be.equal( 'bar' );
+			} );
+
+			it( 'should be undefined when a fake image is selected', () => {
+				model.schema.register( 'fake', { isBlock: true, allowWhere: '$text' } );
+
+				setData( model, '[<fake></fake>]' );
+
+				expect( command.value ).to.be.undefined;
+			} );
+		} );
 	} );
 
 	describe( 'execute()', () => {
@@ -194,73 +276,74 @@ describe( 'LinkCommand', () => {
 			} );
 
 			it( 'should set `linkHref` attribute to allowed elements', () => {
-				model.schema.register( 'img', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
+				model.schema.register( 'image', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
 
-				setData( model, '<p>f[oo<img></img>ba]r</p>' );
+				setData( model, '<p>f[oo<image></image>ba]r</p>' );
 
 				expect( command.value ).to.be.undefined;
 
 				command.execute( 'url' );
 
-				expect( getData( model ) )
-					.to.equal( '<p>f[<$text linkHref="url">oo</$text><img linkHref="url"></img><$text linkHref="url">ba</$text>]r</p>' );
+				expect( getData( model ) ).to.equal(
+					'<p>f[<$text linkHref="url">oo</$text><image linkHref="url"></image><$text linkHref="url">ba</$text>]r</p>'
+				);
 				expect( command.value ).to.equal( 'url' );
 			} );
 
 			it( 'should set `linkHref` attribute to nested allowed elements', () => {
-				model.schema.register( 'img', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
+				model.schema.register( 'image', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
 				model.schema.register( 'blockQuote', { allowWhere: '$block', allowContentOf: '$root' } );
 
-				setData( model, '<p>foo</p>[<blockQuote><img></img></blockQuote>]<p>bar</p>' );
+				setData( model, '<p>foo</p>[<blockQuote><image></image></blockQuote>]<p>bar</p>' );
 
 				command.execute( 'url' );
 
 				expect( getData( model ) )
-					.to.equal( '<p>foo</p>[<blockQuote><img linkHref="url"></img></blockQuote>]<p>bar</p>' );
+					.to.equal( '<p>foo</p>[<blockQuote><image linkHref="url"></image></blockQuote>]<p>bar</p>' );
 			} );
 
 			it( 'should set `linkHref` attribute to allowed elements on multi-selection', () => {
-				model.schema.register( 'img', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
+				model.schema.register( 'image', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
 
-				setData( model, '<p>[<img></img>][<img></img>]</p>' );
+				setData( model, '<p>[<image></image>][<image></image>]</p>' );
 
 				command.execute( 'url' );
 
 				expect( getData( model ) )
-					.to.equal( '<p>[<img linkHref="url"></img>][<img linkHref="url"></img>]</p>' );
+					.to.equal( '<p>[<image linkHref="url"></image>][<image linkHref="url"></image>]</p>' );
 			} );
 
 			it( 'should set `linkHref` attribute to allowed elements and omit disallowed', () => {
-				model.schema.register( 'img', { isBlock: true, allowWhere: '$text' } );
-				model.schema.register( 'caption', { allowIn: 'img' } );
+				model.schema.register( 'image', { isBlock: true, allowWhere: '$text' } );
+				model.schema.register( 'caption', { allowIn: 'image' } );
 				model.schema.extend( '$text', { allowIn: 'caption' } );
 
-				setData( model, '<p>f[oo<img><caption>xxx</caption></img>ba]r</p>' );
+				setData( model, '<p>f[oo<image><caption>xxx</caption></image>ba]r</p>' );
 
 				command.execute( 'url' );
 
 				expect( getData( model ) ).to.equal(
 					'<p>' +
 						'f[<$text linkHref="url">oo</$text>' +
-						'<img><caption><$text linkHref="url">xxx</$text></caption></img>' +
+						'<image><caption><$text linkHref="url">xxx</$text></caption></image>' +
 						'<$text linkHref="url">ba</$text>]r' +
 					'</p>'
 				);
 			} );
 
 			it( 'should set `linkHref` attribute to allowed elements and omit their children even if they accept the attribute', () => {
-				model.schema.register( 'img', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
-				model.schema.register( 'caption', { allowIn: 'img' } );
+				model.schema.register( 'image', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
+				model.schema.register( 'caption', { allowIn: 'image' } );
 				model.schema.extend( '$text', { allowIn: 'caption' } );
 
-				setData( model, '<p>f[oo<img><caption>xxx</caption></img>ba]r</p>' );
+				setData( model, '<p>f[oo<image><caption>xxx</caption></image>ba]r</p>' );
 
 				command.execute( 'url' );
 
 				expect( getData( model ) ).to.equal(
 					'<p>' +
 						'f[<$text linkHref="url">oo</$text>' +
-						'<img linkHref="url"><caption>xxx</caption></img>' +
+						'<image linkHref="url"><caption>xxx</caption></image>' +
 						'<$text linkHref="url">ba</$text>]r' +
 					'</p>'
 				);

+ 50 - 0
packages/ckeditor5-link/tests/unlinkcommand.js

@@ -51,6 +51,56 @@ describe( 'UnlinkCommand', () => {
 
 			expect( command.isEnabled ).to.false;
 		} );
+
+		describe( 'for images', () => {
+			beforeEach( () => {
+				model.schema.register( 'image', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } );
+			} );
+
+			it( 'should be true when an image is selected', () => {
+				setData( model, '[<image linkHref="foo"></image>]' );
+
+				expect( command.isEnabled ).to.be.true;
+			} );
+
+			it( 'should be true when an image and a text are selected', () => {
+				setData( model, '[<image linkHref="foo"></image>Foo]' );
+
+				expect( command.isEnabled ).to.be.true;
+			} );
+
+			it( 'should be true when a text and an image are selected', () => {
+				setData( model, '[Foo<image linkHref="foo"></image>]' );
+
+				expect( command.isEnabled ).to.be.true;
+			} );
+
+			it( 'should be true when two images are selected', () => {
+				setData( model, '[<image linkHref="foo"></image><image linkHref="foo"></image>]' );
+
+				expect( command.isEnabled ).to.be.true;
+			} );
+
+			it( 'should be false when a fake image is selected', () => {
+				model.schema.register( 'fake', { isBlock: true, allowWhere: '$text' } );
+
+				setData( model, '[<fake></fake>]' );
+
+				expect( command.isEnabled ).to.be.false;
+			} );
+
+			it( 'should be false if an image does not accept the `linkHref` attribute in given context', () => {
+				model.schema.addAttributeCheck( ( ctx, attributeName ) => {
+					if ( ctx.endsWith( '$root image' ) && attributeName == 'linkHref' ) {
+						return false;
+					}
+				} );
+
+				setData( model, '[<image></image>]' );
+
+				expect( command.isEnabled ).to.be.false;
+			} );
+		} );
 	} );
 
 	describe( 'execute()', () => {