V1
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
/* ALFRED_CAMERA_POPUP_V1
|
||||
* Utilise le pilote caméra MJPEG existant (alfred-camera.js), sans ouvrir
|
||||
* un deuxième flux concurrent : ouverture = clic sur cameraToggle ;
|
||||
* fermeture = arrêt immédiat du flux, libérant la webcam pour le MCP visage.
|
||||
*/
|
||||
(() => {
|
||||
'use strict';
|
||||
const trigger = document.getElementById('cameraPopupButton');
|
||||
const overlay = document.getElementById('cameraPopup');
|
||||
const closeButton = document.getElementById('cameraPopupClose');
|
||||
const toggle = document.getElementById('cameraToggle');
|
||||
if (!trigger || !overlay || !closeButton || !toggle) return;
|
||||
let previousFocus = null;
|
||||
|
||||
function active() { return toggle.getAttribute('aria-pressed') === 'true'; }
|
||||
function opened() { return !overlay.hidden; }
|
||||
function setExpanded(value) { trigger.setAttribute('aria-expanded', String(value)); }
|
||||
|
||||
function openPopup() {
|
||||
if (opened()) return;
|
||||
previousFocus = document.activeElement;
|
||||
overlay.hidden = false;
|
||||
document.body.classList.add('alfred-camera-dialog-open');
|
||||
setExpanded(true);
|
||||
closeButton.focus();
|
||||
// Réutilise la logique précédente pour accéder à /api/camera/stream.
|
||||
if (!active()) toggle.click();
|
||||
}
|
||||
|
||||
function closePopup() {
|
||||
if (!opened()) return;
|
||||
// L'ancienne implémentation du bouton ferme le flux MJPEG et retire src.
|
||||
if (active()) toggle.click();
|
||||
// Garde-fou contre un éventuel gestionnaire caméra incomplet.
|
||||
const feed = document.getElementById('cameraFeed');
|
||||
if (feed && feed.hasAttribute('src')) feed.removeAttribute('src');
|
||||
overlay.hidden = true;
|
||||
document.body.classList.remove('alfred-camera-dialog-open');
|
||||
setExpanded(false);
|
||||
if (previousFocus && document.contains(previousFocus) && typeof previousFocus.focus === 'function') {
|
||||
previousFocus.focus();
|
||||
} else {
|
||||
trigger.focus();
|
||||
}
|
||||
previousFocus = null;
|
||||
}
|
||||
|
||||
trigger.addEventListener('click', () => opened() ? closePopup() : openPopup());
|
||||
closeButton.addEventListener('click', closePopup);
|
||||
overlay.addEventListener('pointerdown', evt => {
|
||||
if (evt.target === overlay) closePopup();
|
||||
});
|
||||
document.addEventListener('keydown', evt => {
|
||||
if (!opened()) return;
|
||||
if (evt.key === 'Escape') {
|
||||
evt.preventDefault();
|
||||
closePopup();
|
||||
} else if (evt.key === 'Tab') {
|
||||
// La page principale ne doit pas recevoir le focus derrière la modale.
|
||||
const nodes = [...overlay.querySelectorAll('button:not([disabled]),a[href],input:not([disabled])')]
|
||||
.filter(node => node.getClientRects().length);
|
||||
if (!nodes.length) return;
|
||||
const first = nodes[0], last = nodes[nodes.length - 1];
|
||||
if (evt.shiftKey && document.activeElement === first) {
|
||||
evt.preventDefault(); last.focus();
|
||||
} else if (!evt.shiftKey && document.activeElement === last) {
|
||||
evt.preventDefault(); first.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
// Le flux est également fermé par alfred-camera.js en cas de page masquée.
|
||||
window.addEventListener('pagehide', () => { if (opened()) closePopup(); });
|
||||
setExpanded(false);
|
||||
})();
|
||||
Reference in New Issue
Block a user