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,258 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>src/js/getCascadePreview.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/getCascadePreview.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import getPropKey from './getPropKey.mjs'
49
+ import { fmtWarn, getRefWarns } from './getAuthWarn.mjs'
50
+ import { REF_OF, planRefChanges } from './refCascade.mjs'
51
+
52
+
53
+ //清單頁「儲存」前之引用連帶預覽(規則帳本 R-PRINCIPLE-00 原則 6、適用表 m/n; R-REF-CASCADE-01; ADR-036):
54
+ //群組頁/權限頁改名 → 引用端(使用者 cgrups/群組 cpemis)於同一次寫入內連帶改名; 標的頁刪除或改 id → 引用它之權限 crules 項目被連帶清理(標的 id 即名稱, 改 id 等同刪舊增新, 不級聯).
55
+ //預覽與伺服端寫入用同一純函數 planRefChanges(src/js/refCascade.mjs), 前端以 store 之基準列計, 伺服端以實際為準.
56
+ //本檔只判定「要不要彈確認框」與「改名之成功訊息是否附帶筆數」並產生文字(刪除與標的頁之成功訊息不變), 不依賴 Vue/DOM; 元件只做薄接線(確認框、鎖釋放與 loading 仍在元件之 core()).
57
+ //
58
+ //kind: 'Grup'(群組頁, 引用端 users)、'Pemi'(權限頁, 引用端 grups)、'Target'(標的頁, 引用端 pemis)
59
+
60
+
61
+ let KIND = {
62
+ Grup: {
63
+ keyTable: 'grups',
64
+ rename: true,
65
+ confirm: 'confirmSaveRenameRefsGrup',
66
+ confirmExt: 'confirmSaveRenameRefsExtGrup',
67
+ success: 'grupSaveGrupsSuccessCascade',
68
+ },
69
+ Pemi: {
70
+ keyTable: 'pemis',
71
+ rename: true,
72
+ confirm: 'confirmSaveRenameRefsPemi',
73
+ confirmExt: 'confirmSaveRenameRefsExtPemi',
74
+ success: 'pemiSavePemisSuccessCascade',
75
+ },
76
+ Target: {
77
+ keyTable: 'targets',
78
+ rename: false,
79
+ confirm: 'confirmSaveDelRefsTarget',
80
+ confirmExt: '',
81
+ success: '', //標的頁不改成功訊息(刪除之筆數已於確認框告知)
82
+ },
83
+ }
84
+
85
+
86
+ let MAX_NAMES = 5
87
+
88
+
89
+ let hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k)
90
+ let isStr = (v) => typeof v === 'string'
91
+
92
+
93
+ //showName: 名稱之顯示形式, 空字串顯示為 "" (否則清單中看不到, 同 getRefWarns 之 label)
94
+ let showName = (v) => (v === '' ? '""' : String(v))
95
+
96
+
97
+ /**
98
+ * 把項目陣列以「, 」串接, 超過上限者截斷並加「共 N 個」之語系文字(cascadeListMore, {n} 為項目總數)
99
+ *
100
+ * @param {Array} items 輸入項目字串陣列
101
+ * @param {Function} $t 輸入語系函數(key → 文字)
102
+ * @param {Number} [max=5] 輸入最多列出幾項, 預設5
103
+ * @returns {String} 回傳字串, 如 'a, b' 或 'a, b, c, d, e …等 12 個'
104
+ */
105
+ function joinList(items, $t, max = MAX_NAMES) {
106
+ let s = items.slice(0, max).join(', ')
107
+ if (items.length > max) {
108
+ s = `${s} ${fmtWarn($t('cascadeListMore'), { n: items.length })}`
109
+ }
110
+ return s
111
+ }
112
+
113
+
114
+ //getHitKeys: 計畫內「有被改寫之引用端列」之原授權字串中出現之名稱鍵集合(field 為 'nRename' 取有改名者、'nDel' 取有刪除者);
115
+ //解碼經 getRefWarns(getAuthWarn.mjs 之 parseKp+cvKpToArr, 與 rewriteRefs 及伺服端同一套; 不另開 JSON5.parse 讀取點, 見 test/unit-cvKpToObj SITE-AD-001), 被引用表列給空陣列(只取 items 之名稱, 不查實體);
116
+ //名稱依 kind 取比對鍵('ref' 只認字串, 'rule' 取屬性鍵轉型, 同 rewriteRefs), 供名單只列「真的有人引用」者, 不列無人引用之改名/刪除
117
+ let getHitKeys = (plan, field) => {
118
+ let set = new Set()
119
+ let kind = hasOwn(REF_OF, plan.keyTable) ? REF_OF[plan.keyTable].kind : 'ref'
120
+ plan.changes.forEach((c) => {
121
+ if (!(c[field] > 0) || !isStr(c.before)) {
122
+ return
123
+ }
124
+ getRefWarns(c.before, []).items.forEach((it) => {
125
+ if (kind === 'ref' &amp;&amp; !isStr(it.name)) {
126
+ return
127
+ }
128
+ let key = getPropKey(it.name)
129
+ if (key !== null) {
130
+ set.add(key)
131
+ }
132
+ })
133
+ })
134
+ return set
135
+ }
136
+
137
+
138
+ /**
139
+ * 依引用連帶計畫產生儲存前確認框文字與儲存成功訊息(群組頁/權限頁/標的頁共用)
140
+ *
141
+ * 確認框(confirmText, 空字串不彈框):
142
+ * Grup/Pemi: plan.err 為 null、有改名(plan.renames)且有引用端列因改名被連帶更新(plan.nRenameHolders > 0)時, 列出受影響引用端數與「舊→新」(至多 5 個, 只列有人引用者, 其餘「…等 N 個」),
143
+ * 其中來源 from 非空(外部應用)之引用端另加一句警示(下次外部同步時可能被外部資料覆寫); 僅刪除所致之連帶清理已於「刪除」時確認(getDelImpact), 儲存時不再重複.
144
+ * Target: plan.err 為 null 且有權限之規則將被清理(plan.nDelHolders > 0)時, 列出受影響之權限數與被刪除或改 id 之管控對象(同上截斷).
145
+ * plan.err 非 null(伺服端將以固定語系鍵拒存)不彈框, 由呼叫端照常送出, 錯誤訊息由既有 showCheckYes 顯示.
146
+ * 成功訊息(successText, 空字串即使用原成功文字): 只有 Grup/Pemi 且 plan.err 為 null、有改名(plan.renames.length > 0)且有引用端因改名被連帶更新(plan.nRenameHolders > 0)時, 回傳附帶筆數(nRenameHolders)之「引用已更新為新名稱」訊息;
147
+ * 刪除所致之連帶清理(筆數已於刪除確認框告知, 且既有案例刪除被引用列後儲存之成功彈窗須維持原文字)與 Target 頁一律回空字串.
148
+ *
149
+ * @param {Object} plan 輸入 planRefChanges 之結果; null/非物件/keyTable 與 kind 不符視為無影響
150
+ * @param {Function} $t 輸入語系函數(key → 文字)
151
+ * @param {String} kind 輸入頁面種類: 'Grup'、'Pemi' 或 'Target'
152
+ * @returns {Object} 回傳 { confirmText, successText }
153
+ * @example
154
+ *
155
+ * let plan = planRefChanges({ keyTable: 'grups', rowsOld: [{ id: 'g1', name: 'A' }], rowsNew: [{ id: 'g1', name: 'B' }], holdersOld: [{ id: 'u1', cgrups: '{"A":{"mode":"OR","isActive":"y"}}' }] })
156
+ * console.log(getCascadePreview(plan, (k) => k, 'Grup').confirmText)
157
+ * // => confirmSaveRenameRefsGrup(語系函數為恆等時回傳鍵名)
158
+ *
159
+ */
160
+ function getCascadePreview(plan, $t, kind) {
161
+ let res = { confirmText: '', successText: '' }
162
+ if (!hasOwn(KIND, kind)) {
163
+ return res
164
+ }
165
+ let cfg = KIND[kind]
166
+ if (plan === null || typeof plan !== 'object' || plan.err !== null || plan.keyTable !== cfg.keyTable || !Array.isArray(plan.changes) || !Array.isArray(plan.renames)) {
167
+ return res
168
+ }
169
+
170
+ //confirmText, successText(successText 只描述改名, 條件同改名確認框, 筆數為 nRenameHolders 而非 nHolders)
171
+ if (cfg.rename) {
172
+ if (plan.renames.length > 0 &amp;&amp; plan.nRenameHolders > 0) {
173
+ res.successText = fmtWarn($t(cfg.success), { n: plan.nRenameHolders })
174
+ let hit = getHitKeys(plan, 'nRename')
175
+ let rns = plan.renames.filter((rn) => hit.has(rn.from))
176
+ if (rns.length === 0) {
177
+ rns = plan.renames //防呆: 名單判不出時退回全部改名, 不讓確認框無名單
178
+ }
179
+ let list = joinList(rns.map((rn) => `${showName(rn.from)}→${showName(rn.to)}`), $t)
180
+ let nExt = plan.changes.filter((c) => c.nRename > 0 &amp;&amp; isStr(c.from) &amp;&amp; c.from !== '').length
181
+ res.confirmText = fmtWarn($t(nExt > 0 ? cfg.confirmExt : cfg.confirm), { n: plan.nRenameHolders, e: nExt, list })
182
+ }
183
+ }
184
+ else if (plan.nDelHolders > 0) {
185
+ let hit = getHitKeys(plan, 'nDel')
186
+ let names = plan.delNames.filter((v) => hit.has(v))
187
+ if (names.length === 0) {
188
+ names = plan.delNames
189
+ }
190
+ let list = joinList(names.map((v) => showName(v)), $t)
191
+ res.confirmText = fmtWarn($t(cfg.confirm), { n: plan.nDelHolders, list })
192
+ }
193
+
194
+ return res
195
+ }
196
+
197
+
198
+ /**
199
+ * 儲存前預覽: 以與伺服端同一純函數規劃(planRefChanges), 再產生確認框文字與成功訊息; 預覽為輔助資訊, 計畫過程拋例外不得擋住儲存(回傳全空, 伺服端以實際為準)
200
+ *
201
+ * @param {Object} p 輸入參數物件
202
+ * @param {String} p.kind 輸入頁面種類: 'Grup'、'Pemi' 或 'Target'
203
+ * @param {Array} p.rowsOld 輸入基準列(store 之 grups/pemis/targets)
204
+ * @param {Array} p.rowsNew 輸入欲送出之列(清單目前之列)
205
+ * @param {Array} p.holdersOld 輸入引用端列(store 之 users/grups/pemis)
206
+ * @param {Boolean} [p.cascadeRename=true] 輸入伺服端是否做改名級聯(webInfor.cascadeRename), 僅給 false 才關閉, 預設true
207
+ * @param {Function} p.$t 輸入語系函數(key → 文字)
208
+ * @returns {Object} 回傳 { plan, confirmText, successText }; 發生例外時 plan 為 null
209
+ */
210
+ function getSavePreview(p) {
211
+ let kind = p ? p.kind : ''
212
+ if (!hasOwn(KIND, kind)) {
213
+ return { plan: null, confirmText: '', successText: '' }
214
+ }
215
+ try {
216
+ let plan = planRefChanges({
217
+ keyTable: KIND[kind].keyTable,
218
+ rowsOld: p.rowsOld,
219
+ rowsNew: p.rowsNew,
220
+ holdersOld: p.holdersOld,
221
+ opt: { cascadeRename: p.cascadeRename !== false },
222
+ })
223
+ return { plan, ...getCascadePreview(plan, p.$t, kind) }
224
+ }
225
+ catch (err) {
226
+ console.log('getSavePreview', err)
227
+ return { plan: null, confirmText: '', successText: '' }
228
+ }
229
+ }
230
+
231
+
232
+ export { getCascadePreview, getSavePreview, joinList }
233
+ export default getCascadePreview
234
+ </code></pre>
235
+ </article>
236
+ </section>
237
+
238
+
239
+
240
+
241
+
242
+
243
+ </div>
244
+
245
+ <br class="clear">
246
+
247
+ <footer>
248
+ 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.
249
+ </footer>
250
+
251
+ <script>prettyPrint();</script>
252
+ <script src="scripts/polyfill.js"></script>
253
+ <script src="scripts/linenumber.js"></script>
254
+
255
+
256
+
257
+ </body>
258
+ </html>
@@ -0,0 +1,210 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>src/js/getDelRefCount.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/getDelRefCount.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import eachOwn from './eachOwn.mjs'
49
+ import { countAndRefs, fmtWarn } from './getAuthWarn.mjs'
50
+ import { planRefChanges } from './refCascade.mjs'
51
+
52
+
53
+ //群組頁/權限頁按「刪除」前, 計算刪除對引用端的影響, 並產生確認框文字(規則帳本 R-PRINCIPLE-00 c、d、原則 6、適用表 n; ADR-036):
54
+ // n: 刪除後, 引用被刪名稱之引用端列(任何 mode、含停用項目)將於同一次寫入內被連帶清理(自其授權字串移除該引用), 其數量以 planRefChanges 之 nDelHolders 計(與伺服端同一純函數, R-REF-CASCADE-01);
55
+ // c: 其中以 AND 引用且刪除後該名稱完全消失者 → 引用被移除後其 AND 限制解除, 授權可能變多(run05 前為「AND 項變懸空、授權被收回」, 與連帶清理互斥, 已改);
56
+ // d: 引用的名稱有多筆同名(歷史同名)而只刪其一 → 取各候選之交集, 候選變少則交集變寬, 其授權可能變多(任何 mode; 該名稱仍有實體, 引用不清理, 不計入 n).
57
+ //兩頁共用: 群組頁引用端為 users(欄位 cgrups)、權限頁引用端為 grups(欄位 cpemis). 純函數, 不依賴 Vue/DOM.
58
+
59
+
60
+ //KIND_OF: 被刪者種類 → 被刪表與引用欄位('Grup' 群組頁、'Pemi' 權限頁)
61
+ let KIND_OF = {
62
+ Grup: { keyTable: 'grups', field: 'cgrups' },
63
+ Pemi: { keyTable: 'pemis', field: 'cpemis' },
64
+ }
65
+
66
+
67
+ /**
68
+ * 計算刪除所選列對引用者授權的影響(其中 AND 與歷史同名兩項)
69
+ *
70
+ * 被刪名稱只取「基準(store 之已儲存列)中存在」之列的名稱: 尚未儲存的新增列(id 不在基準)刪除不影響他人;
71
+ * 以基準名稱為準(引用者所寫的是已儲存的名稱, 未儲存的改名不影響其引用). 「刪除後」以刪除後的剩餘列(含未儲存的新增與改名)判斷,
72
+ * 「刪除前」之同名筆數以基準列計.
73
+ *
74
+ * @param {Array} delIds 輸入被刪列的 id 陣列
75
+ * @param {Array} rowsBase 輸入基準列(store 之 grups 或 pemis)
76
+ * @param {Array} holders 輸入引用者列(store 之 users 或 grups)
77
+ * @param {String} field 輸入引用欄位名('cgrups' 或 'cpemis')
78
+ * @param {Array} rowsRemain 輸入刪除後剩餘之列(目前清單剔除被刪列)
79
+ * @returns {Object} 回傳 { n, nWiden }: n 為以 AND 引用且名稱完全消失之引用者數(其 AND 限制將隨引用被清理而解除), nWiden 為授權可能變多之引用者數(歷史同名只刪其一)
80
+ * @example
81
+ *
82
+ * let users = [{ cgrups: '{"G1":{"mode":"AND","isActive":"y"}}' }]
83
+ * console.log(getDelRefCount(['g1'], [{ id: 'g1', name: 'G1' }], users, 'cgrups', []))
84
+ * // => { n: 1, nWiden: 0 }
85
+ *
86
+ */
87
+ function getDelRefCount(delIds, rowsBase, holders, field, rowsRemain) {
88
+ let setIds = new Set(Array.isArray(delIds) ? delIds : [])
89
+ let delNames = []
90
+ eachOwn(rowsBase, (r) => {
91
+ if (r !== null &amp;&amp; typeof r === 'object' &amp;&amp; setIds.has(r.id)) {
92
+ delNames.push(r.name === undefined ? '' : r.name)
93
+ }
94
+ })
95
+ if (delNames.length === 0) {
96
+ return { n: 0, nWiden: 0 }
97
+ }
98
+ let res = countAndRefs(holders, field, delNames, rowsRemain, rowsBase)
99
+ return { n: res.n, nWiden: res.nWiden }
100
+ }
101
+
102
+
103
+ /**
104
+ * 計算刪除所選列對引用端之完整影響: 將被連帶清理(移除引用)之引用端列數、其中以 AND 引用者、歷史同名致授權可能變多者
105
+ *
106
+ * nRefs 以 planRefChanges 計(只算本次刪除: rowsOld 為基準列、rowsNew 為基準列剔除被刪 id 之列, 不含其他未儲存之編輯; holdersOld 為引用端列),
107
+ * 即伺服端寫入時實際會被改寫之引用端列數(任何 mode、含停用項目); nAnd/nWiden 沿用 getDelRefCount.
108
+ * nAnd 以 nRefs 為上限(AND 引用者本即屬被清理者之子集; 若「目前清單之未儲存改名」使兩者判準不一致, 不使文案出現「其中 M 位」大於總數).
109
+ *
110
+ * @param {Array} delIds 輸入被刪列的 id 陣列
111
+ * @param {Array} rowsBase 輸入基準列(store 之 grups 或 pemis)
112
+ * @param {Array} holders 輸入引用端列(store 之 users 或 grups)
113
+ * @param {String} kind 輸入被刪者種類: 'Grup'(群組頁)或 'Pemi'(權限頁); 其他值回傳全 0
114
+ * @param {Array} rowsRemain 輸入刪除後剩餘之列(目前清單剔除被刪列)
115
+ * @returns {Object} 回傳 { nRefs, nAnd, nWiden }
116
+ * @example
117
+ *
118
+ * let users = [{ id: 'u1', cgrups: '{"G1":{"mode":"AND","isActive":"y"}}' }, { id: 'u2', cgrups: '{"G1":{"mode":"OR","isActive":"n"}}' }]
119
+ * console.log(getDelImpact(['g1'], [{ id: 'g1', name: 'G1' }], users, 'Grup', []))
120
+ * // => { nRefs: 2, nAnd: 1, nWiden: 0 }
121
+ *
122
+ */
123
+ function getDelImpact(delIds, rowsBase, holders, kind, rowsRemain) {
124
+ let res = { nRefs: 0, nAnd: 0, nWiden: 0 }
125
+ if (!Object.prototype.hasOwnProperty.call(KIND_OF, kind)) {
126
+ return res
127
+ }
128
+ let ref = KIND_OF[kind]
129
+ let base = Array.isArray(rowsBase) ? rowsBase : []
130
+ let setIds = new Set(Array.isArray(delIds) ? delIds : [])
131
+ let rowsNew = base.filter((r) => !(r !== null &amp;&amp; typeof r === 'object' &amp;&amp; setIds.has(r.id)))
132
+ let plan = planRefChanges({
133
+ keyTable: ref.keyTable,
134
+ rowsOld: base,
135
+ rowsNew,
136
+ holdersOld: Array.isArray(holders) ? holders : [],
137
+ })
138
+ //名稱是否「仍有存續列」依伺服端之身分判準(refCascade.diffRefTargets): 只有「同 id 同名」之列算存續, 刪除後以同名新增之新 id 列或由他列改名而來者不繼承引用, 故不算(否則 nRefs 計其被清理而 nAnd 以為名稱仍在, 漏報 AND 限制解除)
139
+ let nameOf = (r) => (r.name === undefined ? '' : r.name)
140
+ let baseById = new Map()
141
+ base.forEach((r) => {
142
+ if (r !== null &amp;&amp; typeof r === 'object' &amp;&amp; typeof r.id === 'string') {
143
+ baseById.set(r.id, r)
144
+ }
145
+ })
146
+ let remainRetained = (Array.isArray(rowsRemain) ? rowsRemain : []).filter((r) => {
147
+ let b = (r !== null &amp;&amp; typeof r === 'object') ? baseById.get(r.id) : undefined
148
+ return b !== undefined &amp;&amp; nameOf(b) === nameOf(r)
149
+ })
150
+ let c = getDelRefCount(delIds, rowsBase, holders, ref.field, remainRetained)
151
+ res.nRefs = plan.nDelHolders
152
+ res.nAnd = Math.min(c.n, res.nRefs)
153
+ res.nWiden = c.nWiden
154
+ return res
155
+ }
156
+
157
+
158
+ /**
159
+ * 刪除確認框文字: 有引用端將被清理(nRefs)或授權可能變多(nWiden)任一大於 0 才有文字(單一框、單一問句); 皆為 0 回空字串(不彈框)
160
+ *
161
+ * 文案依 nRefs/nAnd/nWiden 組合選鍵(語系鍵尾碼 kind): 僅 nRefs → confirmDelRefs; nRefs+nAnd → confirmDelRefsAnd; nRefs+nWiden → confirmDelRefsDup;
162
+ * 三者皆有 → confirmDelRefsAndDup; 僅 nWiden → confirmDelDupRefs({n} 為 nWiden). nAnd 為 0 或 nRefs 為 0 時不提 AND(nAnd 以 nRefs 為上限).
163
+ *
164
+ * @param {Object} impact 輸入 getDelImpact 之結果 { nRefs, nAnd, nWiden }
165
+ * @param {Function} $t 輸入語系函數(key → 文字)
166
+ * @param {String} kind 輸入被刪者種類: 'Grup'(群組頁) 或 'Pemi'(權限頁), 組成語系鍵 confirmDelRefs/confirmDelRefsAnd/confirmDelRefsDup/confirmDelRefsAndDup/confirmDelDupRefs 之尾碼
167
+ * @returns {String} 回傳確認框文字, 無影響為空字串
168
+ */
169
+ function getDelConfirmText(impact, $t, kind) {
170
+ let n = impact &amp;&amp; impact.nRefs > 0 ? impact.nRefs : 0
171
+ let m = n > 0 &amp;&amp; impact &amp;&amp; impact.nAnd > 0 ? Math.min(impact.nAnd, n) : 0
172
+ let w = impact &amp;&amp; impact.nWiden > 0 ? impact.nWiden : 0
173
+ if (n > 0) {
174
+ let key = `confirmDelRefs${m > 0 ? 'And' : ''}${w > 0 ? 'Dup' : ''}${kind}`
175
+ return fmtWarn($t(key), { n, m, w })
176
+ }
177
+ if (w > 0) {
178
+ return fmtWarn($t(`confirmDelDupRefs${kind}`), { n: w })
179
+ }
180
+ return ''
181
+ }
182
+
183
+
184
+ export { getDelRefCount, getDelImpact, getDelConfirmText }
185
+ export default getDelRefCount
186
+ </code></pre>
187
+ </article>
188
+ </section>
189
+
190
+
191
+
192
+
193
+
194
+
195
+ </div>
196
+
197
+ <br class="clear">
198
+
199
+ <footer>
200
+ 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.
201
+ </footer>
202
+
203
+ <script>prettyPrint();</script>
204
+ <script src="scripts/polyfill.js"></script>
205
+ <script src="scripts/linenumber.js"></script>
206
+
207
+
208
+
209
+ </body>
210
+ </html>
@@ -0,0 +1,92 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>src/js/getEffMode.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/getEffMode.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>/**
49
+ * 取得合併模式之有效值: 'OR' 為 'OR', 其餘(缺、非字串、'or'、'XOR' 等無法判讀者)一律視為 'AND'
50
+ *
51
+ * 規則帳本 R-AUTH-MERGE-00 第 5 條、R-PRINCIPLE-00 e: 無法判讀時取最嚴之解讀. 略過該項會使 AND 限制消失而放寬, 故改視為 AND(mergeRules 中為「限制項」:只當交集項、不單獨當基底,該層無合法 mode 之啟用項時全 n,否則唯一項成基底而比修正前多給).
52
+ * 伺服端 mergeRules(src/plugins/mShare.mjs)、編輯器解碼(cvKpToObj)、無損表示判定(getKpLossy)與頁面提示(getAuthWarn)共用, 單一擁有者.
53
+ *
54
+ * @param {*} m 輸入 mode
55
+ * @returns {String} 回傳 'OR' 或 'AND'
56
+ * @example
57
+ *
58
+ * console.log(getEffMode('OR'), getEffMode('AND'), getEffMode('or'), getEffMode(undefined))
59
+ * // => OR AND AND AND
60
+ *
61
+ */
62
+ function getEffMode(m) {
63
+ return m === 'OR' ? 'OR' : 'AND'
64
+ }
65
+
66
+
67
+ export default getEffMode
68
+ </code></pre>
69
+ </article>
70
+ </section>
71
+
72
+
73
+
74
+
75
+
76
+
77
+ </div>
78
+
79
+ <br class="clear">
80
+
81
+ <footer>
82
+ 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.
83
+ </footer>
84
+
85
+ <script>prettyPrint();</script>
86
+ <script src="scripts/polyfill.js"></script>
87
+ <script src="scripts/linenumber.js"></script>
88
+
89
+
90
+
91
+ </body>
92
+ </html>