Bug 1507870 - add Print to JSON functionality to the a11y inspector. r=pbro

MozReview-Commit-ID: HyqYgHCCp3T

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Yura Zenevich 2018-11-30 14:55:42 +00:00
Родитель 80eec2f7ae
Коммит e2f524a9d5
4 изменённых файлов: 217 добавлений и 0 удалений

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

@ -16,12 +16,20 @@ const TreeRow = require("devtools/client/shared/components/tree/TreeRow");
// Utils
const {flashElementOn, flashElementOff} =
require("devtools/client/inspector/markup/utils");
const { openDocLink } = require("devtools/client/shared/link");
const { VALUE_FLASHING_DURATION, VALUE_HIGHLIGHT_DURATION } = require("../constants");
// Actions
const { updateDetails } = require("../actions/details");
const { unhighlight } = require("../actions/accessibles");
const { L10N } = require("../utils/l10n");
loader.lazyRequireGetter(this, "Menu", "devtools/client/framework/menu");
loader.lazyRequireGetter(this, "MenuItem", "devtools/client/framework/menu-item");
const JSON_URL_PREFIX = "data:application/json;charset=UTF-8,";
class HighlightableTreeRowClass extends TreeRow {
shouldComponentUpdate(nextProps) {
const props = ["name", "open", "value", "loading", "selected", "hasChildren"];
@ -138,6 +146,44 @@ class AccessibilityRow extends Component {
walker.unhighlight().catch(error => console.warn(error));
}
async printToJSON() {
const { member, supports } = this.props;
if (!supports.snapshot) {
// Debugger server does not support Accessible actor snapshots.
return;
}
const snapshot = await member.object.snapshot();
openDocLink(`${JSON_URL_PREFIX}${encodeURIComponent(JSON.stringify(snapshot))}`);
}
onContextMenu(e) {
e.stopPropagation();
e.preventDefault();
if (!gToolbox) {
return;
}
const menu = new Menu({ id: "accessibility-row-contextmenu" });
const { supports } = this.props;
if (supports.snapshot) {
menu.append(new MenuItem({
id: "menu-printtojson",
label: L10N.getStr("accessibility.tree.menu.printToJSON"),
click: () => this.printToJSON(),
}));
}
menu.popup(e.screenX, e.screenY, gToolbox);
}
get hasContextMenu() {
const { supports } = this.props;
return supports.snapshot;
}
/**
* Render accessible row component.
* @returns acecssible-row React component.
@ -145,6 +191,7 @@ class AccessibilityRow extends Component {
render() {
const { object } = this.props.member;
const props = Object.assign({}, this.props, {
onContextMenu: this.hasContextMenu && (e => this.onContextMenu(e)),
onMouseOver: () => this.highlight(object),
onMouseOut: () => this.unhighlight(),
});

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

@ -5,3 +5,4 @@ support-files =
[test_accessible_learnMoreLink.html]
[test_accessible_openLink.html]
[test_accessible_relations.html]
[test_accessible_row_context_menu.html]

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

@ -0,0 +1,164 @@
<!-- 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/. -->
<!DOCTYPE HTML>
<html>
<!--
Test that openLink function is called if accessible object property is rendered as a link.
-->
<head>
<meta charset="utf-8">
<title>AccessibilityRow context menu test</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<link rel="stylesheet" href="chrome://devtools/skin/light-theme.css" type="text/css">
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
"use strict";
window.onload = async function() {
try {
const { gDevTools } = require("devtools/client/framework/devtools");
const Services = browserRequire("Services");
const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
const { createFactory, createElement } =
browserRequire("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const createStore = require("devtools/client/shared/redux/create-store")();
const { Simulate } =
browserRequire("devtools/client/shared/vendor/react-dom-test-utils");
const AccessibilityRow = createFactory(
browserRequire("devtools/client/accessibility/components/AccessibilityRow"));
async function withMockEnv(func) {
const { gToolbox: originalToolbox, gTelemetry: originalTelemetry } = window;
window.gToolbox = { doc: document };
window.gTelemetry = null;
await func();
window.gToolbox = originalToolbox;
window.gTelemetry = originalTelemetry;
}
function renderAccessibilityRow(newProps, newState) {
let container = document.getElementById("container");
if (container) {
container.remove();
}
const accRow = AccessibilityRow(newProps);
const mockStore = createStore((state, action) =>
action ? { ...state, ...action } : state, newState);
const provider = createElement(Provider, { store: mockStore }, accRow);
container = document.createElement("div");
container.id = "container";
document.body.appendChild(container);
return ReactDOM.render(provider, container);
}
const checker = Symbol();
let isCalled;
const ROW_ID = "test-row";
const JSON_URL_PREFIX = "data:application/json;charset=UTF-8,";
const SNAPSHOT = { "snapshot": true };
const defaultProps = {
id: ROW_ID,
member: {
object: {
name: "test",
value: "test",
loading: false,
selected: false,
hasChildren: false,
snapshot: async () => SNAPSHOT,
},
},
columns: [
{ "id": "default", "title": "role" },
{ "id": "value", "title": "name" },
],
provider: {
getValue: (object, id) => object[id],
},
};
const mockProps = {
...defaultProps,
onContextMenu: () => {
isCalled = true;
},
};
const defaultState = { ui: { supports: { snapshot: true }}};
const mockState = { ui: { supports: {}}};
info("Check contextmenu default behaviour.");
renderAccessibilityRow(defaultProps, defaultState);
let row = document.getElementById(ROW_ID);
await withMockEnv(async function() {
Simulate.contextMenu(row);
const menu = document.getElementById("accessibility-row-contextmenu");
const printtojsonMenuItem = document.getElementById("menu-printtojson");
ok(menu, "Accessibility row context menu is open");
ok(printtojsonMenuItem, "Print to JSON menu item is visible");
const browserWindow = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
const defaultOpenWebLinkIn = browserWindow.openWebLinkIn;
let openWebLinkInCalled;
const openWebLinkInPromise = new Promise(resolve => {
openWebLinkInCalled = resolve;
});
// Mock top chrome window's @openWebLinkIn method.
browserWindow.openWebLinkIn = (...args) => {
openWebLinkInCalled(args);
};
printtojsonMenuItem.click();
const [ url, where ] = await openWebLinkInPromise;
is(url, `${JSON_URL_PREFIX}${encodeURIComponent(JSON.stringify(SNAPSHOT))}`,
"Correct URL is opened");
is(where, "tab", "URL was opened correctly");
// Reset @openWebLinkIn to default.
browserWindow.openWebLinkIn = defaultOpenWebLinkIn;
});
info("Check accessibility row when context menu is not supported.");
renderAccessibilityRow(mockProps, mockState);
row = document.getElementById(ROW_ID);
info("Check contextmenu listener is not called when context menu is not supported.");
isCalled = checker;
Simulate.contextMenu(row);
ok(isCalled === checker, "contextmenu event handler was never called.");
info("Check accessibility row when context menu is supported.");
renderAccessibilityRow(mockProps, defaultState);
row = document.getElementById(ROW_ID);
info("Check contextmenu listener is called when context menu is supported.");
isCalled = checker;
Simulate.contextMenu(row);
ok(isCalled, "contextmenu event handler was called correctly.");
} catch (e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
} finally {
SimpleTest.finish();
}
};
</script>
</pre>
</body>
</html>

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

@ -101,3 +101,8 @@ accessibility.description.general.p2=Accessibility features may affect the perfo
# when accessibility service description is provided when a client is connected
# to an older version of accessibility actor.
accessibility.description.oldVersion=You are connected to a debugger server that is too old. To use Accessibility panel, please connect to the latest debugger server version.
# LOCALIZATION NOTE (accessibility.tree.menu.printToJSON): A title text used when a
# context menu item for printing an accessible tree to JSON is rendered after triggering a
# context menu for an accessible tree row.
accessibility.tree.menu.printToJSON=Print to JSON