iframeTools.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*!
  2. * artDialog iframeTools
  3. * Date: 2011-11-25 13:54
  4. * http://code.google.com/p/artdialog/
  5. * (c) 2009-2011 TangBin, http://www.planeArt.cn
  6. *
  7. * This is licensed under the GNU LGPL, version 2.1 or later.
  8. * For details, see: http://creativecommons.org/licenses/LGPL/2.1/
  9. */
  10. ;(function ($, window, artDialog, undefined) {
  11. var _topDialog, _proxyDialog, _zIndex,
  12. _data = '@ARTDIALOG.DATA',
  13. _open = '@ARTDIALOG.OPEN',
  14. _opener = '@ARTDIALOG.OPENER',
  15. _winName = window.name = window.name
  16. || '@ARTDIALOG.WINNAME' + + new Date,
  17. _isIE6 = window.VBArray && !window.XMLHttpRequest;
  18. $(function () {
  19. !window.jQuery && document.compatMode === 'BackCompat'
  20. // 不支持怪异模式,请用主流的XHTML1.0或者HTML5的DOCTYPE申明
  21. && alert('artDialog Error: document.compatMode === "BackCompat"');
  22. });
  23. /** 获取 artDialog 可跨级调用的最高层的 window 对象 */
  24. var _top = artDialog.top = function () {
  25. var top = window,
  26. test = function (name) {
  27. try {
  28. var doc = window[name].document; // 跨域|无权限
  29. doc.getElementsByTagName; // chrome 本地安全限制
  30. } catch (e) {
  31. return false;
  32. }
  33. return window[name].artDialog
  34. // 框架集无法显示第三方元素
  35. && doc.getElementsByTagName('frameset').length === 0;
  36. };
  37. if (test('top')) {
  38. top = window.top;
  39. } else if (test('parent')) {
  40. top = window.parent;
  41. }
  42. return top;
  43. }();
  44. artDialog.parent = _top; // 兼容v4.1之前版本,未来版本将删除此
  45. _topDialog = _top.artDialog;
  46. // 获取顶层页面对话框叠加值
  47. _zIndex = function () {
  48. return _topDialog.defaults.zIndex;
  49. };
  50. /**
  51. * 跨框架数据共享接口
  52. * @see http://www.planeart.cn/?p=1554
  53. * @param {String} 存储的数据名
  54. * @param {Any} 将要存储的任意数据(无此项则返回被查询的数据)
  55. */
  56. artDialog.data = function (name, value) {
  57. var top = artDialog.top,
  58. cache = top[_data] || {};
  59. top[_data] = cache;
  60. if (value !== undefined) {
  61. cache[name] = value;
  62. } else {
  63. return cache[name];
  64. }
  65. return cache;
  66. };
  67. /**
  68. * 数据共享删除接口
  69. * @param {String} 删除的数据名
  70. */
  71. artDialog.removeData = function (name) {
  72. var cache = artDialog.top[_data];
  73. if (cache && cache[name]) delete cache[name];
  74. };
  75. /** 跨框架普通对话框 */
  76. artDialog.through = _proxyDialog = function () {
  77. var api = _topDialog.apply(this, arguments);
  78. // 缓存从当前 window(可能为iframe)调出所有跨框架对话框,
  79. // 以便让当前 window 卸载前去关闭这些对话框。
  80. // 因为iframe注销后也会从内存中删除其创建的对象,这样可以防止回调函数报错
  81. if (_top !== window) artDialog.list[api.config.id] = api;
  82. return api;
  83. };
  84. // 框架页面卸载前关闭所有穿越的对话框
  85. _top !== window && $(window).bind('unload', function () {
  86. var list = artDialog.list, config;
  87. for (var i in list) {
  88. if (list[i]) {
  89. config = list[i].config;
  90. if (config) config.duration = 0; // 取消动画
  91. list[i].close();
  92. //delete list[i];
  93. }
  94. }
  95. });
  96. /**
  97. * 弹窗 (iframe)
  98. * @param {String} 地址
  99. * @param {Object} 配置参数. 这里传入的回调函数接收的第1个参数为iframe内部window对象
  100. * @param {Boolean} 是否允许缓存. 默认true
  101. */
  102. artDialog.open = function (url, options, cache) {
  103. options = options || {};
  104. var api, DOM,
  105. $content, $main, iframe, $iframe, $idoc, iwin, ibody,
  106. top = artDialog.top,
  107. initCss = 'position:absolute;left:-9999em;top:-9999em;border:none 0;background:transparent',
  108. loadCss = 'width:100%;height:100%;border:none 0';
  109. if (cache === false) {
  110. var ts = + new Date,
  111. ret = url.replace(/([?&])_=[^&]*/, "$1_=" + ts );
  112. url = ret + ((ret === url) ? (/\?/.test(url) ? "&" : "?") + "_=" + ts : "");
  113. }
  114. var load = function () {
  115. var iWidth, iHeight,
  116. loading = DOM.content.find('.aui_loading'),
  117. aConfig = api.config;
  118. $content.addClass('aui_state_full');
  119. loading && loading.hide();
  120. try {
  121. iwin = iframe.contentWindow;
  122. $idoc = $(iwin.document);
  123. ibody = iwin.document.body;
  124. } catch (e) {// 跨域
  125. iframe.style.cssText = loadCss;
  126. aConfig.follow
  127. ? api.follow(aConfig.follow)
  128. : api.position(aConfig.left, aConfig.top);
  129. options.init && options.init.call(api, iwin, top);
  130. options.init = null;
  131. return;
  132. }
  133. // 获取iframe内部尺寸
  134. iWidth = aConfig.width === 'auto'
  135. ? $idoc.width() + (_isIE6 ? 0 : parseInt($(ibody).css('marginLeft')))
  136. : aConfig.width;
  137. iHeight = aConfig.height === 'auto'
  138. ? $idoc.height()
  139. : aConfig.height;
  140. // 适应iframe尺寸
  141. setTimeout(function () {
  142. iframe.style.cssText = loadCss;
  143. }, 0);// setTimeout: 防止IE6~7对话框样式渲染异常
  144. api.size(iWidth, iHeight);
  145. // 调整对话框位置
  146. aConfig.follow
  147. ? api.follow(aConfig.follow)
  148. : api.position(aConfig.left, aConfig.top);
  149. options.init && options.init.call(api, iwin, top);
  150. options.init = null;
  151. };
  152. var config = {
  153. zIndex: _zIndex(),
  154. init: function () {
  155. api = this;
  156. DOM = api.DOM;
  157. $main = DOM.main;
  158. $content = DOM.content;
  159. iframe = api.iframe = top.document.createElement('iframe');
  160. iframe.src = url;
  161. iframe.name = 'Open' + api.config.id;
  162. iframe.style.cssText = initCss;
  163. iframe.setAttribute('frameborder', 0, 0);
  164. iframe.setAttribute('allowTransparency', true);
  165. $iframe = $(iframe);
  166. api.content().appendChild(iframe);
  167. iwin = iframe.contentWindow;
  168. try {
  169. iwin.name = iframe.name;
  170. artDialog.data(iframe.name + _open, api);
  171. artDialog.data(iframe.name + _opener, window);
  172. } catch (e) {
  173. }
  174. $iframe.bind('load', load);
  175. },
  176. close: function () {
  177. $iframe.css('display', 'none').unbind('load', load);
  178. if (options.close && options.close.call(this, iframe.contentWindow, top) === false) {
  179. return false;
  180. }
  181. $content.removeClass('aui_state_full');
  182. // 重要!需要重置iframe地址,否则下次出现的对话框在IE6、7无法聚焦input
  183. // IE删除iframe后,iframe仍然会留在内存中出现上述问题,置换src是最容易解决的方法
  184. $iframe[0].src = 'about:blank';
  185. $iframe.remove();
  186. try {
  187. artDialog.removeData(iframe.name + _open);
  188. artDialog.removeData(iframe.name + _opener);
  189. } catch (e) {
  190. }
  191. }
  192. };
  193. // 回调函数第一个参数指向iframe内部window对象
  194. if (typeof options.ok === 'function') config.ok = function () {
  195. return options.ok.call(api, iframe.contentWindow, top);
  196. };
  197. if (typeof options.cancel === 'function') config.cancel = function () {
  198. return options.cancel.call(api, iframe.contentWindow, top);
  199. };
  200. delete options.content;
  201. for (var i in options) {
  202. if (config[i] === undefined) config[i] = options[i];
  203. }
  204. return _proxyDialog(config);
  205. };
  206. /** 引用open方法扩展方法(在open打开的iframe内部私有方法) */
  207. artDialog.open.api = artDialog.data(_winName + _open);
  208. /** 引用open方法触发来源页面window(在open打开的iframe内部私有方法) */
  209. artDialog.opener = artDialog.data(_winName + _opener) || window;
  210. artDialog.open.origin = artDialog.opener; // 兼容v4.1之前版本,未来版本将删除此
  211. /** artDialog.open 打开的iframe页面里关闭对话框快捷方法 */
  212. artDialog.close = function () {
  213. var api = artDialog.data(_winName + _open);
  214. api && api.close();
  215. return false;
  216. };
  217. // 点击iframe内容切换叠加高度
  218. _top != window && $(document).bind('mousedown', function () {
  219. var api = artDialog.open.api;
  220. api && api.zIndex();
  221. });
  222. /**
  223. * Ajax填充内容
  224. * @param {String} 地址
  225. * @param {Object} 配置参数
  226. * @param {Boolean} 是否允许缓存. 默认true
  227. */
  228. artDialog.load = function(url, options, cache){
  229. cache = cache || false;
  230. var opt = options || {};
  231. var config = {
  232. zIndex: _zIndex(),
  233. init: function(here){
  234. var api = this,
  235. aConfig = api.config;
  236. $.ajax({
  237. url: url,
  238. success: function (content) {
  239. api.content(content);
  240. opt.init && opt.init.call(api, here);
  241. },
  242. cache: cache
  243. });
  244. }
  245. };
  246. delete options.content;
  247. for (var i in opt) {
  248. if (config[i] === undefined) config[i] = opt[i];
  249. }
  250. return _proxyDialog(config);
  251. };
  252. /**
  253. * 警告
  254. * @param {String} 消息内容
  255. */
  256. artDialog.alert = function (content, callback) {
  257. return _proxyDialog({
  258. id: 'Alert',
  259. zIndex: _zIndex(),
  260. icon: 'warning',
  261. fixed: true,
  262. lock: true,
  263. content: content,
  264. ok: true,
  265. close: callback
  266. });
  267. };
  268. /**
  269. * 确认
  270. * @param {String} 消息内容
  271. * @param {Function} 确定按钮回调函数
  272. * @param {Function} 取消按钮回调函数
  273. */
  274. artDialog.confirm = function (content, yes, no) {
  275. return _proxyDialog({
  276. id: 'Confirm',
  277. zIndex: _zIndex(),
  278. icon: 'question',
  279. fixed: true,
  280. lock: true,
  281. opacity: .1,
  282. content: content,
  283. ok: function (here) {
  284. return yes.call(this, here);
  285. },
  286. cancel: function (here) {
  287. return no && no.call(this, here);
  288. }
  289. });
  290. };
  291. /**
  292. * 提问
  293. * @param {String} 提问内容
  294. * @param {Function} 回调函数. 接收参数:输入值
  295. * @param {String} 默认值
  296. */
  297. artDialog.prompt = function (content, yes, value) {
  298. value = value || '';
  299. var input;
  300. return _proxyDialog({
  301. id: 'Prompt',
  302. zIndex: _zIndex(),
  303. icon: 'question',
  304. fixed: true,
  305. lock: true,
  306. opacity: .1,
  307. content: [
  308. '<div style="margin-bottom:5px;font-size:12px">',
  309. content,
  310. '</div>',
  311. '<div>',
  312. '<input value="',
  313. value,
  314. '" style="width:18em;padding:6px 4px" />',
  315. '</div>'
  316. ].join(''),
  317. init: function () {
  318. input = this.DOM.content.find('input')[0];
  319. input.select();
  320. input.focus();
  321. },
  322. ok: function (here) {
  323. return yes && yes.call(this, input.value, here);
  324. },
  325. cancel: true
  326. });
  327. };
  328. /**
  329. * 短暂提示
  330. * @param {String} 提示内容
  331. * @param {Number} 显示时间 (默认1.5秒)
  332. */
  333. artDialog.tips = function (content, time) {
  334. return _proxyDialog({
  335. id: 'Tips',
  336. zIndex: _zIndex(),
  337. title: false,
  338. cancel: false,
  339. fixed: true,
  340. lock: false
  341. })
  342. .content('<div style="padding: 0 1em;">' + content + '</div>')
  343. .time(time || 1.5);
  344. };
  345. // 增强artDialog拖拽体验
  346. // - 防止鼠标落入iframe导致不流畅
  347. // - 对超大对话框拖动优化
  348. $(function () {
  349. var event = artDialog.dragEvent;
  350. if (!event) return;
  351. var $window = $(window),
  352. $document = $(document),
  353. positionType = _isIE6 ? 'absolute' : 'fixed',
  354. dragEvent = event.prototype,
  355. mask = document.createElement('div'),
  356. style = mask.style;
  357. style.cssText = 'display:none;position:' + positionType + ';left:0;top:0;width:100%;height:100%;'
  358. + 'cursor:move;filter:alpha(opacity=0);opacity:0;background:#FFF';
  359. document.body.appendChild(mask);
  360. dragEvent._start = dragEvent.start;
  361. dragEvent._end = dragEvent.end;
  362. dragEvent.start = function () {
  363. var DOM = artDialog.focus.DOM,
  364. main = DOM.main[0],
  365. iframe = DOM.content[0].getElementsByTagName('iframe')[0];
  366. dragEvent._start.apply(this, arguments);
  367. style.display = 'block';
  368. style.zIndex = artDialog.defaults.zIndex + 3;
  369. if (positionType === 'absolute') {
  370. style.width = $window.width() + 'px';
  371. style.height = $window.height() + 'px';
  372. style.left = $document.scrollLeft() + 'px';
  373. style.top = $document.scrollTop() + 'px';
  374. }
  375. if (iframe && main.offsetWidth * main.offsetHeight > 307200) {
  376. main.style.visibility = 'hidden';
  377. }
  378. };
  379. dragEvent.end = function () {
  380. var dialog = artDialog.focus;
  381. dragEvent._end.apply(this, arguments);
  382. style.display = 'none';
  383. if (dialog) dialog.DOM.main[0].style.visibility = 'visible';
  384. };
  385. });
  386. })(this.art || this.jQuery, this, this.artDialog);