code: unDRY inline and block copy-to-clipboard buttons #1022

This commit is contained in:
Sören Weber 2025-02-14 22:49:58 +01:00
parent 865f195d59
commit 4714e07770
No known key found for this signature in database
GPG key ID: BEC6D55545451B6D
6 changed files with 78 additions and 87 deletions

View file

@ -46,7 +46,8 @@ pre:not(.mermaid) {
#R-body .copy-to-clipboard-code {
padding-inline-end: 2px;
}
#R-body .copy-to-clipboard-button {
#R-body .inline-copy-to-clipboard-button,
#R-body .block-copy-to-clipboard-button {
display: none;
}

View file

@ -955,7 +955,7 @@ code.copy-to-clipboard-code {
border-start-end-radius: 0;
border-inline-end-width: 0;
}
body:not(.disableInlineCopyToClipboard) code.copy-to-clipboard-code:has(+ .copy-to-clipboard-button) {
code.copy-to-clipboard-code:has(+ .inline-copy-to-clipboard-button) {
padding-inline-end: 24px;
}
@ -973,9 +973,8 @@ pre:not(.mermaid) {
position: relative;
}
/* pre:not(.mermaid):has( code ), */
/* the :has() operator isn't available in FF yet, so we patch this by JS */
pre:not(.mermaid).pre-code {
div.highlight {
/* even in RTL languages code is supposed to be LTR */
direction: ltr;
text-align: left;
}
@ -1430,9 +1429,8 @@ html[dir='rtl'] .topbar-button-next i {
}
}
.copy-to-clipboard-button {
background-color: var(--INTERNAL-CODE-INLINE-BG-color);
border-color: var(--INTERNAL-CODE-INLINE-BORDER-color);
.inline-copy-to-clipboard-button,
.block-copy-to-clipboard-button {
border-start-start-radius: 0;
border-start-end-radius: 2px;
border-end-end-radius: 2px;
@ -1440,7 +1438,6 @@ html[dir='rtl'] .topbar-button-next i {
border-style: solid;
border-width: 1px;
bottom: calc(var(--bpx1) * -1px);
color: var(--INTERNAL-CODE-INLINE-color);
cursor: pointer;
display: inline;
font: initial;
@ -1449,81 +1446,63 @@ html[dir='rtl'] .topbar-button-next i {
margin-inline-start: -22px;
position: absolute;
}
.copy-to-clipboard-button:hover {
background-color: var(--INTERNAL-CODE-INLINE-color);
color: var(--INTERNAL-CODE-INLINE-BG-color);
}
span > .copy-to-clipboard-button {
.inline-copy-to-clipboard-button {
background-color: var(--INTERNAL-CODE-INLINE-BG-color);
border-color: var(--INTERNAL-CODE-INLINE-BORDER-color);
border-start-start-radius: 0;
border-start-end-radius: 2px;
border-end-end-radius: 2px;
border-end-start-radius: 0;
color: var(--INTERNAL-CODE-INLINE-color);
}
.inline-copy-to-clipboard-button:hover {
background-color: var(--INTERNAL-CODE-INLINE-color);
color: var(--INTERNAL-CODE-INLINE-BG-color);
}
.copy-to-clipboard-button > i {
font-size: 0.859625rem;
}
/* only show copy to clipboard on hover for code blocks if configured */
div.highlight .copy-to-clipboard-button {
display: none;
}
@media (any-hover: none) {
/* if there is at least one input device that does not support hover, we want to force the copy button */
div.highlight .copy-to-clipboard-button {
display: block;
}
}
div.highlight:focus-within .copy-to-clipboard-button,
div.highlight .copy-to-clipboard-button:active,
div.highlight:hover .copy-to-clipboard-button {
display: block;
}
.disableHoverBlockCopyToClipBoard div.highlight .copy-to-clipboard-button {
display: block;
}
.force-display {
display: block !important;
}
div.highlight > div table + .copy-to-clipboard-button > i,
div.highlight pre:not(.mermaid) + .copy-to-clipboard-button > i,
.copy-to-clipboard-code + .copy-to-clipboard-button > i {
padding-left: 5px;
padding-right: 5px;
}
div.highlight > div table + .copy-to-clipboard-button,
div.highlight pre:not(.mermaid) + .copy-to-clipboard-button,
pre:not(.mermaid) > .copy-to-clipboard-button {
.block-copy-to-clipboard-button {
background-color: rgba(160, 160, 160, 0.2);
border-color: transparent;
border-radius: 2px;
border-style: solid;
border-width: 1px;
color: var(--INTERNAL-MAIN-LINK-color);
/* only show copy to clipboard on hover for code blocks if configured */
display: none;
padding: 5px 3px;
position: absolute;
right: 4px;
top: 4px;
}
div.highlight > div table + .copy-to-clipboard-button:hover,
div.highlight pre:not(.mermaid) + .copy-to-clipboard-button:hover,
pre:not(.mermaid) .copy-to-clipboard-button:hover {
@media (any-hover: none) {
/* if there is at least one input device that does not support hover, we want to force the copy button */
.block-copy-to-clipboard-button {
display: block;
}
}
div.highlight:focus-within .block-copy-to-clipboard-button,
div.highlight .block-copy-to-clipboard-button:active,
div.highlight:hover .block-copy-to-clipboard-button {
display: block;
}
.disableHoverBlockCopyToClipBoard div.highlight .block-copy-to-clipboard-button {
display: block;
}
.force-display {
display: block !important;
}
.block-copy-to-clipboard-button:hover {
background-color: var(--INTERNAL-MAIN-LINK-color);
border-color: var(--INTERNAL-MAIN-LINK-color);
color: var(--INTERNAL-CODE-BLOCK-BG-color);
}
body.disableInlineCopyToClipboard span > code.copy-to-clipboard-code + .copy-to-clipboard-button {
display: none;
}
body.disableInlineCopyToClipboard span > code.copy-to-clipboard-code {
border-start-end-radius: 2px;
border-end-end-radius: 2px;
border-inline-end-width: 1px;
.inline-copy-to-clipboard-button > i,
.block-copy-to-clipboard-button > i {
font-size: 0.859625rem;
padding-left: 5px;
padding-right: 5px;
}
#R-homelinks {

View file

@ -40,7 +40,7 @@
{{- partial "dependencies.gotmpl" (dict "page" . "location" "header") }}
{{- partial "custom-header.html" . }}
</head>
<body class="mobile-support {{ with .Store.Get "relearnOutputFormat" }}{{ . }}{{ else }}html{{ end }}{{- if .Site.Params.disableInlineCopyToClipBoard }} disableInlineCopyToClipboard{{ end }}{{- if .Site.Params.disableHoverBlockCopyToClipBoard }} disableHoverBlockCopyToClipBoard{{ end }}" data-url="{{ partial "permalink.gotmpl" (dict "to" .) }}">
<body class="mobile-support {{ with .Store.Get "relearnOutputFormat" }}{{ . }}{{ else }}html{{ end }}{{- if .Site.Params.disableHoverBlockCopyToClipBoard }} disableHoverBlockCopyToClipBoard{{ end }}" data-url="{{ partial "permalink.gotmpl" (dict "to" .) }}">
<div id="R-body" class="default-animation">
<div id="R-body-overlay"></div>
<nav id="R-topbar">

View file

@ -17,6 +17,7 @@
{{- if isset .Params "highlightwrap" }}
{{- $wrap = .Params.highlightWrap }}
{{- end }}
{{- $disableInlineCopyToClipboard := site.Params.disableInlineCopyToClipBoard }}
{{- $minify := not hugo.IsServer }}
{{- if and (isset site.Params "minify") (ne site.Params.minify "") }}
{{- $minify = site.Params.minify }}
@ -33,6 +34,7 @@
window.relearn.disableAnchorCopy={{ printf "%t" (eq .Site.Params.disableAnchorCopy true) | safeJS }};
window.relearn.disableAnchorScrolling={{ printf "%t" (eq .Site.Params.disableAnchorScrolling true) | safeJS }};
window.relearn.enableBlockCodeWrap={{ printf "%t" (eq $wrap true) | safeJS }};
window.relearn.disableInlineCopyToClipboard={{ printf "%t" (eq $disableInlineCopyToClipboard true) | safeJS }};
{{ "// variant stuff" | safeJS }}
{{- $quotedthemevariants := slice }}
{{- range $themevariants }}

View file

@ -1 +1 @@
7.3.2+4a25b6a875b2b452f58f70fa254a8dd19a5724dd
7.3.2+865f195d595ccfd74eac88b825db8f890aa97633

View file

@ -657,6 +657,7 @@ function initCodeClipboard() {
var inTable = inPre && code.parentNode.parentNode.tagName.toLowerCase() == 'td' && code.parentNode.parentNode.classList.contains('lntd');
// avoid copy-to-clipboard for highlight shortcode in table lineno mode
var isFirstLineCell = inTable && code.parentNode.parentNode.parentNode.querySelector('td:first-child > pre > code') == code;
var isBlock = inTable || inPre;
if (!isFirstLineCell && (inPre || text.length > 5)) {
code.classList.add('copy-to-clipboard-code');
@ -671,14 +672,34 @@ function initCodeClipboard() {
code.parentNode.replaceChild(span, code);
code = clone;
}
var button = document.createElement('button');
button.classList.add('copy-to-clipboard-button');
button.setAttribute('title', window.T_Copy_to_clipboard);
button.innerHTML = '<i class="far fa-copy"></i>';
button.addEventListener('mouseleave', function () {
this.removeAttribute('aria-label');
this.classList.remove('tooltipped', 'tooltipped-w', 'tooltipped-se', 'tooltipped-sw');
});
var button = null;
if (isBlock || !window.relearn.disableInlineCopyToClipboard) {
button = document.createElement('button');
var buttonPrefix = isBlock ? 'block' : 'inline';
button.classList.add(buttonPrefix + '-copy-to-clipboard-button');
button.setAttribute('title', window.T_Copy_to_clipboard);
button.innerHTML = '<i class="far fa-copy"></i>';
button.addEventListener('mouseleave', function () {
this.removeAttribute('aria-label');
this.classList.remove('tooltipped', 'tooltipped-w', 'tooltipped-se', 'tooltipped-sw');
});
if (isBlock) {
// we have to make sure, the button is visible while
// Clipboard.js is doing its magic
button.addEventListener('focus', function (ev) {
setTimeout(function () {
ev.target.classList.add('force-display');
}, 0);
});
button.addEventListener('blur', function (ev) {
this.removeAttribute('aria-label');
this.classList.remove('tooltipped', 'tooltipped-w', 'tooltipped-se', 'tooltipped-sw');
setTimeout(function () {
ev.target.classList.remove('force-display');
}, 0);
});
}
}
if (inTable) {
var table = code.parentNode.parentNode.parentNode.parentNode.parentNode;
table.dataset.code = text;
@ -702,30 +723,18 @@ function initCodeClipboard() {
pre.parentNode.replaceChild(div, pre);
pre = clone;
}
// we have to make sure, the button is visible while
// Clipboard.js is doing its magic
button.addEventListener('focus', function (ev) {
setTimeout(function () {
ev.target.classList.add('force-display');
}, 0);
});
button.addEventListener('blur', function (ev) {
this.removeAttribute('aria-label');
this.classList.remove('tooltipped', 'tooltipped-w', 'tooltipped-se', 'tooltipped-sw');
setTimeout(function () {
ev.target.classList.remove('force-display');
}, 0);
});
pre.parentNode.insertBefore(button, pre.nextSibling);
} else {
code.classList.add('highlight');
code.dataset.code = text;
code.parentNode.insertBefore(button, code.nextSibling);
if (button) {
code.parentNode.insertBefore(button, code.nextSibling);
}
}
}
}
var clip = new ClipboardJS('.copy-to-clipboard-button', {
var clip = new ClipboardJS('.block-copy-to-clipboard-button, .inline-copy-to-clipboard-button', {
text: function (trigger) {
if (!trigger.previousElementSibling) {
return '';