@vaadin/grid 24.2.0-dev.e9803eea7 → 24.2.0-rc1
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 +11 -11
- package/src/vaadin-grid-column-group.js +3 -1
- package/src/vaadin-grid-column.js +5 -2
- package/src/vaadin-grid-data-provider-mixin.d.ts +25 -0
- package/src/vaadin-grid-data-provider-mixin.js +246 -75
- package/src/vaadin-grid-dynamic-columns-mixin.js +1 -1
- package/src/vaadin-grid-filter-column.js +5 -1
- package/src/vaadin-grid-filter.js +3 -1
- package/src/vaadin-grid-keyboard-navigation-mixin.js +23 -3
- package/src/vaadin-grid-mixin.d.ts +218 -0
- package/src/vaadin-grid-mixin.js +1022 -0
- package/src/vaadin-grid-selection-column-base-mixin.d.ts +6 -0
- package/src/vaadin-grid-selection-column-base-mixin.js +151 -0
- package/src/vaadin-grid-selection-column.js +4 -1
- package/src/vaadin-grid-sort-column.js +5 -1
- package/src/vaadin-grid-sorter.js +3 -1
- package/src/vaadin-grid-tree-column.js +6 -2
- package/src/vaadin-grid-tree-toggle.js +3 -1
- package/src/vaadin-grid.d.ts +5 -190
- package/src/vaadin-grid.js +7 -1018
- package/web-types.json +2311 -0
- package/web-types.lit.json +1007 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/grid",
|
|
3
|
-
"version": "24.2.0-
|
|
3
|
+
"version": "24.2.0-rc1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -46,18 +46,18 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
48
48
|
"@polymer/polymer": "^3.0.0",
|
|
49
|
-
"@vaadin/a11y-base": "24.2.0-
|
|
50
|
-
"@vaadin/checkbox": "24.2.0-
|
|
51
|
-
"@vaadin/component-base": "24.2.0-
|
|
52
|
-
"@vaadin/lit-renderer": "24.2.0-
|
|
53
|
-
"@vaadin/text-field": "24.2.0-
|
|
54
|
-
"@vaadin/vaadin-lumo-styles": "24.2.0-
|
|
55
|
-
"@vaadin/vaadin-material-styles": "24.2.0-
|
|
56
|
-
"@vaadin/vaadin-themable-mixin": "24.2.0-
|
|
49
|
+
"@vaadin/a11y-base": "24.2.0-rc1",
|
|
50
|
+
"@vaadin/checkbox": "24.2.0-rc1",
|
|
51
|
+
"@vaadin/component-base": "24.2.0-rc1",
|
|
52
|
+
"@vaadin/lit-renderer": "24.2.0-rc1",
|
|
53
|
+
"@vaadin/text-field": "24.2.0-rc1",
|
|
54
|
+
"@vaadin/vaadin-lumo-styles": "24.2.0-rc1",
|
|
55
|
+
"@vaadin/vaadin-material-styles": "24.2.0-rc1",
|
|
56
|
+
"@vaadin/vaadin-themable-mixin": "24.2.0-rc1"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@esm-bundle/chai": "^4.3.4",
|
|
60
|
-
"@vaadin/testing-helpers": "^0.
|
|
60
|
+
"@vaadin/testing-helpers": "^0.5.0",
|
|
61
61
|
"lit": "^2.0.0",
|
|
62
62
|
"sinon": "^13.0.2"
|
|
63
63
|
},
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"web-types.json",
|
|
66
66
|
"web-types.lit.json"
|
|
67
67
|
],
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "012bef350bbf29865748f4c78338dd17c6f61a74"
|
|
69
69
|
}
|
|
@@ -7,6 +7,7 @@ import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nod
|
|
|
7
7
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
8
8
|
import { animationFrame } from '@vaadin/component-base/src/async.js';
|
|
9
9
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
10
|
+
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
10
11
|
import { ColumnBaseMixin } from './vaadin-grid-column.js';
|
|
11
12
|
import { updateColumnOrders } from './vaadin-grid-helpers.js';
|
|
12
13
|
|
|
@@ -39,6 +40,7 @@ import { updateColumnOrders } from './vaadin-grid-helpers.js';
|
|
|
39
40
|
* column2.renderer = (root, column, model) => { ... };
|
|
40
41
|
* ```
|
|
41
42
|
*
|
|
43
|
+
* @customElement
|
|
42
44
|
* @extends HTMLElement
|
|
43
45
|
* @mixes ColumnBaseMixin
|
|
44
46
|
*/
|
|
@@ -396,6 +398,6 @@ class GridColumnGroup extends ColumnBaseMixin(PolymerElement) {
|
|
|
396
398
|
}
|
|
397
399
|
}
|
|
398
400
|
|
|
399
|
-
|
|
401
|
+
defineCustomElement(GridColumnGroup);
|
|
400
402
|
|
|
401
403
|
export { GridColumnGroup };
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
7
7
|
import { animationFrame } from '@vaadin/component-base/src/async.js';
|
|
8
8
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
9
|
+
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
9
10
|
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
|
|
11
|
+
import { get } from '@vaadin/component-base/src/path-utils.js';
|
|
10
12
|
import { processTemplates } from '@vaadin/component-base/src/templates.js';
|
|
11
13
|
import { updateCellState } from './vaadin-grid-helpers.js';
|
|
12
14
|
|
|
@@ -713,7 +715,7 @@ export const ColumnBaseMixin = (superClass) =>
|
|
|
713
715
|
return;
|
|
714
716
|
}
|
|
715
717
|
|
|
716
|
-
this.__setTextContent(root,
|
|
718
|
+
this.__setTextContent(root, get(this.path, item));
|
|
717
719
|
}
|
|
718
720
|
|
|
719
721
|
/**
|
|
@@ -783,6 +785,7 @@ export const ColumnBaseMixin = (superClass) =>
|
|
|
783
785
|
* See [`<vaadin-grid>`](#/elements/vaadin-grid) documentation for instructions on how
|
|
784
786
|
* to configure the `<vaadin-grid-column>`.
|
|
785
787
|
*
|
|
788
|
+
* @customElement
|
|
786
789
|
* @extends HTMLElement
|
|
787
790
|
* @mixes ColumnBaseMixin
|
|
788
791
|
*/
|
|
@@ -894,6 +897,6 @@ class GridColumn extends ColumnBaseMixin(DirMixin(PolymerElement)) {
|
|
|
894
897
|
}
|
|
895
898
|
}
|
|
896
899
|
|
|
897
|
-
|
|
900
|
+
defineCustomElement(GridColumn);
|
|
898
901
|
|
|
899
902
|
export { GridColumn };
|
|
@@ -33,6 +33,31 @@ export type GridDataProvider<TItem> = (
|
|
|
33
33
|
callback: GridDataProviderCallback<TItem>,
|
|
34
34
|
) => void;
|
|
35
35
|
|
|
36
|
+
export declare class ItemCache<TItem> {
|
|
37
|
+
grid: HTMLElement;
|
|
38
|
+
parentCache: ItemCache<TItem> | undefined;
|
|
39
|
+
parentItem: TItem | undefined;
|
|
40
|
+
itemCaches: object | null;
|
|
41
|
+
items: object | null;
|
|
42
|
+
effectiveSize: number;
|
|
43
|
+
size: number;
|
|
44
|
+
pendingRequests: object | null;
|
|
45
|
+
|
|
46
|
+
constructor(grid: HTMLElement, parentCache: ItemCache<TItem> | undefined, parentItem: TItem | undefined);
|
|
47
|
+
|
|
48
|
+
isLoading(): boolean;
|
|
49
|
+
|
|
50
|
+
getItemForIndex(index: number): TItem | undefined;
|
|
51
|
+
|
|
52
|
+
updateSize(): void;
|
|
53
|
+
|
|
54
|
+
ensureSubCacheForScaledIndex(scaledIndex: number): void;
|
|
55
|
+
|
|
56
|
+
getCacheAndIndex(index: number): { cache: ItemCache<TItem>; scaledIndex: number };
|
|
57
|
+
|
|
58
|
+
getFlatIndex(scaledIndex: number): number;
|
|
59
|
+
}
|
|
60
|
+
|
|
36
61
|
export declare function DataProviderMixin<TItem, T extends Constructor<HTMLElement>>(
|
|
37
62
|
base: T,
|
|
38
63
|
): Constructor<DataProviderMixinClass<TItem>> & T;
|
|
@@ -4,10 +4,116 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { timeOut } from '@vaadin/component-base/src/async.js';
|
|
7
|
-
import { DataProviderController } from '@vaadin/component-base/src/data-provider-controller.js';
|
|
8
7
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
8
|
+
import { get } from '@vaadin/component-base/src/path-utils.js';
|
|
9
9
|
import { getBodyRowCells, updateCellsPart, updateState } from './vaadin-grid-helpers.js';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* @private
|
|
13
|
+
*/
|
|
14
|
+
export const ItemCache = class ItemCache {
|
|
15
|
+
/**
|
|
16
|
+
* @param {!HTMLElement} grid
|
|
17
|
+
* @param {!ItemCache | undefined} parentCache
|
|
18
|
+
* @param {!GridItem | undefined} parentItem
|
|
19
|
+
*/
|
|
20
|
+
constructor(grid, parentCache, parentItem) {
|
|
21
|
+
/** @type {!HTMLElement} */
|
|
22
|
+
this.grid = grid;
|
|
23
|
+
/** @type {!ItemCache | undefined} */
|
|
24
|
+
this.parentCache = parentCache;
|
|
25
|
+
/** @type {!GridItem | undefined} */
|
|
26
|
+
this.parentItem = parentItem;
|
|
27
|
+
/** @type {object} */
|
|
28
|
+
this.itemCaches = {};
|
|
29
|
+
/** @type {object[]} */
|
|
30
|
+
this.items = [];
|
|
31
|
+
/** @type {number} */
|
|
32
|
+
this.effectiveSize = 0;
|
|
33
|
+
/** @type {number} */
|
|
34
|
+
this.size = 0;
|
|
35
|
+
/** @type {object} */
|
|
36
|
+
this.pendingRequests = {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @return {boolean}
|
|
41
|
+
*/
|
|
42
|
+
isLoading() {
|
|
43
|
+
return Boolean(
|
|
44
|
+
Object.keys(this.pendingRequests).length ||
|
|
45
|
+
Object.keys(this.itemCaches).filter((index) => {
|
|
46
|
+
return this.itemCaches[index].isLoading();
|
|
47
|
+
})[0],
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {number} index
|
|
53
|
+
* @return {!GridItem | undefined}
|
|
54
|
+
*/
|
|
55
|
+
getItemForIndex(index) {
|
|
56
|
+
const { cache, scaledIndex } = this.getCacheAndIndex(index);
|
|
57
|
+
return cache.items[scaledIndex];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
updateSize() {
|
|
61
|
+
this.effectiveSize =
|
|
62
|
+
!this.parentItem || this.grid._isExpanded(this.parentItem)
|
|
63
|
+
? this.size +
|
|
64
|
+
Object.keys(this.itemCaches).reduce((prev, curr) => {
|
|
65
|
+
const subCache = this.itemCaches[curr];
|
|
66
|
+
subCache.updateSize();
|
|
67
|
+
return prev + subCache.effectiveSize;
|
|
68
|
+
}, 0)
|
|
69
|
+
: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {number} scaledIndex
|
|
74
|
+
*/
|
|
75
|
+
ensureSubCacheForScaledIndex(scaledIndex) {
|
|
76
|
+
if (!this.itemCaches[scaledIndex]) {
|
|
77
|
+
const subCache = new ItemCache(this.grid, this, this.items[scaledIndex]);
|
|
78
|
+
this.itemCaches[scaledIndex] = subCache;
|
|
79
|
+
this.grid._loadPage(0, subCache);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {number} index
|
|
85
|
+
* @return {{cache: !ItemCache, scaledIndex: number}}
|
|
86
|
+
*/
|
|
87
|
+
getCacheAndIndex(index) {
|
|
88
|
+
let thisLevelIndex = index;
|
|
89
|
+
for (const [index, subCache] of Object.entries(this.itemCaches)) {
|
|
90
|
+
const numberIndex = Number(index);
|
|
91
|
+
if (thisLevelIndex <= numberIndex) {
|
|
92
|
+
return { cache: this, scaledIndex: thisLevelIndex };
|
|
93
|
+
} else if (thisLevelIndex <= numberIndex + subCache.effectiveSize) {
|
|
94
|
+
return subCache.getCacheAndIndex(thisLevelIndex - numberIndex - 1);
|
|
95
|
+
}
|
|
96
|
+
thisLevelIndex -= subCache.effectiveSize;
|
|
97
|
+
}
|
|
98
|
+
return { cache: this, scaledIndex: thisLevelIndex };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Gets the scaled index as flattened index on this cache level.
|
|
103
|
+
* In practice, this means that the effective size of any expanded
|
|
104
|
+
* subcaches preceding the index are added to the value.
|
|
105
|
+
* @param {number} scaledIndex
|
|
106
|
+
* @return {number} The flat index on this cache level.
|
|
107
|
+
*/
|
|
108
|
+
getFlatIndex(scaledIndex) {
|
|
109
|
+
const clampedIndex = Math.max(0, Math.min(this.size - 1, scaledIndex));
|
|
110
|
+
|
|
111
|
+
return Object.entries(this.itemCaches).reduce((prev, [index, subCache]) => {
|
|
112
|
+
return clampedIndex > Number(index) ? prev + subCache.effectiveSize : prev;
|
|
113
|
+
}, clampedIndex);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
11
117
|
/**
|
|
12
118
|
* @polymerMixin
|
|
13
119
|
*/
|
|
@@ -75,6 +181,18 @@ export const DataProviderMixin = (superClass) =>
|
|
|
75
181
|
reflectToAttribute: true,
|
|
76
182
|
},
|
|
77
183
|
|
|
184
|
+
/**
|
|
185
|
+
* @type {!ItemCache}
|
|
186
|
+
* @protected
|
|
187
|
+
*/
|
|
188
|
+
_cache: {
|
|
189
|
+
type: Object,
|
|
190
|
+
value() {
|
|
191
|
+
const cache = new ItemCache(this);
|
|
192
|
+
return cache;
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
|
|
78
196
|
/**
|
|
79
197
|
* @protected
|
|
80
198
|
*/
|
|
@@ -126,32 +244,12 @@ export const DataProviderMixin = (superClass) =>
|
|
|
126
244
|
return ['_sizeChanged(size)', '_expandedItemsChanged(expandedItems.*)'];
|
|
127
245
|
}
|
|
128
246
|
|
|
129
|
-
constructor() {
|
|
130
|
-
super();
|
|
131
|
-
|
|
132
|
-
/** @type {DataProviderController} */
|
|
133
|
-
this._dataProviderController = new DataProviderController(this, {
|
|
134
|
-
size: this.size,
|
|
135
|
-
pageSize: this.pageSize,
|
|
136
|
-
isExpanded: this._isExpanded.bind(this),
|
|
137
|
-
dataProvider: this.dataProvider ? this.dataProvider.bind(this) : null,
|
|
138
|
-
dataProviderParams: () => {
|
|
139
|
-
return {
|
|
140
|
-
sortOrders: this._mapSorters(),
|
|
141
|
-
filters: this._mapFilters(),
|
|
142
|
-
};
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
this._dataProviderController.addEventListener('page-requested', this._onDataProviderPageRequested.bind(this));
|
|
147
|
-
this._dataProviderController.addEventListener('page-received', this._onDataProviderPageReceived.bind(this));
|
|
148
|
-
this._dataProviderController.addEventListener('page-loaded', this._onDataProviderPageLoaded.bind(this));
|
|
149
|
-
}
|
|
150
|
-
|
|
151
247
|
/** @private */
|
|
152
248
|
_sizeChanged(size) {
|
|
153
|
-
this.
|
|
154
|
-
this.
|
|
249
|
+
const delta = size - this._cache.size;
|
|
250
|
+
this._cache.size += delta;
|
|
251
|
+
this._cache.effectiveSize += delta;
|
|
252
|
+
this._effectiveSize = this._cache.effectiveSize;
|
|
155
253
|
}
|
|
156
254
|
|
|
157
255
|
/** @private */
|
|
@@ -174,17 +272,17 @@ export const DataProviderMixin = (superClass) =>
|
|
|
174
272
|
}
|
|
175
273
|
|
|
176
274
|
el.index = index;
|
|
177
|
-
|
|
178
|
-
const
|
|
275
|
+
const { cache, scaledIndex } = this._cache.getCacheAndIndex(index);
|
|
276
|
+
const item = cache.items[scaledIndex];
|
|
179
277
|
if (item) {
|
|
180
278
|
this.__updateLoading(el, false);
|
|
181
279
|
this._updateItem(el, item);
|
|
182
280
|
if (this._isExpanded(item)) {
|
|
183
|
-
|
|
281
|
+
cache.ensureSubCacheForScaledIndex(scaledIndex);
|
|
184
282
|
}
|
|
185
283
|
} else {
|
|
186
284
|
this.__updateLoading(el, true);
|
|
187
|
-
this.
|
|
285
|
+
this._loadPage(this._getPageForIndex(scaledIndex), cache);
|
|
188
286
|
}
|
|
189
287
|
}
|
|
190
288
|
|
|
@@ -210,7 +308,7 @@ export const DataProviderMixin = (superClass) =>
|
|
|
210
308
|
* @return {!GridItem | !unknown}
|
|
211
309
|
*/
|
|
212
310
|
getItemId(item) {
|
|
213
|
-
return this.itemIdPath ?
|
|
311
|
+
return this.itemIdPath ? get(this.itemIdPath, item) : item;
|
|
214
312
|
}
|
|
215
313
|
|
|
216
314
|
/**
|
|
@@ -224,8 +322,8 @@ export const DataProviderMixin = (superClass) =>
|
|
|
224
322
|
|
|
225
323
|
/** @private */
|
|
226
324
|
_expandedItemsChanged() {
|
|
227
|
-
this.
|
|
228
|
-
this._effectiveSize = this.
|
|
325
|
+
this._cache.updateSize();
|
|
326
|
+
this._effectiveSize = this._cache.effectiveSize;
|
|
229
327
|
this.__updateVisibleRows();
|
|
230
328
|
}
|
|
231
329
|
|
|
@@ -265,68 +363,119 @@ export const DataProviderMixin = (superClass) =>
|
|
|
265
363
|
* @return {number}
|
|
266
364
|
* @protected
|
|
267
365
|
*/
|
|
268
|
-
_getIndexLevel(index
|
|
269
|
-
|
|
366
|
+
_getIndexLevel(index) {
|
|
367
|
+
let { cache } = this._cache.getCacheAndIndex(index);
|
|
368
|
+
let level = 0;
|
|
369
|
+
while (cache.parentCache) {
|
|
370
|
+
cache = cache.parentCache;
|
|
371
|
+
level += 1;
|
|
372
|
+
}
|
|
270
373
|
return level;
|
|
271
374
|
}
|
|
272
375
|
|
|
273
|
-
/**
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
376
|
+
/**
|
|
377
|
+
* @param {number} page
|
|
378
|
+
* @param {ItemCache} cache
|
|
379
|
+
* @protected
|
|
380
|
+
*/
|
|
381
|
+
_loadPage(page, cache) {
|
|
382
|
+
// Make sure same page isn't requested multiple times.
|
|
383
|
+
if (!cache.pendingRequests[page] && this.dataProvider) {
|
|
384
|
+
this._setLoading(true);
|
|
385
|
+
cache.pendingRequests[page] = true;
|
|
386
|
+
const params = {
|
|
387
|
+
page,
|
|
388
|
+
pageSize: this.pageSize,
|
|
389
|
+
sortOrders: this._mapSorters(),
|
|
390
|
+
filters: this._mapFilters(),
|
|
391
|
+
parentItem: cache.parentItem,
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
this.dataProvider(params, (items, size) => {
|
|
395
|
+
if (size !== undefined) {
|
|
396
|
+
cache.size = size;
|
|
397
|
+
} else if (params.parentItem) {
|
|
398
|
+
cache.size = items.length;
|
|
399
|
+
}
|
|
282
400
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
401
|
+
// Populate the cache with new items
|
|
402
|
+
items.forEach((item, itemsIndex) => {
|
|
403
|
+
const itemIndex = page * this.pageSize + itemsIndex;
|
|
404
|
+
cache.items[itemIndex] = item;
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// With the new items added, update the cache size and the grid's effective size
|
|
408
|
+
this._cache.updateSize();
|
|
409
|
+
this._effectiveSize = this._cache.effectiveSize;
|
|
410
|
+
|
|
411
|
+
// After updating the cache, check if some of the expanded items should have sub-caches loaded
|
|
412
|
+
this._getRenderedRows().forEach((row) => {
|
|
413
|
+
const { cache, scaledIndex } = this._cache.getCacheAndIndex(row.index);
|
|
414
|
+
const item = cache.items[scaledIndex];
|
|
415
|
+
if (item && this._isExpanded(item)) {
|
|
416
|
+
cache.ensureSubCacheForScaledIndex(scaledIndex);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
this._hasData = true;
|
|
421
|
+
|
|
422
|
+
// Remove the pending request
|
|
423
|
+
delete cache.pendingRequests[page];
|
|
424
|
+
|
|
425
|
+
// Schedule a debouncer to update the visible rows
|
|
426
|
+
this._debouncerApplyCachedData = Debouncer.debounce(this._debouncerApplyCachedData, timeOut.after(0), () => {
|
|
427
|
+
this._setLoading(false);
|
|
428
|
+
|
|
429
|
+
this._getRenderedRows().forEach((row) => {
|
|
430
|
+
const cachedItem = this._cache.getItemForIndex(row.index);
|
|
431
|
+
if (cachedItem) {
|
|
432
|
+
this._getItem(row.index, row);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
this.__scrollToPendingIndexes();
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
// If the grid is not loading anything, flush the debouncer immediately
|
|
440
|
+
if (!this._cache.isLoading()) {
|
|
441
|
+
this._debouncerApplyCachedData.flush();
|
|
442
|
+
}
|
|
287
443
|
|
|
288
|
-
|
|
444
|
+
// Notify that new data has been received
|
|
445
|
+
this._onDataProviderPageLoaded();
|
|
446
|
+
});
|
|
447
|
+
}
|
|
289
448
|
}
|
|
290
449
|
|
|
291
450
|
/** @protected */
|
|
292
|
-
_onDataProviderPageLoaded() {
|
|
293
|
-
// Schedule a debouncer to update the visible rows
|
|
294
|
-
this._debouncerApplyCachedData = Debouncer.debounce(this._debouncerApplyCachedData, timeOut.after(0), () => {
|
|
295
|
-
this._setLoading(false);
|
|
296
|
-
|
|
297
|
-
this._getRenderedRows().forEach((row) => {
|
|
298
|
-
const { item } = this._dataProviderController.getFlatIndexInfo(row.index);
|
|
299
|
-
if (item) {
|
|
300
|
-
this._getItem(row.index, row);
|
|
301
|
-
}
|
|
302
|
-
});
|
|
451
|
+
_onDataProviderPageLoaded() {}
|
|
303
452
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
453
|
+
/**
|
|
454
|
+
* @param {number} index
|
|
455
|
+
* @return {number}
|
|
456
|
+
* @private
|
|
457
|
+
*/
|
|
458
|
+
_getPageForIndex(index) {
|
|
459
|
+
return Math.floor(index / this.pageSize);
|
|
311
460
|
}
|
|
312
461
|
|
|
313
462
|
/**
|
|
314
463
|
* Clears the cached pages and reloads data from dataprovider when needed.
|
|
315
464
|
*/
|
|
316
465
|
clearCache() {
|
|
317
|
-
this.
|
|
466
|
+
this._cache = new ItemCache(this);
|
|
467
|
+
this._cache.size = this.size || 0;
|
|
468
|
+
this._cache.updateSize();
|
|
318
469
|
this._hasData = false;
|
|
319
470
|
this.__updateVisibleRows();
|
|
320
471
|
|
|
321
472
|
if (!this._effectiveSize) {
|
|
322
|
-
this.
|
|
473
|
+
this._loadPage(0, this._cache);
|
|
323
474
|
}
|
|
324
475
|
}
|
|
325
476
|
|
|
326
477
|
/** @private */
|
|
327
478
|
_pageSizeChanged(pageSize, oldPageSize) {
|
|
328
|
-
this._dataProviderController.setPageSize(pageSize);
|
|
329
|
-
|
|
330
479
|
if (oldPageSize !== undefined && pageSize !== oldPageSize) {
|
|
331
480
|
this.clearCache();
|
|
332
481
|
}
|
|
@@ -346,8 +495,6 @@ export const DataProviderMixin = (superClass) =>
|
|
|
346
495
|
|
|
347
496
|
/** @private */
|
|
348
497
|
_dataProviderChanged(dataProvider, oldDataProvider) {
|
|
349
|
-
this._dataProviderController.setDataProvider(dataProvider ? dataProvider.bind(this) : null);
|
|
350
|
-
|
|
351
498
|
if (oldDataProvider !== undefined) {
|
|
352
499
|
this.clearCache();
|
|
353
500
|
}
|
|
@@ -366,7 +513,7 @@ export const DataProviderMixin = (superClass) =>
|
|
|
366
513
|
if (!this._hasData) {
|
|
367
514
|
// Load data before adding rows to make sure they have content when
|
|
368
515
|
// rendered for the first time.
|
|
369
|
-
this.
|
|
516
|
+
this._loadPage(0, this._cache);
|
|
370
517
|
}
|
|
371
518
|
}
|
|
372
519
|
|
|
@@ -416,15 +563,39 @@ export const DataProviderMixin = (superClass) =>
|
|
|
416
563
|
// ending up in a loading state. Try scrolling to the index until the target
|
|
417
564
|
// index stabilizes.
|
|
418
565
|
let targetIndex;
|
|
419
|
-
while (targetIndex !== (targetIndex = this.
|
|
566
|
+
while (targetIndex !== (targetIndex = this.__getGlobalFlatIndex(indexes))) {
|
|
420
567
|
this._scrollToFlatIndex(targetIndex);
|
|
421
568
|
}
|
|
422
569
|
|
|
423
|
-
if (this.
|
|
570
|
+
if (this._cache.isLoading() || !this.clientHeight) {
|
|
424
571
|
this.__pendingScrollToIndexes = indexes;
|
|
425
572
|
}
|
|
426
573
|
}
|
|
427
574
|
|
|
575
|
+
/**
|
|
576
|
+
* Recursively returns the globally flat index of the item the given indexes point to.
|
|
577
|
+
* Each index in the array points to a sub-item of the previous index.
|
|
578
|
+
* Using `Infinity` as an index will point to the last item on the level.
|
|
579
|
+
*
|
|
580
|
+
* @param {!Array<number>} indexes
|
|
581
|
+
* @param {!ItemCache} cache
|
|
582
|
+
* @param {number} flatIndex
|
|
583
|
+
* @return {number}
|
|
584
|
+
* @private
|
|
585
|
+
*/
|
|
586
|
+
__getGlobalFlatIndex([levelIndex, ...subIndexes], cache = this._cache, flatIndex = 0) {
|
|
587
|
+
if (levelIndex === Infinity) {
|
|
588
|
+
// Treat Infinity as the last index on the level
|
|
589
|
+
levelIndex = cache.size - 1;
|
|
590
|
+
}
|
|
591
|
+
const flatIndexOnLevel = cache.getFlatIndex(levelIndex);
|
|
592
|
+
const subCache = cache.itemCaches[levelIndex];
|
|
593
|
+
if (subCache && subCache.effectiveSize && subIndexes.length) {
|
|
594
|
+
return this.__getGlobalFlatIndex(subIndexes, subCache, flatIndex + flatIndexOnLevel + 1);
|
|
595
|
+
}
|
|
596
|
+
return flatIndex + flatIndexOnLevel;
|
|
597
|
+
}
|
|
598
|
+
|
|
428
599
|
/** @private */
|
|
429
600
|
__scrollToPendingIndexes() {
|
|
430
601
|
if (this.__pendingScrollToIndexes && this.$.items.children.length) {
|
|
@@ -112,7 +112,7 @@ export const DynamicColumnsMixin = (superClass) =>
|
|
|
112
112
|
if (hasColumnElements(info.addedNodes) || hasColumnElements(info.removedNodes)) {
|
|
113
113
|
const allRemovedCells = info.removedNodes.flatMap((c) => c._allCells);
|
|
114
114
|
const filterNotConnected = (element) =>
|
|
115
|
-
allRemovedCells.filter((cell) => cell._content.contains(element)).length;
|
|
115
|
+
allRemovedCells.filter((cell) => cell && cell._content.contains(element)).length;
|
|
116
116
|
|
|
117
117
|
this.__removeSorters(this._sorters.filter(filterNotConnected));
|
|
118
118
|
this.__removeFilters(this._filters.filter(filterNotConnected));
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import './vaadin-grid-filter.js';
|
|
7
|
+
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
7
8
|
import { GridColumn } from './vaadin-grid-column.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -18,6 +19,9 @@ import { GridColumn } from './vaadin-grid-column.js';
|
|
|
18
19
|
* <vaadin-grid-column>
|
|
19
20
|
* ...
|
|
20
21
|
* ```
|
|
22
|
+
*
|
|
23
|
+
* @customElement
|
|
24
|
+
* @extends GridColumn
|
|
21
25
|
*/
|
|
22
26
|
class GridFilterColumn extends GridColumn {
|
|
23
27
|
static get is() {
|
|
@@ -114,6 +118,6 @@ class GridFilterColumn extends GridColumn {
|
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
|
|
117
|
-
|
|
121
|
+
defineCustomElement(GridFilterColumn);
|
|
118
122
|
|
|
119
123
|
export { GridFilterColumn };
|
|
@@ -8,6 +8,7 @@ import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
|
8
8
|
import { timeOut } from '@vaadin/component-base/src/async.js';
|
|
9
9
|
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
10
10
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
11
|
+
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
11
12
|
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -35,6 +36,7 @@ import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
|
|
|
35
36
|
*
|
|
36
37
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
37
38
|
*
|
|
39
|
+
* @customElement
|
|
38
40
|
* @extends HTMLElement
|
|
39
41
|
*/
|
|
40
42
|
class GridFilter extends ControllerMixin(PolymerElement) {
|
|
@@ -125,6 +127,6 @@ class GridFilter extends ControllerMixin(PolymerElement) {
|
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
|
|
128
|
-
|
|
130
|
+
defineCustomElement(GridFilter);
|
|
129
131
|
|
|
130
132
|
export { GridFilter };
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
|
|
7
7
|
import { addValueToAttribute, removeValueFromAttribute } from '@vaadin/component-base/src/dom-utils.js';
|
|
8
|
+
import { get } from '@vaadin/component-base/src/path-utils.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @polymerMixin
|
|
@@ -266,7 +267,7 @@ export const KeyboardNavigationMixin = (superClass) =>
|
|
|
266
267
|
__isRowExpandable(row) {
|
|
267
268
|
if (this.itemHasChildrenPath) {
|
|
268
269
|
const item = row._item;
|
|
269
|
-
return item &&
|
|
270
|
+
return item && get(this.itemHasChildrenPath, item) && !this._isExpanded(item);
|
|
270
271
|
}
|
|
271
272
|
}
|
|
272
273
|
|
|
@@ -475,7 +476,7 @@ export const KeyboardNavigationMixin = (superClass) =>
|
|
|
475
476
|
// Row details navigation logic
|
|
476
477
|
if (activeRowGroup === this.$.items) {
|
|
477
478
|
const item = activeRow._item;
|
|
478
|
-
const
|
|
479
|
+
const dstItem = this._cache.getItemForIndex(dstRowIndex);
|
|
479
480
|
// Should we navigate to row details?
|
|
480
481
|
if (isRowDetails) {
|
|
481
482
|
dstIsRowDetails = dy === 0;
|
|
@@ -681,7 +682,26 @@ export const KeyboardNavigationMixin = (superClass) =>
|
|
|
681
682
|
}
|
|
682
683
|
}
|
|
683
684
|
|
|
684
|
-
|
|
685
|
+
let focusStepTarget = tabOrder[index];
|
|
686
|
+
|
|
687
|
+
// If the target focusable is tied to a column that is not visible,
|
|
688
|
+
// find the first visible column and update the target in order to
|
|
689
|
+
// prevent scrolling to the start of the row.
|
|
690
|
+
if (focusStepTarget && focusStepTarget._column && !this.__isColumnInViewport(focusStepTarget._column)) {
|
|
691
|
+
const firstVisibleColumn = this._getColumnsInOrder().find((column) => this.__isColumnInViewport(column));
|
|
692
|
+
if (firstVisibleColumn) {
|
|
693
|
+
if (focusStepTarget === this._headerFocusable) {
|
|
694
|
+
focusStepTarget = firstVisibleColumn._headerCell;
|
|
695
|
+
} else if (focusStepTarget === this._itemsFocusable) {
|
|
696
|
+
const rowIndex = focusStepTarget._column._cells.indexOf(focusStepTarget);
|
|
697
|
+
focusStepTarget = firstVisibleColumn._cells[rowIndex];
|
|
698
|
+
} else if (focusStepTarget === this._footerFocusable) {
|
|
699
|
+
focusStepTarget = firstVisibleColumn._footerCell;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
return focusStepTarget;
|
|
685
705
|
}
|
|
686
706
|
|
|
687
707
|
/** @private */
|