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