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