1c3d8af9eee91f8e66cab00a8d6839cdc96ae074
[roojs1] / Roo / XComponent.js
1 /*
2  * Original code for Roojs - LGPL
3  * <script type="text/javascript">
4  */
5  
6 /**
7  * @class Roo.XComponent
8  * A delayed Element creator...
9  * Or a way to group chunks of interface together.
10  * 
11  * Mypart.xyx = new Roo.XComponent({
12
13     parent : 'Mypart.xyz', // empty == document.element.!!
14     order : '001',
15     name : 'xxxx'
16     region : 'xxxx'
17     disabled : function() {} 
18      
19     tree : function() { // return an tree of xtype declared components
20         var MODULE = this;
21         return 
22         {
23             xtype : 'NestedLayoutPanel',
24             // technicall
25         }
26      ]
27  *})
28  *
29  *
30  * It can be used to build a big heiracy,
31  * or you can use
32  * MYPART.renderTo(Roo.Element | String(id) | dom_element )
33  * 
34  *
35  * @extends Roo.util.Observable
36  * @constructor
37  * @param cfg {Object} configuration of component
38  * 
39  */
40 Roo.XComponent = function(cfg) {
41     Roo.apply(this, cfg);
42     this.addEvents({ 
43         /**
44              * @event built
45              * Fires when this the componnt is built
46              * @param {Roo.XComponent} c the component
47              */
48         'built' : true,
49         /**
50              * @event buildcomplete
51              * Fires on the top level element when all elements have been built
52              * @param {Roo.XComponent} c the top level component.
53          */
54         'buildcomplete' : true
55         
56     });
57     
58     Roo.XComponent.register(this);
59     this.modules = false;
60     this.el = false; // where the layout goes..
61     
62     
63 }
64 Roo.extend(Roo.XComponent, Roo.util.Observable, {
65     /**
66      * @property el
67      * The created element (with Roo.factory())
68      * @type {Roo.Layout}
69      */
70     el  : false,
71     
72     /**
73      * @property el
74      * for BC  - use el in new code
75      * @type {Roo.Layout}
76      */
77     panel : false,
78     
79     /**
80      * @property layout
81      * for BC  - use el in new code
82      * @type {Roo.Layout}
83      */
84     layout : false,
85     
86      /**
87      * @cfg {Function|boolean} disabled
88      * If this module is disabled by some rule, return true from the funtion
89      */
90     disabled : false,
91     
92     /**
93      * @cfg {String} parent 
94      * Name of parent element which it get xtype added to..
95      */
96     parent: false,
97     
98     /**
99      * @cfg {String} order
100      * Used to set the order in which elements are created (usefull for multiple tabs)
101      */
102     
103     order : false,
104     /**
105      * @cfg {String} name
106      * String to display while loading.
107      */
108     name : false,
109     /**
110      * @cfg {String} region
111      * Region to render component to (defaults to center)
112      */
113     region : 'center',
114     
115     /**
116      * @cfg {Array} items
117      * A single item array - the first element is the root of the tree..
118      * It's done this way to stay compatible with the Xtype system...
119      */
120     items : false,
121     
122     
123      /**
124      * render
125      * render element to dom or tree
126      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
127      */
128     
129     render : function(el)
130     {
131         
132         if (!this.parent) {
133             
134             el = el ? Roo.get(el) : false;
135             
136             
137             // it's a top level one..
138             this.parent =  {
139                 el : new Ext.BorderLayout(el || document.body, {
140                 
141                      center: {
142                          titlebar: false,
143                          autoScroll:false,
144                          closeOnTab: true,
145                          tabPosition: 'top',
146                           //resizeTabs: true,
147                          alwaysShowTabs: el ? false :  true,
148                          minTabWidth: 140
149                      }
150                  })
151             }
152         }
153             
154         var tree = this.tree();
155         tree.region = tree.region || this.region;
156         this.el = this.parent.el.addxtype(tree);
157         this.fireEvent('built', this);
158         
159         this.panel = this.el;
160         this.layout = this.panel.layout;    
161          
162     }
163     
164      
165      
166     
167 });
168
169 Roo.apply(Roo.XComponent, {
170     
171     /**
172      * @property  buildCompleted
173      * True when the builder has completed building the interface.
174      * @type Boolean
175      */
176     buildCompleted : false,
177      
178     /**
179      * @property  topModule
180      * the upper most module - uses document.element as it's constructor.
181      * @type Object
182      */
183      
184     topModule  : false,
185       
186     /**
187      * @property  modules
188      * array of modules to be created by registration system.
189      * @type Roo.XComponent
190      */
191     
192     modules : [],
193       
194     
195     /**
196      * Register components to be built later.
197      *
198      * This solves the following issues
199      * - Building is not done on page load, but after an authentication process has occured.
200      * - Interface elements are registered on page load
201      * - Parent Interface elements may not be loaded before child, so this handles that..
202      * 
203      *
204      * example:
205      * 
206      * MyApp.register({
207           order : '000001',
208           module : 'Pman.Tab.projectMgr',
209           region : 'center',
210           parent : 'Pman.layout',
211           disabled : false,  // or use a function..
212         })
213      
214      * * @param {Object} details about module
215      */
216     register : function(obj) {
217         this.modules.push(obj);
218          
219     },
220     /**
221      * convert a string to an object..
222      * 
223      */
224     
225     toObject : function(str)
226     {
227         if (!str || typeof(str) == 'object') {
228             return str;
229         }
230         var ar = str.split('.');
231         var rt, o;
232         rt = ar.shift();
233             /** eval:var:o */
234         eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
235         if (o === false) {
236             throw "Module not found : " + str;
237         }
238         Roo.each(ar, function(e) {
239             if (typeof(o[e]) == 'undefined') {
240                 throw "Module not found : " + str;
241             }
242             o = o[e];
243         });
244         return o;
245         
246     },
247     
248     
249     /**
250      * move modules into their correct place in the tree..
251      * 
252      */
253     preBuild : function ()
254     {
255         
256         Roo.each(this.modules , function (obj)
257         {
258             obj.parent = this.toObject(obj.parent);
259             
260             if (!obj.parent) {
261                 this.topModule = obj;
262                 return;
263             }
264             
265             if (!obj.parent.modules) {
266                 obj.parent.modules = new Roo.util.MixedCollection(false, 
267                     function(o) { return o.order + '' }
268                 );
269             }
270             
271             obj.parent.modules.add(obj);
272         }, this);
273     },
274     
275      /**
276      * make a list of modules to build.
277      * @return {Array} list of modules. 
278      */ 
279     
280     buildOrder : function()
281     {
282         var _this = this;
283         var cmp = function(a,b) {   
284             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
285         };
286         
287         if (!this.topModule || !this.topModule.modules) {
288             throw "No top level modules to build";
289         }
290        
291         // make a flat list in order of modules to build.
292         var mods = [ this.topModule ];
293         
294         
295         // add modules to their parents..
296         var addMod = function(m) {
297            // Roo.debug && Roo.log(m.modKey);
298             
299             mods.push(m);
300             if (m.modules) {
301                 m.modules.keySort('ASC',  cmp );
302                 m.modules.each(addMod);
303             }
304             // not sure if this is used any more..
305             if (m.finalize) {
306                 m.finalize.name = m.name + " (clean up) ";
307                 mods.push(m.finalize);
308             }
309             
310         }
311         this.topModule.modules.keySort('ASC',  cmp );
312         this.topModule.modules.each(addMod);
313         return mods;
314     },
315     
316      /**
317      * Build the registered modules.
318      * @param {Object} parent element.
319      * @param {Function} optional method to call after module has been added.
320      * 
321      */ 
322    
323     build : function() 
324     {
325         
326         this.preBuild();
327         var mods = this.buildOrder();
328       
329         //this.allmods = mods;
330         //Roo.debug && Roo.log(mods);
331         //return;
332         if (!mods.length) { // should not happen
333             throw "NO modules!!!";
334         }
335         
336         
337         
338         // flash it up as modal - so we store the mask!?
339         Roo.MessageBox.show({ title: 'loading' });
340         Roo.MessageBox.show({
341            title: "Please wait...",
342            msg: "Building Interface...",
343            width:450,
344            progress:true,
345            closable:false,
346            modal: false
347           
348         });
349         var total = mods.length;
350         
351         var _this = this;
352         var progressRun = function() {
353             if (!mods.length) {
354                 Roo.debug && Roo.log('hide?');
355                 Roo.MessageBox.hide();
356                 _this.topModule.fireEvent('buildcomplete', _this.topModule);
357                 return flase;    
358             }
359             
360             var m = mods.shift();
361             
362             
363             Roo.debug && Roo.log(m);
364             // not sure if this is supported any more.. - modules that are are just function
365             if (typeof(m) == 'function') { 
366                 m.call(this);
367                 return progressRun.defer(10, _this);
368             } 
369             
370             
371             
372             Roo.MessageBox.updateProgress(
373                 (total  - mods.length)/total,  "Building Interface " + (total  - mods.length) + 
374                     " of " + total + 
375                     (m.name ? (' - ' + m.name) : '')
376                     );
377             
378          
379             // is the module disabled?
380             var disabled = (typeof(m.disabled) == 'function') ?
381                 m.disabled.call(m.module.disabled) : m.disabled;    
382             
383             
384             if (disabled) {
385                 return progressRun(); // we do not update the display!
386             }
387             
388             // now build 
389             
390             m.render();
391             // it's 10 on top level, and 1 on others??? why...
392             return progressRun.defer(10, _this);
393              
394         }
395         progressRun.defer(1, _this);
396      
397         
398         
399     }
400     
401      
402    
403     
404     
405 });
406