summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/components/App.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /devtools/client/debugger/src/components/App.js
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/debugger/src/components/App.js')
-rw-r--r--devtools/client/debugger/src/components/App.js355
1 files changed, 355 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/components/App.js b/devtools/client/debugger/src/components/App.js
new file mode 100644
index 0000000000..0ca95736aa
--- /dev/null
+++ b/devtools/client/debugger/src/components/App.js
@@ -0,0 +1,355 @@
+/* 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/>. */
+
+// @flow
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+import classnames from "classnames";
+
+import { connect } from "../utils/connect";
+import { prefs, features } from "../utils/prefs";
+import actions from "../actions";
+import A11yIntention from "./A11yIntention";
+import { ShortcutsModal } from "./ShortcutsModal";
+
+import {
+ getSelectedSource,
+ getPaneCollapse,
+ getActiveSearch,
+ getQuickOpenEnabled,
+ getOrientation,
+} from "../selectors";
+
+import type { OrientationType } from "../reducers/types";
+import type { Source } from "../types";
+
+// $FlowIgnore
+const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
+
+import Services from "devtools-services";
+const shortcuts = new KeyShortcuts({ window });
+
+const { appinfo } = Services;
+
+const isMacOS = appinfo.OS === "Darwin";
+
+const horizontalLayoutBreakpoint = window.matchMedia("(min-width: 800px)");
+const verticalLayoutBreakpoint = window.matchMedia(
+ "(min-width: 10px) and (max-width: 799px)"
+);
+
+import "./variables.css";
+import "./App.css";
+
+import type { ActiveSearchType } from "../selectors";
+
+import "./shared/menu.css";
+
+import SplitBox from "devtools-splitter";
+import ProjectSearch from "./ProjectSearch";
+import PrimaryPanes from "./PrimaryPanes";
+import Editor from "./Editor";
+import SecondaryPanes from "./SecondaryPanes";
+import WelcomeBox from "./WelcomeBox";
+import EditorTabs from "./Editor/Tabs";
+import EditorFooter from "./Editor/Footer";
+import QuickOpenModal from "./QuickOpenModal";
+
+type OwnProps = {|
+ toolboxDoc: Object,
+|};
+type Props = {
+ selectedSource: ?Source,
+ orientation: OrientationType,
+ startPanelCollapsed: boolean,
+ endPanelCollapsed: boolean,
+ activeSearch: ?ActiveSearchType,
+ quickOpenEnabled: boolean,
+ toolboxDoc: Object,
+ setActiveSearch: typeof actions.setActiveSearch,
+ closeActiveSearch: typeof actions.closeActiveSearch,
+ closeProjectSearch: typeof actions.closeProjectSearch,
+ openQuickOpen: typeof actions.openQuickOpen,
+ closeQuickOpen: typeof actions.closeQuickOpen,
+ setOrientation: typeof actions.setOrientation,
+};
+
+type State = {
+ shortcutsModalEnabled: boolean,
+ startPanelSize: number,
+ endPanelSize: number,
+};
+
+class App extends Component<Props, State> {
+ onLayoutChange: Function;
+ getChildContext: Function;
+ renderEditorPane: Function;
+ renderLayout: Function;
+ toggleQuickOpenModal: Function;
+ onEscape: Function;
+ onCommandSlash: Function;
+
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ shortcutsModalEnabled: false,
+ startPanelSize: 0,
+ endPanelSize: 0,
+ };
+ }
+
+ getChildContext() {
+ return {
+ toolboxDoc: this.props.toolboxDoc,
+ shortcuts,
+ l10n: L10N,
+ };
+ }
+
+ componentDidMount() {
+ horizontalLayoutBreakpoint.addListener(this.onLayoutChange);
+ verticalLayoutBreakpoint.addListener(this.onLayoutChange);
+ this.setOrientation();
+
+ shortcuts.on(L10N.getStr("symbolSearch.search.key2"), e =>
+ this.toggleQuickOpenModal(e, "@")
+ );
+
+ const searchKeys = [
+ L10N.getStr("sources.search.key2"),
+ L10N.getStr("sources.search.alt.key"),
+ ];
+ searchKeys.forEach(key => shortcuts.on(key, this.toggleQuickOpenModal));
+
+ shortcuts.on(L10N.getStr("gotoLineModal.key3"), e =>
+ this.toggleQuickOpenModal(e, ":")
+ );
+
+ shortcuts.on("Escape", this.onEscape);
+ shortcuts.on("Cmd+/", this.onCommandSlash);
+ }
+
+ componentWillUnmount() {
+ horizontalLayoutBreakpoint.removeListener(this.onLayoutChange);
+ verticalLayoutBreakpoint.removeListener(this.onLayoutChange);
+ shortcuts.off(
+ L10N.getStr("symbolSearch.search.key2"),
+ this.toggleQuickOpenModal
+ );
+
+ const searchKeys = [
+ L10N.getStr("sources.search.key2"),
+ L10N.getStr("sources.search.alt.key"),
+ ];
+ searchKeys.forEach(key => shortcuts.off(key, this.toggleQuickOpenModal));
+
+ shortcuts.off(L10N.getStr("gotoLineModal.key3"), this.toggleQuickOpenModal);
+
+ shortcuts.off("Escape", this.onEscape);
+ }
+
+ onEscape = (e: KeyboardEvent) => {
+ const {
+ activeSearch,
+ closeActiveSearch,
+ closeQuickOpen,
+ quickOpenEnabled,
+ } = this.props;
+ const { shortcutsModalEnabled } = this.state;
+
+ if (activeSearch) {
+ e.preventDefault();
+ closeActiveSearch();
+ }
+
+ if (quickOpenEnabled) {
+ e.preventDefault();
+ closeQuickOpen();
+ }
+
+ if (shortcutsModalEnabled) {
+ e.preventDefault();
+ this.toggleShortcutsModal();
+ }
+ };
+
+ onCommandSlash = () => {
+ this.toggleShortcutsModal();
+ };
+
+ isHorizontal() {
+ return this.props.orientation === "horizontal";
+ }
+
+ toggleQuickOpenModal = (e: SyntheticEvent<HTMLElement>, query?: string) => {
+ const { quickOpenEnabled, openQuickOpen, closeQuickOpen } = this.props;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ if (quickOpenEnabled === true) {
+ closeQuickOpen();
+ return;
+ }
+
+ if (query != null) {
+ openQuickOpen(query);
+ return;
+ }
+ openQuickOpen();
+ };
+
+ onLayoutChange = () => {
+ this.setOrientation();
+ };
+
+ setOrientation() {
+ // If the orientation does not match (if it is not visible) it will
+ // not setOrientation, or if it is the same as before, calling
+ // setOrientation will not cause a rerender.
+ if (horizontalLayoutBreakpoint.matches) {
+ this.props.setOrientation("horizontal");
+ } else if (verticalLayoutBreakpoint.matches) {
+ this.props.setOrientation("vertical");
+ }
+ }
+
+ renderEditorPane = () => {
+ const { startPanelCollapsed, endPanelCollapsed } = this.props;
+ const { endPanelSize, startPanelSize } = this.state;
+ const horizontal = this.isHorizontal();
+
+ return (
+ <div className="editor-pane">
+ <div className="editor-container">
+ <EditorTabs
+ startPanelCollapsed={startPanelCollapsed}
+ endPanelCollapsed={endPanelCollapsed}
+ horizontal={horizontal}
+ />
+ <Editor startPanelSize={startPanelSize} endPanelSize={endPanelSize} />
+ {!this.props.selectedSource ? (
+ <WelcomeBox
+ horizontal={horizontal}
+ toggleShortcutsModal={() => this.toggleShortcutsModal()}
+ />
+ ) : null}
+ <EditorFooter horizontal={horizontal} />
+ <ProjectSearch />
+ </div>
+ </div>
+ );
+ };
+
+ toggleShortcutsModal() {
+ this.setState(prevState => ({
+ shortcutsModalEnabled: !prevState.shortcutsModalEnabled,
+ }));
+ }
+
+ // Important so that the tabs chevron updates appropriately when
+ // the user resizes the left or right columns
+ triggerEditorPaneResize() {
+ const editorPane = window.document.querySelector(".editor-pane");
+ if (editorPane) {
+ editorPane.dispatchEvent(new Event("resizeend"));
+ }
+ }
+
+ renderLayout = () => {
+ const { startPanelCollapsed, endPanelCollapsed } = this.props;
+ const horizontal = this.isHorizontal();
+
+ return (
+ <SplitBox
+ style={{ width: "100vw" }}
+ initialSize={prefs.endPanelSize}
+ minSize={30}
+ maxSize="70%"
+ splitterSize={1}
+ vert={horizontal}
+ onResizeEnd={num => {
+ prefs.endPanelSize = num;
+ this.triggerEditorPaneResize();
+ }}
+ startPanel={
+ <SplitBox
+ style={{ width: "100vw" }}
+ initialSize={prefs.startPanelSize}
+ minSize={30}
+ maxSize="85%"
+ splitterSize={1}
+ onResizeEnd={num => {
+ prefs.startPanelSize = num;
+ }}
+ startPanelCollapsed={startPanelCollapsed}
+ startPanel={<PrimaryPanes horizontal={horizontal} />}
+ endPanel={this.renderEditorPane()}
+ />
+ }
+ endPanelControl={true}
+ endPanel={<SecondaryPanes horizontal={horizontal} />}
+ endPanelCollapsed={endPanelCollapsed}
+ />
+ );
+ };
+
+ renderShortcutsModal() {
+ const additionalClass = isMacOS ? "mac" : "";
+
+ if (!features.shortcuts) {
+ return;
+ }
+
+ return (
+ <ShortcutsModal
+ additionalClass={additionalClass}
+ enabled={this.state.shortcutsModalEnabled}
+ handleClose={() => this.toggleShortcutsModal()}
+ />
+ );
+ }
+
+ render() {
+ const { quickOpenEnabled } = this.props;
+ return (
+ <div className={classnames("debugger")}>
+ <A11yIntention>
+ {this.renderLayout()}
+ {quickOpenEnabled === true && (
+ <QuickOpenModal
+ shortcutsModalEnabled={this.state.shortcutsModalEnabled}
+ toggleShortcutsModal={() => this.toggleShortcutsModal()}
+ />
+ )}
+ {this.renderShortcutsModal()}
+ </A11yIntention>
+ </div>
+ );
+ }
+}
+
+App.childContextTypes = {
+ toolboxDoc: PropTypes.object,
+ shortcuts: PropTypes.object,
+ l10n: PropTypes.object,
+};
+
+const mapStateToProps = state => ({
+ selectedSource: getSelectedSource(state),
+ startPanelCollapsed: getPaneCollapse(state, "start"),
+ endPanelCollapsed: getPaneCollapse(state, "end"),
+ activeSearch: getActiveSearch(state),
+ quickOpenEnabled: getQuickOpenEnabled(state),
+ orientation: getOrientation(state),
+});
+
+export default connect<Props, OwnProps, _, _, _, _>(mapStateToProps, {
+ setActiveSearch: actions.setActiveSearch,
+ closeActiveSearch: actions.closeActiveSearch,
+ closeProjectSearch: actions.closeProjectSearch,
+ openQuickOpen: actions.openQuickOpen,
+ closeQuickOpen: actions.closeQuickOpen,
+ setOrientation: actions.setOrientation,
+})(App);