Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tools: add button to copy code example to clipboard #46928

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions doc/api_assets/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,36 @@
updateHashes();
}

function setupCopyButton() {
const buttons = document.querySelectorAll('.copy-button');
buttons.forEach((button) => {
button.addEventListener('click', (el) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The event handler may be able to extract.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @btea thank you for your feedback, I am just not too sure if it is worth the effort of function extraction.

  • The code is temp and won't live in the future doc tool
  • the function is relatively short and straightforward

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, what you said makes sense. I made this point because each page of the nodejs official website has a lot of content, and some have many code blocks, so there may be many bindings of the same event, so I think it is worth extracting.

Anyway, I think this feature looks great 👍

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');
Expand All @@ -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') {
Expand Down
27 changes: 27 additions & 0 deletions doc/api_assets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 6 additions & 2 deletions tools/doc/html.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,13 @@ export function preprocessElements({ filename }) {
const className = isJSFlavorSnippet(node) ?
`language-js ${node.lang}` :
`language-${node.lang}`;

const highlighted =
`<code class='${className}'>${(getLanguage(node.lang || '') ? highlight(node.value, { language: node.lang }) : node).value}</code>`;
node.type = 'html';

const copyButton = '<button class="copy-button">copy</button>';

if (isJSFlavorSnippet(node)) {
const previousNode = parent.children[index - 1] || {};
const nextNode = parent.children[index + 1] || {};
Expand All @@ -253,16 +256,17 @@ export function preprocessElements({ filename }) {
' aria-label="Show modern ES modules syntax">' +
previousNode.value +
highlighted +
copyButton +
'</pre>';
node.lang = null;
previousNode.value = '';
previousNode.lang = null;
} else {
// Isolated JS snippet, no need to add the checkbox.
node.value = `<pre>${highlighted}</pre>`;
node.value = `<pre>${highlighted} ${copyButton}</pre>`;
}
} else {
node.value = `<pre>${highlighted}</pre>`;
node.value = `<pre>${highlighted} ${copyButton}</pre>`;
}
} else if (node.type === 'html' && common.isYAMLBlock(node.value)) {
node.value = parseYAML(node.value);
Expand Down