8
0
Prechádzať zdrojové kódy

Introduced Plugin.deps and automatic loading of dependencies.

fredck 10 rokov pred
rodič
commit
c88e2d1221

+ 40 - 6
packages/ckeditor5-engine/src/plugincollection.js

@@ -37,6 +37,9 @@ CKEDITOR.define( [ 'mvc/collection', 'promise' ], function( Collection, Promise
 		load: function( plugins ) {
 			var that = this;
 
+			// The list of plugins which are being loaded (to avoid circular references issues).
+			var loading = {};
+
 			plugins = plugins.split( ',' );
 
 			// Creates a promise for the loading of each plugin and returns a main promise that resolves when all are
@@ -46,17 +49,31 @@ CKEDITOR.define( [ 'mvc/collection', 'promise' ], function( Collection, Promise
 			// Returns a promise that will load the plugin and add it to the collection before resolving.
 			function pluginPromise( plugin ) {
 				return new Promise( function( resolve, reject ) {
+					// Do nothing if the plugin is already loaded (or if is being loaded right now).
+					if ( that._names[ plugin ] || loading[ plugin ] ) {
+						resolve();
+
+						return;
+					}
+
 					CKEDITOR.require( [ 'plugin!' + plugin ],
 						// Success callback.
 						function( LoadedPlugin ) {
 							var loadedPlugin = new LoadedPlugin( that._editor );
 							loadedPlugin.name = plugin;
-
-							// Adds a new instance of the loaded plugin to the collection.
-							that.add( loadedPlugin );
-
-							// Done! Resolve this promise.
-							resolve();
+							loadedPlugin.deps = getPluginDeps( plugin );
+
+							loading[ plugin ] = true;
+
+							// Resolve with a promise that resolves once all dependencies are loaded.
+							resolve(
+								Promise.all( loadedPlugin.deps.map( pluginPromise ) )
+									.then( function() {
+										// Once dependencies are loaded, add the new instance of the loaded plugin to
+										// the collection. This guarantees that dependecies come first in the collection.
+										that.add( loadedPlugin );
+									} )
+							);
 						},
 						// Error callback.
 						function() {
@@ -67,6 +84,23 @@ CKEDITOR.define( [ 'mvc/collection', 'promise' ], function( Collection, Promise
 					);
 				} );
 			}
+
+			function getPluginDeps( name ) {
+				// Get the list of AMD modules that the plugin depends on.
+				var deps = CKEDITOR._dependencies[ 'plugin!' + name ] || [];
+
+				deps = deps
+					// Pick only dependencies that are other plugins.
+					.filter( function( dep ) {
+						return dep.indexOf( 'plugin!' ) === 0;
+					} )
+					// Remove the 'plugin!' prefix.
+					.map( function( dep ) {
+						return dep.substr( 7 );
+					} );
+
+				return deps;
+			}
 		},
 
 		/**

+ 81 - 5
packages/ckeditor5-engine/tests/plugincollection/plugincollection.js

@@ -9,7 +9,7 @@
 
 var modules = bender.amd.require( 'plugincollection', 'plugin', 'editor' );
 var editor;
-var PluginA, PluginB, PluginC;
+var PluginA, PluginB;
 
 before( function() {
 	var Editor = modules.editor;
@@ -17,12 +17,11 @@ before( function() {
 
 	PluginA = Plugin.extend();
 	PluginB = Plugin.extend();
-	PluginC = Plugin.extend();
 
 	editor = new Editor( document.body.appendChild( document.createElement( 'div' ) ) );
 } );
 
-// Create 3 fake plugins that will be used on tests.
+// Create fake plugins that will be used on tests.
 
 CKEDITOR.define( 'plugin!A', [ 'plugin' ], function() {
 	return PluginA;
@@ -32,8 +31,20 @@ CKEDITOR.define( 'plugin!B', [ 'plugin' ], function() {
 	return PluginB;
 } );
 
-CKEDITOR.define( 'plugin!C', [ 'plugin' ], function() {
-	return PluginC;
+CKEDITOR.define( 'plugin!C', [ 'plugin', 'plugin!B' ], function() {
+	return modules.plugin;
+} );
+
+CKEDITOR.define( 'plugin!D', [ 'plugin', 'plugin!A', 'plugin!C' ], function() {
+	return modules.plugin;
+} );
+
+CKEDITOR.define( 'plugin!E', [ 'plugin', 'plugin!F' ], function() {
+	return modules.plugin;
+} );
+
+CKEDITOR.define( 'plugin!F', [ 'plugin', 'plugin!E' ], function() {
+	return modules.plugin;
 } );
 
 /////////////
@@ -53,6 +64,71 @@ describe( 'load', function() {
 			} );
 	} );
 
+	it( 'should load dependency plugins', function() {
+		var PluginCollection = modules.plugincollection;
+
+		var plugins = new PluginCollection( editor );
+
+		return plugins.load( 'A,C' )
+			.then( function() {
+				expect( plugins.length ).to.equal( 3 );
+
+				// The order must have dependencies first.
+				expect( plugins.get( 0 ).name ).to.equal( 'A' );
+				expect( plugins.get( 1 ).name ).to.equal( 'B' );
+				expect( plugins.get( 2 ).name ).to.equal( 'C' );
+			} );
+	} );
+
+	it( 'should be ok when dependencies are loaded first', function() {
+		var PluginCollection = modules.plugincollection;
+
+		var plugins = new PluginCollection( editor );
+
+		return plugins.load( 'A,B,C' )
+			.then( function() {
+				expect( plugins.length ).to.equal( 3 );
+
+				// The order must have dependencies first.
+				expect( plugins.get( 0 ).name ).to.equal( 'A' );
+				expect( plugins.get( 1 ).name ).to.equal( 'B' );
+				expect( plugins.get( 2 ).name ).to.equal( 'C' );
+			} );
+	} );
+
+	it( 'should load deep dependency plugins', function() {
+		var PluginCollection = modules.plugincollection;
+
+		var plugins = new PluginCollection( editor );
+
+		return plugins.load( 'D' )
+			.then( function() {
+				expect( plugins.length ).to.equal( 4 );
+
+				// The order must have dependencies first.
+				expect( plugins.get( 0 ).name ).to.equal( 'A' );
+				expect( plugins.get( 1 ).name ).to.equal( 'B' );
+				expect( plugins.get( 2 ).name ).to.equal( 'C' );
+				expect( plugins.get( 3 ).name ).to.equal( 'D' );
+			} );
+	} );
+
+	it( 'should handle cross dependency plugins', function() {
+		var PluginCollection = modules.plugincollection;
+
+		var plugins = new PluginCollection( editor );
+
+		return plugins.load( 'A,E' )
+			.then( function() {
+				expect( plugins.length ).to.equal( 3 );
+
+				// The order must have dependencies first.
+				expect( plugins.get( 0 ).name ).to.equal( 'A' );
+				expect( plugins.get( 1 ).name ).to.equal( 'F' );
+				expect( plugins.get( 2 ).name ).to.equal( 'E' );
+			} );
+	} );
+
 	it( 'should set the `editor` property on loaded plugins', function() {
 		var PluginCollection = modules.plugincollection;