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. |
hirono
2014/12/24 01:43:22
nit: !HTMLElement
yawano
2014/12/24 02:39:55
Done.
| |
12 * @param {function} onMediaError Function to display an error message. | 12 * @param {function(Event)} onMediaError Function to display an error message. |
13 * @constructor | 13 * @constructor |
14 * @struct | |
14 */ | 15 */ |
15 function MediaControls(containerElement, onMediaError) { | 16 function MediaControls(containerElement, onMediaError) { |
16 this.container_ = containerElement; | 17 this.container_ = containerElement; |
17 this.document_ = this.container_.ownerDocument; | 18 this.document_ = this.container_.ownerDocument; |
18 this.media_ = null; | 19 this.media_ = null; |
19 | 20 |
20 this.onMediaPlayBound_ = this.onMediaPlay_.bind(this, true); | 21 this.onMediaPlayBound_ = this.onMediaPlay_.bind(this, true); |
21 this.onMediaPauseBound_ = this.onMediaPlay_.bind(this, false); | 22 this.onMediaPauseBound_ = this.onMediaPlay_.bind(this, false); |
22 this.onMediaDurationBound_ = this.onMediaDuration_.bind(this); | 23 this.onMediaDurationBound_ = this.onMediaDuration_.bind(this); |
23 this.onMediaProgressBound_ = this.onMediaProgress_.bind(this); | 24 this.onMediaProgressBound_ = this.onMediaProgress_.bind(this); |
24 this.onMediaError_ = onMediaError || function() {}; | 25 this.onMediaError_ = onMediaError || function() {}; |
25 | 26 |
26 this.savedVolume_ = 1; // 100% volume. | 27 this.savedVolume_ = 1; // 100% volume. |
28 | |
29 /** | |
30 * @type {HTMLElement} | |
31 * @private | |
32 */ | |
33 this.playButton_ = null; | |
34 | |
35 /** | |
36 * @type {MediaControls.Slider} | |
37 * @private | |
38 */ | |
39 this.progressSlider_ = null; | |
40 | |
41 /** | |
42 * @type {HTMLElement} | |
43 * @private | |
44 */ | |
45 this.duration_ = null; | |
46 | |
47 /** | |
48 * @type {MediaControls.AnimatedSlider} | |
49 * @private | |
50 */ | |
51 this.volume_ = null; | |
52 | |
53 /** | |
54 * @type {HTMLElement} | |
55 * @private | |
56 */ | |
57 this.textBanner_ = null; | |
58 | |
59 /** | |
60 * @type {HTMLElement} | |
61 * @private | |
62 */ | |
63 this.soundButton_ = null; | |
64 | |
65 /** | |
66 * @type {boolean} | |
67 * @private | |
68 */ | |
69 this.resumeAfterDrag_ = false; | |
70 | |
71 /** | |
72 * @type {HTMLElement} | |
73 * @private | |
74 */ | |
75 this.currentTime_ = null; | |
27 } | 76 } |
28 | 77 |
29 /** | 78 /** |
30 * Button's state types. Values are used as CSS class names. | 79 * Button's state types. Values are used as CSS class names. |
31 * @enum {string} | 80 * @enum {string} |
32 */ | 81 */ |
33 MediaControls.ButtonStateType = { | 82 MediaControls.ButtonStateType = { |
34 DEFAULT: 'default', | 83 DEFAULT: 'default', |
35 PLAYING: 'playing', | 84 PLAYING: 'playing', |
36 ENDED: 'ended' | 85 ENDED: 'ended' |
(...skipping 22 matching lines...) Expand all Loading... | |
59 if (seconds < 10) result += '0'; | 108 if (seconds < 10) result += '0'; |
60 result += seconds; | 109 result += seconds; |
61 return result; | 110 return result; |
62 }; | 111 }; |
63 | 112 |
64 /** | 113 /** |
65 * Create a custom control. | 114 * Create a custom control. |
66 * | 115 * |
67 * @param {string} className Class name. | 116 * @param {string} className Class name. |
68 * @param {HTMLElement=} opt_parent Parent element or container if undefined. | 117 * @param {HTMLElement=} opt_parent Parent element or container if undefined. |
69 * @return {HTMLElement} The new control element. | 118 * @return {!HTMLElement} The new control element. |
70 */ | 119 */ |
71 MediaControls.prototype.createControl = function(className, opt_parent) { | 120 MediaControls.prototype.createControl = function(className, opt_parent) { |
72 var parent = opt_parent || this.container_; | 121 var parent = opt_parent || this.container_; |
73 var control = this.document_.createElement('div'); | 122 var control = assertInstanceof(this.document_.createElement('div'), |
123 HTMLDivElement); | |
74 control.className = className; | 124 control.className = className; |
75 parent.appendChild(control); | 125 parent.appendChild(control); |
76 return control; | 126 return control; |
77 }; | 127 }; |
78 | 128 |
79 /** | 129 /** |
80 * Create a custom button. | 130 * Create a custom button. |
81 * | 131 * |
82 * @param {string} className Class name. | 132 * @param {string} className Class name. |
83 * @param {function(Event)} handler Click handler. | 133 * @param {function(Event)=} opt_handler Click handler. |
84 * @param {HTMLElement=} opt_parent Parent element or container if undefined. | 134 * @param {HTMLElement=} opt_parent Parent element or container if undefined. |
85 * @param {number=} opt_numStates Number of states, default: 1. | 135 * @param {number=} opt_numStates Number of states, default: 1. |
86 * @return {HTMLElement} The new button element. | 136 * @return {!HTMLElement} The new button element. |
87 */ | 137 */ |
88 MediaControls.prototype.createButton = function( | 138 MediaControls.prototype.createButton = function( |
89 className, handler, opt_parent, opt_numStates) { | 139 className, opt_handler, opt_parent, opt_numStates) { |
90 opt_numStates = opt_numStates || 1; | 140 opt_numStates = opt_numStates || 1; |
91 | 141 |
92 var button = this.createControl(className, opt_parent); | 142 var button = this.createControl(className, opt_parent); |
93 button.classList.add('media-button'); | 143 button.classList.add('media-button'); |
94 button.addEventListener('click', handler); | |
95 | 144 |
96 var stateTypes = Object.keys(MediaControls.ButtonStateType); | 145 var stateTypes = Object.keys(MediaControls.ButtonStateType); |
97 for (var state = 0; state != opt_numStates; state++) { | 146 for (var state = 0; state != opt_numStates; state++) { |
98 var stateClass = MediaControls.ButtonStateType[stateTypes[state]]; | 147 var stateClass = MediaControls.ButtonStateType[stateTypes[state]]; |
99 this.createControl('normal ' + stateClass, button); | 148 this.createControl('normal ' + stateClass, button); |
100 this.createControl('hover ' + stateClass, button); | 149 this.createControl('hover ' + stateClass, button); |
101 this.createControl('active ' + stateClass, button); | 150 this.createControl('active ' + stateClass, button); |
102 } | 151 } |
103 this.createControl('disabled', button); | 152 this.createControl('disabled', button); |
104 | 153 |
105 button.setAttribute('state', MediaControls.ButtonStateType.DEFAULT); | 154 button.setAttribute('state', MediaControls.ButtonStateType.DEFAULT); |
106 button.addEventListener('click', handler); | 155 |
156 if (opt_handler) | |
157 button.addEventListener('click', opt_handler); | |
158 | |
107 return button; | 159 return button; |
108 }; | 160 }; |
109 | 161 |
110 /** | 162 /** |
111 * Enable/disable controls matching a given selector. | 163 * Enable/disable controls matching a given selector. |
112 * | 164 * |
113 * @param {string} selector CSS selector. | 165 * @param {string} selector CSS selector. |
114 * @param {boolean} on True if enable, false if disable. | 166 * @param {boolean} on True if enable, false if disable. |
115 * @private | 167 * @private |
116 */ | 168 */ |
(...skipping 29 matching lines...) Expand all Loading... | |
146 if (!this.media_) | 198 if (!this.media_) |
147 return; // Media is detached. | 199 return; // Media is detached. |
148 | 200 |
149 this.media_.pause(); | 201 this.media_.pause(); |
150 }; | 202 }; |
151 | 203 |
152 /** | 204 /** |
153 * @return {boolean} True if the media is currently playing. | 205 * @return {boolean} True if the media is currently playing. |
154 */ | 206 */ |
155 MediaControls.prototype.isPlaying = function() { | 207 MediaControls.prototype.isPlaying = function() { |
156 return this.media_ && !this.media_.paused && !this.media_.ended; | 208 return !!this.media_ && !this.media_.paused && !this.media_.ended; |
157 }; | 209 }; |
158 | 210 |
159 /** | 211 /** |
160 * Toggle play/pause. | 212 * Toggle play/pause. |
161 */ | 213 */ |
162 MediaControls.prototype.togglePlayState = function() { | 214 MediaControls.prototype.togglePlayState = function() { |
163 if (this.isPlaying()) | 215 if (this.isPlaying()) |
164 this.pause(); | 216 this.pause(); |
165 else | 217 else |
166 this.play(); | 218 this.play(); |
167 }; | 219 }; |
168 | 220 |
169 /** | 221 /** |
170 * Toggle play/pause state on a mouse click on the play/pause button. Can be | 222 * Toggle play/pause state on a mouse click on the play/pause button. |
hirono
2014/12/24 01:43:22
nit: Toggle -> Toggles
yawano
2014/12/24 02:39:55
Done.
| |
171 * called externally. TODO(mtomasz): Remove it. http://www.crbug.com/254318. | |
172 * | 223 * |
173 * @param {Event=} opt_event Mouse click event. | 224 * @param {Event} event Mouse click event. |
174 */ | 225 */ |
175 MediaControls.prototype.onPlayButtonClicked = function(opt_event) { | 226 MediaControls.prototype.onPlayButtonClicked = function(event) { |
176 this.togglePlayState(); | 227 this.togglePlayState(); |
177 }; | 228 }; |
178 | 229 |
179 /** | 230 /** |
180 * @param {HTMLElement=} opt_parent Parent container. | 231 * @param {HTMLElement=} opt_parent Parent container. |
181 */ | 232 */ |
182 MediaControls.prototype.initPlayButton = function(opt_parent) { | 233 MediaControls.prototype.initPlayButton = function(opt_parent) { |
183 this.playButton_ = this.createButton('play media-control', | 234 this.playButton_ = this.createButton('play media-control', |
184 this.onPlayButtonClicked.bind(this), opt_parent, 3 /* States. */); | 235 this.onPlayButtonClicked.bind(this), opt_parent, 3 /* States. */); |
185 }; | 236 }; |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
434 else | 485 else |
435 sliderContainer.classList.add('readonly'); | 486 sliderContainer.classList.add('readonly'); |
436 | 487 |
437 var valueToString = function(value) { | 488 var valueToString = function(value) { |
438 var duration = this.media_ ? this.media_.duration : 0; | 489 var duration = this.media_ ? this.media_.duration : 0; |
439 return MediaControls.formatTime_(this.media_.duration * value); | 490 return MediaControls.formatTime_(this.media_.duration * value); |
440 }.bind(this); | 491 }.bind(this); |
441 | 492 |
442 this.duration_.textContent = valueToString(1); | 493 this.duration_.textContent = valueToString(1); |
443 | 494 |
444 if (this.progressSlider_.setValueToStringFunction) | 495 this.progressSlider_.setValueToStringFunction(valueToString); |
445 this.progressSlider_.setValueToStringFunction(valueToString); | |
446 | 496 |
447 if (this.media_.seekable) | 497 if (this.media_.seekable) |
448 this.restorePlayState(); | 498 this.restorePlayState(); |
449 }; | 499 }; |
450 | 500 |
451 /** | 501 /** |
452 * 'timeupdate' event handler. | 502 * 'timeupdate' event handler. |
453 * @private | 503 * @private |
454 */ | 504 */ |
455 MediaControls.prototype.onMediaProgress_ = function() { | 505 MediaControls.prototype.onMediaProgress_ = function() { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
549 | 599 |
550 /** | 600 /** |
551 * Create a customized slider control. | 601 * Create a customized slider control. |
552 * | 602 * |
553 * @param {HTMLElement} container The containing div element. | 603 * @param {HTMLElement} container The containing div element. |
554 * @param {number} value Initial value [0..1]. | 604 * @param {number} value Initial value [0..1]. |
555 * @param {number} range Number of distinct slider positions to be supported. | 605 * @param {number} range Number of distinct slider positions to be supported. |
556 * @param {function(number)} onChange Value change handler. | 606 * @param {function(number)} onChange Value change handler. |
557 * @param {function(boolean)} onDrag Drag begin/end handler. | 607 * @param {function(boolean)} onDrag Drag begin/end handler. |
558 * @constructor | 608 * @constructor |
609 * @struct | |
559 */ | 610 */ |
560 | 611 |
561 MediaControls.Slider = function(container, value, range, onChange, onDrag) { | 612 MediaControls.Slider = function(container, value, range, onChange, onDrag) { |
562 this.container_ = container; | 613 this.container_ = container; |
563 this.onChange_ = onChange; | 614 this.onChange_ = onChange; |
564 this.onDrag_ = onDrag; | 615 this.onDrag_ = onDrag; |
565 | 616 |
617 /** | |
618 * @type {boolean} | |
619 * @private | |
620 */ | |
621 this.isDragging_ = false; | |
622 | |
566 var document = this.container_.ownerDocument; | 623 var document = this.container_.ownerDocument; |
567 | 624 |
568 this.container_.classList.add('custom-slider'); | 625 this.container_.classList.add('custom-slider'); |
569 | 626 |
570 this.input_ = document.createElement('input'); | 627 this.input_ = assertInstanceof(document.createElement('input'), |
628 HTMLInputElement); | |
571 this.input_.type = 'range'; | 629 this.input_.type = 'range'; |
572 this.input_.min = 0; | 630 this.input_.min = (0).toString(); |
573 this.input_.max = range; | 631 this.input_.max = range.toString(); |
574 this.input_.value = value * range; | 632 this.input_.value = (value * range).toString(); |
575 this.container_.appendChild(this.input_); | 633 this.container_.appendChild(this.input_); |
576 | 634 |
577 this.input_.addEventListener( | 635 this.input_.addEventListener( |
578 'change', this.onInputChange_.bind(this)); | 636 'change', this.onInputChange_.bind(this)); |
579 this.input_.addEventListener( | 637 this.input_.addEventListener( |
580 'mousedown', this.onInputDrag_.bind(this, true)); | 638 'mousedown', this.onInputDrag_.bind(this, true)); |
581 this.input_.addEventListener( | 639 this.input_.addEventListener( |
582 'mouseup', this.onInputDrag_.bind(this, false)); | 640 'mouseup', this.onInputDrag_.bind(this, false)); |
583 | 641 |
584 this.bar_ = document.createElement('div'); | 642 this.bar_ = assertInstanceof(document.createElement('div'), HTMLDivElement); |
585 this.bar_.className = 'bar'; | 643 this.bar_.className = 'bar'; |
586 this.container_.appendChild(this.bar_); | 644 this.container_.appendChild(this.bar_); |
587 | 645 |
588 this.filled_ = document.createElement('div'); | 646 this.filled_ = document.createElement('div'); |
589 this.filled_.className = 'filled'; | 647 this.filled_.className = 'filled'; |
590 this.bar_.appendChild(this.filled_); | 648 this.bar_.appendChild(this.filled_); |
591 | 649 |
592 var leftCap = document.createElement('div'); | 650 var leftCap = document.createElement('div'); |
593 leftCap.className = 'cap left'; | 651 leftCap.className = 'cap left'; |
594 this.bar_.appendChild(leftCap); | 652 this.bar_.appendChild(leftCap); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
658 return this.input_.value / this.input_.max; | 716 return this.input_.value / this.input_.max; |
659 }; | 717 }; |
660 | 718 |
661 /** | 719 /** |
662 * Update the UI with the current value. | 720 * Update the UI with the current value. |
663 * | 721 * |
664 * @param {number} value [0..1]. | 722 * @param {number} value [0..1]. |
665 * @private | 723 * @private |
666 */ | 724 */ |
667 MediaControls.Slider.prototype.setValueToUI_ = function(value) { | 725 MediaControls.Slider.prototype.setValueToUI_ = function(value) { |
668 this.input_.value = value * this.input_.max; | 726 this.input_.value = (value * this.input_.max).toString(); |
669 this.setFilled_(value); | 727 this.setFilled_(value); |
670 }; | 728 }; |
671 | 729 |
672 /** | 730 /** |
673 * Compute the proportion in which the given position divides the slider bar. | 731 * Compute the proportion in which the given position divides the slider bar. |
674 * | 732 * |
675 * @param {number} position in pixels. | 733 * @param {number} position in pixels. |
676 * @return {number} [0..1] proportion. | 734 * @return {number} [0..1] proportion. |
677 */ | 735 */ |
678 MediaControls.Slider.prototype.getProportion = function(position) { | 736 MediaControls.Slider.prototype.getProportion = function(position) { |
679 var rect = this.bar_.getBoundingClientRect(); | 737 var rect = this.bar_.getBoundingClientRect(); |
680 return Math.max(0, Math.min(1, (position - rect.left) / rect.width)); | 738 return Math.max(0, Math.min(1, (position - rect.left) / rect.width)); |
681 }; | 739 }; |
682 | 740 |
683 /** | 741 /** |
742 * Set value formatting function. | |
hirono
2014/12/24 01:43:22
nit: Sets
yawano
2014/12/24 02:39:55
Done.
| |
743 * @param {function(number):string} func Value formatting function. | |
744 */ | |
745 MediaControls.Slider.prototype.setValueToStringFunction = function(func) {}; | |
746 | |
747 /** | |
684 * 'change' event handler. | 748 * 'change' event handler. |
685 * @private | 749 * @private |
686 */ | 750 */ |
687 MediaControls.Slider.prototype.onInputChange_ = function() { | 751 MediaControls.Slider.prototype.onInputChange_ = function() { |
688 this.value_ = this.getValueFromUI_(); | 752 this.value_ = this.getValueFromUI_(); |
689 this.setFilled_(this.value_); | 753 this.setFilled_(this.value_); |
690 this.onChange_(this.value_); | 754 this.onChange_(this.value_); |
691 }; | 755 }; |
692 | 756 |
693 /** | 757 /** |
(...skipping 22 matching lines...) Expand all Loading... | |
716 }; | 780 }; |
717 | 781 |
718 /** | 782 /** |
719 * Create a customized slider with animated thumb movement. | 783 * Create a customized slider with animated thumb movement. |
720 * | 784 * |
721 * @param {HTMLElement} container The containing div element. | 785 * @param {HTMLElement} container The containing div element. |
722 * @param {number} value Initial value [0..1]. | 786 * @param {number} value Initial value [0..1]. |
723 * @param {number} range Number of distinct slider positions to be supported. | 787 * @param {number} range Number of distinct slider positions to be supported. |
724 * @param {function(number)} onChange Value change handler. | 788 * @param {function(number)} onChange Value change handler. |
725 * @param {function(boolean)} onDrag Drag begin/end handler. | 789 * @param {function(boolean)} onDrag Drag begin/end handler. |
726 * @param {function(number):string} formatFunction Value formatting function. | |
727 * @constructor | 790 * @constructor |
791 * @struct | |
792 * @extends {MediaControls.Slider} | |
728 */ | 793 */ |
729 MediaControls.AnimatedSlider = function( | 794 MediaControls.AnimatedSlider = function( |
730 container, value, range, onChange, onDrag, formatFunction) { | 795 container, value, range, onChange, onDrag) { |
731 MediaControls.Slider.apply(this, arguments); | 796 MediaControls.Slider.apply(this, arguments); |
797 | |
798 /** | |
799 * @type {number} | |
800 * @private | |
801 */ | |
802 this.animationInterval_ = 0; | |
732 }; | 803 }; |
733 | 804 |
734 MediaControls.AnimatedSlider.prototype = { | 805 MediaControls.AnimatedSlider.prototype = { |
735 __proto__: MediaControls.Slider.prototype | 806 __proto__: MediaControls.Slider.prototype |
736 }; | 807 }; |
737 | 808 |
738 /** | 809 /** |
739 * Number of animation steps. | 810 * Number of animation steps. |
740 */ | 811 */ |
741 MediaControls.AnimatedSlider.STEPS = 10; | 812 MediaControls.AnimatedSlider.STEPS = 10; |
(...skipping 30 matching lines...) Expand all Loading... | |
772 * | 843 * |
773 * The time value is shown above the slider bar at the mouse position. | 844 * The time value is shown above the slider bar at the mouse position. |
774 * | 845 * |
775 * @param {HTMLElement} container The containing div element. | 846 * @param {HTMLElement} container The containing div element. |
776 * @param {number} value Initial value [0..1]. | 847 * @param {number} value Initial value [0..1]. |
777 * @param {number} range Number of distinct slider positions to be supported. | 848 * @param {number} range Number of distinct slider positions to be supported. |
778 * @param {function(number)} onChange Value change handler. | 849 * @param {function(number)} onChange Value change handler. |
779 * @param {function(boolean)} onDrag Drag begin/end handler. | 850 * @param {function(boolean)} onDrag Drag begin/end handler. |
780 * @param {function(number):string} formatFunction Value formatting function. | 851 * @param {function(number):string} formatFunction Value formatting function. |
781 * @constructor | 852 * @constructor |
853 * @struct | |
854 * @extends {MediaControls.Slider} | |
782 */ | 855 */ |
783 MediaControls.PreciseSlider = function( | 856 MediaControls.PreciseSlider = function( |
784 container, value, range, onChange, onDrag, formatFunction) { | 857 container, value, range, onChange, onDrag, formatFunction) { |
785 MediaControls.Slider.apply(this, arguments); | 858 MediaControls.Slider.apply(this, arguments); |
786 | 859 |
787 var doc = this.container_.ownerDocument; | 860 var doc = this.container_.ownerDocument; |
788 | 861 |
789 /** | 862 /** |
790 * @type {function(number):string} | 863 * @type {number} |
864 * @private | |
865 */ | |
866 this.latestMouseUpTime_ = 0; | |
867 | |
868 /** | |
869 * @type {number} | |
870 * @private | |
871 */ | |
872 this.seekMarkTimer_ = 0; | |
873 | |
874 /** | |
875 * @type {number} | |
876 * @private | |
877 */ | |
878 this.latestSeekRatio_ = 0; | |
879 | |
880 /** | |
881 * @type {?function(number):string} | |
791 * @private | 882 * @private |
792 */ | 883 */ |
793 this.valueToString_ = null; | 884 this.valueToString_ = null; |
794 | 885 |
795 this.seekMark_ = doc.createElement('div'); | 886 this.seekMark_ = doc.createElement('div'); |
796 this.seekMark_.className = 'seek-mark'; | 887 this.seekMark_.className = 'seek-mark'; |
797 this.getBar().appendChild(this.seekMark_); | 888 this.getBar().appendChild(this.seekMark_); |
798 | 889 |
799 this.seekLabel_ = doc.createElement('div'); | 890 this.seekLabel_ = doc.createElement('div'); |
800 this.seekLabel_.className = 'seek-label'; | 891 this.seekLabel_.className = 'seek-label'; |
(...skipping 23 matching lines...) Expand all Loading... | |
824 * Hide the seek mark for this long after changing the position with a drag. | 915 * Hide the seek mark for this long after changing the position with a drag. |
825 */ | 916 */ |
826 MediaControls.PreciseSlider.HIDE_AFTER_DRAG_DELAY = 750; | 917 MediaControls.PreciseSlider.HIDE_AFTER_DRAG_DELAY = 750; |
827 | 918 |
828 /** | 919 /** |
829 * Default hide timeout (no hiding). | 920 * Default hide timeout (no hiding). |
830 */ | 921 */ |
831 MediaControls.PreciseSlider.NO_AUTO_HIDE = 0; | 922 MediaControls.PreciseSlider.NO_AUTO_HIDE = 0; |
832 | 923 |
833 /** | 924 /** |
834 * @param {function(number):string} func Value formatting function. | 925 * @override |
835 */ | 926 */ |
836 MediaControls.PreciseSlider.prototype.setValueToStringFunction = | 927 MediaControls.PreciseSlider.prototype.setValueToStringFunction = |
837 function(func) { | 928 function(func) { |
838 this.valueToString_ = func; | 929 this.valueToString_ = func; |
839 | 930 |
840 /* It is not completely accurate to assume that the max value corresponds | 931 /* It is not completely accurate to assume that the max value corresponds |
841 to the longest string, but generous CSS padding will compensate for that. */ | 932 to the longest string, but generous CSS padding will compensate for that. */ |
842 var labelWidth = this.valueToString_(1).length / 2 + 1; | 933 var labelWidth = this.valueToString_(1).length / 2 + 1; |
843 this.seekLabel_.style.width = labelWidth + 'em'; | 934 this.seekLabel_.style.width = labelWidth + 'em'; |
844 this.seekLabel_.style.marginLeft = -labelWidth / 2 + 'em'; | 935 this.seekLabel_.style.marginLeft = -labelWidth / 2 + 'em'; |
(...skipping 19 matching lines...) Expand all Loading... | |
864 this.seekMark_.classList.remove('inverted'); | 955 this.seekMark_.classList.remove('inverted'); |
865 } else { | 956 } else { |
866 this.seekMark_.classList.add('inverted'); | 957 this.seekMark_.classList.add('inverted'); |
867 } | 958 } |
868 this.seekLabel_.textContent = this.valueToString_(ratio); | 959 this.seekLabel_.textContent = this.valueToString_(ratio); |
869 | 960 |
870 this.seekMark_.classList.add('visible'); | 961 this.seekMark_.classList.add('visible'); |
871 | 962 |
872 if (this.seekMarkTimer_) { | 963 if (this.seekMarkTimer_) { |
873 clearTimeout(this.seekMarkTimer_); | 964 clearTimeout(this.seekMarkTimer_); |
874 this.seekMarkTimer_ = null; | 965 this.seekMarkTimer_ = 0; |
875 } | 966 } |
876 if (timeout != MediaControls.PreciseSlider.NO_AUTO_HIDE) { | 967 if (timeout != MediaControls.PreciseSlider.NO_AUTO_HIDE) { |
877 this.seekMarkTimer_ = setTimeout(this.hideSeekMark_.bind(this), timeout); | 968 this.seekMarkTimer_ = setTimeout(this.hideSeekMark_.bind(this), timeout); |
878 } | 969 } |
879 }; | 970 }; |
880 | 971 |
881 /** | 972 /** |
882 * @private | 973 * @private |
883 */ | 974 */ |
884 MediaControls.PreciseSlider.prototype.hideSeekMark_ = function() { | 975 MediaControls.PreciseSlider.prototype.hideSeekMark_ = function() { |
885 this.seekMarkTimer_ = null; | 976 this.seekMarkTimer_ = 0; |
886 this.seekMark_.classList.remove('visible'); | 977 this.seekMark_.classList.remove('visible'); |
887 }; | 978 }; |
888 | 979 |
889 /** | 980 /** |
890 * 'mouseout' event handler. | 981 * 'mouseout' event handler. |
891 * @param {Event} e Event. | 982 * @param {Event} e Event. |
892 * @private | 983 * @private |
893 */ | 984 */ |
894 MediaControls.PreciseSlider.prototype.onMouseMove_ = function(e) { | 985 MediaControls.PreciseSlider.prototype.onMouseMove_ = function(e) { |
895 this.latestSeekRatio_ = this.getProportion(e.clientX); | 986 this.latestSeekRatio_ = this.getProportion(e.clientX); |
896 | 987 |
897 var self = this; | 988 var showMark = function() { |
898 function showMark() { | 989 if (!this.isDragging()) { |
899 if (!self.isDragging()) { | 990 this.showSeekMark_(this.latestSeekRatio_, |
900 self.showSeekMark_(self.latestSeekRatio_, | |
901 MediaControls.PreciseSlider.HIDE_AFTER_MOVE_DELAY); | 991 MediaControls.PreciseSlider.HIDE_AFTER_MOVE_DELAY); |
902 } | 992 } |
903 } | 993 }.bind(this); |
904 | 994 |
905 if (this.seekMark_.classList.contains('visible')) { | 995 if (this.seekMark_.classList.contains('visible')) { |
906 showMark(); | 996 showMark(); |
907 } else if (!this.seekMarkTimer_) { | 997 } else if (!this.seekMarkTimer_) { |
908 this.seekMarkTimer_ = | 998 this.seekMarkTimer_ = |
909 setTimeout(showMark, MediaControls.PreciseSlider.SHOW_DELAY); | 999 setTimeout(showMark, MediaControls.PreciseSlider.SHOW_DELAY); |
910 } | 1000 } |
911 }; | 1001 }; |
912 | 1002 |
913 /** | 1003 /** |
914 * 'mouseout' event handler. | 1004 * 'mouseout' event handler. |
915 * @param {Event} e Event. | 1005 * @param {Event} e Event. |
916 * @private | 1006 * @private |
917 */ | 1007 */ |
918 MediaControls.PreciseSlider.prototype.onMouseOut_ = function(e) { | 1008 MediaControls.PreciseSlider.prototype.onMouseOut_ = function(e) { |
919 for (var element = e.relatedTarget; element; element = element.parentNode) { | 1009 for (var element = e.relatedTarget; element; element = element.parentNode) { |
920 if (element == this.getContainer()) | 1010 if (element == this.getContainer()) |
921 return; | 1011 return; |
922 } | 1012 } |
923 if (this.seekMarkTimer_) { | 1013 if (this.seekMarkTimer_) { |
924 clearTimeout(this.seekMarkTimer_); | 1014 clearTimeout(this.seekMarkTimer_); |
925 this.seekMarkTimer_ = null; | 1015 this.seekMarkTimer_ = 0; |
926 } | 1016 } |
927 this.hideSeekMark_(); | 1017 this.hideSeekMark_(); |
928 }; | 1018 }; |
929 | 1019 |
930 /** | 1020 /** |
931 * 'change' event handler. | 1021 * 'change' event handler. |
932 * @private | 1022 * @private |
933 */ | 1023 */ |
934 MediaControls.PreciseSlider.prototype.onInputChange_ = function() { | 1024 MediaControls.PreciseSlider.prototype.onInputChange_ = function() { |
935 MediaControls.Slider.prototype.onInputChange_.apply(this, arguments); | 1025 MediaControls.Slider.prototype.onInputChange_.apply(this, arguments); |
(...skipping 21 matching lines...) Expand all Loading... | |
957 this.showSeekMark_( | 1047 this.showSeekMark_( |
958 this.getValue(), MediaControls.PreciseSlider.HIDE_AFTER_DRAG_DELAY); | 1048 this.getValue(), MediaControls.PreciseSlider.HIDE_AFTER_DRAG_DELAY); |
959 this.latestMouseUpTime_ = Date.now(); | 1049 this.latestMouseUpTime_ = Date.now(); |
960 } | 1050 } |
961 }; | 1051 }; |
962 | 1052 |
963 /** | 1053 /** |
964 * Create video controls. | 1054 * Create video controls. |
965 * | 1055 * |
966 * @param {HTMLElement} containerElement The container for the controls. | 1056 * @param {HTMLElement} containerElement The container for the controls. |
967 * @param {function} onMediaError Function to display an error message. | 1057 * @param {function(Event)} onMediaError Function to display an error message. |
968 * @param {function(string):string} stringFunction Function providing localized | 1058 * @param {function(string):string} stringFunction Function providing localized |
969 * strings. | 1059 * strings. |
970 * @param {function=} opt_fullScreenToggle Function to toggle fullscreen mode. | 1060 * @param {function(Event)=} opt_fullScreenToggle Function to toggle fullscreen |
1061 * mode. | |
971 * @param {HTMLElement=} opt_stateIconParent The parent for the icon that | 1062 * @param {HTMLElement=} opt_stateIconParent The parent for the icon that |
972 * gives visual feedback when the playback state changes. | 1063 * gives visual feedback when the playback state changes. |
973 * @constructor | 1064 * @constructor |
1065 * @struct | |
1066 * @extends {MediaControls} | |
974 */ | 1067 */ |
975 function VideoControls(containerElement, onMediaError, stringFunction, | 1068 function VideoControls(containerElement, onMediaError, stringFunction, |
976 opt_fullScreenToggle, opt_stateIconParent) { | 1069 opt_fullScreenToggle, opt_stateIconParent) { |
977 MediaControls.call(this, containerElement, onMediaError); | 1070 MediaControls.call(this, containerElement, onMediaError); |
978 this.stringFunction_ = stringFunction; | 1071 this.stringFunction_ = stringFunction; |
979 | 1072 |
980 this.container_.classList.add('video-controls'); | 1073 this.container_.classList.add('video-controls'); |
981 this.initPlayButton(); | 1074 this.initPlayButton(); |
982 this.initTimeControls(true /* show seek mark */); | 1075 this.initTimeControls(true /* show seek mark */); |
983 this.initVolumeControls(); | 1076 this.initVolumeControls(); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1065 'webkitAnimationEnd', onAnimationEnd); | 1158 'webkitAnimationEnd', onAnimationEnd); |
1066 this.textBanner_.removeAttribute('visible'); | 1159 this.textBanner_.removeAttribute('visible'); |
1067 }.bind(this); | 1160 }.bind(this); |
1068 this.textBanner_.addEventListener('webkitAnimationEnd', onAnimationEnd); | 1161 this.textBanner_.addEventListener('webkitAnimationEnd', onAnimationEnd); |
1069 | 1162 |
1070 this.textBanner_.setAttribute('visible', 'true'); | 1163 this.textBanner_.setAttribute('visible', 'true'); |
1071 }.bind(this), 0); | 1164 }.bind(this), 0); |
1072 }; | 1165 }; |
1073 | 1166 |
1074 /** | 1167 /** |
1075 * Toggle play/pause state on a mouse click on the play/pause button. Can be | 1168 * @override |
1076 * called externally. | |
1077 * | |
1078 * @param {Event} event Mouse click event. | |
1079 */ | 1169 */ |
1080 VideoControls.prototype.onPlayButtonClicked = function(event) { | 1170 VideoControls.prototype.onPlayButtonClicked = function(event) { |
1081 if (event.ctrlKey) { | 1171 if (event.ctrlKey) { |
1082 this.toggleLoopedModeWithFeedback(true); | 1172 this.toggleLoopedModeWithFeedback(true); |
1083 if (!this.isPlaying()) | 1173 if (!this.isPlaying()) |
1084 this.togglePlayState(); | 1174 this.togglePlayState(); |
1085 } else { | 1175 } else { |
1086 this.togglePlayState(); | 1176 this.togglePlayState(); |
1087 } | 1177 } |
1088 }; | 1178 }; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1209 hideBelow('.volume', 275); | 1299 hideBelow('.volume', 275); |
1210 hideBelow('.volume-controls', 210); | 1300 hideBelow('.volume-controls', 210); |
1211 hideBelow('.fullscreen', 150); | 1301 hideBelow('.fullscreen', 150); |
1212 }; | 1302 }; |
1213 | 1303 |
1214 /** | 1304 /** |
1215 * Creates audio controls. | 1305 * Creates audio controls. |
1216 * | 1306 * |
1217 * @param {HTMLElement} container Parent container. | 1307 * @param {HTMLElement} container Parent container. |
1218 * @param {function(boolean)} advanceTrack Parameter: true=forward. | 1308 * @param {function(boolean)} advanceTrack Parameter: true=forward. |
1219 * @param {function} onError Error handler. | 1309 * @param {function(Event)} onError Error handler. |
1220 * @constructor | 1310 * @constructor |
1311 * @struct | |
1312 * @extends {MediaControls} | |
1221 */ | 1313 */ |
1222 function AudioControls(container, advanceTrack, onError) { | 1314 function AudioControls(container, advanceTrack, onError) { |
1223 MediaControls.call(this, container, onError); | 1315 MediaControls.call(this, container, onError); |
1224 | 1316 |
1225 this.container_.classList.add('audio-controls'); | 1317 this.container_.classList.add('audio-controls'); |
1226 | 1318 |
1227 this.advanceTrack_ = advanceTrack; | 1319 this.advanceTrack_ = advanceTrack; |
1228 | 1320 |
1229 this.initPlayButton(); | 1321 this.initPlayButton(); |
1230 this.initTimeControls(false /* no seek mark */); | 1322 this.initTimeControls(false /* no seek mark */); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1265 AudioControls.prototype.onAdvanceClick_ = function(forward) { | 1357 AudioControls.prototype.onAdvanceClick_ = function(forward) { |
1266 if (!forward && | 1358 if (!forward && |
1267 (this.getMedia().currentTime > AudioControls.TRACK_RESTART_THRESHOLD)) { | 1359 (this.getMedia().currentTime > AudioControls.TRACK_RESTART_THRESHOLD)) { |
1268 // We are far enough from the beginning of the current track. | 1360 // We are far enough from the beginning of the current track. |
1269 // Restart it instead of than skipping to the previous one. | 1361 // Restart it instead of than skipping to the previous one. |
1270 this.getMedia().currentTime = 0; | 1362 this.getMedia().currentTime = 0; |
1271 } else { | 1363 } else { |
1272 this.advanceTrack_(forward); | 1364 this.advanceTrack_(forward); |
1273 } | 1365 } |
1274 }; | 1366 }; |
OLD | NEW |