/* 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"; const EXPORTED_SYMBOLS = ["WebNavigationFrames"]; var Ci = Components.interfaces; /* exported WebNavigationFrames */ /** * Retrieve the DOMWindow associated to the docShell passed as parameter. * * @param {nsIDocShell} docShell - the docShell that we want to get the DOMWindow from. * @returns {nsIDOMWindow} - the DOMWindow associated to the docShell. */ function docShellToWindow(docShell) { return docShell.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindow); } /** * The FrameDetail object which represents a frame in WebExtensions APIs. * * @typedef {Object} FrameDetail * @inner * @property {number} frameId - Represents the numeric id which identify the frame in its tab. * @property {number} parentFrameId - Represents the numeric id which identify the parent frame. * @property {string} url - Represents the current location URL loaded in the frame. * @property {boolean} errorOccurred - Indicates whether an error is occurred during the last load * happened on this frame (NOT YET SUPPORTED). */ /** * A generator function which iterates over a docShell tree, given a root docShell. * * @param {nsIDocShell} docShell - the root docShell object */ function* iterateDocShellTree(docShell) { let docShellsEnum = docShell.getDocShellEnumerator( docShell.typeContent, docShell.ENUMERATE_FORWARDS); while (docShellsEnum.hasMoreElements()) { yield docShellsEnum.getNext(); } } /** * Returns the frame ID of the given window. If the window is the * top-level content window, its frame ID is 0. Otherwise, its frame ID * is its outer window ID. * * @param {Window} window - The window to retrieve the frame ID for. * @returns {number} */ function getFrameId(window) { if (window.parent === window) { return 0; } let utils = window.getInterface(Ci.nsIDOMWindowUtils); return utils.outerWindowID; } /** * Returns the frame ID of the given window's parent. * * @param {Window} window - The window to retrieve the parent frame ID for. * @returns {number} */ function getParentFrameId(window) { if (window.parent === window) { return -1; } return getFrameId(window.parent); } function getDocShellFrameId(docShell) { if (!docShell) { return undefined; } return getFrameId(docShell.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindow)); } /** * Convert a docShell object into its internal FrameDetail representation. * * @param {nsIDocShell} docShell - the docShell object to be converted into a FrameDetail JSON object. * @returns {FrameDetail} the FrameDetail JSON object which represents the docShell. */ function convertDocShellToFrameDetail(docShell) { let window = docShellToWindow(docShell); return { frameId: getFrameId(window), parentFrameId: getParentFrameId(window), url: window.location.href, }; } /** * Search for a frame starting from the passed root docShell and * convert it to its related frame detail representation. * * @param {number} frameId - the frame ID of the frame to retrieve, as * described in getFrameId. * @param {nsIDocShell} rootDocShell - the root docShell object * @returns {nsIDocShell?} the docShell with the given frameId, or null * if no match. */ function findDocShell(frameId, rootDocShell) { for (let docShell of iterateDocShellTree(rootDocShell)) { if (frameId == getFrameId(docShellToWindow(docShell))) { return docShell; } } return null; } var WebNavigationFrames = { iterateDocShellTree, findDocShell, getFrame(docShell, frameId) { let result = findDocShell(frameId, docShell); if (result) { return convertDocShellToFrameDetail(result); } return null; }, getFrameId, getParentFrameId, getAllFrames(docShell) { return Array.from(iterateDocShellTree(docShell), convertDocShellToFrameDetail); }, getDocShellFrameId, };