8
0

plugincollection.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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( [ 'collection', 'promise', 'log' ], function( Collection, Promise, log ) {
  13. class PluginCollection extends Collection {
  14. /**
  15. * Creates an instance of the PluginCollection class, initializing it with a set of plugins.
  16. *
  17. * @constructor
  18. */
  19. constructor( editor ) {
  20. super();
  21. this._editor = editor;
  22. // The hash table used to store pointers to loaded plugins by name.
  23. this._names = {};
  24. }
  25. /**
  26. * Loads a set of plugins and add them to the collection.
  27. *
  28. * @param {String} plugins A comma separated list of plugin names to get loaded.
  29. * @returns {Promise} A promise which gets resolved once all plugins are loaded and available into the
  30. * collection.
  31. */
  32. load( plugins ) {
  33. var that = this;
  34. // The list of plugins which are being loaded (to avoid circular references issues).
  35. var loading = {};
  36. plugins = plugins ? plugins.split( ',' ) : [];
  37. // Creates a promise for the loading of each plugin and returns a main promise that resolves when all are
  38. // done.
  39. return Promise.all( plugins.map( pluginPromise ) );
  40. // Returns a promise that will load the plugin and add it to the collection before resolving.
  41. function pluginPromise( plugin ) {
  42. return new Promise( function( resolve, reject ) {
  43. // Do nothing if the plugin is already loaded (or if is being loaded right now).
  44. if ( that._names[ plugin ] || loading[ plugin ] ) {
  45. return resolve();
  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( err ) {
  67. /**
  68. * It was not possible to load the plugin.
  69. *
  70. * @error plugincollection-load
  71. * @param {String} plugin The name of the plugin that could not be loaded.
  72. */
  73. log.error( 'plugincollection-load: It was not possible to load the plugin.', { plugin: plugin } );
  74. reject( err );
  75. }
  76. );
  77. } );
  78. }
  79. function getPluginDeps( name ) {
  80. // Get the list of AMD modules that the plugin depends on.
  81. var deps = CKEDITOR._dependencies[ 'plugin!' + name ] || [];
  82. deps = deps
  83. // Pick only dependencies that are other plugins.
  84. .filter( function( dep ) {
  85. return dep.indexOf( 'plugin!' ) === 0;
  86. } )
  87. // Remove the 'plugin!' prefix.
  88. .map( function( dep ) {
  89. return dep.substr( 7 );
  90. } );
  91. return deps;
  92. }
  93. }
  94. /**
  95. * Adds a plugin to the collection.
  96. *
  97. * The `name` property must be set to the plugin object before passing it to this function. Adding plugins
  98. * with the same name has no effect and silently fails.
  99. *
  100. * @param {Plugin} plugin The plugin to be added.
  101. */
  102. add( plugin ) {
  103. // Do nothing if the plugin is already loaded.
  104. if ( this._names[ plugin.name ] ) {
  105. return;
  106. }
  107. // Save a pointer to the plugin by its name.
  108. this._names[ plugin.name ] = plugin;
  109. // Call the original implementation.
  110. super.add.apply( this, arguments );
  111. }
  112. /**
  113. * Gets a plugin from the collection.
  114. *
  115. * @param {String} name The plugin name.
  116. * @returns {Plugin} The requested plugin, if available in the collection.
  117. */
  118. get( name ) {
  119. if ( typeof name != 'string' ) {
  120. return super.get.apply( this, arguments );
  121. }
  122. return this._names[ name ];
  123. }
  124. }
  125. return PluginCollection;
  126. } );