feat(UI): Improve shaka player UI accessibility (#10023)

### ARIA attributes
  - Add `aria-hidden="true"` to all decorative SVG icons (`icon.js`)
- Implement missing `aria-label` for ad controls (`skip_ad_button.js`,
`ad_info.js`)
- Add `aria-pressed` to toggle buttons (mute, fullscreen, pip, loop,
statistics, remote, stereoscopic)
- Remove incorrect `aria-pressed` from one-shot action button
(`recenter_vr.js`)
- Add `role="menu"`, `aria-haspopup`, `aria-expanded` to menus
(`overflow_menu.js`, `settings_menu.js`, `context_menu.js`)
- Add `role="menuitemradio"` and `aria-checked` to selection menus
(resolution, language, text, playback rate, etc.)
- Add `role="toolbar"` to control panel (`controls.js`)
- Add `role="heading"` to content title (`content_title.js`)
  
### Focus management
- Restore focus to trigger button when menus close
  - Maintain focus on fullscreen button after toggle     

 ### CSS
- Add `forced-colors` media query for Windows high contrast mode
  ### Other
- Add `alt=""` to seek bar thumbnail image
- Add `aria-hidden="true"` to watermark canvas
  - Add accessibility unit tests for ARIA attributes
- Remove redundant `aria-hidden` from checkmark icon (`ui_utils.js`)
  - Add ARIA terms to project spell-check dictionary  

Issue https://github.com/shaka-project/shaka-player/issues/3146
This commit is contained in:
Andy(김규회)
2026-04-23 21:53:23 +09:00
committed by GitHub
parent 07669cf917
commit f1c0468f70
31 changed files with 185 additions and 20 deletions
+2
View File
@@ -1,5 +1,7 @@
# events / html
abrstatuschanged
haspopup
menuitemradio
adblocker
audiofocuspaused
audiofocusgranted
+74 -2
View File
@@ -385,6 +385,17 @@ describe('UI', () => {
}
}
});
it('has correct ARIA roles', () => {
expect(overflowMenu.getAttribute('role')).toBe('menu');
});
it('has aria-haspopup and aria-expanded on menu button', () => {
const menuButton = videoContainer.getElementsByClassName(
'shaka-overflow-menu-button')[0];
expect(menuButton.getAttribute('aria-haspopup')).toBe('true');
expect(menuButton.getAttribute('aria-expanded')).toBe('false');
});
});
describe('controls-button-panel', () => {
@@ -502,6 +513,39 @@ describe('UI', () => {
confirmAriaLabel('shaka-fast-forward-button');
confirmAriaLabel('shaka-rewind-button');
});
it('has toolbar role', async () => {
await UiUtils.createUIThroughAPI(videoContainer, video);
const controlsButtonPanels = videoContainer.getElementsByClassName(
'shaka-controls-button-panel');
expect(controlsButtonPanels.length).toBe(1);
expect(controlsButtonPanels[0].getAttribute('role')).toBe('toolbar');
});
it('has aria-pressed on toggle buttons', async () => {
const config = {
controlPanelElements: [
'mute',
'fullscreen',
],
};
await UiUtils.createUIThroughAPI(videoContainer, video, config);
const muteButton = videoContainer.getElementsByClassName(
'shaka-mute-button')[0];
const fullscreenButton = videoContainer.getElementsByClassName(
'shaka-fullscreen-button')[0];
expect(muteButton.hasAttribute('aria-pressed')).toBe(true);
expect(fullscreenButton.hasAttribute('aria-pressed')).toBe(true);
});
it('has aria-hidden on SVG icons', async () => {
await UiUtils.createUIThroughAPI(videoContainer, video);
const icons = videoContainer.getElementsByClassName('shaka-ui-icon');
for (const icon of icons) {
expect(icon.getAttribute('aria-hidden')).toBe('true');
}
});
});
describe('control panel buttons with submenus', () => {
@@ -583,6 +627,33 @@ describe('UI', () => {
expect(resolutionMenu.classList.contains('shaka-hidden')).toBe(true);
expect(languageMenu.classList.contains('shaka-hidden')).toBe(false);
});
it('settings menus have ARIA roles', () => {
expect(resolutionMenu.getAttribute('role')).toBe('menu');
expect(languageMenu.getAttribute('role')).toBe('menu');
});
it('settings menu buttons have aria-haspopup and aria-expanded', () => {
expect(resolutionMenuButton.getAttribute('aria-haspopup'))
.toBe('true');
expect(resolutionMenuButton.getAttribute('aria-expanded'))
.toBe('false');
expect(languageMenuButton.getAttribute('aria-haspopup'))
.toBe('true');
expect(languageMenuButton.getAttribute('aria-expanded'))
.toBe('false');
});
it('aria-expanded updates when menu opens and closes', () => {
resolutionMenuButton.click();
expect(resolutionMenuButton.getAttribute('aria-expanded'))
.toBe('true');
resolutionMenuButton.click();
expect(resolutionMenuButton.getAttribute('aria-expanded'))
.toBe('false');
});
});
describe('resolutions menu', () => {
@@ -854,8 +925,9 @@ describe('UI', () => {
it('builds internal elements', () => {
expect(contextMenu.childNodes.length).toBe(1);
expect(contextMenu.childNodes[0]['className'])
.toBe('shaka-statistics-button');
const element = /** @type {!HTMLElement} */ (contextMenu.childNodes[0]);
expect(element.classList.contains('shaka-statistics-button'))
.toBe(true);
});
});
+3 -1
View File
@@ -77,7 +77,7 @@ shaka.ui.AdInfo = class extends shaka.ui.Element {
* @private
*/
updateAriaLabel_() {
// TODO
// arai-label is set dynamically in onTimerTick_().
}
/**
@@ -119,6 +119,7 @@ shaka.ui.AdInfo = class extends shaka.ui.Element {
if (secondsLeft == -1 || adDuration == -1 ||
!isFinite(secondsLeft) || !isFinite(adDuration)) {
this.adInfo_.textContent = text;
this.adInfo_.ariaLabel = text;
shaka.ui.Utils.setDisplay(this.adInfo_, text != '');
return;
}
@@ -141,6 +142,7 @@ shaka.ui.AdInfo = class extends shaka.ui.Element {
.replace('[AD_TIME]', timeString);
}
this.adInfo_.textContent = text;
this.adInfo_.ariaLabel = text;
shaka.ui.Utils.setDisplay(this.adInfo_, text != '');
} else {
this.reset_();
+5
View File
@@ -38,6 +38,9 @@ shaka.ui.AdStatisticsButton = class extends shaka.ui.Element {
/** @private {!HTMLButtonElement} */
this.button_ = shaka.util.Dom.createButton();
this.button_.classList.add('shaka-ad-statistics-button');
this.button_.classList.add('shaka-tooltip');
this.button_.classList.add('shaka-no-propagation');
this.button_.ariaPressed = 'false';
/** @private {!shaka.ui.Icon} */
this.icon_ = new shaka.ui.Icon(this.button_,
@@ -156,10 +159,12 @@ shaka.ui.AdStatisticsButton = class extends shaka.ui.Element {
this.icon_.use(shaka.ui.Enums.MaterialDesignSVGIcons['STATISTICS_OFF']);
this.timer_.tickEvery(0.1);
shaka.ui.Utils.setDisplay(this.container_, true);
this.button_.ariaPressed = 'true';
} else {
this.icon_.use(shaka.ui.Enums.MaterialDesignSVGIcons['STATISTICS_ON']);
this.timer_.stop();
shaka.ui.Utils.setDisplay(this.container_, false);
this.button_.ariaPressed = 'false';
}
}
+1
View File
@@ -114,6 +114,7 @@ shaka.ui.ChapterSelection = class extends shaka.ui.SettingsMenu {
if (chapters.length) {
for (const chapter of chapters) {
const button = shaka.util.Dom.createButton();
button.setAttribute('role', 'menuitem');
button.classList.add('shaka-chapter-item');
const span = shaka.util.Dom.createHTMLElement('span');
span.classList.add('shaka-chapter');
+2
View File
@@ -34,6 +34,8 @@ shaka.ui.ContentTitle = class extends shaka.ui.Element {
/** @type {!HTMLElement} */
this.title_ = shaka.util.Dom.createHTMLElement('div');
this.title_.classList.add('shaka-content-title');
this.title_.setAttribute('role', 'heading');
this.title_.setAttribute('aria-level', '2');
this.parent.appendChild(this.title_);
this.eventManager.listen(this.player, 'unloading', () => {
+1
View File
@@ -44,6 +44,7 @@ shaka.ui.ContextMenu = class extends shaka.ui.Element {
this.contextMenu_.classList.add('shaka-no-propagation');
this.contextMenu_.classList.add('shaka-context-menu');
this.contextMenu_.classList.add('shaka-hidden');
this.contextMenu_.setAttribute('role', 'menu');
this.controlsContainer_.appendChild(this.contextMenu_);
+2
View File
@@ -1528,6 +1528,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
this.controlsButtonPanel_.classList.add('shaka-controls-button-panel');
this.controlsButtonPanel_.classList.add(
'shaka-show-controls-on-mouse-over');
this.controlsButtonPanel_.setAttribute('role', 'toolbar');
if (this.config_.enableTooltips) {
this.controlsButtonPanel_.classList.add('shaka-tooltips-on');
}
+3
View File
@@ -63,6 +63,7 @@ shaka.ui.FullscreenButton = class extends shaka.ui.Element {
return;
}
await this.controls.toggleFullScreen();
this.button_.focus();
});
this.eventManager.listen(document, 'fullscreenchange', () => {
@@ -110,6 +111,8 @@ shaka.ui.FullscreenButton = class extends shaka.ui.Element {
LocIds.EXIT_FULL_SCREEN : LocIds.FULL_SCREEN;
this.button_.ariaLabel = this.localization.resolve(label);
this.button_.ariaPressed =
this.controls.isFullScreenEnabled() ? 'true' : 'false';
}
/**
+3
View File
@@ -24,6 +24,9 @@ shaka.ui.Icon = class {
this.svg_ = shaka.util.Dom.createSVGElement('svg');
this.svg_.classList.add('shaka-ui-icon');
// Screen reader should ignore icon text.
// all icons should have this attribute
this.svg_.ariaHidden = 'true';
this.svg_.setAttribute('viewBox', '0 -960 960 960');
if (icon) {
+8 -2
View File
@@ -181,6 +181,9 @@ shaka.ui.LanguageUtils = class {
button.addEventListener('click', () => {
onTrackSelected(track);
});
// ARIA: single-select menu item
button.setAttribute('role', 'menuitemradio');
button.setAttribute('aria-checked', 'false');
const span = shaka.util.Dom.createHTMLElement('span');
button.appendChild(span);
@@ -262,7 +265,7 @@ shaka.ui.LanguageUtils = class {
if (updateChosen && (combinationName == selectedCombination)) {
button.appendChild(shaka.ui.Utils.checkmarkIcon());
span.classList.add('shaka-chosen-item');
button.ariaSelected = 'true';
button.setAttribute('aria-checked', 'true');
currentSelectionElement.textContent = span.textContent;
}
langMenu.appendChild(button);
@@ -345,6 +348,9 @@ shaka.ui.LanguageUtils = class {
button.addEventListener('click', () => {
onTrackSelected(track);
});
// ARIA: single-select menu item
button.setAttribute('role', 'menuitemradio');
button.setAttribute('aria-checked', 'false');
const span = shaka.util.Dom.createHTMLElement('span');
button.appendChild(span);
@@ -433,7 +439,7 @@ shaka.ui.LanguageUtils = class {
if (updateChosen && (combinationName == selectedCombination)) {
button.appendChild(shaka.ui.Utils.checkmarkIcon());
span.classList.add('shaka-chosen-item');
button.ariaSelected = 'true';
button.setAttribute('aria-checked', 'true');
currentSelectionElement.textContent = span.textContent;
}
langMenu.appendChild(button);
+8
View File
@@ -145,3 +145,11 @@ the control buttons panel. */
@quality-mark-color: #fff;
@quality-mark-hightlight-color: #f00;
@media (forced-colors: active) {
.shaka-overflow-menu,
.shaka-settings-menu,
.shaka-context-menu {
border: 1px solid ButtonText;
}
}
+2
View File
@@ -39,6 +39,7 @@ shaka.ui.LoopButton = class extends shaka.ui.Element {
this.button_.classList.add('shaka-loop-button');
this.button_.classList.add('shaka-tooltip');
this.button_.classList.add('shaka-no-propagation');
this.button_.ariaPressed = 'false';
/** @private {!shaka.ui.Icon} */
this.icon_ = new shaka.ui.Icon(this.button_,
@@ -181,6 +182,7 @@ shaka.ui.LoopButton = class extends shaka.ui.Element {
LocIds.EXIT_LOOP_MODE : LocIds.ENTER_LOOP_MODE;
this.button_.ariaLabel = this.localization.resolve(ariaText);
this.button_.ariaPressed = this.video.loop ? 'true' : 'false';
}
+4
View File
@@ -38,6 +38,7 @@ shaka.ui.MuteButton = class extends shaka.ui.Element {
this.button_.classList.add('shaka-mute-button');
this.button_.classList.add('shaka-tooltip');
this.button_.classList.add('shaka-no-propagation');
this.button_.ariaPressed = 'false';
/** @private {!shaka.ui.Icon} */
this.icon_ = new shaka.ui.Icon(this.button_,
@@ -154,6 +155,9 @@ shaka.ui.MuteButton = class extends shaka.ui.Element {
}
this.button_.ariaLabel = this.localization.resolve(label);
this.button_.ariaLabel = this.localization.resolve(label);
this.button_.ariaPressed = label == LocIds.UNMUTE ? 'true' : 'false';
this.nameSpan_.textContent = this.localization.resolve(label);
this.nameSpan_.textContent = this.localization.resolve(label);
}
+6
View File
@@ -145,6 +145,7 @@ shaka.ui.OverflowMenu = class extends shaka.ui.Element {
this.overflowMenu_.classList.add('shaka-no-propagation');
this.overflowMenu_.classList.add('shaka-show-controls-on-mouse-over');
this.overflowMenu_.classList.add('shaka-hidden');
this.overflowMenu_.setAttribute('role', 'menu');
this.controlsContainer_.appendChild(this.overflowMenu_);
}
@@ -155,6 +156,8 @@ shaka.ui.OverflowMenu = class extends shaka.ui.Element {
addOverflowMenuButton_() {
/** @private {!HTMLButtonElement} */
this.overflowMenuButton_ = shaka.util.Dom.createButton();
this.overflowMenuButton_.setAttribute('aria-haspopup', 'true');
this.overflowMenuButton_.setAttribute('aria-expanded', 'false');
this.overflowMenuButton_.classList.add('shaka-overflow-menu-button');
this.overflowMenuButton_.classList.add('shaka-no-propagation');
this.overflowMenuButton_.classList.add('shaka-tooltip');
@@ -191,11 +194,14 @@ shaka.ui.OverflowMenu = class extends shaka.ui.Element {
this.controls.hideContextMenus();
if (this.controls.anySettingsMenusAreOpen()) {
this.controls.hideSettingsMenus();
this.overflowMenuButton_.setAttribute('aria-expanded', 'false');
this.overflowMenuButton_.focus();
} else {
// Force to close any submenu.
this.controls.dispatchEvent(new shaka.util.FakeEvent('submenuclose'));
shaka.ui.Utils.setDisplay(this.overflowMenu_, true);
this.overflowMenuButton_.setAttribute('aria-expanded', 'true');
this.controls.computeOpacity();
// If overflow menu has currently visible buttons, focus on the
+3
View File
@@ -44,6 +44,7 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
this.pipButton_.classList.add('shaka-pip-button');
this.pipButton_.classList.add('shaka-tooltip');
this.pipButton_.classList.add('shaka-no-propagation');
this.pipButton_.ariaPressed = 'false';
/** @private {!shaka.ui.Icon} */
this.pipIcon_ = new shaka.ui.Icon(this.pipButton_,
@@ -143,6 +144,7 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
this.localization.resolve(LocIds.EXIT_PICTURE_IN_PICTURE);
this.currentPipState_.textContent =
this.localization.resolve(LocIds.ON);
this.pipButton_.ariaPressed = 'true';
}
@@ -154,6 +156,7 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
this.localization.resolve(LocIds.ENTER_PICTURE_IN_PICTURE);
this.currentPipState_.textContent =
this.localization.resolve(LocIds.OFF);
this.pipButton_.ariaPressed = 'false';
}
+4 -1
View File
@@ -115,7 +115,7 @@ shaka.ui.PlaybackRateSelection = class extends shaka.ui.SettingsMenu {
if (span) {
const button = span.parentElement;
button.appendChild(shaka.ui.Utils.checkmarkIcon());
button.ariaSelected = 'true';
button.setAttribute('aria-checked', 'true');
span.classList.add('shaka-chosen-item');
}
@@ -132,6 +132,9 @@ shaka.ui.PlaybackRateSelection = class extends shaka.ui.SettingsMenu {
addPlaybackRates_() {
for (const rate of this.controls.getConfig().playbackRates) {
const button = shaka.util.Dom.createButton();
// ARIA: single-select menu item
button.setAttribute('role', 'menuitemradio');
button.setAttribute('aria-checked', 'false');
const span = shaka.util.Dom.createHTMLElement('span');
span.textContent = rate + 'x';
button.appendChild(span);
-1
View File
@@ -36,7 +36,6 @@ shaka.ui.RecenterVRButton = class extends shaka.ui.Element {
this.recenterVRButton_ = shaka.util.Dom.createButton();
this.recenterVRButton_.classList.add('shaka-recenter-vr-button');
this.recenterVRButton_.classList.add('shaka-tooltip');
this.recenterVRButton_.ariaPressed = 'false';
/** @private {!shaka.ui.Icon} */
this.recenterVRIcon_ = new shaka.ui.Icon(this.recenterVRButton_,
+2
View File
@@ -197,6 +197,8 @@ shaka.ui.RemoteButton = class extends shaka.ui.Element {
this.callbackId_ = -1;
}
}
this.remoteButton_.ariaPressed =
this.remote_?.state == 'connected' ? 'true' : 'false';
}
/**
+12 -3
View File
@@ -230,6 +230,9 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
// Add the Auto button
const autoButton = shaka.util.Dom.createButton();
// ARIA: single-select menu item
autoButton.setAttribute('role', 'menuitemradio');
autoButton.setAttribute('aria-checked', 'false');
autoButton.classList.add('shaka-enable-abr-button');
this.eventManager.listen(autoButton, 'click', () => {
const config = {abr: {enabled: true}};
@@ -245,7 +248,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
// If abr is enabled reflect it by marking 'Auto' as selected.
if (this.player.getConfiguration().abr.enabled) {
autoButton.ariaSelected = 'true';
autoButton.setAttribute('aria-checked', 'true');
autoButton.appendChild(shaka.ui.Utils.checkmarkIcon());
this.abrOnSpan_.classList.add('shaka-chosen-item');
@@ -332,6 +335,9 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
// Add new ones
for (const track of tracks) {
const button = shaka.util.Dom.createButton();
// ARIA: single-select menu item
button.setAttribute('role', 'menuitemradio');
button.setAttribute('aria-checked', 'false');
button.classList.add('explicit-resolution');
this.eventManager.listen(button, 'click',
() => this.onTrackSelected_(track));
@@ -346,7 +352,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
if (!abrEnabled && track == selectedTrack) {
// If abr is disabled, mark the selected track's resolution.
button.ariaSelected = 'true';
button.setAttribute('aria-checked', 'true');
button.appendChild(shaka.ui.Utils.checkmarkIcon());
span.classList.add('shaka-chosen-item');
this.currentSelection.textContent = span.textContent;
@@ -405,6 +411,9 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
// Add new ones
for (const track of tracks) {
const button = shaka.util.Dom.createButton();
// ARIA: single-select menu item
button.setAttribute('role', 'menuitemradio');
button.setAttribute('aria-checked', 'false');
button.classList.add('explicit-resolution');
this.eventManager.listen(button, 'click',
() => this.onVideoTrackSelected_(track));
@@ -429,7 +438,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
if (!abrEnabled && track == selectedTrack) {
// If abr is disabled, mark the selected track's resolution.
button.ariaSelected = 'true';
button.setAttribute('aria-checked', 'true');
button.appendChild(shaka.ui.Utils.checkmarkIcon());
span.classList.add('shaka-chosen-item');
this.currentSelection.textContent = span.textContent;
+1
View File
@@ -746,6 +746,7 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement {
}
this.thumbnailImage_ = /** @type {!HTMLImageElement} */ (
shaka.util.Dom.createHTMLElement('img'));
this.thumbnailImage_.alt = '';
this.thumbnailImage_.classList.add('shaka-player-ui-thumbnail-image');
this.thumbnailImage_.draggable = false;
this.thumbnailImage_.src = uri;
+8
View File
@@ -88,6 +88,8 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
addButton_(iconText) {
/** @protected {!HTMLButtonElement} */
this.button = shaka.util.Dom.createButton();
this.button.setAttribute('aria-haspopup', 'true');
this.button.setAttribute('aria-expanded', 'false');
this.button.classList.add('shaka-overflow-button');
/** @protected {!shaka.ui.Icon}*/
@@ -118,6 +120,7 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
this.menu = shaka.util.Dom.createHTMLElement('div');
this.menu.classList.add('shaka-no-propagation');
this.menu.classList.add('shaka-show-controls-on-mouse-over');
this.menu.setAttribute('role', 'menu');
if (this.isSubMenu) {
this.menu.classList.add('shaka-sub-menu');
} else {
@@ -131,6 +134,7 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
this.menu.appendChild(this.backButton);
this.eventManager.listen(this.backButton, 'click', () => {
this.controls.hideSettingsMenus();
this.backButton.focus();
});
/** @private {shaka.ui.Icon} */
@@ -195,6 +199,7 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
onButtonClick_() {
if (!this.parent.classList.contains('shaka-context-menu')) {
this.controls.hideContextMenus();
this.button.setAttribute('aria-expanded', 'false');
}
if (!this.isSubMenu && this.controls.anySettingsMenusAreOpen()) {
this.controls.hideSettingsMenus();
@@ -206,8 +211,11 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
shaka.ui.Utils.setDisplay(this.menu, true);
shaka.ui.Utils.focusOnTheChosenItem(this.menu);
this.adjustCustomStyle_();
this.button.setAttribute('aria-expanded', 'true');
} else {
shaka.ui.Utils.setDisplay(this.menu, false);
this.button.setAttribute('aria-expanded', 'false');
this.button.focus();
}
}
}
+2 -1
View File
@@ -118,7 +118,8 @@ shaka.ui.SkipAdButton = class extends shaka.ui.Element {
* @private
*/
updateAriaLabel_() {
// TODO
const LocIds = shaka.ui.Locales.Ids;
this.button_.ariaLabel = this.localization.resolve(LocIds.SKIP_AD);
}
/**
+5
View File
@@ -37,6 +37,9 @@ shaka.ui.StatisticsButton = class extends shaka.ui.Element {
/** @private {!HTMLButtonElement} */
this.button_ = shaka.util.Dom.createButton();
this.button_.classList.add('shaka-statistics-button');
this.button_.classList.add('shaka-tooltip');
this.button_.classList.add('shaka-no-propagation');
this.button_.ariaPressed = 'false';
/** @private {!shaka.ui.Icon} */
this.icon_ = new shaka.ui.Icon(this.button_,
@@ -207,10 +210,12 @@ shaka.ui.StatisticsButton = class extends shaka.ui.Element {
this.icon_.use(shaka.ui.Enums.MaterialDesignSVGIcons['STATISTICS_OFF']);
this.timer_.tickEvery(0.1);
shaka.ui.Utils.setDisplay(this.container_, true);
this.button_.ariaPressed = 'true';
} else {
this.icon_.use(shaka.ui.Enums.MaterialDesignSVGIcons['STATISTICS_ON']);
this.timer_.stop();
shaka.ui.Utils.setDisplay(this.container_, false);
this.button_.ariaPressed = 'false';
}
}
+5 -2
View File
@@ -123,6 +123,9 @@ shaka.ui.TextPosition = class extends shaka.ui.SettingsMenu {
// 4. Add new items
for (const position of Object.values(shaka.config.PositionArea)) {
const button = shaka.util.Dom.createButton();
// ARIA: single-select menu item
button.setAttribute('role', 'menuitemradio');
button.setAttribute('aria-checked', 'false');
const span = shaka.util.Dom.createHTMLElement('span');
span.textContent = this.getNameOfPosition_(position);
button.appendChild(span);
@@ -145,7 +148,7 @@ shaka.ui.TextPosition = class extends shaka.ui.SettingsMenu {
this.menu, 'shaka-ui-icon shaka-chosen-item');
if (checkmarkIcon) {
const previouslySelectedButton = checkmarkIcon.parentElement;
previouslySelectedButton.removeAttribute('aria-selected');
previouslySelectedButton.setAttribute('aria-checked', 'false');
const previouslySelectedSpan =
previouslySelectedButton.getElementsByTagName('span')[0];
if (previouslySelectedSpan) {
@@ -164,7 +167,7 @@ shaka.ui.TextPosition = class extends shaka.ui.SettingsMenu {
if (span) {
const button = span.parentElement;
button.appendChild(shaka.ui.Utils.checkmarkIcon());
button.ariaSelected = 'true';
button.setAttribute('aria-checked', 'true');
span.classList.add('shaka-chosen-item');
}
this.currentSelection.textContent = positionAreaName;
+6 -2
View File
@@ -107,7 +107,9 @@ shaka.ui.TextSelection = class extends shaka.ui.SettingsMenu {
*/
addOffOption_() {
const off = shaka.util.Dom.createButton();
off.ariaSelected = 'true';
// ARIA: single-select menu item
off.setAttribute('role', 'menuitemradio');
off.setAttribute('aria-checked', 'true');
this.menu.appendChild(off);
off.appendChild(shaka.ui.Utils.checkmarkIcon());
@@ -164,7 +166,9 @@ shaka.ui.TextSelection = class extends shaka.ui.SettingsMenu {
this.menu.appendChild(offButton);
if (!hasTrack) {
offButton.ariaSelected = 'true';
// ARIA: single-select menu item
offButton.setAttribute('role', 'menuitemradio');
offButton.setAttribute('aria-checked', 'true');
offButton.appendChild(shaka.ui.Utils.checkmarkIcon());
this.captionsOffSpan_.classList.add('shaka-chosen-item');
this.currentSelection.textContent =
+5 -2
View File
@@ -121,6 +121,9 @@ shaka.ui.TextSize = class extends shaka.ui.SettingsMenu {
for (const fontScaleFactor of
this.controls.getConfig().captionsFontScaleFactors) {
const button = shaka.util.Dom.createButton();
// ARIA: single-select menu item
button.setAttribute('role', 'menuitemradio');
button.setAttribute('aria-checked', 'false');
const span = shaka.util.Dom.createHTMLElement('span');
span.textContent = fontScaleFactor * 100 + '%';
button.appendChild(span);
@@ -143,7 +146,7 @@ shaka.ui.TextSize = class extends shaka.ui.SettingsMenu {
this.menu, 'shaka-ui-icon shaka-chosen-item');
if (checkmarkIcon) {
const previouslySelectedButton = checkmarkIcon.parentElement;
previouslySelectedButton.removeAttribute('aria-selected');
previouslySelectedButton.setAttribute('aria-checked', 'false');
const previouslySelectedSpan =
previouslySelectedButton.getElementsByTagName('span')[0];
if (previouslySelectedSpan) {
@@ -162,7 +165,7 @@ shaka.ui.TextSize = class extends shaka.ui.SettingsMenu {
if (span) {
const button = span.parentElement;
button.appendChild(shaka.ui.Utils.checkmarkIcon());
button.ariaSelected = 'true';
button.setAttribute('aria-checked', 'true');
span.classList.add('shaka-chosen-item');
}
this.currentSelection.textContent = fontScaleFactorName;
+2
View File
@@ -77,6 +77,8 @@ shaka.ui.ToggleStereoscopicButton = class extends shaka.ui.Element {
return;
}
vr.toggleStereoscopicMode();
this.toggleStereoscopicButton_.ariaPressed =
vr.isStereoscopicModeEnabled() ? 'true' : 'false';
});
this.eventManager.listen(vr, 'vrstatuschanged', () => {
+1 -2
View File
@@ -70,8 +70,7 @@ shaka.ui.Utils = class {
shaka.ui.Enums.MaterialDesignSVGIcons['CHECKMARK']);
const iconElement = icon.getSvgElement();
iconElement.classList.add('shaka-chosen-item');
// Screen reader should ignore icon text.
iconElement.ariaHidden = 'true';
return iconElement;
}
+4 -1
View File
@@ -120,6 +120,9 @@ shaka.ui.VideoTypeSelection = class extends shaka.ui.SettingsMenu {
if (roles.size > 1) {
for (const role of roles) {
const button = shaka.util.Dom.createButton();
// ARIA: single-select menu item
button.setAttribute('role', 'menuitemradio');
button.setAttribute('aria-checked', 'false');
this.eventManager.listen(button, 'click',
() => this.onVideoRoleSelected_(role));
@@ -128,7 +131,7 @@ shaka.ui.VideoTypeSelection = class extends shaka.ui.SettingsMenu {
button.appendChild(span);
if (selectedTrack.roles.includes(role)) {
button.ariaSelected = 'true';
button.setAttribute('aria-checked', 'true');
button.appendChild(shaka.ui.Utils.checkmarkIcon());
span.classList.add('shaka-chosen-item');
this.currentSelection.textContent = span.textContent;
+1
View File
@@ -38,6 +38,7 @@ shaka.ui.Watermark = class extends shaka.ui.Element {
this.canvas_.style.height = '100%';
this.canvas_.style.zIndex = '2';
this.canvas_.style.pointerEvents = 'none';
this.canvas_.setAttribute('aria-hidden', 'true');
this.parent.appendChild(this.canvas_);
this.resizeCanvas_();