mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-03 22:47:03 +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
|
|
@ -18,7 +18,7 @@
|
|||
realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor,
|
||||
isFunc = typeof(realDataItemOrAccessor) == "function" && !ko.isObservable(realDataItemOrAccessor),
|
||||
subscribable,
|
||||
dataDependency = options && options['dataDependency'],
|
||||
dataDependency = options?.['dataDependency'],
|
||||
|
||||
// The binding context object includes static properties for the current, parent, and root view models.
|
||||
// If a view model is actually stored in an observable, the corresponding binding context object, and
|
||||
|
|
@ -64,12 +64,11 @@
|
|||
// The extendCallback function is provided when creating a child context or extending a context.
|
||||
// It handles the specific actions needed to finish setting up the binding context. Actions in this
|
||||
// function could also add dependencies to this binding context.
|
||||
if (extendCallback)
|
||||
extendCallback(self, parentContext, dataItem);
|
||||
extendCallback?.(self, parentContext, dataItem);
|
||||
|
||||
// When a "parent" context is given and we don't already have a dependency on its context, register a dependency on it.
|
||||
// Thus whenever the parent context is updated, this context will also be updated.
|
||||
if (parentContext && parentContext[contextSubscribable] && !ko.dependencyDetection.computed().hasAncestorDependency(parentContext[contextSubscribable])) {
|
||||
if (parentContext?.[contextSubscribable] && !ko.dependencyDetection.computed().hasAncestorDependency(parentContext[contextSubscribable])) {
|
||||
parentContext[contextSubscribable]();
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +79,7 @@
|
|||
return self['$data'];
|
||||
};
|
||||
|
||||
if (options && options['exportDependencies']) {
|
||||
if (options?.['exportDependencies']) {
|
||||
// The "exportDependencies" option means that the calling code will track any dependencies and re-create
|
||||
// the binding context when they change.
|
||||
updateContext();
|
||||
|
|
@ -138,7 +137,7 @@
|
|||
|
||||
function asyncContextDispose(node) {
|
||||
var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey),
|
||||
asyncContext = bindingInfo && bindingInfo.asyncContext;
|
||||
asyncContext = bindingInfo?.asyncContext;
|
||||
if (asyncContext) {
|
||||
bindingInfo.asyncContext = null;
|
||||
asyncContext.notifyAncestor();
|
||||
|
|
@ -152,25 +151,19 @@
|
|||
this.asyncDescendants = new Set;
|
||||
this.childrenComplete = false;
|
||||
|
||||
if (!bindingInfo.asyncContext) {
|
||||
ko.utils.domNodeDisposal.addDisposeCallback(node, asyncContextDispose);
|
||||
}
|
||||
bindingInfo.asyncContext || ko.utils.domNodeDisposal.addDisposeCallback(node, asyncContextDispose);
|
||||
|
||||
if (ancestorBindingInfo && ancestorBindingInfo.asyncContext) {
|
||||
if (ancestorBindingInfo?.asyncContext) {
|
||||
ancestorBindingInfo.asyncContext.asyncDescendants.add(node);
|
||||
this.ancestorBindingInfo = ancestorBindingInfo;
|
||||
}
|
||||
}
|
||||
notifyAncestor() {
|
||||
if (this.ancestorBindingInfo && this.ancestorBindingInfo.asyncContext) {
|
||||
this.ancestorBindingInfo.asyncContext.descendantComplete(this.node);
|
||||
}
|
||||
this.ancestorBindingInfo?.asyncContext?.descendantComplete(this.node);
|
||||
}
|
||||
descendantComplete(node) {
|
||||
this.asyncDescendants.delete(node);
|
||||
if (!this.asyncDescendants.size && this.childrenComplete) {
|
||||
this.completeChildren();
|
||||
}
|
||||
this.asyncDescendants.size || this.completeChildren?.();
|
||||
}
|
||||
completeChildren() {
|
||||
this.childrenComplete = true;
|
||||
|
|
@ -192,7 +185,7 @@
|
|||
if (!bindingInfo.eventSubscribable) {
|
||||
bindingInfo.eventSubscribable = new ko.subscribable;
|
||||
}
|
||||
if (options && options['notifyImmediately'] && bindingInfo.notifiedEvents[event]) {
|
||||
if (options?.['notifyImmediately'] && bindingInfo.notifiedEvents[event]) {
|
||||
ko.dependencyDetection.ignore(callback, context, [node]);
|
||||
}
|
||||
return bindingInfo.eventSubscribable.subscribe(callback, context, event);
|
||||
|
|
@ -202,13 +195,11 @@
|
|||
var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);
|
||||
if (bindingInfo) {
|
||||
bindingInfo.notifiedEvents[event] = true;
|
||||
if (bindingInfo.eventSubscribable) {
|
||||
bindingInfo.eventSubscribable.notifySubscribers(node, event);
|
||||
}
|
||||
bindingInfo.eventSubscribable?.notifySubscribers(node, event);
|
||||
if (event == ko.bindingEvent.childrenComplete) {
|
||||
if (bindingInfo.asyncContext) {
|
||||
bindingInfo.asyncContext.completeChildren();
|
||||
} else if (bindingInfo.asyncContext === undefined && bindingInfo.eventSubscribable && bindingInfo.eventSubscribable.hasSubscriptionsForEvent(ko.bindingEvent.descendantsComplete)) {
|
||||
} else if (bindingInfo.asyncContext === undefined && bindingInfo.eventSubscribable?.hasSubscriptionsForEvent(ko.bindingEvent.descendantsComplete)) {
|
||||
// It's currently an error to register a descendantsComplete handler for a node that was never registered as completing asynchronously.
|
||||
// That's because without the asyncContext, we don't have a way to know that all descendants have completed.
|
||||
throw new Error("descendantsComplete event not supported for bindings on this node");
|
||||
|
|
@ -260,8 +251,7 @@
|
|||
// Perf optimisation: Apply bindings only if...
|
||||
// (1) We need to store the binding info for the node (all element nodes)
|
||||
// (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
|
||||
var shouldApplyBindings = isElement || ko.bindingProvider.nodeHasBindings(nodeVerified);
|
||||
if (shouldApplyBindings)
|
||||
if (isElement || ko.bindingProvider.nodeHasBindings(nodeVerified))
|
||||
bindingContextForDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext)['bindingContextForDescendants'];
|
||||
|
||||
// Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,
|
||||
|
|
@ -269,7 +259,7 @@
|
|||
// Also bindings should not operate on <template> elements since this breaks in Internet Explorer
|
||||
// and because such elements' contents are always intended to be bound in a different context
|
||||
// from where they appear in the document.
|
||||
if (bindingContextForDescendants && nodeVerified.matches && !nodeVerified.matches('SCRIPT,TEXTAREA,TEMPLATE')) {
|
||||
if (bindingContextForDescendants && !nodeVerified.matches?.('SCRIPT,TEXTAREA,TEMPLATE')) {
|
||||
applyBindingsToDescendantsInternal(bindingContextForDescendants, nodeVerified);
|
||||
}
|
||||
}
|
||||
|
|
@ -336,12 +326,8 @@
|
|||
bindings = sourceBindings ? sourceBindings(bindingContext, node) : ko.bindingProvider.getBindingAccessors(node, bindingContext);
|
||||
// Register a dependency on the binding context to support observable view models.
|
||||
if (bindings) {
|
||||
if (bindingContext[contextSubscribable]) {
|
||||
bindingContext[contextSubscribable]();
|
||||
}
|
||||
if (bindingContext[contextDataDependency]) {
|
||||
bindingContext[contextDataDependency]();
|
||||
}
|
||||
bindingContext[contextSubscribable]?.();
|
||||
bindingContext[contextDataDependency]?.();
|
||||
}
|
||||
return bindings;
|
||||
},
|
||||
|
|
@ -374,9 +360,7 @@
|
|||
var callback = bindings[ko.bindingEvent.childrenComplete]();
|
||||
if (callback) {
|
||||
var nodes = ko.virtualElements.childNodes(node);
|
||||
if (nodes.length) {
|
||||
callback(nodes, ko.dataFor(nodes[0]));
|
||||
}
|
||||
nodes.length && callback(nodes, ko.dataFor(nodes[0]));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -176,9 +176,7 @@ ko.expressionRewriting = (() => {
|
|||
// it is !== existing value on that writable observable
|
||||
writeValueToProperty: (property, allBindings, key, value, checkIfDifferent) => {
|
||||
if (!property || !ko.isObservable(property)) {
|
||||
var propWriters = allBindings.get('_ko_property_writers');
|
||||
if (propWriters && propWriters[key])
|
||||
propWriters[key](value);
|
||||
allBindings.get('_ko_property_writers')?.[key]?.(value);
|
||||
} else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
|
||||
property(value);
|
||||
}
|
||||
|
|
|
|||
15
vendors/knockout/src/binding/selectExtensions.js
vendored
15
vendors/knockout/src/binding/selectExtensions.js
vendored
|
|
@ -8,11 +8,13 @@
|
|||
readValue : element => {
|
||||
switch (element.nodeName) {
|
||||
case 'OPTION':
|
||||
if (element[hasDomDataExpandoProperty] === true)
|
||||
return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
|
||||
return element.value;
|
||||
return (element[hasDomDataExpandoProperty] === true)
|
||||
? ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey)
|
||||
: element.value;
|
||||
case 'SELECT':
|
||||
return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
|
||||
return element.selectedIndex >= 0
|
||||
? ko.selectExtensions.readValue(element.options[element.selectedIndex])
|
||||
: undefined;
|
||||
default:
|
||||
return element.value;
|
||||
}
|
||||
|
|
@ -37,8 +39,9 @@
|
|||
break;
|
||||
case 'SELECT':
|
||||
// A blank string or null value will select the caption
|
||||
var selection = -1, noValue = ("" === value || null == value);
|
||||
for (var i = 0, n = element.options.length, optionValue; i < n; ++i) {
|
||||
var selection = -1, noValue = ("" === value || null == value),
|
||||
i = element.options.length, optionValue;
|
||||
while (i--) {
|
||||
optionValue = ko.selectExtensions.readValue(element.options[i]);
|
||||
// Include special check to handle selecting a caption with a blank string value
|
||||
if (optionValue == value || (optionValue === "" && noValue)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue