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

Merge pull request #210 from ckeditor/i/6089

Internal: `Context#editors` is now public property and a `Collection` instance which allows for listening to adding an editor to a `Context`. Closes ckeditor/ckeditor5#6089.
Piotrek Koszuliński 6 лет назад
Родитель
Сommit
7735f3eff4

+ 9 - 6
packages/ckeditor5-core/src/context.js

@@ -8,6 +8,7 @@
  */
 
 import Config from '@ckeditor/ckeditor5-utils/src/config';
+import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import PluginCollection from './plugincollection';
 import Locale from '@ckeditor/ckeditor5-utils/src/locale';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
@@ -86,10 +87,10 @@ export default class Context {
 		/**
 		 * List of editors to which this context instance is injected.
 		 *
-		 * @private
-		 * @type {Set.<module:core/editor/editor~Editor>}
+		 * @readonly
+		 * @type {module:utils/collection~Collection}
 		 */
-		this._editors = new Set();
+		this.editors = new Collection();
 
 		/**
 		 * Reference to the editor which created the context.
@@ -151,7 +152,7 @@ export default class Context {
 	 * @returns {Promise} A promise that resolves once the context instance is fully destroyed.
 	 */
 	destroy() {
-		return Promise.all( Array.from( this._editors, editor => editor.destroy() ) )
+		return Promise.all( Array.from( this.editors, editor => editor.destroy() ) )
 			.then( () => this.plugins.destroy() );
 	}
 
@@ -179,7 +180,7 @@ export default class Context {
 			);
 		}
 
-		this._editors.add( editor );
+		this.editors.add( editor );
 
 		if ( isContextOwner ) {
 			this._contextOwner = editor;
@@ -197,7 +198,9 @@ export default class Context {
 	 * @return {Promise} A promise that resolves once the editor is removed from the context or when the context has been destroyed.
 	 */
 	_removeEditor( editor ) {
-		this._editors.delete( editor );
+		if ( this.editors.has( editor ) ) {
+			this.editors.remove( editor );
+		}
 
 		if ( this._contextOwner === editor ) {
 			return this.destroy();

+ 35 - 0
packages/ckeditor5-core/tests/context.js

@@ -49,6 +49,26 @@ describe( 'Context', () => {
 		} );
 	} );
 
+	describe( 'editors', () => {
+		it( 'should keep all the editors created within the context and fire event:add whenever an editor is added', async () => {
+			const spy = sinon.spy();
+			const context = await Context.create();
+
+			context.editors.on( 'add', spy );
+
+			const editorA = await VirtualTestEditor.create( { context } );
+
+			expect( spy.calledOnce );
+
+			const editorB = await VirtualTestEditor.create( { context } );
+
+			expect( spy.calledTwice );
+
+			expect( context.editors.has( editorA ) );
+			expect( context.editors.has( editorB ) );
+		} );
+	} );
+
 	describe( 'locale', () => {
 		it( 'is instantiated and t() is exposed', () => {
 			const context = new Context();
@@ -260,5 +280,20 @@ describe( 'Context', () => {
 			sinon.assert.calledOnce( editorB.destroy );
 			sinon.assert.notCalled( editorC.destroy );
 		} );
+
+		it( 'should not crash when destroyed for the second time', async () => {
+			const context = await Context.create();
+
+			await VirtualTestEditor.create( { context } );
+			await context.destroy();
+			await context.destroy();
+		} );
+
+		it( 'should not crash when destroyed for the second time - editor own managed context', async () => {
+			const editor = await VirtualTestEditor.create();
+
+			await editor.destroy();
+			await editor.destroy();
+		} );
 	} );
 } );

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

@@ -43,7 +43,9 @@ describe( 'attachToForm()', () => {
 		submitStub.restore();
 		form.remove();
 
-		return editor.destroy();
+		if ( editor ) {
+			return editor.destroy();
+		}
 	} );
 
 	it( 'should throw an error when is used with editor without `ElementApiMixin`', () => {
@@ -126,6 +128,7 @@ describe( 'attachToForm()', () => {
 		expect( textarea.value ).to.equal( '' );
 
 		return editor.destroy().then( () => {
+			editor = null;
 			// Submit method is no longer replaced by our implementation.
 			expect( form.submit ).to.equal( submitStub );
 			form.submit();
@@ -141,6 +144,8 @@ describe( 'attachToForm()', () => {
 		expect( textarea.value ).to.equal( '' );
 
 		return editor.destroy().then( () => {
+			editor = null;
+
 			form.dispatchEvent( new Event( 'submit', {
 				// We need to be able to do preventDefault() to prevent page reloads in Firefox.
 				cancelable: true
@@ -172,6 +177,8 @@ describe( 'attachToForm()', () => {
 		expect( textarea.value ).to.equal( 'foo bar' );
 
 		return editor.destroy().then( () => {
+			editor = null;
+
 			expect( form.submit ).to.equal( input );
 			input.remove();
 		} );

+ 2 - 0
packages/ckeditor5-core/tests/editor/utils/securesourceelement.js

@@ -53,6 +53,8 @@ describe( 'secureSourceElement()', () => {
 
 		return editor.destroy()
 			.then( () => {
+				editor = null;
+
 				expect( sourceElement.ckeditorInstance ).to.be.undefined;
 			} );
 	} );