From deb80b1c46a775a72e007d4c3ab16dd2317b3c7e Mon Sep 17 00:00:00 2001 From: jakecastelli <38635403+jakecastelli@users.noreply.github.com> Date: Sat, 25 Mar 2023 19:11:43 +1030 Subject: [PATCH] tools: add button to copy code example to clipboard PR-URL: https://github.com/nodejs/node/pull/46928 Refs: https://github.com/nodejs/node/issues/46894 Reviewed-By: Debadree Chatterjee --- doc/api_assets/api.js | 32 ++++++++++++++++++++++++++++++++ doc/api_assets/style.css | 27 +++++++++++++++++++++++++++ tools/doc/html.mjs | 8 ++++++-- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/doc/api_assets/api.js b/doc/api_assets/api.js index 49906b1a2abab5..c1151ae493e8da 100644 --- a/doc/api_assets/api.js +++ b/doc/api_assets/api.js @@ -136,6 +136,36 @@ updateHashes(); } + function setupCopyButton() { + const buttons = document.querySelectorAll('.copy-button'); + buttons.forEach((button) => { + button.addEventListener('click', (el) => { + const parentNode = el.target.parentNode; + + const flavorSelector = parentNode.querySelector('.js-flavor-selector'); + + let code = ''; + + if (flavorSelector) { + if (flavorSelector.checked) { + code = parentNode.querySelector('.mjs').textContent; + } else { + code = parentNode.querySelector('.cjs').textContent; + } + } else { + code = parentNode.querySelector('code').textContent; + } + + button.textContent = 'Copied'; + navigator.clipboard.writeText(code); + + setTimeout(() => { + button.textContent = 'Copy'; + }, 2500); + }); + }); + } + function bootstrap() { // Check if we have JavaScript support. document.documentElement.classList.add('has-js'); @@ -151,6 +181,8 @@ // Make link to other versions of the doc open to the same hash target (if it exists). setupAltDocsLink(); + + setupCopyButton(); } if (document.readyState === 'loading') { diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index 42126949d55d5c..6b27fa1fb71b94 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -973,6 +973,33 @@ kbd { .dark-mode .js-flavor-selector { filter: invert(1); } + +.copy-button { + float: right; + + outline: none; + font-size: 10px; + color: #fff; + background-color: var(--green1); + line-height: 1; + border-radius: 500px; + border: 1px solid transparent; + letter-spacing: 2px; + min-width: 7.5rem; + text-transform: uppercase; + font-weight: 700; + padding: 0 .5rem; + margin-right: .2rem; + height: 1.5rem; + transition-property: background-color,border-color,color,box-shadow,filter; + transition-duration: .3s; + cursor: pointer; +} + +.copy-button:hover { + background-color: var(--green2); +} + @supports (aspect-ratio: 1 / 1) { .js-flavor-selector { height: 1.5em; diff --git a/tools/doc/html.mjs b/tools/doc/html.mjs index 86df5162f58000..d5dd7973e206ac 100644 --- a/tools/doc/html.mjs +++ b/tools/doc/html.mjs @@ -226,10 +226,13 @@ export function preprocessElements({ filename }) { const className = isJSFlavorSnippet(node) ? `language-js ${node.lang}` : `language-${node.lang}`; + const highlighted = `${(getLanguage(node.lang || '') ? highlight(node.value, { language: node.lang }) : node).value}`; node.type = 'html'; + const copyButton = ''; + if (isJSFlavorSnippet(node)) { const previousNode = parent.children[index - 1] || {}; const nextNode = parent.children[index + 1] || {}; @@ -253,16 +256,17 @@ export function preprocessElements({ filename }) { ' aria-label="Show modern ES modules syntax">' + previousNode.value + highlighted + + copyButton + ''; node.lang = null; previousNode.value = ''; previousNode.lang = null; } else { // Isolated JS snippet, no need to add the checkbox. - node.value = `
${highlighted}
`; + node.value = `
${highlighted} ${copyButton}
`; } } else { - node.value = `
${highlighted}
`; + node.value = `
${highlighted} ${copyButton}
`; } } else if (node.type === 'html' && common.isYAMLBlock(node.value)) { node.value = parseYAML(node.value);