Bladeren bron

Improved features code, added keystrokes, added and updated tests.

Piotrek Koszuliński 9 jaren geleden
bovenliggende
commit
8cd7b35760

+ 3 - 0
packages/ckeditor5-basic-styles/src/bold.js

@@ -38,5 +38,8 @@ export default class Bold extends Feature {
 
 		// Add bold button to feature components.
 		editor.ui.featureComponents.add( 'bold', ButtonController, ButtonView, buttonModel );
+
+		// Set the CTRL+B keystroke.
+		editor.keystrokes.set( 'CTRL+B', 'bold' );
 	}
 }

+ 5 - 8
packages/ckeditor5-basic-styles/src/boldengine.js

@@ -15,15 +15,13 @@ const BOLD = 'bold';
 export default class BoldEngine extends Feature {
 	init() {
 		const editor = this.editor;
-		const document = editor.document;
-		const schema = document.schema;
 		const data = editor.data;
 		const editing = editor.editing;
 
-		// Schema.
-		schema.allow( { name: '$inline', attributes: [ BOLD ] } );
+		// Allow bold attribute on all inline nodes.
+		editor.document.schema.allow( { name: '$inline', attributes: [ BOLD ] } );
 
-		// Build converter from model to view for data pipeline.
+		// Build converter from model to view for data and editing pipelines.
 		BuildModelConverterFor( data.modelToView, editing.modelToView )
 			.fromAttribute( BOLD )
 			.toElement( 'strong' );
@@ -35,8 +33,7 @@ export default class BoldEngine extends Feature {
 			.fromAttribute( 'style', { 'font-weight': 'bold' } )
 			.toAttribute( BOLD, true );
 
-		// Command.
-		const command = new AttributeCommand( editor, BOLD );
-		editor.commands.set( BOLD, command );
+		// Create bold command.
+		editor.commands.set( BOLD, new AttributeCommand( editor, BOLD ) );
 	}
 }

+ 3 - 0
packages/ckeditor5-basic-styles/src/italic.js

@@ -38,5 +38,8 @@ export default class Italic extends Feature {
 
 		// Add bold button to feature components.
 		editor.ui.featureComponents.add( 'italic', ButtonController, ButtonView, buttonModel );
+
+		// Set the CTRL+I keystroke.
+		editor.keystrokes.set( 'CTRL+I', 'italic' );
 	}
 }

+ 5 - 8
packages/ckeditor5-basic-styles/src/italicengine.js

@@ -15,15 +15,13 @@ const ITALIC = 'italic';
 export default class ItalicEngine extends Feature {
 	init() {
 		const editor = this.editor;
-		const document = editor.document;
-		const schema = document.schema;
 		const data = editor.data;
 		const editing = editor.editing;
 
-		// Schema.
-		schema.allow( { name: '$inline', attributes: [ ITALIC ] } );
+		// Allow italic attribute on all inline nodes.
+		editor.document.schema.allow( { name: '$inline', attributes: [ ITALIC ] } );
 
-		// Build converter from model to view for data pipeline.
+		// Build converter from model to view for data and editing pipelines.
 		BuildModelConverterFor( data.modelToView, editing.modelToView )
 			.fromAttribute( ITALIC )
 			.toElement( 'em' );
@@ -35,8 +33,7 @@ export default class ItalicEngine extends Feature {
 			.fromAttribute( 'style', { 'font-style': 'italic' } )
 			.toAttribute( ITALIC, true );
 
-		// Command.
-		const command = new AttributeCommand( editor, ITALIC );
-		editor.commands.set( ITALIC, command );
+		// Create italic command.
+		editor.commands.set( ITALIC, new AttributeCommand( editor, ITALIC ) );
 	}
 }

+ 0 - 1
packages/ckeditor5-basic-styles/tests/bold.html

@@ -1 +0,0 @@
-<div id="editor"></div>

+ 23 - 13
packages/ckeditor5-basic-styles/tests/bold.js

@@ -10,19 +10,24 @@ import Bold from '/ckeditor5/basic-styles/bold.js';
 import BoldEngine from '/ckeditor5/basic-styles/boldengine.js';
 import ButtonController from '/ckeditor5/ui/button/button.js';
 import testUtils from '/tests/ckeditor5/_utils/utils.js';
+import { keyCodes } from '/ckeditor5/utils/keyboard.js';
 
 testUtils.createSinonSandbox();
 
 describe( 'Bold', () => {
-	let editor;
+	let editor, boldController;
 
 	beforeEach( () => {
-		return ClassicTestEditor.create( document.getElementById( 'editor' ), {
-				features: [ Bold ],
-				toolbar: [ 'bold' ]
+		const editorElement = document.createElement( 'div' );
+		document.body.appendChild( editorElement );
+
+		return ClassicTestEditor.create( editorElement, {
+				features: [ Bold ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;
+
+				boldController = editor.ui.featureComponents.create( 'bold' );
 			} );
 	} );
 
@@ -39,15 +44,12 @@ describe( 'Bold', () => {
 	} );
 
 	it( 'should register bold feature component', () => {
-		const controller = editor.ui.featureComponents.create( 'bold' );
-
-		expect( controller ).to.be.instanceOf( ButtonController );
+		expect( boldController ).to.be.instanceOf( ButtonController );
 	} );
 
 	it( 'should execute bold command on model execute event', () => {
 		const executeSpy = testUtils.sinon.spy( editor, 'execute' );
-		const controller = editor.ui.featureComponents.create( 'bold' );
-		const model = controller.model;
+		const model = boldController.model;
 
 		model.fire( 'execute' );
 
@@ -56,8 +58,7 @@ describe( 'Bold', () => {
 	} );
 
 	it( 'should bind model to bold command', () => {
-		const controller = editor.ui.featureComponents.create( 'bold' );
-		const model = controller.model;
+		const model = boldController.model;
 		const command = editor.commands.get( 'bold' );
 
 		expect( model.isOn ).to.be.false;
@@ -65,9 +66,18 @@ describe( 'Bold', () => {
 		expect( model.isEnabled ).to.be.true;
 
 		command.value = true;
-		expect( model.isOn ).to.equal( true );
+		expect( model.isOn ).to.be.true;
 
 		command.isEnabled = false;
-		expect( model.isEnabled ).to.equal( false );
+		expect( model.isEnabled ).to.be.false;
+	} );
+
+	it( 'should set CTRL+B keystroke', () => {
+		const spy = sinon.spy( editor, 'execute' );
+
+		const wasHandled = editor.keystrokes.press( { keyCode: keyCodes.b, ctrlKey: true } );
+
+		expect( wasHandled ).to.be.true;
+		expect( spy.calledOnce ).to.be.true;
 	} );
 } );

+ 37 - 36
packages/ckeditor5-basic-styles/tests/boldengine.js

@@ -7,13 +7,12 @@
 
 import BoldEngine from '/ckeditor5/basic-styles/boldengine.js';
 import VirtualTestEditor from '/tests/ckeditor5/_utils/virtualtesteditor.js';
-import { getData } from '/tests/engine/_utils/model.js';
-import BuildModelConverterFor from '/ckeditor5/engine/conversion/model-converter-builder.js';
-import BuildViewConverterFor from '/ckeditor5/engine/conversion/view-converter-builder.js';
+import { getData as getModelData } from '/tests/engine/_utils/model.js';
+import { getData as getViewData } from '/tests/engine/_utils/view.js';
 import AttributeCommand from '/ckeditor5/command/attributecommand.js';
 
 describe( 'BoldEngine', () => {
-	let editor, document;
+	let editor, doc;
 
 	beforeEach( () => {
 		return VirtualTestEditor.create( {
@@ -22,20 +21,9 @@ describe( 'BoldEngine', () => {
 			.then( newEditor => {
 				editor = newEditor;
 
-				document = editor.document;
+				doc = editor.document;
 
-				// Register some block element for tests.
-				document.schema.registerItem( 'p', '$block' );
-
-				// Build converter from model to view for data and editing pipelines.
-				BuildModelConverterFor( editor.data.modelToView, editor.editing.modelToView )
-					.fromElement( 'p' )
-					.toElement( 'p' );
-
-				// Build converter from view to model for data and editing pipelines.
-				BuildViewConverterFor( editor.data.viewToModel )
-					.fromElement( 'p' )
-					.toElement( 'p' );
+				doc.schema.allow( { name: '$text', inside: '$root' } );
 			} );
 	} );
 
@@ -44,36 +32,49 @@ describe( 'BoldEngine', () => {
 	} );
 
 	it( 'should set proper schema rules', () => {
-		expect( document.schema.check( { name: '$inline', attributes: [ 'bold' ] } ) ).to.be.true;
+		expect( doc.schema.check( { name: '$inline', attributes: [ 'bold' ] } ) ).to.be.true;
 	} );
 
-	it( 'should register bold command', () => {
-		expect( editor.commands.has( 'bold' ) ).to.be.true;
+	describe( 'command', () => {
+		it( 'should register bold command', () => {
+			expect( editor.commands.has( 'bold' ) ).to.be.true;
 
-		const command = editor.commands.get( 'bold' );
+			const command = editor.commands.get( 'bold' );
 
-		expect( command ).to.be.instanceOf( AttributeCommand );
-		expect( command.attributeKey ).to.equal( 'bold' );
+			expect( command ).to.be.instanceOf( AttributeCommand );
+			expect( command ).to.have.property( 'attributeKey', 'bold' );
+		} );
 	} );
 
-	it( 'should convert <strong> to bold attribute', () => {
-		editor.setData( '<p><strong>foobar</strong></p>' );
+	describe( 'data pipeline conversions', () => {
+		it( 'should convert <strong> to bold attribute', () => {
+			editor.setData( '<strong>foo</strong>bar' );
 
-		expect( getData( document, { withoutSelection: true } ) ).to.equal( '<p><$text bold=true>foobar</$text></p>' );
-		expect( editor.getData() ).to.equal( '<p><strong>foobar</strong></p>' );
-	} );
+			expect( getModelData( doc, { withoutSelection: true } ) ).to.equal( '<$text bold=true>foo</$text>bar' );
+			expect( editor.getData() ).to.equal( '<strong>foo</strong>bar' );
+		} );
+
+		it( 'should convert <b> to bold attribute', () => {
+			editor.setData( '<b>foo</b>bar' );
+
+			expect( getModelData( doc, { withoutSelection: true } ) ).to.equal( '<$text bold=true>foo</$text>bar' );
+			expect( editor.getData() ).to.equal( '<strong>foo</strong>bar' );
+		} );
 
-	it( 'should convert <b> to bold attribute', () => {
-		editor.setData( '<p><b>foobar</b></p>' );
+		it( 'should convert font-weight:bold to bold attribute', () => {
+			editor.setData( '<span style="font-weight: bold;">foo</span>bar' );
 
-		expect( getData( document, { withoutSelection: true } ) ).to.equal( '<p><$text bold=true>foobar</$text></p>' );
-		expect( editor.getData() ).to.equal( '<p><strong>foobar</strong></p>' );
+			expect( getModelData( doc, { withoutSelection: true } ) ).to.equal( '<$text bold=true>foo</$text>bar' );
+			expect( editor.getData() ).to.equal( '<strong>foo</strong>bar' );
+		} );
 	} );
 
-	it( 'should convert font-weight:bold to bold attribute', () => {
-		editor.setData( '<p><span style="font-weight: bold;">foobar</span></p>' );
+	describe( 'editing pipeline conversion', () => {
+		it( 'should convert paragraph', () => {
+			// Workaround for setting model data: https://github.com/ckeditor/ckeditor5-engine/issues/455
+			editor.setData( '<strong>foo</strong>bar' );
 
-		expect( getData( document, { withoutSelection: true } ) ).to.equal( '<p><$text bold=true>foobar</$text></p>' );
-		expect( editor.getData() ).to.equal( '<p><strong>foobar</strong></p>' );
+			expect( getViewData( editor.editing.view, { withoutSelection: true } ) ).to.equal( '<strong>foo</strong>bar' );
+		} );
 	} );
 } );

+ 0 - 1
packages/ckeditor5-basic-styles/tests/italic.html

@@ -1 +0,0 @@
-<div id="editor"></div>

+ 27 - 17
packages/ckeditor5-basic-styles/tests/italic.js

@@ -10,19 +10,24 @@ import Italic from '/ckeditor5/basic-styles/italic.js';
 import ItalicEngine from '/ckeditor5/basic-styles/italicengine.js';
 import ButtonController from '/ckeditor5/ui/button/button.js';
 import testUtils from '/tests/ckeditor5/_utils/utils.js';
+import { keyCodes } from '/ckeditor5/utils/keyboard.js';
 
 testUtils.createSinonSandbox();
 
 describe( 'Italic', () => {
-	let editor;
+	let editor, italicController;
 
 	beforeEach( () => {
-		return ClassicTestEditor.create( document.getElementById( 'editor' ), {
-				features: [ Italic ],
-				toolbar: [ 'italic' ]
+		const editorElement = document.createElement( 'div' );
+		document.body.appendChild( editorElement );
+
+		return ClassicTestEditor.create( editorElement, {
+				features: [ Italic ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;
+
+				italicController = editor.ui.featureComponents.create( 'italic' );
 			} );
 	} );
 
@@ -34,20 +39,17 @@ describe( 'Italic', () => {
 		expect( editor.plugins.get( Italic ) ).to.be.instanceOf( Italic );
 	} );
 
-	it( 'should load BoldEngine', () => {
+	it( 'should load ItalicEngine', () => {
 		expect( editor.plugins.get( ItalicEngine ) ).to.be.instanceOf( ItalicEngine );
 	} );
 
-	it( 'should register bold feature component', () => {
-		const controller = editor.ui.featureComponents.create( 'italic' );
-
-		expect( controller ).to.be.instanceOf( ButtonController );
+	it( 'should register italic feature component', () => {
+		expect( italicController ).to.be.instanceOf( ButtonController );
 	} );
 
-	it( 'should execute bold command on model execute event', () => {
+	it( 'should execute italic command on model execute event', () => {
 		const executeSpy = testUtils.sinon.spy( editor, 'execute' );
-		const controller = editor.ui.featureComponents.create( 'italic' );
-		const model = controller.model;
+		const model = italicController.model;
 
 		model.fire( 'execute' );
 
@@ -55,9 +57,8 @@ describe( 'Italic', () => {
 		sinon.assert.calledWithExactly( executeSpy, 'italic' );
 	} );
 
-	it( 'should bind model to bold command', () => {
-		const controller = editor.ui.featureComponents.create( 'italic' );
-		const model = controller.model;
+	it( 'should bind model to italic command', () => {
+		const model = italicController.model;
 		const command = editor.commands.get( 'italic' );
 
 		expect( model.isOn ).to.be.false;
@@ -65,9 +66,18 @@ describe( 'Italic', () => {
 		expect( model.isEnabled ).to.be.true;
 
 		command.value = true;
-		expect( model.isOn ).to.equal( true );
+		expect( model.isOn ).to.be.true;
 
 		command.isEnabled = false;
-		expect( model.isEnabled ).to.equal( false );
+		expect( model.isEnabled ).to.be.false;
+	} );
+
+	it( 'should set CTRL+I keystroke', () => {
+		const spy = sinon.spy( editor, 'execute' );
+
+		const wasHandled = editor.keystrokes.press( { keyCode: keyCodes.i, ctrlKey: true } );
+
+		expect( wasHandled ).to.be.true;
+		expect( spy.calledOnce ).to.be.true;
 	} );
 } );

+ 37 - 36
packages/ckeditor5-basic-styles/tests/italicengine.js

@@ -7,13 +7,12 @@
 
 import ItalicEngine from '/ckeditor5/basic-styles/italicengine.js';
 import VirtualTestEditor from '/tests/ckeditor5/_utils/virtualtesteditor.js';
-import { getData } from '/tests/engine/_utils/model.js';
-import BuildModelConverterFor from '/ckeditor5/engine/conversion/model-converter-builder.js';
-import BuildViewConverterFor from '/ckeditor5/engine/conversion/view-converter-builder.js';
+import { getData as getModelData } from '/tests/engine/_utils/model.js';
+import { getData as getViewData } from '/tests/engine/_utils/view.js';
 import AttributeCommand from '/ckeditor5/command/attributecommand.js';
 
 describe( 'ItalicEngine', () => {
-	let editor, document;
+	let editor, doc;
 
 	beforeEach( () => {
 		return VirtualTestEditor.create( {
@@ -22,20 +21,9 @@ describe( 'ItalicEngine', () => {
 			.then( newEditor => {
 				editor = newEditor;
 
-				document = editor.document;
+				doc = editor.document;
 
-				// Register some block element for tests.
-				document.schema.registerItem( 'p', '$block' );
-
-				// Build converter from model to view for data and editing pipelines.
-				BuildModelConverterFor( editor.data.modelToView, editor.editing.modelToView )
-					.fromElement( 'p' )
-					.toElement( 'p' );
-
-				// Build converter from view to model for data and editing pipelines.
-				BuildViewConverterFor( editor.data.viewToModel )
-					.fromElement( 'p' )
-					.toElement( 'p' );
+				doc.schema.allow( { name: '$text', inside: '$root' } );
 			} );
 	} );
 
@@ -44,36 +32,49 @@ describe( 'ItalicEngine', () => {
 	} );
 
 	it( 'should set proper schema rules', () => {
-		expect( document.schema.check( { name: '$inline', attributes: [ 'italic' ] } ) ).to.be.true;
+		expect( doc.schema.check( { name: '$inline', attributes: [ 'italic' ] } ) ).to.be.true;
 	} );
 
-	it( 'should register bold command', () => {
-		expect( editor.commands.has( 'italic' ) ).to.be.true;
+	describe( 'command', () => {
+		it( 'should register italic command', () => {
+			expect( editor.commands.has( 'italic' ) ).to.be.true;
 
-		const command = editor.commands.get( 'italic' );
+			const command = editor.commands.get( 'italic' );
 
-		expect( command ).to.be.instanceOf( AttributeCommand );
-		expect( command.attributeKey ).to.equal( 'italic' );
+			expect( command ).to.be.instanceOf( AttributeCommand );
+			expect( command ).to.have.property( 'attributeKey', 'italic' );
+		} );
 	} );
 
-	it( 'should convert <em> to italic attribute', () => {
-		editor.setData( '<p><em>foobar</em></p>' );
+	describe( 'data pipeline conversions', () => {
+		it( 'should convert <em> to italic attribute', () => {
+			editor.setData( '<em>foo</em>bar' );
 
-		expect( getData( document, { withoutSelection: true } ) ).to.equal( '<p><$text italic=true>foobar</$text></p>' );
-		expect( editor.getData() ).to.equal( '<p><em>foobar</em></p>' );
-	} );
+			expect( getModelData( doc, { withoutSelection: true } ) ).to.equal( '<$text italic=true>foo</$text>bar' );
+			expect( editor.getData() ).to.equal( '<em>foo</em>bar' );
+		} );
+
+		it( 'should convert <i> to italic attribute', () => {
+			editor.setData( '<i>foo</i>bar' );
+
+			expect( getModelData( doc, { withoutSelection: true } ) ).to.equal( '<$text italic=true>foo</$text>bar' );
+			expect( editor.getData() ).to.equal( '<em>foo</em>bar' );
+		} );
 
-	it( 'should convert <i> to italic attribute', () => {
-		editor.setData( '<p><i>foobar</i></p>' );
+		it( 'should convert font-weight:italic to italic attribute', () => {
+			editor.setData( '<span style="font-style: italic;">foo</span>bar' );
 
-		expect( getData( document, { withoutSelection: true } ) ).to.equal( '<p><$text italic=true>foobar</$text></p>' );
-		expect( editor.getData() ).to.equal( '<p><em>foobar</em></p>' );
+			expect( getModelData( doc, { withoutSelection: true } ) ).to.equal( '<$text italic=true>foo</$text>bar' );
+			expect( editor.getData() ).to.equal( '<em>foo</em>bar' );
+		} );
 	} );
 
-	it( 'should convert font-style:italic to italic attribute', () => {
-		editor.setData( '<p><span style="font-style: italic;">foobar</span></p>' );
+	describe( 'editing pipeline conversion', () => {
+		it( 'should convert paragraph', () => {
+			// Workaround for setting model data: https://github.com/ckeditor/ckeditor5-engine/issues/455
+			editor.setData( '<em>foo</em>bar' );
 
-		expect( getData( document, { withoutSelection: true } ) ).to.equal( '<p><$text italic=true>foobar</$text></p>' );
-		expect( editor.getData() ).to.equal( '<p><em>foobar</em></p>' );
+			expect( getViewData( editor.editing.view, { withoutSelection: true } ) ).to.equal( '<em>foo</em>bar' );
+		} );
 	} );
 } );

+ 2 - 2
packages/ckeditor5-basic-styles/tests/manual/basic-styles.html

@@ -2,6 +2,6 @@
 	<link rel="stylesheet" href="%APPS_DIR%ckeditor/build/amd/theme/ckeditor.css">
 </head>
 
-<div id="editor1">
-	<p>Hello world!</p>
+<div id="editor">
+	<p><em>This</em> is an <strong>editor</strong> instance.</p>
 </div>

+ 4 - 8
packages/ckeditor5-basic-styles/tests/manual/basic-styles.js

@@ -7,15 +7,11 @@
 
 'use strict';
 
-import CKEDITOR from '/ckeditor.js';
-import ClassicCreator from '/ckeditor5/creator-classic/classiccreator.js';
-import Bold from '/ckeditor5/basic-styles/bold.js';
-import Italic from '/ckeditor5/basic-styles/italic.js';
+import ClassicEditor from '/ckeditor5/creator-classic/classic.js';
 
-CKEDITOR.create( '#editor1', {
-	creator: ClassicCreator,
-	features: [ Bold, Italic ],
-	toolbar: [ 'bold', 'italic' ]
+ClassicEditor.create( document.querySelector( '#editor' ), {
+	features: [ 'delete', 'enter', 'typing', 'paragraph', 'undo', 'basic-styles/bold', 'basic-styles/italic' ],
+	toolbar: [ 'bold', 'italic', 'undo', 'redo' ]
 } )
 .then( editor => {
 	window.editor = editor;

+ 6 - 1
packages/ckeditor5-basic-styles/tests/manual/basic-styles.md

@@ -1,3 +1,8 @@
 @bender-ui: collapsed
+
 ## Basic styles
-TODO: Create valid test description once features are finished.
+
+1. The data should be loaded with:
+  * italic "This",
+  * bold "editor".
+2. Test the bold and italic features live.