/* Barre d'apps commune dracodev — comportement (v0.1.0, ACC-0.2 ; * v0.1.3 : menu des applications ouvert par la marque ✦). * * Aucun gestionnaire inline : un seul écouteur délégué sur le document * (patron validé par le prototype — les onclick du HTML généré sont * proscrits dans tout le programme). * * Configuration attendue avant le chargement : * window.DRACO_BAR_CONFIG = { * current: "tiktak", // app courante * domain: "pro", // domaine actif * counts: { tiktak: 3, kanbante: 3, alertes: 3, spark: 0 }, * onAction: function (act, el) { … } // l'app relaie les actions * } // qu'elle ne connaît pas * Actions émises (data-act) : rail, palette, domaine (data-dom), * alertes, spark, menu, rappel-entete. L'app intégratrice décide de * chacune (ouvrir la palette, le panneau Spark, changer de domaine…). * Action INTERNE (jamais relayée) : apps — la marque ✦ ouvre le menu * des applications, construit depuis les onglets ; c'est le moyen de * changer d'app en mobile, où les onglets sont repliés (v0.1.2). */ (function () { "use strict"; var cfg = window.DRACO_BAR_CONFIG || {}; function setCounts(counts) { Object.keys(counts || {}).forEach(function (k) { /* Toutes les occurrences : l'onglet ET sa ligne dans le menu. */ document.querySelectorAll('.draco-badge[data-badge="' + k + '"]').forEach(function (b) { b.textContent = counts[k]; b.hidden = !(counts[k] > 0); }); }); } function setCurrent(app) { document.querySelectorAll(".draco-apptab, .draco-apps-item").forEach(function (t) { if (t.dataset.app) t.dataset.active = t.dataset.app === app ? "true" : "false"; }); } function setDomain(dom) { document.querySelectorAll('.draco-domaines [data-dom]').forEach(function (b) { b.dataset.on = b.dataset.dom === dom ? "true" : "false"; }); } /* ── Menu des applications (v0.1.3) ────────────────────────────── * Construit depuis les onglets présents dans la barre : mêmes * liens, mêmes icônes, mêmes badges. Ouvert par la marque ✦ * (data-act="apps"), fermé par un clic extérieur, Échap, ou le * choix d'une application (la navigation suit son cours). */ var bar = document.querySelector(".draco-bar"); var brand = bar ? bar.querySelector(".draco-brand") : null; var menu = null; function buildMenu() { if (!bar || !brand || menu) return; menu = document.createElement("div"); menu.className = "draco-apps-menu"; menu.hidden = true; menu.setAttribute("role", "menu"); menu.setAttribute("aria-label", "Applications"); document.querySelectorAll(".draco-apptab").forEach(function (t) { var a = document.createElement("a"); a.className = "draco-apps-item"; a.href = t.getAttribute("href"); a.dataset.app = t.dataset.app; a.setAttribute("role", "menuitem"); var ico = t.querySelector(".draco-apptab-ico"); if (ico) a.appendChild(ico.cloneNode(true)); var txt = document.createElement("span"); txt.className = "draco-apps-item-txt"; var fort = t.querySelector(".draco-apptab-txt strong"); var petit = t.querySelector(".draco-apptab-txt small"); var nom = document.createElement("span"); nom.className = "draco-apps-item-nom"; nom.textContent = fort ? fort.textContent : t.dataset.app; txt.appendChild(nom); if (petit) { var role = document.createElement("span"); role.className = "draco-apps-item-role"; role.textContent = petit.textContent; txt.appendChild(role); } a.appendChild(txt); var badge = t.querySelector(".draco-badge"); if (badge) a.appendChild(badge.cloneNode(true)); menu.appendChild(a); }); bar.appendChild(menu); } function toggleMenu(force) { buildMenu(); if (!menu) return; var open = typeof force === "boolean" ? force : menu.hidden; menu.hidden = !open; if (brand) brand.setAttribute("aria-expanded", open ? "true" : "false"); } document.addEventListener("click", function (ev) { var el = ev.target.closest("[data-act]"); if (el && el.dataset.act === "apps") { ev.preventDefault(); toggleMenu(); return; } if (menu && !menu.hidden && !ev.target.closest(".draco-apps-menu") && !ev.target.closest(".draco-brand")) { toggleMenu(false); } if (!el) return; var act = el.dataset.act; if (act === "domaine") setDomain(el.dataset.dom); if (typeof cfg.onAction === "function") cfg.onAction(act, el, ev); else document.dispatchEvent(new CustomEvent("draco:bar", { detail: { act: act, el: el } })); }); document.addEventListener("keydown", function (ev) { if (ev.key === "Escape") toggleMenu(false); }); /* API publique : l'app met les compteurs à jour sans recharger. */ window.DRACO_BAR = { setCounts: setCounts, setCurrent: setCurrent, setDomain: setDomain }; buildMenu(); if (cfg.current) setCurrent(cfg.current); if (cfg.domain) setDomain(cfg.domain); if (cfg.counts) setCounts(cfg.counts); })();