浏览代码

Other: Refactor HighlightCommand and Highlight UI creation.

Maciej Gołaszewski 8 年之前
父节点
当前提交
dc4459559b

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

@@ -16,13 +16,19 @@ import Command from '@ckeditor/ckeditor5-core/src/command';
  * @extends module:core/command~Command
  */
 export default class HighlightCommand extends Command {
+	constructor( editor, className ) {
+		super( editor );
+
+		this.className = className;
+	}
+
 	/**
 	 * @inheritDoc
 	 */
 	refresh() {
 		const doc = this.editor.document;
 
-		this.value = doc.selection.getAttribute( 'highlight' );
+		this.value = doc.selection.getAttribute( 'highlight' ) === this.className;
 		this.isEnabled = doc.schema.checkAttributeInSelection( doc.selection, 'highlight' );
 	}
 
@@ -39,7 +45,7 @@ export default class HighlightCommand extends Command {
 		const doc = this.editor.document;
 		const selection = doc.selection;
 
-		// Do not apply highlight no collapsed selection.
+		// Do not apply highlight on collapsed selection.
 		if ( selection.isCollapsed ) {
 			return;
 		}
@@ -49,11 +55,7 @@ export default class HighlightCommand extends Command {
 			const batch = options.batch || doc.batch();
 
 			for ( const range of ranges ) {
-				if ( options.class ) {
-					batch.setAttribute( range, 'highlight', options.class );
-				} else {
-					batch.removeAttribute( range, 'highlight' );
-				}
+				batch.setAttribute( range, 'highlight', this.className );
 			}
 		} );
 	}

+ 11 - 6
packages/ckeditor5-highlight/src/highlightediting.js

@@ -15,6 +15,7 @@ import buildModelConverter from '@ckeditor/ckeditor5-engine/src/conversion/build
 import AttributeElement from '@ckeditor/ckeditor5-engine/src/view/attributeelement';
 
 import HighlightCommand from './highlightcommand';
+import RemoveHighlightCommand from './removehighlightcommand';
 
 /**
  * The highlight editing feature. It introduces `highlight` command which allow to highlight selected text with defined 'marker' or 'pen'.
@@ -29,11 +30,11 @@ export default class HighlightEditing extends Plugin {
 		super( editor );
 
 		editor.config.define( 'highlight', [
-			{ class: 'marker', title: 'Marker', color: '#ffff66', type: 'marker' },
-			{ class: 'marker-green', title: 'Green Marker', color: '#66ff00', type: 'marker' },
-			{ class: 'marker-pink', title: 'Pink Marker', color: '#ff6fff', type: 'marker' },
-			{ class: 'pen-red', title: 'Red Pen', color: '#ff0000', type: 'pen' },
-			{ class: 'pen-blue', title: 'Blue Pen', color: '#0000ff', type: 'pen' }
+			{ name: 'marker', class: 'marker', title: 'Marker', color: '#ffff66', type: 'marker' },
+			{ name: 'greenMarker', class: 'marker-green', title: 'Green Marker', color: '#66ff00', type: 'marker' },
+			{ name: 'pinkMarker', class: 'marker-pink', title: 'Pink Marker', color: '#ff6fff', type: 'marker' },
+			{ name: 'redPen', class: 'pen-red', title: 'Red Pen', color: '#ff0000', type: 'pen' },
+			{ name: 'bluePen', class: 'pen-blue', title: 'Blue Pen', color: '#0000ff', type: 'pen' }
 		] );
 	}
 
@@ -70,7 +71,11 @@ export default class HighlightEditing extends Plugin {
 				}
 			} );
 
-		editor.commands.add( 'highlight', new HighlightCommand( editor ) );
+		editor.config
+			.get( 'highlight' )
+			.map( highlighter => editor.commands.add( highlighter.name, new HighlightCommand( editor, highlighter.class ) ) );
+
+		editor.commands.add( 'removeHighlight', new RemoveHighlightCommand( editor ) );
 	}
 }
 

+ 63 - 48
packages/ckeditor5-highlight/src/highlightui.js

@@ -47,43 +47,57 @@ export default class HighlightUI extends Plugin {
 		const highlighters = this.editor.config.get( 'highlight' );
 
 		for ( const highlighter of highlighters ) {
-			this._addButton( highlighter );
+			this._addHighlighterButton( highlighter );
 		}
 
-		this._addRubberButton();
+		this._addRemoveHighlightButton();
 
 		this._addDropdown( highlighters );
 	}
 
-	_addButton( highlighter ) {
+	_addRemoveHighlightButton() {
+		const t = this.editor.t;
+
+		this._addButton( 'removeHighlight', t( 'Remove highlighting' ), highlightRemoveIcon );
+	}
+
+	_addHighlighterButton( highlighter ) {
+		const name = highlighter.name;
+		const command = this.editor.commands.get( name );
+
+		this._addButton( name, highlighter.title, highlightIcon, decorateHighlightButton );
+
+		function decorateHighlightButton( button ) {
+			button.bind( 'isEnabled' ).to( command, 'isEnabled' );
+			button.bind( 'isOn' ).to( command, 'value' );
+
+			// TODO: bind to
+			button.iconView.extendTemplate( {
+				attributes: {
+					style: highlighter.type === 'pen' ? { color: highlighter.color } : { backgroundColor: highlighter.color }
+				}
+			} );
+		}
+	}
+
+	_addButton( name, label, icon, decorateButton = () => {} ) {
 		const editor = this.editor;
-		const command = editor.commands.get( 'highlight' );
 
-		editor.ui.componentFactory.add( 'highlight-' + highlighter.class, locale => {
+		editor.ui.componentFactory.add( name, locale => {
 			const buttonView = new ButtonView( locale );
 
 			buttonView.set( {
-				label: highlighter.title,
-				icon: highlightIcon,
-				tooltip: true,
-				// TODO: how to pass this & name
-				class: highlighter.class
+				label,
+				icon,
+				tooltip: true
 			} );
 
-			// Bind button model to command.
-			buttonView.bind( 'isEnabled' ).to( command, 'isEnabled' );
-			buttonView.bind( 'isOn' ).to( command, 'value', value => value === highlighter.class );
-
-			// Execute command.
 			this.listenTo( buttonView, 'execute', () => {
-				editor.execute( 'highlight', { class: highlighter.class } );
+				editor.execute( name );
 				editor.editing.view.focus();
 			} );
 
-			// TODO:
-			buttonView.iconView.extendTemplate( {
-				attributes: { style: highlighter.type === 'pen' ? { color: highlighter.color } : { backgroundColor: highlighter.color } }
-			} );
+			decorateButton( buttonView );
 
 			return buttonView;
 		} );
@@ -102,11 +116,11 @@ export default class HighlightUI extends Plugin {
 				icon: highlightIcon
 			} );
 
-			const buttons = highlighters.map( highlighter => componentFactory.create( 'highlight-' + highlighter.class ) );
+			const buttons = highlighters.map( highlighter => componentFactory.create( highlighter.name ) );
 
-			buttons.push( componentFactory.create( 'highlightRemove' ) );
+			buttons.push( componentFactory.create( 'removeHighlight' ) );
 
-			const buttonView = componentFactory.create( 'highlight-' + highlighters[ 0 ].class );
+			const initialButton = componentFactory.create( highlighters[ 0 ].name );
 
 			model.bind( 'isEnabled' ).to(
 				// Bind to #isEnabled of each command...
@@ -116,7 +130,7 @@ export default class HighlightUI extends Plugin {
 			);
 
 			// TODO: Is this needed in UI at all?
-			const dropdownView = createSplitButtonDropdown( model, locale, buttonView );
+			const dropdownView = createSplitButtonDropdown( model, locale, initialButton );
 
 			const buttonGroupView = dropdownView.buttonGroupView = new ButtonGroupView( { isVertical: model.isVertical } );
 
@@ -145,13 +159,36 @@ export default class HighlightUI extends Plugin {
 				}
 			} );
 
+			const bind = dropdownView.buttonView.buttonView.iconView.bindTemplate;
+
+			// const bind = Template.bind( observable, emitter );
+
+			// TODO: check binding
+
+			dropdownView.buttonView.buttonView.iconView.extendTemplate( {
+				attributes: {
+					style: bind.to( 'style' )
+				}
+			} );
+
+			dropdownView.buttonView.buttonView.iconView.bind( 'style' ).to( model, 'type', model, 'color', ( type, color ) => {
+				if ( type === 'pen' ) {
+					return 'color:' + color;
+				} else {
+					return 'background-color:' + color;
+				}
+			} );
+
 			// TODO: A bit hack-ish: Swap the split button button to executed one.
 			buttons.map( buttonView => {
 				this.listenTo( buttonView, 'execute', () => {
 					if ( dropdownView.buttonView.buttonView.class !== buttonView.class ) {
-						const newButton = componentFactory.create( buttonView.class ? 'highlight-' + buttonView.class : 'highlightRemove' );
+						// TODO: const newButton =
+						// componentFactory.create( buttonView.class ? 'highlight-' + buttonView.class : 'highlightRemove' );
 
-						dropdownView.buttonView.swapButton( newButton );
+						model.type = '';
+						model.color = '';
+						model.command = '';
 					}
 				} );
 			} );
@@ -159,28 +196,6 @@ export default class HighlightUI extends Plugin {
 			return dropdownView;
 		} );
 	}
-
-	_addRubberButton() {
-		const editor = this.editor;
-		const t = editor.t;
-
-		editor.ui.componentFactory.add( 'highlightRemove', locale => {
-			const buttonView = new ButtonView( locale );
-
-			buttonView.set( {
-				label: t( 'Remove highlighting' ),
-				icon: highlightRemoveIcon,
-				tooltip: true
-			} );
-
-			this.listenTo( buttonView, 'execute', () => {
-				editor.execute( 'highlight' );
-				editor.editing.view.focus();
-			} );
-
-			return buttonView;
-		} );
-	}
 }
 
 // TODO: this is duplicated

+ 64 - 0
packages/ckeditor5-highlight/src/removehighlightcommand.js

@@ -0,0 +1,64 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module highlight/removehighlightcommand
+ */
+
+import Command from '@ckeditor/ckeditor5-core/src/command';
+
+/**
+ * The highlight command. It is used by the {@link module:highlight/highlightediting~HighlightEditing highlight feature}
+ * to apply text highlighting.
+ *
+ * @extends module:core/command~Command
+ */
+export default class RemoveHighlightCommand extends Command {
+	/**
+	 * @inheritDoc
+	 */
+	refresh() {
+		const doc = this.editor.document;
+
+		this.value = false;
+		this.isEnabled = doc.schema.checkAttributeInSelection( doc.selection, 'highlight' );
+	}
+
+	/**
+	 * Executes the command.
+	 *
+	 * @protected
+	 * @param {Object} [options] Options for the executed command.
+	 * @param {String} options.class Name of highlighter class.
+	 * @param {module:engine/model/batch~Batch} [options.batch] A batch to collect all the change steps.
+	 * A new batch will be created if this option is not set.
+	 */
+	execute( options = {} ) {
+		const doc = this.editor.document;
+		const selection = doc.selection;
+
+		// Do nothing on collapsed selection.
+		if ( selection.isCollapsed ) {
+			return;
+		}
+
+		doc.enqueueChanges( () => {
+			const ranges = doc.schema.getValidRanges( selection.getRanges(), 'highlight' );
+			const batch = options.batch || doc.batch();
+
+			for ( const range of ranges ) {
+				batch.removeAttribute( range, 'highlight' );
+			}
+		} );
+	}
+}
+
+/**
+ * Holds current highlight class. If there is no highlight in selection then value will be undefined.
+ *
+ * @observable
+ * @readonly
+ * @member {undefined|String} module:highlight/highlightcommand~HighlightCommand#value
+ */