Newer
Older
gnexus-ui-kit / src / js / code-examples.js
function fallbackCopy(text) {
  const textarea = document.createElement("textarea");
  textarea.value = text;
  textarea.setAttribute("readonly", "readonly");
  textarea.style.position = "fixed";
  textarea.style.opacity = "0";
  document.body.append(textarea);
  textarea.select();
  document.execCommand("copy");
  textarea.remove();
}

function escapeHtml(text) {
  return text
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;");
}

function highlightJavascript(code) {
  const source = code.textContent;
  const tokens = /\/\/.*$|\/\*[\s\S]*?\*\/|`(?:\\[\s\S]|[^`\\])*`|'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|\b(?:async|await|break|case|catch|class|const|continue|default|do|else|export|for|from|function|if|import|let|new|null|return|switch|throw|try|var|while)\b|\b\d+(?:\.\d+)?\b|\b[A-Za-z_$][\w$]*(?=\s*\()/gm;
  let html = "";
  let cursor = 0;
  let match;

  while ((match = tokens.exec(source)) !== null) {
    const token = match[0];
    html += escapeHtml(source.slice(cursor, match.index));

    if (token.startsWith("//") || token.startsWith("/*")) {
      html += `<span class="hljs-comment">${escapeHtml(token)}</span>`;
    } else if (token.startsWith("\"") || token.startsWith("'") || token.startsWith("`")) {
      html += `<span class="hljs-string">${escapeHtml(token)}</span>`;
    } else if (/^\d/.test(token)) {
      html += `<span class="hljs-number">${escapeHtml(token)}</span>`;
    } else if (/^[A-Za-z_$][\w$]*$/.test(token) && source[match.index + token.length]?.match(/\s|\(/)) {
      const keyword = /^(async|await|break|case|catch|class|const|continue|default|do|else|export|for|from|function|if|import|let|new|null|return|switch|throw|try|var|while)$/.test(token);
      html += keyword
        ? `<span class="hljs-keyword">${token}</span>`
        : `<span class="hljs-title function_">${token}</span>`;
    } else {
      html += escapeHtml(token);
    }

    cursor = match.index + token.length;
  }

  html += escapeHtml(source.slice(cursor));
  code.innerHTML = html;
  code.classList.add("hljs");
}

function highlightCode() {
  document.querySelectorAll("code.language-js, code.language-javascript").forEach(highlightJavascript);

  if (window.hljs) {
    document
      .querySelectorAll("code:not(.language-js):not(.language-javascript)")
      .forEach(code => window.hljs.highlightElement(code));
  }
}

export default function codeExamples() {
  highlightCode();

  document.querySelectorAll(".code-example-copy").forEach(button => {
    button.addEventListener("click", async () => {
      const example = button.closest(".code-example");
      const code = example?.querySelector("code");
      const text = code?.textContent ?? "";
      const originalText = button.textContent;

      if (!text) {
        return;
      }

      try {
        if (navigator.clipboard?.writeText) {
          await navigator.clipboard.writeText(text);
        } else {
          fallbackCopy(text);
        }

        button.textContent = "Copied";
      } catch (err) {
        fallbackCopy(text);
        button.textContent = "Copied";
      }

      setTimeout(() => {
        button.textContent = originalText;
      }, 1200);
    });
  });
}