diff options
Diffstat (limited to 'devtools/client/accessibility/components/MainFrame.js')
-rw-r--r-- | devtools/client/accessibility/components/MainFrame.js | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/devtools/client/accessibility/components/MainFrame.js b/devtools/client/accessibility/components/MainFrame.js new file mode 100644 index 0000000000..d918dc7be0 --- /dev/null +++ b/devtools/client/accessibility/components/MainFrame.js @@ -0,0 +1,245 @@ +/* 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"; + +// React & Redux +const { + Component, + createFactory, +} = require("resource://devtools/client/shared/vendor/react.js"); +const { + span, + div, +} = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); +const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js"); +const { + connect, +} = require("resource://devtools/client/shared/vendor/react-redux.js"); +const { + enable, + reset, + updateCanBeEnabled, + updateCanBeDisabled, +} = require("resource://devtools/client/accessibility/actions/ui.js"); + +// Localization +const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); +const LocalizationProvider = createFactory(FluentReact.LocalizationProvider); + +// Constants +const { + SIDEBAR_WIDTH, + PORTRAIT_MODE_WIDTH, +} = require("resource://devtools/client/accessibility/constants.js"); + +// Accessibility Panel +const AccessibilityTree = createFactory( + require("resource://devtools/client/accessibility/components/AccessibilityTree.js") +); +const AuditProgressOverlay = createFactory( + require("resource://devtools/client/accessibility/components/AuditProgressOverlay.js") +); +const Description = createFactory( + require("resource://devtools/client/accessibility/components/Description.js") + .Description +); +const RightSidebar = createFactory( + require("resource://devtools/client/accessibility/components/RightSidebar.js") +); +const Toolbar = createFactory( + require("resource://devtools/client/accessibility/components/Toolbar.js") + .Toolbar +); +const SplitBox = createFactory( + require("resource://devtools/client/shared/components/splitter/SplitBox.js") +); + +/** + * Renders basic layout of the Accessibility panel. The Accessibility panel + * content consists of two main parts: tree and sidebar. + */ +class MainFrame extends Component { + static get propTypes() { + return { + fluentBundles: PropTypes.array.isRequired, + enabled: PropTypes.bool.isRequired, + dispatch: PropTypes.func.isRequired, + auditing: PropTypes.array.isRequired, + supports: PropTypes.object, + toolbox: PropTypes.object.isRequired, + getAccessibilityTreeRoot: PropTypes.func.isRequired, + startListeningForAccessibilityEvents: PropTypes.func.isRequired, + stopListeningForAccessibilityEvents: PropTypes.func.isRequired, + audit: PropTypes.func.isRequired, + simulate: PropTypes.func, + enableAccessibility: PropTypes.func.isRequired, + resetAccessiblity: PropTypes.func.isRequired, + startListeningForLifecycleEvents: PropTypes.func.isRequired, + stopListeningForLifecycleEvents: PropTypes.func.isRequired, + startListeningForParentLifecycleEvents: PropTypes.func.isRequired, + stopListeningForParentLifecycleEvents: PropTypes.func.isRequired, + highlightAccessible: PropTypes.func.isRequired, + unhighlightAccessible: PropTypes.func.isRequired, + }; + } + + constructor(props) { + super(props); + + this.resetAccessibility = this.resetAccessibility.bind(this); + this.onPanelWindowResize = this.onPanelWindowResize.bind(this); + this.onCanBeEnabledChange = this.onCanBeEnabledChange.bind(this); + this.onCanBeDisabledChange = this.onCanBeDisabledChange.bind(this); + } + + // FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507 + UNSAFE_componentWillMount() { + this.props.startListeningForLifecycleEvents({ + init: this.resetAccessibility, + shutdown: this.resetAccessibility, + }); + this.props.startListeningForParentLifecycleEvents({ + "can-be-enabled-change": this.onCanBeEnabledChange, + "can-be-disabled-change": this.onCanBeDisabledChange, + }); + this.props.startListeningForAccessibilityEvents({ + "top-level-document-ready": this.resetAccessibility, + }); + window.addEventListener("resize", this.onPanelWindowResize, true); + } + + componentWillUnmount() { + this.props.stopListeningForLifecycleEvents({ + init: this.resetAccessibility, + shutdown: this.resetAccessibility, + }); + this.props.stopListeningForParentLifecycleEvents({ + "can-be-enabled-change": this.onCanBeEnabledChange, + "can-be-disabled-change": this.onCanBeDisabledChange, + }); + this.props.stopListeningForAccessibilityEvents({ + "top-level-document-ready": this.resetAccessibility, + }); + window.removeEventListener("resize", this.onPanelWindowResize, true); + } + + resetAccessibility() { + const { dispatch, resetAccessiblity, supports } = this.props; + dispatch(reset(resetAccessiblity, supports)); + } + + onCanBeEnabledChange(canBeEnabled) { + const { enableAccessibility, dispatch } = this.props; + dispatch(updateCanBeEnabled(canBeEnabled)); + if (canBeEnabled) { + dispatch(enable(enableAccessibility)); + } + } + + onCanBeDisabledChange(canBeDisabled) { + this.props.dispatch(updateCanBeDisabled(canBeDisabled)); + } + + get useLandscapeMode() { + const { clientWidth } = document.getElementById("content"); + return clientWidth > PORTRAIT_MODE_WIDTH; + } + + /** + * If panel width is less than PORTRAIT_MODE_WIDTH px, the splitter changes + * its mode to `horizontal` to support portrait view. + */ + onPanelWindowResize() { + if (this.refs.splitBox) { + this.refs.splitBox.setState({ vert: this.useLandscapeMode }); + } + } + + /** + * Render Accessibility panel content + */ + render() { + const { + fluentBundles, + enabled, + auditing, + simulate, + toolbox, + getAccessibilityTreeRoot, + startListeningForAccessibilityEvents, + stopListeningForAccessibilityEvents, + audit, + highlightAccessible, + unhighlightAccessible, + } = this.props; + + if (!enabled) { + return Description(); + } + + // Audit is currently running. + const isAuditing = !!auditing.length; + + return LocalizationProvider( + { bundles: fluentBundles }, + div( + { className: "mainFrame", role: "presentation", tabIndex: "-1" }, + Toolbar({ + audit, + simulate, + toolboxDoc: toolbox.doc, + }), + isAuditing && AuditProgressOverlay(), + span( + { + "aria-hidden": isAuditing, + role: "presentation", + style: { display: "contents" }, + }, + SplitBox({ + ref: "splitBox", + initialSize: SIDEBAR_WIDTH, + minSize: "10%", + maxSize: "80%", + splitterSize: 1, + endPanelControl: true, + startPanel: div( + { + className: "main-panel", + role: "presentation", + tabIndex: "-1", + }, + AccessibilityTree({ + toolboxDoc: toolbox.doc, + getAccessibilityTreeRoot, + startListeningForAccessibilityEvents, + stopListeningForAccessibilityEvents, + highlightAccessible, + unhighlightAccessible, + }) + ), + endPanel: RightSidebar({ + highlightAccessible, + unhighlightAccessible, + toolbox, + }), + vert: this.useLandscapeMode, + }) + ) + ) + ); + } +} + +const mapStateToProps = ({ + ui: { enabled, supports }, + audit: { auditing }, +}) => ({ + enabled, + supports, + auditing, +}); + +// Exports from this module +module.exports = connect(mapStateToProps)(MainFrame); |