Skip to content
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
33 changes: 33 additions & 0 deletions src/core/clipboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// @ts-check
/**
* Module core/clipboard
*
* Shared clipboard copy button for code blocks (WebIDL, CDDL, etc.).
*/

const COPY_SVG =
'<svg height="16" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M2 13h4v1H2v-1zm5-6H2v1h5V7zm2 3V8l-3 3 3 3v-2h5v-2H9zM4.5 9H2v1h2.5V9zM2 12h2.5v-1H2v1zm9 1h1v2c-.02.28-.11.52-.3.7-.19.18-.42.28-.7.3H1c-.55 0-1-.45-1-1V4c0-.55.45-1 1-1h3c0-1.11.89-2 2-2 1.11 0 2 .89 2 2h3c.55 0 1 .45 1 1v5h-1V6H1v9h10v-2zM2 5h8c0-.55-.45-1-1-1H8c-.55 0-1-.45-1-1s-.45-1-1-1-1 .45-1 1-.45 1-1 1H3c-.55 0-1 .45-1 1z"/></svg>';

/**
* Create a copy-to-clipboard button for a code block.
* The button excludes the header element (matched by headerSelector) from copy.
*
* @param {string} headerSelector - Selector for the header to exclude from copy
* @param {string} [title="Copy to clipboard"] - Accessible label and tooltip for the copy button
* @returns {HTMLButtonElement}
*/
export function createCopyButton(headerSelector, title = "Copy to clipboard") {
const button = document.createElement("button");
button.innerHTML = COPY_SVG;
button.title = title;
button.setAttribute("aria-label", title);
button.classList.add("respec-button-copy-paste", "removeOnSave");
button.addEventListener("click", () => {
const pre = button.closest("pre");
if (!pre) return;
const clone = /** @type {HTMLElement} */ (pre.cloneNode(true));
clone.querySelector(headerSelector)?.remove();
navigator.clipboard.writeText(clone.textContent ?? "");
});
return button;
}
25 changes: 2 additions & 23 deletions src/core/webidl-clipboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,14 @@
* well-formatted IDL to the clipboard.
*
*/
import { createCopyButton } from "./clipboard.js";
export const name = "core/webidl-clipboard";

function createButton() {
const copyButton = document.createElement("button");
copyButton.innerHTML =
'<svg height="16" viewBox="0 0 14 16" width="14"><path fill-rule="evenodd" d="M2 13h4v1H2v-1zm5-6H2v1h5V7zm2 3V8l-3 3 3 3v-2h5v-2H9zM4.5 9H2v1h2.5V9zM2 12h2.5v-1H2v1zm9 1h1v2c-.02.28-.11.52-.3.7-.19.18-.42.28-.7.3H1c-.55 0-1-.45-1-1V4c0-.55.45-1 1-1h3c0-1.11.89-2 2-2 1.11 0 2 .89 2 2h3c.55 0 1 .45 1 1v5h-1V6H1v9h10v-2zM2 5h8c0-.55-.45-1-1-1H8c-.55 0-1-.45-1-1s-.45-1-1-1-1 .45-1 1-.45 1-1 1H3c-.55 0-1 .45-1 1z"/></svg>';
copyButton.title = "Copy IDL to clipboard";
copyButton.classList.add("respec-button-copy-paste", "removeOnSave");
return copyButton;
}

const copyButton = createButton();

/**
* Adds a HTML button that copies WebIDL to the clipboard.
*
* @param {HTMLSpanElement} idlHeader
*/
export function addCopyIDLButton(idlHeader) {
// There may be multiple <span>s of IDL, so we take everything
// apart from the idl header.
const pre = idlHeader.closest("pre.idl");
if (!pre) return;
const idl = pre.cloneNode(true);
idl.querySelector(".idlHeader")?.remove();
const { textContent: idlText } = idl;
const button = copyButton.cloneNode(true);
button.addEventListener("click", () => {
navigator.clipboard.writeText(idlText);
});
idlHeader.append(button);
idlHeader.append(createCopyButton(".idlHeader", "Copy IDL to clipboard"));
}
5 changes: 4 additions & 1 deletion tests/spec/core/markdown-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,10 @@ describe("Core - Markdown", () => {
expect(webidlBlock.classList).toContain("idl");
expect(webidlBlock.querySelector("code.hljs")).toBeNull();
expect(webidlBlock.querySelector(".idlConstructor")).not.toBeNull();
expect(webidlBlock.querySelector(".respec-button-copy-paste")).toBeTruthy();
const copyButton = webidlBlock.querySelector(".respec-button-copy-paste");
expect(copyButton).toBeTruthy();
expect(copyButton.title).toBe("Copy IDL to clipboard");
expect(copyButton.getAttribute("aria-label")).toBe("Copy IDL to clipboard");

expect(jsBlock.firstElementChild.localName).toBe("code");
expect(jsBlock.querySelector("code.hljs").classList).toContain("js");
Expand Down
Loading