Excerpts

A Weave of Lies

Chapters 1 to 4


Page - of -
Loading PDF...
// PDF.js worker setup pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js" class PDFViewer { constructor(url) { this.url = url this.pdfDoc = null this.currentPage = 1 this.totalPages = 0 this.scale = 1 this.container = document.getElementById("pdfViewer") this.loading = document.getElementById("loading") this.initializeControls() this.loadPDF() } initializeControls() { const prevBtn = document.getElementById("prevBtn") const nextBtn = document.getElementById("nextBtn") const zoomSelect = document.getElementById("zoomSelect") prevBtn.addEventListener("click", () => this.previousPage()) nextBtn.addEventListener("click", () => this.nextPage()) zoomSelect.addEventListener("change", (e) => this.changeZoom(e.target.value), ) // Keyboard navigation document.addEventListener("keydown", (e) => { if (e.key === "ArrowLeft" || e.key === "ArrowUp") { this.previousPage() } else if (e.key === "ArrowRight" || e.key === "ArrowDown") { this.nextPage() } }) } async loadPDF() { try { // First try direct loading await this.tryDirectLoad() } catch (error) { console.error("Direct load failed:", error) // Try multiple CORS proxy services await this.tryWithMultipleProxies() } } async tryDirectLoad() { const loadingTask = pdfjsLib.getDocument({ url: this.url, withCredentials: false, disableRange: true, disableStream: true, }) this.pdfDoc = await loadingTask.promise this.totalPages = this.pdfDoc.numPages this.updatePageInfo() this.updateControls() await this.renderAllPages() this.loading.style.display = "none" } async tryWithMultipleProxies() { // Try a more reliable CORS proxy service first const proxies = [ // Using a more reliable proxy service `https://api.codetabs.com/v1/proxy?quest=${encodeURIComponent(this.url)}`, // Backup proxies `https://cors-proxy.htmldriven.com/?url=${encodeURIComponent(this.url)}`, ] for (let i = 0; i < proxies.length; i++) { try { console.log( `Trying proxy ${i + 1}/${proxies.length}: ${proxies[i].split("?")[0]}...`, ) // Set a timeout for the fetch request const controller = new AbortController() const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout const response = await fetch(proxies[i], { signal: controller.signal, method: "GET", headers: { Accept: "application/pdf,*/*", }, }) clearTimeout(timeoutId) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } const pdfBlob = await response.blob() // Verify it's actually a PDF if (pdfBlob.type && !pdfBlob.type.includes("pdf")) { throw new Error(`Received ${pdfBlob.type} instead of PDF`) } const pdfArrayBuffer = await pdfBlob.arrayBuffer() const loadingTask = pdfjsLib.getDocument({ data: pdfArrayBuffer, disableRange: true, disableStream: true, }) this.pdfDoc = await loadingTask.promise this.totalPages = this.pdfDoc.numPages this.updatePageInfo() this.updateControls() await this.renderAllPages() this.loading.style.display = "none" console.log(`Successfully loaded PDF using proxy ${i + 1}`) return // Success - exit the function } catch (proxyError) { console.error(`Proxy ${i + 1} failed:`, proxyError.message) // If this was the last proxy, try iframe fallback if (i === proxies.length - 1) { this.tryIframeEmbedding() } } } } tryIframeEmbedding() { console.log("Attempting iframe embedding as final fallback...") // Create iframe container this.container.innerHTML = `

Open PDF in new tab

` this.loading.style.display = "none" // Hide the PDF controls since iframe doesn't need them document.querySelector(".pdf-controls").style.display = "none" // Set up a timeout to check if iframe loaded setTimeout(() => { const iframe = this.container.querySelector("iframe") try { // Try to access iframe content (will fail if blocked by X-Frame-Options) if (iframe.contentWindow) { console.log("Iframe embedding appears to be working") } } catch (e) { console.warn("PDF server may be blocking iframe embedding") this.showFinalError() } }, 3000) } showFinalError() { this.container.innerHTML = `

🚫 Unable to Load External PDF

The PDF cannot be loaded due to CORS restrictions and server policies.
This is a security limitation imposed by the PDF hosting server.

✅ Working Solutions:

  1. Download and host locally: Save the PDF to your server
  2. Server-side proxy: Create a backend endpoint to fetch the PDF
  3. Use PDF.js Express: Commercial solution with better CORS handling
  4. Google Docs Viewer: Use iframe with Google's viewer

PDF URL: ${this.url}

` } async renderAllPages() { this.container.innerHTML = "" for (let pageNum = 1; pageNum <= this.totalPages; pageNum++) { const pageContainer = document.createElement("div") pageContainer.className = "page-container" pageContainer.id = `page-${pageNum}` const canvas = document.createElement("canvas") canvas.className = "pdf-page" pageContainer.appendChild(canvas) this.container.appendChild(pageContainer) await this.renderPage(pageNum, canvas) } } async renderPage(pageNum, canvas) { try { const page = await this.pdfDoc.getPage(pageNum) const viewport = page.getViewport({ scale: this.scale }) canvas.height = viewport.height canvas.width = viewport.width const renderContext = { canvasContext: canvas.getContext("2d"), viewport: viewport, } await page.render(renderContext).promise } catch (error) { console.error(`Error rendering page ${pageNum}:`, error) } } changeZoom(zoomValue) { if (zoomValue === "fit") { const containerWidth = this.container.clientWidth - 40 // Account for padding this.scale = containerWidth / 612 // 612 is typical PDF page width } else { this.scale = parseFloat(zoomValue) } this.renderAllPages() } previousPage() { if (this.currentPage > 1) { this.currentPage-- this.scrollToPage(this.currentPage) this.updatePageInfo() this.updateControls() } } nextPage() { if (this.currentPage < this.totalPages) { this.currentPage++ this.scrollToPage(this.currentPage) this.updatePageInfo() this.updateControls() } } scrollToPage(pageNum) { const pageElement = document.getElementById(`page-${pageNum}`) if (pageElement) { pageElement.scrollIntoView({ behavior: "smooth", block: "start" }) } } updatePageInfo() { document.getElementById("currentPage").textContent = this.currentPage document.getElementById("totalPages").textContent = this.totalPages } updateControls() { document.getElementById("prevBtn").disabled = this.currentPage <= 1 document.getElementById("nextBtn").disabled = this.currentPage >= this.totalPages } showError(message) { this.container.innerHTML = `
${message}
` this.loading.style.display = "none" } } // Initialize the PDF viewer const pdfUrl = "https://drive.google.com/file/d/1LQRCut7tS8GmU4kOxeaD66l4FaGTtB5R/preview" // "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" new PDFViewer(pdfUrl) // Update current page based on scroll position document.getElementById("pdfViewer").addEventListener("scroll", () => { const viewer = document.getElementById("pdfViewer") const pages = document.querySelectorAll(".page-container") pages.forEach((page, index) => { const rect = page.getBoundingClientRect() const viewerRect = viewer.getBoundingClientRect() if ( rect.top <= viewerRect.top + 100 && rect.bottom >= viewerRect.top + 100 ) { const newPage = index + 1 if (newPage !== window.pdfViewerInstance?.currentPage) { document.getElementById("currentPage").textContent = newPage document.getElementById("prevBtn").disabled = newPage <= 1 document.getElementById("nextBtn").disabled = newPage >= parseInt(document.getElementById("totalPages").textContent) } } }) })