iframe.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. 'use strict';
  2. var eventUtils = require('./event')
  3. , JSON3 = require('json3')
  4. , browser = require('./browser')
  5. ;
  6. var debug = function() {};
  7. if (process.env.NODE_ENV !== 'production') {
  8. debug = require('debug')('sockjs-client:utils:iframe');
  9. }
  10. module.exports = {
  11. WPrefix: '_jp'
  12. , currentWindowId: null
  13. , polluteGlobalNamespace: function() {
  14. if (!(module.exports.WPrefix in global)) {
  15. global[module.exports.WPrefix] = {};
  16. }
  17. }
  18. , postMessage: function(type, data) {
  19. if (global.parent !== global) {
  20. global.parent.postMessage(JSON3.stringify({
  21. windowId: module.exports.currentWindowId
  22. , type: type
  23. , data: data || ''
  24. }), '*');
  25. } else {
  26. debug('Cannot postMessage, no parent window.', type, data);
  27. }
  28. }
  29. , createIframe: function(iframeUrl, errorCallback) {
  30. var iframe = global.document.createElement('iframe');
  31. var tref, unloadRef;
  32. var unattach = function() {
  33. debug('unattach');
  34. clearTimeout(tref);
  35. // Explorer had problems with that.
  36. try {
  37. iframe.onload = null;
  38. } catch (x) {
  39. // intentionally empty
  40. }
  41. iframe.onerror = null;
  42. };
  43. var cleanup = function() {
  44. debug('cleanup');
  45. if (iframe) {
  46. unattach();
  47. // This timeout makes chrome fire onbeforeunload event
  48. // within iframe. Without the timeout it goes straight to
  49. // onunload.
  50. setTimeout(function() {
  51. if (iframe) {
  52. iframe.parentNode.removeChild(iframe);
  53. }
  54. iframe = null;
  55. }, 0);
  56. eventUtils.unloadDel(unloadRef);
  57. }
  58. };
  59. var onerror = function(err) {
  60. debug('onerror', err);
  61. if (iframe) {
  62. cleanup();
  63. errorCallback(err);
  64. }
  65. };
  66. var post = function(msg, origin) {
  67. debug('post', msg, origin);
  68. try {
  69. // When the iframe is not loaded, IE raises an exception
  70. // on 'contentWindow'.
  71. setTimeout(function() {
  72. if (iframe && iframe.contentWindow) {
  73. iframe.contentWindow.postMessage(msg, origin);
  74. }
  75. }, 0);
  76. } catch (x) {
  77. // intentionally empty
  78. }
  79. };
  80. iframe.src = iframeUrl;
  81. iframe.style.display = 'none';
  82. iframe.style.position = 'absolute';
  83. iframe.onerror = function() {
  84. onerror('onerror');
  85. };
  86. iframe.onload = function() {
  87. debug('onload');
  88. // `onload` is triggered before scripts on the iframe are
  89. // executed. Give it few seconds to actually load stuff.
  90. clearTimeout(tref);
  91. tref = setTimeout(function() {
  92. onerror('onload timeout');
  93. }, 2000);
  94. };
  95. global.document.body.appendChild(iframe);
  96. tref = setTimeout(function() {
  97. onerror('timeout');
  98. }, 15000);
  99. unloadRef = eventUtils.unloadAdd(cleanup);
  100. return {
  101. post: post
  102. , cleanup: cleanup
  103. , loaded: unattach
  104. };
  105. }
  106. /* eslint no-undef: "off", new-cap: "off" */
  107. , createHtmlfile: function(iframeUrl, errorCallback) {
  108. var axo = ['Active'].concat('Object').join('X');
  109. var doc = new global[axo]('htmlfile');
  110. var tref, unloadRef;
  111. var iframe;
  112. var unattach = function() {
  113. clearTimeout(tref);
  114. iframe.onerror = null;
  115. };
  116. var cleanup = function() {
  117. if (doc) {
  118. unattach();
  119. eventUtils.unloadDel(unloadRef);
  120. iframe.parentNode.removeChild(iframe);
  121. iframe = doc = null;
  122. CollectGarbage();
  123. }
  124. };
  125. var onerror = function(r) {
  126. debug('onerror', r);
  127. if (doc) {
  128. cleanup();
  129. errorCallback(r);
  130. }
  131. };
  132. var post = function(msg, origin) {
  133. try {
  134. // When the iframe is not loaded, IE raises an exception
  135. // on 'contentWindow'.
  136. setTimeout(function() {
  137. if (iframe && iframe.contentWindow) {
  138. iframe.contentWindow.postMessage(msg, origin);
  139. }
  140. }, 0);
  141. } catch (x) {
  142. // intentionally empty
  143. }
  144. };
  145. doc.open();
  146. doc.write('<html><s' + 'cript>' +
  147. 'document.domain="' + global.document.domain + '";' +
  148. '</s' + 'cript></html>');
  149. doc.close();
  150. doc.parentWindow[module.exports.WPrefix] = global[module.exports.WPrefix];
  151. var c = doc.createElement('div');
  152. doc.body.appendChild(c);
  153. iframe = doc.createElement('iframe');
  154. c.appendChild(iframe);
  155. iframe.src = iframeUrl;
  156. iframe.onerror = function() {
  157. onerror('onerror');
  158. };
  159. tref = setTimeout(function() {
  160. onerror('timeout');
  161. }, 15000);
  162. unloadRef = eventUtils.unloadAdd(cleanup);
  163. return {
  164. post: post
  165. , cleanup: cleanup
  166. , loaded: unattach
  167. };
  168. }
  169. };
  170. module.exports.iframeEnabled = false;
  171. if (global.document) {
  172. // postMessage misbehaves in konqueror 4.6.5 - the messages are delivered with
  173. // huge delay, or not at all.
  174. module.exports.iframeEnabled = (typeof global.postMessage === 'function' ||
  175. typeof global.postMessage === 'object') && (!browser.isKonqueror());
  176. }