shaka-player 3.2.2 → 3.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  3. package/.github/ISSUE_TEMPLATE/question.md +1 -1
  4. package/.github/workflows/build_and_test.yaml +73 -0
  5. package/.github/workflows/release.yaml +53 -0
  6. package/AUTHORS +6 -5
  7. package/CHANGELOG.md +314 -1
  8. package/CONTRIBUTORS +4 -2
  9. package/build/checkversion.py +1 -1
  10. package/build/conformance.textproto +183 -169
  11. package/build/test.py +6 -0
  12. package/build/types/core +3 -0
  13. package/build/types/offline +1 -0
  14. package/build/types/polyfill +1 -0
  15. package/build/types/ui +2 -0
  16. package/demo/common/assets.js +18 -0
  17. package/demo/common/message_ids.js +13 -1
  18. package/demo/config.js +31 -1
  19. package/demo/index.html +1 -1
  20. package/demo/locales/en.json +12 -0
  21. package/demo/locales/source.json +48 -0
  22. package/dist/controls.css +26 -2
  23. package/dist/controls.css.map +1 -1
  24. package/dist/demo.compiled.debug.js +19 -16
  25. package/dist/demo.compiled.debug.map +3 -3
  26. package/dist/demo.compiled.js +19 -16
  27. package/dist/demo.compiled.map +3 -3
  28. package/dist/deps.js +21 -14
  29. package/dist/locales.js +31 -29
  30. package/dist/receiver.compiled.debug.js +11 -9
  31. package/dist/receiver.compiled.debug.map +3 -3
  32. package/dist/receiver.compiled.js +11 -9
  33. package/dist/receiver.compiled.map +3 -3
  34. package/dist/shaka-player.compiled.d.ts +232 -18
  35. package/dist/shaka-player.compiled.debug.d.ts +232 -18
  36. package/dist/shaka-player.compiled.debug.externs.js +293 -17
  37. package/dist/shaka-player.compiled.debug.js +481 -422
  38. package/dist/shaka-player.compiled.debug.map +4 -4
  39. package/dist/shaka-player.compiled.externs.js +293 -17
  40. package/dist/shaka-player.compiled.js +846 -817
  41. package/dist/shaka-player.compiled.map +4 -4
  42. package/dist/shaka-player.ui.d.ts +250 -30
  43. package/dist/shaka-player.ui.debug.d.ts +250 -30
  44. package/dist/shaka-player.ui.debug.externs.js +322 -28
  45. package/dist/shaka-player.ui.debug.js +630 -553
  46. package/dist/shaka-player.ui.debug.map +4 -4
  47. package/dist/shaka-player.ui.externs.js +322 -28
  48. package/dist/shaka-player.ui.js +1048 -1006
  49. package/dist/shaka-player.ui.map +4 -4
  50. package/docs/design/bg-fetch-after.gv +29 -0
  51. package/docs/design/bg-fetch-after.gv.png +0 -0
  52. package/docs/design/bg-fetch-before.gv +18 -0
  53. package/docs/design/bg-fetch-before.gv.png +0 -0
  54. package/docs/design/bg-fetch.md +134 -0
  55. package/docs/tutorials/blob-url.md +15 -0
  56. package/docs/tutorials/index.json +1 -0
  57. package/docs/tutorials/ui-customization.md +66 -0
  58. package/docs/tutorials/ui.md +5 -5
  59. package/externs/cmcd.js +186 -0
  60. package/externs/ima.js +3 -0
  61. package/externs/shaka/ads.js +5 -0
  62. package/externs/shaka/manifest.js +12 -1
  63. package/externs/shaka/manifest_parser.js +10 -1
  64. package/externs/shaka/net.js +20 -4
  65. package/externs/shaka/offline.js +31 -2
  66. package/externs/shaka/player.js +138 -5
  67. package/externs/shaka/text.js +24 -0
  68. package/externs/webcrypto.js +18 -0
  69. package/karma.conf.js +19 -15
  70. package/lib/abr/ewma.js +14 -0
  71. package/lib/abr/ewma_bandwidth_estimator.js +16 -2
  72. package/lib/abr/simple_abr_manager.js +6 -0
  73. package/lib/ads/ad_manager.js +1 -0
  74. package/lib/ads/client_side_ad.js +8 -0
  75. package/lib/ads/client_side_ad_manager.js +8 -4
  76. package/lib/ads/server_side_ad.js +7 -0
  77. package/lib/cast/cast_proxy.js +3 -0
  78. package/lib/cast/cast_receiver.js +3 -0
  79. package/lib/cast/cast_utils.js +1 -0
  80. package/lib/dash/dash_parser.js +79 -33
  81. package/lib/dash/segment_base.js +25 -1
  82. package/lib/dash/segment_list.js +18 -9
  83. package/lib/dash/segment_template.js +23 -10
  84. package/lib/hls/hls_parser.js +116 -23
  85. package/lib/hls/manifest_text_parser.js +1 -0
  86. package/lib/media/quality_observer.js +274 -0
  87. package/lib/media/region_observer.js +39 -33
  88. package/lib/media/region_timeline.js +17 -19
  89. package/lib/media/segment_index.js +8 -1
  90. package/lib/media/segment_reference.js +37 -4
  91. package/lib/media/streaming_engine.js +47 -6
  92. package/lib/net/http_fetch_plugin.js +31 -11
  93. package/lib/net/http_plugin_utils.js +1 -0
  94. package/lib/net/http_xhr_plugin.js +40 -14
  95. package/lib/net/networking_engine.js +85 -18
  96. package/lib/offline/download_info.js +68 -0
  97. package/lib/offline/download_manager.js +13 -5
  98. package/lib/offline/indexeddb/base_storage_cell.js +35 -0
  99. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  100. package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
  101. package/lib/offline/storage.js +401 -293
  102. package/lib/offline/stored_content_utils.js +2 -0
  103. package/lib/player.js +254 -27
  104. package/lib/polyfill/media_capabilities.js +30 -15
  105. package/lib/polyfill/random_uuid.js +52 -0
  106. package/lib/text/cue.js +18 -0
  107. package/lib/text/ttml_text_parser.js +109 -60
  108. package/lib/text/ui_text_displayer.js +19 -13
  109. package/lib/util/cmcd_manager.js +672 -0
  110. package/lib/util/error.js +6 -0
  111. package/lib/util/fake_event_target.js +21 -1
  112. package/lib/util/language_utils.js +12 -0
  113. package/lib/util/mutex.js +52 -0
  114. package/lib/util/periods.js +98 -64
  115. package/lib/util/player_configuration.js +18 -0
  116. package/lib/util/stream_utils.js +86 -10
  117. package/lib/util/xml_utils.js +19 -0
  118. package/package.json +3 -6
  119. package/shaka-player.uncompiled.js +3 -0
  120. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  121. package/test/dash/dash_parser_live_unit.js +144 -1
  122. package/test/dash/dash_parser_manifest_unit.js +37 -2
  123. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  124. package/test/dash/dash_parser_segment_list_unit.js +2 -1
  125. package/test/dash/dash_parser_segment_template_unit.js +2 -1
  126. package/test/hls/hls_live_unit.js +2 -0
  127. package/test/hls/hls_parser_unit.js +76 -0
  128. package/test/media/drm_engine_unit.js +3 -3
  129. package/test/media/quality_observer_unit.js +142 -0
  130. package/test/media/region_observer_unit.js +40 -5
  131. package/test/media/region_timeline_unit.js +40 -22
  132. package/test/media/segment_reference_unit.js +16 -1
  133. package/test/media/streaming_engine_integration.js +4 -2
  134. package/test/media/streaming_engine_unit.js +147 -0
  135. package/test/net/http_plugin_unit.js +20 -15
  136. package/test/offline/storage_integration.js +108 -4
  137. package/test/player_integration.js +140 -8
  138. package/test/player_src_equals_integration.js +41 -8
  139. package/test/player_unit.js +19 -9
  140. package/test/test/assets/chapters.vtt +2 -2
  141. package/test/test/assets/chapters2.vtt +10 -0
  142. package/test/test/util/dash_parser_util.js +4 -0
  143. package/test/test/util/fake_ad.js +7 -0
  144. package/test/test/util/fake_drm_engine.js +9 -2
  145. package/test/test/util/manifest_generator.js +3 -2
  146. package/test/test/util/test_scheme.js +14 -1
  147. package/test/test/util/ttml_utils.js +81 -0
  148. package/test/test/util/util.js +10 -7
  149. package/test/text/mp4_ttml_parser_unit.js +11 -18
  150. package/test/text/ttml_text_parser_unit.js +544 -228
  151. package/test/ui/text_displayer_layout_unit.js +8 -7
  152. package/test/ui/ui_unit.js +250 -0
  153. package/test/util/cmcd_manager_unit.js +291 -0
  154. package/test/util/stream_utils_unit.js +36 -30
  155. package/third_party/closure-uri/uri.js +21 -0
  156. package/ui/airplay_button.js +1 -0
  157. package/ui/audio_language_selection.js +7 -0
  158. package/ui/cast_button.js +1 -0
  159. package/ui/context_menu.js +109 -0
  160. package/ui/controls.js +44 -7
  161. package/ui/controls.less +1 -0
  162. package/ui/enums.js +4 -0
  163. package/ui/externs/ui.js +28 -1
  164. package/ui/fast_forward_button.js +14 -5
  165. package/ui/fullscreen_button.js +1 -0
  166. package/ui/less/buttons.less +0 -4
  167. package/ui/less/containers.less +74 -0
  168. package/ui/less/overflow_menu.less +0 -10
  169. package/ui/less/tooltip.less +97 -0
  170. package/ui/locales/en.json +1 -0
  171. package/ui/locales/source.json +4 -0
  172. package/ui/localization.js +12 -36
  173. package/ui/loop_button.js +5 -0
  174. package/ui/mute_button.js +2 -1
  175. package/ui/overflow_menu.js +5 -25
  176. package/ui/pip_button.js +5 -0
  177. package/ui/play_button.js +2 -2
  178. package/ui/playback_rate_selection.js +8 -9
  179. package/ui/resolution_selection.js +7 -0
  180. package/ui/rewind_button.js +15 -6
  181. package/ui/seek_bar.js +4 -2
  182. package/ui/settings_menu.js +36 -4
  183. package/ui/small_play_button.js +1 -0
  184. package/ui/statistics_button.js +253 -0
  185. package/ui/text_selection.js +12 -4
  186. package/ui/ui.js +30 -0
  187. package/ui/volume_bar.js +1 -1
  188. package/externs/media_capabilities.js +0 -16
@@ -141,13 +141,3 @@
141
141
  /* TODO(b/116651454): eliminate hard-coded offsets */
142
142
  left: 17px;
143
143
  }
144
-
145
- /* The captions button, when captions are on. */
146
- .shaka-captions-on {
147
- color: black;
148
- }
149
-
150
- /* The captions button, when captions are off. */
151
- .shaka-captions-off {
152
- color: grey;
153
- }
@@ -0,0 +1,97 @@
1
+ /*!
2
+ * @license
3
+ * The tooltip is based on https://github.com/felipefialho/css-components/
4
+ * Local modifications have been performed.
5
+ *
6
+ * Copyright (c) 2017 Felipe Fialho
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ */
26
+
27
+ @material-icons-width: 32px;
28
+
29
+ .translateX(@percent) {
30
+ -webkit-transform: translateX(percentage(@percent));
31
+ -moz-transform: translateX(percentage(@percent));
32
+ -ms-transform: translateX(percentage(@percent));
33
+ -o-transform: translateX(percentage(@percent));
34
+ transform: translateX(percentage(@percent));
35
+ }
36
+
37
+ /* .shaka-tooltips-on enables the tooltips and is only added to the
38
+ * control panel when the 'enableTooltips' option is set to true */
39
+ .shaka-tooltips-on {
40
+ overflow: visible;
41
+
42
+ & > [class*="shaka-tooltip"] {
43
+ position: relative;
44
+
45
+ /* The :after pseudo-element contains the tooltip */
46
+ &:hover:after, &:focus-visible:after, &:active:after {
47
+ content: attr(aria-label);
48
+
49
+ /* Override .material-icons-round text styling */
50
+ font-family: Roboto-Regular, Roboto, sans-serif;
51
+ line-height: @material-icons-width / 2;
52
+ white-space: nowrap;
53
+ font-size: 13px;
54
+
55
+ /* Styling */
56
+ background: rgba(35, 35, 35, 0.9);
57
+ color: white;
58
+ border-radius: 3px;
59
+ padding: 5px 10px;
60
+
61
+ /* Positioning */
62
+ position: absolute;
63
+ bottom: @material-icons-width + 5px;
64
+
65
+ /* Left attribute is set to half of the width of the parent button */
66
+ left: @material-icons-width / 2;
67
+
68
+ /* The tooltip is also translated 50% to appear centered */
69
+ .translateX(-0.5);
70
+ }
71
+ }
72
+
73
+ /* Adds an additional attribute for the status in .shaka-tooltip-status */
74
+ & > .shaka-tooltip-status {
75
+ &:hover:after, &:focus-visible:after, &:active:after {
76
+ content: attr(aria-label) " (" attr(shaka-status) ")";
77
+ }
78
+ }
79
+
80
+ /* The first tooltip of the panel is not centered on top of the button
81
+ * but rather aligned with the left border of the control panel */
82
+ button:first-child {
83
+ &:hover:after, &:focus-visible:after, &:active:after {
84
+ left: 0;
85
+ .translateX(0);
86
+ }
87
+ }
88
+
89
+ /* The last tooltip of the panel is not centered on top of the button
90
+ * but rather aligned with the right border of the control panel */
91
+ button:last-child {
92
+ &:hover:after, &:focus-visible:after,&:active:after {
93
+ left: @material-icons-width;
94
+ .translateX(-1);
95
+ }
96
+ }
97
+ }
@@ -33,6 +33,7 @@
33
33
  "SEEK": "Seek",
34
34
  "SKIP_AD": "Skip Ad",
35
35
  "SKIP_TO_LIVE": "Skip ahead to live",
36
+ "STATISTICS": "Statistics",
36
37
  "SUBTITLE_FORCED": "Forced",
37
38
  "UNDETERMINED_LANGUAGE": "Undetermined",
38
39
  "UNMUTE": "Unmute",
@@ -138,6 +138,10 @@
138
138
  "description": "Label for a button used to skip ahead to the live broadcast.",
139
139
  "message": "Skip ahead to live"
140
140
  },
141
+ "STATISTICS": {
142
+ "description": "Label for a button that displays statistics of the video.",
143
+ "message": "Statistics"
144
+ },
141
145
  "SUBTITLE_FORCED": {
142
146
  "description": "Label used to identify a subtitle track that is forced to be shown.",
143
147
  "message": "Forced"
@@ -23,17 +23,18 @@ goog.require('shaka.util.LanguageUtils');
23
23
  * If a string is not available, it will return the localized
24
24
  * form in the closest related locale.
25
25
  *
26
- * @implements {EventTarget}
27
26
  * @final
28
27
  * @export
29
28
  */
30
- shaka.ui.Localization = class {
29
+ shaka.ui.Localization = class extends shaka.util.FakeEventTarget {
31
30
  /**
32
31
  * @param {string} fallbackLocale
33
32
  * The fallback locale that should be used. It will be assumed that this
34
33
  * locale should have entries for just about every request.
35
34
  */
36
35
  constructor(fallbackLocale) {
36
+ super();
37
+
37
38
  /** @private {string} */
38
39
  this.fallbackLocale_ = shaka.util.LanguageUtils.normalize(fallbackLocale);
39
40
 
@@ -62,41 +63,16 @@ shaka.ui.Localization = class {
62
63
  * @private {!Map.<string, !Map.<string, string>>}
63
64
  */
64
65
  this.localizations_ = new Map();
65
-
66
- /**
67
- * The event target that we will wrap so that we can fire events
68
- * without having to manage the listeners directly.
69
- *
70
- * @private {!EventTarget}
71
- */
72
- this.events_ = new shaka.util.FakeEventTarget();
73
- }
74
-
75
- /**
76
- * @override
77
- * @export
78
- */
79
- addEventListener(type, listener, options) {
80
- this.events_.addEventListener(type, listener, options);
81
- }
82
-
83
- /**
84
- * @override
85
- * @export
86
- */
87
- removeEventListener(type, listener, options) {
88
- // Apparently Closure says we can be passed a null |option|, but we can't
89
- // pass a null option, so if we get have a null-like |option|, force it to
90
- // be undefined.
91
- this.events_.removeEventListener(type, listener, options || undefined);
92
66
  }
93
67
 
94
68
  /**
95
69
  * @override
96
70
  * @export
97
71
  */
98
- dispatchEvent(event) {
99
- return this.events_.dispatchEvent(event);
72
+ release() {
73
+ // Placeholder so that readers know this implements IReleasable (via
74
+ // FakeEventTarget)
75
+ super.release();
100
76
  }
101
77
 
102
78
  /**
@@ -130,7 +106,7 @@ shaka.ui.Localization = class {
130
106
  (locale) => !this.localizations_.has(locale));
131
107
 
132
108
  if (missing.length) {
133
- this.events_.dispatchEvent(new shaka.util.FakeEvent(
109
+ this.dispatchEvent(new shaka.util.FakeEvent(
134
110
  Class.UNKNOWN_LOCALES,
135
111
  (new Map()).set('locales', missing)));
136
112
  }
@@ -141,7 +117,7 @@ shaka.ui.Localization = class {
141
117
 
142
118
  const data = (new Map()).set(
143
119
  'locales', found.length ? found : [this.fallbackLocale_]);
144
- this.events_.dispatchEvent(new shaka.util.FakeEvent(
120
+ this.dispatchEvent(new shaka.util.FakeEvent(
145
121
  Class.LOCALE_CHANGED,
146
122
  data));
147
123
  }
@@ -193,7 +169,7 @@ shaka.ui.Localization = class {
193
169
  // data from.
194
170
  this.updateCurrentMap_();
195
171
 
196
- this.events_.dispatchEvent(new FakeEvent(Class.LOCALE_UPDATED));
172
+ this.dispatchEvent(new FakeEvent(Class.LOCALE_UPDATED));
197
173
 
198
174
  return this;
199
175
  }
@@ -249,7 +225,7 @@ shaka.ui.Localization = class {
249
225
  // Make a copy to avoid leaking references.
250
226
  .set('locales', Array.from(this.currentLocales_))
251
227
  .set('missing', id);
252
- this.events_.dispatchEvent(new FakeEvent(Class.UNKNOWN_LOCALIZATION, data));
228
+ this.dispatchEvent(new FakeEvent(Class.UNKNOWN_LOCALIZATION, data));
253
229
 
254
230
  return '';
255
231
  }
@@ -377,7 +353,7 @@ shaka.ui.Localization = class {
377
353
  // an array.
378
354
  .set('missing', Array.from(missing));
379
355
 
380
- this.events_.dispatchEvent(new shaka.util.FakeEvent(
356
+ this.dispatchEvent(new shaka.util.FakeEvent(
381
357
  shaka.ui.Localization.MISSING_LOCALIZATIONS,
382
358
  data));
383
359
  }
package/ui/loop_button.js CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  goog.provide('shaka.ui.LoopButton');
9
9
 
10
+ goog.require('shaka.ui.ContextMenu');
10
11
  goog.require('shaka.ui.Controls');
11
12
  goog.require('shaka.ui.Element');
12
13
  goog.require('shaka.ui.Enums');
@@ -35,6 +36,7 @@ shaka.ui.LoopButton = class extends shaka.ui.Element {
35
36
  /** @private {!HTMLButtonElement} */
36
37
  this.button_ = shaka.util.Dom.createButton();
37
38
  this.button_.classList.add('shaka-loop-button');
39
+ this.button_.classList.add('shaka-tooltip');
38
40
 
39
41
  /** @private {!HTMLElement} */
40
42
  this.icon_ = shaka.util.Dom.createHTMLElement('i');
@@ -171,3 +173,6 @@ shaka.ui.OverflowMenu.registerElement(
171
173
 
172
174
  shaka.ui.Controls.registerElement(
173
175
  'loop', new shaka.ui.LoopButton.Factory());
176
+
177
+ shaka.ui.ContextMenu.registerElement(
178
+ 'loop', new shaka.ui.LoopButton.Factory());
package/ui/mute_button.js CHANGED
@@ -33,6 +33,7 @@ shaka.ui.MuteButton = class extends shaka.ui.Element {
33
33
  this.button_ = shaka.util.Dom.createButton();
34
34
  this.button_.classList.add('shaka-mute-button');
35
35
  this.button_.classList.add('material-icons-round');
36
+ this.button_.classList.add('shaka-tooltip');
36
37
  this.parent.appendChild(this.button_);
37
38
  this.updateAriaLabel_();
38
39
  this.updateIcon_();
@@ -48,7 +49,7 @@ shaka.ui.MuteButton = class extends shaka.ui.Element {
48
49
  });
49
50
 
50
51
  this.eventManager.listen(this.button_, 'click', () => {
51
- if (this.ad) {
52
+ if (this.ad && this.ad.isLinear()) {
52
53
  this.ad.setMuted(!this.ad.isMuted());
53
54
  } else {
54
55
  this.video.muted = !this.video.muted;
@@ -48,29 +48,6 @@ shaka.ui.OverflowMenu = class extends shaka.ui.Element {
48
48
 
49
49
  this.createChildren_();
50
50
 
51
-
52
- const backToOverflowMenuButtons =
53
- this.controls.getVideoContainer().getElementsByClassName(
54
- 'shaka-back-to-overflow-button');
55
-
56
- for (const button of backToOverflowMenuButtons) {
57
- this.eventManager.listen(button, 'click', () => {
58
- // Hide the submenus, display the overflow menu
59
- this.controls.hideSettingsMenus();
60
- shaka.ui.Utils.setDisplay(this.overflowMenu_, true);
61
-
62
- // If there are back to overflow menu buttons, there must be
63
- // overflow menu buttons, but oh well
64
- if (this.overflowMenu_.childNodes.length) {
65
- /** @type {!HTMLElement} */ (this.overflowMenu_.childNodes[0])
66
- .focus();
67
- }
68
-
69
- // Make sure controls are displayed
70
- this.controls.computeOpacity();
71
- });
72
- }
73
-
74
51
  this.eventManager.listen(
75
52
  this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
76
53
  this.updateAriaLabel_();
@@ -83,7 +60,9 @@ shaka.ui.OverflowMenu = class extends shaka.ui.Element {
83
60
 
84
61
  this.eventManager.listen(
85
62
  this.adManager, shaka.ads.AdManager.AD_STARTED, () => {
86
- shaka.ui.Utils.setDisplay(this.overflowMenuButton_, false);
63
+ if (this.ad && this.ad.isLinear()) {
64
+ shaka.ui.Utils.setDisplay(this.overflowMenuButton_, false);
65
+ }
87
66
  });
88
67
 
89
68
  this.eventManager.listen(
@@ -112,7 +91,7 @@ shaka.ui.OverflowMenu = class extends shaka.ui.Element {
112
91
 
113
92
  this.updateAriaLabel_();
114
93
 
115
- if (this.ad) {
94
+ if (this.ad && this.ad.isLinear()) {
116
95
  // There was already an ad.
117
96
  shaka.ui.Utils.setDisplay(this.overflowMenuButton_, false);
118
97
  }
@@ -163,6 +142,7 @@ shaka.ui.OverflowMenu = class extends shaka.ui.Element {
163
142
  this.overflowMenuButton_.classList.add('shaka-overflow-menu-button');
164
143
  this.overflowMenuButton_.classList.add('shaka-no-propagation');
165
144
  this.overflowMenuButton_.classList.add('material-icons-round');
145
+ this.overflowMenuButton_.classList.add('shaka-tooltip');
166
146
  this.overflowMenuButton_.textContent =
167
147
  shaka.ui.Enums.MaterialDesignIcons.OPEN_OVERFLOW;
168
148
  this.parent.appendChild(this.overflowMenuButton_);
package/ui/pip_button.js CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  goog.provide('shaka.ui.PipButton');
9
9
 
10
+ goog.require('shaka.ui.ContextMenu');
10
11
  goog.require('shaka.ui.Controls');
11
12
  goog.require('shaka.ui.Element');
12
13
  goog.require('shaka.ui.Enums');
@@ -39,6 +40,7 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
39
40
  /** @private {!HTMLButtonElement} */
40
41
  this.pipButton_ = shaka.util.Dom.createButton();
41
42
  this.pipButton_.classList.add('shaka-pip-button');
43
+ this.pipButton_.classList.add('shaka-tooltip');
42
44
 
43
45
  /** @private {!HTMLElement} */
44
46
  this.pipIcon_ = shaka.util.Dom.createHTMLElement('i');
@@ -237,3 +239,6 @@ shaka.ui.OverflowMenu.registerElement(
237
239
 
238
240
  shaka.ui.Controls.registerElement(
239
241
  'picture_in_picture', new shaka.ui.PipButton.Factory());
242
+
243
+ shaka.ui.ContextMenu.registerElement(
244
+ 'picture_in_picture', new shaka.ui.PipButton.Factory());
package/ui/play_button.js CHANGED
@@ -73,7 +73,7 @@ shaka.ui.PlayButton = class extends shaka.ui.Element {
73
73
  });
74
74
 
75
75
  this.eventManager.listen(this.button, 'click', () => {
76
- if (this.ad) {
76
+ if (this.ad && this.ad.isLinear()) {
77
77
  this.controls.playPauseAd();
78
78
  } else {
79
79
  this.controls.playPausePresentation();
@@ -92,7 +92,7 @@ shaka.ui.PlayButton = class extends shaka.ui.Element {
92
92
  * @protected
93
93
  */
94
94
  isPaused() {
95
- if (this.ad) {
95
+ if (this.ad && this.ad.isLinear()) {
96
96
  return this.ad.isPaused();
97
97
  }
98
98
 
@@ -7,6 +7,7 @@
7
7
 
8
8
  goog.provide('shaka.ui.PlaybackRateSelection');
9
9
 
10
+ goog.require('shaka.ui.Controls');
10
11
  goog.require('shaka.ui.Enums');
11
12
  goog.require('shaka.ui.Locales');
12
13
  goog.require('shaka.ui.Localization');
@@ -31,6 +32,7 @@ shaka.ui.PlaybackRateSelection = class extends shaka.ui.SettingsMenu {
31
32
 
32
33
  this.button.classList.add('shaka-playbackrate-button');
33
34
  this.menu.classList.add('shaka-playback-rates');
35
+ this.button.classList.add('shaka-tooltip-status');
34
36
 
35
37
  this.eventManager.listen(
36
38
  this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
@@ -47,15 +49,8 @@ shaka.ui.PlaybackRateSelection = class extends shaka.ui.SettingsMenu {
47
49
  });
48
50
 
49
51
  /** @type {!Map.<string, number>} */
50
- this.playbackRates_ = new Map([
51
- ['0.5x', 0.5],
52
- ['0.75x', 0.75],
53
- ['1x', 1],
54
- ['1.25x', 1.25],
55
- ['1.5x', 1.5],
56
- ['1.75x', 1.75],
57
- ['2x', 2],
58
- ]);
52
+ this.playbackRates_ = new Map(this.controls.getConfig().playbackRates
53
+ .map((rate) => [rate + 'x', rate]));
59
54
 
60
55
  // Set up all the strings in the user's preferred language.
61
56
  this.updateLocalizedStrings_();
@@ -109,6 +104,7 @@ shaka.ui.PlaybackRateSelection = class extends shaka.ui.SettingsMenu {
109
104
  // Set the label to display the current playback rate in the overflow menu,
110
105
  // in the format of '1x', '1.5x', etc.
111
106
  this.currentSelection.textContent = rate + 'x';
107
+ this.button.setAttribute('shaka-status', rate + 'x');
112
108
  }
113
109
 
114
110
  /** @private */
@@ -143,3 +139,6 @@ shaka.ui.PlaybackRateSelection.Factory = class {
143
139
 
144
140
  shaka.ui.OverflowMenu.registerElement(
145
141
  'playback_rate', new shaka.ui.PlaybackRateSelection.Factory());
142
+
143
+ shaka.ui.Controls.registerElement(
144
+ 'playback_rate', new shaka.ui.PlaybackRateSelection.Factory());
@@ -8,6 +8,7 @@
8
8
  goog.provide('shaka.ui.ResolutionSelection');
9
9
 
10
10
  goog.require('goog.asserts');
11
+ goog.require('shaka.ui.Controls');
11
12
  goog.require('shaka.ui.Enums');
12
13
  goog.require('shaka.ui.Locales');
13
14
  goog.require('shaka.ui.Localization');
@@ -33,6 +34,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
33
34
  super(parent, controls, shaka.ui.Enums.MaterialDesignIcons.RESOLUTION);
34
35
 
35
36
  this.button.classList.add('shaka-resolution-button');
37
+ this.button.classList.add('shaka-tooltip-status');
36
38
  this.menu.classList.add('shaka-resolutions');
37
39
 
38
40
  this.eventManager.listen(
@@ -171,6 +173,8 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
171
173
  this.localization.resolve(shaka.ui.Locales.Ids.AUTO_QUALITY);
172
174
  }
173
175
 
176
+ this.button.setAttribute('shaka-status', this.currentSelection.textContent);
177
+
174
178
  this.menu.appendChild(autoButton);
175
179
  shaka.ui.Utils.focusOnTheChosenItem(this.menu);
176
180
  this.controls.dispatchEvent(
@@ -227,3 +231,6 @@ shaka.ui.ResolutionSelection.Factory = class {
227
231
 
228
232
  shaka.ui.OverflowMenu.registerElement(
229
233
  'quality', new shaka.ui.ResolutionSelection.Factory());
234
+
235
+ shaka.ui.Controls.registerElement(
236
+ 'quality', new shaka.ui.ResolutionSelection.Factory());
@@ -32,11 +32,17 @@ shaka.ui.RewindButton = class extends shaka.ui.Element {
32
32
  this.button_ = shaka.util.Dom.createButton();
33
33
  this.button_.classList.add('material-icons-round');
34
34
  this.button_.classList.add('shaka-rewind-button');
35
+ this.button_.classList.add('shaka-tooltip-status');
36
+ this.button_.setAttribute('shaka-status',
37
+ this.localization.resolve(shaka.ui.Locales.Ids.OFF));
35
38
  this.button_.textContent =
36
39
  shaka.ui.Enums.MaterialDesignIcons.REWIND;
37
40
  this.parent.appendChild(this.button_);
38
41
  this.updateAriaLabel_();
39
42
 
43
+ /** @private {!Array.<number>} */
44
+ this.rewindRates_ = this.controls.getConfig().rewindRates;
45
+
40
46
  this.eventManager.listen(
41
47
  this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
42
48
  this.updateAriaLabel_();
@@ -61,7 +67,7 @@ shaka.ui.RewindButton = class extends shaka.ui.Element {
61
67
  }
62
68
 
63
69
  /**
64
- * Cycles trick play rate between -1, -2, -4, and -8.
70
+ * Cycles trick play rate between the selected rewind rates.
65
71
  * @private
66
72
  */
67
73
  rewind_() {
@@ -70,12 +76,15 @@ shaka.ui.RewindButton = class extends shaka.ui.Element {
70
76
  }
71
77
 
72
78
  const trickPlayRate = this.player.getPlaybackRate();
73
- // Every time the button is clicked, the rate is multiplied by 2,
74
- // unless the rate is at it's slowest (-8), in which case it is
75
- // dropped back to 1.
76
- const newRate = (trickPlayRate > 0 || trickPlayRate < -4) ?
77
- -1 : trickPlayRate * 2;
79
+ const newRateIndex = this.rewindRates_.indexOf(trickPlayRate) + 1;
80
+
81
+ // When the button is clicked, the next rate in this.rewindRates_ is
82
+ // selected. If no more rates are available, the first one is set.
83
+ const newRate = (newRateIndex != this.rewindRates_.length) ?
84
+ this.rewindRates_[newRateIndex] : this.rewindRates_[0];
78
85
  this.player.trickPlay(newRate);
86
+
87
+ this.button_.setAttribute('shaka-status', newRate + 'x');
79
88
  }
80
89
  };
81
90
 
package/ui/seek_bar.js CHANGED
@@ -95,7 +95,9 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement {
95
95
 
96
96
  this.eventManager.listen(
97
97
  this.adManager, shaka.ads.AdManager.AD_STARTED, () => {
98
- shaka.ui.Utils.setDisplay(this.container, false);
98
+ if (!this.shouldBeDisplayed_()) {
99
+ shaka.ui.Utils.setDisplay(this.container, false);
100
+ }
99
101
  });
100
102
 
101
103
  this.eventManager.listen(
@@ -366,7 +368,7 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement {
366
368
  return false;
367
369
  }
368
370
 
369
- return this.ad == null;
371
+ return this.ad == null || !this.ad.isLinear();
370
372
  }
371
373
 
372
374
  /** @private */
@@ -33,6 +33,8 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
33
33
 
34
34
  this.addMenu_();
35
35
 
36
+ this.inOverflowMenu_();
37
+
36
38
  this.eventManager.listen(this.button, 'click', () => {
37
39
  this.onButtonClick_();
38
40
  });
@@ -46,6 +48,7 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
46
48
  addButton_(iconText) {
47
49
  /** @protected {!HTMLButtonElement} */
48
50
  this.button = shaka.util.Dom.createButton();
51
+ this.button.classList.add('shaka-overflow-button');
49
52
 
50
53
  /** @protected {!HTMLElement}*/
51
54
  this.icon = shaka.util.Dom.createHTMLElement('i');
@@ -55,6 +58,7 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
55
58
 
56
59
  const label = shaka.util.Dom.createHTMLElement('label');
57
60
  label.classList.add('shaka-overflow-button-label');
61
+ label.classList.add('shaka-overflow-menu-only');
58
62
 
59
63
  /** @protected {!HTMLElement}*/
60
64
  this.nameSpan = shaka.util.Dom.createHTMLElement('span');
@@ -83,10 +87,13 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
83
87
  this.backButton = shaka.util.Dom.createButton();
84
88
  this.backButton.classList.add('shaka-back-to-overflow-button');
85
89
  this.menu.appendChild(this.backButton);
90
+ this.eventManager.listen(this.backButton, 'click', () => {
91
+ this.controls.hideSettingsMenus();
92
+ });
86
93
 
87
94
  const backIcon = shaka.util.Dom.createHTMLElement('i');
88
95
  backIcon.classList.add('material-icons-round');
89
- backIcon.textContent = shaka.ui.Enums.MaterialDesignIcons.BACK;
96
+ backIcon.textContent = shaka.ui.Enums.MaterialDesignIcons.CLOSE;
90
97
  this.backButton.appendChild(backIcon);
91
98
 
92
99
  /** @protected {!HTMLElement}*/
@@ -97,11 +104,36 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
97
104
  controlsContainer.appendChild(this.menu);
98
105
  }
99
106
 
107
+ /** @private */
108
+ inOverflowMenu_() {
109
+ // Initially, submenus are created with a "Close" option. When present
110
+ // inside of the overflow menu, that option must be replaced with a
111
+ // "Back" arrow that returns the user to the main menu.
112
+ if (this.parent.classList.contains('shaka-overflow-menu')) {
113
+ this.backButton.firstChild.textContent =
114
+ shaka.ui.Enums.MaterialDesignIcons.BACK;
115
+
116
+ this.eventManager.listen(this.backButton, 'click', () => {
117
+ shaka.ui.Utils.setDisplay(this.parent, true);
118
+
119
+ /** @type {!HTMLElement} */
120
+ (this.parent.childNodes[0]).focus();
121
+
122
+ // Make sure controls are displayed
123
+ this.controls.computeOpacity();
124
+ });
125
+ }
126
+ }
127
+
100
128
 
101
129
  /** @private */
102
130
  onButtonClick_() {
103
- this.controls.dispatchEvent(new shaka.util.FakeEvent('submenuopen'));
104
- shaka.ui.Utils.setDisplay(this.menu, true);
105
- shaka.ui.Utils.focusOnTheChosenItem(this.menu);
131
+ if (this.menu.classList.contains('shaka-hidden')) {
132
+ this.controls.dispatchEvent(new shaka.util.FakeEvent('submenuopen'));
133
+ shaka.ui.Utils.setDisplay(this.menu, true);
134
+ shaka.ui.Utils.focusOnTheChosenItem(this.menu);
135
+ } else {
136
+ shaka.ui.Utils.setDisplay(this.menu, false);
137
+ }
106
138
  }
107
139
  };
@@ -28,6 +28,7 @@ shaka.ui.SmallPlayButton = class extends shaka.ui.PlayButton {
28
28
 
29
29
  this.button.classList.add('shaka-small-play-button');
30
30
  this.button.classList.add('material-icons-round');
31
+ this.button.classList.add('shaka-tooltip');
31
32
 
32
33
  this.updateIcon();
33
34
  this.updateAriaLabel();