/* Section « Liens » des notes — Fusion #215 (ACC-1.2 + ACC-1.3). * * Module autonome (vanilla, zéro dépendance, zéro build) : il écoute * l'événement « obsigate:file-rendered » émis par renderFile * (frontend/app.js) et rend sa section à la fin de #content-area : * * - ACC-1.2 : si la note est une projection TikTak (frontmatter * « tiktak_id » écrit par la synchro TikTak ↔ ObsiGate), un bandeau * « Tâche TikTak projetée » avec le bouton « Ouvrir dans TikTak » * (lien profond https://tiktak.dracodev.net/?task=) ; * - ACC-1.3 : les références croisées de la note (GET /api/refs), * ajout par collage d'une URL profonde, retrait en un clic. * * Textes via window.t (i18n FR/EN — clés « draco.links.* » des locales). */ (function () { "use strict"; var COLORS = { obsigate: "#7a5af5", flowdeck: "#2f6fed", tiktak: "#e8762c", kanbante: "#0d9488", }; function t(key, fallback) { try { var v = window.t && window.t(key); return v && v !== key ? v : fallback; } catch (e) { return fallback; } } function authHeaders() { var tok = null; try { tok = sessionStorage.getItem("obsigate_access_token"); } catch (e) { /* stockage indisponible */ } return tok ? { Authorization: "Bearer " + tok } : {}; } async function api(path, opts) { var options = opts || {}; options.headers = Object.assign( { "Content-Type": "application/json" }, authHeaders(), options.headers || {} ); options.credentials = "same-origin"; var resp = await fetch(path, options); if (!resp.ok) { var detail = ""; try { detail = (await resp.json()).detail || ""; } catch (e) { /* corps non JSON */ } throw new Error(detail || "HTTP " + resp.status); } return resp.json(); } function el(tag, cls, text) { var node = document.createElement(tag); if (cls) node.className = cls; if (text !== undefined) node.textContent = text; return node; } async function render(vault, path) { var area = document.getElementById("content-area"); if (!area || !vault || !path) return; var old = document.getElementById("draco-liens"); if (old) old.remove(); var section = el("section", "draco-liens"); section.id = "draco-liens"; var title = el("h3", "draco-liens-title", t("draco.links.title", "Liens")); section.appendChild(title); area.appendChild(section); // ACC-1.2 — note projetée depuis TikTak ? if (/\.md$/i.test(path)) { try { var rawUrl = "/api/file/" + encodeURIComponent(vault) + "/raw?path=" + encodeURIComponent(path); var rawData = await api(rawUrl); var m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(rawData.raw || ""); var tid = m && /^tiktak_id:\s*(\d+)\s*$/m.exec(m[1]); if (tid) { var bandeau = el("div", "draco-liens-projete"); bandeau.appendChild(el("span", "draco-liens-badge", t("draco.links.projected", "Tâche TikTak projetée"))); var ouvrir = el("a", "btn-action draco-liens-ouvrir", t("draco.links.openInTikTak", "Ouvrir dans TikTak")); ouvrir.href = "https://tiktak.dracodev.net/?task=" + tid[1]; ouvrir.target = "_blank"; ouvrir.rel = "noopener"; bandeau.appendChild(ouvrir); section.appendChild(bandeau); } } catch (e) { /* la détection est opportuniste : silence */ } } // ACC-1.3 — références croisées de la note var list = el("ul", "draco-liens-list"); section.appendChild(list); var erreur = el("p", "draco-liens-erreur"); erreur.hidden = true; section.appendChild(erreur); async function refresh() { list.innerHTML = ""; try { var data = await api("/api/refs?vault=" + encodeURIComponent(vault) + "&path=" + encodeURIComponent(path)); (data.refs || []).forEach(function (r) { var li = el("li", "draco-liens-item"); var dot = el("span", "draco-ref-dot"); dot.style.background = COLORS[r.target_app] || "#888"; li.appendChild(dot); var a = el("a", "", r.label); a.href = r.target_url; a.target = "_blank"; a.rel = "noopener"; li.appendChild(a); var del = el("button", "draco-liens-del", "✕"); del.type = "button"; del.title = t("draco.links.remove", "Retirer le lien"); del.addEventListener("click", async function () { try { await api("/api/refs/" + encodeURIComponent(r.id), { method: "DELETE" }); refresh(); } catch (e) { erreur.textContent = e.message; erreur.hidden = false; } }); li.appendChild(del); list.appendChild(li); }); } catch (e) { /* section facultative : ne jamais casser la note */ } } var form = el("form", "draco-liens-form"); var urlInput = el("input"); urlInput.type = "url"; urlInput.required = true; urlInput.placeholder = t("draco.links.urlPlaceholder", "Coller une URL profonde (Flowdeck, TikTak, Gitea, ObsiGate)…"); var labelInput = el("input"); labelInput.type = "text"; labelInput.placeholder = t("draco.links.labelPlaceholder", "Libellé (optionnel)"); var submit = el("button", "btn-action", t("draco.links.add", "Lier")); submit.type = "submit"; form.appendChild(urlInput); form.appendChild(labelInput); form.appendChild(submit); form.addEventListener("submit", async function (ev) { ev.preventDefault(); erreur.hidden = true; try { await api("/api/refs", { method: "POST", body: JSON.stringify({ vault: vault, path: path, url: urlInput.value.trim(), label: labelInput.value.trim() || null, }), }); urlInput.value = ""; labelInput.value = ""; refresh(); } catch (e) { erreur.textContent = e.message; erreur.hidden = false; } }); section.appendChild(form); refresh(); } document.addEventListener("obsigate:file-rendered", function (ev) { if (ev.detail) render(ev.detail.vault, ev.detail.path); }); })();