filer html tags, fixed configs

This commit is contained in:
liyunze 2026-08-03 15:00:04 +10:00
parent 0363068dc8
commit e835d74272
6 changed files with 168 additions and 42 deletions

View file

@ -57,18 +57,54 @@ class EmoteManager {
this.#patternSize = this.#emotes.size;
}
parseText(text) {
if (!text || !this.#loaded || this.#emotes.size === 0) return text;
renderInto(container, text) {
container.replaceChildren();
if (text == null || text === "") return;
if (!this.#loaded || this.#emotes.size === 0) {
container.textContent = text;
return;
}
this.#buildPattern();
if (!this.#pattern) return text;
if (!this.#pattern) {
container.textContent = text;
return;
}
return text.replace(this.#pattern, (match) => {
const emote = this.#emotes.get(match);
if (!emote) return match;
console.log(emote);
return `<img src="${emote.url}" alt="${match}" title="${match} (${emote.provider})" class="emote-img" />`;
});
const pattern = new RegExp(this.#pattern.source, this.#pattern.flags);
const nodes = [];
let lastIndex = 0;
let match;
while ((match = pattern.exec(text)) !== null) {
if (match.index > lastIndex) {
nodes.push(
document.createTextNode(text.slice(lastIndex, match.index)),
);
}
const name = match[0];
const emote = this.#emotes.get(name);
if (emote?.url && /^https?:\/\//i.test(emote.url)) {
const img = document.createElement("img");
img.src = emote.url;
img.alt = name;
img.title = `${name} (${emote.provider})`;
img.className = "emote-img";
nodes.push(img);
} else {
nodes.push(document.createTextNode(name));
}
lastIndex = match.index + name.length;
}
if (lastIndex < text.length) {
nodes.push(document.createTextNode(text.slice(lastIndex)));
}
container.replaceChildren(...nodes);
}
async init() {

View file

@ -303,11 +303,17 @@ class TaskList {
// ── dom helpers ────────────────────────────────────
#parseTaskText(text) {
#stripHtml(text) {
return String(text ?? "").replace(/<\/?[^>\n]+>/g, "");
}
#setTaskText(el, text) {
const safe = this.#stripHtml(text);
if (window.emoteManager && window.emoteManager.loaded) {
return window.emoteManager.parseText(text);
window.emoteManager.renderInto(el, safe);
} else {
el.textContent = safe;
}
return text;
}
#createTaskEl(task, index) {
@ -323,7 +329,7 @@ class TaskList {
const textSpan = document.createElement("span");
textSpan.className = "task-text";
textSpan.innerHTML = this.#parseTaskText(task.text);
this.#setTaskText(textSpan, task.text);
div.replaceChildren(numberSpan, textSpan);
return div;
@ -378,7 +384,7 @@ class TaskList {
const textEl =
el.querySelector(".task-text") ||
el.querySelector("span:last-child");
textEl.innerHTML = this.#parseTaskText(task.text);
this.#setTaskText(textEl, task.text);
}
el.querySelector(".task-number").textContent = `${i + 1}.`;

View file

@ -57,18 +57,54 @@ class EmoteManager {
this.#patternSize = this.#emotes.size;
}
parseText(text) {
if (!text || !this.#loaded || this.#emotes.size === 0) return text;
renderInto(container, text) {
container.replaceChildren();
if (text == null || text === "") return;
if (!this.#loaded || this.#emotes.size === 0) {
container.textContent = text;
return;
}
this.#buildPattern();
if (!this.#pattern) return text;
if (!this.#pattern) {
container.textContent = text;
return;
}
return text.replace(this.#pattern, (match) => {
const emote = this.#emotes.get(match);
if (!emote) return match;
console.log(emote);
return `<img src="${emote.url}" alt="${match}" title="${match} (${emote.provider})" class="emote-img" />`;
});
const pattern = new RegExp(this.#pattern.source, this.#pattern.flags);
const nodes = [];
let lastIndex = 0;
let match;
while ((match = pattern.exec(text)) !== null) {
if (match.index > lastIndex) {
nodes.push(
document.createTextNode(text.slice(lastIndex, match.index)),
);
}
const name = match[0];
const emote = this.#emotes.get(name);
if (emote?.url && /^https?:\/\//i.test(emote.url)) {
const img = document.createElement("img");
img.src = emote.url;
img.alt = name;
img.title = `${name} (${emote.provider})`;
img.className = "emote-img";
nodes.push(img);
} else {
nodes.push(document.createTextNode(name));
}
lastIndex = match.index + name.length;
}
if (lastIndex < text.length) {
nodes.push(document.createTextNode(text.slice(lastIndex)));
}
container.replaceChildren(...nodes);
}
async init() {

View file

@ -279,11 +279,17 @@ class TaskList {
// ── dom helpers ────────────────────────────────────
#parseTaskText(text) {
#stripHtml(text) {
return String(text ?? "").replace(/<\/?[^>\n]+>/g, "");
}
#setTaskText(el, text) {
const safe = this.#stripHtml(text);
if (window.emoteManager && window.emoteManager.loaded) {
return window.emoteManager.parseText(text);
window.emoteManager.renderInto(el, safe);
} else {
el.textContent = safe;
}
return text;
}
#createTaskEl(task, index) {
@ -299,7 +305,7 @@ class TaskList {
const textSpan = document.createElement("span");
textSpan.className = "task-text";
textSpan.innerHTML = this.#parseTaskText(task.text);
this.#setTaskText(textSpan, task.text);
div.replaceChildren(numberSpan, textSpan);
return div;
@ -354,7 +360,7 @@ class TaskList {
const textEl =
el.querySelector(".task-text") ||
el.querySelector("span:last-child");
textEl.innerHTML = this.#parseTaskText(task.text);
this.#setTaskText(textEl, task.text);
}
el.querySelector(".task-number").textContent = `${i + 1}.`;

View file

@ -57,18 +57,54 @@ class EmoteManager {
this.#patternSize = this.#emotes.size;
}
parseText(text) {
if (!text || !this.#loaded || this.#emotes.size === 0) return text;
renderInto(container, text) {
container.replaceChildren();
if (text == null || text === "") return;
if (!this.#loaded || this.#emotes.size === 0) {
container.textContent = text;
return;
}
this.#buildPattern();
if (!this.#pattern) return text;
if (!this.#pattern) {
container.textContent = text;
return;
}
return text.replace(this.#pattern, (match) => {
const emote = this.#emotes.get(match);
if (!emote) return match;
console.log(emote);
return `<img src="${emote.url}" alt="${match}" title="${match} (${emote.provider})" class="emote-img" />`;
});
const pattern = new RegExp(this.#pattern.source, this.#pattern.flags);
const nodes = [];
let lastIndex = 0;
let match;
while ((match = pattern.exec(text)) !== null) {
if (match.index > lastIndex) {
nodes.push(
document.createTextNode(text.slice(lastIndex, match.index)),
);
}
const name = match[0];
const emote = this.#emotes.get(name);
if (emote?.url && /^https?:\/\//i.test(emote.url)) {
const img = document.createElement("img");
img.src = emote.url;
img.alt = name;
img.title = `${name} (${emote.provider})`;
img.className = "emote-img";
nodes.push(img);
} else {
nodes.push(document.createTextNode(name));
}
lastIndex = match.index + name.length;
}
if (lastIndex < text.length) {
nodes.push(document.createTextNode(text.slice(lastIndex)));
}
container.replaceChildren(...nodes);
}
async init() {

View file

@ -302,11 +302,17 @@ class TaskList {
// ── dom helpers ────────────────────────────────────
#parseTaskText(text) {
#stripHtml(text) {
return String(text ?? "").replace(/<\/?[^>\n]+>/g, "");
}
#setTaskText(el, text) {
const safe = this.#stripHtml(text);
if (window.emoteManager && window.emoteManager.loaded) {
return window.emoteManager.parseText(text);
window.emoteManager.renderInto(el, safe);
} else {
el.textContent = safe;
}
return text;
}
#createTaskEl(task, index) {
@ -322,7 +328,7 @@ class TaskList {
const textSpan = document.createElement("span");
textSpan.className = "task-text";
textSpan.innerHTML = this.#parseTaskText(task.text);
this.#setTaskText(textSpan, task.text);
div.replaceChildren(numberSpan, textSpan);
return div;
@ -377,7 +383,7 @@ class TaskList {
const textEl =
el.querySelector(".task-text") ||
el.querySelector("span:last-child");
textEl.innerHTML = this.#parseTaskText(task.text);
this.#setTaskText(textEl, task.text);
}
el.querySelector(".task-number").textContent = `${i + 1}.`;