From c97875ac7ea308fe4572653a972505ece54e661d Mon Sep 17 00:00:00 2001 From: Dan Macpherson Date: Tue, 1 Aug 2023 15:26:43 +1000 Subject: [PATCH] Creating a javascript script for codeblocks This script modifies the asciidoc codeblocks in the following ways: - Applies Patternfly formatting to the codeblocks - Adds a copy button to the the top right corner of the codeblock --- layouts/_default/baseof.html | 1 + static/css/custom.css | 13 ++++-- static/js/codeblock.js | 91 ++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 static/js/codeblock.js diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index 44ba5f081..ef35d7b10 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -8,5 +8,6 @@ {{- end }} + diff --git a/static/css/custom.css b/static/css/custom.css index a8b914318..1e69f7306 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -71,17 +71,22 @@ td > code { /*Adds type of content to listingblock*/ -.listingblock > .content { +.listingblock { + margin-bottom: 1rem; + margin-top: 1rem; +} + +.listingblock > .pf-c-code-block { position: relative; } -.listingblock code[data-lang]::before { +.listingblock div[data-lang]::before { content: attr(data-lang); position: absolute; font-size: 0.75em; top: 0.425rem; - right: 0.5rem; - line-height: 1; + left: 0.5rem; + line-height: 2; text-transform: uppercase; color: inherit; opacity: 0.5; diff --git a/static/js/codeblock.js b/static/js/codeblock.js new file mode 100644 index 000000000..c1c801e82 --- /dev/null +++ b/static/js/codeblock.js @@ -0,0 +1,91 @@ +function createElementAndClass(element, classes) { + result = document.createElement(element); + result.className = classes; + return result; +} + +function createCopyButton(highlightDiv) { + const codeBlockActionsCopyButton = createElementAndClass("button", "pf-c-button pf-m-plain"); + codeBlockActionsCopyButton.type = "button"; + codeBlockActionsCopyButton.addEventListener("click", () => + copyCodeToClipboard(codeBlockActionsCopyButton, highlightDiv) + ); + const codeBlockActionsCopyButtonIcon = createElementAndClass("i", "fas fa-copy"); + codeBlockActionsCopyButton.appendChild(codeBlockActionsCopyButtonIcon); + addCopyButtonToDom(codeBlockActionsCopyButton, highlightDiv); +} + +async function copyCodeToClipboard(button, highlightDiv) { + const codeToCopy = highlightDiv.querySelector(":last-child > .highlight > code") + .innerText; + try { + result = await navigator.permissions.query({ name: "clipboard-write" }); + if (result.state == "granted" || result.state == "prompt") { + await navigator.clipboard.writeText(codeToCopy); + } else { + copyCodeBlockExecCommand(codeToCopy, highlightDiv); + } + } catch (_) { + copyCodeBlockExecCommand(codeToCopy, highlightDiv); + } finally { + + codeWasCopied(button); + } +} + +function copyCodeBlockExecCommand(codeToCopy, highlightDiv) { + const textArea = document.createElement("textArea"); + textArea.contentEditable = "true"; + textArea.readOnly = "false"; + textArea.className = "copyable-text-area"; + textArea.value = codeToCopy; + highlightDiv.insertBefore(textArea, highlightDiv.firstChild); + const range = document.createRange(); + range.selectNodeContents(textArea); + const sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + textArea.setSelectionRange(0, 999999); + document.execCommand("copy"); + highlightDiv.removeChild(textArea); +} + +function codeWasCopied(button) { + button.blur(); + const icon = document.createElement("i"); + icon.className = "fas fa-check"; + button.replaceChild(icon, button.firstChild); + setTimeout(function () { + const icon = document.createElement("i"); + icon.className = "fas fa-copy"; + button.replaceChild(icon, button.firstChild); + }, 2000); +} + +function addCopyButtonToDom(button, highlightDiv) { + dataLang = highlightDiv.querySelector("pre > code[data-lang]").attributes["data-lang"].value; + highlightDiv.classList.add("pf-c-code-block__content") + pre = highlightDiv.getElementsByTagName("pre"); + pre[0].classList.add("pf-c-code-block__pre") + code = pre[0].getElementsByTagName("code"); + code[0].classList.add("pf-c-code-block__code") + console.log(highlightDiv); + highlightDiv.insertBefore(button, highlightDiv.firstChild); + const codeBlock = createElementAndClass("div", "pf-c-code-block"); + codeBlock.setAttribute("data-lang", dataLang) + const codeBlockHeader = createElementAndClass("div", "pf-c-code-block__header"); + const codeBlockActions = createElementAndClass("div", "pf-c-code-block__actions"); + const codeBlockActionsCopy = createElementAndClass("div", "pf-c-code-block__actions-item"); + codeBlockActionsCopy.appendChild(button); + codeBlockActions.appendChild(codeBlockActionsCopy); + codeBlockHeader.appendChild(codeBlockActions); + codeBlock.appendChild(codeBlockHeader); + highlightDiv.parentNode.insertBefore(codeBlock, highlightDiv); + codeBlock.appendChild(highlightDiv); + // const wrapper = document.createElement("div"); + // wrapper.className = "highlight-wrapper"; + // highlightDiv.parentNode.insertBefore(wrapper, highlightDiv); + // wrapper.appendChild(highlightDiv); +} + +document.querySelectorAll(".listingblock .content").forEach((highlightDiv) => createCopyButton(highlightDiv));