summaryrefslogtreecommitdiffstats
path: root/toolkit/modules/addons/WebNavigationFrames.jsm
blob: 5efa6d10488ab4d56b4a748a93c1cafecf64a541 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* 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 */

function getWindowId(window) {
  return window.QueryInterface(Ci.nsIInterfaceRequestor)
               .getInterface(Ci.nsIDOMWindowUtils)
               .outerWindowID;
}

function getParentWindowId(window) {
  return getWindowId(window.parent);
}

/**
 * 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}  windowId       - Represents the numeric id which identify the frame in its tab.
 * @property {number}  parentWindowId - 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).
 */

/**
 * 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 {
    windowId: getWindowId(window),
    parentWindowId: getParentWindowId(window),
    url: window.location.href,
  };
}

/**
 * A generator function which iterates over a docShell tree, given a root docShell.
 *
 * @param   {nsIDocShell} docShell - the root docShell object
 * @returns {Iterator<DocShell>} the FrameDetail JSON object which represents the docShell.
 */
function* iterateDocShellTree(docShell) {
  let docShellsEnum = docShell.getDocShellEnumerator(
    Ci.nsIDocShellTreeItem.typeContent,
    Ci.nsIDocShell.ENUMERATE_FORWARDS
  );

  while (docShellsEnum.hasMoreElements()) {
    yield docShellsEnum.getNext();
  }

  return null;
}

/**
 * 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) {
  let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIDocShell);

  if (!docShell.sameTypeParent) {
    return 0;
  }

  let utils = window.getInterface(Ci.nsIDOMWindowUtils);
  return utils.outerWindowID;
}

/**
 * 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,

  getAllFrames(docShell) {
    return Array.from(iterateDocShellTree(docShell), convertDocShellToFrameDetail);
  },

  getWindowId,
  getParentWindowId,
};