zui
Version:
一个基于 Bootstrap 深度定制开源前端实践方案,帮助你快速构建现代跨屏应用。
456 lines (408 loc) • 18.6 kB
JavaScript
/* ========================================================================
* ZUI: modal.trigger.js [1.2.0+]
* http://zui.sexy
* ========================================================================
* Copyright (c) 2014-2016 cnezsoft.com; Licensed MIT
* ======================================================================== */
(function($, window, undefined) {
'use strict';
if(!$.fn.modal) throw new Error('Modal trigger requires modal.js');
var NAME = 'zui.modaltrigger',
STR_AJAX = 'ajax',
ZUI_MODAL = '.zui.modal',
STR_STRING = 'string';
// MODAL TRIGGER CLASS DEFINITION
// ======================
var ModalTrigger = function(options, $trigger) {
options = $.extend({}, ModalTrigger.DEFAULTS, $.ModalTriggerDefaults, $trigger ? $trigger.data() : null, options);
this.isShown;
this.$trigger = $trigger;
this.options = options;
this.id = $.zui.uuid();
};
ModalTrigger.DEFAULTS = {
type: 'custom',
// width: null, // number, css definition
// size: null, // 'md', 'sm', 'lg', 'fullscreen'
height: 'auto',
// icon: null,
name: 'triggerModal',
// className: '',
fade: true,
position: 'fit',
showHeader: true,
delay: 0,
// iframeBodyClass: '',
// onlyIncreaseHeight: false,
// moveable: false,
// rememberPos: false,
backdrop: true,
keyboard: true,
waittime: 0,
loadingIcon: 'icon-spinner-indicator',
scrollInside: false,
// headerHeight: 'auto',
};
ModalTrigger.prototype.init = function(options) {
var that = this;
if(options.url) {
if(!options.type || (options.type != STR_AJAX && options.type != 'iframe')) {
options.type = STR_AJAX;
}
}
if(options.remote) {
options.type = STR_AJAX;
if(typeof options.remote === STR_STRING) options.url = options.remote;
} else if(options.iframe) {
options.type = 'iframe';
if(typeof options.iframe === STR_STRING) options.url = options.iframe;
} else if(options.custom) {
options.type = 'custom';
if(typeof options.custom === STR_STRING) {
var $doms;
try {
$doms = $(options.custom);
} catch(e) {}
if($doms && $doms.length) {
options.custom = $doms;
} else if($.isFunction(window[options.custom])) {
options.custom = window[options.custom];
}
}
}
var $modal = $('#' + options.name);
if($modal.length) {
if(!that.isShown) $modal.off(ZUI_MODAL);
$modal.remove();
}
$modal = $('<div id="' + options.name + '" class="modal modal-trigger ' + (options.className || '') + '">' + (typeof options.loadingIcon === 'string' && options.loadingIcon.indexOf('icon-') === 0 ? ('<div class="icon icon-spin loader ' + options.loadingIcon + '"></div>') : options.loadingIcon) + '<div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button class="close" data-dismiss="modal">×</button><h4 class="modal-title"><i class="modal-icon"></i> <span class="modal-title-name"></span></h4></div><div class="modal-body"></div></div></div></div>').appendTo('body').data(NAME, that);
var bindEvent = function(optonName, eventName) {
var handleFunc = options[optonName];
if($.isFunction(handleFunc)) $modal.on(eventName + ZUI_MODAL, handleFunc);
};
bindEvent('onShow', 'show');
bindEvent('shown', 'shown');
bindEvent('onHide', 'hide');
bindEvent('hidden', 'hidden');
bindEvent('loaded', 'loaded');
$modal.on('shown' + ZUI_MODAL, function() {
that.isShown = true;
}).on('hidden' + ZUI_MODAL, function() {
that.isShown = false;
});
this.$modal = $modal;
this.$dialog = $modal.find('.modal-dialog');
if(options.mergeOptions) this.options = options;
};
ModalTrigger.prototype.show = function(option) {
var options = $.extend({}, this.options, {
url: this.$trigger ? (this.$trigger.attr('href') || this.$trigger.attr('data-url') || this.$trigger.data('url')) : this.options.url
}, option);
this.init(options);
var that = this,
$modal = this.$modal,
$dialog = this.$dialog,
custom = options.custom;
var $body = $dialog.find('.modal-body').css('padding', ''),
$header = $dialog.find('.modal-header'),
$content = $dialog.find('.modal-content');
$modal.toggleClass('fade', options.fade)
.addClass(options.className)
.toggleClass('modal-loading', !this.isShown)
.toggleClass('modal-scroll-inside', !!options.scrollInside);
$dialog.toggleClass('modal-md', options.size === 'md')
.toggleClass('modal-sm', options.size === 'sm')
.toggleClass('modal-lg', options.size === 'lg')
.toggleClass('modal-fullscreen', options.size === 'fullscreen');
$header.toggle(options.showHeader);
$header.find('.modal-icon').attr('class', 'modal-icon icon-' + options.icon);
$header.find('.modal-title-name').text(options.title || '');
if(options.size && options.size === 'fullscreen') {
options.width = '';
options.height = '';
}
var resizeDialog = function() {
clearTimeout(this.resizeTask);
this.resizeTask = setTimeout(function() {
that.ajustPosition(options.position);
}, 100);
};
var readyToShow = function(delay, callback) {
if(typeof delay === 'undefined') delay = options.delay;
return setTimeout(function() {
$dialog = $modal.find('.modal-dialog');
if(options.width && options.width != 'auto') {
$dialog.css('width', options.width);
}
if(options.height && options.height != 'auto') {
$dialog.css('height', options.height);
if(options.type === 'iframe') $body.css('height', $dialog.height() - $header.outerHeight());
}
that.ajustPosition(options.position);
$modal.removeClass('modal-loading');
if(options.type != 'iframe') {
$dialog.off('resize.' + NAME).on('resize.' + NAME, resizeDialog);
}
callback && callback();
}, delay);
};
if(options.type === 'custom' && custom) {
if($.isFunction(custom)) {
var customContent = custom({
modal: $modal,
options: options,
modalTrigger: that,
ready: readyToShow
});
if(typeof customContent === STR_STRING) {
$body.html(customContent);
readyToShow();
}
} else if(custom instanceof $) {
$body.html($('<div>').append(custom.clone()).html());
readyToShow();
} else {
$body.html(custom);
readyToShow();
}
} else if(options.url) {
var onLoadBroken = function() {
var brokenContent = $modal.callComEvent(that, 'broken');
if(brokenContent) {
$body.html(brokenContent);
readyToShow();
}
};
$modal.attr('ref', options.url);
if(options.type === 'iframe') {
$modal.addClass('modal-iframe');
this.firstLoad = true;
var iframeName = 'iframe-' + options.name;
$header.detach();
$body.detach();
$content.empty().append($header).append($body);
$body.css('padding', 0)
.html('<iframe id="' + iframeName + '" name="' + iframeName + '" src="' + options.url + '" frameborder="no" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true" scrolling="auto" style="width: 100%; height: 100%; left: 0px;"></iframe>');
if(options.waittime > 0) {
that.waitTimeout = readyToShow(options.waittime, onLoadBroken);
}
var frame = document.getElementById(iframeName);
frame.onload = frame.onreadystatechange = function() {
var scrollInside = !!options.scrollInside;
if(that.firstLoad) $modal.addClass('modal-loading');
if(this.readyState && this.readyState != 'complete') return;
that.firstLoad = false;
if(options.waittime > 0) {
clearTimeout(that.waitTimeout);
}
try {
$modal.attr('ref', frame.contentWindow.location.href);
var frame$ = window.frames[iframeName].$;
if(frame$ && options.height === 'auto' && options.size != 'fullscreen') {
// todo: update iframe url to ref attribute
var $framebody = frame$('body').addClass('body-modal').toggleClass('body-modal-scroll-inside', scrollInside);
if(options.iframeBodyClass) $framebody.addClass(options.iframeBodyClass);
var frameSizeRecords = [];
var ajustFrameSize = function(check) {
$modal.removeClass('fade');
var height = $framebody.outerHeight();
if(check === true && options.onlyIncreaseHeight) {
height = Math.max(height, $body.data('minModalHeight') || 0);
$body.data('minModalHeight', height);
}
if (scrollInside)
{
var headerHeight = options.headerHeight;
if (typeof headerHeight !== 'number') {
headerHeight = $header.height();
} else if ($.isFunction(headerHeight)) {
headerHeight = headerHeight($header);
}
var winHeight = $(window).height();
height = Math.min(height, winHeight - headerHeight);
}
if (frameSizeRecords.length > 1 && height === frameSizeRecords[0]) {
height = Math.max(height, frameSizeRecords[1]);
}
frameSizeRecords.push(height);
while (frameSizeRecords.length > 2) {
frameSizeRecords.shift();
}
$body.css('height', height);
if(options.fade) $modal.addClass('fade');
readyToShow();
};
$modal.callComEvent(that, 'loaded', {
modalType: 'iframe',
jQuery: frame$
});
setTimeout(ajustFrameSize, 100);
$framebody.off('resize.' + NAME).on('resize.' + NAME, ajustFrameSize);
if (scrollInside) {
$(window).off('resize.' + NAME).on('resize.' + NAME, ajustFrameSize);
}
} else {
readyToShow();
}
} catch(e) {
readyToShow();
}
};
} else {
$.ajax($.extend({
url: options.url,
success: function(data) {
try {
var $data = $(data);
if($data.filter('.modal-dialog').length) {
$dialog.replaceWith($data);
} else if($data.filter('.modal-content').length) {
$dialog.find('.modal-content').replaceWith($data);
} else {
$body.wrapInner($data);
}
} catch(e) {
if (window.console && window.console.warn) {
console.warn('ZUI: Cannot recogernize remote content.', {error: e, data: data});
}
$modal.html(data);
}
$modal.callComEvent(that, 'loaded', {
modalType: STR_AJAX
});
readyToShow();
},
error: onLoadBroken
}, options.ajaxOptions));
}
}
$modal.modal({
show : 'show',
backdrop : options.backdrop,
moveable : options.moveable,
rememberPos : options.rememberPos,
keyboard : options.keyboard,
scrollInside : options.scrollInside,
});
};
ModalTrigger.prototype.close = function(callback, redirect) {
var that = this;
if(callback || redirect) {
that.$modal.on('hidden' + ZUI_MODAL, function() {
if($.isFunction(callback)) callback();
if(typeof redirect === STR_STRING && redirect.length && !that.$modal.data('cancel-reload')) {
if(redirect === 'this') window.location.reload();
else window.location = redirect;
}
});
}
that.$modal.modal('hide');
};
ModalTrigger.prototype.toggle = function(options) {
if(this.isShown) this.close();
else this.show(options);
};
ModalTrigger.prototype.ajustPosition = function(position) {
position = position === undefined ? this.options.position : position;
if ($.isFunction(position)) {
position = position(this);
}
this.$modal.modal('ajustPosition', position);
};
$.zui({
ModalTrigger: ModalTrigger,
modalTrigger: new ModalTrigger()
});
$.fn.modalTrigger = function(option, settings) {
return $(this).each(function() {
var $this = $(this);
var data = $this.data(NAME),
options = $.extend({
title: $this.attr('title') || $this.text(),
url: $this.attr('href'),
type: $this.hasClass('iframe') ? 'iframe' : ''
}, $this.data(), $.isPlainObject(option) && option);
if(!data) $this.data(NAME, (data = new ModalTrigger(options, $this)));
if(typeof option == STR_STRING) data[option](settings);
else if(options.show) data.show(settings);
$this.on((options.trigger || 'click') + '.toggle.' + NAME, function(e) {
options = $.extend(options, {
url: $this.attr('href') || $this.attr('data-url') || $this.data('url') || options.url
});
data.toggle(options);
if($this.is('a')) e.preventDefault();
});
});
};
var old = $.fn.modal;
$.fn.modal = function(option, settings) {
return $(this).each(function() {
var $this = $(this);
if($this.hasClass('modal')) old.call($this, option, settings);
else $this.modalTrigger(option, settings);
});
};
$.fn.modal.bs = old;
var getModal = function(modal) {
if (!modal) {
modal = $('.modal.modal-trigger');
} else {
modal = $(modal);
}
if(modal && (modal instanceof $)) return modal;
return null;
};
// callback, redirect, modal
var closeModal = function(modal, callback, redirect) {
var originModal = modal;
if($.isFunction(modal)) {
var oldModal = redirect;
redirect = callback;
callback = modal;
modal = oldModal;
}
modal = getModal(modal);
if(modal && modal.length) {
modal.each(function() {
$(this).data(NAME).close(callback, redirect);
});
} else if(!$('body').hasClass('modal-open') && !$('.modal.in').length) {
// check if current page is as modal iframe
if ($('body').hasClass('body-modal')) {
window.parent.$.zui.closeModal(originModal, callback, redirect);
}
}
};
var ajustModalPosition = function(position, modal) {
modal = getModal(modal);
if(modal && modal.length) {
modal.modal('ajustPosition', position);
}
};
$.zui({
closeModal: closeModal,
ajustModalPosition: ajustModalPosition
});
$(document).on('click.' + NAME + '.data-api', '[data-toggle="modal"]', function(e) {
var $this = $(this);
var href = $this.attr('href');
var $target = null;
try {
$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, '')));
} catch(ex) {}
if(!$target || !$target.length) {
if(!$this.data(NAME)) {
$this.modalTrigger({
show: true,
});
} else {
$this.trigger('.toggle.' + NAME);
}
}
if($this.is('a')) {
e.preventDefault();
}
}).on('click.' + NAME + '.data-api', '[data-dismiss="modal"]', function() {
$.zui.closeModal();
});
}(window.jQuery, window, undefined));