media: Massive UX improvements
- Keyboard controls are now available, though they might not be good enough. Thanks firefox. - f: Fullscreen - m: Mute - Space: Play/Pause - Home: Jump to Start - End: Jump to End - Comma: Go back 0.1s - Period: Go forward 0.1s - Left Arrow: Go back 5s - Right Arrow: Go forward 5s - Up Arrow: Increase logarithmic volume by 5% - Down Arrow: Decrease logarithmic volume by 5% - P: Toggle pitch correction - Page Up: Speed up video - Page Down: Slow down video - Mouse controls are improved too. - Accessibility drastically improved. - Now using the new symbols as well.
This commit is contained in:
+227
-111
@@ -1,3 +1,7 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import("./HTMLMediaElement.mjs");
|
||||||
|
|
||||||
async function xmr_media_lazyload_perform(element) {
|
async function xmr_media_lazyload_perform(element) {
|
||||||
let content = element.querySelector("noscript");
|
let content = element.querySelector("noscript");
|
||||||
if (content) {
|
if (content) {
|
||||||
@@ -22,18 +26,21 @@ async function xmr_initialize_player(el) {
|
|||||||
if (!media)
|
if (!media)
|
||||||
el.querySelector("audio");
|
el.querySelector("audio");
|
||||||
|
|
||||||
// Play/Pause
|
|
||||||
let play_pause = el.querySelector(".play");
|
let play_pause = el.querySelector(".play");
|
||||||
|
{ // Play/Pause
|
||||||
play_pause.update = function() {
|
play_pause.update = function() {
|
||||||
if (media.paused) {
|
if (media.paused) {
|
||||||
play_pause.classList.remove("playing");
|
play_pause.classList.remove("playing");
|
||||||
play_pause.innerText = "⏵";
|
play_pause.dataset.symbol = "⏵";
|
||||||
|
play_pause.ariaLabel = "Play";
|
||||||
} else if (media.error || media.ended) {
|
} else if (media.error || media.ended) {
|
||||||
play_pause.classList.remove("playing");
|
play_pause.classList.remove("playing");
|
||||||
play_pause.innerText = "⏹";
|
play_pause.dataset.symbol = "⏹";
|
||||||
|
play_pause.ariaLabel = "Stopped";
|
||||||
} else {
|
} else {
|
||||||
play_pause.classList.add("playing");
|
play_pause.classList.add("playing");
|
||||||
play_pause.innerText = "⏸";
|
play_pause.dataset.symbol = "⏸";
|
||||||
|
play_pause.ariaLabel = "Pause";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
play_pause.addEventListener("click", () => {
|
play_pause.addEventListener("click", () => {
|
||||||
@@ -43,66 +50,26 @@ async function xmr_initialize_player(el) {
|
|||||||
media.pause();
|
media.pause();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
play_pause.addEventListener("keydown", (ev) => {
|
||||||
|
if (ev.isComposing || ev.keyCode === 229) {
|
||||||
|
// Ignore IME compositing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (["Space", "Enter"].includes(ev.code)) {
|
||||||
|
play_pause.click();
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
media.addEventListener("play", () => { play_pause.update(); });
|
media.addEventListener("play", () => { play_pause.update(); });
|
||||||
media.addEventListener("pause", () => { play_pause.update(); });
|
media.addEventListener("pause", () => { play_pause.update(); });
|
||||||
media.addEventListener("ended", () => { play_pause.update(); });
|
media.addEventListener("ended", () => { play_pause.update(); });
|
||||||
media.addEventListener("error", () => { play_pause.update(); });
|
media.addEventListener("error", () => { play_pause.update(); });
|
||||||
play_pause.update();
|
play_pause.update();
|
||||||
|
}
|
||||||
|
|
||||||
// Mute
|
|
||||||
let audio_mute = el.querySelector(".mute");
|
|
||||||
audio_mute.update = function() {
|
|
||||||
if (media.muted) {
|
|
||||||
audio_mute.classList.add("muted");
|
|
||||||
audio_mute.innerText = "🔇";
|
|
||||||
} else {
|
|
||||||
audio_mute.classList.remove("muted");
|
|
||||||
if (media.volume > 0.5) {
|
|
||||||
audio_mute.innerText = "🔊";
|
|
||||||
} else if (media.volume > 0.125) {
|
|
||||||
audio_mute.innerText = "🔉";
|
|
||||||
} else {
|
|
||||||
audio_mute.innerText = "🔈";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
audio_mute.addEventListener("click", () => {
|
|
||||||
media.muted = !media.muted;
|
|
||||||
});
|
|
||||||
media.addEventListener("volumechange", () => {
|
|
||||||
audio_mute.update();
|
|
||||||
});
|
|
||||||
audio_mute.update();
|
|
||||||
|
|
||||||
// Volume
|
|
||||||
let audio_volume = el.querySelector(".volume");
|
|
||||||
audio_volume.min = 0;
|
|
||||||
audio_volume.max = 2147483647;
|
|
||||||
audio_volume.update = function() {
|
|
||||||
let min = parseInt(audio_volume.min, 10);
|
|
||||||
let max = parseInt(audio_volume.max, 10);
|
|
||||||
let dlt = max - min;
|
|
||||||
audio_volume.value = (media.volume * dlt) + min;
|
|
||||||
if (media.muted) {
|
|
||||||
audio_volume.classList.add("muted");
|
|
||||||
} else {
|
|
||||||
audio_volume.classList.remove("muted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
audio_volume.addEventListener("input", () => {
|
|
||||||
let min = parseInt(audio_volume.min, 10);
|
|
||||||
let max = parseInt(audio_volume.max, 10);
|
|
||||||
let val = parseInt(audio_volume.value, 10);
|
|
||||||
let dlt = max - min;
|
|
||||||
let vol = (val + min) / dlt;
|
|
||||||
media.volume = vol;
|
|
||||||
media.muted = (media.volume < 0.01);
|
|
||||||
});
|
|
||||||
media.addEventListener("volumechange", () => { audio_volume.update(); });
|
|
||||||
audio_volume.update();
|
|
||||||
|
|
||||||
// Time
|
|
||||||
let playback_time = el.querySelector(".time");
|
let playback_time = el.querySelector(".time");
|
||||||
|
{ // Time
|
||||||
playback_time.update = function() {
|
playback_time.update = function() {
|
||||||
function formatSeconds(seconds, with_ms, with_minutes, with_hour) {
|
function formatSeconds(seconds, with_ms, with_minutes, with_hour) {
|
||||||
let result = [];
|
let result = [];
|
||||||
@@ -145,9 +112,10 @@ async function xmr_initialize_player(el) {
|
|||||||
media.addEventListener("durationupdate", () => { playback_progress.update(); });
|
media.addEventListener("durationupdate", () => { playback_progress.update(); });
|
||||||
media.addEventListener("loadedmetadata", () => { playback_time.update(); });
|
media.addEventListener("loadedmetadata", () => { playback_time.update(); });
|
||||||
playback_time.update();
|
playback_time.update();
|
||||||
|
}
|
||||||
|
|
||||||
// Progress
|
|
||||||
let playback_progress = el.querySelector(".progress");
|
let playback_progress = el.querySelector(".progress");
|
||||||
|
{ // Progress
|
||||||
playback_progress.update = function() {
|
playback_progress.update = function() {
|
||||||
playback_progress.disabled = !media.seekable;
|
playback_progress.disabled = !media.seekable;
|
||||||
playback_progress.min = 0;
|
playback_progress.min = 0;
|
||||||
@@ -164,14 +132,83 @@ async function xmr_initialize_player(el) {
|
|||||||
media.addEventListener("loadeddata", () => { playback_progress.update(); });
|
media.addEventListener("loadeddata", () => { playback_progress.update(); });
|
||||||
media.addEventListener("loadedmetadata", () => { playback_progress.update(); });
|
media.addEventListener("loadedmetadata", () => { playback_progress.update(); });
|
||||||
playback_progress.update();
|
playback_progress.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
let audio_mute = el.querySelector(".mute");
|
||||||
|
{ // Mute
|
||||||
|
audio_mute.update = function() {
|
||||||
|
if (media.muted) {
|
||||||
|
audio_mute.classList.add("muted");
|
||||||
|
audio_mute.dataset.symbol = "🔇";
|
||||||
|
audio_mute.ariaLabel = "Unmute";
|
||||||
|
} else {
|
||||||
|
audio_mute.classList.remove("muted");
|
||||||
|
if (media.volume > 0.5) {
|
||||||
|
audio_mute.dataset.symbol = "🔊";
|
||||||
|
} else if (media.volume > 0.25) {
|
||||||
|
audio_mute.dataset.symbol = "🔉";
|
||||||
|
} else {
|
||||||
|
audio_mute.dataset.symbol = "🔈";
|
||||||
|
}
|
||||||
|
audio_mute.ariaLabel = `Volume: ${(media.volume * 100).toString(10)}%`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
audio_mute.addEventListener("click", () => {
|
||||||
|
media.muted = !media.muted;
|
||||||
|
});
|
||||||
|
audio_mute.addEventListener("keydown", (ev) => {
|
||||||
|
if (ev.isComposing || ev.keyCode === 229) {
|
||||||
|
// Ignore IME compositing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (["Space", "Enter"].includes(ev.code)) {
|
||||||
|
audio_mute.click();
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
media.addEventListener("volumechange", () => {
|
||||||
|
audio_mute.update();
|
||||||
|
});
|
||||||
|
audio_mute.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
let audio_volume = el.querySelector(".volume");
|
||||||
|
{ // Volume
|
||||||
|
audio_volume.min = 0;
|
||||||
|
audio_volume.max = 2147483647;
|
||||||
|
audio_volume.update = function() {
|
||||||
|
let min = parseInt(audio_volume.min, 10);
|
||||||
|
let max = parseInt(audio_volume.max, 10);
|
||||||
|
let dlt = max - min;
|
||||||
|
audio_volume.value = (media.logVolume * dlt) + min;
|
||||||
|
audio_volume.ariaLabel = `Volume: ${(media.volume * 100).toString(10)}%`;
|
||||||
|
if (media.muted) {
|
||||||
|
audio_volume.classList.add("muted");
|
||||||
|
} else {
|
||||||
|
audio_volume.classList.remove("muted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
audio_volume.addEventListener("input", () => {
|
||||||
|
let min = parseInt(audio_volume.min, 10);
|
||||||
|
let max = parseInt(audio_volume.max, 10);
|
||||||
|
let val = parseInt(audio_volume.value, 10);
|
||||||
|
let dlt = max - min;
|
||||||
|
let vol = (val + min) / dlt;
|
||||||
|
media.logVolume = vol;
|
||||||
|
media.muted = (media.volume < 0.01);
|
||||||
|
});
|
||||||
|
media.addEventListener("volumechange", () => { audio_volume.update(); });
|
||||||
|
audio_volume.update();
|
||||||
|
}
|
||||||
|
|
||||||
// Fullscreen
|
|
||||||
let fullscreen = el.querySelector(".fullscreen");
|
let fullscreen = el.querySelector(".fullscreen");
|
||||||
|
{ // Fullscreen
|
||||||
fullscreen.update = function() {
|
fullscreen.update = function() {
|
||||||
if (document.fullscreenElement) {
|
if (document.fullscreenElement) {
|
||||||
fullscreen.innerText = "⬚";
|
fullscreen.dataset.symbol = "⬚";
|
||||||
} else {
|
} else {
|
||||||
fullscreen.innerText = "⛶";
|
fullscreen.dataset.symbol = "⛶";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fullscreen.addEventListener("click", () => {
|
fullscreen.addEventListener("click", () => {
|
||||||
@@ -181,62 +218,24 @@ async function xmr_initialize_player(el) {
|
|||||||
el.requestFullscreen();
|
el.requestFullscreen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
el.addEventListener("fullscreenchange", (ev) => {
|
fullscreen.addEventListener("keydown", (ev) => {
|
||||||
fullscreen.update();
|
if (ev.isComposing || ev.keyCode === 229) {
|
||||||
});
|
// Ignore IME compositing.
|
||||||
fullscreen.update();
|
return;
|
||||||
|
}
|
||||||
// Media Play/Pause by click
|
if (["Space", "Enter"].includes(ev.code)) {
|
||||||
media.addEventListener("click", () => {
|
|
||||||
play_pause.click();
|
|
||||||
})
|
|
||||||
|
|
||||||
// Media Fullscreen by dblclick
|
|
||||||
media.addEventListener("dblclick", () => {
|
|
||||||
fullscreen.click();
|
fullscreen.click();
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
el.addEventListener("fullscreenchange", () => {
|
||||||
// Hide/Show controls
|
fullscreen.update();
|
||||||
el.showOverlay = function() {
|
|
||||||
el.cancelHideOverlay();
|
|
||||||
el.classList.remove("hide");
|
|
||||||
}
|
|
||||||
el.hideOverlay = function() {
|
|
||||||
if (!media.paused && !media.ended && !media.error) {
|
|
||||||
el.classList.add("hide");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
el.delayHideOverlay = function() {
|
|
||||||
el.cancelHideOverlay();
|
|
||||||
el.timer = setTimeout(() => { el.hideOverlay(); }, 2500);
|
|
||||||
}
|
|
||||||
el.cancelHideOverlay = function() {
|
|
||||||
if (el.timer) {
|
|
||||||
clearTimeout(el.timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
el.addEventListener("mousemove", () => {
|
|
||||||
el.showOverlay();
|
|
||||||
if (!media.paused && !media.ended && !media.error) {
|
|
||||||
el.delayHideOverlay();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
el.hideOverlay();
|
fullscreen.update();
|
||||||
|
|
||||||
// Show/Hide Audio controls without audio.
|
|
||||||
function checkAudioPresence() {
|
|
||||||
let hasAudio = Boolean(media.mozHasAudio)
|
|
||||||
|| Boolean(media.webkitAudioDecodedByteCount)
|
|
||||||
|| Boolean(media.audioTracks && media.audioTracks.length);
|
|
||||||
audio_mute.style.display = hasAudio ? "" : "none";
|
|
||||||
audio_volume.style.display = hasAudio ? "" : "none";
|
|
||||||
}
|
}
|
||||||
media.addEventListener("loadedmetadata", () => { checkAudioPresence() });
|
|
||||||
media.addEventListener("loadeddata", () => { checkAudioPresence() });
|
|
||||||
checkAudioPresence();
|
|
||||||
|
|
||||||
// Variants
|
|
||||||
let variant = el.querySelector(".variant");
|
let variant = el.querySelector(".variant");
|
||||||
|
{ // Variants
|
||||||
variant.update = function() {
|
variant.update = function() {
|
||||||
// Store current state and pause.
|
// Store current state and pause.
|
||||||
let paused = media.paused;
|
let paused = media.paused;
|
||||||
@@ -278,6 +277,123 @@ async function xmr_initialize_player(el) {
|
|||||||
variant.appendChild(option);
|
variant.appendChild(option);
|
||||||
}
|
}
|
||||||
variant.value = media.currentSrc;
|
variant.value = media.currentSrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Keyboard/Mouse Controls
|
||||||
|
el.addEventListener("keydown", (ev) => {
|
||||||
|
if (ev.isComposing || ev.keyCode === 229) {
|
||||||
|
// Ignore IME compositing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["f", "F"].includes(ev.key)) {
|
||||||
|
fullscreen.click();
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (["m", "M"].includes(ev.key)) {
|
||||||
|
audio_mute.click();
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "Space") {
|
||||||
|
play_pause.click();
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "Home") {
|
||||||
|
media.currentTime = 0;
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "ArrowLeft") {
|
||||||
|
media.currentTime -= 5;
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "Comma") {
|
||||||
|
media.currentTime -= .1;
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "Period") {
|
||||||
|
media.currentTime += .1;
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "ArrowRight") {
|
||||||
|
media.currentTime += 5;
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "End") {
|
||||||
|
media.currentTime = media.duration;
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "ArrowUp") {
|
||||||
|
media.volume = Math.max(0, Math.min(media.logVolume + 0.05, 1.0));
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "ArrowDown") {
|
||||||
|
media.volume = Math.max(0, Math.min(media.logVolume - 0.05, 1.0));
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (["p", "P"].includes(ev.key)) {
|
||||||
|
media.preservesPitch = !media.preservesPitch;
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "PageDown") {
|
||||||
|
media.playbackRate = Math.max(0.25, Math.min(media.playbackRate - 0.05, 4.0));
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else if (ev.code === "PageUp") {
|
||||||
|
media.playbackRate = Math.max(0.25, Math.min(media.playbackRate + 0.05, 4.0));
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
media.addEventListener("click", () => {
|
||||||
|
play_pause.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
media.addEventListener("dblclick", () => {
|
||||||
|
fullscreen.click();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Hide/Show controls
|
||||||
|
el.showOverlay = function() {
|
||||||
|
el.cancelHideOverlay();
|
||||||
|
el.classList.remove("hide");
|
||||||
|
}
|
||||||
|
el.hideOverlay = function() {
|
||||||
|
if (!media.paused && !media.ended && !media.error) {
|
||||||
|
el.classList.add("hide");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
el.delayHideOverlay = function() {
|
||||||
|
el.cancelHideOverlay();
|
||||||
|
el.timer = setTimeout(() => { el.hideOverlay(); }, 2500);
|
||||||
|
}
|
||||||
|
el.cancelHideOverlay = function() {
|
||||||
|
if (el.timer) {
|
||||||
|
clearTimeout(el.timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
el.addEventListener("mousemove", () => {
|
||||||
|
el.showOverlay();
|
||||||
|
if (!media.paused && !media.ended && !media.error) {
|
||||||
|
el.delayHideOverlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
el.hideOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Show/Hide Audio controls without audio.
|
||||||
|
function checkAudioPresence() {
|
||||||
|
let hasAudio = Boolean(media.mozHasAudio)
|
||||||
|
|| Boolean(media.webkitAudioDecodedByteCount)
|
||||||
|
|| Boolean(media.audioTracks && media.audioTracks.length);
|
||||||
|
audio_mute.style.display = hasAudio ? "" : "none";
|
||||||
|
audio_volume.style.display = hasAudio ? "" : "none";
|
||||||
|
}
|
||||||
|
media.addEventListener("loadedmetadata", () => { checkAudioPresence() });
|
||||||
|
media.addEventListener("loadeddata", () => { checkAudioPresence() });
|
||||||
|
checkAudioPresence();
|
||||||
|
}
|
||||||
|
|
||||||
// Signal the browser to try and load some information.
|
// Signal the browser to try and load some information.
|
||||||
media.load();
|
media.load();
|
||||||
|
|||||||
Reference in New Issue
Block a user