diff options
Diffstat (limited to 'browser/modules/HiddenFrame.jsm')
-rw-r--r-- | browser/modules/HiddenFrame.jsm | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/browser/modules/HiddenFrame.jsm b/browser/modules/HiddenFrame.jsm new file mode 100644 index 000000000..7676ae189 --- /dev/null +++ b/browser/modules/HiddenFrame.jsm @@ -0,0 +1,86 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["HiddenFrame"]; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/PromiseUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Timer.jsm"); + +const HTML_NS = "http://www.w3.org/1999/xhtml"; +const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='win'/>"; + +/** + * An hidden frame object. It takes care of creating an IFRAME and attaching it the + * |hiddenDOMWindow|. + */ +function HiddenFrame() {} + +HiddenFrame.prototype = { + _frame: null, + _deferred: null, + _retryTimerId: null, + + get hiddenDOMDocument() { + return Services.appShell.hiddenDOMWindow.document; + }, + + get isReady() { + return this.hiddenDOMDocument.readyState === "complete"; + }, + + /** + * Gets the |contentWindow| of the hidden frame. Creates the frame if needed. + * @returns Promise Returns a promise which is resolved when the hidden frame has finished + * loading. + */ + get: function () { + if (!this._deferred) { + this._deferred = PromiseUtils.defer(); + this._create(); + } + + return this._deferred.promise; + }, + + destroy: function () { + clearTimeout(this._retryTimerId); + + if (this._frame) { + if (!Cu.isDeadWrapper(this._frame)) { + this._frame.removeEventListener("load", this, true); + this._frame.remove(); + } + + this._frame = null; + this._deferred = null; + } + }, + + handleEvent: function () { + let contentWindow = this._frame.contentWindow; + if (contentWindow.location.href === XUL_PAGE) { + this._frame.removeEventListener("load", this, true); + this._deferred.resolve(contentWindow); + } else { + contentWindow.location = XUL_PAGE; + } + }, + + _create: function () { + if (this.isReady) { + let doc = this.hiddenDOMDocument; + this._frame = doc.createElementNS(HTML_NS, "iframe"); + this._frame.addEventListener("load", this, true); + doc.documentElement.appendChild(this._frame); + } else { + // Check again if |hiddenDOMDocument| is ready as soon as possible. + this._retryTimerId = setTimeout(this._create.bind(this), 0); + } + } +}; |