Переглянути джерело

Improved docs and added basic tests.

Kamil Piechaczek 6 роки тому
батько
коміт
191b84e348

+ 2 - 6
packages/ckeditor5-special-characters/src/insertspecialcharactercommand.js

@@ -27,13 +27,9 @@ export default class InsertSpecialCharacterCommand extends Command {
 		 * @member {module:typing/inputcommand~InputCommand} #_inputCommand
 		 */
 		this._inputCommand = editor.commands.get( 'input' );
-	}
 
-	/**
-	 * @inheritDoc
-	 */
-	refresh() {
-		this.isEnabled = this._inputCommand.isEnabled;
+		// Use the state of `Input` command to determine whether the special characters could be inserted.
+		this.bind( 'isEnabled' ).to( this._inputCommand, 'isEnabled' );
 	}
 
 	/**

+ 19 - 6
packages/ckeditor5-special-characters/src/specialcharacters.js

@@ -25,7 +25,7 @@ export default class SpecialCharacters extends Plugin {
 		 * Registered characters. A pair of a character name and its symbol.
 		 *
 		 * @private
-		 * @member {Map.<String, String>}
+		 * @member {Map.<String, String>} #_characters
 		 */
 		this._characters = new Map();
 
@@ -33,7 +33,7 @@ export default class SpecialCharacters extends Plugin {
 		 * Registered groups. Each group contains a collection with symbol names.
 		 *
 		 * @private
-		 * @member {Map.<String, Set.<String>>}
+		 * @member {Map.<String, Set.<String>>} #_groups
 		 */
 		this._groups = new Map();
 	}
@@ -42,7 +42,7 @@ export default class SpecialCharacters extends Plugin {
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ SpecialCharactersUI, Typing ];
+		return [ Typing, SpecialCharactersUI ];
 	}
 
 	/**
@@ -53,7 +53,7 @@ export default class SpecialCharacters extends Plugin {
 	}
 
 	/**
-	 * Adds a collection of special characters to specified group.
+	 * Adds a collection of special characters to specified group. A title of a special character must be unique.
 	 *
 	 * @param {String} groupName
 	 * @param {Array.<~SpecialCharacterDefinition>} items
@@ -64,9 +64,14 @@ export default class SpecialCharacters extends Plugin {
 		for ( const item of items ) {
 			if ( this._characters.has( item.title ) ) {
 				/**
+				 * The provided title for a special character is already. Titles for special characters must be unique.
+				 *
 				 * @error specialcharacters-duplicated-character-name
+				 * @param {~SpecialCharacterDefinition} item The invalid special character definition.
 				 */
-				throw new CKEditorError( 'specialcharacters-duplicated-character-name', null );
+				throw new CKEditorError(
+					'specialcharacters-duplicated-character-name: Duplicated special character title.', null, { item }
+				);
 			}
 
 			group.add( item.title );
@@ -75,6 +80,8 @@ export default class SpecialCharacters extends Plugin {
 	}
 
 	/**
+	 * Returns iterator of special characters groups.
+	 *
 	 * @returns {Iterable.<String>}
 	 */
 	getGroups() {
@@ -82,10 +89,12 @@ export default class SpecialCharacters extends Plugin {
 	}
 
 	/**
+	 * Returns a collection of symbol names (titles).
+	 *
 	 * @param {String} groupName
 	 * @returns {Set<String>|undefined}
 	 */
-	getCharacterForGroup( groupName ) {
+	getCharactersForGroup( groupName ) {
 		return this._groups.get( groupName );
 	}
 
@@ -105,6 +114,7 @@ export default class SpecialCharacters extends Plugin {
 	 * @param {String} groupName A name of group to create.
 	 */
 	_getGroup( groupName ) {
+		/* istanbul ignore else */
 		if ( !this._groups.has( groupName ) ) {
 			this._groups.set( groupName, new Set() );
 		}
@@ -113,6 +123,9 @@ export default class SpecialCharacters extends Plugin {
 	}
 }
 
+// TODO: Make an interface for "SpecialCharacters" class.
+// It should provide methods: `addItems()`, `getGroups()`, `getCharactersForGroup()`, `getCharacter()`.
+
 /**
  * @typedef {Object} module:special-characters/specialcharacters~SpecialCharacterDefinition
  *

+ 2 - 2
packages/ckeditor5-special-characters/src/specialcharactersui.js

@@ -71,10 +71,10 @@ export default class SpecialCharactersUI extends Plugin {
 
 		function printCharacters( selectView ) {
 			const groupName = selectView.element.value;
-			const characters = specialCharacterPlugin.getCharacterForGroup( groupName );
+			const characters = specialCharacterPlugin.getCharactersForGroup( groupName );
 
 			console.log( { groupName, characters } );
-			console.log( 'Rysuj!' );
+			console.log( 'Draw!' );
 		}
 	}
 }

+ 109 - 0
packages/ckeditor5-special-characters/tests/insertspecialcharactercommand.js

@@ -0,0 +1,109 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* globals document */
+
+import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
+import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+import SpecialCharacters from '../src/specialcharacters';
+
+describe( 'InsertSpecialCharacterCommand', () => {
+	let editor, model, editorElement, command;
+
+	testUtils.createSinonSandbox();
+
+	beforeEach( () => {
+		editorElement = document.createElement( 'div' );
+		document.body.appendChild( editorElement );
+
+		return ClassicTestEditor
+			.create( editorElement, {
+				plugins: [ Paragraph, SpecialCharacters ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				command = editor.commands.get( 'specialCharacters' );
+
+				editor.plugins.get( 'SpecialCharacters' ).addItems( 'Arrows', [
+					{ title: 'arrow left', character: '←' },
+					{ title: 'arrow right', character: '→' }
+				] );
+			} );
+	} );
+
+	afterEach( () => {
+		return editor.destroy()
+			.then( () => {
+				editorElement.remove();
+			} );
+	} );
+
+	describe( 'isEnabled', () => {
+		it( 'should be bound to InputCommand#isEnables', () => {
+			const inputCommand = editor.commands.get( 'input' );
+
+			inputCommand.isEnabled = true;
+			expect( command.isEnabled ).to.equal( true );
+
+			inputCommand.isEnabled = false;
+			expect( command.isEnabled ).to.equal( false );
+		} );
+	} );
+
+	describe( 'execute()', () => {
+		it( 'should create a single batch', () => {
+			setModelData( model, '<paragraph>foo[]</paragraph>' );
+
+			const spy = sinon.spy();
+
+			model.document.on( 'change', spy );
+
+			command.execute( { item: 'arrow left' } );
+
+			sinon.assert.calledOnce( spy );
+		} );
+
+		it( 'executes InputCommand#execute()', () => {
+			const inputCommand = editor.commands.get( 'input' );
+
+			setModelData( model, '<paragraph>foo[]</paragraph>' );
+
+			const spy = sinon.stub( inputCommand, 'execute' );
+
+			command.execute( { item: 'arrow left' } );
+
+			sinon.assert.calledWithExactly( spy, { text: '←' } );
+
+			spy.restore();
+		} );
+
+		it( 'does nothing if specified object is invalid', () => {
+			setModelData( model, '<paragraph>foo[]</paragraph>' );
+
+			const spy = sinon.spy();
+
+			model.document.on( 'change', spy );
+
+			command.execute( { foo: 'arrow left' } );
+
+			sinon.assert.notCalled( spy );
+		} );
+
+		it( 'does nothing if specified item name does not exist', () => {
+			setModelData( model, '<paragraph>foo[]</paragraph>' );
+
+			const spy = sinon.spy();
+
+			model.document.on( 'change', spy );
+
+			command.execute( { item: 'arrow up' } );
+
+			sinon.assert.notCalled( spy );
+		} );
+	} );
+} );

+ 4 - 0
packages/ckeditor5-special-characters/tests/manual/specialcharacters.html

@@ -0,0 +1,4 @@
+<h2>Editor</h2>
+<div id="editor">
+	<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris viverra ipsum a sapien accumsan, in fringilla ligula congue. Suspendisse eget urna ac nulla dignissim sollicitudin vel non sem. Curabitur consequat nisi vel orci mollis tincidunt. Nam eget sapien non ligula aliquet commodo vel sed lectus. Sed arcu orci, vehicula vitae augue lobortis, posuere tristique nisl. Sed eleifend venenatis magna in elementum. Cras sit amet arcu mi. Suspendisse vel purus a ex maximus pharetra quis in massa. Mauris pellentesque leo sed mi faucibus molestie. Cras felis justo, volutpat sed erat at, lacinia fermentum nunc. Pellentesque est leo, dignissim at odio sit amet, vulputate placerat turpis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla eget pharetra enim. Donec fermentum ligula est, quis ultrices arcu tristique eu. Vivamus a dui sem.</p>
+</div>

+ 59 - 0
packages/ckeditor5-special-characters/tests/manual/specialcharacters.js

@@ -0,0 +1,59 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* globals console, window, document */
+
+import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
+import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
+import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';
+import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
+import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';
+import SpecialCharacters from '../../src/specialcharacters';
+import SpecialCharactersMathematical from '../../src/specialcharactersmathematical';
+import SpecialCharactersArrows from '../../src/specialcharactersarrows';
+
+ClassicEditor
+	.create( document.querySelector( '#editor' ), {
+		cloudServices: CS_CONFIG,
+		plugins: [ ArticlePluginSet, ImageUpload, EasyImage, SpecialCharacters, SpecialCharactersMathematical, SpecialCharactersArrows ],
+		toolbar: [
+			'heading',
+			'|',
+			'bold', 'italic', 'numberedList', 'bulletedList',
+			'|',
+			'link', 'blockquote', 'imageUpload', 'insertTable', 'mediaEmbed',
+			'|',
+			'undo', 'redo',
+			'|',
+			'specialCharacters'
+		],
+		image: {
+			styles: [
+				'full',
+				'alignLeft',
+				'alignRight'
+			],
+			toolbar: [
+				'imageStyle:alignLeft',
+				'imageStyle:full',
+				'imageStyle:alignRight',
+				'|',
+				'imageTextAlternative'
+			]
+		},
+		table: {
+			contentToolbar: [
+				'tableColumn',
+				'tableRow',
+				'mergeTableCells'
+			]
+		},
+	} )
+	.then( editor => {
+		window.editor = editor;
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );

+ 4 - 0
packages/ckeditor5-special-characters/tests/manual/specialcharacters.md

@@ -0,0 +1,4 @@
+## Testing
+
+1. Use the special characters icon in order to add a special character to the editor.
+1. Use the select in order to change category of displayed special characters.

+ 107 - 0
packages/ckeditor5-special-characters/tests/specialcharacters.js

@@ -0,0 +1,107 @@
+/**
+ * @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 SpecialCharacters from '../src/specialcharacters';
+import SpecialCharactersUI from '../src/specialcharactersui';
+import Typing from '@ckeditor/ckeditor5-typing/src/typing';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
+
+describe( 'SpecialCharacters', () => {
+	let plugin;
+
+	beforeEach( () => {
+		plugin = new SpecialCharacters( {} );
+	} );
+
+	it( 'should require Typing and SpecialCharactersUI', () => {
+		expect( SpecialCharacters.requires ).to.deep.equal( [ Typing, SpecialCharactersUI ] );
+	} );
+
+	it( 'should be named', () => {
+		expect( SpecialCharacters.pluginName ).to.equal( 'SpecialCharacters' );
+	} );
+
+	describe( 'addItems()', () => {
+		it( 'adds special characters to the available symbols', () => {
+			plugin.addItems( 'Arrows', [
+				{ title: 'arrow left', character: '←' },
+				{ title: 'arrow right', character: '→' }
+			] );
+
+			expect( plugin._groups.size ).to.equal( 1 );
+			expect( plugin._groups.has( 'Arrows' ) ).to.equal( true );
+
+			expect( plugin._characters.size ).to.equal( 2 );
+			expect( plugin._characters.has( 'arrow left' ) ).to.equal( true );
+			expect( plugin._characters.has( 'arrow right' ) ).to.equal( true );
+		} );
+
+		it( 'throw an error when a title is not a unique value', () => {
+			expectToThrowCKEditorError( () => {
+				plugin.addItems( 'Arrows', [
+					{ title: 'arrow left', character: '←' },
+					{ title: 'arrow left', character: '←' }
+				] );
+			}, /^specialcharacters-duplicated-character-name/ )
+		} );
+	} );
+
+	describe( 'getGroups()', () => {
+		it( 'returns iterator of defined groups', () => {
+			plugin.addItems( 'Arrows', [
+				{ title: 'arrow left', character: '←' }
+			] );
+
+			plugin.addItems( 'Mathematical', [
+				{ title: 'precedes', character: '≺' },
+				{ title: 'succeeds', character: '≻' }
+			] );
+
+			const groups = [ ...plugin.getGroups() ];
+			expect( groups ).to.deep.equal( [ 'Arrows', 'Mathematical' ] );
+		} );
+	} );
+
+	describe( 'getCharactersForGroup()', () => {
+		it( 'returns a collection of defined special characters names', () => {
+			plugin.addItems( 'Mathematical', [
+				{ title: 'precedes', character: '≺' },
+				{ title: 'succeeds', character: '≻' }
+			] );
+
+			const characters = plugin.getCharactersForGroup( 'Mathematical' );
+
+			expect( characters.size ).to.equal( 2 );
+			expect( characters.has( 'precedes' ) ).to.equal( true );
+			expect( characters.has( 'succeeds' ) ).to.equal( true );
+		} );
+
+		it( 'returns undefined for non-existing group', () => {
+			plugin.addItems( 'Mathematical', [
+				{ title: 'precedes', character: '≺' },
+				{ title: 'succeeds', character: '≻' }
+			] );
+
+			const characters = plugin.getCharactersForGroup( 'Foo' );
+
+			expect( characters ).to.be.undefined;
+		} );
+	} );
+
+	describe( 'getCharacter()', () => {
+		it( 'returns a collection of defined special characters names', () => {
+			plugin.addItems( 'Mathematical', [
+				{ title: 'precedes', character: '≺' },
+				{ title: 'succeeds', character: '≻' }
+			] );
+
+			expect( plugin.getCharacter( 'succeeds' ) ).to.equal( '≻' );
+		} );
+
+		it( 'returns undefined for non-existing character', () => {
+			expect( plugin.getCharacter( 'succeeds' ) ).to.be.undefined;
+		} );
+	} );
+} );