/*! * dialog 5.0.4 */ (function ($, window, undefined) { if (document.compatMode === 'BackCompat') { throw new Error('dialog: Document types require more than xhtml1.0'); } var _singleton, _count = 0, _expando = 'dialog' + (+new Date), _isIE6 = window.VBArray && !window.XMLHttpRequest, _isMobile = 'createTouch' in document && !('onmousemove' in document) || /(iPhone|iPad|iPod)/i.test(navigator.userAgent), _isFixed = !_isIE6 && !_isMobile, _getActive = function () { try { return document.activeElement; // bug: ie8~9, iframe #26 } catch (e) { } }, _activeElement = _getActive(); var dialog = function (config, ok, cancel) { this.version = '1.0'; config = config || {}; if (typeof config === 'string' || config.nodeType === 1) { config = {content: config, fixed: !_isMobile}; } var api, defaults = dialog.defaults; var elem = config.follow = this.nodeType === 1 && this || config.follow; // 合并默认配置 for (var i in defaults) { if (config[i] === undefined) { config[i] = defaults[i]; } } config.id = elem && elem[_expando + 'follow'] || config.id || _expando + _count; api = dialog.list[config.id]; if (api) { if (elem) { api.follow(elem); } api.zIndex().focus(); return api; } // 目前主流移动设备对fixed支持不好,禁用此特性 if (!_isFixed) { config.fixed = false; } // !$.isArray(config.button) if (!config.button || !config.button.push) { config.button = []; } // 确定按钮 if (ok !== undefined) { config.ok = ok; } if (config.ok) { config.button.push({ id: 'ok', value: config.okValue, callback: config.ok, focus: true }); } // 取消按钮 if (cancel !== undefined) { config.cancel = cancel; } if (config.cancel) { config.button.push({ id: 'cancel', value: config.cancelValue, callback: config.cancel }); } // 更新 zIndex 全局配置 dialog.defaults.zIndex = config.zIndex; _count++; return dialog.list[config.id] = _singleton ? _singleton._create(config) : new dialog.fn._create(config); }; dialog.fn = dialog.prototype = { _create: function (config) { var dom; this.closed = false; this.config = config; this.dom = dom = this.dom || this._innerHTML(config); this.node = dom.content[0]; config.skin && dom.wrap.addClass(config.skin); dom.wrap.css('position', config.fixed ? 'fixed' : 'absolute'); dom.close[config.cancel === false ? 'hide' : 'show'](); dom.content.css('padding', config.padding); this.button.apply(this, config.button); this.title(config.title).content(config.content).size(config.width, config.height).time(config.time); this._reset(); this.zIndex(); config.lock && this.lock(); this._addEvent(); this[config.visible ? 'visible' : 'hidden']().focus(); _singleton = null; config.initialize && config.initialize.call(this); return this; }, /** * 设置内容 * @param {String, HTMLElement, Object} 内容 (可选) */ content: function (message) { var prev, next, parent, display, that = this, $content = this.dom.content, content = $content[0]; if (this._elemBack) { this._elemBack(); delete this._elemBack; } if (typeof message === 'string') { $content.html(message); } else if (message && message.nodeType === 1) { // 让传入的元素在对话框关闭后可以返回到原来的地方 display = message.style.display; prev = message.previousSibling; next = message.nextSibling; parent = message.parentNode; this._elemBack = function () { if (prev && prev.parentNode) { prev.parentNode.insertBefore(message, prev.nextSibling); } else if (next && next.parentNode) { next.parentNode.insertBefore(message, next); } else if (parent) { parent.appendChild(message); } message.style.display = display; that._elemBack = null; }; $content.html(''); content.appendChild(message); $(message).show(); } this._reset(); return this; }, /** * 设置标题 * @param {String, Boolean} 标题内容. 为 false 则隐藏标题栏 */ title: function (content) { var dom = this.dom, outer = dom.outer, $title = dom.title, className = 'd-state-noTitle'; if (content === false) { $title.hide().html(''); outer.addClass(className); } else { $title.show().html(content); outer.removeClass(className); } return this; }, /** @inner 位置居中 */ position: function () { var dom = this.dom, wrap = dom.wrap[0], $window = dom.window, $document = dom.document, fixed = this.config.fixed, dl = fixed ? 0 : $document.scrollLeft(), dt = fixed ? 0 : $document.scrollTop(), ww = $window.width(), wh = $window.height(), ow = wrap.offsetWidth, oh = wrap.offsetHeight, left = (ww - ow) / 2 + dl, top = (wh - oh) * 382 / 1000 + dt, // 黄金比例 style = wrap.style; style.left = Math.max(parseInt(left), dl) + 'px'; style.top = Math.max(parseInt(top), dt) + 'px'; if (this._follow) { this._follow.removeAttribute(_expando + 'follow'); this._follow = null; } return this; }, /** * 尺寸 * @param {Number, String} 宽度 * @param {Number, String} 高度 */ size: function (width, height) { var style = this.dom.main[0].style; if (typeof width === 'number') { width = width + 'px'; } if (typeof height === 'number') { height = height + 'px'; } style.width = width; style.height = height; return this; }, /** * 跟随元素 * @param {HTMLElement} */ follow: function (elem) { var $elem = $(elem), config = this.config; // 隐藏元素不可用 if (!elem || !elem.offsetWidth && !elem.offsetHeight) { return this.position(this._left, this._top); } var fixed = config.fixed, expando = _expando + 'follow', dom = this.dom, $window = dom.window, $document = dom.document, winWidth = $window.width(), winHeight = $window.height(), docLeft = $document.scrollLeft(), docTop = $document.scrollTop(), offset = $elem.offset(), width = elem.offsetWidth, height = elem.offsetHeight, left = fixed ? offset.left - docLeft : offset.left, top = fixed ? offset.top - docTop : offset.top, wrap = this.dom.wrap[0], style = wrap.style, wrapWidth = wrap.offsetWidth, wrapHeight = wrap.offsetHeight, setLeft = left - (wrapWidth - width) / 2, setTop = top + height, dl = fixed ? 0 : docLeft, dt = fixed ? 0 : docTop; setLeft = setLeft < dl ? left : (setLeft + wrapWidth > winWidth) && (left - wrapWidth > dl) ? left - wrapWidth + width : setLeft; setTop = (setTop + wrapHeight > winHeight + dt) && (top - wrapHeight > dt) ? top - wrapHeight : setTop; style.left = parseInt(setLeft) + 'px'; style.top = parseInt(setTop) + 'px'; this._follow && this._follow.removeAttribute(expando); this._follow = elem; elem[expando] = config.id; return this; }, /** * 自定义按钮 * @example button({ value: 'login', callback: function () {}, disabled: false, focus: true }, .., ..) */ button: function () { var dom = this.dom, $buttons = dom.buttons, elem = $buttons[0], strongButton = 'd-state-highlight', listeners = this._listeners = this._listeners || {}, ags = [].slice.call(arguments); var i = 0, val, value, id, isNewButton, button; for (; i < ags.length; i++) { val = ags[i]; value = val.value; id = val.id || value; isNewButton = !listeners[id]; button = !isNewButton ? listeners[id].elem : document.createElement('input'); button.type = 'button'; button.className = 'd-button'; if (!listeners[id]) { listeners[id] = {}; } if (value) { button.value = value; } if (val.width) { button.style.width = val.width; } if (val.callback) { listeners[id].callback = val.callback; } if (val.focus) { this._focus && this._focus.removeClass(strongButton); this._focus = $(button).addClass(strongButton); this.focus(); } button[_expando + 'callback'] = id; button.disabled = !!val.disabled; if (isNewButton) { listeners[id].elem = button; elem.appendChild(button); } } $buttons[0].style.display = ags.length ? '' : 'none'; return this; }, /** 显示对话框 */ visible: function () { //this.dom.wrap.show(); this.dom.wrap.css('visibility', 'visible'); this.dom.outer.addClass('d-state-visible'); if (this._isLock) { this._lockMask.show(); } return this; }, /** 隐藏对话框 */ hidden: function () { //this.dom.wrap.hide(); this.dom.wrap.css('visibility', 'hidden'); this.dom.outer.removeClass('d-state-visible'); if (this._isLock) { this._lockMask.hide(); } return this; }, /** 关闭对话框 */ close: function () { if (this.closed) { return this; } var dom = this.dom, $wrap = dom.wrap, list = dialog.list, beforeunload = this.config.beforeunload; if (beforeunload && beforeunload.call(this) === false) { return this; } if (dialog.focus === this) { dialog.focus = null; } if (this._follow) { this._follow.removeAttribute(_expando + 'follow'); } if (this._elemBack) { this._elemBack(); } this.time(); this.unlock(); this._removeEvent(); delete list[this.config.id]; if (_singleton) { $wrap.remove(); // 使用单例模式 } else { _singleton = this; dom.title.html(''); dom.content.html(''); dom.buttons.html(''); $wrap[0].className = $wrap[0].style.cssText = ''; dom.outer[0].className = 'd-outer'; $wrap.css({ left: 0, top: 0, position: _isFixed ? 'fixed' : 'absolute' }); for (var i in this) { if (this.hasOwnProperty(i) && i !== 'dom') { delete this[i]; } } this.hidden(); } // 恢复焦点,照顾键盘操作的用户 if (_activeElement) { try { _activeElement.focus(); } catch (e) { } } this.closed = true; return this; }, /** * 定时关闭 * @param {Number} 单位毫秒, 无参数则停止计时器 */ time: function (time) { var that = this, timer = this._timer; timer && clearTimeout(timer); if (time) { this._timer = setTimeout(function () { that._click('cancel'); }, time); } return this; }, /** @inner 设置焦点 */ focus: function () { var that = this, isFocus = function () { var activeElement = _getActive(); return activeElement && that.dom.wrap[0].contains(activeElement); }; if (!isFocus()) { _activeElement = _getActive(); } setTimeout(function () { if (!isFocus()) { try { var elem = that._focus || that.dom.close || taht.dom.wrap; elem[0].focus(); // IE对不可见元素设置焦点会报错 } catch (e) { } } }, 16); return this; }, /** 置顶对话框 */ zIndex: function () { var dom = this.dom, top = dialog.focus, index = dialog.defaults.zIndex++; // 设置叠加高度 dom.wrap.css('zIndex', index); this._lockMask && this._lockMask.css('zIndex', index - 1); // 设置最高层的样式 top && top.dom.outer.removeClass('d-state-focus'); dialog.focus = this; dom.outer.addClass('d-state-focus'); return this; }, /** 设置屏锁 */ lock: function () { if (this._isLock) { return this; } var that = this, config = this.config, dom = this.dom, div = document.createElement('div'), $div = $(div), index = dialog.defaults.zIndex - 1; this.zIndex(); dom.outer.addClass('d-state-lock'); $div.css({ zIndex: index, position: 'fixed', left: 0, top: 0, width: '100%', height: '100%', overflow: 'hidden' }).addClass('d-mask'); if (!_isFixed) { $div.css({ position: 'absolute', width: $(window).width() + 'px', height: $(document).height() + 'px' }); } $div.bind('dblclick', function () { that._click('cancel'); }); document.body.appendChild(div); this._lockMask = $div; this._isLock = true; return this; }, /** 解开屏锁 */ unlock: function () { if (!this._isLock) { return this; } this._lockMask.unbind(); this._lockMask.hide(); this._lockMask.remove(); this.dom.outer.removeClass('d-state-lock'); this._isLock = false; return this; }, // 获取元素 _innerHTML: function (data) { var body = document.body; if (!body) { throw new Error('dialog: "documents.body" not ready'); } var wrap = document.createElement('div'); wrap.style.cssText = 'position:absolute;left:0;top:0'; wrap.innerHTML = dialog._templates .replace(/{([^}]+)}/g, function ($0, $1) { var value = data[$1]; return typeof value === 'string' ? value : ''; }); body.insertBefore(wrap, body.firstChild); var name, i = 0, dom = {}, els = wrap.getElementsByTagName('*'), elsLen = els.length; for (; i < elsLen; i++) { name = els[i].className.split('d-')[1]; if (name) { dom[name] = $(els[i]); } } dom.window = $(window); dom.document = $(document); dom.wrap = $(wrap); return dom; }, // 按钮回调函数触发 _click: function (id) { var fn = this._listeners[id] && this._listeners[id].callback; return typeof fn !== 'function' || fn.call(this) !== false ? this.close() : this; }, // 重置位置 _reset: function () { var elem = this.config.follow || this._follow; elem ? this.follow(elem) : this.position(); }, // 事件代理 _addEvent: function () { var that = this, dom = this.dom; // 监听点击 dom.wrap .bind('click', function (event) { var target = event.target, callbackID; // IE BUG if (target.disabled) { return false; } if (target === dom.close[0]) { that._click('cancel'); return false; } else { callbackID = target[_expando + 'callback']; callbackID && that._click(callbackID); } }) .bind('mousedown', function () { that.zIndex(); }); }, // 卸载事件代理 _removeEvent: function () { this.dom.wrap.unbind(); } }; dialog.fn._create.prototype = dialog.fn; // 快捷方式绑定触发元素 $.fn.dialog = $.fn.dialog = function () { var config = arguments; this[this.live ? 'live' : 'bind']('click', function () { dialog.apply(this, config); return false; }); return this; }; /** 最顶层的对话框API */ dialog.focus = null; /** * 根据 ID 获取某对话框 API * @param {String} 对话框 ID * @return {Object} 对话框 API (实例) */ dialog.get = function (id) { return id === undefined ? dialog.list : dialog.list[id]; }; dialog.list = {}; // 全局快捷键 $(document).bind('keydown', function (event) { var target = event.target, nodeName = target.nodeName, rinput = /^input|textarea$/i, api = dialog.focus, keyCode = event.keyCode; if (!api || rinput.test(nodeName) && target.type !== 'button') { return; } // ESC keyCode === 27 && api._click('cancel'); }); // 锁屏限制tab function focusin(event) { var api = dialog.focus; if (api && api._isLock && !api.dom.wrap[0].contains(event.target)) { event.stopPropagation(); api.dom.outer[0].focus(); } } if ($.fn.live) { $('body').live('focus', focusin); } else if (document.addEventListener) { document.addEventListener('focus', focusin, true); } else { $(document).bind('focusin', focusin); } // 浏览器窗口改变后重置对话框位置 $(window).bind('resize', function () { var dialogs = dialog.list; for (var id in dialogs) { dialogs[id]._reset(); } }); // XHTML 模板 // 使用 uglifyjs 压缩能够预先处理"+"号合并字符串 // @see http://marijnhaverbeke.nl/uglifyjs dialog._templates = '
' + ' | ' + ' | ' + ' | |||
' + ' | '
+ ' '
+ ' '
+ '
| '
+ '' + ' | |||
' + ' | ' + ' | ' + ' |