From b63a9921ea6300f2c9a15aa0851ab95fbd13f6e8 Mon Sep 17 00:00:00 2001 From: SnehaChaursia Date: Tue, 24 Feb 2026 23:49:07 +0530 Subject: [PATCH] Add copy-to-clipboard button for code snippets --- _includes/footer.html | 1 + css/customstyles-precice.css | 36 ++++++++++++++++++++++++ js/copy-code.js | 54 ++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 js/copy-code.js diff --git a/_includes/footer.html b/_includes/footer.html index 7bd28c61921..b7de5a3ef10 100644 --- a/_includes/footer.html +++ b/_includes/footer.html @@ -62,4 +62,5 @@

The preCICE newsletter

+ diff --git a/css/customstyles-precice.css b/css/customstyles-precice.css index d2f06afc241..fc65ec87d91 100644 --- a/css/customstyles-precice.css +++ b/css/customstyles-precice.css @@ -376,3 +376,39 @@ details > summary::after { details[open] > summary::after { content: "▲"; } + +/* Copy to Clipboard Button Styles */ +div.highlighter-rouge { + position: relative; +} + +.copy-code-btn { + position: absolute; + top: 5px; + right: 5px; + padding: 4px 8px; + font-size: 12px; + color: #555; + background-color: #f8f9fa; + border: 1px solid #ccc; + border-radius: 4px; + cursor: pointer; + opacity: 0; + transition: opacity 0.2s, background-color 0.2s, color 0.2s; + z-index: 10; +} + +div.highlighter-rouge:hover .copy-code-btn { + opacity: 1; +} + +.copy-code-btn:hover { + background-color: #e2e6ea; + color: #333; +} + +.copy-code-btn.copied { + background-color: #28a745; + color: white; + border-color: #28a745; +} diff --git a/js/copy-code.js b/js/copy-code.js new file mode 100644 index 00000000000..2d8a7085055 --- /dev/null +++ b/js/copy-code.js @@ -0,0 +1,54 @@ +document.addEventListener('DOMContentLoaded', () => { + const codeBlocks = document.querySelectorAll('div.highlighter-rouge'); + + codeBlocks.forEach(codeBlock => { + const copyButton = document.createElement('button'); + copyButton.className = 'copy-code-btn'; + copyButton.innerHTML = ' Copy'; + copyButton.setAttribute('aria-label', 'Copy code to clipboard'); + + codeBlock.appendChild(copyButton); + + copyButton.addEventListener('click', async () => { + const code = codeBlock.querySelector('code'); + if (!code) return; + + try { + const textToCopy = code.textContent; + + if (navigator.clipboard && window.isSecureContext) { + await navigator.clipboard.writeText(textToCopy); + } else { + // Fallback for HTTP (non-secure) contexts + const textArea = document.createElement("textarea"); + textArea.value = textToCopy; + textArea.style.position = "fixed"; + textArea.style.left = "-999999px"; + textArea.style.top = "-999999px"; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + document.execCommand('copy'); + } catch (err) { + console.error('Fallback copy failed', err); + } + textArea.remove(); + } + + // Visual feedback + const originalHtml = copyButton.innerHTML; + copyButton.innerHTML = ' Copied!'; + copyButton.classList.add('copied'); + + setTimeout(() => { + copyButton.innerHTML = originalHtml; + copyButton.classList.remove('copied'); + }, 2000); + } catch (err) { + console.error('Failed to copy text: ', err); + } + }); + }); +});