@refinitiv-ui/efx-grid 6.0.111 → 6.0.112
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/filter-dialog/lib/checkbox-list.d.ts +13 -0
- package/lib/filter-dialog/lib/checkbox-list.js +74 -40
- package/lib/filter-dialog/lib/filter-dialog.d.ts +5 -0
- package/lib/filter-dialog/lib/filter-dialog.js +57 -46
- package/lib/grid/index.js +1 -1
- package/lib/tr-grid-row-filtering/es6/RowFiltering.d.ts +8 -0
- package/lib/tr-grid-row-filtering/es6/RowFiltering.js +90 -9
- package/lib/versions.json +2 -2
- package/package.json +1 -1
@@ -6,6 +6,19 @@ import "@refinitiv-ui/elements/item";
|
|
6
6
|
import "@refinitiv-ui/elements/checkbox";
|
7
7
|
import translation from "./locale/translation.js";
|
8
8
|
|
9
|
+
declare namespace CheckboxList {
|
10
|
+
|
11
|
+
type itemState = {
|
12
|
+
type?: string|null,
|
13
|
+
label?: string|null,
|
14
|
+
checked?: boolean|null,
|
15
|
+
index?: number|null,
|
16
|
+
elem?: Element|null,
|
17
|
+
value?: (string|boolean)|null
|
18
|
+
};
|
19
|
+
|
20
|
+
}
|
21
|
+
|
9
22
|
declare class CheckboxList extends BasicElement {
|
10
23
|
|
11
24
|
constructor();
|
@@ -5,6 +5,15 @@ import "@refinitiv-ui/elements/item";
|
|
5
5
|
import "@refinitiv-ui/elements/checkbox";
|
6
6
|
import translation from "./locale/translation.js";
|
7
7
|
|
8
|
+
/**
|
9
|
+
* @typedef {Object} CheckboxList~itemState
|
10
|
+
* @property {string=} type
|
11
|
+
* @property {string=} label
|
12
|
+
* @property {boolean=} checked
|
13
|
+
* @property {number=} index
|
14
|
+
* @property {Element=} elem
|
15
|
+
* @property {(string|boolean)=} value
|
16
|
+
*/
|
8
17
|
/** @type {number}
|
9
18
|
* @private
|
10
19
|
* @constant
|
@@ -28,15 +37,18 @@ const _toLabelText = function(val) {
|
|
28
37
|
* @function
|
29
38
|
* @param {*} val
|
30
39
|
* @param {number} idx
|
31
|
-
* @return {
|
40
|
+
* @return {CheckboxList~itemState}
|
32
41
|
*/
|
33
42
|
const _toItemStates = function(val, idx) {
|
43
|
+
let textLabel = _toLabelText(val);
|
34
44
|
return {
|
35
|
-
|
45
|
+
type: val.type,
|
46
|
+
label: textLabel,
|
47
|
+
title: textLabel,
|
36
48
|
checked: (val && val.checked) ? true : false,
|
37
49
|
index: idx,
|
38
50
|
elem: null,
|
39
|
-
value: val.value
|
51
|
+
value: val.value || textLabel
|
40
52
|
};
|
41
53
|
};
|
42
54
|
/** @private
|
@@ -77,9 +89,13 @@ const _updateElement = function(elem, txt, checked) {
|
|
77
89
|
* @param {string} str
|
78
90
|
* @param {number} idx
|
79
91
|
* @param {string} ctx
|
92
|
+
* @param {string} type
|
80
93
|
* @returns {boolean}
|
81
94
|
*/
|
82
|
-
const _caseInsensitiveFilter = function(str, idx, ctx) {
|
95
|
+
const _caseInsensitiveFilter = function(str, idx, ctx, type) {
|
96
|
+
if(type === "header" || type === "divider") {
|
97
|
+
return true;
|
98
|
+
}
|
83
99
|
return str.toLowerCase().indexOf(ctx) >= 0;
|
84
100
|
};
|
85
101
|
|
@@ -108,6 +124,7 @@ class CheckboxList extends BasicElement {
|
|
108
124
|
this._states = []; // Item states before filtering
|
109
125
|
this._cachedItems = []; // To avoid repeatedly creating the same item element
|
110
126
|
this._items = []; // Actual existing elements (filtered items)
|
127
|
+
this._filterStates = []; // Existing item (after filtered)
|
111
128
|
this._inputFilter = null;
|
112
129
|
}
|
113
130
|
|
@@ -131,8 +148,8 @@ class CheckboxList extends BasicElement {
|
|
131
148
|
}
|
132
149
|
|
133
150
|
render() {
|
134
|
-
|
135
|
-
|
151
|
+
let lang = this._translation[this.lang] ? this.lang : "en";
|
152
|
+
let t = this._translation[lang];
|
136
153
|
return html`
|
137
154
|
<div class='root'>
|
138
155
|
<div>
|
@@ -146,10 +163,10 @@ class CheckboxList extends BasicElement {
|
|
146
163
|
|
147
164
|
firstUpdated(changedProps) {
|
148
165
|
// Prepare list item template. TODO: This should be static variable
|
149
|
-
|
150
|
-
|
166
|
+
let checkBox = document.createElement("ef-checkbox");
|
167
|
+
let label = document.createElement("div");
|
151
168
|
label.classList.add("item-label");
|
152
|
-
|
169
|
+
let itemContainer = document.createElement("div");
|
153
170
|
itemContainer.classList.add("item-container");
|
154
171
|
itemContainer.appendChild(checkBox);
|
155
172
|
itemContainer.appendChild(label);
|
@@ -157,7 +174,7 @@ class CheckboxList extends BasicElement {
|
|
157
174
|
this._templateItemEl.appendChild(itemContainer);
|
158
175
|
|
159
176
|
// Elements has been rendered. Cache element references for better performance
|
160
|
-
|
177
|
+
let root = this.shadowRoot;
|
161
178
|
this._containerEl = root.getElementById("container");
|
162
179
|
|
163
180
|
this._selectAllBtn = root.getElementById("select_all");
|
@@ -169,8 +186,8 @@ class CheckboxList extends BasicElement {
|
|
169
186
|
|
170
187
|
updated(changedProps) {
|
171
188
|
if (changedProps.has("data")) {
|
172
|
-
|
173
|
-
|
189
|
+
let dataList = this.data;
|
190
|
+
let len = dataList ? dataList.length : 0;
|
174
191
|
if (this._cachedItems.length < len) {
|
175
192
|
this._cachedItems.length = len;
|
176
193
|
}
|
@@ -186,15 +203,15 @@ class CheckboxList extends BasicElement {
|
|
186
203
|
* @return {!Element}
|
187
204
|
*/
|
188
205
|
_toItemElement(state) {
|
189
|
-
|
206
|
+
let elem = state.elem;
|
190
207
|
if(!elem) {
|
191
|
-
|
208
|
+
let idx = state.index;
|
192
209
|
elem = this._cachedItems[idx];
|
193
210
|
if(!elem) {
|
194
211
|
elem = this._cachedItems[idx] = this._templateItemEl.cloneNode(true);
|
195
212
|
elem.addEventListener("click", this._onItemClicked);
|
196
213
|
|
197
|
-
|
214
|
+
let itemContainer = elem.firstChild; // div.item-container
|
198
215
|
elem._checkbox = itemContainer.firstChild; // ef-checkbox
|
199
216
|
elem._label = itemContainer.lastChild; // label
|
200
217
|
}
|
@@ -213,15 +230,30 @@ class CheckboxList extends BasicElement {
|
|
213
230
|
}
|
214
231
|
|
215
232
|
// TODO: Optimize appending and removing items by finding appropriate item number
|
216
|
-
|
233
|
+
let container = this._containerEl;
|
217
234
|
while(container.lastChild) {
|
218
235
|
container.removeChild(container.lastChild);
|
219
236
|
}
|
220
237
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
238
|
+
let ary = this._items;
|
239
|
+
let filterStates = this._filterStates;
|
240
|
+
let len = ary.length;
|
241
|
+
for(let i = 0; i < len; ++i) {
|
242
|
+
let item = ary[i];
|
243
|
+
let state = filterStates[i];
|
244
|
+
item.type = "";
|
245
|
+
let itemContainer = item.firstChild;
|
246
|
+
if(!itemContainer.contains(item._checkbox)){
|
247
|
+
itemContainer.insertBefore(item._checkbox, item._label);
|
248
|
+
}
|
249
|
+
let type = state.type;
|
250
|
+
if(type) {
|
251
|
+
if(type === "header") {
|
252
|
+
itemContainer.removeChild(item._checkbox);
|
253
|
+
}
|
254
|
+
item.type = type;
|
255
|
+
}
|
256
|
+
container.appendChild(item);
|
225
257
|
}
|
226
258
|
this._updateSelectAllState();
|
227
259
|
}
|
@@ -249,9 +281,9 @@ class CheckboxList extends BasicElement {
|
|
249
281
|
return;
|
250
282
|
}
|
251
283
|
|
252
|
-
|
253
|
-
|
254
|
-
for(
|
284
|
+
let states = this._states;
|
285
|
+
let len = states.length;
|
286
|
+
for(let i = 0; i < len; ++i) {
|
255
287
|
_assignItemState(states[i], this.data[i]);
|
256
288
|
}
|
257
289
|
|
@@ -263,14 +295,15 @@ class CheckboxList extends BasicElement {
|
|
263
295
|
* @return {!Array<object>}
|
264
296
|
*/
|
265
297
|
getSelectedItems() {
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
for(
|
270
|
-
|
298
|
+
let items = [];
|
299
|
+
let states = this._states;
|
300
|
+
let len = states.length;
|
301
|
+
for(let i = 0; i < len; ++i) {
|
302
|
+
let state = states[i];
|
271
303
|
if(_getCheckedState(state)) {
|
272
304
|
items.push({
|
273
305
|
title: state.label,
|
306
|
+
label: state.label,
|
274
307
|
index: i,
|
275
308
|
value: state.value
|
276
309
|
});
|
@@ -285,9 +318,9 @@ class CheckboxList extends BasicElement {
|
|
285
318
|
*/
|
286
319
|
selectAll(selected) {
|
287
320
|
selected = selected !== false;
|
288
|
-
|
289
|
-
|
290
|
-
for(
|
321
|
+
let ary = this._items;
|
322
|
+
let len = ary.length;
|
323
|
+
for(let i = 0; i < len; ++i) {
|
291
324
|
ary[i]._checkbox.checked = selected;
|
292
325
|
}
|
293
326
|
this._updateSelectAllState(selected);
|
@@ -308,7 +341,7 @@ class CheckboxList extends BasicElement {
|
|
308
341
|
if(!inputFilter) {
|
309
342
|
inputFilter = null;
|
310
343
|
}
|
311
|
-
|
344
|
+
let dirty = (typeof inputFilter === "function");
|
312
345
|
if(this._inputFilter !== inputFilter) {
|
313
346
|
this._inputFilter = inputFilter || null;
|
314
347
|
dirty = true;
|
@@ -323,14 +356,14 @@ class CheckboxList extends BasicElement {
|
|
323
356
|
* @private
|
324
357
|
*/
|
325
358
|
_filterItems() {
|
326
|
-
|
327
|
-
|
359
|
+
let states = this._states;
|
360
|
+
let len = states ? states.length : 0;
|
328
361
|
if(!len) {
|
329
362
|
this._items.length = 0;
|
330
363
|
return; // No new copy is generated
|
331
364
|
}
|
332
365
|
|
333
|
-
|
366
|
+
let inputFilter = this._inputFilter;
|
334
367
|
if(inputFilter) {
|
335
368
|
if(typeof inputFilter === "function") {
|
336
369
|
this._filterMethod = inputFilter;
|
@@ -349,6 +382,7 @@ class CheckboxList extends BasicElement {
|
|
349
382
|
states = states.slice(0, ITEM_LIMIT);
|
350
383
|
}
|
351
384
|
|
385
|
+
this._filterStates = states;
|
352
386
|
this._items = states.map(this._toItemElement);
|
353
387
|
}
|
354
388
|
/**
|
@@ -358,7 +392,7 @@ class CheckboxList extends BasicElement {
|
|
358
392
|
* @return {boolean}
|
359
393
|
*/
|
360
394
|
_byLabelText(state, idx) {
|
361
|
-
return this._filterMethod(state.label, idx, this._filterCtx);
|
395
|
+
return this._filterMethod(state.label, idx, this._filterCtx, state.type);
|
362
396
|
}
|
363
397
|
|
364
398
|
/**
|
@@ -367,7 +401,7 @@ class CheckboxList extends BasicElement {
|
|
367
401
|
*/
|
368
402
|
_onItemClicked(e) {
|
369
403
|
if(e.target.tagName !== "EF-CHECKBOX") { // checkbox may already toggle its state
|
370
|
-
|
404
|
+
let itemEl = e.currentTarget;
|
371
405
|
itemEl._checkbox.checked = !itemEl._checkbox.checked;
|
372
406
|
}
|
373
407
|
this._updateSelectAllState();
|
@@ -383,10 +417,10 @@ class CheckboxList extends BasicElement {
|
|
383
417
|
}
|
384
418
|
|
385
419
|
if(selected == null) {
|
386
|
-
|
387
|
-
|
420
|
+
let ary = this._items;
|
421
|
+
let len = ary.length;
|
388
422
|
selected = len ? false : true;
|
389
|
-
for (
|
423
|
+
for (let i = 0; i < len; i++) {
|
390
424
|
if (ary[i]._checkbox.checked) {
|
391
425
|
selected = true;
|
392
426
|
break;
|
@@ -34,6 +34,11 @@ import "./checkbox-list.js";
|
|
34
34
|
* @property {Function=} sortChanged Sort changed handler
|
35
35
|
*/
|
36
36
|
|
37
|
+
/**
|
38
|
+
* @typedef {Object} FilterDialog~ComboBoxItem
|
39
|
+
* @property {string} label text of item
|
40
|
+
* @property {string} value value of item when item is selected
|
41
|
+
*/
|
37
42
|
|
38
43
|
/** @type {string}
|
39
44
|
* @private
|
@@ -111,9 +116,9 @@ const NUMBER_FILTERS = [
|
|
111
116
|
/** @private
|
112
117
|
* @function
|
113
118
|
* @param {Array.<String>} options
|
114
|
-
* @returns {
|
119
|
+
* @returns {FilterDialog~ComboBoxItem}
|
115
120
|
*/
|
116
|
-
|
121
|
+
let arrayToComboBoxItem = function(options) {
|
117
122
|
return {
|
118
123
|
label: options[1],
|
119
124
|
value: options[0]
|
@@ -124,7 +129,7 @@ var arrayToComboBoxItem = function(options) {
|
|
124
129
|
* @param {Array.<Array>} conditions
|
125
130
|
* @returns {Array.<Object>}
|
126
131
|
*/
|
127
|
-
|
132
|
+
let createComboBoxData = function(conditions) {
|
128
133
|
return conditions.map(arrayToComboBoxItem);
|
129
134
|
};
|
130
135
|
|
@@ -199,7 +204,7 @@ class FilterDialog extends BasicElement {
|
|
199
204
|
}
|
200
205
|
|
201
206
|
if(changedProperties.has("config")) {
|
202
|
-
|
207
|
+
let options = this.config;
|
203
208
|
if(options) {
|
204
209
|
if (options.data) {
|
205
210
|
this.data = options.data;
|
@@ -287,8 +292,8 @@ class FilterDialog extends BasicElement {
|
|
287
292
|
* @return {*}
|
288
293
|
*/
|
289
294
|
render() {
|
290
|
-
|
291
|
-
|
295
|
+
let lang = this._translation[this._lang] ? this._lang : "en";
|
296
|
+
let t = this._translation[lang];
|
292
297
|
return html`
|
293
298
|
<ef-panel id="root_panel" spacing with-shadow with-border>
|
294
299
|
<div id="filterDialogContent" class="filter-dialog dialog-theme-wrapper">
|
@@ -420,9 +425,9 @@ class FilterDialog extends BasicElement {
|
|
420
425
|
*/
|
421
426
|
updated(changedProps) {
|
422
427
|
// Update Sort UI
|
423
|
-
|
424
|
-
|
425
|
-
|
428
|
+
let isHiddenSortUIChanged = changedProps.has("hiddenSortUI");
|
429
|
+
let isHiddenFilterUIChanged = changedProps.has("hiddenFilterUI");
|
430
|
+
let isHiddenAdvancedFilterChanged = changedProps.has("hiddenAdvancedFilter");
|
426
431
|
if (isHiddenSortUIChanged) {
|
427
432
|
let pn = this._sortUI.parentNode;
|
428
433
|
if (this.hiddenSortUI) {
|
@@ -458,7 +463,7 @@ class FilterDialog extends BasicElement {
|
|
458
463
|
}
|
459
464
|
|
460
465
|
if (isHiddenSortUIChanged || isHiddenFilterUIChanged) {
|
461
|
-
|
466
|
+
let isHide = this.hiddenSortUI || this.hiddenFilterUI;
|
462
467
|
this._separator.classList.toggle("hide", isHide);
|
463
468
|
}
|
464
469
|
if(isHiddenAdvancedFilterChanged) {
|
@@ -490,7 +495,7 @@ class FilterDialog extends BasicElement {
|
|
490
495
|
this._cancelBtn.focus(); // Keep focus on cancel button when open dialog
|
491
496
|
this._updateDialogHeight(); // position of the popup element will always be updated
|
492
497
|
|
493
|
-
|
498
|
+
let popupElem = this._popup.getElement();
|
494
499
|
if(popupElem) {// After all changes, ensure that visibility is reset back
|
495
500
|
popupElem.style.visibility = "";
|
496
501
|
}
|
@@ -508,7 +513,7 @@ class FilterDialog extends BasicElement {
|
|
508
513
|
* @public
|
509
514
|
*/
|
510
515
|
show() {
|
511
|
-
|
516
|
+
let popupElem = this._popup.getElement();
|
512
517
|
if(popupElem) {// To prevent blinking due to size and position change
|
513
518
|
popupElem.style.visibility = "hidden";
|
514
519
|
}
|
@@ -664,9 +669,9 @@ class FilterDialog extends BasicElement {
|
|
664
669
|
if (this._isAdvancedFilterMode()) {
|
665
670
|
// Retrieve filter conditions from UI;
|
666
671
|
let oper1, oper2, val1, val2, connector;
|
667
|
-
|
668
|
-
|
669
|
-
|
672
|
+
let dateTimeType = toDateTimeType(this.fieldDataType);
|
673
|
+
let fdt = dateTimeType ? dateTimeType : this.fieldDataType.toLowerCase();
|
674
|
+
let useUTCTime = false;
|
670
675
|
if (fdt === DATE_TIME) {
|
671
676
|
useUTCTime = this.useUTCTime;
|
672
677
|
oper1 = this._dateTimeComboBoxes[0].value;
|
@@ -699,7 +704,7 @@ class FilterDialog extends BasicElement {
|
|
699
704
|
|
700
705
|
// Perform automatic data type conversion for only number field data type
|
701
706
|
if (fdt === "number") {
|
702
|
-
|
707
|
+
let num = NaN;
|
703
708
|
if (val1) {
|
704
709
|
num = Number(val1);
|
705
710
|
if(num === num) { // Convert to number only when number is valid
|
@@ -715,7 +720,7 @@ class FilterDialog extends BasicElement {
|
|
715
720
|
}
|
716
721
|
}
|
717
722
|
}
|
718
|
-
|
723
|
+
let ary2D = [];
|
719
724
|
|
720
725
|
if(this._isValidCondition(oper1, val1)) {
|
721
726
|
ary2D.push([oper1, val1]);
|
@@ -757,9 +762,9 @@ class FilterDialog extends BasicElement {
|
|
757
762
|
* @private
|
758
763
|
*/
|
759
764
|
_clearAdvanceFilterUI() {
|
760
|
-
|
761
|
-
|
762
|
-
|
765
|
+
let defaultVal = "";
|
766
|
+
let dateTimeType = toDateTimeType(this.fieldDataType);
|
767
|
+
let fdt = dateTimeType ? dateTimeType : this.fieldDataType.toLowerCase();
|
763
768
|
if (fdt === DATE_TIME) {
|
764
769
|
defaultVal = "DT";
|
765
770
|
this._clearValue(this._dateTimeComboBoxes[0], defaultVal);
|
@@ -785,9 +790,9 @@ class FilterDialog extends BasicElement {
|
|
785
790
|
*/
|
786
791
|
_updateGeneralComboBoxes() {
|
787
792
|
if(this._initialized) {
|
788
|
-
|
789
|
-
|
790
|
-
|
793
|
+
let filterItems;
|
794
|
+
let dateTimeType = toDateTimeType(this.fieldDataType);
|
795
|
+
let fdt = dateTimeType ? dateTimeType : this.fieldDataType.toLowerCase();
|
791
796
|
if(fdt === "number") {
|
792
797
|
filterItems = NUMBER_FILTERS;
|
793
798
|
} else if(fdt === "string" || fdt === "text") {
|
@@ -798,7 +803,7 @@ class FilterDialog extends BasicElement {
|
|
798
803
|
if(this._blankValues) {
|
799
804
|
filterItems = filterItems.concat(BLANK_FILTERS);
|
800
805
|
}
|
801
|
-
|
806
|
+
let translated = this._translateFilters(filterItems);
|
802
807
|
this._generalComboBoxes[0].data = createComboBoxData(translated);
|
803
808
|
this._generalComboBoxes[2].data = createComboBoxData(translated);
|
804
809
|
}
|
@@ -828,7 +833,7 @@ class FilterDialog extends BasicElement {
|
|
828
833
|
// So wee need to remove free-text and re-set again
|
829
834
|
// to track bug https://jira.refinitiv.com/browse/ELF-1694
|
830
835
|
// TODO:: need to remove WORKAROUND after ELF-1694 fixed
|
831
|
-
|
836
|
+
let hasFreeTextMode = elem.getAttribute("free-text") != null;
|
832
837
|
if (hasFreeTextMode) {
|
833
838
|
elem.removeAttribute("free-text");
|
834
839
|
}
|
@@ -874,10 +879,10 @@ class FilterDialog extends BasicElement {
|
|
874
879
|
}
|
875
880
|
|
876
881
|
const con1 = userConditions[0];
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
882
|
+
let validCon1 = false;
|
883
|
+
let conOp1 = "";
|
884
|
+
let conVal1 = "";
|
885
|
+
let connector = "";
|
881
886
|
if(Array.isArray(con1)) {
|
882
887
|
conOp1 = con1[0];
|
883
888
|
if(con1.length && con1[0]) {
|
@@ -892,9 +897,9 @@ class FilterDialog extends BasicElement {
|
|
892
897
|
}
|
893
898
|
|
894
899
|
const con2 = userConditions[1];
|
895
|
-
|
896
|
-
|
897
|
-
|
900
|
+
let validCon2 = false;
|
901
|
+
let conOp2 = "";
|
902
|
+
let conVal2 = "";
|
898
903
|
if(validCon1 && Array.isArray(con2)) {
|
899
904
|
conOp2 = con2[0];
|
900
905
|
if(con2.length && conOp2) {
|
@@ -907,7 +912,7 @@ class FilterDialog extends BasicElement {
|
|
907
912
|
}
|
908
913
|
}
|
909
914
|
|
910
|
-
|
915
|
+
let firstRadioState = true;
|
911
916
|
if(validCon1 && validCon2) {
|
912
917
|
firstRadioState = connector !== "OR";
|
913
918
|
}
|
@@ -966,7 +971,7 @@ class FilterDialog extends BasicElement {
|
|
966
971
|
const dialogCoverage = position.y + dialogHeight;
|
967
972
|
const heightDiff = dialogCoverage - windowHeight;
|
968
973
|
|
969
|
-
|
974
|
+
let heightChange = false;
|
970
975
|
if(heightDiff > 0) {
|
971
976
|
heightChange = true;
|
972
977
|
const isAdvancedFilter = this._isAdvancedFilterMode();
|
@@ -1007,7 +1012,7 @@ class FilterDialog extends BasicElement {
|
|
1007
1012
|
* @private
|
1008
1013
|
*/
|
1009
1014
|
_addBlankItem() {
|
1010
|
-
|
1015
|
+
let ary = this._dataToArray(this.data);
|
1011
1016
|
if(this._blankValues) {
|
1012
1017
|
let blankItem = {
|
1013
1018
|
id: "_blank",
|
@@ -1026,16 +1031,22 @@ class FilterDialog extends BasicElement {
|
|
1026
1031
|
* @private
|
1027
1032
|
*/
|
1028
1033
|
_updateValueSelector() {
|
1029
|
-
|
1034
|
+
let ary = this._dataToArray(this.data);
|
1030
1035
|
this._dataSelector.data = ary; // Preserve original referencing
|
1031
1036
|
// Value selector for Filter by Condition
|
1032
1037
|
if(ary.length > ITEM_LIMIT) {
|
1033
1038
|
ary = ary.slice(0, ITEM_LIMIT); // Prevent combo box from over population
|
1034
1039
|
}
|
1035
1040
|
// Advance items
|
1036
|
-
|
1041
|
+
let advanceItems = [];
|
1042
|
+
for (let i = 0; i < ary.length; i++) {
|
1043
|
+
let item = ary[i];
|
1044
|
+
if(!item.type) {
|
1045
|
+
advanceItems.push(this._toComboBoxItem(item));
|
1046
|
+
}
|
1047
|
+
}
|
1037
1048
|
if(this._blankValues) {
|
1038
|
-
|
1049
|
+
let basicItems = advanceItems.slice(1);
|
1039
1050
|
this._generalComboBoxes[1].data = basicItems;
|
1040
1051
|
this._generalComboBoxes[3].data = basicItems;
|
1041
1052
|
} else {
|
@@ -1046,10 +1057,10 @@ class FilterDialog extends BasicElement {
|
|
1046
1057
|
/**
|
1047
1058
|
* @private
|
1048
1059
|
* @param {*} obj
|
1049
|
-
* @returns {
|
1060
|
+
* @returns {FilterDialog~ComboBoxItem}
|
1050
1061
|
*/
|
1051
1062
|
_toComboBoxItem(obj) {
|
1052
|
-
let itemVal = (typeof obj === "string") ? obj : obj.title || "";
|
1063
|
+
let itemVal = (typeof obj === "string") ? obj : (obj.label || obj.title) || "";
|
1053
1064
|
return {
|
1054
1065
|
"label": itemVal,
|
1055
1066
|
"value": itemVal
|
@@ -1076,7 +1087,7 @@ class FilterDialog extends BasicElement {
|
|
1076
1087
|
* @return {Date}
|
1077
1088
|
*/
|
1078
1089
|
_getDateObject(dateString) {
|
1079
|
-
|
1090
|
+
let date = new Date(dateString);
|
1080
1091
|
if(date && this.useUTCTime == false){
|
1081
1092
|
date.setTime(date.getTime() + (date.getTimezoneOffset() * 60000)); // convert to local time
|
1082
1093
|
}
|
@@ -1088,7 +1099,7 @@ class FilterDialog extends BasicElement {
|
|
1088
1099
|
* @return {Object}
|
1089
1100
|
*/
|
1090
1101
|
_getTranslation() {
|
1091
|
-
|
1102
|
+
let lang = this._translation[this._lang] ? this._lang : "en";
|
1092
1103
|
return this._translation[lang];
|
1093
1104
|
}
|
1094
1105
|
|
@@ -1099,10 +1110,10 @@ class FilterDialog extends BasicElement {
|
|
1099
1110
|
*/
|
1100
1111
|
_translateFilters(filters) {
|
1101
1112
|
let trans = this._getTranslation();
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
for (
|
1113
|
+
let len = filters.length;
|
1114
|
+
let items = [];
|
1115
|
+
let item;
|
1116
|
+
for (let i = 0; i < len; i++) {
|
1106
1117
|
item = filters[i];
|
1107
1118
|
items.push([item[0], trans[item[1]]]);
|
1108
1119
|
}
|
package/lib/grid/index.js
CHANGED
@@ -32,12 +32,20 @@ declare namespace RowFilteringPlugin {
|
|
32
32
|
rawDataAccessor?: ((...params: any[]) => any)|null,
|
33
33
|
formattedDataAccessor?: ((...params: any[]) => any)|null,
|
34
34
|
sortLogic?: ((...params: any[]) => any)|null,
|
35
|
+
groupCriteria?: ((...params: any[]) => any)|null,
|
36
|
+
groupSortLogic?: ((...params: any[]) => any)|null,
|
35
37
|
itemList?: any[]|null,
|
36
38
|
additionalItems?: any[]|null,
|
37
39
|
compactMode?: boolean|null,
|
38
40
|
blankValues?: (boolean|string)|null
|
39
41
|
};
|
40
42
|
|
43
|
+
type FilterEntry = {
|
44
|
+
type?: string|null,
|
45
|
+
label: string,
|
46
|
+
checked: boolean
|
47
|
+
};
|
48
|
+
|
41
49
|
type Options = {
|
42
50
|
emptySegmentFiltering?: boolean|null,
|
43
51
|
separatorFiltering?: boolean|null,
|
@@ -86,12 +86,21 @@ The expression can take various forms:<br>
|
|
86
86
|
* @property {Function=} rawDataAccessor In case you have custom data type for the specified field, data getter is needed to retrieve raw value for filtering
|
87
87
|
* @property {Function=} formattedDataAccessor This function will be called on each raw data, allowing formatting data to be displayed on the filter item list
|
88
88
|
* @property {Function=} sortLogic This function for sorting filter item list in the dialog. The comparison will perform on raw values, and not formatted values
|
89
|
+
* @property {Function=} groupCriteria This function for specify group of items to show group as headers.
|
90
|
+
* @property {Function=} groupSortLogic This function for sorting of group header, used with `groupCriteria` to show as group.
|
89
91
|
* @property {Array=} itemList Item list to be shown in the dialog. If this is not specified, the list will be collected from existing data on the grid
|
90
92
|
* @property {Array=} additionalItems Additional items to be put on the itemList
|
91
93
|
* @property {boolean=} compactMode=false force compact mode in dialog
|
92
94
|
* @property {(boolean|string)=} blankValues Display a "(Blanks)" item in the filter dialog to represent an empty value. If a string is passed, it will be used as the label for the blank item
|
93
95
|
*/
|
94
96
|
|
97
|
+
/** @typedef {Object} RowFilteringPlugin~FilterEntry
|
98
|
+
* @description item object to rendered element-item
|
99
|
+
* @property {string=} type=null Available types are "header" and "divider". If null, it will be shown as a normal item.
|
100
|
+
* @property {string} label="" Text of each item. If the type is "header", it will be shown as a header. If the type is "divider", it will not be shown.
|
101
|
+
* @property {boolean} checked=false Set to true to check the checkbox item in the filter dialog basic item.
|
102
|
+
*/
|
103
|
+
|
95
104
|
/** @typedef {Object} RowFilteringPlugin~Options
|
96
105
|
* @description The options can be specified by `rowFiltering` property of the main grid's options
|
97
106
|
* @property {boolean=} emptySegmentFiltering=false If enabled, the filter will automatically hide empty segment when all of its member are filtered out. If there is no active filter, any empty segment will not be hidden. Collapsed segment does not count as having a filter. A segment with no child is treated the same way as an empty segment.
|
@@ -1922,13 +1931,10 @@ RowFilteringPlugin.prototype.openDialog = function(colIndex, runtimeDialogOption
|
|
1922
1931
|
});
|
1923
1932
|
}
|
1924
1933
|
|
1925
|
-
let items =
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
nodes: [],
|
1930
|
-
checked: selectedItems[formattedVal] ? true : false
|
1931
|
-
};
|
1934
|
+
let items = this._toListScheme({
|
1935
|
+
dialogConfig: dialogConfig,
|
1936
|
+
keys: keys,
|
1937
|
+
selectedItems: selectedItems
|
1932
1938
|
});
|
1933
1939
|
|
1934
1940
|
// Adding inputs from conditions to uniqueValues for mapping back from the dialog
|
@@ -1946,7 +1952,6 @@ RowFilteringPlugin.prototype.openDialog = function(colIndex, runtimeDialogOption
|
|
1946
1952
|
}
|
1947
1953
|
}
|
1948
1954
|
}
|
1949
|
-
|
1950
1955
|
// Initialize dialog
|
1951
1956
|
if(this._filterDialog.init) { // TODO: support initiailization in v1
|
1952
1957
|
this._filterDialog.init(dialogConfig);
|
@@ -2016,6 +2021,16 @@ RowFilteringPlugin._overrideConfig = function(config, userConfig) {
|
|
2016
2021
|
config.sortLogic = sortLogic;
|
2017
2022
|
}
|
2018
2023
|
|
2024
|
+
let groupCriteria = userConfig["groupCriteria"];
|
2025
|
+
if(typeof groupCriteria === "function" || groupCriteria === null) { // Allow null value
|
2026
|
+
config.groupCriteria = groupCriteria;
|
2027
|
+
}
|
2028
|
+
|
2029
|
+
let groupSortLogic = userConfig["groupSortLogic"];
|
2030
|
+
if(typeof groupSortLogic === "function" || groupSortLogic === null) { // Allow null value
|
2031
|
+
config.groupSortLogic = groupSortLogic;
|
2032
|
+
}
|
2033
|
+
|
2019
2034
|
let itemList = userConfig["itemList"];
|
2020
2035
|
if(itemList != null) {
|
2021
2036
|
config.itemList = itemList;
|
@@ -2034,6 +2049,72 @@ RowFilteringPlugin._overrideConfig = function(config, userConfig) {
|
|
2034
2049
|
}
|
2035
2050
|
}
|
2036
2051
|
};
|
2052
|
+
|
2053
|
+
/** @private
|
2054
|
+
* @param {Object} listObj
|
2055
|
+
* @return {Array<Object>}
|
2056
|
+
*/
|
2057
|
+
RowFilteringPlugin.prototype._toListScheme = function(listObj) {
|
2058
|
+
let dialogConfig = listObj.dialogConfig;
|
2059
|
+
let keys = listObj.keys;
|
2060
|
+
let selectedItems = listObj.selectedItems;
|
2061
|
+
|
2062
|
+
let groupCriteria = dialogConfig.groupCriteria;
|
2063
|
+
let items = keys;
|
2064
|
+
let groupMap = {};
|
2065
|
+
if(groupCriteria) {
|
2066
|
+
for (let idx = 0; idx < items.length; idx++) {
|
2067
|
+
let formattedVal = items[idx];
|
2068
|
+
let item = {
|
2069
|
+
id: idx,
|
2070
|
+
label: formattedVal,
|
2071
|
+
title: formattedVal, // Backward compatibility
|
2072
|
+
nodes: [],
|
2073
|
+
checked: selectedItems[formattedVal] ? true : false,
|
2074
|
+
group: groupCriteria(formattedVal) || null // no group will be null map
|
2075
|
+
};
|
2076
|
+
if(!groupMap[item.group]) {
|
2077
|
+
groupMap[item.group] = [];
|
2078
|
+
}
|
2079
|
+
groupMap[item.group].push(item);
|
2080
|
+
}
|
2081
|
+
let groupOrdered = Object.keys(groupMap);
|
2082
|
+
let groupSortLogic = dialogConfig.groupSortLogic;
|
2083
|
+
if(groupSortLogic) {
|
2084
|
+
groupOrdered = groupOrdered.sort(groupSortLogic);
|
2085
|
+
}
|
2086
|
+
let sortedGroupItems = [];
|
2087
|
+
for (let i = 0; i < groupOrdered.length; i++) {
|
2088
|
+
let groupName = groupOrdered[i];
|
2089
|
+
let groupAry = groupMap[groupName];
|
2090
|
+
let validGroup = groupName != "null" ? true : false;
|
2091
|
+
if(validGroup) {
|
2092
|
+
sortedGroupItems.push({
|
2093
|
+
type: "header",
|
2094
|
+
label: groupName
|
2095
|
+
});
|
2096
|
+
}
|
2097
|
+
sortedGroupItems = sortedGroupItems.concat(groupAry);
|
2098
|
+
if(validGroup) {
|
2099
|
+
sortedGroupItems.push({
|
2100
|
+
type: "divider"
|
2101
|
+
});
|
2102
|
+
}
|
2103
|
+
}
|
2104
|
+
items = sortedGroupItems;
|
2105
|
+
} else {
|
2106
|
+
items = keys.map(function(formattedVal, idx) {
|
2107
|
+
return {
|
2108
|
+
id: idx,
|
2109
|
+
label: formattedVal,
|
2110
|
+
title: formattedVal, // Backward compatibility
|
2111
|
+
nodes: [],
|
2112
|
+
checked: selectedItems[formattedVal] ? true : false
|
2113
|
+
};
|
2114
|
+
});
|
2115
|
+
}
|
2116
|
+
return items;
|
2117
|
+
};
|
2037
2118
|
/** @private
|
2038
2119
|
* @param {number} colIndex
|
2039
2120
|
* @return {Function}
|
@@ -2144,7 +2225,7 @@ RowFilteringPlugin.prototype._onDialogFilterChanged = function(e) {
|
|
2144
2225
|
let selectedItems = {};
|
2145
2226
|
let atLeastOne = false;
|
2146
2227
|
for(let i = 0; i < selCount; ++i) {
|
2147
|
-
let formattedVal = selAry[i].title; // title is defined by the multi-select element
|
2228
|
+
let formattedVal = selAry[i].label || selAry[i].title; // title is defined by the multi-select element
|
2148
2229
|
// let selIdx = selAry[i].index; // index cannot be used due to filtering
|
2149
2230
|
if(selAry[i].value === BLANKS) {
|
2150
2231
|
if(!ctx) {
|
package/lib/versions.json
CHANGED
@@ -24,7 +24,7 @@
|
|
24
24
|
"tr-grid-percent-bar": "1.0.24",
|
25
25
|
"tr-grid-range-bar": "2.0.8",
|
26
26
|
"tr-grid-row-dragging": "1.0.35",
|
27
|
-
"tr-grid-row-filtering": "1.0.
|
27
|
+
"tr-grid-row-filtering": "1.0.79",
|
28
28
|
"tr-grid-row-grouping": "1.0.88",
|
29
29
|
"tr-grid-row-selection": "1.0.30",
|
30
30
|
"tr-grid-rowcoloring": "1.0.25",
|
@@ -32,6 +32,6 @@
|
|
32
32
|
"tr-grid-titlewrap": "1.0.22",
|
33
33
|
"@grid/formatters": "1.0.55",
|
34
34
|
"@grid/column-selection-dialog": "4.0.57",
|
35
|
-
"@grid/filter-dialog": "4.0.
|
35
|
+
"@grid/filter-dialog": "4.0.66",
|
36
36
|
"@grid/column-format-dialog": "4.0.45"
|
37
37
|
}
|
package/package.json
CHANGED