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