From ffe06be91f95ffd2459ebdb2f9130d1e38d53ea7 Mon Sep 17 00:00:00 2001
From: zzw <228544128@qq.com>
Date: 星期二, 06 十月 2026 18:32:34 +0800
Subject: [PATCH] fix: preserve manually edited menu names

---
 emergency-repair-web/src/utils/sensitive.js |   62 +++++++++++++++++++++++++-----
 1 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/emergency-repair-web/src/utils/sensitive.js b/emergency-repair-web/src/utils/sensitive.js
index b0e0513..2be439a 100644
--- a/emergency-repair-web/src/utils/sensitive.js
+++ b/emergency-repair-web/src/utils/sensitive.js
@@ -12,6 +12,16 @@
     !(realName.startsWith('[') && realName.endsWith(']'))
 }
 
+// Table body cells render stored data, so they keep the codenames from the
+// source instead of being rewritten like headers, labels and placeholders.
+function isInsideTableCell(node) {
+  const element = node && node.nodeType === 1 ? node : node && node.parentElement
+  if (!element || !element.closest) {
+    return false
+  }
+  return !!element.closest('td')
+}
+
 function replaceAsciiCodename(value, codename, realName) {
   const pattern = new RegExp('(^|[^A-Za-z0-9])' + codename + '(?=$|[^A-Za-z0-9])', 'g')
   return value.replace(pattern, function (match, prefix) {
@@ -57,11 +67,16 @@
     return
   }
   if (root.nodeType === 1) {
-    attributes.forEach(function (attribute) {
-      replaceAttribute(root, attribute)
-    })
+    if (!isInsideTableCell(root)) {
+      attributes.forEach(function (attribute) {
+        replaceAttribute(root, attribute)
+      })
+    }
   }
   root.querySelectorAll('[placeholder], [title], [aria-label]').forEach(function (element) {
+    if (isInsideTableCell(element)) {
+      return
+    }
     attributes.forEach(function (attribute) {
       replaceAttribute(element, attribute)
     })
@@ -74,7 +89,9 @@
   }
 
   if (root.nodeType === 3) {
-    replaceTextNode(root)
+    if (!isInsideTableCell(root)) {
+      replaceTextNode(root)
+    }
     return
   }
 
@@ -85,9 +102,10 @@
     {
       acceptNode: function (node) {
         const parent = node.parentElement
-        return parent && !SKIPPED_TAGS[parent.tagName]
-          ? NodeFilter.FILTER_ACCEPT
-          : NodeFilter.FILTER_REJECT
+        if (!parent || SKIPPED_TAGS[parent.tagName] || isInsideTableCell(parent)) {
+          return NodeFilter.FILTER_REJECT
+        }
+        return NodeFilter.FILTER_ACCEPT
       }
     }
   )
@@ -107,7 +125,9 @@
   observer = new MutationObserver(function (mutations) {
     mutations.forEach(function (mutation) {
       if (mutation.type === 'characterData') {
-        replaceTextNode(mutation.target)
+        if (!isInsideTableCell(mutation.target)) {
+          replaceTextNode(mutation.target)
+        }
         return
       }
       mutation.addedNodes.forEach(function (node) {
@@ -123,6 +143,24 @@
   })
 }
 
+function expandPrefixedAliases(items) {
+  const expanded = []
+  const seen = {}
+  items.forEach(function (item) {
+    const names = [item.codename]
+    if (item.codename.indexOf('rk_') === 0 && item.codename.length > 3) {
+      names.push(item.codename.substring(3))
+    }
+    names.forEach(function (codename) {
+      if (!codename || seen[codename]) {
+        return
+      }
+      seen[codename] = true
+      expanded.push({ codename: codename, real_name: item.real_name })
+    })
+  })
+  return expanded
+}
 export async function installSensitiveWords() {
   try {
     const baseUrl = process.env.BASE_URL || '/'
@@ -138,11 +176,13 @@
       .filter(function (item) {
         return item && item.codename && isConfigured(item.real_name, item.codename)
       })
-      .sort(function (left, right) {
-        return right.codename.length - left.codename.length
-      })
+
+    replacements = expandPrefixedAliases(replacements).sort(function (left, right) {
+      return right.codename.length - left.codename.length
+    })
 
     replaceDom(document.body)
+    document.title = replaceSensitiveText(document.title)
     watchDom()
   } catch (error) {
     // The application still works with development codenames if the dictionary is unavailable.

--
Gitblit v1.9.1