diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /devtools/client/debugger/src/components/App.js | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
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.js | 396 |
1 files changed, 396 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..40911e5167 --- /dev/null +++ b/devtools/client/debugger/src/components/App.js @@ -0,0 +1,396 @@ +/* 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/>. */ + +import React, { Component } from "devtools/client/shared/vendor/react"; +import { + div, + main, + span, +} from "devtools/client/shared/vendor/react-dom-factories"; +import PropTypes from "devtools/client/shared/vendor/react-prop-types"; +import { connect } from "devtools/client/shared/vendor/react-redux"; +import { prefs } from "../utils/prefs"; +import { primaryPaneTabs } from "../constants"; +import actions from "../actions/index"; +import AccessibleImage from "./shared/AccessibleImage"; + +import { + getSelectedLocation, + getPaneCollapse, + getActiveSearch, + getQuickOpenEnabled, + getOrientation, + getIsCurrentThreadPaused, + isMapScopesEnabled, + getSourceMapErrorForSourceActor, +} from "../selectors/index"; +const KeyShortcuts = require("resource://devtools/client/shared/key-shortcuts.js"); + +const SplitBox = require("resource://devtools/client/shared/components/splitter/SplitBox.js"); +const AppErrorBoundary = require("resource://devtools/client/shared/components/AppErrorBoundary.js"); + +const shortcuts = new KeyShortcuts({ window }); + +const horizontalLayoutBreakpoint = window.matchMedia("(min-width: 800px)"); +const verticalLayoutBreakpoint = window.matchMedia( + "(min-width: 10px) and (max-width: 799px)" +); + +import { ShortcutsModal } from "./ShortcutsModal"; +import PrimaryPanes from "./PrimaryPanes/index"; +import Editor from "./Editor/index"; +import SecondaryPanes from "./SecondaryPanes/index"; +import WelcomeBox from "./WelcomeBox"; +import EditorTabs from "./Editor/Tabs"; +import EditorFooter from "./Editor/Footer"; +import QuickOpenModal from "./QuickOpenModal"; + +class App extends Component { + constructor(props) { + super(props); + this.state = { + shortcutsModalEnabled: false, + startPanelSize: 0, + endPanelSize: 0, + }; + } + + static get propTypes() { + return { + activeSearch: PropTypes.oneOf(["file", "project"]), + closeActiveSearch: PropTypes.func.isRequired, + closeQuickOpen: PropTypes.func.isRequired, + endPanelCollapsed: PropTypes.bool.isRequired, + fluentBundles: PropTypes.array.isRequired, + openQuickOpen: PropTypes.func.isRequired, + orientation: PropTypes.oneOf(["horizontal", "vertical"]).isRequired, + quickOpenEnabled: PropTypes.bool.isRequired, + selectedLocation: PropTypes.object, + setActiveSearch: PropTypes.func.isRequired, + setOrientation: PropTypes.func.isRequired, + setPrimaryPaneTab: PropTypes.func.isRequired, + startPanelCollapsed: PropTypes.bool.isRequired, + toolboxDoc: PropTypes.object.isRequired, + showOriginalVariableMappingWarning: PropTypes.bool, + }; + } + + getChildContext() { + return { + fluentBundles: this.props.fluentBundles, + 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, "@") + ); + + [ + L10N.getStr("sources.search.key2"), + L10N.getStr("sources.search.alt.key"), + ].forEach(key => shortcuts.on(key, this.toggleQuickOpenModal)); + + shortcuts.on(L10N.getStr("gotoLineModal.key3"), e => + this.toggleQuickOpenModal(e, ":") + ); + + shortcuts.on( + L10N.getStr("projectTextSearch.key"), + this.jumpToProjectSearch + ); + + shortcuts.on("Escape", this.onEscape); + shortcuts.on("CmdOrCtrl+/", this.onCommandSlash); + } + + componentWillUnmount() { + horizontalLayoutBreakpoint.removeListener(this.onLayoutChange); + verticalLayoutBreakpoint.removeListener(this.onLayoutChange); + shortcuts.off( + L10N.getStr("symbolSearch.search.key2"), + this.toggleQuickOpenModal + ); + + [ + L10N.getStr("sources.search.key2"), + L10N.getStr("sources.search.alt.key"), + ].forEach(key => shortcuts.off(key, this.toggleQuickOpenModal)); + + shortcuts.off(L10N.getStr("gotoLineModal.key3"), this.toggleQuickOpenModal); + + shortcuts.off( + L10N.getStr("projectTextSearch.key"), + this.jumpToProjectSearch + ); + + shortcuts.off("Escape", this.onEscape); + shortcuts.off("CmdOrCtrl+/", this.onCommandSlash); + } + + jumpToProjectSearch = e => { + e.preventDefault(); + this.props.setPrimaryPaneTab(primaryPaneTabs.PROJECT_SEARCH); + this.props.setActiveSearch(primaryPaneTabs.PROJECT_SEARCH); + }; + + onEscape = e => { + 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, query) => { + 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"); + } + } + + renderEditorNotificationBar() { + if (this.props.sourceMapError) { + return div( + { className: "editor-notification-footer", "aria-role": "status" }, + span( + { className: "info icon" }, + React.createElement(AccessibleImage, { className: "sourcemap" }) + ), + `Source Map Error: ${this.props.sourceMapError}` + ); + } + if (this.props.showOriginalVariableMappingWarning) { + return div( + { className: "editor-notification-footer", "aria-role": "status" }, + span( + { className: "info icon" }, + React.createElement(AccessibleImage, { className: "sourcemap" }) + ), + L10N.getFormatStr( + "editorNotificationFooter.noOriginalScopes", + L10N.getStr("scopes.showOriginalScopes") + ) + ); + } + return null; + } + + renderEditorPane = () => { + const { startPanelCollapsed, endPanelCollapsed } = this.props; + const { endPanelSize, startPanelSize } = this.state; + const horizontal = this.isHorizontal(); + return main( + { + className: "editor-pane", + }, + div( + { + className: "editor-container", + }, + React.createElement(EditorTabs, { + startPanelCollapsed: startPanelCollapsed, + endPanelCollapsed: endPanelCollapsed, + horizontal: horizontal, + }), + React.createElement(Editor, { + startPanelSize: startPanelSize, + endPanelSize: endPanelSize, + }), + !this.props.selectedLocation + ? React.createElement(WelcomeBox, { + horizontal, + toggleShortcutsModal: () => this.toggleShortcutsModal(), + }) + : null, + this.renderEditorNotificationBar(), + React.createElement(EditorFooter, { + horizontal, + }) + ) + ); + }; + + 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 React.createElement(SplitBox, { + style: { + width: "100vw", + }, + initialSize: prefs.endPanelSize, + minSize: 30, + maxSize: "70%", + splitterSize: 1, + vert: horizontal, + onResizeEnd: num => { + prefs.endPanelSize = num; + this.triggerEditorPaneResize(); + }, + startPanel: React.createElement(SplitBox, { + style: { + width: "100vw", + }, + initialSize: prefs.startPanelSize, + minSize: 30, + maxSize: "85%", + splitterSize: 1, + onResizeEnd: num => { + prefs.startPanelSize = num; + this.triggerEditorPaneResize(); + }, + startPanelCollapsed: startPanelCollapsed, + startPanel: React.createElement(PrimaryPanes, { + horizontal, + }), + endPanel: this.renderEditorPane(), + }), + endPanelControl: true, + endPanel: React.createElement(SecondaryPanes, { + horizontal, + }), + endPanelCollapsed: endPanelCollapsed, + }); + }; + + render() { + const { quickOpenEnabled } = this.props; + return div( + { + className: "debugger", + }, + React.createElement( + AppErrorBoundary, + { + componentName: "Debugger", + panel: L10N.getStr("ToolboxDebugger.label"), + }, + this.renderLayout(), + quickOpenEnabled === true && + React.createElement(QuickOpenModal, { + shortcutsModalEnabled: this.state.shortcutsModalEnabled, + toggleShortcutsModal: () => this.toggleShortcutsModal(), + }), + React.createElement(ShortcutsModal, { + enabled: this.state.shortcutsModalEnabled, + handleClose: () => this.toggleShortcutsModal(), + }) + ) + ); + } +} + +App.childContextTypes = { + toolboxDoc: PropTypes.object, + shortcuts: PropTypes.object, + l10n: PropTypes.object, + fluentBundles: PropTypes.array, +}; + +const mapStateToProps = state => { + const selectedLocation = getSelectedLocation(state); + const mapScopeEnabled = isMapScopesEnabled(state); + const isPaused = getIsCurrentThreadPaused(state); + + const showOriginalVariableMappingWarning = + isPaused && + selectedLocation?.source.isOriginal && + !selectedLocation?.source.isPrettyPrinted && + !mapScopeEnabled; + + return { + showOriginalVariableMappingWarning, + selectedLocation, + startPanelCollapsed: getPaneCollapse(state, "start"), + endPanelCollapsed: getPaneCollapse(state, "end"), + activeSearch: getActiveSearch(state), + quickOpenEnabled: getQuickOpenEnabled(state), + orientation: getOrientation(state), + sourceMapError: selectedLocation?.sourceActor + ? getSourceMapErrorForSourceActor(state, selectedLocation.sourceActor.id) + : null, + }; +}; + +export default connect(mapStateToProps, { + setActiveSearch: actions.setActiveSearch, + closeActiveSearch: actions.closeActiveSearch, + openQuickOpen: actions.openQuickOpen, + closeQuickOpen: actions.closeQuickOpen, + setOrientation: actions.setOrientation, + setPrimaryPaneTab: actions.setPrimaryPaneTab, +})(App); |