2018-03-28 18:40:49 +03:00
|
|
|
/* 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";
|
|
|
|
|
2019-08-28 14:54:42 +03:00
|
|
|
/* global EVENTS */
|
2018-04-13 20:16:53 +03:00
|
|
|
|
|
|
|
const nodeConstants = require("devtools/shared/dom-node-constants");
|
2018-03-28 18:40:49 +03:00
|
|
|
|
|
|
|
// React & Redux
|
|
|
|
const {
|
|
|
|
createFactory,
|
|
|
|
createElement,
|
|
|
|
} = require("devtools/client/shared/vendor/react");
|
|
|
|
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
|
|
|
const { Provider } = require("devtools/client/shared/vendor/react-redux");
|
|
|
|
|
|
|
|
// Accessibility Panel
|
|
|
|
const MainFrame = createFactory(require("./components/MainFrame"));
|
|
|
|
const OldVersionDescription = createFactory(
|
|
|
|
require("./components/Description").OldVersionDescription
|
|
|
|
);
|
|
|
|
|
|
|
|
// Store
|
2019-08-09 04:27:53 +03:00
|
|
|
const createStore = require("devtools/client/shared/redux/create-store");
|
2018-03-28 18:40:49 +03:00
|
|
|
|
|
|
|
// Reducers
|
|
|
|
const { reducers } = require("./reducers/index");
|
2019-08-09 04:27:53 +03:00
|
|
|
const store = createStore(reducers);
|
2018-03-28 18:40:49 +03:00
|
|
|
|
|
|
|
// Actions
|
|
|
|
const { reset } = require("./actions/ui");
|
|
|
|
const { select, highlight } = require("./actions/accessibles");
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This object represents view of the Accessibility panel and is responsible
|
|
|
|
* for rendering the content. It renders the top level ReactJS
|
|
|
|
* component: the MainFrame.
|
|
|
|
*/
|
|
|
|
function AccessibilityView(localStore) {
|
|
|
|
addEventListener("devtools/chrome/message", this.onMessage.bind(this), true);
|
|
|
|
this.store = localStore;
|
|
|
|
}
|
|
|
|
|
|
|
|
AccessibilityView.prototype = {
|
|
|
|
/**
|
|
|
|
* Initialize accessibility view, create its top level component and set the
|
|
|
|
* data store.
|
|
|
|
*
|
|
|
|
* @param {Object} accessibility front that can initialize accessibility
|
|
|
|
* walker and enable/disable accessibility
|
|
|
|
* services.
|
2018-10-11 17:51:35 +03:00
|
|
|
* @param {Object} walker front for accessibility walker actor responsible for
|
|
|
|
* managing accessible objects actors/fronts.
|
|
|
|
* @param {JSON} supports a collection of flags indicating which accessibility
|
|
|
|
* panel features are supported by the current serverside
|
|
|
|
* version.
|
2019-07-04 06:36:35 +03:00
|
|
|
* @param {Array} fluentBundles array of FluentBundles elements for localization
|
2018-03-28 18:40:49 +03:00
|
|
|
*/
|
2019-07-04 06:36:35 +03:00
|
|
|
async initialize(accessibility, walker, supports, fluentBundles) {
|
2018-03-28 18:40:49 +03:00
|
|
|
// Make sure state is reset every time accessibility panel is initialized.
|
2018-10-11 17:51:35 +03:00
|
|
|
await this.store.dispatch(reset(accessibility, supports));
|
2018-03-28 18:40:49 +03:00
|
|
|
const container = document.getElementById("content");
|
|
|
|
|
2018-10-11 17:51:35 +03:00
|
|
|
if (!supports.enableDisable) {
|
2018-03-28 18:40:49 +03:00
|
|
|
ReactDOM.render(OldVersionDescription(), container);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-12 03:21:56 +03:00
|
|
|
const mainFrame = MainFrame({
|
|
|
|
accessibility,
|
|
|
|
accessibilityWalker: walker,
|
|
|
|
fluentBundles,
|
|
|
|
});
|
2018-03-28 18:40:49 +03:00
|
|
|
// Render top level component
|
|
|
|
const provider = createElement(Provider, { store: this.store }, mainFrame);
|
|
|
|
this.mainFrame = ReactDOM.render(provider, container);
|
|
|
|
},
|
|
|
|
|
|
|
|
async selectAccessible(walker, accessible) {
|
|
|
|
await this.store.dispatch(select(walker, accessible));
|
|
|
|
window.emit(EVENTS.NEW_ACCESSIBLE_FRONT_INSPECTED);
|
|
|
|
},
|
|
|
|
|
|
|
|
async highlightAccessible(walker, accessible) {
|
|
|
|
await this.store.dispatch(highlight(walker, accessible));
|
|
|
|
window.emit(EVENTS.NEW_ACCESSIBLE_FRONT_HIGHLIGHTED);
|
|
|
|
},
|
|
|
|
|
2019-04-27 16:33:17 +03:00
|
|
|
async selectNodeAccessible(walker, node, supports) {
|
2018-04-13 20:16:53 +03:00
|
|
|
let accessible = await walker.getAccessibleFor(node);
|
2019-04-27 16:33:17 +03:00
|
|
|
if (accessible && supports.hydration) {
|
|
|
|
await accessible.hydrate();
|
|
|
|
}
|
|
|
|
|
2018-04-13 20:16:53 +03:00
|
|
|
// If node does not have an accessible object, try to find node's child text node and
|
|
|
|
// try to retrieve an accessible object for that child instead. This is the best
|
|
|
|
// effort approach until there's accessibility API to retrieve accessible object at
|
|
|
|
// point.
|
|
|
|
if (!accessible || accessible.indexInParent < 0) {
|
2019-08-28 14:54:42 +03:00
|
|
|
const { nodes: children } = await node.walkerFront.children(node);
|
2018-06-01 13:36:09 +03:00
|
|
|
for (const child of children) {
|
2018-04-13 20:16:53 +03:00
|
|
|
if (child.nodeType === nodeConstants.TEXT_NODE) {
|
|
|
|
accessible = await walker.getAccessibleFor(child);
|
2019-04-27 16:33:17 +03:00
|
|
|
// indexInParent property is only available with additional request
|
|
|
|
// for data (hydration) about the accessible object.
|
|
|
|
if (accessible && supports.hydration) {
|
|
|
|
await accessible.hydrate();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (accessible.indexInParent >= 0) {
|
2018-04-13 20:16:53 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-28 18:40:49 +03:00
|
|
|
|
|
|
|
await this.store.dispatch(select(walker, accessible));
|
|
|
|
window.emit(EVENTS.NEW_ACCESSIBLE_FRONT_HIGHLIGHTED);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process message from accessibility panel.
|
|
|
|
*
|
|
|
|
* @param {Object} event message type and data.
|
|
|
|
*/
|
|
|
|
onMessage(event) {
|
|
|
|
const data = event.data;
|
|
|
|
const method = data.type;
|
|
|
|
|
|
|
|
if (typeof this[method] === "function") {
|
|
|
|
this[method](...data.args);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
window.view = new AccessibilityView(store);
|