1220 lines
54 KiB
JavaScript
1220 lines
54 KiB
JavaScript
/*
|
||
* webui popover plugin - v1.2.17
|
||
* 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
|
||
*/
|
||
|
||
layui.define(['jquery', 'element'], function(exports) {
|
||
var $=layui.$;
|
||
// Create the defaults once
|
||
var pluginName = 'webuiPopover';
|
||
var pluginClass = 'webui-popover';
|
||
var pluginType = 'webui.popover';
|
||
var defaults = {
|
||
placement: 'auto',
|
||
container: null,
|
||
width: 'auto',
|
||
height: 'auto',
|
||
trigger: 'click', //hover,click,sticky,manual
|
||
style: '',
|
||
opacity:null,
|
||
selector: false, // jQuery selector, if a selector is provided, popover objects will be delegated to the specified.
|
||
delay: {
|
||
show: null,
|
||
hide: 300
|
||
},
|
||
async: {
|
||
type: 'GET',
|
||
before: null, //function(that, xhr, settings){}
|
||
success: null, //function(that, xhr){}
|
||
error: null //function(that, xhr, data){}
|
||
},
|
||
cache: true,
|
||
multi: false,
|
||
arrow: true,
|
||
title: '',
|
||
content: '',
|
||
closeable: false,
|
||
padding: true,
|
||
url: '',
|
||
type: 'html',
|
||
direction: '', // ltr,rtl
|
||
animation: null,
|
||
template: '<div class="webui-popover">' +
|
||
'<div class="webui-arrow"></div>' +
|
||
'<div class="webui-popover-inner">' +
|
||
'<a href="#" class="close"></a>' +
|
||
'<h3 class="webui-popover-title"></h3>' +
|
||
'<div class="webui-popover-content"><i class="icon-refresh"></i> <p> </p></div>' +
|
||
'</div>' +
|
||
'</div>',
|
||
backdrop: false,
|
||
dismissible: true,
|
||
onShow: null,
|
||
onHide: null,
|
||
abortXHR: true,
|
||
autoHide: false,
|
||
offsetTop: 0,
|
||
offsetLeft: 0,
|
||
iframeOptions: {
|
||
frameborder: '0',
|
||
allowtransparency: 'true',
|
||
id: '',
|
||
name: '',
|
||
scrolling: '',
|
||
onload: '',
|
||
height: '',
|
||
width: ''
|
||
},
|
||
hideEmpty: false
|
||
};
|
||
|
||
var rtlClass = pluginClass + '-rtl';
|
||
var _srcElements = [];
|
||
var backdrop = $('<div class="webui-popover-backdrop"></div>');
|
||
var _globalIdSeed = 0;
|
||
var _isBodyEventHandled = false;
|
||
var _offsetOut = -2000; // the value offset out of the screen
|
||
var $document = $(document);
|
||
|
||
var toNumber = function (numeric, fallback) {
|
||
return isNaN(numeric) ? (fallback || 0) : Number(numeric);
|
||
};
|
||
|
||
var getPopFromElement = function ($element) {
|
||
return $element.data('plugin_' + pluginName);
|
||
};
|
||
|
||
var hideAllPop = function () {
|
||
var pop = null;
|
||
for (var i = 0; i < _srcElements.length; i++) {
|
||
pop = getPopFromElement(_srcElements[i]);
|
||
if (pop) {
|
||
pop.hide(true);
|
||
}
|
||
}
|
||
$document.trigger('hiddenAll.' + pluginType);
|
||
};
|
||
|
||
var hideOtherPops = function (currentPop) {
|
||
var pop = null;
|
||
for (var i = 0; i < _srcElements.length; i++) {
|
||
pop = getPopFromElement(_srcElements[i]);
|
||
if (pop && pop.id !== currentPop.id) {
|
||
pop.hide(true);
|
||
}
|
||
}
|
||
$document.trigger('hiddenAll.' + pluginType);
|
||
};
|
||
|
||
var isMobile = ('ontouchstart' in document.documentElement) && (/Mobi/.test(navigator.userAgent));
|
||
|
||
var pointerEventToXY = function (e) {
|
||
var out = {
|
||
x: 0,
|
||
y: 0
|
||
};
|
||
if (e.type === 'touchstart' || e.type === 'touchmove' || e.type === 'touchend' || e.type === 'touchcancel') {
|
||
var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
|
||
out.x = touch.pageX;
|
||
out.y = touch.pageY;
|
||
} else if (e.type === 'mousedown' || e.type === 'mouseup' || e.type === 'click') {
|
||
out.x = e.pageX;
|
||
out.y = e.pageY;
|
||
}
|
||
return out;
|
||
};
|
||
|
||
|
||
// 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();
|
||
_srcElements.push(this.$element);
|
||
return this;
|
||
|
||
}
|
||
|
||
WebuiPopover.prototype = {
|
||
//init webui popover
|
||
init: function () {
|
||
if (this.$element[0] instanceof document.constructor && !this.options.selector) {
|
||
throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!');
|
||
}
|
||
|
||
if (this.getTrigger() !== 'manual') {
|
||
//init the event handlers
|
||
if (isMobile) {
|
||
this.$element.off('touchend', this.options.selector).on('touchend', this.options.selector, $.proxy(this.toggle, this));
|
||
} else if (this.getTrigger() === 'click') {
|
||
this.$element.off('click', this.options.selector).on('click', this.options.selector, $.proxy(this.toggle, this));
|
||
} else if (this.getTrigger() === 'hover') {
|
||
this.$element
|
||
.off('mouseenter mouseleave click', this.options.selector)
|
||
.on('mouseenter', this.options.selector, $.proxy(this.mouseenterHandler, this))
|
||
.on('mouseleave', this.options.selector, $.proxy(this.mouseleaveHandler, this));
|
||
}
|
||
}
|
||
this._poped = false;
|
||
this._inited = true;
|
||
this._opened = false;
|
||
this._idSeed = _globalIdSeed;
|
||
this.id = pluginName + this._idSeed;
|
||
// normalize container
|
||
this.options.container = $(this.options.container || document.body).first();
|
||
|
||
if (this.options.backdrop) {
|
||
backdrop.appendTo(this.options.container).hide();
|
||
}
|
||
_globalIdSeed++;
|
||
if (this.getTrigger() === 'sticky') {
|
||
this.show();
|
||
}
|
||
|
||
if (this.options.selector) {
|
||
this._options = $.extend({}, this.options, {
|
||
selector: ''
|
||
});
|
||
}
|
||
|
||
},
|
||
/* api methods and actions */
|
||
destroy: function () {
|
||
var index = -1;
|
||
|
||
for (var i = 0; i < _srcElements.length; i++) {
|
||
if (_srcElements[i] === this.$element) {
|
||
index = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
_srcElements.splice(index, 1);
|
||
|
||
|
||
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();
|
||
}
|
||
},
|
||
getDelegateOptions: function () {
|
||
var options = {};
|
||
|
||
this._options && $.each(this._options, function (key, value) {
|
||
if (defaults[key] !== value) {
|
||
options[key] = value;
|
||
}
|
||
});
|
||
return options;
|
||
},
|
||
/*
|
||
param: force boolean value, if value is true then force hide the popover
|
||
param: event dom event,
|
||
*/
|
||
hide: function (force, event) {
|
||
|
||
if (!force && this.getTrigger() === 'sticky') {
|
||
return;
|
||
}
|
||
if (!this._opened) {
|
||
return;
|
||
}
|
||
if (event) {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
}
|
||
|
||
if (this.xhr && this.options.abortXHR === true) {
|
||
this.xhr.abort();
|
||
this.xhr = null;
|
||
}
|
||
|
||
|
||
var e = $.Event('hide.' + pluginType);
|
||
this.$element.trigger(e, [this.$target]);
|
||
if (this.$target) {
|
||
this.$target.removeClass('in').addClass(this.getHideAnimation());
|
||
var that = this;
|
||
setTimeout(function () {
|
||
that.$target.hide();
|
||
if (!that.getCache()) {
|
||
that.$target.remove();
|
||
//that.getTriggerElement.removeAttr('data-target');
|
||
}
|
||
}, that.getHideDelay());
|
||
}
|
||
if (this.options.backdrop) {
|
||
backdrop.hide();
|
||
}
|
||
this._opened = false;
|
||
this.$element.trigger('hidden.' + pluginType, [this.$target]);
|
||
|
||
if (this.options.onHide) {
|
||
this.options.onHide(this.$target);
|
||
}
|
||
|
||
},
|
||
resetAutoHide: function () {
|
||
var that = this;
|
||
var autoHide = that.getAutoHide();
|
||
if (autoHide) {
|
||
if (that.autoHideHandler) {
|
||
clearTimeout(that.autoHideHandler);
|
||
}
|
||
that.autoHideHandler = setTimeout(function () {
|
||
that.hide();
|
||
}, autoHide);
|
||
}
|
||
},
|
||
delegate: function (eventTarget) {
|
||
var self = $(eventTarget).data('plugin_' + pluginName);
|
||
if (!self) {
|
||
self = new WebuiPopover(eventTarget, this.getDelegateOptions());
|
||
$(eventTarget).data('plugin_' + pluginName, self);
|
||
}
|
||
return self;
|
||
},
|
||
toggle: function (e) {
|
||
var self = this;
|
||
if (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
if (this.options.selector) {
|
||
self = this.delegate(e.currentTarget);
|
||
}
|
||
}
|
||
self[self.getTarget().hasClass('in') ? 'hide' : 'show']();
|
||
},
|
||
hideAll: function () {
|
||
hideAllPop();
|
||
},
|
||
hideOthers: function () {
|
||
hideOtherPops(this);
|
||
},
|
||
/*core method ,show popover */
|
||
show: function () {
|
||
if (this._opened) {
|
||
return;
|
||
}
|
||
//removeAllTargets();
|
||
var
|
||
$target = this.getTarget().removeClass().addClass(pluginClass).addClass(this._customTargetClass);
|
||
if (!this.options.multi) {
|
||
this.hideOthers();
|
||
}
|
||
|
||
// use cache by default, if not cache setted , reInit the contents
|
||
if (!this.getCache() || !this._poped || this.content === '') {
|
||
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);
|
||
}
|
||
|
||
if (this.canEmptyHide() && this.content === '') {
|
||
return;
|
||
}
|
||
$target.show();
|
||
}
|
||
|
||
this.displayContent();
|
||
|
||
if (this.options.onShow) {
|
||
this.options.onShow($target);
|
||
}
|
||
|
||
this.bindBodyEvents();
|
||
if (this.options.backdrop) {
|
||
backdrop.show();
|
||
}
|
||
this._opened = true;
|
||
this.resetAutoHide();
|
||
},
|
||
displayContent: function () {
|
||
var
|
||
//element postion
|
||
elementPos = this.getElementPosition(),
|
||
//target postion
|
||
$target = this.getTarget().removeClass().addClass(pluginClass).addClass(this._customTargetClass),
|
||
//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.canEmptyHide()) {
|
||
|
||
var content = $targetContent.children().html();
|
||
if (content !== null && content.trim().length === 0) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
//if (this.hasContent()){
|
||
this.$element.trigger(e, [$target]);
|
||
//}
|
||
// support width as data attribute
|
||
var optWidth = this.$element.data('width') || this.options.width;
|
||
if (optWidth === '') {
|
||
optWidth = this._defaults.width;
|
||
}
|
||
|
||
if (optWidth !== 'auto') {
|
||
$target.width(optWidth);
|
||
}
|
||
|
||
// support height as data attribute
|
||
var optHeight = this.$element.data('height') || this.options.height;
|
||
if (optHeight === '') {
|
||
optHeight = this._defaults.height;
|
||
}
|
||
|
||
if (optHeight !== 'auto') {
|
||
$targetContent.height(optHeight);
|
||
}
|
||
|
||
if (this.options.style) {
|
||
this.$target.addClass(pluginClass + '-' + this.options.style);
|
||
}
|
||
|
||
//check rtl
|
||
if (this.options.direction === 'rtl' && !$targetContent.hasClass(rtlClass)) {
|
||
$targetContent.addClass(rtlClass);
|
||
}
|
||
|
||
//init the popover and insert into the document body
|
||
if (!this.options.arrow) {
|
||
$target.find('.webui-arrow').remove();
|
||
}
|
||
$target.detach().css({
|
||
top: _offsetOut,
|
||
left: _offsetOut,
|
||
display: 'block',
|
||
opacity:this.options.opacity || 1
|
||
});
|
||
|
||
if (this.getAnimation()) {
|
||
$target.addClass(this.getAnimation());
|
||
}
|
||
$target.appendTo(this.options.container);
|
||
|
||
|
||
placement = this.getPlacement(elementPos);
|
||
|
||
//This line is just for compatible with knockout custom binding
|
||
this.$element.trigger('added.' + pluginType);
|
||
|
||
this.initTargetEvents();
|
||
|
||
if (!this.options.padding) {
|
||
if (this.options.height !== 'auto') {
|
||
$targetContent.css('height', $targetContent.outerHeight());
|
||
}
|
||
this.$target.addClass('webui-no-padding');
|
||
}
|
||
|
||
// add maxHeight and maxWidth support by limodou@gmail.com 2016/10/1
|
||
if (this.options.maxHeight) {
|
||
$targetContent.css('maxHeight', this.options.maxHeight);
|
||
}
|
||
|
||
if (this.options.maxWidth) {
|
||
$targetContent.css('maxWidth', this.options.maxWidth);
|
||
}
|
||
// end
|
||
|
||
targetWidth = $target[0].offsetWidth;
|
||
targetHeight = $target[0].offsetHeight;
|
||
|
||
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');
|
||
var iframeWidth = $target.width();
|
||
var iframeHeight = $iframe.parent().height();
|
||
|
||
if (this.options.iframeOptions.width !== '' && this.options.iframeOptions.width !== 'auto') {
|
||
iframeWidth = this.options.iframeOptions.width;
|
||
}
|
||
|
||
if (this.options.iframeOptions.height !== '' && this.options.iframeOptions.height !== 'auto') {
|
||
iframeHeight = this.options.iframeOptions.height;
|
||
}
|
||
|
||
$iframe.width(iframeWidth).height(iframeHeight);
|
||
}
|
||
|
||
if (!this.options.arrow) {
|
||
this.$target.css({
|
||
'margin': 0
|
||
});
|
||
}
|
||
if (this.options.arrow) {
|
||
var $arrow = this.$target.find('.webui-arrow');
|
||
$arrow.removeAttr('style');
|
||
|
||
//prevent arrow change by content size
|
||
if (placement === 'left' || placement === 'right') {
|
||
$arrow.css({
|
||
top: this.$target.height() / 2
|
||
});
|
||
} else if (placement === 'top' || placement === 'bottom') {
|
||
$arrow.css({
|
||
left: this.$target.width() / 2
|
||
});
|
||
}
|
||
|
||
if (postionInfo.arrowOffset) {
|
||
//hide the arrow if offset is negative
|
||
if (postionInfo.arrowOffset.left === -1 || postionInfo.arrowOffset.top === -1) {
|
||
$arrow.hide();
|
||
} else {
|
||
$arrow.css(postionInfo.arrowOffset);
|
||
}
|
||
}
|
||
|
||
}
|
||
this._poped = true;
|
||
this.$element.trigger('shown.' + pluginType, [this.$target]);
|
||
},
|
||
|
||
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);
|
||
this._customTargetClass = this.$target.attr('class') !== pluginClass ? this.$target.attr('class') : null;
|
||
this.getTriggerElement().attr('data-target', id);
|
||
}
|
||
if (!this.$target.data('trigger-element')) {
|
||
this.$target.data('trigger-element', this.getTriggerElement());
|
||
}
|
||
return this.$target;
|
||
},
|
||
removeTarget: function () {
|
||
this.$target.remove();
|
||
this.$target = null;
|
||
this.$contentElement = null;
|
||
},
|
||
getTitleElement: function () {
|
||
return this.getTarget().find('.' + pluginClass + '-title');
|
||
},
|
||
getContentElement: function () {
|
||
if (!this.$contentElement) {
|
||
this.$contentElement = this.getTarget().find('.' + pluginClass + '-content');
|
||
}
|
||
return this.$contentElement;
|
||
},
|
||
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;
|
||
},
|
||
getAutoHide: function () {
|
||
return this.$element.attr('data-auto-hide') || this.options.autoHide;
|
||
},
|
||
getOffsetTop: function () {
|
||
return toNumber(this.$element.attr('data-offset-top')) || this.options.offsetTop;
|
||
},
|
||
getOffsetLeft: function () {
|
||
return toNumber(this.$element.attr('data-offset-left')) || this.options.offsetLeft;
|
||
},
|
||
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;
|
||
},
|
||
getAnimation: function () {
|
||
var dataAttr = this.$element.attr('data-animation');
|
||
return dataAttr || this.options.animation;
|
||
},
|
||
getHideAnimation: function () {
|
||
var ani = this.getAnimation();
|
||
return ani ? ani + '-out' : 'out';
|
||
},
|
||
setTitle: function (title) {
|
||
var $titleEl = this.getTitleElement();
|
||
if (title) {
|
||
//check rtl
|
||
if (this.options.direction === 'rtl' && !$titleEl.hasClass(rtlClass)) {
|
||
$titleEl.addClass(rtlClass);
|
||
}
|
||
$titleEl.html(title);
|
||
} else {
|
||
$titleEl.remove();
|
||
}
|
||
},
|
||
hasContent: function () {
|
||
return this.getContent();
|
||
},
|
||
canEmptyHide: function () {
|
||
return this.options.hideEmpty && this.options.type === 'html';
|
||
},
|
||
getIframe: function () {
|
||
var $iframe = $('<iframe></iframe>').attr('src', this.getUrl());
|
||
var self = this;
|
||
$.each(this._defaults.iframeOptions, function (opt) {
|
||
if (typeof self.options.iframeOptions[opt] !== 'undefined') {
|
||
$iframe.attr(opt, self.options.iframeOptions[opt]);
|
||
}
|
||
});
|
||
|
||
return $iframe;
|
||
},
|
||
getContent: function () {
|
||
if (this.getUrl()) {
|
||
switch (this.options.type) {
|
||
case 'iframe':
|
||
this.content = this.getIframe();
|
||
break;
|
||
case 'html':
|
||
try {
|
||
this.content = $(this.getUrl());
|
||
if (!this.content.is(':visible')) {
|
||
this.content.show();
|
||
}
|
||
} catch (error) {
|
||
throw new Error('Unable to get popover content. Invalid selector specified.');
|
||
}
|
||
break;
|
||
}
|
||
} else if (!this.content) {
|
||
var content = '';
|
||
if ($.isFunction(this.options.content)) {
|
||
content = this.options.content.apply(this.$element[0], [this]);
|
||
} else {
|
||
content = this.options.content;
|
||
}
|
||
this.content = this.$element.attr('data-content') || content;
|
||
if (!this.content) {
|
||
var $next = this.$element.next();
|
||
|
||
if ($next && $next.hasClass(pluginClass + '-content')) {
|
||
this.content = $next;
|
||
}
|
||
}
|
||
}
|
||
return this.content;
|
||
},
|
||
setContent: function (content) {
|
||
var $target = this.getTarget();
|
||
var $ct = this.getContentElement();
|
||
if (typeof content === 'string') {
|
||
$ct.html(content);
|
||
} else if (content instanceof $) {
|
||
$ct.html('');
|
||
//Don't want to clone too many times.
|
||
if (!this.options.cache) {
|
||
content.clone(true, true).removeClass(pluginClass + '-content').appendTo($ct);
|
||
} else {
|
||
content.removeClass(pluginClass + '-content').appendTo($ct);
|
||
}
|
||
}
|
||
this.$target = $target;
|
||
},
|
||
isAsync: function () {
|
||
return this.options.type === 'async';
|
||
},
|
||
setContentASync: function (content) {
|
||
var that = this;
|
||
if (this.xhr) {
|
||
return;
|
||
}
|
||
this.xhr = $.ajax({
|
||
url: this.getUrl(),
|
||
type: this.options.async.type,
|
||
cache: this.getCache(),
|
||
beforeSend: function (xhr, settings) {
|
||
if (that.options.async.before) {
|
||
that.options.async.before(that, xhr, settings);
|
||
}
|
||
},
|
||
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);
|
||
}
|
||
},
|
||
complete: function () {
|
||
that.xhr = null;
|
||
},
|
||
error: function (xhr, data) {
|
||
if (that.options.async.error) {
|
||
that.options.async.error(that, xhr, data);
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
bindBodyEvents: function () {
|
||
if (_isBodyEventHandled) {
|
||
return;
|
||
}
|
||
if (this.options.dismissible && this.getTrigger() === 'click') {
|
||
if (isMobile) {
|
||
$document.off('touchstart.webui-popover').on('touchstart.webui-popover', $.proxy(this.bodyTouchStartHandler, this));
|
||
} else {
|
||
$document.off('keyup.webui-popover').on('keyup.webui-popover', $.proxy(this.escapeHandler, this));
|
||
$document.off('click.webui-popover').on('click.webui-popover', $.proxy(this.bodyClickHandler, this));
|
||
}
|
||
} else if (this.getTrigger() === 'hover') {
|
||
$document.off('touchend.webui-popover')
|
||
.on('touchend.webui-popover', $.proxy(this.bodyClickHandler, this));
|
||
}
|
||
},
|
||
|
||
/* event handlers */
|
||
mouseenterHandler: function (e) {
|
||
var self = this;
|
||
|
||
if (e && this.options.selector) {
|
||
self = this.delegate(e.currentTarget);
|
||
}
|
||
|
||
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();
|
||
}
|
||
},
|
||
bodyTouchStartHandler: function (e) {
|
||
var self = this;
|
||
var $eventEl = $(e.currentTarget);
|
||
$eventEl.on('touchend', function (e) {
|
||
self.bodyClickHandler(e);
|
||
$eventEl.off('touchend');
|
||
});
|
||
$eventEl.on('touchmove', function () {
|
||
$eventEl.off('touchend');
|
||
});
|
||
},
|
||
bodyClickHandler: function (e) {
|
||
_isBodyEventHandled = true;
|
||
var canHide = true;
|
||
for (var i = 0; i < _srcElements.length; i++) {
|
||
var pop = getPopFromElement(_srcElements[i]);
|
||
if (pop && pop._opened) {
|
||
var offset = pop.getTarget().offset();
|
||
var popX1 = offset.left;
|
||
var popY1 = offset.top;
|
||
var popX2 = offset.left + pop.getTarget().width();
|
||
var popY2 = offset.top + pop.getTarget().height();
|
||
var pt = pointerEventToXY(e);
|
||
var inPop = pt.x >= popX1 && pt.x <= popX2 && pt.y >= popY1 && pt.y <= popY2;
|
||
if (inPop) {
|
||
canHide = false;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (canHide) {
|
||
hideAllPop();
|
||
}
|
||
},
|
||
|
||
/*
|
||
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, true));
|
||
//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,
|
||
container = this.options.container,
|
||
clientWidth = container.innerWidth(),
|
||
clientHeight = container.innerHeight(),
|
||
scrollTop = container.scrollTop(),
|
||
scrollLeft = container.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;
|
||
}
|
||
|
||
var isH = placement === 'horizontal';
|
||
var isV = placement === 'vertical';
|
||
var detect = placement === 'auto' || isH || isV;
|
||
|
||
if (detect) {
|
||
if (pageX < clientWidth / 3) {
|
||
if (pageY < clientHeight / 3) {
|
||
placement = isH ? 'right-bottom' : 'bottom-right';
|
||
} else if (pageY < clientHeight * 2 / 3) {
|
||
if (isV) {
|
||
placement = pageY <= clientHeight / 2 ? 'bottom-right' : 'top-right';
|
||
} else {
|
||
placement = 'right';
|
||
}
|
||
} else {
|
||
placement = isH ? 'right-top' : 'top-right';
|
||
}
|
||
//placement= pageY>targetHeight+arrowSize?'top-right':'bottom-right';
|
||
} else if (pageX < clientWidth * 2 / 3) {
|
||
if (pageY < clientHeight / 3) {
|
||
if (isH) {
|
||
placement = pageX <= clientWidth / 2 ? 'right-bottom' : 'left-bottom';
|
||
} else {
|
||
placement = 'bottom';
|
||
}
|
||
} else if (pageY < clientHeight * 2 / 3) {
|
||
if (isH) {
|
||
placement = pageX <= clientWidth / 2 ? 'right' : 'left';
|
||
} else {
|
||
placement = pageY <= clientHeight / 2 ? 'bottom' : 'top';
|
||
}
|
||
} else {
|
||
if (isH) {
|
||
placement = pageX <= clientWidth / 2 ? 'right-top' : 'left-top';
|
||
} else {
|
||
placement = 'top';
|
||
}
|
||
}
|
||
} else {
|
||
//placement = pageY>targetHeight+arrowSize?'top-left':'bottom-left';
|
||
if (pageY < clientHeight / 3) {
|
||
placement = isH ? 'left-bottom' : 'bottom-left';
|
||
} else if (pageY < clientHeight * 2 / 3) {
|
||
if (isV) {
|
||
placement = pageY <= clientHeight / 2 ? 'bottom-left' : 'top-left';
|
||
} else {
|
||
placement = 'left';
|
||
}
|
||
} else {
|
||
placement = isH ? 'left-top' : 'top-left';
|
||
}
|
||
}
|
||
} else if (placement === 'auto-top') {
|
||
if (pageX < clientWidth / 3) {
|
||
placement = 'top-right';
|
||
} else if (pageX < clientWidth * 2 / 3) {
|
||
placement = 'top';
|
||
} else {
|
||
placement = 'top-left';
|
||
}
|
||
} else if (placement === 'auto-bottom') {
|
||
if (pageX < clientWidth / 3) {
|
||
placement = 'bottom-right';
|
||
} else if (pageX < clientWidth * 2 / 3) {
|
||
placement = 'bottom';
|
||
} else {
|
||
placement = 'bottom-left';
|
||
}
|
||
} else if (placement === 'auto-left') {
|
||
if (pageY < clientHeight / 3) {
|
||
placement = 'left-top';
|
||
} else if (pageY < clientHeight * 2 / 3) {
|
||
placement = 'left';
|
||
} else {
|
||
placement = 'left-bottom';
|
||
}
|
||
} else if (placement === 'auto-right') {
|
||
if (pageY < clientHeight / 3) {
|
||
placement = 'right-bottom';
|
||
} else if (pageY < clientHeight * 2 / 3) {
|
||
placement = 'right';
|
||
} else {
|
||
placement = 'right-top';
|
||
}
|
||
}
|
||
return placement;
|
||
},
|
||
getElementPosition: function () {
|
||
// If the container is the body or normal conatiner, just use $element.offset()
|
||
var elRect = this.$element[0].getBoundingClientRect();
|
||
var container = this.options.container;
|
||
var cssPos = container.css('position');
|
||
|
||
if (container.is(document.body) || cssPos === 'static') {
|
||
return $.extend({}, this.$element.offset(), {
|
||
width: this.$element[0].offsetWidth || elRect.width,
|
||
height: this.$element[0].offsetHeight || elRect.height
|
||
});
|
||
// Else fixed container need recalculate the position
|
||
} else if (cssPos === 'fixed') {
|
||
var containerRect = container[0].getBoundingClientRect();
|
||
return {
|
||
top: elRect.top - containerRect.top + container.scrollTop(),
|
||
left: elRect.left - containerRect.left + container.scrollLeft(),
|
||
width: elRect.width,
|
||
height: elRect.height
|
||
};
|
||
} else if (cssPos === 'relative') {
|
||
return {
|
||
top: this.$element.offset().top - container.offset().top,
|
||
left: this.$element.offset().left - container.offset().left,
|
||
width: this.$element[0].offsetWidth || elRect.width,
|
||
height: this.$element[0].offsetHeight || elRect.height
|
||
};
|
||
}
|
||
},
|
||
|
||
getTargetPositin: function (elementPos, placement, targetWidth, targetHeight) {
|
||
var pos = elementPos,
|
||
container = this.options.container,
|
||
//clientWidth = container.innerWidth(),
|
||
//clientHeight = container.innerHeight(),
|
||
elementW = this.$element.outerWidth(),
|
||
elementH = this.$element.outerHeight(),
|
||
scrollTop = document.documentElement.scrollTop + container.scrollTop(),
|
||
scrollLeft = document.documentElement.scrollLeft + container.scrollLeft(),
|
||
position = {},
|
||
arrowOffset = null,
|
||
arrowSize = this.options.arrow ? 20 : 0,
|
||
padding = 10,
|
||
fixedW = elementW < arrowSize + padding ? arrowSize : 0,
|
||
fixedH = elementH < arrowSize + padding ? arrowSize : 0,
|
||
refix = 0,
|
||
pageH = document.documentElement.clientHeight + scrollTop,
|
||
pageW = document.documentElement.clientWidth + scrollLeft;
|
||
|
||
var validLeft = pos.left + pos.width / 2 - fixedW > 0;
|
||
var validRight = pos.left + pos.width / 2 + fixedW < pageW;
|
||
var validTop = pos.top + pos.height / 2 - fixedH > 0;
|
||
var validBottom = pos.top + pos.height / 2 + fixedH < pageH;
|
||
|
||
|
||
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: validLeft ? pos.left - fixedW : padding
|
||
};
|
||
arrowOffset = {
|
||
left: validLeft ? Math.min(elementW, targetWidth) / 2 + fixedW : _offsetOut
|
||
};
|
||
break;
|
||
case 'top-left':
|
||
refix = validRight ? fixedW : -padding;
|
||
position = {
|
||
top: pos.top - targetHeight,
|
||
left: pos.left - targetWidth + pos.width + refix
|
||
};
|
||
arrowOffset = {
|
||
left: validRight ? targetWidth - Math.min(elementW, targetWidth) / 2 - fixedW : _offsetOut
|
||
};
|
||
break;
|
||
case 'bottom-right':
|
||
position = {
|
||
top: pos.top + pos.height,
|
||
left: validLeft ? pos.left - fixedW : padding
|
||
};
|
||
arrowOffset = {
|
||
left: validLeft ? Math.min(elementW, targetWidth) / 2 + fixedW : _offsetOut
|
||
};
|
||
break;
|
||
case 'bottom-left':
|
||
refix = validRight ? fixedW : -padding;
|
||
position = {
|
||
top: pos.top + pos.height,
|
||
left: pos.left - targetWidth + pos.width + refix
|
||
};
|
||
arrowOffset = {
|
||
left: validRight ? targetWidth - Math.min(elementW, targetWidth) / 2 - fixedW : _offsetOut
|
||
};
|
||
break;
|
||
case 'right-top':
|
||
refix = validBottom ? fixedH : -padding;
|
||
position = {
|
||
top: pos.top - targetHeight + pos.height + refix,
|
||
left: pos.left + pos.width
|
||
};
|
||
arrowOffset = {
|
||
top: validBottom ? targetHeight - Math.min(elementH, targetHeight) / 2 - fixedH : _offsetOut
|
||
};
|
||
break;
|
||
case 'right-bottom':
|
||
position = {
|
||
top: validTop ? pos.top - fixedH : padding,
|
||
left: pos.left + pos.width
|
||
};
|
||
arrowOffset = {
|
||
top: validTop ? Math.min(elementH, targetHeight) / 2 + fixedH : _offsetOut
|
||
};
|
||
break;
|
||
case 'left-top':
|
||
refix = validBottom ? fixedH : -padding;
|
||
position = {
|
||
top: pos.top - targetHeight + pos.height + refix,
|
||
left: pos.left - targetWidth
|
||
};
|
||
arrowOffset = {
|
||
top: validBottom ? targetHeight - Math.min(elementH, targetHeight) / 2 - fixedH : _offsetOut
|
||
};
|
||
break;
|
||
case 'left-bottom':
|
||
position = {
|
||
top: validTop ? pos.top - fixedH : padding,
|
||
left: pos.left - targetWidth
|
||
};
|
||
arrowOffset = {
|
||
top: validTop ? Math.min(elementH, targetHeight) / 2 + fixedH : _offsetOut
|
||
};
|
||
break;
|
||
|
||
}
|
||
position.top += this.getOffsetTop();
|
||
position.left += this.getOffsetLeft();
|
||
|
||
return {
|
||
position: position,
|
||
arrowOffset: arrowOffset
|
||
};
|
||
}
|
||
};
|
||
$.fn[pluginName] = function (options, noInit) {
|
||
var results = [];
|
||
var $result = 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') {
|
||
if (!noInit) {
|
||
webuiPopover = new WebuiPopover(this, null);
|
||
results.push(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') {
|
||
results.push(webuiPopover[options]());
|
||
}
|
||
}
|
||
});
|
||
return (results.length) ? results : $result;
|
||
};
|
||
|
||
//Global object exposes to window.
|
||
var webuiPopovers = (function () {
|
||
var _hideAll = function () {
|
||
hideAllPop();
|
||
};
|
||
var _create = function (selector, options) {
|
||
options = options || {};
|
||
$(selector).webuiPopover(options);
|
||
};
|
||
var _isCreated = function (selector) {
|
||
var created = true;
|
||
$(selector).each(function (i, item) {
|
||
created = created && $(item).data('plugin_' + pluginName) !== undefined;
|
||
});
|
||
return created;
|
||
};
|
||
var _show = function (selector, options) {
|
||
if (options) {
|
||
$(selector).webuiPopover(options).webuiPopover('show');
|
||
} else {
|
||
$(selector).webuiPopover('show');
|
||
}
|
||
};
|
||
var _hide = function (selector) {
|
||
$(selector).webuiPopover('hide');
|
||
};
|
||
|
||
var _setDefaultOptions = function (options) {
|
||
defaults = $.extend({}, defaults, options);
|
||
};
|
||
|
||
var _updateContent = function (selector, content) {
|
||
var pop = $(selector).data('plugin_' + pluginName);
|
||
if (pop) {
|
||
var cache = pop.getCache();
|
||
pop.options.cache = false;
|
||
pop.options.content = content;
|
||
if (pop._opened) {
|
||
pop._opened = false;
|
||
pop.show();
|
||
} else {
|
||
if (pop.isAsync()) {
|
||
pop.setContentASync(content);
|
||
} else {
|
||
pop.setContent(content);
|
||
}
|
||
}
|
||
pop.options.cache = cache;
|
||
}
|
||
};
|
||
|
||
var _updateContentAsync = function (selector, url) {
|
||
var pop = $(selector).data('plugin_' + pluginName);
|
||
if (pop) {
|
||
var cache = pop.getCache();
|
||
var type = pop.options.type;
|
||
pop.options.cache = false;
|
||
pop.options.url = url;
|
||
|
||
if (pop._opened) {
|
||
pop._opened = false;
|
||
pop.show();
|
||
} else {
|
||
pop.options.type = 'async';
|
||
pop.setContentASync(pop.content);
|
||
}
|
||
pop.options.cache = cache;
|
||
pop.options.type = type;
|
||
}
|
||
};
|
||
|
||
return {
|
||
show: _show,
|
||
hide: _hide,
|
||
create: _create,
|
||
isCreated: _isCreated,
|
||
hideAll: _hideAll,
|
||
updateContent: _updateContent,
|
||
updateContentAsync: _updateContentAsync,
|
||
setDefaultOptions: _setDefaultOptions
|
||
};
|
||
})();
|
||
window.WebuiPopovers = webuiPopovers;
|
||
exports("popover",WebuiPopovers);
|
||
})
|
||
|
||
|
||
|
||
|