- 1 :
/**
- 2 :
* @file progress-control.js
- 3 :
*/
- 4 :
import Component from '../../component.js';
- 5 :
import * as Dom from '../../utils/dom.js';
- 6 :
import {clamp} from '../../utils/num.js';
- 7 :
import {bind_, throttle, UPDATE_REFRESH_INTERVAL} from '../../utils/fn.js';
- 8 :
import {silencePromise} from '../../utils/promise';
- 9 :
- 10 :
import './seek-bar.js';
- 11 :
- 12 :
/**
- 13 :
* The Progress Control component contains the seek bar, load progress,
- 14 :
* and play progress.
- 15 :
*
- 16 :
* @extends Component
- 17 :
*/
- 18 :
class ProgressControl extends Component {
- 19 :
- 20 :
/**
- 21 :
* Creates an instance of this class.
- 22 :
*
- 23 :
* @param { import('../../player').default } player
- 24 :
* The `Player` that this class should be attached to.
- 25 :
*
- 26 :
* @param {Object} [options]
- 27 :
* The key/value store of player options.
- 28 :
*/
- 29 :
constructor(player, options) {
- 30 :
super(player, options);
- 31 :
this.handleMouseMove = throttle(bind_(this, this.handleMouseMove), UPDATE_REFRESH_INTERVAL);
- 32 :
this.throttledHandleMouseSeek = throttle(bind_(this, this.handleMouseSeek), UPDATE_REFRESH_INTERVAL);
- 33 :
this.handleMouseUpHandler_ = (e) => this.handleMouseUp(e);
- 34 :
this.handleMouseDownHandler_ = (e) => this.handleMouseDown(e);
- 35 :
- 36 :
this.enable();
- 37 :
}
- 38 :
- 39 :
/**
- 40 :
* Create the `Component`'s DOM element
- 41 :
*
- 42 :
* @return {Element}
- 43 :
* The element that was created.
- 44 :
*/
- 45 :
createEl() {
- 46 :
return super.createEl('div', {
- 47 :
className: 'vjs-progress-control vjs-control'
- 48 :
});
- 49 :
}
- 50 :
- 51 :
/**
- 52 :
* When the mouse moves over the `ProgressControl`, the pointer position
- 53 :
* gets passed down to the `MouseTimeDisplay` component.
- 54 :
*
- 55 :
* @param {Event} event
- 56 :
* The `mousemove` event that caused this function to run.
- 57 :
*
- 58 :
* @listen mousemove
- 59 :
*/
- 60 :
handleMouseMove(event) {
- 61 :
const seekBar = this.getChild('seekBar');
- 62 :
- 63 :
if (!seekBar) {
- 64 :
return;
- 65 :
}
- 66 :
- 67 :
const playProgressBar = seekBar.getChild('playProgressBar');
- 68 :
const mouseTimeDisplay = seekBar.getChild('mouseTimeDisplay');
- 69 :
- 70 :
if (!playProgressBar && !mouseTimeDisplay) {
- 71 :
return;
- 72 :
}
- 73 :
- 74 :
const seekBarEl = seekBar.el();
- 75 :
const seekBarRect = Dom.findPosition(seekBarEl);
- 76 :
let seekBarPoint = Dom.getPointerPosition(seekBarEl, event).x;
- 77 :
- 78 :
// The default skin has a gap on either side of the `SeekBar`. This means
- 79 :
// that it's possible to trigger this behavior outside the boundaries of
- 80 :
// the `SeekBar`. This ensures we stay within it at all times.
- 81 :
seekBarPoint = clamp(seekBarPoint, 0, 1);
- 82 :
- 83 :
if (mouseTimeDisplay) {
- 84 :
mouseTimeDisplay.update(seekBarRect, seekBarPoint);
- 85 :
}
- 86 :
- 87 :
if (playProgressBar) {
- 88 :
playProgressBar.update(seekBarRect, seekBar.getProgress());
- 89 :
}
- 90 :
- 91 :
}
- 92 :
- 93 :
/**
- 94 :
* A throttled version of the {@link ProgressControl#handleMouseSeek} listener.
- 95 :
*
- 96 :
* @method ProgressControl#throttledHandleMouseSeek
- 97 :
* @param {Event} event
- 98 :
* The `mousemove` event that caused this function to run.
- 99 :
*
- 100 :
* @listen mousemove
- 101 :
* @listen touchmove
- 102 :
*/
- 103 :
- 104 :
/**
- 105 :
* Handle `mousemove` or `touchmove` events on the `ProgressControl`.
- 106 :
*
- 107 :
* @param {Event} event
- 108 :
* `mousedown` or `touchstart` event that triggered this function
- 109 :
*
- 110 :
* @listens mousemove
- 111 :
* @listens touchmove
- 112 :
*/
- 113 :
handleMouseSeek(event) {
- 114 :
const seekBar = this.getChild('seekBar');
- 115 :
- 116 :
if (seekBar) {
- 117 :
seekBar.handleMouseMove(event);
- 118 :
}
- 119 :
}
- 120 :
- 121 :
/**
- 122 :
* Are controls are currently enabled for this progress control.
- 123 :
*
- 124 :
* @return {boolean}
- 125 :
* true if controls are enabled, false otherwise
- 126 :
*/
- 127 :
enabled() {
- 128 :
return this.enabled_;
- 129 :
}
- 130 :
- 131 :
/**
- 132 :
* Disable all controls on the progress control and its children
- 133 :
*/
- 134 :
disable() {
- 135 :
this.children().forEach((child) => child.disable && child.disable());
- 136 :
- 137 :
if (!this.enabled()) {
- 138 :
return;
- 139 :
}
- 140 :
- 141 :
this.off(['mousedown', 'touchstart'], this.handleMouseDownHandler_);
- 142 :
this.off(this.el_, 'mousemove', this.handleMouseMove);
- 143 :
- 144 :
this.removeListenersAddedOnMousedownAndTouchstart();
- 145 :
- 146 :
this.addClass('disabled');
- 147 :
- 148 :
this.enabled_ = false;
- 149 :
- 150 :
// Restore normal playback state if controls are disabled while scrubbing
- 151 :
if (this.player_.scrubbing()) {
- 152 :
const seekBar = this.getChild('seekBar');
- 153 :
- 154 :
this.player_.scrubbing(false);
- 155 :
- 156 :
if (seekBar.videoWasPlaying) {
- 157 :
silencePromise(this.player_.play());
- 158 :
}
- 159 :
}
- 160 :
}
- 161 :
- 162 :
/**
- 163 :
* Enable all controls on the progress control and its children
- 164 :
*/
- 165 :
enable() {
- 166 :
this.children().forEach((child) => child.enable && child.enable());
- 167 :
- 168 :
if (this.enabled()) {
- 169 :
return;
- 170 :
}
- 171 :
- 172 :
this.on(['mousedown', 'touchstart'], this.handleMouseDownHandler_);
- 173 :
this.on(this.el_, 'mousemove', this.handleMouseMove);
- 174 :
this.removeClass('disabled');
- 175 :
- 176 :
this.enabled_ = true;
- 177 :
}
- 178 :
- 179 :
/**
- 180 :
* Cleanup listeners after the user finishes interacting with the progress controls
- 181 :
*/
- 182 :
removeListenersAddedOnMousedownAndTouchstart() {
- 183 :
const doc = this.el_.ownerDocument;
- 184 :
- 185 :
this.off(doc, 'mousemove', this.throttledHandleMouseSeek);
- 186 :
this.off(doc, 'touchmove', this.throttledHandleMouseSeek);
- 187 :
this.off(doc, 'mouseup', this.handleMouseUpHandler_);
- 188 :
this.off(doc, 'touchend', this.handleMouseUpHandler_);
- 189 :
}
- 190 :
- 191 :
/**
- 192 :
* Handle `mousedown` or `touchstart` events on the `ProgressControl`.
- 193 :
*
- 194 :
* @param {Event} event
- 195 :
* `mousedown` or `touchstart` event that triggered this function
- 196 :
*
- 197 :
* @listens mousedown
- 198 :
* @listens touchstart
- 199 :
*/
- 200 :
handleMouseDown(event) {
- 201 :
const doc = this.el_.ownerDocument;
- 202 :
const seekBar = this.getChild('seekBar');
- 203 :
- 204 :
if (seekBar) {
- 205 :
seekBar.handleMouseDown(event);
- 206 :
}
- 207 :
- 208 :
this.on(doc, 'mousemove', this.throttledHandleMouseSeek);
- 209 :
this.on(doc, 'touchmove', this.throttledHandleMouseSeek);
- 210 :
this.on(doc, 'mouseup', this.handleMouseUpHandler_);
- 211 :
this.on(doc, 'touchend', this.handleMouseUpHandler_);
- 212 :
}
- 213 :
- 214 :
/**
- 215 :
* Handle `mouseup` or `touchend` events on the `ProgressControl`.
- 216 :
*
- 217 :
* @param {Event} event
- 218 :
* `mouseup` or `touchend` event that triggered this function.
- 219 :
*
- 220 :
* @listens touchend
- 221 :
* @listens mouseup
- 222 :
*/
- 223 :
handleMouseUp(event) {
- 224 :
const seekBar = this.getChild('seekBar');
- 225 :
- 226 :
if (seekBar) {
- 227 :
seekBar.handleMouseUp(event);
- 228 :
}
- 229 :
- 230 :
this.removeListenersAddedOnMousedownAndTouchstart();
- 231 :
}
- 232 :
}
- 233 :
- 234 :
/**
- 235 :
* Default options for `ProgressControl`
- 236 :
*
- 237 :
* @type {Object}
- 238 :
* @private
- 239 :
*/
- 240 :
ProgressControl.prototype.options_ = {
- 241 :
children: [
- 242 :
'seekBar'
- 243 :
]
- 244 :
};
- 245 :
- 246 :
Component.registerComponent('ProgressControl', ProgressControl);
- 247 :
export default ProgressControl;