w-web-perm 1.1.11 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +158 -117
  2. package/dist/css/app.f09c7433.css +1 -0
  3. package/dist/index.tmp +1 -1
  4. package/dist/js/app-legacy.8af87052.js +1 -0
  5. package/dist/js/app.8af87052.js +1 -0
  6. package/dist/js/{chunk-vendors.3e9e3ef1.js → chunk-vendors-legacy.ece5a361.js} +1 -1
  7. package/dist/js/{chunk-vendors-legacy.3e9e3ef1.js → chunk-vendors.ece5a361.js} +1 -1
  8. package/dist/w-web-perm.umd.js +2 -2
  9. package/dist/w-web-perm.umd.js.map +1 -1
  10. package/docs/WWebPerm.html +84 -4
  11. package/docs/global.html +24747 -832
  12. package/docs/index.html +2 -2
  13. package/docs/server_WWebPerm.mjs.html +245 -32
  14. package/docs/server_cascadeWrite.mjs.html +225 -0
  15. package/docs/server_dataChannel.mjs.html +2 -2
  16. package/docs/server_keyCheck.mjs.html +353 -0
  17. package/docs/server_lockSave.mjs.html +2 -2
  18. package/docs/server_maskLog.mjs.html +2 -2
  19. package/docs/server_procCore.mjs.html +180 -41
  20. package/docs/server_staLogs_resolveShellWorker.mjs.html +2 -2
  21. package/docs/server_syncKeep.mjs.html +311 -0
  22. package/docs/server_tools_authRefsAudit.mjs.html +247 -0
  23. package/docs/server_tools_authRefsClean.mjs.html +335 -0
  24. package/docs/server_tools_fromTools.mjs.html +797 -0
  25. package/docs/server_tools_isMain.mjs.html +103 -0
  26. package/docs/server_tools_nameDupReport.mjs.html +280 -0
  27. package/docs/server_validateRows.mjs.html +15 -4
  28. package/docs/server_wrapInjected.mjs.html +3 -3
  29. package/docs/src_fetchJson.mjs.html +2 -2
  30. package/docs/src_js_cvKpToArr.mjs.html +125 -0
  31. package/docs/src_js_cvKpToObj.mjs.html +210 -0
  32. package/docs/src_js_draftSync.mjs.html +142 -0
  33. package/docs/src_js_eachOwn.mjs.html +3 -3
  34. package/docs/src_js_editorRefRows.mjs.html +356 -0
  35. package/docs/src_js_externalRows.mjs.html +338 -0
  36. package/docs/src_js_externalUi.mjs.html +230 -0
  37. package/docs/src_js_findRefRows.mjs.html +107 -0
  38. package/docs/src_js_findTouchedDup.mjs.html +150 -0
  39. package/docs/src_js_fmtLossyMsg.mjs.html +95 -0
  40. package/docs/src_js_fromAudit.mjs.html +489 -0
  41. package/docs/src_js_getAddImpact.mjs.html +269 -0
  42. package/docs/src_js_getAuthWarn.mjs.html +463 -0
  43. package/docs/src_js_getCascadePreview.mjs.html +258 -0
  44. package/docs/src_js_getDelRefCount.mjs.html +210 -0
  45. package/docs/src_js_getEffMode.mjs.html +92 -0
  46. package/docs/src_js_getKpLossy.mjs.html +155 -0
  47. package/docs/src_js_getNameErrs.mjs.html +266 -0
  48. package/docs/src_js_getOwn.mjs.html +3 -3
  49. package/docs/src_js_getPropKey.mjs.html +109 -0
  50. package/docs/src_js_getRuleEnable.mjs.html +2 -2
  51. package/docs/src_js_isAuthMode.mjs.html +92 -0
  52. package/docs/src_js_joinNames.mjs.html +96 -0
  53. package/docs/src_js_legendFit.mjs.html +2 -2
  54. package/docs/src_js_pairRowsToSnapshot.mjs.html +156 -0
  55. package/docs/src_js_refAudit.mjs.html +359 -0
  56. package/docs/src_js_refCascade.mjs.html +572 -0
  57. package/docs/src_js_relDialogSend.mjs.html +199 -0
  58. package/docs/src_js_rowDigest.mjs.html +265 -0
  59. package/docs/src_plugins_dataReloadGuard.mjs.html +109 -0
  60. package/docs/src_plugins_reuseDeletedIds.mjs.html +2 -2
  61. package/docs/src_plugins_submitGuard.mjs.html +2 -2
  62. package/g_authRefsClean.mjs +79 -0
  63. package/g_fixFromType.mjs +92 -0
  64. package/g_initialData.mjs +3 -3
  65. package/g_purgeFrom.mjs +127 -0
  66. package/package.json +1 -1
  67. package/server/WWebPerm.mjs +243 -30
  68. package/server/cascadeWrite.mjs +153 -0
  69. package/server/keyCheck.mjs +281 -0
  70. package/server/procCore.mjs +178 -39
  71. package/server/procLang.mjs +271 -0
  72. package/server/syncKeep.mjs +239 -0
  73. package/server/tools/authRefsAudit.mjs +175 -0
  74. package/server/tools/authRefsClean.mjs +263 -0
  75. package/server/tools/fromTools.mjs +725 -0
  76. package/server/tools/isMain.mjs +31 -0
  77. package/server/tools/nameDupReport.mjs +208 -0
  78. package/server/validateRows.mjs +13 -2
  79. package/server/wrapInjected.mjs +1 -1
  80. package/src/components/LayoutContentGrups.vue +399 -77
  81. package/src/components/LayoutContentPemis.vue +400 -78
  82. package/src/components/LayoutContentTargets.vue +261 -25
  83. package/src/components/LayoutContentUsers.vue +336 -98
  84. package/src/components/VeCgrups.vue +119 -115
  85. package/src/components/VeCpemis.vue +117 -115
  86. package/src/components/VeCrules.vue +18 -2
  87. package/src/components/VeGrupBlngUsers.vue +240 -73
  88. package/src/components/VePemiBlngGrups.vue +247 -83
  89. package/src/js/cvKpToArr.mjs +53 -0
  90. package/src/js/cvKpToObj.mjs +138 -0
  91. package/src/js/draftSync.mjs +70 -0
  92. package/src/js/eachOwn.mjs +1 -1
  93. package/src/js/editorRefRows.mjs +284 -0
  94. package/src/js/externalRows.mjs +266 -0
  95. package/src/js/externalUi.mjs +158 -0
  96. package/src/js/findRefRows.mjs +35 -0
  97. package/src/js/findTouchedDup.mjs +78 -0
  98. package/src/js/fmtLossyMsg.mjs +23 -0
  99. package/src/js/fromAudit.mjs +417 -0
  100. package/src/js/getAddImpact.mjs +197 -0
  101. package/src/js/getAuthWarn.mjs +391 -0
  102. package/src/js/getCascadePreview.mjs +186 -0
  103. package/src/js/getDelRefCount.mjs +138 -0
  104. package/src/js/getEffMode.mjs +20 -0
  105. package/src/js/getKpLossy.mjs +83 -0
  106. package/src/js/getNameErrs.mjs +194 -0
  107. package/src/js/getOwn.mjs +1 -1
  108. package/src/js/getPropKey.mjs +37 -0
  109. package/src/js/isAuthMode.mjs +20 -0
  110. package/src/js/joinNames.mjs +24 -0
  111. package/src/js/pairRowsToSnapshot.mjs +84 -0
  112. package/src/js/refAudit.mjs +287 -0
  113. package/src/js/refCascade.mjs +500 -0
  114. package/src/js/relDialogSend.mjs +127 -0
  115. package/src/js/rowDigest.mjs +193 -0
  116. package/src/plugins/dataReloadGuard.mjs +37 -0
  117. package/src/plugins/mShare.mjs +147 -174
  118. package/src/plugins/mUI.mjs +3 -8
  119. package/src/schema/tables/users.mjs +152 -152
  120. package/dist/css/app.6918ec45.css +0 -1
  121. package/dist/js/app-legacy.963e800c.js +0 -1
  122. package/dist/js/app.963e800c.js +0 -1
@@ -0,0 +1,269 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>src/js/getAddImpact.mjs - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+ <!--[if lt IE 9]>
12
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13
+ <![endif]-->
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16
+ <script src="scripts/nav.js" defer></script>
17
+
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ </head>
20
+ <body>
21
+
22
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
23
+ <label for="nav-trigger" class="navicon-button x">
24
+ <div class="navicon"></div>
25
+ </label>
26
+
27
+ <label for="nav-trigger" class="overlay"></label>
28
+
29
+ <nav >
30
+
31
+
32
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#applyPurgePlan">applyPurgePlan</a></li><li><a href="global.html#auditFrom">auditFrom</a></li><li><a href="global.html#auditRefs">auditRefs</a></li><li><a href="global.html#buildReport">buildReport</a></li><li><a href="global.html#buildRowsSend">buildRowsSend</a></li><li><a href="global.html#buildSyncRowsNew">buildSyncRowsNew</a></li><li><a href="global.html#checkBaseline">checkBaseline</a></li><li><a href="global.html#checkCascadePlan">checkCascadePlan</a></li><li><a href="global.html#checkDbNotInUse">checkDbNotInUse</a></li><li><a href="global.html#checkExternalWrite">checkExternalWrite</a></li><li><a href="global.html#checkMapKeyBatch">checkMapKeyBatch</a></li><li><a href="global.html#checkUsersWrite">checkUsersWrite</a></li><li><a href="global.html#cleanOutOf">cleanOutOf</a></li><li><a href="global.html#compareBaseline">compareBaseline</a></li><li><a href="global.html#countAndRefs">countAndRefs</a></li><li><a href="global.html#countExternalRows">countExternalRows</a></li><li><a href="global.html#countIdRenumber">countIdRenumber</a></li><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#cvKpToArr">cvKpToArr</a></li><li><a href="global.html#cvKpToObj">cvKpToObj</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#diffRefTargets">diffRefTargets</a></li><li><a href="global.html#dropServerOnlyDiff">dropServerOnlyDiff</a></li><li><a href="global.html#eachOwn">eachOwn</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#fillIdlessIds">fillIdlessIds</a></li><li><a href="global.html#findDupIndex">findDupIndex</a></li><li><a href="global.html#findKeyOtherFrom">findKeyOtherFrom</a></li><li><a href="global.html#findRefRows">findRefRows</a></li><li><a href="global.html#findTouchedDup">findTouchedDup</a></li><li><a href="global.html#fmtLossyMsg">fmtLossyMsg</a></li><li><a href="global.html#fmtVars">fmtVars</a></li><li><a href="global.html#fmtWarn">fmtWarn</a></li><li><a href="global.html#formatFixReport">formatFixReport</a></li><li><a href="global.html#formatFromAudit">formatFromAudit</a></li><li><a href="global.html#formatPurgeReport">formatPurgeReport</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#getAddConfirmText">getAddConfirmText</a></li><li><a href="global.html#getAddImpact">getAddImpact</a></li><li><a href="global.html#getBannerLines">getBannerLines</a></li><li><a href="global.html#getBaselineDigest">getBaselineDigest</a></li><li><a href="global.html#getCascadePreview">getCascadePreview</a></li><li><a href="global.html#getChangedIdx">getChangedIdx</a></li><li><a href="global.html#getDelConfirmText">getDelConfirmText</a></li><li><a href="global.html#getDelImpact">getDelImpact</a></li><li><a href="global.html#getDelRefCount">getDelRefCount</a></li><li><a href="global.html#getDigestFields">getDigestFields</a></li><li><a href="global.html#getDupRowsInconsistent">getDupRowsInconsistent</a></li><li><a href="global.html#getEffMode">getEffMode</a></li><li><a href="global.html#getExternalEdits">getExternalEdits</a></li><li><a href="global.html#getItemWarnText">getItemWarnText</a></li><li><a href="global.html#getKpLossy">getKpLossy</a></li><li><a href="global.html#getLockFields">getLockFields</a></li><li><a href="global.html#getNameErrs">getNameErrs</a></li><li><a href="global.html#getOwn">getOwn</a></li><li><a href="global.html#getPropKey">getPropKey</a></li><li><a href="global.html#getRawModeMap">getRawModeMap</a></li><li><a href="global.html#getRefRowsExtra">getRefRowsExtra</a></li><li><a href="global.html#getRefState">getRefState</a></li><li><a href="global.html#getRefWarnText">getRefWarnText</a></li><li><a href="global.html#getRefWarns">getRefWarns</a></li><li><a href="global.html#getRowIdxs">getRowIdxs</a></li><li><a href="global.html#getRowState">getRowState</a></li><li><a href="global.html#getRuleEnable">getRuleEnable</a></li><li><a href="global.html#getRuleWarnText">getRuleWarnText</a></li><li><a href="global.html#getRuleWarns">getRuleWarns</a></li><li><a href="global.html#getSavePreview">getSavePreview</a></li><li><a href="global.html#getSyncWarnLines">getSyncWarnLines</a></li><li><a href="global.html#hasDupKey">hasDupKey</a></li><li><a href="global.html#hasExternalDiff">hasExternalDiff</a></li><li><a href="global.html#isAuthMode">isAuthMode</a></li><li><a href="global.html#isBaselineStale">isBaselineStale</a></li><li><a href="global.html#isBaselineValid">isBaselineValid</a></li><li><a href="global.html#isDraftStale">isDraftStale</a></li><li><a href="global.html#isExternalRow">isExternalRow</a></li><li><a href="global.html#isJsonLossy">isJsonLossy</a></li><li><a href="global.html#isMain">isMain</a></li><li><a href="global.html#joinList">joinList</a></li><li><a href="global.html#joinNames">joinNames</a></li><li><a href="global.html#keepAssignByEntity">keepAssignByEntity</a></li><li><a href="global.html#keepAssignOnMissing">keepAssignOnMissing</a></li><li><a href="global.html#makeBaseline">makeBaseline</a></li><li><a href="global.html#makeRowStates">makeRowStates</a></li><li><a href="global.html#mapKeyOf">mapKeyOf</a></li><li><a href="global.html#mapNameKp">mapNameKp</a></li><li><a href="global.html#markDataReload">markDataReload</a></li><li><a href="global.html#markHasKey">markHasKey</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#pairRowsToSnapshot">pairRowsToSnapshot</a></li><li><a href="global.html#pickUniqueUser">pickUniqueUser</a></li><li><a href="global.html#planDraftSync">planDraftSync</a></li><li><a href="global.html#planFixFromType">planFixFromType</a></li><li><a href="global.html#planPurgeChain">planPurgeChain</a></li><li><a href="global.html#planPurgeFrom">planPurgeFrom</a></li><li><a href="global.html#planRefChanges">planRefChanges</a></li><li><a href="global.html#putRefEntry">putRefEntry</a></li><li><a href="global.html#putRowsToKp">putRowsToKp</a></li><li><a href="global.html#refsChanged">refsChanged</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#restoreExternalOrder">restoreExternalOrder</a></li><li><a href="global.html#restoreServerFields">restoreServerFields</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#rewriteRefs">rewriteRefs</a></li><li><a href="global.html#rowDigest">rowDigest</a></li><li><a href="global.html#runAuditFrom">runAuditFrom</a></li><li><a href="global.html#runClean">runClean</a></li><li><a href="global.html#runFixFromType">runFixFromType</a></li><li><a href="global.html#runPurgeFrom">runPurgeFrom</a></li><li><a href="global.html#splitCheckedRows">splitCheckedRows</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#tabWriteKey">tabWriteKey</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#withTabLocks">withTabLocks</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li><li><a href="global.html#writeWithCascade">writeWithCascade</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">src/js/getAddImpact.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import { fmtWarn } from './getAuthWarn.mjs'
49
+ import getEffMode from './getEffMode.mjs'
50
+ import { REF_OF, keyOf, entName, decodeKp, listEntries } from './refCascade.mjs'
51
+
52
+
53
+ //清單頁「儲存」前之「新增撞懸空名」確認(F-23/F-26 run07 設計摘要原則 7; 規則帳本 R-PRINCIPLE-00 原則 3「遇衝突或歧義: 收嚴+提示」、明確同意; 純函數, 不依賴 Vue/DOM/ORM):
54
+ //新增(id 不在基準)之群組/權限/標的, 其名稱(群組/權限為 name, 標的為 id)在基準內查無任何同名實體, 而仍有「啟用中之引用」指向該名稱(懸空引用: 使用者 cgrups、群組 cpemis、權限 crules)——
55
+ //新增後該引用即解到此新實體, 引用端(使用者/群組/權限)之授權隨之變多或受其限制(AND). 後台允許新增, 但須於送出前列出影響並由使用者按「是」才送出.
56
+ //引用之解碼、名稱比對鍵、被引用表與引用端之對應皆沿用 refCascade.mjs(REF_OF/decodeKp/listEntries/entName/keyOf, 與伺服端引用連帶同一套口徑);
57
+ //AND 之判定沿用 getEffMode(mode 缺或非 OR 者視為 AND, 與刪除確認框 countAndRefs 一致); 只有群組/權限之引用項有 mode, 標的之 crules 項目無 mode(mergeRules 之規則只取 isActive), 故標的之 nAnd 恆為 0.
58
+
59
+
60
+ //MAX_NAMES: 供顯示之名稱上限(同 getCascadePreview 之 joinList)
61
+ let MAX_NAMES = 5
62
+
63
+
64
+ //TEXT_KEY: 頁面種類 → 語系鍵(無 AND 句, 有 AND 句)
65
+ let TEXT_KEY = {
66
+ Grup: ['confirmAddRefsGrup', 'confirmAddRefsAndGrup'],
67
+ Pemi: ['confirmAddRefsPemi', 'confirmAddRefsAndPemi'],
68
+ Target: ['confirmAddRefsTarget', ''],
69
+ }
70
+
71
+
72
+ let isStr = (v) => typeof v === 'string'
73
+ let isObj = (v) => v !== null &amp;&amp; typeof v === 'object'
74
+ let hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k)
75
+
76
+
77
+ //toId: 列之 id 取字串形式(字串原樣; 有限數字取其字串, 同伺服端寫入前之主鍵正規化), 否則 null(視為無 id: 新列)
78
+ let toId = (r) => {
79
+ let id = isObj(r) ? r.id : undefined
80
+ if (isStr(id)) {
81
+ return id
82
+ }
83
+ return (typeof id === 'number' &amp;&amp; Number.isFinite(id)) ? String(id) : null
84
+ }
85
+
86
+
87
+ //showName: 名稱之顯示形式, 空字串顯示為 "" (否則文案中看不到, 同 getCascadePreview)
88
+ let showName = (v) => (v === '' ? '""' : String(v))
89
+
90
+
91
+ /**
92
+ * 計算「本次新增且撞懸空名」對引用端之影響
93
+ *
94
+ * 新增列: rowsNew 中 id 不在 rowsOld 者(缺 id 者亦為新增; 有限數字 id 取字串形式比對). 撞懸空名: 新增列之名稱(群組/權限為 name〔缺欄視為 ''〕, 標的為 id)非字串者不計,
95
+ * 其比對鍵(群組/權限為字串本身, 標的為屬性鍵轉型)在 rowsOld 內無任何同名實體(歷史同名、本次一併刪除或改名之舊列仍算有同名實體, 其引用之去留由刪除/改名流程確認);
96
+ * 同一名稱多列新增只計一次. 引用端: holders 中授權字串(cgrups/cpemis/crules)解碼後, 有「isActive 為 'y' 且名稱指向該新名稱」之項目者(停用項目、壞 JSON、空字串、非容器皆不計; 含外部列).
97
+ * nHolders 為受影響之引用端列數(一列引用多個新名稱只計一次); nAnd 為其中至少有一個此類引用項之有效模式為 AND 者(群組/權限; 標的恆為 0); names 為受影響之新名稱(依 rowsNew 次序、去重、至多 5 個), nNames 為其總數.
98
+ *
99
+ * @param {Object} p 輸入參數物件
100
+ * @param {String} p.keyTable 輸入被新增之表, 'grups'(引用端 users.cgrups)、'pemis'(引用端 grups.cpemis)或 'targets'(引用端 pemis.crules); 其他回傳全 0
101
+ * @param {Array} p.rowsOld 輸入基準列(store 之該表列, 已儲存者)
102
+ * @param {Array} p.rowsNew 輸入欲送出之該表整表(清單目前之列; 標的頁為 reuseDeletedIds 正規化後之 rowsSend)
103
+ * @param {Array} p.holders 輸入引用端表全部列(users/grups/pemis, 含外部列)
104
+ * @returns {Object} 回傳 { nHolders, nAnd, names, nNames }
105
+ * @example
106
+ *
107
+ * let r = getAddImpact({
108
+ * keyTable: 'grups',
109
+ * rowsOld: [],
110
+ * rowsNew: [{ id: 'g1', name: 'G1' }],
111
+ * holders: [{ id: 'u1', cgrups: '{"G1":{"mode":"AND","isActive":"y"}}' }],
112
+ * })
113
+ * console.log(r.nHolders, r.nAnd, r.names)
114
+ * // => 1 1 [ 'G1' ]
115
+ *
116
+ */
117
+ function getAddImpact(p) {
118
+ let res = { nHolders: 0, nAnd: 0, names: [], nNames: 0 }
119
+ let p0 = isObj(p) ? p : {}
120
+ let keyTable = p0.keyTable
121
+ if (!isStr(keyTable) || !hasOwn(REF_OF, keyTable)) {
122
+ return res
123
+ }
124
+ let ref = REF_OF[keyTable]
125
+ let rowsOld = Array.isArray(p0.rowsOld) ? p0.rowsOld : []
126
+ let rowsNew = Array.isArray(p0.rowsNew) ? p0.rowsNew : []
127
+ let holders = Array.isArray(p0.holders) ? p0.holders : []
128
+
129
+ //oldIds, keysOld: 基準之字串主鍵集合、基準名稱之比對鍵集合
130
+ let oldIds = new Set()
131
+ let keysOld = new Set()
132
+ rowsOld.forEach((r) => {
133
+ let id = toId(r)
134
+ if (id !== null) {
135
+ oldIds.add(id)
136
+ }
137
+ let k = keyOf(entName(r, keyTable), ref.kind)
138
+ if (k !== null) {
139
+ keysOld.add(k)
140
+ }
141
+ })
142
+
143
+ //kpNew: 比對鍵 → 新名稱(新增列且基準無同名實體; Map 依 rowsNew 次序)
144
+ let kpNew = new Map()
145
+ rowsNew.forEach((r) => {
146
+ if (!isObj(r)) {
147
+ return
148
+ }
149
+ let id = toId(r)
150
+ if (id !== null &amp;&amp; oldIds.has(id)) {
151
+ return //既有列(含改名), 非新增
152
+ }
153
+ let name = entName(r, keyTable)
154
+ let k = keyOf(name, ref.kind)
155
+ if (k === null || keysOld.has(k) || kpNew.has(k)) {
156
+ return
157
+ }
158
+ kpNew.set(k, name)
159
+ })
160
+ if (kpNew.size === 0) {
161
+ return res
162
+ }
163
+
164
+ //holders: 解碼各引用端之授權字串, 找啟用中且指向新名稱之項目
165
+ let kpHit = new Set() //受影響之比對鍵
166
+ holders.forEach((h) => {
167
+ if (!isObj(h)) {
168
+ return
169
+ }
170
+ let kp = decodeKp(h[ref.field])
171
+ if (kp === null) {
172
+ return
173
+ }
174
+ let isHit = false
175
+ let isAnd = false
176
+ listEntries(kp, ref.kind).forEach((e) => {
177
+ if (e.key === null || !kpNew.has(e.key) || e.isActive !== 'y') {
178
+ return
179
+ }
180
+ isHit = true
181
+ kpHit.add(e.key)
182
+ if (ref.kind === 'ref') {
183
+ let mode = (e.isObj &amp;&amp; hasOwn(e.el, 'mode')) ? e.el.mode : undefined
184
+ if (getEffMode(mode) === 'AND') {
185
+ isAnd = true
186
+ }
187
+ }
188
+ })
189
+ if (isHit) {
190
+ res.nHolders++
191
+ }
192
+ if (isAnd) {
193
+ res.nAnd++
194
+ }
195
+ })
196
+
197
+ //names: 受影響之新名稱(依 rowsNew 次序)
198
+ let names = []
199
+ kpNew.forEach((name, k) => {
200
+ if (kpHit.has(k)) {
201
+ names.push(name)
202
+ }
203
+ })
204
+ res.nNames = names.length
205
+ res.names = names.slice(0, MAX_NAMES)
206
+
207
+ return res
208
+ }
209
+
210
+
211
+ /**
212
+ * 新增撞懸空名之確認框文字: nHolders 為 0 回空字串(不彈框); 有 AND 引用者(群組/權限頁)選含 AND 句之語系鍵
213
+ *
214
+ * 文案依頁面種類選鍵: 'Grup'(群組頁, 引用端為使用者) confirmAddRefsGrup/confirmAddRefsAndGrup; 'Pemi'(權限頁, 引用端為群組) confirmAddRefsPemi/confirmAddRefsAndPemi;
215
+ * 'Target'(標的頁, 引用端為權限) confirmAddRefsTarget(無 AND 句). 佔位符: {list} 為新名稱清單(至多 5 個, 超過附 cascadeListMore 之總數), {n} 為受影響之引用端數, {m} 為其中以 AND 引用者.
216
+ * 單一框、單一問句(「確定新增?」). 種類不明回空字串.
217
+ *
218
+ * @param {Object} impact 輸入 getAddImpact 之結果 { nHolders, nAnd, names, nNames }
219
+ * @param {Function} $t 輸入語系函數(key → 文字)
220
+ * @param {String} kind 輸入頁面種類: 'Grup'、'Pemi' 或 'Target'
221
+ * @returns {String} 回傳確認框文字, 無影響為空字串
222
+ */
223
+ function getAddConfirmText(impact, $t, kind) {
224
+ if (!isStr(kind) || !hasOwn(TEXT_KEY, kind)) {
225
+ return ''
226
+ }
227
+ let n = (isObj(impact) &amp;&amp; impact.nHolders > 0) ? impact.nHolders : 0
228
+ if (n === 0) {
229
+ return ''
230
+ }
231
+ let m = (impact.nAnd > 0 &amp;&amp; TEXT_KEY[kind][1] !== '') ? Math.min(impact.nAnd, n) : 0
232
+ let key = TEXT_KEY[kind][m > 0 ? 1 : 0]
233
+ let names = Array.isArray(impact.names) ? impact.names : []
234
+ let nNames = impact.nNames > names.length ? impact.nNames : names.length
235
+ let list = names.map(showName).join(', ')
236
+ if (nNames > names.length) {
237
+ list = `${list} ${fmtWarn($t('cascadeListMore'), { n: nNames })}`
238
+ }
239
+ return fmtWarn($t(key), { n, m, list })
240
+ }
241
+
242
+
243
+ export { getAddImpact, getAddConfirmText }
244
+ export default getAddImpact
245
+ </code></pre>
246
+ </article>
247
+ </section>
248
+
249
+
250
+
251
+
252
+
253
+
254
+ </div>
255
+
256
+ <br class="clear">
257
+
258
+ <footer>
259
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 23 2026 10:56:39 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
260
+ </footer>
261
+
262
+ <script>prettyPrint();</script>
263
+ <script src="scripts/polyfill.js"></script>
264
+ <script src="scripts/linenumber.js"></script>
265
+
266
+
267
+
268
+ </body>
269
+ </html>