@vaadin/grid 24.2.0-beta3 → 24.2.0-beta4
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 +10 -10
- package/src/vaadin-grid-array-data-provider-mixin.js +1 -1
- package/src/vaadin-grid-column-group.d.ts +14 -4
- package/src/vaadin-grid-column-group.js +355 -5
- package/src/vaadin-grid-column.d.ts +138 -11
- package/src/vaadin-grid-column.js +876 -3
- package/src/vaadin-grid-data-provider-mixin.d.ts +30 -6
- package/src/vaadin-grid-data-provider-mixin.js +241 -100
- package/src/vaadin-grid-drag-and-drop-mixin.js +1 -1
- package/src/vaadin-grid-filter.d.ts +21 -4
- package/src/vaadin-grid-filter.js +84 -5
- package/src/vaadin-grid-keyboard-navigation-mixin.js +2 -2
- package/src/vaadin-grid-mixin.js +10 -10
- package/src/vaadin-grid-scroll-mixin.js +1 -1
- package/src/vaadin-grid-sorter.d.ts +32 -3
- package/src/vaadin-grid-sorter.js +181 -5
- package/src/vaadin-grid-tree-column.d.ts +7 -9
- package/src/vaadin-grid-tree-column.js +82 -3
- package/src/vaadin-grid-tree-toggle.d.ts +27 -4
- package/src/vaadin-grid-tree-toggle.js +141 -9
- package/web-types.json +98 -98
- package/web-types.lit.json +42 -42
- package/src/vaadin-grid-column-group-mixin.d.ts +0 -20
- package/src/vaadin-grid-column-group-mixin.js +0 -369
- package/src/vaadin-grid-column-mixin.d.ts +0 -156
- package/src/vaadin-grid-column-mixin.js +0 -887
- package/src/vaadin-grid-filter-element-mixin.d.ts +0 -34
- package/src/vaadin-grid-filter-element-mixin.js +0 -99
- package/src/vaadin-grid-sorter-mixin.d.ts +0 -44
- package/src/vaadin-grid-sorter-mixin.js +0 -198
- package/src/vaadin-grid-tree-column-mixin.d.ts +0 -19
- package/src/vaadin-grid-tree-column-mixin.js +0 -92
- package/src/vaadin-grid-tree-toggle-mixin.d.ts +0 -39
- package/src/vaadin-grid-tree-toggle-mixin.js +0 -151
|
@@ -4,10 +4,6 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
|
-
import type {
|
|
8
|
-
DataProvider,
|
|
9
|
-
DataProviderCallback,
|
|
10
|
-
} from '@vaadin/component-base/src/data-provider-controller/data-provider-controller.js';
|
|
11
7
|
import { GridSorterDirection } from './vaadin-grid-sorter.js';
|
|
12
8
|
|
|
13
9
|
export { GridSorterDirection };
|
|
@@ -22,7 +18,7 @@ export interface GridSorterDefinition {
|
|
|
22
18
|
direction: GridSorterDirection;
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
export type GridDataProviderCallback<TItem> =
|
|
21
|
+
export type GridDataProviderCallback<TItem> = (items: TItem[], size?: number) => void;
|
|
26
22
|
|
|
27
23
|
export type GridDataProviderParams<TItem> = {
|
|
28
24
|
page: number;
|
|
@@ -32,7 +28,35 @@ export type GridDataProviderParams<TItem> = {
|
|
|
32
28
|
parentItem?: TItem;
|
|
33
29
|
};
|
|
34
30
|
|
|
35
|
-
export type GridDataProvider<TItem> =
|
|
31
|
+
export type GridDataProvider<TItem> = (
|
|
32
|
+
params: GridDataProviderParams<TItem>,
|
|
33
|
+
callback: GridDataProviderCallback<TItem>,
|
|
34
|
+
) => void;
|
|
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
|
+
}
|
|
36
60
|
|
|
37
61
|
export declare function DataProviderMixin<TItem, T extends Constructor<HTMLElement>>(
|
|
38
62
|
base: T,
|
|
@@ -4,11 +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/data-provider-controller.js';
|
|
8
7
|
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
9
8
|
import { get } from '@vaadin/component-base/src/path-utils.js';
|
|
10
9
|
import { getBodyRowCells, updateCellsPart, updateState } from './vaadin-grid-helpers.js';
|
|
11
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
|
+
|
|
12
117
|
/**
|
|
13
118
|
* @polymerMixin
|
|
14
119
|
*/
|
|
@@ -76,6 +181,18 @@ export const DataProviderMixin = (superClass) =>
|
|
|
76
181
|
reflectToAttribute: true,
|
|
77
182
|
},
|
|
78
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
|
+
|
|
79
196
|
/**
|
|
80
197
|
* @protected
|
|
81
198
|
*/
|
|
@@ -127,50 +244,12 @@ export const DataProviderMixin = (superClass) =>
|
|
|
127
244
|
return ['_sizeChanged(size)', '_expandedItemsChanged(expandedItems.*)'];
|
|
128
245
|
}
|
|
129
246
|
|
|
130
|
-
constructor() {
|
|
131
|
-
super();
|
|
132
|
-
|
|
133
|
-
/** @type {DataProviderController} */
|
|
134
|
-
this._dataProviderController = new DataProviderController(this, {
|
|
135
|
-
size: this.size,
|
|
136
|
-
pageSize: this.pageSize,
|
|
137
|
-
isExpanded: this._isExpanded.bind(this),
|
|
138
|
-
dataProvider: this.dataProvider ? this.dataProvider.bind(this) : null,
|
|
139
|
-
dataProviderParams: () => {
|
|
140
|
-
return {
|
|
141
|
-
sortOrders: this._mapSorters(),
|
|
142
|
-
filters: this._mapFilters(),
|
|
143
|
-
};
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
this._dataProviderController.addEventListener('page-requested', this._onDataProviderPageRequested.bind(this));
|
|
148
|
-
this._dataProviderController.addEventListener('page-received', this._onDataProviderPageReceived.bind(this));
|
|
149
|
-
this._dataProviderController.addEventListener('page-loaded', this._onDataProviderPageLoaded.bind(this));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* @protected
|
|
154
|
-
* @deprecated since 24.3 and will be removed in Vaadin 25.
|
|
155
|
-
*/
|
|
156
|
-
get _cache() {
|
|
157
|
-
console.warn('<vaadin-grid> The `_cache` property is deprecated and will be removed in Vaadin 25.');
|
|
158
|
-
return this._dataProviderController.rootCache;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* @protected
|
|
163
|
-
* @deprecated since 24.3 and will be removed in Vaadin 25.
|
|
164
|
-
*/
|
|
165
|
-
get _effectiveSize() {
|
|
166
|
-
console.warn('<vaadin-grid> The `_effectiveSize` property is deprecated and will be removed in Vaadin 25.');
|
|
167
|
-
return this._flatSize;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
247
|
/** @private */
|
|
171
248
|
_sizeChanged(size) {
|
|
172
|
-
this.
|
|
173
|
-
this.
|
|
249
|
+
const delta = size - this._cache.size;
|
|
250
|
+
this._cache.size += delta;
|
|
251
|
+
this._cache.effectiveSize += delta;
|
|
252
|
+
this._effectiveSize = this._cache.effectiveSize;
|
|
174
253
|
}
|
|
175
254
|
|
|
176
255
|
/** @private */
|
|
@@ -188,22 +267,22 @@ export const DataProviderMixin = (superClass) =>
|
|
|
188
267
|
* @protected
|
|
189
268
|
*/
|
|
190
269
|
_getItem(index, el) {
|
|
191
|
-
if (index >= this.
|
|
270
|
+
if (index >= this._effectiveSize) {
|
|
192
271
|
return;
|
|
193
272
|
}
|
|
194
273
|
|
|
195
274
|
el.index = index;
|
|
196
|
-
|
|
197
|
-
const
|
|
275
|
+
const { cache, scaledIndex } = this._cache.getCacheAndIndex(index);
|
|
276
|
+
const item = cache.items[scaledIndex];
|
|
198
277
|
if (item) {
|
|
199
278
|
this.__updateLoading(el, false);
|
|
200
279
|
this._updateItem(el, item);
|
|
201
280
|
if (this._isExpanded(item)) {
|
|
202
|
-
|
|
281
|
+
cache.ensureSubCacheForScaledIndex(scaledIndex);
|
|
203
282
|
}
|
|
204
283
|
} else {
|
|
205
284
|
this.__updateLoading(el, true);
|
|
206
|
-
this.
|
|
285
|
+
this._loadPage(this._getPageForIndex(scaledIndex), cache);
|
|
207
286
|
}
|
|
208
287
|
}
|
|
209
288
|
|
|
@@ -243,8 +322,8 @@ export const DataProviderMixin = (superClass) =>
|
|
|
243
322
|
|
|
244
323
|
/** @private */
|
|
245
324
|
_expandedItemsChanged() {
|
|
246
|
-
this.
|
|
247
|
-
this.
|
|
325
|
+
this._cache.updateSize();
|
|
326
|
+
this._effectiveSize = this._cache.effectiveSize;
|
|
248
327
|
this.__updateVisibleRows();
|
|
249
328
|
}
|
|
250
329
|
|
|
@@ -284,8 +363,13 @@ export const DataProviderMixin = (superClass) =>
|
|
|
284
363
|
* @return {number}
|
|
285
364
|
* @protected
|
|
286
365
|
*/
|
|
287
|
-
_getIndexLevel(index
|
|
288
|
-
|
|
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
|
+
}
|
|
289
373
|
return level;
|
|
290
374
|
}
|
|
291
375
|
|
|
@@ -293,70 +377,105 @@ export const DataProviderMixin = (superClass) =>
|
|
|
293
377
|
* @param {number} page
|
|
294
378
|
* @param {ItemCache} cache
|
|
295
379
|
* @protected
|
|
296
|
-
* @deprecated since 24.3 and will be removed in Vaadin 25.
|
|
297
380
|
*/
|
|
298
381
|
_loadPage(page, cache) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
+
}
|
|
312
400
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
+
}
|
|
317
443
|
|
|
318
|
-
|
|
444
|
+
// Notify that new data has been received
|
|
445
|
+
this._onDataProviderPageLoaded();
|
|
446
|
+
});
|
|
447
|
+
}
|
|
319
448
|
}
|
|
320
449
|
|
|
321
450
|
/** @protected */
|
|
322
|
-
_onDataProviderPageLoaded() {
|
|
323
|
-
// Schedule a debouncer to update the visible rows
|
|
324
|
-
this._debouncerApplyCachedData = Debouncer.debounce(this._debouncerApplyCachedData, timeOut.after(0), () => {
|
|
325
|
-
this._setLoading(false);
|
|
326
|
-
|
|
327
|
-
this._getRenderedRows().forEach((row) => {
|
|
328
|
-
const { item } = this._dataProviderController.getFlatIndexContext(row.index);
|
|
329
|
-
if (item) {
|
|
330
|
-
this._getItem(row.index, row);
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
this.__scrollToPendingIndexes();
|
|
335
|
-
});
|
|
451
|
+
_onDataProviderPageLoaded() {}
|
|
336
452
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
453
|
+
/**
|
|
454
|
+
* @param {number} index
|
|
455
|
+
* @return {number}
|
|
456
|
+
* @private
|
|
457
|
+
*/
|
|
458
|
+
_getPageForIndex(index) {
|
|
459
|
+
return Math.floor(index / this.pageSize);
|
|
341
460
|
}
|
|
342
461
|
|
|
343
462
|
/**
|
|
344
463
|
* Clears the cached pages and reloads data from dataprovider when needed.
|
|
345
464
|
*/
|
|
346
465
|
clearCache() {
|
|
347
|
-
this.
|
|
466
|
+
this._cache = new ItemCache(this);
|
|
467
|
+
this._cache.size = this.size || 0;
|
|
468
|
+
this._cache.updateSize();
|
|
348
469
|
this._hasData = false;
|
|
349
470
|
this.__updateVisibleRows();
|
|
350
471
|
|
|
351
|
-
if (!this.
|
|
352
|
-
this.
|
|
472
|
+
if (!this._effectiveSize) {
|
|
473
|
+
this._loadPage(0, this._cache);
|
|
353
474
|
}
|
|
354
475
|
}
|
|
355
476
|
|
|
356
477
|
/** @private */
|
|
357
478
|
_pageSizeChanged(pageSize, oldPageSize) {
|
|
358
|
-
this._dataProviderController.setPageSize(pageSize);
|
|
359
|
-
|
|
360
479
|
if (oldPageSize !== undefined && pageSize !== oldPageSize) {
|
|
361
480
|
this.clearCache();
|
|
362
481
|
}
|
|
@@ -364,7 +483,7 @@ export const DataProviderMixin = (superClass) =>
|
|
|
364
483
|
|
|
365
484
|
/** @protected */
|
|
366
485
|
_checkSize() {
|
|
367
|
-
if (this.size === undefined && this.
|
|
486
|
+
if (this.size === undefined && this._effectiveSize === 0) {
|
|
368
487
|
console.warn(
|
|
369
488
|
'The <vaadin-grid> needs the total number of items in' +
|
|
370
489
|
' order to display rows, which you can specify either by setting' +
|
|
@@ -376,8 +495,6 @@ export const DataProviderMixin = (superClass) =>
|
|
|
376
495
|
|
|
377
496
|
/** @private */
|
|
378
497
|
_dataProviderChanged(dataProvider, oldDataProvider) {
|
|
379
|
-
this._dataProviderController.setDataProvider(dataProvider ? dataProvider.bind(this) : null);
|
|
380
|
-
|
|
381
498
|
if (oldDataProvider !== undefined) {
|
|
382
499
|
this.clearCache();
|
|
383
500
|
}
|
|
@@ -396,7 +513,7 @@ export const DataProviderMixin = (superClass) =>
|
|
|
396
513
|
if (!this._hasData) {
|
|
397
514
|
// Load data before adding rows to make sure they have content when
|
|
398
515
|
// rendered for the first time.
|
|
399
|
-
this.
|
|
516
|
+
this._loadPage(0, this._cache);
|
|
400
517
|
}
|
|
401
518
|
}
|
|
402
519
|
|
|
@@ -446,15 +563,39 @@ export const DataProviderMixin = (superClass) =>
|
|
|
446
563
|
// ending up in a loading state. Try scrolling to the index until the target
|
|
447
564
|
// index stabilizes.
|
|
448
565
|
let targetIndex;
|
|
449
|
-
while (targetIndex !== (targetIndex = this.
|
|
566
|
+
while (targetIndex !== (targetIndex = this.__getGlobalFlatIndex(indexes))) {
|
|
450
567
|
this._scrollToFlatIndex(targetIndex);
|
|
451
568
|
}
|
|
452
569
|
|
|
453
|
-
if (this.
|
|
570
|
+
if (this._cache.isLoading() || !this.clientHeight) {
|
|
454
571
|
this.__pendingScrollToIndexes = indexes;
|
|
455
572
|
}
|
|
456
573
|
}
|
|
457
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
|
+
|
|
458
599
|
/** @private */
|
|
459
600
|
__scrollToPendingIndexes() {
|
|
460
601
|
if (this.__pendingScrollToIndexes && this.$.items.children.length) {
|
|
@@ -211,7 +211,7 @@ export const DragAndDropMixin = (superClass) =>
|
|
|
211
211
|
|
|
212
212
|
let row = e.composedPath().find((node) => node.localName === 'tr');
|
|
213
213
|
|
|
214
|
-
if (!this.
|
|
214
|
+
if (!this._effectiveSize || this.dropMode === DropMode.ON_GRID) {
|
|
215
215
|
// The grid is empty or "on-grid" drop mode was used, always default to "empty"
|
|
216
216
|
this._dropLocation = DropLocation.EMPTY;
|
|
217
217
|
} else if (!row || row.parentNode !== this.$.items) {
|
|
@@ -3,11 +3,18 @@
|
|
|
3
3
|
* Copyright (c) 2016 - 2023 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
+
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Fired when the `value` property changes.
|
|
10
|
+
*/
|
|
11
|
+
export type GridFilterValueChangedEvent = CustomEvent<{ value: string }>;
|
|
12
|
+
|
|
13
|
+
export interface GridFilterCustomEventMap {
|
|
14
|
+
'value-changed': GridFilterValueChangedEvent;
|
|
15
|
+
}
|
|
9
16
|
|
|
10
|
-
export
|
|
17
|
+
export interface GridFilterEventMap extends HTMLElementEventMap, GridFilterCustomEventMap {}
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* `<vaadin-grid-filter>` is a helper element for the `<vaadin-grid>` that provides out-of-the-box UI controls,
|
|
@@ -34,7 +41,17 @@ export * from './vaadin-grid-filter-element-mixin.js';
|
|
|
34
41
|
*
|
|
35
42
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
36
43
|
*/
|
|
37
|
-
declare class GridFilter extends
|
|
44
|
+
declare class GridFilter extends ControllerMixin(HTMLElement) {
|
|
45
|
+
/**
|
|
46
|
+
* JS Path of the property in the item used for filtering the data.
|
|
47
|
+
*/
|
|
48
|
+
path: string | null | undefined;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Current filter value.
|
|
52
|
+
*/
|
|
53
|
+
value: string | null | undefined;
|
|
54
|
+
|
|
38
55
|
addEventListener<K extends keyof GridFilterEventMap>(
|
|
39
56
|
type: K,
|
|
40
57
|
listener: (this: GridFilter, ev: GridFilterEventMap[K]) => void,
|
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import '@vaadin/text-field/src/vaadin-text-field.js';
|
|
7
7
|
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
8
|
+
import { timeOut } from '@vaadin/component-base/src/async.js';
|
|
9
|
+
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
10
|
+
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
8
11
|
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
9
|
-
import {
|
|
10
|
-
import { GridFilterElementMixin } from './vaadin-grid-filter-element-mixin.js';
|
|
12
|
+
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* `<vaadin-grid-filter>` is a helper element for the `<vaadin-grid>` that provides out-of-the-box UI controls,
|
|
@@ -36,16 +38,93 @@ import { GridFilterElementMixin } from './vaadin-grid-filter-element-mixin.js';
|
|
|
36
38
|
*
|
|
37
39
|
* @customElement
|
|
38
40
|
* @extends HTMLElement
|
|
39
|
-
* @mixes GridFilterElementMixin
|
|
40
41
|
*/
|
|
41
|
-
class GridFilter extends
|
|
42
|
+
class GridFilter extends ControllerMixin(PolymerElement) {
|
|
42
43
|
static get template() {
|
|
43
|
-
return html
|
|
44
|
+
return html`
|
|
45
|
+
<style>
|
|
46
|
+
:host {
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
max-width: 100%;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
::slotted(*) {
|
|
52
|
+
width: 100%;
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
}
|
|
55
|
+
</style>
|
|
56
|
+
<slot></slot>
|
|
57
|
+
`;
|
|
44
58
|
}
|
|
45
59
|
|
|
46
60
|
static get is() {
|
|
47
61
|
return 'vaadin-grid-filter';
|
|
48
62
|
}
|
|
63
|
+
|
|
64
|
+
static get properties() {
|
|
65
|
+
return {
|
|
66
|
+
/**
|
|
67
|
+
* JS Path of the property in the item used for filtering the data.
|
|
68
|
+
*/
|
|
69
|
+
path: String,
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Current filter value.
|
|
73
|
+
*/
|
|
74
|
+
value: {
|
|
75
|
+
type: String,
|
|
76
|
+
notify: true,
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/** @private */
|
|
80
|
+
_textField: {
|
|
81
|
+
type: Object,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static get observers() {
|
|
87
|
+
return ['_filterChanged(path, value, _textField)'];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** @protected */
|
|
91
|
+
ready() {
|
|
92
|
+
super.ready();
|
|
93
|
+
|
|
94
|
+
this._filterController = new SlotController(this, '', 'vaadin-text-field', {
|
|
95
|
+
initializer: (field) => {
|
|
96
|
+
field.addEventListener('value-changed', (e) => {
|
|
97
|
+
this.value = e.detail.value;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
this._textField = field;
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
this.addController(this._filterController);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** @private */
|
|
107
|
+
_filterChanged(path, value, textField) {
|
|
108
|
+
if (path === undefined || value === undefined || !textField) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (this._previousValue === undefined && value === '') {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
textField.value = value;
|
|
116
|
+
this._previousValue = value;
|
|
117
|
+
|
|
118
|
+
this._debouncerFilterChanged = Debouncer.debounce(this._debouncerFilterChanged, timeOut.after(200), () => {
|
|
119
|
+
this.dispatchEvent(new CustomEvent('filter-changed', { bubbles: true }));
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
focus() {
|
|
124
|
+
if (this._textField) {
|
|
125
|
+
this._textField.focus();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
49
128
|
}
|
|
50
129
|
|
|
51
130
|
defineCustomElement(GridFilter);
|