From 9e0dce6c7ad226ab277307f1eac6c50f91e61ef9 Mon Sep 17 00:00:00 2001 From: Jerry Date: Tue, 2 Apr 2024 23:44:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=20toc=20=E6=89=93?= =?UTF-8?q?=E9=96=8B=E6=95=88=E6=9E=9C=20feat:=20=E9=81=A9=E9=85=8D=20hexo?= =?UTF-8?q?-blog-encrypt=20fix:=20=E4=BF=AE=E5=BE=A9=20hexo=20=E6=96=B0?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=B8=8B=EF=BC=8Cprismjs=20=E7=9A=84?= =?UTF-8?q?=E5=95=8F=E9=A1=8C=20improvement:=20=E5=9C=A8=20pjax=20?= =?UTF-8?q?=E9=97=9C=E9=96=89=E7=9A=84=E6=83=85=E6=B3=81=E4=B8=8B=E3=80=82?= =?UTF-8?q?=E6=B8=9B=E5=B0=91=E4=B8=8D=E5=BF=85=E8=A6=81=E7=9A=84=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E8=AE=8A=E9=87=8F=20improvement:=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E4=BE=9D=E8=B3=B4=E7=89=88=E6=9C=AC=20improvement:=20=E9=A0=81?= =?UTF-8?q?=E9=9D=A2=E9=80=B2=E5=85=A5=E6=95=88=E6=9E=9C=E5=84=AA=E5=8C=96?= =?UTF-8?q?=20improvement:=20=E6=B7=BB=E5=8A=A0=E5=B9=B3=E6=BB=91=E6=BB=BE?= =?UTF-8?q?=E5=8B=95=20improvement:=20=E5=85=BC=E5=AE=B9=E6=80=A7=E5=84=AA?= =?UTF-8?q?=E5=8C=96=20improvement:=20=E5=84=AA=E5=8C=96=20lighthouse=20?= =?UTF-8?q?=E5=88=86=E6=95=B8=20improvement:=20=E5=84=AA=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A2=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- layout/includes/head.pug | 4 +- layout/includes/head/analytics.pug | 14 +- layout/includes/header/menu_item.pug | 2 +- layout/includes/header/nav.pug | 6 +- layout/includes/loading/fullpage-loading.pug | 4 +- layout/includes/loading/pace.pug | 5 +- layout/includes/third-party/abcjs/abcjs.pug | 4 +- layout/includes/third-party/aplayer.pug | 22 +- .../third-party/card-post-count/twikoo.pug | 2 +- .../third-party/card-post-count/valine.pug | 2 +- .../includes/third-party/comments/artalk.pug | 4 +- .../third-party/comments/disqusjs.pug | 4 +- .../includes/third-party/comments/gitalk.pug | 4 +- .../includes/third-party/comments/twikoo.pug | 2 +- .../includes/third-party/comments/valine.pug | 2 +- .../includes/third-party/comments/waline.pug | 14 +- layout/includes/third-party/math/katex.pug | 9 +- layout/includes/third-party/math/mathjax.pug | 71 +-- layout/includes/third-party/math/mermaid.pug | 18 +- .../third-party/newest-comments/artalk.pug | 7 +- .../newest-comments/disqus-comment.pug | 6 +- .../newest-comments/github-issues.pug | 6 +- .../third-party/newest-comments/remark42.pug | 6 +- .../newest-comments/twikoo-comment.pug | 8 +- .../third-party/newest-comments/valine.pug | 6 +- .../third-party/newest-comments/waline.pug | 6 +- layout/includes/third-party/pangu.pug | 33 +- layout/includes/third-party/pjax.pug | 38 +- layout/includes/third-party/prismjs.pug | 28 +- layout/includes/third-party/subtitle.pug | 7 +- package.json | 2 +- plugins.yml | 30 +- scripts/helpers/inject_head_js.js | 107 ++-- source/css/_global/function.styl | 21 +- source/css/_global/index.styl | 1 + source/css/_layout/head.styl | 11 +- source/css/_layout/sidebar.styl | 3 +- source/css/_layout/third-party.styl | 7 +- source/js/main.js | 76 ++- source/js/tw_cn.js | 11 +- source/js/utils.js | 524 +++++++++--------- 41 files changed, 601 insertions(+), 536 deletions(-) diff --git a/layout/includes/head.pug b/layout/includes/head.pug index 0038afc..364965c 100644 --- a/layout/includes/head.pug +++ b/layout/includes/head.pug @@ -48,6 +48,8 @@ if (theme.snackbar && theme.snackbar.enable) if theme.fancybox link(rel='stylesheet' href=url_for(theme.asset.fancybox_css) media="print" onload="this.media='all'") +!=fragment_cache('injectHeadJs', function(){return inject_head_js()}) + //- google_adsense !=partial('includes/head/google_adsense', {}, {cache: true}) @@ -63,6 +65,4 @@ if theme.blog_title_font && theme.blog_title_font.font_link include ./head/config_site.pug -!=fragment_cache('injectHeadJs', function(){return inject_head_js()}) - !=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)}) diff --git a/layout/includes/head/analytics.pug b/layout/includes/head/analytics.pug index ad4a395..5c389ba 100644 --- a/layout/includes/head/analytics.pug +++ b/layout/includes/head/analytics.pug @@ -7,14 +7,20 @@ if theme.baidu_analytics var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); + btf.addGlobalFn('pjaxComplete', () => { + _hmt.push(['_trackPageview',window.location.pathname]) + }, 'baidu_analytics') if theme.google_analytics script(async src=`https://www.googletagmanager.com/gtag/js?id=${theme.google_analytics}`) script. - window.dataLayer = window.dataLayer || []; - function gtag(){dataLayer.push(arguments);} - gtag('js', new Date()); - gtag('config', '!{theme.google_analytics}'); + window.dataLayer = window.dataLayer || [] + function gtag(){dataLayer.push(arguments)} + gtag('js', new Date()) + gtag('config', '!{theme.google_analytics}') + btf.addGlobalFn('pjaxComplete', () => { + gtag('config', '!{theme.google_analytics}', {'page_path': window.location.pathname}) + }, 'google_analytics') if theme.cloudflare_analytics script(defer data-pjax src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon=`{"token": "${theme.cloudflare_analytics}"}`) diff --git a/layout/includes/header/menu_item.pug b/layout/includes/header/menu_item.pug index d172db7..b0d7076 100644 --- a/layout/includes/header/menu_item.pug +++ b/layout/includes/header/menu_item.pug @@ -12,7 +12,7 @@ if theme.menu .menus_item - const labelArray = label.split('||') - const hideClass = labelArray[2] && trim(labelArray[2]) === 'hide' ? 'hide' : '' - a.site-page.group(class=`${hideClass}` href='javascript:void(0);') + span.site-page.group(class=`${hideClass}`) if labelArray[1] i.fa-fw(class=trim(labelArray[1])) span=' '+ trim(labelArray[0]) diff --git a/layout/includes/header/nav.pug b/layout/includes/header/nav.pug index f6376ca..cf50db3 100644 --- a/layout/includes/header/nav.pug +++ b/layout/includes/header/nav.pug @@ -2,20 +2,20 @@ nav#nav span#blog-info a(href=url_for('/') title=config.title) if theme.nav.logo - img.site-icon(src=url_for(theme.nav.logo)) + img.site-icon(src=url_for(theme.nav.logo) alt='Logo') if theme.nav.display_title span.site-name=config.title #menus if (theme.algolia_search.enable || theme.local_search.enable || theme.docsearch.enable) #search-button - a.site-page.social-icon.search(href="javascript:void(0);") + span.site-page.social-icon.search i.fas.fa-search.fa-fw span=' '+_p('search.title') !=partial('includes/header/menu_item', {}, {cache: true}) #toggle-menu - a.site-page(href="javascript:void(0);") + span.site-page i.fas.fa-bars.fa-fw diff --git a/layout/includes/loading/fullpage-loading.pug b/layout/includes/loading/fullpage-loading.pug index 4a2c8bf..8f5783b 100644 --- a/layout/includes/loading/fullpage-loading.pug +++ b/layout/includes/loading/fullpage-loading.pug @@ -27,7 +27,7 @@ script. window.addEventListener('load',() => { preloader.endLoading() }) if (!{theme.pjax && theme.pjax.enable}) { - document.addEventListener('pjax:send', () => { preloader.initLoading() }) - document.addEventListener('pjax:complete', () => { preloader.endLoading() }) + btf.addGlobalFn('pjaxSend', () => { preloader.initLoading() }, 'preloader_init') + btf.addGlobalFn('pjaxComplete', () => { preloader.endLoading() }, 'preloader_end') } })() \ No newline at end of file diff --git a/layout/includes/loading/pace.pug b/layout/includes/loading/pace.pug index 7abd617..4cf2a4e 100644 --- a/layout/includes/loading/pace.pug +++ b/layout/includes/loading/pace.pug @@ -3,9 +3,10 @@ script. restartOnPushState: false } - document.addEventListener('pjax:send', () => { + btf.addGlobalFn('pjaxSend', () => { Pace.restart() - }) + }, 'pace_restart') + link(rel="stylesheet", href=url_for(theme.preloader.pace_css_url || theme.asset.pace_default_css)) script(src=url_for(theme.asset.pace_js)) \ No newline at end of file diff --git a/layout/includes/third-party/abcjs/abcjs.pug b/layout/includes/third-party/abcjs/abcjs.pug index 79f86c4..089ee2b 100644 --- a/layout/includes/third-party/abcjs/abcjs.pug +++ b/layout/includes/third-party/abcjs/abcjs.pug @@ -3,13 +3,15 @@ script. const abcjsInit = () => { const abcjsFn = () => { document.querySelectorAll(".abc-music-sheet").forEach(ele => { + if (ele.children.length > 0) return ABCJS.renderAbc(ele, ele.innerHTML, {responsive: 'resize'}) }) } typeof ABCJS === 'object' ? abcjsFn() - : getScript('!{url_for(theme.asset.abcjs_basic_js)}').then(abcjsFn) + : btf.getScript('!{url_for(theme.asset.abcjs_basic_js)}').then(abcjsFn) } window.pjax ? abcjsInit() : window.addEventListener('load', abcjsInit) + btf.addGlobalFn('encrypt', abcjsInit, 'abcjs') })() \ No newline at end of file diff --git a/layout/includes/third-party/aplayer.pug b/layout/includes/third-party/aplayer.pug index c439c4c..e049ea0 100644 --- a/layout/includes/third-party/aplayer.pug +++ b/layout/includes/third-party/aplayer.pug @@ -1,3 +1,23 @@ link(rel='stylesheet' href=url_for(theme.asset.aplayer_css) media="print" onload="this.media='all'") script(src=url_for(theme.asset.aplayer_js)) -script(src=url_for(theme.asset.meting_js)) \ No newline at end of file +script(src=url_for(theme.asset.meting_js)) +if theme.pjax.enable + script. + (() => { + const destroyAplayer = () => { + if (window.aplayers) { + for (let i = 0; i < window.aplayers.length; i++) { + if (!window.aplayers[i].options.fixed) { + window.aplayers[i].destroy() + } + } + } + } + + const loadMeting = () => { + typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting() + } + + btf.addGlobalFn('pjaxSend', destroyAplayer, 'destroyAplayer') + btf.addGlobalFn('pjaxComplete', loadMeting, 'loadMeting') + })() diff --git a/layout/includes/third-party/card-post-count/twikoo.pug b/layout/includes/third-party/card-post-count/twikoo.pug index 72a4223..8d47c05 100644 --- a/layout/includes/third-party/card-post-count/twikoo.pug +++ b/layout/includes/third-party/card-post-count/twikoo.pug @@ -28,7 +28,7 @@ script. if (typeof twikoo === 'object') { runTwikoo() } else { - getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo) + btf.getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo) } } diff --git a/layout/includes/third-party/card-post-count/valine.pug b/layout/includes/third-party/card-post-count/valine.pug index dfe9b6d..1bbddde 100644 --- a/layout/includes/third-party/card-post-count/valine.pug +++ b/layout/includes/third-party/card-post-count/valine.pug @@ -13,7 +13,7 @@ script. } if (typeof Valine === 'function') initValine() - else getScript('!{url_for(theme.asset.valine)}').then(initValine) + else btf.getScript('!{url_for(theme.asset.valine)}').then(initValine) } window.pjax ? loadValine() : window.addEventListener('load', loadValine) diff --git a/layout/includes/third-party/comments/artalk.pug b/layout/includes/third-party/comments/artalk.pug index e7cf9ce..aadfabc 100644 --- a/layout/includes/third-party/comments/artalk.pug +++ b/layout/includes/third-party/comments/artalk.pug @@ -31,8 +31,8 @@ script. const loadArtalk = async () => { if (typeof Artalk === 'object') initArtalk() else { - await getCSS('!{theme.asset.artalk_css}') - await getScript('!{theme.asset.artalk_js}') + await btf.getCSS('!{theme.asset.artalk_css}') + await btf.getScript('!{theme.asset.artalk_js}') initArtalk() } } diff --git a/layout/includes/third-party/comments/disqusjs.pug b/layout/includes/third-party/comments/disqusjs.pug index af41696..3550392 100644 --- a/layout/includes/third-party/comments/disqusjs.pug +++ b/layout/includes/third-party/comments/disqusjs.pug @@ -28,8 +28,8 @@ script. const loadDisqusjs = async() => { if (window.disqusJsLoad) initDisqusjs() else { - await getCSS('!{url_for(theme.asset.disqusjs_css)}') - await getScript('!{url_for(theme.asset.disqusjs)}') + await btf.getCSS('!{url_for(theme.asset.disqusjs_css)}') + await btf.getScript('!{url_for(theme.asset.disqusjs)}') initDisqusjs() window.disqusJsLoad = true } diff --git a/layout/includes/third-party/comments/gitalk.pug b/layout/includes/third-party/comments/gitalk.pug index e0a1389..fb2d694 100644 --- a/layout/includes/third-party/comments/gitalk.pug +++ b/layout/includes/third-party/comments/gitalk.pug @@ -19,8 +19,8 @@ script. const loadGitalk = async() => { if (typeof Gitalk === 'function') initGitalk() else { - await getCSS('!{url_for(theme.asset.gitalk_css)}') - await getScript('!{url_for(theme.asset.gitalk)}') + await btf.getCSS('!{url_for(theme.asset.gitalk_css)}') + await btf.getScript('!{url_for(theme.asset.gitalk)}') initGitalk() } } diff --git a/layout/includes/third-party/comments/twikoo.pug b/layout/includes/third-party/comments/twikoo.pug index b2aacf4..8f3bc42 100644 --- a/layout/includes/third-party/comments/twikoo.pug +++ b/layout/includes/third-party/comments/twikoo.pug @@ -33,7 +33,7 @@ script. const loadTwikoo = () => { if (typeof twikoo === 'object') setTimeout(init,0) - else getScript('!{url_for(theme.asset.twikoo)}').then(init) + else btf.getScript('!{url_for(theme.asset.twikoo)}').then(init) } if ('!{use[0]}' === 'Twikoo' || !!{lazyload}) { diff --git a/layout/includes/third-party/comments/valine.pug b/layout/includes/third-party/comments/valine.pug index 85781d5..b53e3fc 100644 --- a/layout/includes/third-party/comments/valine.pug +++ b/layout/includes/third-party/comments/valine.pug @@ -23,7 +23,7 @@ script. const loadValine = async () => { if (typeof Valine === 'function') initValine() else { - await getScript('!{url_for(theme.asset.valine)}') + await btf.getScript('!{url_for(theme.asset.valine)}') initValine() } } diff --git a/layout/includes/third-party/comments/waline.pug b/layout/includes/third-party/comments/waline.pug index 6f5f07e..0b0ce4a 100644 --- a/layout/includes/third-party/comments/waline.pug +++ b/layout/includes/third-party/comments/waline.pug @@ -22,14 +22,16 @@ script. btf.addGlobalFn('pjax', destroyWaline, 'destroyWaline') } - const loadWaline = async () => { + const loadWaline = () => { if (initFn) initWaline(initFn) else { - await getCSS('!{url_for(theme.asset.waline_css)}') - const { init } = await import('!{url_for(theme.asset.waline_js)}') - initFn = init || Waline.init - initWaline(initFn) - window.walineFn = initFn + btf.getCSS('!{url_for(theme.asset.waline_css)}') + .then(() => import('!{url_for(theme.asset.waline_js)}')) + .then(({ init }) => { + initFn = init || Waline.init + initWaline(initFn) + window.walineFn = initFn + }) } } diff --git a/layout/includes/third-party/math/katex.pug b/layout/includes/third-party/math/katex.pug index c1f0bd6..4303063 100644 --- a/layout/includes/third-party/math/katex.pug +++ b/layout/includes/third-party/math/katex.pug @@ -1,9 +1,2 @@ link(rel="stylesheet" type="text/css" href=url_for(theme.asset.katex)) -script(src=url_for(theme.asset.katex_copytex)) -script. - (() => { - document.querySelectorAll('#article-container span.katex-display').forEach(item => { - btf.wrap(item, 'div', { class: 'katex-wrap'}) - }) - })() - \ No newline at end of file +script(src=url_for(theme.asset.katex_copytex)) \ No newline at end of file diff --git a/layout/includes/third-party/math/mathjax.pug b/layout/includes/third-party/math/mathjax.pug index 470aa45..0baefdc 100644 --- a/layout/includes/third-party/math/mathjax.pug +++ b/layout/includes/third-party/math/mathjax.pug @@ -1,38 +1,45 @@ //- Mathjax 3 script. - if (!window.MathJax) { - window.MathJax = { - tex: { - inlineMath: [['$', '$'], ['\\(', '\\)']], - tags: 'ams' - }, - chtml: { - scale: 1.1 - }, - options: { - renderActions: { - findScript: [10, doc => { - for (const node of document.querySelectorAll('script[type^="math/tex"]')) { - const display = !!node.type.match(/; *mode=display/) - const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display) - const text = document.createTextNode('') - node.parentNode.replaceChild(text, node) - math.start = {node: text, delim: '', n: 0} - math.end = {node: text, delim: '', n: 0} - doc.math.push(math) + (() => { + const loadMathjax = () => { + if (!window.MathJax) { + window.MathJax = { + tex: { + inlineMath: [['$', '$'], ['\\(', '\\)']], + tags: 'ams' + }, + chtml: { + scale: 1.1 + }, + options: { + renderActions: { + findScript: [10, doc => { + for (const node of document.querySelectorAll('script[type^="math/tex"]')) { + const display = !!node.type.match(/; *mode=display/) + const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display) + const text = document.createTextNode('') + node.parentNode.replaceChild(text, node) + math.start = {node: text, delim: '', n: 0} + math.end = {node: text, delim: '', n: 0} + doc.math.push(math) + } + }, ''] } - }, ''] + } } + + const script = document.createElement('script') + script.src = '!{url_for(theme.asset.mathjax)}' + script.id = 'MathJax-script' + script.async = true + document.head.appendChild(script) + } else { + MathJax.startup.document.state(0) + MathJax.texReset() + MathJax.typesetPromise() } } - - const script = document.createElement('script') - script.src = '!{url_for(theme.asset.mathjax)}' - script.id = 'MathJax-script' - script.async = true - document.head.appendChild(script) - } else { - MathJax.startup.document.state(0) - MathJax.texReset() - MathJax.typesetPromise() - } \ No newline at end of file + + btf.addGlobalFn('encrypt', loadMathjax, 'mathjax') + window.pjax ? loadMathjax() : window.addEventListener('load', loadMathjax) + })() \ No newline at end of file diff --git a/layout/includes/third-party/math/mermaid.pug b/layout/includes/third-party/math/mermaid.pug index 2cfc1c7..d094e89 100644 --- a/layout/includes/third-party/math/mermaid.pug +++ b/layout/includes/third-party/math/mermaid.pug @@ -1,12 +1,10 @@ script. (() => { - const $mermaid = document.querySelectorAll('#article-container .mermaid-wrap') - if ($mermaid.length === 0) return - const runMermaid = () => { + const runMermaid = (ele) => { window.loadMermaid = true const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{theme.mermaid.theme.dark}' : '!{theme.mermaid.theme.light}' - Array.from($mermaid).forEach((item, index) => { + Array.from(ele).forEach((item, index) => { const mermaidSrc = item.firstElementChild const mermaidThemeConfig = '%%{init:{ \'theme\':\'' + theme + '\'}}%%\n' const mermaidID = 'mermaid-' + index @@ -29,10 +27,14 @@ script. } const loadMermaid = () => { - window.loadMermaid ? runMermaid() : getScript('!{url_for(theme.asset.mermaid)}').then(runMermaid) + const $mermaid = document.querySelectorAll('#article-container .mermaid-wrap') + if ($mermaid.length === 0) return + + const runMermaidFn = () => runMermaid($mermaid) + btf.addGlobalFn('themeChange', runMermaidFn, 'mermaid') + window.loadMermaid ? runMermaidFn() : btf.getScript('!{url_for(theme.asset.mermaid)}').then(runMermaidFn) } - - btf.addGlobalFn('themeChange', runMermaid, 'mermaid') - + + btf.addGlobalFn('encrypt', loadMermaid, 'mermaid') window.pjax ? loadMermaid() : document.addEventListener('DOMContentLoaded', loadMermaid) })() \ No newline at end of file diff --git a/layout/includes/third-party/newest-comments/artalk.pug b/layout/includes/third-party/newest-comments/artalk.pug index 2df0bac..03ad068 100644 --- a/layout/includes/third-party/newest-comments/artalk.pug +++ b/layout/includes/third-party/newest-comments/artalk.pug @@ -81,7 +81,7 @@ script. 'date': e.date, } }) - saveToLocal.set('artalk-newest-comments', JSON.stringify(artalk), !{theme.newest_comments.storage}/(60*24)) + btf.saveToLocal.set('artalk-newest-comments', JSON.stringify(artalk), !{theme.newest_comments.storage}/(60*24)) generateHtml(artalk) } catch (e) { console.log(e) @@ -92,7 +92,7 @@ script. const newestCommentInit = () => { if (document.querySelector('#card-newest-comments .aside-list')) { - const data = saveToLocal.get('artalk-newest-comments') + const data = btf.saveToLocal.get('artalk-newest-comments') if (data) { generateHtml(JSON.parse(data)) } else { @@ -102,5 +102,6 @@ script. } newestCommentInit() - document.addEventListener('pjax:complete', newestCommentInit) + btf.addGlobalFn('pjaxComplete', newestCommentInit, 'artalk_newestComment') + }) diff --git a/layout/includes/third-party/newest-comments/disqus-comment.pug b/layout/includes/third-party/newest-comments/disqus-comment.pug index c729130..93feec5 100644 --- a/layout/includes/third-party/newest-comments/disqus-comment.pug +++ b/layout/includes/third-party/newest-comments/disqus-comment.pug @@ -28,7 +28,7 @@ script. } }) - saveToLocal.set('disqus-newest-comments', JSON.stringify(disqusArray), !{theme.newest_comments.storage}/(60*24)) + btf.saveToLocal.set('disqus-newest-comments', JSON.stringify(disqusArray), !{theme.newest_comments.storage}/(60*24)) generateHtml(disqusArray) }).catch(e => { const $dom = document.querySelector('#card-newest-comments .aside-list') @@ -65,7 +65,7 @@ script. const newestCommentInit = () => { if (document.querySelector('#card-newest-comments .aside-list')) { - const data = saveToLocal.get('disqus-newest-comments') + const data = btf.saveToLocal.get('disqus-newest-comments') if (data) { generateHtml(JSON.parse(data)) } else { @@ -75,7 +75,7 @@ script. } newestCommentInit() - document.addEventListener('pjax:complete', newestCommentInit) + btf.addGlobalFn('pjaxComplete', newestCommentInit, 'disqus_newestComment') }) diff --git a/layout/includes/third-party/newest-comments/github-issues.pug b/layout/includes/third-party/newest-comments/github-issues.pug index 82b4a92..59f7cd7 100644 --- a/layout/includes/third-party/newest-comments/github-issues.pug +++ b/layout/includes/third-party/newest-comments/github-issues.pug @@ -35,7 +35,7 @@ script. } }) - saveToLocal.set('github-newest-comments', JSON.stringify(array), !{theme.newest_comments.storage}/(60*24)) + btf.saveToLocal.set('github-newest-comments', JSON.stringify(array), !{theme.newest_comments.storage}/(60*24)) generateHtml(array) }); } @@ -94,7 +94,7 @@ script. const newestCommentInit = () => { if (document.querySelector('#card-newest-comments .aside-list')) { - const data = saveToLocal.get('github-newest-comments') + const data = btf.saveToLocal.get('github-newest-comments') if (data) { generateHtml(JSON.parse(data)) } else { @@ -104,7 +104,7 @@ script. } newestCommentInit() - document.addEventListener('pjax:complete', newestCommentInit) + btf.addGlobalFn('pjaxComplete', newestCommentInit, 'github_newestComment') }) diff --git a/layout/includes/third-party/newest-comments/remark42.pug b/layout/includes/third-party/newest-comments/remark42.pug index 92e3446..2e2e432 100644 --- a/layout/includes/third-party/newest-comments/remark42.pug +++ b/layout/includes/third-party/newest-comments/remark42.pug @@ -56,7 +56,7 @@ script. 'date': e.time, } }) - saveToLocal.set('remark42-newest-comments', JSON.stringify(remark42), !{theme.newest_comments.storage}/(60*24)) + btf.saveToLocal.set('remark42-newest-comments', JSON.stringify(remark42), !{theme.newest_comments.storage}/(60*24)) generateHtml(remark42) }).catch(e => { const $dom = document.querySelector('#card-newest-comments .aside-list') @@ -66,7 +66,7 @@ script. const newestCommentInit = () => { if (document.querySelector('#card-newest-comments .aside-list')) { - const data = saveToLocal.get('remark42-newest-comments') + const data = btf.saveToLocal.get('remark42-newest-comments') if (data) { generateHtml(JSON.parse(data)) } else { @@ -76,5 +76,5 @@ script. } newestCommentInit() - document.addEventListener('pjax:complete', newestCommentInit) + btf.addGlobalFn('pjaxComplete', newestCommentInit, 'remark42_newestComment') }) diff --git a/layout/includes/third-party/newest-comments/twikoo-comment.pug b/layout/includes/third-party/newest-comments/twikoo-comment.pug index 4a0ca8e..7ea418a 100644 --- a/layout/includes/third-party/newest-comments/twikoo-comment.pug +++ b/layout/includes/third-party/newest-comments/twikoo-comment.pug @@ -32,7 +32,7 @@ script. } }) - saveToLocal.set('twikoo-newest-comments', JSON.stringify(twikooArray), !{theme.newest_comments.storage}/(60*24)) + btf.saveToLocal.set('twikoo-newest-comments', JSON.stringify(twikooArray), !{theme.newest_comments.storage}/(60*24)) generateHtml(twikooArray) }).catch(function (err) { const $dom = document.querySelector('#card-newest-comments .aside-list') @@ -43,7 +43,7 @@ script. if (typeof twikoo === 'object') { runTwikoo() } else { - getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo) + btf.getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo) } } @@ -76,7 +76,7 @@ script. const newestCommentInit = () => { if (document.querySelector('#card-newest-comments .aside-list')) { - const data = saveToLocal.get('twikoo-newest-comments') + const data = btf.saveToLocal.get('twikoo-newest-comments') if (data) { generateHtml(JSON.parse(data)) } else { @@ -86,7 +86,7 @@ script. } newestCommentInit() - document.addEventListener('pjax:complete', newestCommentInit) + btf.addGlobalFn('pjaxComplete', newestCommentInit, 'twikoo_newestComment') }) diff --git a/layout/includes/third-party/newest-comments/valine.pug b/layout/includes/third-party/newest-comments/valine.pug index 7ac6af2..55f0a91 100644 --- a/layout/includes/third-party/newest-comments/valine.pug +++ b/layout/includes/third-party/newest-comments/valine.pug @@ -75,7 +75,7 @@ script. 'date': e.updatedAt, } }) - saveToLocal.set('valine-newest-comments', JSON.stringify(valineArray), !{theme.newest_comments.storage}/(60*24)) + btf.saveToLocal.set('valine-newest-comments', JSON.stringify(valineArray), !{theme.newest_comments.storage}/(60*24)) generateHtml(valineArray) }).catch(e => { const $dom = document.querySelector('#card-newest-comments .aside-list') @@ -85,7 +85,7 @@ script. const newestCommentInit = () => { if (document.querySelector('#card-newest-comments .aside-list')) { - const data = saveToLocal.get('valine-newest-comments') + const data = btf.saveToLocal.get('valine-newest-comments') if (data) { generateHtml(JSON.parse(data)) } else { @@ -95,5 +95,5 @@ script. } newestCommentInit() - document.addEventListener('pjax:complete', newestCommentInit) + btf.addGlobalFn('pjaxComplete', newestCommentInit, 'valine_newestComment') }) diff --git a/layout/includes/third-party/newest-comments/waline.pug b/layout/includes/third-party/newest-comments/waline.pug index d26eb1a..a5eb0cc 100644 --- a/layout/includes/third-party/newest-comments/waline.pug +++ b/layout/includes/third-party/newest-comments/waline.pug @@ -56,7 +56,7 @@ script. 'date': e.time || e.insertedAt } }) - saveToLocal.set('waline-newest-comments', JSON.stringify(walineArray), !{theme.newest_comments.storage}/(60*24)) + btf.saveToLocal.set('waline-newest-comments', JSON.stringify(walineArray), !{theme.newest_comments.storage}/(60*24)) generateHtml(walineArray) } catch (err) { console.error(err) @@ -67,7 +67,7 @@ script. const newestCommentInit = () => { if (document.querySelector('#card-newest-comments .aside-list')) { - const data = saveToLocal.get('waline-newest-comments') + const data = btf.saveToLocal.get('waline-newest-comments') if (data) { generateHtml(JSON.parse(data)) } else { @@ -77,5 +77,5 @@ script. } newestCommentInit() - document.addEventListener('pjax:complete', newestCommentInit) + btf.addGlobalFn('pjaxComplete', newestCommentInit, 'waline_newestComment') }) diff --git a/layout/includes/third-party/pangu.pug b/layout/includes/third-party/pangu.pug index 2027ca7..53bb064 100644 --- a/layout/includes/third-party/pangu.pug +++ b/layout/includes/third-party/pangu.pug @@ -1,20 +1,23 @@ script. - function panguFn () { - if (typeof pangu === 'object') pangu.autoSpacingPage() - else { - getScript('!{url_for(theme.asset.pangu)}') - .then(() => { - pangu.autoSpacingPage() - }) + (() => { + const panguFn = () => { + if (typeof pangu === 'object') pangu.autoSpacingPage() + else { + btf.getScript('!{url_for(theme.asset.pangu)}') + .then(() => { + pangu.autoSpacingPage() + }) + } } - } - function panguInit () { - if (!{theme.pangu.field === 'post'}){ - GLOBAL_CONFIG_SITE.isPost && panguFn() - } else { - panguFn() + const panguInit = () => { + if (!{theme.pangu.field === 'post'}){ + GLOBAL_CONFIG_SITE.isPost && panguFn() + } else { + panguFn() + } } - } - document.addEventListener('DOMContentLoaded', panguInit) + btf.addGlobalFn('pjaxComplete', panguInit, 'pangu') + document.addEventListener('DOMContentLoaded', panguInit) + })() diff --git a/layout/includes/third-party/pjax.pug b/layout/includes/third-party/pjax.pug index 2b783c6..0872385 100644 --- a/layout/includes/third-party/pjax.pug +++ b/layout/includes/third-party/pjax.pug @@ -24,34 +24,25 @@ script. scrollRestoration: false }) + const triggerPjaxFn = (val) => { + if (!val) return + Object.values(val).forEach(fn => { fn() }) + } + document.addEventListener('pjax:send', function () { // removeEventListener btf.removeGlobalFnEvent('pjax') btf.removeGlobalFnEvent('themeChange') - document.getElementById('rightside').classList.remove('rightside-show') - - if (window.aplayers) { - for (let i = 0; i < window.aplayers.length; i++) { - if (!window.aplayers[i].options.fixed) { - window.aplayers[i].destroy() - } - } - } - - typeof typed === 'object' && typed.destroy() - //reset readmode const $bodyClassList = document.body.classList $bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode') - typeof disqusjs === 'object' && disqusjs.destroy() + triggerPjaxFn(window.globalFn.pjaxSend) }) - document.addEventListener('pjax:complete', function () { - window.refreshFn() - + document.addEventListener('pjax:complete', () => { document.querySelectorAll('script[data-pjax]').forEach(item => { const newScript = document.createElement('script') const content = item.text || item.textContent || item.innerHTML || "" @@ -60,20 +51,7 @@ script. item.parentNode.replaceChild(newScript, item) }) - GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update() - - typeof panguInit === 'function' && panguInit() - - // google analytics - typeof gtag === 'function' && gtag('config', '!{theme.google_analytics}', {'page_path': window.location.pathname}); - - // baidu analytics - typeof _hmt === 'object' && _hmt.push(['_trackPageview',window.location.pathname]); - - typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting() - - // prismjs - typeof Prism === 'object' && Prism.highlightAll() + triggerPjaxFn(window.globalFn.pjaxComplete) }) document.addEventListener('pjax:error', e => { diff --git a/layout/includes/third-party/prismjs.pug b/layout/includes/third-party/prismjs.pug index 6af44dd..ee30e8b 100644 --- a/layout/includes/third-party/prismjs.pug +++ b/layout/includes/third-party/prismjs.pug @@ -1,5 +1,23 @@ -if config.prismjs && config.prismjs.enable && !config.prismjs.preprocess - script(src=url_for(theme.asset.prismjs_js)) - script(src=url_for(theme.asset.prismjs_autoloader)) - if config.prismjs.line_number - script(src=url_for(theme.asset.prismjs_lineNumber_js)) +- const { prismjs_js, prismjs_autoloader, prismjs_lineNumber_js } = theme.asset +- const { prismjs, syntax_highlighter } = config +- const { enable, preprocess, line_number } = prismjs + +if (syntax_highlighter === 'prismjs' || enable) && !preprocess + script. + (() => { + window.Prism = window.Prism || {} + window.Prism.manual = true + + const highlightAll = () => { + window.Prism.highlightAll() + } + + window.addEventListener('load', highlightAll) + btf.addGlobalFn('pjaxComplete', highlightAll, 'prismjs') + btf.addGlobalFn('encrypt', highlightAll, 'prismjs') + })() + + script(src=url_for(prismjs_js)) + script(src=url_for(prismjs_autoloader)) + if (line_number) + script(src=url_for(prismjs_lineNumber_js)) \ No newline at end of file diff --git a/layout/includes/third-party/subtitle.pug b/layout/includes/third-party/subtitle.pug index 0b4f6cc..c5fed4c 100644 --- a/layout/includes/third-party/subtitle.pug +++ b/layout/includes/third-party/subtitle.pug @@ -17,13 +17,14 @@ script. if (typeof Typed === 'function') { subtitleType() } else { - getScript('!{url_for(theme.asset.typed)}').then(subtitleType) + btf.getScript('!{url_for(theme.asset.typed)}').then(subtitleType) } } else { subtitleType() } } } + btf.addGlobalFn('pjaxSend', () => { typed.destroy() }, 'typedDestroy') case source when 1 @@ -47,7 +48,7 @@ case source when 2 script. function subtitleType () { - getScript('https://yijuzhan.com/api/word.php?m=js').then(() => { + btf.getScript('https://yijuzhan.com/api/word.php?m=js').then(() => { const con = str[0] if (!{effect}) { const from = '出自 ' + str[1] @@ -64,7 +65,7 @@ case source when 3 script. function subtitleType () { - getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js').then(() => { + btf.getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js').then(() => { jinrishici.load(result =>{ if (!{effect}) { const sub = !{JSON.stringify(subContent)} diff --git a/package.json b/package.json index 4602d98..787592f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hexo-theme-butterfly", - "version": "4.13.0", + "version": "4.14.0-b1", "description": "A Simple and Card UI Design theme for Hexo", "main": "package.json", "scripts": { diff --git a/plugins.yml b/plugins.yml index d8165bb..be6ecfa 100644 --- a/plugins.yml +++ b/plugins.yml @@ -1,11 +1,11 @@ algolia_search: name: algoliasearch file: dist/algoliasearch-lite.umd.js - version: 4.22.1 + version: 4.23.2 instantsearch: name: instantsearch.js file: dist/instantsearch.production.min.js - version: 4.65.0 + version: 4.66.1 pjax: name: pjax file: pjax.min.js @@ -37,17 +37,17 @@ disqusjs_css: twikoo: name: twikoo file: dist/twikoo.all.min.js - version: 1.6.31 + version: 1.6.32 waline_js: name: '@waline/client' file: dist/waline.js other_name: waline - version: 3.1.2 + version: 3.1.3 waline_css: name: '@waline/client' file: dist/waline.css other_name: waline - version: 3.1.2 + version: 3.1.3 sharejs: name: butterfly-extsrc file: sharejs/dist/js/social-share.min.js @@ -64,16 +64,16 @@ katex: name: katex file: dist/katex.min.css other_name: KaTeX - version: 0.16.9 + version: 0.16.10 katex_copytex: name: katex file: dist/contrib/copy-tex.min.js other_name: KaTeX - version: 0.16.9 + version: 0.16.10 mermaid: name: mermaid file: dist/mermaid.min.js - version: 10.8.0 + version: 10.9.0 canvas_ribbon: name: butterfly-extsrc file: dist/canvas-ribbon.min.js @@ -105,7 +105,7 @@ clickShowText: lazyload: name: vanilla-lazyload file: dist/lazyload.iife.min.js - version: 17.8.8 + version: 19.0.5 instantpage: name: instant.page file: instantpage.js @@ -121,12 +121,12 @@ pangu: fancybox_css: name: '@fancyapps/ui' file: dist/fancybox/fancybox.css - version: 5.0.33 + version: 5.0.35 other_name: fancyapps-ui fancybox: name: '@fancyapps/ui' file: dist/fancybox/fancybox.umd.js - version: 5.0.33 + version: 5.0.35 other_name: fancyapps-ui medium_zoom: name: medium-zoom @@ -180,11 +180,11 @@ prismjs_autoloader: artalk_js: name: artalk file: dist/Artalk.js - version: 2.8.2 + version: 2.8.3 artalk_css: name: artalk file: dist/Artalk.css - version: 2.8.2 + version: 2.8.3 pace_js: name: pace-js other_name: pace @@ -199,12 +199,12 @@ docsearch_js: name: '@docsearch/js' other_name: docsearch-js file: dist/umd/index.js - version: 3.5.2 + version: 3.6.0 docsearch_css: name: '@docsearch/css' other_name: docsearch-css file: dist/style.css - version: 3.5.2 + version: 3.6.0 abcjs_basic_js: name: abcjs file: dist/abcjs-basic-min.js diff --git a/scripts/helpers/inject_head_js.js b/scripts/helpers/inject_head_js.js index 5871fd7..417d851 100644 --- a/scripts/helpers/inject_head_js.js +++ b/scripts/helpers/inject_head_js.js @@ -6,16 +6,16 @@ 'use strict' hexo.extend.helper.register('inject_head_js', function () { - const { darkmode, aside } = this.theme + const { darkmode, aside, pjax } = this.theme const start = darkmode.start || 6 const end = darkmode.end || 18 const { theme_color } = hexo.theme.config const themeColorLight = (theme_color && theme_color.enable && theme_color.meta_theme_color_light) || '#ffffff' const themeColorDark = (theme_color && theme_color.enable && theme_color.meta_theme_color_dark) || '#0d0d0d' - const createLocalStore = () => { + const createCustonJs = () => { return ` - win.saveToLocal = { + const saveToLocal = { set: (key, value, ttl) => { if (ttl === 0) return const now = Date.now() @@ -43,49 +43,58 @@ hexo.extend.helper.register('inject_head_js', function () { return item.value } } - ` - } + + window.btf = { + saveToLocal: saveToLocal, + getScript: (url, attr = {}) => new Promise((resolve, reject) => { + const script = document.createElement('script') + script.src = url + script.async = true + script.onerror = reject + script.onload = script.onreadystatechange = function() { + const loadState = this.readyState + if (loadState && loadState !== 'loaded' && loadState !== 'complete') return + script.onload = script.onreadystatechange = null + resolve() + } - // https://stackoverflow.com/questions/16839698/jquery-getscript-alternative-in-native-javascript - const createGetScript = () => { - return ` - win.getScript = (url, attr = {}) => new Promise((resolve, reject) => { - const script = document.createElement('script') - script.src = url - script.async = true - script.onerror = reject - script.onload = script.onreadystatechange = function() { - const loadState = this.readyState - if (loadState && loadState !== 'loaded' && loadState !== 'complete') return - script.onload = script.onreadystatechange = null - resolve() + Object.keys(attr).forEach(key => { + script.setAttribute(key, attr[key]) + }) + + document.head.appendChild(script) + }), + + getCSS: (url, id = false) => new Promise((resolve, reject) => { + const link = document.createElement('link') + link.rel = 'stylesheet' + link.href = url + if (id) link.id = id + link.onerror = reject + link.onload = link.onreadystatechange = function() { + const loadState = this.readyState + if (loadState && loadState !== 'loaded' && loadState !== 'complete') return + link.onload = link.onreadystatechange = null + resolve() + } + document.head.appendChild(link) + }), + + addGlobalFn: (key, fn, name = false, parent = window) => { + const pjaxEnable = ${pjax.enable} + if (!pjaxEnable && key.startsWith('pjax')) return + + const globalFn = parent.globalFn || {} + const keyObj = globalFn[key] || {} + + if (name && keyObj[name]) return + + name = name || Object.keys(keyObj).length + keyObj[name] = fn + globalFn[key] = keyObj + parent.globalFn = globalFn } - - Object.keys(attr).forEach(key => { - script.setAttribute(key, attr[key]) - }) - - document.head.appendChild(script) - }) - ` - } - - const createGetCSS = () => { - return ` - win.getCSS = (url, id = false) => new Promise((resolve, reject) => { - const link = document.createElement('link') - link.rel = 'stylesheet' - link.href = url - if (id) link.id = id - link.onerror = reject - link.onload = link.onreadystatechange = function() { - const loadState = this.readyState - if (loadState && loadState !== 'loaded' && loadState !== 'complete') return - link.onload = link.onreadystatechange = null - resolve() - } - document.head.appendChild(link) - }) + } ` } @@ -93,18 +102,22 @@ hexo.extend.helper.register('inject_head_js', function () { if (!darkmode.enable) return '' let darkmodeJs = ` - win.activateDarkMode = () => { + const activateDarkMode = () => { document.documentElement.setAttribute('data-theme', 'dark') if (document.querySelector('meta[name="theme-color"]') !== null) { document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorDark}') } } - win.activateLightMode = () => { + const activateLightMode = () => { document.documentElement.setAttribute('data-theme', 'light') if (document.querySelector('meta[name="theme-color"]') !== null) { document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorLight}') } } + + btf.activateDarkMode = activateDarkMode + btf.activateLightMode = activateLightMode + const t = saveToLocal.get('theme') ` @@ -179,5 +192,5 @@ hexo.extend.helper.register('inject_head_js', function () { ` } - return `` + return `` }) diff --git a/source/css/_global/function.styl b/source/css/_global/function.styl index 9a4fa3c..85d96db 100644 --- a/source/css/_global/function.styl +++ b/source/css/_global/function.styl @@ -134,16 +134,14 @@ if hexo-config('enter_transitions') #footer animation: bottom-top 1s - #page-header:not(.full_page) + #page-header:not(.full_page), + #nav.show animation: header-effect 1s #site-title, #site-subtitle animation: titleScale 1s - #nav.show - animation: headerNoOpacity 1s - canvas:not(#ribbon-canvas), #web_bg animation: to_show 4s @@ -182,27 +180,16 @@ if hexo-config('avatar.effect') == true @keyframes header-effect 0% - opacity: 0 - transform: translateY(-50px) - - 100% - opacity: 1 - transform: translateY(0) - -@keyframes headerNoOpacity - 0% - transform: translateY(-50px) + transform: translateY(-35px) 100% transform: translateY(0) @keyframes bottom-top 0% - opacity: 0 - transform: translateY(50px) + transform: translateY(35px) 100% - opacity: 1 transform: translateY(0) @keyframes titleScale diff --git a/source/css/_global/index.styl b/source/css/_global/index.styl index 22c87c2..1f55e41 100644 --- a/source/css/_global/index.styl +++ b/source/css/_global/index.styl @@ -46,6 +46,7 @@ body font-family: $font-family line-height: $text-line-height -webkit-tap-highlight-color: rgba(0, 0, 0, 0) + scroll-behavior: smooth if !hexo-config('copy.enable') user-select: none diff --git a/source/css/_layout/head.styl b/source/css/_layout/head.styl index 97cb0ff..7847f12 100644 --- a/source/css/_layout/head.styl +++ b/source/css/_layout/head.styl @@ -117,6 +117,7 @@ box-shadow: 0 5px 6px -5px rgba(133, 133, 133, .6) a, + span.site-page, .site-name color: var(--font-color) text-shadow: none @@ -140,6 +141,7 @@ text-shadow: none a, + span.site-page, #toggle-menu color: var(--font-color) text-shadow: none @@ -290,7 +292,8 @@ &:hover color: var(--white) - a + a, + span.site-page color: var(--light-grey) &:hover @@ -312,10 +315,10 @@ .menus_item_child display: block - & > a > i:last-child + & > span > i:last-child transform: rotate(180deg) - & > a > i:last-child + & > span > i:last-child padding: 4px transition: transform .3s @@ -370,7 +373,7 @@ .menus_items display: none - #search-button span + #search-button span:not(.site-page) display: none #search-button diff --git a/source/css/_layout/sidebar.styl b/source/css/_layout/sidebar.styl index d960fff..e058f7c 100644 --- a/source/css/_layout/sidebar.styl +++ b/source/css/_layout/sidebar.styl @@ -40,9 +40,10 @@ position: relative display: block padding: 3px 28px 3px 20px + border-radius: 6px color: var(--font-color) font-size: 1.15em - border-radius: 6px + cursor: pointer &:hover background: var(--text-bg-hover) diff --git a/source/css/_layout/third-party.styl b/source/css/_layout/third-party.styl index 20705f9..b401d7a 100644 --- a/source/css/_layout/third-party.styl +++ b/source/css/_layout/third-party.styl @@ -74,8 +74,9 @@ if hexo-config('waline.bg') margin: 0 0 .8em padding: 6px 0 16px -.katex-wrap - overflow: auto +.katex-display + overflow: auto hidden + padding: 5px if hexo-config('katex') && hexo-config('katex.hide_scrollbar') &::-webkit-scrollbar @@ -132,4 +133,4 @@ mjx-assistive-mml +maxWidth768() .fancybox__toolbar__column.is-middle - display: none + display: none \ No newline at end of file diff --git a/source/js/main.js b/source/js/main.js index 2929801..fe552ea 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -180,6 +180,7 @@ document.addEventListener('DOMContentLoaded', function () { * PhotoFigcaption */ const addPhotoFigcaption = () => { + if (!GLOBAL_CONFIG.isPhotoFigcaption) return document.querySelectorAll('#article-container img').forEach(item => { const altValue = item.title || item.alt if (!altValue) return @@ -333,7 +334,7 @@ document.addEventListener('DOMContentLoaded', function () { if (typeof InfiniteGrid === 'function') { init() } else { - await getScript(`${GLOBAL_CONFIG.infinitegrid.js}`) + await btf.getScript(`${GLOBAL_CONFIG.infinitegrid.js}`) init() } } @@ -461,6 +462,9 @@ document.addEventListener('DOMContentLoaded', function () { $cardToc.scrollTop = sidebarScrollTop - 150 } } + + // 處理 hexo-blog-encrypt 事件 + $cardToc.style.display = 'block' } // find head position & add active class @@ -563,13 +567,13 @@ document.addEventListener('DOMContentLoaded', function () { darkmode: () => { // switch between light and dark mode const willChangeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark' if (willChangeMode === 'dark') { - activateDarkMode() + btf.activateDarkMode() GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) } else { - activateLightMode() + btf.activateLightMode() GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) } - saveToLocal.set('theme', willChangeMode, 2) + btf.saveToLocal.set('theme', willChangeMode, 2) handleThemeChange(willChangeMode) }, 'rightside-config': item => { // Show or hide rightside-hide-btn @@ -589,15 +593,24 @@ document.addEventListener('DOMContentLoaded', function () { 'hide-aside-btn': () => { // Hide aside const $htmlDom = document.documentElement.classList const saveStatus = $htmlDom.contains('hide-aside') ? 'show' : 'hide' - saveToLocal.set('aside-status', saveStatus, 2) + btf.saveToLocal.set('aside-status', saveStatus, 2) $htmlDom.toggle('hide-aside') }, - 'mobile-toc-button': item => { // Show mobile toc + 'mobile-toc-button': function (p, item) { // Show mobile toc const tocEle = document.getElementById('card-toc') tocEle.style.transition = 'transform 0.3s ease-in-out' + + const tocEleHeight = tocEle.clientHeight + const btData = item.getBoundingClientRect() + + const tocEleBottom = window.innerHeight - btData.bottom - 30 + if (tocEleHeight > tocEleBottom) { + tocEle.style.transformOrigin = `right ${tocEleHeight - tocEleBottom - btData.height / 2}px` + } + tocEle.classList.toggle('open') tocEle.addEventListener('transitionend', () => { - tocEle.style.transition = '' + tocEle.style.cssText = '' }, { once: true }) }, 'chat-btn': () => { // Show chat @@ -611,7 +624,7 @@ document.addEventListener('DOMContentLoaded', function () { document.getElementById('rightside').addEventListener('click', function (e) { const $target = e.target.closest('[id]') if ($target && rightSideFn[$target.id]) { - rightSideFn[$target.id](this) + rightSideFn[$target.id](this, $target) } }) @@ -812,6 +825,10 @@ document.addEventListener('DOMContentLoaded', function () { threshold: 0, data_src: 'lazy-src' }) + + btf.addGlobalFn('pjaxComplete', () => { + window.lazyLoadInstance.update() + }, 'lazyload') } const relativeDate = function (selector) { @@ -835,14 +852,29 @@ document.addEventListener('DOMContentLoaded', function () { GLOBAL_CONFIG.copyright !== undefined && addCopyright() if (GLOBAL_CONFIG.autoDarkmode) { - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { - if (saveToLocal.get('theme') !== undefined) return + window.matchMedia('(prefers-color-scheme: dark)').addListener(e => { + if (btf.saveToLocal.get('theme') !== undefined) return e.matches ? handleThemeChange('dark') : handleThemeChange('light') }) } } - window.refreshFn = function () { + const forPostFn = () => { + addHighlightTool() + addPhotoFigcaption() + + btf.removeGlobalFnEvent('justifiedGallery') + const galleryContainer = document.querySelectorAll('#article-container .gallery-container') + galleryContainer.length && addJustifiedGallery(galleryContainer) + + runLightbox() + scrollFnToDo() + addTableWrap() + clickFnOfTagHide() + tabsFn() + } + + const refreshFn = () => { initAdjust() if (GLOBAL_CONFIG_SITE.isPost) { @@ -855,24 +887,24 @@ document.addEventListener('DOMContentLoaded', function () { toggleCardCategory() } - scrollFnToDo() GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex() - addHighlightTool() - GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption() scrollFn() - btf.removeGlobalFnEvent('justifiedGallery') - const galleryContainer = document.querySelectorAll('#article-container .gallery-container') - galleryContainer.length && addJustifiedGallery(galleryContainer) - - runLightbox() - addTableWrap() - clickFnOfTagHide() - tabsFn() + forPostFn() switchComments() openMobileMenu() } + btf.addGlobalFn('pjaxComplete', refreshFn, 'refreshFn') refreshFn() unRefreshFn() + + // 處理 hexo-blog-encrypt 事件 + window.addEventListener('hexo-blog-decrypt', e => { + forPostFn() + window.translateFn.translateInitialization() + Object.values(window.globalFn.encrypt).forEach(fn => { + fn() + }) + }) }) diff --git a/source/js/tw_cn.js b/source/js/tw_cn.js index 15d8d15..fc3d4fa 100644 --- a/source/js/tw_cn.js +++ b/source/js/tw_cn.js @@ -4,9 +4,9 @@ document.addEventListener('DOMContentLoaded', function () { let currentEncoding = defaultEncoding const targetEncodingCookie = 'translate-chn-cht' let targetEncoding = - saveToLocal.get(targetEncodingCookie) === undefined + btf.saveToLocal.get(targetEncodingCookie) === undefined ? defaultEncoding - : Number(saveToLocal.get('translate-chn-cht')) + : Number(btf.saveToLocal.get('translate-chn-cht')) let translateButtonObject const isSnackbar = snackbarData !== undefined @@ -63,7 +63,7 @@ document.addEventListener('DOMContentLoaded', function () { translateButtonObject.textContent = msgToSimplifiedChinese isSnackbar && btf.snackbarShow(snackbarData.chs_to_cht) } - saveToLocal.set(targetEncodingCookie, targetEncoding, 2) + btf.saveToLocal.set(targetEncodingCookie, targetEncoding, 2) setLang() translateBody() } @@ -114,9 +114,10 @@ document.addEventListener('DOMContentLoaded', function () { window.translateFn = { translatePage, Traditionalized, - Simplized + Simplized, + translateInitialization } translateInitialization() - document.addEventListener('pjax:complete', translateInitialization) + btf.addGlobalFn('pjaxComplete', translateInitialization, 'translateInitialization') }) diff --git a/source/js/utils.js b/source/js/utils.js index 2c8242c..be1f32b 100644 --- a/source/js/utils.js +++ b/source/js/utils.js @@ -1,296 +1,288 @@ -const btf = { - debounce: (func, wait = 0, immediate = false) => { - let timeout - return (...args) => { - const later = () => { - timeout = null - if (!immediate) func(...args) - } - const callNow = immediate && !timeout - clearTimeout(timeout) - timeout = setTimeout(later, wait) - if (callNow) func(...args) - } - }, - - throttle: function (func, wait, options = {}) { - let timeout, context, args - let previous = 0 - - const later = () => { - previous = options.leading === false ? 0 : new Date().getTime() - timeout = null - func.apply(context, args) - if (!timeout) context = args = null - } - - const throttled = (...params) => { - const now = new Date().getTime() - if (!previous && options.leading === false) previous = now - const remaining = wait - (now - previous) - context = this - args = params - if (remaining <= 0 || remaining > wait) { - if (timeout) { - clearTimeout(timeout) +(() => { + const btfFn = { + debounce: (func, wait = 0, immediate = false) => { + let timeout + return (...args) => { + const later = () => { timeout = null + if (!immediate) func(...args) } - previous = now + const callNow = immediate && !timeout + clearTimeout(timeout) + timeout = setTimeout(later, wait) + if (callNow) func(...args) + } + }, + + throttle: function (func, wait, options = {}) { + let timeout, context, args + let previous = 0 + + const later = () => { + previous = options.leading === false ? 0 : new Date().getTime() + timeout = null func.apply(context, args) if (!timeout) context = args = null - } else if (!timeout && options.trailing !== false) { - timeout = setTimeout(later, remaining) } - } - return throttled - }, - - sidebarPaddingR: () => { - const innerWidth = window.innerWidth - const clientWidth = document.body.clientWidth - const paddingRight = innerWidth - clientWidth - if (innerWidth !== clientWidth) { - document.body.style.paddingRight = paddingRight + 'px' - } - }, - - snackbarShow: (text, showAction = false, duration = 2000) => { - const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar - const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark - Snackbar.show({ - text, - backgroundColor: bg, - showAction, - duration, - pos: position, - customClass: 'snackbar-css' - }) - }, - - diffDate: (d, more = false) => { - const dateNow = new Date() - const datePost = new Date(d) - const dateDiff = dateNow.getTime() - datePost.getTime() - const minute = 1000 * 60 - const hour = minute * 60 - const day = hour * 24 - const month = day * 30 - const { dateSuffix } = GLOBAL_CONFIG - - if (!more) return parseInt(dateDiff / day) - - const monthCount = dateDiff / month - const dayCount = dateDiff / day - const hourCount = dateDiff / hour - const minuteCount = dateDiff / minute - - if (monthCount > 12) return datePost.toISOString().slice(0, 10) - if (monthCount >= 1) return `${parseInt(monthCount)} ${dateSuffix.month}` - if (dayCount >= 1) return `${parseInt(dayCount)} ${dateSuffix.day}` - if (hourCount >= 1) return `${parseInt(hourCount)} ${dateSuffix.hour}` - if (minuteCount >= 1) return `${parseInt(minuteCount)} ${dateSuffix.min}` - return dateSuffix.just - }, - - loadComment: (dom, callback) => { - if ('IntersectionObserver' in window) { - const observerItem = new IntersectionObserver((entries) => { - if (entries[0].isIntersecting) { - callback() - observerItem.disconnect() + const throttled = (...params) => { + const now = new Date().getTime() + if (!previous && options.leading === false) previous = now + const remaining = wait - (now - previous) + context = this + args = params + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout) + timeout = null + } + previous = now + func.apply(context, args) + if (!timeout) context = args = null + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining) } - }, { threshold: [0] }) - observerItem.observe(dom) - } else { - callback() - } - }, + } - scrollToDest: (pos, time = 500) => { - const currentPos = window.pageYOffset - const isNavFixed = document.getElementById('page-header').classList.contains('fixed') - if (currentPos > pos || isNavFixed) pos = pos - 70 + return throttled + }, - if ('scrollBehavior' in document.documentElement.style) { - window.scrollTo({ - top: pos, - behavior: 'smooth' + sidebarPaddingR: () => { + const innerWidth = window.innerWidth + const clientWidth = document.body.clientWidth + const paddingRight = innerWidth - clientWidth + if (innerWidth !== clientWidth) { + document.body.style.paddingRight = paddingRight + 'px' + } + }, + + snackbarShow: (text, showAction = false, duration = 2000) => { + const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar + const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark + Snackbar.show({ + text, + backgroundColor: bg, + showAction, + duration, + pos: position, + customClass: 'snackbar-css' }) - return - } + }, - let start = null - pos = +pos - window.requestAnimationFrame(function step (currentTime) { - start = !start ? currentTime : start - const progress = currentTime - start - if (currentPos < pos) { - window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos) + diffDate: (d, more = false) => { + const dateNow = new Date() + const datePost = new Date(d) + const dateDiff = dateNow.getTime() - datePost.getTime() + const minute = 1000 * 60 + const hour = minute * 60 + const day = hour * 24 + const month = day * 30 + const { dateSuffix } = GLOBAL_CONFIG + + if (!more) return parseInt(dateDiff / day) + + const monthCount = dateDiff / month + const dayCount = dateDiff / day + const hourCount = dateDiff / hour + const minuteCount = dateDiff / minute + + if (monthCount > 12) return datePost.toISOString().slice(0, 10) + if (monthCount >= 1) return `${parseInt(monthCount)} ${dateSuffix.month}` + if (dayCount >= 1) return `${parseInt(dayCount)} ${dateSuffix.day}` + if (hourCount >= 1) return `${parseInt(hourCount)} ${dateSuffix.hour}` + if (minuteCount >= 1) return `${parseInt(minuteCount)} ${dateSuffix.min}` + return dateSuffix.just + }, + + loadComment: (dom, callback) => { + if ('IntersectionObserver' in window) { + const observerItem = new IntersectionObserver((entries) => { + if (entries[0].isIntersecting) { + callback() + observerItem.disconnect() + } + }, { threshold: [0] }) + observerItem.observe(dom) } else { - window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time)) + callback() } - if (progress < time) { - window.requestAnimationFrame(step) - } else { - window.scrollTo(0, pos) + }, + + scrollToDest: (pos, time = 500) => { + const currentPos = window.pageYOffset + const isNavFixed = document.getElementById('page-header').classList.contains('fixed') + if (currentPos > pos || isNavFixed) pos = pos - 70 + + if ('scrollBehavior' in document.documentElement.style) { + window.scrollTo({ + top: pos, + behavior: 'smooth' + }) + return } - }) - }, - animateIn: (ele, text) => { - ele.style.display = 'block' - ele.style.animation = text - }, - - animateOut: (ele, text) => { - ele.addEventListener('animationend', function f () { - ele.style.display = '' - ele.style.animation = '' - ele.removeEventListener('animationend', f) - }) - ele.style.animation = text - }, - - wrap: (selector, eleType, options) => { - const createEle = document.createElement(eleType) - for (const [key, value] of Object.entries(options)) { - createEle.setAttribute(key, value) - } - selector.parentNode.insertBefore(createEle, selector) - createEle.appendChild(selector) - }, - - isHidden: ele => ele.offsetHeight === 0 && ele.offsetWidth === 0, - - getEleTop: ele => { - let actualTop = ele.offsetTop - let current = ele.offsetParent - - while (current !== null) { - actualTop += current.offsetTop - current = current.offsetParent - } - - return actualTop - }, - - loadLightbox: ele => { - const service = GLOBAL_CONFIG.lightbox - - if (service === 'mediumZoom') { - mediumZoom(ele, { background: 'var(--zoom-bg)' }) - } - - if (service === 'fancybox') { - Array.from(ele).forEach(i => { - if (i.parentNode.tagName !== 'A') { - const dataSrc = i.dataset.lazySrc || i.src - const dataCaption = i.title || i.alt || '' - btf.wrap(i, 'a', { href: dataSrc, 'data-fancybox': 'gallery', 'data-caption': dataCaption, 'data-thumb': dataSrc }) + let start = null + pos = +pos + window.requestAnimationFrame(function step (currentTime) { + start = !start ? currentTime : start + const progress = currentTime - start + if (currentPos < pos) { + window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos) + } else { + window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time)) + } + if (progress < time) { + window.requestAnimationFrame(step) + } else { + window.scrollTo(0, pos) } }) + }, - if (!window.fancyboxRun) { - Fancybox.bind('[data-fancybox]', { - Hash: false, - Thumbs: { - showOnStart: false - }, - Images: { - Panzoom: { - maxScale: 4 - } - }, - Carousel: { - transition: 'slide' - }, - Toolbar: { - display: { - left: ['infobar'], - middle: [ - 'zoomIn', - 'zoomOut', - 'toggle1to1', - 'rotateCCW', - 'rotateCW', - 'flipX', - 'flipY' - ], - right: ['slideshow', 'thumbs', 'close'] - } + animateIn: (ele, text) => { + ele.style.display = 'block' + ele.style.animation = text + }, + + animateOut: (ele, text) => { + ele.addEventListener('animationend', function f () { + ele.style.display = '' + ele.style.animation = '' + ele.removeEventListener('animationend', f) + }) + ele.style.animation = text + }, + + wrap: (selector, eleType, options) => { + const createEle = document.createElement(eleType) + for (const [key, value] of Object.entries(options)) { + createEle.setAttribute(key, value) + } + selector.parentNode.insertBefore(createEle, selector) + createEle.appendChild(selector) + }, + + isHidden: ele => ele.offsetHeight === 0 && ele.offsetWidth === 0, + + getEleTop: ele => { + let actualTop = ele.offsetTop + let current = ele.offsetParent + + while (current !== null) { + actualTop += current.offsetTop + current = current.offsetParent + } + + return actualTop + }, + + loadLightbox: ele => { + const service = GLOBAL_CONFIG.lightbox + + if (service === 'mediumZoom') { + mediumZoom(ele, { background: 'var(--zoom-bg)' }) + } + + if (service === 'fancybox') { + Array.from(ele).forEach(i => { + if (i.parentNode.tagName !== 'A') { + const dataSrc = i.dataset.lazySrc || i.src + const dataCaption = i.title || i.alt || '' + btf.wrap(i, 'a', { href: dataSrc, 'data-fancybox': 'gallery', 'data-caption': dataCaption, 'data-thumb': dataSrc }) } }) - window.fancyboxRun = true - } - } - }, - setLoading: { - add: ele => { - const html = ` + if (!window.fancyboxRun) { + Fancybox.bind('[data-fancybox]', { + Hash: false, + Thumbs: { + showOnStart: false + }, + Images: { + Panzoom: { + maxScale: 4 + } + }, + Carousel: { + transition: 'slide' + }, + Toolbar: { + display: { + left: ['infobar'], + middle: [ + 'zoomIn', + 'zoomOut', + 'toggle1to1', + 'rotateCCW', + 'rotateCW', + 'flipX', + 'flipY' + ], + right: ['slideshow', 'thumbs', 'close'] + } + } + }) + window.fancyboxRun = true + } + } + }, + + setLoading: { + add: ele => { + const html = `
` - ele.insertAdjacentHTML('afterend', html) + ele.insertAdjacentHTML('afterend', html) + }, + remove: ele => { + ele.nextElementSibling.remove() + } }, - remove: ele => { - ele.nextElementSibling.remove() + + updateAnchor: (anchor) => { + if (anchor !== window.location.hash) { + if (!anchor) anchor = location.pathname + const title = GLOBAL_CONFIG_SITE.title + window.history.replaceState({ + url: location.href, + title + }, title, anchor) + } + }, + + getScrollPercent: (currentTop, ele) => { + const docHeight = ele.clientHeight + const winHeight = document.documentElement.clientHeight + const headerHeight = ele.offsetTop + const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight) + const scrollPercent = (currentTop - headerHeight) / (contentMath) + const scrollPercentRounded = Math.round(scrollPercent * 100) + const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded + return percentage + }, + + addEventListenerPjax: (ele, event, fn, option = false) => { + ele.addEventListener(event, fn, option) + btf.addGlobalFn('pjax', () => { + ele.removeEventListener(event, fn, option) + }) + }, + + removeGlobalFnEvent: (key, parent = window) => { + const { globalFn = {} } = parent + const keyObj = globalFn[key] || {} + const keyArr = Object.keys(keyObj) + if (!keyArr.length) return + keyArr.forEach(i => { + keyObj[i]() + }) + delete parent.globalFn[key] } - }, - - updateAnchor: (anchor) => { - if (anchor !== window.location.hash) { - if (!anchor) anchor = location.pathname - const title = GLOBAL_CONFIG_SITE.title - window.history.replaceState({ - url: location.href, - title - }, title, anchor) - } - }, - - getScrollPercent: (currentTop, ele) => { - const docHeight = ele.clientHeight - const winHeight = document.documentElement.clientHeight - const headerHeight = ele.offsetTop - const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight) - const scrollPercent = (currentTop - headerHeight) / (contentMath) - const scrollPercentRounded = Math.round(scrollPercent * 100) - const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded - return percentage - }, - - addGlobalFn: (key, fn, name = false, parent = window) => { - const globalFn = parent.globalFn || {} - const keyObj = globalFn[key] || {} - - if (name && keyObj[name]) return - - name = name || Object.keys(keyObj).length - keyObj[name] = fn - globalFn[key] = keyObj - parent.globalFn = globalFn - }, - - addEventListenerPjax: (ele, event, fn, option = false) => { - ele.addEventListener(event, fn, option) - btf.addGlobalFn('pjax', () => { - ele.removeEventListener(event, fn, option) - }) - }, - - removeGlobalFnEvent: (key, parent = window) => { - const { globalFn = {} } = parent - const keyObj = globalFn[key] || {} - const keyArr = Object.keys(keyObj) - if (!keyArr.length) return - keyArr.forEach(i => { - keyObj[i]() - }) - delete parent.globalFn[key] } -} + + window.btf = { ...window.btf, ...btfFn } +})()