text-viewer.js (3120B)
1 let originalText = ''; 2 3 async function loadTextFile() { 4 const viewer = document.getElementById("text-viewer"); 5 const filename = viewer.dataset.filename; 6 const response = await fetch(`/uploads/${filename}`); 7 const text = await response.text(); 8 originalText = text; 9 viewer.textContent = text; 10 } 11 12 function toggleLineNumbers() { 13 const viewer = document.getElementById("text-viewer"); 14 if (viewer.classList.contains("with-lines")) { 15 viewer.classList.remove("with-lines"); 16 viewer.textContent = originalText; // Use stored original text 17 } else { 18 const lines = originalText.split("\n"); // Use stored original text 19 viewer.innerHTML = lines.map((line, i) => 20 `<span style="display:block;"><span style="color:#888; user-select:none; width:3em; display:inline-block;">${i+1}</span> ${escapeHtml(line)}</span>` 21 ).join(""); 22 viewer.classList.add("with-lines"); 23 } 24 } 25 26 function toggleFullscreen() { 27 const container = document.getElementById("text-viewer-container"); 28 if (!document.fullscreenElement) { 29 container.requestFullscreen(); 30 } else { 31 document.exitFullscreen(); 32 } 33 } 34 35 function parseLineNumber(str) { 36 // Match [l123] or [L123] 37 const match = str.match(/^[lL](\d+)$/); 38 return match ? Number(match[1]) : null; 39 } 40 41 function makeLineNumbersClickable(containerId, viewerId) { 42 const container = document.getElementById(containerId); 43 const viewer = document.getElementById(viewerId); 44 45 // Regex: [l123] or [L123] 46 const regex = /\[([lL]\d+)\]/g; 47 48 container.innerHTML = container.innerHTML.replace(regex, (match, lineRef) => { 49 const lineNum = parseLineNumber(lineRef); 50 return `<a href="#" class="line-link" data-line="${lineNum}">${match}</a>`; 51 }); 52 53 if (container.dataset.lineClickBound) return; 54 container.dataset.lineClickBound = 'true'; 55 56 container.addEventListener("click", e => { 57 if (e.target.classList.contains("line-link")) { 58 e.preventDefault(); 59 const lineNum = Number(e.target.dataset.line); 60 scrollToLine(lineNum); 61 } 62 }); 63 } 64 65 function scrollToLine(lineNum) { 66 const viewer = document.getElementById("text-viewer"); 67 68 // If line numbers are visible, find the specific line span 69 if (viewer.classList.contains("with-lines")) { 70 const lines = viewer.querySelectorAll("span[style*='display:block']"); 71 if (lines[lineNum - 1]) { 72 lines[lineNum - 1].scrollIntoView({ behavior: "smooth", block: "center" }); 73 // Optional: highlight the line briefly 74 lines[lineNum - 1].style.background = "#ff06"; 75 setTimeout(() => lines[lineNum - 1].style.background = "", 2000); 76 } 77 } else { 78 // If no line numbers shown, calculate approximate position 79 const lines = originalText.split("\n"); 80 const totalLines = lines.length; 81 const percentage = (lineNum - 1) / totalLines; 82 viewer.scrollTop = viewer.scrollHeight * percentage; 83 } 84 } 85 86 // Run it after the page loads 87 document.addEventListener("DOMContentLoaded", () => { 88 // Replace "description-container" with the ID of your description element 89 makeLineNumbersClickable("current-description", "text-viewer"); 90 }); 91 92 loadTextFile();