iframeTools.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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. $iframe.bind('load', load);
  174. },
  175. close: function () {
  176. $iframe.css('display', 'none').unbind('load', load);
  177. if (options.close && options.close.call(this, iframe.contentWindow, top) === false) {
  178. return false;
  179. };
  180. $content.removeClass('aui_state_full');
  181. // 重要!需要重置iframe地址,否则下次出现的对话框在IE6、7无法聚焦input
  182. // IE删除iframe后,iframe仍然会留在内存中出现上述问题,置换src是最容易解决的方法
  183. $iframe[0].src = 'about:blank';
  184. $iframe.remove();
  185. try {
  186. artDialog.removeData(iframe.name + _open);
  187. artDialog.removeData(iframe.name + _opener);
  188. } catch (e) {};
  189. }
  190. };
  191. // 回调函数第一个参数指向iframe内部window对象
  192. if (typeof options.ok === 'function') config.ok = function () {
  193. return options.ok.call(api, iframe.contentWindow, top);
  194. };
  195. if (typeof options.cancel === 'function') config.cancel = function () {
  196. return options.cancel.call(api, iframe.contentWindow, top);
  197. };
  198. delete options.content;
  199. for (var i in options) {
  200. if (config[i] === undefined) config[i] = options[i];
  201. };
  202. return _proxyDialog(config);
  203. };
  204. /** 引用open方法扩展方法(在open打开的iframe内部私有方法) */
  205. artDialog.open.api = artDialog.data(_winName + _open);
  206. /** 引用open方法触发来源页面window(在open打开的iframe内部私有方法) */
  207. artDialog.opener = artDialog.data(_winName + _opener) || window;
  208. artDialog.open.origin = artDialog.opener; // 兼容v4.1之前版本,未来版本将删除此
  209. /** artDialog.open 打开的iframe页面里关闭对话框快捷方法 */
  210. artDialog.close = function () {
  211. var api = artDialog.data(_winName + _open);
  212. api && api.close();
  213. return false;
  214. };
  215. // 点击iframe内容切换叠加高度
  216. _top != window && $(document).bind('mousedown', function () {
  217. var api = artDialog.open.api;
  218. api && api.zIndex();
  219. });
  220. /**
  221. * Ajax填充内容
  222. * @param {String} 地址
  223. * @param {Object} 配置参数
  224. * @param {Boolean} 是否允许缓存. 默认true
  225. */
  226. artDialog.load = function(url, options, cache){
  227. cache = cache || false;
  228. var opt = options || {};
  229. var config = {
  230. zIndex: _zIndex(),
  231. init: function(here){
  232. var api = this,
  233. aConfig = api.config;
  234. $.ajax({
  235. url: url,
  236. success: function (content) {
  237. api.content(content);
  238. opt.init && opt.init.call(api, here);
  239. },
  240. cache: cache
  241. });
  242. }
  243. };
  244. delete options.content;
  245. for (var i in opt) {
  246. if (config[i] === undefined) config[i] = opt[i];
  247. };
  248. return _proxyDialog(config);
  249. };
  250. /**
  251. * 警告
  252. * @param {String} 消息内容
  253. */
  254. artDialog.alert = function (content, callback) {
  255. return _proxyDialog({
  256. id: 'Alert',
  257. zIndex: _zIndex(),
  258. icon: 'warning',
  259. fixed: true,
  260. lock: true,
  261. content: content,
  262. ok: true,
  263. close: callback
  264. });
  265. };
  266. /**
  267. * 确认
  268. * @param {String} 消息内容
  269. * @param {Function} 确定按钮回调函数
  270. * @param {Function} 取消按钮回调函数
  271. */
  272. artDialog.confirm = function (content, yes, no) {
  273. return _proxyDialog({
  274. id: 'Confirm',
  275. zIndex: _zIndex(),
  276. icon: 'question',
  277. fixed: true,
  278. lock: true,
  279. opacity: .1,
  280. content: content,
  281. ok: function (here) {
  282. return yes.call(this, here);
  283. },
  284. cancel: function (here) {
  285. return no && no.call(this, here);
  286. }
  287. });
  288. };
  289. /**
  290. * 提问
  291. * @param {String} 提问内容
  292. * @param {Function} 回调函数. 接收参数:输入值
  293. * @param {String} 默认值
  294. */
  295. artDialog.prompt = function (content, yes, value) {
  296. value = value || '';
  297. var input;
  298. return _proxyDialog({
  299. id: 'Prompt',
  300. zIndex: _zIndex(),
  301. icon: 'question',
  302. fixed: true,
  303. lock: true,
  304. opacity: .1,
  305. content: [
  306. '<div style="margin-bottom:5px;font-size:12px">',
  307. content,
  308. '</div>',
  309. '<div>',
  310. '<input value="',
  311. value,
  312. '" style="width:18em;padding:6px 4px" />',
  313. '</div>'
  314. ].join(''),
  315. init: function () {
  316. input = this.DOM.content.find('input')[0];
  317. input.select();
  318. input.focus();
  319. },
  320. ok: function (here) {
  321. return yes && yes.call(this, input.value, here);
  322. },
  323. cancel: true
  324. });
  325. };
  326. /**
  327. * 短暂提示
  328. * @param {String} 提示内容
  329. * @param {Number} 显示时间 (默认1.5秒)
  330. */
  331. artDialog.tips = function (content, time) {
  332. return _proxyDialog({
  333. id: 'Tips',
  334. zIndex: _zIndex(),
  335. title: false,
  336. cancel: false,
  337. fixed: true,
  338. lock: false
  339. })
  340. .content('<div style="padding: 0 1em;">' + content + '</div>')
  341. .time(time || 1.5);
  342. };
  343. // 增强artDialog拖拽体验
  344. // - 防止鼠标落入iframe导致不流畅
  345. // - 对超大对话框拖动优化
  346. $(function () {
  347. var event = artDialog.dragEvent;
  348. if (!event) return;
  349. var $window = $(window),
  350. $document = $(document),
  351. positionType = _isIE6 ? 'absolute' : 'fixed',
  352. dragEvent = event.prototype,
  353. mask = document.createElement('div'),
  354. style = mask.style;
  355. style.cssText = 'display:none;position:' + positionType + ';left:0;top:0;width:100%;height:100%;'
  356. + 'cursor:move;filter:alpha(opacity=0);opacity:0;background:#FFF';
  357. document.body.appendChild(mask);
  358. dragEvent._start = dragEvent.start;
  359. dragEvent._end = dragEvent.end;
  360. dragEvent.start = function () {
  361. var DOM = artDialog.focus.DOM,
  362. main = DOM.main[0],
  363. iframe = DOM.content[0].getElementsByTagName('iframe')[0];
  364. dragEvent._start.apply(this, arguments);
  365. style.display = 'block';
  366. style.zIndex = artDialog.defaults.zIndex + 3;
  367. if (positionType === 'absolute') {
  368. style.width = $window.width() + 'px';
  369. style.height = $window.height() + 'px';
  370. style.left = $document.scrollLeft() + 'px';
  371. style.top = $document.scrollTop() + 'px';
  372. };
  373. if (iframe && main.offsetWidth * main.offsetHeight > 307200) {
  374. main.style.visibility = 'hidden';
  375. };
  376. };
  377. dragEvent.end = function () {
  378. var dialog = artDialog.focus;
  379. dragEvent._end.apply(this, arguments);
  380. style.display = 'none';
  381. if (dialog) dialog.DOM.main[0].style.visibility = 'visible';
  382. };
  383. });
  384. })(this.art || this.jQuery, this, this.artDialog);