Skip to content

Commit

Permalink
Add click to copy button
Browse files Browse the repository at this point in the history
Adds a click to copy button to code samples that don't use the Prism
highlighter.
  • Loading branch information
geriom committed Oct 6, 2022
1 parent 5c4662c commit de7048f
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 2 deletions.
86 changes: 86 additions & 0 deletions assets/js/click-to-copy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
let codeListings = document.querySelectorAll('.highlight > pre');

for (let index = 0; index < codeListings.length; index++)
{
const codeSample = codeListings[index].querySelector('code');
const copyButton = document.createElement("button");
copyButton.setAttribute('type', 'button');
copyButton.onclick = function() { copyCode(codeSample); };
copyButton.classList.add('fas', 'fa-copy');

const buttonTooltip = document.createElement('div');
buttonTooltip.classList.add('c2c-tooltip');
buttonTooltip.setAttribute('role', 'tooltip');
buttonTooltip.innerHTML += 'Copy to clipboard';

const buttonDiv = document.createElement('div');
buttonDiv.classList.add('click-to-copy');

// Use Popper to create and handle the tooltip behavior.

const popperInstance = Popper.createPopper(copyButton, buttonTooltip,
{
modifiers:
[
{
name: 'offset',
options:
{
offset: [0, -48],
},
},
],
});

copyButton.addEventListener('click', () =>
{
buttonTooltip.innerHTML = 'Copied!';
});

copyButton.addEventListener('mouseenter', () =>
{
buttonTooltip.setAttribute('show-tooltip', '');

// Enable eventListeners when the code block is on the viewport

popperInstance.setOptions((options) => ({
...options,
modifiers:
[
...options.modifiers,
{ name: 'eventListeners', enabled: true },
],
}));
popperInstance.update();
});

copyButton.addEventListener('mouseleave', () =>
{
buttonTooltip.removeAttribute('show-tooltip');

// Reset the message in case the button was clicked
buttonTooltip.innerHTML = 'Copy to clipboard';

// Disble eventListeners when the code block is NOT on the viewport

popperInstance.setOptions((options) => ({
...options,
modifiers:
[
...options.modifiers,
{ name: 'eventListeners', enabled: false },
],
}));
});

buttonDiv.append(copyButton);
buttonDiv.append(buttonTooltip);
codeListings[index].insertBefore(buttonDiv, codeSample);

}

function copyCode(codeSample)
{
navigator.clipboard.writeText(codeSample.textContent.trim());
}

48 changes: 47 additions & 1 deletion assets/scss/_code.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,56 @@

margin: 2rem 0;
padding: 0;

position: relative;

.click-to-copy {
display: block;
text-align: right;
height: 1ex;
}

pre {
margin: 0;
padding: 1rem;

// Default click-to-copy button

button {
position: absolute;
color: $gray-400;
border-radius: 3px;
border-width: 0;
background-color: inherit;
box-shadow: 1px 1px $gray-400;
right: 8px;
top: 6px;

&:hover {
color: $dark;
background-color: $gray-400;
}
&:active {
color: $dark;
background-color: $gray-400;
transform: translateY(2px);
}
}

.c2c-tooltip {
background: $dark;
color: $white;
padding: 2px 4px;
border-radius: 3px;
display: block;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s linear;
}

.c2c-tooltip[show-tooltip] {
visibility: visible;
opacity: 1;
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion layouts/partials/scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
{{ printf "onload='renderMathInElement(%s, %s);'" (( .Site.Params.katex.html_dom_element | default "document.body" ) | safeJS ) ( printf "%s" ( $.Site.Params.katex.options | jsonify )) | safeHTMLAttr }}></script>
{{ end -}}

{{ $jsPopper := resources.GetRemote "https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" -}}
{{ $jsPopper := resources.GetRemote "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.9.2/umd/popper.min.js" -}}
{{ $jsBs := resources.Get "vendor/bootstrap/dist/js/bootstrap.js" -}}
{{ $jsBase := resources.Get "js/base.js" -}}
{{ $jsAnchor := resources.Get "js/anchor.js" -}}
Expand All @@ -70,6 +70,9 @@

{{ if .Site.Params.prism_syntax_highlighting -}}
<script src='{{ "js/prism.js" | relURL }}'></script>
{{ else -}}
{{ $c2cJS := resources.Get "js/click-to-copy.js" | minify | fingerprint }}

This comment has been minimized.

Copy link
@chalin

chalin Oct 7, 2022

Collaborator

My preference would be to fingerprint only in production mode, but this is ok for now.

Thanks for this feature!

<script defer src="{{ $c2cJS.RelPermalink }}" integrity="{{ $c2cJS.Data.Integrity }}" crossorigin="anonymous"></script>
{{ end -}}

<script src='{{ "js/tabpane-persist.js" | relURL }}'></script>
Expand Down

0 comments on commit de7048f

Please sign in to comment.