pub(crate) fn wanted(body: &str) -> bool {
body.contains("listingblock") || body.contains("literalblock")
}
pub(crate) const SCRIPT: &str = r#"<style>
.adocers-copyable { position: relative; }
.adocers-copyable > pre { padding-right: 2.75rem; }
.adocers-copy {
position: absolute; top: 0.5rem; right: 0.5rem;
display: flex; align-items: center; justify-content: center;
width: 1.9rem; height: 1.9rem; padding: 0;
border: 1px solid var(--rule, #d0d7de); border-radius: 5px;
background: var(--bg, #ffffff); color: var(--muted, #656d77);
cursor: pointer; opacity: 0; transition: opacity 0.15s ease, color 0.15s ease;
}
.adocers-copy:hover { color: var(--accent, #1565a8); }
.adocers-copyable:hover > .adocers-copy,
.adocers-copy:focus-visible,
.adocers-copy.adocers-copied { opacity: 1; }
.adocers-copy.adocers-copied { color: var(--accent, #1565a8); }
/* There is no hovering on a touch screen, so there the button is simply
there. */
@media (hover: none) { .adocers-copy { opacity: 1; } }
@media print { .adocers-copy { display: none; } }
</style>
<script>
(function () {
var blocks = document.querySelectorAll(
".listingblock > .content, .literalblock > .content"
);
if (!blocks.length) { return; }
var COPY = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" ' +
'stroke="currentColor" stroke-width="1.4" stroke-linecap="round" ' +
'stroke-linejoin="round" aria-hidden="true">' +
'<rect x="6" y="6" width="8" height="8" rx="1.5"/>' +
'<path d="M10 4V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h1"/></svg>';
var DONE = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" ' +
'stroke="currentColor" stroke-width="1.8" stroke-linecap="round" ' +
'stroke-linejoin="round" aria-hidden="true">' +
'<path d="M3 8.5l3.5 3.5L13 5"/></svg>';
// What the reader would have selected by hand. A callout mark is drawn from
// an attribute, but the `(1)` beside it that a page without a stylesheet
// shows is real text, and neither belongs in the clipboard.
function source(pre) {
var clone = pre.cloneNode(true);
var marks = clone.querySelectorAll(".conum, .conum + b");
for (var i = 0; i < marks.length; i++) {
marks[i].parentNode.removeChild(marks[i]);
}
return clone.textContent.replace(/[ \t]+$/gm, "");
}
// The clipboard API needs a secure context, which a page opened from disk or
// served over plain HTTP may not be, and it can refuse even there. The old
// selection-and-execCommand dance is what is left when it does.
function write(text) {
if (navigator.clipboard && window.isSecureContext) {
return navigator.clipboard.writeText(text).catch(function () {
return legacy(text);
});
}
return legacy(text);
}
function legacy(text) {
return new Promise(function (resolve, reject) {
var area = document.createElement("textarea");
area.value = text;
area.setAttribute("readonly", "");
area.style.position = "fixed";
area.style.top = "0";
area.style.left = "-9999px";
document.body.appendChild(area);
area.select();
var copied = false;
try { copied = document.execCommand("copy"); } catch (error) { copied = false; }
document.body.removeChild(area);
if (copied) { resolve(); } else { reject(new Error("copy refused")); }
});
}
function attach(content) {
var pre = content.querySelector("pre");
if (!pre) { return; }
var button = document.createElement("button");
var pending = null;
button.type = "button";
button.className = "adocers-copy";
button.innerHTML = COPY;
button.title = "Copy to clipboard";
button.setAttribute("aria-label", "Copy to clipboard");
button.addEventListener("click", function () {
write(source(pre)).then(function () {
say("Copied", DONE, true);
}, function () {
say("Copying failed", COPY, false);
});
});
function say(label, icon, copied) {
button.innerHTML = icon;
button.title = label;
button.setAttribute("aria-label", label);
button.classList.toggle("adocers-copied", copied);
clearTimeout(pending);
pending = setTimeout(function () {
button.innerHTML = COPY;
button.title = "Copy to clipboard";
button.setAttribute("aria-label", "Copy to clipboard");
button.classList.remove("adocers-copied");
}, 1600);
}
content.classList.add("adocers-copyable");
content.appendChild(button);
}
for (var i = 0; i < blocks.length; i++) { attach(blocks[i]); }
})();
</script>"#;