All checks were successful
check / check (push) Successful in 4s
Unifies user-visible copy on "Webhook" (routes and URLs unchanged), drops the placeholder Profile settings section, and adds a copy-to-clipboard affordance for the entrypoint URL as progressive enhancement — the button stays hidden unless both the target element and the Clipboard API resolve, so no dead control appears without JavaScript and the URL stays selectable. Retention copy now matches what the code does: deletion is permanent, 0 retains forever, and a blank field means the default on create or the current value on edit. The permanent-deletion sentence is suppressed for a retain-forever webhook, which the reaper exempts before computing a cutoff. Template tests gained a render-completed assertion. Without it, a page that aborted mid-render still satisfied assertions matching the already-flushed prefix, because renderTemplate streams to the ResponseWriter (#123).
61 lines
1.8 KiB
JavaScript
61 lines
1.8 KiB
JavaScript
// Webhooker client-side JavaScript
|
|
console.log("Webhooker loaded");
|
|
|
|
// Copy-to-clipboard, as progressive enhancement.
|
|
//
|
|
// Markup renders each copy button with the `hidden` attribute and a
|
|
// `data-copy-target` pointing at the id of the element holding the
|
|
// text. This script reveals a button only once it has both a resolvable
|
|
// target and a usable Clipboard API, so a browser without either shows
|
|
// no button at all and the text stays selectable.
|
|
(function () {
|
|
"use strict";
|
|
|
|
const revertDelayMs = 2000;
|
|
|
|
function flash(button, message) {
|
|
const original = button.getAttribute("data-copy-label");
|
|
button.textContent = message;
|
|
window.setTimeout(function () {
|
|
button.textContent = original;
|
|
}, revertDelayMs);
|
|
}
|
|
|
|
function wire(button) {
|
|
const target = document.getElementById(
|
|
button.getAttribute("data-copy-target")
|
|
);
|
|
if (!target) {
|
|
return;
|
|
}
|
|
|
|
button.setAttribute("data-copy-label", button.textContent);
|
|
button.addEventListener("click", function () {
|
|
navigator.clipboard.writeText(target.textContent.trim()).then(
|
|
function () {
|
|
flash(button, "Copied");
|
|
},
|
|
function () {
|
|
flash(button, "Copy failed");
|
|
}
|
|
);
|
|
});
|
|
button.removeAttribute("hidden");
|
|
}
|
|
|
|
function init() {
|
|
if (!navigator.clipboard || !navigator.clipboard.writeText) {
|
|
return;
|
|
}
|
|
|
|
const buttons = document.querySelectorAll("[data-copy-target]");
|
|
buttons.forEach(wire);
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|