diff --git a/frontend/js/viewer.js b/frontend/js/viewer.js index 197334e..2aef5ca 100644 --- a/frontend/js/viewer.js +++ b/frontend/js/viewer.js @@ -652,21 +652,33 @@ export function renderFile(data) { }); // Action buttons + // Cache local au rendu courant: state.cachedRawSource global est fiable + // uniquement quand openFile() initialise le fichier (il le réinitialise). + // Or le contenu d'un onglet peut être rendu via renderFile() direct sans + // passer par openFile() — un cache partagé transporterait le contenu du + // fichier précédent (bug pretty print sur fichiers successifs). + let localRaw = null; + const getRaw = async () => { + if (localRaw != null) return localRaw; + if (state.currentVault === data.vault && state.currentPath === data.path && state.cachedRawSource) { + localRaw = state.cachedRawSource; + return localRaw; + } + const rawUrl = `/api/file/${encodeURIComponent(data.vault)}/raw?path=${encodeURIComponent(data.path)}`; + const rawData = await api(rawUrl); + localRaw = rawData.raw; + return localRaw; + }; const copyBtn = el("button", { class: "btn-action", title: "Copier la source" }, [icon("copy", 14), document.createTextNode("Copier")]); copyBtn.addEventListener("click", async () => { try { - // Fetch raw content if not already cached - if (!state.cachedRawSource) { - const rawUrl = `/api/file/${encodeURIComponent(data.vault)}/raw?path=${encodeURIComponent(data.path)}`; - const rawData = await api(rawUrl); - state.cachedRawSource = rawData.raw; - } + const rawSrc = await getRaw(); if (navigator.clipboard) { - await navigator.clipboard.writeText(state.cachedRawSource); + await navigator.clipboard.writeText(rawSrc); } else { // Fallback for non-secure contexts const ta = document.createElement("textarea"); - ta.value = state.cachedRawSource; + ta.value = rawSrc; ta.style.position = "fixed"; ta.style.opacity = "0"; document.body.appendChild(ta); ta.select(); document.execCommand("copy"); @@ -832,12 +844,7 @@ export function renderFile(data) { state.showingSource = !state.showingSource; if (state.showingSource) { sourceBtn.classList.add("active"); - if (!state.cachedRawSource) { - const rawUrl = `/api/file/${encodeURIComponent(data.vault)}/raw?path=${encodeURIComponent(data.path)}`; - const rawData = await api(rawUrl); - state.cachedRawSource = rawData.raw; - } - raw.textContent = state.cachedRawSource; + raw.textContent = await getRaw(); rendered.style.display = "none"; raw.style.display = "block"; } else { @@ -856,18 +863,15 @@ export function renderFile(data) { prettyBtn.addEventListener("click", async () => { const on = !prettyBtn.classList.contains("active"); if (on) { + let rawText = ""; try { - if (!state.cachedRawSource) { - const rawUrl = `/api/file/${encodeURIComponent(data.vault)}/raw?path=${encodeURIComponent(data.path)}`; - const rawData = await api(rawUrl); - state.cachedRawSource = rawData.raw; - } + rawText = await getRaw(); } catch (_) { - state.cachedRawSource = mdDiv.textContent || ""; + rawText = mdDiv.textContent || ""; } - mdDiv.innerHTML = buildPrettyHtml(data, state.cachedRawSource); + mdDiv.innerHTML = buildPrettyHtml(data, rawText); const codeEl = mdDiv.querySelector("code"); - applyPrettyHighlight(codeEl, detectPrettyLang(data), state.cachedRawSource); + applyPrettyHighlight(codeEl, detectPrettyLang(data), rawText); prettyBtn.classList.add("active"); } else { mdDiv.innerHTML = data.html;