Many improvements

This commit is contained in:
2026-06-26 15:48:12 -05:00
parent 2a52e0546e
commit c5725a0259
22 changed files with 1392 additions and 97 deletions
+82
View File
@@ -0,0 +1,82 @@
const overlay = document.createElement("section");
overlay.className = "error-overlay";
overlay.hidden = true;
overlay.innerHTML = `
<div class="error-overlay-header">
<strong>JavaScript error</strong>
<div class="error-overlay-actions">
<button type="button" data-action="copy">Copy</button>
<button type="button" data-action="dismiss" aria-label="Dismiss error">Dismiss</button>
</div>
</div>
<pre></pre>
`;
const messageNode = overlay.querySelector("pre");
const copyButton = overlay.querySelector("[data-action='copy']");
const dismissButton = overlay.querySelector("[data-action='dismiss']");
copyButton.addEventListener("click", async () => {
await copyText(messageNode.textContent);
showCopyStatus();
});
dismissButton.addEventListener("click", () => {
overlay.hidden = true;
});
document.addEventListener("DOMContentLoaded", () => {
document.body.append(overlay);
});
window.addEventListener("error", (event) => {
showError(formatErrorEvent(event));
});
window.addEventListener("unhandledrejection", (event) => {
showError(formatReason(event.reason));
});
function showError(message) {
messageNode.textContent = message;
copyButton.textContent = "Copy";
overlay.hidden = false;
}
async function copyText(value) {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(value);
return;
}
const textArea = document.createElement("textarea");
textArea.value = value;
textArea.setAttribute("readonly", "");
textArea.className = "error-overlay-copy-buffer";
document.body.append(textArea);
textArea.select();
document.execCommand("copy");
textArea.remove();
}
function showCopyStatus() {
copyButton.textContent = "Copied";
window.setTimeout(() => {
copyButton.textContent = "Copy";
}, 1400);
}
function formatErrorEvent(event) {
const location = [event.filename, event.lineno, event.colno].filter(Boolean).join(":");
const detail = formatReason(event.error ?? event.message);
return location ? `${detail}\n\n${location}` : detail;
}
function formatReason(reason) {
if (reason instanceof Error) {
return reason.stack ?? `${reason.name}: ${reason.message}`;
}
return String(reason);
}