Use JavaScript Optional chaining in vendors/*

This commit is contained in:
the-djmaze 2022-09-12 22:07:51 +02:00
parent e5e4675c1b
commit ef8b1f40e4
28 changed files with 619 additions and 750 deletions

View file

@ -13,10 +13,17 @@
ko.bindingContext = class {
constructor(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, options)
{
var self = this,
shouldInheritData = dataItemOrAccessor === inheritParentVm,
realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor,
isFunc = typeof(realDataItemOrAccessor) == "function" && !ko.isObservable(realDataItemOrAccessor),
subscribable,
dataDependency = options && 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
// any child contexts, must be updated when the view model is changed.
function updateContext() {
updateContext = () => {
// Most of the time, the context will directly get a view model object, but if a function is given,
// we call the function to retrieve the view model. If the function accesses any observables or returns
// an observable, the dependency is tracked, and those observables can later cause the binding
@ -71,14 +78,7 @@
}
return self['$data'];
}
var self = this,
shouldInheritData = dataItemOrAccessor === inheritParentVm,
realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor,
isFunc = typeof(realDataItemOrAccessor) == "function" && !ko.isObservable(realDataItemOrAccessor),
subscribable,
dataDependency = options && options['dataDependency'];
};
if (options && options['exportDependencies']) {
// The "exportDependencies" option means that the calling code will track any dependencies and re-create

View file

@ -16,9 +16,6 @@ ko.bindingHandlers['attr'] = {
namespace ? element.removeAttributeNS(namespace, attrName) : element.removeAttribute(attrName);
} else {
attrValue = attrValue.toString();
}
if (!toRemove) {
namespace ? element.setAttributeNS(namespace, attrName, attrValue) : element.setAttribute(attrName, attrValue);
}

View file

@ -1,16 +1,13 @@
var classesWrittenByBindingKey = '__ko__cssValue',
toggleClasses = (node, classNames, force) => {
if (classNames) {
classNames.split(/\s+/).forEach(className =>
node.classList.toggle(className, force)
);
}
};
toggleClasses = (node, classNames, force) =>
classNames && classNames.split(/\s+/).forEach(className =>
node.classList.toggle(className, force)
);
ko.bindingHandlers['css'] = {
'update': (element, valueAccessor) => {
var value = ko.utils.unwrapObservable(valueAccessor());
if (value !== null && typeof value == "object") {
if (typeof value == "object") {
ko.utils.objectForEach(value, (className, shouldHaveClass) => {
shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);
toggleClasses(element, className, !!shouldHaveClass);

View file

@ -3,7 +3,7 @@ ko.bindingHandlers['enable'] = {
var value = ko.utils.unwrapObservable(valueAccessor());
if (value && element.disabled)
element.removeAttribute("disabled");
else if ((!value) && (!element.disabled))
else if (!value && !element.disabled)
element.disabled = true;
}
};

View file

@ -3,12 +3,9 @@
function makeEventHandlerShortcut(eventName) {
ko.bindingHandlers[eventName] = {
'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var newValueAccessor = () => {
return {
[eventName]: valueAccessor()
};
};
return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);
return ko.bindingHandlers['event']['init'].call(this, element,
() => ({[eventName]: valueAccessor()}), // newValueAccessor
allBindings, viewModel, bindingContext);
}
}
}
@ -18,19 +15,18 @@ ko.bindingHandlers['event'] = {
var eventsToHandle = valueAccessor() || {};
ko.utils.objectForEach(eventsToHandle, eventName => {
if (typeof eventName == "string") {
element.addEventListener(eventName, function (event) {
element.addEventListener(eventName, (...args) => {
var handlerReturnValue;
var handlerFunction = valueAccessor()[eventName];
if (!handlerFunction)
return;
try {
viewModel = bindingContext['$data'];
// Take all the event args, and prefix with the viewmodel
handlerReturnValue = handlerFunction.apply(viewModel, [viewModel, ...arguments]);
} finally {
if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
event.preventDefault();
if (handlerFunction) {
try {
viewModel = bindingContext['$data'];
// Take all the event args, and prefix with the viewmodel
handlerReturnValue = handlerFunction.apply(viewModel, [viewModel, ...args]);
} finally {
if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
args[0].preventDefault();
}
}
}
});

View file

@ -1,4 +1,4 @@
(function () {
(() => {
// Makes a binding like with or if
function makeWithIfBinding(bindingKey, isWith, isNot) {
@ -7,8 +7,7 @@ function makeWithIfBinding(bindingKey, isWith, isNot) {
var savedNodes, contextOptions = {}, needAsyncContext;
if (isWith) {
var as = allBindings.get('as');
contextOptions = { 'as': as, 'exportDependencies': true };
contextOptions = { 'as': allBindings.get('as'), 'exportDependencies': true };
}
needAsyncContext = allBindings['has'](ko.bindingEvent.descendantsComplete);

View file

@ -5,17 +5,15 @@ ko.bindingHandlers['options'] = {
throw new Error("options binding applies only to SELECT elements");
// Remove all existing <option>s.
while (element.length > 0) {
element.remove(0);
let l = element.length;
while (l--) {
element.remove(l);
}
// Ensures that the binding processor doesn't try to bind the options
return { 'controlsDescendantBindings': true };
},
'update': (element, valueAccessor, allBindings) => {
function selectedOptions() {
return Array.from(element.options).filter(node => node.selected);
}
var selectWasPreviouslyEmpty = element.length == 0,
multiple = element.multiple,
@ -25,7 +23,36 @@ ko.bindingHandlers['options'] = {
arrayToDomNodeChildrenOptions = {},
captionValue,
filteredArray,
previousSelectedValues = [];
previousSelectedValues = [],
selectedOptions = () => Array.from(element.options).filter(node => node.selected),
applyToObject = (object, predicate, defaultValue) => {
var predicateType = typeof predicate;
if (predicateType == "function") // Given a function; run it against the data value
return predicate(object);
else if (predicateType == "string") // Given a string; treat it as a property name on the data value
return object[predicate];
// Given no optionsText arg; use the data value itself
return defaultValue;
},
setSelectionCallback = (arrayEntry, newOptions) => {
if (itemUpdate && valueAllowUnset) {
// The model value is authoritative, so make sure its value is the one selected
ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);
} else if (previousSelectedValues.length) {
// IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
// That's why we first added them without selection. Now it's time to set the selection.
var isSelected = previousSelectedValues.includes(ko.selectExtensions.readValue(newOptions[0]));
newOptions[0].selected = isSelected;
// If this option was changed from being selected during a single-item update, notify the change
if (itemUpdate && !isSelected) {
ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
}
}
};
if (!valueAllowUnset) {
if (multiple) {
@ -54,22 +81,12 @@ ko.bindingHandlers['options'] = {
// If a falsy value is provided (e.g. null), we'll simply empty the select element
}
function applyToObject(object, predicate, defaultValue) {
var predicateType = typeof predicate;
if (predicateType == "function") // Given a function; run it against the data value
return predicate(object);
else if (predicateType == "string") // Given a string; treat it as a property name on the data value
return object[predicate];
else // Given no optionsText arg; use the data value itself
return defaultValue;
}
// The following functions can run at two different times:
// The first is when the whole array is being updated directly from this binding handler.
// The second is when an observable value for a specific array entry is updated.
// oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.
var itemUpdate = false;
function optionForArrayItem(arrayEntry, index, oldOptions) {
var itemUpdate = false,
optionForArrayItem = (arrayEntry, index, oldOptions) => {
if (oldOptions.length) {
previousSelectedValues = !valueAllowUnset && oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];
itemUpdate = true;
@ -88,29 +105,12 @@ ko.bindingHandlers['options'] = {
ko.utils.setTextContent(option, optionText);
}
return [option];
}
};
// By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection
// problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208
arrayToDomNodeChildrenOptions['beforeRemove'] = option => element.removeChild(option);
function setSelectionCallback(arrayEntry, newOptions) {
if (itemUpdate && valueAllowUnset) {
// The model value is authoritative, so make sure its value is the one selected
ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);
} else if (previousSelectedValues.length) {
// IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
// That's why we first added them without selection. Now it's time to set the selection.
var isSelected = previousSelectedValues.includes(ko.selectExtensions.readValue(newOptions[0]));
newOptions[0].selected = isSelected;
// If this option was changed from being selected during a single-item update, notify the change
if (itemUpdate && !isSelected) {
ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
}
}
}
var callback = setSelectionCallback;
if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') == "function") {
callback = (arrayEntry, newOptions) => {
@ -123,25 +123,23 @@ ko.bindingHandlers['options'] = {
if (!valueAllowUnset) {
// Determine if the selection has changed as a result of updating the options list
var selectionChanged;
var selectionChanged, prevLength = previousSelectedValues.length;
if (multiple) {
// For a multiple-select box, compare the new selection count to the previous one
// But if nothing was selected before, the selection can't have changed
selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;
selectionChanged = prevLength && selectedOptions().length < prevLength;
} else {
// For a single-select box, compare the current value to the previous value
// But if nothing was selected before or nothing is selected now, just look for a change in selection
selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)
selectionChanged = (prevLength && element.selectedIndex >= 0)
? (ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])
: (previousSelectedValues.length || element.selectedIndex >= 0);
: (prevLength || element.selectedIndex >= 0);
}
// Ensure consistency between model value and selected option.
// If the dropdown was changed so that selection is no longer the same,
// notify the value or selectedOptions binding.
if (selectionChanged) {
ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
}
selectionChanged && ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
}
if (valueAllowUnset || ko.dependencyDetection.isInitial()) {

View file

@ -8,10 +8,7 @@ ko.bindingHandlers['submit'] = {
try { handlerReturnValue = value.call(bindingContext['$data'], element); }
finally {
if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
if (event.preventDefault)
event.preventDefault();
else
event.returnValue = false;
event.preventDefault();
}
}
});

View file

@ -18,23 +18,9 @@ ko.utils.findMovesInArrayComparison = (left, right, limitFailedCompares) => {
};
ko.utils.compareArrays = (() => {
var statusNotInOld = 'added', statusNotInNew = 'deleted';
var statusNotInOld = 'added', statusNotInNew = 'deleted',
// Simple calculation based on Levenshtein distance.
function compareArrays(oldArray, newArray, options) {
// For backward compatibility, if the third arg is actually a bool, interpret
// it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.
options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});
oldArray = oldArray || [];
newArray = newArray || [];
if (oldArray.length < newArray.length)
return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options);
else
return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);
}
function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, options) {
compareSmallArrayToBigArray = (smlArray, bigArray, statusNotInSml, statusNotInBig, options) => {
var myMin = Math.min,
myMax = Math.max,
editDistanceMatrix = [],
@ -94,7 +80,18 @@ ko.utils.compareArrays = (() => {
ko.utils.findMovesInArrayComparison(notInBig, notInSml, !options['dontLimitMoves'] && smlIndexMax * 10);
return editScript.reverse();
}
};
return compareArrays;
// Simple calculation based on Levenshtein distance.
return (oldArray, newArray, options) => {
// For backward compatibility, if the third arg is actually a bool, interpret
// it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.
options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});
oldArray = oldArray || [];
newArray = newArray || [];
return (oldArray.length < newArray.length)
? compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options)
: compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);
};
})();