1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-11-23 00:55:58 +01:00

Rework custom video controls.

Move custom video controls into its own function.  Remove some
DOM traversals, avoid querySelector.  Remove dead code.
This commit is contained in:
Juliusz Chroboczek 2020-11-28 01:53:29 +01:00
parent 907a712d6a
commit a2e322edcb
2 changed files with 106 additions and 109 deletions

View file

@ -209,21 +209,13 @@
<div id="videocontrols-template" class="invisible"> <div id="videocontrols-template" class="invisible">
<div class="video-controls vc-overlay"> <div class="video-controls vc-overlay">
<span class="volume" title="Volume"> <span class="volume" title="Volume">
<i class="fas fa-volume-up" data-type="bt-volume" aria-hidden="true"></i> <i class="fas fa-volume-up" aria-hidden="true"></i>
</span> </span>
<span class="pip" title="Picture In Picture"> <span class="pip" title="Picture In Picture">
<i class="fas fa-clone" data-type="bt-pip" aria-hidden="true"></i> <i class="fas fa-clone" aria-hidden="true"></i>
</span> </span>
<span class="fullscreen" title="Fullscreen"> <span class="fullscreen" title="Fullscreen">
<i class="fas fa-expand-alt" data-type="bt-fullscreen" aria-hidden="true"></i> <i class="fas fa-expand-alt" aria-hidden="true"></i>
</span>
</div>
</div>
<div id="top-videocontrols-template" class="invisible">
<div class="top-video-controls">
<span class="expand invisible" title="Maximize">
<i class="fas fa-external-link" data-type="bt-expand" aria-hidden="true"></i>
</span> </span>
</div> </div>
</div> </div>

View file

@ -1002,19 +1002,17 @@ function muteLocalTracks(mute) {
} }
/** /**
* setMedia adds a new media element corresponding to stream c.
*
* @param {Stream} c * @param {Stream} c
* @param {boolean} isUp * @param {boolean} isUp
* - indicates whether the stream goes in the up direction
* @param {HTMLVideoElement} [video] * @param {HTMLVideoElement} [video]
* - the video element to add. If null, a new element with custom
* controls will be created.
*/ */
function setMedia(c, isUp, video) { function setMedia(c, isUp, video) {
let peersdiv = document.getElementById('peers'); let peersdiv = document.getElementById('peers');
let local_media;
for(let id in serverConnection.up) {
if (id === c.id) {
local_media = serverConnection.up[id];
}
}
let div = document.getElementById('peer-' + c.id); let div = document.getElementById('peer-' + c.id);
if(!div) { if(!div) {
@ -1026,21 +1024,28 @@ function setMedia(c, isUp, video) {
let media = /** @type {HTMLVideoElement} */ let media = /** @type {HTMLVideoElement} */
(document.getElementById('media-' + c.id)); (document.getElementById('media-' + c.id));
if(!media) { if(media) {
if(video) {
throw new Error("Duplicate video");
}
} else {
if(video) { if(video) {
media = video; media = video;
} else { } else {
media = document.createElement('video'); media = document.createElement('video');
media.controls = false;
if(isUp) if(isUp)
media.muted = true; media.muted = true;
media.srcObject = c.stream;
} }
media.classList.add('media'); media.classList.add('media');
media.autoplay = true; media.autoplay = true;
/** @ts-ignore */ /** @ts-ignore */
media.playsinline = true; media.playsinline = true;
media.id = 'media-' + c.id; media.id = 'media-' + c.id;
div.appendChild(media); div.appendChild(media);
if(!video)
addCustomControls(media, div, c);
} }
let label = document.getElementById('label-' + c.id); let label = document.getElementById('label-' + c.id);
@ -1051,128 +1056,128 @@ function setMedia(c, isUp, video) {
div.appendChild(label); div.appendChild(label);
} }
if(!video) {
let template = document.getElementById('videocontrols-template')
.firstElementChild;
let top_template = document.getElementById('top-videocontrols-template')
.firstElementChild;
let top_controls = document.getElementById('topcontrols-' + c.id);
if(template && !top_controls) {
top_controls = /** @type{HTMLElement} */(top_template.cloneNode(true));
top_controls.id = 'topcontrols-' + c.id;
div.appendChild(top_controls);
}
let controls = document.getElementById('controls-' + c.id);
if(template && !controls) {
controls = /** @type{HTMLElement} */(template.cloneNode(true));
controls.id = 'controls-' + c.id;
div.appendChild(controls);
let volume = controls.querySelector(".fa-volume-up");
if(media.muted) {
if (volume) {
volume.classList.remove("fa-volume-up");
volume.classList.add("fa-volume-off");
}
}
if (local_media && local_media.kind === "local")
volume.parentElement.remove();
}
media.srcObject = c.stream;
}
setLabel(c); setLabel(c);
setMediaStatus(c); setMediaStatus(c);
showVideo(); showVideo();
resizePeers(); resizePeers();
registerControlEvent(div.id);
} }
/** /**
* @param {HTMLVideoElement} video * @param {Element} elt
*/ */
async function videoPIP(video) { function cloneHTMLElement(elt) {
/** @ts-ignore */ if(!(elt instanceof HTMLElement))
if (video.requestPictureInPicture) { throw new Error('Unexpected element type');
/** @ts-ignore */ return /** @type{HTMLElement} */(elt.cloneNode(true));
await video.requestPictureInPicture(); }
/**
* @param {HTMLVideoElement} media
* @param {HTMLElement} container
* @param {Stream} c
*/
function addCustomControls(media, container, c) {
media.controls = false;
let controls = document.getElementById('controls-' + c.id);
if(controls) {
console.warn('Attempted to add duplicate controls');
return;
}
let template =
document.getElementById('videocontrols-template').firstElementChild;
controls = cloneHTMLElement(template);
controls.id = 'controls-' + c.id;
let volume = getVideoButton(controls, 'volume');
if(c.kind === 'local') {
volume.remove();
} else { } else {
displayWarning("Video PIP Mode not supported!"); setVolumeButton(
/** @type{HTMLElement} */(volume.firstElementChild),
media.muted,
);
}
container.appendChild(controls);
registerControlHandlers(media, container);
}
/**
* @param {HTMLElement} container
* @param {string} name
*/
function getVideoButton(container, name) {
return /** @type {HTMLElement} */(container.getElementsByClassName(name)[0]);
}
/**
* @param {HTMLElement} button
* @param {boolean} muted
*/
function setVolumeButton(button, muted) {
if(!muted) {
button.classList.remove("fa-volume-off");
button.classList.add("fa-volume-up");
} else {
button.classList.remove("fa-volume-up");
button.classList.add("fa-volume-off");
} }
} }
/** /**
* @param {HTMLElement} target * @param {HTMLVideoElement} media
* @param {HTMLElement} container
*/ */
function getParentVideo(target) { function registerControlHandlers(media, container) {
// target is the <i> element, parent the div <div><span><i/></span></div> let volume = getVideoButton(container, 'volume');
let control = target.parentElement.parentElement;
let id = control.id.split('-')[1];
let media = /** @type {HTMLVideoElement} */
(document.getElementById('media-' + id));
if (!media) {
displayError("Cannot find media!");
}
return media;
}
/**
* @param {string} peerid
*/
function registerControlEvent(peerid) {
let peer = document.getElementById(peerid);
//Add event listener when a video component is added to the DOM
let volume = /** @type {HTMLElement} */(peer.querySelector("span.volume"));
if (volume) { if (volume) {
volume.onclick = function(event) { volume.onclick = function(event) {
event.preventDefault(); event.preventDefault();
let volume = /** @type{HTMLElement} */(event.target); media.muted = !media.muted;
let video = getParentVideo(volume); setVolumeButton(
if(volume.className.indexOf("fa-volume-off") !== -1) { /** @type{HTMLElement} */(event.target),
volume.classList.remove("fa-volume-off"); media.muted,
volume.classList.add("fa-volume-up"); );
video.muted = false;
} else {
volume.classList.remove("fa-volume-up");
volume.classList.add("fa-volume-off");
// mute video sound
video.muted = true;
}
}; };
} }
let pip = /** @type {HTMLElement} */(peer.querySelector("span.pip")); let pip = getVideoButton(container, 'pip');
if(pip) { if(pip) {
/** @ts-ignore */ /** @ts-ignore */
if(HTMLVideoElement.prototype.requestPictureInPicture) { if(HTMLVideoElement.prototype.requestPictureInPicture) {
pip.onclick = function(event) { pip.onclick = function(e) {
event.preventDefault(); e.preventDefault();
let pip = /** @type{HTMLElement} */(event.target); /** @ts-ignore */
let video = getParentVideo(pip); if(media.requestPictureInPicture) {
videoPIP(video); /** @ts-ignore */
media.requestPictureInPicture();
} else {
displayWarning('Picture in Picture not supported.');
}
}; };
} else { } else {
pip.style.display = 'none'; pip.style.display = 'none';
} }
} }
let fs = /** @type {HTMLElement} */(peer.querySelector("span.fullscreen")); let fs = getVideoButton(container, 'fullscreen');
if(fs) { if(fs) {
fs.onclick = function(event) { if(HTMLVideoElement.prototype.requestFullscreen) {
event.preventDefault(); fs.onclick = function(e) {
let fs = /** @type {HTMLElement} */(event.target); e.preventDefault();
let video = getParentVideo(fs); if(media.requestFullscreen) {
if(video.requestFullscreen) { media.requestFullscreen();
video.requestFullscreen();
} else { } else {
displayWarning("Video Fullscreen not supported!"); displayWarning('Full screen not supported!');
} }
}; };
} else {
fs.style.display = 'none';
}
} }
} }
/** /**
* @param {string} id * @param {string} id