ketekny-ui-kit 1.0.31 → 1.0.32
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/package.json +1 -1
- package/src/ui/kDatatable.vue +372 -188
package/package.json
CHANGED
package/src/ui/kDatatable.vue
CHANGED
|
@@ -1,31 +1,51 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
ref="tableWrapper"
|
|
4
|
+
:class="[
|
|
5
|
+
'k-datatable-wrapper rounded-lg border border-primary/15',
|
|
6
|
+
disabled ? 'pointer-events-none opacity-60' : '',
|
|
7
|
+
]"
|
|
8
|
+
>
|
|
3
9
|
<EasyDataTable
|
|
4
10
|
v-bind="$attrs"
|
|
5
|
-
:headers="
|
|
6
|
-
:items="
|
|
11
|
+
:headers="computedHeaders"
|
|
12
|
+
:items="keyedItems"
|
|
7
13
|
:search="search"
|
|
8
14
|
:theme-color="themeColor"
|
|
9
|
-
:show-select="
|
|
10
|
-
:single-select="effectiveSelectionMode === 'single'"
|
|
11
|
-
v-if="effectiveSelectionMode !== 'none'"
|
|
12
|
-
:items-selected="internalSelection"
|
|
13
|
-
@update:items-selected="handleSelectionUpdate"
|
|
14
|
-
:itemSelectable="itemSelectable"
|
|
15
|
+
:show-select="false"
|
|
15
16
|
:body-row-class-name="composeBodyRowClassName"
|
|
16
17
|
alternating
|
|
17
18
|
buttons-pagination
|
|
18
19
|
table-class-name="customize-table"
|
|
19
20
|
>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
<template v-if="effectiveSelectionMode === 'multiple'" #header-__kdt_select>
|
|
22
|
+
<div class="k-datatable-select-cell">
|
|
23
|
+
<input
|
|
24
|
+
type="checkbox"
|
|
25
|
+
class="easy-checkbox"
|
|
26
|
+
:checked="allSelectableSelected"
|
|
27
|
+
:indeterminate.prop="partiallySelectableSelected"
|
|
28
|
+
:disabled="disabled || pageSelectableKeys.length === 0"
|
|
29
|
+
@click.stop
|
|
30
|
+
@change="handleSelectAllChange"
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<template v-if="effectiveSelectionMode !== 'none'" #item-__kdt_select="slotItem">
|
|
36
|
+
<div class="k-datatable-select-cell">
|
|
37
|
+
<input
|
|
38
|
+
type="checkbox"
|
|
39
|
+
class="easy-checkbox"
|
|
40
|
+
:checked="isItemSelected(slotItem)"
|
|
41
|
+
:disabled="disabled || !isItemSelectable(slotItem)"
|
|
42
|
+
@click.stop
|
|
43
|
+
@change="($event) => handleItemSelectionChange($event, slotItem)"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
23
46
|
</template>
|
|
24
|
-
</EasyDataTable>
|
|
25
47
|
|
|
26
|
-
|
|
27
|
-
<EasyDataTable v-else v-bind="$attrs" :headers="headers" :items="items" :search="search" :theme-color="themeColor" :show-select="false" :body-row-class-name="composeBodyRowClassName" alternating buttons-pagination table-class-name="customize-table">
|
|
28
|
-
<template v-for="(_, name) in $slots" :key="name" v-slot:[name]="slotProps">
|
|
48
|
+
<template v-for="name in forwardedSlotNames" :key="name" v-slot:[name]="slotProps">
|
|
29
49
|
<slot :name="name" v-bind="slotProps" />
|
|
30
50
|
</template>
|
|
31
51
|
</EasyDataTable>
|
|
@@ -39,7 +59,7 @@ import "vue3-easy-data-table/dist/style.css";
|
|
|
39
59
|
export default {
|
|
40
60
|
name: "kDatatable",
|
|
41
61
|
components: { EasyDataTable },
|
|
42
|
-
inheritAttrs: false,
|
|
62
|
+
inheritAttrs: false,
|
|
43
63
|
|
|
44
64
|
props: {
|
|
45
65
|
headers: { type: Array, required: true },
|
|
@@ -59,7 +79,12 @@ export default {
|
|
|
59
79
|
|
|
60
80
|
itemSelectable: {
|
|
61
81
|
type: Function,
|
|
62
|
-
default: () =>
|
|
82
|
+
default: () => true,
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
itemKey: {
|
|
86
|
+
type: [String, Function, null],
|
|
87
|
+
default: null,
|
|
63
88
|
},
|
|
64
89
|
|
|
65
90
|
modelValue: {
|
|
@@ -72,115 +97,195 @@ export default {
|
|
|
72
97
|
|
|
73
98
|
data() {
|
|
74
99
|
return {
|
|
75
|
-
internalSelection:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
100
|
+
internalSelection: [],
|
|
101
|
+
selectedKeys: [],
|
|
102
|
+
selectedKeySet: new Set(),
|
|
103
|
+
lastSelectionAnchorKey: null,
|
|
104
|
+
currentPageRowsCache: [],
|
|
105
|
+
keyedItems: [],
|
|
106
|
+
currentItemsByKey: new Map(),
|
|
107
|
+
baseKeyToKeys: new Map(),
|
|
108
|
+
sourceItemToKey: new WeakMap(),
|
|
109
|
+
selectableKeys: [],
|
|
79
110
|
};
|
|
80
111
|
},
|
|
81
|
-
|
|
82
|
-
this.currentPageRowsCache = [];
|
|
83
|
-
},
|
|
84
|
-
mounted() {
|
|
85
|
-
this.bindSelectionInteractionListener();
|
|
86
|
-
},
|
|
87
|
-
beforeUnmount() {
|
|
88
|
-
this.unbindSelectionInteractionListener();
|
|
89
|
-
},
|
|
112
|
+
|
|
90
113
|
computed: {
|
|
91
114
|
effectiveSelectionMode() {
|
|
92
115
|
return this.disabled ? "none" : this.selectionMode;
|
|
93
116
|
},
|
|
117
|
+
computedHeaders() {
|
|
118
|
+
if (this.effectiveSelectionMode === "none") return this.headers;
|
|
119
|
+
return [{ text: "", value: "__kdt_select", width: 36 }, ...this.headers];
|
|
120
|
+
},
|
|
121
|
+
forwardedSlotNames() {
|
|
122
|
+
const reserved = new Set(["header-__kdt_select", "item-__kdt_select"]);
|
|
123
|
+
return Object.keys(this.$slots).filter((name) => !reserved.has(name));
|
|
124
|
+
},
|
|
125
|
+
pageSelectableKeys() {
|
|
126
|
+
const keys = [];
|
|
127
|
+
const seen = new Set();
|
|
128
|
+
this.currentPageRowsCache.forEach((rowItem) => {
|
|
129
|
+
const key = this.resolveIncomingItemKey(rowItem);
|
|
130
|
+
if (!key || seen.has(key)) return;
|
|
131
|
+
const sourceItem = this.currentItemsByKey.get(key);
|
|
132
|
+
if (!sourceItem || !this.isItemSelectable(sourceItem)) return;
|
|
133
|
+
seen.add(key);
|
|
134
|
+
keys.push(key);
|
|
135
|
+
});
|
|
136
|
+
return keys;
|
|
137
|
+
},
|
|
138
|
+
allSelectableSelected() {
|
|
139
|
+
if (!this.pageSelectableKeys.length) return false;
|
|
140
|
+
return this.pageSelectableKeys.every((key) => this.selectedKeySet.has(key));
|
|
141
|
+
},
|
|
142
|
+
partiallySelectableSelected() {
|
|
143
|
+
if (!this.pageSelectableKeys.length || this.allSelectableSelected) return false;
|
|
144
|
+
return this.pageSelectableKeys.some((key) => this.selectedKeySet.has(key));
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
created() {
|
|
149
|
+
this.rebuildItemCaches();
|
|
150
|
+
this.applyExternalModelValue(this.modelValue);
|
|
94
151
|
},
|
|
95
152
|
|
|
96
153
|
watch: {
|
|
154
|
+
items: {
|
|
155
|
+
handler() {
|
|
156
|
+
this.rebuildItemCaches();
|
|
157
|
+
this.reconcileSelectionWithItems();
|
|
158
|
+
},
|
|
159
|
+
deep: false,
|
|
160
|
+
},
|
|
161
|
+
itemSelectable: {
|
|
162
|
+
handler() {
|
|
163
|
+
this.rebuildItemCaches();
|
|
164
|
+
this.reconcileSelectionWithItems();
|
|
165
|
+
},
|
|
166
|
+
deep: false,
|
|
167
|
+
},
|
|
168
|
+
itemKey: {
|
|
169
|
+
handler() {
|
|
170
|
+
this.rebuildItemCaches();
|
|
171
|
+
this.reconcileSelectionWithItems();
|
|
172
|
+
},
|
|
173
|
+
deep: false,
|
|
174
|
+
},
|
|
97
175
|
modelValue(val) {
|
|
98
|
-
this.
|
|
176
|
+
this.applyExternalModelValue(val);
|
|
177
|
+
},
|
|
178
|
+
selectionMode() {
|
|
179
|
+
this.applyExternalModelValue(this.modelValue);
|
|
99
180
|
},
|
|
100
181
|
},
|
|
101
182
|
|
|
102
183
|
methods: {
|
|
103
|
-
|
|
104
|
-
if (this.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.$emit("update:modelValue", nextSelection[0] || null);
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
184
|
+
handleSelectAllChange(event) {
|
|
185
|
+
if (this.effectiveSelectionMode !== "multiple" || this.disabled) return;
|
|
186
|
+
const shouldSelect = Boolean(event?.target?.checked);
|
|
187
|
+
const nextKeySet = new Set(this.selectedKeys);
|
|
110
188
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this
|
|
121
|
-
},
|
|
122
|
-
unbindSelectionInteractionListener() {
|
|
123
|
-
this.$refs.tableWrapper?.removeEventListener("click", this.captureSelectionInteraction, true);
|
|
189
|
+
this.pageSelectableKeys.forEach((key) => {
|
|
190
|
+
if (shouldSelect) nextKeySet.add(key);
|
|
191
|
+
else nextKeySet.delete(key);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const nextKeys = this.keyedItems
|
|
195
|
+
.map((item) => item.__kdt_key)
|
|
196
|
+
.filter((itemKey) => nextKeySet.has(itemKey));
|
|
197
|
+
|
|
198
|
+
this.commitSelectionByKeys(nextKeys, { emit: true, anchorKey: null });
|
|
124
199
|
},
|
|
125
|
-
|
|
126
|
-
if (this.
|
|
200
|
+
handleItemSelectionChange(event, slotItem) {
|
|
201
|
+
if (this.effectiveSelectionMode === "none" || this.disabled) return;
|
|
202
|
+
|
|
203
|
+
const key = this.resolveIncomingItemKey(slotItem);
|
|
204
|
+
if (!key) return;
|
|
205
|
+
|
|
206
|
+
const sourceItem = this.currentItemsByKey.get(key);
|
|
207
|
+
if (!sourceItem || !this.isItemSelectable(sourceItem)) return;
|
|
208
|
+
|
|
209
|
+
const shouldSelect = Boolean(event?.target?.checked);
|
|
210
|
+
|
|
211
|
+
if (this.selectionMode === "single") {
|
|
212
|
+
this.commitSelectionByKeys(shouldSelect ? [key] : [], {
|
|
213
|
+
emit: true,
|
|
214
|
+
anchorKey: shouldSelect ? key : null,
|
|
215
|
+
});
|
|
127
216
|
return;
|
|
128
217
|
}
|
|
129
218
|
|
|
130
|
-
|
|
131
|
-
|
|
219
|
+
if (event?.shiftKey && this.lastSelectionAnchorKey && key !== this.lastSelectionAnchorKey) {
|
|
220
|
+
const selectableKeySet = new Set(this.selectableKeys);
|
|
221
|
+
const rangeKeys = this.resolveRangeKeys(this.lastSelectionAnchorKey, key).filter((rangeKey) =>
|
|
222
|
+
selectableKeySet.has(rangeKey),
|
|
223
|
+
);
|
|
224
|
+
const nextKeySet = new Set(this.selectedKeys);
|
|
225
|
+
|
|
226
|
+
rangeKeys.forEach((rangeKey) => {
|
|
227
|
+
if (shouldSelect) nextKeySet.add(rangeKey);
|
|
228
|
+
else nextKeySet.delete(rangeKey);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const nextKeys = this.keyedItems
|
|
232
|
+
.map((item) => item.__kdt_key)
|
|
233
|
+
.filter((itemKey) => nextKeySet.has(itemKey));
|
|
132
234
|
|
|
133
|
-
|
|
134
|
-
if (!row) {
|
|
135
|
-
// Clear pending row interaction so bulk select doesn't reuse stale row state.
|
|
136
|
-
this.pendingSelectionInteraction = null;
|
|
235
|
+
this.commitSelectionByKeys(nextKeys, { emit: true });
|
|
137
236
|
return;
|
|
138
237
|
}
|
|
139
238
|
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
142
|
-
|
|
239
|
+
const nextKeySet = new Set(this.selectedKeys);
|
|
240
|
+
if (shouldSelect) nextKeySet.add(key);
|
|
241
|
+
else nextKeySet.delete(key);
|
|
143
242
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
243
|
+
const nextKeys = this.keyedItems
|
|
244
|
+
.map((item) => item.__kdt_key)
|
|
245
|
+
.filter((itemKey) => nextKeySet.has(itemKey));
|
|
148
246
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
247
|
+
this.commitSelectionByKeys(nextKeys, { emit: true, anchorKey: key });
|
|
248
|
+
},
|
|
249
|
+
isItemSelected(item) {
|
|
250
|
+
const key = this.resolveIncomingItemKey(item);
|
|
251
|
+
return key != null && this.selectedKeySet.has(key);
|
|
252
|
+
},
|
|
253
|
+
isItemSelectable(item) {
|
|
254
|
+
if (typeof this.itemSelectable !== "function") return true;
|
|
255
|
+
try {
|
|
256
|
+
return this.itemSelectable(this.normalizeItem(item)) !== false;
|
|
257
|
+
} catch {
|
|
258
|
+
return false;
|
|
162
259
|
}
|
|
163
|
-
|
|
164
|
-
this.pendingSelectionInteraction = {
|
|
165
|
-
shiftKey: event.shiftKey,
|
|
166
|
-
rowNumber,
|
|
167
|
-
};
|
|
168
260
|
},
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
261
|
+
resolveRangeKeys(anchorKey, targetKey) {
|
|
262
|
+
const visibleKeys = this.currentPageRowsCache
|
|
263
|
+
.map((item) => this.resolveIncomingItemKey(item))
|
|
264
|
+
.filter((key) => key != null);
|
|
265
|
+
|
|
266
|
+
const fallbackKeys = this.keyedItems.map((item) => item.__kdt_key);
|
|
267
|
+
const keyOrders = visibleKeys.length ? [visibleKeys, fallbackKeys] : [fallbackKeys];
|
|
268
|
+
|
|
269
|
+
for (const orderedKeys of keyOrders) {
|
|
270
|
+
const anchorIndex = orderedKeys.indexOf(anchorKey);
|
|
271
|
+
const targetIndex = orderedKeys.indexOf(targetKey);
|
|
272
|
+
if (anchorIndex === -1 || targetIndex === -1) continue;
|
|
273
|
+
|
|
274
|
+
const [start, end] =
|
|
275
|
+
anchorIndex <= targetIndex ? [anchorIndex, targetIndex] : [targetIndex, anchorIndex];
|
|
276
|
+
return orderedKeys.slice(start, end + 1);
|
|
277
|
+
}
|
|
172
278
|
|
|
173
|
-
|
|
174
|
-
const rowIndex = selectableRows.indexOf(rowElement);
|
|
175
|
-
return rowIndex === -1 ? null : rowIndex + 1;
|
|
279
|
+
return [targetKey];
|
|
176
280
|
},
|
|
177
281
|
composeBodyRowClassName(item, rowNumber) {
|
|
178
282
|
if (rowNumber === 1) {
|
|
179
283
|
this.currentPageRowsCache = [];
|
|
180
284
|
}
|
|
181
|
-
this.currentPageRowsCache[rowNumber - 1] =
|
|
285
|
+
this.currentPageRowsCache[rowNumber - 1] = item;
|
|
182
286
|
|
|
183
|
-
const externalBodyRowClass =
|
|
287
|
+
const externalBodyRowClass =
|
|
288
|
+
this.$attrs["body-row-class-name"] ?? this.$attrs.bodyRowClassName;
|
|
184
289
|
if (typeof externalBodyRowClass === "function") {
|
|
185
290
|
return externalBodyRowClass(item, rowNumber);
|
|
186
291
|
}
|
|
@@ -189,126 +294,200 @@ export default {
|
|
|
189
294
|
}
|
|
190
295
|
return "";
|
|
191
296
|
},
|
|
192
|
-
|
|
193
|
-
|
|
297
|
+
rebuildItemCaches() {
|
|
298
|
+
const keyedItems = [];
|
|
299
|
+
const currentItemsByKey = new Map();
|
|
300
|
+
const baseKeyToKeys = new Map();
|
|
301
|
+
const sourceItemToKey = new WeakMap();
|
|
302
|
+
const selectableKeys = [];
|
|
303
|
+
|
|
304
|
+
this.items.forEach((sourceItem, index) => {
|
|
305
|
+
const baseKey = this.deriveBaseKey(sourceItem, index);
|
|
306
|
+
const uniqueKey = this.ensureUniqueKey(baseKey, currentItemsByKey);
|
|
307
|
+
const normalizedItem = this.normalizeItem(sourceItem);
|
|
308
|
+
const keyedItem =
|
|
309
|
+
normalizedItem && typeof normalizedItem === "object"
|
|
310
|
+
? { ...normalizedItem, __kdt_key: uniqueKey }
|
|
311
|
+
: { value: normalizedItem, __kdt_key: uniqueKey };
|
|
312
|
+
|
|
313
|
+
keyedItems.push(keyedItem);
|
|
314
|
+
currentItemsByKey.set(uniqueKey, sourceItem);
|
|
315
|
+
|
|
316
|
+
if (sourceItem && typeof sourceItem === "object") {
|
|
317
|
+
sourceItemToKey.set(sourceItem, uniqueKey);
|
|
318
|
+
}
|
|
194
319
|
|
|
195
|
-
|
|
196
|
-
|
|
320
|
+
const keyList = baseKeyToKeys.get(baseKey) ?? [];
|
|
321
|
+
keyList.push(uniqueKey);
|
|
322
|
+
baseKeyToKeys.set(baseKey, keyList);
|
|
197
323
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
324
|
+
if (this.isItemSelectable(sourceItem)) {
|
|
325
|
+
selectableKeys.push(uniqueKey);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
this.keyedItems = keyedItems;
|
|
330
|
+
this.currentItemsByKey = currentItemsByKey;
|
|
331
|
+
this.baseKeyToKeys = baseKeyToKeys;
|
|
332
|
+
this.sourceItemToKey = sourceItemToKey;
|
|
333
|
+
this.selectableKeys = selectableKeys;
|
|
334
|
+
this.currentPageRowsCache = [];
|
|
335
|
+
},
|
|
336
|
+
ensureUniqueKey(baseKey, usedKeysMap) {
|
|
337
|
+
if (!usedKeysMap.has(baseKey)) return baseKey;
|
|
338
|
+
let suffix = 1;
|
|
339
|
+
let candidate = `${baseKey}#${suffix}`;
|
|
340
|
+
while (usedKeysMap.has(candidate)) {
|
|
341
|
+
suffix += 1;
|
|
342
|
+
candidate = `${baseKey}#${suffix}`;
|
|
343
|
+
}
|
|
344
|
+
return candidate;
|
|
345
|
+
},
|
|
346
|
+
deriveBaseKey(item, index = null) {
|
|
347
|
+
const normalized = this.normalizeItem(item);
|
|
348
|
+
const configuredKey = this.resolveConfiguredKey(normalized, index);
|
|
349
|
+
if (configuredKey != null && configuredKey !== "") {
|
|
350
|
+
return `k:${String(configuredKey)}`;
|
|
351
|
+
}
|
|
204
352
|
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
353
|
+
if (normalized && typeof normalized === "object") {
|
|
354
|
+
if (normalized.id != null) return `id:${String(normalized.id)}`;
|
|
355
|
+
if (normalized.uuid != null) return `uuid:${String(normalized.uuid)}`;
|
|
356
|
+
if (normalized.hospIncNumber != null) {
|
|
357
|
+
return `hospIncNumber:${String(normalized.hospIncNumber)}`;
|
|
358
|
+
}
|
|
209
359
|
}
|
|
210
360
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return
|
|
361
|
+
if (index != null) return `index:${index}`;
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
return `json:${JSON.stringify(normalized)}`;
|
|
365
|
+
} catch {
|
|
366
|
+
return "fallback:0";
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
resolveConfiguredKey(item, index = null) {
|
|
370
|
+
if (!this.itemKey) return null;
|
|
371
|
+
|
|
372
|
+
if (typeof this.itemKey === "function") {
|
|
373
|
+
try {
|
|
374
|
+
return this.itemKey(item, index);
|
|
375
|
+
} catch {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
217
378
|
}
|
|
218
379
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const shouldSelectRange = this.containsItem(newSelection, toggledItem);
|
|
222
|
-
return this.applyRangeSelection(newSelection, anchorIndex, targetIndex, interaction.rowNumber, shouldSelectRange);
|
|
223
|
-
},
|
|
224
|
-
applyRangeSelection(baseSelection, anchorIndex, targetIndex, targetRowNumber, shouldSelectRange) {
|
|
225
|
-
const rangeItems = this.getRangeItems(anchorIndex, targetIndex, targetRowNumber);
|
|
226
|
-
if (!rangeItems.length) return baseSelection;
|
|
227
|
-
|
|
228
|
-
let nextSelection = [...baseSelection];
|
|
229
|
-
if (shouldSelectRange) {
|
|
230
|
-
rangeItems.forEach((item) => {
|
|
231
|
-
if (!this.containsItem(nextSelection, item)) {
|
|
232
|
-
nextSelection.push(this.normalizeItem(item));
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
} else {
|
|
236
|
-
nextSelection = nextSelection.filter((selectedItem) => !rangeItems.some((item) => this.areItemsEqual(selectedItem, item)));
|
|
380
|
+
if (typeof this.itemKey === "string" && item && typeof item === "object") {
|
|
381
|
+
return item[this.itemKey];
|
|
237
382
|
}
|
|
238
383
|
|
|
239
|
-
return
|
|
384
|
+
return null;
|
|
240
385
|
},
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
const
|
|
246
|
-
if (
|
|
247
|
-
return
|
|
386
|
+
resolveIncomingItemKey(item, index = null) {
|
|
387
|
+
const normalized = this.normalizeItem(item);
|
|
388
|
+
|
|
389
|
+
if (normalized && typeof normalized === "object") {
|
|
390
|
+
const slotKey = normalized.__kdt_key;
|
|
391
|
+
if (slotKey != null && this.currentItemsByKey.has(String(slotKey))) {
|
|
392
|
+
return String(slotKey);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const byReference = this.sourceItemToKey.get(normalized);
|
|
396
|
+
if (byReference && this.currentItemsByKey.has(byReference)) {
|
|
397
|
+
return byReference;
|
|
248
398
|
}
|
|
249
399
|
}
|
|
250
400
|
|
|
251
|
-
const
|
|
252
|
-
|
|
401
|
+
const baseKey = this.deriveBaseKey(normalized, index);
|
|
402
|
+
const candidates = this.baseKeyToKeys.get(baseKey) ?? [];
|
|
403
|
+
|
|
404
|
+
if (candidates.length === 1) return candidates[0];
|
|
405
|
+
if (candidates.length > 1) return candidates[0];
|
|
406
|
+
return null;
|
|
253
407
|
},
|
|
254
408
|
normalizeItem(item) {
|
|
255
409
|
if (!item || typeof item !== "object") return item;
|
|
256
410
|
const normalized = { ...item };
|
|
257
411
|
delete normalized.checkbox;
|
|
258
412
|
delete normalized.index;
|
|
413
|
+
delete normalized.__kdt_select;
|
|
259
414
|
return normalized;
|
|
260
415
|
},
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (normalized.uuid != null) return `uuid:${normalized.uuid}`;
|
|
266
|
-
if (normalized.hospIncNumber != null) return `hospIncNumber:${normalized.hospIncNumber}`;
|
|
267
|
-
return null;
|
|
268
|
-
},
|
|
269
|
-
areItemsEqual(left, right) {
|
|
270
|
-
const leftKey = this.extractStableKey(left);
|
|
271
|
-
const rightKey = this.extractStableKey(right);
|
|
272
|
-
if (leftKey != null || rightKey != null) {
|
|
273
|
-
return leftKey != null && leftKey === rightKey;
|
|
416
|
+
applyExternalModelValue(value) {
|
|
417
|
+
if (this.selectionMode === "none") {
|
|
418
|
+
this.commitSelectionByKeys([], { emit: false, anchorKey: null });
|
|
419
|
+
return;
|
|
274
420
|
}
|
|
275
421
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return
|
|
280
|
-
} catch {
|
|
281
|
-
return normalizedLeft === normalizedRight;
|
|
422
|
+
if (this.selectionMode === "single") {
|
|
423
|
+
const key = value ? this.resolveIncomingItemKey(value) : null;
|
|
424
|
+
this.commitSelectionByKeys(key ? [key] : [], { emit: false, anchorKey: key ?? null });
|
|
425
|
+
return;
|
|
282
426
|
}
|
|
427
|
+
|
|
428
|
+
const incomingArray = Array.isArray(value) ? value : [];
|
|
429
|
+
const nextKeys = incomingArray
|
|
430
|
+
.map((item, index) => this.resolveIncomingItemKey(item, index))
|
|
431
|
+
.filter((key) => key != null);
|
|
432
|
+
this.commitSelectionByKeys(nextKeys, { emit: false });
|
|
283
433
|
},
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
434
|
+
reconcileSelectionWithItems() {
|
|
435
|
+
const changed = this.commitSelectionByKeys(this.selectedKeys, { emit: false });
|
|
436
|
+
if (changed) {
|
|
437
|
+
this.emitSelection();
|
|
438
|
+
}
|
|
289
439
|
},
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
440
|
+
commitSelectionByKeys(keys, { emit = true, anchorKey } = {}) {
|
|
441
|
+
const requestedKeys = Array.isArray(keys) ? keys : [];
|
|
442
|
+
const nextKeys = [];
|
|
443
|
+
const seen = new Set();
|
|
444
|
+
|
|
445
|
+
requestedKeys.forEach((key) => {
|
|
446
|
+
if (key == null || seen.has(key)) return;
|
|
447
|
+
const sourceItem = this.currentItemsByKey.get(key);
|
|
448
|
+
if (!sourceItem || !this.isItemSelectable(sourceItem)) return;
|
|
449
|
+
seen.add(key);
|
|
450
|
+
nextKeys.push(key);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
if (this.selectionMode === "single" && nextKeys.length > 1) {
|
|
454
|
+
nextKeys.splice(1);
|
|
455
|
+
}
|
|
294
456
|
|
|
295
|
-
const
|
|
296
|
-
if (removed.length === 1) return this.normalizeItem(removed[0]);
|
|
457
|
+
const hasChanged = !this.areKeyArraysEqual(nextKeys, this.selectedKeys);
|
|
297
458
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
459
|
+
this.selectedKeys = nextKeys;
|
|
460
|
+
this.selectedKeySet = new Set(nextKeys);
|
|
461
|
+
this.internalSelection = nextKeys
|
|
462
|
+
.map((key) => this.currentItemsByKey.get(key))
|
|
463
|
+
.filter((item) => item != null);
|
|
464
|
+
|
|
465
|
+
if (anchorKey !== undefined) {
|
|
466
|
+
this.lastSelectionAnchorKey = anchorKey;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (emit && hasChanged) {
|
|
470
|
+
this.emitSelection();
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return hasChanged;
|
|
302
474
|
},
|
|
303
|
-
|
|
304
|
-
if (
|
|
305
|
-
return
|
|
475
|
+
areKeyArraysEqual(left, right) {
|
|
476
|
+
if (left.length !== right.length) return false;
|
|
477
|
+
return left.every((key, index) => key === right[index]);
|
|
306
478
|
},
|
|
307
|
-
|
|
308
|
-
if (this.selectionMode === "
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
479
|
+
emitSelection() {
|
|
480
|
+
if (this.selectionMode === "single") {
|
|
481
|
+
this.$emit("update:modelValue", this.internalSelection[0] ?? null);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (this.selectionMode === "multiple") {
|
|
486
|
+
this.$emit("update:modelValue", [...this.internalSelection]);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
this.$emit("update:modelValue", null);
|
|
312
491
|
},
|
|
313
492
|
},
|
|
314
493
|
};
|
|
@@ -348,12 +527,11 @@ export default {
|
|
|
348
527
|
--easy-table-footer-background-color: transparent;
|
|
349
528
|
--easy-table-footer-font-color: #1f2937;
|
|
350
529
|
--easy-table-footer-font-size: 14px;
|
|
351
|
-
--easy-table-footer-padding: 1rem;
|
|
530
|
+
--easy-table-footer-padding: 1rem;
|
|
352
531
|
--easy-table-footer-height: auto;
|
|
353
532
|
|
|
354
533
|
--easy-table-rows-per-page-selector-width: 70px;
|
|
355
534
|
--easy-table-rows-per-page-selector-option-padding: 10px;
|
|
356
|
-
--easy-table-rows-per-page-selector-z-index: 1;
|
|
357
535
|
--easy-table-rows-per-page-selector-z-index: 200;
|
|
358
536
|
--easy-table-rows-per-page-selector-font-color: #1f2937;
|
|
359
537
|
|
|
@@ -365,11 +543,17 @@ export default {
|
|
|
365
543
|
--easy-table-loading-mask-background-color: rgba(255, 255, 255, 0.6);
|
|
366
544
|
}
|
|
367
545
|
|
|
546
|
+
.k-datatable-select-cell {
|
|
547
|
+
display: flex;
|
|
548
|
+
align-items: center;
|
|
549
|
+
justify-content: center;
|
|
550
|
+
}
|
|
551
|
+
|
|
368
552
|
/* Target the rows-per-page dropdown */
|
|
369
553
|
.customize-table .easy-data-table__footer select {
|
|
370
|
-
background-color: #fff;
|
|
371
|
-
color: #1f2937;
|
|
372
|
-
padding: 0.25rem 0.5rem;
|
|
554
|
+
background-color: #fff;
|
|
555
|
+
color: #1f2937;
|
|
556
|
+
padding: 0.25rem 0.5rem;
|
|
373
557
|
border: 1px solid #bfdbfe;
|
|
374
558
|
border-radius: 0.25rem;
|
|
375
559
|
}
|