Greasy Fork is available in English.

tieba.ui

贴吧对话框 for GreaseMonkey 2.x

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @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);