Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

js: add support for keydown events #678

Merged
merged 2 commits into from
Aug 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
332 changes: 269 additions & 63 deletions assets/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,69 +38,7 @@ var shareOptions = {
embedCode: "<iframe id='ivplayer' type='text/html' width='640' height='360' src='" + embed_url + "' frameborder='0'></iframe>"
}

var player = videojs('player', options, function () {
this.hotkeys({
volumeStep: 0.1,
seekStep: 5,
enableModifiersForNumbers: false,
enableHoverScroll: true,
customKeys: {
// Toggle play with K Key
play: {
key: function (e) {
return e.which === 75;
},
handler: function (player, options, e) {
if (player.paused()) {
player.play();
} else {
player.pause();
}
}
},
// Go backward 10 seconds
backward: {
key: function (e) {
return e.which === 74;
},
handler: function (player, options, e) {
player.currentTime(player.currentTime() - 10);
}
},
// Go forward 10 seconds
forward: {
key: function (e) {
return e.which === 76;
},
handler: function (player, options, e) {
player.currentTime(player.currentTime() + 10);
}
},
// Increase speed
increase_speed: {
key: function (e) {
return (e.which === 190 && e.shiftKey);
},
handler: function (player, _, e) {
size = options.playbackRates.length;
index = options.playbackRates.indexOf(player.playbackRate());
player.playbackRate(options.playbackRates[(index + 1) % size]);
}
},
// Decrease speed
decrease_speed: {
key: function (e) {
return (e.which === 188 && e.shiftKey);
},
handler: function (player, _, e) {
size = options.playbackRates.length;
index = options.playbackRates.indexOf(player.playbackRate());
player.playbackRate(options.playbackRates[(size + index - 1) % size]);
}
}
}
});
});
var player = videojs('player', options);

if (location.pathname.startsWith('/embed/')) {
player.overlay({
Expand Down Expand Up @@ -254,5 +192,273 @@ if (!video_data.params.listen && video_data.params.annotations) {
xhr.send();
}

function increase_volume(delta) {
const curVolume = player.volume();
let newVolume = curVolume + delta;
if (newVolume > 1) {
newVolume = 1;
} else if (newVolume < 0) {
newVolume = 0;
}
player.volume(newVolume);
}

function toggle_muted() {
const isMuted = player.muted();
player.muted(!isMuted);
}

function skip_seconds(delta) {
const duration = player.duration();
const curTime = player.currentTime();
let newTime = curTime + delta;
if (newTime > duration) {
newTime = duration;
} else if (newTime < 0) {
newTime = 0;
}
player.currentTime(newTime);
}

function set_time_percent(percent) {
const duration = player.duration();
const newTime = duration * (percent / 100);
player.currentTime(newTime);
}

function toggle_play() {
if (player.paused()) {
player.play();
} else {
player.pause();
}
}

const toggle_captions = (function() {
let toggledTrack = null;
const onChange = function(e) {
toggledTrack = null;
};
const bindChange = function(onOrOff) {
player.textTracks()[onOrOff]('change', onChange);
};
// Wrapper function to ignore our own emitted events and only listen
// to events emitted by Video.js on click on the captions menu items.
const setMode = function(track, mode) {
bindChange('off');
track.mode = mode;
window.setTimeout(function() {
bindChange('on');
}, 0);
};
bindChange('on');
return function() {
if (toggledTrack !== null) {
if (toggledTrack.mode !== 'showing') {
setMode(toggledTrack, 'showing');
} else {
setMode(toggledTrack, 'disabled');
}
toggledTrack = null;
return;
}

// Used as a fallback if no captions are currently active.
// TODO: Make this more intelligent by e.g. relying on browser language.
let fallbackCaptionsTrack = null;

const tracks = player.textTracks();
for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];
if (track.kind !== 'captions') {
continue;
}

if (fallbackCaptionsTrack === null) {
fallbackCaptionsTrack = track;
}
if (track.mode === 'showing') {
setMode(track, 'disabled');
toggledTrack = track;
return;
}
}

// Fallback if no captions are currently active.
if (fallbackCaptionsTrack !== null) {
setMode(fallbackCaptionsTrack, 'showing');
toggledTrack = fallbackCaptionsTrack;
}
};
})();

function toggle_fullscreen() {
if (player.isFullscreen()) {
player.exitFullscreen();
} else {
player.requestFullscreen();
}
}

function increase_playback_rate(steps) {
const maxIndex = options.playbackRates.length - 1;
const curIndex = options.playbackRates.indexOf(player.playbackRate());
let newIndex = curIndex + steps;
if (newIndex > maxIndex) {
newIndex = maxIndex;
} else if (newIndex < 0) {
newIndex = 0;
}
player.playbackRate(options.playbackRates[newIndex]);
}

window.addEventListener('keydown', e => {
if (e.target.tagName.toLowerCase() === 'input') {
// Ignore input when focus is on certain elements, e.g. form fields.
return;
}
// See https://github.com/ctd1500/videojs-hotkeys/blob/bb4a158b2e214ccab87c2e7b95f42bc45c6bfd87/videojs.hotkeys.js#L310-L313
const isPlayerFocused = false
|| e.target === document.querySelector('.video-js')
|| e.target === document.querySelector('.vjs-tech')
|| e.target === document.querySelector('.iframeblocker')
|| e.target === document.querySelector('.vjs-control-bar')
;
let action = null;

const code = e.keyCode;
const key = e.key;
switch (key) {
case ' ':
case 'k':
action = toggle_play;
break;

case 'ArrowUp':
if (isPlayerFocused) {
action = increase_volume.bind(this, 0.1);
}
break;
case 'ArrowDown':
if (isPlayerFocused) {
action = increase_volume.bind(this, -0.1);
}
break;

case 'm':
action = toggle_muted;
break;

case 'ArrowRight':
action = skip_seconds.bind(this, 5);
break;
case 'ArrowLeft':
action = skip_seconds.bind(this, -5);
break;
case 'l':
action = skip_seconds.bind(this, 10);
break;
case 'j':
action = skip_seconds.bind(this, -10);
break;

case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
const percent = (code - 48) * 10;
action = set_time_percent.bind(this, percent);
break;

case 'c':
action = toggle_captions;
break;
case 'f':
action = toggle_fullscreen;
break;

case 'N':
action = next_video;
break;
case 'P':
// TODO: Add support to play back previous video.
break;

case '.':
// TODO: Add support for next-frame-stepping.
break;
case ',':
// TODO: Add support for previous-frame-stepping.
break;

case '>':
action = increase_playback_rate.bind(this, 1);
break;
case '<':
action = increase_playback_rate.bind(this, -1);
break;

default:
console.info('Unhandled key down event: %s:', key, e);
break;
}

if (action) {
e.preventDefault();
action();
}
}, false);

// Add support for controlling the player volume by scrolling over it. Adapted from
// https://github.com/ctd1500/videojs-hotkeys/blob/bb4a158b2e214ccab87c2e7b95f42bc45c6bfd87/videojs.hotkeys.js#L292-L328
(function() {
const volumeStep = 0.05;
const enableVolumeScroll = true;
const enableHoverScroll = true;
const doc = document;
const pEl = document.getElementById('player');

var volumeHover = false;
var volumeSelector = pEl.querySelector('.vjs-volume-menu-button') || pEl.querySelector('.vjs-volume-panel');
if (volumeSelector != null) {
volumeSelector.onmouseover = function() { volumeHover = true; };
volumeSelector.onmouseout = function() { volumeHover = false; };
}

var mouseScroll = function mouseScroll(event) {
var activeEl = doc.activeElement;
if (enableHoverScroll) {
// If we leave this undefined then it can match non-existent elements below
activeEl = 0;
}

// When controls are disabled, hotkeys will be disabled as well
if (player.controls()) {
if (volumeHover) {
if (enableVolumeScroll) {
event = window.event || event;
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
event.preventDefault();

if (delta == 1) {
increase_volume(volumeStep);
} else if (delta == -1) {
increase_volume(-volumeStep);
}
}
}
}
};

player.on('mousewheel', mouseScroll);
player.on("DOMMouseScroll", mouseScroll);
}());

// Since videojs-share can sometimes be blocked, we defer it until last
player.share(shareOptions);
2 changes: 0 additions & 2 deletions assets/js/videojs.hotkeys.min.js

This file was deleted.

Loading