translate: add open-in-tab button, move controls above preview, fix blob lifetime

This commit is contained in:
russell@unturf.com 2026-05-21 21:26:38 -04:00
parent bd30ee1fab
commit 21edbe7d81
No known key found for this signature in database
3 changed files with 67 additions and 21 deletions

View file

@ -518,12 +518,20 @@ ${samplePreserved}`;
htmlWithBase = `<!DOCTYPE html>\n<html><head><base href="${baseUrl}">${scriptTag}</head><body>${translatedText}</body></html>`;
}
// Revoke any blob URL kept alive from a previous translation
if (resultArea._translateBlobUrl) {
URL.revokeObjectURL(resultArea._translateBlobUrl);
}
// Render inline via iframe with blob URL (no popup)
const blob = new Blob([htmlWithBase], { type: "text/html" });
const blobUrl = URL.createObjectURL(blob);
resultArea.innerHTML = "";
resultArea.className = "translate-result-area";
// Keep the blob URL alive so the iframe and the
// open-in-tab link both stay valid until the next render.
resultArea._translateBlobUrl = blobUrl;
const iframe = document.createElement("iframe");
iframe.src = blobUrl;
@ -542,36 +550,46 @@ ${samplePreserved}`;
}
iframe.title = iframeTitle;
// Clean up blob URL when iframe loads
iframe.addEventListener("load", () => URL.revokeObjectURL(blobUrl));
// Controls bar above the preview
const controls = document.createElement("div");
controls.className = "translate-result-controls";
const toggleContainer = document.createElement("div");
toggleContainer.style.marginBottom = "12px";
const toggleBtn = document.createElement("button");
toggleBtn.className = "translate-raw-toggle-btn";
toggleBtn.textContent = "Show Raw HTML";
toggleBtn.onclick = () => {
const raw = toggleContainer.querySelector(".translate-raw-html");
if (raw.style.display === "none") {
raw.style.display = "block";
toggleBtn.textContent = "Hide Raw HTML";
} else {
raw.style.display = "none";
toggleBtn.textContent = "Show Raw HTML";
}
};
// Open the translated page in a real browser tab. A user
// click on an anchor is a genuine gesture, so it is not
// blocked like the automatic window.open popups we replaced.
const openTabLink = document.createElement("a");
openTabLink.className =
"translate-raw-toggle-btn translate-open-tab-btn";
openTabLink.href = blobUrl;
openTabLink.target = "_blank";
openTabLink.rel = "noopener";
openTabLink.textContent = "Open full page ↗";
openTabLink.title = iframeTitle;
const rawHtml = document.createElement("div");
rawHtml.className = "translate-raw-html";
rawHtml.style.display = "none";
rawHtml.textContent = translatedText;
toggleContainer.appendChild(toggleBtn);
toggleContainer.appendChild(rawHtml);
const toggleBtn = document.createElement("button");
toggleBtn.className = "translate-raw-toggle-btn";
toggleBtn.textContent = "Show Raw HTML";
toggleBtn.onclick = () => {
if (rawHtml.style.display === "none") {
rawHtml.style.display = "block";
toggleBtn.textContent = "Hide Raw HTML";
} else {
rawHtml.style.display = "none";
toggleBtn.textContent = "Show Raw HTML";
}
};
controls.appendChild(openTabLink);
controls.appendChild(toggleBtn);
resultArea.appendChild(controls);
resultArea.appendChild(iframe);
resultArea.appendChild(toggleContainer);
resultArea.appendChild(rawHtml);
} else {
resultArea.textContent = translatedText;
resultArea.className = "translate-result-area pre-wrap";

View file

@ -451,6 +451,20 @@ dialog#translate-modal > article > .translate-btn {
cursor: pointer;
}
.translate-result-controls {
display: grid;
grid-auto-flow: column;
justify-content: start;
gap: 8px;
margin-bottom: 12px;
}
.translate-open-tab-btn {
background: #0b7285;
text-decoration: none;
display: inline-block;
}
.translate-result-area {
white-space: normal;
}

View file

@ -500,6 +500,20 @@ dialog#translate-modal > article > .translate-btn {
cursor: pointer;
}
.translate-result-controls {
display: grid;
grid-auto-flow: column;
justify-content: start;
gap: 8px;
margin-bottom: 12px;
}
.translate-open-tab-btn {
background: #0b7285;
text-decoration: none;
display: inline-block;
}
.translate-result-area {
white-space: normal;
}