Resolve Knockout/#2560 with

45e86bf034
This commit is contained in:
djmaze 2021-09-13 15:52:40 +02:00
parent 47b75755c4
commit f09820d0b9

View file

@ -60,7 +60,8 @@
var nodesToDelete = []; var nodesToDelete = [];
var itemsToMoveFirstIndexes = []; var itemsToMoveFirstIndexes = [];
var itemsForBeforeRemoveCallbacks = []; var itemsForBeforeRemoveCallbacks = [];
var itemsForMoveCallbacks = []; var itemsForBeforeMoveCallbacks = [];
var itemsForAfterMoveCallbacks = [];
var itemsForAfterAddCallbacks = []; var itemsForAfterAddCallbacks = [];
var mapData; var mapData;
var countWaitingForRemove = 0; var countWaitingForRemove = 0;
@ -69,14 +70,16 @@
mapData = { arrayEntry: value, indexObservable: ko.observable(currentArrayIndex++) }; mapData = { arrayEntry: value, indexObservable: ko.observable(currentArrayIndex++) };
newMappingResult.push(mapData); newMappingResult.push(mapData);
if (!isFirstExecution) { if (!isFirstExecution) {
itemsForAfterAddCallbacks.push(mapData); itemsForAfterAddCallbacks[currentArrayIndex - 1] = mapData;
} }
} }
function itemMovedOrRetained(oldPosition) { function itemMovedOrRetained(oldPosition) {
mapData = lastMappingResult[oldPosition]; mapData = lastMappingResult[oldPosition];
if (currentArrayIndex !== mapData.indexObservable.peek()) if (currentArrayIndex !== mapData.indexObservable.peek()) {
itemsForMoveCallbacks.push(mapData); itemsForBeforeMoveCallbacks[mapData.indexObservable.peek()] = mapData;
itemsForAfterMoveCallbacks[currentArrayIndex] = mapData;
}
// Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray
mapData.indexObservable(currentArrayIndex++); mapData.indexObservable(currentArrayIndex++);
ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode); ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);
@ -86,7 +89,7 @@
function callCallback(callback, items) { function callCallback(callback, items) {
if (callback) { if (callback) {
for (var i = 0, n = items.length; i < n; i++) { for (var i = 0, n = items.length; i < n; i++) {
items[i].mappedNodes.forEach(node => callback(node, i, items[i].arrayEntry)); items[i] && items[i].mappedNodes.forEach(node => callback(node, i, items[i].arrayEntry));
} }
} }
} }
@ -129,7 +132,7 @@
if (mapData.arrayEntry === deletedItemDummyValue) { if (mapData.arrayEntry === deletedItemDummyValue) {
mapData = null; mapData = null;
} else { } else {
itemsForBeforeRemoveCallbacks.push(mapData); itemsForBeforeRemoveCallbacks[mapData.indexObservable.peek()] = mapData;
} }
} }
if (mapData) { if (mapData) {
@ -167,7 +170,7 @@
ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult); ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
// Call beforeMove first before any changes have been made to the DOM // Call beforeMove first before any changes have been made to the DOM
callCallback(options['beforeMove'], itemsForMoveCallbacks); callCallback(options['beforeMove'], itemsForBeforeMoveCallbacks);
// Next remove nodes for deleted items (or just clean if there's a beforeRemove callback) // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
nodesToDelete.forEach(options['beforeRemove'] ? ko.cleanNode : ko.removeNode); nodesToDelete.forEach(options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
@ -184,7 +187,7 @@
mapData = newMappingResult[i]; mapData = newMappingResult[i];
for (lastNode = undefined; i; ) { for (lastNode = undefined; i; ) {
if ((mappedNodes = newMappingResult[--i].mappedNodes) && mappedNodes.length) { if ((mappedNodes = newMappingResult[--i].mappedNodes) && mappedNodes.length) {
lastNode = mappedNodes[mappedNodes.length-1]; lastNode = mappedNodes[mappedNodes.length - 1];
break; break;
} }
} }
@ -229,11 +232,13 @@
// as already "removed" so we won't call beforeRemove for it again, and it ensures that the item won't match up // as already "removed" so we won't call beforeRemove for it again, and it ensures that the item won't match up
// with an actual item in the array and appear as "retained" or "moved". // with an actual item in the array and appear as "retained" or "moved".
for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) { for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) {
itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue; if (itemsForBeforeRemoveCallbacks[i]) {
itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue;
}
} }
// Finally call afterMove and afterAdd callbacks // Finally call afterMove and afterAdd callbacks
callCallback(options['afterMove'], itemsForMoveCallbacks); callCallback(options['afterMove'], itemsForAfterMoveCallbacks);
callCallback(options['afterAdd'], itemsForAfterAddCallbacks); callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
} }
})(); })();