Source code
Revision control
Copy as Markdown
Other Tools
/* 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
"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);
}
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);