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.
- package/README.md +158 -117
- package/dist/css/app.f09c7433.css +1 -0
- package/dist/index.tmp +1 -1
- package/dist/js/app-legacy.8af87052.js +1 -0
- package/dist/js/app.8af87052.js +1 -0
- package/dist/js/{chunk-vendors.3e9e3ef1.js → chunk-vendors-legacy.ece5a361.js} +1 -1
- package/dist/js/{chunk-vendors-legacy.3e9e3ef1.js → chunk-vendors.ece5a361.js} +1 -1
- package/dist/w-web-perm.umd.js +2 -2
- package/dist/w-web-perm.umd.js.map +1 -1
- package/docs/WWebPerm.html +84 -4
- package/docs/global.html +24747 -832
- package/docs/index.html +2 -2
- package/docs/server_WWebPerm.mjs.html +245 -32
- package/docs/server_cascadeWrite.mjs.html +225 -0
- package/docs/server_dataChannel.mjs.html +2 -2
- package/docs/server_keyCheck.mjs.html +353 -0
- package/docs/server_lockSave.mjs.html +2 -2
- package/docs/server_maskLog.mjs.html +2 -2
- package/docs/server_procCore.mjs.html +180 -41
- package/docs/server_staLogs_resolveShellWorker.mjs.html +2 -2
- package/docs/server_syncKeep.mjs.html +311 -0
- package/docs/server_tools_authRefsAudit.mjs.html +247 -0
- package/docs/server_tools_authRefsClean.mjs.html +335 -0
- package/docs/server_tools_fromTools.mjs.html +797 -0
- package/docs/server_tools_isMain.mjs.html +103 -0
- package/docs/server_tools_nameDupReport.mjs.html +280 -0
- package/docs/server_validateRows.mjs.html +15 -4
- package/docs/server_wrapInjected.mjs.html +3 -3
- package/docs/src_fetchJson.mjs.html +2 -2
- package/docs/src_js_cvKpToArr.mjs.html +125 -0
- package/docs/src_js_cvKpToObj.mjs.html +210 -0
- package/docs/src_js_draftSync.mjs.html +142 -0
- package/docs/src_js_eachOwn.mjs.html +3 -3
- package/docs/src_js_editorRefRows.mjs.html +356 -0
- package/docs/src_js_externalRows.mjs.html +338 -0
- package/docs/src_js_externalUi.mjs.html +230 -0
- package/docs/src_js_findRefRows.mjs.html +107 -0
- package/docs/src_js_findTouchedDup.mjs.html +150 -0
- package/docs/src_js_fmtLossyMsg.mjs.html +95 -0
- package/docs/src_js_fromAudit.mjs.html +489 -0
- package/docs/src_js_getAddImpact.mjs.html +269 -0
- package/docs/src_js_getAuthWarn.mjs.html +463 -0
- package/docs/src_js_getCascadePreview.mjs.html +258 -0
- package/docs/src_js_getDelRefCount.mjs.html +210 -0
- package/docs/src_js_getEffMode.mjs.html +92 -0
- package/docs/src_js_getKpLossy.mjs.html +155 -0
- package/docs/src_js_getNameErrs.mjs.html +266 -0
- package/docs/src_js_getOwn.mjs.html +3 -3
- package/docs/src_js_getPropKey.mjs.html +109 -0
- package/docs/src_js_getRuleEnable.mjs.html +2 -2
- package/docs/src_js_isAuthMode.mjs.html +92 -0
- package/docs/src_js_joinNames.mjs.html +96 -0
- package/docs/src_js_legendFit.mjs.html +2 -2
- package/docs/src_js_pairRowsToSnapshot.mjs.html +156 -0
- package/docs/src_js_refAudit.mjs.html +359 -0
- package/docs/src_js_refCascade.mjs.html +572 -0
- package/docs/src_js_relDialogSend.mjs.html +199 -0
- package/docs/src_js_rowDigest.mjs.html +265 -0
- package/docs/src_plugins_dataReloadGuard.mjs.html +109 -0
- package/docs/src_plugins_reuseDeletedIds.mjs.html +2 -2
- package/docs/src_plugins_submitGuard.mjs.html +2 -2
- package/g_authRefsClean.mjs +79 -0
- package/g_fixFromType.mjs +92 -0
- package/g_initialData.mjs +3 -3
- package/g_purgeFrom.mjs +127 -0
- package/package.json +1 -1
- package/server/WWebPerm.mjs +243 -30
- package/server/cascadeWrite.mjs +153 -0
- package/server/keyCheck.mjs +281 -0
- package/server/procCore.mjs +178 -39
- package/server/procLang.mjs +271 -0
- package/server/syncKeep.mjs +239 -0
- package/server/tools/authRefsAudit.mjs +175 -0
- package/server/tools/authRefsClean.mjs +263 -0
- package/server/tools/fromTools.mjs +725 -0
- package/server/tools/isMain.mjs +31 -0
- package/server/tools/nameDupReport.mjs +208 -0
- package/server/validateRows.mjs +13 -2
- package/server/wrapInjected.mjs +1 -1
- package/src/components/LayoutContentGrups.vue +399 -77
- package/src/components/LayoutContentPemis.vue +400 -78
- package/src/components/LayoutContentTargets.vue +261 -25
- package/src/components/LayoutContentUsers.vue +336 -98
- package/src/components/VeCgrups.vue +119 -115
- package/src/components/VeCpemis.vue +117 -115
- package/src/components/VeCrules.vue +18 -2
- package/src/components/VeGrupBlngUsers.vue +240 -73
- package/src/components/VePemiBlngGrups.vue +247 -83
- package/src/js/cvKpToArr.mjs +53 -0
- package/src/js/cvKpToObj.mjs +138 -0
- package/src/js/draftSync.mjs +70 -0
- package/src/js/eachOwn.mjs +1 -1
- package/src/js/editorRefRows.mjs +284 -0
- package/src/js/externalRows.mjs +266 -0
- package/src/js/externalUi.mjs +158 -0
- package/src/js/findRefRows.mjs +35 -0
- package/src/js/findTouchedDup.mjs +78 -0
- package/src/js/fmtLossyMsg.mjs +23 -0
- package/src/js/fromAudit.mjs +417 -0
- package/src/js/getAddImpact.mjs +197 -0
- package/src/js/getAuthWarn.mjs +391 -0
- package/src/js/getCascadePreview.mjs +186 -0
- package/src/js/getDelRefCount.mjs +138 -0
- package/src/js/getEffMode.mjs +20 -0
- package/src/js/getKpLossy.mjs +83 -0
- package/src/js/getNameErrs.mjs +194 -0
- package/src/js/getOwn.mjs +1 -1
- package/src/js/getPropKey.mjs +37 -0
- package/src/js/isAuthMode.mjs +20 -0
- package/src/js/joinNames.mjs +24 -0
- package/src/js/pairRowsToSnapshot.mjs +84 -0
- package/src/js/refAudit.mjs +287 -0
- package/src/js/refCascade.mjs +500 -0
- package/src/js/relDialogSend.mjs +127 -0
- package/src/js/rowDigest.mjs +193 -0
- package/src/plugins/dataReloadGuard.mjs +37 -0
- package/src/plugins/mShare.mjs +147 -174
- package/src/plugins/mUI.mjs +3 -8
- package/src/schema/tables/users.mjs +152 -152
- package/dist/css/app.6918ec45.css +0 -1
- package/dist/js/app-legacy.963e800c.js +0 -1
- 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' && !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 && 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 && isStr(c.from) && 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 && typeof r === 'object' && 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 && typeof r === 'object' && 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 && typeof r === 'object' && 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 && typeof r === 'object') ? baseById.get(r.id) : undefined
|
|
148
|
+
return b !== undefined && 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 && impact.nRefs > 0 ? impact.nRefs : 0
|
|
171
|
+
let m = n > 0 && impact && impact.nAnd > 0 ? Math.min(impact.nAnd, n) : 0
|
|
172
|
+
let w = impact && 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>
|