vscroll
Version:
Virtual scroll engine
411 lines • 14.3 kB
JavaScript
import { __read, __spreadArray } from "tslib";
import { Cache } from './buffer/cache';
import { CheckBufferCall } from './buffer/checkCall';
import { Reactive } from './reactive';
import { Direction } from '../inputs/index';
var Buffer = /** @class */ (function () {
function Buffer(settings, onDataChanged, logger) {
this._items = [];
this.logger = logger;
this.changeItems = onDataChanged;
this.bof = new Reactive(false);
this.eof = new Reactive(false);
this.cache = new Cache(settings, logger);
this.checkCall = new CheckBufferCall(this, logger);
this.startIndexUser = settings.startIndex;
this.minIndexUser = settings.minIndex;
this.maxIndexUser = settings.maxIndex;
this.reset(true);
}
Buffer.prototype.dispose = function () {
this.bof.dispose();
this.eof.dispose();
this._items.forEach(function (item) { return item.dispose(); });
this._items = [];
};
Buffer.prototype.reset = function (force, startIndex) {
this.items.forEach(function (item) { return item.hide(); });
this.pristine = true;
this.items = [];
this.cache.reset(force);
this.absMinIndex = this.minIndexUser;
this.absMaxIndex = this.maxIndexUser;
this.setCurrentStartIndex(startIndex);
this.bof.set(false);
this.eof.set(false);
this.pristine = false;
};
Buffer.prototype.setCurrentStartIndex = function (newStartIndex) {
var min = this.minIndexUser;
var max = this.maxIndexUser;
var start = this.startIndexUser;
var index = Number(newStartIndex);
if (Number.isNaN(index)) {
this.logger.log(function () { return "fallback startIndex to settings.startIndex (".concat(start, ")"); });
index = start;
}
if (index < min) {
this.logger.log(function () { return "setting startIndex to settings.minIndex (".concat(min, ") because ").concat(index, " < ").concat(min); });
index = min;
}
if (index > max) {
this.logger.log(function () { return "setting startIndex to settings.maxIndex (".concat(max, ") because ").concat(index, " > ").concat(max); });
index = max;
}
this.startIndex = index;
};
Object.defineProperty(Buffer.prototype, "items", {
get: function () {
return this._items;
},
set: function (items) {
this._items = items;
this.changeItems(items);
if (!this.pristine) {
this.checkBOF();
this.checkEOF();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "absMinIndex", {
get: function () {
return this._absMinIndex;
},
set: function (value) {
if (this._absMinIndex !== value) {
this._absMinIndex =
Number.isFinite(this._absMaxIndex) && value > this._absMaxIndex ? this._absMaxIndex : value;
}
if (!this.pristine) {
this.checkBOF();
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "absMaxIndex", {
get: function () {
return this._absMaxIndex;
},
set: function (value) {
if (this._absMaxIndex !== value) {
this._absMaxIndex =
Number.isFinite(this._absMinIndex) && value < this._absMinIndex ? this._absMinIndex : value;
}
if (!this.pristine) {
this.checkEOF();
}
},
enumerable: false,
configurable: true
});
Buffer.prototype.checkBOF = function () {
// since bof has no setter, need to call checkBOF() on items and absMinIndex change
var bof = this.items.length
? this.items[0].$index === this.absMinIndex
: isFinite(this.absMinIndex);
this.bof.set(bof);
};
Buffer.prototype.checkEOF = function () {
// since eof has no setter, need to call checkEOF() on items and absMaxIndex change
var eof = this.items.length
? this.items[this.items.length - 1].$index === this.absMaxIndex
: isFinite(this.absMaxIndex);
this.eof.set(eof);
};
Object.defineProperty(Buffer.prototype, "size", {
get: function () {
return this._items.length;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "cacheSize", {
get: function () {
return this.cache.size;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "defaultSize", {
get: function () {
return this.cache.getDefaultSize();
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "minIndex", {
get: function () {
return isFinite(this.cache.minIndex) ? this.cache.minIndex : this.startIndex;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "maxIndex", {
get: function () {
return isFinite(this.cache.maxIndex) ? this.cache.maxIndex : this.startIndex;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "firstIndex", {
get: function () {
return this.items.length ? this.items[0].$index : NaN;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "lastIndex", {
get: function () {
return this.items.length ? this.items[this.items.length - 1].$index : NaN;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "finiteAbsMinIndex", {
get: function () {
return isFinite(this.absMinIndex) ? this.absMinIndex : this.minIndex;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Buffer.prototype, "finiteAbsMaxIndex", {
get: function () {
return isFinite(this.absMaxIndex) ? this.absMaxIndex : this.maxIndex;
},
enumerable: false,
configurable: true
});
Buffer.prototype.get = function ($index) {
return this.items.find(function (item) { return item.$index === $index; });
};
Buffer.prototype.setItems = function (items) {
if (!this.items.length) {
this.items = __spreadArray([], __read(items), false);
}
else if (this.items[0].$index > items[items.length - 1].$index) {
this.items = __spreadArray(__spreadArray([], __read(items), false), __read(this.items), false);
}
else if (items[0].$index > this.items[this.items.length - 1].$index) {
this.items = __spreadArray(__spreadArray([], __read(this.items), false), __read(items), false);
}
else {
return false;
}
return true;
};
Buffer.prototype.clip = function () {
this.items = this.items.filter(function (_a) {
var toRemove = _a.toRemove;
return !toRemove;
});
};
Buffer.prototype.getIndexToInsert = function (predicate, before, after) {
return this.checkCall.insertInBuffer(predicate, before, after);
};
Buffer.prototype.shiftExtremum = function (amount, fixRight) {
if (!fixRight) {
this.absMaxIndex += amount;
}
else {
this.absMinIndex -= amount;
this.startIndex -= amount;
}
if (this.startIndex > this.absMaxIndex) {
this.startIndex = this.absMaxIndex;
}
else if (this.startIndex < this.absMinIndex) {
this.startIndex = this.absMinIndex;
}
};
Buffer.prototype.insertVirtually = function (items, index, direction, fixRight) {
if (!this.checkCall.insertVirtual(items, index, direction)) {
return false;
}
var shift = 0;
if (index <= this.firstIndex && !fixRight) {
shift = items.length;
}
else if (index >= this.lastIndex && fixRight) {
shift = -items.length;
}
if (shift) {
this.items.forEach(function (item) { return item.updateIndex(item.$index + shift); });
this.cache.insertItems(items, index, direction, fixRight);
this.items = __spreadArray([], __read(this.items), false);
}
this.shiftExtremum(items.length, fixRight);
return true;
};
Buffer.prototype.removeVirtually = function (indexes, fixRight) {
var length = this.items.length;
var shifted = false;
var _loop_1 = function (i) {
var item = this_1.items[i];
var diff = indexes.reduce(function (acc, index) {
return acc + (fixRight ? (item.$index < index ? 1 : 0) : item.$index > index ? -1 : 0);
}, 0);
shifted = shifted || !!diff;
item.updateIndex(item.$index + diff);
};
var this_1 = this;
for (var i = fixRight ? length - 1 : 0; fixRight ? i >= 0 : i < length; fixRight ? i-- : i++) {
_loop_1(i);
}
this.shiftExtremum(-indexes.length, fixRight);
if (shifted) {
this.items = __spreadArray([], __read(this.items), false);
}
this.cache.removeItems(indexes, fixRight);
};
Buffer.prototype.fillEmpty = function (items, beforeIndex, afterIndex, fixRight, generator) {
if (!this.checkCall.fillEmpty(items, beforeIndex, afterIndex)) {
return false;
}
var before = Number.isInteger(beforeIndex);
var index = (before ? beforeIndex : afterIndex);
var shift = fixRight ? items.length : before ? 1 : 0;
this.items = items.map(function (data, i) { return generator(index + i + (!before ? 1 : 0) - shift, data); });
this._absMinIndex = this.items[0].$index;
this._absMaxIndex = this.items[this.size - 1].$index;
if (this.startIndex <= this.absMinIndex) {
this.startIndex = this.absMinIndex;
}
else if (this.startIndex > this.absMaxIndex) {
this.startIndex = this.absMaxIndex;
}
return true;
};
Buffer.prototype.updateItems = function (predicate, generator, indexToTrack, fixRight) {
if (!this.size || Number.isNaN(this.firstIndex)) {
return { trackedIndex: NaN, toRemove: [] };
}
var trackedIndex = indexToTrack;
var index = fixRight ? this.lastIndex : this.firstIndex;
var items = [];
var diff = fixRight ? -1 : 1;
var limit = this.size - 1;
var beforeMap = new Map(); // need to persist original $indexes
var updateArray = Array.prototype[fixRight ? 'unshift' : 'push'];
var _loop_2 = function (i) {
var item = this_2.items[i];
beforeMap.set(item.$index, item);
var result = predicate(item);
// if predicate result is falsy or empty array -> delete
if (!result || (Array.isArray(result) && !result.length)) {
item.toRemove = true;
trackedIndex += item.$index >= indexToTrack ? (fixRight ? 1 : 0) : fixRight ? 0 : -1;
this_2.shiftExtremum(-1, fixRight);
return "continue";
}
// if predicate result is truthy but not array -> leave
if (!Array.isArray(result)) {
item.updateIndex(index);
updateArray.call(items, item);
index += diff;
return "continue";
}
// if predicate result is non-empty array -> insert/replace
if (item.$index < indexToTrack) {
trackedIndex += fixRight ? 0 : result.length - 1;
}
else if (item.$index > indexToTrack) {
trackedIndex += fixRight ? 1 - result.length : 0;
}
var toRemove_1 = true;
var newItems = [];
(fixRight ? __spreadArray([], __read(result), false).reverse() : result).forEach(function (data, i) {
var newItem;
if (item.data === data) {
if (indexToTrack === item.$index) {
trackedIndex = index + i * diff;
}
item.updateIndex(index + i * diff);
newItem = item;
toRemove_1 = false; // insert case
}
else {
newItem = generator(index + i * diff, data);
newItem.toInsert = true;
}
updateArray.call(newItems, newItem);
});
item.toRemove = toRemove_1;
updateArray.call.apply(updateArray, __spreadArray([items], __read(newItems), false));
index += diff * result.length;
if (result.length > 1) {
this_2.shiftExtremum(result.length - 1, fixRight);
}
};
var this_2 = this;
for (var i = fixRight ? limit : 0; fixRight ? i >= 0 : i <= limit; i += diff) {
_loop_2(i);
}
var toRemove = this.items.filter(function (item) { return item.toRemove; });
var itemsBefore = Array.from(beforeMap)
.map(function (_a) {
var _b = __read(_a, 2), $index = _b[0], _c = _b[1], size = _c.size, toRemove = _c.toRemove;
return ({ $index: $index, size: size, toRemove: toRemove });
})
.sort(function (a, b) { return a.$index - b.$index; });
this.items = items;
this.cache.updateSubset(itemsBefore, items, fixRight);
if (this.finiteAbsMinIndex === this.finiteAbsMaxIndex) {
trackedIndex = NaN;
}
else if (trackedIndex > this.finiteAbsMaxIndex) {
trackedIndex = this.finiteAbsMaxIndex;
}
else if (trackedIndex < this.finiteAbsMinIndex) {
trackedIndex = this.finiteAbsMinIndex;
}
return { trackedIndex: trackedIndex, toRemove: toRemove };
};
Buffer.prototype.cacheItem = function (item) {
this.cache.add(item);
};
Buffer.prototype.getFirstVisibleItemIndex = function () {
var length = this.items.length;
for (var i = 0; i < length; i++) {
if (!this.items[i].invisible) {
return i;
}
}
return -1;
};
Buffer.prototype.getLastVisibleItemIndex = function () {
for (var i = this.items.length - 1; i >= 0; i--) {
if (!this.items[i].invisible) {
return i;
}
}
return -1;
};
Buffer.prototype.getFirstVisibleItem = function () {
var index = this.getFirstVisibleItemIndex();
return index >= 0 ? this.items[index] : void 0;
};
Buffer.prototype.getLastVisibleItem = function () {
var index = this.getLastVisibleItemIndex();
return index >= 0 ? this.items[index] : void 0;
};
Buffer.prototype.getEdgeVisibleItem = function (direction, opposite) {
return direction === (!opposite ? Direction.forward : Direction.backward)
? this.getLastVisibleItem()
: this.getFirstVisibleItem();
};
Buffer.prototype.getVisibleItemsCount = function () {
return this.items.reduce(function (acc, item) { return acc + (item.invisible ? 0 : 1); }, 0);
};
Buffer.prototype.getSizeByIndex = function (index) {
return this.cache.getSizeByIndex(index);
};
Buffer.prototype.checkDefaultSize = function () {
return this.cache.recalculateDefaultSize();
};
return Buffer;
}());
export { Buffer };
//# sourceMappingURL=buffer.js.map