UNPKG

reveal.js-copycode

Version:

A simple plugin for Reveal.js that automatically shows a copy button in code blocks

8 lines (7 loc) 15.7 kB
(function(y,b){typeof exports=="object"&&typeof module<"u"?module.exports=b():typeof define=="function"&&define.amd?define(b):(y=typeof globalThis<"u"?globalThis:y||self,y.CopyCode=b())})(this,function(){"use strict";var y=typeof document<"u"?document.currentScript:null;const b={button:"always",display:"text",text:{copy:"Copy",copied:"Copied!"},plaintextonly:!0,timeout:1e3,style:{copybg:"orange",copiedbg:"green",copycolor:"black",copiedcolor:"white",copyborder:"",copiedborder:"",scale:1,offset:0,radius:0},tooltip:!0,iconsvg:{copy:"",copied:""},cssautoload:!0,csspath:""};function D(o){return o&&o.__esModule&&Object.prototype.hasOwnProperty.call(o,"default")?o.default:o}var $,A;function R(){if(A)return $;A=1;var o=function(i){return e(i)&&!t(i)};function e(s){return!!s&&typeof s=="object"}function t(s){var i=Object.prototype.toString.call(s);return i==="[object RegExp]"||i==="[object Date]"||l(s)}var r=typeof Symbol=="function"&&Symbol.for,n=r?Symbol.for("react.element"):60103;function l(s){return s.$$typeof===n}function p(s){return Array.isArray(s)?[]:{}}function a(s,i){return i.clone!==!1&&i.isMergeableObject(s)?v(p(s),s,i):s}function f(s,i,c){return s.concat(i).map(function(S){return a(S,c)})}function u(s,i){if(!i.customMerge)return v;var c=i.customMerge(s);return typeof c=="function"?c:v}function d(s){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(s).filter(function(i){return Object.propertyIsEnumerable.call(s,i)}):[]}function g(s){return Object.keys(s).concat(d(s))}function C(s,i){try{return i in s}catch{return!1}}function w(s,i){return C(s,i)&&!(Object.hasOwnProperty.call(s,i)&&Object.propertyIsEnumerable.call(s,i))}function T(s,i,c){var S={};return c.isMergeableObject(s)&&g(s).forEach(function(m){S[m]=a(s[m],c)}),g(i).forEach(function(m){w(s,m)||(C(s,m)&&c.isMergeableObject(i[m])?S[m]=u(m,c)(s[m],i[m],c):S[m]=a(i[m],c))}),S}function v(s,i,c){c=c||{},c.arrayMerge=c.arrayMerge||f,c.isMergeableObject=c.isMergeableObject||o,c.cloneUnlessOtherwiseSpecified=a;var S=Array.isArray(i),m=Array.isArray(s),ee=S===m;return ee?S?c.arrayMerge(s,i,c):T(s,i,c):a(i,c)}v.all=function(i,c){if(!Array.isArray(i))throw new Error("first argument should be an array");return i.reduce(function(S,m){return v(S,m,c)},{})};var x=v;return $=x,$}var P=R();const q=D(P);var U=Object.defineProperty,_=(o,e,t)=>e in o?U(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t,h=(o,e,t)=>_(o,typeof e!="symbol"?e+"":e,t);const N=()=>{const o=typeof window<"u",e=typeof document<"u",t=o&&typeof location<"u"&&/localhost|127\.0\.0\.1/.test(location.hostname);let r=!1;try{r=new Function('return typeof module !== "undefined" && !!module.hot')()}catch{}let n=!1;try{n=new Function('return typeof import.meta !== "undefined" && typeof import.meta.env !== "undefined" && import.meta.env.DEV === true')()}catch{}const l=o&&typeof navigator<"u"&&/vite|localhost|127\.0\.0\.1/.test(location.origin)&&/AppleWebKit|Chrome|Vite/.test(navigator.userAgent),p=e&&!!document.querySelector('script[type="module"]');let a=!1;try{a=new Function('return typeof process !== "undefined" && process.env && (process.env.ROLLUP_WATCH === "true" || process.env.NODE_ENV === "development")')()}catch{}let f=!1;try{f=new Function('return typeof define === "function" && !!define.amd')()}catch{}return{isDevServer:t,isWebpackHMR:r,isVite:n,isVitePreview:l,hasModuleScripts:p,isModuleBundler:a,isAMD:f,isBundlerEnvironment:r||n||l||p||a||f||t}};class H{constructor(e,t,r){h(this,"defaultConfig"),h(this,"pluginInit"),h(this,"pluginId"),h(this,"mergedConfig",null),h(this,"userConfigData",null),h(this,"data",{}),h(this,"getEnvironmentInfo",()=>N()),typeof e=="string"?(this.pluginId=e,this.pluginInit=t,this.defaultConfig=r||{}):(this.pluginId=e.id,this.pluginInit=e.init,this.defaultConfig=e.defaultConfig||{})}initializeConfig(e){const t=this.defaultConfig,r=e.getConfig()[this.pluginId]||{};this.userConfigData=r,this.mergedConfig=q(t,r,{arrayMerge:(n,l)=>l,clone:!0})}getCurrentConfig(){if(!this.mergedConfig)throw new Error("Plugin configuration has not been initialized");return this.mergedConfig}getData(){return Object.keys(this.data).length>0?this.data:void 0}get userConfig(){return this.userConfigData||{}}init(e){if(this.initializeConfig(e),this.pluginInit)return this.pluginInit(this,e,this.getCurrentConfig())}createInterface(e={}){return{id:this.pluginId,init:t=>this.init(t),getConfig:()=>this.getCurrentConfig(),getData:()=>this.getData(),...e}}}const F=o=>{const e=document.querySelector(`script[src$="${o}.js"], script[src$="${o}.min.js"], script[src$="${o}.mjs"]`);if(e!=null&&e.src){const t=e.getAttribute("src")||"",r=t.lastIndexOf("/");if(r!==-1)return t.substring(0,r+1)}try{if(typeof{url:typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:y&&y.tagName.toUpperCase()==="SCRIPT"&&y.src||new URL("plugin/copycode/copycode.js",document.baseURI).href}<"u"&&(typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:y&&y.tagName.toUpperCase()==="SCRIPT"&&y.src||new URL("plugin/copycode/copycode.js",document.baseURI).href))return(typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:y&&y.tagName.toUpperCase()==="SCRIPT"&&y.src||new URL("plugin/copycode/copycode.js",document.baseURI).href).slice(0,(typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:y&&y.tagName.toUpperCase()==="SCRIPT"&&y.src||new URL("plugin/copycode/copycode.js",document.baseURI).href).lastIndexOf("/")+1)}catch{}return`plugin/${o}/`},M="data-css-id",B=(o,e)=>new Promise((t,r)=>{const n=document.createElement("link");n.rel="stylesheet",n.href=e,n.setAttribute(M,o);const l=setTimeout(()=>{n.parentNode&&n.parentNode.removeChild(n),r(new Error(`[${o}] Timeout loading CSS from: ${e}`))},5e3);n.onload=()=>{clearTimeout(l),t()},n.onerror=()=>{clearTimeout(l),n.parentNode&&n.parentNode.removeChild(n),r(new Error(`[${o}] Failed to load CSS from: ${e}`))},document.head.appendChild(n)}),E=o=>document.querySelectorAll(`[${M}="${o}"]`).length>0,z=o=>new Promise(e=>{if(t())return e(!0);setTimeout(()=>{e(t())},50);function t(){if(E(o))return!0;try{return window.getComputedStyle(document.documentElement).getPropertyValue(`--cssimported-${o}`).trim()!==""}catch{return!1}}}),I=async o=>{const{id:e,cssautoload:t=!0,csspath:r="",debug:n=!1}=o;if(t===!1||r===!1)return;if(E(e)){n&&console.log(`[${e}] CSS already loaded, skipping`);return}const l=[];typeof r=="string"&&r.trim()!==""&&l.push(r);const p=F(e);if(p){const f=`${p}${e}.css`;l.push(f)}const a=`plugin/${e}/${e}.css`;l.push(a);for(const f of l)try{await B(e,f);let u="CSS";r&&f===r?u="user-specified CSS":p&&f===`${p}${e}.css`?u="CSS (auto-detected from script location)":u="CSS (standard fallback)",n&&console.log(`[${e}] ${u} loaded successfully from: ${f}`);return}catch{n&&console.log(`[${e}] Failed to load CSS from: ${f}`)}console.warn(`[${e}] Could not load CSS from any location`)};async function V(o,e){if("getEnvironmentInfo"in o&&e){const t=o,r=t.getEnvironmentInfo();if(await z(t.pluginId)){e.debug&&console.log(`[${t.pluginId}] CSS already imported, skipping`);return}if("cssautoload"in t.userConfig?e.cssautoload:!r.isBundlerEnvironment)return I({id:t.pluginId,cssautoload:!0,csspath:e.csspath,debug:e.debug});r.isBundlerEnvironment&&console.warn(`[${t.pluginId}] CSS autoloading is disabled in bundler environments. Please import the CSS manually, using import.`);return}return I(o)}class k{constructor(){h(this,"debugMode",!1),h(this,"label","DEBUG"),h(this,"groupDepth",0),h(this,"group",(...e)=>{this.debugLog("group",...e),this.groupDepth++}),h(this,"groupCollapsed",(...e)=>{this.debugLog("groupCollapsed",...e),this.groupDepth++}),h(this,"groupEnd",()=>{this.groupDepth>0&&(this.groupDepth--,this.debugLog("groupEnd"))}),h(this,"error",(...e)=>{const t=this.debugMode;this.debugMode=!0,this.formatAndLog(console.error,e),this.debugMode=t}),h(this,"table",(e,t,r)=>{if(this.debugMode)try{typeof e=="string"&&t!==void 0&&typeof t!="string"?(this.groupDepth===0?console.log(`[${this.label}]: ${e}`):console.log(e),r?console.table(t,r):console.table(t)):(this.groupDepth===0&&console.log(`[${this.label}]: Table data`),typeof t=="object"&&Array.isArray(t)?console.table(e,t):console.table(e))}catch(n){console.error(`[${this.label}]: Error showing table:`,n),console.log(`[${this.label}]: Raw data:`,e)}}),h(this,"formatAndLog",(e,t)=>{if(this.debugMode)try{this.groupDepth>0?e.call(console,...t):t.length>0&&typeof t[0]=="string"?e.call(console,`[${this.label}]: ${t[0]}`,...t.slice(1)):e.call(console,`[${this.label}]:`,...t)}catch(r){console.error(`[${this.label}]: Error in logging:`,r),console.log(`[${this.label}]: Original log data:`,...t)}})}initialize(e,t="DEBUG"){this.debugMode=e,this.label=t}debugLog(e,...t){const r=console[e];if(!this.debugMode&&e!=="error"||typeof r!="function")return;const n=r;if(e==="group"||e==="groupCollapsed"){t.length>0&&typeof t[0]=="string"?n.call(console,`[${this.label}]: ${t[0]}`,...t.slice(1)):n.call(console,`[${this.label}]:`,...t);return}if(e==="groupEnd"){n.call(console);return}if(e==="table"){t.length===1?this.table(t[0]):t.length===2?typeof t[0]=="string"?this.table(t[0],t[1]):this.table(t[0],t[1]):t.length>=3&&this.table(t[0],t[1],t[2]);return}this.groupDepth>0?n.call(console,...t):t.length>0&&typeof t[0]=="string"?n.call(console,`[${this.label}]: ${t[0]}`,...t.slice(1)):n.call(console,`[${this.label}]:`,...t)}}const G=o=>new Proxy(o,{get:(e,t)=>{if(t in e)return e[t];const r=t.toString();if(typeof console[r]=="function")return(...n)=>{e.debugLog(r,...n)}}}),j=G(new k),W=(o,e)=>{const t=(r,n)=>r===void 0||r===""&&String(n)==="0"?!1:String(r)!==String(n);t(e.style.copybg,b.style.copybg)&&o.style.setProperty("--cc-copy-bg",e.style.copybg),t(e.style.copiedbg,b.style.copiedbg)&&o.style.setProperty("--cc-copied-bg",e.style.copiedbg),t(e.style.copycolor,b.style.copycolor)&&o.style.setProperty("--cc-copy-color",e.style.copycolor),t(e.style.copiedcolor,b.style.copiedcolor)&&o.style.setProperty("--cc-copied-color",e.style.copiedcolor),t(e.style.scale,b.style.scale)&&o.style.setProperty("--cc-scale",String(e.style.scale)),t(e.style.offset,b.style.offset)&&o.style.setProperty("--cc-offset",String(e.style.offset)),t(e.style.radius,b.style.radius)&&o.style.setProperty("--cc-radius",String(e.style.radius)),t(e.style.copyborder,b.style.copyborder)&&e.style.copyborder!==""&&o.style.setProperty("--cc-copyborder",e.style.copyborder),t(e.style.copiedborder,b.style.copiedborder)&&e.style.copiedborder!==""&&o.style.setProperty("--cc-copiedborder",e.style.copiedborder)},L={copy:'<svg aria-hidden="true" height="16" width="16" viewBox="0 0 16 16" version="1.1"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg>',copied:'<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16"><path d="M15.7,2.8c0.4,0.4,0.4,1,0,1.4L6,13.9c-0.4,0.4-1,0.4-1.4,0L0.3,9.6c-0.4-0.4-0.4-1,0-1.4c0.4-0.4,1-0.4,1.4,0l3.6,3.6l9-9C14.7,2.4,15.3,2.4,15.7,2.8z"/></svg>'},Z=(o,e)=>{var l,p,a;const t=(l=e.iconsvg)!=null&&l.copy&&e.iconsvg.copy!==""?e.iconsvg.copy:L.copy,r=(p=e.iconsvg)!=null&&p.copied&&e.iconsvg.copied!==""?e.iconsvg.copied:L.copied,n=o.dataset.ccDisplay||e.display;n==="icons"||n==="both"?(o.innerHTML="<span></span>",o.textholder=o.querySelector("span"),o.insertAdjacentHTML("afterbegin",r),o.insertAdjacentHTML("afterbegin",t),o.dataset.ccDisplay==="icons"&&e.tooltip&&(o.textholder.style.display="flex")):(o.innerHTML="<span></span>",o.textholder=o.querySelector("span")),o.textholder&&(o.textholder.textContent=o.dataset.ccCopy?o.dataset.ccCopy:((a=e.text)==null?void 0:a.copy)||"Copy")},K=async(o,e)=>{if(e.plaintextonly){let t;const r=o.querySelector("table.hljs-ln");r?t=Array.from(r.querySelectorAll("td.hljs-ln-code")).map(n=>n.textContent).join(` `):t=o.innerText.replace(/^\s+|\s+$/g,""),await navigator.clipboard.writeText(t)}else try{const t=o.cloneNode(!0);let r;const n=t.querySelector("table.hljs-ln");if(n){const d=n.querySelectorAll("td.hljs-ln-numbers");for(const g of d)g.style.display="none";r=Array.from(n.querySelectorAll("td.hljs-ln-code")).map(g=>g.textContent).join(` `)}else r=t.innerText;const p=` <style>${Array.from(document.styleSheets).flatMap(d=>{try{return Array.from(d.cssRules)}catch{return[]}}).filter(d=>d.cssText.includes(".hljs")||d.cssText.includes("pre code")||d.cssText.includes("code[class")||d.cssText.includes(".language-")||d.cssText.includes("pre")||d.cssText.includes("code")).map(d=>d.cssText).join(` `)}pre, code, .hljs, .hljs-ln-code { white-space: pre !important; font-family: monospace !important;}</style> <div>${t.outerHTML}</div> `,a=new Blob([p],{type:"text/html"}),f=new Blob([r],{type:"text/plain"}),u=new ClipboardItem({"text/html":a,"text/plain":f});await navigator.clipboard.write([u])}catch(t){console.error("Rich text clipboard error:",t),await navigator.clipboard.writeText(o.innerText)}},Y=(o,e)=>{const t=o.querySelectorAll(".codeblock > button:not(.code-copy-button)");for(const r of t)r.addEventListener("click",async()=>{const n=r,l=n.nextElementSibling;if(!l||!(l instanceof HTMLElement))return;const p=l.querySelector("code");if(!p||!(p instanceof HTMLElement)){j.error("Could not find code element");return}try{await K(p,e),J(n,e)}catch(a){j.error("Error copying code:",a)}})},J=(o,e)=>{o.textholder&&(o.dataset.textOriginal=o.textholder.innerHTML,o.textholder.innerHTML=o.dataset.ccCopied||e.text.copied),o.setAttribute("disabled","true"),setTimeout(()=>{o.textholder&&(o.dataset.ccDisplay!=="icons"||!o.dataset.ccDisplay)&&(o.textholder.innerHTML=o.dataset.textOriginal||""),delete o.dataset.textOriginal,o.removeAttribute("disabled")},e.timeout)},Q=async(o,e,t)=>{var f;const r=e.getRevealElement(),n='pre:not([data-cc="false"]) > code',l=document.querySelector("[name=generator]"),p=((f=l==null?void 0:l.getAttribute("content"))==null?void 0:f.includes("quarto"))??!1;let a=[];if(r&&(W(r,t),a=Array.from(r.querySelectorAll(n)).map(u=>u.parentElement).filter(u=>u instanceof HTMLPreElement)),a.length>0&&r){j.log(`${a.length} code blocks found`,a);for(const u of a){let d=null,g=null;const C=u.parentElement;if(p&&(C!=null&&C.matches(".sourceCode"))?(d=C,g=d,C.dataset.did="quartoblock"):(g=u,C!=null&&C.classList.contains("codeblock")||(d=document.createElement("div"),C==null||C.insertBefore(d,u))),d&&g){d.classList.add("codeblock"),d.appendChild(u),(t.display==="icon"||t.display==="icons"||t.display==="both")&&g&&(g.dataset.ccDisplay=t.display),u.classList.contains("fragment")&&(d.classList.add("fragment"),u.classList.remove("fragment"));const w=document.createElement("button");w.dataset.cc="true",w.title="Copy to Clipboard",t.button!=="always"&&(w.dataset.cc=t.button);const T=["cc","ccCopy","ccCopied","ccDisplay"];for(const x of T)g.dataset[x]&&(w.dataset[x]=g.dataset[x],delete g.dataset[x]);const v=u.querySelectorAll("code")[0];v!=null&&v.innerText&&(Z(w,t),d.insertBefore(w,u))}}Y(r,t)}},O="copycode",X=async(o,e,t)=>{j&&t.debug&&j.initialize(!0,O),await V(o,t),await Q(o,e,t)};return()=>new H(O,X,b).createInterface()});