From c6c03d55d21792267fda3bb7c1fd31e8fbb6f920 Mon Sep 17 00:00:00 2001 From: Geoffrey Garrett Date: Thu, 30 Jun 2022 09:40:04 +0200 Subject: [PATCH] feat(clipboard): initial code copy to clipboard implemented - Issue persists with tables that have linenos in table format. --- assets/js/clipboard.js | 46 ++++++++++++++++++++++++++++++++++++ assets/styles/clipboard.scss | 40 +++++++++++++++++++++++++++++++ data/config.yaml | 3 ++- layouts/partials/head.html | 17 +++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 assets/js/clipboard.js create mode 100644 assets/styles/clipboard.scss diff --git a/assets/js/clipboard.js b/assets/js/clipboard.js new file mode 100644 index 000000000..f770161a1 --- /dev/null +++ b/assets/js/clipboard.js @@ -0,0 +1,46 @@ +const svgCopy = + ''; +const svgCheck = + ''; + + +const addCopyButtons = (clipboard) => { + // 1. Look for pre > code elements in the DOM + document.querySelectorAll("pre > code").forEach((codeBlock) => { + // if buttom exists, skip + if (codeBlock.parentElement.querySelector(".clipboard-button")) return; + // 2. Create a button that will trigger a copy operation + const button = document.createElement("button"); + button.className = "clipboard-button"; + button.type = "button"; + button.innerHTML = svgCopy; + button.addEventListener("click", () => { + clipboard.writeText(codeBlock.innerText).then( + () => { + button.blur(); + button.innerHTML = svgCheck; + setTimeout(() => (button.innerHTML = svgCopy), 2000); + }, + (error) => (button.innerHTML = "Error") + ); + }); + // 3. Append the button directly before the pre tag + const pre = codeBlock.parentNode; + pre.parentNode.insertBefore(button, pre); + }); +}; + + +function initClipboard() { + if (navigator && navigator.clipboard) { + addCopyButtons(navigator.clipboard); + } else { + const script = document.createElement("script"); + script.src = + "https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/2.7.0/clipboard-polyfill.promise.js"; + script.integrity = "sha256-waClS2re9NUbXRsryKoof+F9qc1gjjIhc2eT7ZbIv94="; + script.crossOrigin = "anonymous"; + script.onload = () => addCopyButtons(clipboard); + document.body.appendChild(script); + } +} diff --git a/assets/styles/clipboard.scss b/assets/styles/clipboard.scss new file mode 100644 index 000000000..4e2310989 --- /dev/null +++ b/assets/styles/clipboard.scss @@ -0,0 +1,40 @@ +.clipboard-button { + position: absolute; + display: flex; + float: right; + right: 0; + padding: 0.7em; + margin: 0.5em; + color: var(--lightgray); + border-color: var(--dark); + background-color: var(--lightgray); + filter: brightness(1.5); + border: 1px solid; + border-radius: 6px; + font-size: 0.8em; + z-index: 1; + opacity: 0; + transition: 0.1s; +} +.clipboard-button > svg { + fill: var(--dark); +} +.clipboard-button:hover { + cursor: pointer; + border-color: var(--primary); + background-color: var(--dark); +} +.clipboard-button:hover > svg { + fill: var(--primary); +} +.clipboard-button:focus { + outline: 0; +} +.highlight { + position: relative; +} +.highlight:hover > .clipboard-button { + opacity: 1; + transition: 0.2s; +} + diff --git a/data/config.yaml b/data/config.yaml index e55035a08..0fad6f771 100644 --- a/data/config.yaml +++ b/data/config.yaml @@ -4,7 +4,8 @@ openToc: false enableLinkPreview: true enableLatex: true enableCodeBlockTitle: true -enableSPA: true +enableClipboard: true +enableSPA: false enableFooter: true enableContextualBacklinks: true enableRecentNotes: false diff --git a/layouts/partials/head.html b/layouts/partials/head.html index a17d87d94..8fb0e2490 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -54,6 +54,13 @@ {{end}} + {{ if $.Site.Data.config.enableClipboard }} + {{ $clipboard := resources.Get "js/clipboard.js" | resources.Fingerprint "md5" | resources.Minify }} + {{ if (findRE " + {{ end }} + {{ end }} + {{$linkIndex := resources.Get "indices/linkIndex.json" | resources.Fingerprint "md5" | resources.Minify | }} {{$contentIndex := resources.Get @@ -84,6 +91,9 @@ const pathWindow = window.location.pathname; const isHome = pathBase == pathWindow; + {{if $.Site.Data.config.enableClipboard -}} + initClipboard(); + {{ end }} {{if $.Site.Data.config.enableSPA -}} addTitleToCodeBlocks(); {{ end }} @@ -117,6 +127,13 @@ const init = (doc = document) => { // NOTE: everything within this callback will be executed for initial page navigation. This is a good place to put JavaScript that only replaces DOM nodes. + {{if $.Site.Data.config.enableClipboard -}} + {{if $.Site.Data.config.enableSPA -}} + initClipboard(); + {{ else }} + window.addEventListener("DOMContentLoaded", initClipboard); + {{ end }} + {{ end }} {{if $.Site.Data.config.enableCodeBlockTitle -}} {{if $.Site.Data.config.enableSPA -}} addTitleToCodeBlocks();