/* 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);