This commit is contained in:
2026-07-15 21:54:02 -05:00
parent 8e0253821f
commit e1b4e4372f
2 changed files with 53 additions and 46 deletions

View File

@@ -1,5 +1,4 @@
// Native Chromium PDF viewer using a single persistent iframe. // Native Chromium PDF viewer using a single persistent iframe.
// The iframe is created once in index.html and reused for all documents.
class NativePdfViewer { class NativePdfViewer {
constructor(frame, container) { constructor(frame, container) {
@@ -17,12 +16,10 @@ class NativePdfViewer {
this.loadingDiv = document.createElement("div"); this.loadingDiv = document.createElement("div");
this.loadingDiv.className = "native-pdf-loading"; this.loadingDiv.className = "native-pdf-loading";
this.loadingDiv.textContent = "Loading PDF\u2026"; this.loadingDiv.textContent = "Loading PDF\u2026";
this.loadingDiv.hidden = true;
this.container.appendChild(this.loadingDiv); this.container.appendChild(this.loadingDiv);
this.errorDiv = document.createElement("div"); this.errorDiv = document.createElement("div");
this.errorDiv.className = "native-pdf-error"; //this.errorDiv.className = "native-pdf-error";
this.errorDiv.hidden = true;
this.errorMsg = document.createElement("div"); this.errorMsg = document.createElement("div");
this.errorMsg.className = "native-pdf-error-msg"; this.errorMsg.className = "native-pdf-error-msg";
@@ -38,19 +35,11 @@ class NativePdfViewer {
}); });
this.errorDiv.appendChild(this.retryBtn); this.errorDiv.appendChild(this.retryBtn);
this.container.appendChild(this.errorDiv); this.container.appendChild(this.errorDiv);
// Log iframe sizing once
console.log(
"[BizMatch QC] iframe size:",
this.frame.clientWidth + "x" + this.frame.clientHeight,
"container:",
this.container.clientWidth + "x" + this.container.clientHeight,
);
} }
_showState(state) { _showState(state) {
this.loadingDiv.hidden = state !== "loading"; this.loadingDiv.classList.toggle("is-visible", state === "loading");
this.errorDiv.hidden = state !== "error"; this.errorDiv.classList.toggle("is-visible", state === "error");
} }
load(url, _byteSize, key) { load(url, _byteSize, key) {
@@ -58,46 +47,34 @@ class NativePdfViewer {
} }
_navigate(url, key, force) { _navigate(url, key, force) {
// Deduplicate only AFTER the key is accepted if (!force && key && key === this.currentKey) return;
if (!force && key && key === this.currentKey) {
return;
}
const generation = ++this.generation; const generation = ++this.generation;
this.currentKey = key; this.currentKey = key;
this.lastUrl = url; this.lastUrl = url;
// Clear old error text, show loading badge
this.errorMsg.textContent = "";
this._showState("loading"); this._showState("loading");
console.log(`[BizMatch QC] Native PDF src assigned: ${key}`);
console.log(
`[BizMatch QC] Native PDF iframe size: ${this.frame.clientWidth}x${this.frame.clientHeight}`,
);
// Register per-navigation load handler // Shared hide function, idempotent per navigation
if (this._onLoad) { const hideLoading = () => {
this.frame.removeEventListener("load", this._onLoad);
}
this._onLoad = () => {
if (generation !== this.generation) return; if (generation !== this.generation) return;
if (this.loadTimer) { if (this.loadTimer) {
clearTimeout(this.loadTimer); clearTimeout(this.loadTimer);
this.loadTimer = null; this.loadTimer = null;
} }
this._showState("loaded"); this._showState("loaded");
console.log(`[BizMatch QC] Native PDF load event: ${key}`);
}; };
this.frame.addEventListener("load", this._onLoad, { once: true });
// Safety timeout // Optional early signal from iframe load event
if (this._onLoad) this.frame.removeEventListener("load", this._onLoad);
this._onLoad = hideLoading;
this.frame.addEventListener("load", hideLoading, { once: true });
// Fallback: hide loading after 800ms regardless of load event
if (this.loadTimer) clearTimeout(this.loadTimer); if (this.loadTimer) clearTimeout(this.loadTimer);
this.loadTimer = setTimeout(() => { this.loadTimer = setTimeout(hideLoading, 800);
if (generation === this.generation) {
console.warn(`[BizMatch QC] Native PDF load timeout: ${key}`);
this._showState("error");
this.errorMsg.textContent =
"PDF load timed out. The file may be very large.";
}
}, 15000);
this.frame.src = url; this.frame.src = url;
} }

View File

@@ -100,21 +100,51 @@ aside,
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.3);
} }
.native-pdf-loading { .native-pdf-loading {
display: none;
position: absolute; position: absolute;
inset: 0; top: 18px;
display: grid; left: 50%;
place-items: center; transform: translateX(-50%);
color: #aaa;
background: rgba(60, 60, 60, 0.8);
z-index: 3; z-index: 3;
font-size: 15px; pointer-events: none;
}
.native-pdf-loading.is-visible {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 18px;
border-radius: 8px;
background: rgba(0, 0, 0, 0.72);
color: #ddd;
font-size: 13px;
white-space: nowrap;
}
.native-pdf-loading.is-visible::before {
content: "";
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: pdf-spin 0.7s linear infinite;
flex-shrink: 0;
}
@keyframes pdf-spin {
to {
transform: rotate(360deg);
}
} }
.native-pdf-error { .native-pdf-error {
display: none;
position: absolute; position: absolute;
inset: 0; inset: 0;
display: grid;
place-items: center;
z-index: 3; z-index: 3;
}
.native-pdf-error.is-visible {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(50, 50, 50, 0.9); background: rgba(50, 50, 50, 0.9);
text-align: center; text-align: center;
padding: 30px 20px; padding: 30px 20px;