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:
parent
907a712d6a
commit
a2e322edcb
2 changed files with 106 additions and 109 deletions
|
@ -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>
|
||||||
|
|
195
static/sfu.js
195
static/sfu.js
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue