text-viewer.js (3152B)
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 escapeHtml(text) { 27 const div = document.createElement('div'); 28 div.textContent = text; 29 return div.innerHTML; 30 } 31 32 function toggleFullscreen() { 33 const container = document.getElementById("text-viewer-container"); 34 if (!document.fullscreenElement) { 35 container.requestFullscreen(); 36 } else { 37 document.exitFullscreen(); 38 } 39 } 40 41 function parseLineNumber(str) { 42 // Match [l123] or [L123] 43 const match = str.match(/^[lL](\d+)$/); 44 return match ? Number(match[1]) : null; 45 } 46 47 function makeLineNumbersClickable(containerId, viewerId) { 48 const container = document.getElementById(containerId); 49 const viewer = document.getElementById(viewerId); 50 51 // Regex: [l123] or [L123] 52 const regex = /\[([lL]\d+)\]/g; 53 54 container.innerHTML = container.innerHTML.replace(regex, (match, lineRef) => { 55 const lineNum = parseLineNumber(lineRef); 56 return `<a href="#" class="line-link" data-line="${lineNum}">${match}</a>`; 57 }); 58 59 container.addEventListener("click", e => { 60 if (e.target.classList.contains("line-link")) { 61 e.preventDefault(); 62 const lineNum = Number(e.target.dataset.line); 63 scrollToLine(lineNum); 64 } 65 }); 66 } 67 68 function scrollToLine(lineNum) { 69 const viewer = document.getElementById("text-viewer"); 70 71 // If line numbers are visible, find the specific line span 72 if (viewer.classList.contains("with-lines")) { 73 const lines = viewer.querySelectorAll("span[style*='display:block']"); 74 if (lines[lineNum - 1]) { 75 lines[lineNum - 1].scrollIntoView({ behavior: "smooth", block: "center" }); 76 // Optional: highlight the line briefly 77 lines[lineNum - 1].style.background = "#ff06"; 78 setTimeout(() => lines[lineNum - 1].style.background = "", 2000); 79 } 80 } else { 81 // If no line numbers shown, calculate approximate position 82 const lines = originalText.split("\n"); 83 const totalLines = lines.length; 84 const percentage = (lineNum - 1) / totalLines; 85 viewer.scrollTop = viewer.scrollHeight * percentage; 86 } 87 } 88 89 // Run it after the page loads 90 document.addEventListener("DOMContentLoaded", () => { 91 // Replace "description-container" with the ID of your description element 92 makeLineNumbersClickable("current-description", "text-viewer"); 93 }); 94 95 loadTextFile();