mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-10 08:58:15 +08:00
♻️ 公告解析重构完成
This commit is contained in:
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* @file assets/css/post-parser.css
|
||||
* @description 游戏公告解析 css
|
||||
* @since Beta v0.5.0
|
||||
*/
|
||||
|
||||
.anno-body {
|
||||
width: 800px;
|
||||
margin: 0 auto;
|
||||
font-family: var(--font-text);
|
||||
}
|
||||
|
||||
.anno-title,
|
||||
.anno-subtitle {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.anno-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.anno-subtitle {
|
||||
font-size: 16px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.anno-img {
|
||||
width: 800px;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10px;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.anno-content {
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.anno-content :deep(a) {
|
||||
color: #00c3ff;
|
||||
cursor: pointer;
|
||||
text-decoration: underline solid #00c3ff;
|
||||
text-underline-position: under;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
.anno-content :deep(p) {
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.anno-content :deep(details) {
|
||||
padding: 10px;
|
||||
border: 1px var(--common-shadow-2) solid;
|
||||
border-radius: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.anno-content :deep(details) div {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.anno-content :deep(details) ::marker {
|
||||
color: var(--tgc-pink-1);
|
||||
content: "✧";
|
||||
}
|
||||
|
||||
.anno-content :deep(ol) {
|
||||
list-style: "✧";
|
||||
}
|
||||
|
||||
.anno-content :deep(td) {
|
||||
padding-left: 10px;
|
||||
line-height: 2;
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import TpText from "../post/tp-text.vue";
|
||||
import TpTexts from "../post/tp-texts.vue";
|
||||
import TpUnknown from "../post/tp-unknown.vue";
|
||||
|
||||
import TaTable from "./ta-table.vue";
|
||||
|
||||
interface TaParserProps {
|
||||
data: TGApp.BBS.Announcement.ContentItem;
|
||||
}
|
||||
@@ -25,6 +27,7 @@ function getTaName(ta: TGApp.Plugins.Mys.SctPost.Base) {
|
||||
if (typeof ta.insert === "string") return TpText;
|
||||
if ("image" in ta.insert) return TpImage;
|
||||
if ("backup_text" in ta.insert) return TpBackupText;
|
||||
if ("table" in ta.insert) return TaTable;
|
||||
return TpUnknown;
|
||||
}
|
||||
</script>
|
||||
|
||||
16
src/components/anno/ta-table.vue
Normal file
16
src/components/anno/ta-table.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div v-html="props.data.insert.table"></div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
interface TaTableType {
|
||||
insert: {
|
||||
table: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface TaTableProps {
|
||||
data: TaTableType;
|
||||
}
|
||||
|
||||
const props = defineProps<TaTableProps>();
|
||||
</script>
|
||||
@@ -47,7 +47,6 @@ const props = defineProps<TpTextProps>();
|
||||
const mode = ref<string>("text");
|
||||
const localEmojis = ref(localStorage.getItem("emojis"));
|
||||
const emojis = ref<TpText[]>([]);
|
||||
const router = useRouter();
|
||||
|
||||
console.log("tpText", JSON.stringify(props.data.insert), toRaw(props.data)?.attributes);
|
||||
|
||||
@@ -100,7 +99,7 @@ async function toLink() {
|
||||
const link = props.data.attributes.link;
|
||||
const isPost = await parsePost(link);
|
||||
if (isPost !== false) {
|
||||
await router.push({
|
||||
await useRouter().push({
|
||||
name: "帖子详情",
|
||||
params: {
|
||||
post_id: isPost,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import { StyleValue } from "vue";
|
||||
import type { Component } from "vue";
|
||||
|
||||
import TpImage from "./tp-image.vue";
|
||||
import TpMention, { type TpMention as TpMentionType } from "./tp-mention.vue";
|
||||
import TpText, { type TpText as TpTextType } from "./tp-text.vue";
|
||||
|
||||
@@ -29,6 +30,9 @@ function getComp(text: TpTextType | TpMentionType): Component {
|
||||
if (typeof text.insert === "string") {
|
||||
return TpText;
|
||||
}
|
||||
if ("image" in text.insert) {
|
||||
return TpImage;
|
||||
}
|
||||
return TpMention;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<!-- todo 优化显示样式 -->
|
||||
<template>
|
||||
<TSwitchTheme />
|
||||
<TShareBtn
|
||||
@@ -17,7 +15,6 @@
|
||||
<div class="anno-subtitle">
|
||||
{{ parseText(annoData.subtitle) }}
|
||||
</div>
|
||||
<!-- <div class="anno-content" v-html="annoHtml" />-->
|
||||
<div class="anno-content">
|
||||
<TaParser :data="annoData" />
|
||||
</div>
|
||||
@@ -137,5 +134,29 @@ onUnmounted(() => {
|
||||
font-family: var(--font-title);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.anno-body {
|
||||
width: 800px;
|
||||
margin: 0 auto;
|
||||
font-family: var(--font-text);
|
||||
}
|
||||
|
||||
.anno-title,
|
||||
.anno-subtitle {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.anno-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.anno-subtitle {
|
||||
font-size: 16px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.anno-content {
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
||||
<style lang="css" src="../assets/css/anno-parser.css" scoped></style>
|
||||
|
||||
@@ -6,13 +6,11 @@
|
||||
|
||||
import { getAnnoCard } from "./getAnnoCard.js";
|
||||
import { getRequestHeader } from "./getRequestHeader.js";
|
||||
import { parseAnnoContent } from "./parseAnno.js";
|
||||
import { getServerByUid, transCookie } from "./tools.js";
|
||||
|
||||
const TGUtils = {
|
||||
Anno: {
|
||||
getCard: getAnnoCard,
|
||||
parseContent: parseAnnoContent,
|
||||
},
|
||||
User: {
|
||||
getHeader: getRequestHeader,
|
||||
|
||||
@@ -4,8 +4,85 @@
|
||||
* @since Beta v0.5.3
|
||||
*/
|
||||
|
||||
import { h, render } from "vue";
|
||||
|
||||
import TpText from "../../components/post/tp-text.vue";
|
||||
|
||||
import { decodeRegExp } from "./tools.js";
|
||||
|
||||
/**
|
||||
* @description 预处理p
|
||||
* @since Beta v0.5.2
|
||||
* @param {HTMLParagraphElement} p p 元素
|
||||
* @returns {HTMLParagraphElement} 解析后的 p 元素
|
||||
*/
|
||||
function handleAnnoP(p: HTMLParagraphElement): HTMLParagraphElement {
|
||||
if (p.children.length === 0) {
|
||||
p.innerHTML = decodeRegExp(p.innerHTML);
|
||||
} else {
|
||||
p.querySelectorAll("*").forEach((child) => {
|
||||
child.innerHTML = decodeRegExp(child.innerHTML);
|
||||
child.querySelectorAll("span").forEach((span) => handleAnnoSpan(span));
|
||||
});
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 预处理 span
|
||||
* @since Beta v0.4.4
|
||||
* @param {HTMLSpanElement} span span 元素
|
||||
* @returns {HTMLSpanElement} 解析后的 span 元素
|
||||
*/
|
||||
function handleAnnoSpan(span: HTMLSpanElement): HTMLSpanElement {
|
||||
if (span.style.fontSize) {
|
||||
span.style.fontSize = "";
|
||||
}
|
||||
if (span.children.length === 0) {
|
||||
span.innerHTML = decodeRegExp(span.innerHTML);
|
||||
} else {
|
||||
span.querySelectorAll("*").forEach((child) => {
|
||||
if (child.children.length === 0) {
|
||||
child.innerHTML = decodeRegExp(child.innerHTML);
|
||||
}
|
||||
if (child.tagName === "T") {
|
||||
child.outerHTML = child.innerHTML;
|
||||
}
|
||||
});
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 预处理table
|
||||
* @since Beta v0.4.7
|
||||
* @param {HTMLTableElement} table table 元素
|
||||
* @returns {HTMLTableElement} 解析后的 table 元素
|
||||
*/
|
||||
function handleAnnoTable(table: HTMLTableElement): HTMLTableElement {
|
||||
table.style.borderColor = "var(--common-shadow-2)";
|
||||
table.querySelectorAll("colgroup").forEach((colgroup) => colgroup.remove());
|
||||
table.querySelectorAll("td").forEach((td) => {
|
||||
if (td.style.backgroundColor) td.style.backgroundColor = "var(--box-bg-1)";
|
||||
td.style.textAlign = "center";
|
||||
});
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 预处理公告内容
|
||||
* @since Beta v0.4.4
|
||||
* @param {string} data 游戏内公告数据
|
||||
* @returns {string} 解析后的数据
|
||||
*/
|
||||
export function handleAnnoContent(data: string): string {
|
||||
const htmlBase = new DOMParser().parseFromString(data, "text/html");
|
||||
htmlBase.querySelectorAll("p").forEach((p) => handleAnnoP(p));
|
||||
htmlBase.querySelectorAll("span").forEach((span) => handleAnnoSpan(span));
|
||||
htmlBase.querySelectorAll("table").forEach((table) => handleAnnoTable(table));
|
||||
return htmlBase.body.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析公告内容,转换为结构化数据
|
||||
* @since Beta v0.5.3
|
||||
@@ -16,14 +93,10 @@ export function parseAnnoContent(
|
||||
anno: TGApp.BBS.Announcement.ContentItem,
|
||||
): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(anno.content, "text/html");
|
||||
const first = handleAnnoContent(anno.content);
|
||||
const doc = parser.parseFromString(first, "text/html");
|
||||
const children: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||
const bannerNode: TGApp.Plugins.Mys.SctPost.Base = {
|
||||
insert: {
|
||||
image: anno.banner,
|
||||
},
|
||||
};
|
||||
children.push(bannerNode);
|
||||
if (anno.banner !== "") children.push({ insert: { image: anno.banner } });
|
||||
doc.body.childNodes.forEach((child) => {
|
||||
children.push(...parseAnnoNode(child));
|
||||
});
|
||||
@@ -34,9 +107,13 @@ export function parseAnnoContent(
|
||||
* @description 解析公告节点
|
||||
* @since Beta v0.5.3
|
||||
* @param {Node} node - 节点
|
||||
* @param {Record<string, string>} attr - 属性
|
||||
* @returns {TGApp.Plugins.Mys.SctPost.Base} 结构化数据
|
||||
*/
|
||||
function parseAnnoNode(node: Node): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||
function parseAnnoNode(
|
||||
node: Node,
|
||||
attr?: Record<string, string>,
|
||||
): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||
let defaultRes: TGApp.Plugins.Mys.SctPost.Base = {
|
||||
insert: {
|
||||
tag: node.nodeName,
|
||||
@@ -48,7 +125,7 @@ function parseAnnoNode(node: Node): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||
return [defaultRes];
|
||||
}
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
return [{ insert: node.textContent }];
|
||||
return [{ insert: node.textContent, attributes: attr }];
|
||||
}
|
||||
const element = <HTMLElement>node;
|
||||
defaultRes = {
|
||||
@@ -61,42 +138,56 @@ function parseAnnoNode(node: Node): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||
},
|
||||
};
|
||||
if (element.tagName === "P") {
|
||||
return [parseAnnoParagraph(element)];
|
||||
element.innerHTML = decodeRegExp(element.innerHTML);
|
||||
return [parseAnnoParagraph(element, attr)];
|
||||
}
|
||||
if (element.tagName === "OL" || element.tagName === "LI" || element.tagName === "UL") {
|
||||
const res: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||
Array.from(element.children).forEach((child) => {
|
||||
res.push(...parseAnnoNode(child));
|
||||
res.push(...parseAnnoNode(child, attr));
|
||||
});
|
||||
return res;
|
||||
}
|
||||
if (element.tagName === "DETAILS") {
|
||||
return [parseAnnoDetails(element)];
|
||||
}
|
||||
// todo table解析
|
||||
if (element.tagName === "TABLE") {
|
||||
return [defaultRes];
|
||||
return [parseAnnoTable(element)];
|
||||
}
|
||||
if (element.tagName === "DIV") {
|
||||
if (element.childNodes.length > 1) {
|
||||
const res: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||
element.childNodes.forEach((child) => {
|
||||
res.push(...parseAnnoNode(child));
|
||||
res.push(...parseAnnoNode(child, attr));
|
||||
});
|
||||
return res;
|
||||
}
|
||||
if (element.childNodes.length === 0) return [defaultRes];
|
||||
const child = element.childNodes[0];
|
||||
if (child.nodeType !== Node.ELEMENT_NODE) return [defaultRes];
|
||||
return parseAnnoNode(child);
|
||||
return parseAnnoNode(child, attr);
|
||||
}
|
||||
if (element.tagName === "SUMMARY") {
|
||||
const p = document.createElement("p");
|
||||
p.innerHTML = element.innerHTML;
|
||||
return [parseAnnoParagraph(p)];
|
||||
return [parseAnnoParagraph(p, attr)];
|
||||
}
|
||||
if (element.tagName === "SPAN") {
|
||||
return [parseAnnoSpan(element)];
|
||||
return [parseAnnoSpan(element, attr)];
|
||||
}
|
||||
if (element.tagName === "STRONG") {
|
||||
const res: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||
element.childNodes.forEach((child) => {
|
||||
res.push(...parseAnnoNode(child, { bold: "true" }));
|
||||
});
|
||||
return res;
|
||||
}
|
||||
if (element.tagName === "T") {
|
||||
const res: TGApp.Plugins.Mys.SctPost.Base[] = [];
|
||||
element.childNodes.forEach((child) => {
|
||||
res.push(...parseAnnoNode(child, attr));
|
||||
});
|
||||
return res;
|
||||
}
|
||||
return [defaultRes];
|
||||
}
|
||||
@@ -105,9 +196,13 @@ function parseAnnoNode(node: Node): TGApp.Plugins.Mys.SctPost.Base[] {
|
||||
* @description 解析公告段落
|
||||
* @since Beta v0.5.3
|
||||
* @param {HTMLElement} p - 段落元素
|
||||
* @param {Record<string, string>} attr - 属性
|
||||
* @returns {TGApp.Plugins.Mys.SctPost.Base} 结构化数据
|
||||
*/
|
||||
function parseAnnoParagraph(p: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
function parseAnnoParagraph(
|
||||
p: HTMLElement,
|
||||
attr?: Record<string, string>,
|
||||
): TGApp.Plugins.Mys.SctPost.Base {
|
||||
const defaultRes = {
|
||||
insert: {
|
||||
tag: p.tagName,
|
||||
@@ -135,14 +230,14 @@ function parseAnnoParagraph(p: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
span.innerHTML = p.innerHTML;
|
||||
return {
|
||||
insert: "",
|
||||
children: [parseAnnoSpan(span)],
|
||||
children: [parseAnnoSpan(span, attr)],
|
||||
};
|
||||
}
|
||||
const child = <HTMLElement>p.childNodes[0];
|
||||
if (child.tagName === "SPAN") {
|
||||
return {
|
||||
insert: "",
|
||||
children: [parseAnnoSpan(child)],
|
||||
children: [parseAnnoSpan(child, attr)],
|
||||
};
|
||||
}
|
||||
if (child.tagName === "IMG") {
|
||||
@@ -156,9 +251,10 @@ function parseAnnoParagraph(p: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
};
|
||||
}
|
||||
if (child.tagName === "STRONG") {
|
||||
const res = parseAnnoNode(child, { bold: "true" });
|
||||
return {
|
||||
insert: child.innerHTML,
|
||||
attributes: { bold: true },
|
||||
insert: "",
|
||||
children: res,
|
||||
};
|
||||
}
|
||||
return defaultRes;
|
||||
@@ -184,6 +280,16 @@ function parseAnnoParagraph(p: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
insert: element.innerHTML,
|
||||
attributes: { bold: true },
|
||||
};
|
||||
} else if (element.tagName === "T") {
|
||||
element.innerHTML = element.outerHTML;
|
||||
const resE = parseAnnoNode(element);
|
||||
if (resE.length > 1) {
|
||||
childRes = { insert: element.outerHTML };
|
||||
} else {
|
||||
childRes = resE[0];
|
||||
}
|
||||
} else if (element.tagName === "IMG") {
|
||||
childRes = parseAnnoImage(element);
|
||||
} else {
|
||||
throw new Error(`Unknown node type: ${element.tagName}`);
|
||||
}
|
||||
@@ -199,9 +305,13 @@ function parseAnnoParagraph(p: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
* @description 解析公告 span
|
||||
* @since Beta v0.5.3
|
||||
* @param {HTMLElement} span - span 元素
|
||||
* @param {Record<string, string>} attr - 属性
|
||||
* @returns {TGApp.Plugins.Mys.SctPost.Base} 结构化数据
|
||||
*/
|
||||
function parseAnnoSpan(span: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
function parseAnnoSpan(
|
||||
span: HTMLElement,
|
||||
attr?: Record<string, string>,
|
||||
): TGApp.Plugins.Mys.SctPost.Base {
|
||||
const defaultRes = {
|
||||
insert: {
|
||||
tag: span.tagName,
|
||||
@@ -216,6 +326,7 @@ function parseAnnoSpan(span: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
console.error(span.innerHTML);
|
||||
return {
|
||||
insert: span.innerHTML === "" ? "\n" : decodeRegExp(span.innerHTML),
|
||||
attributes: attr,
|
||||
};
|
||||
}
|
||||
if (span.childNodes.length === 1) {
|
||||
@@ -230,11 +341,10 @@ function parseAnnoSpan(span: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
if (res.length > 1) return defaultRes;
|
||||
return res[0];
|
||||
}
|
||||
let spanAttrs: Record<string, string> | null = {};
|
||||
let spanAttrs: Record<string, string> | undefined = attr;
|
||||
if (!spanAttrs) spanAttrs = {};
|
||||
if (span.style.color !== "") {
|
||||
spanAttrs.color = span.style.color;
|
||||
} else {
|
||||
spanAttrs = null;
|
||||
}
|
||||
const parse = decodeRegExp(span.innerHTML);
|
||||
if (parse.includes("</t>")) {
|
||||
@@ -347,3 +457,52 @@ function parseAnnoDetails(details: HTMLElement): TGApp.Plugins.Mys.SctPost.Base
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析公告表格
|
||||
* @since Beta v0.5.3
|
||||
* @param {HTMLElement} table - 表格元素
|
||||
* @returns {TGApp.Plugins.Mys.SctPost.Base} 结构化数据
|
||||
*/
|
||||
function parseAnnoTable(table: HTMLElement): TGApp.Plugins.Mys.SctPost.Base {
|
||||
const defaultRes = {
|
||||
insert: {
|
||||
tag: table.tagName,
|
||||
text: table.textContent,
|
||||
style: table.style.cssText,
|
||||
html: table.innerHTML,
|
||||
outerHtml: table.outerHTML,
|
||||
},
|
||||
};
|
||||
if (table.tagName !== "TABLE") return defaultRes;
|
||||
if (table.childNodes.length === 0) return defaultRes;
|
||||
const tableBody = table.querySelector("tbody");
|
||||
if (tableBody === null) return defaultRes;
|
||||
tableBody.childNodes.forEach((tr) => {
|
||||
tr.childNodes.forEach((td) => {
|
||||
td.childNodes.forEach((child, index) => {
|
||||
const cellParsed = parseAnnoNode(child);
|
||||
const span = document.createElement("div");
|
||||
span.style.lineHeight = "2";
|
||||
for (const cell of cellParsed) {
|
||||
if (cell.children && cell.children.length > 0) {
|
||||
for (const cellChild of cell.children) {
|
||||
if (cellChild.attributes && JSON.stringify(cellChild.attributes === "{}")) {
|
||||
delete cellChild.attributes;
|
||||
}
|
||||
const cellSpan = document.createElement("span");
|
||||
render(h(TpText, { data: cellChild }), cellSpan);
|
||||
span.appendChild(cellSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
td.replaceChild(span, td.childNodes[index]);
|
||||
});
|
||||
});
|
||||
});
|
||||
return {
|
||||
insert: {
|
||||
table: table.outerHTML,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/**
|
||||
* @file web/utils/parseAnno.ts
|
||||
* @description 解析游戏内公告数据
|
||||
* @since Beta v0.5.2
|
||||
*/
|
||||
|
||||
import { saveImgLocal } from "../../utils/TGShare.js";
|
||||
import { isColorSimilar } from "../../utils/toolFunc.js";
|
||||
|
||||
import { decodeRegExp } from "./tools.js";
|
||||
|
||||
/**
|
||||
* @description 解析 a
|
||||
* @since Beta v0.5.0
|
||||
* @param {HTMLAnchorElement} a a 元素
|
||||
* @returns {HTMLAnchorElement} 解析后的 a 元素
|
||||
*/
|
||||
function parseAnnoA(a: HTMLAnchorElement): HTMLAnchorElement {
|
||||
const regex = /javascript:miHoYoGameJSSDK.openIn(Browser|Webview)\('(.+)'\);/;
|
||||
if (regex.test(a.getAttribute("href") ?? "")) {
|
||||
const href = a.getAttribute("href")?.match(regex);
|
||||
if (href) {
|
||||
a.setAttribute("href", href[2]);
|
||||
a.target = "_blank";
|
||||
a.title = href[2];
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析 p
|
||||
* @since Beta v0.5.2
|
||||
* @param {HTMLParagraphElement} p p 元素
|
||||
* @returns {HTMLParagraphElement} 解析后的 p 元素
|
||||
*/
|
||||
function parseAnnoP(p: HTMLParagraphElement): HTMLParagraphElement {
|
||||
if (p.children.length === 0) {
|
||||
p.innerHTML = decodeRegExp(p.innerHTML);
|
||||
} else {
|
||||
p.querySelectorAll("*").forEach((child) => {
|
||||
child.innerHTML = decodeRegExp(child.innerHTML);
|
||||
child.querySelectorAll("span").forEach((span) => parseAnnoSpan(span));
|
||||
});
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析 span
|
||||
* @since Beta v0.4.4
|
||||
* @param {HTMLSpanElement} span span 元素
|
||||
* @returns {HTMLSpanElement} 解析后的 span 元素
|
||||
*/
|
||||
function parseAnnoSpan(span: HTMLSpanElement): HTMLSpanElement {
|
||||
if (span.style.fontSize) {
|
||||
span.style.fontSize = "";
|
||||
}
|
||||
if (span.style.color) {
|
||||
if (isColorSimilar("#000000", span.style.color)) {
|
||||
span.style.color = "var(--app-page-content)";
|
||||
}
|
||||
}
|
||||
if (span.children.length === 0) {
|
||||
span.innerHTML = decodeRegExp(span.innerHTML);
|
||||
} else {
|
||||
span.querySelectorAll("*").forEach((child) => {
|
||||
if (child.children.length === 0) {
|
||||
child.innerHTML = decodeRegExp(child.innerHTML);
|
||||
}
|
||||
if (child.tagName === "T") {
|
||||
child.outerHTML = child.innerHTML;
|
||||
}
|
||||
});
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析 table
|
||||
* @since Beta v0.4.7
|
||||
* @param {HTMLTableElement} table table 元素
|
||||
* @returns {HTMLTableElement} 解析后的 table 元素
|
||||
*/
|
||||
function parseAnnoTable(table: HTMLTableElement): HTMLTableElement {
|
||||
table.style.borderColor = "var(--common-shadow-2)";
|
||||
table.querySelectorAll("colgroup").forEach((colgroup) => colgroup.remove());
|
||||
table.querySelectorAll("td").forEach((td) => {
|
||||
if (td.style.backgroundColor) td.style.backgroundColor = "var(--box-bg-1)";
|
||||
td.style.textAlign = "center";
|
||||
});
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 解析游戏内公告数据
|
||||
* @since Beta v0.4.4
|
||||
* @todo 需要完善
|
||||
* @param {string} data 游戏内公告数据
|
||||
* @returns {Promise<string>} 解析后的数据
|
||||
*/
|
||||
export async function parseAnnoContent(data: string): Promise<string> {
|
||||
const htmlBase = new DOMParser().parseFromString(data, "text/html");
|
||||
htmlBase.querySelectorAll("a").forEach((a) => parseAnnoA(a));
|
||||
const imgList = Array.from(htmlBase.querySelectorAll("img"));
|
||||
for (const img of imgList) {
|
||||
img.style.maxWidth = "100%";
|
||||
img.style.borderRadius = "10px";
|
||||
img.style.margin = "10px 0";
|
||||
const src = img.getAttribute("src");
|
||||
if (src) {
|
||||
img.setAttribute("src", await saveImgLocal(src));
|
||||
}
|
||||
}
|
||||
htmlBase.querySelectorAll("p").forEach((p) => parseAnnoP(p));
|
||||
htmlBase.querySelectorAll("span").forEach((span) => parseAnnoSpan(span));
|
||||
htmlBase.querySelectorAll("table").forEach((table) => parseAnnoTable(table));
|
||||
return htmlBase.body.innerHTML;
|
||||
}
|
||||
Reference in New Issue
Block a user