187 lines
4.9 KiB
JavaScript
187 lines
4.9 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
var eventUtils = require('./event')
|
||
|
, JSON3 = require('json3')
|
||
|
, browser = require('./browser')
|
||
|
;
|
||
|
|
||
|
var debug = function() {};
|
||
|
if (process.env.NODE_ENV !== 'production') {
|
||
|
debug = require('debug')('sockjs-client:utils:iframe');
|
||
|
}
|
||
|
|
||
|
module.exports = {
|
||
|
WPrefix: '_jp'
|
||
|
, currentWindowId: null
|
||
|
|
||
|
, polluteGlobalNamespace: function() {
|
||
|
if (!(module.exports.WPrefix in global)) {
|
||
|
global[module.exports.WPrefix] = {};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
, postMessage: function(type, data) {
|
||
|
if (global.parent !== global) {
|
||
|
global.parent.postMessage(JSON3.stringify({
|
||
|
windowId: module.exports.currentWindowId
|
||
|
, type: type
|
||
|
, data: data || ''
|
||
|
}), '*');
|
||
|
} else {
|
||
|
debug('Cannot postMessage, no parent window.', type, data);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
, createIframe: function(iframeUrl, errorCallback) {
|
||
|
var iframe = global.document.createElement('iframe');
|
||
|
var tref, unloadRef;
|
||
|
var unattach = function() {
|
||
|
debug('unattach');
|
||
|
clearTimeout(tref);
|
||
|
// Explorer had problems with that.
|
||
|
try {
|
||
|
iframe.onload = null;
|
||
|
} catch (x) {
|
||
|
// intentionally empty
|
||
|
}
|
||
|
iframe.onerror = null;
|
||
|
};
|
||
|
var cleanup = function() {
|
||
|
debug('cleanup');
|
||
|
if (iframe) {
|
||
|
unattach();
|
||
|
// This timeout makes chrome fire onbeforeunload event
|
||
|
// within iframe. Without the timeout it goes straight to
|
||
|
// onunload.
|
||
|
setTimeout(function() {
|
||
|
if (iframe) {
|
||
|
iframe.parentNode.removeChild(iframe);
|
||
|
}
|
||
|
iframe = null;
|
||
|
}, 0);
|
||
|
eventUtils.unloadDel(unloadRef);
|
||
|
}
|
||
|
};
|
||
|
var onerror = function(err) {
|
||
|
debug('onerror', err);
|
||
|
if (iframe) {
|
||
|
cleanup();
|
||
|
errorCallback(err);
|
||
|
}
|
||
|
};
|
||
|
var post = function(msg, origin) {
|
||
|
debug('post', msg, origin);
|
||
|
setTimeout(function() {
|
||
|
try {
|
||
|
// When the iframe is not loaded, IE raises an exception
|
||
|
// on 'contentWindow'.
|
||
|
if (iframe && iframe.contentWindow) {
|
||
|
iframe.contentWindow.postMessage(msg, origin);
|
||
|
}
|
||
|
} catch (x) {
|
||
|
// intentionally empty
|
||
|
}
|
||
|
}, 0);
|
||
|
};
|
||
|
|
||
|
iframe.src = iframeUrl;
|
||
|
iframe.style.display = 'none';
|
||
|
iframe.style.position = 'absolute';
|
||
|
iframe.onerror = function() {
|
||
|
onerror('onerror');
|
||
|
};
|
||
|
iframe.onload = function() {
|
||
|
debug('onload');
|
||
|
// `onload` is triggered before scripts on the iframe are
|
||
|
// executed. Give it few seconds to actually load stuff.
|
||
|
clearTimeout(tref);
|
||
|
tref = setTimeout(function() {
|
||
|
onerror('onload timeout');
|
||
|
}, 2000);
|
||
|
};
|
||
|
global.document.body.appendChild(iframe);
|
||
|
tref = setTimeout(function() {
|
||
|
onerror('timeout');
|
||
|
}, 15000);
|
||
|
unloadRef = eventUtils.unloadAdd(cleanup);
|
||
|
return {
|
||
|
post: post
|
||
|
, cleanup: cleanup
|
||
|
, loaded: unattach
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/* eslint no-undef: "off", new-cap: "off" */
|
||
|
, createHtmlfile: function(iframeUrl, errorCallback) {
|
||
|
var axo = ['Active'].concat('Object').join('X');
|
||
|
var doc = new global[axo]('htmlfile');
|
||
|
var tref, unloadRef;
|
||
|
var iframe;
|
||
|
var unattach = function() {
|
||
|
clearTimeout(tref);
|
||
|
iframe.onerror = null;
|
||
|
};
|
||
|
var cleanup = function() {
|
||
|
if (doc) {
|
||
|
unattach();
|
||
|
eventUtils.unloadDel(unloadRef);
|
||
|
iframe.parentNode.removeChild(iframe);
|
||
|
iframe = doc = null;
|
||
|
CollectGarbage();
|
||
|
}
|
||
|
};
|
||
|
var onerror = function(r) {
|
||
|
debug('onerror', r);
|
||
|
if (doc) {
|
||
|
cleanup();
|
||
|
errorCallback(r);
|
||
|
}
|
||
|
};
|
||
|
var post = function(msg, origin) {
|
||
|
try {
|
||
|
// When the iframe is not loaded, IE raises an exception
|
||
|
// on 'contentWindow'.
|
||
|
setTimeout(function() {
|
||
|
if (iframe && iframe.contentWindow) {
|
||
|
iframe.contentWindow.postMessage(msg, origin);
|
||
|
}
|
||
|
}, 0);
|
||
|
} catch (x) {
|
||
|
// intentionally empty
|
||
|
}
|
||
|
};
|
||
|
|
||
|
doc.open();
|
||
|
doc.write('<html><s' + 'cript>' +
|
||
|
'document.domain="' + global.document.domain + '";' +
|
||
|
'</s' + 'cript></html>');
|
||
|
doc.close();
|
||
|
doc.parentWindow[module.exports.WPrefix] = global[module.exports.WPrefix];
|
||
|
var c = doc.createElement('div');
|
||
|
doc.body.appendChild(c);
|
||
|
iframe = doc.createElement('iframe');
|
||
|
c.appendChild(iframe);
|
||
|
iframe.src = iframeUrl;
|
||
|
iframe.onerror = function() {
|
||
|
onerror('onerror');
|
||
|
};
|
||
|
tref = setTimeout(function() {
|
||
|
onerror('timeout');
|
||
|
}, 15000);
|
||
|
unloadRef = eventUtils.unloadAdd(cleanup);
|
||
|
return {
|
||
|
post: post
|
||
|
, cleanup: cleanup
|
||
|
, loaded: unattach
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
module.exports.iframeEnabled = false;
|
||
|
if (global.document) {
|
||
|
// postMessage misbehaves in konqueror 4.6.5 - the messages are delivered with
|
||
|
// huge delay, or not at all.
|
||
|
module.exports.iframeEnabled = (typeof global.postMessage === 'function' ||
|
||
|
typeof global.postMessage === 'object') && (!browser.isKonqueror());
|
||
|
}
|