cx 24.3.6 → 24.3.8
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/dist/data.js +46 -15
- package/dist/manifest.js +784 -784
- package/dist/ui.js +11 -9
- package/dist/widgets.js +38 -39
- package/package.json +1 -1
- package/src/data/Grouper.js +144 -120
- package/src/data/Grouper.spec.js +57 -42
- package/src/ui/adapter/GroupAdapter.js +141 -138
- package/src/widgets/grid/Grid.js +25 -10
|
@@ -1,138 +1,141 @@
|
|
|
1
|
-
import { ArrayAdapter } from "./ArrayAdapter";
|
|
2
|
-
import { ReadOnlyDataView } from "../../data/ReadOnlyDataView";
|
|
3
|
-
import { Grouper } from "../../data/Grouper";
|
|
4
|
-
import { isArray } from "../../util/isArray";
|
|
5
|
-
import { isDefined } from "../../util/isDefined";
|
|
6
|
-
import { getComparer } from "../../data/comparer";
|
|
7
|
-
import { Culture } from "../Culture";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
result
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
let
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
let
|
|
44
|
-
grouper
|
|
45
|
-
grouper.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
let
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
1
|
+
import { ArrayAdapter } from "./ArrayAdapter";
|
|
2
|
+
import { ReadOnlyDataView } from "../../data/ReadOnlyDataView";
|
|
3
|
+
import { Grouper } from "../../data/Grouper";
|
|
4
|
+
import { isArray } from "../../util/isArray";
|
|
5
|
+
import { isDefined } from "../../util/isDefined";
|
|
6
|
+
import { getComparer } from "../../data/comparer";
|
|
7
|
+
import { Culture } from "../Culture";
|
|
8
|
+
import { isObject } from "../../util/isObject";
|
|
9
|
+
|
|
10
|
+
export class GroupAdapter extends ArrayAdapter {
|
|
11
|
+
init() {
|
|
12
|
+
super.init();
|
|
13
|
+
|
|
14
|
+
if (this.groupRecordsAlias) this.groupRecordsName = this.groupRecordsAlias;
|
|
15
|
+
|
|
16
|
+
if (this.groupings) this.groupBy(this.groupings);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getRecords(context, instance, records, parentStore) {
|
|
20
|
+
let result = super.getRecords(context, instance, records, parentStore);
|
|
21
|
+
|
|
22
|
+
if (this.groupings) {
|
|
23
|
+
let groupedResults = [];
|
|
24
|
+
this.processLevel([], result, groupedResults, parentStore);
|
|
25
|
+
result = groupedResults;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
processLevel(keys, records, result, parentStore) {
|
|
32
|
+
let level = keys.length;
|
|
33
|
+
let inverseLevel = this.groupings.length - level;
|
|
34
|
+
|
|
35
|
+
if (inverseLevel == 0) {
|
|
36
|
+
for (let i = 0; i < records.length; i++) {
|
|
37
|
+
records[i].store.setStore(parentStore);
|
|
38
|
+
result.push(records[i]);
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let grouping = this.groupings[level];
|
|
44
|
+
let { grouper } = grouping;
|
|
45
|
+
grouper.reset();
|
|
46
|
+
grouper.processAll(records);
|
|
47
|
+
let results = grouper.getResults();
|
|
48
|
+
if (grouping.comparer) results.sort(grouping.comparer);
|
|
49
|
+
|
|
50
|
+
results.forEach((gr) => {
|
|
51
|
+
keys.push(gr.key);
|
|
52
|
+
|
|
53
|
+
let key = keys.map(serializeKey).join("|");
|
|
54
|
+
|
|
55
|
+
let $group = {
|
|
56
|
+
...gr.key,
|
|
57
|
+
...gr.aggregates,
|
|
58
|
+
$name: gr.name,
|
|
59
|
+
$level: inverseLevel,
|
|
60
|
+
$records: gr.records || [],
|
|
61
|
+
$key: key,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
let data = {
|
|
65
|
+
[this.recordName]: gr.records.length > 0 ? gr.records[0].data : null,
|
|
66
|
+
[this.groupName]: $group,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
let groupStore = new ReadOnlyDataView({
|
|
70
|
+
store: parentStore,
|
|
71
|
+
data,
|
|
72
|
+
immutable: this.immutable,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
let group = {
|
|
76
|
+
key,
|
|
77
|
+
data,
|
|
78
|
+
group: $group,
|
|
79
|
+
grouping,
|
|
80
|
+
store: groupStore,
|
|
81
|
+
level: inverseLevel,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
if (grouping.includeHeader !== false)
|
|
85
|
+
result.push({
|
|
86
|
+
...group,
|
|
87
|
+
type: "group-header",
|
|
88
|
+
key: "header:" + group.key,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
this.processLevel(keys, gr.records, result, groupStore);
|
|
92
|
+
|
|
93
|
+
if (grouping.includeFooter !== false)
|
|
94
|
+
result.push({
|
|
95
|
+
...group,
|
|
96
|
+
type: "group-footer",
|
|
97
|
+
key: "footer:" + group.key,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
keys.pop();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
groupBy(groupings) {
|
|
105
|
+
if (!groupings) this.groupings = null;
|
|
106
|
+
else if (isArray(groupings)) {
|
|
107
|
+
this.groupings = groupings;
|
|
108
|
+
this.groupings.forEach((g) => {
|
|
109
|
+
let groupSorters = [];
|
|
110
|
+
let key = {};
|
|
111
|
+
for (let name in g.key) {
|
|
112
|
+
if (!g.key[name] || !isDefined(g.key[name].direction) || !isDefined(g.key[name].value))
|
|
113
|
+
g.key[name] = { value: g.key[name], direction: "ASC" };
|
|
114
|
+
key[name] = g.key[name].value;
|
|
115
|
+
groupSorters.push({
|
|
116
|
+
field: name,
|
|
117
|
+
direction: g.key[name].direction,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
g.grouper = new Grouper(key, { ...this.aggregates, ...g.aggregates }, (r) => r.store.getData(), g.text);
|
|
121
|
+
g.comparer = null;
|
|
122
|
+
if (groupSorters.length > 0)
|
|
123
|
+
g.comparer = getComparer(
|
|
124
|
+
groupSorters,
|
|
125
|
+
(x) => x.key,
|
|
126
|
+
this.sortOptions ? Culture.getComparer(this.sortOptions) : null,
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
} else throw new Error("Invalid grouping provided.");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
GroupAdapter.prototype.groupName = "$group";
|
|
134
|
+
|
|
135
|
+
function serializeKey(data) {
|
|
136
|
+
if (isObject(data))
|
|
137
|
+
return Object.keys(data)
|
|
138
|
+
.map((k) => serializeKey(data[k]))
|
|
139
|
+
.join(":");
|
|
140
|
+
return data?.toString() ?? "";
|
|
141
|
+
}
|
package/src/widgets/grid/Grid.js
CHANGED
|
@@ -43,6 +43,7 @@ import { unfocusElement } from "../../ui/FocusManager";
|
|
|
43
43
|
import { tooltipMouseMove, tooltipMouseLeave } from "../overlay/tooltip-ops";
|
|
44
44
|
import { Container } from "../../ui/Container";
|
|
45
45
|
import { findFirstChild } from "../../util/DOM";
|
|
46
|
+
import { Binding } from "../../data/Binding";
|
|
46
47
|
|
|
47
48
|
export class Grid extends Container {
|
|
48
49
|
declareData(...args) {
|
|
@@ -910,9 +911,9 @@ export class Grid extends Container {
|
|
|
910
911
|
}
|
|
911
912
|
|
|
912
913
|
if (colSpan > 1) skip = colSpan - 1;
|
|
913
|
-
} else if (c.aggregate && c.
|
|
914
|
+
} else if (c.aggregate && c.aggregateAliasGetter && c.caption !== false) {
|
|
914
915
|
empty = false;
|
|
915
|
-
v =
|
|
916
|
+
v = c.aggregateAliasGetter(group);
|
|
916
917
|
if (isString(ci.data.format)) v = Format.value(v, ci.data.format);
|
|
917
918
|
}
|
|
918
919
|
|
|
@@ -993,9 +994,9 @@ export class Grid extends Container {
|
|
|
993
994
|
}
|
|
994
995
|
|
|
995
996
|
if (colSpan > 1) skip = colSpan - 1;
|
|
996
|
-
} else if (c.aggregate && c.
|
|
997
|
+
} else if (c.aggregate && c.aggregateAliasGetter && c.footer !== false) {
|
|
997
998
|
empty = false;
|
|
998
|
-
v =
|
|
999
|
+
v = c.aggregateAliasGetter(group);
|
|
999
1000
|
if (isString(ci.data.format)) v = Format.value(v, ci.data.format);
|
|
1000
1001
|
}
|
|
1001
1002
|
|
|
@@ -1594,19 +1595,25 @@ class GridComponent extends VDOM.Component {
|
|
|
1594
1595
|
</tbody>
|
|
1595
1596
|
);
|
|
1596
1597
|
|
|
1598
|
+
let dataRecordClass = CSS.element(baseClass, "data");
|
|
1599
|
+
|
|
1600
|
+
let isDataRecord = widget.buffered
|
|
1601
|
+
? (item) => item?.props?.instance?.data?.class == dataRecordClass
|
|
1602
|
+
: (item) => item?.props?.record?.type;
|
|
1603
|
+
|
|
1597
1604
|
let index = 0;
|
|
1598
|
-
while (index < children.length && children[index]
|
|
1605
|
+
while (index < children.length && !isDataRecord(children[index])) index++;
|
|
1599
1606
|
|
|
1600
1607
|
let count = 0;
|
|
1601
1608
|
while (index < children.length && count < this.state.dropInsertionIndex) {
|
|
1602
|
-
if (children[index]
|
|
1609
|
+
if (isDataRecord(children[index])) count++;
|
|
1603
1610
|
index++;
|
|
1604
1611
|
}
|
|
1605
1612
|
|
|
1606
1613
|
let savedIndexPos = index;
|
|
1607
1614
|
|
|
1608
1615
|
if (!this.state.dropNextToTheRowAbove)
|
|
1609
|
-
while (index < children.length && children[index]
|
|
1616
|
+
while (index < children.length && !isDataRecord(children[index])) index++;
|
|
1610
1617
|
|
|
1611
1618
|
// do not allow insertion after the last group footer
|
|
1612
1619
|
if (savedIndexPos < index && index == children.length) index = savedIndexPos;
|
|
@@ -2002,15 +2009,15 @@ class GridComponent extends VDOM.Component {
|
|
|
2002
2009
|
if (dropTarget == "grid" && widget.onDrop && dropInsertionIndex != null) {
|
|
2003
2010
|
e.target = {
|
|
2004
2011
|
insertionIndex: start + dropInsertionIndex,
|
|
2005
|
-
recordBefore: this.
|
|
2006
|
-
recordAfter: this.
|
|
2012
|
+
recordBefore: this.getDataRecordAt(start + dropInsertionIndex - 1),
|
|
2013
|
+
recordAfter: this.getDataRecordAt(start + dropInsertionIndex),
|
|
2007
2014
|
dropNextToTheRowAbove,
|
|
2008
2015
|
};
|
|
2009
2016
|
instance.invoke("onDrop", e, instance);
|
|
2010
2017
|
} else if (dropTarget == "row") {
|
|
2011
2018
|
e.target = {
|
|
2012
2019
|
index: start + dropInsertionIndex,
|
|
2013
|
-
record: this.
|
|
2020
|
+
record: this.getDataRecordAt(start + dropInsertionIndex),
|
|
2014
2021
|
};
|
|
2015
2022
|
instance.invoke("onRowDrop", e, instance);
|
|
2016
2023
|
} else if (dropTarget == "column" && widget.onColumnDrop) {
|
|
@@ -2730,6 +2737,13 @@ class GridComponent extends VDOM.Component {
|
|
|
2730
2737
|
widget.selection.selectMultiple(instance.store, selection, indexes, options);
|
|
2731
2738
|
}
|
|
2732
2739
|
|
|
2740
|
+
getDataRecordAt(index) {
|
|
2741
|
+
let { records } = this.props.instance;
|
|
2742
|
+
if (!records) return this.getRecordAt(index);
|
|
2743
|
+
let dataRecords = records.filter((r) => r.type == "data");
|
|
2744
|
+
return dataRecords[index];
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2733
2747
|
getRecordAt(cursor) {
|
|
2734
2748
|
let { instance, data } = this.props;
|
|
2735
2749
|
let { records, widget } = instance;
|
|
@@ -3097,6 +3111,7 @@ class GridColumnHeader extends Widget {
|
|
|
3097
3111
|
if (!this.aggregateField && this.field) this.aggregateField = this.field;
|
|
3098
3112
|
|
|
3099
3113
|
if (!this.aggregateAlias) this.aggregateAlias = this.aggregateField;
|
|
3114
|
+
if (this.aggregateAlias) this.aggregateAliasGetter = Binding.get(this.aggregateAlias).value;
|
|
3100
3115
|
|
|
3101
3116
|
if (this.footer && isSelector(this.footer))
|
|
3102
3117
|
this.footer = {
|