gecko-dev/devtools/bootstrap.js

213 lines
7.5 KiB
JavaScript

/* 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 Cu = Components.utils;
const Ci = Components.interfaces;
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
function actionOccurred(id) {
let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
let Telemetry = require("devtools/client/shared/telemetry");;
let telemetry = new Telemetry();
telemetry.actionOccurred(id);
}
// Helper to listen to a key on all windows
function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
let keyListener = function (event) {
if (event.ctrlKey == !!ctrlKey &&
event.altKey == !!altKey &&
event.keyCode === keyCode) {
callback(event);
// Call preventDefault to avoid duplicated events when
// doing the key stroke within a tab.
event.preventDefault();
}
};
let observer = function (window, topic, data) {
// Listen on keyup to call keyListener only once per stroke
if (topic === "domwindowopened") {
window.addEventListener("keyup", keyListener);
} else {
window.removeEventListener("keyup", keyListener);
}
};
return {
start: function () {
// Automatically process already opened windows
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
observer(window, "domwindowopened", null);
}
// And listen for new ones to come
Services.ww.registerNotification(observer);
},
stop: function () {
Services.ww.unregisterNotification(observer);
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
observer(window, "domwindowclosed", null);
}
}
};
};
let getTopLevelWindow = function (window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
};
function reload(event) {
// We automatically reload the toolbox if we are on a browser tab
// with a toolbox already opened
let top = getTopLevelWindow(event.view)
let isBrowser = top.location.href.includes("/browser.xul") && top.gDevToolsBrowser;
let reloadToolbox = false;
if (isBrowser && top.gDevToolsBrowser.hasToolboxOpened) {
reloadToolbox = top.gDevToolsBrowser.hasToolboxOpened(top);
}
dump("Reload DevTools. (reload-toolbox:"+reloadToolbox+")\n");
// Invalidate xul cache in order to see changes made to chrome:// files
Services.obs.notifyObservers(null, "startupcache-invalidate", null);
// Ask the loader to update itself and reopen the toolbox if needed
const {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
devtools.reload();
// Go over all top level windows to reload all devtools related things
let windowsEnum = Services.wm.getEnumerator(null);
while (windowsEnum.hasMoreElements()) {
let window = windowsEnum.getNext();
let windowtype = window.document.documentElement.getAttribute("windowtype");
if (windowtype == "navigator:browser" && window.gBrowser) {
// Enumerate tabs on firefox windows
for (let tab of window.gBrowser.tabs) {
let browser = tab.linkedBrowser;
let location = browser.documentURI.spec;
let mm = browser.messageManager;
// To reload JSON-View tabs and any devtools document
if (location.startsWith("about:debugging") ||
location.startsWith("chrome://devtools/")) {
browser.reload();
}
// We have to use a frame script to query "baseURI"
mm.loadFrameScript("data:text/javascript,new " + function () {
let isJSONView = content.document.baseURI.startsWith("resource://devtools/");
if (isJSONView) {
content.location.reload();
}
}, false);
}
// Manually reload gcli if it has been used
// Bug 1248348: Inject the developer toolbar dynamically within browser/
// so that we can easily remove/reinject it
const desc = Object.getOwnPropertyDescriptor(window, "DeveloperToolbar");
if (desc && !desc.get) {
let wasVisible = window.DeveloperToolbar.visible;
window.DeveloperToolbar.hide()
.then(() => {
window.DeveloperToolbar.destroy();
let { DeveloperToolbar } = devtools.require("devtools/client/shared/developer-toolbar");
window.DeveloperToolbar = new DeveloperToolbar(window, window.document.getElementById("developer-toolbar"));
if (wasVisible) {
window.DeveloperToolbar.show();
}
});
}
} else if (windowtype === "devtools:webide") {
window.location.reload();
} else if (windowtype === "devtools:webconsole") {
// Browser console document can't just be reloaded.
// HUDService is going to close it on unload.
// Instead we have to manually toggle it.
let HUDService = devtools.require("devtools/client/webconsole/hudservice");
HUDService.toggleBrowserConsole()
.then(() => {
HUDService.toggleBrowserConsole();
});
}
}
if (reloadToolbox) {
// Reopen the toolbox automatically if we are reloading from toolbox shortcut
// and are on a browser window.
// Wait for a second before opening the toolbox to avoid races
// between the old and the new one.
let {setTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
setTimeout(() => {
let { TargetFactory } = devtools.require("devtools/client/framework/target");
let { gDevTools } = devtools.require("devtools/client/framework/devtools");
let target = TargetFactory.forTab(top.gBrowser.selectedTab);
gDevTools.showToolbox(target);
}, 1000);
}
actionOccurred("reloadAddonReload");
}
let prefs = {
// Enable dump as some errors are only printed on the stdout
"browser.dom.window.dump.enabled": true,
// Enable the browser toolbox and various chrome-only features
"devtools.chrome.enabled": true,
"devtools.debugger.remote-enabled": true,
// Disable the prompt to ease usage of the browser toolbox
"devtools.debugger.prompt-connection": false,
};
let originalPrefValues = {};
let listener;
function startup() {
dump("DevTools addon started.\n");
listener = new MultiWindowKeyListener({
keyCode: Ci.nsIDOMKeyEvent.DOM_VK_R, ctrlKey: true, altKey: true,
callback: reload
});
listener.start();
// Toggle development prefs and save original values
originalPrefValues = {};
for (let name in prefs) {
let value = prefs[name];
let userValue = Services.prefs.getBoolPref(name);
// Only toggle if the pref isn't already set to the right value
if (userValue != value) {
Services.prefs.setBoolPref(name, value);
originalPrefValues[name] = userValue;
}
}
}
function shutdown() {
listener.stop();
listener = null;
// Restore preferences that used to be before the addon was installed
for (let name in originalPrefValues) {
let userValue = Services.prefs.getBoolPref(name);
// Only reset the pref if it hasn't changed
if (userValue == prefs[name]) {
Services.prefs.setBoolPref(name, originalPrefValues[name]);
}
}
}
function install() {
actionOccurred("reloadAddonInstalled");
}
function uninstall() {}