chunk-012-copy-code.js

I’ll build this as a reusable RX Theme static chunk: safe copy-code buttons, toolbar actions, accessibility labels, toast messages, keyboard support, fallback clipboard methods, and WordPress-friendly no-dependency JavaScript.

Yes friend — create this file:

assets/static-js/static-chunks-js/chunk-012-copy-code.js

Paste this full advanced code inside it.

/*!
 * RX Theme - Static Chunk 012: Advanced Copy Code System
 * File: assets/static-js/static-chunks-js/chunk-012-copy-code.js
 * Theme: RX Theme
 * Author: RxHarun
 *
 * Features:
 * - Auto adds copy buttons to code blocks
 * - Works with <pre><code>, <pre>, and custom selectors
 * - Clipboard API with fallback method
 * - Accessible buttons with aria-label
 * - Copy success/error toast
 * - Optional line numbers
 * - Optional code language label
 * - Optional select-all button
 * - Optional collapse/expand for long code
 * - Optional double-click copy
 * - Prevents duplicate initialization
 * - Works after AJAX/dynamic content
 */

(function () {
  'use strict';

  var RX_COPY_CODE_VERSION = '1.0.0';

  var DEFAULT_OPTIONS = {
    root: document,
    selector: 'pre',
    codeSelector: 'code',
    wrapperClass: 'rx-code-copy-wrapper',
    toolbarClass: 'rx-code-copy-toolbar',
    buttonClass: 'rx-code-copy-button',
    selectButtonClass: 'rx-code-select-button',
    collapseButtonClass: 'rx-code-collapse-button',
    copiedClass: 'is-copied',
    failedClass: 'is-failed',
    initializedAttr: 'data-rx-copy-code-init',
    languageAttr: 'data-language',
    copiedText: 'Copied!',
    copyText: 'Copy',
    copyErrorText: 'Copy failed',
    selectText: 'Select',
    collapseText: 'Collapse',
    expandText: 'Expand',
    enableToast: true,
    enableLanguageLabel: true,
    enableSelectButton: true,
    enableCollapseButton: true,
    enableDoubleClickCopy: true,
    enableKeyboardShortcut: true,
    enableLineNumbers: false,
    minLinesForCollapse: 18,
    buttonResetDelay: 1600,
    toastDuration: 2200,
    maxToastCount: 3
  };

  var state = {
    toastContainer: null,
    activeToasts: [],
    observer: null,
    options: null
  };

  function extend(target) {
    var sources = Array.prototype.slice.call(arguments, 1);

    sources.forEach(function (source) {
      if (!source) return;

      Object.keys(source).forEach(function (key) {
        target[key] = source[key];
      });
    });

    return target;
  }

  function ready(callback) {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', callback, { once: true });
    } else {
      callback();
    }
  }

  function isElement(node) {
    return node && node.nodeType === 1;
  }

  function createElement(tag, className, text) {
    var element = document.createElement(tag);

    if (className) {
      element.className = className;
    }

    if (typeof text === 'string') {
      element.textContent = text;
    }

    return element;
  }

  function normalizeText(text) {
    if (!text) return '';

    return String(text)
      .replace(/\u00a0/g, ' ')
      .replace(/\r\n/g, '\n')
      .replace(/\r/g, '\n')
      .replace(/\n+$/g, '');
  }

  function getCodeElement(pre, options) {
    if (!pre) return null;

    if (pre.matches && pre.matches(options.codeSelector)) {
      return pre;
    }

    return pre.querySelector(options.codeSelector) || pre;
  }

  function getCodeText(pre, options) {
    var codeElement = getCodeElement(pre, options);

    if (!codeElement) return '';

    var clone = codeElement.cloneNode(true);

    var ignored = clone.querySelectorAll(
      '.rx-code-copy-toolbar, .rx-code-language-label, .rx-code-line-number, .rx-code-line-numbers'
    );

    ignored.forEach(function (node) {
      node.remove();
    });

    return normalizeText(clone.innerText || clone.textContent || '');
  }

  function getLineCount(text) {
    if (!text) return 0;
    return text.split('\n').length;
  }

  function detectLanguage(pre, codeElement) {
    var language = '';

    if (pre.getAttribute('data-language')) {
      language = pre.getAttribute('data-language');
    }

    if (!language && codeElement && codeElement.getAttribute('data-language')) {
      language = codeElement.getAttribute('data-language');
    }

    if (!language && codeElement && codeElement.className) {
      var match = String(codeElement.className).match(/language-([a-zA-Z0-9_-]+)/);

      if (match && match[1]) {
        language = match[1];
      }
    }

    if (!language && pre.className) {
      var preMatch = String(pre.className).match(/language-([a-zA-Z0-9_-]+)/);

      if (preMatch && preMatch[1]) {
        language = preMatch[1];
      }
    }

    if (!language) {
      language = 'code';
    }

    return language
      .replace(/-/g, ' ')
      .replace(/_/g, ' ')
      .trim()
      .toUpperCase();
  }

  function copyUsingClipboardApi(text) {
    if (
      navigator.clipboard &&
      window.isSecureContext &&
      typeof navigator.clipboard.writeText === 'function'
    ) {
      return navigator.clipboard.writeText(text);
    }

    return Promise.reject(new Error('Clipboard API unavailable'));
  }

  function copyUsingFallback(text) {
    return new Promise(function (resolve, reject) {
      var textarea = document.createElement('textarea');

      textarea.value = text;
      textarea.setAttribute('readonly', '');
      textarea.setAttribute('aria-hidden', 'true');

      textarea.style.position = 'fixed';
      textarea.style.top = '-9999px';
      textarea.style.left = '-9999px';
      textarea.style.width = '1px';
      textarea.style.height = '1px';
      textarea.style.opacity = '0';
      textarea.style.pointerEvents = 'none';

      document.body.appendChild(textarea);

      textarea.focus();
      textarea.select();

      try {
        var successful = document.execCommand('copy');

        document.body.removeChild(textarea);

        if (successful) {
          resolve();
        } else {
          reject(new Error('Fallback copy failed'));
        }
      } catch (error) {
        document.body.removeChild(textarea);
        reject(error);
      }
    });
  }

  function copyText(text) {
    return copyUsingClipboardApi(text).catch(function () {
      return copyUsingFallback(text);
    });
  }

  function ensureToastContainer() {
    if (state.toastContainer) {
      return state.toastContainer;
    }

    var container = createElement('div', 'rx-copy-toast-container');

    container.setAttribute('aria-live', 'polite');
    container.setAttribute('aria-atomic', 'true');

    document.body.appendChild(container);

    state.toastContainer = container;

    return container;
  }

  function showToast(message, type, options) {
    if (!options.enableToast) return;

    var container = ensureToastContainer();

    while (state.activeToasts.length >= options.maxToastCount) {
      var oldToast = state.activeToasts.shift();

      if (oldToast && oldToast.parentNode) {
        oldToast.parentNode.removeChild(oldToast);
      }
    }

    var toast = createElement('div', 'rx-copy-toast rx-copy-toast-' + type, message);

    container.appendChild(toast);
    state.activeToasts.push(toast);

    window.setTimeout(function () {
      toast.classList.add('is-visible');
    }, 20);

    window.setTimeout(function () {
      toast.classList.remove('is-visible');

      window.setTimeout(function () {
        if (toast.parentNode) {
          toast.parentNode.removeChild(toast);
        }

        state.activeToasts = state.activeToasts.filter(function (item) {
          return item !== toast;
        });
      }, 300);
    }, options.toastDuration);
  }

  function setButtonState(button, stateName, text, options) {
    if (!button) return;

    button.classList.remove(options.copiedClass);
    button.classList.remove(options.failedClass);

    if (stateName === 'copied') {
      button.classList.add(options.copiedClass);
    }

    if (stateName === 'failed') {
      button.classList.add(options.failedClass);
    }

    button.textContent = text;
    button.setAttribute('aria-label', text);
  }

  function resetCopyButton(button, options) {
    window.setTimeout(function () {
      if (!button) return;

      button.classList.remove(options.copiedClass);
      button.classList.remove(options.failedClass);
      button.textContent = options.copyText;
      button.setAttribute('aria-label', options.copyText);
    }, options.buttonResetDelay);
  }

  function selectCode(pre, options) {
    var codeElement = getCodeElement(pre, options);

    if (!codeElement) return;

    var range = document.createRange();
    var selection = window.getSelection();

    range.selectNodeContents(codeElement);

    selection.removeAllRanges();
    selection.addRange(range);

    showToast('Code selected', 'info', options);
  }

  function toggleCollapse(pre, button, options) {
    var isCollapsed = pre.classList.toggle('rx-code-is-collapsed');

    if (isCollapsed) {
      button.textContent = options.expandText;
      button.setAttribute('aria-label', options.expandText);
      button.setAttribute('aria-expanded', 'false');
    } else {
      button.textContent = options.collapseText;
      button.setAttribute('aria-label', options.collapseText);
      button.setAttribute('aria-expanded', 'true');
    }
  }

  function addLanguageLabel(wrapper, pre, codeElement, options) {
    if (!options.enableLanguageLabel) return;

    if (wrapper.querySelector('.rx-code-language-label')) return;

    var language = detectLanguage(pre, codeElement);
    var label = createElement('span', 'rx-code-language-label', language);

    label.setAttribute(options.languageAttr, language);

    wrapper.appendChild(label);
  }

  function addLineNumbers(pre, text, options) {
    if (!options.enableLineNumbers) return;

    if (pre.querySelector('.rx-code-line-numbers')) return;

    var lineCount = getLineCount(text);

    if (lineCount < 2) return;

    var numbers = createElement('span', 'rx-code-line-numbers');

    numbers.setAttribute('aria-hidden', 'true');

    var fragment = document.createDocumentFragment();

    for (var i = 1; i <= lineCount; i += 1) {
      var line = createElement('span', 'rx-code-line-number', String(i));
      fragment.appendChild(line);
    }

    numbers.appendChild(fragment);
    pre.insertBefore(numbers, pre.firstChild);
    pre.classList.add('rx-code-has-line-numbers');
  }

  function createToolbar(pre, options) {
    var toolbar = createElement('div', options.toolbarClass);

    toolbar.setAttribute('role', 'toolbar');
    toolbar.setAttribute('aria-label', 'Code tools');

    var copyButton = createElement('button', options.buttonClass, options.copyText);

    copyButton.type = 'button';
    copyButton.setAttribute('aria-label', options.copyText);

    copyButton.addEventListener('click', function () {
      var text = getCodeText(pre, options);

      if (!text.trim()) {
        setButtonState(copyButton, 'failed', options.copyErrorText, options);
        showToast(options.copyErrorText, 'error', options);
        resetCopyButton(copyButton, options);
        return;
      }

      copyText(text)
        .then(function () {
          setButtonState(copyButton, 'copied', options.copiedText, options);
          showToast(options.copiedText, 'success', options);
          resetCopyButton(copyButton, options);
        })
        .catch(function () {
          setButtonState(copyButton, 'failed', options.copyErrorText, options);
          showToast(options.copyErrorText, 'error', options);
          resetCopyButton(copyButton, options);
        });
    });

    toolbar.appendChild(copyButton);

    if (options.enableSelectButton) {
      var selectButton = createElement('button', options.selectButtonClass, options.selectText);

      selectButton.type = 'button';
      selectButton.setAttribute('aria-label', options.selectText);

      selectButton.addEventListener('click', function () {
        selectCode(pre, options);
      });

      toolbar.appendChild(selectButton);
    }

    if (options.enableCollapseButton) {
      var text = getCodeText(pre, options);
      var lineCount = getLineCount(text);

      if (lineCount >= options.minLinesForCollapse) {
        var collapseButton = createElement(
          'button',
          options.collapseButtonClass,
          options.expandText
        );

        collapseButton.type = 'button';
        collapseButton.setAttribute('aria-label', options.expandText);
        collapseButton.setAttribute('aria-expanded', 'false');

        pre.classList.add('rx-code-is-collapsed');
        pre.setAttribute('data-rx-code-lines', String(lineCount));

        collapseButton.addEventListener('click', function () {
          toggleCollapse(pre, collapseButton, options);
        });

        toolbar.appendChild(collapseButton);
      }
    }

    return toolbar;
  }

  function wrapPre(pre, options) {
    if (!isElement(pre)) return null;

    if (pre.getAttribute(options.initializedAttr) === 'true') {
      return null;
    }

    if (pre.closest('.' + options.wrapperClass)) {
      pre.setAttribute(options.initializedAttr, 'true');
      return pre.closest('.' + options.wrapperClass);
    }

    var wrapper = createElement('div', options.wrapperClass);

    pre.parentNode.insertBefore(wrapper, pre);
    wrapper.appendChild(pre);

    return wrapper;
  }

  function initSingleCodeBlock(pre, customOptions) {
    var options = extend({}, DEFAULT_OPTIONS, state.options || {}, customOptions || {});

    if (!pre || !pre.parentNode) return;

    if (pre.getAttribute(options.initializedAttr) === 'true') return;

    var codeElement = getCodeElement(pre, options);
    var text = getCodeText(pre, options);

    if (!text.trim()) return;

    var wrapper = wrapPre(pre, options);

    if (!wrapper) return;

    wrapper.classList.add('rx-code-copy-ready');

    pre.setAttribute(options.initializedAttr, 'true');
    pre.classList.add('rx-code-block');

    if (codeElement && codeElement !== pre) {
      codeElement.classList.add('rx-code-inner');
    }

    addLanguageLabel(wrapper, pre, codeElement, options);
    addLineNumbers(pre, text, options);

    if (!wrapper.querySelector('.' + options.toolbarClass)) {
      var toolbar = createToolbar(pre, options);
      wrapper.appendChild(toolbar);
    }

    if (options.enableDoubleClickCopy) {
      pre.addEventListener('dblclick', function () {
        var currentText = getCodeText(pre, options);

        if (!currentText.trim()) return;

        copyText(currentText)
          .then(function () {
            showToast(options.copiedText, 'success', options);
          })
          .catch(function () {
            showToast(options.copyErrorText, 'error', options);
          });
      });
    }
  }

  function initCodeBlocks(customOptions) {
    var options = extend({}, DEFAULT_OPTIONS, state.options || {}, customOptions || {});
    var root = options.root || document;

    state.options = options;

    if (!root.querySelectorAll) return;

    var blocks = root.querySelectorAll(options.selector);

    blocks.forEach(function (pre) {
      initSingleCodeBlock(pre, options);
    });
  }

  function observeDynamicContent(options) {
    if (state.observer) return;

    if (!('MutationObserver' in window)) return;

    state.observer = new MutationObserver(function (mutations) {
      var shouldScan = false;

      mutations.forEach(function (mutation) {
        if (shouldScan) return;

        mutation.addedNodes.forEach(function (node) {
          if (shouldScan) return;

          if (!isElement(node)) return;

          if (
            node.matches &&
            (node.matches(options.selector) || node.querySelector(options.selector))
          ) {
            shouldScan = true;
          }
        });
      });

      if (shouldScan) {
        window.requestAnimationFrame(function () {
          initCodeBlocks(options);
        });
      }
    });

    state.observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  function handleKeyboardShortcut(options) {
    if (!options.enableKeyboardShortcut) return;

    document.addEventListener('keydown', function (event) {
      var isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
      var modifier = isMac ? event.metaKey : event.ctrlKey;

      if (!modifier || event.shiftKey || event.altKey) return;

      if (String(event.key).toLowerCase() !== 'c') return;

      var active = document.activeElement;

      if (!active) return;

      var wrapper = active.closest && active.closest('.' + options.wrapperClass);

      if (!wrapper) return;

      var pre = wrapper.querySelector(options.selector);

      if (!pre) return;

      var selection = window.getSelection();

      if (selection && String(selection).trim()) {
        return;
      }

      event.preventDefault();

      var text = getCodeText(pre, options);

      if (!text.trim()) return;

      copyText(text)
        .then(function () {
          showToast(options.copiedText, 'success', options);
        })
        .catch(function () {
          showToast(options.copyErrorText, 'error', options);
        });
    });
  }

  function injectBaseStyles() {
    if (document.getElementById('rx-copy-code-style')) return;

    var css = [
      '.rx-code-copy-wrapper{position:relative;margin:1.5rem 0;}',
      '.rx-code-copy-wrapper pre{position:relative;overflow:auto;padding-top:3rem;}',
      '.rx-code-copy-toolbar{position:absolute;top:.5rem;right:.5rem;z-index:5;display:flex;gap:.4rem;align-items:center;}',
      '.rx-code-copy-toolbar button{border:1px solid rgba(120,120,120,.35);border-radius:.45rem;background:rgba(255,255,255,.92);color:#222;font-size:.78rem;line-height:1;padding:.48rem .65rem;cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,.08);}',
      '.rx-code-copy-toolbar button:hover{background:#fff;}',
      '.rx-code-copy-toolbar button:focus{outline:2px solid currentColor;outline-offset:2px;}',
      '.rx-code-copy-button.is-copied{font-weight:700;}',
      '.rx-code-copy-button.is-failed{font-weight:700;}',
      '.rx-code-language-label{position:absolute;top:.65rem;left:.75rem;z-index:4;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;opacity:.72;}',
      '.rx-code-is-collapsed{max-height:24rem;overflow:hidden;}',
      '.rx-code-is-collapsed:after{content:"";position:absolute;left:0;right:0;bottom:0;height:4rem;background:linear-gradient(to bottom,rgba(255,255,255,0),rgba(255,255,255,.9));pointer-events:none;}',
      '.rx-code-has-line-numbers{display:grid;grid-template-columns:auto 1fr;gap:0;}',
      '.rx-code-line-numbers{user-select:none;text-align:right;padding-right:1rem;margin-right:1rem;border-right:1px solid rgba(120,120,120,.25);opacity:.55;}',
      '.rx-code-line-number{display:block;line-height:inherit;}',
      '.rx-code-inner{min-width:0;}',
      '.rx-copy-toast-container{position:fixed;right:1rem;bottom:1rem;z-index:99999;display:flex;flex-direction:column;gap:.5rem;pointer-events:none;}',
      '.rx-copy-toast{opacity:0;transform:translateY(8px);transition:opacity .25s ease,transform .25s ease;border-radius:.6rem;background:#111;color:#fff;padding:.75rem 1rem;font-size:.9rem;box-shadow:0 8px 24px rgba(0,0,0,.18);}',
      '.rx-copy-toast.is-visible{opacity:1;transform:translateY(0);}',
      '@media (prefers-color-scheme:dark){.rx-code-copy-toolbar button{background:rgba(24,24,24,.92);color:#f5f5f5;border-color:rgba(255,255,255,.18);}.rx-code-copy-toolbar button:hover{background:#111;}.rx-code-is-collapsed:after{background:linear-gradient(to bottom,rgba(20,20,20,0),rgba(20,20,20,.9));}}'
    ].join('');

    var style = document.createElement('style');

    style.id = 'rx-copy-code-style';
    style.textContent = css;

    document.head.appendChild(style);
  }

  function init(customOptions) {
    var options = extend({}, DEFAULT_OPTIONS, customOptions || {});

    state.options = options;

    ready(function () {
      injectBaseStyles();
      initCodeBlocks(options);
      observeDynamicContent(options);
      handleKeyboardShortcut(options);
    });
  }

  window.RXCopyCode = {
    version: RX_COPY_CODE_VERSION,
    init: init,
    refresh: initCodeBlocks,
    copyText: copyText,
    selectCode: selectCode
  };

  init(window.rxCopyCodeOptions || {});
})();

For loading in functions.php, use this:

function rx_theme_enqueue_copy_code_chunk() {
    wp_enqueue_script(
        'rx-theme-copy-code-chunk',
        get_template_directory_uri() . '/assets/static-js/static-chunks-js/chunk-012-copy-code.js',
        array(),
        wp_get_theme()->get( 'Version' ),
        true
    );
}
add_action( 'wp_enqueue_scripts', 'rx_theme_enqueue_copy_code_chunk' );

Optional advanced settings before the script loads:

function rx_theme_copy_code_inline_options() {
    wp_add_inline_script(
        'rx-theme-copy-code-chunk',
        'window.rxCopyCodeOptions = {
            enableToast: true,
            enableLanguageLabel: true,
            enableSelectButton: true,
            enableCollapseButton: true,
            enableDoubleClickCopy: true,
            enableKeyboardShortcut: true,
            enableLineNumbers: false,
            minLinesForCollapse: 18,
            copiedText: "Copied!",
            copyText: "Copy",
            copyErrorText: "Copy failed"
        };',
        'before'
    );
}
add_action( 'wp_enqueue_scripts', 'rx_theme_copy_code_inline_options', 20 );

Best RX Theme path:

rx-theme/
└── assets/
    └── static-js/
        └── static-chunks-js/
            └── chunk-012-copy-code.js

This file is safe for your medical article pages, tutorial pages, and developer/code guide posts. It will automatically add copy buttons to code blocks without needing jQuery.

Leave a Reply

Your email address will not be published. Required fields are marked *