-
Notifications
You must be signed in to change notification settings - Fork 17
/
PhabricatorA11yFixes.user.js
113 lines (99 loc) · 3.3 KB
/
PhabricatorA11yFixes.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// ==UserScript==
// @name Phabricator Accessibility Fixes
// @namespace http://axSgrease.nvaccess.org/
// @description Improves the accessibility of Phabricator.
// @author James Teh <[email protected]>
// @copyright 2018 Mozilla Corporation
// @license Mozilla Public License version 2.0
// @version 2018.2
// @grant GM_log
// @include https://phabricator.services.mozilla.com/D*
// ==/UserScript==
/*** Functions for common tweaks. ***/
function makeHeading(el, level) {
el.setAttribute("role", "heading");
el.setAttribute("aria-level", level);
}
function makeRegion(el, label) {
el.setAttribute("role", "region");
el.setAttribute("aria-label", label);
}
function makeButton(el, label) {
el.setAttribute("role", "button");
el.setAttribute("aria-label", label);
}
function makePresentational(el) {
el.setAttribute("role", "presentation");
}
function setLabel(el, label) {
el.setAttribute("aria-label", label);
}
/*** Code to apply the tweaks when appropriate. ***/
function applyTweaks(root, tweaks) {
for (let tweak of tweaks) {
for (let el of root.querySelectorAll(tweak.selector)) {
if (Array.isArray(tweak.tweak)) {
let [func, ...args] = tweak.tweak;
func(el, ...args);
} else {
tweak.tweak(el);
}
}
}
}
function init() {
applyTweaks(document, LOAD_TWEAKS);
applyTweaks(document, DYNAMIC_TWEAKS);
}
let observer = new MutationObserver(function(mutations) {
for (let mutation of mutations) {
try {
if (mutation.type === "childList") {
for (let node of mutation.addedNodes) {
if (node.nodeType != Node.ELEMENT_NODE) {
continue;
}
applyTweaks(node, DYNAMIC_TWEAKS);
}
}/* else if (mutation.type === "attributes") {
if (mutation.attributeName == "class") {
onClassModified(mutation.target);
}
}*/
} catch (e) {
// Catch exceptions for individual mutations so other mutations are still handled.
GM_log("Exception while handling mutation: " + e);
}
}
});
observer.observe(document, {childList: true,/* attributes: true,*/
subtree: true/*, attributeFilter: ["class"]*/});
/*** Define the actual tweaks. ***/
// Tweaks that only need to be applied on load.
const LOAD_TWEAKS = [
// There are some off-screen headings to denote various sections, but they
// are h3 instead of h1 as they should be.
{selector: '.phui-main-column .phui-timeline-view h3.aural-only, .phui-comment-preview-view .phui-timeline-view h3.aural-only, .phui-comment-form-view h3.aural-only',
tweak: [makeHeading, 1]},
// The diff is an h1, so the files inside the diff should be an h2, not an h1.
{selector: '.differential-file-icon-header',
tweak: [makeHeading, 2]},
]
// Tweaks that must be applied whenever a node is added.
const DYNAMIC_TWEAKS = [
// Timeline headings, "Summary" heading.
{selector: '.phui-timeline-title, .phui-property-list-section-header',
tweak: [makeHeading, 2]},
// Inline comment headings.
{selector: '.differential-inline-comment-head .inline-head-left',
tweak: [makeHeading, 3]},
{selector: '.phui-timeline-image, .phui-head-thing-image',
tweak: makePresentational},
// Code line numbers.
{selector: '.remarkup-code th',
// We don't want these to be header cells, as this causes a heap of spurious
// verbosity.
tweak: el => el.setAttribute("role", "cell")},
]
/*** Lights, camera, action! ***/
init();