244 lines
7.4 KiB
JavaScript
244 lines
7.4 KiB
JavaScript
/* 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.mjs");
|
|
const {
|
|
span,
|
|
div,
|
|
} = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
|
|
const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
|
|
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);
|
|
}
|
|
|
|
componentDidMount() {
|
|
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);
|