Bug 1605757 - decouple accessibility front front the accessibility panel UI. r=rcaliman

Differential Revision: https://phabricator.services.mozilla.com/D58553

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Yura Zenevich 2020-03-06 16:27:59 +00:00
Родитель aa241077e3
Коммит 041d2c6235
7 изменённых файлов: 157 добавлений и 67 удалений

Просмотреть файл

@ -51,11 +51,6 @@ AccessibilityView.prototype = {
*
* @param {Object}
* Object that contains the following properties:
* - front {Object}
* front that can initialize
* accessibility walker and
* enable/disable accessibility
* services.
* - supports {JSON}
* a collection of flags indicating
* which accessibility panel features
@ -84,9 +79,21 @@ AccessibilityView.prototype = {
* Apply simulation of a given type
* (by setting color matrices in
* docShell).
* - enableAccessibility {Function}
* Enable accessibility services.
* - disableAccessibility {Function}
* Disable accessibility services.
* - resetAccessiblity {Function}
* Reset the state of the
* accessibility services.
* - startListeningForLifecycleEvents {Function}
* Add listeners for accessibility
* service lifecycle events.
* - stopListeningForLifecycleEvents {Function}
* Remove listeners for accessibility
* service lifecycle events.
*/
async initialize({
front,
supports,
fluentBundles,
toolbox,
@ -95,12 +102,16 @@ AccessibilityView.prototype = {
stopListeningForAccessibilityEvents,
audit,
simulate,
enableAccessibility,
disableAccessibility,
resetAccessiblity,
startListeningForLifecycleEvents,
stopListeningForLifecycleEvents,
}) {
// Make sure state is reset every time accessibility panel is initialized.
await this.store.dispatch(reset(front, supports));
await this.store.dispatch(reset(resetAccessiblity, supports));
const container = document.getElementById("content");
const mainFrame = MainFrame({
accessibility: front,
fluentBundles,
toolbox,
getAccessibilityTreeRoot,
@ -108,6 +119,11 @@ AccessibilityView.prototype = {
stopListeningForAccessibilityEvents,
audit,
simulate,
enableAccessibility,
disableAccessibility,
resetAccessiblity,
startListeningForLifecycleEvents,
stopListeningForLifecycleEvents,
});
// Render top level component
const provider = createElement(Provider, { store: this.store }, mainFrame);

Просмотреть файл

@ -18,8 +18,14 @@ const {
/**
* Reset accessibility panel UI.
*/
exports.reset = (accessibility, supports) => dispatch =>
dispatch({ accessibility, supports, type: RESET });
exports.reset = (resetAccessiblity, supports) => async dispatch => {
try {
const { enabled, canBeDisabled, canBeEnabled } = await resetAccessiblity();
dispatch({ enabled, canBeDisabled, canBeEnabled, supports, type: RESET });
} catch (error) {
dispatch({ type: RESET, error });
}
};
/**
* Update a "canBeDisabled" flag for accessibility service.
@ -41,17 +47,23 @@ exports.updatePref = (name, value) => dispatch => {
/**
* Enable accessibility services in order to view accessible tree.
*/
exports.enable = accessibility => dispatch =>
accessibility
.enable()
.then(() => dispatch({ type: ENABLE }))
.catch(error => dispatch({ error, type: ENABLE }));
exports.enable = enableAccessibility => async dispatch => {
try {
await enableAccessibility();
dispatch({ type: ENABLE });
} catch (error) {
dispatch({ error, type: ENABLE });
}
};
/**
* Enable accessibility services in order to view accessible tree.
*/
exports.disable = accessibility => dispatch =>
accessibility
.disable()
.then(() => dispatch({ type: DISABLE }))
.catch(error => dispatch({ type: DISABLE, error }));
exports.disable = disableAccessibility => async dispatch => {
try {
await disableAccessibility();
dispatch({ type: DISABLE });
} catch (error) {
dispatch({ error, type: DISABLE });
}
};

Просмотреть файл

@ -44,9 +44,11 @@ const {
class Description extends Component {
static get propTypes() {
return {
accessibility: PropTypes.object.isRequired,
canBeEnabled: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
enableAccessibility: PropTypes.func.isRequired,
startListeningForLifecycleEvents: PropTypes.func.isRequired,
stopListeningForLifecycleEvents: PropTypes.func.isRequired,
};
}
@ -62,28 +64,26 @@ class Description extends Component {
}
componentWillMount() {
this.props.accessibility.on(
"can-be-enabled-change",
this.onCanBeEnabledChange
);
this.props.startListeningForLifecycleEvents({
"can-be-enabled-change": this.onCanBeEnabledChange,
});
}
componentWillUnmount() {
this.props.accessibility.off(
"can-be-enabled-change",
this.onCanBeEnabledChange
);
this.props.stopListeningForLifecycleEvents({
"can-be-enabled-change": this.onCanBeEnabledChange,
});
}
onEnable() {
const { accessibility, dispatch } = this.props;
const { enableAccessibility, dispatch } = this.props;
this.setState({ enabling: true });
if (gTelemetry) {
gTelemetry.scalarAdd(A11Y_SERVICE_ENABLED_COUNT, 1);
}
dispatch(enable(accessibility))
dispatch(enable(enableAccessibility))
.then(() => this.setState({ enabling: false }))
.catch(() => this.setState({ enabling: false }));
}

Просмотреть файл

@ -53,7 +53,6 @@ const SplitBox = createFactory(
class MainFrame extends Component {
static get propTypes() {
return {
accessibility: PropTypes.object.isRequired,
fluentBundles: PropTypes.array.isRequired,
enabled: PropTypes.bool.isRequired,
dispatch: PropTypes.func.isRequired,
@ -65,6 +64,11 @@ class MainFrame extends Component {
stopListeningForAccessibilityEvents: PropTypes.func.isRequired,
audit: PropTypes.func.isRequired,
simulate: PropTypes.func,
enableAccessibility: PropTypes.func.isRequired,
disableAccessibility: PropTypes.func.isRequired,
resetAccessiblity: PropTypes.func.isRequired,
startListeningForLifecycleEvents: PropTypes.func.isRequired,
stopListeningForLifecycleEvents: PropTypes.func.isRequired,
};
}
@ -76,8 +80,10 @@ class MainFrame extends Component {
}
componentWillMount() {
this.props.accessibility.on("init", this.resetAccessibility);
this.props.accessibility.on("shutdown", this.resetAccessibility);
this.props.startListeningForLifecycleEvents({
init: this.resetAccessibility,
shutdown: this.resetAccessibility,
});
this.props.startListeningForAccessibilityEvents({
"document-ready": this.resetAccessibility,
});
@ -91,8 +97,10 @@ class MainFrame extends Component {
}
componentWillUnmount() {
this.props.accessibility.off("init", this.resetAccessibility);
this.props.accessibility.off("shutdown", this.resetAccessibility);
this.props.stopListeningForLifecycleEvents({
init: this.resetAccessibility,
shutdown: this.resetAccessibility,
});
this.props.stopListeningForAccessibilityEvents({
"document-ready": this.resetAccessibility,
});
@ -100,8 +108,8 @@ class MainFrame extends Component {
}
resetAccessibility() {
const { dispatch, accessibility, supports } = this.props;
dispatch(reset(accessibility, supports));
const { dispatch, resetAccessiblity, supports } = this.props;
dispatch(reset(resetAccessiblity, supports));
}
get useLandscapeMode() {
@ -124,7 +132,6 @@ class MainFrame extends Component {
*/
render() {
const {
accessibility,
fluentBundles,
enabled,
auditing,
@ -134,10 +141,18 @@ class MainFrame extends Component {
startListeningForAccessibilityEvents,
stopListeningForAccessibilityEvents,
audit,
enableAccessibility,
disableAccessibility,
startListeningForLifecycleEvents,
stopListeningForLifecycleEvents,
} = this.props;
if (!enabled) {
return Description({ accessibility });
return Description({
enableAccessibility,
startListeningForLifecycleEvents,
stopListeningForLifecycleEvents,
});
}
// Audit is currently running.
@ -148,9 +163,11 @@ class MainFrame extends Component {
div(
{ className: "mainFrame", role: "presentation" },
Toolbar({
accessibility,
audit,
disableAccessibility,
simulate,
startListeningForLifecycleEvents,
stopListeningForLifecycleEvents,
toolboxDoc: toolbox.doc,
}),
isAuditing && AuditProgressOverlay(),

Просмотреть файл

@ -39,11 +39,13 @@ class Toolbar extends Component {
static get propTypes() {
return {
dispatch: PropTypes.func.isRequired,
accessibility: PropTypes.object.isRequired,
disableAccessibility: PropTypes.func.isRequired,
canBeDisabled: PropTypes.bool.isRequired,
toolboxDoc: PropTypes.object.isRequired,
audit: PropTypes.func.isRequired,
simulate: PropTypes.func,
startListeningForLifecycleEvents: PropTypes.func.isRequired,
stopListeningForLifecycleEvents: PropTypes.func.isRequired,
};
}
@ -59,17 +61,15 @@ class Toolbar extends Component {
}
componentWillMount() {
this.props.accessibility.on(
"can-be-disabled-change",
this.onCanBeDisabledChange
);
this.props.startListeningForLifecycleEvents({
"can-be-disabled-change": this.onCanBeDisabledChange,
});
}
componentWillUnmount() {
this.props.accessibility.off(
"can-be-disabled-change",
this.onCanBeDisabledChange
);
this.props.stopListeningForLifecycleEvents({
"can-be-disabled-change": this.onCanBeDisabledChange,
});
}
onCanBeDisabledChange(canBeDisabled) {
@ -77,10 +77,10 @@ class Toolbar extends Component {
}
onDisable() {
const { accessibility, dispatch } = this.props;
const { disableAccessibility, dispatch } = this.props;
this.setState({ disabling: true });
dispatch(disable(accessibility))
dispatch(disable(disableAccessibility))
.then(() => this.setState({ disabling: false }))
.catch(() => this.setState({ disabling: false }));
}

Просмотреть файл

@ -65,6 +65,15 @@ function AccessibilityPanel(iframeWindow, toolbox, startup) {
);
this.audit = this.audit.bind(this);
this.simulate = this.simulate.bind(this);
this.enableAccessibility = this.enableAccessibility.bind(this);
this.disableAccessibility = this.disableAccessibility.bind(this);
this.resetAccessiblity = this.resetAccessiblity.bind(this);
this.startListeningForLifecycleEvents = this.startListeningForLifecycleEvents.bind(
this
);
this.stopListeningForLifecycleEvents = this.stopListeningForLifecycleEvents.bind(
this
);
EventEmitter.decorate(this);
}
@ -108,11 +117,13 @@ AccessibilityPanel.prototype = {
this.fluentBundles = await this.createFluentBundles();
this.updateA11YServiceDurationTimer();
this.front.on("init", this.updateA11YServiceDurationTimer);
this.front.on("shutdown", this.updateA11YServiceDurationTimer);
this.front.on("init", this.forceUpdatePickerButton);
this.front.on("shutdown", this.forceUpdatePickerButton);
this.startListeningForLifecycleEvents({
init: [this.updateA11YServiceDurationTimer, this.forceUpdatePickerButton],
shutdown: [
this.updateA11YServiceDurationTimer,
this.forceUpdatePickerButton,
],
});
this.isReady = true;
this.emit("ready");
@ -180,7 +191,6 @@ AccessibilityPanel.prototype = {
// Alright reset the flag we are about to refresh the panel.
this.shouldRefresh = false;
this.postContentMessage("initialize", {
front: this.front,
supports: this.supports,
fluentBundles: this.fluentBundles,
toolbox: this._toolbox,
@ -191,6 +201,11 @@ AccessibilityPanel.prototype = {
.stopListeningForAccessibilityEvents,
audit: this.audit,
simulate: this.startup.simulator && this.simulate,
enableAccessibility: this.enableAccessibility,
disableAccessibility: this.disableAccessibility,
resetAccessiblity: this.resetAccessiblity,
startListeningForLifecycleEvents: this.startListeningForLifecycleEvents,
stopListeningForLifecycleEvents: this.stopListeningForLifecycleEvents,
});
},
@ -306,6 +321,24 @@ AccessibilityPanel.prototype = {
}
},
startListeningForLifecycleEvents(eventMap) {
for (let [type, listeners] of Object.entries(eventMap)) {
listeners = Array.isArray(listeners) ? listeners : [listeners];
for (const listener of listeners) {
this.front.on(type, listener);
}
}
},
stopListeningForLifecycleEvents(eventMap) {
for (let [type, listeners] of Object.entries(eventMap)) {
listeners = Array.isArray(listeners) ? listeners : [listeners];
for (const listener of listeners) {
this.front.off(type, listener);
}
}
},
/**
* Perform an audit for a given filter.
*
@ -357,6 +390,19 @@ AccessibilityPanel.prototype = {
return this.startup.simulator.simulate({ types });
},
enableAccessibility() {
return this.front.enable();
},
disableAccessibility() {
return this.front.disable();
},
async resetAccessiblity() {
const { enabled, canBeDisabled, canBeEnabled } = this.front;
return { enabled, canBeDisabled, canBeEnabled };
},
get front() {
return this.startup.accessibility;
},
@ -406,13 +452,13 @@ AccessibilityPanel.prototype = {
this.picker = null;
}
if (this.front) {
this.front.off("init", this.updateA11YServiceDurationTimer);
this.front.off("shutdown", this.updateA11YServiceDurationTimer);
this.front.off("init", this.forceUpdatePickerButton);
this.front.off("shutdown", this.forceUpdatePickerButton);
}
this.stopListeningForLifecycleEvents({
init: [this.updateA11YServiceDurationTimer, this.forceUpdatePickerButton],
shutdown: [
this.updateA11YServiceDurationTimer,
this.forceUpdatePickerButton,
],
});
this._telemetry = null;
this.panelWin.gTelemetry = null;

Просмотреть файл

@ -178,8 +178,7 @@ function onPrefChange(state, { name, value }) {
* @param {Object} action Redux action object
* @return {Object} updated state
*/
function onReset(state, { accessibility, supports }) {
const { enabled, canBeDisabled, canBeEnabled } = accessibility;
function onReset(state, { enabled, canBeDisabled, canBeEnabled, supports }) {
const newState = {
...getInitialState(),
enabled,