Blame Raw
Cohee · 51ad27fb · · 131 lines (3.5 KB)
2 contributors
1/**
2 * Shared module between login and main app.
3 * Be careful what you import!
4 */
5
6const buttonSelectors = [
7 '.menu_button',
8 '.right_menu_button',
9 '.mes_button',
10 '.drawer-icon',
11 '.inline-drawer-icon',
12 '.swipe_left',
13 '.swipe_right',
14 '.character_select',
15 '.tags .tag',
16 '.jg-menu .jg-button',
17 '.bg_example .mobile-only-menu-toggle',
18 '.paginationjs-pages li a',
19 '#show_more_messages',
20].join(', ');
21
22const listSelectors = [
23 '.options-content',
24 '.list-group',
25 '#rm_print_characters_block',
26 '#rm_group_members',
27 '#rm_group_add_members',
28 '.tag_view_list_tags',
29 '.secretKeyManagerList',
30 '.recentChatList',
31 '.dataMaidCategoryContent',
32 '#userList',
33 '.bg_list',
34].join(', ');
35
36const listItemSelectors = [
37 '.options-content .list-group-item',
38 '.list-group .list-group-item',
39 '#rm_print_characters_block .entity_block',
40 '#rm_group_members .group_member',
41 '#rm_group_add_members .group_member',
42 '.tag_view_list_tags .tag_view_item',
43 '.secretKeyManagerList .secretKeyManagerItem',
44 '.recentChatList .recentChat',
45 '.dataMaidCategoryContent .dataMaidItem',
46 '#userList .userSelect',
47 '.bg_list .bg_example',
48].join(', ');
49
50const toolbarSelectors = [
51 '.jg-menu',
52].join(', ');
53
54const tabListSelectors = [
55 '#bg_tabs .bg_tabs_list',
56].join(', ');
57
58const tabItemSelectors = [
59 '#bg_tabs .bg_tabs_list .bg_tab_button',
60].join(', ');
61
62/** @type {Record<string, (element: Element) => void>} */
63const a11yRules = {
64 [buttonSelectors]: (element) => {
65 element.setAttribute('role', 'button');
66 },
67 [listSelectors]: (element) => {
68 element.setAttribute('role', 'list');
69 },
70 [listItemSelectors]: (element) => {
71 element.setAttribute('role', 'listitem');
72 },
73 [toolbarSelectors]: (element) => {
74 element.setAttribute('role', 'toolbar');
75 },
76 [tabListSelectors]: (element) => {
77 element.setAttribute('role', 'tablist');
78 },
79 [tabItemSelectors]: (element) => {
80 element.setAttribute('role', 'tab');
81 },
82 '#toast-container .toast': (element) => {
83 element.setAttribute('role', 'status');
84 },
85};
86
87/**
88 * Apply accessibility rules to an element.
89 * @param {Element} element Element to process.
90 */
91function applyA11yRules(element) {
92 try {
93 for (const [selector, rule] of Object.entries(a11yRules)) {
94 // Apply if the element directly matches the selector
95 if (element.matches(selector)) {
96 rule(element);
97 }
98 // Apply the rule to descendants
99 element.querySelectorAll(selector).forEach(rule);
100 }
101 } catch (error) {
102 console.error('Error applying accessibility rules to element:', element, error);
103 }
104}
105
106function setAccessibilityObserver() {
107 // Apply for existing elements
108 applyA11yRules(document.body);
109
110 // Setup observer for dynamic content
111 const observer = new MutationObserver((mutationsList) => {
112 for (const mutation of mutationsList) {
113 if (mutation.type === 'childList') {
114 for (const addedNode of mutation.addedNodes) {
115 if (addedNode instanceof Element && addedNode.nodeType === Node.ELEMENT_NODE) {
116 applyA11yRules(addedNode);
117 }
118 }
119 }
120 }
121 });
122
123 observer.observe(document.body, {
124 childList: true,
125 subtree: true,
126 });
127}
128
129export function initAccessibility() {
130 setAccessibilityObserver();
131}