// Copy-to-clipboard for `.js-copy` buttons, loaded by the Domains page only
// (domains-registry D9).
//
// Delegated on document so it survives the claim status view's 5s HTMX
// self-swap, and CSP-safe: strict CSP drops inline handlers, so every button
// carries its payload in data-copy and nothing else.
//
// An integration's dashboard card that needs the same behavior ships its own
// copy inside its card script (the member-dashboard contract requires card
// scripts to come from the integration's own static mount), so this handler
// may be functionally duplicated by integration bundles. Core's copy and an
// integration's never load on the same page — this one belongs to core
// surfaces — so there is no double-fire and neither may be deleted in favor
// of the other.
(function () {
document.addEventListener("click", function (evt) {
var button = evt.target.closest(".js-copy");
if (!button || !button.dataset.copy) return;
// Clipboard API requires a secure context (HTTPS or localhost — both true
// for every supported deployment).
if (!navigator.clipboard) return;
var showFeedback = function (html) {
if (button.dataset.copyRestore) return; // feedback already showing
button.dataset.copyRestore = button.innerHTML;
button.innerHTML = html;
setTimeout(function () {
// The 5s poll may have replaced the node; only restore if it's live.
if (button.isConnected && button.dataset.copyRestore) {
button.innerHTML = button.dataset.copyRestore;
delete button.dataset.copyRestore;
}
}, 1500);
};
navigator.clipboard
.writeText(button.dataset.copy)
.then(function () {
showFeedback('Copied ✓');
})
.catch(function () {
// Permission denied or document unfocused — tell the member instead
// of failing silently (and swallow the rejection).
showFeedback('Copy failed');
});
});
})();