document.addEventListener("DOMContentLoaded", function () { // Check URL parameters for custom views const urlParams = new URLSearchParams(window.location.search); const searchTagsRaw = urlParams.get("searchtags") || urlParams.get("searchTags") || ""; // Also check URL path for tag format (e.g., /tag/note) const urlPath = window.location.pathname; const pathMatch = urlPath.match(/\/tag\/(.+)$/); const pathTagRaw = pathMatch ? decodeURIComponent(pathMatch[1]) : ""; // Parse all active tags to safely detect the view const activeTags = (searchTagsRaw + " " + pathTagRaw).toLowerCase().split(/[\s,]+/).filter(t => t); // Foolproof detection using sidebar active state and DOM rendered tags const hasNoteActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Notes"].active, .header-nav-link[aria-label="Notes"].active, .sidebar-link[href*="searchtags=note"].active, .sidebar-link[href*="searchtags=shaarli-note"].active'); const hasTodoActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Mes tâches"].active, .header-nav-link[aria-label="Mes tâches"].active, .sidebar-link[href*="searchtags=shaarli-todo"].active'); const hasArchiveActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Archive"].active, .header-nav-link[aria-label="Archive"].active, .sidebar-link[href*="searchtags=shaarli-archive"].active'); const domChipTags = Array.from(document.querySelectorAll('.search-tag-chip')).map(el => (el.textContent || "").trim().toLowerCase()); const isNoteView = activeTags.includes("note") || activeTags.includes("shaarli-note") || hasNoteActiveMenu || domChipTags.includes("note") || domChipTags.includes("shaarli-note"); const isTodoView = activeTags.includes("shaarli-todo") || hasTodoActiveMenu || domChipTags.includes("shaarli-todo"); const isArchiveView = activeTags.includes("shaarli-archive") || hasArchiveActiveMenu || domChipTags.includes("shaarli-archive"); const linkList = document.getElementById("links-list"); const container = document.querySelector(".content-container"); const showErrorBanner = (msg, err) => { const banner = document.createElement("div"); banner.style.cssText = "background: #ffebee; color: #c62828; padding: 16px; margin: 16px; border-radius: 8px; border: 1px solid #ef9a9a; z-index: 9999; position: relative;"; banner.innerHTML = `Erreur Custom Views: ${msg}
${err ? err.stack || err : ''}
`; if (container) container.prepend(banner); else document.body.prepend(banner); }; const restoreDefaultListView = () => { try { document.body.classList.remove("view-todo", "view-notes", "view-archive"); } catch (e) { // noop } const toolbar = document.querySelector(".content-toolbar"); if (toolbar) toolbar.style.display = ""; const list = document.getElementById("links-list"); if (list) list.style.display = ""; document.querySelectorAll(".notes-wrapper.todo-wrapper").forEach((el) => el.remove()); }; // Rendu Markdown étendu pour les cartes Notes/Tâches function renderMarkdown(markdown) { if (!markdown) return ""; const normalizeNewlines = String(markdown).replace(/\r\n?/g, "\n"); const escape = (value) => String(value) .replace(/&/g, "&") .replace(//g, ">"); const escapeAttr = (value) => String(value) .replace(/&/g, "&") .replace(/"/g, """) .replace(//g, ">"); const sanitizeUrl = (rawUrl) => { const url = String(rawUrl || "").trim(); if (!url) return ""; if (/^(https?:|mailto:|\/)/i.test(url)) return url; return ""; }; const renderInline = (input) => { let out = escape(input || ""); const codeTokens = []; out = out.replace(/`([^`\n]+)`/g, (_, code) => { const token = `__MD_CODE_${codeTokens.length}__`; codeTokens.push(`${code}`); return token; }); out = out.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt, rawUrl) => { const url = sanitizeUrl(rawUrl); if (!url) return _; return `${escapeAttr(alt)}`; }); out = out.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, rawUrl) => { const url = sanitizeUrl(rawUrl); if (!url) return _; return `${label}`; }); out = out.replace(/\*\*(.+?)\*\*/g, "$1"); out = out.replace(/__(.+?)__/g, "$1"); out = out.replace(/~~(.+?)~~/g, "$1"); out = out.replace(/\*(.+?)\*/g, "$1"); out = out.replace(/_(.+?)_/g, "$1"); out = out.replace(/<u>([\s\S]*?)<\/u>/g, "$1"); out = out.replace(/__MD_CODE_(\d+)__/g, (_, idx) => codeTokens[Number(idx)] || ""); return out; }; const lines = normalizeNewlines.split("\n"); const html = []; let inUl = false; let inOl = false; let inTodo = false; let inCode = false; let codeLang = ""; let codeLines = []; const closeLists = () => { if (inUl) { html.push(""); inUl = false; } if (inOl) { html.push(""); inOl = false; } if (inTodo) { html.push(""); inTodo = false; } }; lines.forEach((line) => { const trimmed = line.trim(); const codeFenceMatch = trimmed.match(/^```\s*([\w-]+)?\s*$/); if (codeFenceMatch) { closeLists(); if (!inCode) { inCode = true; codeLang = codeFenceMatch[1] || ""; codeLines = []; } else { const langAttr = codeLang ? ` data-lang="${escapeAttr(codeLang)}"` : ""; html.push(`
${escape(codeLines.join("\n"))}
`); inCode = false; codeLang = ""; codeLines = []; } return; } if (inCode) { codeLines.push(line); return; } if (!trimmed) { closeLists(); html.push('
'); return; } const headingMatch = line.match(/^\s*(#{1,6})\s+(.+)$/); if (headingMatch) { closeLists(); const level = headingMatch[1].length; html.push(`${renderInline(headingMatch[2])}`); return; } const quoteMatch = line.match(/^\s*>\s?(.*)$/); if (quoteMatch) { closeLists(); html.push(`
${renderInline(quoteMatch[1])}
`); return; } const todoMatch = line.match(/^\s*[-*]\s+\[( |x|X)\]\s+(.+)$/); if (todoMatch) { if (inUl) { html.push(""); inUl = false; } if (inOl) { html.push(""); inOl = false; } if (!inTodo) { html.push('"); inUl = false; } if (inTodo) { html.push(""); inTodo = false; } if (!inOl) { html.push("
    "); inOl = true; } html.push(`
  1. ${renderInline(olMatch[1])}
  2. `); return; } const ulMatch = line.match(/^\s*[-*+]\s+(.+)$/); if (ulMatch) { if (inOl) { html.push("
"); inOl = false; } if (inTodo) { html.push(""); inTodo = false; } if (!inUl) { html.push("