Преглед изворни кода

Added a status bar to grid view.

Kamil Piechaczek пре 6 година
родитељ
комит
53b3fc7fd3

+ 15 - 3
packages/ckeditor5-special-characters/src/specialcharacters.js

@@ -13,6 +13,7 @@ import { createDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import SpecialCharactersNavigationView from './ui/specialcharactersnavigationview';
 import CharacterGridView from './ui/charactergridview';
+import CharacterInfoView from './ui/characterinfoview';
 
 import specialCharactersIcon from '../theme/icons/specialcharacters.svg';
 import '../theme/specialcharacters.css';
@@ -82,12 +83,22 @@ export default class SpecialCharacters extends Plugin {
 			specialCharsGroups.push( ALL_SPECIAL_CHARACTERS_GROUP );
 
 			const navigationView = new SpecialCharactersNavigationView( locale, specialCharsGroups );
-			const gridView = new CharacterGridView( this.locale, {
-				columns: 10
-			} );
+			const gridView = new CharacterGridView( locale );
+			const infoView = new CharacterInfoView( locale );
 
 			gridView.delegate( 'execute' ).to( dropdownView );
 
+			gridView.on( 'tileHover', ( evt, data ) => {
+				infoView.set( data );
+			} );
+
+			dropdownView.on( 'change:isOpen', () => {
+				infoView.set( {
+					character: null,
+					name: null
+				} );
+			} );
+
 			// Set the initial content of the special characters grid.
 			this._updateGrid( navigationView.currentGroupName, gridView );
 
@@ -112,6 +123,7 @@ export default class SpecialCharacters extends Plugin {
 
 			dropdownView.panelView.children.add( navigationView );
 			dropdownView.panelView.children.add( gridView );
+			dropdownView.panelView.children.add( infoView );
 
 			return dropdownView;
 		} );

+ 7 - 0
packages/ckeditor5-special-characters/src/ui/charactergridview.js

@@ -88,9 +88,16 @@ export default class CharacterGridView extends View {
 		tile.extendTemplate( {
 			attributes: {
 				title: name
+			},
+			on: {
+				mouseover: tile.bindTemplate.to( 'mouseover' )
 			}
 		} );
 
+		tile.on( 'mouseover', () => {
+			this.fire( 'tileHover', { character, name } );
+		} );
+
 		tile.on( 'execute', () => {
 			this.fire( 'execute', { name, character } );
 		} );

+ 78 - 0
packages/ckeditor5-special-characters/src/ui/characterinfoview.js

@@ -0,0 +1,78 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/**
+ * @module special-characters/ui/characterinfoview
+ */
+
+import View from '@ckeditor/ckeditor5-ui/src/view';
+
+import '../../theme/characterinfo.css';
+
+export default class CharacterInfoView extends View {
+	constructor( locale ) {
+		super( locale );
+
+		const bind = this.bindTemplate;
+
+		this.set( 'character', null );
+		this.set( 'name', null );
+
+		this.bind( 'code' ).to( this, 'character', char => {
+			if ( char === null ) {
+				return '';
+			}
+
+			const hexCode = char.codePointAt( 0 ).toString( 16 );
+
+			return 'U+' + ( '0000' + hexCode ).slice( -4 );
+		} );
+
+		this.setTemplate( {
+			tag: 'div',
+			children: [
+				{
+					tag: 'span',
+					attributes: {
+						class: [
+							'ck-character-info__name'
+						]
+					},
+					children: [
+						{
+							text: bind.to( 'name', name => {
+								if ( !name ) {
+									// ZWSP to prevent vertical collapsing.
+									return '\u200B';
+								}
+
+								return name;
+							} )
+						}
+					]
+				},
+				{
+					tag: 'span',
+					attributes: {
+						class: [
+							'ck-character-info__code'
+						]
+					},
+					children: [
+						{
+							text: bind.to( 'code' )
+						}
+					]
+				}
+			],
+			attributes: {
+				class: [
+					'ck',
+					'ck-character-info'
+				]
+			}
+		} );
+	}
+}

+ 49 - 12
packages/ckeditor5-special-characters/tests/specialcharacters.js

@@ -13,6 +13,7 @@ import SpecialCharactersMathematical from '../src/specialcharactersmathematical'
 import SpecialCharactersArrows from '../src/specialcharactersarrows';
 import SpecialCharactersNavigationView from '../src/ui/specialcharactersnavigationview';
 import CharacterGridView from '../src/ui/charactergridview';
+import CharacterInfoView from '../src/ui/characterinfoview';
 import specialCharactersIcon from '../theme/icons/specialcharacters.svg';
 import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
@@ -82,7 +83,11 @@ describe( 'SpecialCharacters', () => {
 			} );
 
 			it( 'has a grid view', () => {
-				expect( dropdown.panelView.children.last ).to.be.instanceOf( CharacterGridView );
+				expect( dropdown.panelView.children.get( 1 ) ).to.be.instanceOf( CharacterGridView );
+			} );
+
+			it( 'has a character info view', () => {
+				expect( dropdown.panelView.children.last ).to.be.instanceOf( CharacterInfoView );
 			} );
 
 			describe( '#buttonView', () => {
@@ -102,7 +107,7 @@ describe( 'SpecialCharacters', () => {
 			} );
 
 			it( 'executes a command and focuses the editing view', () => {
-				const grid = dropdown.panelView.children.last;
+				const grid = dropdown.panelView.children.get( 1 );
 				const executeSpy = sinon.stub( editor, 'execute' );
 				const focusSpy = sinon.stub( editor.editing.view, 'focus' );
 
@@ -119,7 +124,7 @@ describe( 'SpecialCharacters', () => {
 				let grid;
 
 				beforeEach( () => {
-					grid = dropdown.panelView.children.last;
+					grid = dropdown.panelView.children.get( 1 );
 				} );
 
 				it( 'delegates #execute to the dropdown', () => {
@@ -144,6 +149,34 @@ describe( 'SpecialCharacters', () => {
 					expect( grid.tiles.get( 0 ).label ).to.equal( '⇐' );
 				} );
 			} );
+
+			describe( 'character info view', () => {
+				let grid, characterInfo;
+
+				beforeEach( () => {
+					grid = dropdown.panelView.children.get( 1 );
+					characterInfo = dropdown.panelView.children.last;
+				} );
+
+				it( 'is empty when the dropdown was shown', () => {
+					dropdown.fire( 'change:isOpen' );
+
+					expect( characterInfo.character ).to.equal( null );
+					expect( characterInfo.name ).to.equal( null );
+					expect( characterInfo.code ).to.equal( '' );
+				} );
+
+				it( 'is updated when the tile fires #mouseover', () => {
+					const tile = grid.tiles.get( 0 );
+
+					tile.fire( 'mouseover' );
+
+					expect( tile.label ).to.equal( '<' );
+					expect( characterInfo.character ).to.equal( '<' );
+					expect( characterInfo.name ).to.equal( 'Less-than sign' );
+					expect( characterInfo.code ).to.equal( 'U+003c' );
+				} );
+			} );
 		} );
 	} );
 
@@ -163,15 +196,19 @@ describe( 'SpecialCharacters', () => {
 		} );
 
 		it( 'works with subsequent calls to the same group', () => {
-			plugin.addItems( 'Mathematical', [ {
-				title: 'dot',
-				character: '.'
-			} ] );
-
-			plugin.addItems( 'Mathematical', [ {
-				title: ',',
-				character: 'comma'
-			} ] );
+			plugin.addItems( 'Mathematical', [
+				{
+					title: 'dot',
+					character: '.'
+				}
+			] );
+
+			plugin.addItems( 'Mathematical', [
+				{
+					title: ',',
+					character: 'comma'
+				}
+			] );
 
 			const groups = [ ...plugin.getGroups() ];
 			expect( groups ).to.deep.equal( [ 'Mathematical' ] );

+ 11 - 0
packages/ckeditor5-special-characters/tests/ui/charactergridview.js

@@ -63,5 +63,16 @@ describe( 'CharacterGridView', () => {
 			sinon.assert.calledOnce( spy );
 			sinon.assert.calledWithExactly( spy, sinon.match.any, { name: 'foo bar baz', character: 'ε' } );
 		} );
+
+		it( 'delegates #tileHover from the tile to the grid on hover the tile', () => {
+			const tile = view.createTile( 'ε', 'foo bar baz' );
+			const spy = sinon.spy();
+
+			view.on( 'tileHover', spy );
+			tile.fire( 'mouseover' );
+
+			sinon.assert.calledOnce( spy );
+			sinon.assert.calledWithExactly( spy, sinon.match.any, { name: 'foo bar baz', character: 'ε' } );
+		} );
 	} );
 } );

+ 74 - 0
packages/ckeditor5-special-characters/tests/ui/characterinfoview.js

@@ -0,0 +1,74 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+import CharacterInfoView from '../../src/ui/characterinfoview';
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+
+describe( 'CharacterInfoView', () => {
+	let view;
+
+	testUtils.createSinonSandbox();
+
+	beforeEach( () => {
+		view = new CharacterInfoView();
+		view.render();
+	} );
+
+	afterEach( () => {
+		view.destroy();
+	} );
+
+	describe( 'constructor()', () => {
+		describe( '#character', () => {
+			it( 'is defined', () => {
+				expect( view.character ).to.equal( null );
+			} );
+		} );
+
+		describe( '#name', () => {
+			it( 'is defined', () => {
+				expect( view.name ).to.equal( null );
+			} );
+		} );
+
+		describe( '#code', () => {
+			it( 'is defined', () => {
+				expect( view.code ).to.equal( '' );
+			} );
+
+			it( 'is bound to #character', () => {
+				view.set( 'character', 'A' );
+
+				expect( view.code ).to.equal( 'U+0041' );
+			} );
+		} );
+
+		describe( '#element', () => {
+			it( 'is being created from template', () => {
+				expect( view.element.classList.contains( 'ck' ) ).to.be.true;
+				expect( view.element.classList.contains( 'ck-character-info' ) ).to.be.true;
+
+				expect( view.element.firstElementChild.classList.contains( 'ck-character-info__name' ) ).to.be.true;
+				expect( view.element.lastElementChild.classList.contains( 'ck-character-info__code' ) ).to.be.true;
+			} );
+
+			it( 'is being updated when #code and #name have changed', () => {
+				const infoEl = view.element.firstElementChild;
+				const codeEl = view.element.lastElementChild;
+
+				expect( infoEl.innerText ).to.equal( '\u200B' );
+				expect( codeEl.innerText ).to.equal( '' );
+
+				view.set( {
+					character: 'A',
+					name: 'SYMBOL: A'
+				} );
+
+				expect( infoEl.innerText ).to.equal( 'SYMBOL: A' );
+				expect( codeEl.innerText ).to.equal( 'U+0041' );
+			} );
+		} );
+	} );
+} );

+ 9 - 0
packages/ckeditor5-special-characters/theme/characterinfo.css

@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+.ck.ck-character-info {
+	display: flex;
+	justify-content: space-between;
+}