summaryrefslogtreecommitdiffstats
path: root/browser/base/content/webext-panels.js
blob: 787193ab7d26fe4cef49f8f1df9f41ee0447ece5 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/* 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/. */

// Via webext-panels.xhtml
/* import-globals-from browser.js */
/* import-globals-from nsContextMenu.js */

ChromeUtils.defineESModuleGetters(this, {
  ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs",
});

const { ExtensionUtils } = ChromeUtils.importESModule(
  "resource://gre/modules/ExtensionUtils.sys.mjs"
);

var { promiseEvent } = ExtensionUtils;

function getBrowser(panel) {
  let browser = document.getElementById("webext-panels-browser");
  if (browser) {
    return Promise.resolve(browser);
  }

  let stack = document.getElementById("webext-panels-stack");
  if (!stack) {
    stack = document.createXULElement("stack");
    stack.setAttribute("flex", "1");
    stack.setAttribute("id", "webext-panels-stack");
    document.documentElement.appendChild(stack);
  }

  browser = document.createXULElement("browser");
  browser.setAttribute("id", "webext-panels-browser");
  browser.setAttribute("type", "content");
  browser.setAttribute("flex", "1");
  browser.setAttribute("disableglobalhistory", "true");
  browser.setAttribute("messagemanagergroup", "webext-browsers");
  browser.setAttribute("webextension-view-type", panel.viewType);
  browser.setAttribute("context", "contentAreaContextMenu");
  browser.setAttribute("tooltip", "aHTMLTooltip");
  browser.setAttribute("autocompletepopup", "PopupAutoComplete");

  // Ensure that the browser is going to run in the same bc group as the other
  // extension pages from the same addon.
  browser.setAttribute(
    "initialBrowsingContextGroupId",
    panel.extension.policy.browsingContextGroupId
  );

  let readyPromise;
  if (panel.extension.remote) {
    browser.setAttribute("remote", "true");
    let oa = E10SUtils.predictOriginAttributes({ browser });
    browser.setAttribute(
      "remoteType",
      E10SUtils.getRemoteTypeForURI(
        panel.uri,
        /* remote */ true,
        /* fission */ false,
        E10SUtils.EXTENSION_REMOTE_TYPE,
        null,
        oa
      )
    );
    browser.setAttribute("maychangeremoteness", "true");

    readyPromise = promiseEvent(browser, "XULFrameLoaderCreated");
  } else {
    readyPromise = Promise.resolve();
  }

  stack.appendChild(browser);

  browser.addEventListener(
    "DoZoomEnlargeBy10",
    () => {
      let { ZoomManager } = browser.ownerGlobal;
      let zoom = browser.fullZoom;
      zoom += 0.1;
      if (zoom > ZoomManager.MAX) {
        zoom = ZoomManager.MAX;
      }
      browser.fullZoom = zoom;
    },
    true
  );
  browser.addEventListener(
    "DoZoomReduceBy10",
    () => {
      let { ZoomManager } = browser.ownerGlobal;
      let zoom = browser.fullZoom;
      zoom -= 0.1;
      if (zoom < ZoomManager.MIN) {
        zoom = ZoomManager.MIN;
      }
      browser.fullZoom = zoom;
    },
    true
  );

  const initBrowser = () => {
    ExtensionParent.apiManager.emit(
      "extension-browser-inserted",
      browser,
      panel.browserInsertedData
    );

    browser.messageManager.loadFrameScript(
      "chrome://extensions/content/ext-browser-content.js",
      false,
      true
    );

    let options = {};
    if (panel.browserStyle) {
      options.stylesheets = ["chrome://browser/content/extension.css"];
    }
    browser.messageManager.sendAsyncMessage("Extension:InitBrowser", options);
    return browser;
  };

  browser.addEventListener("DidChangeBrowserRemoteness", initBrowser);
  return readyPromise.then(initBrowser);
}

// Stub tabbrowser implementation to make sure that links from inside
// extension sidebar panels open in new tabs, see bug 1488055.
var gBrowser = {
  get selectedBrowser() {
    return document.getElementById("webext-panels-browser");
  },

  getTabForBrowser() {
    return null;
  },
};

function updatePosition() {
  // We need both of these to make sure we update the position
  // after any lower level updates have finished.
  requestAnimationFrame(() =>
    setTimeout(() => {
      let browser = document.getElementById("webext-panels-browser");
      if (browser && browser.isRemoteBrowser) {
        browser.frameLoader.requestUpdatePosition();
      }
    }, 0)
  );
}

function loadPanel(extensionId, extensionUrl, browserStyle) {
  let browserEl = document.getElementById("webext-panels-browser");
  if (browserEl) {
    if (browserEl.currentURI.spec === extensionUrl) {
      return;
    }
    // Forces runtime disconnect.  Remove the stack (parent).
    browserEl.parentNode.remove();
  }

  let policy = WebExtensionPolicy.getByID(extensionId);

  let sidebar = {
    uri: extensionUrl,
    extension: policy.extension,
    browserStyle,
    viewType: "sidebar",
  };

  getBrowser(sidebar).then(browser => {
    let uri = Services.io.newURI(policy.getURL());
    let triggeringPrincipal =
      Services.scriptSecurityManager.createContentPrincipal(uri, {});
    browser.fixupAndLoadURIString(extensionUrl, { triggeringPrincipal });
  });
}