FastForEach.prototype.onArrayChange = function()

in src/bindingHandlers/fastForeach.ts [119:169]


FastForEach.prototype.onArrayChange = function (changeSet, isInitial) {
    const self = this;
    const changeMap = {
        added: [],
        deleted: []
    };

    // knockout array change notification index handling:
    // - sends the original array indexes for deletes
    // - sends the new array indexes for adds
    // - sorts them all by index in ascending order
    // because of this, when checking for possible batch additions, any delete can be between to adds with neighboring indexes, so only additions should be checked
    for (let i = 0, len = changeSet.length; i < len; i++) {

        if (changeMap.added.length && changeSet[i].status == "added") {
            let lastAdd = changeMap.added[changeMap.added.length - 1];
            const lastIndex = lastAdd.isBatch ? lastAdd.index + lastAdd.values.length - 1 : lastAdd.index;
            if (lastIndex + 1 == changeSet[i].index) {
                if (!lastAdd.isBatch) {
                    // transform the last addition into a batch addition object
                    lastAdd = {
                        isBatch: true,
                        status: "added",
                        index: lastAdd.index,
                        values: [lastAdd.value]
                    };
                    changeMap.added.splice(changeMap.added.length - 1, 1, lastAdd);
                }
                lastAdd.values.push(changeSet[i].value);
                continue;
            }
        }

        changeMap[changeSet[i].status].push(changeSet[i]);
    }

    if (changeMap.deleted.length > 0) {
        this.changeQueue.push.apply(this.changeQueue, changeMap.deleted);
        this.changeQueue.push({ status: "clearDeletedIndexes" });
    }
    this.changeQueue.push.apply(this.changeQueue, changeMap.added);
    // Once a change is registered, the ticking count-down starts for the processQueue.
    if (this.changeQueue.length > 0 && !this.rendering_queued) {
        this.rendering_queued = true;
        if (isInitial) {
            self.processQueue();
        } else {
            FastForEach.animateFrame.call(window, function () { self.processQueue(); });
        }
    }
};