mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-01 13:39:22 +03:00
More Optional chaining in Knockout.js
This commit is contained in:
parent
d18f93d87f
commit
a566f6ed5a
10 changed files with 391 additions and 476 deletions
|
|
@ -49,55 +49,57 @@
|
|||
array = [array];
|
||||
|
||||
options = options || {};
|
||||
var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey);
|
||||
var isFirstExecution = !lastMappingResult;
|
||||
var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey),
|
||||
isFirstExecution = !lastMappingResult,
|
||||
|
||||
// Build the new mapping result
|
||||
var newMappingResult = [];
|
||||
var lastMappingResultIndex = 0;
|
||||
var currentArrayIndex = 0;
|
||||
// Build the new mapping result
|
||||
newMappingResult = [],
|
||||
lastMappingResultIndex = 0,
|
||||
currentArrayIndex = 0,
|
||||
|
||||
var nodesToDelete = [];
|
||||
var itemsToMoveFirstIndexes = [];
|
||||
var itemsForBeforeRemoveCallbacks = [];
|
||||
var mapData;
|
||||
var countWaitingForRemove = 0;
|
||||
nodesToDelete = [],
|
||||
itemsToMoveFirstIndexes = [],
|
||||
itemsForBeforeRemoveCallbacks = [],
|
||||
mapData,
|
||||
countWaitingForRemove = 0,
|
||||
|
||||
function itemAdded(value) {
|
||||
mapData = { arrayEntry: value, indexObservable: ko.observable(currentArrayIndex++) };
|
||||
newMappingResult.push(mapData);
|
||||
}
|
||||
itemAdded = value => {
|
||||
mapData = { arrayEntry: value, indexObservable: ko.observable(currentArrayIndex++) };
|
||||
newMappingResult.push(mapData);
|
||||
},
|
||||
|
||||
function itemMovedOrRetained(oldPosition) {
|
||||
mapData = lastMappingResult[oldPosition];
|
||||
// Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray
|
||||
mapData.indexObservable(currentArrayIndex++);
|
||||
ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);
|
||||
newMappingResult.push(mapData);
|
||||
}
|
||||
itemMovedOrRetained = oldPosition => {
|
||||
mapData = lastMappingResult[oldPosition];
|
||||
// Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray
|
||||
mapData.indexObservable(currentArrayIndex++);
|
||||
ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);
|
||||
newMappingResult.push(mapData);
|
||||
},
|
||||
|
||||
function callCallback(callback, items) {
|
||||
if (callback) {
|
||||
for (var i = 0, n = items.length; i < n; i++) {
|
||||
items[i] && items[i].mappedNodes.forEach(node => callback(node, i, items[i].arrayEntry));
|
||||
callCallback = (callback, items) => {
|
||||
if (callback) {
|
||||
for (var i = 0, n = items.length; i < n; i++) {
|
||||
items[i] && items[i].mappedNodes.forEach(node => callback(node, i, items[i].arrayEntry));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isFirstExecution) {
|
||||
array.forEach(itemAdded);
|
||||
} else {
|
||||
if (!editScript || (lastMappingResult && lastMappingResult['_countWaitingForRemove'])) {
|
||||
// Compare the provided array against the previous one
|
||||
var lastArray = Array.prototype.map.call(lastMappingResult, x => x.arrayEntry),
|
||||
compareOptions = {
|
||||
editScript = ko.utils.compareArrays(
|
||||
Array.prototype.map.call(lastMappingResult, x => x.arrayEntry),
|
||||
array,
|
||||
{
|
||||
'dontLimitMoves': options['dontLimitMoves'],
|
||||
'sparse': true
|
||||
};
|
||||
editScript = ko.utils.compareArrays(lastArray, array, compareOptions);
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {
|
||||
let movedIndex, itemIndex;
|
||||
editScript.forEach(editScriptItem => {
|
||||
movedIndex = editScriptItem['moved'];
|
||||
itemIndex = editScriptItem['index'];
|
||||
switch (editScriptItem['status']) {
|
||||
|
|
@ -145,7 +147,7 @@
|
|||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
while (currentArrayIndex < array.length) {
|
||||
itemMovedOrRetained(lastMappingResultIndex++);
|
||||
|
|
@ -162,7 +164,11 @@
|
|||
// Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
|
||||
nodesToDelete.forEach(options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
|
||||
|
||||
var i, j, lastNode, nodeToInsert, mappedNodes, activeElement;
|
||||
var i, lastNode, mappedNodes, activeElement,
|
||||
insertNode = nodeToInsert => {
|
||||
ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);
|
||||
lastNode = nodeToInsert;
|
||||
};
|
||||
|
||||
// Since most browsers remove the focus from an element when it's moved to another location,
|
||||
// save the focused element and try to restore it later.
|
||||
|
|
@ -173,27 +179,24 @@
|
|||
while ((i = itemsToMoveFirstIndexes.shift()) != undefined) {
|
||||
mapData = newMappingResult[i];
|
||||
for (lastNode = undefined; i; ) {
|
||||
if ((mappedNodes = newMappingResult[--i].mappedNodes) && mappedNodes.length) {
|
||||
mappedNodes = newMappingResult[--i].mappedNodes;
|
||||
if (mappedNodes?.length) {
|
||||
lastNode = mappedNodes[mappedNodes.length - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (j = 0; nodeToInsert = mapData.mappedNodes[j]; lastNode = nodeToInsert, j++) {
|
||||
ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);
|
||||
}
|
||||
mapData.mappedNodes.forEach(insertNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
|
||||
for (i = 0; mapData = newMappingResult[i]; i++) {
|
||||
newMappingResult.forEach(mapData => {
|
||||
// Get nodes for newly added items
|
||||
if (!mapData.mappedNodes)
|
||||
ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
|
||||
mapData.mappedNodes
|
||||
|| ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
|
||||
|
||||
// Put nodes in the right place if they aren't there already
|
||||
for (j = 0; nodeToInsert = mapData.mappedNodes[j]; lastNode = nodeToInsert, j++) {
|
||||
ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);
|
||||
}
|
||||
mapData.mappedNodes.forEach(insertNode);
|
||||
|
||||
// Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
|
||||
if (!mapData.initialized && callbackAfterAddingNodes) {
|
||||
|
|
@ -201,11 +204,11 @@
|
|||
mapData.initialized = true;
|
||||
lastNode = mapData.mappedNodes[mapData.mappedNodes.length - 1]; // get the last node again since it may have been changed by a preprocessor
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Restore the focused element if it had lost focus
|
||||
if (activeElement && domNode.ownerDocument.activeElement != activeElement) {
|
||||
activeElement.focus();
|
||||
if (domNode.ownerDocument.activeElement != activeElement) {
|
||||
activeElement?.focus();
|
||||
}
|
||||
|
||||
// If there's a beforeRemove callback, call it after reordering.
|
||||
|
|
@ -218,10 +221,6 @@
|
|||
// Replace the stored values of deleted items with a dummy value. This provides two benefits: it marks this item
|
||||
// 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) {
|
||||
if (itemsForBeforeRemoveCallbacks[i]) {
|
||||
itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue;
|
||||
}
|
||||
}
|
||||
itemsForBeforeRemoveCallbacks.forEach(callback => callback && (callback.arrayEntry = deletedItemDummyValue));
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
// Go through the items that have been added and deleted and try to find matches between them.
|
||||
ko.utils.findMovesInArrayComparison = (left, right, limitFailedCompares) => {
|
||||
if (left.length && right.length) {
|
||||
var failedCompares, l, r, leftItem, rightItem;
|
||||
for (failedCompares = l = 0; (!limitFailedCompares || failedCompares < limitFailedCompares) && (leftItem = left[l]); ++l) {
|
||||
for (r = 0; rightItem = right[r]; ++r) {
|
||||
if (leftItem['value'] === rightItem['value']) {
|
||||
leftItem['moved'] = rightItem['index'];
|
||||
rightItem['moved'] = leftItem['index'];
|
||||
right.splice(r, 1); // This item is marked as moved; so remove it from right list
|
||||
failedCompares = r = 0; // Reset failed compares count because we're checking for consecutive failures
|
||||
break;
|
||||
}
|
||||
}
|
||||
failedCompares += r;
|
||||
var failedCompares = 0, r, l = right.length;
|
||||
l && left.every(leftItem => {
|
||||
r = right.findIndex(rightItem => leftItem['value'] === rightItem['value']);
|
||||
if (r >= 0) {
|
||||
leftItem['moved'] = right[r]['index'];
|
||||
right[r]['moved'] = leftItem['index'];
|
||||
right.splice(r, 1); // This item is marked as moved; so remove it from right list
|
||||
// right[r] = null;
|
||||
failedCompares = r = 0; // Reset failed compares count because we're checking for consecutive failures
|
||||
--l;
|
||||
}
|
||||
}
|
||||
failedCompares += l;
|
||||
return l && (!limitFailedCompares || failedCompares < limitFailedCompares);
|
||||
});
|
||||
};
|
||||
|
||||
ko.utils.compareArrays = (() => {
|
||||
|
|
@ -24,15 +23,15 @@ ko.utils.compareArrays = (() => {
|
|||
var myMin = Math.min,
|
||||
myMax = Math.max,
|
||||
editDistanceMatrix = [],
|
||||
smlIndex, smlIndexMax = smlArray.length,
|
||||
smlIndex = -1, smlIndexMax = smlArray.length,
|
||||
bigIndex, bigIndexMax = bigArray.length,
|
||||
compareRange = (bigIndexMax - smlIndexMax) || 1,
|
||||
maxDistance = smlIndexMax + bigIndexMax + 1,
|
||||
thisRow, lastRow,
|
||||
thisRow, prevRow,
|
||||
bigIndexMaxForRow, bigIndexMinForRow;
|
||||
|
||||
for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
|
||||
lastRow = thisRow;
|
||||
while (++smlIndex <= smlIndexMax) {
|
||||
prevRow = thisRow;
|
||||
editDistanceMatrix.push(thisRow = []);
|
||||
bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
|
||||
bigIndexMinForRow = myMax(0, smlIndex - 1);
|
||||
|
|
@ -42,9 +41,9 @@ ko.utils.compareArrays = (() => {
|
|||
else if (!smlIndex) // Top row - transform empty array into new array via additions
|
||||
thisRow[bigIndex] = bigIndex + 1;
|
||||
else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
|
||||
thisRow[bigIndex] = lastRow[bigIndex - 1]; // copy value (no edit)
|
||||
thisRow[bigIndex] = prevRow[bigIndex - 1]; // copy value (no edit)
|
||||
else {
|
||||
var northDistance = lastRow[bigIndex] || maxDistance; // not in big (deletion)
|
||||
var northDistance = prevRow[bigIndex] || maxDistance; // not in big (deletion)
|
||||
var westDistance = thisRow[bigIndex - 1] || maxDistance; // not in small (addition)
|
||||
thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
|
||||
}
|
||||
|
|
@ -52,7 +51,9 @@ ko.utils.compareArrays = (() => {
|
|||
}
|
||||
|
||||
var editScript = [], meMinusOne, notInSml = [], notInBig = [];
|
||||
for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
|
||||
smlIndex = smlIndexMax;
|
||||
bigIndex = bigIndexMax
|
||||
while (smlIndex || bigIndex) {
|
||||
meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
|
||||
if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
|
||||
notInSml.push(editScript[editScript.length] = { // added
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue