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}
(已啟用,重整後歸檔)
`;