a11y: role=menu / menuitem / separator on the two right-click context menus
Both context menus (queue row + VOD card) were built as plain <div> trees with no ARIA roles — screen readers couldn't tell they were menus, and the individual rows weren't exposed as menu items. Users on assistive tech got a generic "group of nested divs" with no menu semantics, despite the menus being visually and functionally menus. Added the WAI-ARIA menu pattern roles: - role="menu" on the container - role="menuitem" on each clickable row - aria-disabled="true" on disabled menu items - role="separator" on the horizontal divider lines Both renderer-queue.ts (queue right-click context menu) and renderer-streamers.ts (VOD card right-click context menu) get the same treatment so the two share both visual style (.context-menu — 4.6.120) and accessibility semantics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7de560f44c
commit
8d95a4a6a5
@ -186,11 +186,14 @@ function showQueueContextMenu(x: number, y: number, item: QueueItem): void {
|
|||||||
|
|
||||||
const menu = document.createElement('div');
|
const menu = document.createElement('div');
|
||||||
menu.className = 'context-menu';
|
menu.className = 'context-menu';
|
||||||
|
menu.setAttribute('role', 'menu');
|
||||||
|
|
||||||
const makeItem = (label: string, onClick: () => void, disabled = false): HTMLElement => {
|
const makeItem = (label: string, onClick: () => void, disabled = false): HTMLElement => {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.textContent = label;
|
el.textContent = label;
|
||||||
el.className = 'context-menu-item' + (disabled ? ' disabled' : '');
|
el.className = 'context-menu-item' + (disabled ? ' disabled' : '');
|
||||||
|
el.setAttribute('role', 'menuitem');
|
||||||
|
if (disabled) el.setAttribute('aria-disabled', 'true');
|
||||||
if (!disabled) {
|
if (!disabled) {
|
||||||
el.addEventListener('click', () => {
|
el.addEventListener('click', () => {
|
||||||
try { onClick(); } finally { closeQueueContextMenu(); }
|
try { onClick(); } finally { closeQueueContextMenu(); }
|
||||||
@ -202,6 +205,7 @@ function showQueueContextMenu(x: number, y: number, item: QueueItem): void {
|
|||||||
const makeSeparator = (): HTMLElement => {
|
const makeSeparator = (): HTMLElement => {
|
||||||
const sep = document.createElement('div');
|
const sep = document.createElement('div');
|
||||||
sep.className = 'context-menu-separator';
|
sep.className = 'context-menu-separator';
|
||||||
|
sep.setAttribute('role', 'separator');
|
||||||
return sep;
|
return sep;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -925,6 +925,7 @@ function showVodContextMenu(x: number, y: number, ctx: VodCardContext): void {
|
|||||||
|
|
||||||
const menu = document.createElement('div');
|
const menu = document.createElement('div');
|
||||||
menu.className = 'context-menu';
|
menu.className = 'context-menu';
|
||||||
|
menu.setAttribute('role', 'menu');
|
||||||
|
|
||||||
const downloadedIds = new Set(
|
const downloadedIds = new Set(
|
||||||
Array.isArray(config.downloaded_vod_ids)
|
Array.isArray(config.downloaded_vod_ids)
|
||||||
@ -937,6 +938,7 @@ function showVodContextMenu(x: number, y: number, ctx: VodCardContext): void {
|
|||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.textContent = label;
|
el.textContent = label;
|
||||||
el.className = 'context-menu-item';
|
el.className = 'context-menu-item';
|
||||||
|
el.setAttribute('role', 'menuitem');
|
||||||
el.addEventListener('click', () => {
|
el.addEventListener('click', () => {
|
||||||
try { onClick(); } finally { closeVodContextMenu(); }
|
try { onClick(); } finally { closeVodContextMenu(); }
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user