/* * - LGPL * * base class for bootstrap elements. * */ Roo.bootstrap = Roo.bootstrap || {}; /** * @class Roo.bootstrap.Component * @extends Roo.Component * Bootstrap Component base class * @cfg {String} cls css class * @cfg {String} style any extra css * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.) * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page * @cfg {string} dataId cutomer id * @cfg {string} name Specifies name attribute * @cfg {string} tooltip Text for the tooltip * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer) * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl()) * @constructor * Do not use directly - it does not do anything.. * @param {Object} config The config object */ Roo.bootstrap.Component = function(config){ Roo.bootstrap.Component.superclass.constructor.call(this, config); this.addEvents({ /** * @event childrenrendered * Fires when the children have been rendered.. * @param {Roo.bootstrap.Component} this */ "childrenrendered" : true }); }; Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, { allowDomMove : false, // to stop relocations in parent onRender... cls : false, style : false, autoCreate : false, tooltip : null, /** * Initialize Events for the element */ initEvents : function() { }, xattr : false, parentId : false, can_build_overlaid : true, container_method : false, dataId : false, name : false, parent: function() { // returns the parent component.. return Roo.ComponentMgr.get(this.parentId) }, // private onRender : function(ct, position) { // Roo.log("Call onRender: " + this.xtype); Roo.bootstrap.Component.superclass.onRender.call(this, ct, position); if(this.el){ if (this.el.attr('xtype')) { this.el.attr('xtypex', this.el.attr('xtype')); this.el.dom.removeAttribute('xtype'); this.initEvents(); } return; } var cfg = Roo.apply({}, this.getAutoCreate()); cfg.id = this.id || Roo.id(); // fill in the extra attributes if (this.xattr && typeof(this.xattr) =='object') { for (var i in this.xattr) { cfg[i] = this.xattr[i]; } } if(this.dataId){ cfg.dataId = this.dataId; } if (this.cls) { cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls; } if (this.style) { // fixme needs to support more complex style data. cfg.style = this.style; } if(this.name){ cfg.name = this.name; } this.el = ct.createChild(cfg, position); if (this.tooltip) { this.tooltipEl().attr('tooltip', this.tooltip); } if(this.tabIndex !== undefined){ this.el.dom.setAttribute('tabIndex', this.tabIndex); } this.initEvents(); }, /** * Fetch the element to add children to * @return {Roo.Element} defaults to this.el */ getChildContainer : function() { return this.el; }, /** * Fetch the element to display the tooltip on. * @return {Roo.Element} defaults to this.el */ tooltipEl : function() { return this.el; }, addxtype : function(tree,cntr) { var cn = this; cn = Roo.factory(tree); //Roo.log(['addxtype', cn]); cn.parentType = this.xtype; //?? cn.parentId = this.id; cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr; if (typeof(cn.container_method) == 'string') { cntr = cn.container_method; } var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined'); var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined'); var build_from_html = Roo.XComponent.build_from_html; var is_body = (tree.xtype == 'Body') ; var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body'); var self_cntr_el = Roo.get(this[cntr](false)); // do not try and build conditional elements if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) { return false; } if (!has_flexy_each || !build_from_html || is_body || !page_has_body) { if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){ return this.addxtypeChild(tree,cntr, is_body); } var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false; if(echild){ return this.addxtypeChild(Roo.apply({}, tree),cntr); } Roo.log('skipping render'); return cn; } var ret = false; if (!build_from_html) { return false; } // this i think handles overlaying multiple children of the same type // with the sam eelement.. - which might be buggy.. while (true) { var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false; if (!echild) { break; } if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) { break; } ret = this.addxtypeChild(Roo.apply({}, tree),cntr); } return ret; }, addxtypeChild : function (tree, cntr, is_body) { Roo.debug && Roo.log('addxtypeChild:' + cntr); var cn = this; cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr; var has_flexy = (typeof(tree['flexy:if']) != 'undefined') || (typeof(tree['flexy:foreach']) != 'undefined'); skip_children = false; // render the element if it's not BODY. if (!is_body) { // if parent was disabled, then do not try and create the children.. if(!this[cntr](true)){ tree.items = []; return tree; } cn = Roo.factory(tree); cn.parentType = this.xtype; //?? cn.parentId = this.id; var build_from_html = Roo.XComponent.build_from_html; // does the container contain child eleemnts with 'xtype' attributes. // that match this xtype.. // note - when we render we create these as well.. // so we should check to see if body has xtype set. if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') { var self_cntr_el = Roo.get(this[cntr](false)); var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false; if (echild) { //Roo.log(Roo.XComponent.build_from_html); //Roo.log("got echild:"); //Roo.log(echild); } // there is a scenario where some of the child elements are flexy:if (and all of the same type) // and are not displayed -this causes this to use up the wrong element when matching. // at present the only work around for this is to nest flexy:if elements in another element that is always rendered. if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) { // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') ); cn.el = echild; // Roo.log("GOT"); //echild.dom.removeAttribute('xtype'); } else { Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent')); Roo.debug && Roo.log(self_cntr_el); Roo.debug && Roo.log(echild); Roo.debug && Roo.log(cn); } } // if object has flexy:if - then it may or may not be rendered. if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) { // skip a flexy if element. Roo.debug && Roo.log('skipping render'); Roo.debug && Roo.log(tree); if (!cn.el) { Roo.debug && Roo.log('skipping all children'); skip_children = true; } } else { // actually if flexy:foreach is found, we really want to create // multiple copies here... //Roo.log('render'); //Roo.log(this[cntr]()); // some elements do not have render methods.. like the layouts... /* if(this[cntr](true) === false){ cn.items = []; return cn; } */ cn.render && cn.render(this[cntr](true)); } // then add the element.. } // handle the kids.. var nitems = []; /* if (typeof (tree.menu) != 'undefined') { tree.menu.parentType = cn.xtype; tree.menu.triggerEl = cn.el; nitems.push(cn.addxtype(Roo.apply({}, tree.menu))); } */ if (!tree.items || !tree.items.length) { cn.items = nitems; //Roo.log(["no children", this]); return cn; } var items = tree.items; delete tree.items; //Roo.log(items.length); // add the items.. if (!skip_children) { for(var i =0;i < items.length;i++) { // Roo.log(['add child', items[i]]); nitems.push(cn.addxtype(Roo.apply({}, items[i]))); } } cn.items = nitems; //Roo.log("fire childrenrendered"); cn.fireEvent('childrenrendered', this); return cn; }, /** * Set the element that will be used to show or hide */ setVisibilityEl : function(el) { this.visibilityEl = el; }, /** * Get the element that will be used to show or hide */ getVisibilityEl : function() { if (typeof(this.visibilityEl) == 'object') { return this.visibilityEl; } if (typeof(this.visibilityEl) == 'string') { return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl(); } return this.getEl(); }, /** * Show a component - removes 'hidden' class */ show : function() { if(!this.getVisibilityEl()){ return; } this.getVisibilityEl().removeClass(['hidden','d-none']); this.fireEvent('show', this); }, /** * Hide a component - adds 'hidden' class */ hide: function() { if(!this.getVisibilityEl()){ return; } this.getVisibilityEl().addClass(['hidden','d-none']); this.fireEvent('hide', this); } });