tieba.ui

贴吧对话框 for GreaseMonkey 2.x

Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta // @require https://update.greatest.deepsurf.us/scripts/2657/7292/tiebaui.js

  1. /**
  2. * @package org.jixun.tieba.ui
  3. * @author jixun
  4. * @source http://tb1.bdstatic.com/tb/static-common/lib/tb_lib_04e7791.js
  5. */
  6.  
  7. // Debugging
  8. // var unsafeWindow = window;
  9.  
  10. // 配置项目参见 $.dialog.setting 的值
  11. // new $.dialog ( { 配置 } )
  12.  
  13. // 静态函数已经在相关函数注释了
  14. // $.dialog.open
  15. // $.dialog.ask
  16. // ...
  17.  
  18. (function ($) {
  19. $.fn.draggable = function(opt) {
  20. var $that = this;
  21. opt = $.extend({
  22. handle: $that,
  23. start: $.noop,
  24. stop: $.noop
  25. }, opt);
  26.  
  27. var _element = $that[0],
  28. _elementParent = $that.parent()[0];
  29.  
  30. var _getPos = function (ele) {
  31. var addOn = ele.offsetParent != _elementParent && ele.offsetParent
  32. ? _getPos (ele.offsetParent)
  33. : {x: 0, y: 0};
  34.  
  35. return {
  36. x: ele.offsetLeft + addOn.x,
  37. y: ele.offsetTop + addOn.y
  38. };
  39. };
  40.  
  41. var baseOffset, offset, isDrag;
  42. var _mouseDown = function (e) {
  43. baseOffset = _getPos (_element);
  44. offset = {
  45. x: e.pageX,
  46. y: e.pageY
  47. };
  48.  
  49. isDrag = true;
  50. e.preventDefault();
  51. opt.start();
  52. }, _mouseUp = function () {
  53. isDrag = false;
  54. opt.stop ();
  55. }, _mouseMove = function (e) {
  56. if (!isDrag) return;
  57.  
  58. $that.css ({
  59. left: baseOffset.x + e.pageX - offset.x,
  60. top : baseOffset.y + e.pageY - offset.y
  61. });
  62. };
  63.  
  64. opt.handle.on('mousedown', _mouseDown);
  65. $(document)
  66. .on ('mousemove', _mouseMove)
  67. .on ('mouseup', _mouseUp);
  68.  
  69. return function () {
  70. opt.handle.off ('mousedown', _mouseDown);
  71. $(document)
  72. .off ('mousemove', _mouseMove)
  73. .off ('mouseup', _mouseUp);
  74. };
  75. };
  76.  
  77. $.getzIndex = function () {
  78. $.zIndex = $.zIndex || 50000;
  79. return $.zIndex ++;
  80. };
  81.  
  82. var $modal = function (opts) {
  83. var that = this;
  84. this.cfg = $.extend({}, {
  85. className: "dialogJmodal",
  86. resizeable: true
  87. }, opts);
  88.  
  89. this.element =
  90. $('<div>')
  91. .addClass(this.cfg.className)
  92. .appendTo(document.body)
  93. .css({
  94. display: "none",
  95. zIndex: $.getzIndex(),
  96. width: this.width(),
  97. height: this.height()
  98. });
  99.  
  100. if (this.cfg.show)
  101. this.show ();
  102.  
  103. this.resizeFunc = function () {
  104. that.css({
  105. width: that.width (),
  106. height: that.height ()
  107. });
  108.  
  109. that.triggerHandler("resize");
  110. };
  111.  
  112. if (this.cfg.resizeable) {
  113. $(unsafeWindow).on("resize", this.resizeFunc);
  114. }
  115. };
  116.  
  117.  
  118.  
  119. $modal.prototype = {
  120. constructor: $modal,
  121.  
  122. show: function () {
  123. this.element.show.apply(this.element, arguments);
  124. },
  125.  
  126. hide: function () {
  127. this.element.hide.apply(this.element, arguments);
  128. },
  129.  
  130. width: function () {
  131. return $(unsafeWindow).width();
  132. },
  133.  
  134. height: function () {
  135. return Math.max($("body").height(), $("html").height());
  136. },
  137.  
  138. css: function () {
  139. return this.element.css.apply(this.element, arguments);
  140. },
  141.  
  142. triggerHandler: function () {
  143. this.element.triggerHandler.apply(this.element, arguments);
  144. },
  145.  
  146. bind: function () {
  147. this.element.on.apply(this.element, arguments);
  148. },
  149.  
  150. remove: function () {
  151. if (this.element) {
  152. this.element.remove();
  153. }
  154. $(unsafeWindow).off("resize", this.resizeFunc);
  155. for (var t in this) {
  156. if (this.hasOwnProperty(t)) {
  157. delete this[t];
  158. }
  159. }
  160. }
  161.  
  162. // _processTages 移除
  163. // 因为全部都是兼容 IE 用代码。
  164.  
  165. };
  166.  
  167. $.modal = $modal;
  168.  
  169. var lstEvents = ["onaccept", "oncancel", "onclose", "onresize", "onhide"];
  170. var $dialog = function (dialogOpts) {
  171. var that = this;
  172. var cbOnResize = function () {
  173. if (!that.dragged) {
  174. that.element.triggerHandler("onresize");
  175. if (that.sizeTimer)
  176. clearTimeout(that.sizeTimer);
  177. that.sizeTimer = setTimeout(that.setPosition.on(that), 5)
  178. }
  179. };
  180.  
  181. $dialog.INST.push(this);
  182. this.cfg = $.extend({}, $dialog.setting, dialogOpts);
  183. if (!this.cfg.showTitle)
  184. this.cfg.draggable = false;
  185. if (null != this.cfg.top || null != this.cfg.left) {
  186. this.cfg.autoCenter = false;
  187. }
  188.  
  189. var dialogClass = "dialogJ dialogTiebaUi";
  190.  
  191. if (this.cfg.holderClassName)
  192. dialogClass += " " + this.cfg.holderClassName;
  193.  
  194. if (this.cfg.fixed)
  195. dialogClass += " dialogJfix";
  196.  
  197. if (this.cfg.showShadow)
  198. dialogClass += " dialogJshadow";
  199.  
  200. if (this.cfg.modal) {
  201. var modalArg = {};
  202.  
  203. if (this.cfg.modalClassName)
  204. modalArg.className = this.cfg.modalClassName;
  205.  
  206. this.modal = new $.modal(modalArg);
  207. }
  208.  
  209. this.element =
  210. $('<div class="' + dialogClass + '"></div>')
  211. .hide ()
  212. .css({
  213. zIndex: $.getzIndex()
  214. }).appendTo(document.body);
  215.  
  216. this.elementWrapper = $('<div>').addClass('uiDialogWrapper').appendTo(this.element);
  217.  
  218. // 准备对话框标题
  219. this._setupTitleBar();
  220. this.setTitle(this.cfg.title);
  221. this._setupNoTitle();
  222.  
  223. // 准备对话框内容
  224. this._setupContent();
  225. if ('iframe' === this.cfg.contentType) {
  226. this.cfg.html = $("<iframe>").css({
  227. width: "100%",
  228. height: "100%",
  229. border: "none"
  230. }).attr({
  231. src: this.cfg.html
  232. });
  233. }
  234. this.setContent(this.cfg.html);
  235.  
  236. // 设定对话框宽、高
  237. // Jixun: 设定默认 400x80 的宽高。
  238. this.width(this.cfg.width);
  239. this.height(this.cfg.height);
  240. this.setPosition(this.cfg.left, this.cfg.top);
  241.  
  242. if (this.cfg.show)
  243. this.show();
  244.  
  245. if (this.cfg.autoCenter )
  246. $(unsafeWindow).on("resize", cbOnResize);
  247.  
  248. // 设定拖动
  249. this._setScroll ();
  250. $.each (lstEvents, function (i, eventName) {
  251. if (that.cfg[eventName]) {
  252. that.on(eventName, that.cfg[eventName]);
  253. }
  254. });
  255.  
  256. if (this.cfg.escable)
  257. this._setupEscKey();
  258.  
  259. // 关闭对话框
  260. this.close = function () {
  261. // 如果拒绝关闭则返回
  262. if (that.element.triggerHandler("onclose") === false)
  263. return false;
  264.  
  265. // 取消绑定 resize 事件
  266. $(unsafeWindow).off("resize", cbOnResize);
  267.  
  268. // 移除 modal
  269. if (that.modal)
  270. that.modal.remove();
  271.  
  272. that._setScroll(true);
  273. that.element.remove();
  274.  
  275. for (var t = 0; t < $dialog.INST.length; t++) {
  276. if ($dialog.INST[t] == that) {
  277. $dialog.INST.splice(t, 1);
  278. break;
  279. }
  280. }
  281.  
  282. return true;
  283. }
  284. };
  285.  
  286. $.extend($dialog, {
  287. /**
  288. * 启动一个基本对话框
  289. * @param content 对话框内容
  290. * @param opts 其它传参
  291. * @returns {$dialog}
  292. */
  293. open: function (content, opts) {
  294. return (new $dialog($.extend({}, opts, {html: content})));
  295. },
  296.  
  297. /**
  298. * 创建一个询问对话框
  299. * @param html 对话框内容
  300. * @param arrAnswers 回答按钮内容
  301. *
  302. * @param callback 两个参数, 原型如下:
  303. * callback (i, $dialog)
  304. * i 为回答按钮序号, $dialog 为对话框本体
  305. * this 绑定为 $(按钮)。
  306. *
  307. * @param opts 创建时传递给 $dialog / $modal 的参数
  308. * @returns {}
  309. */
  310. ask: function (html, arrAnswers, callback, opts) {
  311. if (!opts) opts = {};
  312.  
  313. var _$dialog = new $dialog($.extend({modal: true}, opts, {html: html || "", show: true}));
  314.  
  315. if ($.isArray(arrAnswers) && arrAnswers.length) {
  316. var answerContainer = $('<div>')
  317. .addClass('dialogJanswers')
  318. .appendTo(_$dialog.elementWrapper);
  319.  
  320. $(arrAnswers).each (function (i, val) {
  321. //answerContainer.append ($('<input>').val(val).addClass('dialogJbtn').attr('type', 'button'))
  322. // .append (' ');
  323.  
  324. // 下面这个的按钮有蓝色样式
  325. answerContainer
  326. .append (
  327. $('<a>').addClass('ui_btn ui_btn_m').append($('<span>').append('<em>').text(val))
  328. .click (function () {
  329. if (false !== callback.call(this, i, _$dialog))
  330. _$dialog.close();
  331. })
  332. );
  333. });
  334.  
  335. _$dialog.buttons = $("input", answerContainer);
  336. }
  337. _$dialog.setPosition();
  338.  
  339. if (opts.show)
  340. _$dialog.show();
  341. return _$dialog;
  342. },
  343.  
  344. /**
  345. * 显示一条警告框
  346. * @param message 警告消息
  347. * @param [opts] $modal / $dialog 参数
  348. * @param opts.acceptValue 「确定」按钮标题
  349. * @returns {$dialog}
  350. */
  351. alert: function (message, opts) {
  352. var extOpts = $.extend({}, opts || {});
  353. return $dialog.ask(message, [extOpts.acceptValue || "确定"], function (e, t) {
  354. return t.element.triggerHandler(lstEvents[e], this)
  355. }, extOpts)
  356. },
  357.  
  358. /**
  359. * 显示一个确认框
  360. * @param message 确认的消息
  361. * @param [opts] $modal / $dialog 参数
  362. * @param opts.acceptValue 「确定」按钮标题
  363. * @returns {$dialog}
  364. */
  365. confirm: function (message, opts) {
  366. var extOpts = $.extend({}, opts || {});
  367. return $dialog.ask(message, [extOpts.acceptValue || "确定", extOpts.cancelValue || "取消"], function (e, t) {
  368. return t.element.triggerHandler(lstEvents[e], this)
  369. }, extOpts)
  370. },
  371.  
  372. /**
  373. * 显示一个定时警告框
  374. * @param message 显示的消息
  375. * @param callback 回调, 无参数
  376. * @param [opts] 参数集合
  377. * @param opts.acceptValue 「确定」按钮标题
  378. * @param {Boolean} opts.button 是否显示确定按钮
  379. * @param opts.time 等待时长
  380. * @returns {*}
  381. */
  382. assert: function (message, callback, opts) {
  383. var extOpts = $.extend({button: true}, opts || {});
  384.  
  385. if (2 == arguments.length) {
  386. extOpts = callback;
  387. callback = $.noop;
  388. }
  389.  
  390. var $dialogAsk = $dialog.ask(
  391. message,
  392. extOpts.button ? [extOpts.acceptValue || "确定"] : [],
  393. function (i, $dialog) {
  394. return $dialog.element.triggerHandler(lstEvents[i], this)
  395. },
  396. extOpts
  397. );
  398.  
  399. setTimeout(function () {
  400. if ($dialogAsk && $dialogAsk.close)
  401. $dialogAsk.close();
  402.  
  403. if (callback)
  404. callback();
  405.  
  406. }, parseInt(extOpts.time) || 2000);
  407.  
  408. return $dialogAsk;
  409. },
  410.  
  411. /**
  412. * 远端加载一个页面并显示其内容
  413. * @param url 目标地址
  414. * @param opts 选项
  415. * @param opts.filter 页面内容选择器
  416. * @param opts.cache 参见 jQuery.ajax
  417. * @param opts.type 参见 jQuery.ajax
  418. * @returns {$dialog}
  419. */
  420. load: function (url, opts) {
  421. opts = opts || {};
  422. var _$dialog = new $dialog(opts);
  423. var requestObj = {
  424. url: url,
  425. type: "GET",
  426. dataType: "html",
  427. cache: false,
  428. success: function (html) {
  429. if (opts.filter)
  430. html = $(opts.filter, html);
  431.  
  432. _$dialog.setContent(html);
  433. }
  434. };
  435.  
  436. $.each(["type", "cache"], function (i, str) {
  437. if (opts.hasOwnProperty(str)) {
  438. requestObj[str] = opts[str];
  439. delete opts[str];
  440. }
  441. });
  442.  
  443. $.ajax(requestObj);
  444. return _$dialog;
  445. },
  446.  
  447. /**
  448. * 关闭所有开启的对话框
  449. */
  450. close: function () {
  451. for (var i = 0; i < this.INST.length; i++) {
  452. // 如果拒绝关闭, i-- 然后继续枚举关闭过程
  453. if (false !== this.INST[i].close()) {
  454. i--;
  455. }
  456. }
  457. },
  458.  
  459. setting: {
  460. modal: true,
  461. showShadow: true,
  462. showTitle: true,
  463. noTitle: false,
  464.  
  465. // 默认 400 x 80
  466. width: 400,
  467. height: 80,
  468. fixed: true,
  469. left: null,
  470. top: null,
  471. show: true,
  472. closeable: true,
  473. hideOnclose: false,
  474. draggable: true,
  475. contentType: null,
  476. resizeable: false,
  477. closeTips: null,
  478. escable: true,
  479. scrollable: true,
  480. modalClassName: null,
  481. autoCenter: true,
  482. html: null,
  483. minWidth: 200,
  484. minHeight: 100,
  485. maxWidth: null,
  486. maxHeight: null
  487. }
  488. });
  489.  
  490. $dialog.prototype = {
  491. constructor: $dialog,
  492.  
  493. /**
  494. * 擦除原始标题并设定新标题
  495. * 可以为 jQuery 对象、DOM 对象
  496. * @param newTitle
  497. */
  498. setTitle: function (newTitle) {
  499. this.element.find(".dialogJtitle>span.dialogJtxt").html(newTitle || "");
  500. },
  501.  
  502. /**
  503. * 擦除原始内容并设定新内容
  504. * 可以为 jQuery 对象、DOM 对象
  505. * @param newContent
  506. */
  507. setContent: function (newContent) {
  508. newContent && this.element.find(".dialogJbody").html(newContent);
  509. },
  510.  
  511. /**
  512. * 设定新宽度
  513. * @param newWidth
  514. * @returns {*}
  515. */
  516. width: function (newWidth) {
  517. return this.element.css("width", newWidth);
  518. },
  519.  
  520. /**
  521. * 设定新高度
  522. * @param newHeight
  523. * @returns {*}
  524. */
  525. height: function (newHeight) {
  526. return $(".dialogJbody", this.element).css("height", newHeight);
  527. },
  528.  
  529. /**
  530. * 设定对话框位置
  531. * @param [left] 左边, 留空居中
  532. * @param [top] 右边, 留空居中
  533. */
  534. setPosition: function (left, top) {
  535. if (!$.isNumeric(left) && !$.isNumeric(top)) {
  536. var $doc = $(document),
  537. $win = $(unsafeWindow),
  538. newPosOffset = this.cfg.fixed ? [0, 0] : [$doc.scrollLeft(), $doc.scrollTop()];
  539.  
  540. left = newPosOffset [0] + ($win.width() - this.element.outerWidth() ) / 2;
  541. top = newPosOffset [1] + ($win.height() - this.element.outerHeight()) / 2;
  542.  
  543. if (top < 0) top = 0;
  544. }
  545.  
  546. this.element.css({
  547. left: left,
  548. top: top
  549. });
  550.  
  551. this.triggerHandler("resize");
  552. },
  553. /**
  554. * 获取标题 (HTML)
  555. * @returns {String}
  556. */
  557. getTitle: function () {
  558. return this.element.find(".dialogJtitle>span").html();
  559. },
  560. /**
  561. * 获取标题文本
  562. * @returns {String}
  563. */
  564. getTitleText: function () {
  565. return this.element.find(".dialogJtitle").text();
  566. },
  567.  
  568. /**
  569. * 获取对话框内容 (HTML)
  570. * @returns {String}
  571. */
  572. getContent: function () {
  573. return $(".dialogJbody", this.element).html()
  574. },
  575. /**
  576. * 获取对话框内容
  577. * @returns {String}
  578. */
  579. getContentText: function () {
  580. return $(".dialogJbody", this.element).text()
  581. },
  582.  
  583. /**
  584. * 显示对话框
  585. */
  586. show: function () {
  587. this.element.show.apply(this.element, arguments);
  588.  
  589. if (this.modal) {
  590. this.modal.cfg.safety = this.element;
  591. this.modal.show.apply(this.modal, arguments);
  592. }
  593. },
  594.  
  595. /**
  596. * 隐藏对话框
  597. * @returns {boolean}
  598. */
  599. hide: function () {
  600. if (this.element.triggerHandler("onhide") === false)
  601. return false;
  602.  
  603. this.element.hide.apply(this.element, arguments);
  604. if (this.modal)
  605. this.modal.hide.apply(this.modal, arguments);
  606.  
  607. return true;
  608. },
  609.  
  610. /**
  611. * 获取对话框 DOM 元素
  612. * @returns {HTMLElement}
  613. */
  614. getElement: function () {
  615. return this.element[0];
  616. },
  617.  
  618. /**
  619. * 绑定事件
  620. * @returns {$dialog}
  621. */
  622. bind: function () {
  623. this.element.on.apply(this.element, arguments);
  624. return this;
  625. },
  626.  
  627. /**
  628. * 触发事件
  629. */
  630. triggerHandler: function () {
  631. this.element.triggerHandler.apply(this.element, arguments);
  632. },
  633.  
  634. /**
  635. * 获取按钮
  636. * @returns {Array|undefined}
  637. */
  638. getButtons: function () {
  639. return this.buttons;
  640. },
  641.  
  642. /**
  643. * 内部函数: 设定无标题对话框
  644. * @private
  645. */
  646. _setupNoTitle: function () {
  647. if (this.cfg.noTitle) {
  648. $(".dialogJtitle").css({
  649. "border-bottom": 0,
  650. "background-color": "#fff"
  651. });
  652. }
  653. },
  654.  
  655. /**
  656. * 内部函数: 设定对话框标题栏
  657. * @private
  658. */
  659. _setupTitleBar: function () {
  660. if (this.cfg.showTitle) {
  661. var that = this;
  662. var titleBar = that.titleBar =
  663. $('<div>').append(
  664. $('<span>').addClass('dialogJtxt')
  665. ).addClass('dialogJtitle')
  666. .appendTo(this.elementWrapper);
  667.  
  668. if (this.cfg.closeable) {
  669. $('<a>').addClass('dialogJclose').attr({
  670. title: this.cfg.closeTips || "关闭本窗口",
  671. href: '#'
  672. }).text(' ').appendTo(titleBar)
  673. .on ('mousedown', function (e) {
  674. e.stopPropagation();
  675. }).click(function () {
  676. if (that.cfg.hideOnclose) {
  677. that.hide()
  678. } else {
  679. that.close();
  680. }
  681. return false;
  682. });
  683.  
  684. if (this.cfg.draggable) {
  685. titleBar.css ({
  686. cursor: 'move'
  687. });
  688.  
  689. var _rmDrag = $(that.element).draggable({
  690. handle: titleBar,
  691. start: function () {
  692. that._setupHackDiv(1)
  693. },
  694. stop: function () {
  695. that.dragged = true;
  696. that._setupHackDiv(0);
  697. }
  698. });
  699. $(that.element).on("onclose", _rmDrag);
  700. }
  701. }
  702. }
  703. },
  704.  
  705. _setupHackDiv: function (bShowHackDiv) {
  706. var _$dialog = this;
  707. if (bShowHackDiv) {
  708. if ($("IFRAME", _$dialog.element).length) {
  709. var $content = $(".dialogJcontent", _$dialog.element);
  710. if (!_$dialog.hack_div) {
  711. _$dialog.hack_div = $("<div>").appendTo($content).css({
  712. position: "absolute",
  713. left: 0,
  714. top: 0,
  715. cursor: "move"
  716. });
  717. }
  718. _$dialog.hack_div.show().css({
  719. width: _$dialog.element.outerWidth(),
  720. height: _$dialog.element.outerHeight()
  721. })
  722. }
  723. } else {
  724. if (_$dialog.hack_div)
  725. _$dialog.hack_div.hide ();
  726. }
  727. },
  728.  
  729. _setupEscKey: function () {
  730. var $that = this;
  731.  
  732. var _escKeyCb = function (n) {
  733. // ESC - 0x1b
  734. if (0x1b == n.which) {
  735. if ($that.showTitle) {
  736. $(".dialogJclose", $that.titleBar).triggerHandler("click")
  737. } else {
  738. $that.close();
  739. }
  740. }
  741. };
  742.  
  743. $(document).on("keydown", _escKeyCb);
  744. $($that.element).on("onclose", function () {
  745. $(document).off("keydown", _escKeyCb)
  746. });
  747. },
  748.  
  749. _setupContent: function () {
  750. this.elementWrapper.append(
  751. $('<div>').addClass('dialogJcontent').append(
  752. $('<div>').addClass('dialogJbody')));
  753. },
  754.  
  755. _setScroll: function (bSetScroll) {
  756. if (this.cfg.modal && !this.cfg.scrollable) {
  757. var htmlRoot = $("html");
  758. if (htmlRoot.length) {
  759. var i = htmlRoot[0].scrollTop;
  760. if (bSetScroll) {
  761. htmlRoot.css({
  762. overflow: this.element.data("htmlOverflow") || "",
  763. paddingRight: 0
  764. });
  765. } else {
  766. if (htmlRoot[0].style.overFlow) {
  767. this.element.data("htmlOverflow", htmlRoot[0].style.overFlow);
  768. }
  769.  
  770. htmlRoot.css({
  771. overflow: "hidden",
  772. paddingRight: 17
  773. })
  774. }
  775.  
  776. htmlRoot[0].scrollTop = i
  777. }
  778. }
  779. }
  780. };
  781.  
  782. $.each(lstEvents, function (e, t) {
  783. $dialog.prototype[t] = function (e) {
  784. this.on(t, e)
  785. }
  786. });
  787. $dialog.INST = [];
  788. $.dialog = $dialog;
  789. })(jQuery);