api-site/www/static/common/js/webui-popover.js
lidong 175070a9fd Fix typos
correct some spelling errors

Change-Id: I1c99feeff3d03ff6dc71f749919a9696e1e3a51c
2017-05-19 00:19:33 -07:00

435 lines
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;(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="icon-refresh"></i> <p>&nbsp;</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();
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 = $('<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);
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 autocaculate 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){
if (pageY<clientHeight/3){
placement = 'bottom-right';
}else if (pageY<clientHeight*2/3){
placement = 'right';
}else{
placement = 'top-right';
}
//placement= pageY>targetHeight+arrowSize?'top-right':'bottom-right';
}else if (pageX<clientWidth*2/3){
if (pageY<clientHeight/3){
placement = 'bottom';
}else if (pageY<clientHeight*2/3){
placement = 'bottom';
}else{
placement = 'top';
}
}else{
placement = pageY>targetHeight+arrowSize?'top-left':'bottom-left';
if (pageY<clientHeight/3){
placement = 'bottom-left';
}else if (pageY<clientHeight*2/3){
placement = 'left';
}else{
placement = 'top-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(),
elementH = this.$element.outerHeight(),
position={},
arrowOffset=null,
arrowSize = this.options.arrow?28:0,
fixedW = elementW<arrowSize+10?arrowSize:0,
fixedH = elementH<arrowSize+10?arrowSize: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, left: pos.left + pos.width / 2 - targetWidth / 2};
break;
case 'left':
position = {top: pos.top + pos.height / 2 - targetHeight / 2, left: pos.left - targetWidth};
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, left: pos.left-fixedW};
arrowOffset = {left: elementW/2 + fixedW};
break;
case 'top-left':
position = {top: pos.top - targetHeight, left: pos.left -targetWidth +pos.width + fixedW};
arrowOffset = {left: targetWidth - elementW /2 -fixedW};
break;
case 'bottom-right':
position = {top: pos.top + pos.height, left: pos.left-fixedW};
arrowOffset = {left: elementW /2+fixedW};
break;
case 'bottom-left':
position = {top: pos.top + pos.height, left: pos.left -targetWidth +pos.width+fixedW};
arrowOffset = {left: targetWidth- elementW /2 - fixedW};
break;
case 'right-top':
position = {top: pos.top -targetHeight + pos.height + fixedH, left: pos.left + pos.width};
arrowOffset = {top: targetHeight - elementH/2 -fixedH};
break;
case 'right-bottom':
position = {top: pos.top - fixedH, left: pos.left + pos.width};
arrowOffset = {top: elementH /2 +fixedH };
break;
case 'left-top':
position = {top: pos.top -targetHeight + pos.height+fixedH, left: pos.left - targetWidth};
arrowOffset = {top: targetHeight - elementH/2 - fixedH};
break;
case 'left-bottom':
position = {top: pos.top , left: pos.left -targetWidth};
arrowOffset = {top: elementH /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 );