mirror of
https://github.com/jerryc127/hexo-theme-butterfly.git
synced 2026-08-10 20:48:42 +08:00
- wordcount/min2read/totalcount built-in helpers (replaces hexo-wordcount) - cloudTags random sort support - waline lightbox via MutationObserver - subtitle: seq guard prevents stale API response race - newest-comments: escapeHtml XSS fix, unified fetchAndRender with cache fallback - katex: try/catch asset load, encrypt re-render - chartjs: destroy charts on pjax, fix theme property check - mathjax: DOMContentLoaded instead of load - mermaid: clean stale error elements - medium-zoom: single instance, detach on pjax - getScrollPercent: WeakMap cache with resize invalidation - overflowPaddingR: avoid stale DOM refs - readmode: dedupe button, pjax cleanup - hexo-blog-decrypt: null-guard translateFn and encryptFn - tw_cn: expand skipped translate tags - localStorage: try/catch setItem - cdn.js: fix [lib|dist]* character class regex bug - findArchivesTitle: support custom archive_dir - shuoshuoFN: guard moment.tz when timezone empty - umami: no-store cache, error handling, path param - artalk: vote config option - bump version 5.7.1.260810
121 lines
3.7 KiB
Plaintext
121 lines
3.7 KiB
Plaintext
- const { effect, source, sub, typed_option } = theme.subtitle
|
|
- let subContent = typeof sub === 'string' ? [sub] : (sub || new Array())
|
|
|
|
script.
|
|
window.typedJSFn = {
|
|
_seq: 0,
|
|
init: str => {
|
|
window.typed = new Typed('#subtitle', Object.assign({
|
|
strings: str,
|
|
startDelay: 300,
|
|
typeSpeed: 150,
|
|
loop: true,
|
|
backSpeed: 50,
|
|
}, !{JSON.stringify(typed_option)}))
|
|
},
|
|
run: subtitleType => {
|
|
const seq = ++window.typedJSFn._seq
|
|
const invoke = () => {
|
|
if (seq === window.typedJSFn._seq) subtitleType()
|
|
}
|
|
|
|
if (!{effect}) {
|
|
if (typeof Typed === 'function') invoke()
|
|
else btf.getScript('!{url_for(theme.asset.typed)}').then(invoke)
|
|
} else {
|
|
invoke()
|
|
}
|
|
},
|
|
fetchSubtitle: (fetcher, parser) => {
|
|
const seq = window.typedJSFn._seq
|
|
Promise.resolve()
|
|
.then(fetcher)
|
|
.then(parser)
|
|
.then(({ content, extra = [] }) => {
|
|
if (seq !== window.typedJSFn._seq) return
|
|
typedJSFn.processSubtitle(content, extra)
|
|
})
|
|
.catch(err => {
|
|
if (seq !== window.typedJSFn._seq) return
|
|
console.error('Failed to get the subtitle API:', err)
|
|
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
|
})
|
|
},
|
|
processSubtitle: (content, extraContents = []) => {
|
|
if (!{effect}) {
|
|
const sub = !{JSON.stringify(subContent)}.slice()
|
|
|
|
if (extraContents.length > 0) {
|
|
sub.unshift(...extraContents)
|
|
}
|
|
|
|
if (typeof content === 'string') {
|
|
sub.unshift(content)
|
|
} else if (Array.isArray(content)) {
|
|
sub.unshift(...content)
|
|
}
|
|
|
|
sub.length > 0 && typedJSFn.init(sub)
|
|
} else {
|
|
document.getElementById('subtitle').textContent = typeof content === 'string' ? content :
|
|
(Array.isArray(content) && content.length > 0 ? content[0] : '')
|
|
}
|
|
}
|
|
}
|
|
btf.addGlobalFn('pjaxSendOnce', () => {
|
|
window.typedJSFn._seq++
|
|
typed && typed.destroy()
|
|
window.typed = null
|
|
}, 'typedDestroy')
|
|
|
|
case source
|
|
when 1
|
|
script.
|
|
function subtitleType () {
|
|
typedJSFn.fetchSubtitle(
|
|
() => fetch('https://v1.hitokoto.cn').then(response => response.json()),
|
|
data => ({ content: data.hitokoto, extra: data.from ? ['出自 ' + data.from] : [] })
|
|
)
|
|
}
|
|
typedJSFn.run(subtitleType)
|
|
|
|
when 2
|
|
script.
|
|
function subtitleType () {
|
|
typedJSFn.fetchSubtitle(
|
|
() => fetch('https://v.api.aa1.cn/api/yiyan/index.php').then(response => response.text()),
|
|
data => {
|
|
const reg = /<p>(.*?)<\/p>/g
|
|
const result = reg.exec(data)
|
|
if (result && result[1]) return { content: result[1] }
|
|
throw new Error('Failed to parse the return value of the Yiyan API')
|
|
}
|
|
)
|
|
}
|
|
typedJSFn.run(subtitleType)
|
|
|
|
when 3
|
|
script.
|
|
function subtitleType () {
|
|
typedJSFn.fetchSubtitle(
|
|
() => btf.getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js').then(() =>
|
|
new Promise((resolve, reject) => {
|
|
jinrishici.load(result => {
|
|
if (result && result.data && result.data.content) resolve(result.data.content)
|
|
else reject(new Error('Failed to parse the return value of Jinrishici API'))
|
|
})
|
|
})
|
|
),
|
|
content => ({ content })
|
|
)
|
|
}
|
|
typedJSFn.run(subtitleType)
|
|
|
|
default
|
|
if subContent.length > 0
|
|
script.
|
|
function subtitleType () {
|
|
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
|
}
|
|
typedJSFn.run(subtitleType)
|