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