browser-console-manager.js (4796B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 CommandsFactory, 9 } = require("resource://devtools/shared/commands/commands-factory.js"); 10 11 loader.lazyRequireGetter( 12 this, 13 "Tools", 14 "resource://devtools/client/definitions.js", 15 true 16 ); 17 loader.lazyRequireGetter( 18 this, 19 "l10n", 20 "resource://devtools/client/webconsole/utils/l10n.js" 21 ); 22 loader.lazyRequireGetter( 23 this, 24 "BrowserConsole", 25 "resource://devtools/client/webconsole/browser-console.js" 26 ); 27 28 const BC_WINDOW_FEATURES = 29 "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no"; 30 31 class BrowserConsoleManager { 32 #browserConsole = null; 33 #browserConsoleInitializing = null; 34 #browserConsoleSessionState = false; 35 36 storeBrowserConsoleSessionState() { 37 this.#browserConsoleSessionState = !!this.getBrowserConsole(); 38 } 39 40 getBrowserConsoleSessionState() { 41 return this.#browserConsoleSessionState; 42 } 43 44 /** 45 * Open a Browser Console for the current commands context. 46 * 47 * @param nsIDOMWindow iframeWindow 48 * The window where the browser console UI is already loaded. 49 * @return object 50 * A promise object for the opening of the new BrowserConsole instance. 51 */ 52 async openBrowserConsole(win) { 53 const hud = new BrowserConsole(this.commands, win, win); 54 this.#browserConsole = hud; 55 await hud.init(); 56 return hud; 57 } 58 59 /** 60 * Close the opened Browser Console 61 */ 62 async closeBrowserConsole() { 63 if (!this.#browserConsole) { 64 return; 65 } 66 67 // Ensure destroying the commands, 68 // even if the console throws during cleanup. 69 try { 70 await this.#browserConsole.destroy(); 71 } catch (e) { 72 console.error(e); 73 } 74 this.#browserConsole = null; 75 76 await this.commands.destroy(); 77 this.commands = null; 78 } 79 80 /** 81 * Toggle the Browser Console. 82 */ 83 async toggleBrowserConsole() { 84 if (this.#browserConsole) { 85 return this.closeBrowserConsole(); 86 } 87 88 if (this.#browserConsoleInitializing) { 89 return this.#browserConsoleInitializing; 90 } 91 92 // Temporarily cache the async startup sequence so that if toggleBrowserConsole 93 // gets called again we can return this console instead of opening another one. 94 this.#browserConsoleInitializing = (async () => { 95 this.commands = await CommandsFactory.forBrowserConsole(); 96 const win = await this.openWindow(); 97 const browserConsole = await this.openBrowserConsole(win); 98 return browserConsole; 99 })(); 100 101 try { 102 const browserConsole = await this.#browserConsoleInitializing; 103 this.#browserConsoleInitializing = null; 104 return browserConsole; 105 } catch (e) { 106 // Ensure always clearing this field, even in case of exception, 107 // which may happen when closing during initialization. 108 this.#browserConsoleInitializing = null; 109 throw e; 110 } 111 } 112 113 async openWindow() { 114 const win = Services.ww.openWindow( 115 null, 116 Tools.webConsole.url, 117 "_blank", 118 BC_WINDOW_FEATURES, 119 null 120 ); 121 122 await new Promise(resolve => { 123 win.addEventListener("DOMContentLoaded", resolve, { once: true }); 124 }); 125 126 // It's important to declare the unload *after* the initial "DOMContentLoaded", 127 // otherwise, since the window is navigated to Tools.webConsole.url, an unload event 128 // is fired. 129 win.addEventListener("unload", this.closeBrowserConsole.bind(this), { 130 once: true, 131 }); 132 133 this.updateWindowTitle(win); 134 return win; 135 } 136 137 /** 138 * Opens or focuses the Browser Console. 139 */ 140 openBrowserConsoleOrFocus() { 141 const hud = this.getBrowserConsole(); 142 if (hud) { 143 hud.iframeWindow.focus(); 144 return Promise.resolve(hud); 145 } 146 147 return this.toggleBrowserConsole(); 148 } 149 150 /** 151 * Get the Browser Console instance, if open. 152 * 153 * @return object|null 154 * A BrowserConsole instance or null if the Browser Console is not 155 * open. 156 */ 157 getBrowserConsole() { 158 return this.#browserConsole; 159 } 160 161 /** 162 * Set the title of the Browser Console window. 163 * 164 * @param {Window} win: The BrowserConsole window 165 */ 166 updateWindowTitle(win) { 167 let title; 168 const mode = Services.prefs.getCharPref( 169 "devtools.browsertoolbox.scope", 170 null 171 ); 172 if (mode == "everything") { 173 title = l10n.getStr("multiProcessBrowserConsole.title"); 174 } else if (mode == "parent-process") { 175 title = l10n.getStr("parentProcessBrowserConsole.title"); 176 } else { 177 throw new Error("Unsupported mode: " + mode); 178 } 179 180 win.document.title = title; 181 } 182 } 183 184 exports.BrowserConsoleManager = new BrowserConsoleManager();