贴吧对话框 for GreaseMonkey 2.x
สคริปต์นี้ไม่ควรถูกติดตั้งโดยตรง มันเป็นคลังสำหรับสคริปต์อื่น ๆ เพื่อบรรจุด้วยคำสั่งเมทา // @require https://update.greasyfork.org/scripts/2657/7292/tiebaui.js
/** * @package org.jixun.tieba.ui * @author jixun * @source http://tb1.bdstatic.com/tb/static-common/lib/tb_lib_04e7791.js */ // Debugging // var unsafeWindow = window; // 配置项目参见 $.dialog.setting 的值 // new $.dialog ( { 配置 } ) // 静态函数已经在相关函数注释了 // $.dialog.open // $.dialog.ask // ... (function ($) { $.fn.draggable = function(opt) { var $that = this; opt = $.extend({ handle: $that, start: $.noop, stop: $.noop }, opt); var _element = $that[0], _elementParent = $that.parent()[0]; var _getPos = function (ele) { var addOn = ele.offsetParent != _elementParent && ele.offsetParent ? _getPos (ele.offsetParent) : {x: 0, y: 0}; return { x: ele.offsetLeft + addOn.x, y: ele.offsetTop + addOn.y }; }; var baseOffset, offset, isDrag; var _mouseDown = function (e) { baseOffset = _getPos (_element); offset = { x: e.pageX, y: e.pageY }; isDrag = true; e.preventDefault(); opt.start(); }, _mouseUp = function () { isDrag = false; opt.stop (); }, _mouseMove = function (e) { if (!isDrag) return; $that.css ({ left: baseOffset.x + e.pageX - offset.x, top : baseOffset.y + e.pageY - offset.y }); }; opt.handle.on('mousedown', _mouseDown); $(document) .on ('mousemove', _mouseMove) .on ('mouseup', _mouseUp); return function () { opt.handle.off ('mousedown', _mouseDown); $(document) .off ('mousemove', _mouseMove) .off ('mouseup', _mouseUp); }; }; $.getzIndex = function () { $.zIndex = $.zIndex || 50000; return $.zIndex ++; }; var $modal = function (opts) { var that = this; this.cfg = $.extend({}, { className: "dialogJmodal", resizeable: true }, opts); this.element = $('<div>') .addClass(this.cfg.className) .appendTo(document.body) .css({ display: "none", zIndex: $.getzIndex(), width: this.width(), height: this.height() }); if (this.cfg.show) this.show (); this.resizeFunc = function () { that.css({ width: that.width (), height: that.height () }); that.triggerHandler("resize"); }; if (this.cfg.resizeable) { $(unsafeWindow).on("resize", this.resizeFunc); } }; $modal.prototype = { constructor: $modal, show: function () { this.element.show.apply(this.element, arguments); }, hide: function () { this.element.hide.apply(this.element, arguments); }, width: function () { return $(unsafeWindow).width(); }, height: function () { return Math.max($("body").height(), $("html").height()); }, css: function () { return this.element.css.apply(this.element, arguments); }, triggerHandler: function () { this.element.triggerHandler.apply(this.element, arguments); }, bind: function () { this.element.on.apply(this.element, arguments); }, remove: function () { if (this.element) { this.element.remove(); } $(unsafeWindow).off("resize", this.resizeFunc); for (var t in this) { if (this.hasOwnProperty(t)) { delete this[t]; } } } // _processTages 移除 // 因为全部都是兼容 IE 用代码。 }; $.modal = $modal; var lstEvents = ["onaccept", "oncancel", "onclose", "onresize", "onhide"]; var $dialog = function (dialogOpts) { var that = this; var cbOnResize = function () { if (!that.dragged) { that.element.triggerHandler("onresize"); if (that.sizeTimer) clearTimeout(that.sizeTimer); that.sizeTimer = setTimeout(that.setPosition.on(that), 5) } }; $dialog.INST.push(this); this.cfg = $.extend({}, $dialog.setting, dialogOpts); if (!this.cfg.showTitle) this.cfg.draggable = false; if (null != this.cfg.top || null != this.cfg.left) { this.cfg.autoCenter = false; } var dialogClass = "dialogJ dialogTiebaUi"; if (this.cfg.holderClassName) dialogClass += " " + this.cfg.holderClassName; if (this.cfg.fixed) dialogClass += " dialogJfix"; if (this.cfg.showShadow) dialogClass += " dialogJshadow"; if (this.cfg.modal) { var modalArg = {}; if (this.cfg.modalClassName) modalArg.className = this.cfg.modalClassName; this.modal = new $.modal(modalArg); } this.element = $('<div class="' + dialogClass + '"></div>') .hide () .css({ zIndex: $.getzIndex() }).appendTo(document.body); this.elementWrapper = $('<div>').addClass('uiDialogWrapper').appendTo(this.element); // 准备对话框标题 this._setupTitleBar(); this.setTitle(this.cfg.title); this._setupNoTitle(); // 准备对话框内容 this._setupContent(); if ('iframe' === this.cfg.contentType) { this.cfg.html = $("<iframe>").css({ width: "100%", height: "100%", border: "none" }).attr({ src: this.cfg.html }); } this.setContent(this.cfg.html); // 设定对话框宽、高 // Jixun: 设定默认 400x80 的宽高。 this.width(this.cfg.width); this.height(this.cfg.height); this.setPosition(this.cfg.left, this.cfg.top); if (this.cfg.show) this.show(); if (this.cfg.autoCenter ) $(unsafeWindow).on("resize", cbOnResize); // 设定拖动 this._setScroll (); $.each (lstEvents, function (i, eventName) { if (that.cfg[eventName]) { that.on(eventName, that.cfg[eventName]); } }); if (this.cfg.escable) this._setupEscKey(); // 关闭对话框 this.close = function () { // 如果拒绝关闭则返回 if (that.element.triggerHandler("onclose") === false) return false; // 取消绑定 resize 事件 $(unsafeWindow).off("resize", cbOnResize); // 移除 modal if (that.modal) that.modal.remove(); that._setScroll(true); that.element.remove(); for (var t = 0; t < $dialog.INST.length; t++) { if ($dialog.INST[t] == that) { $dialog.INST.splice(t, 1); break; } } return true; } }; $.extend($dialog, { /** * 启动一个基本对话框 * @param content 对话框内容 * @param opts 其它传参 * @returns {$dialog} */ open: function (content, opts) { return (new $dialog($.extend({}, opts, {html: content}))); }, /** * 创建一个询问对话框 * @param html 对话框内容 * @param arrAnswers 回答按钮内容 * * @param callback 两个参数, 原型如下: * callback (i, $dialog) * i 为回答按钮序号, $dialog 为对话框本体 * this 绑定为 $(按钮)。 * * @param opts 创建时传递给 $dialog / $modal 的参数 * @returns {} */ ask: function (html, arrAnswers, callback, opts) { if (!opts) opts = {}; var _$dialog = new $dialog($.extend({modal: true}, opts, {html: html || "", show: true})); if ($.isArray(arrAnswers) && arrAnswers.length) { var answerContainer = $('<div>') .addClass('dialogJanswers') .appendTo(_$dialog.elementWrapper); $(arrAnswers).each (function (i, val) { //answerContainer.append ($('<input>').val(val).addClass('dialogJbtn').attr('type', 'button')) // .append (' '); // 下面这个的按钮有蓝色样式 answerContainer .append ( $('<a>').addClass('ui_btn ui_btn_m').append($('<span>').append('<em>').text(val)) .click (function () { if (false !== callback.call(this, i, _$dialog)) _$dialog.close(); }) ); }); _$dialog.buttons = $("input", answerContainer); } _$dialog.setPosition(); if (opts.show) _$dialog.show(); return _$dialog; }, /** * 显示一条警告框 * @param message 警告消息 * @param [opts] $modal / $dialog 参数 * @param opts.acceptValue 「确定」按钮标题 * @returns {$dialog} */ alert: function (message, opts) { var extOpts = $.extend({}, opts || {}); return $dialog.ask(message, [extOpts.acceptValue || "确定"], function (e, t) { return t.element.triggerHandler(lstEvents[e], this) }, extOpts) }, /** * 显示一个确认框 * @param message 确认的消息 * @param [opts] $modal / $dialog 参数 * @param opts.acceptValue 「确定」按钮标题 * @returns {$dialog} */ confirm: function (message, opts) { var extOpts = $.extend({}, opts || {}); return $dialog.ask(message, [extOpts.acceptValue || "确定", extOpts.cancelValue || "取消"], function (e, t) { return t.element.triggerHandler(lstEvents[e], this) }, extOpts) }, /** * 显示一个定时警告框 * @param message 显示的消息 * @param callback 回调, 无参数 * @param [opts] 参数集合 * @param opts.acceptValue 「确定」按钮标题 * @param {Boolean} opts.button 是否显示确定按钮 * @param opts.time 等待时长 * @returns {*} */ assert: function (message, callback, opts) { var extOpts = $.extend({button: true}, opts || {}); if (2 == arguments.length) { extOpts = callback; callback = $.noop; } var $dialogAsk = $dialog.ask( message, extOpts.button ? [extOpts.acceptValue || "确定"] : [], function (i, $dialog) { return $dialog.element.triggerHandler(lstEvents[i], this) }, extOpts ); setTimeout(function () { if ($dialogAsk && $dialogAsk.close) $dialogAsk.close(); if (callback) callback(); }, parseInt(extOpts.time) || 2000); return $dialogAsk; }, /** * 远端加载一个页面并显示其内容 * @param url 目标地址 * @param opts 选项 * @param opts.filter 页面内容选择器 * @param opts.cache 参见 jQuery.ajax * @param opts.type 参见 jQuery.ajax * @returns {$dialog} */ load: function (url, opts) { opts = opts || {}; var _$dialog = new $dialog(opts); var requestObj = { url: url, type: "GET", dataType: "html", cache: false, success: function (html) { if (opts.filter) html = $(opts.filter, html); _$dialog.setContent(html); } }; $.each(["type", "cache"], function (i, str) { if (opts.hasOwnProperty(str)) { requestObj[str] = opts[str]; delete opts[str]; } }); $.ajax(requestObj); return _$dialog; }, /** * 关闭所有开启的对话框 */ close: function () { for (var i = 0; i < this.INST.length; i++) { // 如果拒绝关闭, i-- 然后继续枚举关闭过程 if (false !== this.INST[i].close()) { i--; } } }, setting: { modal: true, showShadow: true, showTitle: true, noTitle: false, // 默认 400 x 80 width: 400, height: 80, fixed: true, left: null, top: null, show: true, closeable: true, hideOnclose: false, draggable: true, contentType: null, resizeable: false, closeTips: null, escable: true, scrollable: true, modalClassName: null, autoCenter: true, html: null, minWidth: 200, minHeight: 100, maxWidth: null, maxHeight: null } }); $dialog.prototype = { constructor: $dialog, /** * 擦除原始标题并设定新标题 * 可以为 jQuery 对象、DOM 对象 * @param newTitle */ setTitle: function (newTitle) { this.element.find(".dialogJtitle>span.dialogJtxt").html(newTitle || ""); }, /** * 擦除原始内容并设定新内容 * 可以为 jQuery 对象、DOM 对象 * @param newContent */ setContent: function (newContent) { newContent && this.element.find(".dialogJbody").html(newContent); }, /** * 设定新宽度 * @param newWidth * @returns {*} */ width: function (newWidth) { return this.element.css("width", newWidth); }, /** * 设定新高度 * @param newHeight * @returns {*} */ height: function (newHeight) { return $(".dialogJbody", this.element).css("height", newHeight); }, /** * 设定对话框位置 * @param [left] 左边, 留空居中 * @param [top] 右边, 留空居中 */ setPosition: function (left, top) { if (!$.isNumeric(left) && !$.isNumeric(top)) { var $doc = $(document), $win = $(unsafeWindow), newPosOffset = this.cfg.fixed ? [0, 0] : [$doc.scrollLeft(), $doc.scrollTop()]; left = newPosOffset [0] + ($win.width() - this.element.outerWidth() ) / 2; top = newPosOffset [1] + ($win.height() - this.element.outerHeight()) / 2; if (top < 0) top = 0; } this.element.css({ left: left, top: top }); this.triggerHandler("resize"); }, /** * 获取标题 (HTML) * @returns {String} */ getTitle: function () { return this.element.find(".dialogJtitle>span").html(); }, /** * 获取标题文本 * @returns {String} */ getTitleText: function () { return this.element.find(".dialogJtitle").text(); }, /** * 获取对话框内容 (HTML) * @returns {String} */ getContent: function () { return $(".dialogJbody", this.element).html() }, /** * 获取对话框内容 * @returns {String} */ getContentText: function () { return $(".dialogJbody", this.element).text() }, /** * 显示对话框 */ show: function () { this.element.show.apply(this.element, arguments); if (this.modal) { this.modal.cfg.safety = this.element; this.modal.show.apply(this.modal, arguments); } }, /** * 隐藏对话框 * @returns {boolean} */ hide: function () { if (this.element.triggerHandler("onhide") === false) return false; this.element.hide.apply(this.element, arguments); if (this.modal) this.modal.hide.apply(this.modal, arguments); return true; }, /** * 获取对话框 DOM 元素 * @returns {HTMLElement} */ getElement: function () { return this.element[0]; }, /** * 绑定事件 * @returns {$dialog} */ bind: function () { this.element.on.apply(this.element, arguments); return this; }, /** * 触发事件 */ triggerHandler: function () { this.element.triggerHandler.apply(this.element, arguments); }, /** * 获取按钮 * @returns {Array|undefined} */ getButtons: function () { return this.buttons; }, /** * 内部函数: 设定无标题对话框 * @private */ _setupNoTitle: function () { if (this.cfg.noTitle) { $(".dialogJtitle").css({ "border-bottom": 0, "background-color": "#fff" }); } }, /** * 内部函数: 设定对话框标题栏 * @private */ _setupTitleBar: function () { if (this.cfg.showTitle) { var that = this; var titleBar = that.titleBar = $('<div>').append( $('<span>').addClass('dialogJtxt') ).addClass('dialogJtitle') .appendTo(this.elementWrapper); if (this.cfg.closeable) { $('<a>').addClass('dialogJclose').attr({ title: this.cfg.closeTips || "关闭本窗口", href: '#' }).text(' ').appendTo(titleBar) .on ('mousedown', function (e) { e.stopPropagation(); }).click(function () { if (that.cfg.hideOnclose) { that.hide() } else { that.close(); } return false; }); if (this.cfg.draggable) { titleBar.css ({ cursor: 'move' }); var _rmDrag = $(that.element).draggable({ handle: titleBar, start: function () { that._setupHackDiv(1) }, stop: function () { that.dragged = true; that._setupHackDiv(0); } }); $(that.element).on("onclose", _rmDrag); } } } }, _setupHackDiv: function (bShowHackDiv) { var _$dialog = this; if (bShowHackDiv) { if ($("IFRAME", _$dialog.element).length) { var $content = $(".dialogJcontent", _$dialog.element); if (!_$dialog.hack_div) { _$dialog.hack_div = $("<div>").appendTo($content).css({ position: "absolute", left: 0, top: 0, cursor: "move" }); } _$dialog.hack_div.show().css({ width: _$dialog.element.outerWidth(), height: _$dialog.element.outerHeight() }) } } else { if (_$dialog.hack_div) _$dialog.hack_div.hide (); } }, _setupEscKey: function () { var $that = this; var _escKeyCb = function (n) { // ESC - 0x1b if (0x1b == n.which) { if ($that.showTitle) { $(".dialogJclose", $that.titleBar).triggerHandler("click") } else { $that.close(); } } }; $(document).on("keydown", _escKeyCb); $($that.element).on("onclose", function () { $(document).off("keydown", _escKeyCb) }); }, _setupContent: function () { this.elementWrapper.append( $('<div>').addClass('dialogJcontent').append( $('<div>').addClass('dialogJbody'))); }, _setScroll: function (bSetScroll) { if (this.cfg.modal && !this.cfg.scrollable) { var htmlRoot = $("html"); if (htmlRoot.length) { var i = htmlRoot[0].scrollTop; if (bSetScroll) { htmlRoot.css({ overflow: this.element.data("htmlOverflow") || "", paddingRight: 0 }); } else { if (htmlRoot[0].style.overFlow) { this.element.data("htmlOverflow", htmlRoot[0].style.overFlow); } htmlRoot.css({ overflow: "hidden", paddingRight: 17 }) } htmlRoot[0].scrollTop = i } } } }; $.each(lstEvents, function (e, t) { $dialog.prototype[t] = function (e) { this.on(t, e) } }); $dialog.INST = []; $.dialog = $dialog; })(jQuery);