OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview MediaControls class implements media playback controls | 6 * @fileoverview MediaControls class implements media playback controls |
7 * that exist outside of the audio/video HTML element. | 7 * that exist outside of the audio/video HTML element. |
8 */ | 8 */ |
9 | 9 |
10 /** | 10 /** |
11 * @param {HTMLElement} containerElement The container for the controls. | 11 * @param {HTMLElement} containerElement The container for the controls. |
12 * @param {function} onMediaError Function to display an error message. | 12 * @param {function} onMediaError Function to display an error message. |
13 * @constructor | 13 * @constructor |
14 */ | 14 */ |
15 function MediaControls(containerElement, onMediaError) { | 15 function MediaControls(containerElement, onMediaError) { |
16 this.container_ = containerElement; | 16 this.container_ = containerElement; |
17 this.document_ = this.container_.ownerDocument; | 17 this.document_ = this.container_.ownerDocument; |
18 this.media_ = null; | 18 this.media_ = null; |
19 | 19 |
20 this.onMediaPlayBound_ = this.onMediaPlay_.bind(this, true); | 20 this.onMediaPlayBound_ = this.onMediaPlay_.bind(this, true); |
21 this.onMediaPauseBound_ = this.onMediaPlay_.bind(this, false); | 21 this.onMediaPauseBound_ = this.onMediaPlay_.bind(this, false); |
22 this.onMediaDurationBound_ = this.onMediaDuration_.bind(this); | 22 this.onMediaDurationBound_ = this.onMediaDuration_.bind(this); |
23 this.onMediaProgressBound_ = this.onMediaProgress_.bind(this); | 23 this.onMediaProgressBound_ = this.onMediaProgress_.bind(this); |
24 this.onMediaError_ = onMediaError || function() {}; | 24 this.onMediaError_ = onMediaError || function() {}; |
25 } | 25 } |
26 | 26 |
27 /** | 27 /** |
28 * Button's state types. Values are used as CSS class names. | |
29 * @enum {string} | |
30 */ | |
31 MediaControls.ButtonStateType = { | |
32 DEFAULT: 'default', | |
33 PLAYING: 'playing', | |
34 ENDED: 'ended' | |
35 }; | |
36 | |
37 /** | |
28 * @return {HTMLAudioElement|HTMLVideoElement} The media element. | 38 * @return {HTMLAudioElement|HTMLVideoElement} The media element. |
29 */ | 39 */ |
30 MediaControls.prototype.getMedia = function() { return this.media_ }; | 40 MediaControls.prototype.getMedia = function() { return this.media_ }; |
31 | 41 |
32 /** | 42 /** |
33 * Format the time in hh:mm:ss format (omitting redundant leading zeros). | 43 * Format the time in hh:mm:ss format (omitting redundant leading zeros). |
34 * | 44 * |
35 * @param {number} timeInSec Time in seconds. | 45 * @param {number} timeInSec Time in seconds. |
36 * @return {string} Formatted time string. | 46 * @return {string} Formatted time string. |
37 * @private | 47 * @private |
(...skipping 25 matching lines...) Expand all Loading... | |
63 parent.appendChild(control); | 73 parent.appendChild(control); |
64 return control; | 74 return control; |
65 }; | 75 }; |
66 | 76 |
67 /** | 77 /** |
68 * Create a custom button. | 78 * Create a custom button. |
69 * | 79 * |
70 * @param {string} className Class name. | 80 * @param {string} className Class name. |
71 * @param {function(Event)} handler Click handler. | 81 * @param {function(Event)} handler Click handler. |
72 * @param {HTMLElement=} opt_parent Parent element or container if undefined. | 82 * @param {HTMLElement=} opt_parent Parent element or container if undefined. |
73 * @param {boolean=} opt_toggle True if the button has toggle state. | 83 * @param {number=} opt_numStates Number of states, default: 1. |
yoshiki
2013/03/11 04:42:45
Could you change the type of the last argument to
mtomasz
2013/03/11 04:48:15
I think it would make the code worse. The enum con
yoshiki
2013/03/11 05:17:03
Sorry, I misunderstood. |number=| is ok
| |
74 * @return {HTMLElement} The new button element. | 84 * @return {HTMLElement} The new button element. |
75 */ | 85 */ |
76 MediaControls.prototype.createButton = function( | 86 MediaControls.prototype.createButton = function( |
77 className, handler, opt_parent, opt_toggle) { | 87 className, handler, opt_parent, opt_numStates) { |
88 opt_numStates = opt_numStates || 1; | |
89 | |
78 var button = this.createControl(className, opt_parent); | 90 var button = this.createControl(className, opt_parent); |
79 button.classList.add('media-button'); | 91 button.classList.add('media-button'); |
80 button.addEventListener('click', handler); | 92 button.addEventListener('click', handler); |
81 | 93 |
82 var numStates = opt_toggle ? 2 : 1; | 94 var stateTypes = Object.keys(MediaControls.ButtonStateType); |
83 for (var state = 0; state != numStates; state++) { | 95 for (var state = 0; state != opt_numStates; state++) { |
84 var stateClass = 'state' + state; | 96 var stateClass = MediaControls.ButtonStateType[stateTypes[state]]; |
85 this.createControl('normal ' + stateClass, button); | 97 this.createControl('normal ' + stateClass, button); |
86 this.createControl('hover ' + stateClass, button); | 98 this.createControl('hover ' + stateClass, button); |
87 this.createControl('active ' + stateClass, button); | 99 this.createControl('active ' + stateClass, button); |
88 } | 100 } |
89 this.createControl('disabled', button); | 101 this.createControl('disabled', button); |
90 | 102 |
91 button.setAttribute('state', 0); | 103 button.setAttribute('state', MediaControls.ButtonStateType.DEFAULT); |
92 button.addEventListener('click', handler); | 104 button.addEventListener('click', handler); |
93 return button; | 105 return button; |
94 }; | 106 }; |
95 | 107 |
96 /** | 108 /** |
97 * Enable/disable controls matching a given selector. | 109 * Enable/disable controls matching a given selector. |
98 * | 110 * |
99 * @param {string} selector CSS selector. | 111 * @param {string} selector CSS selector. |
100 * @param {boolean} on True if enable, false if disable. | 112 * @param {boolean} on True if enable, false if disable. |
101 * @private | 113 * @private |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
144 this.pause(); | 156 this.pause(); |
145 else | 157 else |
146 this.play(); | 158 this.play(); |
147 }; | 159 }; |
148 | 160 |
149 /** | 161 /** |
150 * @param {HTMLElement=} opt_parent Parent container. | 162 * @param {HTMLElement=} opt_parent Parent container. |
151 */ | 163 */ |
152 MediaControls.prototype.initPlayButton = function(opt_parent) { | 164 MediaControls.prototype.initPlayButton = function(opt_parent) { |
153 this.playButton_ = this.createButton('play media-control', | 165 this.playButton_ = this.createButton('play media-control', |
154 this.togglePlayState.bind(this), opt_parent, true /* toggle */); | 166 this.togglePlayState.bind(this), opt_parent, 3 /* States. */); |
yoshiki
2013/03/11 04:42:45
Could you change "3" to MediaControls.ButtonStateT
mtomasz
2013/03/11 04:48:15
It is not out of array. This is not an index, but
yoshiki
2013/03/11 05:17:03
ditto, "3" is ok
| |
155 }; | 167 }; |
156 | 168 |
157 /* | 169 /* |
158 * Time controls | 170 * Time controls |
159 */ | 171 */ |
160 | 172 |
161 /** | 173 /** |
162 * The default range of 100 is too coarse for the media progress slider. | 174 * The default range of 100 is too coarse for the media progress slider. |
163 */ | 175 */ |
164 MediaControls.PROGRESS_RANGE = 5000; | 176 MediaControls.PROGRESS_RANGE = 5000; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
224 if (on) { | 236 if (on) { |
225 this.resumeAfterDrag_ = this.isPlaying(); | 237 this.resumeAfterDrag_ = this.isPlaying(); |
226 this.media_.pause(); | 238 this.media_.pause(); |
227 } else { | 239 } else { |
228 if (this.resumeAfterDrag_) { | 240 if (this.resumeAfterDrag_) { |
229 if (this.media_.ended) | 241 if (this.media_.ended) |
230 this.onMediaPlay_(false); | 242 this.onMediaPlay_(false); |
231 else | 243 else |
232 this.media_.play(); | 244 this.media_.play(); |
233 } | 245 } |
246 this.updatePlayButtonState_(this.isPlaying()); | |
234 } | 247 } |
235 }; | 248 }; |
236 | 249 |
237 /* | 250 /* |
238 * Volume controls | 251 * Volume controls |
239 */ | 252 */ |
240 | 253 |
241 /** | 254 /** |
242 * @param {HTMLElement=} opt_parent Parent element for the controls. | 255 * @param {HTMLElement=} opt_parent Parent element for the controls. |
243 */ | 256 */ |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
358 | 371 |
359 /** | 372 /** |
360 * 'play' and 'pause' event handler. | 373 * 'play' and 'pause' event handler. |
361 * @param {boolean} playing True if playing. | 374 * @param {boolean} playing True if playing. |
362 * @private | 375 * @private |
363 */ | 376 */ |
364 MediaControls.prototype.onMediaPlay_ = function(playing) { | 377 MediaControls.prototype.onMediaPlay_ = function(playing) { |
365 if (this.progressSlider_.isDragging()) | 378 if (this.progressSlider_.isDragging()) |
366 return; | 379 return; |
367 | 380 |
368 this.playButton_.setAttribute('state', playing ? '1' : '0'); | 381 this.updatePlayButtonState_(playing); |
369 this.onPlayStateChanged(); | 382 this.onPlayStateChanged(); |
370 }; | 383 }; |
371 | 384 |
372 /** | 385 /** |
373 * 'durationchange' event handler. | 386 * 'durationchange' event handler. |
374 * @private | 387 * @private |
375 */ | 388 */ |
376 MediaControls.prototype.onMediaDuration_ = function() { | 389 MediaControls.prototype.onMediaDuration_ = function() { |
377 if (!this.media_.duration) { | 390 if (!this.media_.duration) { |
378 this.enableControls_('.media-control', false); | 391 this.enableControls_('.media-control', false); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
429 */ | 442 */ |
430 MediaControls.prototype.onMediaComplete = function() {}; | 443 MediaControls.prototype.onMediaComplete = function() {}; |
431 | 444 |
432 /** | 445 /** |
433 * Called when play/pause state is changed or on playback progress. | 446 * Called when play/pause state is changed or on playback progress. |
434 * This is the right moment to save the play state. | 447 * This is the right moment to save the play state. |
435 */ | 448 */ |
436 MediaControls.prototype.onPlayStateChanged = function() {}; | 449 MediaControls.prototype.onPlayStateChanged = function() {}; |
437 | 450 |
438 /** | 451 /** |
452 * Updates the play button state. | |
453 * @param {boolean} playing If the video is playing. | |
454 * @private | |
455 */ | |
456 MediaControls.prototype.updatePlayButtonState_ = function(playing) { | |
457 if (playing) { | |
458 this.playButton_.setAttribute('state', | |
459 MediaControls.ButtonStateType.PLAYING); | |
460 } else if (!this.media_.ended) { | |
461 this.playButton_.setAttribute('state', | |
462 MediaControls.ButtonStateType.DEFAULT); | |
463 } else { | |
464 this.playButton_.setAttribute('state', | |
465 MediaControls.ButtonStateType.ENDED); | |
466 } | |
467 }; | |
468 | |
469 /** | |
439 * Restore play state. Base implementation is empty. | 470 * Restore play state. Base implementation is empty. |
440 */ | 471 */ |
441 MediaControls.prototype.restorePlayState = function() {}; | 472 MediaControls.prototype.restorePlayState = function() {}; |
442 | 473 |
443 /** | 474 /** |
444 * Encode current state into the page URL or the app state. | 475 * Encode current state into the page URL or the app state. |
445 */ | 476 */ |
446 MediaControls.prototype.encodeState = function() { | 477 MediaControls.prototype.encodeState = function() { |
447 if (!this.media_.duration) | 478 if (!this.media_.duration) |
448 return; | 479 return; |
(...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1132 AudioControls.prototype.onAdvanceClick_ = function(forward) { | 1163 AudioControls.prototype.onAdvanceClick_ = function(forward) { |
1133 if (!forward && | 1164 if (!forward && |
1134 (this.getMedia().currentTime > AudioControls.TRACK_RESTART_THRESHOLD)) { | 1165 (this.getMedia().currentTime > AudioControls.TRACK_RESTART_THRESHOLD)) { |
1135 // We are far enough from the beginning of the current track. | 1166 // We are far enough from the beginning of the current track. |
1136 // Restart it instead of than skipping to the previous one. | 1167 // Restart it instead of than skipping to the previous one. |
1137 this.getMedia().currentTime = 0; | 1168 this.getMedia().currentTime = 0; |
1138 } else { | 1169 } else { |
1139 this.advanceTrack_(forward); | 1170 this.advanceTrack_(forward); |
1140 } | 1171 } |
1141 }; | 1172 }; |
OLD | NEW |