umy-ui-table 1.2.3 → 1.2.5

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 (59) hide show
  1. package/lib/button.js +1 -1
  2. package/lib/icon.js +1 -1
  3. package/lib/index.js +1 -1
  4. package/lib/locale/format.js +1 -1
  5. package/lib/locale/index.js +1 -72
  6. package/lib/mixins/locale.js +1 -1
  7. package/lib/theme-chalk/button.css +1 -1
  8. package/lib/theme-chalk/icon.css +1 -1
  9. package/lib/theme-chalk/iconfont.1785242763644.ttf +0 -0
  10. package/lib/theme-chalk/iconfont.1785242763644.woff +0 -0
  11. package/lib/theme-chalk/iconfont.1785242763644.woff2 +0 -0
  12. package/lib/theme-chalk/index.css +1 -1
  13. package/lib/theme-chalk/u-table.css +1 -1
  14. package/lib/theme-chalk/ux-grid.css +1 -1
  15. package/lib/u-table-column.js +1 -1
  16. package/lib/u-table.js +1 -1
  17. package/lib/umy-ui.common.js +1 -1
  18. package/lib/utils/util.js +1 -1
  19. package/lib/ux-grid.js +1 -1
  20. package/lib/ux-table-column.js +1 -1
  21. package/package.json +4 -3
  22. package/packages/.DS_Store +0 -0
  23. package/packages/input/.DS_Store +0 -0
  24. package/packages/pagination/.DS_Store +0 -0
  25. package/packages/scrollbar/.DS_Store +0 -0
  26. package/packages/select/.DS_Store +0 -0
  27. package/packages/table/.DS_Store +0 -0
  28. package/packages/tag/.DS_Store +0 -0
  29. package/packages/tools/.DS_Store +0 -0
  30. package/packages/tools/locale/index.js +2 -48
  31. package/packages/tools/utils/.DS_Store +0 -0
  32. package/packages/tooltip/.DS_Store +0 -0
  33. package/packages/u-table/.DS_Store +0 -0
  34. package/packages/ux-grid/.DS_Store +0 -0
  35. package/packages/ux-grid/mixins/index.js +136 -29
  36. package/packages/ux-grid/src/dialog-draft.js +75 -0
  37. package/packages/ux-grid/src/element-renderer.js +784 -0
  38. package/packages/ux-grid/src/grid-height.js +65 -0
  39. package/packages/ux-grid/src/grid-kernel.js +14 -0
  40. package/packages/ux-grid/src/setup.js +42 -0
  41. package/packages/ux-grid/src/ux-grid.vue +225 -44
  42. package/packages/ux-grid/test/browser-acceptance.cjs +192 -0
  43. package/packages/ux-grid/test/browser-baseline-loader.cjs +10 -0
  44. package/packages/ux-grid/test/browser-entry.js +242 -0
  45. package/packages/ux-grid/test/browser-renderer-contracts.cjs +246 -0
  46. package/packages/ux-grid/test/browser-renderer-entry.js +129 -0
  47. package/packages/ux-grid/test/browser-resize-contracts.cjs +150 -0
  48. package/packages/ux-grid/test/compatibility.cjs +176 -0
  49. package/packages/ux-grid/test/contracts.cjs +281 -0
  50. package/packages/ux-grid/test/delivery.cjs +103 -0
  51. package/packages/ux-grid/test/integration.cjs +132 -0
  52. package/packages/ux-grid/test/real-kernel-contracts.cjs +335 -0
  53. package/packages/ux-grid/test/real-kernel-events.cjs +233 -0
  54. package/packages/ux-grid/test/renderer-boundaries.cjs +165 -0
  55. package/packages/ux-grid/test/ui-components.cjs +103 -0
  56. package/tools/locale/format.js +1 -1
  57. package/tools/locale/index.js +1 -7
  58. package/tools/mixins/locale.js +1 -1
  59. package/tools/utils/util.js +1 -1
@@ -0,0 +1,784 @@
1
+ import XEUtils from "xe-utils";
2
+ import "./setup";
3
+ import { renderer, interceptor } from "vxe-table/lib/ui";
4
+
5
+ const inputRendererNames = [
6
+ "ElAutocomplete",
7
+ "ElInput",
8
+ "ElInputNumber",
9
+ "ElRate",
10
+ "ElSwitch",
11
+ "ElSlider",
12
+ ];
13
+
14
+ const popupClassNames = [
15
+ "el-autocomplete-suggestion",
16
+ "el-select-dropdown",
17
+ "el-cascader__dropdown",
18
+ "el-cascader-menus",
19
+ "el-time-panel",
20
+ "el-picker-panel",
21
+ "el-color-dropdown",
22
+ ];
23
+
24
+ function isEmptyValue(value) {
25
+ return value === null || value === undefined || value === "";
26
+ }
27
+
28
+ function getCellValue({ row, column }) {
29
+ return XEUtils.get(row, column.field || column.property);
30
+ }
31
+
32
+ function setCellValue({ row, column }, value) {
33
+ XEUtils.set(row, column.field || column.property, value);
34
+ }
35
+
36
+ function getComponentProps(renderOpts, params, value, extraProps) {
37
+ const size = params.$table && params.$table.vSize;
38
+ return XEUtils.assign(
39
+ size ? { size } : {},
40
+ renderOpts.name === "ElCascader" ? { options: renderOpts.options } : {},
41
+ extraProps,
42
+ renderOpts.props,
43
+ { value }
44
+ );
45
+ }
46
+
47
+ function getNativeOns(renderOpts, params) {
48
+ const nativeOns = {};
49
+ XEUtils.objectEach(renderOpts.nativeEvents, (callback, name) => {
50
+ nativeOns[name] = (...args) => callback(params, ...args);
51
+ });
52
+ return nativeOns;
53
+ }
54
+
55
+ function getEventOns(renderOpts, params, modelCallback, changeCallback) {
56
+ const events = renderOpts.events || {};
57
+ // Element emits input as well as change/select. Write the model on input,
58
+ // but validate/activate filters only on that component's legacy status event.
59
+ const statusEvent = renderOpts.name === "ElAutocomplete" ? "select"
60
+ : ["ElInput", "ElInputNumber"].indexOf(renderOpts.name) > -1 ? "input" : "change";
61
+ const ons = {};
62
+ XEUtils.objectEach(events, (callback, name) => {
63
+ ons[name] = (...args) => callback(params, ...args);
64
+ });
65
+
66
+ if (modelCallback) {
67
+ ons.input = (value) => {
68
+ modelCallback(value);
69
+ if (events.input) events.input(params, value);
70
+ if (statusEvent === "input" && changeCallback) changeCallback(value);
71
+ };
72
+ }
73
+ if (changeCallback && statusEvent !== "input") {
74
+ ons[statusEvent] = (...args) => {
75
+ changeCallback(...args);
76
+ if (events[statusEvent]) events[statusEvent](params, ...args);
77
+ };
78
+ }
79
+ return ons;
80
+ }
81
+
82
+ function getEditOns(renderOpts, params) {
83
+ const { $table } = params;
84
+ return getEventOns(
85
+ renderOpts,
86
+ params,
87
+ (value) => {
88
+ setCellValue(params, value);
89
+ },
90
+ () => {
91
+ // Body-mounted Element popups deactivate VXE's table on mousedown even
92
+ // when its edit-close interceptor vetoes closing. Restore activation so
93
+ // the ensuing component change still runs the kernel's change rules.
94
+ const getEditRecord = $table.getEditCell || $table.getEditRecord;
95
+ const active = getEditRecord && getEditRecord.call($table);
96
+ if (active && active.row === params.row && $table.focus) $table.focus();
97
+ $table.updateStatus(params);
98
+ }
99
+ );
100
+ }
101
+
102
+ function getFilterOns(renderOpts, params, option) {
103
+ const updateOption = () => {
104
+ const checked = Array.isArray(option.data)
105
+ ? option.data.length > 0
106
+ : !isEmptyValue(option.data);
107
+ if (params.$panel && params.$panel.changeOption) {
108
+ params.$panel.changeOption({}, checked, option);
109
+ } else if (params.$table && params.$table.updateFilterOptionStatus) {
110
+ params.$table.updateFilterOptionStatus(option, checked);
111
+ }
112
+ };
113
+ return getEventOns(
114
+ renderOpts,
115
+ params,
116
+ (value) => {
117
+ option.data = value;
118
+ },
119
+ updateOption
120
+ );
121
+ }
122
+
123
+ function renderComponent(h, renderOpts, params, value, ons, extraProps, children) {
124
+ return [
125
+ h(renderOpts.name, {
126
+ attrs: renderOpts.attrs,
127
+ props: getComponentProps(renderOpts, params, value, extraProps),
128
+ on: ons,
129
+ nativeOn: getNativeOns(renderOpts, params),
130
+ }, children),
131
+ ];
132
+ }
133
+
134
+ function renderEdit(h, renderOpts, params) {
135
+ return renderComponent(
136
+ h,
137
+ renderOpts,
138
+ params,
139
+ getCellValue(params),
140
+ getEditOns(renderOpts, params)
141
+ );
142
+ }
143
+
144
+ function renderFilter(h, renderOpts, params) {
145
+ return params.column.filters.map((option) =>
146
+ renderComponent(
147
+ h,
148
+ renderOpts,
149
+ params,
150
+ option.data,
151
+ getFilterOns(renderOpts, params, option)
152
+ )[0]
153
+ );
154
+ }
155
+
156
+ function isEqualValue(left, right) {
157
+ if (left === right) return true;
158
+ if (isEmptyValue(left) || isEmptyValue(right)) return false;
159
+ return String(left) === String(right);
160
+ }
161
+
162
+ function filterMethod({ option, row, column }) {
163
+ return isEqualValue(
164
+ XEUtils.get(row, column.field || column.property),
165
+ option.data
166
+ );
167
+ }
168
+
169
+ function selectFilterMethod({ option, row, column }) {
170
+ const renderOpts = column.filterRender || {};
171
+ const props = renderOpts.props || {};
172
+ const cellValue = XEUtils.get(row, column.field || column.property);
173
+ const optionValue = option.data;
174
+ if (!props.multiple) return isEqualValue(cellValue, optionValue);
175
+ if (Array.isArray(cellValue)) {
176
+ const values = Array.isArray(optionValue) ? optionValue : [optionValue];
177
+ return values.every((value) => cellValue.indexOf(value) > -1);
178
+ }
179
+ return Array.isArray(optionValue) && optionValue.indexOf(cellValue) > -1;
180
+ }
181
+
182
+ const selectLabelCache = new WeakMap();
183
+
184
+ function getSelectLabel(renderOpts, value, params) {
185
+ const props = renderOpts.props || {};
186
+ const optionProps = renderOpts.optionProps || {};
187
+ const groupProps = renderOpts.optionGroupProps || {};
188
+ const labelProp = optionProps.label || "label";
189
+ const valueProp = optionProps.value || "value";
190
+ const optionsProp = groupProps.options || "options";
191
+ let options = renderOpts.options || [];
192
+
193
+ if (renderOpts.optionGroups) {
194
+ options = [];
195
+ renderOpts.optionGroups.forEach((group) => {
196
+ options = options.concat(group[optionsProp] || []);
197
+ });
198
+ }
199
+
200
+ const values = props.multiple && Array.isArray(value) ? value : [value];
201
+ let cache;
202
+ if ((props.filterable || props.remote) && params && params.row && params.column) {
203
+ let columns = selectLabelCache.get(params.row);
204
+ if (!columns) selectLabelCache.set(params.row, (columns = new WeakMap()));
205
+ cache = columns.get(params.column);
206
+ if (!cache) columns.set(params.column, (cache = new Map()));
207
+ }
208
+ return values
209
+ .map((itemValue) => {
210
+ const option = options.find(
211
+ (item) => item && item[valueProp] === itemValue
212
+ );
213
+ if (option) {
214
+ if (cache) cache.set(itemValue, option[labelProp]);
215
+ return option[labelProp];
216
+ }
217
+ return cache && cache.has(itemValue) ? cache.get(itemValue) : itemValue;
218
+ })
219
+ .filter((label) => !isEmptyValue(label))
220
+ .join(", ");
221
+ }
222
+
223
+ function selectCellRender(h, renderOpts, params) {
224
+ return [String(getSelectLabel(renderOpts, getCellValue(params), params) || "")];
225
+ }
226
+
227
+ // Element Select 通过子组件收集选项,不接收 options 配置属性。
228
+ function renderSelectOptions(h, renderOpts) {
229
+ const props = renderOpts.optionProps || {};
230
+ const groupProps = renderOpts.optionGroupProps || {};
231
+ const renderOptions = (options) => (options || []).map((option, index) =>
232
+ h("el-option", {
233
+ key: index,
234
+ props: {
235
+ value: option[props.value || "value"],
236
+ label: option[props.label || "label"],
237
+ disabled: option[props.disabled || "disabled"],
238
+ },
239
+ })
240
+ );
241
+ return renderOpts.optionGroups
242
+ ? renderOpts.optionGroups.map((group, index) => h("el-option-group", {
243
+ key: index,
244
+ props: { label: group[groupProps.label || "label"], disabled: group[groupProps.disabled || "disabled"] },
245
+ }, renderOptions(group[groupProps.options || "options"])))
246
+ : renderOptions(renderOpts.options);
247
+ }
248
+
249
+ function selectEditRender(h, renderOpts, params) {
250
+ getSelectLabel(renderOpts, getCellValue(params), params);
251
+ const ons = getEditOns(renderOpts, params);
252
+ const onInput = ons.input;
253
+ ons.input = (value) => {
254
+ getSelectLabel(renderOpts, value, params);
255
+ onInput(value);
256
+ };
257
+ return renderComponent(
258
+ h,
259
+ renderOpts,
260
+ params,
261
+ getCellValue(params),
262
+ ons,
263
+ undefined,
264
+ renderSelectOptions(h, renderOpts)
265
+ );
266
+ }
267
+
268
+ function selectFilterRender(h, renderOpts, params) {
269
+ return params.column.filters.map((option) =>
270
+ renderComponent(
271
+ h,
272
+ renderOpts,
273
+ params,
274
+ option.data,
275
+ getFilterOns(renderOpts, params, option),
276
+ undefined,
277
+ renderSelectOptions(h, renderOpts)
278
+ )[0]
279
+ );
280
+ }
281
+
282
+ const cascaderLabelCache = new WeakMap();
283
+
284
+ function getCascaderOptionIdentity(options, config, identity) {
285
+ if (!Array.isArray(options)) return;
286
+ identity.push(options, options.length);
287
+ options.forEach((option) => {
288
+ identity.push(option, option[config.value || "value"], option[config.leaf || "leaf"]);
289
+ getCascaderOptionIdentity(option[config.children || "children"], config, identity);
290
+ });
291
+ }
292
+
293
+ function getCascaderIdentity(renderOpts) {
294
+ const props = renderOpts.props || {};
295
+ const config = props.props || {};
296
+ const identity = [props.options || renderOpts.options, config.lazyLoad, config.lazy,
297
+ config.value, config.label, config.children, config.leaf, config.disabled,
298
+ config.emitPath, config.multiple, config.checkStrictly];
299
+ getCascaderOptionIdentity(props.options || renderOpts.options, config, identity);
300
+ return identity;
301
+ }
302
+
303
+ function sameCascaderIdentity(left, right) {
304
+ return left.length === right.length && left.every((value, index) => value === right[index]);
305
+ }
306
+
307
+ function getCascaderCache(params, create, renderOpts) {
308
+ if (!params || !params.row || !params.column) return;
309
+ let columns = cascaderLabelCache.get(params.row);
310
+ if (!columns && create) cascaderLabelCache.set(params.row, (columns = new WeakMap()));
311
+ if (!columns) return;
312
+ let cache = columns.get(params.column);
313
+ const identity = getCascaderIdentity(renderOpts);
314
+ if (cache && !sameCascaderIdentity(identity, cache.identity)) {
315
+ columns.delete(params.column);
316
+ cache = undefined;
317
+ }
318
+ if (!cache && create) columns.set(params.column, (cache = new Map()));
319
+ if (cache && !cache.identity) {
320
+ cache.identity = identity;
321
+ cache.loaded = new Map();
322
+ cache.hydrated = new WeakSet();
323
+ cache.arrays = new WeakMap();
324
+ cache.items = new WeakMap();
325
+ cache.empty = [];
326
+ }
327
+ return cache;
328
+ }
329
+
330
+ function getCascaderOptions(options, config, cache, path = []) {
331
+ const valueKey = config.value || "value";
332
+ const childrenKey = config.children || "children";
333
+ const leafKey = config.leaf || "leaf";
334
+ const source = options || cache.loaded.get(JSON.stringify(path)) || cache.empty;
335
+ const result = source.map((item) => {
336
+ const itemPath = path.concat(item[valueKey]);
337
+ const loaded = cache.loaded.get(JSON.stringify(itemPath));
338
+ const explicit = Array.isArray(item[childrenKey]);
339
+ if (!explicit && !loaded) return item;
340
+ const children = getCascaderOptions(explicit ? item[childrenKey] : loaded, config, cache, itemPath);
341
+ if (explicit && children === item[childrenKey]) return item;
342
+ const previous = cache.items.get(item);
343
+ if (previous && previous.children === children &&
344
+ Object.keys(previous.original).length === Object.keys(item).length &&
345
+ Object.keys(item).every((key) => previous.original[key] === item[key])) return previous.option;
346
+ const option = Object.assign({}, item, { [childrenKey]: children });
347
+ if (!explicit) {
348
+ cache.hydrated.add(option);
349
+ if (!children.length && option[leafKey] === undefined) option[leafKey] = true;
350
+ }
351
+ cache.items.set(item, { original: Object.assign({}, item), children, option });
352
+ return option;
353
+ });
354
+ if (result.every((item, index) => item === source[index])) return source;
355
+ const previous = cache.arrays.get(source);
356
+ if (previous && previous.length === result.length && result.every((item, index) => item === previous[index])) return previous;
357
+ cache.arrays.set(source, result);
358
+ return result;
359
+ }
360
+
361
+ function cascaderEditRender(h, renderOpts, params) {
362
+ const ons = getEditOns(renderOpts, params);
363
+ const onInput = ons.input;
364
+ const props = renderOpts.props || {};
365
+ const config = props.props || {};
366
+ const cache = getCascaderCache(params, !!config.lazy, renderOpts);
367
+ let nodes;
368
+ const pendingMountRequests = [];
369
+ const getComponent = () => nodes && nodes[0].componentInstance;
370
+ const bindRequest = (request) => {
371
+ const component = getComponent();
372
+ if (component) request.component = component;
373
+ // Read the ref directly: evaluating Element's computed panel before mount
374
+ // can cache undefined because refs are not reactive. Retain only identity.
375
+ const panel = component && component.$refs && component.$refs.panel;
376
+ if (panel) request.store = panel.store;
377
+ };
378
+ let componentOpts = renderOpts;
379
+ if (config.lazy && cache) {
380
+ const options = props.options || renderOpts.options;
381
+ const hydrated = getCascaderOptions(options && options.length ? options : undefined, config, cache);
382
+ const lazyLoad = config.lazyLoad;
383
+ componentOpts = Object.assign({}, renderOpts, { props: Object.assign({}, props, {
384
+ options: hydrated,
385
+ props: Object.assign({}, config, { lazyLoad(node, resolve) {
386
+ const path = node.root ? [] : node.getPath();
387
+ // These complete children are already present through the options prop.
388
+ // Resolve loading without appending the same sibling list twice.
389
+ if (!node.root && cache.hydrated.has(node.data)) { resolve([]); return; }
390
+ if (typeof lazyLoad !== "function") { resolve([]); return; }
391
+ const request = {};
392
+ bindRequest(request);
393
+ if (!request.store) pendingMountRequests.push(request);
394
+ return lazyLoad.call(this, node, (children) => {
395
+ if (request.settled) return;
396
+ const columns = cascaderLabelCache.get(params.row);
397
+ const component = request.component || getComponent();
398
+ // An obsolete request must not invoke Element's resolve: that closure
399
+ // appends to the panel's *current* store, even after options changed.
400
+ // Read the cache directly so stale renderOpts cannot invalidate a newer
401
+ // cache while checking whether this request still belongs to it.
402
+ if (!columns || columns.get(params.column) !== cache ||
403
+ !sameCascaderIdentity(getCascaderIdentity(renderOpts), cache.identity) ||
404
+ (component && (component._isDestroyed || component._isBeingDestroyed))) return;
405
+ const panel = component && component.$refs && component.$refs.panel;
406
+ if (request.store && (!panel || panel.store !== request.store)) return;
407
+ request.settled = true;
408
+ if (Array.isArray(children)) cache.loaded.set(JSON.stringify(path), children.slice());
409
+ resolve(children);
410
+ });
411
+ } }),
412
+ }) });
413
+ }
414
+ ons.input = (value) => {
415
+ const component = nodes[0].componentInstance;
416
+ if (config.lazy && cache && component && component.getCheckedNodes) {
417
+ cache.clear();
418
+ component.getCheckedNodes().forEach((node) => {
419
+ if (!node) return;
420
+ cache.set(JSON.stringify(node.getValueByOption()), {
421
+ labels: node.pathLabels.slice(), values: node.getPath().slice(),
422
+ });
423
+ });
424
+ }
425
+ onInput(value);
426
+ };
427
+ nodes = renderComponent(h, componentOpts, params, getCellValue(params), ons);
428
+ if (config.lazy && cache) {
429
+ // Initial root loading starts before the panel ref exists. Vue's insert
430
+ // hook runs in that same mount turn, before asynchronous results can arrive.
431
+ const hooks = nodes[0].data.hook || {};
432
+ const onInsert = hooks.insert;
433
+ nodes[0].data.hook = Object.assign({}, hooks, {
434
+ insert(...args) {
435
+ if (onInsert) onInsert.apply(this, args);
436
+ pendingMountRequests.forEach((request) => {
437
+ if (!request.settled) bindRequest(request);
438
+ });
439
+ pendingMountRequests.length = 0;
440
+ },
441
+ });
442
+ }
443
+ return nodes;
444
+ }
445
+
446
+ function getCascaderLabel(renderOpts, value, params) {
447
+ const props = renderOpts.props || {};
448
+ const cascaderProps = props.props || {};
449
+ const options = props.options || renderOpts.options || [];
450
+ const valueProp = cascaderProps.value || "value";
451
+ const labelProp = cascaderProps.label || "label";
452
+ const childrenProp = cascaderProps.children || "children";
453
+ const cache = getCascaderCache(params, false, renderOpts);
454
+
455
+ const findPath = (items, target, path = []) => {
456
+ for (const item of items) {
457
+ const next = path.concat(item[labelProp]);
458
+ if (item[valueProp] === target) return next;
459
+ const found = findPath(item[childrenProp] || [], target, next);
460
+ if (found) return found;
461
+ }
462
+ };
463
+ const labelFor = (selected) => {
464
+ let labels = [];
465
+ let complete = true;
466
+ if (cascaderProps.emitPath === false) {
467
+ labels = findPath(options, selected) || [];
468
+ complete = labels.length > 0;
469
+ } else {
470
+ let level = options;
471
+ (Array.isArray(selected) ? selected : []).forEach((itemValue) => {
472
+ const option = level.find((item) => item[valueProp] === itemValue);
473
+ if (option) {
474
+ labels.push(option[labelProp]);
475
+ level = option[childrenProp] || [];
476
+ } else {
477
+ complete = false;
478
+ }
479
+ });
480
+ }
481
+ if (!complete && cache && cache.has(JSON.stringify(selected))) {
482
+ const cached = cache.get(JSON.stringify(selected));
483
+ let level = options;
484
+ labels = cached.values.map((itemValue, index) => {
485
+ const option = level.find((item) => item[valueProp] === itemValue);
486
+ level = option ? option[childrenProp] || [] : [];
487
+ return option ? option[labelProp] : cached.labels[index];
488
+ });
489
+ }
490
+ return (props.showAllLevels === false ? labels.slice(-1) : labels)
491
+ .join(` ${props.separator || "/"} `);
492
+ };
493
+ return cascaderProps.multiple && Array.isArray(value)
494
+ ? value.map(labelFor).filter(Boolean).join(", ") : labelFor(value);
495
+ }
496
+
497
+ function cascaderCellRender(h, renderOpts, params) {
498
+ return [getCascaderLabel(renderOpts, getCellValue(params), params)];
499
+ }
500
+
501
+ function formatDateValue(value, props, format) {
502
+ if (isEmptyValue(value)) return "";
503
+ const date = props.valueFormat === "timestamp" ? new Date(Number(value))
504
+ : XEUtils.toStringDate(value, typeof value === "string" ? props.valueFormat : undefined);
505
+ return XEUtils.isValidDate(date) ? XEUtils.toDateString(date, format) : "";
506
+ }
507
+
508
+ function dateCellRender(h, renderOpts, params) {
509
+ const props = renderOpts.props || {};
510
+ const value = getCellValue(params);
511
+ if (isEmptyValue(value)) return [""];
512
+ const rangeSeparator = props.rangeSeparator === undefined ? "-" : props.rangeSeparator;
513
+ const formats = {
514
+ week: "yyyywWW",
515
+ month: "yyyy-MM",
516
+ year: "yyyy",
517
+ dates: "yyyy-MM-dd",
518
+ daterange: "yyyy-MM-dd",
519
+ datetime: "yyyy-MM-dd HH:mm:ss",
520
+ datetimerange: "yyyy-MM-dd HH:mm:ss",
521
+ monthrange: "yyyy-MM",
522
+ };
523
+ const format = props.format || formats[props.type] || "yyyy-MM-dd";
524
+ const values = Array.isArray(value) ? value : [value];
525
+ return [
526
+ values
527
+ .map((item) => formatDateValue(item, props, format))
528
+ .join(props.type === "dates" ? ", " : ` ${rangeSeparator} `),
529
+ ];
530
+ }
531
+
532
+ function dateFilterMethod({ option, row, column }) {
533
+ const renderOpts = column.filterRender || {};
534
+ const props = renderOpts.props || {};
535
+ const cellValue = XEUtils.get(row, column.field || column.property);
536
+ const optionValue = option.data;
537
+ // Compare model values at the picker's precision, not Date.toString() or the
538
+ // display format (dd/MM/yyyy, for example, is not chronologically sortable).
539
+ const format = props.type === "month" || props.type === "monthrange" ? "yyyy-MM"
540
+ : props.type === "year" ? "yyyy"
541
+ : props.type === "datetime" || props.type === "datetimerange" ? "yyyy-MM-dd HH:mm:ss"
542
+ : "yyyy-MM-dd";
543
+ const valueLabel = formatDateValue(cellValue, props, format);
544
+ if (!valueLabel) return false;
545
+ if (!Array.isArray(optionValue)) {
546
+ const optionLabel = formatDateValue(optionValue, props, format);
547
+ return !!optionLabel && valueLabel === optionLabel;
548
+ }
549
+ if (props.type === "dates") {
550
+ return optionValue.some((value) => formatDateValue(value, props, format) === valueLabel);
551
+ }
552
+ if (optionValue.length !== 2 || optionValue.some(isEmptyValue) || isEmptyValue(cellValue)) return false;
553
+ const start = formatDateValue(optionValue[0], props, format);
554
+ const end = formatDateValue(optionValue[1], props, format);
555
+ return !!start && !!end && valueLabel >= start && valueLabel <= end;
556
+ }
557
+
558
+ function formatTimeValue(value, props, format) {
559
+ if (isEmptyValue(value)) return "";
560
+ // XEUtils requires a calendar date when parsing time-only strings.
561
+ let valueFormat = props.valueFormat;
562
+ const timeOnly = typeof value === "string" && valueFormat &&
563
+ valueFormat !== "timestamp" && !/[yMd]/.test(valueFormat);
564
+ // XEUtils parses 24-hour tokens; normalize Element's explicit AM/PM input.
565
+ if (timeOnly && /h/.test(valueFormat) && /[aA]/.test(valueFormat)) {
566
+ const meridiem = value.match(/am|pm/i);
567
+ if (meridiem) {
568
+ value = value.replace(/am|pm/i, "").trim();
569
+ valueFormat = valueFormat.replace(/h/g, "H").replace(/[aA]/g, "").trim();
570
+ const date = XEUtils.toStringDate(`2000-01-01 ${value}`, `yyyy-MM-dd ${valueFormat}`);
571
+ if (!XEUtils.isValidDate(date)) return "";
572
+ date.setHours(date.getHours() % 12 + (/pm/i.test(meridiem[0]) ? 12 : 0));
573
+ return XEUtils.toDateString(date, format);
574
+ }
575
+ }
576
+ return formatDateValue(timeOnly ? `2000-01-01 ${value}` : value,
577
+ timeOnly ? Object.assign({}, props, { valueFormat: `yyyy-MM-dd ${valueFormat}` }) : props,
578
+ format);
579
+ }
580
+
581
+ function timeFilterMethod({ option, row, column }) {
582
+ const props = (column.filterRender || {}).props || {};
583
+ const value = formatTimeValue(XEUtils.get(row, column.field || column.property), props, "HH:mm:ss");
584
+ if (!value) return false;
585
+ if (props.isRange) {
586
+ if (!Array.isArray(option.data) || option.data.length !== 2) return false;
587
+ const start = formatTimeValue(option.data[0], props, "HH:mm:ss");
588
+ const end = formatTimeValue(option.data[1], props, "HH:mm:ss");
589
+ return !!start && !!end && value >= start && value <= end;
590
+ }
591
+ const optionValue = formatTimeValue(option.data, props, "HH:mm:ss");
592
+ return !!optionValue && value === optionValue;
593
+ }
594
+
595
+ function timeCellRender(h, renderOpts, params) {
596
+ const props = renderOpts.props || {};
597
+ const value = getCellValue(params);
598
+ if (isEmptyValue(value)) return [""];
599
+ if (renderOpts.name === "ElTimeSelect") return [String(value)];
600
+ const values = Array.isArray(value) ? value : [value];
601
+ const rangeSeparator = props.rangeSeparator === undefined ? "-" : props.rangeSeparator;
602
+ return [
603
+ values
604
+ .map((item) => formatTimeValue(item, props, props.format || "HH:mm:ss"))
605
+ .join(Array.isArray(value) ? ` ${rangeSeparator} ` : ""),
606
+ ];
607
+ }
608
+
609
+ function buttonRender(h, renderOpts, params) {
610
+ return [
611
+ h(
612
+ renderOpts.name || "ElButton",
613
+ {
614
+ attrs: renderOpts.attrs,
615
+ props: getComponentProps(renderOpts, params, null),
616
+ on: getEventOns(renderOpts, params),
617
+ nativeOn: getNativeOns(renderOpts, params),
618
+ },
619
+ renderOpts.content == null ? [] : [String(renderOpts.content)]
620
+ ),
621
+ ];
622
+ }
623
+
624
+ function buttonsRender(h, renderOpts, params) {
625
+ return (renderOpts.children || []).reduce(
626
+ (nodes, child) => nodes.concat(buttonRender(h, child, params)),
627
+ []
628
+ );
629
+ }
630
+
631
+ function addRenderer(name, config) {
632
+ // 新版表单回调与旧 renderItem 同时提供;不覆盖应用注册的同名 renderer。
633
+ config.renderFormItemContent = renderFormItem;
634
+ config.renderItem = renderFormItem;
635
+ // 尊重业务在加载 umy-ui 前已经注册的同名渲染器。
636
+ if (!renderer.get(name)) renderer.add(name, config);
637
+ }
638
+
639
+ function renderFormItem(h, renderOpts, params) {
640
+ const field = params.field || params.property;
641
+ const value = XEUtils.get(params.data, field);
642
+ const ons = getEventOns(renderOpts, params, (nextValue) => {
643
+ XEUtils.set(params.data, field, nextValue);
644
+ }, () => {
645
+ if (params.$form) params.$form.updateStatus(params);
646
+ });
647
+ const formParams = Object.assign({}, params, { $table: params.$form });
648
+ if (renderOpts.name === "ElButtons") {
649
+ return (renderOpts.children || []).reduce((nodes, child) => nodes.concat(
650
+ renderFormItem(h, Object.assign({ name: "ElButton" }, child), params)
651
+ ), []);
652
+ }
653
+ if (renderOpts.name === "ElButton") {
654
+ return buttonRender(h, Object.assign({}, renderOpts, {
655
+ content: renderOpts.content == null ? (renderOpts.props || {}).content : renderOpts.content,
656
+ }), formParams);
657
+ }
658
+ if (renderOpts.name === "ElRadio" || renderOpts.name === "ElCheckbox") {
659
+ const optionProps = renderOpts.optionProps || {};
660
+ return renderComponent(h, Object.assign({}, renderOpts, { name: `${renderOpts.name}Group` }),
661
+ formParams, value, ons, undefined, (renderOpts.options || []).map((option, index) =>
662
+ h(renderOpts.name, { key: index, props: {
663
+ label: option[optionProps.value || "value"],
664
+ disabled: option[optionProps.disabled || "disabled"],
665
+ } }, [String(option[optionProps.label || "label"] == null ? "" : option[optionProps.label || "label"])])));
666
+ }
667
+ return renderComponent(h, renderOpts, formParams, value, ons, undefined,
668
+ renderOpts.name === "ElSelect" ? renderSelectOptions(h, renderOpts) : undefined);
669
+ }
670
+
671
+ inputRendererNames.forEach((name) => {
672
+ addRenderer(name, {
673
+ tableAutoFocus: ".el-input__inner",
674
+ renderTableDefault: renderEdit,
675
+ renderTableEdit: renderEdit,
676
+ renderTableFilter: renderFilter,
677
+ tableFilterDefaultMethod: filterMethod,
678
+ tableExportMethod: ({ row, column }) =>
679
+ XEUtils.get(row, column.field || column.property),
680
+ });
681
+ });
682
+
683
+ addRenderer("ElSelect", {
684
+ tableAutoFocus: ".el-input__inner",
685
+ renderTableDefault: selectEditRender,
686
+ renderTableEdit: selectEditRender,
687
+ renderTableCell: selectCellRender,
688
+ renderTableFilter: selectFilterRender,
689
+ tableFilterDefaultMethod: selectFilterMethod,
690
+ tableExportMethod: (params) =>
691
+ getSelectLabel(
692
+ params.column.editRender || params.column.cellRender || {},
693
+ getCellValue(params),
694
+ params
695
+ ),
696
+ });
697
+
698
+ addRenderer("ElCascader", {
699
+ tableAutoFocus: ".el-input__inner",
700
+ renderTableEdit: cascaderEditRender,
701
+ renderTableCell: cascaderCellRender,
702
+ tableExportMethod: (params) =>
703
+ getCascaderLabel(
704
+ params.column.editRender || params.column.cellRender || {},
705
+ getCellValue(params),
706
+ params
707
+ ),
708
+ });
709
+
710
+ ["ElDatePicker"].forEach((name) => {
711
+ addRenderer(name, {
712
+ tableAutoFocus: ".el-input__inner",
713
+ renderTableEdit: renderEdit,
714
+ renderTableCell: dateCellRender,
715
+ renderTableFilter: renderFilter,
716
+ tableFilterDefaultMethod: dateFilterMethod,
717
+ tableExportMethod: (params) => dateCellRender(null,
718
+ params.column.editRender || params.column.cellRender || {}, params)[0],
719
+ });
720
+ });
721
+
722
+ ["ElTimePicker", "ElTimeSelect"].forEach((name) => {
723
+ addRenderer(name, {
724
+ tableAutoFocus: ".el-input__inner",
725
+ renderTableEdit: renderEdit,
726
+ renderTableCell: timeCellRender,
727
+ renderTableFilter: renderFilter,
728
+ tableFilterDefaultMethod: name === "ElTimePicker" ? timeFilterMethod : filterMethod,
729
+ tableExportMethod: (params) => timeCellRender(null,
730
+ params.column.editRender || params.column.cellRender || {}, params)[0],
731
+ });
732
+ });
733
+
734
+ ["ElRadio", "ElCheckbox"].forEach((name) => {
735
+ addRenderer(name, {
736
+ tableAutoFocus: "input",
737
+ renderTableDefault: renderEdit,
738
+ renderTableEdit: renderEdit,
739
+ });
740
+ });
741
+
742
+ addRenderer("ElButton", { renderTableDefault: buttonRender });
743
+ addRenderer("ElButtons", { renderTableDefault: buttonsRender });
744
+
745
+ function isPopupEvent(params, event) {
746
+ const evnt = (params && params.$event) || event;
747
+ let target = evnt && evnt.target;
748
+ const doc = typeof document === "undefined" ? null : document;
749
+ while (target && target.nodeType && target !== doc) {
750
+ if (target.classList) {
751
+ for (let index = 0; index < popupClassNames.length; index += 1) {
752
+ if (target.classList.contains(popupClassNames[index])) return false;
753
+ }
754
+ }
755
+ target = target.parentNode;
756
+ }
757
+ }
758
+
759
+ const popupGuardKey = "__umyElementPopupGuard";
760
+ isPopupEvent[popupGuardKey] = true;
761
+ if (!interceptor.get("event.clearActived").some((callback) => callback[popupGuardKey])) {
762
+ interceptor.add("event.clearActived", isPopupEvent);
763
+ }
764
+ // VXE only falls back to the legacy list when the modern list is empty.
765
+ // Keep that priority while making popup protection available to both APIs.
766
+ function clearEditAdapter(params, event) {
767
+ if (interceptor.get("event.clearEdit").some((callback) => callback !== clearEditAdapter)) {
768
+ return isPopupEvent(params, event);
769
+ }
770
+ const callbacks = interceptor.get("event.clearActived");
771
+ for (let index = 0; index < callbacks.length; index += 1) {
772
+ const callback = callbacks[index];
773
+ if (callback === clearEditAdapter) continue;
774
+ const result = callback(Object.assign({}, params), event);
775
+ if (result === false || (result && result.status === false)) return result;
776
+ }
777
+ }
778
+ clearEditAdapter[popupGuardKey] = true;
779
+ if (!interceptor.get("event.clearEdit").some((callback) => callback[popupGuardKey])) {
780
+ interceptor.add("event.clearEdit", clearEditAdapter);
781
+ }
782
+ if (!interceptor.get("event.clearFilter").some((callback) => callback[popupGuardKey])) {
783
+ interceptor.add("event.clearFilter", isPopupEvent);
784
+ }