You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

474 lines
18 KiB

  1. /*!
  2. * jQuery blockUI plugin
  3. * Version 2.31 (06-JAN-2010)
  4. * @requires jQuery v1.2.3 or later
  5. *
  6. * Examples at: http://malsup.com/jquery/block/
  7. * Copyright (c) 2007-2008 M. Alsup
  8. * Dual licensed under the MIT and GPL licenses:
  9. * http://www.opensource.org/licenses/mit-license.php
  10. * http://www.gnu.org/licenses/gpl.html
  11. *
  12. * Thanks to Amir-Hossein Sobhi for some excellent contributions!
  13. */
  14. ; (function ($) {
  15. if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
  16. alert('blockUI requires jQuery v1.2.3 or later! You are using v' + $.fn.jquery);
  17. return;
  18. }
  19. $.fn._fadeIn = $.fn.fadeIn;
  20. var noOp = function () { };
  21. // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
  22. // retarded userAgent strings on Vista)
  23. var mode = document.documentMode || 0;
  24. var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8);
  25. var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode;
  26. // global $ methods for blocking/unblocking the entire page
  27. $.blockUI = function (opts) { install(window, opts); };
  28. $.unblockUI = function (opts) { remove(window, opts); };
  29. // convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
  30. $.growlUI = function (title, message, timeout, onClose) {
  31. var $m = $('<div class="growlUI"></div>');
  32. if (title) $m.append('<h1>' + title + '</h1>');
  33. if (message) $m.append('<h2>' + message + '</h2>');
  34. if (timeout == undefined) timeout = 3000;
  35. $.blockUI({
  36. message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
  37. timeout: timeout, showOverlay: false,
  38. onUnblock: onClose,
  39. css: $.blockUI.defaults.growlCSS
  40. });
  41. };
  42. // plugin method for blocking element content
  43. $.fn.block = function (opts) {
  44. return this.unblock({ fadeOut: 0 }).each(function () {
  45. if ($.css(this, 'position') == 'static')
  46. this.style.position = 'relative';
  47. if ($.browser.msie)
  48. this.style.zoom = 1; // force 'hasLayout'
  49. install(this, opts);
  50. });
  51. };
  52. // plugin method for unblocking element content
  53. $.fn.unblock = function (opts) {
  54. return this.each(function () {
  55. remove(this, opts);
  56. });
  57. };
  58. $.blockUI.version = 2.31; // 2nd generation blocking at no extra cost!
  59. // override these in your code to change the default behavior and style
  60. $.blockUI.defaults = {
  61. // message displayed when blocking (use null for no message)
  62. message: '<h1>Please wait...</h1>',
  63. title: null, // title string; only used when theme == true
  64. draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
  65. theme: false, // set to true to use with jQuery UI themes
  66. // styles for the message when blocking; if you wish to disable
  67. // these and use an external stylesheet then do this in your code:
  68. // $.blockUI.defaults.css = {};
  69. css: {
  70. padding: 0,
  71. margin: 0,
  72. width: '30%',
  73. top: '40%',
  74. left: '35%',
  75. textAlign: 'center',
  76. color: '#000',
  77. border: '3px solid #aaa',
  78. backgroundColor: '#fff',
  79. cursor: 'wait'
  80. },
  81. // minimal style set used when themes are used
  82. themedCSS: {
  83. width: '30%',
  84. top: '40%',
  85. left: '35%'
  86. },
  87. // styles for the overlay
  88. overlayCSS: {
  89. backgroundColor: '#000',
  90. opacity: 0.6,
  91. cursor: 'wait'
  92. },
  93. // styles applied when using $.growlUI
  94. growlCSS: {
  95. width: '350px',
  96. top: '10px',
  97. left: '',
  98. right: '10px',
  99. border: 'none',
  100. padding: '5px',
  101. opacity: 0.6,
  102. cursor: 'default',
  103. color: '#fff',
  104. backgroundColor: '#000',
  105. '-webkit-border-radius': '10px',
  106. '-moz-border-radius': '10px'
  107. },
  108. // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
  109. // (hat tip to Jorge H. N. de Vasconcelos)
  110. iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
  111. // force usage of iframe in non-IE browsers (handy for blocking applets)
  112. forceIframe: false,
  113. // z-index for the blocking overlay
  114. baseZ: 1000,
  115. // set these to true to have the message automatically centered
  116. centerX: true, // <-- only effects element blocking (page block controlled via css above)
  117. centerY: true,
  118. // allow body element to be stetched in ie6; this makes blocking look better
  119. // on "short" pages. disable if you wish to prevent changes to the body height
  120. allowBodyStretch: true,
  121. // enable if you want key and mouse events to be disabled for content that is blocked
  122. bindEvents: true,
  123. // be default blockUI will supress tab navigation from leaving blocking content
  124. // (if bindEvents is true)
  125. constrainTabKey: true,
  126. // fadeIn time in millis; set to 0 to disable fadeIn on block
  127. fadeIn: 200,
  128. // fadeOut time in millis; set to 0 to disable fadeOut on unblock
  129. fadeOut: 400,
  130. // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
  131. timeout: 0,
  132. // disable if you don't want to show the overlay
  133. showOverlay: true,
  134. // if true, focus will be placed in the first available input field when
  135. // page blocking
  136. focusInput: true,
  137. // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
  138. applyPlatformOpacityRules: true,
  139. // callback method invoked when fadeIn has completed and blocking message is visible
  140. onBlock: null,
  141. // callback method invoked when unblocking has completed; the callback is
  142. // passed the element that has been unblocked (which is the window object for page
  143. // blocks) and the options that were passed to the unblock call:
  144. // onUnblock(element, options)
  145. onUnblock: null,
  146. // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
  147. quirksmodeOffsetHack: 4
  148. };
  149. // private data and functions follow...
  150. var pageBlock = null;
  151. var pageBlockEls = [];
  152. function install(el, opts) {
  153. var full = (el == window);
  154. var msg = opts && opts.message !== undefined ? opts.message : undefined;
  155. opts = $.extend({}, $.blockUI.defaults, opts || {});
  156. opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
  157. var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
  158. var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
  159. msg = msg === undefined ? opts.message : msg;
  160. // remove the current block (if there is one)
  161. if (full && pageBlock)
  162. remove(window, { fadeOut: 0 });
  163. // if an existing element is being used as the blocking content then we capture
  164. // its current place in the DOM (and current display style) so we can restore
  165. // it when we unblock
  166. if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
  167. var node = msg.jquery ? msg[0] : msg;
  168. var data = {};
  169. $(el).data('blockUI.history', data);
  170. data.el = node;
  171. data.parent = node.parentNode;
  172. data.display = node.style.display;
  173. data.position = node.style.position;
  174. if (data.parent)
  175. data.parent.removeChild(node);
  176. }
  177. var z = opts.baseZ;
  178. // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
  179. // layer1 is the iframe layer which is used to supress bleed through of underlying content
  180. // layer2 is the overlay layer which has opacity and a wait cursor (by default)
  181. // layer3 is the message content that is displayed while blocking
  182. var lyr1 = ($.browser.msie || opts.forceIframe)
  183. ? $('<iframe class="blockUI" style="z-index:' + (z++) + ';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="' + opts.iframeSrc + '"></iframe>')
  184. : $('<div class="blockUI" style="display:none"></div>');
  185. var lyr2 = $('<div class="blockUI blockOverlay" style="z-index:' + (z++) + ';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
  186. var lyr3;
  187. if (opts.theme && full) {
  188. var s = '<div class="blockUI blockMsg blockPage ui-dialog ui-widget ui-corner-all" style="z-index:' + z + ';display:none;position:fixed">' +
  189. '<div class="ui-widget-header ui-dialog-titlebar blockTitle">' + (opts.title || '&nbsp;') + '</div>' +
  190. '<div class="ui-widget-content ui-dialog-content"></div>' +
  191. '</div>';
  192. lyr3 = $(s);
  193. }
  194. else {
  195. lyr3 = full ? $('<div class="blockUI blockMsg blockPage" style="z-index:' + z + ';display:none;position:fixed"></div>')
  196. : $('<div class="blockUI blockMsg blockElement" style="z-index:' + z + ';display:none;position:absolute"></div>');
  197. }
  198. // if we have a message, style it
  199. if (msg) {
  200. if (opts.theme) {
  201. lyr3.css(themedCSS);
  202. lyr3.addClass('ui-widget-content');
  203. }
  204. else
  205. lyr3.css(css);
  206. }
  207. // style the overlay
  208. if (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform)))
  209. lyr2.css(opts.overlayCSS);
  210. lyr2.css('position', full ? 'fixed' : 'absolute');
  211. // make iframe layer transparent in IE
  212. if ($.browser.msie || opts.forceIframe)
  213. lyr1.css('opacity', 0.0);
  214. //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
  215. var layers = [lyr1, lyr2, lyr3], $par = full ? $('body') : $(el);
  216. $.each(layers, function () {
  217. this.appendTo($par);
  218. });
  219. if (opts.theme && opts.draggable && $.fn.draggable) {
  220. lyr3.draggable({
  221. handle: '.ui-dialog-titlebar',
  222. cancel: 'li'
  223. });
  224. }
  225. // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
  226. var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
  227. if (ie6 || expr) {
  228. // give body 100% height
  229. if (full && opts.allowBodyStretch && $.boxModel)
  230. $('html,body').css('height', '100%');
  231. // fix ie6 issue when blocked element has a border width
  232. if ((ie6 || !$.boxModel) && !full) {
  233. var t = sz(el, 'borderTopWidth'), l = sz(el, 'borderLeftWidth');
  234. var fixT = t ? '(0 - ' + t + ')' : 0;
  235. var fixL = l ? '(0 - ' + l + ')' : 0;
  236. }
  237. // simulate fixed position
  238. $.each([lyr1, lyr2, lyr3], function (i, o) {
  239. var s = o[0].style;
  240. s.position = 'absolute';
  241. if (i < 2) {
  242. full ? s.setExpression('height', 'Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:' + opts.quirksmodeOffsetHack + ') + "px"')
  243. : s.setExpression('height', 'this.parentNode.offsetHeight + "px"');
  244. full ? s.setExpression('width', 'jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
  245. : s.setExpression('width', 'this.parentNode.offsetWidth + "px"');
  246. if (fixL) s.setExpression('left', fixL);
  247. if (fixT) s.setExpression('top', fixT);
  248. }
  249. else if (opts.centerY) {
  250. if (full) s.setExpression('top', '(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
  251. s.marginTop = 0;
  252. }
  253. else if (!opts.centerY && full) {
  254. var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
  255. var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + ' + top + ') + "px"';
  256. s.setExpression('top', expression);
  257. }
  258. });
  259. }
  260. // show the message
  261. if (msg) {
  262. if (opts.theme)
  263. lyr3.find('.ui-widget-content').append(msg);
  264. else
  265. lyr3.append(msg);
  266. if (msg.jquery || msg.nodeType)
  267. $(msg).show();
  268. }
  269. if (($.browser.msie || opts.forceIframe) && opts.showOverlay)
  270. lyr1.show(); // opacity is zero
  271. if (opts.fadeIn) {
  272. var cb = opts.onBlock ? opts.onBlock : noOp;
  273. var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
  274. var cb2 = msg ? cb : noOp;
  275. if (opts.showOverlay)
  276. lyr2._fadeIn(opts.fadeIn, cb1);
  277. if (msg)
  278. lyr3._fadeIn(opts.fadeIn, cb2);
  279. }
  280. else {
  281. if (opts.showOverlay)
  282. lyr2.show();
  283. if (msg)
  284. lyr3.show();
  285. if (opts.onBlock)
  286. opts.onBlock();
  287. }
  288. // bind key and mouse events
  289. bind(1, el, opts);
  290. if (full) {
  291. pageBlock = lyr3[0];
  292. pageBlockEls = $(':input:enabled:visible', pageBlock);
  293. if (opts.focusInput)
  294. setTimeout(focus, 20);
  295. }
  296. else
  297. center(lyr3[0], opts.centerX, opts.centerY);
  298. if (opts.timeout) {
  299. // auto-unblock
  300. var to = setTimeout(function () {
  301. full ? $.unblockUI(opts) : $(el).unblock(opts);
  302. }, opts.timeout);
  303. $(el).data('blockUI.timeout', to);
  304. }
  305. };
  306. // remove the block
  307. function remove(el, opts) {
  308. var full = (el == window);
  309. var $el = $(el);
  310. var data = $el.data('blockUI.history');
  311. var to = $el.data('blockUI.timeout');
  312. if (to) {
  313. clearTimeout(to);
  314. $el.removeData('blockUI.timeout');
  315. }
  316. opts = $.extend({}, $.blockUI.defaults, opts || {});
  317. bind(0, el, opts); // unbind events
  318. var els;
  319. if (full) // crazy selector to handle odd field errors in ie6/7
  320. els = $('body').children().filter('.blockUI').add('body > .blockUI');
  321. else
  322. els = $('.blockUI', el);
  323. if (full)
  324. pageBlock = pageBlockEls = null;
  325. if (opts.fadeOut) {
  326. els.fadeOut(opts.fadeOut);
  327. setTimeout(function () { reset(els, data, opts, el); }, opts.fadeOut);
  328. }
  329. else
  330. reset(els, data, opts, el);
  331. };
  332. // move blocking element back into the DOM where it started
  333. function reset(els, data, opts, el) {
  334. els.each(function (i, o) {
  335. // remove via DOM calls so we don't lose event handlers
  336. if (this.parentNode)
  337. this.parentNode.removeChild(this);
  338. });
  339. if (data && data.el) {
  340. data.el.style.display = data.display;
  341. data.el.style.position = data.position;
  342. if (data.parent)
  343. data.parent.appendChild(data.el);
  344. $(el).removeData('blockUI.history');
  345. }
  346. if (typeof opts.onUnblock == 'function')
  347. opts.onUnblock(el, opts);
  348. };
  349. // bind/unbind the handler
  350. function bind(b, el, opts) {
  351. var full = el == window, $el = $(el);
  352. // don't bother unbinding if there is nothing to unbind
  353. if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
  354. return;
  355. if (!full)
  356. $el.data('blockUI.isBlocked', b);
  357. // don't bind events when overlay is not in use or if bindEvents is false
  358. if (!opts.bindEvents || (b && !opts.showOverlay))
  359. return;
  360. // bind anchors and inputs for mouse and key events
  361. var events = 'mousedown mouseup keydown keypress';
  362. b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);
  363. // former impl...
  364. // var $e = $('a,:input');
  365. // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
  366. };
  367. // event handler to suppress keyboard/mouse events when blocking
  368. function handler(e) {
  369. // allow tab navigation (conditionally)
  370. if (e.keyCode && e.keyCode == 9) {
  371. if (pageBlock && e.data.constrainTabKey) {
  372. var els = pageBlockEls;
  373. var fwd = !e.shiftKey && e.target == els[els.length - 1];
  374. var back = e.shiftKey && e.target == els[0];
  375. if (fwd || back) {
  376. setTimeout(function () { focus(back) }, 10);
  377. return false;
  378. }
  379. }
  380. }
  381. // allow events within the message content
  382. if ($(e.target).parents('div.blockMsg').length > 0)
  383. return true;
  384. // allow events for content that is not being blocked
  385. return $(e.target).parents().children().filter('div.blockUI').length == 0;
  386. };
  387. function focus(back) {
  388. if (!pageBlockEls)
  389. return;
  390. var e = pageBlockEls[back === true ? pageBlockEls.length - 1 : 0];
  391. if (e)
  392. e.focus();
  393. };
  394. function center(el, x, y) {
  395. var p = el.parentNode, s = el.style;
  396. var l = ((p.offsetWidth - el.offsetWidth) / 2) - sz(p, 'borderLeftWidth');
  397. var t = ((p.offsetHeight - el.offsetHeight) / 2) - sz(p, 'borderTopWidth');
  398. if (x) s.left = l > 0 ? (l + 'px') : '0';
  399. if (y) s.top = t > 0 ? (t + 'px') : '0';
  400. };
  401. function sz(el, p) {
  402. return parseInt($.css(el, p)) || 0;
  403. };
  404. })(jQuery);