8
0

plugincollection.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. /**
  7. * Manages a list of CKEditor plugins, including loading, initialization and destruction.
  8. *
  9. * @class PluginCollection
  10. * @extends Collection
  11. */
  12. CKEDITOR.define( [ 'mvc/collection', 'promise' ], function( Collection, Promise ) {
  13. var PluginCollection = Collection.extend( {
  14. /**
  15. * Creates an instance of the PluginCollection class, initializing it with a set of plugins.
  16. *
  17. * @constructor
  18. */
  19. constructor: function PluginCollection( editor ) {
  20. // Call the base constructor.
  21. Collection.apply( this );
  22. this._editor = editor;
  23. // The hash table used to store pointers to loaded plugins by name.
  24. this._names = {};
  25. },
  26. /**
  27. * Loads a set of plugins and add them to the collection.
  28. *
  29. * @param {String} plugins A comma separated list of plugin names to get loaded.
  30. */
  31. load: function( plugins ) {
  32. var that = this;
  33. // The list of plugins which are being loaded (to avoid circular references issues).
  34. var loading = {};
  35. plugins = plugins ? plugins.split( ',' ) : [];
  36. // Creates a promise for the loading of each plugin and returns a main promise that resolves when all are
  37. // done.
  38. return Promise.all( plugins.map( pluginPromise ) );
  39. // Returns a promise that will load the plugin and add it to the collection before resolving.
  40. function pluginPromise( plugin ) {
  41. return new Promise( function( resolve, reject ) {
  42. // Do nothing if the plugin is already loaded (or if is being loaded right now).
  43. if ( that._names[ plugin ] || loading[ plugin ] ) {
  44. resolve();
  45. return;
  46. }
  47. CKEDITOR.require( [ 'plugin!' + plugin ],
  48. // Success callback.
  49. function( LoadedPlugin ) {
  50. var loadedPlugin = new LoadedPlugin( that._editor );
  51. loadedPlugin.name = plugin;
  52. loadedPlugin.path = CKEDITOR.getPluginPath( plugin );
  53. loadedPlugin.deps = getPluginDeps( plugin );
  54. loading[ plugin ] = true;
  55. // Resolve with a promise that resolves once all dependencies are loaded.
  56. resolve(
  57. Promise.all( loadedPlugin.deps.map( pluginPromise ) )
  58. .then( function() {
  59. // Once dependencies are loaded, add the new instance of the loaded plugin to
  60. // the collection. This guarantees that dependecies come first in the collection.
  61. that.add( loadedPlugin );
  62. } )
  63. );
  64. },
  65. // Error callback.
  66. function() {
  67. var err = new Error( 'It was not possible to load the "' + plugin + '" plugin.' );
  68. err.name = 'CKEditor Error';
  69. reject( err );
  70. }
  71. );
  72. } );
  73. }
  74. function getPluginDeps( name ) {
  75. // Get the list of AMD modules that the plugin depends on.
  76. var deps = CKEDITOR._dependencies[ 'plugin!' + name ] || [];
  77. deps = deps
  78. // Pick only dependencies that are other plugins.
  79. .filter( function( dep ) {
  80. return dep.indexOf( 'plugin!' ) === 0;
  81. } )
  82. // Remove the 'plugin!' prefix.
  83. .map( function( dep ) {
  84. return dep.substr( 7 );
  85. } );
  86. return deps;
  87. }
  88. },
  89. /**
  90. * Adds a plugin to the collection.
  91. *
  92. * The `name` property must be set to the plugin object before passing it to this function. Adding plugins
  93. * with the same name has no effect and silently fails.
  94. *
  95. * @param {Plugin} plugin The plugin to be added.
  96. */
  97. add: function( plugin ) {
  98. // Do nothing if the plugin is already loaded.
  99. if ( this._names[ plugin.name ] ) {
  100. return;
  101. }
  102. // Save a pointer to the plugin by its name.
  103. this._names[ plugin.name ] = plugin;
  104. // Call the original implementation.
  105. Collection.prototype.add.apply( this, arguments );
  106. },
  107. /**
  108. * Gets a plugin from the collection.
  109. *
  110. * @param {String} name The plugin name.
  111. * @returns {Plugin} The requested plugin, if available in the collection.
  112. */
  113. get: function( name ) {
  114. if ( typeof name != 'string' ) {
  115. return Collection.prototype.get.apply( this, arguments );
  116. }
  117. return this._names[ name ];
  118. }
  119. } );
  120. return PluginCollection;
  121. } );