8
0
Просмотр исходного кода

Merge branch 'master' into t/64

Kamil Piechaczek 7 лет назад
Родитель
Сommit
b5fa9f123b

+ 14 - 5
packages/ckeditor5-core/src/editor/editor.js

@@ -239,17 +239,26 @@ export default class Editor {
 	/**
 	 * Destroys the editor instance, releasing all resources used by it.
 	 *
+	 * **Note** The editor can not be destroyed during the initialization phase so
+	 * this methods waits for the editor initialization before destroying.
+	 *
 	 * @fires destroy
 	 * @returns {Promise} A promise that resolves once the editor instance is fully destroyed.
 	 */
 	destroy() {
-		this.fire( 'destroy' );
-
-		this.stopListening();
+		let readyPromise = Promise.resolve();
 
-		this.commands.destroy();
+		if ( this.state == 'initializing' ) {
+			readyPromise = new Promise( resolve => this.once( 'ready', resolve ) );
+		}
 
-		return this.plugins.destroy()
+		return readyPromise
+			.then( () => {
+				this.fire( 'destroy' );
+				this.stopListening();
+				this.commands.destroy();
+			} )
+			.then( () => this.plugins.destroy() )
 			.then( () => {
 				this.model.destroy();
 				this.data.destroy();

+ 92 - 0
packages/ckeditor5-core/src/editor/editorui.js

@@ -0,0 +1,92 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module core/editor/editorui
+ */
+
+import ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';
+import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
+
+import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
+import mix from '@ckeditor/ckeditor5-utils/src/mix';
+
+/**
+ * A class providing the minimal interface that is required to successfully bootstrap any editor UI.
+ *
+ * @mixes module:utils/emittermixin~EmitterMixin
+ */
+export default class EditorUI {
+	/**
+	 * Creates an instance of the editor UI class.
+	 *
+	 * @param {module:core/editor/editor~Editor} editor The editor instance.
+	 * @param {module:ui/editorui/editoruiview~EditorUIView} view The view of the UI.
+	 */
+	constructor( editor, view ) {
+		/**
+		 * The editor that the UI belongs to.
+		 *
+		 * @readonly
+		 * @member {module:core/editor/editor~Editor} #editor
+		 */
+		this.editor = editor;
+
+		/**
+		 * The main (top–most) view of the editor UI.
+		 *
+		 * @readonly
+		 * @member {module:ui/editorui/editoruiview~EditorUIView} #view
+		 */
+		this.view = view;
+
+		/**
+		 * An instance of the {@link module:ui/componentfactory~ComponentFactory}, a registry used by plugins
+		 * to register factories of specific UI components.
+		 *
+		 * @readonly
+		 * @member {module:ui/componentfactory~ComponentFactory} #componentFactory
+		 */
+		this.componentFactory = new ComponentFactory( editor );
+
+		/**
+		 * Stores the information about the editor UI focus and propagates it so various plugins and components
+		 * are unified as a focus group.
+		 *
+		 * @readonly
+		 * @member {module:utils/focustracker~FocusTracker} #focusTracker
+		 */
+		this.focusTracker = new FocusTracker();
+
+		// Informs UI components that should be refreshed after layout change.
+		this.listenTo( editor.editing.view.document, 'layoutChanged', () => this.update() );
+	}
+
+	/**
+	 * Fires the {@link module:core/editor/editorui~EditorUI#event:update} event.
+	 */
+	update() {
+		this.fire( 'update' );
+	}
+
+	/**
+	 * Destroys the UI.
+	 */
+	destroy() {
+		this.stopListening();
+		this.view.destroy();
+	}
+
+	/**
+	 * Fired whenever the UI (all related components) should be refreshed.
+	 *
+	 * **Note:**: The event is fired after each {@link module:engine/view/document~Document#event:layoutChanged}.
+	 * It can also be fired manually via the {@link module:core/editor/editorui~EditorUI#update} method.
+	 *
+	 * @event update
+	 */
+}
+
+mix( EditorUI, EmitterMixin );

+ 0 - 44
packages/ckeditor5-core/src/editor/editorui.jsdoc

@@ -1,44 +0,0 @@
-/**
- * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/**
- * @module core/editor/editorui
- */
-
-/**
- * Minimal interface that is required to successfully bootstrap any editor UI.
- *
- * @interface EditorUI
- */
-
-/**
- * Editor that the UI belongs to.
- *
- * @readonly
- * @member {module:core/editor/editor~Editor} #editor
- */
-
-/**
- * The main (top–most) view of the editor UI.
- *
- * @readonly
- * @member {module:ui/editorui/editoruiview~EditorUIView} #view
- */
-
-/**
- * Instance of the {@link module:ui/componentfactory~ComponentFactory}, a registry used by plugins
- * to register factories of specific UI components.
- *
- * @readonly
- * @member {module:ui/componentfactory~ComponentFactory} #componentFactory
- */
-
-/**
- * Keeps information about editor UI focus and propagates it among various plugins and components,
- * unifying them in a uniform focus group.
- *
- * @readonly
- * @member {module:utils/focustracker~FocusTracker} #focusTracker
- */

+ 3 - 3
packages/ckeditor5-core/tests/_utils-tests/classictesteditor.js

@@ -11,7 +11,7 @@ import ClassicTestEditor from '../../tests/_utils/classictesteditor';
 import Plugin from '../../src/plugin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
 
-import ClassicTestEditorUI from '../../tests/_utils/classictesteditorui';
+import EditorUI from '../../src/editor/editorui';
 import BoxedEditorUIView from '@ckeditor/ckeditor5-ui/src/editorui/boxed/boxededitoruiview';
 import InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';
 
@@ -39,7 +39,7 @@ describe( 'ClassicTestEditor', () => {
 			expect( editor ).to.be.instanceof( Editor );
 			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
 			expect( editor.element ).to.equal( editorElement );
-			expect( editor.ui ).to.be.instanceOf( ClassicTestEditorUI );
+			expect( editor.ui ).to.be.instanceOf( EditorUI );
 			expect( editor.ui.view ).to.be.instanceOf( BoxedEditorUIView );
 			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
 		} );
@@ -82,7 +82,7 @@ describe( 'ClassicTestEditor', () => {
 		it( 'creates and initializes the UI', () => {
 			return ClassicTestEditor.create( editorElement, { foo: 1 } )
 				.then( editor => {
-					expect( editor.ui ).to.be.instanceOf( ClassicTestEditorUI );
+					expect( editor.ui ).to.be.instanceOf( EditorUI );
 					expect( editor.ui.view ).to.be.instanceOf( BoxedEditorUIView );
 				} );
 		} );

+ 0 - 46
packages/ckeditor5-core/tests/_utils-tests/classictesteditorui.js

@@ -1,46 +0,0 @@
-/**
- * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-import ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';
-import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
-import ClassicTestEditorUI from '../../tests/_utils/classictesteditorui';
-import View from '@ckeditor/ckeditor5-ui/src/view';
-
-describe( 'ClassicTestEditorUI', () => {
-	let editor, view, ui;
-
-	beforeEach( () => {
-		editor = {};
-		view = new View();
-		ui = new ClassicTestEditorUI( editor, view );
-	} );
-
-	describe( 'constructor()', () => {
-		it( 'sets #editor', () => {
-			expect( ui.editor ).to.equal( editor );
-		} );
-
-		it( 'sets #view', () => {
-			expect( ui.view ).to.equal( view );
-		} );
-
-		it( 'creates #componentFactory factory', () => {
-			expect( ui.componentFactory ).to.be.instanceOf( ComponentFactory );
-		} );
-
-		it( 'creates #focusTracker', () => {
-			expect( ui.focusTracker ).to.be.instanceOf( FocusTracker );
-		} );
-	} );
-
-	describe( 'destroy()', () => {
-		it( 'destroys the #view', () => {
-			const spy = sinon.spy( view, 'destroy' );
-
-			ui.destroy();
-			sinon.assert.calledOnce( spy );
-		} );
-	} );
-} );

+ 6 - 4
packages/ckeditor5-core/tests/_utils-tests/modeltesteditor.js

@@ -29,12 +29,14 @@ describe( 'ModelTestEditor', () => {
 
 		it( 'should disable editing pipeline', () => {
 			const spy = sinon.spy( EditingController.prototype, 'destroy' );
-			const editor = new ModelTestEditor( { foo: 1 } );
 
-			sinon.assert.calledOnce( spy );
+			return ModelTestEditor.create( { foo: 1 } ).then( editor => {
+				sinon.assert.calledOnce( spy );
+
+				spy.restore();
 
-			spy.restore();
-			return editor.destroy();
+				return editor.destroy();
+			} );
 		} );
 
 		it( 'creates main root element', () => {

+ 2 - 2
packages/ckeditor5-core/tests/_utils/classictesteditor.js

@@ -7,7 +7,7 @@ import Editor from '../../src/editor/editor';
 import ElementApiMixin from '../../src/editor/utils/elementapimixin';
 import DataApiMixin from '../../src/editor/utils/dataapimixin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
-import ClassicTestEditorUI from './classictesteditorui';
+import EditorUI from '../../src/editor/editorui';
 import BoxedEditorUIView from '@ckeditor/ckeditor5-ui/src/editorui/boxed/boxededitoruiview';
 import ElementReplacer from '@ckeditor/ckeditor5-utils/src/elementreplacer';
 import InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';
@@ -33,7 +33,7 @@ export default class ClassicTestEditor extends Editor {
 		// Use the HTML data processor in this editor.
 		this.data.processor = new HtmlDataProcessor();
 
-		this.ui = new ClassicTestEditorUI( this, new BoxedEditorUIView( this.locale ) );
+		this.ui = new EditorUI( this, new BoxedEditorUIView( this.locale ) );
 
 		// Expose properties normally exposed by the ClassicEditorUI.
 		this.ui.view.editable = new InlineEditableUIView( this.ui.view.locale );

+ 0 - 63
packages/ckeditor5-core/tests/_utils/classictesteditorui.js

@@ -1,63 +0,0 @@
-/**
- * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-import ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';
-import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
-
-/**
- * A simplified classic editor UI class. Useful for testing features.
- *
- * @memberOf tests.core._utils
- * @extends ui.View
- */
-export default class ClassicTestEditorUI {
-	/**
-	 * Creates an instance of the test editor UI class.
-	 *
-	 * @param {core.editor.Editor} editor The editor instance.
-	 * @param {ui.editorUI.EditorUIView} view View of the ui.
-	 */
-	constructor( editor, view ) {
-		/**
-		 * Editor that the UI belongs to.
-		 *
-		 * @readonly
-		 * @member {core.editor.Editor} tests.core._utils.ClassicTestEditorUI#editor
-		 */
-		this.editor = editor;
-
-		/**
-		 * View of the ui.
-		 *
-		 * @readonly
-		 * @member {ui.editorUI.EditorUIView} tests.core._utils.ClassicTestEditorUI#view
-		 */
-		this.view = view;
-
-		/**
-		 * Instance of the {@link ui.ComponentFactory}.
-		 *
-		 * @readonly
-		 * @member {ui.ComponentFactory} tests.core._utils.ClassicTestEditorUI#componentFactory
-		 */
-		this.componentFactory = new ComponentFactory( editor );
-
-		/**
-		 * Keeps information about editor focus.
-		 *
-		 * @member {utils.FocusTracker} tests.core._utils.ClassicTestEditorUI#focusTracker
-		 */
-		this.focusTracker = new FocusTracker();
-	}
-
-	/**
-	 * Destroys the UI.
-	 *
-	 * @returns {Promise} A Promise resolved when the destruction process is finished.
-	 */
-	destroy() {
-		this.view.destroy();
-	}
-}

+ 38 - 22
packages/ckeditor5-core/tests/editor/editor.js

@@ -197,10 +197,10 @@ describe( 'Editor', () => {
 		} );
 
 		it( 'is `destroyed` after editor destroy', () => {
-			const editor = new Editor();
-
-			return editor.destroy().then( () => {
-				expect( editor.state ).to.equal( 'destroyed' );
+			return Editor.create().then( editor => {
+				return editor.destroy().then( () => {
+					expect( editor.state ).to.equal( 'destroyed' );
+				} );
 			} );
 		} );
 
@@ -283,33 +283,49 @@ describe( 'Editor', () => {
 
 	describe( 'destroy()', () => {
 		it( 'should fire "destroy"', () => {
-			const editor = new Editor();
-			const spy = sinon.spy();
+			return Editor.create().then( editor => {
+				const spy = sinon.spy();
 
-			editor.on( 'destroy', spy );
+				editor.on( 'destroy', spy );
 
-			return editor.destroy().then( () => {
-				expect( spy.calledOnce ).to.be.true;
+				return editor.destroy().then( () => {
+					expect( spy.calledOnce ).to.be.true;
+				} );
 			} );
 		} );
 
 		it( 'should destroy all components it initialized', () => {
+			return Editor.create().then( editor => {
+				const dataDestroySpy = sinon.spy( editor.data, 'destroy' );
+				const modelDestroySpy = sinon.spy( editor.model, 'destroy' );
+				const editingDestroySpy = sinon.spy( editor.editing, 'destroy' );
+				const pluginsDestroySpy = sinon.spy( editor.plugins, 'destroy' );
+				const keystrokesDestroySpy = sinon.spy( editor.keystrokes, 'destroy' );
+
+				return editor.destroy()
+					.then( () => {
+						sinon.assert.calledOnce( dataDestroySpy );
+						sinon.assert.calledOnce( modelDestroySpy );
+						sinon.assert.calledOnce( editingDestroySpy );
+						sinon.assert.calledOnce( pluginsDestroySpy );
+						sinon.assert.calledOnce( keystrokesDestroySpy );
+					} );
+			} );
+		} );
+
+		it( 'should wait for the full init before destroying', done => {
+			const spy = sinon.spy();
 			const editor = new Editor();
 
-			const dataDestroySpy = sinon.spy( editor.data, 'destroy' );
-			const modelDestroySpy = sinon.spy( editor.model, 'destroy' );
-			const editingDestroySpy = sinon.spy( editor.editing, 'destroy' );
-			const pluginsDestroySpy = sinon.spy( editor.plugins, 'destroy' );
-			const keystrokesDestroySpy = sinon.spy( editor.keystrokes, 'destroy' );
+			editor.on( 'destroy', () => {
+				done();
+			} );
 
-			return editor.destroy()
-				.then( () => {
-					sinon.assert.calledOnce( dataDestroySpy );
-					sinon.assert.calledOnce( modelDestroySpy );
-					sinon.assert.calledOnce( editingDestroySpy );
-					sinon.assert.calledOnce( pluginsDestroySpy );
-					sinon.assert.calledOnce( keystrokesDestroySpy );
-				} );
+			editor.destroy();
+
+			sinon.assert.notCalled( spy );
+
+			editor.fire( 'ready' );
 		} );
 	} );
 

+ 98 - 0
packages/ckeditor5-core/tests/editor/editorui.js

@@ -0,0 +1,98 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import EditorUI from '../../src/editor/editorui';
+import Editor from '../../src/editor/editor';
+
+import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
+import ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';
+import View from '@ckeditor/ckeditor5-ui/src/view';
+
+import testUtils from '../_utils/utils';
+
+testUtils.createSinonSandbox();
+
+describe( 'EditorUI', () => {
+	let editor, view, ui;
+
+	beforeEach( () => {
+		editor = new Editor();
+		view = new View();
+		ui = new EditorUI( editor, view );
+	} );
+
+	afterEach( () => {
+		return Promise.all( [
+			editor.destroy(),
+			ui.destroy()
+		] );
+	} );
+
+	describe( 'constructor()', () => {
+		it( 'should set #editor', () => {
+			expect( ui.editor ).to.equal( editor );
+		} );
+
+		it( 'should set #view', () => {
+			expect( ui.view ).to.equal( view );
+		} );
+
+		it( 'should create #componentFactory factory', () => {
+			expect( ui.componentFactory ).to.be.instanceOf( ComponentFactory );
+		} );
+
+		it( 'should create #focusTracker', () => {
+			expect( ui.focusTracker ).to.be.instanceOf( FocusTracker );
+		} );
+
+		it( 'should fire update event after viewDocument#layoutChanged', () => {
+			const spy = sinon.spy();
+
+			ui.on( 'update', spy );
+
+			editor.editing.view.document.fire( 'layoutChanged' );
+
+			sinon.assert.calledOnce( spy );
+
+			editor.editing.view.document.fire( 'layoutChanged' );
+
+			sinon.assert.calledTwice( spy );
+		} );
+	} );
+
+	describe( 'update()', () => {
+		it( 'should fire update event', () => {
+			const spy = sinon.spy();
+
+			ui.on( 'update', spy );
+
+			ui.update();
+
+			sinon.assert.calledOnce( spy );
+
+			ui.update();
+
+			sinon.assert.calledTwice( spy );
+		} );
+	} );
+
+	describe( 'destroy()', () => {
+		it( 'should stop listening', () => {
+			const spy = sinon.spy( ui, 'stopListening' );
+
+			ui.destroy();
+
+			sinon.assert.called( spy );
+		} );
+
+		it( 'should destroy the #view', () => {
+			const spy = sinon.spy( view, 'destroy' );
+
+			ui.destroy();
+
+			sinon.assert.called( spy );
+		} );
+	} );
+} );

+ 1 - 0
packages/ckeditor5-core/tests/editor/utils/attachtoform.js

@@ -34,6 +34,7 @@ describe( 'attachToForm()', () => {
 		editor.data.processor = new HtmlDataProcessor();
 		editor.model.document.createRoot();
 		editor.model.schema.extend( '$text', { allowIn: '$root' } );
+		editor.fire( 'ready' );
 
 		editor.data.set( 'foo bar' );
 	} );