diff --git a/static/edit-mode.js b/static/edit-mode.js index 7bce1f2..f5e5c74 100644 --- a/static/edit-mode.js +++ b/static/edit-mode.js @@ -6,6 +6,17 @@ import { } from './api.js'; import { getGlobalConnectionInfo } from './utils.js'; +// --- 安全跳脫 HTML 特殊字元,防止破版 --- +function escapeHTML(str) { + if (str === null || str === undefined) return ""; + return String(str) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + // ========================================== // 1. 全域狀態與鎖定管理 (Lock Management) // ========================================== @@ -80,6 +91,10 @@ export async function startEditFolder(path, elementId) { leafContainers.forEach(container => { const origVal = container.getAttribute('data-original'); const rawPath = container.getAttribute('data-path'); + + // ✅ 修改這裡:新增 safeOrigVal + const safeOrigVal = escapeHTML(origVal); + let cacheKey = rawPath.replace(/::/g, ' ').replace(/\s*\[\d+\]/g, ''); if (rawPath.endsWith('::no')) { @@ -108,12 +123,15 @@ export async function startEditFolder(path, elementId) { inputHtml = `${hintIcon}`; } else { - inputHtml = `${hintIcon}`; + // ✅ 修改這裡:把 value="${origVal}" 改成 value="${safeOrigVal}" + inputHtml = `${hintIcon}`; } container.innerHTML = inputHtml; }); @@ -144,6 +162,10 @@ export async function startEditLeaf(path, elementId) { const container = document.getElementById(`container-${elementId}`); const origVal = container.getAttribute('data-original'); + + // ✅ 修改這裡:新增 safeOrigVal + const safeOrigVal = escapeHTML(origVal); + container.innerHTML = `⏳ 設備連線與載入選項中...`; try { @@ -188,17 +210,21 @@ export async function startEditLeaf(path, elementId) { inputHtml = `${hintIcon}`; } else { - inputHtml = `${hintIcon}`; + // ✅ 修改這裡:使用 safeOrigVal + inputHtml = `${hintIcon}`; } container.innerHTML = inputHtml; } catch (e) { console.warn("選項載入失敗", e); - container.innerHTML = ``; + // ✅ 修改這裡:catch 區塊也要使用 safeOrigVal + container.innerHTML = ``; } } } catch (error) { @@ -220,7 +246,9 @@ export async function cancelEditFolder(path, elementId) { const leafContainers = contentDiv.querySelectorAll('.leaf-container'); leafContainers.forEach(container => { const origVal = container.getAttribute('data-original'); - container.innerHTML = `${origVal}`; + // ✅ 修改這裡:還原時也要跳脫 + const safeOrigVal = escapeHTML(origVal); + container.innerHTML = `${safeOrigVal}`; }); } @@ -236,7 +264,9 @@ export async function cancelEditLeaf(path, elementId) { const container = document.getElementById(`container-${elementId}`); const origVal = container.getAttribute('data-original'); - container.innerHTML = `${origVal}`; + // ✅ 修改這裡:還原時也要跳脫 + const safeOrigVal = escapeHTML(origVal); + container.innerHTML = `${safeOrigVal}`; } // ========================================== @@ -508,6 +538,8 @@ function transformNoToActive(elementId, newCommand) { const firstWord = parts[0]; const restCommand = parts.slice(1).join(' '); + const safeRestCommand = escapeHTML(restCommand); + const svgEnabled = ``; const iconHtml = `${svgEnabled}`; @@ -515,7 +547,7 @@ function transformNoToActive(elementId, newCommand) { ${iconHtml} ${firstWord} - ${restCommand} + ${safeRestCommand} (已啟用,重整後歸檔) `;