Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy code to clipboard #2812

Merged
merged 12 commits into from
May 5, 2024
50 changes: 50 additions & 0 deletions _sass/minimal-mistakes/_utilities.scss
Original file line number Diff line number Diff line change
Expand Up @@ -591,3 +591,53 @@ a.reversefootnote {
position: static;
}
}

/*
Copy <pre> block to clipboard
========================================================================== */

// a <textarea> to hold text for document.execCommand("copy")
.clipboard-helper {
// Prevent zooming on iOS
font-size: 12pt !important;
border: 0 !important;
padding: 0 !important;
margin: 0 !important;
outline: none !important;
position: absolute;
}

pre {
.clipboard-copy-button {
position: absolute;
top: 0.6em;
right: 0.5em;
z-index: 1;
background: none;
border: none;
outline: none;
border-radius: 0.1em;
padding: 0.2em 0.5em;
color: white;
opacity: 0.4;
transition: color 0.25s linear -0.25s, opacity 0.25s linear;

&:hover {
color: #ffffca;
}

&::before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 2;
}
}

&:hover .clipboard-copy-button {
opacity: 1;
}
}
65 changes: 64 additions & 1 deletion assets/js/_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ $(document).ready(function() {
});

// Gumshoe scroll spy init
if($("nav.toc").length > 0) {
if ($("nav.toc").length > 0) {
var spy = new Gumshoe("nav.toc a", {
// Active classes
navClass: "active", // applied to the nav list item
Expand Down Expand Up @@ -133,4 +133,67 @@ $(document).ready(function() {
$(this).append(anchor);
}
});

// Add copy button for <pre> blocks
var copyText = function(text) {
var isRTL = document.documentElement.getAttribute('dir') === 'rtl';

var textarea = document.createElement('textarea');
textarea.className = "clipboard-helper";
textarea.style[isRTL ? 'right' : 'left'] = '-9999px';
// Move element to the same position vertically
var yPosition = window.pageYOffset || document.documentElement.scrollTop;
textarea.style.top = yPosition + "px";

textarea.setAttribute('readonly', '');
textarea.value = text;
document.body.appendChild(textarea);

var success = true;
try {
textarea.select();
success = document.execCommand("copy");
} catch (e) {
success = false;
}
textarea.parentNode.removeChild(textarea);
return success;
};

var copyButtonEventListener = function(event) {
var thisButton = event.target;

// Locate the <code> element
var codeBlock = thisButton.nextElementSibling;
while (codeBlock && codeBlock.tagName.toLowerCase() !== 'code') {
codeBlock = codeBlock.nextElementSibling;
}
if (!codeBlock) {
// No <code> found - wtf?
console.warn(thisButton);
throw new Error("No code block found for this button.");
}

// Skip line numbers if present (i.e. {% highlight lineno %})
var realCodeBlock = codeBlock.querySelector("td.code");
iBug marked this conversation as resolved.
Show resolved Hide resolved
if (realCodeBlock) {
codeBlock = realCodeBlock;
}
return copyText(codeBlock.innerText);
};

document.querySelectorAll(".page__content pre > code").forEach(function(element, index, parentList) {
// Locate the <pre> element
var container = element.parentElement;
// Sanity check - don't add an extra button if there's already one
if (container.firstElementChild.tagName.toLowerCase() !== 'code') {
return;
}
var copyButton = document.createElement("button");
copyButton.title = "Copy to clipboard";
copyButton.className = "clipboard-copy-button";
copyButton.innerHTML = '<i class="far fa-copy"></i>';
copyButton.addEventListener("click", copyButtonEventListener);
container.prepend(copyButton);
});
});
2 changes: 1 addition & 1 deletion assets/js/main.min.js

Large diffs are not rendered by default.

Loading