first commit
This commit is contained in:
66
node_modules/hexo-theme-redefine/scripts/config-export.js
generated
vendored
Executable file
66
node_modules/hexo-theme-redefine/scripts/config-export.js
generated
vendored
Executable file
@@ -0,0 +1,66 @@
|
||||
/* main hexo */
|
||||
|
||||
"use strict";
|
||||
|
||||
const url = require("url");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const yaml = require("js-yaml");
|
||||
const { version } = require("../package.json");
|
||||
|
||||
/**
|
||||
* Export theme config to js
|
||||
*/
|
||||
hexo.extend.helper.register("export_config", function () {
|
||||
let hexo_config = {
|
||||
hostname: new URL(this.config.url).hostname || this.config.url,
|
||||
root: this.config.root,
|
||||
language: this.config.language,
|
||||
};
|
||||
|
||||
if (this.config.search) {
|
||||
hexo_config.path = this.config.search.path;
|
||||
}
|
||||
|
||||
let theme_config = {
|
||||
articles: this.theme.articles,
|
||||
colors: this.theme.colors,
|
||||
global: this.theme.global,
|
||||
home_banner: this.theme.home_banner,
|
||||
plugins: this.theme.plugins,
|
||||
version: version,
|
||||
code_block: this.theme.code_block,
|
||||
navbar: this.theme.navbar,
|
||||
page_templates: this.theme.page_templates,
|
||||
home: this.theme.home,
|
||||
|
||||
footerStart: this.theme.footer.start,
|
||||
};
|
||||
|
||||
const languageDir = path.join(__dirname, "../languages");
|
||||
let file = fs
|
||||
.readdirSync(languageDir)
|
||||
.find((v) => v === `${this.config.language}.yml`);
|
||||
file = languageDir + "/" + (file ? file : "en.yml");
|
||||
let languageContent = fs.readFileSync(file, "utf8");
|
||||
try {
|
||||
languageContent = yaml.load(languageContent);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
let data_config = {
|
||||
masonry: false,
|
||||
};
|
||||
|
||||
if (this.theme.masonry) {
|
||||
data_config.masonry = true;
|
||||
}
|
||||
|
||||
return `<script id="hexo-configurations">
|
||||
window.config = ${JSON.stringify(hexo_config)};
|
||||
window.theme = ${JSON.stringify(theme_config)};
|
||||
window.lang_ago = ${JSON.stringify(languageContent["ago"])};
|
||||
window.data = ${JSON.stringify(data_config)};
|
||||
</script>`;
|
||||
});
|
||||
37
node_modules/hexo-theme-redefine/scripts/data-handle.js
generated
vendored
Executable file
37
node_modules/hexo-theme-redefine/scripts/data-handle.js
generated
vendored
Executable file
@@ -0,0 +1,37 @@
|
||||
hexo.on('generateBefore', function () {
|
||||
|
||||
if (hexo.locals.get) {
|
||||
const data = hexo.locals.get('data');
|
||||
|
||||
if (data) {
|
||||
// theme config file handle
|
||||
if (data._config) {
|
||||
hexo.theme.config = data._config;
|
||||
|
||||
} else if (data.redefine) {
|
||||
hexo.theme.config = data.redefine;
|
||||
|
||||
} else if (data._redefine) {
|
||||
hexo.theme.config = data._redefine;
|
||||
}
|
||||
|
||||
// friends link file handle
|
||||
if (data.links || data.link) {
|
||||
hexo.theme.config.links = (data.links || data.link);
|
||||
}
|
||||
|
||||
if (data.essays || data.essay || data.shuoshuo) {
|
||||
hexo.theme.config.essays = (data.essays || data.essay || data.shuoshuo);
|
||||
}
|
||||
|
||||
if (data.masonry || data.gallery || data.photos) {
|
||||
hexo.theme.config.masonry = (data.masonry || data.gallery || data.photos);
|
||||
}
|
||||
|
||||
if (data.bookmarks || data.tools) {
|
||||
hexo.theme.config.bookmarks = data.bookmarks || data.tools;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
16
node_modules/hexo-theme-redefine/scripts/events/404.js
generated
vendored
Executable file
16
node_modules/hexo-theme-redefine/scripts/events/404.js
generated
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Theme Redefine
|
||||
* 404 error page
|
||||
*/
|
||||
|
||||
hexo.extend.generator.register('404', function (locals) {
|
||||
return {
|
||||
path: '404.html',
|
||||
layout: '404',
|
||||
data: {
|
||||
title: 'Page Not Found',
|
||||
type: 'notfound',
|
||||
page: locals.pages.findOne({ path: '404.html' })
|
||||
}
|
||||
}
|
||||
});
|
||||
139
node_modules/hexo-theme-redefine/scripts/events/welcome.js
generated
vendored
Normal file
139
node_modules/hexo-theme-redefine/scripts/events/welcome.js
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Theme Redefine
|
||||
* welcome.js
|
||||
*/
|
||||
const { version } = require("../../package.json");
|
||||
const https = require("https");
|
||||
|
||||
hexo.on("ready", async () => {
|
||||
const timeout = 3000;
|
||||
|
||||
async function fetchRedefineInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
https
|
||||
.get(
|
||||
`https://redefine-version.ohevan.com/api/v2/info`,
|
||||
{ timeout: timeout },
|
||||
(response) => {
|
||||
if (response.statusCode < 200 || response.statusCode > 299) {
|
||||
logFailedInfo();
|
||||
return reject(
|
||||
new Error(
|
||||
`Failed to load page, status code: ${response.statusCode}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
let data = "";
|
||||
response.on("data", (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
response.on("end", () => {
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
|
||||
if (jsonData.status !== "success") {
|
||||
logFailedInfo();
|
||||
return reject(
|
||||
new Error(`Failed to fetch data: ${jsonData.message}`),
|
||||
);
|
||||
}
|
||||
|
||||
const redefineData = jsonData.data;
|
||||
|
||||
logInfo(redefineData);
|
||||
checkVersionAndCDNAvailability(redefineData);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
logFailedInfo();
|
||||
reject(new Error(`JSON parse failed: ${error.message}`));
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
.on("error", (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await fetchRedefineInfo();
|
||||
} catch (error) {
|
||||
hexo.log.warn(`Check latest version failed: ${error}`);
|
||||
hexo.locals.set(`cdnTestStatus_cdnjs`, 404);
|
||||
hexo.locals.set(`cdnTestStatus_zstatic`, 404);
|
||||
hexo.locals.set(`cdnTestStatus_npmMirror`, 404);
|
||||
}
|
||||
});
|
||||
|
||||
function logInfo(data) {
|
||||
hexo.log.info(
|
||||
`
|
||||
+======================================================================================+
|
||||
| |
|
||||
| _____ _ _ _____ __ __ _____ ____ _____ ____ _____ _____ ___ _ _ _____ |
|
||||
| |_ _| | | | ____| \\/ | ____| | _ \\| ____| _ \\| ____| ___|_ _| \\ | | ____| |
|
||||
| | | | |_| | _| | |\\/| | _| | |_) | _| | | | | _| | |_ | || \\| | _| |
|
||||
| | | | _ | |___| | | | |___ | _ <| |___| |_| | |___| _| | || |\\ | |___ |
|
||||
| |_| |_| |_|_____|_| |_|_____| |_| \\_\\_____|____/|_____|_| |___|_| \\_|_____| |
|
||||
| |
|
||||
| current v${version} latest v${data.npmVersion} |
|
||||
| https://github.com/EvanNotFound/hexo-theme-redefine |
|
||||
+======================================================================================+
|
||||
`,
|
||||
);
|
||||
}
|
||||
|
||||
function logFailedInfo() {
|
||||
hexo.log.info(
|
||||
`
|
||||
+======================================================================================+
|
||||
| |
|
||||
| _____ _ _ _____ __ __ _____ ____ _____ ____ _____ _____ ___ _ _ _____ |
|
||||
| |_ _| | | | ____| \\/ | ____| | _ \\| ____| _ \\| ____| ___|_ _| \\ | | ____| |
|
||||
| | | | |_| | _| | |\\/| | _| | |_) | _| | | | | _| | |_ | || \\| | _| |
|
||||
| | | | _ | |___| | | | |___ | _ <| |___| |_| | |___| _| | || |\\ | |___ |
|
||||
| |_| |_| |_|_____|_| |_|_____| |_| \\_\\_____|____/|_____|_| |___|_| \\_|_____| |
|
||||
| |
|
||||
| current v${version} fetch latest failed |
|
||||
| https://github.com/EvanNotFound/hexo-theme-redefine |
|
||||
+======================================================================================+
|
||||
`,
|
||||
);
|
||||
}
|
||||
|
||||
function checkVersionAndCDNAvailability(data) {
|
||||
if (data.npmVersion > version) {
|
||||
hexo.log.warn(
|
||||
`\x1b[33m%s\x1b[0m`,
|
||||
`Redefine v${version} is outdated, please update to v${data.npmVersion}!`,
|
||||
);
|
||||
}
|
||||
|
||||
if (data.npmMirrorCDN) {
|
||||
hexo.log.info(
|
||||
`\x1b[32m%s\x1b[0m`,
|
||||
`CDN available: NPMMirror (Recommended)`,
|
||||
);
|
||||
hexo.locals.set(`cdnTestStatus_npmMirror`, 200);
|
||||
} else {
|
||||
hexo.log.warn(`\x1b[31m%s\x1b[0m`, `NPMMirror CDN is unavailable yet.`);
|
||||
hexo.locals.set(`cdnTestStatus_npmMirror`, 404);
|
||||
}
|
||||
|
||||
if (data.zstaticCDN) {
|
||||
hexo.log.info(`\x1b[32m%s\x1b[0m`, `CDN available: ZStatic`);
|
||||
hexo.locals.set(`cdnTestStatus_zstatic`, 200);
|
||||
} else {
|
||||
hexo.log.warn(`\x1b[31m%s\x1b[0m`, `ZStatic CDN is unavailable yet.`);
|
||||
hexo.locals.set(`cdnTestStatus_zstatic`, 404);
|
||||
}
|
||||
|
||||
if (data.cdnjsCDN) {
|
||||
hexo.log.info(`\x1b[32m%s\x1b[0m`, `CDN available: CDNJS`);
|
||||
hexo.locals.set(`cdnTestStatus_cdnjs`, 200);
|
||||
} else {
|
||||
hexo.log.warn(`\x1b[31m%s\x1b[0m`, `CDNJS CDN is unavailable yet.`);
|
||||
hexo.locals.set(`cdnTestStatus_cdnjs`, 404);
|
||||
}
|
||||
}
|
||||
27
node_modules/hexo-theme-redefine/scripts/filters/delete-mask-handle.js
generated
vendored
Normal file
27
node_modules/hexo-theme-redefine/scripts/filters/delete-mask-handle.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/* delete mask */
|
||||
|
||||
"use strict";
|
||||
|
||||
hexo.extend.filter.register(
|
||||
"after_post_render",
|
||||
function (data) {
|
||||
const theme = this.theme;
|
||||
|
||||
// 处理del标签的代码
|
||||
const regPureDelTag = /<del(?:\s+[^>]*)?>((?:(?!<\/?del[\s>])[^])*)<\/del>/g;
|
||||
|
||||
data.content = data.content.replace(
|
||||
regPureDelTag,
|
||||
function (match, html) {
|
||||
// 只有在配置为true时才添加mask类
|
||||
if (theme.config.articles.style.delete_mask === true) {
|
||||
return `<del class="mask">${html}</del>`;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
0
|
||||
);
|
||||
202
node_modules/hexo-theme-redefine/scripts/filters/encrypt.js
generated
vendored
Executable file
202
node_modules/hexo-theme-redefine/scripts/filters/encrypt.js
generated
vendored
Executable file
@@ -0,0 +1,202 @@
|
||||
/* main hexo, __dirname */
|
||||
|
||||
"use strict";
|
||||
|
||||
const crypto = require("crypto");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const log = hexo.log;
|
||||
const { hbeTheme } = require("./lib/hbe.default.js");
|
||||
|
||||
const defaultConfig = {
|
||||
abstract:
|
||||
"Here's something encrypted, password is required to continue reading.",
|
||||
message: "Hey, password is required here.",
|
||||
theme: "default",
|
||||
wrong_pass_message:
|
||||
"Oh, this is an invalid password. Check and try again, please.",
|
||||
wrong_hash_message:
|
||||
"OOPS, these decrypted content may changed, but you can still have a look.",
|
||||
silent: false,
|
||||
};
|
||||
|
||||
const keySalt = textToArray("too young too simple");
|
||||
const ivSalt = textToArray("sometimes naive!");
|
||||
|
||||
// As we can't detect the wrong password with AES-CBC,
|
||||
// so adding an empty tag and check it when decrption.
|
||||
const knownPrefix = "<hbe-prefix></hbe-prefix>";
|
||||
|
||||
// disable log
|
||||
var silent = false;
|
||||
// use default theme
|
||||
var theme = "default";
|
||||
|
||||
hexo.extend.filter.register(
|
||||
"after_post_render",
|
||||
(data) => {
|
||||
const tagEncryptPairs = [];
|
||||
|
||||
let password = data.password;
|
||||
let tagUsed = false;
|
||||
|
||||
// use a empty password to disable category encryption
|
||||
if (password === "") {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (hexo.config.encrypt === undefined) {
|
||||
hexo.config.encrypt = [];
|
||||
}
|
||||
|
||||
if ("encrypt" in hexo.config && "tags" in hexo.config.encrypt) {
|
||||
hexo.config.encrypt.tags.forEach((tagObj) => {
|
||||
tagEncryptPairs[tagObj.name] = tagObj.password;
|
||||
});
|
||||
}
|
||||
|
||||
if (data.tags) {
|
||||
data.tags.forEach((cTag) => {
|
||||
if (tagEncryptPairs.hasOwnProperty(cTag.name)) {
|
||||
tagUsed = password ? tagUsed : cTag.name;
|
||||
password = password || tagEncryptPairs[cTag.name];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (password == undefined) {
|
||||
return data;
|
||||
}
|
||||
|
||||
password = password.toString();
|
||||
|
||||
// make sure toc can work.
|
||||
data.origin = data.content;
|
||||
|
||||
// Let's rock n roll
|
||||
const config = Object.assign(defaultConfig, hexo.config.encrypt, data);
|
||||
silent = config.silent;
|
||||
theme = config.theme.trim().toLowerCase();
|
||||
|
||||
// deprecate the template keyword
|
||||
if (config.template) {
|
||||
dlog(
|
||||
"warn",
|
||||
'Looks like you use a deprecated property "template" to set up template, consider to use "theme"? See https://github.com/D0n9X1n/hexo-blog-encrypt#encrypt-theme',
|
||||
);
|
||||
}
|
||||
|
||||
// read theme from file
|
||||
let template = hbeTheme;
|
||||
|
||||
if (tagUsed === false) {
|
||||
dlog(
|
||||
"info",
|
||||
`hexo-blog-encrypt: encrypting "${data.title.trim()}" based on the password configured in Front-matter with theme: ${theme}.`,
|
||||
);
|
||||
} else {
|
||||
dlog(
|
||||
"info",
|
||||
`hexo-blog-encrypt: encrypting "${data.title.trim()}" based on Tag: "${tagUsed}" with theme ${theme}.`,
|
||||
);
|
||||
}
|
||||
|
||||
data.content = knownPrefix + data.content.trim();
|
||||
data.encrypt = true;
|
||||
|
||||
const key = crypto.pbkdf2Sync(password, keySalt, 1024, 32, "sha256");
|
||||
const iv = crypto.pbkdf2Sync(password, ivSalt, 512, 16, "sha256");
|
||||
|
||||
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
|
||||
const hmac = crypto.createHmac("sha256", key);
|
||||
|
||||
let encryptedData = cipher.update(data.content, "utf8", "hex");
|
||||
hmac.update(data.content, "utf8");
|
||||
encryptedData += cipher.final("hex");
|
||||
const hmacDigest = hmac.digest("hex");
|
||||
|
||||
data.content = template
|
||||
.replace(/{{hbeEncryptedData}}/g, encryptedData)
|
||||
.replace(/{{hbeHmacDigest}}/g, hmacDigest)
|
||||
.replace(/{{hbeWrongPassMessage}}/g, config.wrong_pass_message)
|
||||
.replace(/{{hbeWrongHashMessage}}/g, config.wrong_hash_message)
|
||||
.replace(/{{hbeMessage}}/g, config.message);
|
||||
data.content += `<link href="${hexo.config.root}css/hbe.style.css" rel="stylesheet" type="text/css"><script data-swup-reload-script type="module" src="${hexo.config.root}js/plugins/hbe.js"></script>
|
||||
<script data-swup-reload-script type="module">
|
||||
import {initHBE} from "${hexo.config.root}js/plugins/hbe.js";
|
||||
console.log("hexo-blog-encrypt: loaded.");
|
||||
initHBE();
|
||||
</script>
|
||||
`;
|
||||
data.excerpt = data.more = config.abstract;
|
||||
|
||||
return data;
|
||||
},
|
||||
1000,
|
||||
);
|
||||
|
||||
hexo.extend.generator.register("hexo-blog-encrypt", () => [
|
||||
{
|
||||
data: () =>
|
||||
fs.createReadStream(
|
||||
path.resolve(__dirname, `../../source/assets/hbe.style.css`),
|
||||
),
|
||||
path: `css/hbe.style.css`,
|
||||
},
|
||||
{
|
||||
data: () =>
|
||||
fs.createReadStream(
|
||||
path.resolve(__dirname, "../../source/js/plugins/hbe.js"),
|
||||
),
|
||||
path: "js/plugins/hbe.js",
|
||||
},
|
||||
]);
|
||||
|
||||
// log function
|
||||
function dlog(level, x) {
|
||||
switch (level) {
|
||||
case "warn":
|
||||
log.warn(x);
|
||||
break;
|
||||
|
||||
case "info":
|
||||
default:
|
||||
if (silent) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(x);
|
||||
}
|
||||
}
|
||||
|
||||
// Utils functions
|
||||
function textToArray(s) {
|
||||
var i = s.length;
|
||||
var n = 0;
|
||||
var ba = new Array();
|
||||
|
||||
for (var j = 0; j < i; ) {
|
||||
var c = s.codePointAt(j);
|
||||
if (c < 128) {
|
||||
ba[n++] = c;
|
||||
j++;
|
||||
} else if (c > 127 && c < 2048) {
|
||||
ba[n++] = (c >> 6) | 192;
|
||||
ba[n++] = (c & 63) | 128;
|
||||
j++;
|
||||
} else if (c > 2047 && c < 65536) {
|
||||
ba[n++] = (c >> 12) | 224;
|
||||
ba[n++] = ((c >> 6) & 63) | 128;
|
||||
ba[n++] = (c & 63) | 128;
|
||||
j++;
|
||||
} else {
|
||||
ba[n++] = (c >> 18) | 240;
|
||||
ba[n++] = ((c >> 12) & 63) | 128;
|
||||
ba[n++] = ((c >> 6) & 63) | 128;
|
||||
ba[n++] = (c & 63) | 128;
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return new Uint8Array(ba);
|
||||
}
|
||||
9
node_modules/hexo-theme-redefine/scripts/filters/img-handle.js
generated
vendored
Normal file
9
node_modules/hexo-theme-redefine/scripts/filters/img-handle.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
hexo.extend.filter.register('after_post_render', function(data) {
|
||||
if (this.theme.config.articles.style.image_caption !== false) {
|
||||
const class_name='image-caption';
|
||||
if (data.layout === 'post' || data.layout === 'page' || data.layout === 'about') {
|
||||
data.content = data.content.replace(/(<img [^>]*alt="([^"]+)"[^>]*>)/g, `<figure class="${class_name}">$1<figcaption>$2</figcaption></figure>`);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
});
|
||||
24
node_modules/hexo-theme-redefine/scripts/filters/lazyload-handle.js
generated
vendored
Executable file
24
node_modules/hexo-theme-redefine/scripts/filters/lazyload-handle.js
generated
vendored
Executable file
@@ -0,0 +1,24 @@
|
||||
'use strict'
|
||||
hexo.extend.filter.register(
|
||||
'after_post_render',
|
||||
function (data) {
|
||||
const theme = hexo.theme.config;
|
||||
if (!theme.articles.lazyload || !theme.articles.lazyload) return;
|
||||
data.content = data.content.replace(
|
||||
// Match 'img' tags width the src attribute.
|
||||
/<img([^>]*)src="([^"]*)"([^>\/]*)\/?\s*>/gim,
|
||||
function (match, attrBegin, src, attrEnd) {
|
||||
// Exit if the src doesn't exists.
|
||||
if (!src) return match;
|
||||
|
||||
return `<img ${attrBegin}
|
||||
lazyload
|
||||
src="/images/loading.svg"
|
||||
data-src="${src}"
|
||||
${attrEnd}
|
||||
>`
|
||||
}
|
||||
)
|
||||
},
|
||||
1
|
||||
);
|
||||
15
node_modules/hexo-theme-redefine/scripts/filters/lib/hbe.default.js
generated
vendored
Executable file
15
node_modules/hexo-theme-redefine/scripts/filters/lib/hbe.default.js
generated
vendored
Executable file
@@ -0,0 +1,15 @@
|
||||
const hbeTheme = `
|
||||
<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="{{hbeWrongPassMessage}}" data-whm="{{hbeWrongHashMessage}}">
|
||||
<script id="hbeData" type="hbeData" data-hmacdigest="{{hbeHmacDigest}}">{{hbeEncryptedData}}</script>
|
||||
<div class="hbe hbe-content">
|
||||
<div class="hbe hbe-input hbe-input-default">
|
||||
<input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass">
|
||||
<label class="hbe hbe-input-label hbe-input-label-default" for="hbePass">
|
||||
<span class="hbe hbe-input-label-content hbe-input-label-content-default">{{hbeMessage}}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
module.exports = { hbeTheme };
|
||||
42
node_modules/hexo-theme-redefine/scripts/filters/link-handle.js
generated
vendored
Executable file
42
node_modules/hexo-theme-redefine/scripts/filters/link-handle.js
generated
vendored
Executable file
@@ -0,0 +1,42 @@
|
||||
/* main hexo */
|
||||
|
||||
"use strict";
|
||||
|
||||
hexo.extend.filter.register(
|
||||
"after_post_render",
|
||||
function (data) {
|
||||
const theme = this.theme;
|
||||
const config = this.config;
|
||||
const url = new URL(config.url);
|
||||
const siteHost = url.hostname || config.url;
|
||||
|
||||
// Match 'a' tags that don't contain html children.
|
||||
const regPureATag = /<a([^>]*)href="([^"]*)"([^>]*)>([^<]*)<\/a>/gim;
|
||||
|
||||
data.content = data.content.replace(
|
||||
regPureATag,
|
||||
function (match, attrBegin, href, attrEnd, html) {
|
||||
// Exit if the href attribute doesn't exists.
|
||||
if (!href) return match;
|
||||
|
||||
let link = "";
|
||||
try {
|
||||
link = new URL(href);
|
||||
} catch (e) {
|
||||
// Invalid url, e.g. Anchor link.
|
||||
return match;
|
||||
}
|
||||
|
||||
// Exit if the url has same host with `config.url`, which means isn't an external link.
|
||||
if (!link.protocol || link.hostname === siteHost) return match;
|
||||
|
||||
if (theme.config.articles.style.link_icon == false) {
|
||||
return `<a class="link" ${attrBegin} href="${href}" ${attrEnd}>${html}</a>`;
|
||||
} else {
|
||||
return `<a class="link" ${attrBegin} href="${href}" ${attrEnd}>${html}<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>`;
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
0,
|
||||
);
|
||||
9
node_modules/hexo-theme-redefine/scripts/filters/stylus-handle.js
generated
vendored
Normal file
9
node_modules/hexo-theme-redefine/scripts/filters/stylus-handle.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
hexo.extend.filter.register('stylus:renderer', function (style) {
|
||||
style.define('url-for', function (data) {
|
||||
const urlRender = hexo.extend.helper.get('url_for').bind(hexo);
|
||||
|
||||
const url = urlRender(data.val);
|
||||
|
||||
return url;
|
||||
});
|
||||
})
|
||||
11
node_modules/hexo-theme-redefine/scripts/filters/table-handle.js
generated
vendored
Normal file
11
node_modules/hexo-theme-redefine/scripts/filters/table-handle.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
'use strict';
|
||||
|
||||
hexo.extend.filter.register('after_post_render', function(data) {
|
||||
const tableRegex = /<table(?![\s\S]*?class=["'].*?\bgutter\b.*?["'])[\s\S]*?<\/table>/g;
|
||||
const wrappedTable = match => `<div class="table-container">${match}</div>`;
|
||||
data.content = data.content.replace(tableRegex, wrappedTable);
|
||||
return data;
|
||||
});
|
||||
|
||||
*/
|
||||
38
node_modules/hexo-theme-redefine/scripts/helpers/meta-helpers.js
generated
vendored
Executable file
38
node_modules/hexo-theme-redefine/scripts/helpers/meta-helpers.js
generated
vendored
Executable file
@@ -0,0 +1,38 @@
|
||||
hexo.extend.helper.register('generateMeta', function (theme, page) {
|
||||
const hexo = this;
|
||||
let robots_content="";
|
||||
if (page.robots) {
|
||||
robots_content = page.robots
|
||||
} else if (theme.seo && theme.seo.robots) {
|
||||
if (hexo.is_home()) {
|
||||
if (page.prev == 0) {
|
||||
robots_content=theme.seo.robots.home_first_page
|
||||
}else{
|
||||
robots_content=theme.seo.robots.home_other_pages
|
||||
}
|
||||
} else if (hexo.is_archive()) {
|
||||
robots_content=theme.seo.robots.archive
|
||||
} else if (hexo.is_category()) {
|
||||
robots_content=theme.seo.robots.category
|
||||
} else if (hexo.is_tag()) {
|
||||
robots_content=theme.seo.robots.tag
|
||||
}
|
||||
}
|
||||
if(robots_content){
|
||||
return `<meta name="robots" content="${robots_content}">`
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* hexo-auto-canonical
|
||||
* https://github.com/hyunseob/hexo-auto-canonical.git
|
||||
* Copyright (c) 2015, HyunSeob
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
hexo.extend.helper.register('autoCanonical', function (config, page) {
|
||||
var base_url = config.url;
|
||||
if (config.url.charAt(config.url.length - 1) !== '/') base_url += '/';
|
||||
|
||||
return '<link rel="canonical" href="' + base_url + page.canonical_path.replace('index.html', '').toLowerCase() + '"/>';
|
||||
});
|
||||
153
node_modules/hexo-theme-redefine/scripts/helpers/page-helpers.js
generated
vendored
Normal file
153
node_modules/hexo-theme-redefine/scripts/helpers/page-helpers.js
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
pageData is an object that defines various page types and their associated rendering details.
|
||||
|
||||
Each page type includes the following properties:
|
||||
|
||||
- titles: An array of possible titles for the page, which are used to identify the page type.
|
||||
- types: An array of page types that can be matched; the type takes precedence over the title for identification.
|
||||
- partial: The path to the partial template that will be used to render the content of the page.
|
||||
- layout: Specifies the layout style for the page. "raw" indicates that no theme layout will be applied, while "default" means the standard theme layout (container) will be used.
|
||||
*/
|
||||
|
||||
const pageData = {
|
||||
home: {
|
||||
titles: ["home", "首页"],
|
||||
types: ["home"],
|
||||
partial: "pages/home/home-content",
|
||||
layout: "raw",
|
||||
},
|
||||
archive: {
|
||||
titles: ["archive", "归档"],
|
||||
types: ["archive", "archives"],
|
||||
partial: "pages/archive/archive",
|
||||
layout: "raw",
|
||||
},
|
||||
post: {
|
||||
titles: ["post", "文章"],
|
||||
types: ["post", "posts"],
|
||||
partial: "pages/post/article-content",
|
||||
layout: "raw",
|
||||
},
|
||||
categories: {
|
||||
titles: ["category", "categories"],
|
||||
types: ["category", "categories"],
|
||||
partial: "pages/category/categories",
|
||||
layout: "default",
|
||||
},
|
||||
categoryDetail: {
|
||||
titles: [],
|
||||
types: [],
|
||||
partial: "pages/category/category-detail",
|
||||
layout: "default",
|
||||
},
|
||||
tags: {
|
||||
titles: ["tag", "tags"],
|
||||
types: ["tag", "tags"],
|
||||
partial: "pages/tag/tags",
|
||||
layout: "default",
|
||||
},
|
||||
tagDetail: {
|
||||
titles: [],
|
||||
types: [],
|
||||
partial: "pages/tag/tag-detail",
|
||||
layout: "default",
|
||||
},
|
||||
notFound: {
|
||||
titles: ["404", "notfound"],
|
||||
types: ["404", "notfound"],
|
||||
partial: "pages/notfound/notfound",
|
||||
layout: "raw",
|
||||
},
|
||||
friends: {
|
||||
titles: ["friends", "links", "link", "friend", "友情链接"],
|
||||
types: ["links", "link"],
|
||||
partial: "pages/friends/friends-link",
|
||||
layout: "default",
|
||||
},
|
||||
shuoshuo: {
|
||||
titles: ["shuoshuo", "说说"],
|
||||
types: ["essays", "essay", "shuoshuo"],
|
||||
partial: "pages/shuoshuo/essays",
|
||||
layout: "default",
|
||||
},
|
||||
masonry: {
|
||||
titles: ["gallery", "瀑布流", "相册", "photos", "photo"],
|
||||
types: ["masonry", "gallery", "瀑布流", "相册", "photos", "photo"],
|
||||
partial: "pages/masonry/masonry",
|
||||
layout: "default",
|
||||
},
|
||||
bookmarks: {
|
||||
titles: [],
|
||||
types: ["bookmarks", "bookmark", "tools"],
|
||||
partial: "pages/bookmarks/bookmarks",
|
||||
layout: "raw",
|
||||
},
|
||||
pageTemplate: {
|
||||
titles: [],
|
||||
types: [],
|
||||
partial: "pages/page-template",
|
||||
layout: "default",
|
||||
},
|
||||
};
|
||||
|
||||
hexo.extend.helper.register("getAllPageData", function () {
|
||||
return pageData;
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("getPageData", function (page) {
|
||||
if (this.is_home()) return pageData.home;
|
||||
if (this.is_archive()) return pageData.archive;
|
||||
if (this.is_post()) return pageData.post;
|
||||
if (this.is_category()) return pageData.categoryDetail;
|
||||
if (this.is_tag()) return pageData.tagDetail;
|
||||
|
||||
const currentPageConfig = Object.entries(pageData).find(([type, config]) => {
|
||||
return config.types.includes(page.template || page.type) || config.titles.includes(page.title?.toLowerCase());
|
||||
});
|
||||
return currentPageConfig ? pageData[currentPageConfig[0]] : null;
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("getPagePartialPath", function (page) {
|
||||
const matchesPageType = (type) => {
|
||||
const config = pageData[type];
|
||||
return (
|
||||
config.types.includes(page.template || page.type) ||
|
||||
config.titles.includes(page.title?.toLowerCase())
|
||||
);
|
||||
};
|
||||
|
||||
// Check built-in page types first
|
||||
if (this.is_home()) return pageData.home.partial;
|
||||
|
||||
if (this.is_post()) return pageData.post.partial;
|
||||
// Check custom page types
|
||||
for (const [type, config] of Object.entries(pageData)) {
|
||||
if (matchesPageType(type) && config.layout === "raw") {
|
||||
return config.partial;
|
||||
} else if (this.is_archive() && pageData.archive.layout === "raw") { // return raw layout for archive page
|
||||
return pageData.archive.partial;
|
||||
} else if (this.is_category() && pageData.categoryDetail.layout === "raw") { // return raw layout for category page
|
||||
return pageData.categoryDetail.partial;
|
||||
} else if (this.is_tag() && pageData.tagDetail.layout === "raw") { // return raw layout for tag page
|
||||
return pageData.tagDetail.partial;
|
||||
}
|
||||
}
|
||||
|
||||
return pageData.pageTemplate.partial;
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("getPageTitle", function (page) {
|
||||
const pageData = this.getPageData(page);
|
||||
let type = null;
|
||||
|
||||
// Determine the type based on page properties
|
||||
if (this.is_home()) type = "home";
|
||||
else if (this.is_archive()) type = "archive";
|
||||
else if (this.is_post()) type = "post";
|
||||
else {
|
||||
type = pageData.type;
|
||||
}
|
||||
|
||||
// const config = type ? pageData[type] : null;
|
||||
return page.title || this.__(type) || "Untitled";
|
||||
});
|
||||
367
node_modules/hexo-theme-redefine/scripts/helpers/recommendation-helpers.js
generated
vendored
Executable file
367
node_modules/hexo-theme-redefine/scripts/helpers/recommendation-helpers.js
generated
vendored
Executable file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Optimized by: EvanNotFound
|
||||
*/
|
||||
|
||||
const articleLibrary = [];
|
||||
const corpus = [];
|
||||
let flag = null;
|
||||
|
||||
hexo.extend.filter.register("template_locals", function (localVariables) {
|
||||
const cfg = hexo.theme.config.articles.recommendation;
|
||||
if (!cfg.enable) {
|
||||
return localVariables;
|
||||
}
|
||||
if (!flag) {
|
||||
flag = 1;
|
||||
fetchData(localVariables.site.posts, cfg);
|
||||
fetchData(localVariables.site.pages, cfg);
|
||||
articleRecommendation(cfg);
|
||||
}
|
||||
return localVariables;
|
||||
});
|
||||
|
||||
function fetchData(s, cfg) {
|
||||
s.each(function (p) {
|
||||
if (["post", "docs"].includes(p.layout)) {
|
||||
articleLibrary.push({
|
||||
path: p.path,
|
||||
title: p.title || p.seo_title || p.short_title,
|
||||
headimg: p.thumbnail || p.banner || p.cover || cfg.placeholder,
|
||||
});
|
||||
corpus.push(tokenize(p.raw));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cleanData(data) {
|
||||
const symbolLists = [
|
||||
",",
|
||||
".",
|
||||
"?",
|
||||
"!",
|
||||
":",
|
||||
";",
|
||||
"、",
|
||||
"……",
|
||||
"~",
|
||||
"&",
|
||||
"@",
|
||||
"#",
|
||||
",",
|
||||
"。",
|
||||
"?",
|
||||
"!",
|
||||
":",
|
||||
";",
|
||||
"·",
|
||||
"…",
|
||||
"~",
|
||||
"&",
|
||||
"@",
|
||||
"#",
|
||||
"“",
|
||||
"”",
|
||||
"‘",
|
||||
"’",
|
||||
"〝",
|
||||
"〞",
|
||||
'"',
|
||||
"'",
|
||||
""",
|
||||
"'",
|
||||
"´",
|
||||
"'",
|
||||
"(",
|
||||
")",
|
||||
"【",
|
||||
"】",
|
||||
"《",
|
||||
"》",
|
||||
"<",
|
||||
">",
|
||||
"﹝",
|
||||
"﹞",
|
||||
"<",
|
||||
">",
|
||||
"(",
|
||||
")",
|
||||
"[",
|
||||
"]",
|
||||
"«",
|
||||
"»",
|
||||
"‹",
|
||||
"›",
|
||||
"〔",
|
||||
"〕",
|
||||
"〈",
|
||||
"〉",
|
||||
"{",
|
||||
"}",
|
||||
"[",
|
||||
"]",
|
||||
"「",
|
||||
"」",
|
||||
"{",
|
||||
"}",
|
||||
"〖",
|
||||
"〗",
|
||||
"『",
|
||||
"』",
|
||||
"︵",
|
||||
"︷",
|
||||
"︹",
|
||||
"︿",
|
||||
"︽",
|
||||
"﹁",
|
||||
"﹃",
|
||||
"︻",
|
||||
"︗",
|
||||
"/",
|
||||
"|",
|
||||
"\\",
|
||||
"︶",
|
||||
"︸",
|
||||
"︺",
|
||||
"﹀",
|
||||
"︾",
|
||||
"﹂",
|
||||
"﹄",
|
||||
"﹄",
|
||||
"︼",
|
||||
"︘",
|
||||
"/",
|
||||
"|",
|
||||
"\",
|
||||
"_",
|
||||
"¯",
|
||||
"_",
|
||||
" ̄",
|
||||
"﹏",
|
||||
"﹋",
|
||||
"﹍",
|
||||
"﹉",
|
||||
"﹎",
|
||||
"﹊",
|
||||
"`",
|
||||
"ˋ",
|
||||
"¦",
|
||||
"︴",
|
||||
"¡",
|
||||
"¿",
|
||||
"^",
|
||||
"ˇ",
|
||||
"",
|
||||
"¨",
|
||||
"ˊ",
|
||||
" ",
|
||||
" ",
|
||||
"%",
|
||||
"*",
|
||||
"-",
|
||||
"+",
|
||||
"=",
|
||||
"¥",
|
||||
"$",
|
||||
"(",
|
||||
")",
|
||||
];
|
||||
data = data.replace(/\s/g, " ");
|
||||
data = data.replace(/\!\[(.*?)\]\(.*?\)/g, (_a, b) => {
|
||||
return b;
|
||||
});
|
||||
data = data.replace(
|
||||
/(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/g,
|
||||
" ",
|
||||
);
|
||||
for (const symbol of symbolLists) {
|
||||
data = data.replace(new RegExp("\\" + symbol, "g"), " ");
|
||||
}
|
||||
data = data.replace(/\d+/g, " ");
|
||||
data = data.replace(/\s/g, " ");
|
||||
return data;
|
||||
}
|
||||
|
||||
function tokenize(data) {
|
||||
const jieba = require("nodejieba");
|
||||
return jieba
|
||||
.cut(cleanData(data), true)
|
||||
.filter((word) => word !== " " && !/^[0-9]*$/.test(word));
|
||||
}
|
||||
|
||||
function cosineSimilarity(vector1, vector2) {
|
||||
let numerator = 0;
|
||||
let sqrt1 = 0;
|
||||
let sqrt2 = 0;
|
||||
if (vector1.length == vector2.length) {
|
||||
for (let i = 0; i < vector1.length; i++) {
|
||||
numerator += vector1[i] * vector2[i];
|
||||
sqrt1 += vector1[i] * vector1[i];
|
||||
sqrt2 += vector2[i] * vector2[i];
|
||||
}
|
||||
return numerator / (Math.sqrt(sqrt1) * Math.sqrt(sqrt2));
|
||||
}
|
||||
}
|
||||
|
||||
function createWordLibrary(allWords) {
|
||||
const wordLibrary = {};
|
||||
allWords.forEach((word) => {
|
||||
wordLibrary[word] = 0;
|
||||
});
|
||||
return wordLibrary;
|
||||
}
|
||||
|
||||
function calculateWordFrequency(wordLibrary, wordsInArticle) {
|
||||
const wordOccurrenceLibrary = wordsInArticle.reduce(
|
||||
(wordCountObj, wordName) => {
|
||||
if (wordName in wordCountObj) {
|
||||
wordCountObj[wordName]++;
|
||||
}
|
||||
return wordCountObj;
|
||||
},
|
||||
JSON.parse(JSON.stringify(wordLibrary)),
|
||||
);
|
||||
|
||||
const wordFrequency = JSON.parse(JSON.stringify(wordLibrary));
|
||||
for (const word of Object.keys(wordLibrary)) {
|
||||
wordFrequency[word] = wordOccurrenceLibrary[word] / wordsInArticle.length;
|
||||
}
|
||||
return wordFrequency;
|
||||
}
|
||||
|
||||
function articleRecommendation(cfg) {
|
||||
const dataSet = {};
|
||||
const similaritySet = {};
|
||||
const recommendationSet = {};
|
||||
let allWordsInAllArticles = [];
|
||||
|
||||
for (const wordList of corpus) {
|
||||
allWordsInAllArticles = [
|
||||
...new Set(allWordsInAllArticles.concat(wordList)),
|
||||
];
|
||||
}
|
||||
|
||||
const wordLibrary = createWordLibrary(allWordsInAllArticles);
|
||||
const documentCountLibrary = JSON.parse(JSON.stringify(wordLibrary));
|
||||
|
||||
for (let i = 0; i < corpus.length; i++) {
|
||||
const articlePath = articleLibrary[i].path;
|
||||
const wordsInArticle = corpus[i];
|
||||
|
||||
const wordFrequency = calculateWordFrequency(wordLibrary, wordsInArticle);
|
||||
dataSet[articlePath] = { wordFrequency };
|
||||
|
||||
for (const word of Object.keys(wordLibrary)) {
|
||||
if (wordFrequency[word]) {
|
||||
documentCountLibrary[word]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < corpus.length; i++) {
|
||||
const articlePath = articleLibrary[i].path;
|
||||
dataSet[articlePath]["inverseDocumentFrequency"] = JSON.parse(
|
||||
JSON.stringify(wordLibrary),
|
||||
);
|
||||
dataSet[articlePath]["wordFrequency-inverseDocumentFrequency"] = JSON.parse(
|
||||
JSON.stringify(wordLibrary),
|
||||
);
|
||||
dataSet[articlePath]["wordFrequencyVector"] = [];
|
||||
for (const word of Object.keys(wordLibrary)) {
|
||||
const inverseDocumentFrequency = Math.log(
|
||||
corpus.length / (documentCountLibrary[word] + 1),
|
||||
);
|
||||
const wordFrequencyInverseDocumentFrequency =
|
||||
dataSet[articlePath]["wordFrequency"][word] * inverseDocumentFrequency;
|
||||
dataSet[articlePath]["wordFrequencyVector"].push(
|
||||
wordFrequencyInverseDocumentFrequency,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < corpus.length; i++) {
|
||||
const articlePath1 = articleLibrary[i].path;
|
||||
similaritySet[articlePath1] = {};
|
||||
for (let j = 0; j < corpus.length; j++) {
|
||||
const articlePath2 = articleLibrary[j].path;
|
||||
similaritySet[articlePath1][articlePath2] = cosineSimilarity(
|
||||
dataSet[articlePath1]["wordFrequencyVector"],
|
||||
dataSet[articlePath2]["wordFrequencyVector"],
|
||||
);
|
||||
}
|
||||
for (let j = 0; j < corpus.length; j++) {
|
||||
recommendationSet[articlePath1] = Object.keys(
|
||||
similaritySet[articlePath1],
|
||||
).sort(function (a, b) {
|
||||
return similaritySet[articlePath1][b] - similaritySet[articlePath1][a]; // Descending order
|
||||
});
|
||||
}
|
||||
const index = recommendationSet[articlePath1].indexOf(articlePath1);
|
||||
if (index > -1) {
|
||||
recommendationSet[articlePath1].splice(index, 1);
|
||||
}
|
||||
recommendationSet[articlePath1] = recommendationSet[articlePath1].slice(
|
||||
0,
|
||||
cfg.limit,
|
||||
);
|
||||
for (let j = 0; j < recommendationSet[articlePath1].length; j++) {
|
||||
const e = recommendationSet[articlePath1][j];
|
||||
recommendationSet[articlePath1][j] = articleLibrary.filter(
|
||||
(w) => w.path == e,
|
||||
)[0];
|
||||
}
|
||||
}
|
||||
hexo.locals.set("recommendationSet", function () {
|
||||
return recommendationSet;
|
||||
});
|
||||
}
|
||||
|
||||
hexo.extend.helper.register("articleRecommendationGenerator", function (post) {
|
||||
if (!post) return "";
|
||||
const cfg = hexo.theme.config.articles.recommendation;
|
||||
if (!cfg.enable) {
|
||||
return "";
|
||||
}
|
||||
for (const dir of cfg.skip_dirs) {
|
||||
if (new RegExp("^" + dir, "g").test(post.path)) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
const recommendationSet = hexo.locals.get("recommendationSet");
|
||||
const recommendedArticles = recommendationSet[post.path];
|
||||
return userInterface(recommendedArticles, cfg);
|
||||
});
|
||||
|
||||
function userInterface(recommendedArticles, cfg) {
|
||||
let html = "";
|
||||
let htmlMobile = "";
|
||||
for (const item of recommendedArticles) {
|
||||
html += itemInterface(item);
|
||||
}
|
||||
for (const itemMobile of recommendedArticles.slice(0, cfg.mobile_limit)) {
|
||||
htmlMobile += itemInterface(itemMobile);
|
||||
}
|
||||
return `
|
||||
<div class="recommended-article px-2 sm:px-6 md:px-8">
|
||||
<div class="recommended-desktop">
|
||||
<div class="recommended-article-header text-xl md:text-3xl font-bold mt-10">
|
||||
<i aria-hidden="true"></i><span>${cfg.title}</span>
|
||||
</div>
|
||||
<div class="recommended-article-group">${html}</div>
|
||||
</div>
|
||||
<div class="recommended-mobile">
|
||||
<div class="recommended-article-header text-xl md:text-3xl font-bold mt-10">
|
||||
<i aria-hidden="true"></i><span>${cfg.title}</span>
|
||||
</div>
|
||||
<div class="recommended-article-group">${htmlMobile}</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function itemInterface(item) {
|
||||
return `<a class="recommended-article-item" href="${
|
||||
hexo.config.root + item.path
|
||||
}" title="${item.title}" rel="bookmark">
|
||||
<img src="${item.headimg}" alt="${item.title}" class="!max-w-none">
|
||||
<span class="title">${item.title}</span>
|
||||
</a>`;
|
||||
}
|
||||
251
node_modules/hexo-theme-redefine/scripts/helpers/theme-helpers.js
generated
vendored
Executable file
251
node_modules/hexo-theme-redefine/scripts/helpers/theme-helpers.js
generated
vendored
Executable file
@@ -0,0 +1,251 @@
|
||||
/* main hexo */
|
||||
|
||||
"use strict";
|
||||
|
||||
const url = require("url");
|
||||
const { version } = require("../../package.json");
|
||||
const themeVersion = version;
|
||||
|
||||
hexo.extend.helper.register("isHomePagePagination", function (pagePath, route) {
|
||||
if (pagePath.length > 5 && route === "/") {
|
||||
return pagePath.slice(0, 5) === "page/";
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/* code block language display */
|
||||
hexo.extend.filter.register("after_post_render", function (data) {
|
||||
// Only process if not already processed
|
||||
if (data._processedHighlight) return data;
|
||||
|
||||
// Updated pattern to include numbers and other special characters
|
||||
const pattern = /<figure class="highlight ([^"]+)">([\s\S]*?)<\/figure>/g;
|
||||
data.content = data.content.replace(pattern, function (match, p1, p2) {
|
||||
// If already has code-container anywhere in the match, return unchanged
|
||||
if (match.includes('code-container')) {
|
||||
return match;
|
||||
}
|
||||
|
||||
let language = p1 || "code";
|
||||
if (language === "plain") {
|
||||
language = "code";
|
||||
}
|
||||
|
||||
return '<div class="code-container" data-rel="' +
|
||||
language.charAt(0).toUpperCase() +
|
||||
language.slice(1) +
|
||||
'">' +
|
||||
match.replace(
|
||||
'<figure class="highlight ',
|
||||
'<figure class="iseeu highlight '
|
||||
) +
|
||||
"</div>";
|
||||
});
|
||||
|
||||
// Mark as processed
|
||||
data._processedHighlight = true;
|
||||
return data;
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("createNewArchivePosts", function (posts) {
|
||||
const postList = [],
|
||||
postYearList = [];
|
||||
posts.forEach((post) => postYearList.push(post.date.year()));
|
||||
Array.from(new Set(postYearList)).forEach((year) => {
|
||||
postList.push({
|
||||
year: year,
|
||||
postList: [],
|
||||
});
|
||||
});
|
||||
postList.sort((a, b) => b.year - a.year);
|
||||
postList.forEach((item) => {
|
||||
posts.forEach(
|
||||
(post) => item.year === post.date.year() && item.postList.push(post),
|
||||
);
|
||||
});
|
||||
postList.forEach((item) =>
|
||||
item.postList.sort((a, b) => b.date.unix() - a.date.unix()),
|
||||
);
|
||||
return postList;
|
||||
});
|
||||
|
||||
hexo.extend.helper.register(
|
||||
"getAuthorLabel",
|
||||
function (postCount, isAuto, labelList) {
|
||||
let level = Math.floor(Math.log2(postCount));
|
||||
level = level < 2 ? 1 : level - 1;
|
||||
|
||||
if (isAuto === false && Array.isArray(labelList) && labelList.length > 0) {
|
||||
return level > labelList.length
|
||||
? labelList[labelList.length - 1]
|
||||
: labelList[level - 1];
|
||||
} else {
|
||||
return `Lv${level}`;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
hexo.extend.helper.register("getPostUrl", function (rootUrl, path) {
|
||||
if (rootUrl) {
|
||||
let { href } = new URL(rootUrl);
|
||||
if (href.substring(href.length - 1) !== "/") {
|
||||
href = href + "/";
|
||||
}
|
||||
return href + path;
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("renderJS", function (path, options = {}) {
|
||||
const _js = hexo.extend.helper.get("js").bind(hexo);
|
||||
const { module = false, async = false, swupReload = false } = options;
|
||||
|
||||
if (Array.isArray(path)) {
|
||||
path = path.map((p) => "js/build/" + p);
|
||||
} else {
|
||||
path = "js/build/" + path;
|
||||
}
|
||||
|
||||
const cdnProviders = {
|
||||
zstatic:
|
||||
"https://s4.zstatic.net/ajax/libs/hexo-theme-redefine/:version/:path",
|
||||
cdnjs:
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/hexo-theme-redefine/:version/:path",
|
||||
unpkg: "https://unpkg.com/hexo-theme-redefine@:version/source/:path",
|
||||
jsdelivr:
|
||||
"https://cdn.jsdelivr.net/npm/hexo-theme-redefine@:version/source/:path",
|
||||
aliyun:
|
||||
"https://evan.beee.top/projects/hexo-theme-redefine@:version/source/:path",
|
||||
npmmirror:
|
||||
"https://registry.npmmirror.com/hexo-theme-redefine/:version/files/source/:path",
|
||||
custom: this.theme.cdn.custom_url,
|
||||
};
|
||||
|
||||
const cdnPathHandle = (path) => {
|
||||
const cdnBase =
|
||||
cdnProviders[this.theme.cdn.provider] || cdnProviders.npmmirror;
|
||||
let scriptTag;
|
||||
|
||||
const typeAttr = module ? 'type="module"' : "";
|
||||
// const asyncAttr = async ? "async" : "";
|
||||
const swupAttr = swupReload ? "data-swup-reload-script" : "";
|
||||
|
||||
if (this.theme.cdn.enable) {
|
||||
if (this.theme.cdn.provider === "custom") {
|
||||
const customUrl = cdnBase
|
||||
.replace(":version", themeVersion)
|
||||
.replace(":path", path);
|
||||
scriptTag = `<script ${typeAttr} src="${
|
||||
this.theme.cdn.enable ? customUrl : _js({ src: path })
|
||||
}" ${swupAttr}></script>`;
|
||||
} else {
|
||||
scriptTag = `<script ${typeAttr} src="${cdnBase
|
||||
.replace(":version", themeVersion)
|
||||
.replace(":path", path)}" ${swupAttr}></script>`;
|
||||
}
|
||||
} else {
|
||||
scriptTag = _js({
|
||||
src: path,
|
||||
type: module ? "module" : undefined,
|
||||
"data-swup-reload-script": swupReload ? "" : undefined,
|
||||
// async: async,
|
||||
});
|
||||
}
|
||||
|
||||
return scriptTag;
|
||||
};
|
||||
|
||||
let renderedScripts = "";
|
||||
|
||||
if (Array.isArray(path)) {
|
||||
renderedScripts = path.map(cdnPathHandle).join("");
|
||||
} else {
|
||||
renderedScripts = cdnPathHandle(path);
|
||||
}
|
||||
|
||||
return renderedScripts;
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("renderCSS", function (path) {
|
||||
const _css = hexo.extend.helper.get("css").bind(hexo);
|
||||
|
||||
const cdnProviders = {
|
||||
zstatic:
|
||||
"https://s4.zstatic.net/ajax/libs/hexo-theme-redefine/:version/:path",
|
||||
cdnjs:
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/hexo-theme-redefine/:version/:path",
|
||||
unpkg: "https://unpkg.com/hexo-theme-redefine@:version/source/:path",
|
||||
jsdelivr:
|
||||
"https://cdn.jsdelivr.net/npm/hexo-theme-redefine@:version/source/:path",
|
||||
aliyun:
|
||||
"https://evan.beee.top/projects/hexo-theme-redefine@:version/source/:path",
|
||||
npmmirror:
|
||||
"https://registry.npmmirror.com/hexo-theme-redefine/:version/files/source/:path",
|
||||
custom: this.theme.cdn.custom_url,
|
||||
};
|
||||
|
||||
const cdnPathHandle = (path) => {
|
||||
const cdnBase =
|
||||
cdnProviders[this.theme.cdn.provider] || cdnProviders.npmmirror;
|
||||
let cssLink;
|
||||
|
||||
if (this.theme.cdn.enable) {
|
||||
if (this.theme.cdn.provider === "custom") {
|
||||
const customUrl = cdnBase
|
||||
.replace(":version", themeVersion)
|
||||
.replace(":path", path);
|
||||
cssLink = `<link rel="stylesheet" href="${customUrl}">`;
|
||||
} else {
|
||||
cssLink = `<link rel="stylesheet" href="${cdnBase
|
||||
.replace(":version", themeVersion)
|
||||
.replace(":path", path)}">`;
|
||||
}
|
||||
} else {
|
||||
cssLink = _css(path);
|
||||
}
|
||||
|
||||
return cssLink;
|
||||
};
|
||||
|
||||
if (Array.isArray(path)) {
|
||||
return path.map(cdnPathHandle).join("");
|
||||
} else {
|
||||
return cdnPathHandle(path);
|
||||
}
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("getThemeVersion", function () {
|
||||
return themeVersion;
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("checkDeprecation", function (condition, id, message) {
|
||||
if (condition) {
|
||||
// Use Set to ensure each warning is only logged once per Hexo process
|
||||
if (!global.deprecationWarnings) {
|
||||
global.deprecationWarnings = new Set();
|
||||
}
|
||||
|
||||
if (!global.deprecationWarnings.has(id)) {
|
||||
hexo.log.warn(`${message}`);
|
||||
global.deprecationWarnings.add(id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
hexo.extend.helper.register("configOptions", function (obj, indent = ' ') {
|
||||
if (!obj || typeof obj !== 'object') return '';
|
||||
|
||||
return Object.entries(obj)
|
||||
.filter(([key, value]) => value !== undefined && value !== null && value !== '')
|
||||
.map(([key, value]) => {
|
||||
if (typeof value === 'string') {
|
||||
return `${indent}${key}: '${value}',`;
|
||||
}
|
||||
return `${indent}${key}: ${value},`;
|
||||
})
|
||||
.join('\n');
|
||||
});
|
||||
33
node_modules/hexo-theme-redefine/scripts/helpers/waline-helpers.js
generated
vendored
Normal file
33
node_modules/hexo-theme-redefine/scripts/helpers/waline-helpers.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
hexo.extend.helper.register('waline_reaction_config', function(reactionConfig) {
|
||||
if (Array.isArray(reactionConfig) && reactionConfig.length) {
|
||||
return `[${reactionConfig.map(item => `'${item}'`).join(', ')}]`;
|
||||
} else {
|
||||
return Boolean(reactionConfig);
|
||||
}
|
||||
});
|
||||
|
||||
hexo.extend.helper.register('waline_array_config', function(arrayConfig) {
|
||||
if (Array.isArray(arrayConfig) && arrayConfig.length) {
|
||||
return `[${arrayConfig.map(item => `'${item}'`).join(', ')}]`;
|
||||
}
|
||||
return '[]';
|
||||
});
|
||||
|
||||
hexo.extend.helper.register('waline_config_options', function(config) {
|
||||
if (!config || typeof config !== 'object') return '';
|
||||
|
||||
const formatValue = (value) => {
|
||||
if (typeof value === 'string') {
|
||||
return `'${value}'`;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return `[${value.map(item => typeof item === 'string' ? `'${item}'` : item).join(', ')}]`;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
return Object.entries(config)
|
||||
.filter(([key, value]) => value !== undefined && value !== null && value !== '')
|
||||
.map(([key, value]) => ` ${key}: ${formatValue(value)},`)
|
||||
.join('\n');
|
||||
});
|
||||
85
node_modules/hexo-theme-redefine/scripts/modules/btn.js
generated
vendored
Executable file
85
node_modules/hexo-theme-redefine/scripts/modules/btn.js
generated
vendored
Executable file
@@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Single Button module for Hexo theme Redefine
|
||||
* Creates standalone button elements
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a single button
|
||||
*
|
||||
* @param {Array} args - Button arguments (class, text, url, icon)
|
||||
* @returns {String} HTML for a single button
|
||||
*/
|
||||
function postBtn(args) {
|
||||
// Parse arguments - support both '::' and ',' as separators
|
||||
let parsedArgs;
|
||||
const argsStr = args.join(" ");
|
||||
|
||||
if (argsStr.includes("::")) {
|
||||
parsedArgs = argsStr.split("::");
|
||||
} else {
|
||||
parsedArgs = argsStr.split(",");
|
||||
}
|
||||
|
||||
// Default values
|
||||
let cls = "";
|
||||
let text = "";
|
||||
let url = "";
|
||||
let icon = "";
|
||||
|
||||
// Parse arguments based on count
|
||||
switch(parsedArgs.length) {
|
||||
case 4: // class, text, url, icon
|
||||
cls = parsedArgs[0];
|
||||
text = parsedArgs[1];
|
||||
url = parsedArgs[2];
|
||||
icon = parsedArgs[3];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Check if third arg is an icon (contains fa-)
|
||||
if (parsedArgs[2].includes("fa-")) {
|
||||
// text, url, icon
|
||||
text = parsedArgs[0];
|
||||
url = parsedArgs[1];
|
||||
icon = parsedArgs[2];
|
||||
} else {
|
||||
// class, text, url
|
||||
cls = parsedArgs[0];
|
||||
text = parsedArgs[1];
|
||||
url = parsedArgs[2];
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // text, url
|
||||
text = parsedArgs[0];
|
||||
url = parsedArgs[1];
|
||||
break;
|
||||
|
||||
case 1: // text only
|
||||
text = parsedArgs[0];
|
||||
break;
|
||||
}
|
||||
|
||||
// Clean up values
|
||||
cls = cls.trim();
|
||||
icon = icon.trim();
|
||||
text = text.trim();
|
||||
url = url.trim();
|
||||
|
||||
// Build attributes
|
||||
const hrefAttr = url ? `href='${url}'` : '';
|
||||
const classAttr = cls ? `${cls}` : '';
|
||||
|
||||
// Build button HTML
|
||||
if (icon) {
|
||||
return `<a class="button ${classAttr}" ${hrefAttr} title='${text}'><i class='${icon}'></i> ${text}</a>`;
|
||||
}
|
||||
|
||||
return `<a class="button ${classAttr}" ${hrefAttr} title='${text}'>${text}</a>`;
|
||||
}
|
||||
|
||||
// Register Hexo tags
|
||||
hexo.extend.tag.register("btn", postBtn);
|
||||
hexo.extend.tag.register("button", postBtn);
|
||||
71
node_modules/hexo-theme-redefine/scripts/modules/btns.js
generated
vendored
Executable file
71
node_modules/hexo-theme-redefine/scripts/modules/btns.js
generated
vendored
Executable file
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Buttons module for Hexo theme Redefine
|
||||
* Creates button containers and button elements
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a buttons container
|
||||
*
|
||||
* @param {Array} args - Class names for the container
|
||||
* @param {String} content - Button content (cells)
|
||||
* @returns {String} HTML for the buttons container
|
||||
*/
|
||||
function postBtns(args, content) {
|
||||
const classes = args.join(' ');
|
||||
return `<div class="btns ${classes}">
|
||||
${content}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single button cell
|
||||
*
|
||||
* @param {Array} args - Button properties (text, url, icon/image)
|
||||
* @returns {String} HTML for a single button
|
||||
*/
|
||||
function postCell(args, content) {
|
||||
// Parse arguments - support both '::' and ',' as separators
|
||||
let parsedArgs;
|
||||
const argsStr = args.join(' ');
|
||||
|
||||
if (argsStr.includes('::')) {
|
||||
parsedArgs = argsStr.split('::');
|
||||
} else {
|
||||
parsedArgs = argsStr.split(',');
|
||||
}
|
||||
|
||||
// Extract button properties
|
||||
const text = (parsedArgs[0] || '').trim();
|
||||
const url = (parsedArgs[1] || '').trim();
|
||||
const buttonClasses = ['button'];
|
||||
|
||||
// Handle URL
|
||||
const hrefAttr = url ? `href='${url}'` : '';
|
||||
|
||||
// Handle icon or image
|
||||
let iconOrImage = '';
|
||||
|
||||
if (parsedArgs.length > 2) {
|
||||
const iconOrImgSrc = parsedArgs[2].trim();
|
||||
|
||||
// Check if it's a FontAwesome icon
|
||||
if (iconOrImgSrc.includes('fa-')) {
|
||||
iconOrImage = `<i class='${iconOrImgSrc}'></i> `;
|
||||
} else {
|
||||
// Use specified image or default
|
||||
const imgSrc = iconOrImgSrc || hexo.theme.config.default.image;
|
||||
iconOrImage = `<img src='${imgSrc}'>`;
|
||||
}
|
||||
}
|
||||
|
||||
// Return complete button HTML
|
||||
return `<a class="${buttonClasses.join(' ')}" ${hrefAttr} title='${text}'>${iconOrImage}${text}</a>`;
|
||||
}
|
||||
|
||||
// Register Hexo tags
|
||||
hexo.extend.tag.register('btns', postBtns, {ends: true});
|
||||
hexo.extend.tag.register('buttons', postBtns, {ends: true});
|
||||
hexo.extend.tag.register('cell', postCell);
|
||||
|
||||
34
node_modules/hexo-theme-redefine/scripts/modules/folding.js
generated
vendored
Executable file
34
node_modules/hexo-theme-redefine/scripts/modules/folding.js
generated
vendored
Executable file
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
const postFolding = (args, content) => {
|
||||
// Parse arguments - support both '::' and ',' as delimiters
|
||||
const delimiter = args.join(' ').includes('::') ? '::' : ',';
|
||||
const [style, title = ''] = args.join(' ').split(delimiter).map(arg => arg.trim());
|
||||
|
||||
// Render markdown content
|
||||
const renderedContent = hexo.render.renderSync({
|
||||
text: content,
|
||||
engine: 'markdown'
|
||||
}).split('\n').join('');
|
||||
|
||||
// Replace heading tags with paragraph tags that have heading classes
|
||||
const processedContent = renderedContent.replace(
|
||||
/<(h[1-6])>/g,
|
||||
(_, tag) => `<p class='${tag}'>`
|
||||
).replace(
|
||||
/<\/(h[1-6])>/g,
|
||||
() => '</p>'
|
||||
);
|
||||
|
||||
// Build the HTML with or without custom style
|
||||
const styleAttr = style ? ` class="${style}"` : '';
|
||||
|
||||
return `<details${styleAttr} data-header-exclude>
|
||||
<summary><i class="fa-solid fa-chevron-right"></i>${title} </summary>
|
||||
<div class='content'>
|
||||
${processedContent}
|
||||
</div>
|
||||
</details>`;
|
||||
};
|
||||
|
||||
hexo.extend.tag.register('folding', postFolding, {ends: true});
|
||||
72
node_modules/hexo-theme-redefine/scripts/modules/note-large.js
generated
vendored
Normal file
72
node_modules/hexo-theme-redefine/scripts/modules/note-large.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
function postNoteLarge(args, content) {
|
||||
if (args.length === 0) {
|
||||
args.push("default", "Warning");
|
||||
}
|
||||
|
||||
let icon = "";
|
||||
let title = "";
|
||||
|
||||
// Extract color from args[0]
|
||||
const color = args[0];
|
||||
|
||||
// Process all arguments after color to build icon and title
|
||||
const remainingArgs = args.slice(1);
|
||||
|
||||
// Find all fa- prefixed arguments
|
||||
const faArgs = [];
|
||||
const faIndices = [];
|
||||
|
||||
remainingArgs.forEach((arg, index) => {
|
||||
if (arg && arg.startsWith('fa-')) {
|
||||
faArgs.push(arg);
|
||||
faIndices.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle FontAwesome icons based on how many fa- args we found
|
||||
if (faArgs.length === 2) {
|
||||
// Two fa- args: first is style, second is icon
|
||||
icon = `<i class="notel-icon ${faArgs[0]} ${faArgs[1]}"></i>`;
|
||||
|
||||
// Remove both FA args (remove higher index first to preserve positions)
|
||||
remainingArgs.splice(faIndices[1], 1);
|
||||
remainingArgs.splice(faIndices[0], 1);
|
||||
} else if (faArgs.length === 1) {
|
||||
// One fa- arg: it's the icon, default to fa-solid
|
||||
icon = `<i class="notel-icon fa-solid ${faArgs[0]}"></i>`;
|
||||
|
||||
// Remove the FA arg
|
||||
remainingArgs.splice(faIndices[0], 1);
|
||||
}
|
||||
|
||||
// Join all remaining args as the title
|
||||
title = remainingArgs.join(" ");
|
||||
|
||||
// If no title was provided, set a default
|
||||
if (!title) {
|
||||
title = "Note";
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="note-large ${color}">
|
||||
<div class="notel-title rounded-t-lg p-3 font-bold text-lg flex flex-row gap-2 items-center">
|
||||
${icon}${hexo.render.renderSync({
|
||||
text: title,
|
||||
engine: "markdown",
|
||||
})}
|
||||
</div>
|
||||
<div class="notel-content">
|
||||
${hexo.render.renderSync({
|
||||
text: content,
|
||||
engine: "markdown",
|
||||
})}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register("noteL", postNoteLarge, { ends: true });
|
||||
hexo.extend.tag.register("notel", postNoteLarge, { ends: true });
|
||||
hexo.extend.tag.register("notelarge", postNoteLarge, { ends: true });
|
||||
hexo.extend.tag.register("notel-large", postNoteLarge, { ends: true });
|
||||
hexo.extend.tag.register("notes-large", postNoteLarge, { ends: true });
|
||||
hexo.extend.tag.register("subwarning", postNoteLarge, { ends: true });
|
||||
64
node_modules/hexo-theme-redefine/scripts/modules/note.js
generated
vendored
Normal file
64
node_modules/hexo-theme-redefine/scripts/modules/note.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
function postNote(args, content) {
|
||||
if (args.length === 0) {
|
||||
args.push("default");
|
||||
}
|
||||
|
||||
let icon = "";
|
||||
|
||||
// Extract style classes from all args except potential icon classes
|
||||
let classes = [];
|
||||
const remainingArgs = [...args]; // Copy args array
|
||||
|
||||
// Add first arg as main class
|
||||
if (remainingArgs.length > 0) {
|
||||
classes.push(remainingArgs[0]);
|
||||
remainingArgs.shift();
|
||||
}
|
||||
|
||||
// Find all fa- prefixed arguments
|
||||
const faArgs = [];
|
||||
const faIndices = [];
|
||||
|
||||
remainingArgs.forEach((arg, index) => {
|
||||
if (arg && arg.startsWith('fa-')) {
|
||||
faArgs.push(arg);
|
||||
faIndices.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle FontAwesome icons based on how many fa- args we found
|
||||
if (faArgs.length === 2) {
|
||||
// Two fa- args: first is style, second is icon
|
||||
icon = `<i class="note-icon ${faArgs[0]} ${faArgs[1]}"></i>`;
|
||||
|
||||
// Remove both FA args (remove higher index first to preserve positions)
|
||||
remainingArgs.splice(faIndices[1], 1);
|
||||
remainingArgs.splice(faIndices[0], 1);
|
||||
} else if (faArgs.length === 1) {
|
||||
// One fa- arg: it's the icon, default to fa-solid
|
||||
icon = `<i class="note-icon fa-solid ${faArgs[0]}"></i>`;
|
||||
|
||||
// Remove the FA arg
|
||||
remainingArgs.splice(faIndices[0], 1);
|
||||
}
|
||||
|
||||
// Add any remaining args as additional classes
|
||||
classes = classes.concat(remainingArgs);
|
||||
|
||||
// Add icon-padding class if icon exists
|
||||
if (icon) {
|
||||
classes.push("icon-padding");
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="note p-4 mb-4 rounded-small ${classes.join(" ")}">
|
||||
${icon}${hexo.render.renderSync({
|
||||
text: content,
|
||||
engine: "markdown",
|
||||
})}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register("note", postNote, { ends: true });
|
||||
hexo.extend.tag.register("notes", postNote, { ends: true });
|
||||
hexo.extend.tag.register("subnote", postNote, { ends: true });
|
||||
99
node_modules/hexo-theme-redefine/scripts/modules/tabs.js
generated
vendored
Executable file
99
node_modules/hexo-theme-redefine/scripts/modules/tabs.js
generated
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Module: Tabs
|
||||
* hexo-theme-redefine
|
||||
* By Evan
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const TAB_BLOCK_REGEX = /<!--\s*tab (.*?)\s*-->\n([\w\W\s\S]*?)<!--\s*endtab\s*-->/g;
|
||||
const APLAYER_TAG_REGEX = /\<div.*class=\"aplayer aplayer-tag-marker\"(.|\n)*\<\/script\>/g;
|
||||
const FANCYBOX_TAG_REGEX = /\<div.*galleryFlag(.|\n)*\<\/span\>\<\/div\>\<\/div\>/g;
|
||||
|
||||
function parseArgs(args) {
|
||||
if (/::/g.test(args)) {
|
||||
return args.join(' ').split('::');
|
||||
} else {
|
||||
return args.join(' ').split(',');
|
||||
}
|
||||
}
|
||||
|
||||
function extractMatches(content) {
|
||||
const matches = [];
|
||||
let match;
|
||||
|
||||
while ((match = TAB_BLOCK_REGEX.exec(content)) !== null) {
|
||||
matches.push(match[1]);
|
||||
matches.push(match[2]);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
function processAplayerTag(content) {
|
||||
let aplayerTag = 0;
|
||||
|
||||
if (/class="aplayer aplayer-tag-marker"/g.test(content)) {
|
||||
aplayerTag = APLAYER_TAG_REGEX.exec(content)[0];
|
||||
content = content.replace(APLAYER_TAG_REGEX, "@aplayerTag@");
|
||||
}
|
||||
|
||||
return { content, aplayerTag };
|
||||
}
|
||||
|
||||
function processFancyboxTag(content) {
|
||||
let fancyboxTag = 0;
|
||||
|
||||
if (/galleryFlag/g.test(content)) {
|
||||
fancyboxTag = FANCYBOX_TAG_REGEX.exec(content)[0];
|
||||
content = content.replace(FANCYBOX_TAG_REGEX, "@fancyboxTag@");
|
||||
}
|
||||
|
||||
return { content, fancyboxTag };
|
||||
}
|
||||
|
||||
function buildTabNavAndContent(matches, tabName, tabActive) {
|
||||
let tabNav = '';
|
||||
let tabContent = '';
|
||||
|
||||
for (let i = 0; i < matches.length; i += 2) {
|
||||
const tabParameters = matches[i].split('@');
|
||||
const postContent = matches[i + 1];
|
||||
const tabCaption = tabParameters[0] || '';
|
||||
const tabIcon = tabParameters[1] || '';
|
||||
const tabHref = (tabName + ' ' + (i / 2 + 1)).toLowerCase().split(' ').join('-');
|
||||
|
||||
const { content: contentWithAplayerTag, aplayerTag } = processAplayerTag(postContent);
|
||||
const { content: contentWithFancyboxTag, fancyboxTag } = processFancyboxTag(contentWithAplayerTag);
|
||||
|
||||
const renderedContent = hexo.render.renderSync({ text: contentWithFancyboxTag, engine: 'markdown' }).trim();
|
||||
|
||||
const finalContent = renderedContent.replace(/\<pre\>\<code\>.*@aplayerTag@.*\<\/code><\/pre>/, aplayerTag)
|
||||
.replace(/.*@fancyboxTag@.*/, fancyboxTag);
|
||||
|
||||
const isActive = (tabActive > 0 && tabActive === (i / 2 + 1)) || (tabActive === 0 && i === 0) ? ' active' : '';
|
||||
|
||||
tabNav += `<li class="tab${isActive}"><a class="#${tabHref}">${tabIcon + tabCaption.trim()}</a></li>`;
|
||||
tabContent += `<div class="tab-pane${isActive}" id="${tabHref}">${finalContent}</div>`;
|
||||
}
|
||||
|
||||
return { tabNav, tabContent };
|
||||
}
|
||||
|
||||
function postTabs(args, content) {
|
||||
const [tabName, tabActive] = parseArgs(args);
|
||||
const activeTabIndex = Number(tabActive) || 0;
|
||||
|
||||
!tabName && hexo.log.warn('Tabs block must have unique name!');
|
||||
|
||||
const matches = extractMatches(content);
|
||||
const { tabNav, tabContent } = buildTabNavAndContent(matches, tabName, activeTabIndex);
|
||||
|
||||
const finalTabNav = `<ul class="nav-tabs">${tabNav}</ul>`;
|
||||
const finalTabContent = `<div class="tab-content">${tabContent}</div>`;
|
||||
return `<div class="tabs" id="tab-${tabName.toLowerCase().split(' ').join('-')}">${finalTabNav + finalTabContent}</div>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('tabs', postTabs, { ends: true });
|
||||
hexo.extend.tag.register('subtabs', postTabs, { ends: true });
|
||||
hexo.extend.tag.register('subsubtabs', postTabs, { ends: true });
|
||||
Reference in New Issue
Block a user