ng-virtual-list 20.7.20 → 20.8.0
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/fesm2022/ng-virtual-list.mjs +103 -116
- package/fesm2022/ng-virtual-list.mjs.map +1 -1
- package/index.d.ts +39 -65
- package/package.json +1 -1
|
@@ -803,7 +803,7 @@ const debounce = (cb, debounceTime = 0) => {
|
|
|
803
803
|
|
|
804
804
|
/**
|
|
805
805
|
* Switch css classes
|
|
806
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/
|
|
806
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/toggle-class-name.ts
|
|
807
807
|
* @author Evgenii Grebennikov
|
|
808
808
|
* @email djonnyx@gmail.com
|
|
809
809
|
*/
|
|
@@ -818,7 +818,7 @@ const toggleClassName = (el, className, removeClassName) => {
|
|
|
818
818
|
|
|
819
819
|
/**
|
|
820
820
|
* Scroll event.
|
|
821
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/
|
|
821
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/scroll-event.ts
|
|
822
822
|
* @author Evgenii Grebennikov
|
|
823
823
|
* @email djonnyx@gmail.com
|
|
824
824
|
*/
|
|
@@ -860,7 +860,7 @@ class ScrollEvent {
|
|
|
860
860
|
|
|
861
861
|
/**
|
|
862
862
|
* Simple event emitter
|
|
863
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/
|
|
863
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/event-emitter.ts
|
|
864
864
|
* @author Evgenii Grebennikov
|
|
865
865
|
* @email djonnyx@gmail.com
|
|
866
866
|
*/
|
|
@@ -989,13 +989,16 @@ class CMap {
|
|
|
989
989
|
clear() {
|
|
990
990
|
this._dict = {};
|
|
991
991
|
}
|
|
992
|
+
toObject() {
|
|
993
|
+
return this._dict;
|
|
994
|
+
}
|
|
992
995
|
}
|
|
993
996
|
const CACHE_BOX_CHANGE_EVENT_NAME = 'change';
|
|
994
997
|
const MAX_SCROLL_DIRECTION_POOL = 50, CLEAR_SCROLL_DIRECTION_TO = 10, DIR_BACK = '-1', DIR_NONE = '0', DIR_FORWARD = '1';
|
|
995
998
|
/**
|
|
996
999
|
* Cache map.
|
|
997
1000
|
* Emits a change event on each mutation.
|
|
998
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/
|
|
1001
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/cache-map.ts
|
|
999
1002
|
* @author Evgenii Grebennikov
|
|
1000
1003
|
* @email djonnyx@gmail.com
|
|
1001
1004
|
*/
|
|
@@ -1118,6 +1121,12 @@ class CacheMap extends EventEmitter {
|
|
|
1118
1121
|
get(id) {
|
|
1119
1122
|
return this._map.get(id);
|
|
1120
1123
|
}
|
|
1124
|
+
delete(id) {
|
|
1125
|
+
this._map.delete(id);
|
|
1126
|
+
}
|
|
1127
|
+
clear() {
|
|
1128
|
+
this._map.clear();
|
|
1129
|
+
}
|
|
1121
1130
|
snapshot() {
|
|
1122
1131
|
this._snapshot = new CMap(this._map);
|
|
1123
1132
|
}
|
|
@@ -1170,10 +1179,10 @@ class Tracker {
|
|
|
1170
1179
|
if (!items) {
|
|
1171
1180
|
return;
|
|
1172
1181
|
}
|
|
1173
|
-
const
|
|
1182
|
+
const untrackedItems = [...components], newTrackItems = [], isDown = direction === 0 || direction === 1;
|
|
1174
1183
|
let isRegularSnapped = false;
|
|
1175
1184
|
for (let i = isDown ? 0 : items.length - 1, l = isDown ? items.length : 0; isDown ? i < l : i >= l; isDown ? i++ : i--) {
|
|
1176
|
-
const item = items[i], itemTrackingProperty = item
|
|
1185
|
+
const item = items[i], itemTrackingProperty = item.id;
|
|
1177
1186
|
if (this._trackMap) {
|
|
1178
1187
|
if (this._trackMap.has(itemTrackingProperty)) {
|
|
1179
1188
|
const diId = this._trackMap.get(itemTrackingProperty), compIndex = this._displayObjectIndexMapById[diId], comp = components[compIndex];
|
|
@@ -1219,7 +1228,7 @@ class Tracker {
|
|
|
1219
1228
|
}
|
|
1220
1229
|
for (let i = 0, l = newTrackItems.length; i < l; i++) {
|
|
1221
1230
|
if (untrackedItems.length > 0) {
|
|
1222
|
-
const comp = untrackedItems.shift(), item = newTrackItems[i], itemTrackingProperty = item
|
|
1231
|
+
const comp = untrackedItems.shift(), item = newTrackItems[i], itemTrackingProperty = item.id;
|
|
1223
1232
|
if (comp) {
|
|
1224
1233
|
if (snapedComponent) {
|
|
1225
1234
|
if (item['config']['snapped'] || item['config']['snappedOut']) {
|
|
@@ -1294,7 +1303,7 @@ const bufferInterpolation = (currentBufferValue, array, value, extra) => {
|
|
|
1294
1303
|
else {
|
|
1295
1304
|
array.push(value);
|
|
1296
1305
|
}
|
|
1297
|
-
while (array.length
|
|
1306
|
+
while (array.length > bufferSize) {
|
|
1298
1307
|
array.shift();
|
|
1299
1308
|
}
|
|
1300
1309
|
const l = array.length;
|
|
@@ -1320,7 +1329,7 @@ var ItemDisplayMethods;
|
|
|
1320
1329
|
const DEFAULT_BUFFER_EXTREMUM_THRESHOLD = 15, DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH = 30, DEFAULT_RESET_BUFFER_SIZE_TIMEOUT = 10000, IS_NEW = 'isNew';
|
|
1321
1330
|
/**
|
|
1322
1331
|
* An object that performs tracking, calculations and caching.
|
|
1323
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/
|
|
1332
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/track-box.ts
|
|
1324
1333
|
* @author Evgenii Grebennikov
|
|
1325
1334
|
* @email djonnyx@gmail.com
|
|
1326
1335
|
*/
|
|
@@ -1376,14 +1385,14 @@ class TrackBox extends CacheMap {
|
|
|
1376
1385
|
initialize() {
|
|
1377
1386
|
this._tracker = new Tracker(this._trackingPropertyName);
|
|
1378
1387
|
}
|
|
1379
|
-
set(id,
|
|
1388
|
+
set(id, cache) {
|
|
1380
1389
|
if (this._map.has(id)) {
|
|
1381
1390
|
const b = this._map.get(id);
|
|
1382
|
-
if (b?.width ===
|
|
1391
|
+
if (b?.width === cache.width && b.height === cache.height) {
|
|
1383
1392
|
return this._map;
|
|
1384
1393
|
}
|
|
1385
1394
|
}
|
|
1386
|
-
const v = this._map.set(id,
|
|
1395
|
+
const v = this._map.set(id, cache);
|
|
1387
1396
|
this.bumpVersion();
|
|
1388
1397
|
return v;
|
|
1389
1398
|
}
|
|
@@ -1409,7 +1418,7 @@ class TrackBox extends CacheMap {
|
|
|
1409
1418
|
_maxBufferSize = this._defaultBufferSize;
|
|
1410
1419
|
_resetBufferSizeTimeout = DEFAULT_RESET_BUFFER_SIZE_TIMEOUT;
|
|
1411
1420
|
_resetBufferSizeTimer;
|
|
1412
|
-
|
|
1421
|
+
_isReseted = true;
|
|
1413
1422
|
lifeCircle() {
|
|
1414
1423
|
this.fireChangeIfNeed();
|
|
1415
1424
|
this.lifeCircleDo();
|
|
@@ -1418,20 +1427,14 @@ class TrackBox extends CacheMap {
|
|
|
1418
1427
|
* Scans the collection for deleted items and flushes the deleted item cache.
|
|
1419
1428
|
*/
|
|
1420
1429
|
resetCollection(currentCollection, itemSize) {
|
|
1421
|
-
if (currentCollection !== undefined && currentCollection !== null &&
|
|
1430
|
+
if (currentCollection !== undefined && currentCollection !== null &&
|
|
1431
|
+
currentCollection === this._previousCollection) {
|
|
1422
1432
|
console.warn('Attention! The collection must be immutable.');
|
|
1423
1433
|
return;
|
|
1424
1434
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
reseted = false;
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
if (!reseted && (!currentCollection || currentCollection.length === 0)) {
|
|
1432
|
-
reseted = true;
|
|
1433
|
-
}
|
|
1434
|
-
this.isReseted = reseted;
|
|
1435
|
+
const reseted = !((!!this._previousCollection && this._previousCollection.length > 0) &&
|
|
1436
|
+
(!!currentCollection && currentCollection.length > 0));
|
|
1437
|
+
this._isReseted = reseted;
|
|
1435
1438
|
this.dispatch(TrackBoxEvents.RESET, reseted);
|
|
1436
1439
|
this.updateCache(this._previousCollection, currentCollection, itemSize);
|
|
1437
1440
|
this._previousCollection = [...(currentCollection || [])];
|
|
@@ -1440,12 +1443,13 @@ class TrackBox extends CacheMap {
|
|
|
1440
1443
|
* Update the cache of items from the list
|
|
1441
1444
|
*/
|
|
1442
1445
|
updateCache(previousCollection, currentCollection, itemSize) {
|
|
1446
|
+
const trackBy = this._trackingPropertyName;
|
|
1443
1447
|
let crudDetected = false;
|
|
1444
1448
|
if (!currentCollection || currentCollection.length === 0) {
|
|
1445
1449
|
if (previousCollection) {
|
|
1446
1450
|
// deleted
|
|
1447
1451
|
for (let i = 0, l = previousCollection.length; i < l; i++) {
|
|
1448
|
-
const item = previousCollection[i], id = item
|
|
1452
|
+
const item = previousCollection[i], id = item[trackBy];
|
|
1449
1453
|
crudDetected = true;
|
|
1450
1454
|
if (this._map.has(id)) {
|
|
1451
1455
|
this._map.delete(id);
|
|
@@ -1459,7 +1463,7 @@ class TrackBox extends CacheMap {
|
|
|
1459
1463
|
// added
|
|
1460
1464
|
for (let i = 0, l = currentCollection.length; i < l; i++) {
|
|
1461
1465
|
crudDetected = true;
|
|
1462
|
-
const item = currentCollection[i], id = item
|
|
1466
|
+
const item = currentCollection[i], id = item[trackBy];
|
|
1463
1467
|
this._map.set(id, { width: itemSize, height: itemSize, method: ItemDisplayMethods.CREATE });
|
|
1464
1468
|
}
|
|
1465
1469
|
}
|
|
@@ -1469,38 +1473,45 @@ class TrackBox extends CacheMap {
|
|
|
1469
1473
|
for (let i = 0, l = currentCollection.length; i < l; i++) {
|
|
1470
1474
|
const item = currentCollection[i];
|
|
1471
1475
|
if (item) {
|
|
1472
|
-
collectionDict[item
|
|
1476
|
+
collectionDict[item[trackBy]] = item;
|
|
1473
1477
|
}
|
|
1474
1478
|
}
|
|
1475
1479
|
const notChangedMap = {}, deletedMap = {}, deletedItemsMap = {}, updatedMap = {};
|
|
1476
1480
|
for (let i = 0, l = previousCollection.length; i < l; i++) {
|
|
1477
|
-
const item = previousCollection[i], id = item
|
|
1481
|
+
const item = previousCollection[i], id = item[trackBy];
|
|
1478
1482
|
if (item) {
|
|
1479
1483
|
if (collectionDict.hasOwnProperty(id)) {
|
|
1480
1484
|
if (item === collectionDict[id]) {
|
|
1481
1485
|
// not changed
|
|
1482
|
-
notChangedMap[item
|
|
1483
|
-
this._map.set(id, {
|
|
1486
|
+
notChangedMap[item[trackBy]] = item;
|
|
1487
|
+
this._map.set(id, {
|
|
1488
|
+
...(this._map.get(id) || { width: itemSize, height: itemSize }),
|
|
1489
|
+
method: ItemDisplayMethods.NOT_CHANGED
|
|
1490
|
+
});
|
|
1484
1491
|
continue;
|
|
1485
1492
|
}
|
|
1486
1493
|
else {
|
|
1487
1494
|
// updated
|
|
1488
1495
|
crudDetected = true;
|
|
1489
|
-
updatedMap[item
|
|
1490
|
-
this._map.set(id, {
|
|
1496
|
+
updatedMap[item[trackBy]] = item;
|
|
1497
|
+
this._map.set(id, {
|
|
1498
|
+
...(this._map.get(id) || { width: itemSize, height: itemSize }),
|
|
1499
|
+
method: ItemDisplayMethods.UPDATE
|
|
1500
|
+
});
|
|
1491
1501
|
continue;
|
|
1492
1502
|
}
|
|
1493
1503
|
}
|
|
1494
1504
|
// deleted
|
|
1495
1505
|
crudDetected = true;
|
|
1496
|
-
deletedMap[
|
|
1497
|
-
deletedItemsMap[i] = this._map.get(
|
|
1506
|
+
deletedMap[id] = item;
|
|
1507
|
+
deletedItemsMap[i] = this._map.get(id);
|
|
1498
1508
|
this._map.delete(id);
|
|
1499
1509
|
}
|
|
1500
1510
|
}
|
|
1501
1511
|
for (let i = 0, l = currentCollection.length; i < l; i++) {
|
|
1502
|
-
const item = currentCollection[i], id = item
|
|
1503
|
-
if (item && !deletedMap.hasOwnProperty(id) && !updatedMap.hasOwnProperty(id) &&
|
|
1512
|
+
const item = currentCollection[i], id = item[trackBy];
|
|
1513
|
+
if (item && !deletedMap.hasOwnProperty(id) && !updatedMap.hasOwnProperty(id) &&
|
|
1514
|
+
!notChangedMap.hasOwnProperty(id)) {
|
|
1504
1515
|
// added
|
|
1505
1516
|
crudDetected = true;
|
|
1506
1517
|
this._map.set(id, { width: itemSize, height: itemSize, method: ItemDisplayMethods.CREATE });
|
|
@@ -1553,12 +1564,6 @@ class TrackBox extends CacheMap {
|
|
|
1553
1564
|
const displayItems = this.generateDisplayCollection(items, itemConfigMap, { ...metrics, });
|
|
1554
1565
|
return { displayItems, totalSize: metrics.totalSize, delta: metrics.delta, crudDetected };
|
|
1555
1566
|
}
|
|
1556
|
-
/**
|
|
1557
|
-
* Finds the closest element in the collection by scrollSize
|
|
1558
|
-
*/
|
|
1559
|
-
getNearestItem(scrollSize, items, itemSize, isVertical) {
|
|
1560
|
-
return this.getElementFromStart(scrollSize, items, this._map, itemSize, isVertical);
|
|
1561
|
-
}
|
|
1562
1567
|
_previousScrollSize = 0;
|
|
1563
1568
|
updateAdaptiveBufferParams(metrics, totalItemsLength) {
|
|
1564
1569
|
this.disposeClearBufferSizeTimer();
|
|
@@ -1580,41 +1585,18 @@ class TrackBox extends CacheMap {
|
|
|
1580
1585
|
disposeClearBufferSizeTimer() {
|
|
1581
1586
|
clearTimeout(this._resetBufferSizeTimer);
|
|
1582
1587
|
}
|
|
1583
|
-
/**
|
|
1584
|
-
* Calculates the position of an element based on the given scrollSize
|
|
1585
|
-
*/
|
|
1586
|
-
getElementFromStart(scrollSize, collection, map, typicalItemSize, isVertical) {
|
|
1587
|
-
const sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME;
|
|
1588
|
-
let offset = 0;
|
|
1589
|
-
for (let i = 0, l = collection.length; i < l; i++) {
|
|
1590
|
-
const item = collection[i], id = item.id;
|
|
1591
|
-
let itemSize = 0;
|
|
1592
|
-
if (map.has(id)) {
|
|
1593
|
-
const bounds = map.get(id);
|
|
1594
|
-
itemSize = bounds ? bounds[sizeProperty] : typicalItemSize;
|
|
1595
|
-
}
|
|
1596
|
-
else {
|
|
1597
|
-
itemSize = typicalItemSize;
|
|
1598
|
-
}
|
|
1599
|
-
if (offset > scrollSize) {
|
|
1600
|
-
return item;
|
|
1601
|
-
}
|
|
1602
|
-
offset += itemSize;
|
|
1603
|
-
}
|
|
1604
|
-
return undefined;
|
|
1605
|
-
}
|
|
1606
1588
|
/**
|
|
1607
1589
|
* Calculates the entry into the overscroll area and returns the number of overscroll elements
|
|
1608
1590
|
*/
|
|
1609
1591
|
getElementNumToEnd(i, collection, map, typicalItemSize, size, isVertical, indexOffset = 0) {
|
|
1610
|
-
const sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME;
|
|
1592
|
+
const trackBy = this._trackingPropertyName, sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME;
|
|
1611
1593
|
let offset = 0, num = 0;
|
|
1612
1594
|
for (let j = collection.length - indexOffset - 1; j >= i; j--) {
|
|
1613
|
-
const item = collection[j], id = item
|
|
1595
|
+
const item = collection[j], id = item[trackBy];
|
|
1614
1596
|
let itemSize = 0;
|
|
1615
1597
|
if (map.has(id)) {
|
|
1616
|
-
const
|
|
1617
|
-
itemSize =
|
|
1598
|
+
const cache = map.get(id);
|
|
1599
|
+
itemSize = cache ? cache[sizeProperty] : typicalItemSize;
|
|
1618
1600
|
}
|
|
1619
1601
|
else {
|
|
1620
1602
|
itemSize = typicalItemSize;
|
|
@@ -1631,8 +1613,8 @@ class TrackBox extends CacheMap {
|
|
|
1631
1613
|
* Calculates list metrics
|
|
1632
1614
|
*/
|
|
1633
1615
|
recalculateMetrics(options) {
|
|
1634
|
-
const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, bufferSize: minBufferSize, scrollSize, snap, itemConfigMap, enabledBufferOptimization, previousTotalSize, crudDetected, deletedItemsMap } = options;
|
|
1635
|
-
const bufferSize = Math.max(minBufferSize, this._bufferSize), { width, height } = bounds, sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME, size = isVertical ? height : width, totalLength = collection.length, typicalItemSize = itemSize, w = isVertical ? width : typicalItemSize, h = isVertical ? typicalItemSize : height, map = this._map, snapshot = this._snapshot, checkOverscrollItemsLimit = Math.ceil(size / typicalItemSize), snippedPos = Math.floor(scrollSize), leftItemsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
|
|
1616
|
+
const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, bufferSize: minBufferSize, scrollSize, snap, itemConfigMap, enabledBufferOptimization, previousTotalSize, crudDetected, deletedItemsMap } = options, roundedScrollSize = Math.round(scrollSize);
|
|
1617
|
+
const trackBy = this._trackingPropertyName, bufferSize = Math.max(minBufferSize, this._bufferSize), { width, height } = bounds, sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME, size = isVertical ? height : width, totalLength = collection.length, typicalItemSize = itemSize, w = isVertical ? width : typicalItemSize, h = isVertical ? typicalItemSize : height, map = this._map, snapshot = this._snapshot, checkOverscrollItemsLimit = Math.ceil(size / typicalItemSize), snippedPos = Math.floor(scrollSize), leftItemsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
|
|
1636
1618
|
|| (typeof fromItemId === 'string' && fromItemId > '-1');
|
|
1637
1619
|
let leftItemsOffset = 0, rightItemsOffset = 0;
|
|
1638
1620
|
if (enabledBufferOptimization) {
|
|
@@ -1657,41 +1639,40 @@ class TrackBox extends CacheMap {
|
|
|
1657
1639
|
leftItemsOffset = rightItemsOffset = bufferSize;
|
|
1658
1640
|
}
|
|
1659
1641
|
let itemsFromStartToScrollEnd = -1, itemsFromDisplayEndToOffsetEnd = 0, itemsFromStartToDisplayEnd = -1, leftItemLength = 0, rightItemLength = 0, leftItemsWeight = 0, rightItemsWeight = 0, leftHiddenItemsWeight = 0, totalItemsToDisplayEndWeight = 0, leftSizeOfAddedItems = 0, leftSizeOfUpdatedItems = 0, leftSizeOfDeletedItems = 0, itemById = undefined, itemByIdPos = 0, targetDisplayItemIndex = -1, isTargetInOverscroll = false, actualScrollSize = itemByIdPos, totalSize = 0, startIndex, isFromItemIdFound = false, deltaFromStartCreation = 0;
|
|
1660
|
-
let isNew = !this.
|
|
1642
|
+
let isNew = !this._isReseted && (roundedScrollSize === 0);
|
|
1661
1643
|
// If the list is dynamic or there are new elements in the collection, then it switches to the long algorithm.
|
|
1662
1644
|
if (dynamicSize) {
|
|
1663
1645
|
let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0;
|
|
1664
1646
|
for (let i = 0, l = collection.length; i < l; i++) {
|
|
1665
|
-
const ii = i + 1, collectionItem = collection[i], id = collectionItem
|
|
1647
|
+
const ii = i + 1, collectionItem = collection[i], id = collectionItem[trackBy];
|
|
1666
1648
|
let componentSize = 0, componentSizeDelta = 0, itemDisplayMethod = ItemDisplayMethods.NOT_CHANGED;
|
|
1667
1649
|
if (map.has(id)) {
|
|
1668
|
-
const
|
|
1669
|
-
componentSize =
|
|
1670
|
-
itemDisplayMethod =
|
|
1671
|
-
const isItemNew =
|
|
1672
|
-
if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0]
|
|
1650
|
+
const cache = map.get(id) || { width: typicalItemSize, height: typicalItemSize };
|
|
1651
|
+
componentSize = cache[sizeProperty];
|
|
1652
|
+
itemDisplayMethod = cache?.method ?? ItemDisplayMethods.UPDATE;
|
|
1653
|
+
const isItemNew = cache?.[IS_NEW] ?? (this._isLazy && this._isReseted);
|
|
1654
|
+
if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0][trackBy]]?.sticky) || (roundedScrollSize > 0)) {
|
|
1673
1655
|
isNew = false;
|
|
1674
1656
|
}
|
|
1675
1657
|
switch (itemDisplayMethod) {
|
|
1676
1658
|
case ItemDisplayMethods.UPDATE: {
|
|
1677
|
-
const snapshotBounds = snapshot.get(id);
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
if (isItemNew) {
|
|
1659
|
+
const snapshotBounds = snapshot.get(id), componentSnapshotSize = componentSize - (snapshotBounds ? snapshotBounds[sizeProperty] : typicalItemSize);
|
|
1660
|
+
componentSizeDelta = componentSnapshotSize;
|
|
1661
|
+
map.set(id, { ...cache, method: ItemDisplayMethods.NOT_CHANGED, isNew: false });
|
|
1662
|
+
if (isNew) {
|
|
1682
1663
|
deltaFromStartCreation += componentSize;
|
|
1683
1664
|
}
|
|
1684
1665
|
break;
|
|
1685
1666
|
}
|
|
1686
1667
|
case ItemDisplayMethods.CREATE: {
|
|
1687
1668
|
componentSizeDelta = isNew ? 0 : typicalItemSize;
|
|
1688
|
-
map.set(id, { ...
|
|
1669
|
+
map.set(id, { ...cache, method: ItemDisplayMethods.UPDATE, isNew });
|
|
1689
1670
|
break;
|
|
1690
1671
|
}
|
|
1691
1672
|
}
|
|
1692
1673
|
}
|
|
1693
1674
|
if (deletedItemsMap.hasOwnProperty(i)) {
|
|
1694
|
-
const
|
|
1675
|
+
const cache = deletedItemsMap[i], size = cache?.[sizeProperty] ?? typicalItemSize;
|
|
1695
1676
|
if (y < scrollSize - size) {
|
|
1696
1677
|
leftSizeOfDeletedItems += size;
|
|
1697
1678
|
}
|
|
@@ -1713,7 +1694,7 @@ class TrackBox extends CacheMap {
|
|
|
1713
1694
|
y -= size - componentSize;
|
|
1714
1695
|
}
|
|
1715
1696
|
else {
|
|
1716
|
-
if (itemConfigMap && !itemConfigMap[
|
|
1697
|
+
if (itemConfigMap && !itemConfigMap[id] && y >= scrollSize && y < scrollSize + stickyComponentSize) {
|
|
1717
1698
|
const snappedY = scrollSize - stickyComponentSize;
|
|
1718
1699
|
leftHiddenItemsWeight -= (snappedY - y);
|
|
1719
1700
|
y = snappedY;
|
|
@@ -1801,24 +1782,24 @@ class TrackBox extends CacheMap {
|
|
|
1801
1782
|
if (crudDetected) {
|
|
1802
1783
|
let y = 0;
|
|
1803
1784
|
for (let i = 0, l = collection.length; i < l; i++) {
|
|
1804
|
-
const collectionItem = collection[i], id = collectionItem
|
|
1785
|
+
const collectionItem = collection[i], id = collectionItem[trackBy];
|
|
1805
1786
|
let componentSize = typicalItemSize, itemDisplayMethod = ItemDisplayMethods.NOT_CHANGED;
|
|
1806
1787
|
if (map.has(id)) {
|
|
1807
|
-
const
|
|
1808
|
-
itemDisplayMethod =
|
|
1809
|
-
const isItemNew =
|
|
1810
|
-
if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0]
|
|
1788
|
+
const cache = map.get(id);
|
|
1789
|
+
itemDisplayMethod = cache?.method ?? ItemDisplayMethods.UPDATE;
|
|
1790
|
+
const isItemNew = cache?.[IS_NEW] ?? this._isLazy;
|
|
1791
|
+
if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0][trackBy]]?.sticky)) {
|
|
1811
1792
|
isNew = false;
|
|
1812
1793
|
}
|
|
1813
1794
|
if (itemDisplayMethod === ItemDisplayMethods.CREATE) {
|
|
1814
1795
|
if (isNew) {
|
|
1815
1796
|
deltaFromStartCreation += componentSize;
|
|
1816
1797
|
}
|
|
1817
|
-
map.set(id, { ...
|
|
1798
|
+
map.set(id, { ...cache, method: ItemDisplayMethods.NOT_CHANGED, isNew });
|
|
1818
1799
|
}
|
|
1819
1800
|
}
|
|
1820
1801
|
if (deletedItemsMap.hasOwnProperty(i)) {
|
|
1821
|
-
const
|
|
1802
|
+
const cache = deletedItemsMap[i], size = cache?.[sizeProperty] ?? typicalItemSize;
|
|
1822
1803
|
if (y < scrollSize - size) {
|
|
1823
1804
|
leftSizeOfDeletedItems += size;
|
|
1824
1805
|
}
|
|
@@ -1908,14 +1889,15 @@ class TrackBox extends CacheMap {
|
|
|
1908
1889
|
generateDisplayCollection(items, itemConfigMap, metrics) {
|
|
1909
1890
|
const { width, height, normalizedItemWidth, normalizedItemHeight, dynamicSize, itemsOnDisplayLength, itemsFromStartToScrollEnd, isVertical, renderItems: renderItemsLength, scrollSize, sizeProperty, snap, snippedPos, startPosition, totalLength, startIndex, typicalItemSize, } = metrics, displayItems = [];
|
|
1910
1891
|
if (items.length) {
|
|
1911
|
-
const actualSnippedPosition = snippedPos, isSnappingMethodAdvanced = this.isSnappingMethodAdvanced, boundsSize = isVertical ? height : width, actualEndSnippedPosition = boundsSize;
|
|
1892
|
+
const trackBy = this._trackingPropertyName, actualSnippedPosition = snippedPos, isSnappingMethodAdvanced = this.isSnappingMethodAdvanced, boundsSize = isVertical ? height : width, actualEndSnippedPosition = boundsSize;
|
|
1912
1893
|
let pos = startPosition, renderItems = renderItemsLength, stickyItem, nextSticky, stickyItemIndex = -1, stickyItemSize = 0, endStickyItem, nextEndSticky, endStickyItemIndex = -1, endStickyItemSize = 0, count = 1;
|
|
1913
1894
|
if (snap) {
|
|
1914
1895
|
for (let i = Math.min(itemsFromStartToScrollEnd > 0 ? itemsFromStartToScrollEnd : 0, totalLength - 1); i >= 0; i--) {
|
|
1915
|
-
|
|
1896
|
+
const collectionItem = items[i];
|
|
1897
|
+
if (!collectionItem) {
|
|
1916
1898
|
continue;
|
|
1917
1899
|
}
|
|
1918
|
-
const id =
|
|
1900
|
+
const id = collectionItem[trackBy], cache = this.get(id), sticky = itemConfigMap[id]?.sticky ?? 0, selectable = itemConfigMap[id]?.selectable ?? true, collapsable = itemConfigMap[id]?.collapsable ?? false, size = dynamicSize ? cache?.[sizeProperty] || typicalItemSize : typicalItemSize;
|
|
1919
1901
|
if (sticky === 1) {
|
|
1920
1902
|
const isOdd = i % 2 != 0, measures = {
|
|
1921
1903
|
x: isVertical ? 0 : actualSnippedPosition,
|
|
@@ -1939,7 +1921,7 @@ class TrackBox extends CacheMap {
|
|
|
1939
1921
|
tabIndex: count,
|
|
1940
1922
|
zIndex: '1',
|
|
1941
1923
|
};
|
|
1942
|
-
const itemData =
|
|
1924
|
+
const itemData = collectionItem;
|
|
1943
1925
|
stickyItem = { index: i, id, measures, data: itemData, config };
|
|
1944
1926
|
stickyItemIndex = i;
|
|
1945
1927
|
stickyItemSize = size;
|
|
@@ -1950,12 +1932,13 @@ class TrackBox extends CacheMap {
|
|
|
1950
1932
|
}
|
|
1951
1933
|
}
|
|
1952
1934
|
if (snap) {
|
|
1953
|
-
const
|
|
1935
|
+
const si = itemsFromStartToScrollEnd + itemsOnDisplayLength - 1, startIndex = si < 0 ? si : si;
|
|
1954
1936
|
for (let i = Math.min(startIndex, totalLength > 0 ? totalLength - 1 : 0), l = totalLength; i < l; i++) {
|
|
1955
|
-
|
|
1937
|
+
const collectionItem = items[i];
|
|
1938
|
+
if (!collectionItem) {
|
|
1956
1939
|
continue;
|
|
1957
1940
|
}
|
|
1958
|
-
const id =
|
|
1941
|
+
const id = collectionItem[trackBy], cache = this.get(id), sticky = itemConfigMap[id]?.sticky ?? 0, selectable = itemConfigMap[id]?.selectable ?? true, collapsable = itemConfigMap[id]?.collapsable ?? false, size = dynamicSize
|
|
1959
1942
|
? cache?.[sizeProperty] || typicalItemSize
|
|
1960
1943
|
: typicalItemSize;
|
|
1961
1944
|
if (sticky === 2) {
|
|
@@ -1981,7 +1964,7 @@ class TrackBox extends CacheMap {
|
|
|
1981
1964
|
tabIndex: items.length,
|
|
1982
1965
|
zIndex: '1',
|
|
1983
1966
|
};
|
|
1984
|
-
const itemData =
|
|
1967
|
+
const itemData = collectionItem;
|
|
1985
1968
|
endStickyItem = { index: i, id, measures, data: itemData, config };
|
|
1986
1969
|
endStickyItemIndex = i;
|
|
1987
1970
|
endStickyItemSize = size;
|
|
@@ -1995,10 +1978,11 @@ class TrackBox extends CacheMap {
|
|
|
1995
1978
|
if (i >= totalLength) {
|
|
1996
1979
|
break;
|
|
1997
1980
|
}
|
|
1998
|
-
|
|
1981
|
+
const collectionItem = items[i];
|
|
1982
|
+
if (!collectionItem) {
|
|
1999
1983
|
continue;
|
|
2000
1984
|
}
|
|
2001
|
-
const id =
|
|
1985
|
+
const id = collectionItem[trackBy], cache = this.get(id), size = dynamicSize ? cache?.[sizeProperty] || typicalItemSize : typicalItemSize;
|
|
2002
1986
|
if (id !== stickyItem?.id && id !== endStickyItem?.id) {
|
|
2003
1987
|
const isOdd = i % 2 != 0, sticky = itemConfigMap[id]?.sticky ?? 0, selectable = itemConfigMap[id]?.selectable ?? true, collapsable = itemConfigMap[id]?.collapsable ?? false, snapped = snap && (sticky === 1 && pos <= scrollSize || sticky === 2 && pos >= scrollSize + boundsSize - size), measures = {
|
|
2004
1988
|
x: isVertical ? sticky === 1 ? 0 : boundsSize - size : pos,
|
|
@@ -2026,7 +2010,7 @@ class TrackBox extends CacheMap {
|
|
|
2026
2010
|
if (snapped) {
|
|
2027
2011
|
config.zIndex = '2';
|
|
2028
2012
|
}
|
|
2029
|
-
const itemData =
|
|
2013
|
+
const itemData = collectionItem;
|
|
2030
2014
|
const item = { index: i, id, measures, data: itemData, config };
|
|
2031
2015
|
if (!nextSticky && stickyItemIndex < i && sticky === 1 && (pos <= scrollSize + size + stickyItemSize)) {
|
|
2032
2016
|
item.measures.x = isVertical ? 0 : snapped ? actualSnippedPosition : pos;
|
|
@@ -2036,7 +2020,8 @@ class TrackBox extends CacheMap {
|
|
|
2036
2020
|
nextSticky.measures.delta = isVertical ? (item.measures.y - scrollSize) : (item.measures.x - scrollSize);
|
|
2037
2021
|
nextSticky.config.zIndex = '3';
|
|
2038
2022
|
}
|
|
2039
|
-
else if (!nextEndSticky && endStickyItemIndex > i && sticky === 2 &&
|
|
2023
|
+
else if (!nextEndSticky && endStickyItemIndex > i && sticky === 2 &&
|
|
2024
|
+
(pos >= scrollSize + boundsSize - size - endStickyItemSize)) {
|
|
2040
2025
|
item.measures.x = isVertical ? 0 : snapped ? actualEndSnippedPosition - size : pos;
|
|
2041
2026
|
item.measures.y = isVertical ? snapped ? actualEndSnippedPosition - size : pos : 0;
|
|
2042
2027
|
nextEndSticky = item;
|
|
@@ -2064,7 +2049,8 @@ class TrackBox extends CacheMap {
|
|
|
2064
2049
|
nextSticky.measures.delta = isVertical ? nextSticky.measures.y - scrollSize : nextSticky.measures.x - scrollSize;
|
|
2065
2050
|
}
|
|
2066
2051
|
}
|
|
2067
|
-
if (nextEndSticky && endStickyItem &&
|
|
2052
|
+
if (nextEndSticky && endStickyItem &&
|
|
2053
|
+
(nextEndSticky.measures[axis] >= scrollSize + boundsSize - endStickyItemSize - nextEndSticky.measures[sizeProperty])) {
|
|
2068
2054
|
if (nextEndSticky.measures[axis] < scrollSize + boundsSize - endStickyItemSize) {
|
|
2069
2055
|
endStickyItem.measures[axis] = nextEndSticky.measures[axis] + nextEndSticky.measures[sizeProperty];
|
|
2070
2056
|
endStickyItem.config.snapped = nextEndSticky.config.snapped = false;
|
|
@@ -2137,7 +2123,7 @@ const FIREFOX_SCROLLBAR_OVERLAP_SIZE = 12;
|
|
|
2137
2123
|
const HORIZONTAL_ALIASES = [Directions.HORIZONTAL, 'horizontal'], VERTICAL_ALIASES = [Directions.VERTICAL, 'vertical'];
|
|
2138
2124
|
/**
|
|
2139
2125
|
* Determines the axis membership of a virtual list
|
|
2140
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/
|
|
2126
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/is-direction.ts
|
|
2141
2127
|
* @author Evgenii Grebennikov
|
|
2142
2128
|
* @email djonnyx@gmail.com
|
|
2143
2129
|
*/
|
|
@@ -2151,7 +2137,7 @@ const isDirection = (src, expected) => {
|
|
|
2151
2137
|
const NONE_ALIASES = [MethodsForSelecting.NONE, 'none'], SELECT_ALIASES = [MethodsForSelecting.SELECT, 'select'], MULTI_SELECT_ALIASES = [MethodsForSelecting.MULTI_SELECT, 'multi-select'];
|
|
2152
2138
|
/**
|
|
2153
2139
|
* Defines the method for selecting list items.
|
|
2154
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/
|
|
2140
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/is-method-for-selecting.ts
|
|
2155
2141
|
* @author Evgenii Grebennikov
|
|
2156
2142
|
* @email djonnyx@gmail.com
|
|
2157
2143
|
*/
|
|
@@ -2196,7 +2182,7 @@ const copyValueAsReadonly = (source) => {
|
|
|
2196
2182
|
const NORMAL_ALIASES = [CollectionModes.NORMAL, 'normal'], LAZY_ALIASES = [CollectionModes.LAZY, 'lazy'];
|
|
2197
2183
|
/**
|
|
2198
2184
|
* Determines the axis membership of a virtual list
|
|
2199
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/
|
|
2185
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/utils/is-collection-mode.ts
|
|
2200
2186
|
* @author Evgenii Grebennikov
|
|
2201
2187
|
* @email djonnyx@gmail.com
|
|
2202
2188
|
*/
|
|
@@ -2313,11 +2299,12 @@ class NgVirtualListComponent {
|
|
|
2313
2299
|
let valid = validateArray(v, true);
|
|
2314
2300
|
if (valid) {
|
|
2315
2301
|
if (v) {
|
|
2302
|
+
const trackBy = this.trackBy();
|
|
2316
2303
|
for (let i = 0, l = v.length; i < l; i++) {
|
|
2317
2304
|
const item = v[i];
|
|
2318
2305
|
valid = validateObject(item, true);
|
|
2319
2306
|
if (valid) {
|
|
2320
|
-
if (item && !(validateFloat(item
|
|
2307
|
+
if (item && !(validateFloat(item?.[trackBy], true) || validateString(item?.[trackBy], true))) {
|
|
2321
2308
|
valid = false;
|
|
2322
2309
|
break;
|
|
2323
2310
|
}
|
|
@@ -2848,11 +2835,11 @@ class NgVirtualListComponent {
|
|
|
2848
2835
|
combineLatest([$items, $itemSize]).pipe(takeUntilDestroyed(), map(([items, itemSize]) => ({ items, itemSize })), tap(({ items, itemSize }) => {
|
|
2849
2836
|
this._trackBox.resetCollection(items, itemSize);
|
|
2850
2837
|
})).subscribe();
|
|
2851
|
-
combineLatest([$items, $collapsedItemIds, $itemConfigMap]).pipe(takeUntilDestroyed(), tap(([items, collapsedIds, itemConfigMap]) => {
|
|
2838
|
+
combineLatest([$items, $collapsedItemIds, $itemConfigMap, $trackBy]).pipe(takeUntilDestroyed(), tap(([items, collapsedIds, itemConfigMap, trackBy]) => {
|
|
2852
2839
|
const hiddenItems = new CMap();
|
|
2853
2840
|
let isCollapsed = false;
|
|
2854
2841
|
for (let i = 0, l = items.length; i < l; i++) {
|
|
2855
|
-
const item = items[i], id = item
|
|
2842
|
+
const item = items[i], id = item[trackBy], group = (itemConfigMap[id]?.sticky ?? 0) > 0, collapsed = collapsedIds.includes(id);
|
|
2856
2843
|
if (group) {
|
|
2857
2844
|
isCollapsed = collapsed;
|
|
2858
2845
|
}
|
|
@@ -2864,7 +2851,7 @@ class NgVirtualListComponent {
|
|
|
2864
2851
|
}
|
|
2865
2852
|
const actualItems = [];
|
|
2866
2853
|
for (let i = 0, l = items.length; i < l; i++) {
|
|
2867
|
-
const item = items[i], id = item
|
|
2854
|
+
const item = items[i], id = item[trackBy];
|
|
2868
2855
|
if (hiddenItems.has(id)) {
|
|
2869
2856
|
continue;
|
|
2870
2857
|
}
|
|
@@ -2996,7 +2983,7 @@ class NgVirtualListComponent {
|
|
|
2996
2983
|
this._onResizeHandler();
|
|
2997
2984
|
})).subscribe();
|
|
2998
2985
|
const $scrollTo = this.$scrollTo;
|
|
2999
|
-
combineLatest([$container, $scrollTo]).pipe(takeUntilDestroyed(), filter(([container]) => container !== undefined), map(([container, event]) => ({ container: container?.nativeElement, event })), switchMap(({ container, event }) => {
|
|
2986
|
+
combineLatest([$container, $trackBy, $scrollTo]).pipe(takeUntilDestroyed(), filter(([container]) => container !== undefined), map(([container, trackBy, event]) => ({ container: container?.nativeElement, trackBy, event })), switchMap(({ container, trackBy, event }) => {
|
|
3000
2987
|
const cnt = container, { id, behavior = BEHAVIOR_INSTANT, iteration = 0, isLastIteration = false, scrollCalled = false, cb } = event;
|
|
3001
2988
|
const items = this._actualItems();
|
|
3002
2989
|
if (items && items.length) {
|
|
@@ -3047,7 +3034,7 @@ class NgVirtualListComponent {
|
|
|
3047
3034
|
}
|
|
3048
3035
|
}
|
|
3049
3036
|
else {
|
|
3050
|
-
const index = items.findIndex(item => item
|
|
3037
|
+
const index = items.findIndex(item => item[trackBy] === id);
|
|
3051
3038
|
if (index > -1) {
|
|
3052
3039
|
const isVertical = this._isVertical, currentScollSize = (isVertical ? cnt.scrollTop : cnt.scrollLeft), scrollSize = index * this.itemSize();
|
|
3053
3040
|
if (currentScollSize !== scrollSize) {
|
|
@@ -3257,7 +3244,7 @@ class NgVirtualListComponent {
|
|
|
3257
3244
|
const behavior = options?.behavior ?? BEHAVIOR_INSTANT, iteration = options?.iteration ?? 0;
|
|
3258
3245
|
validateScrollBehavior(behavior);
|
|
3259
3246
|
validateIteration(iteration);
|
|
3260
|
-
const items = this.items(), latItem = items[items.length > 0 ? items.length - 1 : 0], id = latItem
|
|
3247
|
+
const trackBy = this.trackBy(), items = this.items(), latItem = items[items.length > 0 ? items.length - 1 : 0], id = latItem[trackBy], actualIteration = validateScrollIteration(iteration);
|
|
3261
3248
|
this._$scrollTo.next({ id, behavior, iteration: actualIteration, isLastIteration: actualIteration === MAX_SCROLL_TO_ITERATIONS, cb });
|
|
3262
3249
|
}
|
|
3263
3250
|
ngOnDestroy() {
|