diff --git a/src/js/control-bar/progress-control/seek-bar.js b/src/js/control-bar/progress-control/seek-bar.js index b078b3d0f0..aae7f003e9 100644 --- a/src/js/control-bar/progress-control/seek-bar.js +++ b/src/js/control-bar/progress-control/seek-bar.js @@ -17,12 +17,6 @@ import './load-progress-bar.js'; import './play-progress-bar.js'; import './mouse-time-display.js'; -// The number of seconds the `step*` functions move the timeline. -const STEP_SECONDS = 5; - -// The multiplier of STEP_SECONDS that PgUp/PgDown move the timeline. -const PAGE_KEY_MULTIPLIER = 12; - /** * Seek bar and container for the progress bars. Uses {@link PlayProgressBar} * as its `bar`. @@ -39,6 +33,10 @@ class SeekBar extends Slider { * * @param {Object} [options] * The key/value store of player options. + * @param {number} [options.stepSeconds=5] + * The number of seconds to increment on keyboard control + * @param {number} [options.pageMultiplier=12] + * The multiplier of stepSeconds that PgUp/PgDown move the timeline. */ constructor(player, options) { options = merge(SeekBar.prototype.options_, options); @@ -431,14 +429,14 @@ class SeekBar extends Slider { * Move more quickly fast forward for keyboard-only users */ stepForward() { - this.userSeek_(this.player_.currentTime() + STEP_SECONDS); + this.userSeek_(this.player_.currentTime() + this.options().stepSeconds); } /** * Move more quickly rewind for keyboard-only users */ stepBack() { - this.userSeek_(this.player_.currentTime() - STEP_SECONDS); + this.userSeek_(this.player_.currentTime() - this.options().stepSeconds); } /** @@ -505,11 +503,11 @@ class SeekBar extends Slider { } else if (event.key === 'PageDown') { event.preventDefault(); event.stopPropagation(); - this.userSeek_(this.player_.currentTime() - (STEP_SECONDS * PAGE_KEY_MULTIPLIER)); + this.userSeek_(this.player_.currentTime() - (this.options().stepSeconds * this.options().pageMultiplier)); } else if (event.key === 'PageUp') { event.preventDefault(); event.stopPropagation(); - this.userSeek_(this.player_.currentTime() + (STEP_SECONDS * PAGE_KEY_MULTIPLIER)); + this.userSeek_(this.player_.currentTime() + (this.options().stepSeconds * this.options().pageMultiplier)); } else { // Pass keydown handling up for unsupported keys super.handleKeyDown(event); @@ -549,7 +547,9 @@ SeekBar.prototype.options_ = { 'loadProgressBar', 'playProgressBar' ], - barName: 'playProgressBar' + barName: 'playProgressBar', + stepSeconds: 5, + pageMultiplier: 12 }; Component.registerComponent('SeekBar', SeekBar); diff --git a/test/unit/controls.test.js b/test/unit/controls.test.js index 0a05551268..1019350940 100644 --- a/test/unit/controls.test.js +++ b/test/unit/controls.test.js @@ -223,6 +223,98 @@ QUnit.test('SeekBar should be filled on 100% when the video/audio ends', functio window.cancelAnimationFrame = oldCAF; }); +QUnit.test('SeekBar keyboard increment is configurable', function(assert) { + const player = TestHelpers.makePlayer({ + controlBar: { + progressControl: { + seekBar: { + stepSeconds: 2, + pageMultiplier: 4 + } + } + } + }); + + const ctSpy = sinon.spy(player, 'currentTime'); + + player.duration(100); + player.currentTime(10); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'ArrowRight'}); + // 10 + 2 + assert.ok(ctSpy.calledWith(12), 'seeked configured amount'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'PageUp'}); + // 12 + (2 * 4) + assert.ok(ctSpy.calledWith(20), 'seeked configured amount with multiplier'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'ArrowLeft'}); + // 20 - 2 + assert.ok(ctSpy.calledWith(18), 'seeked configured amount'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'PageDown'}); + // 18 - (2 * 4) + assert.ok(ctSpy.calledWith(10), 'seeked configured amount with multiplier'); + + player.dispose(); +}); + +QUnit.test('SeekBar keyboard increment is configurable at runtime', function(assert) { + const player = TestHelpers.makePlayer({}); + + const ctSpy = sinon.spy(player, 'currentTime'); + + player.duration(100); + player.currentTime(10); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'ArrowRight'}); + // 10 + 5 + assert.ok(ctSpy.calledWith(15), 'seeked configured amount'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'PageUp'}); + // 15 + (5 * 12) + assert.ok(ctSpy.calledWith(75), 'seeked configured amount with multiplier'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'ArrowLeft'}); + // 75 - 5 + assert.ok(ctSpy.calledWith(70), 'seeked configured amount'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'PageDown'}); + // 70 - (5 * 12) + assert.ok(ctSpy.calledWith(10), 'seeked configured amount with multiplier'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.options().stepSeconds = 3; + player.controlBar.progressControl.seekBar.options().pageMultiplier = 3; + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'ArrowRight'}); + // 10 + 3 + assert.ok(ctSpy.calledWith(13), 'seeked configured amount'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'PageUp'}); + // 13 + (3 * 3) + assert.ok(ctSpy.calledWith(22), 'seeked configured amount with multiplier'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'ArrowLeft'}); + // 22 - 3 + assert.ok(ctSpy.calledWith(19), 'seeked configured amount'); + ctSpy.resetHistory(); + + player.controlBar.progressControl.seekBar.trigger({type: 'keydown', key: 'PageDown'}); + // 19 - (3 * 3) + assert.ok(ctSpy.calledWith(10), 'seeked configured amount with multiplier'); + + player.dispose(); +}); + QUnit.test('Seek bar percent should represent scrub location if we are scrubbing on mobile and have a pending seek time', function(assert) { const player = TestHelpers.makePlayer(); const seekBar = player.controlBar.progressControl.seekBar;