From 2655a6b062f3cd409f31d021b7fcaa5a736447b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Wed, 23 Jan 2019 11:49:53 +0100 Subject: [PATCH 01/11] Introduced `plugins.ready` event. --- src/editor/editor.js | 43 ++++++++++++----------------------------- src/plugincollection.js | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/editor/editor.js b/src/editor/editor.js index ccafa12a..3fa82aa6 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -224,30 +224,17 @@ export default class Editor { const that = this; const config = this.config; - return loadPlugins() - .then( loadedPlugins => { - return initPlugins( loadedPlugins, 'init' ) - .then( () => initPlugins( loadedPlugins, 'afterInit' ) ); - } ) - .then( () => this.fire( 'pluginsReady' ) ); - - function loadPlugins() { - const plugins = config.get( 'plugins' ) || []; - const removePlugins = config.get( 'removePlugins' ) || []; - const extraPlugins = config.get( 'extraPlugins' ) || []; - - return that.plugins.load( plugins.concat( extraPlugins ), removePlugins ); - } - - function initPlugins( loadedPlugins, method ) { - return loadedPlugins.reduce( ( promise, plugin ) => { - if ( !plugin[ method ] ) { - return promise; - } + return Promise.resolve() + .then( () => { + const plugins = config.get( 'plugins' ) || []; + const removePlugins = config.get( 'removePlugins' ) || []; + const extraPlugins = config.get( 'extraPlugins' ) || []; - return promise.then( plugin[ method ].bind( plugin ) ); - }, Promise.resolve() ); - } + return that.plugins.load( plugins.concat( extraPlugins ), removePlugins ); + } ) + .then( loadedPlugins => { + return this.plugins.init( loadedPlugins ); + } ); } /** @@ -321,12 +308,6 @@ export default class Editor { mix( Editor, ObservableMixin ); -/** - * Fired after {@link #initPlugins plugins are initialized}. - * - * @event pluginsReady - */ - /** * Fired when the data loaded to the editor is ready. If a specific editor doesn't load * any data initially, this event will be fired right before {@link #event:ready}. @@ -335,8 +316,8 @@ mix( Editor, ObservableMixin ); */ /** - * Fired when {@link #event:pluginsReady plugins}, and {@link #event:dataReady data} and all additional - * editor components are ready. + * Fired when {@link module:core/plugincollection~PluginCollection#event:ready plugins}, + * and {@link #event:dataReady data} and all additional editor components are ready. * * Note: This event is most useful for plugin developers. When integrating the editor with your website or * application you do not have to listen to `editor#ready` because when the promise returned by the static diff --git a/src/plugincollection.js b/src/plugincollection.js index eddd0b79..b295bf9a 100644 --- a/src/plugincollection.js +++ b/src/plugincollection.js @@ -10,8 +10,13 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import log from '@ckeditor/ckeditor5-utils/src/log'; +import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin'; +import mix from '@ckeditor/ckeditor5-utils/src/mix'; + /** * Manages a list of CKEditor plugins, including loading, resolving dependencies and initialization. + * + * @mixes module:utils/emittermixin~EmitterMixin */ export default class PluginCollection { /** @@ -293,6 +298,29 @@ export default class PluginCollection { } } + /** + * Runs the initialisation process ({@link module:core/plugin~Plugin#init `init()`} + * and {@link module:core/plugin~Plugin#afterInit `afterInit()`} methods) for the given set of plugins. + * + * @param {} plugins The array of plugins to initialise. + * @returns {Promise} A promise which resolves after all given plugins have been initialized. + */ + init( plugins ) { + return initPlugins( plugins, 'init' ) + .then( () => initPlugins( plugins, 'afterInit' ) ) + .then( () => { this.fire( 'ready' ); } ); + + function initPlugins( loadedPlugins, method ) { + return loadedPlugins.reduce( ( promise, plugin ) => { + if ( !plugin[ method ] ) { + return promise; + } + + return promise.then( plugin[ method ].bind( plugin ) ); + }, Promise.resolve() ); + } + } + /** * Destroys all loaded plugins. * @@ -363,3 +391,11 @@ export default class PluginCollection { } } } + +mix( PluginCollection, EmitterMixin ); + +/** + * Fired after {@link #init plugins are initialized}. + * + * @event ready + */ From 4c0a650ae77ddbf36634928328c82b23d40032a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Wed, 23 Jan 2019 13:35:43 +0100 Subject: [PATCH 02/11] Docs: Fixed link. --- src/editor/editorui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/editorui.js b/src/editor/editorui.js index a69c3177..0a12049a 100644 --- a/src/editor/editorui.js +++ b/src/editor/editorui.js @@ -125,7 +125,7 @@ export default class EditorUI { /** * Fired when the editor UI is ready. * - * Fired after {@link module:core/editor/editor~Editor#event:pluginsReady} and before + * Fired after {@link module:core/plugincollection~PluginCollection#event:ready} and before * {@link module:core/editor/editor~Editor#event:dataReady}. * * @event ready From 71fff8497151e4833de45ec3764017017ee0262c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Wed, 23 Jan 2019 13:36:44 +0100 Subject: [PATCH 03/11] Tests: Adjust unit tests to new event. --- tests/_utils-tests/classictesteditor.js | 11 ++++++++--- tests/editor/editor.js | 18 +++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/tests/_utils-tests/classictesteditor.js b/tests/_utils-tests/classictesteditor.js index 8b0ad00d..bfa3d41e 100644 --- a/tests/_utils-tests/classictesteditor.js +++ b/tests/_utils-tests/classictesteditor.js @@ -116,12 +116,12 @@ describe( 'ClassicTestEditor', () => { const fired = []; function spy( evt ) { - fired.push( evt.name ); + fired.push( `${ evt.name }-${ evt.source.constructor.name.toLowerCase() }` ); } class EventWatcher extends Plugin { init() { - this.editor.on( 'pluginsReady', spy ); + this.editor.plugins.on( 'ready', spy ); this.editor.ui.on( 'ready', spy ); this.editor.on( 'dataReady', spy ); this.editor.on( 'ready', spy ); @@ -133,7 +133,12 @@ describe( 'ClassicTestEditor', () => { plugins: [ EventWatcher ] } ) .then( editor => { - expect( fired ).to.deep.equal( [ 'pluginsReady', 'ready', 'dataReady', 'ready' ] ); + expect( fired ).to.deep.equal( [ + 'ready-plugincollection', + 'ready-classictesteditorui', + 'dataReady-classictesteditor', + 'ready-classictesteditor' + ] ); return editor.destroy(); } ); diff --git a/tests/editor/editor.js b/tests/editor/editor.js index d7215650..72f47e98 100644 --- a/tests/editor/editor.js +++ b/tests/editor/editor.js @@ -380,12 +380,12 @@ describe( 'Editor', () => { const fired = []; function spy( evt ) { - fired.push( evt.name ); + fired.push( `${ evt.name }-${ evt.source.constructor.name.toLowerCase() }` ); } class EventWatcher extends Plugin { init() { - this.editor.on( 'pluginsReady', spy ); + this.editor.plugins.on( 'ready', spy ); this.editor.on( 'dataReady', spy ); this.editor.on( 'ready', spy ); } @@ -393,7 +393,7 @@ describe( 'Editor', () => { return Editor.create( { plugins: [ EventWatcher ] } ) .then( () => { - expect( fired ).to.deep.equal( [ 'pluginsReady', 'dataReady', 'ready' ] ); + expect( fired ).to.deep.equal( [ 'ready-plugincollection', 'dataReady-editor', 'ready-editor' ] ); } ); } ); } ); @@ -419,8 +419,8 @@ describe( 'Editor', () => { plugins: [ PluginA, PluginD ] } ); - const pluginsReadySpy = sinon.spy().named( 'pluginsReady' ); - editor.on( 'pluginsReady', pluginsReadySpy ); + const pluginsReadySpy = sinon.spy().named( 'ready' ); + editor.plugins.on( 'ready', pluginsReadySpy ); return editor.initPlugins() .then( () => { @@ -738,8 +738,8 @@ describe( 'Editor', () => { plugins: [ PluginA, PluginE ] } ); - const pluginsReadySpy = sinon.spy().named( 'pluginsReady' ); - editor.on( 'pluginsReady', pluginsReadySpy ); + const pluginsReadySpy = sinon.spy().named( 'ready' ); + editor.plugins.on( 'ready', pluginsReadySpy ); return editor.initPlugins() .then( () => { @@ -757,8 +757,8 @@ describe( 'Editor', () => { plugins: [ PluginA, PluginF ] } ); - const pluginsReadySpy = sinon.spy().named( 'pluginsReady' ); - editor.on( 'pluginsReady', pluginsReadySpy ); + const pluginsReadySpy = sinon.spy().named( 'ready' ); + editor.plugins.on( 'ready', pluginsReadySpy ); return editor.initPlugins() .then( () => { From 6210186e427ec651578d5dc7e62952ff6f5f7ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Wed, 23 Jan 2019 14:51:43 +0100 Subject: [PATCH 04/11] Adjustments to new `data#ready` event. --- src/editor/editor.js | 12 +++--------- src/editor/editorui.js | 2 +- src/plugin.js | 2 +- tests/_utils-tests/classictesteditor.js | 4 ++-- tests/_utils/classictesteditor.js | 1 - tests/editor/editor.js | 4 ++-- 6 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/editor/editor.js b/src/editor/editor.js index 3fa82aa6..61c7db85 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -297,7 +297,8 @@ export default class Editor { resolve( editor.initPlugins() .then( () => { - editor.fire( 'dataReady' ); + // Fire `data#ready` event manually as `data#init()` method is not used. + editor.data.fire( 'ready' ); editor.fire( 'ready' ); } ) .then( () => editor ) @@ -308,16 +309,9 @@ export default class Editor { mix( Editor, ObservableMixin ); -/** - * Fired when the data loaded to the editor is ready. If a specific editor doesn't load - * any data initially, this event will be fired right before {@link #event:ready}. - * - * @event dataReady - */ - /** * Fired when {@link module:core/plugincollection~PluginCollection#event:ready plugins}, - * and {@link #event:dataReady data} and all additional editor components are ready. + * and {@link module:engine/controller/datacontroller~DataController#event:ready data} and all additional editor components are ready. * * Note: This event is most useful for plugin developers. When integrating the editor with your website or * application you do not have to listen to `editor#ready` because when the promise returned by the static diff --git a/src/editor/editorui.js b/src/editor/editorui.js index 0a12049a..a4c0f97c 100644 --- a/src/editor/editorui.js +++ b/src/editor/editorui.js @@ -126,7 +126,7 @@ export default class EditorUI { * Fired when the editor UI is ready. * * Fired after {@link module:core/plugincollection~PluginCollection#event:ready} and before - * {@link module:core/editor/editor~Editor#event:dataReady}. + * {@link module:engine/controller/datacontroller~DataController#event:ready}. * * @event ready */ diff --git a/src/plugin.js b/src/plugin.js index 9d6b8168..5cdc637b 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -70,7 +70,7 @@ mix( Plugin, ObservableMixin ); * // `listenTo()` and `editor` are available thanks to `Plugin`. * // By using `listenTo()` you will ensure that the listener is removed when * // the plugin is destroyed. - * this.listenTo( this.editor, 'dataReady', () => { + * this.listenTo( this.editor.data, 'ready', () => { * // Do something when the data is ready. * } ); * } diff --git a/tests/_utils-tests/classictesteditor.js b/tests/_utils-tests/classictesteditor.js index bfa3d41e..74ecc0e8 100644 --- a/tests/_utils-tests/classictesteditor.js +++ b/tests/_utils-tests/classictesteditor.js @@ -123,7 +123,7 @@ describe( 'ClassicTestEditor', () => { init() { this.editor.plugins.on( 'ready', spy ); this.editor.ui.on( 'ready', spy ); - this.editor.on( 'dataReady', spy ); + this.editor.data.on( 'ready', spy ); this.editor.on( 'ready', spy ); } } @@ -136,7 +136,7 @@ describe( 'ClassicTestEditor', () => { expect( fired ).to.deep.equal( [ 'ready-plugincollection', 'ready-classictesteditorui', - 'dataReady-classictesteditor', + 'ready-datacontroller', 'ready-classictesteditor' ] ); diff --git a/tests/_utils/classictesteditor.js b/tests/_utils/classictesteditor.js index dd7589e2..c25164d2 100644 --- a/tests/_utils/classictesteditor.js +++ b/tests/_utils/classictesteditor.js @@ -66,7 +66,6 @@ export default class ClassicTestEditor extends Editor { .then( () => editor.editing.view.attachDomRoot( editor.ui.getEditableElement() ) ) .then( () => editor.data.init( getDataFromElement( element ) ) ) .then( () => { - editor.fire( 'dataReady' ); editor.state = 'ready'; editor.fire( 'ready' ); } ) diff --git a/tests/editor/editor.js b/tests/editor/editor.js index 72f47e98..b470f145 100644 --- a/tests/editor/editor.js +++ b/tests/editor/editor.js @@ -386,14 +386,14 @@ describe( 'Editor', () => { class EventWatcher extends Plugin { init() { this.editor.plugins.on( 'ready', spy ); - this.editor.on( 'dataReady', spy ); + this.editor.data.on( 'ready', spy ); this.editor.on( 'ready', spy ); } } return Editor.create( { plugins: [ EventWatcher ] } ) .then( () => { - expect( fired ).to.deep.equal( [ 'ready-plugincollection', 'dataReady-editor', 'ready-editor' ] ); + expect( fired ).to.deep.equal( [ 'ready-plugincollection', 'ready-datacontroller', 'ready-editor' ] ); } ); } ); } ); From 74369e4767d269a11194bc05919614665ec25ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Thu, 24 Jan 2019 11:22:39 +0100 Subject: [PATCH 05/11] Docs: Typo fix. --- src/plugincollection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugincollection.js b/src/plugincollection.js index b295bf9a..4d684aff 100644 --- a/src/plugincollection.js +++ b/src/plugincollection.js @@ -302,7 +302,7 @@ export default class PluginCollection { * Runs the initialisation process ({@link module:core/plugin~Plugin#init `init()`} * and {@link module:core/plugin~Plugin#afterInit `afterInit()`} methods) for the given set of plugins. * - * @param {} plugins The array of plugins to initialise. + * @param {Array.} plugins The array of plugins to initialise. * @returns {Promise} A promise which resolves after all given plugins have been initialized. */ init( plugins ) { From 60d06c394c8aeeb7d3bb7cb138e67b24d529fede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Thu, 24 Jan 2019 14:16:00 +0100 Subject: [PATCH 06/11] Make `Editor` class abstract and remove `Editor#create` static method. --- src/editor/editor.js | 25 +------ tests/_utils/modeltesteditor.js | 16 +++++ tests/_utils/virtualtesteditor.js | 16 +++++ tests/editor/editor.js | 110 +++++++++++++++++------------- 4 files changed, 97 insertions(+), 70 deletions(-) diff --git a/src/editor/editor.js b/src/editor/editor.js index 61c7db85..5072dff4 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -42,6 +42,7 @@ import '@ckeditor/ckeditor5-utils/src/version'; * the specific editor implements also the {@link module:core/editor/editorwithui~EditorWithUI} interface * (as most editor implementations do). * + * @abstract * @mixes module:utils/observablemixin~ObservableMixin */ export default class Editor { @@ -281,30 +282,6 @@ export default class Editor { execute( ...args ) { this.commands.execute( ...args ); } - - /** - * Creates and initializes a new editor instance. - * - * @param {Object} config The editor config. You can find the list of config options in - * {@link module:core/editor/editorconfig~EditorConfig}. - * @returns {Promise} Promise resolved once editor is ready. - * @returns {module:core/editor/editor~Editor} return.editor The editor instance. - */ - static create( config ) { - return new Promise( resolve => { - const editor = new this( config ); - - resolve( - editor.initPlugins() - .then( () => { - // Fire `data#ready` event manually as `data#init()` method is not used. - editor.data.fire( 'ready' ); - editor.fire( 'ready' ); - } ) - .then( () => editor ) - ); - } ); - } } mix( Editor, ObservableMixin ); diff --git a/tests/_utils/modeltesteditor.js b/tests/_utils/modeltesteditor.js index 64aeb43e..fcfb2319 100644 --- a/tests/_utils/modeltesteditor.js +++ b/tests/_utils/modeltesteditor.js @@ -29,6 +29,22 @@ export default class ModelTestEditor extends Editor { // Create the ("main") root element of the model tree. this.model.document.createRoot(); } + + static create( config ) { + return new Promise( resolve => { + const editor = new this( config ); + + resolve( + editor.initPlugins() + .then( () => { + // Fire `data#ready` event manually as `data#init()` method is not used. + editor.data.fire( 'ready' ); + editor.fire( 'ready' ); + } ) + .then( () => editor ) + ); + } ); + } } mix( ModelTestEditor, DataApiMixin ); diff --git a/tests/_utils/virtualtesteditor.js b/tests/_utils/virtualtesteditor.js index 77c89dc5..be8b5caf 100644 --- a/tests/_utils/virtualtesteditor.js +++ b/tests/_utils/virtualtesteditor.js @@ -26,6 +26,22 @@ export default class VirtualTestEditor extends Editor { // Create the ("main") root element of the model tree. this.model.document.createRoot(); } + + static create( config ) { + return new Promise( resolve => { + const editor = new this( config ); + + resolve( + editor.initPlugins() + .then( () => { + // Fire `data#ready` event manually as `data#init()` method is not used. + editor.data.fire( 'ready' ); + editor.fire( 'ready' ); + } ) + .then( () => editor ) + ); + } ); + } } mix( VirtualTestEditor, DataApiMixin ); diff --git a/tests/editor/editor.js b/tests/editor/editor.js index b470f145..5ce6b5f7 100644 --- a/tests/editor/editor.js +++ b/tests/editor/editor.js @@ -16,6 +16,24 @@ import Locale from '@ckeditor/ckeditor5-utils/src/locale'; import Command from '../../src/command'; import EditingKeystrokeHandler from '../../src/editingkeystrokehandler'; +class TestEditor extends Editor { + static create( config ) { + return new Promise( resolve => { + const editor = new this( config ); + + resolve( + editor.initPlugins() + .then( () => { + // Fire `data#ready` event manually as `data#init()` method is not used. + editor.data.fire( 'ready' ); + editor.fire( 'ready' ); + } ) + .then( () => editor ) + ); + } ); + } +} + class PluginA extends Plugin { constructor( editor ) { super( editor ); @@ -96,8 +114,8 @@ class PluginF { describe( 'Editor', () => { afterEach( () => { - delete Editor.builtinPlugins; - delete Editor.defaultConfig; + delete TestEditor.builtinPlugins; + delete TestEditor.defaultConfig; } ); it( 'imports the version helper', () => { @@ -106,7 +124,7 @@ describe( 'Editor', () => { describe( 'constructor()', () => { it( 'should create a new editor instance', () => { - const editor = new Editor(); + const editor = new TestEditor(); expect( editor.config ).to.be.an.instanceof( Config ); expect( editor.commands ).to.be.an.instanceof( CommandCollection ); @@ -125,7 +143,7 @@ describe( 'Editor', () => { } }; - const editor = new Editor( { + const editor = new TestEditor( { bar: 'foo', foo: { c: 3 @@ -142,7 +160,7 @@ describe( 'Editor', () => { } ); it( 'should bind editing.view.document#isReadOnly to the editor', () => { - const editor = new Editor(); + const editor = new TestEditor(); editor.isReadOnly = false; @@ -155,7 +173,7 @@ describe( 'Editor', () => { it( 'should activate #keystrokes', () => { const spy = sinon.spy( EditingKeystrokeHandler.prototype, 'listenTo' ); - const editor = new Editor(); + const editor = new TestEditor(); sinon.assert.calledWith( spy, editor.editing.view.document ); } ); @@ -163,7 +181,7 @@ describe( 'Editor', () => { describe( 'plugins', () => { it( 'should be empty on new editor', () => { - const editor = new Editor(); + const editor = new TestEditor(); expect( getPlugins( editor ) ).to.be.empty; } ); @@ -171,14 +189,14 @@ describe( 'Editor', () => { describe( 'locale', () => { it( 'is instantiated and t() is exposed', () => { - const editor = new Editor(); + const editor = new TestEditor(); expect( editor.locale ).to.be.instanceof( Locale ); expect( editor.t ).to.equal( editor.locale.t ); } ); it( 'is configured with the config.language', () => { - const editor = new Editor( { language: 'pl' } ); + const editor = new TestEditor( { language: 'pl' } ); expect( editor.locale.language ).to.equal( 'pl' ); } ); @@ -186,13 +204,13 @@ describe( 'Editor', () => { describe( 'state', () => { it( 'is `initializing` initially', () => { - const editor = new Editor(); + const editor = new TestEditor(); expect( editor.state ).to.equal( 'initializing' ); } ); it( 'is `ready` after initialization chain', () => { - return Editor.create().then( editor => { + return TestEditor.create().then( editor => { expect( editor.state ).to.equal( 'ready' ); return editor.destroy(); @@ -200,7 +218,7 @@ describe( 'Editor', () => { } ); it( 'is `destroyed` after editor destroy', () => { - return Editor.create().then( editor => { + return TestEditor.create().then( editor => { return editor.destroy().then( () => { expect( editor.state ).to.equal( 'destroyed' ); } ); @@ -208,7 +226,7 @@ describe( 'Editor', () => { } ); it( 'is observable', () => { - const editor = new Editor(); + const editor = new TestEditor(); const spy = sinon.spy(); editor.on( 'change:state', spy ); @@ -219,7 +237,7 @@ describe( 'Editor', () => { } ); it( 'reacts on #ready event', done => { - const editor = new Editor(); + const editor = new TestEditor(); expect( editor.state ).to.equal( 'initializing' ); @@ -232,7 +250,7 @@ describe( 'Editor', () => { } ); it( 'reacts on #destroy event', done => { - const editor = new Editor(); + const editor = new TestEditor(); expect( editor.state ).to.equal( 'initializing' ); @@ -247,13 +265,13 @@ describe( 'Editor', () => { describe( 'isReadOnly', () => { it( 'is false initially', () => { - const editor = new Editor(); + const editor = new TestEditor(); expect( editor.isReadOnly ).to.false; } ); it( 'is observable', () => { - const editor = new Editor(); + const editor = new TestEditor(); const spy = sinon.spy(); editor.on( 'change:isReadOnly', spy ); @@ -266,13 +284,13 @@ describe( 'Editor', () => { describe( 'conversion', () => { it( 'should have conversion property', () => { - const editor = new Editor(); + const editor = new TestEditor(); expect( editor ).to.have.property( 'conversion' ); } ); it( 'should have defined default conversion groups', () => { - const editor = new Editor(); + const editor = new TestEditor(); expect( () => { // Would throw if any of this group won't exist. @@ -286,7 +304,7 @@ describe( 'Editor', () => { describe( 'destroy()', () => { it( 'should fire "destroy"', () => { - return Editor.create().then( editor => { + return TestEditor.create().then( editor => { const spy = sinon.spy(); editor.on( 'destroy', spy ); @@ -298,7 +316,7 @@ describe( 'Editor', () => { } ); it( 'should destroy all components it initialized', () => { - return Editor.create().then( editor => { + return TestEditor.create().then( editor => { const dataDestroySpy = sinon.spy( editor.data, 'destroy' ); const modelDestroySpy = sinon.spy( editor.model, 'destroy' ); const editingDestroySpy = sinon.spy( editor.editing, 'destroy' ); @@ -318,7 +336,7 @@ describe( 'Editor', () => { it( 'should wait for the full init before destroying', done => { const spy = sinon.spy(); - const editor = new Editor(); + const editor = new TestEditor(); editor.on( 'destroy', () => { done(); @@ -338,7 +356,7 @@ describe( 'Editor', () => { execute() {} } - const editor = new Editor(); + const editor = new TestEditor(); const command = new SomeCommand( editor ); sinon.spy( command, 'execute' ); @@ -350,7 +368,7 @@ describe( 'Editor', () => { } ); it( 'should throw an error if specified command has not been added', () => { - const editor = new Editor(); + const editor = new TestEditor(); expect( () => { editor.execute( 'command' ); @@ -360,7 +378,7 @@ describe( 'Editor', () => { describe( 'create()', () => { it( 'should return a promise that resolves properly', () => { - const promise = Editor.create(); + const promise = TestEditor.create(); expect( promise ).to.be.an.instanceof( Promise ); @@ -368,7 +386,7 @@ describe( 'Editor', () => { } ); it( 'loads plugins', () => { - return Editor.create( { plugins: [ PluginA ] } ) + return TestEditor.create( { plugins: [ PluginA ] } ) .then( editor => { expect( getPlugins( editor ).length ).to.equal( 1 ); @@ -391,16 +409,16 @@ describe( 'Editor', () => { } } - return Editor.create( { plugins: [ EventWatcher ] } ) + return TestEditor.create( { plugins: [ EventWatcher ] } ) .then( () => { - expect( fired ).to.deep.equal( [ 'ready-plugincollection', 'ready-datacontroller', 'ready-editor' ] ); + expect( fired ).to.deep.equal( [ 'ready-plugincollection', 'ready-datacontroller', 'ready-testeditor' ] ); } ); } ); } ); describe( 'initPlugins()', () => { it( 'should load plugins', () => { - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginB ] } ); @@ -415,7 +433,7 @@ describe( 'Editor', () => { } ); it( 'should initialize plugins in the right order', () => { - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginD ] } ); @@ -468,7 +486,7 @@ describe( 'Editor', () => { } } - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginSync ] } ); @@ -514,7 +532,7 @@ describe( 'Editor', () => { } } - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginSync ] } ); @@ -534,7 +552,7 @@ describe( 'Editor', () => { it( 'should load plugins built in the Editor even if the passed config is empty', () => { Editor.builtinPlugins = [ PluginA, PluginB, PluginC ]; - const editor = new Editor(); + const editor = new TestEditor(); return editor.initPlugins() .then( () => { @@ -549,7 +567,7 @@ describe( 'Editor', () => { it( 'should load plugins provided in the config and should ignore plugins built in the Editor', () => { Editor.builtinPlugins = [ PluginA, PluginB, PluginC, PluginD ]; - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ 'A' ] @@ -568,7 +586,7 @@ describe( 'Editor', () => { Editor.builtinPlugins = [ PluginA, PluginB, PluginC, PluginD ]; - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ 'A', 'B', @@ -591,7 +609,7 @@ describe( 'Editor', () => { it( 'should load plugins inherited from the base Editor', () => { Editor.builtinPlugins = [ PluginA, PluginB, PluginC, PluginD ]; - class CustomEditor extends Editor {} + class CustomEditor extends TestEditor {} const editor = new CustomEditor( { plugins: [ @@ -610,7 +628,7 @@ describe( 'Editor', () => { } ); it( 'should load plugins build into Editor\'s subclass', () => { - class CustomEditor extends Editor {} + class CustomEditor extends TestEditor {} CustomEditor.builtinPlugins = [ PluginA, PluginB, PluginC, PluginD ]; @@ -632,7 +650,7 @@ describe( 'Editor', () => { describe( '"removePlugins" config', () => { it( 'should prevent plugins from being loaded', () => { - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginD ], removePlugins: [ PluginD ] } ); @@ -647,7 +665,7 @@ describe( 'Editor', () => { it( 'should not load plugins built in the Editor', () => { Editor.builtinPlugins = [ PluginA, PluginD ]; - const editor = new Editor( { + const editor = new TestEditor( { removePlugins: [ 'D' ] } ); @@ -659,7 +677,7 @@ describe( 'Editor', () => { } ); it( 'should not load plugins build into Editor\'s subclass', () => { - class CustomEditor extends Editor {} + class CustomEditor extends TestEditor {} CustomEditor.builtinPlugins = [ PluginA, PluginD ]; @@ -677,7 +695,7 @@ describe( 'Editor', () => { describe( '"extraPlugins" config', () => { it( 'should load additional plugins', () => { - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginC ], extraPlugins: [ PluginB ] } ); @@ -690,7 +708,7 @@ describe( 'Editor', () => { } ); it( 'should not duplicate plugins', () => { - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginB ], extraPlugins: [ PluginB ] } ); @@ -705,7 +723,7 @@ describe( 'Editor', () => { it( 'should not duplicate plugins built in the Editor', () => { Editor.builtinPlugins = [ PluginA, PluginB ]; - const editor = new Editor( { + const editor = new TestEditor( { extraPlugins: [ 'B' ] } ); @@ -717,7 +735,7 @@ describe( 'Editor', () => { } ); it( 'should not duplicate plugins build into Editor\'s subclass', () => { - class CustomEditor extends Editor {} + class CustomEditor extends TestEditor {} CustomEditor.builtinPlugins = [ PluginA, PluginB ]; @@ -734,7 +752,7 @@ describe( 'Editor', () => { } ); it( 'should not call "afterInit" method if plugin does not have this method', () => { - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginE ] } ); @@ -753,7 +771,7 @@ describe( 'Editor', () => { } ); it( 'should not call "init" method if plugin does not have this method', () => { - const editor = new Editor( { + const editor = new TestEditor( { plugins: [ PluginA, PluginF ] } ); From b7ec3bfdd648ed90e9c5ef7d4f5e20aa33fffee2 Mon Sep 17 00:00:00 2001 From: Piotr Jasiun Date: Thu, 24 Jan 2019 17:45:51 +0100 Subject: [PATCH 07/11] Apply suggestions from code review Co-Authored-By: f1ames --- src/editor/editor.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/editor/editor.js b/src/editor/editor.js index 5072dff4..eec6111c 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -222,7 +222,6 @@ export default class Editor { * @returns {Promise} A promise which resolves once the initialization is completed. */ initPlugins() { - const that = this; const config = this.config; return Promise.resolve() @@ -231,7 +230,7 @@ export default class Editor { const removePlugins = config.get( 'removePlugins' ) || []; const extraPlugins = config.get( 'extraPlugins' ) || []; - return that.plugins.load( plugins.concat( extraPlugins ), removePlugins ); + return this.plugins.load( plugins.concat( extraPlugins ), removePlugins ); } ) .then( loadedPlugins => { return this.plugins.init( loadedPlugins ); From 05e330ea25cb9015e78fe9fc7f493b7880590e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Thu, 24 Jan 2019 18:00:52 +0100 Subject: [PATCH 08/11] Tests: Simplified tests. --- tests/editor/editor.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/editor/editor.js b/tests/editor/editor.js index 5ce6b5f7..38624023 100644 --- a/tests/editor/editor.js +++ b/tests/editor/editor.js @@ -24,8 +24,6 @@ class TestEditor extends Editor { resolve( editor.initPlugins() .then( () => { - // Fire `data#ready` event manually as `data#init()` method is not used. - editor.data.fire( 'ready' ); editor.fire( 'ready' ); } ) .then( () => editor ) @@ -394,24 +392,22 @@ describe( 'Editor', () => { } ); } ); - it( 'fires all events in the right order', () => { + it( 'fires ready event', () => { const fired = []; function spy( evt ) { - fired.push( `${ evt.name }-${ evt.source.constructor.name.toLowerCase() }` ); + fired.push( evt.name ); } class EventWatcher extends Plugin { init() { - this.editor.plugins.on( 'ready', spy ); - this.editor.data.on( 'ready', spy ); this.editor.on( 'ready', spy ); } } return TestEditor.create( { plugins: [ EventWatcher ] } ) .then( () => { - expect( fired ).to.deep.equal( [ 'ready-plugincollection', 'ready-datacontroller', 'ready-testeditor' ] ); + expect( fired ).to.deep.equal( [ 'ready' ] ); } ); } ); } ); From b35ba804954cbc6397cb2bed1636afdf73025c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Thu, 24 Jan 2019 18:00:52 +0100 Subject: [PATCH 09/11] Tests: Simplified tests. --- tests/editor/editor.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/editor/editor.js b/tests/editor/editor.js index 5ce6b5f7..38624023 100644 --- a/tests/editor/editor.js +++ b/tests/editor/editor.js @@ -24,8 +24,6 @@ class TestEditor extends Editor { resolve( editor.initPlugins() .then( () => { - // Fire `data#ready` event manually as `data#init()` method is not used. - editor.data.fire( 'ready' ); editor.fire( 'ready' ); } ) .then( () => editor ) @@ -394,24 +392,22 @@ describe( 'Editor', () => { } ); } ); - it( 'fires all events in the right order', () => { + it( 'fires ready event', () => { const fired = []; function spy( evt ) { - fired.push( `${ evt.name }-${ evt.source.constructor.name.toLowerCase() }` ); + fired.push( evt.name ); } class EventWatcher extends Plugin { init() { - this.editor.plugins.on( 'ready', spy ); - this.editor.data.on( 'ready', spy ); this.editor.on( 'ready', spy ); } } return TestEditor.create( { plugins: [ EventWatcher ] } ) .then( () => { - expect( fired ).to.deep.equal( [ 'ready-plugincollection', 'ready-datacontroller', 'ready-testeditor' ] ); + expect( fired ).to.deep.equal( [ 'ready' ] ); } ); } ); } ); From 235ac05c94f20a905e43eb4e63c38664dffa5ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Mon, 28 Jan 2019 17:40:13 +0100 Subject: [PATCH 10/11] Remove `ready` event. Merge `plugins.load()` and `plugins.init()` methods. --- src/editor/editor.js | 5 +- src/plugincollection.js | 45 +++++---------- tests/_utils-tests/classictesteditor.js | 2 - tests/editor/editor.js | 18 +----- tests/plugincollection.js | 74 ++++++++++++------------- 5 files changed, 55 insertions(+), 89 deletions(-) diff --git a/src/editor/editor.js b/src/editor/editor.js index eec6111c..df01a542 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -230,10 +230,7 @@ export default class Editor { const removePlugins = config.get( 'removePlugins' ) || []; const extraPlugins = config.get( 'extraPlugins' ) || []; - return this.plugins.load( plugins.concat( extraPlugins ), removePlugins ); - } ) - .then( loadedPlugins => { - return this.plugins.init( loadedPlugins ); + return this.plugins.init( plugins.concat( extraPlugins ), removePlugins ); } ); } diff --git a/src/plugincollection.js b/src/plugincollection.js index 4d684aff..1ef1a1d8 100644 --- a/src/plugincollection.js +++ b/src/plugincollection.js @@ -144,7 +144,7 @@ export default class PluginCollection { } /** - * Loads a set of plugins and adds them to the collection. + * Initializes a set of plugins and adds them to the collection. * * @param {Array.} plugins An array of {@link module:core/plugin~PluginInterface plugin constructors} * or {@link module:core/plugin~PluginInterface.pluginName plugin names}. The second option (names) works only if @@ -155,7 +155,7 @@ export default class PluginCollection { * collection. * @returns {Promise.>} returns.loadedPlugins The array of loaded plugins. */ - load( plugins, removePlugins = [] ) { + init( plugins, removePlugins = [] ) { const that = this; const editor = this._editor; const loading = new Set(); @@ -196,6 +196,8 @@ export default class PluginCollection { } return Promise.all( pluginConstructors.map( loadPlugin ) ) + .then( () => initPlugins( loaded, 'init' ) ) + .then( () => initPlugins( loaded, 'afterInit' ) ) .then( () => loaded ); function loadPlugin( PluginConstructor ) { @@ -236,6 +238,16 @@ export default class PluginCollection { } ); } + function initPlugins( loadedPlugins, method ) { + return loadedPlugins.reduce( ( promise, plugin ) => { + if ( !plugin[ method ] ) { + return promise; + } + + return promise.then( plugin[ method ].bind( plugin ) ); + }, Promise.resolve() ); + } + function instantiatePlugin( PluginConstructor ) { return new Promise( resolve => { loading.add( PluginConstructor ); @@ -298,29 +310,6 @@ export default class PluginCollection { } } - /** - * Runs the initialisation process ({@link module:core/plugin~Plugin#init `init()`} - * and {@link module:core/plugin~Plugin#afterInit `afterInit()`} methods) for the given set of plugins. - * - * @param {Array.} plugins The array of plugins to initialise. - * @returns {Promise} A promise which resolves after all given plugins have been initialized. - */ - init( plugins ) { - return initPlugins( plugins, 'init' ) - .then( () => initPlugins( plugins, 'afterInit' ) ) - .then( () => { this.fire( 'ready' ); } ); - - function initPlugins( loadedPlugins, method ) { - return loadedPlugins.reduce( ( promise, plugin ) => { - if ( !plugin[ method ] ) { - return promise; - } - - return promise.then( plugin[ method ].bind( plugin ) ); - }, Promise.resolve() ); - } - } - /** * Destroys all loaded plugins. * @@ -393,9 +382,3 @@ export default class PluginCollection { } mix( PluginCollection, EmitterMixin ); - -/** - * Fired after {@link #init plugins are initialized}. - * - * @event ready - */ diff --git a/tests/_utils-tests/classictesteditor.js b/tests/_utils-tests/classictesteditor.js index 74ecc0e8..0ed8c3f5 100644 --- a/tests/_utils-tests/classictesteditor.js +++ b/tests/_utils-tests/classictesteditor.js @@ -121,7 +121,6 @@ describe( 'ClassicTestEditor', () => { class EventWatcher extends Plugin { init() { - this.editor.plugins.on( 'ready', spy ); this.editor.ui.on( 'ready', spy ); this.editor.data.on( 'ready', spy ); this.editor.on( 'ready', spy ); @@ -134,7 +133,6 @@ describe( 'ClassicTestEditor', () => { } ) .then( editor => { expect( fired ).to.deep.equal( [ - 'ready-plugincollection', 'ready-classictesteditorui', 'ready-datacontroller', 'ready-classictesteditor' diff --git a/tests/editor/editor.js b/tests/editor/editor.js index 38624023..10d85719 100644 --- a/tests/editor/editor.js +++ b/tests/editor/editor.js @@ -433,9 +433,6 @@ describe( 'Editor', () => { plugins: [ PluginA, PluginD ] } ); - const pluginsReadySpy = sinon.spy().named( 'ready' ); - editor.plugins.on( 'ready', pluginsReadySpy ); - return editor.initPlugins() .then( () => { sinon.assert.callOrder( @@ -446,8 +443,7 @@ describe( 'Editor', () => { editor.plugins.get( PluginA ).afterInit, editor.plugins.get( PluginB ).afterInit, editor.plugins.get( PluginC ).afterInit, - editor.plugins.get( PluginD ).afterInit, - pluginsReadySpy + editor.plugins.get( PluginD ).afterInit ); } ); } ); @@ -752,16 +748,12 @@ describe( 'Editor', () => { plugins: [ PluginA, PluginE ] } ); - const pluginsReadySpy = sinon.spy().named( 'ready' ); - editor.plugins.on( 'ready', pluginsReadySpy ); - return editor.initPlugins() .then( () => { sinon.assert.callOrder( editor.plugins.get( PluginA ).init, editor.plugins.get( PluginE ).init, - editor.plugins.get( PluginA ).afterInit, - pluginsReadySpy + editor.plugins.get( PluginA ).afterInit ); } ); } ); @@ -771,16 +763,12 @@ describe( 'Editor', () => { plugins: [ PluginA, PluginF ] } ); - const pluginsReadySpy = sinon.spy().named( 'ready' ); - editor.plugins.on( 'ready', pluginsReadySpy ); - return editor.initPlugins() .then( () => { sinon.assert.callOrder( editor.plugins.get( PluginA ).init, editor.plugins.get( PluginA ).afterInit, - editor.plugins.get( PluginF ).afterInit, - pluginsReadySpy + editor.plugins.get( PluginF ).afterInit ); } ); } ); diff --git a/tests/plugincollection.js b/tests/plugincollection.js index 21932124..98ed2cdd 100644 --- a/tests/plugincollection.js +++ b/tests/plugincollection.js @@ -77,7 +77,7 @@ describe( 'PluginCollection', () => { it( 'should not fail when trying to load 0 plugins (empty array)', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [] ) + return plugins.init( [] ) .then( () => { expect( getPlugins( plugins ) ).to.be.empty; } ); @@ -86,7 +86,7 @@ describe( 'PluginCollection', () => { it( 'should add collection items for loaded plugins', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ PluginA, PluginB ] ) + return plugins.init( [ PluginA, PluginB ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -98,7 +98,7 @@ describe( 'PluginCollection', () => { it( 'should add collection items for loaded plugins using plugin names', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ 'A', 'B' ] ) + return plugins.init( [ 'A', 'B' ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -111,7 +111,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); const spy = sinon.spy( plugins, '_add' ); - return plugins.load( [ PluginA, PluginC ] ) + return plugins.init( [ PluginA, PluginC ] ) .then( loadedPlugins => { expect( getPlugins( plugins ).length ).to.equal( 3 ); @@ -126,7 +126,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); const spy = sinon.spy( plugins, '_add' ); - return plugins.load( [ 'J' ] ) + return plugins.init( [ 'J' ] ) .then( loadedPlugins => { expect( getPlugins( plugins ).length ).to.equal( 3 ); @@ -141,7 +141,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); const spy = sinon.spy( plugins, '_add' ); - return plugins.load( [ PluginA, PluginB, PluginC ] ) + return plugins.init( [ PluginA, PluginB, PluginC ] ) .then( loadedPlugins => { expect( getPlugins( plugins ).length ).to.equal( 3 ); @@ -156,7 +156,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); const spy = sinon.spy( plugins, '_add' ); - return plugins.load( [ PluginD ] ) + return plugins.init( [ PluginD ] ) .then( loadedPlugins => { expect( getPlugins( plugins ).length ).to.equal( 4 ); @@ -172,7 +172,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); const spy = sinon.spy( plugins, '_add' ); - return plugins.load( [ PluginA, PluginE ] ) + return plugins.init( [ PluginA, PluginE ] ) .then( loadedPlugins => { expect( getPlugins( plugins ).length ).to.equal( 3 ); @@ -187,7 +187,7 @@ describe( 'PluginCollection', () => { it( 'should load grand child classes', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ PluginG ] ) + return plugins.init( [ PluginG ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 1 ); } ); @@ -198,7 +198,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ Y ] ) + return plugins.init( [ Y ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 1 ); } ); @@ -211,7 +211,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ pluginAsFunction ] ) + return plugins.init( [ pluginAsFunction ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 1 ); } ); @@ -230,7 +230,7 @@ describe( 'PluginCollection', () => { } } - return plugins.load( [ PluginA, PluginB, pluginAsFunction, Y ] ) + return plugins.init( [ PluginA, PluginB, pluginAsFunction, Y ] ) .then( () => { expect( plugins.get( PluginA ).editor ).to.equal( editor ); expect( plugins.get( PluginB ).editor ).to.equal( editor ); @@ -244,8 +244,8 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ PluginA, PluginX, PluginB ] ) - // Throw here, so if by any chance plugins.load() was resolved correctly catch() will be stil executed. + return plugins.init( [ PluginA, PluginX, PluginB ] ) + // Throw here, so if by any chance plugins.init() was resolved correctly catch() will be stil executed. .then( () => { throw new Error( 'Test error: this promise should not be resolved successfully' ); } ) @@ -263,8 +263,8 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ 'NonExistentPlugin' ] ) - // Throw here, so if by any chance plugins.load() was resolved correctly catch() will be stil executed. + return plugins.init( [ 'NonExistentPlugin' ] ) + // Throw here, so if by any chance plugins.init() was resolved correctly catch() will be stil executed. .then( () => { throw new Error( 'Test error: this promise should not be resolved successfully' ); } ) @@ -280,7 +280,7 @@ describe( 'PluginCollection', () => { it( 'should load chosen plugins (plugins and removePlugins are constructors)', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ PluginA, PluginB, PluginC ], [ PluginA ] ) + return plugins.init( [ PluginA, PluginB, PluginC ], [ PluginA ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -292,7 +292,7 @@ describe( 'PluginCollection', () => { it( 'should load chosen plugins (plugins are constructors, removePlugins are names)', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ PluginA, PluginB, PluginC ], [ 'A' ] ) + return plugins.init( [ PluginA, PluginB, PluginC ], [ 'A' ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -304,7 +304,7 @@ describe( 'PluginCollection', () => { it( 'should load chosen plugins (plugins and removePlugins are names)', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ 'A', 'B', 'C' ], [ 'A' ] ) + return plugins.init( [ 'A', 'B', 'C' ], [ 'A' ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -316,7 +316,7 @@ describe( 'PluginCollection', () => { it( 'should load chosen plugins (plugins are names, removePlugins are constructors)', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ 'A', 'B', 'C' ], [ PluginA ] ) + return plugins.init( [ 'A', 'B', 'C' ], [ PluginA ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -330,7 +330,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, [ AnonymousPlugin ].concat( availablePlugins ) ); - return plugins.load( [ AnonymousPlugin, 'A', 'B' ], [ AnonymousPlugin ] ) + return plugins.init( [ AnonymousPlugin, 'A', 'B' ], [ AnonymousPlugin ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -343,8 +343,8 @@ describe( 'PluginCollection', () => { const logSpy = testUtils.sinon.stub( log, 'error' ); const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ PluginA, PluginB, PluginC, PluginD ], [ PluginA, PluginB ] ) - // Throw here, so if by any chance plugins.load() was resolved correctly catch() will be stil executed. + return plugins.init( [ PluginA, PluginB, PluginC, PluginD ], [ PluginA, PluginB ] ) + // Throw here, so if by any chance plugins.init() was resolved correctly catch() will be stil executed. .then( () => { throw new Error( 'Test error: this promise should not be resolved successfully' ); } ) @@ -360,7 +360,7 @@ describe( 'PluginCollection', () => { const logSpy = testUtils.sinon.stub( log, 'warn' ); const plugins = new PluginCollection( editor ); - return plugins.load( [ PluginFoo, AnotherPluginFoo ] ) + return plugins.init( [ PluginFoo, AnotherPluginFoo ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -384,7 +384,7 @@ describe( 'PluginCollection', () => { const logSpy = testUtils.sinon.stub( log, 'warn' ); const plugins = new PluginCollection( editor ); - return plugins.load( [ PluginFoo ] ) + return plugins.init( [ PluginFoo ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -405,7 +405,7 @@ describe( 'PluginCollection', () => { const logSpy = testUtils.sinon.stub( log, 'warn' ); const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ 'Foo', AnotherPluginFoo ] ) + return plugins.init( [ 'Foo', AnotherPluginFoo ] ) .then( () => { expect( getPlugins( plugins ).length ).to.equal( 2 ); @@ -428,7 +428,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ SomePlugin ] ) + return plugins.init( [ SomePlugin ] ) .then( () => { expect( plugins.get( SomePlugin ) ).to.be.instanceOf( SomePlugin ); } ); @@ -442,7 +442,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ SomePlugin ] ) + return plugins.init( [ SomePlugin ] ) .then( () => { expect( plugins.get( 'foo/bar' ) ).to.be.instanceOf( SomePlugin ); expect( plugins.get( SomePlugin ) ).to.be.instanceOf( SomePlugin ); @@ -452,7 +452,7 @@ describe( 'PluginCollection', () => { it( 'throws if plugin cannot be retrieved by name', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [] ).then( () => { + return plugins.init( [] ).then( () => { expect( () => plugins.get( 'foo' ) ) .to.throw( CKEditorError, /^plugincollection-plugin-not-loaded:/ ) .with.deep.property( 'data', { plugin: 'foo' } ); @@ -465,7 +465,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [] ).then( () => { + return plugins.init( [] ).then( () => { expect( () => plugins.get( SomePlugin ) ) .to.throw( CKEditorError, /^plugincollection-plugin-not-loaded:/ ) .with.deep.property( 'data', { plugin: 'foo' } ); @@ -477,7 +477,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [] ).then( () => { + return plugins.init( [] ).then( () => { expect( () => plugins.get( SomePlugin ) ) .to.throw( CKEditorError, /^plugincollection-plugin-not-loaded:/ ) .with.deep.property( 'data', { plugin: 'SomePlugin' } ); @@ -504,13 +504,13 @@ describe( 'PluginCollection', () => { } ); it( 'returns true if plugins is loaded (retrieved by name)', () => { - return plugins.load( [ PluginA ] ).then( () => { + return plugins.init( [ PluginA ] ).then( () => { expect( plugins.has( 'A' ) ).to.be.true; } ); } ); it( 'returns true if plugins is loaded (retrieved by class)', () => { - return plugins.load( [ PluginA ] ).then( () => { + return plugins.init( [ PluginA ] ).then( () => { expect( plugins.has( PluginA ) ).to.be.true; } ); } ); @@ -522,7 +522,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, [] ); - return plugins.load( [ PluginA, PluginB ] ) + return plugins.init( [ PluginA, PluginB ] ) .then( () => { destroySpyForPluginA = sinon.spy( plugins.get( PluginA ), 'destroy' ); destroySpyForPluginB = sinon.spy( plugins.get( PluginB ), 'destroy' ); @@ -566,7 +566,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, [] ); - return plugins.load( [ AsynchronousPluginA, AsynchronousPluginB ] ) + return plugins.init( [ AsynchronousPluginA, AsynchronousPluginB ] ) .then( () => plugins.destroy() ) .then( () => { expect( destroyedPlugins ).to.contain( 'AsynchronousPluginB.destroy()' ); @@ -583,7 +583,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, [] ); - return plugins.load( [ PluginA, FooPlugin ] ) + return plugins.init( [ PluginA, FooPlugin ] ) .then( () => plugins.destroy() ) .then( destroyedPlugins => { expect( destroyedPlugins.length ).to.equal( 1 ); @@ -608,7 +608,7 @@ describe( 'PluginCollection', () => { const plugins = new PluginCollection( editor, availablePlugins ); - return plugins.load( [ SomePlugin1, SomePlugin2 ] ) + return plugins.init( [ SomePlugin1, SomePlugin2 ] ) .then( () => { const pluginConstructors = Array.from( plugins ) .map( entry => entry[ 0 ] ); From 94f230c2acba232363abca758f8e5684538c16e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Tue, 29 Jan 2019 10:23:07 +0100 Subject: [PATCH 11/11] Simplified `ediotr.initPlugins()` method. --- src/editor/editor.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/editor/editor.js b/src/editor/editor.js index 605a0025..fc315212 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -219,19 +219,16 @@ export default class Editor { /** * Loads and initializes plugins specified in the config. * - * @returns {Promise} A promise which resolves once the initialization is completed. + * @returns {Promise.>} returns.loadedPlugins A promise which resolves + * once the initialization is completed providing array of loaded plugins. */ initPlugins() { const config = this.config; + const plugins = config.get( 'plugins' ) || []; + const removePlugins = config.get( 'removePlugins' ) || []; + const extraPlugins = config.get( 'extraPlugins' ) || []; - return Promise.resolve() - .then( () => { - const plugins = config.get( 'plugins' ) || []; - const removePlugins = config.get( 'removePlugins' ) || []; - const extraPlugins = config.get( 'extraPlugins' ) || []; - - return this.plugins.init( plugins.concat( extraPlugins ), removePlugins ); - } ); + return this.plugins.init( plugins.concat( extraPlugins ), removePlugins ); } /**