Source: ui/text_selection.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.ui.TextSelection');
  7. goog.require('shaka.ui.Enums');
  8. goog.require('shaka.ui.LanguageUtils');
  9. goog.require('shaka.ui.Locales');
  10. goog.require('shaka.ui.Localization');
  11. goog.require('shaka.ui.OverflowMenu');
  12. goog.require('shaka.ui.SettingsMenu');
  13. goog.require('shaka.ui.Utils');
  14. goog.require('shaka.util.Dom');
  15. goog.require('shaka.util.FakeEvent');
  16. goog.requireType('shaka.ui.Controls');
  17. /**
  18. * @extends {shaka.ui.SettingsMenu}
  19. * @final
  20. * @export
  21. */
  22. shaka.ui.TextSelection = class extends shaka.ui.SettingsMenu {
  23. /**
  24. * @param {!HTMLElement} parent
  25. * @param {!shaka.ui.Controls} controls
  26. */
  27. constructor(parent, controls) {
  28. super(parent,
  29. controls, shaka.ui.Enums.MaterialDesignIcons.CLOSED_CAPTIONS);
  30. this.button.classList.add('shaka-caption-button');
  31. this.menu.classList.add('shaka-text-languages');
  32. if (this.player && this.player.isTextTrackVisible()) {
  33. this.button.ariaPressed = 'true';
  34. } else {
  35. this.button.ariaPressed = 'false';
  36. }
  37. this.addOffOption_();
  38. this.eventManager.listen(
  39. this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
  40. this.updateLocalizedStrings_();
  41. // If captions/subtitles are off, this string needs localization.
  42. // TODO: is there a more efficient way of updating just the strings
  43. // we need instead of running the whole language update?
  44. this.updateTextLanguages_();
  45. });
  46. this.eventManager.listen(
  47. this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => {
  48. this.updateLocalizedStrings_();
  49. // If captions/subtitles are off, this string needs localization.
  50. // TODO: is there a more efficient way of updating just the strings
  51. // we need instead of running the whole language update?
  52. this.updateTextLanguages_();
  53. });
  54. this.eventManager.listen(this.player, 'texttrackvisibility', () => {
  55. this.onCaptionStateChange_();
  56. });
  57. this.eventManager.listen(this.player, 'textchanged', () => {
  58. this.updateTextLanguages_();
  59. });
  60. this.eventManager.listen(this.player, 'trackschanged', () => {
  61. this.onTracksChanged_();
  62. });
  63. // Initialize caption state with a fake event.
  64. this.onCaptionStateChange_();
  65. // Set up all the strings in the user's preferred language.
  66. this.updateLocalizedStrings_();
  67. this.updateTextLanguages_();
  68. this.onTracksChanged_();
  69. }
  70. /**
  71. * @private
  72. */
  73. addOffOption_() {
  74. const off = shaka.util.Dom.createButton();
  75. off.ariaSelected = 'true';
  76. this.menu.appendChild(off);
  77. off.appendChild(shaka.ui.Utils.checkmarkIcon());
  78. /** @private {!HTMLElement} */
  79. this.captionsOffSpan_ = shaka.util.Dom.createHTMLElement('span');
  80. this.captionsOffSpan_.classList.add('shaka-auto-span');
  81. off.appendChild(this.captionsOffSpan_);
  82. }
  83. /** @private */
  84. onCaptionStateChange_() {
  85. if (this.player.isTextTrackVisible()) {
  86. this.icon.classList.add('shaka-captions-on');
  87. this.icon.classList.remove('shaka-captions-off');
  88. this.button.ariaPressed = 'true';
  89. } else {
  90. this.icon.classList.add('shaka-captions-off');
  91. this.icon.classList.remove('shaka-captions-on');
  92. this.button.ariaPressed = 'false';
  93. }
  94. this.controls.dispatchEvent(
  95. new shaka.util.FakeEvent('captionselectionupdated'));
  96. }
  97. /** @private */
  98. updateTextLanguages_() {
  99. const tracks = this.player.getTextTracks();
  100. shaka.ui.LanguageUtils.updateTracks(tracks, this.menu,
  101. (track) => this.onTextTrackSelected_(track),
  102. // Don't mark current text language as chosen unless captions are
  103. // enabled
  104. this.player.isTextTrackVisible(),
  105. this.currentSelection,
  106. this.localization,
  107. this.controls.getConfig().trackLabelFormat);
  108. // Add the Off button
  109. const offButton = shaka.util.Dom.createButton();
  110. offButton.classList.add('shaka-turn-captions-off-button');
  111. this.eventManager.listen(offButton, 'click', () => {
  112. this.player.setTextTrackVisibility(false);
  113. this.updateTextLanguages_();
  114. });
  115. offButton.appendChild(this.captionsOffSpan_);
  116. this.menu.appendChild(offButton);
  117. if (!this.player.isTextTrackVisible()) {
  118. offButton.ariaSelected = 'true';
  119. offButton.appendChild(shaka.ui.Utils.checkmarkIcon());
  120. this.captionsOffSpan_.classList.add('shaka-chosen-item');
  121. this.currentSelection.textContent =
  122. this.localization.resolve(shaka.ui.Locales.Ids.OFF);
  123. }
  124. shaka.ui.Utils.focusOnTheChosenItem(this.menu);
  125. this.controls.dispatchEvent(
  126. new shaka.util.FakeEvent('captionselectionupdated'));
  127. }
  128. /**
  129. * @param {!shaka.extern.Track} track
  130. * @return {!Promise}
  131. * @private
  132. */
  133. async onTextTrackSelected_(track) {
  134. // setTextTrackVisibility should be called after selectTextTrack.
  135. // selectTextTrack sets a text stream, and setTextTrackVisiblity(true)
  136. // will set a text stream if it isn't already set. Consequently, reversing
  137. // the order of these calls makes two languages display simultaneously
  138. // if captions are turned off -> on in a different language.
  139. this.player.selectTextTrack(track);
  140. await this.player.setTextTrackVisibility(true);
  141. }
  142. /**
  143. * @private
  144. */
  145. updateLocalizedStrings_() {
  146. const LocIds = shaka.ui.Locales.Ids;
  147. this.button.ariaLabel = this.localization.resolve(LocIds.CAPTIONS);
  148. this.backButton.ariaLabel = this.localization.resolve(LocIds.BACK);
  149. this.nameSpan.textContent =
  150. this.localization.resolve(LocIds.CAPTIONS);
  151. this.backSpan.textContent =
  152. this.localization.resolve(LocIds.CAPTIONS);
  153. this.captionsOffSpan_.textContent =
  154. this.localization.resolve(LocIds.OFF);
  155. }
  156. /** @private */
  157. onTracksChanged_() {
  158. const hasText = this.player.getTextTracks().length > 0;
  159. shaka.ui.Utils.setDisplay(this.button, hasText);
  160. this.updateTextLanguages_();
  161. }
  162. };
  163. /**
  164. * @implements {shaka.extern.IUIElement.Factory}
  165. * @final
  166. */
  167. shaka.ui.TextSelection.Factory = class {
  168. /** @override */
  169. create(rootElement, controls) {
  170. return new shaka.ui.TextSelection(rootElement, controls);
  171. }
  172. };
  173. shaka.ui.OverflowMenu.registerElement(
  174. 'captions', new shaka.ui.TextSelection.Factory());