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