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         el = Roo.get(el);
118         
119         
120         
121         
122         
123         
124         
125         
126     }
127     
128      
129      
130     
131 });
132
133 Roo.apply(Roo.XComponent, {
134     
135     /**
136      * @property  buildCompleted
137      * True when the builder has completed building the interface.
138      * @type Boolean
139      */
140     buildCompleted : false,
141      
142     /**
143      * @property  topModule
144      * the upper most module - uses document.element as it's constructor.
145      * @type Object
146      */
147      
148     topModule  : false,
149       
150     /**
151      * @property  modules
152      * array of modules to be created by registration system.
153      * @type Roo.XComponent
154      */
155     
156     modules : [],
157       
158     
159     /**
160      * Register components to be built later.
161      *
162      * This solves the following issues
163      * - Building is not done on page load, but after an authentication process has occured.
164      * - Interface elements are registered on page load
165      * - Parent Interface elements may not be loaded before child, so this handles that..
166      * 
167      *
168      * example:
169      * 
170      * MyApp.register({
171           order : '000001',
172           module : 'Pman.Tab.projectMgr',
173           region : 'center',
174           parent : 'Pman.layout',
175           disabled : false,  // or use a function..
176         })
177      
178      * * @param {Object} details about module
179      */
180     register : function(obj) {
181         this.modules.push(obj);
182          
183     },
184     /**
185      * convert a string to an object..
186      * 
187      */
188     
189     toObject : function(str)
190     {
191         if (!str || typeof(str) == 'object') {
192             return str;
193         }
194         var ar = str.split('.');
195         var rt, o;
196         rt = ar.shift();
197             /** eval:var:o */
198         eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
199         if (o === false) {
200             throw "Module not found : " + str;
201         }
202         Roo.each(ar, function(e) {
203             if (typeof(o[e]) == 'undefined') {
204                 throw "Module not found : " + str;
205             }
206             o = o[e];
207         });
208         return o;
209         
210     },
211     
212     
213     /**
214      * move modules into their correct place in the tree..
215      * 
216      */
217     preBuild : function ()
218     {
219         
220         Roo.each(this.modules , function (obj)
221         {
222             obj.parent = this.toObject(obj.parent);
223             
224             if (!obj.parent) {
225                 this.topModule = obj;
226                 return;
227             }
228             
229             if (!obj.parent.modules) {
230                 obj.parent.modules = new Roo.util.MixedCollection(false, 
231                     function(o) { return o.order + '' }
232                 );
233             }
234             
235             obj.parent.modules.add(obj);
236         }, this);
237     },
238     
239      /**
240      * make a list of modules to build.
241      * @return {Array} list of modules. 
242      */ 
243     
244     buildOrder : function()
245     {
246         var _this = this;
247         var cmp = function(a,b) {   
248             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
249         };
250         
251         if (!this.topModule || !this.topModule.modules) {
252             throw "No top level modules to build";
253         }
254        
255         // make a flat list in order of modules to build.
256         var mods = [ this.topModule ];
257         
258         
259         // add modules to their parents..
260         var addMod = function(m) {
261            // Roo.debug && Roo.log(m.modKey);
262             
263             mods.push(m);
264             if (m.modules) {
265                 m.modules.keySort('ASC',  cmp );
266                 m.modules.each(addMod);
267             }
268             // not sure if this is used any more..
269             if (m.finalize) {
270                 m.finalize.name = m.name + " (clean up) ";
271                 mods.push(m.finalize);
272             }
273             
274         }
275         this.topModule.modules.keySort('ASC',  cmp );
276         this.topModule.modules.each(addMod);
277         return mods;
278     },
279     
280      /**
281      * Build the registered modules.
282      * @param {Object} parent element.
283      * @param {Function} optional method to call after module has been added.
284      * 
285      */ 
286    
287     build : function() 
288     {
289         
290         this.preBuild();
291         var mods = this.buildOrder();
292       
293         //this.allmods = mods;
294         //Roo.debug && Roo.log(mods);
295         //return;
296         if (!mods.length) { // should not happen
297             throw "NO modules!!!";
298         }
299         
300         
301         
302         // flash it up as modal - so we store the mask!?
303         Roo.MessageBox.show({ title: 'loading' });
304         Roo.MessageBox.show({
305            title: "Please wait...",
306            msg: "Building Interface...",
307            width:450,
308            progress:true,
309            closable:false,
310            modal: false
311           
312         });
313         var total = mods.length;
314         
315         var _this = this;
316         var progressRun = function() {
317             if (!mods.length) {
318                 Roo.debug && Roo.log('hide?');
319                 Roo.MessageBox.hide();
320                 _this.topModule.fireEvent('buildcomplete', _this.topModule);
321                 return flase;    
322             }
323             
324             var m = mods.shift();
325             Roo.debug && Roo.log(m);
326             if (typeof(m) == 'function') { // not sure if this is supported any more..
327                 m.call(this);
328                 return progressRun.defer(10, _this);
329             } 
330             
331             Roo.MessageBox.updateProgress(
332                 (total  - mods.length)/total,  "Building Interface " + (total  - mods.length) + 
333                     " of " + total + 
334                     (m.name ? (' - ' + m.name) : '')
335                     );
336             
337          
338             
339             var disabled = (typeof(m.disabled) == 'function') ?
340                 m.disabled.call(m.module.disabled) : m.disabled;    
341             
342             
343             if (disabled) {
344                 return progressRun(); // we do not update the display!
345             }
346             
347             if (!m.parent) {
348                 // it's a top level one..
349                 var layoutbase = new Ext.BorderLayout(document.body, {
350                
351                     center: {
352                          titlebar: false,
353                          autoScroll:false,
354                          closeOnTab: true,
355                          tabPosition: 'top',
356                          //resizeTabs: true,
357                          alwaysShowTabs: true,
358                          minTabWidth: 140
359                     }
360                 });
361                 var tree = m.tree();
362                 tree.region = 'center';
363                 m.el = layoutbase.addxtype(tree);
364                 m.panel = m.el;
365                 m.layout = m.panel.layout;    
366                 return progressRun.defer(10, _this);
367             }
368             
369             var tree = m.tree();
370             tree.region = tree.region || m.region;
371             m.el = m.parent.el.addxtype(tree);
372             m.fireEvent('built', m);
373             m.panel = m.el;
374             m.layout = m.panel.layout;    
375             progressRun.defer(10, _this); 
376             return false;
377         }
378         progressRun.defer(1, _this);
379      
380         
381         
382     }
383     
384      
385    
386     
387     
388 });
389