diff --git a/vendors/knockout/src/binding/editDetection/arrayToDomNodeChildren.js b/vendors/knockout/src/binding/editDetection/arrayToDomNodeChildren.js index 411f9930a..b2d3fefb6 100644 --- a/vendors/knockout/src/binding/editDetection/arrayToDomNodeChildren.js +++ b/vendors/knockout/src/binding/editDetection/arrayToDomNodeChildren.js @@ -60,7 +60,8 @@ var nodesToDelete = []; var itemsToMoveFirstIndexes = []; var itemsForBeforeRemoveCallbacks = []; - var itemsForMoveCallbacks = []; + var itemsForBeforeMoveCallbacks = []; + var itemsForAfterMoveCallbacks = []; var itemsForAfterAddCallbacks = []; var mapData; var countWaitingForRemove = 0; @@ -69,14 +70,16 @@ mapData = { arrayEntry: value, indexObservable: ko.observable(currentArrayIndex++) }; newMappingResult.push(mapData); if (!isFirstExecution) { - itemsForAfterAddCallbacks.push(mapData); + itemsForAfterAddCallbacks[currentArrayIndex - 1] = mapData; } } function itemMovedOrRetained(oldPosition) { mapData = lastMappingResult[oldPosition]; - if (currentArrayIndex !== mapData.indexObservable.peek()) - itemsForMoveCallbacks.push(mapData); + if (currentArrayIndex !== mapData.indexObservable.peek()) { + itemsForBeforeMoveCallbacks[mapData.indexObservable.peek()] = mapData; + itemsForAfterMoveCallbacks[currentArrayIndex] = mapData; + } // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray mapData.indexObservable(currentArrayIndex++); ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode); @@ -86,7 +89,7 @@ function callCallback(callback, items) { if (callback) { 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) { mapData = null; } else { - itemsForBeforeRemoveCallbacks.push(mapData); + itemsForBeforeRemoveCallbacks[mapData.indexObservable.peek()] = mapData; } } if (mapData) { @@ -167,7 +170,7 @@ ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult); // 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) nodesToDelete.forEach(options['beforeRemove'] ? ko.cleanNode : ko.removeNode); @@ -184,7 +187,7 @@ mapData = newMappingResult[i]; for (lastNode = undefined; i; ) { if ((mappedNodes = newMappingResult[--i].mappedNodes) && mappedNodes.length) { - lastNode = mappedNodes[mappedNodes.length-1]; + lastNode = mappedNodes[mappedNodes.length - 1]; 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 // with an actual item in the array and appear as "retained" or "moved". for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) { - itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue; + if (itemsForBeforeRemoveCallbacks[i]) { + itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue; + } } // Finally call afterMove and afterAdd callbacks - callCallback(options['afterMove'], itemsForMoveCallbacks); + callCallback(options['afterMove'], itemsForAfterMoveCallbacks); callCallback(options['afterAdd'], itemsForAfterAddCallbacks); } })();