File size: 3,551 Bytes
6efa67a | 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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | /**
* Shared module between login and main app.
* Be careful what you import!
*/
const buttonSelectors = [
'.menu_button',
'.right_menu_button',
'.mes_button',
'.drawer-icon',
'.inline-drawer-icon',
'.swipe_left',
'.swipe_right',
'.character_select',
'.tags .tag',
'.jg-menu .jg-button',
'.bg_example .mobile-only-menu-toggle',
'.paginationjs-pages li a',
].join(', ');
const listSelectors = [
'.options-content',
'.list-group',
'#rm_print_characters_block',
'#rm_group_members',
'#rm_group_add_members',
'.tag_view_list_tags',
'.secretKeyManagerList',
'.recentChatList',
'.dataMaidCategoryContent',
'#userList',
'.bg_list',
].join(', ');
const listItemSelectors = [
'.options-content .list-group-item',
'.list-group .list-group-item',
'#rm_print_characters_block .entity_block',
'#rm_group_members .group_member',
'#rm_group_add_members .group_member',
'.tag_view_list_tags .tag_view_item',
'.secretKeyManagerList .secretKeyManagerItem',
'.recentChatList .recentChat',
'.dataMaidCategoryContent .dataMaidItem',
'#userList .userSelect',
'.bg_list .bg_example',
].join(', ');
const toolbarSelectors = [
'.jg-menu',
].join(', ');
const tabListSelectors = [
'#bg_tabs .bg_tabs_list',
].join(', ');
const tabItemSelectors = [
'#bg_tabs .bg_tabs_list .bg_tab_button',
].join(', ');
/** @type {Record<string, (element: Element) => void>} */
const a11yRules = {
[buttonSelectors]: (element) => {
element.setAttribute('role', 'button');
},
[listSelectors]: (element) => {
element.setAttribute('role', 'list');
},
[listItemSelectors]: (element) => {
element.setAttribute('role', 'listitem');
},
[toolbarSelectors]: (element) => {
element.setAttribute('role', 'toolbar');
},
[tabListSelectors]: (element) => {
element.setAttribute('role', 'tablist');
},
[tabItemSelectors]: (element) => {
element.setAttribute('role', 'tab');
},
'#toast-container .toast': (element) => {
element.setAttribute('role', 'status');
},
};
/**
* Apply accessibility rules to an element.
* @param {Element} element Element to process.
*/
function applyA11yRules(element) {
try {
for (const [selector, rule] of Object.entries(a11yRules)) {
// Apply if the element directly matches the selector
if (element.matches(selector)) {
rule(element);
}
// Apply the rule to descendants
element.querySelectorAll(selector).forEach(rule);
}
} catch (error) {
console.error('Error applying accessibility rules to element:', element, error);
}
}
function setAccessibilityObserver() {
// Apply for existing elements
applyA11yRules(document.body);
// Setup observer for dynamic content
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
for (const addedNode of mutation.addedNodes) {
if (addedNode instanceof Element && addedNode.nodeType === Node.ELEMENT_NODE) {
applyA11yRules(addedNode);
}
}
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
}
export function initAccessibility() {
setAccessibilityObserver();
}
|