Browse Source

Merge pull request #132 from ckeditor/t/124

Feature: Added the observable `Editor#state` property. Closes #124.
Piotrek Koszuliński 7 years ago
parent
commit
a227ca494f

+ 23 - 0
packages/ckeditor5-core/src/editor/editor.js

@@ -105,6 +105,24 @@ export default class Editor {
 		this.t = this.locale.t;
 
 		/**
+		 * Indicates the editor life-cycle state.
+		 *
+		 * The editor is in one of the following states:
+		 *
+		 * * `initializing` - during the editor initialization (before {@link module:core/editor/editor~Editor.create `Editor.create()`)
+		 * finished its job,
+		 * * `ready` - after the promise returned by the {@link module:core/editor/editor~Editor.create `Editor.create()`}
+		 * method is resolved,
+		 * * `destroyed` - once the {@link #destroy `editor.destroy()`} method was called.
+		 *
+		 * @observable
+		 * @member {'initializing'|'ready'|'destroyed'} #state
+		 */
+		this.set( 'state', 'initializing' );
+		this.once( 'ready', () => ( this.state = 'ready' ), { priority: 'high' } );
+		this.once( 'destroy', () => ( this.state = 'destroyed' ), { priority: 'high' } );
+
+		/**
 		 * Defines whether this editor is in read-only mode.
 		 *
 		 * In read-only mode the editor {@link #commands commands} are disabled so it is not possible
@@ -303,6 +321,8 @@ mix( Editor, ObservableMixin );
  * In fact, since the first moment when the editor instance is available to you is inside `then()`'s callback,
  * you cannot even add a listener to the `editor#ready` event.
  *
+ * See also the {@link #state `editor.state`} property.
+ *
  * @event ready
  */
 
@@ -310,6 +330,9 @@ mix( Editor, ObservableMixin );
  * Fired when this editor instance is destroyed. The editor at this point is not usable and this event should be used to
  * perform the clean-up in any plugin.
  *
+ *
+ * See also the {@link #state `editor.state`} property.
+ *
  * @event destroy
  */
 

+ 14 - 0
packages/ckeditor5-core/tests/_utils-tests/classictesteditor.js

@@ -129,6 +129,20 @@ describe( 'ClassicTestEditor', () => {
 				} );
 		} );
 
+		it( 'sets proper states', () => {
+			const editor = new ClassicTestEditor();
+
+			expect( editor.state ).to.equal( 'initializing' );
+
+			return ClassicTestEditor.create( editorElement ).then( editor => {
+				expect( editor.state ).to.equal( 'ready' );
+
+				return editor.destroy().then( () => {
+					expect( editor.state ).to.equal( 'destroyed' );
+				} );
+			} );
+		} );
+
 		it( 'inserts editor UI next to editor element', () => {
 			return ClassicTestEditor.create( editorElement )
 				.then( editor => {

+ 0 - 36
packages/ckeditor5-core/tests/_utils-tests/modeltesteditor.js

@@ -7,7 +7,6 @@ import Editor from '../../src/editor/editor';
 import EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';
 import ModelTestEditor from '../../tests/_utils/modeltesteditor';
 
-import Plugin from '../../src/plugin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
 import DataApiMixin from '../../src/editor/utils/dataapimixin';
 import RootElement from '@ckeditor/ckeditor5-engine/src/model/rootelement';
@@ -49,41 +48,6 @@ describe( 'ModelTestEditor', () => {
 		} );
 	} );
 
-	describe( 'create', () => {
-		it( 'creates an instance of editor', () => {
-			return ModelTestEditor.create( { foo: 1 } )
-				.then( editor => {
-					expect( editor ).to.be.instanceof( ModelTestEditor );
-
-					expect( editor.config.get( 'foo' ) ).to.equal( 1 );
-				} );
-		} );
-
-		it( 'fires all events in the right order', () => {
-			const fired = [];
-
-			function spy( evt ) {
-				fired.push( evt.name );
-			}
-
-			class EventWatcher extends Plugin {
-				init() {
-					this.editor.on( 'pluginsReady', spy );
-					this.editor.on( 'dataReady', spy );
-					this.editor.on( 'ready', spy );
-				}
-			}
-
-			return ModelTestEditor
-				.create( {
-					plugins: [ EventWatcher ]
-				} )
-				.then( () => {
-					expect( fired ).to.deep.equal( [ 'pluginsReady', 'dataReady', 'ready' ] );
-				} );
-		} );
-	} );
-
 	describe( 'setData', () => {
 		let editor;
 

+ 0 - 36
packages/ckeditor5-core/tests/_utils-tests/virtualtesteditor.js

@@ -6,7 +6,6 @@
 import Editor from '../../src/editor/editor';
 import VirtualTestEditor from '../../tests/_utils/virtualtesteditor';
 
-import Plugin from '../../src/plugin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
 import DataApiMixin from '../../src/editor/utils/dataapimixin';
 import RootElement from '@ckeditor/ckeditor5-engine/src/model/rootelement';
@@ -35,39 +34,4 @@ describe( 'VirtualTestEditor', () => {
 			expect( testUtils.isMixed( VirtualTestEditor, DataApiMixin ) ).to.true;
 		} );
 	} );
-
-	describe( 'create', () => {
-		it( 'creates an instance of editor', () => {
-			return VirtualTestEditor.create( { foo: 1 } )
-				.then( editor => {
-					expect( editor ).to.be.instanceof( VirtualTestEditor );
-
-					expect( editor.config.get( 'foo' ) ).to.equal( 1 );
-				} );
-		} );
-
-		it( 'fires all events in the right order', () => {
-			const fired = [];
-
-			function spy( evt ) {
-				fired.push( evt.name );
-			}
-
-			class EventWatcher extends Plugin {
-				init() {
-					this.editor.on( 'pluginsReady', spy );
-					this.editor.on( 'dataReady', spy );
-					this.editor.on( 'ready', spy );
-				}
-			}
-
-			return VirtualTestEditor
-				.create( {
-					plugins: [ EventWatcher ]
-				} )
-				.then( () => {
-					expect( fired ).to.deep.equal( [ 'pluginsReady', 'dataReady', 'ready' ] );
-				} );
-		} );
-	} );
 } );

+ 1 - 0
packages/ckeditor5-core/tests/_utils/classictesteditor.js

@@ -75,6 +75,7 @@ export default class ClassicTestEditor extends Editor {
 					.then( () => editor.data.init( getDataFromElement( element ) ) )
 					.then( () => {
 						editor.fire( 'dataReady' );
+						editor.state = 'ready';
 						editor.fire( 'ready' );
 					} )
 					.then( () => editor )

+ 0 - 22
packages/ckeditor5-core/tests/_utils/modeltesteditor.js

@@ -29,28 +29,6 @@ export default class ModelTestEditor extends Editor {
 		// Create the ("main") root element of the model tree.
 		this.model.document.createRoot();
 	}
-
-	/**
-	 * Creates a virtual, element-less editor instance.
-	 *
-	 * @param {Object} config See {@link core.editor.Editor}'s param.
-	 * @returns {Promise} Promise resolved once editor is ready.
-	 * @returns {core.editor.VirtualTestEditor} return.editor The editor instance.
-	 */
-	static create( config ) {
-		return new Promise( resolve => {
-			const editor = new this( config );
-
-			resolve(
-				editor.initPlugins()
-					.then( () => {
-						editor.fire( 'dataReady' );
-						editor.fire( 'ready' );
-					} )
-					.then( () => editor )
-			);
-		} );
-	}
 }
 
 mix( ModelTestEditor, DataApiMixin );

+ 0 - 22
packages/ckeditor5-core/tests/_utils/virtualtesteditor.js

@@ -26,28 +26,6 @@ export default class VirtualTestEditor extends Editor {
 		// Create the ("main") root element of the model tree.
 		this.model.document.createRoot();
 	}
-
-	/**
-	 * Creates a virtual, element-less editor instance.
-	 *
-	 * @param {Object} config See {@link core.editor.Editor}'s param.
-	 * @returns {Promise} Promise resolved once editor is ready.
-	 * @returns {core.editor.VirtualTestEditor} return.editor The editor instance.
-	 */
-	static create( config ) {
-		return new Promise( resolve => {
-			const editor = new this( config );
-
-			resolve(
-				editor.initPlugins()
-					.then( () => {
-						editor.fire( 'dataReady' );
-						editor.fire( 'ready' );
-					} )
-					.then( () => editor )
-			);
-		} );
-	}
 }
 
 mix( VirtualTestEditor, DataApiMixin );

+ 61 - 0
packages/ckeditor5-core/tests/editor/editor.js

@@ -181,6 +181,67 @@ describe( 'Editor', () => {
 		} );
 	} );
 
+	describe( 'state', () => {
+		it( 'is `initializing` initially', () => {
+			const editor = new Editor();
+
+			expect( editor.state ).to.equal( 'initializing' );
+		} );
+
+		it( 'is `ready` after initialization chain', () => {
+			return Editor.create().then( editor => {
+				expect( editor.state ).to.equal( 'ready' );
+
+				return editor.destroy();
+			} );
+		} );
+
+		it( 'is `destroyed` after editor destroy', () => {
+			const editor = new Editor();
+
+			return editor.destroy().then( () => {
+				expect( editor.state ).to.equal( 'destroyed' );
+			} );
+		} );
+
+		it( 'is observable', () => {
+			const editor = new Editor();
+			const spy = sinon.spy();
+
+			editor.on( 'change:state', spy );
+
+			editor.state = 'ready';
+
+			sinon.assert.calledOnce( spy );
+		} );
+
+		it( 'reacts on #ready event', done => {
+			const editor = new Editor();
+
+			expect( editor.state ).to.equal( 'initializing' );
+
+			editor.on( 'ready', () => {
+				expect( editor.state ).to.equal( 'ready' );
+				done();
+			} );
+
+			editor.fire( 'ready' );
+		} );
+
+		it( 'reacts on #destroy event', done => {
+			const editor = new Editor();
+
+			expect( editor.state ).to.equal( 'initializing' );
+
+			editor.on( 'destroy', () => {
+				expect( editor.state ).to.equal( 'destroyed' );
+				done();
+			} );
+
+			editor.fire( 'destroy' );
+		} );
+	} );
+
 	describe( 'isReadOnly', () => {
 		it( 'is false initially', () => {
 			const editor = new Editor();