From bd8b53cd6046cef9802d593d8257392d81afb5ce Mon Sep 17 00:00:00 2001 From: Osmium Sorcerer Date: Wed, 3 Jun 2026 11:08:07 +0000 Subject: Eliminate innerHTML manipulation Construct DOM nodes directly instead of trying to sanitize every input string and dynamically updating HTML. Replace all uses of innerHTML with textContent, replaceChildren, and appendChild. This removes the need to use safeTags and replace newlines, but now requires preserving whitespace via CSS pre-wrap. Every OOC chat line is now placed into its own element instead of simply being appended to the log. This might be worse, and createTextNode is another alternative. --- webAO/packets/handlers/handleARUP.ts | 2 +- webAO/packets/handlers/handleCT.ts | 11 ++++++----- webAO/packets/handlers/handleLE.ts | 2 +- webAO/packets/handlers/handlePV.ts | 12 +++++++----- webAO/packets/handlers/handleSI.ts | 2 +- webAO/packets/handlers/handleSM.ts | 4 ++-- webAO/packets/handlers/handleZZ.ts | 8 ++++++-- 7 files changed, 24 insertions(+), 17 deletions(-) (limited to 'webAO/packets') diff --git a/webAO/packets/handlers/handleARUP.ts b/webAO/packets/handlers/handleARUP.ts index 7f72b156..7f1c701d 100644 --- a/webAO/packets/handlers/handleARUP.ts +++ b/webAO/packets/handlers/handleARUP.ts @@ -30,7 +30,7 @@ export const handleARUP = (args: string[]) => { i ].status.toLowerCase()}`; - thisarea.innerText = `${client.areas[i].name} (${client.areas[i].players}) [${client.areas[i].status}]`; + thisarea.textContent = `${client.areas[i].name} (${client.areas[i].players}) [${client.areas[i].status}]`; thisarea.title = `Players: ${client.areas[i].players}\n` + diff --git a/webAO/packets/handlers/handleCT.ts b/webAO/packets/handlers/handleCT.ts index 29ec94c0..d4868bd4 100644 --- a/webAO/packets/handlers/handleCT.ts +++ b/webAO/packets/handlers/handleCT.ts @@ -9,12 +9,13 @@ const { mode } = queryParser(); export const handleCT = (args: string[]) => { if (mode !== "replay") { const oocLog = document.getElementById("client_ooclog")!; - const username = prepChat(args[1]); - let message = addLinks(prepChat(args[2])); - // Replace newlines with br - message = message.replace(/\n/g, "
"); + const username = unescapeChat(args[1]); + let message = addLinks(unescapeChat(args[2])); - oocLog.innerHTML += `${username}: ${message}
`; + const line = document.createElement("div"); + line.className = "ooc-line"; + line.textContent = `${username}: ${message}`; + oocLog.appendChild(line); if (oocLog.scrollTop + oocLog.offsetHeight + 120 > oocLog.scrollHeight) oocLog.scrollTo(0, oocLog.scrollHeight); } diff --git a/webAO/packets/handlers/handleLE.ts b/webAO/packets/handlers/handleLE.ts index ae1bb02c..dd2a2f13 100644 --- a/webAO/packets/handlers/handleLE.ts +++ b/webAO/packets/handlers/handleLE.ts @@ -22,7 +22,7 @@ export const handleLE = (args: string[]) => { } const evidence_box = document.getElementById("evidences"); - evidence_box.innerHTML = ""; + evidence_box.replaceChildren(); for (let i = 0; i <= client.evidences.length - 1; i++) { const evi_item = new Image(); evi_item.id = "evi_" + i; diff --git a/webAO/packets/handlers/handlePV.ts b/webAO/packets/handlers/handlePV.ts index ba48f36f..2e14ad2f 100644 --- a/webAO/packets/handlers/handlePV.ts +++ b/webAO/packets/handlers/handlePV.ts @@ -34,15 +34,17 @@ export const handlePV = async (args: string[]) => { const { emotes } = client; const emotesList = document.getElementById("client_emo"); emotesList.style.display = ""; - emotesList.innerHTML = ""; // Clear emote box + emotesList.replaceChildren(); const ini = await ensureCharIni(client.charID); me.side = ini.options.side; updateActionCommands(me.side); if (ini.emotions.number === 0) { - emotesList.innerHTML = `No emotes available`; + let emotesUnavail = document.createElement("span"); + emotesUnavail.id = "emo_0"; + emotesUnavail.className = "emote_button"; + emotesUnavail.textContent = "No emotes available"; + + emotesList.replaceChildren(emotesUnavail); } else { // Probe extensions once using button1_off, then reuse for all emotes const charPath = `${AO_HOST}characters/${encodeURI(me.name)}/emotions/`; diff --git a/webAO/packets/handlers/handleSI.ts b/webAO/packets/handlers/handleSI.ts index eac84e03..369806ba 100644 --- a/webAO/packets/handlers/handleSI.ts +++ b/webAO/packets/handlers/handleSI.ts @@ -14,7 +14,7 @@ export const handleSI = (args: string[]) => { fetchExtensions(); // create the charselect grid, to be filled by the character loader - document.getElementById("client_chartable")!.innerHTML = ""; + document.getElementById("client_chartable")!.replaceChildren(); for (let i = 0; i < client.char_list_length; i++) { const demothing = document.createElement("img"); diff --git a/webAO/packets/handlers/handleSM.ts b/webAO/packets/handlers/handleSM.ts index 1c3fd5e2..21f6ca59 100644 --- a/webAO/packets/handlers/handleSM.ts +++ b/webAO/packets/handlers/handleSM.ts @@ -8,13 +8,13 @@ import { createArea } from "../../client/createArea"; * @param {Array} args packet arguments */ export const handleSM = (args: string[]) => { - document.getElementById("client_loadingtext")!.innerHTML = "Loading Music "; + document.getElementById("client_loadingtext")!.textContent = "Loading Music "; client.resetMusicList(); client.resetAreaList(); client.musics_time = false; - document.getElementById("client_loadingtext")!.innerHTML = `Loading Music`; + document.getElementById("client_loadingtext")!.textContent = `Loading Music`; for (let i = 1; i < args.length - 1; i++) { // Check when found the song for the first time diff --git a/webAO/packets/handlers/handleZZ.ts b/webAO/packets/handlers/handleZZ.ts index 0496d420..66e7d15a 100644 --- a/webAO/packets/handlers/handleZZ.ts +++ b/webAO/packets/handlers/handleZZ.ts @@ -8,8 +8,12 @@ import { prepChat } from "../../encoding"; */ export const handleZZ = (args: string[]) => { const oocLog = document.getElementById("client_ooclog")!; - const message = args[1].replace(/\n/g, "
"); - oocLog.innerHTML += `$Alert: ${prepChat(message)}
`; + + const modAlert = document.createElement("div"); + modAlert.textContent = `$Alert: ${unescapeChat(args[1])}`; + modAlert.className = "ooc-line"; + oocLog.appendChild(modAlert); + if (oocLog.scrollTop > oocLog.scrollHeight - 60) { oocLog.scrollTop = oocLog.scrollHeight; } -- cgit