summaryrefslogtreecommitdiffstats
path: root/assets/js/player.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/player.js')
-rw-r--r--assets/js/player.js332
1 files changed, 269 insertions, 63 deletions
diff --git a/assets/js/player.js b/assets/js/player.js
index 25cbb18b..4a61258c 100644
--- a/assets/js/player.js
+++ b/assets/js/player.js
@@ -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({
@@ -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);