Roo/bootstrap/Component.js
[roojs1] / Roo / bootstrap / Component.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * @cfg {string} tooltip  Text for the tooltip
20  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
21  * 
22  * @constructor
23  * Do not use directly - it does not do anything..
24  * @param {Object} config The config object
25  */
26
27
28
29 Roo.bootstrap.Component = function(config){
30     Roo.bootstrap.Component.superclass.constructor.call(this, config);
31        
32     this.addEvents({
33         /**
34          * @event childrenrendered
35          * Fires when the children have been rendered..
36          * @param {Roo.bootstrap.Component} this
37          */
38         "childrenrendered" : true
39         
40         
41         
42     });
43     
44     
45 };
46
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
48     
49     
50     allowDomMove : false, // to stop relocations in parent onRender...
51     
52     cls : false,
53     
54     style : false,
55     
56     autoCreate : false,
57     
58     tooltip : null,
59     /**
60      * Initialize Events for the element
61      */
62     initEvents : function() { },
63     
64     xattr : false,
65     
66     parentId : false,
67     
68     can_build_overlaid : true,
69     
70     container_method : false,
71     
72     dataId : false,
73     
74     name : false,
75     
76     parent: function() {
77         // returns the parent component..
78         return Roo.ComponentMgr.get(this.parentId)
79         
80         
81     },
82     
83     // private
84     onRender : function(ct, position)
85     {
86        // Roo.log("Call onRender: " + this.xtype);
87         
88         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
89         Roo.log('onRender???');
90         if(this.el){
91             Roo.log('run??');
92             if (this.el.attr('xtype')) {
93                 this.el.attr('xtypex', this.el.attr('xtype'));
94                 this.el.dom.removeAttribute('xtype');
95                 
96                 this.initEvents();
97             }
98             
99             return;
100         }
101         
102          
103         
104         var cfg = Roo.apply({},  this.getAutoCreate());
105         cfg.id = this.id || Roo.id();
106         
107         // fill in the extra attributes 
108         if (this.xattr && typeof(this.xattr) =='object') {
109             for (var i in this.xattr) {
110                 cfg[i] = this.xattr[i];
111             }
112         }
113         
114         if(this.dataId){
115             cfg.dataId = this.dataId;
116         }
117         
118         if (this.cls) {
119             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
120         }
121         
122         if (this.style) { // fixme needs to support more complex style data.
123             cfg.style = this.style;
124         }
125         
126         if(this.name){
127             cfg.name = this.name;
128         }
129         
130         this.el = ct.createChild(cfg, position);
131         
132         Roo.log(this);
133         
134         if (this.tooltip) {
135             Roo.log(this.tooltip);
136             this.tooltipEl().attr('tooltip', this.tooltip);
137         }
138         
139         if(this.tabIndex !== undefined){
140             this.el.dom.setAttribute('tabIndex', this.tabIndex);
141         }
142         this.initEvents();
143         
144         
145     },
146     /**
147      * Fetch the element to add children to
148      * @return {Roo.Element} defaults to this.el
149      */
150     getChildContainer : function()
151     {
152         return this.el;
153     },
154     /**
155      * Fetch the element to display the tooltip on.
156      * @return {Roo.Element} defaults to this.el
157      */
158     tooltipEl : function()
159     {
160         Roo.log('tooltipEl!!!!!!!!!!!!!!');
161         Roo.log(this.el);
162         return this.el;
163     },
164         
165     addxtype  : function(tree,cntr)
166     {
167         Roo.log(tree);
168         var cn = this;
169         
170         cn = Roo.factory(tree);
171            
172         cn.parentType = this.xtype; //??
173         cn.parentId = this.id;
174         
175         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
176         if (typeof(cn.container_method) == 'string') {
177             cntr = cn.container_method;
178         }
179         
180         
181         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
182         
183         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
184         
185         var build_from_html =  Roo.XComponent.build_from_html;
186           
187         var is_body  = (tree.xtype == 'Body') ;
188           
189         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
190           
191         var self_cntr_el = Roo.get(this[cntr](false));
192         
193         // do not try and build conditional elements 
194         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
195             return false;
196         }
197         
198         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
199             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
200                 return this.addxtypeChild(tree,cntr);
201             }
202             
203             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
204                 
205             if(echild){
206                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
207             }
208             
209             Roo.log('skipping render');
210             return cn;
211             
212         }
213         
214         var ret = false;
215         if (!build_from_html) {
216             return false;
217         }
218         
219         // this i think handles overlaying multiple children of the same type
220         // with the sam eelement.. - which might be buggy..
221         while (true) {
222             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223             
224             if (!echild) {
225                 break;
226             }
227             
228             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
229                 break;
230             }
231             
232             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
233         }
234         return ret;
235     },
236     
237     addxtypeChild : function (tree, cntr)
238     {
239         Roo.debug && Roo.log('addxtypeChild:' + cntr);
240         var cn = this;
241         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
242         
243         
244         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
245                     (typeof(tree['flexy:foreach']) != 'undefined');
246           
247         
248         
249          skip_children = false;
250         // render the element if it's not BODY.
251         if (tree.xtype != 'Body') {
252            
253             cn = Roo.factory(tree);
254            
255             cn.parentType = this.xtype; //??
256             cn.parentId = this.id;
257             
258             var build_from_html =  Roo.XComponent.build_from_html;
259             
260             
261             // does the container contain child eleemnts with 'xtype' attributes.
262             // that match this xtype..
263             // note - when we render we create these as well..
264             // so we should check to see if body has xtype set.
265             if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
266                
267                 var self_cntr_el = Roo.get(this[cntr](false));
268                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
269                 if (echild) { 
270                     //Roo.log(Roo.XComponent.build_from_html);
271                     //Roo.log("got echild:");
272                     //Roo.log(echild);
273                 }
274                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
275                 // and are not displayed -this causes this to use up the wrong element when matching.
276                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
277                 
278                 
279                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
280                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
281                   
282                   
283                   
284                     cn.el = echild;
285                   //  Roo.log("GOT");
286                     //echild.dom.removeAttribute('xtype');
287                 } else {
288                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
289                     Roo.debug && Roo.log(self_cntr_el);
290                     Roo.debug && Roo.log(echild);
291                     Roo.debug && Roo.log(cn);
292                 }
293             }
294            
295             
296            
297             // if object has flexy:if - then it may or may not be rendered.
298             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
299                 // skip a flexy if element.
300                 Roo.debug && Roo.log('skipping render');
301                 Roo.debug && Roo.log(tree);
302                 if (!cn.el) {
303                     Roo.debug && Roo.log('skipping all children');
304                     skip_children = true;
305                 }
306                 
307              } else {
308                  
309                 // actually if flexy:foreach is found, we really want to create 
310                 // multiple copies here...
311                 //Roo.log('render');
312                 //Roo.log(this[cntr]());
313                 cn.render(this[cntr](true));
314              }
315             // then add the element..
316         }
317         
318         
319         // handle the kids..
320         
321         var nitems = [];
322         /*
323         if (typeof (tree.menu) != 'undefined') {
324             tree.menu.parentType = cn.xtype;
325             tree.menu.triggerEl = cn.el;
326             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
327             
328         }
329         */
330         if (!tree.items || !tree.items.length) {
331             cn.items = nitems;
332             return cn;
333         }
334         var items = tree.items;
335         delete tree.items;
336         
337         //Roo.log(items.length);
338             // add the items..
339         if (!skip_children) {    
340             for(var i =0;i < items.length;i++) {
341                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
342             }
343         }
344         
345         cn.items = nitems;
346         
347         this.fireEvent('childrenrendered', this);
348         
349         return cn;
350     },
351     /**
352      * Show a component - removes 'hidden' class
353      */
354     show : function()
355     {
356         if (this.el) {
357             this.el.removeClass('hidden');
358         }
359     },
360     /**
361      * Hide a component - adds 'hidden' class
362      */
363     hide: function()
364     {
365         if (this.el && !this.el.hasClass('hidden')) {
366             this.el.addClass('hidden');
367         }
368         
369     }
370 });
371
372