UNPKG

@docs-site/site-docsify

Version:
169 lines (151 loc) 4.94 kB
/** ===================================================== * Copyright © hk. 2022-2025. All rights reserved. * File name : docsify-copy-code.js * Author : 苏木 * Date : 2025-07-18 * Version : * Description: A docsify plugin that copies Markdown code block to your clipboard. * https://github.com/jperasmus/docsify-copy-code * ====================================================== */ // 默认配置选项 var defaultOptions = { buttonText: 'Copy to clipboard', // 按钮文本 errorText: 'Error', // 复制失败提示 successText: 'Copied' // 复制成功提示 }; /** * @brief 主插件函数 * @param {object} hook - Docsify钩子对象 * @param {object} vm - Docsify虚拟机实例 */ function docsifyCopyCode(hook, vm) { /** * @brief 获取当前配置 * @description 合并默认配置和用户配置 */ function getCurrentConfig() { return Object.assign( {}, defaultOptions, window.$docsify.copyCode, vm.config.copyCode ); } /** * @brief 页面渲染完成后钩子 * @description 为每个代码块添加复制按钮 */ hook.doneEach(function () { const config = getCurrentConfig(); // 创建复制按钮模板 const template = [ '<button class="docsify-copy-code-button">', `<span class="label">${config.buttonText}</span>`, `<span class="error" aria-hidden="hidden">${config.errorText}</span>`, `<span class="success" aria-hidden="hidden">${config.successText}</span>`, '<span aria-live="polite"></span>', '</button>', ].join(''); // 为每个代码块添加按钮 Array.from(document.querySelectorAll('pre[data-lang]')).forEach((elm) => { if (!elm.querySelector('.docsify-copy-code-button')) { elm.insertAdjacentHTML('beforeend', template); } }); }); /** * @brief 插件挂载钩子 * @description 设置复制按钮点击事件 */ hook.mounted(function () { const listenerHost = document.querySelector('.content'); if (!listenerHost) return; listenerHost.addEventListener('click', function (evt) { const isCopyCodeButton = evt.target.classList.contains('docsify-copy-code-button') || evt.target.closest('.docsify-copy-code-button'); if (!isCopyCodeButton) return; const buttonElm = evt.target.classList.contains('docsify-copy-code-button') ? evt.target : evt.target.closest('.docsify-copy-code-button'); const preElm = buttonElm.parentNode; const codeElm = preElm.querySelector('code'); const liveRegionElm = buttonElm.querySelector('[aria-live]'); const config = getCurrentConfig(); // 创建选择范围 const range = document.createRange(); range.selectNode(codeElm); // 执行复制操作 try { const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); const successful = document.execCommand('copy'); if (successful) { buttonElm.classList.add('success'); liveRegionElm.innerText = config.successText; setTimeout(() => { buttonElm.classList.remove('success'); liveRegionElm.innerText = ''; }, 1000); } } catch (err) { console.error(`docsify-copy-code: ${err}`); buttonElm.classList.add('error'); liveRegionElm.innerText = config.errorText; setTimeout(() => { buttonElm.classList.remove('error'); liveRegionElm.innerText = ''; }, 1000); } finally { const selection = window.getSelection(); if (selection) { if (typeof selection.removeRange === 'function') { selection.removeRange(range); } else { selection.removeAllRanges(); } } } }); }); } /** * @brief 注册插件 * @description 安全地注册插件并合并配置 */ (function registerPlugin() { // 初始化docsify全局对象 window.$docsify = window.$docsify || {}; // 深度合并配置 window.$docsify.copyCode = Object.assign( {}, defaultOptions, window.$docsify.copyCode || {} ); // 防止重复注册 if (!window.$docsify.plugins) { window.$docsify.plugins = []; } // 检查是否已注册 const isRegistered = window.$docsify.plugins.some( p => p.name === 'docsifyCopyCode' ); if (!isRegistered) { // 为插件函数添加标识 docsifyCopyCode.name = 'docsifyCopyCode'; window.$docsify.plugins.unshift(docsifyCopyCode); } })(); // 兼容旧版API window.DocsifyCopyCodePlugin = { init: function () { return function (hook, vm) { hook.ready(function () { console.warn( '[Deprecation] Manually initializing docsify-copy-code is no longer necessary.' ); }); }; }, };