Welcome to Code Forum!

Join a community that supports you and your coding journey from day one. We strive to be a friendly, supportive community that empowers everyone to be better developers. By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
  • Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • You can also use markdown to share your code. When using markdown your code will be automatically converted to BBCode. For help with markdown check out the markdown guide.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.

    GIF shows where to locate </> in the thread and or post editor toolbar.
    To learn more about how to use our BBCode feature, review our "How to post your code into threads" here.

    Thank you, Code Forum.

PDF Viewer question

Edrol97

Silver Coder
Is there any way to change the default pdf viewer. Ideally I want to make my own pdf viewer which emulates HTML5Flipbooks? When I ask AI as it's something I don't know how to do, it gives me the option to upload a pdf or it can't find my file, even with the filepath being correct. So what's going wrong in this code? AI has advised me to run it from a web-server, but I have no idea how to do this.

Thanks as always,

Eliot


Code:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ContextStack</title>
    <link rel="stylesheet" href="Style.css" />
    <link rel="icon" type="image/x-icon" href="/Fav.svg" />
    <style>
      .body {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
        gap: 20px;
        padding: 20px;
        width: 100%;
        box-sizing: border-box;
      }

      @media (max-width: 768px) {
        .body {
          grid-template-columns: 1fr;
        }
      }

      body::-webkit-scrollbar {
        width: 1em round;
        overflow: scroll;
      }

      body::-webkit-scrollbar-track {
        box-shadow: inset 0 0 6px #012169;
      }

      body::-webkit-scrollbar-thumb {
        background-color: #012169;
        outline: 1px solid #012169;
        width: 1em round;
        border-radius: 10px;
      }

      .publication {
        position: relative;
        width: 100%;
        max-width: 800px;
        margin: 0 auto;
        aspect-ratio: 4 / 3;
      }

      .publication embed {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
      }

      .container {
        background: white;
        border-radius: 15px;
        padding: 30px;
        box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
        max-width: 1000px;
        width: 100%;
        margin: 40px auto;
      }

      h1 {
        text-align: center;
        color: #333;
        margin-bottom: 20px;
        font-size: 24px;
      }

      .viewer-wrapper {
        position: relative;
        width: 100%;
        background: #f5f5f5;
        border-radius: 10px;
        overflow: hidden;
        perspective: 2000px;
        display: none;
      }

      .viewer-wrapper.active {
        display: block;
      }

      .book {
        position: relative;
        width: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 600px;
      }

      .page-container {
        position: relative;
        width: 80%;
        max-width: 700px;
        margin: 40px auto;
      }

      canvas {
        width: 100%;
        height: auto;
        box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2);
        border-radius: 5px;
        background: white;
        transition: transform 0.6s ease;
        transform-origin: left center;
      }

      canvas.flipping {
        animation: flip 0.6s ease-in-out;
      }

      @keyframes flip {
        0% {
          transform: rotateY(0deg);
        }
        50% {
          transform: rotateY(-90deg);
        }
        100% {
          transform: rotateY(-180deg);
          opacity: 0;
        }
      }

      .controls {
        display: flex;
        justify-content: center;
        align-items: center;
        gap: 20px;
        margin-top: 30px;
        padding: 20px;
        background: #f9f9f9;
        border-radius: 10px;
      }

      button {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border: none;
        padding: 12px 30px;
        border-radius: 8px;
        cursor: pointer;
        font-size: 16px;
        font-weight: 600;
        transition: all 0.3s;
        box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
      }

      button:hover:not(:disabled) {
        transform: translateY(-2px);
        box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
      }

      button:disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }

      .page-info {
        font-size: 18px;
        color: #333;
        font-weight: 600;
        min-width: 100px;
        text-align: center;
      }

      .loading {
        text-align: center;
        padding: 40px;
        color: #666;
        font-size: 18px;
      }

      .error {
        text-align: center;
        padding: 40px;
        color: #d32f2f;
        font-size: 16px;
      }

      .file-input-wrapper {
        text-align: center;
        padding: 20px;
        background: #f9f9f9;
        border-radius: 10px;
        margin: 20px 0;
      }

      .file-input-wrapper input[type="file"] {
        margin: 10px 0;
      }
    </style>
  </head>
  <body>
    <main>
      <header>
        <div class="header-content">
          <div class="logo-section">
            <a href="Context.html" style="text-decoration: none; color: #000">
              <img
                style="margin: auto; display: block"
                src="TheContextWeb.png"
                width="50%"
                alt="Logo"
              />
            </a>
          </div>
        </div>
        <button id="hamburger" class="hamburger" aria-label="Toggle menu">
          <span></span>
          <span></span>
          <span></span>
        </button>
        <nav id="nav">
          <a href="index.html">Home</a>
          <a href="About.html">About</a>
          <a href="People.html">People</a>
          <a href="Articles.html">Articles</a>
          <a href="Context.html" class="active">Context</a>
          <a href="Substack.html">Substack</a>
        </nav>
      </header>

      <div class="container">
        <div class="file-input-wrapper">
          <p>
            If the PDF doesn't load automatically, please select it manually:
          </p>
          <input type="file" id="pdf-file-input" accept="application/pdf" />
        </div>

        <div class="viewer-wrapper" id="viewer-wrapper">
          <div class="book">
            <div class="page-container">
              <div id="loading" class="loading">Loading PDF...</div>
              <div id="error" class="error" style="display: none"></div>
              <canvas id="pdf-canvas"></canvas>
            </div>
          </div>
          <div class="controls">
            <button id="prev-btn" disabled>← Previous</button>
            <div class="page-info">
              <span id="page-num">-</span> / <span id="page-count">-</span>
            </div>
            <button id="next-btn" disabled>Next →</button>
          </div>
        </div>
      </div>
    </main>

    <footer>
      <div class="footertop">
        <a href="index.html">Home</a>
        <a href="About.html">About</a>
        <a href="People.html">People</a>
        <a href="Articles.html">Articles</a>
        <a href="Context.html" class="active">Context</a>
        <a href="Substack.html">Substack</a>
        <a href="mailto:[email protected]">Contact</a>
      </div>
      <br />
      <h2>
        © Context Cast News 2025. Design by
        <a href="https://www.house-of-lord.co.uk">Eliot Lord</a>
      </h2>
    </footer>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>

    <script>
      pdfjsLib.GlobalWorkerOptions.workerSrc =
        "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";

      // Try multiple possible filenames
      const POSSIBLE_FILENAMES = [
        "The Context Magazine Edition 1.pdf",
        "./The Context Magazine Edition 1.pdf",
        "The Context Winter Edition 2025.pdf",
        "./The Context Winter Edition 2025.pdf",
        "The%20Context%20Magazine%20Edition%201.pdf",
        "The%20Context%20Winter%20Edition%202025.pdf",
        "the-context-winter-edition-2025.pdf",
      ];

      let pdfDoc = null;
      let pageNum = 1;
      let pageIsRendering = false;
      let pageNumIsPending = null;

      const canvas = document.getElementById("pdf-canvas");
      const ctx = canvas.getContext("2d");
      const loading = document.getElementById("loading");
      const error = document.getElementById("error");
      const prevBtn = document.getElementById("prev-btn");
      const nextBtn = document.getElementById("next-btn");
      const pageNumSpan = document.getElementById("page-num");
      const pageCountSpan = document.getElementById("page-count");
      const viewerWrapper = document.getElementById("viewer-wrapper");
      const fileInput = document.getElementById("pdf-file-input");

      async function renderPage(num) {
        pageIsRendering = true;

        try {
          const page = await pdfDoc.getPage(num);
          const viewport = page.getViewport({ scale: 2 });

          canvas.height = viewport.height;
          canvas.width = viewport.width;

          const renderContext = {
            canvasContext: ctx,
            viewport: viewport,
          };

          await page.render(renderContext).promise;

          pageIsRendering = false;

          if (pageNumIsPending !== null) {
            renderPage(pageNumIsPending);
            pageNumIsPending = null;
          }
        } catch (err) {
          console.error("Error rendering page:", err);
          pageIsRendering = false;
        }
      }

      function queueRenderPage(num) {
        if (pageIsRendering) {
          pageNumIsPending = num;
        } else {
          renderPage(num);
        }
      }

      function showPage(num) {
        canvas.classList.add("flipping");

        setTimeout(() => {
          pageNum = num;
          queueRenderPage(num);
          pageNumSpan.textContent = num;

          prevBtn.disabled = num <= 1;
          nextBtn.disabled = num >= pdfDoc.numPages;

          canvas.classList.remove("flipping");
        }, 300);
      }

      prevBtn.addEventListener("click", () => {
        if (pageNum <= 1) return;
        showPage(pageNum - 1);
      });

      nextBtn.addEventListener("click", () => {
        if (pageNum >= pdfDoc.numPages) return;
        showPage(pageNum + 1);
      });

      async function loadPDFFromData(data) {
        try {
          console.log("Loading PDF from data, size:", data.length, "bytes");
          loading.style.display = "block";
          error.style.display = "none";
          canvas.style.display = "none";
          viewerWrapper.classList.add("active");

          const loadingTask = pdfjsLib.getDocument({ data: data });
          pdfDoc = await loadingTask.promise;
          console.log("PDF loaded successfully, pages:", pdfDoc.numPages);

          pageCountSpan.textContent = pdfDoc.numPages;
          pageNumSpan.textContent = pageNum;

          loading.style.display = "none";
          canvas.style.display = "block";

          await renderPage(pageNum);

          prevBtn.disabled = pageNum <= 1;
          nextBtn.disabled = pageNum >= pdfDoc.numPages;
        } catch (err) {
          console.error("Error loading PDF:", err);
          loading.style.display = "none";
          error.style.display = "block";
          error.textContent = "Error loading PDF: " + err.message;
        }
      }

      // Handle manual file selection
      fileInput.addEventListener("change", async (e) => {
        const file = e.target.files[0];
        if (file && file.type === "application/pdf") {
          try {
            const arrayBuffer = await file.arrayBuffer();
            const typedArray = new Uint8Array(arrayBuffer);
            await loadPDFFromData(typedArray);
          } catch (err) {
            console.error("Error loading selected file:", err);
            error.style.display = "block";
            error.textContent = "Error loading selected PDF: " + err.message;
          }
        }
      });

      async function loadPDF() {
        try {
          console.log("=== Starting PDF Load ===");
          loading.style.display = "block";
          viewerWrapper.classList.add("active");

          // Try each possible filename
          for (const filename of POSSIBLE_FILENAMES) {
            try {
              console.log("Trying to fetch:", filename);
              const response = await fetch(filename, {
                method: "GET",
                cache: "no-cache",
              });

              if (response.ok) {
                const arrayBuffer = await response.arrayBuffer();
                const typedArray = new Uint8Array(arrayBuffer);
                console.log("✓ PDF loaded successfully from:", filename);
                await loadPDFFromData(typedArray);
                return;
              }
            } catch (fetchErr) {
              console.log("✗ Failed to load:", filename, fetchErr.message);
            }
          }

          // If all attempts fail, show helpful error
          throw new Error(
            "Could not automatically load the PDF. Please use the file selector above to choose your PDF file manually."
          );
        } catch (err) {
          console.error("All loading methods failed:", err);
          loading.style.display = "none";
          error.style.display = "block";
          error.textContent = err.message;
        }
      }

      canvas.style.display = "none";

      // Start loading when page is ready
      if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", loadPDF);
      } else {
        loadPDF();
      }
    </script>
  </body>
</html>
 
Last edited:
Back
Top Bottom