shaka-player 2.5.1 → 2.5.5

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 (166) hide show
  1. package/.csslintrc +13 -0
  2. package/AUTHORS +3 -0
  3. package/CHANGELOG.md +156 -0
  4. package/CONTRIBUTORS +3 -0
  5. package/README.md +3 -0
  6. package/build/README.md +5 -5
  7. package/build/apps.py +3 -1
  8. package/build/build.py +5 -2
  9. package/build/check.py +17 -0
  10. package/build/compiler.py +49 -0
  11. package/build/conformance.textproto +1 -0
  12. package/build/docs.py +0 -6
  13. package/build/generateExterns.js +72 -20
  14. package/build/install-linux-prereqs.sh +4 -4
  15. package/build/shakaBuildHelpers.py +7 -8
  16. package/build/test.py +21 -9
  17. package/build/types/core +1 -0
  18. package/build/types/ui +6 -1
  19. package/demo/asset_card.js +129 -41
  20. package/demo/cast_receiver/receiver_app.css +27 -13
  21. package/demo/close_button.js +10 -15
  22. package/demo/common/asset.js +6 -6
  23. package/demo/common/assets.js +72 -14
  24. package/demo/config.js +28 -25
  25. package/demo/custom.js +20 -16
  26. package/demo/demo.less +107 -16
  27. package/demo/demo_uncompiled.js +33 -0
  28. package/demo/demo_utils.js +4 -3
  29. package/demo/front.js +12 -8
  30. package/demo/index.html +14 -17
  31. package/demo/input.js +30 -23
  32. package/demo/input_container.js +15 -11
  33. package/demo/load.js +5 -7
  34. package/demo/main.js +138 -49
  35. package/demo/search.js +40 -36
  36. package/demo/service_worker.js +1 -1
  37. package/demo/tooltip.js +16 -24
  38. package/dist/.csslintstamp +0 -0
  39. package/dist/controls.css +1 -1
  40. package/dist/controls.css.map +1 -1
  41. package/dist/demo.compiled.debug.js +165 -152
  42. package/dist/demo.compiled.debug.map +4 -4
  43. package/dist/demo.compiled.js +165 -152
  44. package/dist/demo.compiled.map +4 -4
  45. package/dist/demo.css +1 -1
  46. package/dist/demo.css.map +1 -1
  47. package/dist/deps.js +28 -11
  48. package/dist/receiver.compiled.debug.js +11 -11
  49. package/dist/receiver.compiled.debug.map +3 -3
  50. package/dist/receiver.compiled.js +11 -11
  51. package/dist/receiver.compiled.map +3 -3
  52. package/dist/shaka-player.compiled.debug.externs.js +232 -102
  53. package/dist/shaka-player.compiled.debug.js +189 -165
  54. package/dist/shaka-player.compiled.debug.map +4 -4
  55. package/dist/shaka-player.compiled.externs.js +232 -102
  56. package/dist/shaka-player.compiled.js +567 -553
  57. package/dist/shaka-player.compiled.map +4 -4
  58. package/dist/shaka-player.ui.debug.externs.js +338 -113
  59. package/dist/shaka-player.ui.debug.js +296 -276
  60. package/dist/shaka-player.ui.debug.map +4 -4
  61. package/dist/shaka-player.ui.externs.js +338 -113
  62. package/dist/shaka-player.ui.js +685 -671
  63. package/dist/shaka-player.ui.map +4 -4
  64. package/docs/tutorials/drm-config.md +1 -0
  65. package/docs/tutorials/fairplay.md +77 -0
  66. package/docs/tutorials/index.json +1 -0
  67. package/docs/tutorials/manifest-parser.md +1 -1
  68. package/docs/tutorials/ui-customization.md +5 -2
  69. package/docs/tutorials/ui.md +10 -4
  70. package/docs/tutorials/welcome.md +2 -2
  71. package/externs/mediasession.js +16 -1
  72. package/externs/shaka/net.js +14 -4
  73. package/externs/shaka/player.js +136 -90
  74. package/externs/tippy.js +30 -0
  75. package/externs/webkitmediakeys.js +4 -0
  76. package/karma.conf.js +30 -24
  77. package/lib/cast/cast_proxy.js +94 -23
  78. package/lib/cast/cast_receiver.js +8 -1
  79. package/lib/dash/content_protection.js +33 -1
  80. package/lib/dash/dash_parser.js +13 -5
  81. package/lib/hls/hls_parser.js +20 -4
  82. package/lib/media/drm_engine.js +29 -2
  83. package/lib/media/media_source_engine.js +9 -6
  84. package/lib/media/play_rate_controller.js +14 -3
  85. package/lib/media/playhead.js +8 -3
  86. package/lib/media/streaming_engine.js +68 -20
  87. package/lib/media/transmuxer.js +2 -2
  88. package/lib/media/video_wrapper.js +8 -3
  89. package/lib/net/data_uri_plugin.js +5 -2
  90. package/lib/net/http_fetch_plugin.js +3 -3
  91. package/lib/net/http_plugin_utils.js +2 -4
  92. package/lib/net/http_xhr_plugin.js +2 -2
  93. package/lib/net/networking_engine.js +1 -0
  94. package/lib/offline/offline_scheme.js +7 -2
  95. package/lib/player.js +18 -8
  96. package/lib/polyfill/input_event.js +7 -11
  97. package/lib/polyfill/mediasource.js +1 -1
  98. package/lib/polyfill/patchedmediakeys_apple.js +2 -72
  99. package/lib/text/cue.js +1 -1
  100. package/lib/text/ttml_text_parser.js +1 -1
  101. package/lib/util/config_utils.js +1 -0
  102. package/lib/util/error.js +45 -11
  103. package/lib/util/event_manager.js +211 -100
  104. package/lib/util/fairplay_utils.js +122 -0
  105. package/lib/util/i_releasable.js +1 -0
  106. package/lib/util/player_configuration.js +7 -0
  107. package/lib/util/pssh.js +41 -0
  108. package/lib/util/string_utils.js +42 -6
  109. package/lib/util/timer.js +1 -1
  110. package/package.json +33 -33
  111. package/roadmap.md +96 -0
  112. package/shaka-player.uncompiled.js +5 -1
  113. package/test/dash/dash_parser_content_protection_unit.js +35 -1
  114. package/test/dash/dash_parser_manifest_unit.js +60 -0
  115. package/test/hls/hls_live_unit.js +7 -1
  116. package/test/hls/hls_parser_unit.js +50 -0
  117. package/test/media/drm_engine_unit.js +10 -4
  118. package/test/media/media_source_engine_integration.js +12 -0
  119. package/test/media/media_source_engine_unit.js +3 -1
  120. package/test/media/playhead_unit.js +7 -5
  121. package/test/media/streaming_engine_unit.js +46 -1
  122. package/test/media/transmuxer_integration.js +13 -0
  123. package/test/net/data_uri_plugin_unit.js +13 -2
  124. package/test/net/http_plugin_unit.js +17 -12
  125. package/test/net/networking_engine_unit.js +17 -8
  126. package/test/offline/offline_scheme_unit.js +18 -8
  127. package/test/player_external.js +3 -2
  128. package/test/player_integration.js +94 -3
  129. package/test/player_src_equals_integration.js +2 -2
  130. package/test/player_unit.js +21 -8
  131. package/test/test/boot.js +20 -5
  132. package/test/test/externs/jasmine.js +48 -0
  133. package/test/test/util/expect_async_polyfill.js +145 -0
  134. package/test/test/util/fake_networking_engine.js +1 -0
  135. package/test/test/util/manifest_generator.js +2 -1
  136. package/test/test/util/test_scheme.js +34 -2
  137. package/test/test/util/ui_utils.js +41 -0
  138. package/test/test/util/util.js +16 -8
  139. package/test/ui/ui_unit.js +130 -4
  140. package/ui/audio_language_selection.js +17 -96
  141. package/ui/big_play_button.js +61 -0
  142. package/ui/controls.js +226 -335
  143. package/ui/controls.less +3 -5
  144. package/ui/element.js +24 -6
  145. package/ui/externs/ui.js +62 -9
  146. package/ui/fullscreen_button.js +2 -52
  147. package/ui/less/buttons.less +10 -16
  148. package/ui/less/containers.less +75 -20
  149. package/ui/less/general.less +18 -2
  150. package/ui/less/other_elements.less +2 -1
  151. package/ui/less/overflow_menu.less +11 -10
  152. package/ui/less/range_elements.less +12 -10
  153. package/ui/less/spinner.less +2 -0
  154. package/ui/overflow_menu.js +1 -1
  155. package/ui/pip_button.js +1 -1
  156. package/ui/{play_pause_button.js → play_button.js} +17 -47
  157. package/ui/presentation_time.js +17 -12
  158. package/ui/range_element.js +176 -0
  159. package/ui/resolution_selection.js +43 -106
  160. package/ui/seek_bar.js +204 -0
  161. package/ui/settings_menu.js +113 -0
  162. package/ui/small_play_button.js +73 -0
  163. package/ui/text_displayer.js +17 -14
  164. package/ui/text_selection.js +42 -107
  165. package/ui/ui.js +17 -40
  166. package/ui/volume_bar.js +40 -68
@@ -18,30 +18,29 @@
18
18
 
19
19
  goog.provide('shaka.ui.ResolutionSelection');
20
20
 
21
- goog.require('shaka.ui.Element');
22
21
  goog.require('shaka.ui.Enums');
23
22
  goog.require('shaka.ui.Locales');
24
23
  goog.require('shaka.ui.Localization');
25
24
  goog.require('shaka.ui.OverflowMenu');
25
+ goog.require('shaka.ui.SettingsMenu');
26
26
  goog.require('shaka.util.Dom');
27
27
 
28
28
 
29
29
  /**
30
- * @extends {shaka.ui.Element}
30
+ * @extends {shaka.ui.SettingsMenu}
31
31
  * @final
32
32
  * @export
33
33
  */
34
- shaka.ui.ResolutionSelection = class extends shaka.ui.Element {
34
+ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
35
35
  /**
36
36
  * @param {!HTMLElement} parent
37
37
  * @param {!shaka.ui.Controls} controls
38
38
  */
39
39
  constructor(parent, controls) {
40
- super(parent, controls);
40
+ super(parent, controls, shaka.ui.Enums.MaterialDesignIcons.RESOLUTION);
41
41
 
42
- this.addResolutionButton_();
43
-
44
- this.addResolutionMenu_();
42
+ this.button.classList.add('shaka-resolution-button');
43
+ this.menu.classList.add('shaka-resolutions');
45
44
 
46
45
  this.eventManager.listen(
47
46
  this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
@@ -53,9 +52,6 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element {
53
52
  this.updateLocalizedStrings_();
54
53
  });
55
54
 
56
- this.eventManager.listen(this.resolutionButton_, 'click', () => {
57
- this.onResolutionClick_();
58
- });
59
55
 
60
56
  this.eventManager.listen(this.player, 'variantchanged', () => {
61
57
  this.updateResolutionSelection_();
@@ -76,108 +72,56 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element {
76
72
  }
77
73
 
78
74
 
79
- /**
80
- * @private
81
- */
82
- addResolutionButton_() {
83
- /** @private {!HTMLElement}*/
84
- this.resolutionButton_ = shaka.util.Dom.createHTMLElement('button');
85
-
86
- this.resolutionButton_.classList.add('shaka-resolution-button');
87
-
88
- const icon = shaka.util.Dom.createHTMLElement('i');
89
- icon.classList.add('material-icons');
90
- icon.textContent = shaka.ui.Enums.MaterialDesignIcons.RESOLUTION;
91
- this.resolutionButton_.appendChild(icon);
92
-
93
- const label = shaka.util.Dom.createHTMLElement('label');
94
- label.classList.add('shaka-overflow-button-label');
95
-
96
- /** @private {!HTMLElement}*/
97
- this.resolutionNameSpan_ = shaka.util.Dom.createHTMLElement('span');
98
- label.appendChild(this.resolutionNameSpan_);
99
-
100
- /** @private {!HTMLElement}*/
101
- this.currentResolution_ = shaka.util.Dom.createHTMLElement('span');
102
- this.currentResolution_.classList.add('shaka-current-selection-span');
103
- label.appendChild(this.currentResolution_);
104
- this.resolutionButton_.appendChild(label);
105
-
106
- this.parent.appendChild(this.resolutionButton_);
107
- }
108
-
109
-
110
- /**
111
- * @private
112
- */
113
- addResolutionMenu_() {
114
- /** @private {!HTMLElement}*/
115
- this.resolutionMenu_ = shaka.util.Dom.createHTMLElement('div');
116
- this.resolutionMenu_.classList.add('shaka-resolutions');
117
- this.resolutionMenu_.classList.add('shaka-no-propagation');
118
- this.resolutionMenu_.classList.add('shaka-show-controls-on-mouse-over');
119
- this.resolutionMenu_.classList.add('shaka-settings-menu');
120
-
121
- /** @private {!HTMLElement}*/
122
- this.backFromResolutionButton_ =
123
- shaka.util.Dom.createHTMLElement('button');
124
- this.backFromResolutionButton_.classList.add(
125
- 'shaka-back-to-overflow-button');
126
- this.resolutionMenu_.appendChild(this.backFromResolutionButton_);
127
-
128
- const backIcon = shaka.util.Dom.createHTMLElement('i');
129
- backIcon.classList.add('material-icons');
130
- backIcon.textContent = shaka.ui.Enums.MaterialDesignIcons.BACK;
131
- this.backFromResolutionButton_.appendChild(backIcon);
132
-
133
- /** @private {!HTMLElement}*/
134
- this.backFromResolutionSpan_ = shaka.util.Dom.createHTMLElement('span');
135
- this.backFromResolutionButton_.appendChild(this.backFromResolutionSpan_);
136
-
137
- const controlsContainer = this.controls.getControlsContainer();
138
- controlsContainer.appendChild(this.resolutionMenu_);
139
- }
140
-
141
-
142
75
  /** @private */
143
76
  updateResolutionSelection_() {
77
+ /** @type {!Array.<shaka.extern.Track>} */
144
78
  let tracks = this.player.getVariantTracks();
145
79
 
146
80
  // Hide resolution menu and button for audio-only content and src= content
147
81
  // without resolution information.
82
+ // TODO: for audio-only content, this should be a bitrate selection menu
83
+ // instead.
148
84
  if (tracks.length && !tracks[0].height) {
149
- shaka.ui.Utils.setDisplay(this.resolutionMenu_, false);
150
- shaka.ui.Utils.setDisplay(this.resolutionButton_, false);
85
+ shaka.ui.Utils.setDisplay(this.menu, false);
86
+ shaka.ui.Utils.setDisplay(this.button, false);
151
87
  return;
152
88
  }
153
89
  // Otherwise, restore it.
154
- shaka.ui.Utils.setDisplay(this.resolutionButton_, true);
90
+ shaka.ui.Utils.setDisplay(this.button, true);
155
91
 
156
- tracks.sort(function(t1, t2) {
157
- return t1.height - t2.height;
92
+ tracks.sort((t1, t2) => {
93
+ return t2.height - t1.height;
158
94
  });
159
- tracks.reverse();
160
95
 
161
96
  // If there is a selected variant track, then we filter out any tracks in
162
97
  // a different language. Then we use those remaining tracks to display the
163
98
  // available resolutions.
164
99
  const selectedTrack = tracks.find((track) => track.active);
165
100
  if (selectedTrack) {
166
- const language = selectedTrack.language;
167
- // Filter by current audio language.
168
- tracks = tracks.filter((track) => track.language == language);
101
+ // Filter by current audio language and channel count.
102
+ tracks = tracks.filter(
103
+ (track) => track.language == selectedTrack.language &&
104
+ track.channelsCount == selectedTrack.channelsCount);
169
105
  }
170
106
 
107
+ // Remove duplicate entries with the same height. This can happen if
108
+ // we have multiple resolutions of audio. Pick an arbitrary one.
109
+ tracks = tracks.filter((track, idx) => {
110
+ // Keep the first one with the same height.
111
+ const otherIdx = tracks.findIndex((t) => t.height == track.height);
112
+ return otherIdx == idx;
113
+ });
114
+
171
115
  // Remove old shaka-resolutions
172
116
  // 1. Save the back to menu button
173
117
  const backButton = shaka.ui.Utils.getFirstDescendantWithClassName(
174
- this.resolutionMenu_, 'shaka-back-to-overflow-button');
118
+ this.menu, 'shaka-back-to-overflow-button');
175
119
 
176
120
  // 2. Remove everything
177
- shaka.ui.Utils.removeAllChildren(this.resolutionMenu_);
121
+ shaka.ui.Utils.removeAllChildren(this.menu);
178
122
 
179
123
  // 3. Add the backTo Menu button back
180
- this.resolutionMenu_.appendChild(backButton);
124
+ this.menu.appendChild(backButton);
181
125
 
182
126
  const abrEnabled = this.player.getConfiguration().abr.enabled;
183
127
 
@@ -185,7 +129,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element {
185
129
  tracks.forEach((track) => {
186
130
  const button = shaka.util.Dom.createHTMLElement('button');
187
131
  button.classList.add('explicit-resolution');
188
- button.addEventListener('click',
132
+ this.eventManager.listen(button, 'click',
189
133
  this.onTrackSelected_.bind(this, track));
190
134
 
191
135
  const span = shaka.util.Dom.createHTMLElement('span');
@@ -197,15 +141,15 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element {
197
141
  button.setAttribute('aria-selected', 'true');
198
142
  button.appendChild(shaka.ui.Utils.checkmarkIcon());
199
143
  span.classList.add('shaka-chosen-item');
200
- this.currentResolution_.textContent = span.textContent;
144
+ this.currentSelection.textContent = span.textContent;
201
145
  }
202
- this.resolutionMenu_.appendChild(button);
146
+ this.menu.appendChild(button);
203
147
  });
204
148
 
205
149
  // Add the Auto button
206
150
  const autoButton = shaka.util.Dom.createHTMLElement('button');
207
151
  autoButton.classList.add('shaka-enable-abr-button');
208
- autoButton.addEventListener('click', function() {
152
+ this.eventManager.listen(autoButton, 'click', function() {
209
153
  const config = {abr: {enabled: true}};
210
154
  this.player.configure(config);
211
155
  this.updateResolutionSelection_();
@@ -225,24 +169,17 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element {
225
169
 
226
170
  this.abrOnSpan_.classList.add('shaka-chosen-item');
227
171
 
228
- this.currentResolution_.textContent =
172
+ this.currentSelection.textContent =
229
173
  this.localization.resolve(shaka.ui.Locales.Ids.AUTO_QUALITY);
230
174
  }
231
175
 
232
- this.resolutionMenu_.appendChild(autoButton);
233
- shaka.ui.Utils.focusOnTheChosenItem(this.resolutionMenu_);
176
+ this.menu.appendChild(autoButton);
177
+ shaka.ui.Utils.focusOnTheChosenItem(this.menu);
234
178
  this.controls.dispatchEvent(
235
179
  new shaka.util.FakeEvent('resolutionselectionupdated'));
236
180
  }
237
181
 
238
182
 
239
- /** @private */
240
- onResolutionClick_() {
241
- this.controls.dispatchEvent(new shaka.util.FakeEvent('submenuopen'));
242
- shaka.ui.Utils.setDisplay(this.resolutionMenu_, true);
243
- shaka.ui.Utils.focusOnTheChosenItem(this.resolutionMenu_);
244
- }
245
-
246
183
  /**
247
184
  * @param {!shaka.extern.Track} track
248
185
  * @private
@@ -251,8 +188,8 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element {
251
188
  // Disable abr manager before changing tracks.
252
189
  let config = {abr: {enabled: false}};
253
190
  this.player.configure(config);
254
-
255
- this.player.selectVariantTrack(track, /* clearBuffer */ true);
191
+ const clearBuffer = this.controls.getConfig().clearBufferOnQualityChange;
192
+ this.player.selectVariantTrack(track, clearBuffer);
256
193
  }
257
194
 
258
195
 
@@ -262,19 +199,19 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element {
262
199
  updateLocalizedStrings_() {
263
200
  const LocIds = shaka.ui.Locales.Ids;
264
201
 
265
- this.resolutionButton_.setAttribute(shaka.ui.Constants.ARIA_LABEL,
202
+ this.button.setAttribute(shaka.ui.Constants.ARIA_LABEL,
266
203
  this.localization.resolve(LocIds.RESOLUTION));
267
- this.backFromResolutionButton_.setAttribute(shaka.ui.Constants.ARIA_LABEL,
204
+ this.backButton.setAttribute(shaka.ui.Constants.ARIA_LABEL,
268
205
  this.localization.resolve(LocIds.RESOLUTION));
269
- this.backFromResolutionSpan_.textContent =
206
+ this.backSpan.textContent =
270
207
  this.localization.resolve(LocIds.RESOLUTION);
271
- this.resolutionNameSpan_.textContent =
208
+ this.nameSpan.textContent =
272
209
  this.localization.resolve(LocIds.RESOLUTION);
273
210
  this.abrOnSpan_.textContent =
274
211
  this.localization.resolve(LocIds.AUTO_QUALITY);
275
212
 
276
213
  if (this.player.getConfiguration().abr.enabled) {
277
- this.currentResolution_.textContent =
214
+ this.currentSelection.textContent =
278
215
  this.localization.resolve(shaka.ui.Locales.Ids.AUTO_QUALITY);
279
216
  }
280
217
  }
package/ui/seek_bar.js ADDED
@@ -0,0 +1,204 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2016 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+
19
+ goog.provide('shaka.ui.SeekBar');
20
+
21
+ goog.require('shaka.ui.Constants');
22
+ goog.require('shaka.ui.Locales');
23
+ goog.require('shaka.ui.Localization');
24
+ goog.require('shaka.ui.RangeElement');
25
+ goog.require('shaka.ui.Utils');
26
+ goog.require('shaka.util.Timer');
27
+
28
+
29
+ /**
30
+ * @extends {shaka.ui.RangeElement}
31
+ * @final
32
+ * @export
33
+ */
34
+ shaka.ui.SeekBar = class extends shaka.ui.RangeElement {
35
+ /**
36
+ * @param {!HTMLElement} parent
37
+ * @param {!shaka.ui.Controls} controls
38
+ */
39
+ constructor(parent, controls) {
40
+ super(parent, controls,
41
+ ['shaka-seek-bar-container'],
42
+ [
43
+ 'shaka-seek-bar',
44
+ 'shaka-no-propagation',
45
+ 'shaka-show-controls-on-mouse-over',
46
+ ]);
47
+
48
+ /**
49
+ * This timer is used to introduce a delay between the user scrubbing across
50
+ * the seek bar and the seek being sent to the player.
51
+ *
52
+ * @private {shaka.util.Timer}
53
+ */
54
+ this.seekTimer_ = new shaka.util.Timer(() => {
55
+ this.video.currentTime = this.getValue();
56
+ });
57
+
58
+ this.eventManager.listen(this.localization,
59
+ shaka.ui.Localization.LOCALE_UPDATED,
60
+ () => this.updateAriaLabel_());
61
+
62
+ this.eventManager.listen(this.localization,
63
+ shaka.ui.Localization.LOCALE_CHANGED,
64
+ () => this.updateAriaLabel_());
65
+
66
+ // Initialize seek state and label.
67
+ this.setValue(this.video.currentTime);
68
+ this.update();
69
+ this.updateAriaLabel_();
70
+ }
71
+
72
+ /** @override */
73
+ async destroy() {
74
+ if (this.seekTimer_) {
75
+ this.seekTimer_.stop();
76
+ this.seekTimer_ = null;
77
+ }
78
+
79
+ await super.destroy();
80
+ }
81
+
82
+ /**
83
+ * Called by the base class when user interaction with the input element
84
+ * begins.
85
+ *
86
+ * @override
87
+ */
88
+ onChangeStart() {
89
+ this.controls.setSeeking(true);
90
+ this.video.pause();
91
+ }
92
+
93
+ /**
94
+ * Update the video element's state to match the input element's state.
95
+ * Called by the base class when the input element changes.
96
+ *
97
+ * @override
98
+ */
99
+ onChange() {
100
+ if (!this.video.duration) {
101
+ // Can't seek yet. Ignore.
102
+ return;
103
+ }
104
+
105
+ // Update the UI right away.
106
+ this.update();
107
+
108
+ // We want to wait until the user has stopped moving the seek bar for a
109
+ // little bit to reduce the number of times we ask the player to seek.
110
+ //
111
+ // To do this, we will start a timer that will fire in a little bit, but if
112
+ // we see another seek bar change, we will cancel that timer and re-start
113
+ // it.
114
+ //
115
+ // Calling |start| on an already pending timer will cancel the old request
116
+ // and start the new one.
117
+ this.seekTimer_.tickAfter(/* seconds= */ 0.125);
118
+ }
119
+
120
+ /**
121
+ * Called by the base class when user interaction with the input element
122
+ * ends.
123
+ *
124
+ * @override
125
+ */
126
+ onChangeEnd() {
127
+ // They just let go of the seek bar, so cancel the timer and manually
128
+ // call the event so that we can respond immediately.
129
+ this.seekTimer_.tickNow();
130
+ this.controls.setSeeking(false);
131
+ this.video.play();
132
+ }
133
+
134
+ /** @return {boolean} */
135
+ isShowing() {
136
+ // It is showing by default, so it is hidden if shaka-hidden is in the list.
137
+ return !this.container.classList.contains('shaka-hidden');
138
+ }
139
+
140
+ /**
141
+ * Called by Controls on a timer to update the state of the seek bar.
142
+ * Also called internally when the user interacts with the input element.
143
+ */
144
+ update() {
145
+ const Constants = shaka.ui.Constants;
146
+
147
+ const currentTime = this.getValue();
148
+ const bufferedLength = this.video.buffered.length;
149
+ const bufferedStart = bufferedLength ? this.video.buffered.start(0) : 0;
150
+ const bufferedEnd =
151
+ bufferedLength ? this.video.buffered.end(bufferedLength - 1) : 0;
152
+
153
+ const seekRange = this.player.seekRange();
154
+ const seekRangeSize = seekRange.end - seekRange.start;
155
+
156
+ this.setRange(seekRange.start, seekRange.end);
157
+
158
+ // Hide seekbar if the seek window is very small.
159
+ if (this.player.isLive() &&
160
+ seekRangeSize < Constants.MIN_SEEK_WINDOW_TO_SHOW_SEEKBAR) {
161
+ shaka.ui.Utils.setDisplay(this.container, false);
162
+ } else {
163
+ shaka.ui.Utils.setDisplay(this.container, true);
164
+
165
+ if (bufferedLength == 0) {
166
+ this.container.style.background = Constants.SEEK_BAR_BASE_COLOR;
167
+ } else {
168
+ const clampedBufferStart = Math.max(bufferedStart, seekRange.start);
169
+ const clampedBufferEnd = Math.min(bufferedEnd, seekRange.end);
170
+ const clampedCurrentTime = Math.min(
171
+ Math.max(currentTime, seekRange.start),
172
+ seekRange.end);
173
+
174
+ const bufferStartDistance = clampedBufferStart - seekRange.start;
175
+ const bufferEndDistance = clampedBufferEnd - seekRange.start;
176
+ const playheadDistance = clampedCurrentTime - seekRange.start;
177
+
178
+ // NOTE: the fallback to zero eliminates NaN.
179
+ const bufferStartFraction = (bufferStartDistance / seekRangeSize) || 0;
180
+ const bufferEndFraction = (bufferEndDistance / seekRangeSize) || 0;
181
+ const playheadFraction = (playheadDistance / seekRangeSize) || 0;
182
+
183
+ const makeColor = (color, fract) => color + ' ' + (fract * 100) + '%';
184
+ const gradient = [
185
+ 'to right',
186
+ makeColor(Constants.SEEK_BAR_BASE_COLOR, bufferStartFraction),
187
+ makeColor(Constants.SEEK_BAR_PLAYED_COLOR, bufferStartFraction),
188
+ makeColor(Constants.SEEK_BAR_PLAYED_COLOR, playheadFraction),
189
+ makeColor(Constants.SEEK_BAR_BUFFERED_COLOR, playheadFraction),
190
+ makeColor(Constants.SEEK_BAR_BUFFERED_COLOR, bufferEndFraction),
191
+ makeColor(Constants.SEEK_BAR_BASE_COLOR, bufferEndFraction),
192
+ ];
193
+ this.container.style.background =
194
+ 'linear-gradient(' + gradient.join(',') + ')';
195
+ }
196
+ }
197
+ }
198
+
199
+ /** @private */
200
+ updateAriaLabel_() {
201
+ this.bar.setAttribute(shaka.ui.Constants.ARIA_LABEL,
202
+ this.localization.resolve(shaka.ui.Locales.Ids.SEEK));
203
+ }
204
+ };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2016 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+
19
+ goog.provide('shaka.ui.SettingsMenu');
20
+
21
+ goog.require('shaka.ui.Element');
22
+ goog.require('shaka.ui.Enums');
23
+ goog.require('shaka.util.Dom');
24
+
25
+
26
+ /**
27
+ * @extends {shaka.ui.Element}
28
+ * @export
29
+ */
30
+ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
31
+ /**
32
+ * @param {!HTMLElement} parent
33
+ * @param {!shaka.ui.Controls} controls
34
+ * @param {string} iconText
35
+ */
36
+ constructor(parent, controls, iconText) {
37
+ super(parent, controls);
38
+
39
+ this.addButton_(iconText);
40
+
41
+ this.addMenu_();
42
+
43
+ this.eventManager.listen(this.button, 'click', () => {
44
+ this.onButtonClick_();
45
+ });
46
+ }
47
+
48
+
49
+ /**
50
+ * @param {string} iconText
51
+ * @private
52
+ */
53
+ addButton_(iconText) {
54
+ /** @protected {!HTMLElement}*/
55
+ this.button = shaka.util.Dom.createHTMLElement('button');
56
+
57
+ /** @protected {!HTMLElement}*/
58
+ this.icon = shaka.util.Dom.createHTMLElement('i');
59
+ this.icon.classList.add('material-icons');
60
+ this.icon.textContent = iconText;
61
+ this.button.appendChild(this.icon);
62
+
63
+ const label = shaka.util.Dom.createHTMLElement('label');
64
+ label.classList.add('shaka-overflow-button-label');
65
+
66
+ /** @protected {!HTMLElement}*/
67
+ this.nameSpan = shaka.util.Dom.createHTMLElement('span');
68
+ label.appendChild(this.nameSpan);
69
+
70
+ /** @protected {!HTMLElement}*/
71
+ this.currentSelection = shaka.util.Dom.createHTMLElement('span');
72
+ this.currentSelection.classList.add('shaka-current-selection-span');
73
+ label.appendChild(this.currentSelection);
74
+ this.button.appendChild(label);
75
+
76
+ this.parent.appendChild(this.button);
77
+ }
78
+
79
+
80
+ /** @private */
81
+ addMenu_() {
82
+ /** @protected {!HTMLElement}*/
83
+ this.menu = shaka.util.Dom.createHTMLElement('div');
84
+ this.menu.classList.add('shaka-no-propagation');
85
+ this.menu.classList.add('shaka-show-controls-on-mouse-over');
86
+ this.menu.classList.add('shaka-settings-menu');
87
+
88
+ /** @protected {!HTMLElement}*/
89
+ this.backButton = shaka.util.Dom.createHTMLElement('button');
90
+ this.backButton.classList.add('shaka-back-to-overflow-button');
91
+ this.menu.appendChild(this.backButton);
92
+
93
+ const backIcon = shaka.util.Dom.createHTMLElement('i');
94
+ backIcon.classList.add('material-icons');
95
+ backIcon.textContent = shaka.ui.Enums.MaterialDesignIcons.BACK;
96
+ this.backButton.appendChild(backIcon);
97
+
98
+ /** @protected {!HTMLElement}*/
99
+ this.backSpan = shaka.util.Dom.createHTMLElement('span');
100
+ this.backButton.appendChild(this.backSpan);
101
+
102
+ const controlsContainer = this.controls.getControlsContainer();
103
+ controlsContainer.appendChild(this.menu);
104
+ }
105
+
106
+
107
+ /** @private */
108
+ onButtonClick_() {
109
+ this.controls.dispatchEvent(new shaka.util.FakeEvent('submenuopen'));
110
+ shaka.ui.Utils.setDisplay(this.menu, true);
111
+ shaka.ui.Utils.focusOnTheChosenItem(this.menu);
112
+ }
113
+ };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2016 Google Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+
19
+ goog.provide('shaka.ui.SmallPlayButton');
20
+
21
+ goog.require('shaka.ui.PlayButton');
22
+
23
+
24
+ /**
25
+ * @extends {shaka.ui.PlayButton}
26
+ * @final
27
+ * @export
28
+ */
29
+ shaka.ui.SmallPlayButton = class extends shaka.ui.PlayButton {
30
+ /**
31
+ * @param {!HTMLElement} parent
32
+ * @param {!shaka.ui.Controls} controls
33
+ */
34
+ constructor(parent, controls) {
35
+ super(parent, controls);
36
+
37
+ this.button.classList.add('shaka-small-play-button');
38
+ this.button.classList.add('material-icons');
39
+
40
+ this.updateIcon_();
41
+ this.updateAriaLabel();
42
+
43
+ this.eventManager.listen(this.video, 'play', () => {
44
+ this.updateIcon_();
45
+ });
46
+
47
+ this.eventManager.listen(this.video, 'pause', () => {
48
+ this.updateIcon_();
49
+ });
50
+ }
51
+
52
+
53
+ /** @private */
54
+ updateIcon_() {
55
+ const Icons = shaka.ui.Enums.MaterialDesignIcons;
56
+ this.button.textContent = this.isPaused() ? Icons.PLAY : Icons.PAUSE;
57
+ }
58
+ };
59
+
60
+
61
+ /**
62
+ * @implements {shaka.extern.IUIElement.Factory}
63
+ * @final
64
+ */
65
+ shaka.ui.SmallPlayButton.Factory = class {
66
+ /** @override */
67
+ create(rootElement, controls) {
68
+ return new shaka.ui.SmallPlayButton(rootElement, controls);
69
+ }
70
+ };
71
+
72
+ shaka.ui.Controls.registerElement(
73
+ 'play_pause', new shaka.ui.SmallPlayButton.Factory());