Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <div class="pdf-container">
- <div class="pdf-controls" id="pdfControls2">
- <div class="control-group">
- <button id="prevBtn2">Previous</button>
- <span class="page-info">
- Page <span id="currentPage2">-</span> of <span id="totalPages2">-</span>
- </span>
- <button id="nextBtn2">Next</button>
- </div>
- <div class="zoom-controls">
- <label for="zoomSelect2" style="font-size: 14px">Zoom:</label>
- <select id="zoomSelect2" class="zoom-select">
- <option value="0.5">50%</option>
- <option value="0.75">75%</option>
- <option value="1" selected>100%</option>
- <option value="1.25">125%</option>
- <option value="1.5">150%</option>
- <option value="2">200%</option>
- <option value="fit">Fit Width</option>
- </select>
- </div>
- </div>
- <div class="pdf-viewer" id="pdfViewer2">
- <div class="loading" id="loading2">Loading PDF...</div>
- </div>
- </div>
- <script>
- // PDF.js worker setup
- pdfjsLib.GlobalWorkerOptions.workerSrc =
- "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";
- class PDFViewer2 {
- constructor(url) {
- this.url = url;
- this.pdfDoc = null;
- this.currentPage = 1;
- this.totalPages = 0;
- this.scale = 1;
- this.container = document.getElementById("pdfViewer2");
- this.loading = document.getElementById("loading2");
- this.prevBtn = document.getElementById("prevBtn2");
- this.nextBtn = document.getElementById("nextBtn2");
- this.zoomSelect = document.getElementById("zoomSelect2");
- this.pdfControls = document.getElementById("pdfControls2");
- this.initializeControls();
- this.loadPDF();
- }
- initializeControls() {
- this.prevBtn.addEventListener("click", () => this.previousPage());
- this.nextBtn.addEventListener("click", () => this.nextPage());
- this.zoomSelect.addEventListener("change", (e) =>
- this.changeZoom(e.target.value)
- );
- // Keyboard navigation scoped only when controls are focused
- this.pdfControls.addEventListener("keydown", (e) => {
- if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
- this.previousPage();
- e.preventDefault();
- } else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
- this.nextPage();
- e.preventDefault();
- }
- });
- // Make pdfControls focusable for keyboard events
- this.pdfControls.tabIndex = 0;
- }
- async loadPDF() {
- try {
- await this.tryDirectLoad();
- } catch (error) {
- console.error("Direct load failed:", error);
- 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() {
- const proxies = [
- `https://api.codetabs.com/v1/proxy?quest=${encodeURIComponent(this.url)}`,
- `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]}...`
- );
- const controller = new AbortController();
- const timeoutId = setTimeout(() => controller.abort(), 10000);
- 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();
- 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;
- } catch (proxyError) {
- console.error(`Proxy ${i + 1} failed:`, proxyError.message);
- if (i === proxies.length - 1) {
- this.tryIframeEmbedding();
- }
- }
- }
- }
- tryIframeEmbedding() {
- console.log("Attempting iframe embedding as final fallback...");
- this.container.innerHTML = `
- <div style="text-align: center; padding: 20px; background: #f9f9f9; margin: 20px; border-radius: 4px;">
- <p style="margin-bottom: 15px; color: #666;">
- <iframe
- src="${this.url}"
- width="100%"
- height="1000px"
- style="border: 1px solid #ccc; border-radius: 4px;"
- onload="console.log('PDF iframe loaded successfully')"
- onerror="console.error('PDF iframe failed to load')">
- <p>Your browser does not support iframes.
- <a href="${this.url}" target="_blank" style="color: #007bff;">Click here to view the PDF in a new tab</a>
- </p>
- </iframe>
- <p style="margin-top: 15px; font-size: 14px; color: #666;">
- <a href="${this.url}" target="_blank" style="color: #007bff; text-decoration: none;">
- Open PDF in new tab
- </a>
- </p>
- </div>
- `;
- this.loading.style.display = "none";
- this.pdfControls.style.display = "none";
- setTimeout(() => {
- const iframe = this.container.querySelector("iframe");
- try {
- 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 = `
- <div style="text-align: center; padding: 30px; background: #fff3cd; margin: 20px; border-radius: 4px; border: 1px solid #ffeaa7;">
- <h3 style="color: #856404; margin-bottom: 20px;">🚫 Unable to Load External PDF</h3>
- <p style="color: #856404; margin-bottom: 15px; line-height: 1.6;">
- The PDF cannot be loaded due to CORS restrictions and server policies.<br>
- This is a security limitation imposed by the PDF hosting server.
- </p>
- <div style="background: white; padding: 20px; border-radius: 4px; margin: 20px 0; text-align: left;">
- <h4 style="color: #495057; margin-bottom: 15px;">✅ Working Solutions:</h4>
- <ol style="color: #495057; line-height: 1.8; padding-left: 20px;">
- <li><strong>Download and host locally:</strong> Save the PDF to your server</li>
- <li><strong>Server-side proxy:</strong> Create a backend endpoint to fetch the PDF</li>
- <li><strong>Use PDF.js Express:</strong> Commercial solution with better CORS handling</li>
- <li><strong>Google Docs Viewer:</strong> Use iframe with Google's viewer</li>
- </ol>
- </div>
- <div style="margin-top: 20px;">
- <a href="${this.url}" target="_blank"
- style="display: inline-block; padding: 12px 24px; background: #007bff; color: white;
- text-decoration: none; border-radius: 4px; font-weight: 500;">
- Open PDF in new tab
- </a>
- </div>
- <p style="margin-top: 20px; font-size: 12px; color: #6c757d;">
- PDF URL: ${this.url}
- </p>
- </div>
- `;
- }
- async renderAllPages() {
- this.container.innerHTML = "";
- for (let pageNum = 1; pageNum <= this.totalPages; pageNum++) {
- const pageContainer = document.createElement("div");
- pageContainer.className = "page-container";
- pageContainer.id = `page2-${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;
- this.scale = containerWidth / 612;
- } 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(`page2-${pageNum}`);
- if (pageElement) {
- pageElement.scrollIntoView({ behavior: "smooth", block: "start" });
- }
- }
- updatePageInfo() {
- document.getElementById("currentPage2").textContent = this.currentPage;
- document.getElementById("totalPages2").textContent = this.totalPages;
- }
- updateControls() {
- this.prevBtn.disabled = this.currentPage <= 1;
- this.nextBtn.disabled = this.currentPage >= this.totalPages;
- }
- showError(message) {
- this.container.innerHTML = `<div class="error">${message}</div>`;
- this.loading.style.display = "none";
- }
- }
- // Example instantiation for second PDF viewer - change the URL to your second PDF
- const pdfUrl2 = "https://example.com/your-second-pdf.pdf";
- const pdfViewer2Instance = new PDFViewer2(pdfUrl2);
- // Update current page based on scroll position for second viewer
- document.getElementById("pdfViewer2").addEventListener("scroll", () => {
- const viewer = document.getElementById("pdfViewer2");
- 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 !== pdfViewer2Instance.currentPage) {
- document.getElementById("currentPage2").textContent = newPage;
- document.getElementById("prevBtn2").disabled = newPage <= 1;
- document.getElementById("nextBtn2").disabled = newPage >= pdfViewer2Instance.totalPages;
- pdfViewer2Instance.currentPage = newPage; // sync internal state
- }
- }
- });
- });
- </script>
Advertisement
Add Comment
Please, Sign In to add comment