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
@@ -39,8 +39,8 @@
39
39
  /* These control the color and size of the various pieces. */
40
40
  @thumb-color: white;
41
41
  @track-default-color: white;
42
- @thumb-size: 10px;
43
- @track-height: 3.4px;
42
+ @thumb-size: 12px;
43
+ @track-height: 4px;
44
44
 
45
45
  /* The range container is the div that contains a range element.
46
46
  * This div will act as a virtual track to allow us to style the track space.
@@ -51,8 +51,10 @@
51
51
 
52
52
  /* Vertical margins to occupy the same space as the thumb. */
53
53
  margin: (@thumb-size - @track-height)/2 6px;
54
+
54
55
  /* Smaller height to contain the background for the virtual track. */
55
56
  height: @track-height;
57
+
56
58
  /* Rounded ends on the virtual track. */
57
59
  border-radius: @track-height;
58
60
 
@@ -123,6 +125,7 @@
123
125
  &::-webkit-slider-runnable-track {
124
126
  .track();
125
127
  }
128
+
126
129
  &::-webkit-slider-thumb {
127
130
  .thumb();
128
131
  }
@@ -131,6 +134,7 @@
131
134
  &::-moz-range-track {
132
135
  .track();
133
136
  }
137
+
134
138
  &::-moz-range-thumb {
135
139
  .thumb();
136
140
  }
@@ -139,6 +143,7 @@
139
143
  &::-ms-track {
140
144
  .track();
141
145
  }
146
+
142
147
  &::-ms-thumb {
143
148
  .thumb();
144
149
  }
@@ -152,14 +157,17 @@
152
157
  &::-ms-fill-lower {
153
158
  .hidden();
154
159
  }
160
+
155
161
  &::-ms-fill-upper {
156
162
  .hidden();
157
163
  }
158
164
  }
159
165
 
160
- .shaka-volume-bar-container {
166
+ .shaka-range-container {
161
167
  .range-container();
168
+ }
162
169
 
170
+ .shaka-volume-bar-container {
163
171
  width: 100px;
164
172
 
165
173
  /* Hide volume slider on mobile-sized screens. */
@@ -169,16 +177,10 @@
169
177
  }
170
178
 
171
179
  .shaka-seek-bar-container {
172
- .range-container();
173
-
174
180
  /* TODO: Document why! */
175
181
  width: 96.5%;
176
182
  }
177
183
 
178
- .shaka-seek-bar {
179
- .range-element();
180
- }
181
-
182
- .shaka-volume-bar {
184
+ .shaka-range-element {
183
185
  .range-element();
184
186
  }
@@ -71,10 +71,12 @@
71
71
  stroke-dasharray: 1, 200;
72
72
  stroke-dashoffset: 0;
73
73
  }
74
+
74
75
  50% {
75
76
  stroke-dasharray: 89, 200;
76
77
  stroke-dashoffset: -35px;
77
78
  }
79
+
78
80
  100% {
79
81
  stroke-dasharray: 89, 200;
80
82
  stroke-dashoffset: -124px;
@@ -64,7 +64,7 @@ goog.require('shaka.util.Dom');
64
64
 
65
65
  for (let i = 0; i < backToOverflowMenuButtons.length; i++) {
66
66
  const button = backToOverflowMenuButtons[i];
67
- button.addEventListener('click', () => {
67
+ this.eventManager.listen(button, 'click', () => {
68
68
  // Hide the submenus, display the overflow menu
69
69
  this.controls.hideSettingsMenus();
70
70
  shaka.ui.Utils.setDisplay(this.overflowMenu_, true);
package/ui/pip_button.js CHANGED
@@ -100,7 +100,7 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
100
100
  this.onLeavePictureInPicture_();
101
101
  });
102
102
 
103
- this.eventManager.listen(this.controls, 'caststatuschange', (e) => {
103
+ this.eventManager.listen(this.controls, 'caststatuschanged', (e) => {
104
104
  this.onCastStatusChange_(e);
105
105
  });
106
106
 
@@ -16,10 +16,9 @@
16
16
  */
17
17
 
18
18
 
19
- goog.provide('shaka.ui.PlayPauseButton');
19
+ goog.provide('shaka.ui.PlayButton');
20
20
 
21
21
  goog.require('shaka.ui.Element');
22
- goog.require('shaka.ui.Enums');
23
22
  goog.require('shaka.ui.Locales');
24
23
  goog.require('shaka.ui.Localization');
25
24
  goog.require('shaka.util.Dom');
@@ -27,10 +26,9 @@ goog.require('shaka.util.Dom');
27
26
 
28
27
  /**
29
28
  * @extends {shaka.ui.Element}
30
- * @final
31
29
  * @export
32
30
  */
33
- shaka.ui.PlayPauseButton = class extends shaka.ui.Element {
31
+ shaka.ui.PlayButton = class extends shaka.ui.Element {
34
32
  /**
35
33
  * @param {!HTMLElement} parent
36
34
  * @param {!shaka.ui.Controls} controls
@@ -38,37 +36,30 @@ shaka.ui.PlayPauseButton = class extends shaka.ui.Element {
38
36
  constructor(parent, controls) {
39
37
  super(parent, controls);
40
38
 
41
- /** @private {!HTMLElement} */
42
- this.button_ = shaka.util.Dom.createHTMLElement('button');
43
- this.button_.classList.add('shaka-play-pause-button');
44
- this.button_.classList.add('material-icons');
45
- this.parent.appendChild(this.button_);
46
-
47
- this.updateIcon_();
48
- this.updateAriaLabel_();
39
+ /** @protected {!HTMLElement} */
40
+ this.button = shaka.util.Dom.createHTMLElement('button');
41
+ this.parent.appendChild(this.button);
49
42
 
50
43
  const LOCALE_UPDATED = shaka.ui.Localization.LOCALE_UPDATED;
51
44
  this.eventManager.listen(this.localization, LOCALE_UPDATED, () => {
52
- this.updateAriaLabel_();
45
+ this.updateAriaLabel();
53
46
  });
54
47
 
55
48
  const LOCALE_CHANGED = shaka.ui.Localization.LOCALE_CHANGED;
56
49
  this.eventManager.listen(this.localization, LOCALE_CHANGED, () => {
57
- this.updateAriaLabel_();
50
+ this.updateAriaLabel();
58
51
  });
59
52
 
60
53
  this.eventManager.listen(this.video, 'play', () => {
61
- this.updateAriaLabel_();
62
- this.updateIcon_();
54
+ this.updateAriaLabel();
63
55
  });
64
56
 
65
57
  this.eventManager.listen(this.video, 'pause', () => {
66
- this.updateAriaLabel_();
67
- this.updateIcon_();
58
+ this.updateAriaLabel();
68
59
  });
69
60
 
70
- this.eventManager.listen(this.button_, 'click', () => {
71
- if (this.isPaused_()) {
61
+ this.eventManager.listen(this.button, 'click', () => {
62
+ if (this.isPaused()) {
72
63
  this.video.play();
73
64
  } else {
74
65
  this.video.pause();
@@ -78,41 +69,20 @@ shaka.ui.PlayPauseButton = class extends shaka.ui.Element {
78
69
 
79
70
  /**
80
71
  * @return {boolean}
81
- * @private
72
+ * @protected
82
73
  */
83
- isPaused_() {
74
+ isPaused() {
84
75
  // The video element is in a paused state while seeking, but we don't count
85
76
  // that.
86
77
  return this.video.paused && !this.controls.isSeeking();
87
78
  }
88
79
 
89
- /** @private */
90
- updateAriaLabel_() {
80
+ /** @protected */
81
+ updateAriaLabel() {
91
82
  const LocIds = shaka.ui.Locales.Ids;
92
- const label = this.isPaused_() ? LocIds.PLAY : LocIds.PAUSE;
83
+ const label = this.isPaused() ? LocIds.PLAY : LocIds.PAUSE;
93
84
 
94
- this.button_.setAttribute(shaka.ui.Constants.ARIA_LABEL,
85
+ this.button.setAttribute(shaka.ui.Constants.ARIA_LABEL,
95
86
  this.localization.resolve(label));
96
87
  }
97
-
98
- /** @private */
99
- updateIcon_() {
100
- const Icons = shaka.ui.Enums.MaterialDesignIcons;
101
- this.button_.textContent = this.isPaused_() ? Icons.PLAY : Icons.PAUSE;
102
- }
103
- };
104
-
105
-
106
- /**
107
- * @implements {shaka.extern.IUIElement.Factory}
108
- * @final
109
- */
110
- shaka.ui.PlayPauseButton.Factory = class {
111
- /** @override */
112
- create(rootElement, controls) {
113
- return new shaka.ui.PlayPauseButton(rootElement, controls);
114
- }
115
88
  };
116
-
117
- shaka.ui.Controls.registerElement(
118
- 'play_pause', new shaka.ui.PlayPauseButton.Factory());
@@ -37,7 +37,7 @@ shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
37
37
 
38
38
  this.currentTime_ = shaka.util.Dom.createHTMLElement('button');
39
39
  this.currentTime_.classList.add('shaka-current-time');
40
- this.currentTime_.textContent = '0:00';
40
+ this.setValue_('0:00');
41
41
  this.parent.appendChild(this.currentTime_);
42
42
 
43
43
  this.eventManager.listen(this.currentTime_, 'click', () => {
@@ -56,10 +56,18 @@ shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
56
56
  });
57
57
  }
58
58
 
59
+ /** @private */
60
+ setValue_(value) {
61
+ // To avoid constant updates to the DOM, which makes debugging more
62
+ // difficult, only set the value if it has changed. If we don't do this
63
+ // check, the DOM updates constantly, this element flashes in the debugger
64
+ // in Chrome, and you can't make changes in the CSS panel.
65
+ if (value != this.currentTime_.textContent) {
66
+ this.currentTime_.textContent = value;
67
+ }
68
+ }
59
69
 
60
- /**
61
- * @private
62
- */
70
+ /** @private */
63
71
  updateTime_() {
64
72
  const isSeeking = this.controls.isSeeking();
65
73
  let displayTime = this.controls.getDisplayTime();
@@ -80,24 +88,21 @@ shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
80
88
  // The button should only be clickable when it's live stream content, and
81
89
  // the current play time is behind live edge.
82
90
  if ((displayTime >= 1) || isSeeking) {
83
- this.currentTime_.textContent =
84
- '- ' + this.buildTimeString_(displayTime, showHour);
91
+ this.setValue_('- ' + this.buildTimeString_(displayTime, showHour));
85
92
  this.currentTime_.disabled = false;
86
93
  } else {
87
- this.currentTime_.textContent =
88
- this.localization.resolve(shaka.ui.Locales.Ids.LIVE);
94
+ this.setValue_(this.localization.resolve(shaka.ui.Locales.Ids.LIVE));
89
95
  this.currentTime_.disabled = true;
90
96
  }
91
97
  } else {
92
98
  let showHour = duration >= 3600;
93
99
 
94
- this.currentTime_.textContent =
95
- this.buildTimeString_(displayTime, showHour);
96
-
100
+ let value = this.buildTimeString_(displayTime, showHour);
97
101
  if (duration) {
98
- this.currentTime_.textContent += ' / ' +
102
+ value += ' / ' +
99
103
  this.buildTimeString_(duration, showHour);
100
104
  }
105
+ this.setValue_(value);
101
106
  this.currentTime_.disabled = true;
102
107
  }
103
108
  }
@@ -0,0 +1,176 @@
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.RangeElement');
20
+
21
+ goog.require('shaka.ui.Element');
22
+ goog.require('shaka.util.Dom');
23
+
24
+
25
+ /**
26
+ * A range element, built to work across browsers.
27
+ *
28
+ * In particular, getting styles to work right on IE requires a specific
29
+ * structure.
30
+ *
31
+ * This also handles the case where the range element is being manipulated and
32
+ * updated at the same time. This can happen when seeking during playback or
33
+ * when casting.
34
+ *
35
+ * @extends {shaka.ui.Element}
36
+ * @export
37
+ */
38
+ shaka.ui.RangeElement = class extends shaka.ui.Element {
39
+ /**
40
+ * @param {!HTMLElement} parent
41
+ * @param {!shaka.ui.Controls} controls
42
+ * @param {!Array.<string>} containerClassNames
43
+ * @param {!Array.<string>} barClassNames
44
+ */
45
+ constructor(parent, controls, containerClassNames, barClassNames) {
46
+ super(parent, controls);
47
+
48
+ /**
49
+ * This container is to support IE 11. See detailed notes in
50
+ * less/range_elements.less for a complete explanation.
51
+ * @protected {!HTMLElement}
52
+ */
53
+ this.container = shaka.util.Dom.createHTMLElement('div');
54
+ this.container.classList.add('shaka-range-container');
55
+ this.container.classList.add(...containerClassNames);
56
+
57
+ /** @private {boolean} */
58
+ this.isChanging_ = false;
59
+
60
+ /** @protected {!HTMLInputElement} */
61
+ this.bar =
62
+ /** @type {!HTMLInputElement} */ (document.createElement('input'));
63
+
64
+ this.bar.classList.add('shaka-range-element');
65
+ this.bar.classList.add(...barClassNames);
66
+ this.bar.type = 'range';
67
+ // TODO(#2027): step=any causes keyboard nav problems on IE 11.
68
+ this.bar.step = 'any';
69
+ this.bar.min = '0';
70
+ this.bar.max = '1';
71
+ this.bar.value = '0';
72
+
73
+ this.container.appendChild(this.bar);
74
+ this.parent.appendChild(this.container);
75
+
76
+ this.eventManager.listen(this.bar, 'mousedown', () => {
77
+ this.isChanging_ = true;
78
+ this.onChangeStart();
79
+ });
80
+
81
+ this.eventManager.listen(this.bar, 'touchstart', (e) => {
82
+ this.isChanging_ = true;
83
+ this.setBarValueForTouch_(e);
84
+ this.onChangeStart();
85
+ }, {passive: true});
86
+
87
+ this.eventManager.listen(this.bar, 'input', () => {
88
+ this.onChange();
89
+ });
90
+
91
+ this.eventManager.listen(this.bar, 'touchmove', (e) => {
92
+ this.setBarValueForTouch_(e);
93
+ this.onChange();
94
+ });
95
+
96
+ this.eventManager.listen(this.bar, 'touchend', (e) => {
97
+ this.isChanging_ = false;
98
+ this.setBarValueForTouch_(e);
99
+ this.onChangeEnd();
100
+ });
101
+
102
+ this.eventManager.listen(this.bar, 'mouseup', () => {
103
+ this.isChanging_ = false;
104
+ this.onChangeEnd();
105
+ });
106
+ }
107
+
108
+ /**
109
+ * @param {number} min
110
+ * @param {number} max
111
+ */
112
+ setRange(min, max) {
113
+ this.bar.min = min;
114
+ this.bar.max = max;
115
+ }
116
+
117
+ /**
118
+ * Called when user interaction begins.
119
+ * To be overridden by subclasses.
120
+ */
121
+ onChangeStart() {}
122
+
123
+ /**
124
+ * Called when a new value is set by user interaction.
125
+ * To be overridden by subclasses.
126
+ */
127
+ onChange() {}
128
+
129
+ /**
130
+ * Called when user interaction ends.
131
+ * To be overridden by subclasses.
132
+ */
133
+ onChangeEnd() {}
134
+
135
+ /** @return {number} */
136
+ getValue() {
137
+ return parseFloat(this.bar.value);
138
+ }
139
+
140
+ /** @param {number} value */
141
+ setValue(value) {
142
+ // The user interaction overrides any external values being pushed in.
143
+ if (this.isChanging_) {
144
+ return;
145
+ }
146
+
147
+ this.bar.value = value;
148
+ }
149
+
150
+ /**
151
+ * Synchronize the touch position with the range value.
152
+ * Comes in handy on iOS, where users have to grab the handle in order
153
+ * to start seeking.
154
+ * @param {Event} event
155
+ * @private
156
+ */
157
+ setBarValueForTouch_(event) {
158
+ event.preventDefault();
159
+
160
+ const changedTouch = /** @type {TouchEvent} */ (event).changedTouches[0];
161
+ const rect = this.bar.getBoundingClientRect();
162
+
163
+ // Calculate the range value based on the touch position.
164
+ let value = (this.bar.max / rect.width) *
165
+ (changedTouch.clientX - rect.left);
166
+
167
+ // Keep value within bounds.
168
+ if (value < this.bar.min) {
169
+ value = this.bar.min;
170
+ } else if (value > this.bar.max) {
171
+ value = this.bar.max;
172
+ }
173
+
174
+ this.bar.value = value;
175
+ }
176
+ };