feat: 修改 toc 打開效果

feat: 適配 hexo-blog-encrypt
fix: 修復 hexo 新版本下,prismjs 的問題
improvement: 在 pjax 關閉的情況下。減少不必要的全局變量
improvement: 更新依賴版本
improvement: 頁面進入效果優化
improvement: 添加平滑滾動
improvement: 兼容性優化
improvement: 優化 lighthouse 分數
improvement: 優化代碼
This commit is contained in:
Jerry
2024-04-02 23:44:46 +08:00
parent ee6b137e94
commit 9e0dce6c7a
41 changed files with 601 additions and 536 deletions

View File

@@ -48,6 +48,8 @@ if (theme.snackbar && theme.snackbar.enable)
if theme.fancybox if theme.fancybox
link(rel='stylesheet' href=url_for(theme.asset.fancybox_css) media="print" onload="this.media='all'") 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 //- google_adsense
!=partial('includes/head/google_adsense', {}, {cache: true}) !=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 include ./head/config_site.pug
!=fragment_cache('injectHeadJs', function(){return inject_head_js()})
!=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)}) !=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)})

View File

@@ -7,14 +7,20 @@ if theme.baidu_analytics
var s = document.getElementsByTagName("script")[0]; var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s); s.parentNode.insertBefore(hm, s);
})(); })();
btf.addGlobalFn('pjaxComplete', () => {
_hmt.push(['_trackPageview',window.location.pathname])
}, 'baidu_analytics')
if theme.google_analytics if theme.google_analytics
script(async src=`https://www.googletagmanager.com/gtag/js?id=${theme.google_analytics}`) script(async src=`https://www.googletagmanager.com/gtag/js?id=${theme.google_analytics}`)
script. script.
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || []
function gtag(){dataLayer.push(arguments);} function gtag(){dataLayer.push(arguments)}
gtag('js', new Date()); gtag('js', new Date())
gtag('config', '!{theme.google_analytics}'); gtag('config', '!{theme.google_analytics}')
btf.addGlobalFn('pjaxComplete', () => {
gtag('config', '!{theme.google_analytics}', {'page_path': window.location.pathname})
}, 'google_analytics')
if theme.cloudflare_analytics if theme.cloudflare_analytics
script(defer data-pjax src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon=`{"token": "${theme.cloudflare_analytics}"}`) script(defer data-pjax src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon=`{"token": "${theme.cloudflare_analytics}"}`)

View File

@@ -12,7 +12,7 @@ if theme.menu
.menus_item .menus_item
- const labelArray = label.split('||') - const labelArray = label.split('||')
- const hideClass = labelArray[2] && trim(labelArray[2]) === 'hide' ? 'hide' : '' - 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] if labelArray[1]
i.fa-fw(class=trim(labelArray[1])) i.fa-fw(class=trim(labelArray[1]))
span=' '+ trim(labelArray[0]) span=' '+ trim(labelArray[0])

View File

@@ -2,20 +2,20 @@ nav#nav
span#blog-info span#blog-info
a(href=url_for('/') title=config.title) a(href=url_for('/') title=config.title)
if theme.nav.logo 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 if theme.nav.display_title
span.site-name=config.title span.site-name=config.title
#menus #menus
if (theme.algolia_search.enable || theme.local_search.enable || theme.docsearch.enable) if (theme.algolia_search.enable || theme.local_search.enable || theme.docsearch.enable)
#search-button #search-button
a.site-page.social-icon.search(href="javascript:void(0);") span.site-page.social-icon.search
i.fas.fa-search.fa-fw i.fas.fa-search.fa-fw
span=' '+_p('search.title') span=' '+_p('search.title')
!=partial('includes/header/menu_item', {}, {cache: true}) !=partial('includes/header/menu_item', {}, {cache: true})
#toggle-menu #toggle-menu
a.site-page(href="javascript:void(0);") span.site-page
i.fas.fa-bars.fa-fw i.fas.fa-bars.fa-fw

View File

@@ -27,7 +27,7 @@ script.
window.addEventListener('load',() => { preloader.endLoading() }) window.addEventListener('load',() => { preloader.endLoading() })
if (!{theme.pjax && theme.pjax.enable}) { if (!{theme.pjax && theme.pjax.enable}) {
document.addEventListener('pjax:send', () => { preloader.initLoading() }) btf.addGlobalFn('pjaxSend', () => { preloader.initLoading() }, 'preloader_init')
document.addEventListener('pjax:complete', () => { preloader.endLoading() }) btf.addGlobalFn('pjaxComplete', () => { preloader.endLoading() }, 'preloader_end')
} }
})() })()

View File

@@ -3,9 +3,10 @@ script.
restartOnPushState: false restartOnPushState: false
} }
document.addEventListener('pjax:send', () => { btf.addGlobalFn('pjaxSend', () => {
Pace.restart() Pace.restart()
}) }, 'pace_restart')
link(rel="stylesheet", href=url_for(theme.preloader.pace_css_url || theme.asset.pace_default_css)) link(rel="stylesheet", href=url_for(theme.preloader.pace_css_url || theme.asset.pace_default_css))
script(src=url_for(theme.asset.pace_js)) script(src=url_for(theme.asset.pace_js))

View File

@@ -3,13 +3,15 @@ script.
const abcjsInit = () => { const abcjsInit = () => {
const abcjsFn = () => { const abcjsFn = () => {
document.querySelectorAll(".abc-music-sheet").forEach(ele => { document.querySelectorAll(".abc-music-sheet").forEach(ele => {
if (ele.children.length > 0) return
ABCJS.renderAbc(ele, ele.innerHTML, {responsive: 'resize'}) ABCJS.renderAbc(ele, ele.innerHTML, {responsive: 'resize'})
}) })
} }
typeof ABCJS === 'object' ? abcjsFn() 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) window.pjax ? abcjsInit() : window.addEventListener('load', abcjsInit)
btf.addGlobalFn('encrypt', abcjsInit, 'abcjs')
})() })()

View File

@@ -1,3 +1,23 @@
link(rel='stylesheet' href=url_for(theme.asset.aplayer_css) media="print" onload="this.media='all'") 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.aplayer_js))
script(src=url_for(theme.asset.meting_js)) 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')
})()

View File

@@ -28,7 +28,7 @@ script.
if (typeof twikoo === 'object') { if (typeof twikoo === 'object') {
runTwikoo() runTwikoo()
} else { } else {
getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo) btf.getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo)
} }
} }

View File

@@ -13,7 +13,7 @@ script.
} }
if (typeof Valine === 'function') initValine() 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) window.pjax ? loadValine() : window.addEventListener('load', loadValine)

View File

@@ -31,8 +31,8 @@ script.
const loadArtalk = async () => { const loadArtalk = async () => {
if (typeof Artalk === 'object') initArtalk() if (typeof Artalk === 'object') initArtalk()
else { else {
await getCSS('!{theme.asset.artalk_css}') await btf.getCSS('!{theme.asset.artalk_css}')
await getScript('!{theme.asset.artalk_js}') await btf.getScript('!{theme.asset.artalk_js}')
initArtalk() initArtalk()
} }
} }

View File

@@ -28,8 +28,8 @@ script.
const loadDisqusjs = async() => { const loadDisqusjs = async() => {
if (window.disqusJsLoad) initDisqusjs() if (window.disqusJsLoad) initDisqusjs()
else { else {
await getCSS('!{url_for(theme.asset.disqusjs_css)}') await btf.getCSS('!{url_for(theme.asset.disqusjs_css)}')
await getScript('!{url_for(theme.asset.disqusjs)}') await btf.getScript('!{url_for(theme.asset.disqusjs)}')
initDisqusjs() initDisqusjs()
window.disqusJsLoad = true window.disqusJsLoad = true
} }

View File

@@ -19,8 +19,8 @@ script.
const loadGitalk = async() => { const loadGitalk = async() => {
if (typeof Gitalk === 'function') initGitalk() if (typeof Gitalk === 'function') initGitalk()
else { else {
await getCSS('!{url_for(theme.asset.gitalk_css)}') await btf.getCSS('!{url_for(theme.asset.gitalk_css)}')
await getScript('!{url_for(theme.asset.gitalk)}') await btf.getScript('!{url_for(theme.asset.gitalk)}')
initGitalk() initGitalk()
} }
} }

View File

@@ -33,7 +33,7 @@ script.
const loadTwikoo = () => { const loadTwikoo = () => {
if (typeof twikoo === 'object') setTimeout(init,0) 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}) { if ('!{use[0]}' === 'Twikoo' || !!{lazyload}) {

View File

@@ -23,7 +23,7 @@ script.
const loadValine = async () => { const loadValine = async () => {
if (typeof Valine === 'function') initValine() if (typeof Valine === 'function') initValine()
else { else {
await getScript('!{url_for(theme.asset.valine)}') await btf.getScript('!{url_for(theme.asset.valine)}')
initValine() initValine()
} }
} }

View File

@@ -22,14 +22,16 @@ script.
btf.addGlobalFn('pjax', destroyWaline, 'destroyWaline') btf.addGlobalFn('pjax', destroyWaline, 'destroyWaline')
} }
const loadWaline = async () => { const loadWaline = () => {
if (initFn) initWaline(initFn) if (initFn) initWaline(initFn)
else { else {
await getCSS('!{url_for(theme.asset.waline_css)}') btf.getCSS('!{url_for(theme.asset.waline_css)}')
const { init } = await import('!{url_for(theme.asset.waline_js)}') .then(() => import('!{url_for(theme.asset.waline_js)}'))
initFn = init || Waline.init .then(({ init }) => {
initWaline(initFn) initFn = init || Waline.init
window.walineFn = initFn initWaline(initFn)
window.walineFn = initFn
})
} }
} }

View File

@@ -1,9 +1,2 @@
link(rel="stylesheet" type="text/css" href=url_for(theme.asset.katex)) link(rel="stylesheet" type="text/css" href=url_for(theme.asset.katex))
script(src=url_for(theme.asset.katex_copytex)) 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'})
})
})()

View File

@@ -1,38 +1,45 @@
//- Mathjax 3 //- Mathjax 3
script. script.
if (!window.MathJax) { (() => {
window.MathJax = { const loadMathjax = () => {
tex: { if (!window.MathJax) {
inlineMath: [['$', '$'], ['\\(', '\\)']], window.MathJax = {
tags: 'ams' tex: {
}, inlineMath: [['$', '$'], ['\\(', '\\)']],
chtml: { tags: 'ams'
scale: 1.1 },
}, chtml: {
options: { scale: 1.1
renderActions: { },
findScript: [10, doc => { options: {
for (const node of document.querySelectorAll('script[type^="math/tex"]')) { renderActions: {
const display = !!node.type.match(/; *mode=display/) findScript: [10, doc => {
const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display) for (const node of document.querySelectorAll('script[type^="math/tex"]')) {
const text = document.createTextNode('') const display = !!node.type.match(/; *mode=display/)
node.parentNode.replaceChild(text, node) const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display)
math.start = {node: text, delim: '', n: 0} const text = document.createTextNode('')
math.end = {node: text, delim: '', n: 0} node.parentNode.replaceChild(text, node)
doc.math.push(math) 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') btf.addGlobalFn('encrypt', loadMathjax, 'mathjax')
script.src = '!{url_for(theme.asset.mathjax)}' window.pjax ? loadMathjax() : window.addEventListener('load', loadMathjax)
script.id = 'MathJax-script' })()
script.async = true
document.head.appendChild(script)
} else {
MathJax.startup.document.state(0)
MathJax.texReset()
MathJax.typesetPromise()
}

View File

@@ -1,12 +1,10 @@
script. script.
(() => { (() => {
const $mermaid = document.querySelectorAll('#article-container .mermaid-wrap') const runMermaid = (ele) => {
if ($mermaid.length === 0) return
const runMermaid = () => {
window.loadMermaid = true window.loadMermaid = true
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{theme.mermaid.theme.dark}' : '!{theme.mermaid.theme.light}' 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 mermaidSrc = item.firstElementChild
const mermaidThemeConfig = '%%{init:{ \'theme\':\'' + theme + '\'}}%%\n' const mermaidThemeConfig = '%%{init:{ \'theme\':\'' + theme + '\'}}%%\n'
const mermaidID = 'mermaid-' + index const mermaidID = 'mermaid-' + index
@@ -29,10 +27,14 @@ script.
} }
const loadMermaid = () => { 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) window.pjax ? loadMermaid() : document.addEventListener('DOMContentLoaded', loadMermaid)
})() })()

View File

@@ -81,7 +81,7 @@ script.
'date': e.date, '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) generateHtml(artalk)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
@@ -92,7 +92,7 @@ script.
const newestCommentInit = () => { const newestCommentInit = () => {
if (document.querySelector('#card-newest-comments .aside-list')) { 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) { if (data) {
generateHtml(JSON.parse(data)) generateHtml(JSON.parse(data))
} else { } else {
@@ -102,5 +102,6 @@ script.
} }
newestCommentInit() newestCommentInit()
document.addEventListener('pjax:complete', newestCommentInit) btf.addGlobalFn('pjaxComplete', newestCommentInit, 'artalk_newestComment')
}) })

View File

@@ -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) generateHtml(disqusArray)
}).catch(e => { }).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
@@ -65,7 +65,7 @@ script.
const newestCommentInit = () => { const newestCommentInit = () => {
if (document.querySelector('#card-newest-comments .aside-list')) { 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) { if (data) {
generateHtml(JSON.parse(data)) generateHtml(JSON.parse(data))
} else { } else {
@@ -75,7 +75,7 @@ script.
} }
newestCommentInit() newestCommentInit()
document.addEventListener('pjax:complete', newestCommentInit) btf.addGlobalFn('pjaxComplete', newestCommentInit, 'disqus_newestComment')
}) })

View File

@@ -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) generateHtml(array)
}); });
} }
@@ -94,7 +94,7 @@ script.
const newestCommentInit = () => { const newestCommentInit = () => {
if (document.querySelector('#card-newest-comments .aside-list')) { 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) { if (data) {
generateHtml(JSON.parse(data)) generateHtml(JSON.parse(data))
} else { } else {
@@ -104,7 +104,7 @@ script.
} }
newestCommentInit() newestCommentInit()
document.addEventListener('pjax:complete', newestCommentInit) btf.addGlobalFn('pjaxComplete', newestCommentInit, 'github_newestComment')
}) })

View File

@@ -56,7 +56,7 @@ script.
'date': e.time, '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) generateHtml(remark42)
}).catch(e => { }).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
@@ -66,7 +66,7 @@ script.
const newestCommentInit = () => { const newestCommentInit = () => {
if (document.querySelector('#card-newest-comments .aside-list')) { 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) { if (data) {
generateHtml(JSON.parse(data)) generateHtml(JSON.parse(data))
} else { } else {
@@ -76,5 +76,5 @@ script.
} }
newestCommentInit() newestCommentInit()
document.addEventListener('pjax:complete', newestCommentInit) btf.addGlobalFn('pjaxComplete', newestCommentInit, 'remark42_newestComment')
}) })

View File

@@ -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) generateHtml(twikooArray)
}).catch(function (err) { }).catch(function (err) {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
@@ -43,7 +43,7 @@ script.
if (typeof twikoo === 'object') { if (typeof twikoo === 'object') {
runTwikoo() runTwikoo()
} else { } 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 = () => { const newestCommentInit = () => {
if (document.querySelector('#card-newest-comments .aside-list')) { 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) { if (data) {
generateHtml(JSON.parse(data)) generateHtml(JSON.parse(data))
} else { } else {
@@ -86,7 +86,7 @@ script.
} }
newestCommentInit() newestCommentInit()
document.addEventListener('pjax:complete', newestCommentInit) btf.addGlobalFn('pjaxComplete', newestCommentInit, 'twikoo_newestComment')
}) })

View File

@@ -75,7 +75,7 @@ script.
'date': e.updatedAt, '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) generateHtml(valineArray)
}).catch(e => { }).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
@@ -85,7 +85,7 @@ script.
const newestCommentInit = () => { const newestCommentInit = () => {
if (document.querySelector('#card-newest-comments .aside-list')) { 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) { if (data) {
generateHtml(JSON.parse(data)) generateHtml(JSON.parse(data))
} else { } else {
@@ -95,5 +95,5 @@ script.
} }
newestCommentInit() newestCommentInit()
document.addEventListener('pjax:complete', newestCommentInit) btf.addGlobalFn('pjaxComplete', newestCommentInit, 'valine_newestComment')
}) })

View File

@@ -56,7 +56,7 @@ script.
'date': e.time || e.insertedAt '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) generateHtml(walineArray)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
@@ -67,7 +67,7 @@ script.
const newestCommentInit = () => { const newestCommentInit = () => {
if (document.querySelector('#card-newest-comments .aside-list')) { 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) { if (data) {
generateHtml(JSON.parse(data)) generateHtml(JSON.parse(data))
} else { } else {
@@ -77,5 +77,5 @@ script.
} }
newestCommentInit() newestCommentInit()
document.addEventListener('pjax:complete', newestCommentInit) btf.addGlobalFn('pjaxComplete', newestCommentInit, 'waline_newestComment')
}) })

View File

@@ -1,20 +1,23 @@
script. script.
function panguFn () { (() => {
if (typeof pangu === 'object') pangu.autoSpacingPage() const panguFn = () => {
else { if (typeof pangu === 'object') pangu.autoSpacingPage()
getScript('!{url_for(theme.asset.pangu)}') else {
.then(() => { btf.getScript('!{url_for(theme.asset.pangu)}')
pangu.autoSpacingPage() .then(() => {
}) pangu.autoSpacingPage()
})
}
} }
}
function panguInit () { const panguInit = () => {
if (!{theme.pangu.field === 'post'}){ if (!{theme.pangu.field === 'post'}){
GLOBAL_CONFIG_SITE.isPost && panguFn() GLOBAL_CONFIG_SITE.isPost && panguFn()
} else { } else {
panguFn() panguFn()
}
} }
}
document.addEventListener('DOMContentLoaded', panguInit) btf.addGlobalFn('pjaxComplete', panguInit, 'pangu')
document.addEventListener('DOMContentLoaded', panguInit)
})()

View File

@@ -24,34 +24,25 @@ script.
scrollRestoration: false scrollRestoration: false
}) })
const triggerPjaxFn = (val) => {
if (!val) return
Object.values(val).forEach(fn => { fn() })
}
document.addEventListener('pjax:send', function () { document.addEventListener('pjax:send', function () {
// removeEventListener // removeEventListener
btf.removeGlobalFnEvent('pjax') btf.removeGlobalFnEvent('pjax')
btf.removeGlobalFnEvent('themeChange') 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 //reset readmode
const $bodyClassList = document.body.classList const $bodyClassList = document.body.classList
$bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode') $bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode')
typeof disqusjs === 'object' && disqusjs.destroy() triggerPjaxFn(window.globalFn.pjaxSend)
}) })
document.addEventListener('pjax:complete', function () { document.addEventListener('pjax:complete', () => {
window.refreshFn()
document.querySelectorAll('script[data-pjax]').forEach(item => { document.querySelectorAll('script[data-pjax]').forEach(item => {
const newScript = document.createElement('script') const newScript = document.createElement('script')
const content = item.text || item.textContent || item.innerHTML || "" const content = item.text || item.textContent || item.innerHTML || ""
@@ -60,20 +51,7 @@ script.
item.parentNode.replaceChild(newScript, item) item.parentNode.replaceChild(newScript, item)
}) })
GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update() triggerPjaxFn(window.globalFn.pjaxComplete)
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()
}) })
document.addEventListener('pjax:error', e => { document.addEventListener('pjax:error', e => {

View File

@@ -1,5 +1,23 @@
if config.prismjs && config.prismjs.enable && !config.prismjs.preprocess - const { prismjs_js, prismjs_autoloader, prismjs_lineNumber_js } = theme.asset
script(src=url_for(theme.asset.prismjs_js)) - const { prismjs, syntax_highlighter } = config
script(src=url_for(theme.asset.prismjs_autoloader)) - const { enable, preprocess, line_number } = prismjs
if config.prismjs.line_number
script(src=url_for(theme.asset.prismjs_lineNumber_js)) 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))

View File

@@ -17,13 +17,14 @@ script.
if (typeof Typed === 'function') { if (typeof Typed === 'function') {
subtitleType() subtitleType()
} else { } else {
getScript('!{url_for(theme.asset.typed)}').then(subtitleType) btf.getScript('!{url_for(theme.asset.typed)}').then(subtitleType)
} }
} else { } else {
subtitleType() subtitleType()
} }
} }
} }
btf.addGlobalFn('pjaxSend', () => { typed.destroy() }, 'typedDestroy')
case source case source
when 1 when 1
@@ -47,7 +48,7 @@ case source
when 2 when 2
script. script.
function subtitleType () { 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] const con = str[0]
if (!{effect}) { if (!{effect}) {
const from = '出自 ' + str[1] const from = '出自 ' + str[1]
@@ -64,7 +65,7 @@ case source
when 3 when 3
script. script.
function subtitleType () { 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 =>{ jinrishici.load(result =>{
if (!{effect}) { if (!{effect}) {
const sub = !{JSON.stringify(subContent)} const sub = !{JSON.stringify(subContent)}

View File

@@ -1,6 +1,6 @@
{ {
"name": "hexo-theme-butterfly", "name": "hexo-theme-butterfly",
"version": "4.13.0", "version": "4.14.0-b1",
"description": "A Simple and Card UI Design theme for Hexo", "description": "A Simple and Card UI Design theme for Hexo",
"main": "package.json", "main": "package.json",
"scripts": { "scripts": {

View File

@@ -1,11 +1,11 @@
algolia_search: algolia_search:
name: algoliasearch name: algoliasearch
file: dist/algoliasearch-lite.umd.js file: dist/algoliasearch-lite.umd.js
version: 4.22.1 version: 4.23.2
instantsearch: instantsearch:
name: instantsearch.js name: instantsearch.js
file: dist/instantsearch.production.min.js file: dist/instantsearch.production.min.js
version: 4.65.0 version: 4.66.1
pjax: pjax:
name: pjax name: pjax
file: pjax.min.js file: pjax.min.js
@@ -37,17 +37,17 @@ disqusjs_css:
twikoo: twikoo:
name: twikoo name: twikoo
file: dist/twikoo.all.min.js file: dist/twikoo.all.min.js
version: 1.6.31 version: 1.6.32
waline_js: waline_js:
name: '@waline/client' name: '@waline/client'
file: dist/waline.js file: dist/waline.js
other_name: waline other_name: waline
version: 3.1.2 version: 3.1.3
waline_css: waline_css:
name: '@waline/client' name: '@waline/client'
file: dist/waline.css file: dist/waline.css
other_name: waline other_name: waline
version: 3.1.2 version: 3.1.3
sharejs: sharejs:
name: butterfly-extsrc name: butterfly-extsrc
file: sharejs/dist/js/social-share.min.js file: sharejs/dist/js/social-share.min.js
@@ -64,16 +64,16 @@ katex:
name: katex name: katex
file: dist/katex.min.css file: dist/katex.min.css
other_name: KaTeX other_name: KaTeX
version: 0.16.9 version: 0.16.10
katex_copytex: katex_copytex:
name: katex name: katex
file: dist/contrib/copy-tex.min.js file: dist/contrib/copy-tex.min.js
other_name: KaTeX other_name: KaTeX
version: 0.16.9 version: 0.16.10
mermaid: mermaid:
name: mermaid name: mermaid
file: dist/mermaid.min.js file: dist/mermaid.min.js
version: 10.8.0 version: 10.9.0
canvas_ribbon: canvas_ribbon:
name: butterfly-extsrc name: butterfly-extsrc
file: dist/canvas-ribbon.min.js file: dist/canvas-ribbon.min.js
@@ -105,7 +105,7 @@ clickShowText:
lazyload: lazyload:
name: vanilla-lazyload name: vanilla-lazyload
file: dist/lazyload.iife.min.js file: dist/lazyload.iife.min.js
version: 17.8.8 version: 19.0.5
instantpage: instantpage:
name: instant.page name: instant.page
file: instantpage.js file: instantpage.js
@@ -121,12 +121,12 @@ pangu:
fancybox_css: fancybox_css:
name: '@fancyapps/ui' name: '@fancyapps/ui'
file: dist/fancybox/fancybox.css file: dist/fancybox/fancybox.css
version: 5.0.33 version: 5.0.35
other_name: fancyapps-ui other_name: fancyapps-ui
fancybox: fancybox:
name: '@fancyapps/ui' name: '@fancyapps/ui'
file: dist/fancybox/fancybox.umd.js file: dist/fancybox/fancybox.umd.js
version: 5.0.33 version: 5.0.35
other_name: fancyapps-ui other_name: fancyapps-ui
medium_zoom: medium_zoom:
name: medium-zoom name: medium-zoom
@@ -180,11 +180,11 @@ prismjs_autoloader:
artalk_js: artalk_js:
name: artalk name: artalk
file: dist/Artalk.js file: dist/Artalk.js
version: 2.8.2 version: 2.8.3
artalk_css: artalk_css:
name: artalk name: artalk
file: dist/Artalk.css file: dist/Artalk.css
version: 2.8.2 version: 2.8.3
pace_js: pace_js:
name: pace-js name: pace-js
other_name: pace other_name: pace
@@ -199,12 +199,12 @@ docsearch_js:
name: '@docsearch/js' name: '@docsearch/js'
other_name: docsearch-js other_name: docsearch-js
file: dist/umd/index.js file: dist/umd/index.js
version: 3.5.2 version: 3.6.0
docsearch_css: docsearch_css:
name: '@docsearch/css' name: '@docsearch/css'
other_name: docsearch-css other_name: docsearch-css
file: dist/style.css file: dist/style.css
version: 3.5.2 version: 3.6.0
abcjs_basic_js: abcjs_basic_js:
name: abcjs name: abcjs
file: dist/abcjs-basic-min.js file: dist/abcjs-basic-min.js

View File

@@ -6,16 +6,16 @@
'use strict' 'use strict'
hexo.extend.helper.register('inject_head_js', function () { 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 start = darkmode.start || 6
const end = darkmode.end || 18 const end = darkmode.end || 18
const { theme_color } = hexo.theme.config const { theme_color } = hexo.theme.config
const themeColorLight = (theme_color && theme_color.enable && theme_color.meta_theme_color_light) || '#ffffff' 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 themeColorDark = (theme_color && theme_color.enable && theme_color.meta_theme_color_dark) || '#0d0d0d'
const createLocalStore = () => { const createCustonJs = () => {
return ` return `
win.saveToLocal = { const saveToLocal = {
set: (key, value, ttl) => { set: (key, value, ttl) => {
if (ttl === 0) return if (ttl === 0) return
const now = Date.now() const now = Date.now()
@@ -43,49 +43,58 @@ hexo.extend.helper.register('inject_head_js', function () {
return item.value return item.value
} }
} }
`
}
// https://stackoverflow.com/questions/16839698/jquery-getscript-alternative-in-native-javascript window.btf = {
const createGetScript = () => { saveToLocal: saveToLocal,
return ` getScript: (url, attr = {}) => new Promise((resolve, reject) => {
win.getScript = (url, attr = {}) => new Promise((resolve, reject) => { const script = document.createElement('script')
const script = document.createElement('script') script.src = url
script.src = url script.async = true
script.async = true script.onerror = reject
script.onerror = reject script.onload = script.onreadystatechange = function() {
script.onload = script.onreadystatechange = function() { const loadState = this.readyState
const loadState = this.readyState if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return script.onload = script.onreadystatechange = null
script.onload = script.onreadystatechange = null resolve()
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 '' if (!darkmode.enable) return ''
let darkmodeJs = ` let darkmodeJs = `
win.activateDarkMode = () => { const activateDarkMode = () => {
document.documentElement.setAttribute('data-theme', 'dark') document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) { if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorDark}') document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorDark}')
} }
} }
win.activateLightMode = () => { const activateLightMode = () => {
document.documentElement.setAttribute('data-theme', 'light') document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) { if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorLight}') document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorLight}')
} }
} }
btf.activateDarkMode = activateDarkMode
btf.activateLightMode = activateLightMode
const t = saveToLocal.get('theme') const t = saveToLocal.get('theme')
` `
@@ -179,5 +192,5 @@ hexo.extend.helper.register('inject_head_js', function () {
` `
} }
return `<script>(win=>{${createLocalStore() + createGetScript() + createGetCSS() + createDarkmodeJs() + createAsideStatus() + createDetectApple()}})(window)</script>` return `<script>(()=>{${createCustonJs() + createDarkmodeJs() + createAsideStatus() + createDetectApple()}})()</script>`
}) })

View File

@@ -134,16 +134,14 @@ if hexo-config('enter_transitions')
#footer #footer
animation: bottom-top 1s animation: bottom-top 1s
#page-header:not(.full_page) #page-header:not(.full_page),
#nav.show
animation: header-effect 1s animation: header-effect 1s
#site-title, #site-title,
#site-subtitle #site-subtitle
animation: titleScale 1s animation: titleScale 1s
#nav.show
animation: headerNoOpacity 1s
canvas:not(#ribbon-canvas), canvas:not(#ribbon-canvas),
#web_bg #web_bg
animation: to_show 4s animation: to_show 4s
@@ -182,27 +180,16 @@ if hexo-config('avatar.effect') == true
@keyframes header-effect @keyframes header-effect
0% 0%
opacity: 0 transform: translateY(-35px)
transform: translateY(-50px)
100%
opacity: 1
transform: translateY(0)
@keyframes headerNoOpacity
0%
transform: translateY(-50px)
100% 100%
transform: translateY(0) transform: translateY(0)
@keyframes bottom-top @keyframes bottom-top
0% 0%
opacity: 0 transform: translateY(35px)
transform: translateY(50px)
100% 100%
opacity: 1
transform: translateY(0) transform: translateY(0)
@keyframes titleScale @keyframes titleScale

View File

@@ -46,6 +46,7 @@ body
font-family: $font-family font-family: $font-family
line-height: $text-line-height line-height: $text-line-height
-webkit-tap-highlight-color: rgba(0, 0, 0, 0) -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
scroll-behavior: smooth
if !hexo-config('copy.enable') if !hexo-config('copy.enable')
user-select: none user-select: none

View File

@@ -117,6 +117,7 @@
box-shadow: 0 5px 6px -5px rgba(133, 133, 133, .6) box-shadow: 0 5px 6px -5px rgba(133, 133, 133, .6)
a, a,
span.site-page,
.site-name .site-name
color: var(--font-color) color: var(--font-color)
text-shadow: none text-shadow: none
@@ -140,6 +141,7 @@
text-shadow: none text-shadow: none
a, a,
span.site-page,
#toggle-menu #toggle-menu
color: var(--font-color) color: var(--font-color)
text-shadow: none text-shadow: none
@@ -290,7 +292,8 @@
&:hover &:hover
color: var(--white) color: var(--white)
a a,
span.site-page
color: var(--light-grey) color: var(--light-grey)
&:hover &:hover
@@ -312,10 +315,10 @@
.menus_item_child .menus_item_child
display: block display: block
& > a > i:last-child & > span > i:last-child
transform: rotate(180deg) transform: rotate(180deg)
& > a > i:last-child & > span > i:last-child
padding: 4px padding: 4px
transition: transform .3s transition: transform .3s
@@ -370,7 +373,7 @@
.menus_items .menus_items
display: none display: none
#search-button span #search-button span:not(.site-page)
display: none display: none
#search-button #search-button

View File

@@ -40,9 +40,10 @@
position: relative position: relative
display: block display: block
padding: 3px 28px 3px 20px padding: 3px 28px 3px 20px
border-radius: 6px
color: var(--font-color) color: var(--font-color)
font-size: 1.15em font-size: 1.15em
border-radius: 6px cursor: pointer
&:hover &:hover
background: var(--text-bg-hover) background: var(--text-bg-hover)

View File

@@ -74,8 +74,9 @@ if hexo-config('waline.bg')
margin: 0 0 .8em margin: 0 0 .8em
padding: 6px 0 16px padding: 6px 0 16px
.katex-wrap .katex-display
overflow: auto overflow: auto hidden
padding: 5px
if hexo-config('katex') && hexo-config('katex.hide_scrollbar') if hexo-config('katex') && hexo-config('katex.hide_scrollbar')
&::-webkit-scrollbar &::-webkit-scrollbar

View File

@@ -180,6 +180,7 @@ document.addEventListener('DOMContentLoaded', function () {
* PhotoFigcaption * PhotoFigcaption
*/ */
const addPhotoFigcaption = () => { const addPhotoFigcaption = () => {
if (!GLOBAL_CONFIG.isPhotoFigcaption) return
document.querySelectorAll('#article-container img').forEach(item => { document.querySelectorAll('#article-container img').forEach(item => {
const altValue = item.title || item.alt const altValue = item.title || item.alt
if (!altValue) return if (!altValue) return
@@ -333,7 +334,7 @@ document.addEventListener('DOMContentLoaded', function () {
if (typeof InfiniteGrid === 'function') { if (typeof InfiniteGrid === 'function') {
init() init()
} else { } else {
await getScript(`${GLOBAL_CONFIG.infinitegrid.js}`) await btf.getScript(`${GLOBAL_CONFIG.infinitegrid.js}`)
init() init()
} }
} }
@@ -461,6 +462,9 @@ document.addEventListener('DOMContentLoaded', function () {
$cardToc.scrollTop = sidebarScrollTop - 150 $cardToc.scrollTop = sidebarScrollTop - 150
} }
} }
// 處理 hexo-blog-encrypt 事件
$cardToc.style.display = 'block'
} }
// find head position & add active class // find head position & add active class
@@ -563,13 +567,13 @@ document.addEventListener('DOMContentLoaded', function () {
darkmode: () => { // switch between light and dark mode darkmode: () => { // switch between light and dark mode
const willChangeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark' const willChangeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'
if (willChangeMode === 'dark') { if (willChangeMode === 'dark') {
activateDarkMode() btf.activateDarkMode()
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
} else { } else {
activateLightMode() btf.activateLightMode()
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) 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) handleThemeChange(willChangeMode)
}, },
'rightside-config': item => { // Show or hide rightside-hide-btn 'rightside-config': item => { // Show or hide rightside-hide-btn
@@ -589,15 +593,24 @@ document.addEventListener('DOMContentLoaded', function () {
'hide-aside-btn': () => { // Hide aside 'hide-aside-btn': () => { // Hide aside
const $htmlDom = document.documentElement.classList const $htmlDom = document.documentElement.classList
const saveStatus = $htmlDom.contains('hide-aside') ? 'show' : 'hide' 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') $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') const tocEle = document.getElementById('card-toc')
tocEle.style.transition = 'transform 0.3s ease-in-out' 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.classList.toggle('open')
tocEle.addEventListener('transitionend', () => { tocEle.addEventListener('transitionend', () => {
tocEle.style.transition = '' tocEle.style.cssText = ''
}, { once: true }) }, { once: true })
}, },
'chat-btn': () => { // Show chat 'chat-btn': () => { // Show chat
@@ -611,7 +624,7 @@ document.addEventListener('DOMContentLoaded', function () {
document.getElementById('rightside').addEventListener('click', function (e) { document.getElementById('rightside').addEventListener('click', function (e) {
const $target = e.target.closest('[id]') const $target = e.target.closest('[id]')
if ($target && rightSideFn[$target.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, threshold: 0,
data_src: 'lazy-src' data_src: 'lazy-src'
}) })
btf.addGlobalFn('pjaxComplete', () => {
window.lazyLoadInstance.update()
}, 'lazyload')
} }
const relativeDate = function (selector) { const relativeDate = function (selector) {
@@ -835,14 +852,29 @@ document.addEventListener('DOMContentLoaded', function () {
GLOBAL_CONFIG.copyright !== undefined && addCopyright() GLOBAL_CONFIG.copyright !== undefined && addCopyright()
if (GLOBAL_CONFIG.autoDarkmode) { if (GLOBAL_CONFIG.autoDarkmode) {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { window.matchMedia('(prefers-color-scheme: dark)').addListener(e => {
if (saveToLocal.get('theme') !== undefined) return if (btf.saveToLocal.get('theme') !== undefined) return
e.matches ? handleThemeChange('dark') : handleThemeChange('light') 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() initAdjust()
if (GLOBAL_CONFIG_SITE.isPost) { if (GLOBAL_CONFIG_SITE.isPost) {
@@ -855,24 +887,24 @@ document.addEventListener('DOMContentLoaded', function () {
toggleCardCategory() toggleCardCategory()
} }
scrollFnToDo()
GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex() GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex()
addHighlightTool()
GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption()
scrollFn() scrollFn()
btf.removeGlobalFnEvent('justifiedGallery') forPostFn()
const galleryContainer = document.querySelectorAll('#article-container .gallery-container')
galleryContainer.length && addJustifiedGallery(galleryContainer)
runLightbox()
addTableWrap()
clickFnOfTagHide()
tabsFn()
switchComments() switchComments()
openMobileMenu() openMobileMenu()
} }
btf.addGlobalFn('pjaxComplete', refreshFn, 'refreshFn')
refreshFn() refreshFn()
unRefreshFn() unRefreshFn()
// 處理 hexo-blog-encrypt 事件
window.addEventListener('hexo-blog-decrypt', e => {
forPostFn()
window.translateFn.translateInitialization()
Object.values(window.globalFn.encrypt).forEach(fn => {
fn()
})
})
}) })

View File

@@ -4,9 +4,9 @@ document.addEventListener('DOMContentLoaded', function () {
let currentEncoding = defaultEncoding let currentEncoding = defaultEncoding
const targetEncodingCookie = 'translate-chn-cht' const targetEncodingCookie = 'translate-chn-cht'
let targetEncoding = let targetEncoding =
saveToLocal.get(targetEncodingCookie) === undefined btf.saveToLocal.get(targetEncodingCookie) === undefined
? defaultEncoding ? defaultEncoding
: Number(saveToLocal.get('translate-chn-cht')) : Number(btf.saveToLocal.get('translate-chn-cht'))
let translateButtonObject let translateButtonObject
const isSnackbar = snackbarData !== undefined const isSnackbar = snackbarData !== undefined
@@ -63,7 +63,7 @@ document.addEventListener('DOMContentLoaded', function () {
translateButtonObject.textContent = msgToSimplifiedChinese translateButtonObject.textContent = msgToSimplifiedChinese
isSnackbar && btf.snackbarShow(snackbarData.chs_to_cht) isSnackbar && btf.snackbarShow(snackbarData.chs_to_cht)
} }
saveToLocal.set(targetEncodingCookie, targetEncoding, 2) btf.saveToLocal.set(targetEncodingCookie, targetEncoding, 2)
setLang() setLang()
translateBody() translateBody()
} }
@@ -114,9 +114,10 @@ document.addEventListener('DOMContentLoaded', function () {
window.translateFn = { window.translateFn = {
translatePage, translatePage,
Traditionalized, Traditionalized,
Simplized Simplized,
translateInitialization
} }
translateInitialization() translateInitialization()
document.addEventListener('pjax:complete', translateInitialization) btf.addGlobalFn('pjaxComplete', translateInitialization, 'translateInitialization')
}) })

View File

@@ -1,296 +1,288 @@
const btf = { (() => {
debounce: (func, wait = 0, immediate = false) => { const btfFn = {
let timeout debounce: (func, wait = 0, immediate = false) => {
return (...args) => { let timeout
const later = () => { return (...args) => {
timeout = null const later = () => {
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)
timeout = null 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) func.apply(context, args)
if (!timeout) context = args = null if (!timeout) context = args = null
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining)
} }
}
return throttled const throttled = (...params) => {
}, const now = new Date().getTime()
if (!previous && options.leading === false) previous = now
sidebarPaddingR: () => { const remaining = wait - (now - previous)
const innerWidth = window.innerWidth context = this
const clientWidth = document.body.clientWidth args = params
const paddingRight = innerWidth - clientWidth if (remaining <= 0 || remaining > wait) {
if (innerWidth !== clientWidth) { if (timeout) {
document.body.style.paddingRight = paddingRight + 'px' clearTimeout(timeout)
} timeout = null
}, }
previous = now
snackbarShow: (text, showAction = false, duration = 2000) => { func.apply(context, args)
const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar if (!timeout) context = args = null
const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark } else if (!timeout && options.trailing !== false) {
Snackbar.show({ timeout = setTimeout(later, remaining)
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()
} }
}, { threshold: [0] }) }
observerItem.observe(dom)
} else {
callback()
}
},
scrollToDest: (pos, time = 500) => { return throttled
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) { sidebarPaddingR: () => {
window.scrollTo({ const innerWidth = window.innerWidth
top: pos, const clientWidth = document.body.clientWidth
behavior: 'smooth' 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 diffDate: (d, more = false) => {
pos = +pos const dateNow = new Date()
window.requestAnimationFrame(function step (currentTime) { const datePost = new Date(d)
start = !start ? currentTime : start const dateDiff = dateNow.getTime() - datePost.getTime()
const progress = currentTime - start const minute = 1000 * 60
if (currentPos < pos) { const hour = minute * 60
window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos) 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 { } else {
window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time)) callback()
} }
if (progress < time) { },
window.requestAnimationFrame(step)
} else { scrollToDest: (pos, time = 500) => {
window.scrollTo(0, pos) 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) => { let start = null
ele.style.display = 'block' pos = +pos
ele.style.animation = text window.requestAnimationFrame(function step (currentTime) {
}, start = !start ? currentTime : start
const progress = currentTime - start
animateOut: (ele, text) => { if (currentPos < pos) {
ele.addEventListener('animationend', function f () { window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos)
ele.style.display = '' } else {
ele.style.animation = '' window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time))
ele.removeEventListener('animationend', f) }
}) if (progress < time) {
ele.style.animation = text window.requestAnimationFrame(step)
}, } else {
window.scrollTo(0, pos)
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 })
} }
}) })
},
if (!window.fancyboxRun) { animateIn: (ele, text) => {
Fancybox.bind('[data-fancybox]', { ele.style.display = 'block'
Hash: false, ele.style.animation = text
Thumbs: { },
showOnStart: false
}, animateOut: (ele, text) => {
Images: { ele.addEventListener('animationend', function f () {
Panzoom: { ele.style.display = ''
maxScale: 4 ele.style.animation = ''
} ele.removeEventListener('animationend', f)
}, })
Carousel: { ele.style.animation = text
transition: 'slide' },
},
Toolbar: { wrap: (selector, eleType, options) => {
display: { const createEle = document.createElement(eleType)
left: ['infobar'], for (const [key, value] of Object.entries(options)) {
middle: [ createEle.setAttribute(key, value)
'zoomIn', }
'zoomOut', selector.parentNode.insertBefore(createEle, selector)
'toggle1to1', createEle.appendChild(selector)
'rotateCCW', },
'rotateCW',
'flipX', isHidden: ele => ele.offsetHeight === 0 && ele.offsetWidth === 0,
'flipY'
], getEleTop: ele => {
right: ['slideshow', 'thumbs', 'close'] 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: { if (!window.fancyboxRun) {
add: ele => { Fancybox.bind('[data-fancybox]', {
const html = ` 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 = `
<div class="loading-container"> <div class="loading-container">
<div class="loading-item"> <div class="loading-item">
<div></div><div></div><div></div><div></div><div></div> <div></div><div></div><div></div><div></div><div></div>
</div> </div>
</div> </div>
` `
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 }
})()