From 77ec8987370279953112d13c308426406efebaa7 Mon Sep 17 00:00:00 2001 From: myw Date: Tue, 21 Jul 2026 18:49:50 +0800 Subject: [PATCH] fix: exclude fancybox links from pjax and refactor series logic - Add :not([data-fancybox]) to pjaxExclude to prevent fancybox links from being loaded via pjax - Refactor series grouping to use a shared hexo._seriesGroups object built once - Improve performance by avoiding repeated post iteration in both tag and helper - Version bump to 5.6.1 --- layout/includes/third-party/pjax.pug | 2 +- package.json | 2 +- scripts/helpers/series.js | 46 ++++---- scripts/tag/series.js | 155 +++++++++++++++------------ 4 files changed, 114 insertions(+), 91 deletions(-) diff --git a/layout/includes/third-party/pjax.pug b/layout/includes/third-party/pjax.pug index 38e0504..107ce2c 100644 --- a/layout/includes/third-party/pjax.pug +++ b/layout/includes/third-party/pjax.pug @@ -1,4 +1,4 @@ -- var pjaxExclude = 'a:not([target="_blank"])' +- var pjaxExclude = 'a:not([target="_blank"]):not([data-fancybox])' if theme.pjax.exclude each val in theme.pjax.exclude - pjaxExclude += `:not([href="${val}"])` diff --git a/package.json b/package.json index 5debe44..f7ee6a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hexo-theme-butterfly", - "version": "5.6.0", + "version": "5.6.1", "description": "A Simple and Card UI Design theme for Hexo", "main": "package.json", "scripts": { diff --git a/scripts/helpers/series.js b/scripts/helpers/series.js index bd4e65f..24bdd06 100644 --- a/scripts/helpers/series.js +++ b/scripts/helpers/series.js @@ -1,22 +1,24 @@ -'use strict' - -hexo.extend.helper.register('groupPosts', function () { - const getGroupArray = array => { - return array.reduce((groups, item) => { - const key = item.series - if (key) { - groups[key] = groups[key] || [] - groups[key].push(item) - } - return groups - }, {}) - } - - const sortPosts = posts => { - const { orderBy = 'date', order = 1 } = this.theme.aside.card_post_series - if (orderBy === 'title') return posts.sort('title', order) - return posts.sort('date', order) - } - - return getGroupArray(sortPosts(this.site.posts)) -}) +'use strict' + +// Read pre-built groups from tag/series.js (hexo._seriesGroups) +// and sort each group according to the sidebar card config. +hexo.extend.helper.register('groupPosts', function () { + const groups = hexo._seriesGroups || {} + const { orderBy = 'date', order = 1 } = this.theme.aside.card_post_series + + const result = {} + Object.keys(groups).forEach(key => { + const arr = groups[key].slice() // copy to avoid mutating the shared data + if (orderBy === 'title') { + arr.sort((a, b) => { + const cmp = a.title.toUpperCase().localeCompare(b.title.toUpperCase()) + return order === 1 ? cmp : -cmp + }) + } else { + arr.sort((a, b) => order === 1 ? a.date - b.date : b.date - a.date) + } + result[key] = arr + }) + + return result +}) diff --git a/scripts/tag/series.js b/scripts/tag/series.js index cadd2d4..8eb9d79 100644 --- a/scripts/tag/series.js +++ b/scripts/tag/series.js @@ -1,67 +1,88 @@ -/** - * series plugin - * Syntax: - * {% series [series name] %} - * Usage: - * {% series %} - * {% series series1 %} - */ - -'use strict' - -const urlFor = require('hexo-util').url_for.bind(hexo) -const groups = {} - -hexo.extend.filter.register('before_generate', () => { - Object.keys(groups).forEach(k => delete groups[k]) -}) - -hexo.extend.filter.register('before_post_render', data => { - if (!hexo.theme.config.series.enable) return data - - const { layout, series } = data - if (layout === 'post' && series) { - if (!groups[series]) groups[series] = [] - groups[series].push({ - title: data.title, - path: data.path, - date: data.date.unix() - }) - } - return data -}) - -function series (args) { - const { series } = hexo.theme.config - if (!series.enable) { - hexo.log.warn('Series plugin is disabled in the theme config') - return '' - } - - const seriesArr = args.length ? groups[args[0]] : groups[this.series] - - if (!seriesArr) { - hexo.log.warn(`There is no series named "${args[0]}"`) - return '' - } - - const isAsc = (series.order || 1) === 1 // 1: asc, -1: desc - const isSortByTitle = series.orderBy === 'title' - - const compareFn = (a, b) => { - const itemA = isSortByTitle ? a.title.toUpperCase() : a.date - const itemB = isSortByTitle ? b.title.toUpperCase() : b.date - - return itemA < itemB ? (isAsc ? -1 : 1) : itemA > itemB ? (isAsc ? 1 : -1) : 0 - } - - seriesArr.sort(compareFn) - - const listItems = seriesArr.map(ele => - `
  • ${ele.title}
  • ` - ).join('') - - return series.number ? `
      ${listItems}
    ` : `` -} - -hexo.extend.tag.register('series', series, { ends: false }) +/** + * series plugin + * Syntax: + * {% series [series name] %} + * Usage: + * {% series %} + * {% series series1 %} + */ + +'use strict' + +const urlFor = require('hexo-util').url_for.bind(hexo) + +// Iterate all posts once and group by series name. +// Result is stored on hexo._seriesGroups, shared by both tag and helper. +function buildSeriesGroups () { + const groups = {} + const posts = hexo.model('Post').toArray() + for (let i = 0, len = posts.length; i < len; i++) { + const p = posts[i] + if (p.series) { + if (!groups[p.series]) groups[p.series] = [] + groups[p.series].push({ + title: p.title, + path: p.path, + date: p.date.unix() + }) + } + } + return groups +} + +// Build once before the first render (hexo generate / hexo server initial load). +// before_generate runs after tag rendering, so we need this as a fallback. +hexo.extend.filter.register('before_post_render', data => { + if (!hexo.theme.config.series.enable) return data + if (!hexo._seriesGroups) { + hexo._seriesGroups = buildSeriesGroups() + } + return data +}) + +// Rebuild after each generate cycle in hexo server to reflect latest post data. +hexo.extend.filter.register('before_generate', () => { + if (!hexo.theme.config.series.enable) return + hexo._seriesGroups = buildSeriesGroups() +}) + +function series (args) { + const { series } = hexo.theme.config + if (!series.enable) { + hexo.log.warn('Series plugin is disabled in the theme config') + return '' + } + + const groupName = args.length ? args[0] : this.series + + if (!groupName) { + hexo.log.warn('No series specified') + return '' + } + + const groups = hexo._seriesGroups || {} + const source = groups[groupName] + + if (!source || !source.length) { + hexo.log.warn(`There is no series named "${groupName}"`) + return '' + } + + const isAsc = (series.order || 1) === 1 + const isSortByTitle = series.orderBy === 'title' + + // .slice() to copy before sorting, so we don't mutate the shared data + const seriesArr = source.slice().sort((a, b) => { + const itemA = isSortByTitle ? a.title.toUpperCase() : a.date + const itemB = isSortByTitle ? b.title.toUpperCase() : b.date + return itemA < itemB ? (isAsc ? -1 : 1) : itemA > itemB ? (isAsc ? 1 : -1) : 0 + }) + + const listItems = seriesArr.map(ele => + `
  • ${ele.title}
  • ` + ).join('') + + return series.number ? `
      ${listItems}
    ` : `` +} + +hexo.extend.tag.register('series', series, { ends: false })