Skip to content

Commit 1cf2fb4

Browse files
committed
Initial import of SlackA11yFixes.
* Reorder some elements which appear earlier in the DOM but later visually. For example, the input area appears near the top of the document but should logically be near the bottom). * Make message timestamps appear on a single line instead of crossing several lines. * Make the star control and its status accessible. * Make the close link for the about channel pane accessible. * Make day separators in the message history and the about channel pane heading into headings. * Hide an editable area which isn't shown visually.
1 parent 97be411 commit 1cf2fb4

File tree

1 file changed

+93
-0
lines changed

1 file changed

+93
-0
lines changed

SlackA11yFixes.user.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// ==UserScript==
2+
// @name Slack Accessibility Fixes
3+
// @namespace http://axSgrease.nvaccess.org/
4+
// @description Improves the accessibility of Slack.
5+
// @author James Teh <jamie@nvaccess.org>
6+
// @copyright 2017 NV Access Limited
7+
// @license GNU General Public License version 2.0
8+
// @version 2017.1
9+
// @grant GM_log
10+
// @include https://*.slack.com/*
11+
// ==/UserScript==
12+
13+
function initial() {
14+
var elem;
15+
// In DOM order, the footer is earlier than the messages.
16+
// Put it below for a11y (as it appears visually).
17+
if (elem = document.querySelector("#col_messages"))
18+
elem.setAttribute("aria-owns", "messages_container footer");
19+
// Same for the unread messages status, which appears below in DOM order but earlier visually.
20+
if (elem = document.querySelector("#messages_container"))
21+
elem.setAttribute("aria-owns", "messages_unread_status monkey_scroll_wrapper_for_msgs_scroller_div");
22+
// Make close link for about channel pane accessible.
23+
for (elem of document.querySelectorAll(".close_flexpane")) {
24+
elem.setAttribute("role", "button");
25+
// The content is a private use Unicode character. Use the title as the name.
26+
elem.setAttribute("aria-label", elem.getAttribute("title"));
27+
}
28+
}
29+
30+
// Make the starred status accessible.
31+
function setStarred(elem) {
32+
elem.setAttribute("aria-pressed",
33+
elem.classList.contains("starred") ? "true" : "false");
34+
}
35+
36+
function onNodeAdded(target) {
37+
if (target.matches(".offscreen[contenteditable]")) {
38+
// Hidden contentEditable near the bottom which doesn't seem to be relevant to the user.
39+
target.setAttribute("role", "presentation");
40+
return;
41+
}
42+
var elem;
43+
for (elem of target.querySelectorAll(".copy_only")) {
44+
// This includes text such as the brackets around message times.
45+
// These chunks of text are block elements, even though they're on the same line.
46+
// Remove the elements from the tree so the text becomes inline.
47+
elem.setAttribute("role", "presentation");
48+
}
49+
// Channel/message star controls.
50+
for (elem of target.querySelectorAll(".star")) {
51+
elem.setAttribute("aria-label", "star");
52+
setStarred(elem);
53+
}
54+
// Make headings for day separators in message history, about channel pane heading.
55+
for (elem of target.querySelectorAll(".day_divider,.heading")) {
56+
elem.setAttribute("role", "heading");
57+
elem.setAttribute("aria-level", "2");
58+
}
59+
}
60+
61+
function onClassModified(target) {
62+
var classes = target.classList;
63+
if (!classes)
64+
return;
65+
if (classes.contains("star")) {
66+
// Starred state changed.
67+
setStarred(target);
68+
}
69+
}
70+
71+
var observer = new MutationObserver(function(mutations) {
72+
for (var mutation of mutations) {
73+
try {
74+
if (mutation.type === "childList") {
75+
for (var node of mutation.addedNodes) {
76+
if (node.nodeType != Node.ELEMENT_NODE)
77+
continue;
78+
onNodeAdded(node);
79+
}
80+
} else if (mutation.type === "attributes") {
81+
if (mutation.attributeName == "class")
82+
onClassModified(mutation.target);
83+
}
84+
} catch (e) {
85+
// Catch exceptions for individual mutations so other mutations are still handled.
86+
GM_log("Exception while handling mutation: " + e);
87+
}
88+
}
89+
});
90+
observer.observe(document, {childList: true, attributes: true,
91+
subtree: true, attributeFilter: ["class"]});
92+
93+
initial();

0 commit comments

Comments
 (0)