Bläddra i källkod

Revert "Merge pull request #34 from ckeditor/t/33"

This reverts commit 444db01bba71bc7b368d7849b5e5d92d757d646f, reversing
changes made to 5102107fdc6d1542db186f1eea53c4c6e86d26fe.
Mateusz Samsel 6 år sedan
förälder
incheckning
c94c7cd6d7

+ 4 - 0
packages/ckeditor5-font/docs/features/font.md

@@ -231,6 +231,10 @@ ClassicEditor
 
 
 It is also possible to configure in how many columns the colors in the grid are displayed. Use the {@link module:font/fontcolor~FontColorConfig#columns `fontColor.columns`} and {@link module:font/fontbackgroundcolor~FontBackgroundColorConfig#columns `fontBackgroundColor.columns`} options to do so.
 It is also possible to configure in how many columns the colors in the grid are displayed. Use the {@link module:font/fontcolor~FontColorConfig#columns `fontColor.columns`} and {@link module:font/fontbackgroundcolor~FontBackgroundColorConfig#columns `fontBackgroundColor.columns`} options to do so.
 
 
+<info-box>
+	The configuration of the columns also affects the number of recently used colors displayed under the color grid. The less columns, the fewer recently used colors will be displayed.
+</info-box>
+
 ```js
 ```js
 ClassicEditor
 ClassicEditor
 	.create( document.querySelector( '#editor' ), {
 	.create( document.querySelector( '#editor' ), {

+ 87 - 1
packages/ckeditor5-font/src/ui/colortableview.js

@@ -9,7 +9,9 @@
 
 
 import View from '@ckeditor/ckeditor5-ui/src/view';
 import View from '@ckeditor/ckeditor5-ui/src/view';
 import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
 import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import ColorTileView from '@ckeditor/ckeditor5-ui/src/colorgrid/colortileview';
 import ColorGridView from '@ckeditor/ckeditor5-ui/src/colorgrid/colorgridview';
 import ColorGridView from '@ckeditor/ckeditor5-ui/src/colorgrid/colorgridview';
+import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
 import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
 import FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';
 import FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';
 import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
 import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
@@ -20,7 +22,8 @@ import '../../theme/fontcolor.css';
  * A class which represents a view with the following sub–components:
  * A class which represents a view with the following sub–components:
  *
  *
  * * A remove color button,
  * * A remove color button,
- * * A {@link module:ui/colorgrid/colorgrid~ColorGridView}.
+ * * A {@link module:ui/colorgrid/colorgrid~ColorGridView},
+ * * A grid of recently used colors.
  *
  *
  * @extends module:ui/view~View
  * @extends module:ui/view~View
  */
  */
@@ -90,6 +93,14 @@ export default class ColorTableView extends View {
 		 */
 		 */
 		this.columns = columns;
 		this.columns = columns;
 
 
+		/**
+		 * A collection storing definitions of recently used colors.
+		 *
+		 * @readonly
+		 * @member {module:utils/collection~Collection}
+		 */
+		this.recentlyUsedColors = new Collection();
+
 		/**
 		/**
 		 * Helps cycling over focusable {@link #items} in the list.
 		 * Helps cycling over focusable {@link #items} in the list.
 		 *
 		 *
@@ -110,6 +121,7 @@ export default class ColorTableView extends View {
 			}
 			}
 		} );
 		} );
 
 
+		this.initRecentCollection();
 		this.setTemplate( {
 		this.setTemplate( {
 			tag: 'div',
 			tag: 'div',
 			attributes: {
 			attributes: {
@@ -123,6 +135,7 @@ export default class ColorTableView extends View {
 
 
 		this.items.add( this.removeColorButton() );
 		this.items.add( this.removeColorButton() );
 		this.items.add( this.createStaticColorTable() );
 		this.items.add( this.createStaticColorTable() );
+		this.items.add( this.recentlyUsed() );
 	}
 	}
 
 
 	/**
 	/**
@@ -165,6 +178,79 @@ export default class ColorTableView extends View {
 		return colorGrid;
 		return colorGrid;
 	}
 	}
 
 
+	/**
+	 * Adds recently used colors section view and binds it to {@link #recentlyUsedColors}.
+	 *
+	 * @private
+	 */
+	recentlyUsed() {
+		const recentViews = new ColorGridView( this.locale, { columns: this.columns } );
+
+		recentViews.items.bindTo( this.recentlyUsedColors ).using(
+			colorObj => {
+				const colorTile = new ColorTileView();
+
+				colorTile.set( {
+					color: colorObj.color,
+					hasBorder: colorObj.hasBorder
+				} );
+
+				if ( colorObj.label ) {
+					colorTile.set( {
+						label: colorObj.label,
+						tooltip: true
+					} );
+				}
+
+				if ( colorObj.isEnabled === false ) {
+					colorTile.set( 'isEnabled', false );
+				}
+
+				colorTile.on( 'execute', () => {
+					this.fire( 'execute', {
+						value: colorObj.color,
+						hasBorder: colorObj.hasBorder,
+						label: colorObj.label
+					} );
+				} );
+
+				return colorTile;
+			}
+		);
+
+		this.recentlyUsedColors.on( 'add', ( evt, item ) => {
+			const duplicates = this.recentlyUsedColors.filter( element => element.color === item.color, this );
+
+			if ( duplicates.length === 2 ) {
+				this.recentlyUsedColors.remove( duplicates[ 1 ] );
+			}
+
+			if ( this.recentlyUsedColors.length > this.columns ) {
+				this.recentlyUsedColors.remove( this.recentlyUsedColors.length - 1 );
+			}
+		} );
+
+		recentViews.delegate( 'execute' ).to( this );
+
+		return recentViews;
+	}
+
+	/**
+	 * Populates {@link #recentlyUsedColors} with empty non-clickable buttons, which represent placeholders
+	 * for colors.
+	 *
+	 * @private
+	 */
+	initRecentCollection() {
+		for ( let i = 0; i < this.columns; i++ ) {
+			this.recentlyUsedColors.add( {
+				color: 'hsla(0, 0%, 0%, 0)',
+				isEnabled: false,
+				hasBorder: true
+			} );
+		}
+	}
+
 	/**
 	/**
 	 * @inheritDoc
 	 * @inheritDoc
 	 */
 	 */

+ 9 - 0
packages/ckeditor5-font/src/ui/colorui.js

@@ -65,6 +65,7 @@ export default class ColorUI extends Plugin {
 
 
 		/**
 		/**
 		 * The number of columns in the color grid.
 		 * The number of columns in the color grid.
+		 *
 		 * @type {Number}
 		 * @type {Number}
 		 */
 		 */
 		this.columns = editor.config.get( `${ this.componentName }.columns` );
 		this.columns = editor.config.get( `${ this.componentName }.columns` );
@@ -113,6 +114,14 @@ export default class ColorUI extends Plugin {
 			dropdownView.bind( 'isEnabled' ).to( command );
 			dropdownView.bind( 'isEnabled' ).to( command );
 
 
 			dropdownView.on( 'execute', ( evt, data ) => {
 			dropdownView.on( 'execute', ( evt, data ) => {
+				if ( data.value !== null ) {
+					colorTableView.recentlyUsedColors.add( {
+						color: data.value,
+						hasBorder: data.hasBorder,
+						label: data.label
+					}, 0 );
+				}
+
 				editor.execute( this.commandName, data );
 				editor.execute( this.commandName, data );
 				editor.editing.view.focus();
 				editor.editing.view.focus();
 			} );
 			} );

+ 2 - 0
packages/ckeditor5-font/tests/manual/font-color.md

@@ -12,3 +12,5 @@ The format in the editor content is: `N. [font color]; [background color]`.
 
 
 - Change the font color and font background color on selected text.
 - Change the font color and font background color on selected text.
 - Change the font color and font background color across many paragraphs.
 - Change the font color and font background color across many paragraphs.
+- Check whether the colors are added to recent colors list.
+- Try to re-apply a color from recent colors list: the color should move to the beginning of the list.

+ 116 - 0
packages/ckeditor5-font/tests/ui/colortableview.js

@@ -6,6 +6,7 @@
 /* globals Event */
 /* globals Event */
 
 
 import ColorTableView from './../../src/ui/colortableview';
 import ColorTableView from './../../src/ui/colortableview';
+import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';
 import ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';
 import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
 import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
 import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
 import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
@@ -81,6 +82,10 @@ describe( 'ColorTableView', () => {
 			expect( colorTableView.columns ).to.equal( 5 );
 			expect( colorTableView.columns ).to.equal( 5 );
 		} );
 		} );
 
 
+		it( 'creaets collection of recently used colors', () => {
+			expect( colorTableView.recentlyUsedColors ).to.be.instanceOf( Collection );
+		} );
+
 		it( 'creates focus cycler', () => {
 		it( 'creates focus cycler', () => {
 			expect( colorTableView._focusCycler ).to.be.instanceOf( FocusCycler );
 			expect( colorTableView._focusCycler ).to.be.instanceOf( FocusCycler );
 		} );
 		} );
@@ -173,4 +178,115 @@ describe( 'ColorTableView', () => {
 			} );
 			} );
 		} );
 		} );
 	} );
 	} );
+
+	describe( 'recent colors grid', () => {
+		const colorBlack = {
+			color: '#000000',
+			label: 'Black',
+			hasBorder: false
+		};
+		const colorWhite = {
+			color: '#FFFFFF',
+			label: 'Black',
+			hasBorder: true
+		};
+		const colorRed = {
+			color: 'rgb(255,0,0)',
+			hasBorder: false
+		};
+		const emptyColor = {
+			color: 'hsla(0, 0%, 0%, 0)',
+			isEnabled: false,
+			hasBorder: true
+		};
+
+		let recentColorsGridView, recentColorModel;
+
+		beforeEach( () => {
+			recentColorModel = colorTableView.recentlyUsedColors;
+			recentColorsGridView = colorTableView.items.last;
+		} );
+
+		describe( 'initialization', () => {
+			it( 'has proper length of populated items', () => {
+				expect( recentColorModel.length ).to.equal( 5 );
+			} );
+
+			for ( let i = 0; i < 5; i++ ) {
+				it( `initialized item with index: "${ i }" has proper attributes`, () => {
+					const modelItem = recentColorModel.get( i );
+					const viewItem = recentColorsGridView.items.get( i );
+
+					expect( modelItem.color ).to.equal( 'hsla(0, 0%, 0%, 0)' );
+					expect( modelItem.isEnabled ).to.be.false;
+					expect( modelItem.hasBorder ).to.be.true;
+					expect( viewItem.isEnabled ).to.be.false;
+					expect( viewItem.color ).to.equal( 'hsla(0, 0%, 0%, 0)' );
+					expect( viewItem.hasBorder ).to.be.true;
+					expect( viewItem.label ).to.be.undefined;
+				} );
+			}
+		} );
+
+		describe( 'model manipulation', () => {
+			it( 'adding item will preserve length of collection', () => {
+				expect( recentColorModel.length ).to.equal( 5 );
+
+				recentColorModel.add( Object.assign( {}, colorBlack ), 0 );
+
+				expect( recentColorModel.length ).to.equal( 5 );
+				expect( recentColorModel.first.color ).to.equal( '#000000' );
+				expect( recentColorModel.first.label ).to.equal( 'Black' );
+				expect( recentColorModel.first.hasBorder ).to.be.false;
+			} );
+
+			it( 'adding multiple times same color should not work', () => {
+				recentColorModel.add( Object.assign( {}, colorBlack ), 0 );
+
+				expect( recentColorModel.first ).to.own.include( colorBlack );
+				expect( recentColorModel.get( 1 ) ).to.own.include( emptyColor );
+
+				recentColorModel.add( Object.assign( {}, colorBlack ), 0 );
+
+				expect( recentColorModel.first ).to.own.include( colorBlack );
+				expect( recentColorModel.get( 1 ) ).to.own.include( emptyColor );
+			} );
+
+			it( 'adding duplicates move color to the front', () => {
+				recentColorModel.add( Object.assign( {}, colorBlack ), 0 );
+				recentColorModel.add( Object.assign( {}, colorWhite ), 0 );
+				recentColorModel.add( Object.assign( {}, colorRed ), 0 );
+
+				expect( recentColorModel.get( 0 ) ).to.own.include( colorRed );
+				expect( recentColorModel.get( 1 ) ).to.own.include( colorWhite );
+				expect( recentColorModel.get( 2 ) ).to.own.include( colorBlack );
+				expect( recentColorModel.get( 3 ) ).to.own.include( emptyColor );
+
+				recentColorModel.add( Object.assign( {}, colorBlack ), 0 );
+
+				expect( recentColorModel.get( 0 ) ).to.own.include( colorBlack );
+				expect( recentColorModel.get( 1 ) ).to.own.include( colorRed );
+				expect( recentColorModel.get( 2 ) ).to.own.include( colorWhite );
+				expect( recentColorModel.get( 3 ) ).to.own.include( emptyColor );
+			} );
+		} );
+
+		describe( 'events', () => {
+			it( 'added colors delegates execute to parent', () => {
+				const spy = sinon.spy();
+				colorTableView.on( 'execute', spy );
+
+				recentColorModel.add( Object.assign( {}, colorBlack ), 0 );
+
+				recentColorsGridView.items.first.element.dispatchEvent( new Event( 'click' ) );
+
+				sinon.assert.calledOnce( spy );
+				sinon.assert.calledWith( spy, sinon.match.any, {
+					value: '#000000',
+					label: 'Black',
+					hasBorder: false
+				} );
+			} );
+		} );
+	} );
 } );
 } );

+ 23 - 1
packages/ckeditor5-font/tests/ui/colorui.js

@@ -3,7 +3,7 @@
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  */
  */
 
 
-/* global document */
+/* global document, Event */
 
 
 import ColorUI from './../../src/ui/colorui';
 import ColorUI from './../../src/ui/colorui';
 import FontColorCommand from './../../src/fontcolor/fontcolorcommand';
 import FontColorCommand from './../../src/fontcolor/fontcolorcommand';
@@ -151,6 +151,28 @@ describe( 'ColorUI', () => {
 			sinon.assert.calledOnce( focusSpy );
 			sinon.assert.calledOnce( focusSpy );
 		} );
 		} );
 
 
+		it( 'static color grid should impact on recent colors', () => {
+			const firstStaticTile = dropdown.colorTableView.items.get( 1 ).items.first;
+			const recentColorsModel = dropdown.colorTableView.recentlyUsedColors;
+			const spy = sinon.spy();
+
+			dropdown.on( 'execute', spy );
+
+			firstStaticTile.element.dispatchEvent( new Event( 'click' ) );
+
+			sinon.assert.calledOnce( spy );
+			sinon.assert.calledWith( spy, sinon.match.any, {
+				value: 'yellow',
+				label: 'yellow',
+				hasBorder: false
+			} );
+			expect( recentColorsModel.get( 0 ) ).to.include( {
+				color: 'yellow',
+				label: 'yellow',
+				hasBorder: false
+			} );
+		} );
+
 		describe( 'model to command binding', () => {
 		describe( 'model to command binding', () => {
 			it( 'isEnabled', () => {
 			it( 'isEnabled', () => {
 				command.isEnabled = false;
 				command.isEnabled = false;