mirror of
https://github.com/jech/galene.git
synced 2024-11-09 18:25: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:
parent
907a712d6a
commit
a2e322edcb
2 changed files with 106 additions and 109 deletions
|
@ -209,21 +209,13 @@
|
|||
<div id="videocontrols-template" class="invisible">
|
||||
<div class="video-controls vc-overlay">
|
||||
<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 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 class="fullscreen" title="Fullscreen">
|
||||
<i class="fas fa-expand-alt" data-type="bt-fullscreen" 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>
|
||||
<i class="fas fa-expand-alt" aria-hidden="true"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
201
static/sfu.js
201
static/sfu.js
|
@ -1002,19 +1002,17 @@ function muteLocalTracks(mute) {
|
|||
}
|
||||
|
||||
/**
|
||||
* setMedia adds a new media element corresponding to stream c.
|
||||
*
|
||||
* @param {Stream} c
|
||||
* @param {boolean} isUp
|
||||
* - indicates whether the stream goes in the up direction
|
||||
* @param {HTMLVideoElement} [video]
|
||||
* - the video element to add. If null, a new element with custom
|
||||
* controls will be created.
|
||||
*/
|
||||
function setMedia(c, isUp, video) {
|
||||
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);
|
||||
if(!div) {
|
||||
|
@ -1026,21 +1024,28 @@ function setMedia(c, isUp, video) {
|
|||
|
||||
let media = /** @type {HTMLVideoElement} */
|
||||
(document.getElementById('media-' + c.id));
|
||||
if(!media) {
|
||||
if(media) {
|
||||
if(video) {
|
||||
throw new Error("Duplicate video");
|
||||
}
|
||||
} else {
|
||||
if(video) {
|
||||
media = video;
|
||||
} else {
|
||||
media = document.createElement('video');
|
||||
media.controls = false;
|
||||
if(isUp)
|
||||
media.muted = true;
|
||||
media.srcObject = c.stream;
|
||||
}
|
||||
|
||||
media.classList.add('media');
|
||||
media.autoplay = true;
|
||||
/** @ts-ignore */
|
||||
media.playsinline = true;
|
||||
media.id = 'media-' + c.id;
|
||||
div.appendChild(media);
|
||||
if(!video)
|
||||
addCustomControls(media, div, c);
|
||||
}
|
||||
|
||||
let label = document.getElementById('label-' + c.id);
|
||||
|
@ -1051,129 +1056,129 @@ function setMedia(c, isUp, video) {
|
|||
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);
|
||||
setMediaStatus(c);
|
||||
|
||||
showVideo();
|
||||
resizePeers();
|
||||
registerControlEvent(div.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLVideoElement} video
|
||||
* @param {Element} elt
|
||||
*/
|
||||
async function videoPIP(video) {
|
||||
/** @ts-ignore */
|
||||
if (video.requestPictureInPicture) {
|
||||
/** @ts-ignore */
|
||||
await video.requestPictureInPicture();
|
||||
function cloneHTMLElement(elt) {
|
||||
if(!(elt instanceof HTMLElement))
|
||||
throw new Error('Unexpected element type');
|
||||
return /** @type{HTMLElement} */(elt.cloneNode(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
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) {
|
||||
// target is the <i> element, parent the div <div><span><i/></span></div>
|
||||
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"));
|
||||
function registerControlHandlers(media, container) {
|
||||
let volume = getVideoButton(container, 'volume');
|
||||
if (volume) {
|
||||
volume.onclick = function(event) {
|
||||
event.preventDefault();
|
||||
let volume = /** @type{HTMLElement} */(event.target);
|
||||
let video = getParentVideo(volume);
|
||||
if(volume.className.indexOf("fa-volume-off") !== -1) {
|
||||
volume.classList.remove("fa-volume-off");
|
||||
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;
|
||||
}
|
||||
media.muted = !media.muted;
|
||||
setVolumeButton(
|
||||
/** @type{HTMLElement} */(event.target),
|
||||
media.muted,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let pip = /** @type {HTMLElement} */(peer.querySelector("span.pip"));
|
||||
let pip = getVideoButton(container, 'pip');
|
||||
if(pip) {
|
||||
/** @ts-ignore */
|
||||
if(HTMLVideoElement.prototype.requestPictureInPicture) {
|
||||
pip.onclick = function(event) {
|
||||
event.preventDefault();
|
||||
let pip = /** @type{HTMLElement} */(event.target);
|
||||
let video = getParentVideo(pip);
|
||||
videoPIP(video);
|
||||
pip.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
/** @ts-ignore */
|
||||
if(media.requestPictureInPicture) {
|
||||
/** @ts-ignore */
|
||||
media.requestPictureInPicture();
|
||||
} else {
|
||||
displayWarning('Picture in Picture not supported.');
|
||||
}
|
||||
};
|
||||
} else {
|
||||
pip.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
let fs = /** @type {HTMLElement} */(peer.querySelector("span.fullscreen"));
|
||||
let fs = getVideoButton(container, 'fullscreen');
|
||||
if(fs) {
|
||||
fs.onclick = function(event) {
|
||||
event.preventDefault();
|
||||
let fs = /** @type {HTMLElement} */(event.target);
|
||||
let video = getParentVideo(fs);
|
||||
if(video.requestFullscreen) {
|
||||
video.requestFullscreen();
|
||||
} else {
|
||||
displayWarning("Video Fullscreen not supported!");
|
||||
}
|
||||
};
|
||||
if(HTMLVideoElement.prototype.requestFullscreen) {
|
||||
fs.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
if(media.requestFullscreen) {
|
||||
media.requestFullscreen();
|
||||
} else {
|
||||
displayWarning('Full screen not supported!');
|
||||
}
|
||||
};
|
||||
} else {
|
||||
fs.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue