Files
shaka-player/ui/content_title.js
T
Andy(김규회) f1c0468f70 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
2026-04-23 14:53:23 +02:00

131 lines
3.4 KiB
JavaScript

/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.ui.ContentTitle');
goog.require('shaka.ads.Utils');
goog.require('shaka.ui.Controls');
goog.require('shaka.ui.Element');
goog.require('shaka.ui.Utils');
goog.require('shaka.util.Dom');
goog.require('shaka.util.TXml');
/**
* @extends {shaka.ui.Element}
* @final
* @export
*/
shaka.ui.ContentTitle = class extends shaka.ui.Element {
/**
* @param {!HTMLElement} parent
* @param {!shaka.ui.Controls} controls
*/
constructor(parent, controls) {
super(parent, controls);
/** @private {shaka.extern.IQueueManager} */
this.queueManager_ = this.controls.getQueueManager();
/** @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', () => {
this.title_.textContent = '';
shaka.ui.Utils.setDisplay(this.title_, false);
});
this.eventManager.listen(this.player, 'loading', () => {
this.title_.textContent = this.video.title || '';
this.setupInfoFromQueue_();
shaka.ui.Utils.setDisplay(this.title_, true);
});
this.eventManager.listen(
this.adManager, shaka.ads.Utils.AD_STARTED, () => {
shaka.ui.Utils.setDisplay(this.title_, !this.ad.isLinear());
});
this.eventManager.listen(
this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
shaka.ui.Utils.setDisplay(this.title_, true);
});
this.eventManager.listen(this.player, 'metadata', (event) => {
const payload = event['payload'];
if (!payload) {
return;
}
let title;
if (payload['key'] == 'TIT2' && payload['data']) {
title = payload['data'];
}
if (title) {
this.title_.textContent = title;
}
});
this.eventManager.listen(this.player, 'sessiondata', (event) => {
if (event['id'] != 'com.apple.hls.title') {
return;
}
const title = event['value'];
if (title) {
this.title_.textContent = title;
}
});
this.eventManager.listen(this.player, 'programinformation', (event) => {
if (!event['detail']) {
return;
}
const TXml = shaka.util.TXml;
/** @type {!shaka.extern.xml.Node} */
const detail = /** @type {!shaka.extern.xml.Node} */(event['detail']);
const titleNode = TXml.findChild(detail, 'Title');
if (titleNode) {
const title = TXml.getContents(titleNode);
if (title) {
this.title_.textContent = title;
}
}
});
}
/**
* @private
*/
setupInfoFromQueue_() {
const queueItemMetadata = this.queueManager_.getCurrentItem()?.metadata;
if (queueItemMetadata) {
const title = queueItemMetadata['title'];
if (title) {
this.title_.textContent = title;
}
}
}
};
/**
* @implements {shaka.extern.IUIElement.Factory}
* @final
*/
shaka.ui.ContentTitle.Factory = class {
/** @override */
create(rootElement, controls) {
return new shaka.ui.ContentTitle(rootElement, controls);
}
};
shaka.ui.Controls.registerElement(
'content_title', new shaka.ui.ContentTitle.Factory());