webext-panels.js (6355B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 // Via webext-panels.xhtml 7 /* import-globals-from browser.js */ 8 /* global windowRoot */ 9 10 ChromeUtils.defineESModuleGetters(this, { 11 ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs", 12 }); 13 14 const { ExtensionUtils } = ChromeUtils.importESModule( 15 "resource://gre/modules/ExtensionUtils.sys.mjs" 16 ); 17 18 var { promiseEvent } = ExtensionUtils; 19 20 function getBrowser(panel) { 21 let browser = document.getElementById("webext-panels-browser"); 22 if (browser) { 23 return Promise.resolve(browser); 24 } 25 26 if (panel.viewType === "sidebar" && gSidebarRevampEnabled) { 27 if (!customElements.get("sidebar-panel-header")) { 28 ChromeUtils.importESModule( 29 "chrome://browser/content/sidebar/sidebar-panel-header.mjs", 30 { global: "current" } 31 ); 32 } 33 const heading = 34 panel.extension.manifest.sidebar_action.default_title ?? 35 panel.extension.name; 36 document.getElementById("sidebar-panel-header").heading = heading; 37 } 38 39 let stack = document.getElementById("webext-panels-stack"); 40 if (!stack) { 41 stack = document.createXULElement("stack"); 42 stack.setAttribute("flex", "1"); 43 stack.setAttribute("id", "webext-panels-stack"); 44 document.documentElement.appendChild(stack); 45 } 46 47 browser = document.createXULElement("browser"); 48 browser.setAttribute("id", "webext-panels-browser"); 49 browser.setAttribute("type", "content"); 50 browser.setAttribute("flex", "1"); 51 browser.setAttribute("disableglobalhistory", "true"); 52 browser.setAttribute("messagemanagergroup", "webext-browsers"); 53 browser.setAttribute("webextension-view-type", panel.viewType); 54 browser.setAttribute("context", "contentAreaContextMenu"); 55 browser.setAttribute("tooltip", "aHTMLTooltip"); 56 browser.setAttribute("autocompletepopup", "PopupAutoComplete"); 57 58 if (gAllowTransparentBrowser) { 59 browser.setAttribute("transparent", "true"); 60 } 61 62 // Ensure that the browser is going to run in the same bc group as the other 63 // extension pages from the same addon. 64 browser.setAttribute( 65 "initialBrowsingContextGroupId", 66 panel.extension.policy.browsingContextGroupId 67 ); 68 69 let readyPromise; 70 if (panel.extension.remote) { 71 browser.setAttribute("remote", "true"); 72 let oa = E10SUtils.predictOriginAttributes({ browser }); 73 browser.setAttribute( 74 "remoteType", 75 E10SUtils.getRemoteTypeForURI( 76 panel.uri, 77 /* remote */ true, 78 /* fission */ false, 79 E10SUtils.EXTENSION_REMOTE_TYPE, 80 null, 81 oa 82 ) 83 ); 84 browser.setAttribute("maychangeremoteness", "true"); 85 86 readyPromise = promiseEvent(browser, "XULFrameLoaderCreated"); 87 } else { 88 readyPromise = Promise.resolve(); 89 } 90 91 stack.appendChild(browser); 92 93 browser.addEventListener( 94 "DoZoomEnlargeBy10", 95 () => { 96 let { ZoomManager } = browser.ownerGlobal; 97 let zoom = browser.fullZoom; 98 zoom += 0.1; 99 if (zoom > ZoomManager.MAX) { 100 zoom = ZoomManager.MAX; 101 } 102 browser.fullZoom = zoom; 103 }, 104 true 105 ); 106 browser.addEventListener( 107 "DoZoomReduceBy10", 108 () => { 109 let { ZoomManager } = browser.ownerGlobal; 110 let zoom = browser.fullZoom; 111 zoom -= 0.1; 112 if (zoom < ZoomManager.MIN) { 113 zoom = ZoomManager.MIN; 114 } 115 browser.fullZoom = zoom; 116 }, 117 true 118 ); 119 browser.addEventListener("DOMWindowClose", event => { 120 if (panel.viewType == "sidebar") { 121 windowRoot.ownerGlobal.SidebarController.hide(); 122 } 123 // Prevent DOMWindowClose events originated from 124 // extensions sidebar and devtools panels to bubble up 125 // to the gBrowser DOMWindowClose listener and 126 // be mistaken as being originated from a tab being closed 127 // (See Bug 1926373) 128 event.stopPropagation(); 129 }); 130 131 const initBrowser = () => { 132 ExtensionParent.apiManager.emit( 133 "extension-browser-inserted", 134 browser, 135 panel.browserInsertedData 136 ); 137 138 browser.messageManager.loadFrameScript( 139 "chrome://extensions/content/ext-browser-content.js", 140 false, 141 true 142 ); 143 144 let options = {}; 145 if (panel.browserStyle) { 146 options.stylesheets = ["chrome://browser/content/extension.css"]; 147 } 148 browser.messageManager.sendAsyncMessage("Extension:InitBrowser", options); 149 return browser; 150 }; 151 152 browser.addEventListener("DidChangeBrowserRemoteness", initBrowser); 153 return readyPromise.then(initBrowser); 154 } 155 156 // Stub tabbrowser implementation to make sure that links from inside 157 // extension sidebar panels open in new tabs, see bug 1488055. 158 var gBrowser = { 159 get selectedBrowser() { 160 return document.getElementById("webext-panels-browser"); 161 }, 162 163 getTabForBrowser() { 164 return null; 165 }, 166 }; 167 168 function updatePosition() { 169 // We need both of these to make sure we update the position 170 // after any lower level updates have finished. 171 requestAnimationFrame(() => 172 setTimeout(() => { 173 let browser = document.getElementById("webext-panels-browser"); 174 if (browser && browser.isRemoteBrowser) { 175 browser.frameLoader.requestUpdatePosition(); 176 } 177 }, 0) 178 ); 179 } 180 181 function loadPanel(extensionId, extensionUrl, browserStyle) { 182 let browserEl = document.getElementById("webext-panels-browser"); 183 if (browserEl) { 184 if (browserEl.currentURI.spec === extensionUrl) { 185 return; 186 } 187 // Forces runtime disconnect. Remove the stack (parent). 188 browserEl.parentNode.remove(); 189 } 190 191 let policy = WebExtensionPolicy.getByID(extensionId); 192 193 let sidebar = { 194 uri: extensionUrl, 195 extension: policy.extension, 196 browserStyle, 197 viewType: "sidebar", 198 }; 199 200 getBrowser(sidebar).then(browser => { 201 let uri = Services.io.newURI(policy.getURL()); 202 let triggeringPrincipal = 203 Services.scriptSecurityManager.createContentPrincipal(uri, {}); 204 browser.fixupAndLoadURIString(extensionUrl, { triggeringPrincipal }); 205 }); 206 } 207 208 XPCOMUtils.defineLazyPreferenceGetter( 209 this, 210 "gAllowTransparentBrowser", 211 "browser.tabs.allow_transparent_browser", 212 false 213 ); 214 215 XPCOMUtils.defineLazyPreferenceGetter( 216 this, 217 "gSidebarRevampEnabled", 218 "sidebar.revamp", 219 false 220 );