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