4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
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 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24 * Do not use directly - it does not do anything..
25 * @param {Object} config The config object
30 Roo.bootstrap.Component = function(config){
31 Roo.bootstrap.Component.superclass.constructor.call(this, config);
35 * @event childrenrendered
36 * Fires when the children have been rendered..
37 * @param {Roo.bootstrap.Component} this
39 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
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];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 * This is really a wrapper for addxtypeChild
161 * it handles stuff relating to flexy:foreach / flexy:if
162 * = some of our projects use a flat rendering of the output, and try and overlay it with dynamic data.
163 * -- this is a bit of a nightmare... and is even more confusing to debug..
168 addxtype : function(tree,cntr)
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172 var cn = Roo.factory(tree); // this is posibly the first of two times that the ctor get's called...
173 cn.parentType = this.xtype; //??
174 cn.parentId = this.id;
175 if (typeof(cn.container_method) == 'string') {
176 cntr = cn.container_method;
180 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
182 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
184 var build_from_html = Roo.XComponent.build_from_html;
186 var is_body = (tree.xtype == 'Body') ;
188 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
190 var self_cntr_el = Roo.get(this[cntr](false));
192 // do not try and build conditional elements
193 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
197 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
198 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
199 //return this.addxtypeChild(tree,cntr, is_body);
200 return this.addxtypeChild(tree, cntr, is_body);
203 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
206 return this.addxtypeChild(Roo.apply({}, tree),cntr);
209 Roo.log('skipping render');
215 if (!build_from_html) {
219 // this i think handles overlaying multiple children of the same type
220 // with the sam eelement.. - which might be buggy..
222 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
228 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
232 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
238 * add a child to this element
239 * - turn the child.cfg into a child_instance
240 * - call child_instance.render( this { getContainerMethod()} )
241 * - loop through the children, and call addxtype.. (reall this) on newly created child.
245 addxtypeChild : function (tree, cntr, is_body)
247 Roo.debug && Roo.log('addxtypeChild:' + cntr);
249 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
252 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
253 (typeof(tree['flexy:foreach']) != 'undefined');
257 skip_children = false;
258 // render the element if it's not BODY.
261 // if parent was disabled, then do not try and create the children..
262 if(!this[cntr](true)){
267 cn = Roo.factory(tree);
269 cn.parentType = this.xtype; //??
270 cn.parentId = this.id;
272 var build_from_html = Roo.XComponent.build_from_html;
275 // does the container contain child eleemnts with 'xtype' attributes.
276 // that match this xtype..
277 // note - when we render we create these as well..
278 // so we should check to see if body has xtype set.
279 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
281 var self_cntr_el = Roo.get(this[cntr](false));
282 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
284 //Roo.log(Roo.XComponent.build_from_html);
285 //Roo.log("got echild:");
288 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
289 // and are not displayed -this causes this to use up the wrong element when matching.
290 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
293 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
294 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
300 //echild.dom.removeAttribute('xtype');
302 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
303 Roo.debug && Roo.log(self_cntr_el);
304 Roo.debug && Roo.log(echild);
305 Roo.debug && Roo.log(cn);
311 // if object has flexy:if - then it may or may not be rendered.
312 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
313 // skip a flexy if element.
314 Roo.debug && Roo.log('skipping render');
315 Roo.debug && Roo.log(tree);
317 Roo.debug && Roo.log('skipping all children');
318 skip_children = true;
323 // actually if flexy:foreach is found, we really want to create
324 // multiple copies here...
326 //Roo.log(this[cntr]());
327 // some elements do not have render methods.. like the layouts...
329 if(this[cntr](true) === false){
334 cn.render && cn.render(this[cntr](true));
337 // then add the element..
344 cn.addxtypeChildren(tree.items, skip_children);
350 * add a number of children to this object,
351 * which in turn calls render...
355 addxtypeChildren: function(child_array, skip_children)
358 if (!child_array || !child_array.length ) {
363 for(var i =0;i < child_array.length;i++) {
367 // Roo.log(['add child', items[i]]);
368 nitems.push(this.addxtype(Roo.apply({}, child_array[i])));
372 this.fireEvent('childrenrendered', this);
382 * xAddChildren - the 'sub-compentized' version of the above idea..
384 xAddChildren: function(child_array, skip_children)
387 if (!child_array || !child_array.length ) {
392 for(var i =0;i < child_array.length;i++) {
396 // Roo.log(['add child', items[i]]);
397 nitems.push(this.xAdd(Roo.apply({}, child_array[i])));
401 this.fireEvent('childrenrendered', this);
407 * add a child to this element
408 * - turn the child.cfg into a child_instance
409 * - call child_instance.render( this { getContainerMethod()} )
410 * - loop through the children, and call addxtype.. (reall this) on newly created child.
411 * xAdd differs from addxtype - as it uses the 'items' returned from
416 xAdd : function (tree, cntr, is_body)
418 Roo.debug && Roo.log('xadd:' + cntr);
420 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
422 var parent_ctnr = this[cntr](true);
423 if(parent_ctnr === false){
424 return false; // getChildContainer an return false explicitly to block children being added?
427 throw new Exception("could not find parent Container for item");
430 var cn = Roo.factory(tree);
431 // at this point items[] array may be set..
432 // constructors should not really be building their children?
433 cn.parentType = this.xtype; //??
434 cn.parentId = this.id;
437 cn.render && cn.render(parent_ctnr);
439 cn.xAddChildren(tree.items);
440 delete tree.items; // not really needed?
446 * Set the element that will be used to show or hide
448 setVisibilityEl : function(el)
450 this.visibilityEl = el;
454 * Get the element that will be used to show or hide
456 getVisibilityEl : function()
458 if (typeof(this.visibilityEl) == 'object') {
459 return this.visibilityEl;
462 if (typeof(this.visibilityEl) == 'string') {
463 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
470 * Show a component - removes 'hidden' class
474 if(!this.getVisibilityEl()){
478 this.getVisibilityEl().removeClass(['hidden','d-none']);
480 this.fireEvent('show', this);
485 * Hide a component - adds 'hidden' class
489 if(!this.getVisibilityEl()){
493 this.getVisibilityEl().addClass(['hidden','d-none']);
495 this.fireEvent('hide', this);