2025-2-26-fixed
This commit is contained in:
16
themes/fluid/scripts/events/index.js
Normal file
16
themes/fluid/scripts/events/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/* global hexo */
|
||||
|
||||
'use strict';
|
||||
|
||||
hexo.on('generateBefore', () => {
|
||||
require('./lib/merge-configs')(hexo);
|
||||
require('./lib/compatible-configs')(hexo);
|
||||
require('./lib/injects')(hexo);
|
||||
require('./lib/highlight')(hexo);
|
||||
require('./lib/lazyload')(hexo);
|
||||
require('./lib/footnote')(hexo);
|
||||
});
|
||||
|
||||
hexo.on('generateAfter', () => {
|
||||
require('./lib/hello')(hexo);
|
||||
});
|
||||
71
themes/fluid/scripts/events/lib/compatible-configs.js
Normal file
71
themes/fluid/scripts/events/lib/compatible-configs.js
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (hexo) => {
|
||||
const isZh = hexo.theme.i18n.languages[0].search(/zh-CN/i) !== -1;
|
||||
|
||||
// Breaking change at v1.8.3 2020/09/03
|
||||
if (hexo.theme.config.highlight && !hexo.theme.config.code) {
|
||||
if (isZh) {
|
||||
hexo.log.warn('[Fluid] 检测到弃用的配置项: "highlight" 已被修改为 "code:highlight",请根据新版本更新');
|
||||
} else {
|
||||
hexo.log.warn('[Fluid] Deprecated config detected: "highlight" has been modified to "code:highlight", please update according to the release.');
|
||||
}
|
||||
hexo.theme.config.code = {
|
||||
copy_btn : hexo.theme.config.highlight.copy_btn,
|
||||
highlight: {
|
||||
enable : hexo.theme.config.highlight.enable,
|
||||
lib : 'highlightjs',
|
||||
highlightjs: {
|
||||
style: hexo.theme.config.highlight.style
|
||||
},
|
||||
prismjs: {
|
||||
style : 'default',
|
||||
preprocess: true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Some configs that require hexo >= 5.0
|
||||
if (parseInt(hexo.version[0], 10) < 5) {
|
||||
if (isZh) {
|
||||
hexo.log.warn('[Fluid] 检测到 Hexo 版本低于 5.0.0,部分功能可能会受影响');
|
||||
} else {
|
||||
hexo.log.warn('[Fluid] Hexo version < 5.0.0 detected, some features may not be available.');
|
||||
}
|
||||
if (hexo.theme.config.code.highlight.lib === 'prismjs' && hexo.theme.config.code.highlight.prismjs.preprocess) {
|
||||
hexo.theme.config.code.highlight.prismjs.preprocess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Breaking change at v1.8.7 2020/12/02
|
||||
if (hexo.theme.config.index.post_default_img) {
|
||||
if (isZh) {
|
||||
hexo.log.warn('[Fluid] 检测到弃用的配置项: "index:post_default_img" 已被修改为 "post:default_index_img",请根据新版本更新');
|
||||
} else {
|
||||
hexo.log.warn('[Fluid] Deprecated config detected: "index:post_default_img" has been modified to "post:default_index_img", please update according to the release.');
|
||||
}
|
||||
hexo.theme.config.post.default_index_img = hexo.theme.config.index.post_default_img;
|
||||
}
|
||||
|
||||
// Breaking change at v1.8.7 2020/12/10
|
||||
if (hexo.theme.config.banner_parallax) {
|
||||
if (isZh) {
|
||||
hexo.log.warn('[Fluid] 检测到弃用的配置项: "banner_parallax" 已被修改为 "banner:parallax",请根据新版本更新');
|
||||
} else {
|
||||
hexo.log.warn('[Fluid] Deprecated config detected: "banner_parallax" has been modified to "banner:parallax", please update according to the release.');
|
||||
}
|
||||
if (!hexo.theme.config.banner) {
|
||||
hexo.theme.config.banner = {};
|
||||
}
|
||||
hexo.theme.config.banner.parallax = hexo.theme.config.banner_parallax;
|
||||
}
|
||||
|
||||
// Breaking change at v1.8.11 2021/05/14
|
||||
if (hexo.theme.config.valine.appid) {
|
||||
hexo.theme.config.valine.appId = hexo.theme.config.valine.appid;
|
||||
}
|
||||
if (hexo.theme.config.valine.appkey) {
|
||||
hexo.theme.config.valine.appKey = hexo.theme.config.valine.appkey;
|
||||
}
|
||||
};
|
||||
117
themes/fluid/scripts/events/lib/footnote.js
Normal file
117
themes/fluid/scripts/events/lib/footnote.js
Normal file
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
const { stripHTML } = require('hexo-util');
|
||||
|
||||
// Register footnotes filter
|
||||
module.exports = (hexo) => {
|
||||
const config = hexo.theme.config;
|
||||
if (config.post.footnote.enable) {
|
||||
hexo.extend.filter.register('before_post_render', (page) => {
|
||||
if (page.footnote !== false) {
|
||||
page.content = renderFootnotes(page.content, page.footnote);
|
||||
}
|
||||
return page;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Modified from https://github.com/kchen0x/hexo-reference
|
||||
*
|
||||
* Render markdown footnotes
|
||||
* @param {String} text
|
||||
* @param {String} header
|
||||
* @returns {String} text
|
||||
*/
|
||||
function renderFootnotes(text, header) {
|
||||
const reFootnoteContent = /\[\^(\d+)]: ?([\S\s]+?)(?=\[\^(?:\d+)]|\n\n|$)/g;
|
||||
const reInlineFootnote = /\[\^(\d+)]\((.+?)\)/g;
|
||||
const reFootnoteIndex = /\[\^(\d+)]/g;
|
||||
const reCodeBlock = /<pre>[\s\S]*?<\/pre>/g;
|
||||
|
||||
let footnotes = [];
|
||||
let html = '';
|
||||
let codeBlocks = [];
|
||||
|
||||
// extract code block
|
||||
text = text.replace(reCodeBlock, function(match) {
|
||||
codeBlocks.push(match);
|
||||
return 'CODE_BLOCK_PLACEHOLDER';
|
||||
});
|
||||
|
||||
// threat all inline footnotes
|
||||
text = text.replace(reInlineFootnote, function(match, index, content) {
|
||||
footnotes.push({
|
||||
index : index,
|
||||
content: content ? content.trim() : ''
|
||||
});
|
||||
// remove content of inline footnote
|
||||
return '[^' + index + ']';
|
||||
});
|
||||
|
||||
// threat all footnote contents
|
||||
text = text.replace(reFootnoteContent, function(match, index, content) {
|
||||
footnotes.push({
|
||||
index : index,
|
||||
content: content ? content.trim() : ''
|
||||
});
|
||||
// remove footnote content
|
||||
return '';
|
||||
});
|
||||
|
||||
// create map for looking footnotes array
|
||||
function createLookMap(field) {
|
||||
let map = {};
|
||||
for (let i = 0; i < footnotes.length; i++) {
|
||||
const item = footnotes[i];
|
||||
const key = item[field];
|
||||
map[key] = item;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
const indexMap = createLookMap('index');
|
||||
|
||||
// render (HTML) footnotes reference
|
||||
text = text.replace(reFootnoteIndex,
|
||||
function(match, index) {
|
||||
if (!indexMap[index]) {
|
||||
return match;
|
||||
}
|
||||
const tooltip = indexMap[index].content;
|
||||
return '<sup id="fnref:' + index + '" class="footnote-ref">'
|
||||
+ '<a href="#fn:' + index + '" rel="footnote">'
|
||||
+ '<span class="hint--top hint--rounded" aria-label="'
|
||||
+ stripHTML(tooltip)
|
||||
+ '">[' + index + ']</span></a></sup>';
|
||||
});
|
||||
|
||||
// sort footnotes by their index
|
||||
footnotes.sort(function(a, b) {
|
||||
return a.index - b.index;
|
||||
});
|
||||
|
||||
// render footnotes (HTML)
|
||||
footnotes.forEach(function(item) {
|
||||
html += '<li><span id="fn:' + item.index + '" class="footnote-text">';
|
||||
html += '<span>';
|
||||
const fn = hexo.render.renderSync({ text: item.content, engine: 'markdown' });
|
||||
html += fn.replace(/(<p>)|(<\/p>)/g, '').replace(/<br>/g, '');
|
||||
html += '<a href="#fnref:' + item.index + '" rev="footnote" class="footnote-backref"> ↩</a></span></span></li>';
|
||||
});
|
||||
|
||||
// add footnotes at the end of the content
|
||||
if (footnotes.length) {
|
||||
text += '<section class="footnotes">';
|
||||
text += header || config.post.footnote.header || '';
|
||||
text += '<div class="footnote-list">';
|
||||
text += '<ol>' + html + '</ol>';
|
||||
text += '</div></section>';
|
||||
}
|
||||
|
||||
// restore code block
|
||||
text = text.replace(/CODE_BLOCK_PLACEHOLDER/g, function() {
|
||||
return codeBlocks.shift();
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
};
|
||||
43
themes/fluid/scripts/events/lib/hello.js
Normal file
43
themes/fluid/scripts/events/lib/hello.js
Normal file
@@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (hexo) => {
|
||||
if (hexo.theme.has_hello) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hexo.theme.i18n.languages[0].search(/zh-CN/i) !== -1) {
|
||||
hexo.log.info(`
|
||||
------------------------------------------------
|
||||
| |
|
||||
| ________ __ _ __ |
|
||||
| |_ __ |[ | (_) | ] |
|
||||
| | |_ \\_| | | __ _ __ .--.| | |
|
||||
| | _| | |[ | | | [ |/ /'\`\\' | |
|
||||
| _| |_ | | | \\_/ |, | || \\__/ | |
|
||||
| |_____| [___]'.__.'_/[___]'.__.;__] |
|
||||
| |
|
||||
| 感谢使用 Fluid 主题 |
|
||||
| 文档: https://hexo.fluid-dev.com/docs/ |
|
||||
| |
|
||||
------------------------------------------------
|
||||
`);
|
||||
} else {
|
||||
hexo.log.info(`
|
||||
------------------------------------------------
|
||||
| |
|
||||
| ________ __ _ __ |
|
||||
| |_ __ |[ | (_) | ] |
|
||||
| | |_ \\_| | | __ _ __ .--.| | |
|
||||
| | _| | |[ | | | [ |/ /'\`\\' | |
|
||||
| _| |_ | | | \\_/ |, | || \\__/ | |
|
||||
| |_____| [___]'.__.'_/[___]'.__.;__] |
|
||||
| |
|
||||
| Thank you for using Fluid theme |
|
||||
| Docs: https://hexo.fluid-dev.com/docs/en/ |
|
||||
| |
|
||||
------------------------------------------------
|
||||
`);
|
||||
}
|
||||
|
||||
hexo.theme.has_hello = true;
|
||||
};
|
||||
156
themes/fluid/scripts/events/lib/highlight.js
Normal file
156
themes/fluid/scripts/events/lib/highlight.js
Normal file
@@ -0,0 +1,156 @@
|
||||
'use strict';
|
||||
|
||||
let css;
|
||||
try {
|
||||
css = require('css');
|
||||
} catch (error) {
|
||||
if (error.code === 'MODULE_NOT_FOUND') {
|
||||
css = require('@adobe/css-tools');
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const fs = require('fs');
|
||||
const objUtil = require('../../utils/object');
|
||||
const resolveModule = require('../../utils/resolve');
|
||||
|
||||
module.exports = (hexo) => {
|
||||
|
||||
function resolveHighlight(name) {
|
||||
if (!name) {
|
||||
name = 'github-gist';
|
||||
}
|
||||
const cssName = name.toLowerCase().replace(/([^0-9])\s+?([^0-9])/g, '$1-$2').replace(/\s/g, '');
|
||||
let file = resolveModule('highlight.js', `styles/${cssName}.css`);
|
||||
if (cssName === 'github-gist' && !fs.existsSync(file)) {
|
||||
file = resolveModule('highlight.js', 'styles/github.css');
|
||||
}
|
||||
let backgroundColor;
|
||||
if (fs.existsSync(file)) {
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
css.parse(content).stylesheet.rules
|
||||
.filter(rule => rule.type === 'rule' && rule.selectors.some(selector => selector.endsWith('.hljs')))
|
||||
.flatMap(rule => rule.declarations)
|
||||
.forEach(declaration => {
|
||||
if (declaration.property === 'background' || declaration.property === 'background-color') {
|
||||
backgroundColor = declaration.value;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
hexo.log.error(`[Fluid] highlightjs style '${name}' not found`);
|
||||
return {};
|
||||
}
|
||||
if (backgroundColor === 'white' || backgroundColor === '#ffffff') {
|
||||
backgroundColor = '#fff';
|
||||
}
|
||||
return { file, backgroundColor };
|
||||
}
|
||||
|
||||
function resolvePrism(name) {
|
||||
if (!name) {
|
||||
name = 'default';
|
||||
}
|
||||
let cssName = name.toLowerCase().replace(/[\s-]/g, '');
|
||||
if (cssName === 'prism' || cssName === 'default') {
|
||||
cssName = '';
|
||||
} else if (cssName === 'tomorrownight') {
|
||||
cssName = 'tomorrow';
|
||||
}
|
||||
let file = resolveModule('prismjs', `themes/${cssName ? 'prism-' + cssName : 'prism'}.css`);
|
||||
if (!fs.existsSync(file)) {
|
||||
file = resolveModule('prism-themes', `themes/${cssName}.css`);
|
||||
}
|
||||
if (!fs.existsSync(file)) {
|
||||
hexo.log.error(`[Fluid] prismjs style '${name}' not found`);
|
||||
return {};
|
||||
}
|
||||
return { file };
|
||||
}
|
||||
|
||||
const config = hexo.theme.config;
|
||||
if (!config.code || !config.code.highlight.enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.code.highlight.lib === 'highlightjs') {
|
||||
// Force set hexo config
|
||||
hexo.config.prismjs = objUtil.merge({}, hexo.config.prismjs, {
|
||||
enable: false
|
||||
});
|
||||
hexo.config.highlight = objUtil.merge({}, hexo.config.highlight, {
|
||||
enable : true,
|
||||
hljs : true,
|
||||
wrap : false,
|
||||
auto_detect: true,
|
||||
line_number: config.code.highlight.line_number || false
|
||||
});
|
||||
hexo.config.syntax_highlighter = 'highlight.js'; // hexo v7.0.0+ config
|
||||
hexo.theme.config.code.highlight.highlightjs = objUtil.merge({}, hexo.theme.config.code.highlight.highlightjs, {
|
||||
light: resolveHighlight(hexo.theme.config.code.highlight.highlightjs.style),
|
||||
dark : hexo.theme.config.dark_mode.enable && resolveHighlight(hexo.theme.config.code.highlight.highlightjs.style_dark)
|
||||
});
|
||||
|
||||
hexo.extend.filter.register('after_post_render', (page) => {
|
||||
if (hexo.config.highlight.line_number) {
|
||||
page.content = page.content.replace(/<figure[^>]+?highlight.+?<td[^>]+?code[^>]+?>.*?(<pre.+?<\/pre>).+?<\/figure>/gims, (str, p1) => {
|
||||
if (/<code[^>]+?mermaid[^>]+?>/ims.test(p1)) {
|
||||
return p1.replace(/(class="[^>]*?)hljs([^>]*?")/gims, '$1$2').replace(/<br>/gims, '\n');
|
||||
}
|
||||
return str;
|
||||
});
|
||||
} else {
|
||||
page.content = page.content.replace(/(?<!<div class="code-wrapper">)<pre.+?<\/pre>/gims, (str) => {
|
||||
if (/<code[^>]+?mermaid[^>]+?>/ims.test(str)) {
|
||||
return str.replace(/(class=".*?)hljs(.*?")/gims, '$1$2');
|
||||
}
|
||||
return `<div class="code-wrapper">${str}</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
// 适配缩进型代码块
|
||||
page.content = page.content.replace(/<pre><code>/gims, (str) => {
|
||||
return '<pre><code class="hljs">';
|
||||
});
|
||||
|
||||
return page;
|
||||
});
|
||||
} else if (config.code.highlight.lib === 'prismjs') {
|
||||
// Force set hexo config
|
||||
hexo.config.highlight = objUtil.merge({}, hexo.config.highlight, {
|
||||
enable: false
|
||||
});
|
||||
hexo.config.prismjs = objUtil.merge({}, hexo.config.prismjs, {
|
||||
enable : true,
|
||||
preprocess : config.code.highlight.prismjs.preprocess || false,
|
||||
line_number: config.code.highlight.line_number || false
|
||||
});
|
||||
hexo.config.syntax_highlighter = 'prismjs'; // hexo v7.0.0+ config
|
||||
hexo.theme.config.code.highlight.prismjs = objUtil.merge({}, hexo.theme.config.code.highlight.prismjs, {
|
||||
light: resolvePrism(hexo.theme.config.code.highlight.prismjs.style),
|
||||
dark : hexo.theme.config.dark_mode.enable && resolvePrism(hexo.theme.config.code.highlight.prismjs.style_dark)
|
||||
});
|
||||
|
||||
hexo.extend.filter.register('after_post_render', (page) => {
|
||||
page.content = page.content.replace(/(?<!<div class="code-wrapper">)<pre.+?<\/pre>/gims, (str) => {
|
||||
if (/<code[^>]+?mermaid[^>]+?>/ims.test(str)) {
|
||||
if (hexo.config.highlight.line_number) {
|
||||
str = str.replace(/<span[^>]+?line-numbers-rows[^>]+?>.+?<\/span><\/code>/, '</code>');
|
||||
}
|
||||
str = str.replace(/<pre[^>]*?>/gims, '<pre>')
|
||||
.replace(/(class=".*?)language-mermaid(.*?")/gims, '$1mermaid$2')
|
||||
.replace(/<span[^>]+?>(.+?)<\/span>/gims, '$1');
|
||||
return str;
|
||||
}
|
||||
return `<figure><div class="code-wrapper">${str}</div></figure>`;
|
||||
});
|
||||
|
||||
// 适配缩进型代码块
|
||||
page.content = page.content.replace(/<pre><code>/gims, (str) => {
|
||||
return '<pre class="language-none"><code class="language-none">';
|
||||
});
|
||||
|
||||
return page;
|
||||
});
|
||||
}
|
||||
};
|
||||
118
themes/fluid/scripts/events/lib/injects.js
Normal file
118
themes/fluid/scripts/events/lib/injects.js
Normal file
@@ -0,0 +1,118 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Modified from https://github.com/next-theme/hexo-theme-next/blob/master/scripts/events/lib/injects.js
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const defaultExtname = '.ejs';
|
||||
|
||||
// Defining stylus types
|
||||
class StylusInject {
|
||||
|
||||
constructor(base_dir) {
|
||||
this.base_dir = base_dir;
|
||||
this.files = [];
|
||||
}
|
||||
|
||||
push(file) {
|
||||
// Get absolute path base on hexo dir
|
||||
this.files.push(path.resolve(this.base_dir, file));
|
||||
}
|
||||
}
|
||||
|
||||
// Defining view types
|
||||
class ViewInject {
|
||||
|
||||
constructor(base_dir) {
|
||||
this.base_dir = base_dir;
|
||||
this.raws = [];
|
||||
}
|
||||
|
||||
raw(name, raw, ...args) {
|
||||
// Set default extname
|
||||
if (path.extname(name) === '') {
|
||||
name += defaultExtname;
|
||||
}
|
||||
this.raws.push({ name, raw, args });
|
||||
}
|
||||
|
||||
file(name, file, ...args) {
|
||||
// Set default extname from file's extname
|
||||
if (path.extname(name) === '') {
|
||||
name += path.extname(file);
|
||||
}
|
||||
// Get absolute path base on hexo dir
|
||||
this.raw(name, fs.readFileSync(path.resolve(this.base_dir, file), 'utf8'), ...args);
|
||||
}
|
||||
}
|
||||
|
||||
const points = {
|
||||
views: [
|
||||
'head',
|
||||
'header',
|
||||
'bodyBegin',
|
||||
'bodyEnd',
|
||||
'footer',
|
||||
'postMetaTop',
|
||||
'postMetaBottom',
|
||||
'postMarkdownBegin',
|
||||
'postMarkdownEnd',
|
||||
'postLeft',
|
||||
'postRight',
|
||||
'postCopyright',
|
||||
'postComments',
|
||||
'pageComments',
|
||||
'linksComments'
|
||||
],
|
||||
styles: [
|
||||
'variable',
|
||||
'mixin',
|
||||
'style'
|
||||
]
|
||||
};
|
||||
|
||||
// Init injects
|
||||
function initInject(base_dir) {
|
||||
const injects = {};
|
||||
points.styles.forEach(item => {
|
||||
injects[item] = new StylusInject(base_dir);
|
||||
});
|
||||
points.views.forEach(item => {
|
||||
injects[item] = new ViewInject(base_dir);
|
||||
});
|
||||
return injects;
|
||||
}
|
||||
|
||||
module.exports = (hexo) => {
|
||||
// Exec theme_inject filter
|
||||
const injects = initInject(hexo.base_dir);
|
||||
hexo.execFilterSync('theme_inject', injects);
|
||||
hexo.theme.config.injects = {};
|
||||
|
||||
// Inject stylus
|
||||
points.styles.forEach(type => {
|
||||
hexo.theme.config.injects[type] = injects[type].files;
|
||||
});
|
||||
|
||||
// Inject views
|
||||
points.views.forEach(type => {
|
||||
const configs = Object.create(null);
|
||||
hexo.theme.config.injects[type] = [];
|
||||
// Add or override view.
|
||||
injects[type].raws.forEach((injectObj, index) => {
|
||||
const name = `inject/${type}/${injectObj.name}`;
|
||||
hexo.theme.setView(name, injectObj.raw);
|
||||
configs[name] = {
|
||||
layout : name,
|
||||
locals : injectObj.args[0],
|
||||
options: injectObj.args[1],
|
||||
order : injectObj.args[2] || index
|
||||
};
|
||||
});
|
||||
// Views sort.
|
||||
hexo.theme.config.injects[type] = Object.values(configs)
|
||||
.sort((x, y) => x.order - y.order);
|
||||
});
|
||||
};
|
||||
50
themes/fluid/scripts/events/lib/lazyload.js
Normal file
50
themes/fluid/scripts/events/lib/lazyload.js
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
const urlJoin = require('../../utils/url-join');
|
||||
|
||||
module.exports = (hexo) => {
|
||||
const config = hexo.theme.config;
|
||||
const loadingImage = urlJoin(hexo.config.root, config.lazyload.loading_img
|
||||
|| urlJoin(config.static_prefix.internal_img, 'loading.gif'));
|
||||
if (!config.lazyload || !config.lazyload.enable || !loadingImage) {
|
||||
return;
|
||||
}
|
||||
if (config.lazyload.onlypost) {
|
||||
hexo.extend.filter.register('after_post_render', (page) => {
|
||||
if (page.layout !== 'post' && !page.lazyload) {
|
||||
return;
|
||||
}
|
||||
if (page.lazyload !== false) {
|
||||
page.content = lazyImages(page.content, loadingImage);
|
||||
page.content = lazyComments(page.content);
|
||||
}
|
||||
return page;
|
||||
});
|
||||
} else {
|
||||
hexo.extend.filter.register('after_render:html', (html, data) => {
|
||||
if (!data.page || data.page.lazyload !== false) {
|
||||
html = lazyImages(html, loadingImage);
|
||||
html = lazyComments(html);
|
||||
return html;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const lazyImages = (htmlContent, loadingImage) => {
|
||||
return htmlContent.replace(/<img[^>]+?src=(".*?")[^>]*?>/gims, (str, p1) => {
|
||||
if (/lazyload/i.test(str)) {
|
||||
return str;
|
||||
}
|
||||
return str.replace(p1, `${p1} srcset="${loadingImage}" lazyload`);
|
||||
});
|
||||
};
|
||||
|
||||
const lazyComments = (htmlContent) => {
|
||||
return htmlContent.replace(/<[^>]+?id="comments"[^>]*?>/gims, (str) => {
|
||||
if (/lazyload/i.test(str)) {
|
||||
return str;
|
||||
}
|
||||
return str.replace('id="comments"', 'id="comments" lazyload');
|
||||
});
|
||||
};
|
||||
93
themes/fluid/scripts/events/lib/merge-configs.js
Normal file
93
themes/fluid/scripts/events/lib/merge-configs.js
Normal file
@@ -0,0 +1,93 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const objUtil = require('../../utils/object');
|
||||
const { isNotEmptyObject } = require('../../utils/object');
|
||||
|
||||
module.exports = (hexo) => {
|
||||
const isZh = hexo.theme.i18n.languages[0].search(/zh-CN/i) !== -1;
|
||||
|
||||
let dataConfig = {};
|
||||
let dataStaticConfig = {};
|
||||
|
||||
if (hexo.locals.get instanceof Function) {
|
||||
const data = hexo.locals.get('data');
|
||||
if (data && isNotEmptyObject(data.fluid_config)) {
|
||||
dataConfig = data.fluid_config;
|
||||
} else if (!configFromRoot(hexo)) {
|
||||
if (isZh) {
|
||||
hexo.log.warn('[Fluid] 推荐你使用覆盖配置功能: https://hexo.fluid-dev.com/docs/guide/#%E8%A6%86%E7%9B%96%E9%85%8D%E7%BD%AE');
|
||||
} else {
|
||||
hexo.log.warn('[Fluid] It is recommended that you use override configuration: https://hexo.fluid-dev.com/docs/en/guide/#override-configuration');
|
||||
}
|
||||
}
|
||||
if (data && isNotEmptyObject(data.fluid_static_prefix)) {
|
||||
dataStaticConfig = data.fluid_static_prefix;
|
||||
}
|
||||
|
||||
const { language } = hexo.config;
|
||||
const { i18n } = hexo.theme;
|
||||
const langConfigMap = {};
|
||||
for (const key in data) {
|
||||
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
||||
if (/^languages\/.+$/.test(key)) {
|
||||
langConfigMap[key.replace('languages/', '')] = data[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isNotEmptyObject(langConfigMap)) {
|
||||
const mergeLang = (lang) => {
|
||||
if (langConfigMap[lang]) {
|
||||
i18n.set(lang, objUtil.merge({}, i18n.get([lang]), langConfigMap[lang]));
|
||||
}
|
||||
};
|
||||
if (Array.isArray(language)) {
|
||||
for (const lang of language) {
|
||||
mergeLang(lang);
|
||||
}
|
||||
} else {
|
||||
mergeLang(language);
|
||||
}
|
||||
if (isZh) {
|
||||
hexo.log.debug('[Fluid] 读取 source/_data/languages/*.yml 文件覆盖语言配置');
|
||||
} else {
|
||||
hexo.log.debug('[Fluid] Merge language config from source/_data/languages/*.yml');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotEmptyObject(hexo.config.theme_config)) {
|
||||
hexo.theme.config = objUtil.merge({}, hexo.theme.config, hexo.config.theme_config);
|
||||
if (isZh) {
|
||||
hexo.log.debug('[Fluid] 读取 _config.yml 中 theme_config 配置项覆盖主题配置');
|
||||
} else {
|
||||
hexo.log.debug('[Fluid] Merge theme config from theme_config in _config.yml');
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotEmptyObject(dataStaticConfig)) {
|
||||
hexo.theme.config.static_prefix = objUtil.merge({}, hexo.theme.config.static_prefix, dataStaticConfig);
|
||||
if (isZh) {
|
||||
hexo.log.debug('[Fluid] 读取 source/_data/fluid_static_prefix.yml 文件覆盖主题配置');
|
||||
} else {
|
||||
hexo.log.debug('[Fluid] Merge theme config from source/_data/fluid_static_prefix.yml');
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotEmptyObject(dataConfig)) {
|
||||
hexo.theme.config = objUtil.merge({}, hexo.theme.config, dataConfig);
|
||||
if (isZh) {
|
||||
hexo.log.debug('[Fluid] 读取 source/_data/fluid_config.yml 文件覆盖主题配置');
|
||||
} else {
|
||||
hexo.log.debug('[Fluid] Merge theme config from source/_data/fluid_config.yml');
|
||||
}
|
||||
}
|
||||
|
||||
hexo.log.debug('[Fluid] Output theme config:\n', JSON.stringify(hexo.theme.config, undefined, 2));
|
||||
};
|
||||
|
||||
const configFromRoot = (hexo) => {
|
||||
const configPath = path.join(hexo.base_dir, '_config.fluid.yml');
|
||||
return fs.existsSync(configPath);
|
||||
};
|
||||
Reference in New Issue
Block a user