diff --git a/assets/css/_common/scaffolding/highlight/copy-code.scss b/assets/css/_common/scaffolding/highlight/copy-code.scss index fc7e19a..bafac01 100644 --- a/assets/css/_common/scaffolding/highlight/copy-code.scss +++ b/assets/css/_common/scaffolding/highlight/copy-code.scss @@ -3,7 +3,7 @@ background: var(--highlight-background); margin-bottom: 26px; - line-height: 1.185; + line-height: 1.25; //TODO Need fixed the copy button show position. div:first-child { diff --git a/assets/js/3rd/others/clipboard.js b/assets/js/3rd/others/clipboard.js new file mode 100644 index 0000000..8862e2b --- /dev/null +++ b/assets/js/3rd/others/clipboard.js @@ -0,0 +1,37 @@ +/* clipboard plugin */ +NexT.plugins.others.clipboard = function() { + const clipboard_js = NexT.utils.getCDNResource(NexT.CONFIG.page.clipboard.js); + + NexT.utils.getScript(clipboard_js, function(){ + + let figure = document.querySelectorAll('.highlight pre'); + if (figure.length === 0 || !NexT.CONFIG.copybtn) return; + figure.forEach(element => { + let cn = element.querySelector('code').className; + if (cn === '') return; + element.children[0].insertAdjacentHTML('beforebegin', '
'); + var clipboard = new ClipboardJS(element.children[0], + { + text: function(trigger) { + return trigger.nextElementSibling.textContent.trim(); + } + }); + clipboard.on('success', function (e) { + e.clearSelection(); + button.querySelector('i').className = 'fa fa-check-circle fa-fw'; + }); + + clipboard.on('error', function (e) { + console.error('Copy failed:', e); + button.querySelector('i').className = 'fa fa-times-circle fa-fw'; + }); + + const button = element.querySelector('.copy-btn'); + element.addEventListener('mouseleave', () => { + setTimeout(() => { + button.querySelector('i').className = 'fa fa-copy fa-fw'; + }, 300); + }); + }); + }); +} \ No newline at end of file diff --git a/assets/js/next-boot.js b/assets/js/next-boot.js index 0e5104a..b6c3ed2 100644 --- a/assets/js/next-boot.js +++ b/assets/js/next-boot.js @@ -67,7 +67,6 @@ NexT.boot.refresh = function() { if (NexT.CONFIG.page.expired) NexT.utils.calPostExpiredDate(); if (NexT.CONFIG.page.music) NexT.utils.registerAPlayer(); - NexT.utils.registerCopyCode(); NexT.utils.registerImageViewer(); NexT.utils.registerPostReward(); diff --git a/assets/js/utils.js b/assets/js/utils.js index a8c0778..1050fca 100644 --- a/assets/js/utils.js +++ b/assets/js/utils.js @@ -306,27 +306,57 @@ NexT.utils = { registerCopyCode: function () { if (!NexT.CONFIG.copybtn) return; - let figure = document.querySelectorAll('.highlight pre'); + /** let figure = document.querySelectorAll('.highlight pre'); if (figure.length === 0 || !NexT.CONFIG.copybtn) return; figure.forEach(element => { - let cn = element.querySelector('code').className; - // TODO seems hard code need find other ways fixed it. - if (cn == '') return; - element.insertAdjacentHTML('beforeend', '
'); + let cn = element.querySelector('code').className; + if (cn === '') return; + element.children[0].insertAdjacentHTML('beforebegin', '
'); + var clipboard = new ClipboardJS(element.children[0], + { + text: function(trigger) { + return trigger.nextElementSibling.textContent.trim(); + } + }); + clipboard.on('success', function (e) { + e.clearSelection(); + console.info('Action:', e.action); + console.info('Text:', e.text); + button.querySelector('i').className = 'fa fa-check-circle fa-fw'; + }); + clipboard.on('error', function (e) { + console.error('复制失败:', e); + button.querySelector('i').className = 'fa fa-times-circle fa-fw'; + }); const button = element.querySelector('.copy-btn'); - button.addEventListener('click', () => { + element.addEventListener('mouseleave', () => { + setTimeout(() => { + button.querySelector('i').className = 'fa fa-copy fa-fw'; + }, 300); + }); + });**/ + /** figure.forEach(element => { + let cn = element.querySelector('code').className; + if (cn === '') return; + element.insertAdjacentHTML('beforeend', '
'); + // element.insertAdjacentHTML('beforeend', '
'); + const button = element.querySelector('.copy-btn'); + button.addEventListener('click', async () => { const lines = element.querySelector('.code') || element.querySelector('code'); - const code = lines.innerText.replace(/(\n{2,})/g, '\n'); + let code = lines.textContent.trim(); + console.log('尝试复制代码:', code); + if (navigator.clipboard) { - // https://caniuse.com/mdn-api_clipboard_writetext navigator.clipboard.writeText(code).then(() => { + console.log('复制成功'); button.querySelector('i').className = 'fa fa-check-circle fa-fw'; - }, () => { + }).catch((err) => { + console.error('复制失败:', err); button.querySelector('i').className = 'fa fa-times-circle fa-fw'; }); } else { const ta = document.createElement('textarea'); - ta.style.top = window.scrollY + 'px'; // Prevent page scrolling + ta.style.top = window.scrollY + 'px'; ta.style.position = 'absolute'; ta.style.opacity = '0'; ta.readOnly = true; @@ -334,20 +364,22 @@ NexT.utils = { document.body.append(ta); ta.select(); ta.setSelectionRange(0, code.length); - ta.readOnly = false; - const result = document.execCommand('copy'); - button.querySelector('i').className = result ? 'fa fa-check-circle fa-fw' : 'fa fa-times-circle fa-fw'; - ta.blur(); // For iOS - button.blur(); + try { + const successful = document.execCommand('copy'); + if (!successful) throw new Error('复制命令执行失败'); + } catch (err) { + console.error('复制失败:', err); + } document.body.removeChild(ta); } + }); element.addEventListener('mouseleave', () => { setTimeout(() => { button.querySelector('i').className = 'fa fa-copy fa-fw'; }, 300); }); - }); + });**/ }, wrapTableWithBox: function () { diff --git a/data/resources.yaml b/data/resources.yaml index a8ad1cd..5c6eabd 100644 --- a/data/resources.yaml +++ b/data/resources.yaml @@ -145,6 +145,7 @@ utterances: livere: js: https://cdn-city.livere.com/js/embed.dist.js + # 全文搜索 # Full text search algolia: @@ -231,4 +232,10 @@ plugins: css: name: aplayer version: 1.10.1 - file: dist/APlayer.min.css \ No newline at end of file + file: dist/APlayer.min.css + # 复制到剪贴板 + clipboard: + js: + name: clipboard + version: 2.0.11 + file: dist/clipboard.min.js \ No newline at end of file diff --git a/exampleSite/content/post/hugo-blockquote.md b/exampleSite/content/post/hugo-blockquote.md index 6c1b1ec..cc1ee62 100644 --- a/exampleSite/content/post/hugo-blockquote.md +++ b/exampleSite/content/post/hugo-blockquote.md @@ -27,9 +27,7 @@ expired: true 用户可以找到如下两处配置项的位置,然后根据自己喜欢的风格和颜色进行调整: ```yaml - # config.yaml 或 hugo.toml - postAlerts: info: icon: "circle-info" @@ -56,7 +54,6 @@ postAlerts: ```yaml # i18n/zh-cn.yaml - PostAlert: info : "信息" note : "注意" diff --git a/layouts/_default/_markup/render-codeblock.html b/layouts/_default/_markup/render-codeblock.html new file mode 100644 index 0000000..5e27219 --- /dev/null +++ b/layouts/_default/_markup/render-codeblock.html @@ -0,0 +1,4 @@ +{{ $result := transform.HighlightCodeBlock . }} +{{ $result.Wrapped }} + +{{ .Page.Store.Set "codeblock" true }} \ No newline at end of file diff --git a/layouts/partials/head/config.html b/layouts/partials/head/config.html index 09ba67b..8bf3a27 100644 --- a/layouts/partials/head/config.html +++ b/layouts/partials/head/config.html @@ -12,6 +12,14 @@ "title" .Page.Title }} +{{/** Append clipboard plugin */}} +{{ if .Store.Get "codeblock" }} +{{ $clipboard := dict + "js" $.Site.Data.resources.plugins.clipboard.js +}} +{{ $pageCfg = merge $pageCfg (dict "clipboard" $clipboard) }} +{{ end }} + {{/** Append APlayer plugin */}} {{ if $scParam.music }} {{ $aplayer := dict diff --git a/layouts/partials/head/script/plugins.html b/layouts/partials/head/script/plugins.html index 184b90d..d2d38d1 100644 --- a/layouts/partials/head/script/plugins.html +++ b/layouts/partials/head/script/plugins.html @@ -1,6 +1,11 @@ {{/* Defind loading plugin scripts which only need in pages */}} {{ if .IsPage }} +{{/** Append codeblack render action **/}} +{{ if .Store.Get "codeblock" }} + {{ partial "_funs/get_plugin.html" (dict "ctx" . "class" "others" "plugin" "clipboard.js") }} +{{ end }} + {{/** Short code params **/}} {{ $scParam := .Store.Get "scParams" }} diff --git a/static/js/3rd/clipboard/2.0.11/clipboard.min.js b/static/js/3rd/clipboard/2.0.11/clipboard.min.js new file mode 100644 index 0000000..9f97edb --- /dev/null +++ b/static/js/3rd/clipboard/2.0.11/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1