359 lines
12 KiB
JavaScript
359 lines
12 KiB
JavaScript
|
|
/*
|
|||
|
|
* webui popover plugin - v1.0.5
|
|||
|
|
* 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:300,
|
|||
|
|
cache:true,
|
|||
|
|
multi:false,
|
|||
|
|
arrow:true,
|
|||
|
|
title:'',
|
|||
|
|
content:'',
|
|||
|
|
closeable:false,
|
|||
|
|
padding:true,
|
|||
|
|
url:'',
|
|||
|
|
type:'html',
|
|||
|
|
template:'<div class="webui-popover">'+
|
|||
|
|
'<div class="arrow"></div>'+
|
|||
|
|
'<div class="webui-popover-inner">'+
|
|||
|
|
'<a href="#" class="close">x</a>'+
|
|||
|
|
'<h3 class="webui-popover-title"></h3>'+
|
|||
|
|
'<div class="webui-popover-content"><i class="glyphicon glyphicon-refresh"></i> <p></p></div>'+
|
|||
|
|
'</div>'+
|
|||
|
|
'</div>'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 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();}
|
|||
|
|
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();}
|
|||
|
|
this[this.getTarget().hasClass('in') ? 'hide' : 'show']();
|
|||
|
|
},
|
|||
|
|
hideAll:function(){
|
|||
|
|
$('div.webui-popover').removeClass('in').hide();
|
|||
|
|
},
|
|||
|
|
/*core method ,show popover */
|
|||
|
|
show: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.options.multi){
|
|||
|
|
this.hideAll();
|
|||
|
|
}
|
|||
|
|
//if (this.hasContent()){
|
|||
|
|
this.$element.trigger(e);
|
|||
|
|
//}
|
|||
|
|
// use cache by default, if not cache setted , reInit the contents
|
|||
|
|
if (!this.options.cache||!this._poped){
|
|||
|
|
if (!this.isAsync()){
|
|||
|
|
this.setContent(this.getContent());
|
|||
|
|
}else{
|
|||
|
|
this.setContentASync(this.options.content);
|
|||
|
|
}
|
|||
|
|
this.setTitle(this.getTitle());
|
|||
|
|
if (!this.options.closeable){
|
|||
|
|
$target.find('.close').off('click').remove();
|
|||
|
|
}
|
|||
|
|
$target.show();
|
|||
|
|
}
|
|||
|
|
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){
|
|||
|
|
//fixed position offset bug
|
|||
|
|
$targetContent.css('height',$targetContent.outerHeight());
|
|||
|
|
this.$target.addClass('webui-no-padding');
|
|||
|
|
}
|
|||
|
|
if (!this.options.arrow){
|
|||
|
|
this.$target.css({'margin':0});
|
|||
|
|
}
|
|||
|
|
if (this.options.arrow&&postionInfo.arrowOffset){
|
|||
|
|
this.$target.find('.arrow').css(postionInfo.arrowOffset);
|
|||
|
|
}
|
|||
|
|
this._poped = true;
|
|||
|
|
this.$element.trigger('shown.'+pluginType);
|
|||
|
|
},
|
|||
|
|
/*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 = $('<iframe frameborder="0"></iframe>').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);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
/* 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);
|
|||
|
|
},
|
|||
|
|
//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));
|
|||
|
|
},
|
|||
|
|
/* 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 (pageX<clientWidth/3){
|
|||
|
|
placement= pageY>targetHeight+arrowSize?'top-right':'bottom-right';
|
|||
|
|
}else if (pageX<clientWidth*2/3){
|
|||
|
|
placement = pageY>targetHeight+arrowSize?'top':'bottom';
|
|||
|
|
}else{
|
|||
|
|
placement = pageY>targetHeight+arrowSize?'top-left':'bottom-left';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return placement;
|
|||
|
|
},
|
|||
|
|
getElementPosition:function(){
|
|||
|
|
return $.extend({},this.$element.offset(), {
|
|||
|
|
width: this.$element[0].offsetWidth,
|
|||
|
|
height: this.$element[0].offsetHeight
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
getTargetPositin:function(elementPos,placement,targetWidth,targetHeight){
|
|||
|
|
var pos = elementPos,
|
|||
|
|
elementW = this.$element.outerWidth(),
|
|||
|
|
position={},
|
|||
|
|
arrowOffset={},
|
|||
|
|
arrowSize = this.options.arrow?0:0;
|
|||
|
|
switch (placement) {
|
|||
|
|
case 'bottom':
|
|||
|
|
position = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - targetWidth / 2};
|
|||
|
|
break;
|
|||
|
|
case 'top':
|
|||
|
|
position = {top: pos.top - targetHeight-arrowSize, left: pos.left + pos.width / 2 - targetWidth / 2};
|
|||
|
|
break;
|
|||
|
|
case 'left':
|
|||
|
|
position = {top: pos.top + pos.height / 2 - targetHeight / 2, left: pos.left - targetWidth -arrowSize};
|
|||
|
|
break;
|
|||
|
|
case 'right':
|
|||
|
|
position = {top: pos.top + pos.height / 2 - targetHeight / 2, left: pos.left + pos.width};
|
|||
|
|
break;
|
|||
|
|
case 'top-right':
|
|||
|
|
position = {top: pos.top - targetHeight -arrowSize, left: pos.left};
|
|||
|
|
arrowOffset = {left: elementW /2 };
|
|||
|
|
break;
|
|||
|
|
case 'top-left':
|
|||
|
|
position = {top: pos.top - targetHeight -arrowSize, left: pos.left -targetWidth +pos.width};
|
|||
|
|
arrowOffset = {left: targetWidth - elementW /2 };
|
|||
|
|
break;
|
|||
|
|
case 'bottom-right':
|
|||
|
|
position = {top: pos.top + pos.height, left: pos.left};
|
|||
|
|
arrowOffset = {left: elementW /2};
|
|||
|
|
break;
|
|||
|
|
case 'bottom-left':
|
|||
|
|
position = {top: pos.top + pos.height, left: pos.left -targetWidth +pos.width};
|
|||
|
|
arrowOffset = {left: targetWidth- elementW /2};
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
return {position:position,arrowOffset:arrowOffset};
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
$.fn[ pluginName ] = function ( options ) {
|
|||
|
|
return this.each(function() {
|
|||
|
|
var webuiPopover = $.data( this, 'plugin_' + pluginName );
|
|||
|
|
if (!webuiPopover) {
|
|||
|
|
if (!options){
|
|||
|
|
webuiPopover = new WebuiPopover( this, null);
|
|||
|
|
}else if (typeof options ==='string'){
|
|||
|
|
if (options!=='destroy'){
|
|||
|
|
webuiPopover = new WebuiPopover( this, null );
|
|||
|
|
webuiPopover[options]();
|
|||
|
|
}
|
|||
|
|
}else if (typeof options ==='object'){
|
|||
|
|
webuiPopover = new WebuiPopover( this, options );
|
|||
|
|
}
|
|||
|
|
$.data( this, 'plugin_' + pluginName, webuiPopover);
|
|||
|
|
}else{
|
|||
|
|
if (options==='destroy'){
|
|||
|
|
webuiPopover.destroy();
|
|||
|
|
}else if (typeof options ==='string'){
|
|||
|
|
webuiPopover[options]();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
})( jQuery, window, document );
|
|||
|
|
|
|||
|
|
|