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