Add copy button to copy code block contents (#345)

* add buttons to copy code block contents

Adds a clickable "copy" link in the top-right corner of each code block.

If available, uses the navigator.clipboard API. Falls back to selecting
the text and calling document.execCommand('copy') to copy text.

* hides copy button unless mouse is hovering over code block

* change text of copy button when text is copied

* add translation keys for copy button text  `code_copy` and `code_copied`

* To disable use `Params.disableCodeCopy: true` in site config
This commit is contained in:
Kian Kasad 2021-04-09 23:03:31 -07:00 committed by GitHub
parent f1bc3471a6
commit 17c4da86b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 1 deletions

View File

@ -41,5 +41,25 @@
} }
code { code {
direction: ltr direction: ltr;
}
div.highlight {
position: relative;
}
.copy-code {
display: none;
position: absolute;
top: 4px;
right: 4px;
color: rgba(255, 255, 255, 0.8);
background: rgba(78, 78, 78, 0.8);
border-radius: var(--radius);
padding: 0 5px;
font-size: 14px;
}
div.highlight:hover .copy-code {
display: block;
} }

View File

@ -17,3 +17,9 @@
- id: home - id: home
translation: "Home" translation: "Home"
- id: code_copy
translation: "copy"
- id: code_copied
translation: "copied!"

View File

@ -84,3 +84,43 @@
</script> </script>
{{- end }} {{- end }}
{{- if (not .Site.Params.disableCodeCopy) }}
<script>
document.querySelectorAll('pre > code').forEach((codeblock) => {
const container = codeblock.parentNode.parentNode;
const copybutton = document.createElement('button');
copybutton.classList.add('copy-code');
copybutton.innerText = '{{- i18n "code_copy" | default "copy" }}';
function copyingDone() {
copybutton.innerText = '{{- i18n "code_copied" | default "copied!" }}';
setTimeout(() => {
copybutton.innerText = '{{- i18n "code_copy" | default "copy" }}';
}, 2000);
}
copybutton.addEventListener('click', (cb) => {
if ('clipboard' in navigator) {
navigator.clipboard.writeText(codeblock.textContent);
copyingDone();
return;
}
const range = document.createRange();
range.selectNodeContents(codeblock);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
try {
document.execCommand('copy');
copyingDone();
} catch (e) { };
selection.removeRange(range);
});
container.appendChild(copybutton);
});
</script>
{{- end }}