Commit fe6cfda8 authored by David Walsh's avatar David Walsh
Browse files

Bug 1630957 - Provide settings menu for debugger UI to allow disabling JavaScript r=jlast,Honza

Differential Revision: https://phabricator.services.mozilla.com/D71365
parent f7455400
......@@ -16,6 +16,7 @@ module.exports = {
"./packages/*/src",
/[/\\]node_modules[/\\]devtools-/,
/[/\\]node_modules[/\\]react-aria-components[/\\]/,
"../../shared",
],
presets: [
"@babel/preset-react",
......
......@@ -41,6 +41,8 @@ module.exports = {
"\\.css$": "<rootDir>/src/test/__mocks__/styleMock.js",
"\\.svg$": "<rootDir>/src/test/__mocks__/svgMock.js",
"^Services": "<rootDir>/src/test/fixtures/Services",
"^chrome": "<rootDir>/src/test/fixtures/Chrome",
"^ChromeUtils": "<rootDir>/src/test/fixtures/ChromeUtils",
// Map all require("devtools/...") to the real devtools root.
"^devtools\\/(.*)": "<rootDir>/../../$1",
},
......
......@@ -431,4 +431,5 @@ export type Panel = {|
highlightDomElement: (grip: Object) => void,
unHighlightDomElement: (grip: Object) => void,
getToolboxStore: () => any,
panelWin: Object,
|};
......@@ -58,7 +58,9 @@ import EditorFooter from "./Editor/Footer";
import QuickOpenModal from "./QuickOpenModal";
import WhyPaused from "./SecondaryPanes/WhyPaused";
type OwnProps = {||};
type OwnProps = {|
toolboxDoc: Object,
|};
type Props = {
selectedSource: ?Source,
orientation: OrientationType,
......@@ -66,6 +68,7 @@ type Props = {
endPanelCollapsed: boolean,
activeSearch: ?ActiveSearchType,
quickOpenEnabled: boolean,
toolboxDoc: Object,
setActiveSearch: typeof actions.setActiveSearch,
closeActiveSearch: typeof actions.closeActiveSearch,
closeProjectSearch: typeof actions.closeProjectSearch,
......@@ -98,9 +101,13 @@ class App extends Component<Props, State> {
};
}
getChildContext = () => {
return { shortcuts, l10n: L10N };
};
getChildContext() {
return {
toolboxDoc: this.props.toolboxDoc,
shortcuts,
l10n: L10N,
};
}
componentDidMount() {
horizontalLayoutBreakpoint.addListener(this.onLayoutChange);
......@@ -331,6 +338,7 @@ class App extends Component<Props, State> {
}
App.childContextTypes = {
toolboxDoc: PropTypes.object,
shortcuts: PropTypes.object,
l10n: PropTypes.object,
};
......
......@@ -9,7 +9,7 @@ import React, { Component } from "react";
import { connect } from "../../utils/connect";
import classnames from "classnames";
import { features } from "../../utils/prefs";
import { features, javascriptPrefs } from "../../utils/prefs";
import {
getIsWaitingOnBreak,
getSkipPausing,
......@@ -26,6 +26,13 @@ import "./CommandBar.css";
import { appinfo } from "devtools-services";
import type { ThreadContext } from "../../types";
// $FlowIgnore
const MenuButton = require("devtools/client/shared/components/menu/MenuButton");
// $FlowIgnore
const MenuItem = require("devtools/client/shared/components/menu/MenuItem");
// $FlowIgnore
const MenuList = require("devtools/client/shared/components/menu/MenuList");
const isMacOS = appinfo.OS === "Darwin";
// NOTE: the "resume" command will call either the resume or breakOnNext action
......@@ -228,6 +235,38 @@ class CommandBar extends Component<Props> {
);
}
renderSettingsButton() {
const { toolboxDoc } = this.context;
return (
<MenuButton
menuId="debugger-settings-menu-button"
toolboxDoc={toolboxDoc}
className="devtools-button command-bar-button debugger-settings-menu-button"
title={L10N.getStr("settings.button.label")}
>
{() => this.renderSettingsMenuItems()}
</MenuButton>
);
}
renderSettingsMenuItems() {
return (
<MenuList id="debugger-settings-menu-list">
<MenuItem
key="debugger-settings-menu-item-disable-javascript"
className="menu-item debugger-settings-menu-item-disable-javascript"
checked={!javascriptPrefs.enableJavaScript}
label={L10N.getStr("settings.disableJavaScript.label")}
tooltip={L10N.getStr("settings.disableJavaScript.tooltip")}
onClick={() => {
javascriptPrefs.enableJavaScript = !javascriptPrefs.enableJavaScript;
}}
/>
</MenuList>
);
}
render() {
return (
<div
......@@ -238,6 +277,7 @@ class CommandBar extends Component<Props> {
{this.renderStepButtons()}
<div className="filler" />
{this.renderSkipPausingButton()}
{this.renderSettingsButton()}
</div>
);
}
......@@ -245,6 +285,7 @@ class CommandBar extends Component<Props> {
CommandBar.contextTypes = {
shortcuts: PropTypes.object,
toolboxDoc: PropTypes.object,
};
const mapStateToProps = state => ({
......
......@@ -19,11 +19,13 @@
cursor: default;
}
.command-bar-button:not(.disabled):hover {
.command-bar-button:not(.disabled):hover,
.devtools-button.debugger-settings-menu-button:empty:not(:disabled):not([aria-expanded="true"]):hover {
background: var(--theme-toolbar-background-hover);
}
.theme-dark .command-bar-button:not(.disabled):hover {
.theme-dark .command-bar-button:not(.disabled):hover,
.devtools-button.debugger-settings-menu-button:empty:not(:disabled):not([aria-expanded="true"]):hover {
background: var(--theme-toolbar-hover);
}
......@@ -37,3 +39,15 @@
display: inline-block;
vertical-align: middle;
}
/**
* Settings icon and menu
*/
.devtools-button.debugger-settings-menu-button {
border-radius: 0;
margin: 0;
}
.devtools-button.debugger-settings-menu-button::before {
background-image: url("chrome://devtools/skin/images/settings.svg");
}
......@@ -33,5 +33,6 @@ bootstrap(React, ReactDOM).then(connection => {
getToolboxStore: () => {
throw new Error("Cannot connect to Toolbox store when running Launchpad");
},
panelWin: window,
});
});
/* 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";
module.exports = {
Cu: {},
components: {},
};
/* 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";
module.exports = {};
......@@ -6,4 +6,6 @@
module.exports = {
appinfo: "",
prefs: { getBoolPref: () => {}, addObserver: () => {} },
obs: { addObserver: () => {} },
};
......@@ -8,7 +8,6 @@
global.Worker = require("workerjs");
import path from "path";
// import getConfig from "../../bin/getConfig";
import { readFileSync } from "fs";
import Enzyme from "enzyme";
// $FlowIgnore
......@@ -51,6 +50,43 @@ global.L10N = require("devtools-launchpad").L10N;
global.L10N.setBundle(getL10nBundle());
global.jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
global.performance = { now: () => 0 };
global.isWorker = false;
global.define = function() {};
global.loader = {
lazyServiceGetter: () => {},
lazyGetter: (context, name, fn) => {
try {
global[name] = fn();
} catch (_) {}
},
lazyRequireGetter: (context, name, _path, destruct) => {
if (
!_path ||
_path.startsWith("resource://") ||
_path.match(/server\/actors/)
) {
return;
}
const excluded = [
"Debugger",
"devtools/shared/event-emitter",
"devtools/client/shared/autocomplete-popup",
"devtools/client/framework/devtools",
"devtools/client/shared/keycodes",
"devtools/client/shared/sourceeditor/editor",
"devtools/client/shared/telemetry",
"devtools/shared/screenshot/save",
"devtools/client/shared/focus",
];
if (!excluded.includes(_path)) {
// $FlowIgnore
const module = require(_path);
global[name] = destruct ? module[name] : module;
}
},
};
const { URL } = require("url");
global.URL = URL;
......
......@@ -42,6 +42,8 @@ function renderPanel(component, store, panel: Panel) {
}
mount.appendChild(root);
const toolboxDoc = panel.panelWin.parent.document;
ReactDOM.render(
React.createElement(
Provider,
......@@ -49,7 +51,7 @@ function renderPanel(component, store, panel: Panel) {
React.createElement(
ToolboxProvider,
{ store: panel.getToolboxStore() },
React.createElement(component)
React.createElement(component, { toolboxDoc })
)
),
root
......
......@@ -77,6 +77,7 @@ if (isDevelopment()) {
pref("devtools.debugger.features.watchpoints", true);
pref("devtools.debugger.features.frame-step", true);
pref("devtools.editor.tabsize", 2);
pref("javascript.enabled", true);
}
export const prefs = new PrefsHelper("devtools", {
......@@ -121,6 +122,10 @@ export const prefs = new PrefsHelper("devtools", {
indentSize: ["Int", "editor.tabsize"],
});
export const javascriptPrefs = new PrefsHelper("javascript", {
enableJavaScript: ["Bool", "enabled"],
});
// The pref may not be defined. Defaulting to null isn't viable (cursor never blinks).
// Can't use CodeMirror.defaults here because it's loaded later.
// Hardcode the fallback value to that of CodeMirror.defaults.cursorBlinkRate.
......
......@@ -204,3 +204,4 @@ skip-if = asan || !nightly_build # Bug 1591064, parent intercept mode is needed
[browser_dbg-wrong-fetch.js]
[browser_dbg-worker-nested.js]
[browser_dbg-step-in-navigate.js]
[browser_dbg-settings-disable-javascript.js]
/* 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/>. */
requestLongerTimeout(2);
async function toggleJavaScript(dbg, shouldBeCheckedAtStart) {
const menuItemClassName = ".debugger-settings-menu-item-disable-javascript";
const menuButton = findElementWithSelector(dbg, ".debugger-settings-menu-button");
menuButton.click();
await waitForTime(200);
// Wait for the menu to show before trying to click the item
const { parent } = dbg.panel.panelWin;
const { document } = parent;
const menuItem = document.querySelector(menuItemClassName);
is(
!!menuItem.getAttribute("aria-checked"),
shouldBeCheckedAtStart,
"Item is checked before clicking"
);
menuItem.click();
}
// Tests that using the Settings menu to enable and disable JavaScript
// updates the pref properly
add_task(async function() {
const dbg = await initDebugger("doc-scripts.html", "simple1.js");
info("Waiting for source to load");
await waitForSource(dbg, "simple1.js");
info("Clicking the disable javascript button in the settings menu");
await toggleJavaScript(dbg, false);
is(Services.prefs.getBoolPref("javascript.enabled"), false, "JavaScript is disabled");
info("Reloading page to ensure there are no sources");
await reload(dbg);
await waitForSourceCount(dbg, 0);
info("Clicking the disable javascript button in the settings menu to reenable JavaScript");
await toggleJavaScript(dbg, true);
is(Services.prefs.getBoolPref("javascript.enabled"), true, "JavaScript is enabled");
info("Reloading page to ensure there are sources");
await reload(dbg);
await waitForSource(dbg, "simple1.js");
});
......@@ -3,7 +3,7 @@
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
// Tests for preview through Babel's compile output.
requestLongerTimeout(3);
requestLongerTimeout(5);
// Test pausing with mapScopes enabled and disabled
add_task(async function() {
......
......@@ -585,7 +585,9 @@ async function clearDebuggerPreferences(prefs = []) {
Services.prefs.clearUserPref("devtools.debugger.scopes-visible");
Services.prefs.clearUserPref("devtools.debugger.skip-pausing");
Services.prefs.clearUserPref("devtools.debugger.map-scopes-enabled");
Services.prefs.clearUserPref("javascript.enabled");
await pushPref("devtools.debugger.log-actions", true);
for (const pref of prefs) {
await pushPref(...pref);
}
......
......@@ -40,6 +40,9 @@ add_task(async function() {
"resource://devtools/client/shared/vendor/redux.js",
"resource://devtools/client/debugger/src/workers/parser/index.js",
"resource://devtools/client/shared/source-map/index.js",
"resource://devtools/client/shared/components/menu/MenuButton.js",
"resource://devtools/client/shared/components/menu/MenuItem.js",
"resource://devtools/client/shared/components/menu/MenuList.js",
];
runDuplicatedModulesTest(loaders, whitelist);
......
......@@ -479,6 +479,17 @@ inlinePreview.show.label=Show inline preview
# for hiding the inline preview block
inlinePreview.hide.label=Hide inline preview
# LOCALIZATION NOTE (settings.button.label): Label for Settings button
settings.button.label=Debugger Settings
# LOCALIZATION NOTE (settings.disableJavaScript.label): Context menu item
# label for disabling JavaScript
settings.disableJavaScript.label=Disable JavaScript
# LOCALIZATION NOTE (settings.disableJavaScript.tooltip): Context menu item
# tooltip for disabling JavaScript
settings.disableJavaScript.tooltip=Disables JavaScript (Requires refresh)
# LOCALIZATION NOTE (preview.noProperties): Label shown in the preview
# popup when there are no properties to show.
preview.noProperties=No properties
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment