vscroll
Version:
Virtual scroll engine
263 lines • 9.34 kB
JavaScript
import { DefaultSize } from './defaultSize';
import { Direction } from '../../inputs/index';
var ItemCache = /** @class */ (function () {
function ItemCache(item, saveData) {
this.$index = item.$index;
this.data = saveData ? item.data : null;
this.size = item.size;
}
ItemCache.prototype.changeIndex = function (value) {
this.$index = value;
};
return ItemCache;
}());
export { ItemCache };
var Cache = /** @class */ (function () {
function Cache(_a, logger) {
var itemSize = _a.itemSize, cacheData = _a.cacheData, cacheOnReload = _a.cacheOnReload, sizeStrategy = _a.sizeStrategy;
this.itemSize = itemSize;
this.saveData = cacheData;
this.cacheOnReload = cacheOnReload;
this.sizeStrategy = sizeStrategy;
this.logger = logger;
this.items = new Map();
this.defaultSize = new DefaultSize(itemSize, sizeStrategy);
this.reset(true);
}
Cache.prototype.reset = function (force) {
force = force || !this.cacheOnReload;
if (force) {
this.minIndex = +Infinity;
this.maxIndex = -Infinity;
this.items.clear();
}
this.defaultSize.reset(force);
};
Object.defineProperty(Cache.prototype, "size", {
get: function () {
return this.items.size;
},
enumerable: false,
configurable: true
});
Cache.prototype.get = function (index) {
return this.items.get(index);
};
Cache.prototype.getSizeByIndex = function (index) {
var item = this.get(index);
return (item && item.size) || this.defaultSize.get();
};
Cache.prototype.getDefaultSize = function () {
return this.defaultSize.get();
};
Cache.prototype.recalculateDefaultSize = function () {
var _this = this;
if (this.defaultSize.recalculate(this.size)) {
this.logger.log(function () { return "default size has been updated: ".concat(_this.defaultSize.get()); });
return true;
}
return false;
};
/**
* Adds item to Set by $index, replaces existed item if $index matches.
* Maintains min/max indexes and default item size.
*
* @param {Item<Data>} item A Buffer item to be cached, an objects with { $index, data, size } props.
* @returns {ItemCache<Data>} Cached item.
*/
Cache.prototype.add = function (item) {
var itemCache = this.get(item.$index);
if (itemCache) {
// adding item is already cached
if (this.saveData) {
itemCache.data = item.data;
}
if (itemCache.size !== item.size) {
if (itemCache.size) {
this.defaultSize.setExisted(itemCache.size, item.size);
}
else {
this.defaultSize.setNew(item.size);
}
itemCache.size = item.size;
}
}
else {
itemCache = new ItemCache(item, this.saveData);
this.items.set(item.$index, itemCache);
this.defaultSize.setNew(item.size);
}
if (item.$index < this.minIndex) {
this.minIndex = item.$index;
}
if (item.$index > this.maxIndex) {
this.maxIndex = item.$index;
}
return itemCache;
};
/**
* Inserts items to Set, shifts $indexes of items that remain.
* Replaces current Set with a new one with new regular $indexes.
* Maintains min/max indexes.
*
* @param {Data[]} toInsert List of non-indexed items to be inserted.
* @param {number} index The index before/after which the insertion is performed.
* @param {Direction} direction Determines the direction of insertion.
* @param {boolean} fixRight Defines indexes shifting strategy.
* If false, indexes that are greater than the inserted ones are increased.
* If true, indexes that are less than than the inserted ones are decreased.
*/
Cache.prototype.insertItems = function (toInsert, index, direction, fixRight) {
var _this = this;
var items = new Map();
var length = toInsert.length;
var min = Infinity, max = -Infinity;
var set = function (item) {
items.set(item.$index, item);
min = item.$index < min ? item.$index : min;
max = item.$index > max ? item.$index : max;
};
this.items.forEach(function (item) {
var shift = 0;
if (direction === Direction.backward) {
if (item.$index < index && fixRight) {
shift = -length;
}
else if (item.$index >= index && !fixRight) {
shift = length;
}
}
else if (direction === Direction.forward) {
if (item.$index <= index && fixRight) {
shift = -length;
}
else if (item.$index > index && !fixRight) {
shift = length;
}
}
if (shift) {
item.changeIndex(item.$index + shift);
}
set(item);
});
if (this.saveData) {
// persist data with no sizes
toInsert.forEach(function (data, i) {
var $index = index + i - (fixRight ? length : 0) + (direction === Direction.forward ? 1 : 0);
var item = new ItemCache({ $index: $index, data: data }, _this.saveData);
set(item);
});
}
this.items = items;
this.minIndex = min;
this.maxIndex = max;
};
/**
* Removes items from Set, shifts $indexes of items that remain.
* Replaces current Set with a new one with new regular $indexes.
* Maintains min/max indexes and default item size.
*
* @param {number[]} toRemove List of indexes to be removed.
* @param {boolean} fixRight Defines indexes shifting strategy.
* If false, indexes that are greater than the removed ones will be decreased.
* If true, indexes that are less than than the removed ones will be increased.
*/
Cache.prototype.removeItems = function (toRemove, fixRight) {
var _this = this;
var items = new Map();
var min = Infinity, max = -Infinity;
this.items.forEach(function (item) {
if (toRemove.some(function (index) { return index === item.$index; })) {
if (item.size) {
_this.defaultSize.setRemoved(item.size);
}
return;
}
var diff = fixRight
? toRemove.reduce(function (acc, index) { return acc + (item.$index < index ? 1 : 0); }, 0)
: toRemove.reduce(function (acc, index) { return acc - (item.$index > index ? 1 : 0); }, 0);
item.changeIndex(item.$index + diff);
items.set(item.$index, item);
min = item.$index < min ? item.$index : min;
max = item.$index > max ? item.$index : max;
});
this.items = items;
this.minIndex = min;
this.maxIndex = max;
};
/**
* Destructively updates Set based on subset (before-after) changes.
* Replaces current Set with a new one with new regular $indexes.
* Maintains min/max indexes. Maintains default item size on remove only.
*
* @param {ItemUpdate[]} before Initial subset of items to be replaced by "after".
* Each element is an object with { $index, size, toRemove } props. Must be $index-incremental.
* Items to be removed must have toRemove flag: before[].toRemove = true.
* @param {Item<Data>[]} after Transformed subset that replaces "before". Must be $index-incremental.
* Must contain at least 1 $index from "before" or be empty.
* @param {boolean} fixRight This is to fix right indexes during subset collapsing. Acts only if "after" is empty.
*/
Cache.prototype.updateSubset = function (before, after, fixRight) {
var _this = this;
if (!this.size || !before.length) {
return;
}
var minB = before[0].$index, maxB = before[before.length - 1].$index;
var leftDiff, rightDiff;
if (after.length) {
var minA = after[0].$index, maxA = after[after.length - 1].$index;
leftDiff = minA - minB;
rightDiff = maxA - maxB;
}
else {
leftDiff = fixRight ? maxB - minB + 1 : 0;
rightDiff = fixRight ? 0 : minB - maxB - 1;
}
var items = new Map();
this.items.forEach(function (item) {
if (item.$index < minB) {
// items to the left of the subset
item.changeIndex(item.$index + leftDiff);
items.set(item.$index, item);
return;
}
else if (item.$index > maxB) {
// items to the right of the subset
item.changeIndex(item.$index + rightDiff);
items.set(item.$index, item);
return;
}
});
after.forEach(function (item // subset items
) { return items.set(item.$index, new ItemCache(item, _this.saveData)); });
before // to maintain default size on remove
.filter(function (item) { return item.toRemove; })
.forEach(function (item) { return _this.defaultSize.setRemoved(item.size); });
this.minIndex += leftDiff;
this.maxIndex += rightDiff;
this.items = items;
};
/**
* Shifts all indexes by some value.
* Replaces current Set with a new one with new regular $indexes.
* Maintains min/max indexes.
*
* @param {number} delta A shift value.
*/
Cache.prototype.shiftIndexes = function (delta) {
var items = new Map();
var min = Infinity, max = -Infinity;
this.items.forEach(function (item) {
item.changeIndex(item.$index + delta);
items.set(item.$index, item);
min = item.$index < min ? item.$index : min;
max = item.$index > max ? item.$index : max;
});
this.items = items;
this.minIndex = min;
this.maxIndex = max;
};
return Cache;
}());
export { Cache };
//# sourceMappingURL=cache.js.map