/* * webui popover plugin - v1.1.3 * A lightWeight popover plugin with jquery ,enchance the popover plugin of bootstrap with some awesome new features. It works well with bootstrap ,but bootstrap is not necessary! * https://github.com/sandywalker/webui-popover * * Made by Sandy Duan * Under MIT License */ ;(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: { show: null, hide: null }, async: { before: null, //function(that, xhr){} success: null //function(that, xhr){} }, cache:true, multi:false, arrow:true, title:'', content:'', closeable:false, padding:true, url:'', type:'html', constrains:null, animation:null, template:'
'+ '
'+ '
'+ 'x'+ '

'+ '

 

'+ '
'+ '
' }; var _globalIdSeed = 0; // The actual plugin constructor function WebuiPopover ( element, options ) { this.$element = $(element); if (options){ if($.type(options.delay) === 'string' || $.type(options.delay) === 'number') { options.delay = {show:options.delay,hide:options.delay}; // bc break fix } } this.options = $.extend( {}, defaults, options ); this._defaults = defaults; this._name = pluginName; this._targetclick = false; this.init(); } WebuiPopover.prototype = { //init webui popover init: function () { //init the event handlers if (this.getTrigger()==='click'){ this.$element.off('click').on('click',$.proxy(this.toggle,this)); }else if (this.getTrigger()==='hover'){ this.$element.off('mouseenter mouseleave click') .on('mouseenter',$.proxy(this.mouseenterHandler,this)) .on('mouseleave',$.proxy(this.mouseleaveHandler,this)) .on('click',function(e){e.stopPropagation();}); } this._poped = false; this._inited = true; this._idSeed = _globalIdSeed; _globalIdSeed++; }, /* api methods and actions */ destroy:function(){ this.hide(); this.$element.data('plugin_'+pluginName,null); if (this.getTrigger()==='click'){ this.$element.off('click'); }else if (this.getTrigger()==='hover'){ this.$element.off('mouseenter mouseleave'); } if (this.$target){ this.$target.remove(); } }, hide:function(event){ if (event){ event.preventDefault(); event.stopPropagation(); } if (this.xhr){ this.xhr.abort(); this.xhr = null; } 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 setted , reInit the contents if (!this.getCache()||!this._poped){ this.content = ''; 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 postion elementPos = this.getElementPosition(), //target postion $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: -2000, left: -2000, display: 'block' }); if (this.getAnimation()){ $target.addClass(this.getAnimation()); } $target.appendTo(document.body); targetWidth = $target[0].offsetWidth; targetHeight = $target[0].offsetHeight; placement = this.getPlacement(elementPos); 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 */ getTriggerElement:function(){ return this.$element; }, getTarget:function(){ if (!this.$target){ var id = pluginName+this._idSeed; this.$target = $(this.options.template) .attr('id',id) .data('trigger-element',this.getTriggerElement()); this.getTriggerElement().attr('data-target',id); } return this.$target; }, getTitleElement:function(){ return this.getTarget().find('.'+pluginClass+'-title'); }, getContentElement:function(){ return this.getTarget().find('.'+pluginClass+'-content'); }, getTitle:function(){ return this.$element.attr('data-title')||this.options.title||this.$element.attr('title'); }, getUrl:function(){ return this.$element.attr('data-url')||this.options.url; }, getCache:function(){ var dataAttr = this.$element.attr('data-cache'); if (typeof(dataAttr) !== 'undefined') { switch(dataAttr.toLowerCase()){ case 'true': case 'yes': case '1': return true; case 'false': case 'no': case '0': return false; } } return this.options.cache; }, getTrigger:function(){ return this.$element.attr('data-trigger')||this.options.trigger; }, getDelayShow:function(){ var dataAttr = this.$element.attr('data-delay-show'); if (typeof(dataAttr) !== 'undefined') { return dataAttr; } return this.options.delay.show===0?0:this.options.delay.show||100; }, getHideDelay:function(){ var dataAttr = this.$element.attr('data-delay-hide'); if (typeof(dataAttr) !== 'undefined') { return dataAttr; } return this.options.delay.hide===0?0:this.options.delay.hide||100; }, getConstrains:function(){ var dataAttr = this.$element.attr('data-contrains'); if (typeof(dataAttr) !== 'undefined') { return dataAttr; } return this.options.constrains; }, getAnimation:function(){ var dataAttr = this.$element.attr('data-animation'); return dataAttr||this.options.animation; }, setTitle:function(title){ var $titleEl = this.getTitleElement(); if (title){ $titleEl.html(title); }else{ $titleEl.remove(); } }, hasContent:function () { return this.getContent(); }, getContent:function(){ if (this.getUrl()){ if (this.options.type==='iframe'){ this.content = $('').attr('src',this.getUrl()); } }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; this.xhr = $.ajax({ url:this.getUrl(), type:'GET', cache:this.getCache(), beforeSend:function(xhr) { if (that.options.async.before){ that.options.async.before(that, xhr); } }, success:function(data){ that.bindBodyEvents(); 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(); if (that.options.async.success){ that.options.async.success(that, data); } this.xhr = null; } }); }, 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);} self._enterTimeout = setTimeout(function(){ if (!self.getTarget().is(':visible')){self.show();} },this.getDelayShow()); }, mouseleaveHandler:function(){ var self = this; clearTimeout(self._enterTimeout); //key point, set the _timeout then use clearTimeout when mouse leave self._timeout = setTimeout(function(){ self.hide(); },this.getHideDelay()); }, escapeHandler:function(e){ if (e.keyCode===27){ this.hideAll(); } }, bodyClickHandler:function(){ if (this.getTrigger()==='click'){ if (this._targetclick){ this._targetclick = false; }else{ this.hideAll(); } } }, targetClickHandler:function(){ this._targetclick = true; }, //reset and init the target events; initTargetEvents:function(){ if (this.getTrigger()==='hover'){ 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){ 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'){ var constrainsH = this.getConstrains() === 'horizontal', constrainsV = this.getConstrains() === 'vertical'; if (pageXtargetHeight+arrowSize?'top-right':'bottom-right'; }else if (pageXtargetHeight+arrowSize?'top-left':'bottom-left'; if (pageY