Files
Alfredv2/alfred/app/static/js/alfred-hide-hermes-activity.js
T

133 lines
5.5 KiB
JavaScript

/* ALFRED_HIDE_HERMES_ACTIVITY_V2
Supprime uniquement l'ancienne vue "Activité Hermes" du DOM visuel.
N'interrompt ni les taches de fond, ni le MCP, ni les evenements Socket.IO.
*/
(() => {
'use strict';
const TITLE = /\bactivit[eé]\s+hermes\b/i;
const EXACT_TITLE = /^\s*[⌄˅∨▾▿▼v]?\s*activit[eé]\s+hermes\s*(?:\d+)?\s*$/i;
const SPECIFIC_SELECTOR = [
'#hermesActivityPopup', '#hermesActivityModal',
'[aria-label="Activité Hermes"]', '[aria-label="Activite Hermes"]',
'[data-component="hermes-activity"]', '[data-widget="hermes-activity"]',
'.hermes-activity-panel', '.hermes-activity-popup',
'.hermes-activity-widget', '.hermes-activity-dock',
'.hermes-task-panel', '.hermes-tasks-panel'
].join(',');
const CLASS_HINT = /(?:hermes.{0,30}(?:activit|activity|tasks?|jobs?)|(?:activit|activity|tasks?|jobs?).{0,30}hermes)/i;
const PANEL_HINT = /(?:activit|activity|tasks?|jobs?|queue|history|panel|widget|dock|drawer|popover|sidebar)/i;
function markHidden(element) {
if (!element || !element.isConnected || element === document.body) return;
if (!element.hasAttribute('data-alfred-hermes-hidden')) {
element.setAttribute('data-alfred-hermes-hidden', 'true');
}
// Important : certains widgets reinitialisent leur attribut hidden ou display.
if (!element.hidden) element.hidden = true;
if (element.style.getPropertyValue('display') !== 'none' ||
element.style.getPropertyPriority('display') !== 'important') {
element.style.setProperty('display', 'none', 'important');
}
}
function isTitle(text) {
return EXACT_TITLE.test(String(text || '').replace(/\u00a0/g, ' ').trim());
}
function isSafeCandidate(el) {
if (!el || !el.isConnected) return false;
if (el.matches('html,body,main,.alfred-shell,#stage,#content')) return false;
if (el.contains(document.querySelector('#stage')) && document.querySelector('#stage')) return false;
if (el.contains(document.querySelector('#alfredTimersDock')) && document.querySelector('#alfredTimersDock')) return false;
return true;
}
function choosePanel(titleNode) {
// La capture montre un dock : le titre est accompagne d'un compteur et
// d'une carte de tache (badge "Termine", bouton "Lire").
const ancestors = [];
let el = titleNode.nodeType === 1 ? titleNode : titleNode.parentElement;
for (let depth = 0; el && depth < 10; depth++, el = el.parentElement) {
if (!isSafeCandidate(el)) break;
ancestors.push(el);
}
if (!ancestors.length) return null;
// Quand l'identifiant ou la classe indiquent explicitement le widget,
// ces conteneurs sont preferes au contenu de la carte.
for (const candidate of ancestors) {
const identity = `${candidate.id || ''} ${typeof candidate.className === 'string' ? candidate.className : ''}`;
if (CLASS_HINT.test(identity)) return candidate;
if (candidate.matches('[role="dialog"],[role="complementary"]') && TITLE.test(candidate.textContent || '')) return candidate;
}
// Cas general (et cas de la capture) : choisir le plus petit ancetre
// suffisamment grand pour contenir l'entete ET la liste des taches.
for (const candidate of ancestors) {
const allText = (candidate.innerText || candidate.textContent || '').trim();
if (allText.length > 15000) continue; // l'ancetre contient deja le titre detecte
const hasTask = /\b(?:termin[eé]|en\s+cours|en\s+attente|erreur|lire|annuler|rapport)\b/i.test(allText);
const childCount = candidate.children ? candidate.children.length : 0;
if (!hasTask || childCount < 2) continue;
const rect = candidate.getBoundingClientRect();
if (rect.width >= 180 && rect.height >= 100 &&
rect.width <= Math.max(window.innerWidth * 0.82, 600) &&
rect.height <= window.innerHeight * 1.5) {
return candidate;
}
}
// Panneau vide : se baser sur la bordure/classe du conteneur, sans cacher
// un parent generic (page entiere, scene, panneau de transcription).
for (const candidate of ancestors) {
const identity = `${candidate.id || ''} ${typeof candidate.className === 'string' ? candidate.className : ''}`;
if (!PANEL_HINT.test(identity)) continue;
const rect = candidate.getBoundingClientRect();
if (rect.width >= 150 && rect.width <= Math.max(window.innerWidth * 0.82, 600)) return candidate;
}
return null;
}
function hideActivity() {
for (const el of document.querySelectorAll(SPECIFIC_SELECTOR)) {
if (isSafeCandidate(el)) markHidden(el);
}
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
let textNode;
while ((textNode = walker.nextNode())) {
if (!textNode.parentElement || textNode.parentElement.closest('[data-alfred-hermes-hidden]')) continue;
if (!isTitle(textNode.nodeValue)) continue;
const panel = choosePanel(textNode);
if (panel) markHidden(panel);
}
}
let queued = false;
function scheduleHide() {
if (queued) return;
queued = true;
queueMicrotask(() => {
queued = false;
if (document.body) hideActivity();
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
hideActivity();
observe();
}, {once:true});
} else {
hideActivity();
observe();
}
function observe() {
const observer = new MutationObserver(scheduleHide);
observer.observe(document.body, {
childList: true,
subtree: true,
characterData: true
});
}
})();