mirror of
https://github.com/jerryc127/hexo-theme-butterfly.git
synced 2026-04-16 17:50:54 +08:00
feat: 更新 plugins.yml 中的依賴版本至最新
feat: 優化 aside_archives ,改進性能和可讀性 feat: 改善 inlineImg 和 timeline 標籤的文檔,優化時間線邏輯 feat: 更新 gallery 標籤以支持額外參數,優化圖片顯示邏輯 improvement: 優化隨機封面過濾器邏輯, 避免連續重複 feat: 最新評論限制顯示 1-10 條之間 fix: artalk 的最新評論顯示待定或者封禁的評論的 bug
This commit is contained in:
@@ -224,14 +224,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
*/
|
||||
|
||||
const fetchUrl = async url => {
|
||||
const response = await fetch(url)
|
||||
return await response.json()
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
return await response.json()
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch URL:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const runJustifiedGallery = (item, data, isButton = false, tabs) => {
|
||||
const dataLength = data.length
|
||||
const runJustifiedGallery = (container, data, config) => {
|
||||
const { isButton, limit, firstLimit, tabs } = config
|
||||
|
||||
const ig = new InfiniteGrid.JustifiedInfiniteGrid(item, {
|
||||
const dataLength = data.length
|
||||
const maxGroupKey = Math.ceil((dataLength - firstLimit) / limit + 1)
|
||||
|
||||
// Gallery configuration
|
||||
const igConfig = {
|
||||
gap: 5,
|
||||
isConstantSize: true,
|
||||
sizeRange: [150, 600],
|
||||
@@ -239,132 +248,130 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
// observeChildren: true,
|
||||
useTransform: true
|
||||
// useRecycle: false
|
||||
})
|
||||
|
||||
const replaceDq = str => str.replace(/"/g, '"') // replace double quotes to "
|
||||
|
||||
const getItems = (nextGroupKey, count) => {
|
||||
const nextItems = []
|
||||
const startCount = (nextGroupKey - 1) * count
|
||||
|
||||
for (let i = 0; i < count; ++i) {
|
||||
const num = startCount + i
|
||||
if (num >= dataLength) {
|
||||
break
|
||||
}
|
||||
|
||||
const item = data[num]
|
||||
const alt = item.alt ? `alt="${replaceDq(item.alt)}"` : ''
|
||||
const title = item.title ? `title="${replaceDq(item.title)}"` : ''
|
||||
|
||||
nextItems.push(`<div class="item">
|
||||
<img src="${item.url}" data-grid-maintained-target="true" ${alt + title} />
|
||||
</div>`)
|
||||
}
|
||||
return nextItems
|
||||
}
|
||||
|
||||
const buttonText = GLOBAL_CONFIG.infinitegrid.buttonText
|
||||
const addButton = item => {
|
||||
const button = document.createElement('button')
|
||||
button.innerHTML = buttonText + '<i class="fa-solid fa-arrow-down"></i>'
|
||||
|
||||
button.addEventListener('click', e => {
|
||||
e.target.closest('button').remove()
|
||||
btf.setLoading.add(item)
|
||||
appendItem(ig.getGroups().length + 1, 10)
|
||||
}, { once: true })
|
||||
|
||||
item.insertAdjacentElement('afterend', button)
|
||||
}
|
||||
|
||||
const appendItem = (nextGroupKey, count) => {
|
||||
ig.append(getItems(nextGroupKey, count), nextGroupKey)
|
||||
}
|
||||
|
||||
const maxGroupKey = Math.ceil(dataLength / 10)
|
||||
const ig = new InfiniteGrid.JustifiedInfiniteGrid(container, igConfig)
|
||||
let isLayoutHidden = false
|
||||
|
||||
const completeFn = e => {
|
||||
if (tabs) {
|
||||
const parentNode = item.parentNode
|
||||
// Utility functions
|
||||
const sanitizeString = str => (str && str.replace(/"/g, '"')) || ''
|
||||
|
||||
const createImageItem = item => {
|
||||
const alt = item.alt ? `alt="${sanitizeString(item.alt)}"` : ''
|
||||
const title = item.title ? `title="${sanitizeString(item.title)}"` : ''
|
||||
return `<div class="item">
|
||||
<img src="${item.url}" data-grid-maintained-target="true" ${alt} ${title} />
|
||||
</div>`
|
||||
}
|
||||
|
||||
const getItems = (nextGroupKey, count, isFirst = false) => {
|
||||
const startIndex = isFirst ? (nextGroupKey - 1) * count : (nextGroupKey - 2) * count + firstLimit
|
||||
return data.slice(startIndex, startIndex + count).map(createImageItem)
|
||||
}
|
||||
|
||||
// Load more button
|
||||
const addLoadMoreButton = container => {
|
||||
const button = document.createElement('button')
|
||||
button.innerHTML = `${GLOBAL_CONFIG.infinitegrid.buttonText}<i class="fa-solid fa-arrow-down"></i>`
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
button.remove()
|
||||
btf.setLoading.add(container)
|
||||
appendItems(ig.getGroups().length + 1, limit)
|
||||
}, { once: true })
|
||||
|
||||
container.insertAdjacentElement('afterend', button)
|
||||
}
|
||||
|
||||
const appendItems = (nextGroupKey, count, isFirst) => {
|
||||
ig.append(getItems(nextGroupKey, count, isFirst), nextGroupKey)
|
||||
}
|
||||
|
||||
// Event handlers
|
||||
const handleRenderComplete = e => {
|
||||
if (tabs) {
|
||||
const parentNode = container.parentNode
|
||||
if (isLayoutHidden) {
|
||||
parentNode.style.visibility = 'visible'
|
||||
}
|
||||
|
||||
if (item.offsetHeight === 0) {
|
||||
if (container.offsetHeight === 0) {
|
||||
parentNode.style.visibility = 'hidden'
|
||||
isLayoutHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
const { updated, isResize, mounted } = e
|
||||
if (!updated.length || !mounted.length || isResize) {
|
||||
return
|
||||
}
|
||||
if (!updated.length || !mounted.length || isResize) return
|
||||
|
||||
btf.loadLightbox(item.querySelectorAll('img:not(.medium-zoom-image)'))
|
||||
btf.loadLightbox(container.querySelectorAll('img:not(.medium-zoom-image)'))
|
||||
|
||||
if (ig.getGroups().length === maxGroupKey) {
|
||||
btf.setLoading.remove(item)
|
||||
!tabs && ig.off('renderComplete', completeFn)
|
||||
btf.setLoading.remove(container)
|
||||
!tabs && ig.off('renderComplete', handleRenderComplete)
|
||||
return
|
||||
}
|
||||
|
||||
if (isButton) {
|
||||
btf.setLoading.remove(item)
|
||||
addButton(item)
|
||||
btf.setLoading.remove(container)
|
||||
addLoadMoreButton(container)
|
||||
}
|
||||
}
|
||||
|
||||
const requestAppendFn = btf.debounce(e => {
|
||||
const handleRequestAppend = btf.debounce(e => {
|
||||
const nextGroupKey = (+e.groupKey || 0) + 1
|
||||
appendItem(nextGroupKey, 10)
|
||||
|
||||
if (nextGroupKey === maxGroupKey) {
|
||||
ig.off('requestAppend', requestAppendFn)
|
||||
}
|
||||
if (nextGroupKey === 1) appendItems(nextGroupKey, firstLimit, true)
|
||||
else appendItems(nextGroupKey, limit)
|
||||
|
||||
if (nextGroupKey === maxGroupKey) ig.off('requestAppend', handleRequestAppend)
|
||||
}, 300)
|
||||
|
||||
btf.setLoading.add(item)
|
||||
ig.on('renderComplete', completeFn)
|
||||
btf.setLoading.add(container)
|
||||
ig.on('renderComplete', handleRenderComplete)
|
||||
|
||||
if (isButton) {
|
||||
appendItem(1, 10)
|
||||
appendItems(1, firstLimit, true)
|
||||
} else {
|
||||
ig.on('requestAppend', requestAppendFn)
|
||||
ig.on('requestAppend', handleRequestAppend)
|
||||
ig.renderItems()
|
||||
}
|
||||
|
||||
btf.addGlobalFn('pjaxSendOnce', () => { ig.destroy() })
|
||||
btf.addGlobalFn('pjaxSendOnce', () => ig.destroy())
|
||||
}
|
||||
|
||||
const addJustifiedGallery = async (ele, tabs = false) => {
|
||||
if (!ele.length) return
|
||||
const init = async () => {
|
||||
for (const item of ele) {
|
||||
if (btf.isHidden(item) || item.classList.contains('loaded')) continue
|
||||
const addJustifiedGallery = async (elements, tabs = false) => {
|
||||
if (!elements.length) return
|
||||
|
||||
const initGallery = async () => {
|
||||
for (const element of elements) {
|
||||
if (btf.isHidden(element) || element.classList.contains('loaded')) continue
|
||||
|
||||
const config = {
|
||||
isButton: element.getAttribute('data-button') === 'true',
|
||||
limit: parseInt(element.getAttribute('data-limit'), 10),
|
||||
firstLimit: parseInt(element.getAttribute('data-first'), 10),
|
||||
tabs
|
||||
}
|
||||
|
||||
const container = element.firstElementChild
|
||||
const content = container.textContent
|
||||
container.textContent = ''
|
||||
element.classList.add('loaded')
|
||||
|
||||
const isButton = item.getAttribute('data-button') === 'true'
|
||||
const children = item.firstElementChild
|
||||
const text = children.textContent
|
||||
children.textContent = ''
|
||||
item.classList.add('loaded')
|
||||
try {
|
||||
const content = item.getAttribute('data-type') === 'url' ? await fetchUrl(text) : JSON.parse(text)
|
||||
runJustifiedGallery(children, content, isButton, tabs)
|
||||
} catch (e) {
|
||||
console.error('Gallery data parsing failed:', e)
|
||||
const data = element.getAttribute('data-type') === 'url' ? await fetchUrl(content) : JSON.parse(content)
|
||||
runJustifiedGallery(container, data, config)
|
||||
} catch (error) {
|
||||
console.error('Gallery data parsing failed:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof InfiniteGrid === 'function') {
|
||||
init()
|
||||
await initGallery()
|
||||
} else {
|
||||
await btf.getScript(`${GLOBAL_CONFIG.infinitegrid.js}`)
|
||||
init()
|
||||
await btf.getScript(GLOBAL_CONFIG.infinitegrid.js)
|
||||
await initGallery()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user