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

WIP - Changing EmitterMixin to a custom event emitter.

Maciej Bukowski пре 6 година
родитељ
комит
c8c9291e76

+ 1 - 1
packages/ckeditor5-watchdog/package.json

@@ -9,7 +9,6 @@
     "ckeditor5-lib"
   ],
   "dependencies": {
-    "@ckeditor/ckeditor5-utils": "^16.0.0",
     "lodash-es": "^4.17.10"
   },
   "devDependencies": {
@@ -17,6 +16,7 @@
     "@ckeditor/ckeditor5-editor-classic": "^16.0.0",
     "@ckeditor/ckeditor5-engine": "^16.0.0",
     "@ckeditor/ckeditor5-paragraph": "^16.0.0",
+    "@ckeditor/ckeditor5-utils": "^16.0.0",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^2.4.1",

+ 9 - 2
packages/ckeditor5-watchdog/src/contextwatchdog.js

@@ -102,6 +102,7 @@ export default class ContextWatchdog extends Watchdog {
 		this._actionQueue.onEmpty( () => {
 			if ( this.state === 'initializing' ) {
 				this.state = 'ready';
+				this.fire( 'stateChange' );
 			}
 		} );
 
@@ -276,11 +277,15 @@ export default class ContextWatchdog extends Watchdog {
 						}
 
 						this._actionQueue.enqueue( () => new Promise( res => {
-							watchdog.once( 'restart', () => {
+							watchdog.on( 'restart', rethrowRestartEventOnce );
+
+							function rethrowRestartEventOnce() {
+								watchdog.off( 'restart', rethrowRestartEventOnce );
+
 								this.fire( 'itemRestart', { itemId: item.id } );
 
 								res();
-							} );
+							}
 						} ) );
 					} );
 
@@ -331,6 +336,7 @@ export default class ContextWatchdog extends Watchdog {
 	destroy() {
 		return this._actionQueue.enqueue( () => {
 			this.state = 'destroyed';
+			this.fire( 'stateChange' );
 
 			super.destroy();
 
@@ -347,6 +353,7 @@ export default class ContextWatchdog extends Watchdog {
 	_restart() {
 		return this._actionQueue.enqueue( () => {
 			this.state = 'initializing';
+			this.fire( 'stateChange' );
 
 			return this._destroy()
 				.catch( err => {

+ 4 - 1
packages/ckeditor5-watchdog/src/editorwatchdog.js

@@ -140,6 +140,7 @@ export default class EditorWatchdog extends Watchdog {
 		return Promise.resolve()
 			.then( () => {
 				this.state = 'initializing';
+				this.fire( 'stateChange' );
 
 				return this._destroy();
 			} )
@@ -189,12 +190,13 @@ export default class EditorWatchdog extends Watchdog {
 			.then( editor => {
 				this._editor = editor;
 
-				this.listenTo( editor.model.document, 'change:data', this._throttledSave );
+				editor.model.document.on( 'change:data', this._throttledSave );
 
 				this._lastDocumentVersion = editor.model.document.version;
 				this._data = this._getData();
 
 				this.state = 'ready';
+				this.fire( 'stateChange' );
 			} );
 	}
 
@@ -208,6 +210,7 @@ export default class EditorWatchdog extends Watchdog {
 		return Promise.resolve()
 			.then( () => {
 				this.state = 'destroyed';
+				this.fire( 'stateChange' );
 
 				super.destroy();
 

+ 80 - 0
packages/ckeditor5-watchdog/src/simpleeventemitter.js

@@ -0,0 +1,80 @@
+/**
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/**
+ * @module watchdog/simpleeventemitter
+ */
+
+/**
+ * @private
+ */
+export default class SimpleEventEmitter {
+	constructor() {
+		/**
+		 * Simple event emitter listeners
+		 *
+		 * @private
+		 * @type {Object.<String,Array.<Function>>}
+		 */
+		this._listeners = {};
+	}
+
+	/**
+	 * Starts listening to the specific event name by registering a callback that will be executed
+	 * when the event with the given name will be fired.
+	 *
+	 * Note that this method differs from the CKEditor 5's default `EventEmitterMixin` implementation.
+	 *
+	 * @param {String} eventName
+	 * @param {Function} callback
+	 */
+	on( eventName, callback ) {
+		if ( !this._listeners[ eventName ] ) {
+			this._listeners[ eventName ] = [];
+		}
+
+		this._listeners[ eventName ].push( callback );
+	}
+
+	/**
+	 * Stops listening to the specified event name by removing the callback.
+	 *
+	 * Note that this method differs from the CKEditor 5's default `EventEmitterMixin` implementation.
+	 *
+	 * @param {String} eventName
+	 * @param {Function} callback
+	 */
+	off( eventName, callback ) {
+		if ( !this._listeners[ eventName ] ) {
+			return;
+		}
+
+		this._listeners[ eventName ] = this._listeners[ eventName ]
+			.filter( cb => cb !== callback );
+	}
+
+	/**
+	 * Fires an event with the given event name and arguments.
+	 *
+	 * Note that this method differs from the CKEditor 5's default `EventEmitterMixin` implementation.
+	 *
+	 * @param {String} eventName
+	 * @param  {...any} args
+	 */
+	fire( eventName, ...args ) {
+		const callbacks = this._listeners[ eventName ] || [];
+
+		for ( const callback of callbacks ) {
+			callback.apply( this, [ null, ...args ] );
+		}
+	}
+
+	/**
+	 * Destroys all listeners and releases the resources associated to this instance.
+	 */
+	destroy() {
+		this._listeners = {};
+	}
+}

+ 10 - 9
packages/ckeditor5-watchdog/src/watchdog.js

@@ -9,8 +9,7 @@
 
 /* globals window */
 
-import mix from '@ckeditor/ckeditor5-utils/src/mix';
-import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
+import SimpleEventEmitter from './simpleeventemitter';
 
 /**
  * An abstract watchdog class that handles most of the error handling process and the state of the underlying component.
@@ -20,11 +19,13 @@ import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
  * @private
  * @abstract
  */
-export default class Watchdog {
+export default class Watchdog extends SimpleEventEmitter {
 	/**
 	 * @param {module:watchdog/watchdog~WatchdogConfig} config The watchdog plugin configuration.
 	 */
 	constructor( config ) {
+		super();
+
 		/**
 		 * An array of crashes saved as an object with the following properties:
 		 *
@@ -52,10 +53,9 @@ export default class Watchdog {
 		 * * `destroyed` - a state when the instance is manually destroyed by the user after calling `watchdog.destroy()`
 		 *
 		 * @public
-		 * @observable
 		 * @member {'initializing'|'ready'|'crashed'|'crashedPermanently'|'destroyed'} #state
 		 */
-		this.set( 'state', 'initializing' );
+		this.state = 'initializing';
 
 		/**
 		 * @protected
@@ -166,11 +166,12 @@ export default class Watchdog {
 	}
 
 	/**
-	 * Destroys the watchdog and release the resources.
+	 * Destroys the watchdog and releases the resources.
 	 */
 	destroy() {
 		this._stopErrorHandling();
-		this.stopListening();
+
+		super.destroy();
 	}
 
 	/**
@@ -222,12 +223,14 @@ export default class Watchdog {
 			const causesRestart = this._shouldRestart();
 
 			this.state = 'crashed';
+			this.fire( 'stateChange' );
 			this.fire( 'error', { error, causesRestart } );
 
 			if ( causesRestart ) {
 				this._restart();
 			} else {
 				this.state = 'crashedPermanently';
+				this.fire( 'stateChange' );
 			}
 		}
 	}
@@ -283,8 +286,6 @@ export default class Watchdog {
 	 */
 }
 
-mix( Watchdog, ObservableMixin );
-
 /**
  * The watchdog plugin configuration.
  *

+ 26 - 44
packages/ckeditor5-watchdog/tests/editorwatchdog.js

@@ -862,15 +862,6 @@ describe( 'EditorWatchdog', () => {
 	} );
 
 	describe( 'state', () => {
-		let orphanEditors = [];
-
-		afterEach( () => {
-			return Promise.all( orphanEditors.map( editor => editor.destroy() ) )
-				.then( () => {
-					orphanEditors = [];
-				} );
-		} );
-
 		it( 'should reflect the state of the watchdog', async () => {
 			const watchdog = new EditorWatchdog( ClassicTestEditor );
 
@@ -882,7 +873,6 @@ describe( 'EditorWatchdog', () => {
 
 			await watchdog.create( element );
 
-			orphanEditors.push( watchdog.editor );
 			expect( watchdog.state ).to.equal( 'ready' );
 
 			await watchdog.create( element );
@@ -905,48 +895,40 @@ describe( 'EditorWatchdog', () => {
 			const watchdog = new EditorWatchdog( ClassicTestEditor );
 			const states = [];
 
-			watchdog.on( 'change:state', ( evt, propName, newValue ) => {
-				states.push( newValue );
+			watchdog.on( 'stateChanged', () => {
+				states.push( watchdog.state );
 			} );
 
 			const originalErrorHandler = window.onerror;
 			window.onerror = undefined;
 
-			return watchdog.create( element ).then( () => {
-				orphanEditors.push( watchdog.editor );
+			await watchdog.create( element );
 
-				return watchdog.create( element ).then( () => {
-					setTimeout( () => throwCKEditorError( 'foo', watchdog.editor ) );
-					setTimeout( () => throwCKEditorError( 'bar', watchdog.editor ) );
-					setTimeout( () => throwCKEditorError( 'baz', watchdog.editor ) );
-					setTimeout( () => throwCKEditorError( 'biz', watchdog.editor ) );
+			setTimeout( () => throwCKEditorError( 'foo', watchdog.editor ) );
+			setTimeout( () => throwCKEditorError( 'bar', watchdog.editor ) );
+			setTimeout( () => throwCKEditorError( 'baz', watchdog.editor ) );
+			setTimeout( () => throwCKEditorError( 'biz', watchdog.editor ) );
 
-					return new Promise( res => {
-						setTimeout( () => {
-							window.onerror = originalErrorHandler;
+			await waitCycle();
 
-							watchdog.destroy().then( () => {
-								expect( states ).to.deep.equal( [
-									'ready',
-									'crashed',
-									'initializing',
-									'ready',
-									'crashed',
-									'initializing',
-									'ready',
-									'crashed',
-									'initializing',
-									'ready',
-									'crashed',
-									'crashedPermanently',
-									'destroyed'
-								] );
-
-								res();
-							} );
-						} );
-					} );
-				} );
+			window.onerror = originalErrorHandler;
+
+			watchdog.destroy().then( () => {
+				expect( states ).to.deep.equal( [
+					'ready',
+					'crashed',
+					'initializing',
+					'ready',
+					'crashed',
+					'initializing',
+					'ready',
+					'crashed',
+					'initializing',
+					'ready',
+					'crashed',
+					'crashedPermanently',
+					'destroyed'
+				] );
 			} );
 		} );
 	} );