_PluginManager.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.grid.enhanced._PluginManager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.grid.enhanced._PluginManager"] = true;
  8. dojo.provide("dojox.grid.enhanced._PluginManager");
  9. dojo.require("dojox.grid.enhanced._Events");
  10. dojo.require("dojox.grid.enhanced._FocusManager");
  11. dojo.declare("dojox.grid.enhanced._PluginManager", null, {
  12. // summary:
  13. // Singleton plugin manager
  14. //
  15. // description:
  16. // Plugin manager is responsible for
  17. // 1. Loading required plugins
  18. // 2. Handling collaboration and dependencies among plugins
  19. //
  20. // Some plugin dependencies:
  21. // - "columnReordering" attribute won't work when either DnD or Indirect Selections plugin is on.
  22. //_options: Object
  23. // Normalized plugin options
  24. _options: null,
  25. //_plugins: Array
  26. // Plugin list
  27. _plugins: null,
  28. //_connects: Array
  29. // Connection list
  30. _connects: null,
  31. constructor: function(inGrid){
  32. this.grid = inGrid;
  33. this._store = inGrid.store;
  34. this._options = {};
  35. this._plugins = [];
  36. this._connects = [];
  37. this._parseProps(this.grid.plugins);
  38. inGrid.connect(inGrid, "_setStore", dojo.hitch(this, function(store){
  39. if(this._store !== store){
  40. this.forEach('onSetStore', [store, this._store]);
  41. this._store = store;
  42. }
  43. }));
  44. },
  45. startup: function(){
  46. this.forEach('onStartUp');
  47. },
  48. preInit: function(){
  49. // summary:
  50. // Load appropriate plugins before DataGrid.postCreate().
  51. // See EnhancedGrid.postCreate()
  52. this.grid.focus.destroy();
  53. this.grid.focus = new dojox.grid.enhanced._FocusManager(this.grid);
  54. new dojox.grid.enhanced._Events(this.grid);//overwrite some default events of DataGrid
  55. this._init(true);
  56. this.forEach('onPreInit');
  57. },
  58. postInit: function(){
  59. // summary:
  60. // Load plugins after DataGrid.postCreate() - the default phase when plugins are created
  61. // See EnhancedGrid.postCreate()
  62. this._init(false);
  63. dojo.forEach(this.grid.views.views, this._initView, this);
  64. this._connects.push(dojo.connect(this.grid.views, 'addView', dojo.hitch(this, this._initView)));
  65. if(this._plugins.length > 0){
  66. var edit = this.grid.edit;
  67. if(edit){ edit.styleRow = function(inRow){}; }
  68. }
  69. this.forEach('onPostInit');
  70. },
  71. forEach: function(func, args){
  72. dojo.forEach(this._plugins, function(p){
  73. if(!p || !p[func]){ return; }
  74. p[func].apply(p, args ? args : []);
  75. });
  76. },
  77. _parseProps: function(plugins){
  78. // summary:
  79. // Parse plugins properties
  80. // plugins: Object
  81. // Plugin properties defined by user
  82. if(!plugins){ return; }
  83. var p, loading = {}, options = this._options, grid = this.grid;
  84. var registry = dojox.grid.enhanced._PluginManager.registry;//global plugin registry
  85. for(p in plugins){
  86. if(plugins[p]){//filter out boolean false e.g. {p:false}
  87. this._normalize(p, plugins, registry, loading);
  88. }
  89. }
  90. //"columnReordering" attribute won't work when either DnD or Indirect Selections plugin is used.
  91. if(options.dnd || options.indirectSelection){
  92. options.columnReordering = false;
  93. }
  94. //mixin all plugin properties into Grid
  95. dojo.mixin(grid, options);
  96. },
  97. _normalize: function(p, plugins, registry, loading){
  98. // summary:
  99. // Normalize plugin properties especially the dependency chain
  100. // p: String
  101. // Plugin name
  102. // plugins: Object
  103. // Plugin properties set by user
  104. // registry: Object
  105. // The global plugin registry
  106. // loading: Object
  107. // Map for checking process state
  108. if(!registry[p]){ throw new Error('Plugin ' + p + ' is required.');}
  109. if(loading[p]){ throw new Error('Recursive cycle dependency is not supported.'); }
  110. var options = this._options;
  111. if(options[p]){ return options[p]; }
  112. loading[p] = true;
  113. //TBD - more strict conditions?
  114. options[p] = dojo.mixin({}, registry[p], dojo.isObject(plugins[p]) ? plugins[p] : {});
  115. var dependencies = options[p]['dependency'];
  116. if(dependencies){
  117. if(!dojo.isArray(dependencies)){
  118. dependencies = options[p]['dependency'] = [dependencies];
  119. }
  120. dojo.forEach(dependencies, function(dependency){
  121. if(!this._normalize(dependency, plugins, registry, loading)){
  122. throw new Error('Plugin ' + dependency + ' is required.');
  123. }
  124. }, this);
  125. }
  126. delete loading[p];
  127. return options[p];
  128. },
  129. _init: function(pre){
  130. // summary:
  131. // Find appropriate plugins and load them
  132. // pre: Boolean
  133. // True - preInit | False - postInit(by default)
  134. var p, preInit, options = this._options;
  135. for(p in options){
  136. preInit = options[p]['preInit'];
  137. if((pre ? preInit : !preInit) && options[p]['class'] && !this.pluginExisted(p)){
  138. this.loadPlugin(p);
  139. }
  140. }
  141. },
  142. loadPlugin: function(name){
  143. // summary:
  144. // Load required plugin("name")
  145. // name: String
  146. // Plugin name
  147. // return: Object
  148. // The newly loaded plugin
  149. var option = this._options[name];
  150. if(!option){ return null; } //return if no plugin option
  151. var plugin = this.getPlugin(name);
  152. if(plugin){ return plugin; } //return if plugin("name") already existed
  153. var dependencies = option['dependency'];
  154. dojo.forEach(dependencies, function(dependency){
  155. if(!this.loadPlugin(dependency)){
  156. throw new Error('Plugin ' + dependency + ' is required.');
  157. }
  158. }, this);
  159. var cls = option['class'];
  160. delete option['class'];//remove it for safety
  161. plugin = new this.getPluginClazz(cls)(this.grid, option);
  162. this._plugins.push(plugin);
  163. return plugin;
  164. },
  165. _initView: function(view){
  166. // summary:
  167. // Overwrite several default behavior for each views(including _RowSelector view)
  168. if(!view){ return; }
  169. //add more events handler - _View
  170. dojox.grid.util.funnelEvents(view.contentNode, view, "doContentEvent", ['mouseup', 'mousemove']);
  171. dojox.grid.util.funnelEvents(view.headerNode, view, "doHeaderEvent", ['mouseup']);
  172. },
  173. pluginExisted: function(name){
  174. // summary:
  175. // Check if plugin("name") existed
  176. // name: String
  177. // Plugin name
  178. // return: Boolean
  179. // True - existed | False - not existed
  180. return !!this.getPlugin(name);
  181. },
  182. getPlugin: function(name){
  183. // summary:
  184. // Get plugin("name")
  185. // name: String
  186. // Plugin name
  187. // return: Object
  188. // Plugin instance
  189. var plugins = this._plugins;
  190. name = name.toLowerCase();
  191. for(var i = 0, len = plugins.length; i < len; i++){
  192. if(name == plugins[i]['name'].toLowerCase()){
  193. return plugins[i];
  194. }
  195. }
  196. return null;
  197. },
  198. getPluginClazz: function(clazz){
  199. // summary:
  200. // Load target plugin which must be already required (dojo.require(..))
  201. // clazz: class | String
  202. // Plugin class
  203. if(dojo.isFunction(clazz)){
  204. return clazz;//return if it's already a clazz
  205. }
  206. var errorMsg = 'Please make sure Plugin "' + clazz + '" is existed.';
  207. try{
  208. var cls = dojo.getObject(clazz);
  209. if(!cls){ throw new Error(errorMsg); }
  210. return cls;
  211. }catch(e){
  212. throw new Error(errorMsg);
  213. }
  214. },
  215. isFixedCell: function(cell){
  216. // summary:
  217. // See if target cell(column) is fixed or not.
  218. // cell: Object
  219. // Target cell(column)
  220. // return: Boolean
  221. // True - fixed| False - not fixed
  222. //target cell can use Boolean attributes named "isRowSelector" or "fixedPos" to mark it's a fixed cell(column)
  223. return cell && (cell.isRowSelector || cell.fixedPos);
  224. },
  225. destroy: function(){
  226. // summary:
  227. // Destroy all resources
  228. dojo.forEach(this._connects, dojo.disconnect);
  229. this.forEach('destroy');
  230. if(this.grid.unwrap){
  231. this.grid.unwrap();
  232. }
  233. delete this._connects;
  234. delete this._plugins;
  235. delete this._options;
  236. }
  237. });
  238. dojox.grid.enhanced._PluginManager.registerPlugin = function(clazz, props){
  239. // summary:
  240. // Register plugins - TODO, a better way rather than global registry?
  241. // clazz: String
  242. // Full class name, e.g. "dojox.grid.enhanced.plugins.DnD"
  243. // props: Object - Optional
  244. // Plugin properties e.g. {"dependency": ["nestedSorting"], ...}
  245. if(!clazz){
  246. console.warn("Failed to register plugin, class missed!");
  247. return;
  248. }
  249. var cls = dojox.grid.enhanced._PluginManager;
  250. cls.registry = cls.registry || {};
  251. cls.registry[clazz.prototype.name]/*plugin name*/ = dojo.mixin({"class": clazz}, (props ? props : {}));
  252. };
  253. }