X-Git-Url: http://git.roojs.org/?a=blobdiff_plain;f=Roo%2Fbootstrap%2FPopover.js;h=031926d4fc85ea0824233a862368bfbdaa1895f9;hb=7700b2c5de4e083e5c3b3d46cc4e2ff2ab68aab1;hp=c78725b58fc745d96452e5a199397ec10c5e7e0a;hpb=ee538703c9dcd43b7e2c31abef0ca9ea6bfc7bac;p=roojs1 diff --git a/Roo/bootstrap/Popover.js b/Roo/bootstrap/Popover.js index c78725b58f..031926d4fc 100644 --- a/Roo/bootstrap/Popover.js +++ b/Roo/bootstrap/Popover.js @@ -11,10 +11,14 @@ * Bootstrap Popover class * @cfg {String} html contents of the popover (or false to use children..) * @cfg {String} title of popover (or false to hide) - * @cfg {String} placement how it is placed + * @cfg {String|function} (right|top|bottom|left|auto) placement how it is placed * @cfg {String} trigger click || hover (or false to trigger manually) - * @cfg {String} over what (parent or false to trigger manually.) - * + * @cfg {Boolean} modal - popovers that are modal will mask the screen, and must be closed with another event. + * @cfg {String|Boolean|Roo.Element} add click hander to trigger show over what element + * - if false and it has a 'parent' then it will be automatically added to that element + * - if string - Roo.get will be called + * @cfg {Number} delay - delay before showing + * @constructor * Create a new Popover * @param {Object} config The config object @@ -22,43 +26,78 @@ Roo.bootstrap.Popover = function(config){ Roo.bootstrap.Popover.superclass.constructor.call(this, config); + + this.addEvents({ + // raw events + /** + * @event show + * After the popover show + * + * @param {Roo.bootstrap.Popover} this + */ + "show" : true, + /** + * @event hide + * After the popover hide + * + * @param {Roo.bootstrap.Popover} this + */ + "hide" : true + }); }; Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, { - title: 'Fill in a title', + title: false, html: false, placement : 'right', trigger : 'hover', // hover + modal : false, + delay : 0, + + over: false, + + can_build_overlaid : false, - over: 'parent', + maskEl : false, // the mask element + headerEl : false, + contentEl : false, + alignEl : false, // when show is called with an element - this get's stored. getChildContainer : function() { - return this.el.select('.popover-content',true).first(); + return this.contentEl; + + }, + getPopoverHeader : function() + { + this.title = true; // flag not to hide it.. + this.headerEl.addClass('p-0'); + return this.headerEl }, + getAutoCreate : function(){ - Roo.log('make popover?'); + var cfg = { - cls : 'popover', + cls : 'popover roo-dynamic shadow roo-popover' + (this.modal ? '-modal' : ''), style: 'display:block', cn : [ { cls : 'arrow' }, { - cls : 'popover-inner', + cls : 'popover-inner ', cn : [ { tag: 'h3', - cls: 'popover-title', - html : this.title + cls: 'popover-title popover-header', + html : this.title === false ? '' : this.title }, { - cls : 'popover-content', - html : this.html + cls : 'popover-content popover-body ' + (this.cls || ''), + html : this.html || '' } ] @@ -68,10 +107,35 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, { return cfg; }, + /** + * @param {string} the title + */ + setTitle: function(str) + { + this.title = str; + if (this.el) { + this.headerEl.dom.innerHTML = str; + } + + }, + /** + * @param {string} the body content + */ + setContent: function(str) + { + this.html = str; + if (this.contentEl) { + this.contentEl.dom.innerHTML = str; + } + + }, // as it get's added to the bottom of the page. onRender : function(ct, position) { Roo.bootstrap.Component.superclass.onRender.call(this, ct, position); + + + if(!this.el){ var cfg = Roo.apply({}, this.getAutoCreate()); cfg.id = Roo.id(); @@ -82,40 +146,77 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, { if (this.style) { cfg.style = this.style; } - Roo.log("adding to ") + //Roo.log("adding to "); this.el = Roo.get(document.body).createChild(cfg, position); - Roo.log(this.el); +// Roo.log(this.el); } + + this.contentEl = this.el.select('.popover-content',true).first(); + this.headerEl = this.el.select('.popover-title',true).first(); + + var nitems = []; + if(typeof(this.items) != 'undefined'){ + var items = this.items; + delete this.items; + + for(var i =0;i < items.length;i++) { + nitems.push(this.addxtype(Roo.apply({}, items[i]))); + } + } + + this.items = nitems; + + this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true); + Roo.EventManager.onWindowResize(this.resizeMask, this, true); + + + this.initEvents(); }, + resizeMask : function() + { + this.maskEl.setSize( + Roo.lib.Dom.getViewWidth(true), + Roo.lib.Dom.getViewHeight(true) + ); + }, + initEvents : function() { - Roo.log('init Popover'); - this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY); + + if (!this.modal) { + Roo.bootstrap.Popover.register(this); + } + + this.arrowEl = this.el.select('.arrow',true).first(); + this.headerEl.setVisibilityMode(Roo.Element.DISPLAY); // probably not needed as it's default in BS4 this.el.enableDisplayMode('block'); this.el.hide(); - if (this.over === false) { + + + if (this.over === false && !this.parent()) { return; } if (this.triggers === false) { return; } - var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over); + + // support parent + var on_el = (this.over == 'parent' || this.over === false) ? this.parent().el : Roo.get(this.over); var triggers = this.trigger ? this.trigger.split(' ') : []; Roo.each(triggers, function(trigger) { if (trigger == 'click') { on_el.on('click', this.toggle, this); } else if (trigger != 'manual') { - var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' - var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' + var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'; + var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'; on_el.on(eventIn ,this.enter, this); on_el.on(eventOut, this.leave, this); } }, this); - }, @@ -128,15 +229,14 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, { }, enter : function () { - - + clearTimeout(this.timeout); - this.hoverState = 'in' + this.hoverState = 'in'; if (!this.delay || !this.delay.show) { this.show(); - return + return; } var _t = this; this.timeout = setTimeout(function () { @@ -145,14 +245,15 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, { } }, this.delay.show) }, + leave : function() { clearTimeout(this.timeout); - this.hoverState = 'out' + this.hoverState = 'out'; if (!this.delay || !this.delay.hide) { this.hide(); - return + return; } var _t = this; this.timeout = setTimeout(function () { @@ -161,74 +262,224 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, { } }, this.delay.hide) }, - - show : function (on_el) + /** + * Show the popover + * @param {Roo.Element|string|Boolean} - element to align and point to. (set align to [ pos, offset ]) + * @param {string} (left|right|top|bottom) position + */ + show : function (on_el, placement) { + this.placement = typeof(placement) == 'undefined' ? this.placement : placement; + on_el = on_el || false; // default to false + if (!on_el) { - on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over); - } - // set content. - this.el.select('.popover-title',true).first().dom.innerHtml = this.title; - if (this.html !== false) { - this.el.select('.popover-content',true).first().dom.innerHtml = this.title; - } - this.el.removeClass(['fade','top','bottom', 'left', 'right','in']); - if (!this.title.length) { - this.el.select('.popover-title',true).hide(); + if (this.parent() && (this.over == 'parent' || (this.over === false))) { + on_el = this.parent().el; + } else if (this.over) { + on_el = Roo.get(this.over); + } + } - var placement = typeof this.placement == 'function' ? - this.placement.call(this, this.el, on_el) : - this.placement; - - var autoToken = /\s?auto?\s?/i; - var autoPlace = autoToken.test(placement); - if (autoPlace) { - placement = placement.replace(autoToken, '') || 'top'; + this.alignEl = Roo.get( on_el ); + + if (!this.el) { + this.render(document.body); } - //this.el.detach() - //this.el.setXY([0,0]); - this.el.show(); - this.el.dom.style.display='block'; - this.el.addClass(placement); - //this.el.appendTo(on_el); + - var p = this.getPosition(); - var box = this.el.getBox(); + if (this.title === false) { + this.headerEl.hide(); + } - if (autoPlace) { - // fixme.. + + this.el.show(); + this.el.dom.style.display = 'block'; + + + if (this.alignEl) { + this.updatePosition(this.placement, true); + + } else { + // this is usually just done by the builder = to show the popoup in the middle of the scren. + var es = this.el.getSize(); + var x = Roo.lib.Dom.getViewWidth()/2; + var y = Roo.lib.Dom.getViewHeight()/2; + this.el.setXY([ x-(es.width/2), y-(es.height/2)] ); + } - var align = Roo.bootstrap.Popover.alignment[placement] - this.el.alignTo(on_el, align[0],align[1]); + + //var arrow = this.el.select('.arrow',true).first(); //arrow.set(align[2], this.el.addClass('in'); - this.hoverState = null; - if (this.el.hasClass('fade')) { - // fade it? + + + this.hoverState = 'in'; + + if (this.modal) { + this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true)); + this.maskEl.setStyle('z-index', Roo.bootstrap.Popover.zIndex++); + this.maskEl.dom.style.display = 'block'; + this.maskEl.addClass('show'); + } + this.el.setStyle('z-index', Roo.bootstrap.Popover.zIndex++); + + this.fireEvent('show', this); + + }, + /** + * fire this manually after loading a grid in the table for example + * @param {string} (left|right|top|bottom) where to try and put it (use false to use the last one) + * @param {Boolean} try and move it if we cant get right position. + */ + updatePosition : function(placement, try_move) + { + // allow for calling with no parameters + placement = placement ? placement : this.placement; + try_move = typeof(try_move) == 'undefined' ? true : try_move; + + this.el.removeClass([ + 'fade','top','bottom', 'left', 'right','in', + 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right' + ]); + this.el.addClass(placement + ' bs-popover-' + placement); + + if (!this.alignEl ) { + return false; + } + + switch (placement) { + case 'right': + var exact = this.el.getAlignToXY(this.alignEl, 'tl-tr', [10,0]); + var offset = this.el.getAlignToXY(this.alignEl, 'tl-tr?',[10,0]); + if (!try_move || exact.equals(offset) || exact[0] == offset[0] ) { + //normal display... or moved up/down. + this.el.setXY(offset); + var xy = this.alignEl.getAnchorXY('tr', false); + xy[0]+=2;xy[1]+=5; + this.arrowEl.setXY(xy); + return true; + } + // continue through... + return this.updatePosition('left', false); + + + case 'left': + var exact = this.el.getAlignToXY(this.alignEl, 'tr-tl', [-10,0]); + var offset = this.el.getAlignToXY(this.alignEl, 'tr-tl?',[-10,0]); + if (!try_move || exact.equals(offset) || exact[0] == offset[0] ) { + //normal display... or moved up/down. + this.el.setXY(offset); + var xy = this.alignEl.getAnchorXY('tl', false); + xy[0]-=10;xy[1]+=5; // << fix me + this.arrowEl.setXY(xy); + return true; + } + // call self... + return this.updatePosition('right', false); + + case 'top': + var exact = this.el.getAlignToXY(this.alignEl, 'b-t', [0,-10]); + var offset = this.el.getAlignToXY(this.alignEl, 'b-t?',[0,-10]); + if (!try_move || exact.equals(offset) || exact[1] == offset[1] ) { + //normal display... or moved up/down. + this.el.setXY(offset); + var xy = this.alignEl.getAnchorXY('t', false); + xy[1]-=10; // << fix me + this.arrowEl.setXY(xy); + return true; + } + // fall through + return this.updatePosition('bottom', false); + + case 'bottom': + var exact = this.el.getAlignToXY(this.alignEl, 't-b', [0,10]); + var offset = this.el.getAlignToXY(this.alignEl, 't-b?',[0,10]); + if (!try_move || exact.equals(offset) || exact[1] == offset[1] ) { + //normal display... or moved up/down. + this.el.setXY(offset); + var xy = this.alignEl.getAnchorXY('b', false); + xy[1]+=2; // << fix me + this.arrowEl.setXY(xy); + return true; + } + // fall through + return this.updatePosition('top', false); + + } + + return false; }, + hide : function() { this.el.setXY([0,0]); this.el.removeClass('in'); this.el.hide(); - + this.hoverState = null; + this.maskEl.hide(); // always.. + this.fireEvent('hide', this); } }); -Roo.bootstrap.Popover.alignment = { - 'left' : ['r-l', [-10,0], 'right'], - 'right' : ['l-r', [10,0], 'left'], - 'bottom' : ['t-b', [0,10], 'top'], - 'top' : [ 'b-t', [0,-10], 'bottom'] -}; - \ No newline at end of file +Roo.apply(Roo.bootstrap.Popover, { + + alignment : { + 'left' : ['r-l', [-10,0], 'left bs-popover-left'], + 'right' : ['l-br', [10,0], 'right bs-popover-right'], + 'bottom' : ['t-b', [0,10], 'top bs-popover-top'], + 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom'] + }, + + zIndex : 20001, + + clickHander : false, + + + + onMouseDown : function(e) + { + if (this.popups.length && !e.getTarget(".roo-popover")) { + /// what is nothing is showing.. + this.hideAll(); + } + + }, + + + popups : [], + + register : function(popup) + { + if (!Roo.bootstrap.Popover.clickHandler) { + Roo.bootstrap.Popover.clickHandler = Roo.get(document).on("mousedown", Roo.bootstrap.Popover.onMouseDown, Roo.bootstrap.Popover); + } + // hide other popups. + popup.on('show', Roo.bootstrap.Popover.onShow, popup); + popup.on('hide', Roo.bootstrap.Popover.onHide, popup); + this.hideAll(); //<< why? + //this.popups.push(popup); + }, + hideAll : function() + { + this.popups.forEach(function(p) { + p.hide(); + }); + }, + onShow : function() { + Roo.bootstrap.Popover.popups.push(this); + }, + onHide : function() { + Roo.bootstrap.Popover.popups.remove(this); + } + +}); \ No newline at end of file