iframe.js 4.9 KB

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