浏览代码

Added: Enable highlighter on collapsed selection.

Maciej Gołaszewski 7 年之前
父节点
当前提交
eea8b248d1

+ 7 - 9
packages/ckeditor5-highlight/src/highlightcommand.js

@@ -25,7 +25,8 @@ export default class HighlightCommand extends Command {
 		const doc = model.document;
 
 		/**
-		 * A flag indicating whether the command is active, which means that the selection has highlight attribute set.
+		 * A value indicating whether the command is active. If the selection has highlight attribute
+		 * set the value will be set to highlight attribute value.
 		 *
 		 * @observable
 		 * @readonly
@@ -33,10 +34,6 @@ export default class HighlightCommand extends Command {
 		 */
 		this.value = doc.selection.getAttribute( 'highlight' );
 		this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'highlight' );
-		// Alternate:
-		// const selection = doc.selection;
-		// this.isEnabled = ( !selection.isCollapsed || selection.hasAttribute( 'highlight' ) )
-		// 		&& model.schema.checkAttributeInSelection( doc.selection, 'highlight' );
 	}
 
 	/**
@@ -53,8 +50,8 @@ export default class HighlightCommand extends Command {
 		const document = model.document;
 		const selection = document.selection;
 
-		// Do not apply highlight on collapsed selection when not inside existing highlight.
-		if ( selection.isCollapsed && !this.value ) {
+		// Do not apply highlight on wrong selection.
+		if ( !this.isEnabled ) {
 			return;
 		}
 
@@ -82,6 +79,7 @@ export default class HighlightCommand extends Command {
 					if ( !highlighter || this.value === highlighter ) {
 						// ...remove attribute when passing highlighter different then current or executing "eraser".
 						writer.removeAttribute( 'highlight', highlightRange );
+						selection.removeAttribute( 'highlight' );
 					} else {
 						// ...update `highlight` value.
 						writer.setAttribute( 'highlight', highlighter, highlightRange );
@@ -89,8 +87,8 @@ export default class HighlightCommand extends Command {
 						// And create new range wrapping changed highlighter.
 						selection.setRanges( [ highlightRange ] );
 					}
-				} else {
-					// TODO
+				} else if ( highlighter ) {
+					selection.setAttribute( 'highlight', highlighter );
 				}
 			} else {
 				for ( const range of ranges ) {

+ 70 - 1
packages/ckeditor5-highlight/tests/highlightcommand.js

@@ -8,15 +8,19 @@ import HighlightCommand from './../src/highlightcommand';
 import Command from '@ckeditor/ckeditor5-core/src/command';
 import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor';
 import { getData, setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+import Position from '../../ckeditor5-engine/src/model/position';
+import Range from '../../ckeditor5-engine/src/model/range';
 
 describe( 'HighlightCommand', () => {
-	let editor, model, command;
+	let editor, model, doc, root, command;
 
 	beforeEach( () => {
 		return ModelTestEditor.create()
 			.then( newEditor => {
 				editor = newEditor;
 				model = editor.model;
+				doc = model.document;
+				root = doc.getRoot();
 
 				command = new HighlightCommand( newEditor );
 				editor.commands.add( 'highlight', command );
@@ -84,6 +88,71 @@ describe( 'HighlightCommand', () => {
 					expect( command.value ).to.be.undefined;
 				} );
 
+				it( 'should change selection attribute in non-empty parent', () => {
+					setData( model, '<paragraph>a[]bc<$text highlight="marker">foobar</$text>xyz</paragraph>' );
+					expect( command.value ).to.be.undefined;
+
+					command.execute( { value: 'foo' } );
+					expect( command.value ).to.equal( 'foo' );
+
+					expect( doc.selection.hasAttribute( 'highlight' ) ).to.be.true;
+
+					command.execute();
+
+					expect( command.value ).to.be.undefined;
+					expect( doc.selection.hasAttribute( 'highlight' ) ).to.be.false;
+				} );
+
+				it( 'should not store attribute change on selection if selection is collapsed in non-empty parent', () => {
+					setData( model, '<paragraph>a[]bc<$text highlight="marker">foobar</$text>xyz</paragraph>' );
+
+					command.execute( { value: 'foo' } );
+
+					// It should not save that bold was executed at position ( root, [ 0, 1 ] ).
+
+					model.change( () => {
+						// Simulate clicking right arrow key by changing selection ranges.
+						doc.selection.setRanges( [ new Range( new Position( root, [ 0, 2 ] ), new Position( root, [ 0, 2 ] ) ) ] );
+
+						// Get back to previous selection.
+						doc.selection.setRanges( [ new Range( new Position( root, [ 0, 1 ] ), new Position( root, [ 0, 1 ] ) ) ] );
+					} );
+
+					expect( command.value ).to.be.undefined;
+				} );
+
+				it( 'should change selection attribute and store it if selection is collapsed in empty parent', () => {
+					setData( model, '<paragraph>abc<$text highlight="marker">foobar</$text>xyz</paragraph><paragraph>[]</paragraph>' );
+
+					expect( command.value ).to.be.undefined;
+
+					command.execute( { value: 'foo' } );
+
+					expect( command.value ).to.equal( 'foo' );
+					expect( doc.selection.hasAttribute( 'highlight' ) ).to.be.true;
+
+					// Attribute should be stored.
+					// Simulate clicking somewhere else in the editor.
+					model.change( () => {
+						doc.selection.setRanges( [ new Range( new Position( root, [ 0, 2 ] ), new Position( root, [ 0, 2 ] ) ) ] );
+					} );
+
+					expect( command.value ).to.be.undefined;
+
+					// Go back to where attribute was stored.
+					model.change( () => {
+						doc.selection.setRanges( [ new Range( new Position( root, [ 1, 0 ] ), new Position( root, [ 1, 0 ] ) ) ] );
+					} );
+
+					// Attribute should be restored.
+					expect( command.value ).to.equal( 'foo' );
+
+					command.execute();
+
+					expect( command.value ).to.be.undefined;
+					expect( doc.selection.hasAttribute( 'highlight' ) ).to.be.false;
+				} );
+
 				it( 'should change entire highlight when inside highlighted text', () => {
 					setData( model, '<paragraph>abc<$text highlight="marker">foo[]bar</$text>xyz</paragraph>' );