;(function ( $, window, document, undefined ) { // Create the defaults once var pluginName = 'webuiPopover'; var pluginClass = 'webui-popover'; var pluginType = 'webui.popover'; var defaults = { placement:'auto', width:'auto', height:'auto', trigger:'click', style:'', delay:300, cache:true, multi:false, arrow:true, title:'', content:'', closeable:false, padding:true, url:'', type:'html', template:'
'+ '
'+ '
'+ 'x'+ '

'+ '

 

'+ '
'+ '
' }; // The actual plugin constructor function WebuiPopover ( element, options ) { this.$element = $(element); this.options = $.extend( {}, defaults, options ); this._defaults = defaults; this._name = pluginName; this.init(); } WebuiPopover.prototype = { //init webui popover init: function () { //init the event handlers if (this.options.trigger==='click'){ this.$element.off('click').on('click',$.proxy(this.toggle,this)); }else{ this.$element.off('mouseenter mouseleave') .on('mouseenter',$.proxy(this.mouseenterHandler,this)) .on('mouseleave',$.proxy(this.mouseleaveHandler,this)); } this._poped = false; this._inited = true; }, /* api methods and actions */ destroy:function(){ this.hide(); this.$element.data('plugin_'+pluginName,null); this.$element.off(); if (this.$target){ this.$target.remove(); } }, hide:function(event){ if (event){ event.preventDefault(); event.stopPropagation(); } var e = $.Event('hide.' + pluginType); this.$element.trigger(e); if (this.$target){this.$target.removeClass('in').hide();} this.$element.trigger('hidden.'+pluginType); }, toggle:function(e){ if (e) { e.preventDefault(); e.stopPropagation(); } this[this.getTarget().hasClass('in') ? 'hide' : 'show'](); }, hideAll:function(){ $('div.webui-popover').not('.webui-popover-fixed').removeClass('in').hide(); }, /*core method ,show popover */ show:function(){ var $target = this.getTarget().removeClass().addClass(pluginClass); if (!this.options.multi){ this.hideAll(); } // use cache by default, if not cache set, reInit the contents if (!this.options.cache||!this._poped){ this.setTitle(this.getTitle()); if (!this.options.closeable){ $target.find('.close').off('click').remove(); } if (!this.isAsync()){ this.setContent(this.getContent()); }else{ this.setContentASync(this.options.content); this.displayContent(); return; } $target.show(); } this.displayContent(); this.bindBodyEvents(); }, displayContent:function(){ var //element position elementPos = this.getElementPosition(), //target position $target = this.getTarget().removeClass().addClass(pluginClass), //target content $targetContent = this.getContentElement(), //target Width targetWidth = $target[0].offsetWidth, //target Height targetHeight = $target[0].offsetHeight, //placement placement = 'bottom', e = $.Event('show.' + pluginType); //if (this.hasContent()){ this.$element.trigger(e); //} if (this.options.width!=='auto') {$target.width(this.options.width);} if (this.options.height!=='auto'){$targetContent.height(this.options.height);} //init the popover and insert into the document body if (!this.options.arrow){ $target.find('.arrow').remove(); } $target.remove().css({ top: -1000, left: -1000, display: 'block' }).appendTo(document.body); targetWidth = $target[0].offsetWidth; targetHeight = $target[0].offsetHeight; placement = this.getPlacement(elementPos,targetHeight); this.initTargetEvents(); var postionInfo = this.getTargetPositin(elementPos,placement,targetWidth,targetHeight); this.$target.css(postionInfo.position).addClass(placement).addClass('in'); if (this.options.type==='iframe'){ var $iframe = $target.find('iframe'); $iframe.width($target.width()).height($iframe.parent().height()); } if (this.options.style){ this.$target.addClass(pluginClass+'-'+this.options.style); } if (!this.options.padding){ $targetContent.css('height',$targetContent.outerHeight()); this.$target.addClass('webui-no-padding'); } if (!this.options.arrow){ this.$target.css({'margin':0}); } if (this.options.arrow){ var $arrow = this.$target.find('.arrow'); $arrow.removeAttr('style'); if (postionInfo.arrowOffset){ $arrow.css(postionInfo.arrowOffset); } } this._poped = true; this.$element.trigger('shown.'+pluginType); }, isTargetLoaded:function(){ return this.getTarget().find('i.glyphicon-refresh').length===0; }, /*getter setters */ getTarget:function(){ if (!this.$target){ this.$target = $(this.options.template); } return this.$target; }, getTitleElement:function(){ return this.getTarget().find('.'+pluginClass+'-title'); }, getContentElement:function(){ return this.getTarget().find('.'+pluginClass+'-content'); }, getTitle:function(){ return this.options.title||this.$element.attr('data-title')||this.$element.attr('title'); }, setTitle:function(title){ var $titleEl = this.getTitleElement(); if (title){ $titleEl.html(title); }else{ $titleEl.remove(); } }, hasContent:function () { return this.getContent(); }, getContent:function(){ if (this.options.url){ if (this.options.type==='iframe'){ this.content = $('').attr('src',this.options.url); } }else if (!this.content){ var content=''; if ($.isFunction(this.options.content)){ content = this.options.content.apply(this.$element[0],arguments); }else{ content = this.options.content; } this.content = this.$element.attr('data-content')||content; } return this.content; }, setContent:function(content){ var $target = this.getTarget(); this.getContentElement().html(content); this.$target = $target; }, isAsync:function(){ return this.options.type==='async'; }, setContentASync:function(content){ var that = this; $.ajax({ url:this.options.url, type:'GET', cache:this.options.cache, success:function(data){ if (content&&$.isFunction(content)){ that.content = content.apply(that.$element[0],[data]); }else{ that.content = data; } that.setContent(that.content); var $targetContent = that.getContentElement(); $targetContent.removeAttr('style'); that.displayContent(); } }); }, bindBodyEvents:function(){ $('body').off('keyup.webui-popover').on('keyup.webui-popover',$.proxy(this.escapeHandler,this)); $('body').off('click.webui-popover').on('click.webui-popover',$.proxy(this.bodyClickHandler,this)); }, /* event handlers */ mouseenterHandler:function(){ var self = this; if (self._timeout){clearTimeout(self._timeout);} if (!self.getTarget().is(':visible')){self.show();} }, mouseleaveHandler:function(){ var self = this; //key point, set the _timeout then use clearTimeout when mouse leave self._timeout = setTimeout(function(){ self.hide(); },self.options.delay); }, escapeHandler:function(e){ if (e.keyCode===27){ this.hideAll(); } }, bodyClickHandler:function(){ this.hideAll(); }, targetClickHandler:function(e){ e.stopPropagation(); }, //reset and init the target events; initTargetEvents:function(){ if (this.options.trigger!=='click'){ this.$target.off('mouseenter mouseleave') .on('mouseenter',$.proxy(this.mouseenterHandler,this)) .on('mouseleave',$.proxy(this.mouseleaveHandler,this)); } this.$target.find('.close').off('click').on('click', $.proxy(this.hide,this)); this.$target.off('click.webui-popover').on('click.webui-popover',$.proxy(this.targetClickHandler,this)); }, /* utils methods */ //caculate placement of the popover getPlacement:function(pos,targetHeight){ var placement, de = document.documentElement, db = document.body, clientWidth = de.clientWidth, clientHeight = de.clientHeight, scrollTop = Math.max(db.scrollTop,de.scrollTop), scrollLeft = Math.max(db.scrollLeft,de.scrollLeft), pageX = Math.max(0,pos.left - scrollLeft), pageY = Math.max(0,pos.top - scrollTop), arrowSize = 20; //if placement equals autoļ¼Œcaculate the placement by element information; if (typeof(this.options.placement)==='function'){ placement = this.options.placement.call(this, this.getTarget()[0], this.$element[0]); }else{ placement = this.$element.data('placement')||this.options.placement; } if (placement==='auto'){ if (pageXtargetHeight+arrowSize?'top-right':'bottom-right'; }else if (pageXtargetHeight+arrowSize?'top-left':'bottom-left'; if (pageY