Source: ui/playback_rate_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.PlaybackRateSelection');
  7. goog.require('shaka.ui.Controls');
  8. goog.require('shaka.ui.Enums');
  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.requireType('shaka.ui.Controls');
  16. /**
  17. * @extends {shaka.ui.SettingsMenu}
  18. * @final
  19. * @export
  20. */
  21. shaka.ui.PlaybackRateSelection = class extends shaka.ui.SettingsMenu {
  22. /**
  23. * @param {!HTMLElement} parent
  24. * @param {!shaka.ui.Controls} controls
  25. */
  26. constructor(parent, controls) {
  27. super(parent, controls,
  28. shaka.ui.Enums.MaterialDesignSVGIcons.PLAYBACK_RATE);
  29. this.button.classList.add('shaka-playbackrate-button');
  30. this.menu.classList.add('shaka-playback-rates');
  31. this.button.classList.add('shaka-tooltip-status');
  32. if (!Array.from(parent.classList).includes('shaka-overflow-menu')) {
  33. this.playbackRateMark = shaka.util.Dom.createHTMLElement('span');
  34. this.playbackRateMark.classList.add('shaka-overflow-playback-rate-mark');
  35. this.button.appendChild(this.playbackRateMark);
  36. }
  37. this.eventManager.listen(
  38. this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
  39. this.updateLocalizedStrings_();
  40. });
  41. this.eventManager.listen(
  42. this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => {
  43. this.updateLocalizedStrings_();
  44. });
  45. this.eventManager.listen(this.player, 'loaded', () => {
  46. this.updatePlaybackRateSelection_();
  47. });
  48. this.eventManager.listen(this.player, 'ratechange', () => {
  49. this.updatePlaybackRateSelection_();
  50. });
  51. // Set up all the strings in the user's preferred language.
  52. this.updateLocalizedStrings_();
  53. this.addPlaybackRates_();
  54. this.updatePlaybackRateSelection_();
  55. }
  56. /**
  57. * @private
  58. */
  59. updateLocalizedStrings_() {
  60. const LocIds = shaka.ui.Locales.Ids;
  61. this.backButton.ariaLabel = this.localization.resolve(LocIds.BACK);
  62. this.button.ariaLabel = this.localization.resolve(LocIds.PLAYBACK_RATE);
  63. this.nameSpan.textContent = this.localization.resolve(LocIds.PLAYBACK_RATE);
  64. this.backSpan.textContent = this.localization.resolve(LocIds.PLAYBACK_RATE);
  65. }
  66. /**
  67. * Update checkmark icon and related class and attribute for the chosen rate
  68. * button.
  69. * @private
  70. */
  71. updatePlaybackRateSelection_() {
  72. const rate = this.player.getPlaybackRate();
  73. // Remove the old checkmark icon and related tags and classes if it exists.
  74. const checkmarkIcon = shaka.ui.Utils.getDescendantIfExists(
  75. this.menu, 'material-svg-icon shaka-chosen-item');
  76. if (checkmarkIcon) {
  77. const previouslySelectedButton = checkmarkIcon.parentElement;
  78. previouslySelectedButton.removeAttribute('aria-selected');
  79. const previouslySelectedSpan =
  80. previouslySelectedButton.getElementsByTagName('span')[0];
  81. if (previouslySelectedSpan) {
  82. previouslySelectedSpan.classList.remove('shaka-chosen-item');
  83. }
  84. previouslySelectedButton.removeChild(checkmarkIcon);
  85. }
  86. // Find the button that represents the newly selected playback rate.
  87. // Add the checkmark icon, related tags and classes to the newly selected
  88. // button.
  89. const span = Array.from(this.menu.querySelectorAll('span')).find((el) => {
  90. return el.textContent == (rate + 'x');
  91. });
  92. if (span) {
  93. const button = span.parentElement;
  94. button.appendChild(shaka.ui.Utils.checkmarkIcon());
  95. button.ariaSelected = 'true';
  96. span.classList.add('shaka-chosen-item');
  97. }
  98. // Set the label to display the current playback rate in the overflow menu,
  99. // in the format of '1x', '1.5x', etc.
  100. this.currentSelection.textContent = rate + 'x';
  101. this.button.setAttribute('shaka-status', rate + 'x');
  102. if (this.playbackRateMark) {
  103. this.playbackRateMark.textContent = rate + 'x';
  104. }
  105. }
  106. /** @private */
  107. addPlaybackRates_() {
  108. for (const rate of this.controls.getConfig().playbackRates) {
  109. const button = shaka.util.Dom.createButton();
  110. const span = shaka.util.Dom.createHTMLElement('span');
  111. span.textContent = rate + 'x';
  112. button.appendChild(span);
  113. this.eventManager.listen(button, 'click', () => {
  114. if (rate == this.video.defaultPlaybackRate) {
  115. this.player.cancelTrickPlay();
  116. } else {
  117. this.player.trickPlay(rate, /* useTrickPlayTrack= */ false);
  118. }
  119. });
  120. this.menu.appendChild(button);
  121. }
  122. shaka.ui.Utils.focusOnTheChosenItem(this.menu);
  123. }
  124. };
  125. /**
  126. * @implements {shaka.extern.IUIElement.Factory}
  127. * @final
  128. */
  129. shaka.ui.PlaybackRateSelection.Factory = class {
  130. /** @override */
  131. create(rootElement, controls) {
  132. return new shaka.ui.PlaybackRateSelection(rootElement, controls);
  133. }
  134. };
  135. shaka.ui.OverflowMenu.registerElement(
  136. 'playback_rate', new shaka.ui.PlaybackRateSelection.Factory());
  137. shaka.ui.Controls.registerElement(
  138. 'playback_rate', new shaka.ui.PlaybackRateSelection.Factory());