//- - author: //- avatar: //- date: //- content: //- tags: //- - tag1 //- - tag2 - page.toc = false #article-container if page.shuoshuo_url || (site.data.shuoshuo && site.data.shuoshuo.length) if page.comments !== false && theme.comments.use - commentsJsLoad = true script. (() => { const commentDiv = `!{partial('includes/third-party/comments/index', {}, {cache: true})}` const runDestroy = (shuoshuoComment) => { if (!shuoshuoComment) return for (const [key, fn] of Object.entries(shuoshuoComment)) { if (key.startsWith('destroy')) fn() } } window.addCommentToShuoshuo = e => { const btn = e.target.closest('.shuoshuo-comment-btn') if (!btn) return const ele = btn.closest('.container').nextElementSibling const { shuoshuoComment } = window const isInclude = ele.classList.contains('no-comment') runDestroy(shuoshuoComment) if (isInclude) { ele.classList.remove('no-comment') ele.innerHTML = commentDiv const key = `${location.pathname.replace(/\/$/, '')}?key=${ele.getAttribute('data-key')}` btf.switchComments(ele, key) shuoshuoComment.loadComment && shuoshuoComment.loadComment(ele, key) } } })() - const localDate = page.shuoshuo_url ? [] : shuoshuoFN(site.data.shuoshuo, page) if !page.shuoshuo_url script(type='application/json' id='shuoshuo-data')!= safeJSON(localDate) - const { enable, native, placeholder, field } = theme.lazyload script. (() => { const limitConfig = !{ JSON.stringify(page.limit || {}) } const escapeHtml = str => String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''') const sortDataByDate = data => data.sort((a, b) => new Date(b.date) - new Date(a.date)) const filterDataByLimit = (data, limit) => { if (!limit || !limit.type) return data if (limit.type === 'num') return data.slice(0, limit.value) if (limit.type === 'date') { const limitDate = new Date(limit.value) return data.filter(item => new Date(item.date) >= limitDate) } return data } const dateFormatter = new Intl.DateTimeFormat('en-GB', { timeZone: !{JSON.stringify(config.timezone || '')} || Intl.DateTimeFormat().resolvedOptions().timeZone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) const formatToTimeZone = (date) => { const fullDate = date.length === 10 ? `${date} 00:00:00` : date const [day, month, year, hour, minute, second] = dateFormatter.format(new Date(fullDate)).match(/\d+/g) return `${year}-${month}-${day} ${hour}:${minute}:${second}` } const addLazyload = str => { const lazyConfig = { enable: !{Boolean(enable)}, native: !{Boolean(native)}, field: !{JSON.stringify(field || '')}, placeholder: !{JSON.stringify(url_for(placeholder))}, } if (!lazyConfig.enable || lazyConfig.field !== 'site' || str.indexOf(' { if (lazyConfig.native) { img.setAttribute('loading', 'lazy') } else { const src = img.getAttribute('src') img.setAttribute('data-lazy-src', src) if (lazyConfig.placeholder) { img.setAttribute('src', lazyConfig.placeholder) } else { img.removeAttribute('src') } } }) return doc.body.innerHTML } let currentPage = 1 const itemsPerPage = 8 let totalPages = 0 let data = [] const renderData = (dataSlice) => { const content = dataSlice.map(item => { const formattedDate = formatToTimeZone(item.date) const tags = item.tags && item.tags.map(tag => `${escapeHtml(tag)}`).join('') || '' const commentButton = item.key && !{commentsJsLoad || false} ? `
` : '' const commentContainer = item.key ? `
` : '' return `
${item.author ? escapeHtml(item.author) : !{JSON.stringify(config.author || '')}}
${addLazyload(item.content)}
${commentContainer}
` }).join('') const container = document.getElementById('article-container') container.innerHTML = content window.lazyLoadInstance && window.lazyLoadInstance.update() btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)')) } const setupNavEvents = (nav) => { nav.querySelector('.shuoshuo-prev-btn').addEventListener('click', () => { if (currentPage > 1) { currentPage--; renderPage(currentPage) } }) nav.querySelector('.shuoshuo-next-btn').addEventListener('click', () => { if (currentPage < totalPages) { currentPage++; renderPage(currentPage) } }) const input = nav.querySelector('.shuoshuo-page-input') input.addEventListener('focus', e => { e.target.placeholder = '' }) input.addEventListener('blur', e => { if (!e.target.value.trim()) e.target.placeholder = currentPage }) input.addEventListener('input', e => { const value = parseInt(e.target.value) || 0 let wasInvalid = false if (value > totalPages) { e.target.value = totalPages; wasInvalid = true } else if (value < 1 && e.target.value !== '') { e.target.value = 1; wasInvalid = true } if (wasInvalid) { e.target.classList.add('invalid') setTimeout(() => e.target.classList.remove('invalid'), 500) } }) input.addEventListener('keydown', e => { const value = e.target.value + e.key if (e.key === 'Enter' || e.key === 'Backspace' || e.key === 'Delete' || e.key === 'ArrowLeft' || e.key === 'ArrowRight' || e.key === 'Tab' || e.ctrlKey || e.metaKey) { if (e.key === 'Enter') { const inputValue = e.target.value.trim() const inputPage = inputValue === '' ? currentPage : parseInt(inputValue) if (inputPage >= 1 && inputPage <= totalPages && inputPage !== currentPage) { currentPage = inputPage renderPage(currentPage) } else if (inputValue === '') { renderPage(currentPage) } } return } if (!/^\d$/.test(e.key)) { e.preventDefault() return } const newValue = parseInt(value) || 0 if (newValue > totalPages || (value.length > 1 && newValue === 0)) { e.preventDefault() e.target.classList.add('invalid') setTimeout(() => e.target.classList.remove('invalid'), 500) } }) } const renderNavigation = () => { const container = document.getElementById('article-container') let nav = container.nextElementSibling const pageInfoTemplate = '#{__('pagination.page_info')}' const pageInfoText = pageInfoTemplate .replace(/\$\{current}/g, currentPage) .replace(/\$\{total}/g, totalPages) if (!nav || !nav.classList.contains('shuoshuo-navigation')) { nav = document.createElement('div') nav.className = 'shuoshuo-navigation' nav.innerHTML = ` ` container.insertAdjacentElement('afterend', nav) setupNavEvents(nav) } nav.querySelector('.shuoshuo-page-info').textContent = pageInfoText nav.querySelector('.shuoshuo-prev-btn').disabled = currentPage === 1 nav.querySelector('.shuoshuo-next-btn').disabled = currentPage === totalPages const input = nav.querySelector('.shuoshuo-page-input') input.max = totalPages input.placeholder = currentPage } const renderPage = (page) => { const start = (page - 1) * itemsPerPage const end = start + itemsPerPage const pageData = data.slice(start, end) renderData(pageData) renderNavigation() } const loadShuoshuo = async () => { const container = document.getElementById('article-container') try { let originData = [] if (!{Boolean(page.shuoshuo_url)}) { container.innerHTML = '
' const response = await fetch('!{url_for(page.shuoshuo_url)}') if (!response.ok) throw new Error(`HTTP ${response.status}`) originData = await response.json() } else { const dataElement = document.getElementById('shuoshuo-data') originData = dataElement ? JSON.parse(dataElement.textContent) : [] } data = filterDataByLimit(sortDataByDate(originData), limitConfig) totalPages = Math.ceil(data.length / itemsPerPage) if (data.length === 0) { container.innerHTML = '
' return } renderPage(currentPage) } catch (error) { console.error(error) container.innerHTML = '
' } } const pjaxCleanup = () => { const container = document.getElementById('article-container') if (container) { const nav = container.nextElementSibling if (nav && nav.classList.contains('shuoshuo-navigation')) nav.remove() } document.removeEventListener('pjax:send', pjaxCleanup) } if (window.pjax) { document.addEventListener('pjax:send', pjaxCleanup) loadShuoshuo() } else { window.addEventListener('load', loadShuoshuo) } })()