'use strict'; const promiseSleep = require('./promise').sleep; const { getHiddenWindow } = require('sdk/window/utils'); let hiddenWindow = null; module.exports = { get window() { if (!hiddenWindow) { try { let win = getHiddenWindow(); if (win.document.readyState === 'complete' && win.document.documentElement.appendChild) { hiddenWindow = win; } } catch (e) {} } return hiddenWindow; }, getFrame: function (props = {}) { if (typeof props.url === 'undefined') { const randomId = Date.now() + Math.floor(Math.random() * 1000000); switch (props.contentType) { case 'xul': props.url = 'data:application/vnd.mozilla.xul+xml;charset=utf-8,' + encodeURIComponent(``); break; default: props.url = 'data:text/html;charset=utf-8,' + encodeURIComponent(`` + '</head><body/></html>'); break; } } return promiseSleep(10000, () => Boolean(this.window)).then(() => createFrame(props)); }, removeFrame: removeFrame }; function createFrame({ url, id }) { return new Promise((resolve, reject) => { if (!url || typeof url !== 'string') { reject(new TypeError('url must be a string.')); return; } let hiddenWindow = module.exports.window; let hiddenDoc = hiddenWindow && hiddenWindow.document; if (!hiddenDoc) { reject(new Error('No hidden document')); return; } id = id || encodeURIComponent(url); let frameLoader = hiddenDoc.getElementById(id); if (!frameLoader) { frameLoader = hiddenDoc.createElement('iframe'); frameLoader.setAttribute('id', id); frameLoader.setAttribute('src', url); hiddenDoc.documentElement.appendChild(frameLoader); } return ensureFrameLoaded(frameLoader).then(resolve); }); } function ensureFrameLoaded(frameLoader) { const url = frameLoader.getAttribute('src'); const waitFrameLocation = promiseSleep(10000, () => { return String(frameLoader.contentWindow && frameLoader.contentWindow.location) === url; }); return new Promise((resolve, reject) => { waitFrameLocation.then(() => { promiseSleep(10000, () => frameLoader.contentWindow.document.readyState === 'complete').then(() => resolve(frameLoader), () => reject(new Error(`Can't get hidden window for "${ url }"`))), e => { reject(new Error(`Can't get hidden window for "${ url }"`)); }; }); }); } function removeFrame({ frame, window, url, id }) { return new Promise((resolve, reject) => { if (!url) { if (frame) { window = frame.contentWindow; } if (window) { url = window.location.toString(); } } if (!url || typeof url !== 'string') { reject(new TypeError('url must be a string.')); return; } const hiddenWindow = module.exports.window; const hiddenDoc = hiddenWindow && hiddenWindow.document; if (!hiddenDoc) { resolve(); return; } id = id || encodeURIComponent(url); const frameLoader = hiddenDoc.getElementById(id); if (frameLoader) { frameLoader.parentNode.removeChild(frameLoader); } resolve(frameLoader); }); }