KnockoutJS to ES2015/ES6

TODO: use the new Proxy for ko.observable
This commit is contained in:
djmaze 2020-10-04 21:58:13 +02:00
parent a0f8ac0dad
commit 72ed2b08b2
56 changed files with 941 additions and 1873 deletions

View file

@ -1,6 +1,6 @@
var attrHtmlToJavaScriptMap = { 'class': 'className', 'for': 'htmlFor' };
ko.bindingHandlers['attr'] = {
'update': function(element, valueAccessor, allBindings) {
'update': (element, valueAccessor, allBindings) => {
var value = ko.utils.unwrapObservable(valueAccessor()) || {};
ko.utils.objectForEach(value, function(attrName, attrValue) {
attrValue = ko.utils.unwrapObservable(attrValue);

View file

@ -1,137 +0,0 @@
(function() {
function addOrRemoveItem(array, value, included) {
var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.peekObservable(array), value);
if (existingEntryIndex < 0) {
if (included)
array.push(value);
} else {
if (!included)
array.splice(existingEntryIndex, 1);
}
}
ko.bindingHandlers['checked'] = {
'after': ['value', 'attr'],
'init': function (element, valueAccessor, allBindings) {
var checkedValue = ko.pureComputed(function() {
// Treat "value" like "checkedValue" when it is included with "checked" binding
if (allBindings['has']('checkedValue')) {
return ko.utils.unwrapObservable(allBindings.get('checkedValue'));
} else if (useElementValue) {
if (allBindings['has']('value')) {
return ko.utils.unwrapObservable(allBindings.get('value'));
} else {
return element.value;
}
}
});
function updateModel() {
// This updates the model value from the view value.
// It runs in response to DOM events (click) and changes in checkedValue.
var isChecked = element.checked,
elemValue = checkedValue();
// When we're first setting up this computed, don't change any model state.
if (ko.computedContext.isInitial()) {
return;
}
// We can ignore unchecked radio buttons, because some other radio
// button will be checked, and that one can take care of updating state.
// Also ignore value changes to an already unchecked checkbox.
if (!isChecked && (isRadio || ko.computedContext.getDependenciesCount())) {
return;
}
var modelValue = ko.dependencyDetection.ignore(valueAccessor);
if (valueIsArray) {
var writableValue = rawValueIsNonArrayObservable ? modelValue.peek() : modelValue,
saveOldValue = oldElemValue;
oldElemValue = elemValue;
if (saveOldValue !== elemValue) {
// When we're responding to the checkedValue changing, and the element is
// currently checked, replace the old elem value with the new elem value
// in the model array.
if (isChecked) {
addOrRemoveItem(writableValue, elemValue, true);
addOrRemoveItem(writableValue, saveOldValue, false);
}
} else {
// When we're responding to the user having checked/unchecked a checkbox,
// add/remove the element value to the model array.
addOrRemoveItem(writableValue, elemValue, isChecked);
}
if (rawValueIsNonArrayObservable && ko.isWriteableObservable(modelValue)) {
modelValue(writableValue);
}
} else {
if (isCheckbox) {
if (elemValue === undefined) {
elemValue = isChecked;
} else if (!isChecked) {
elemValue = undefined;
}
}
ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);
}
};
function updateView() {
// This updates the view value from the model value.
// It runs in response to changes in the bound (checked) value.
var modelValue = ko.utils.unwrapObservable(valueAccessor()),
elemValue = checkedValue();
if (valueIsArray) {
// When a checkbox is bound to an array, being checked represents its value being present in that array
element.checked = ko.utils.arrayIndexOf(modelValue, elemValue) >= 0;
oldElemValue = elemValue;
} else if (isCheckbox && elemValue === undefined) {
// When a checkbox is bound to any other value (not an array) and "checkedValue" is not defined,
// being checked represents the value being trueish
element.checked = !!modelValue;
} else {
// Otherwise, being checked means that the checkbox or radio button's value corresponds to the model value
element.checked = (checkedValue() === modelValue);
}
};
var isCheckbox = element.type == "checkbox",
isRadio = element.type == "radio";
// Only bind to check boxes and radio buttons
if (!isCheckbox && !isRadio) {
return;
}
var rawValue = valueAccessor(),
valueIsArray = isCheckbox && (ko.utils.unwrapObservable(rawValue) instanceof Array),
rawValueIsNonArrayObservable = !(valueIsArray && rawValue.push && rawValue.splice),
useElementValue = isRadio || valueIsArray,
oldElemValue = valueIsArray ? checkedValue() : undefined;
// Set up two computeds to update the binding:
// The first responds to changes in the checkedValue value and to element clicks
ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element });
ko.utils.registerEventHandler(element, "click", updateModel);
// The second responds to changes in the model value (the one associated with the checked binding)
ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });
rawValue = undefined;
}
};
ko.expressionRewriting.twoWayBindings['checked'] = true;
ko.bindingHandlers['checkedValue'] = {
'update': function (element, valueAccessor) {
element.value = ko.utils.unwrapObservable(valueAccessor());
}
};
})();

View file

@ -1,7 +1,7 @@
var classesWrittenByBindingKey = '__ko__cssValue';
ko.bindingHandlers['class'] = {
'update': function (element, valueAccessor) {
'update': (element, valueAccessor) => {
var value = ko.utils.stringTrim(ko.utils.unwrapObservable(valueAccessor()));
ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
element[classesWrittenByBindingKey] = value;
@ -10,10 +10,10 @@ ko.bindingHandlers['class'] = {
};
ko.bindingHandlers['css'] = {
'update': function (element, valueAccessor) {
'update': (element, valueAccessor) => {
var value = ko.utils.unwrapObservable(valueAccessor());
if (value !== null && typeof value == "object") {
ko.utils.objectForEach(value, function(className, shouldHaveClass) {
ko.utils.objectForEach(value, (className, shouldHaveClass) => {
shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);
ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
});

View file

@ -1,5 +1,5 @@
ko.bindingHandlers['enable'] = {
'update': function (element, valueAccessor) {
'update': (element, valueAccessor) => {
var value = ko.utils.unwrapObservable(valueAccessor());
if (value && element.disabled)
element.removeAttribute("disabled");
@ -9,7 +9,6 @@ ko.bindingHandlers['enable'] = {
};
ko.bindingHandlers['disable'] = {
'update': function (element, valueAccessor) {
ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
}
'update': (element, valueAccessor) =>
ko.bindingHandlers['enable']['update'](element, () => !ko.utils.unwrapObservable(valueAccessor()))
};

View file

@ -3,7 +3,7 @@
function makeEventHandlerShortcut(eventName) {
ko.bindingHandlers[eventName] = {
'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var newValueAccessor = function () {
var newValueAccessor = () => {
var result = {};
result[eventName] = valueAccessor();
return result;
@ -14,9 +14,9 @@ function makeEventHandlerShortcut(eventName) {
}
ko.bindingHandlers['event'] = {
'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) {
'init' : (element, valueAccessor, allBindings, viewModel, bindingContext) => {
var eventsToHandle = valueAccessor() || {};
ko.utils.objectForEach(eventsToHandle, function(eventName) {
ko.utils.objectForEach(eventsToHandle, eventName => {
if (typeof eventName == "string") {
ko.utils.registerEventHandler(element, eventName, function (event) {
var handlerReturnValue;

View file

@ -1,8 +1,8 @@
// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
ko.bindingHandlers['foreach'] = {
makeTemplateValueAccessor: function(valueAccessor) {
return function() {
makeTemplateValueAccessor: valueAccessor => {
return () => {
var modelValue = valueAccessor(),
unwrappedValue = ko.utils.peekObservable(modelValue); // Unwrap without setting a dependency here
@ -28,12 +28,11 @@ ko.bindingHandlers['foreach'] = {
};
};
},
'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
},
'update': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext);
}
'init': (element, valueAccessor) =>
ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor))
,
'update': (element, valueAccessor, allBindings, viewModel, bindingContext) =>
ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext)
};
ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
ko.virtualElements.allowedBindings['foreach'] = true;

View file

@ -1,8 +1,8 @@
var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
var hasfocusLastValue = '__ko_hasfocusLastValue';
ko.bindingHandlers['hasfocus'] = {
'init': function(element, valueAccessor, allBindings) {
var handleElementFocusChange = function(isFocused) {
'init': (element, valueAccessor, allBindings) => {
var handleElementFocusChange = isFocused => {
// Where possible, ignore which event was raised and determine focus state using activeElement,
// as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
// However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
@ -29,7 +29,7 @@ ko.bindingHandlers['hasfocus'] = {
// Assume element is not focused (prevents "blur" being called initially)
element[hasfocusLastValue] = false;
},
'update': function(element, valueAccessor) {
'update': (element, valueAccessor) => {
var value = !!ko.utils.unwrapObservable(valueAccessor());
if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {

View file

@ -1,10 +1,9 @@
ko.bindingHandlers['html'] = {
'init': function() {
'init': () => {
// Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
return { 'controlsDescendantBindings': true };
},
'update': function (element, valueAccessor) {
'update': (element, valueAccessor) =>
// setHtml will unwrap the value if needed
ko.utils.setHtml(element, valueAccessor());
}
ko.utils.setHtml(element, valueAccessor())
};

View file

@ -1,81 +0,0 @@
(function () {
// Makes a binding like with or if
function makeWithIfBinding(bindingKey, isWith, isNot) {
ko.bindingHandlers[bindingKey] = {
'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var didDisplayOnLastUpdate, savedNodes, contextOptions = {}, completeOnRender, needAsyncContext, renderOnEveryChange;
if (isWith) {
var as = allBindings.get('as'), noChildContext = allBindings.get('noChildContext');
renderOnEveryChange = !(as && noChildContext);
contextOptions = { 'as': as, 'noChildContext': noChildContext, 'exportDependencies': renderOnEveryChange };
}
completeOnRender = allBindings.get("completeOn") == "render";
needAsyncContext = completeOnRender || allBindings['has'](ko.bindingEvent.descendantsComplete);
ko.computed(function() {
var value = ko.utils.unwrapObservable(valueAccessor()),
shouldDisplay = !isNot !== !value, // equivalent to isNot ? !value : !!value,
isInitial = !savedNodes,
childContext;
if (!renderOnEveryChange && shouldDisplay === didDisplayOnLastUpdate) {
return;
}
if (needAsyncContext) {
bindingContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);
}
if (shouldDisplay) {
if (!isWith || renderOnEveryChange) {
contextOptions['dataDependency'] = ko.computedContext.computed();
}
if (isWith) {
childContext = bindingContext['createChildContext'](typeof value == "function" ? value : valueAccessor, contextOptions);
} else if (ko.computedContext.getDependenciesCount()) {
childContext = bindingContext['extend'](null, contextOptions);
} else {
childContext = bindingContext;
}
}
// Save a copy of the inner nodes on the initial update, but only if we have dependencies.
if (isInitial && ko.computedContext.getDependenciesCount()) {
savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
}
if (shouldDisplay) {
if (!isInitial) {
ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));
}
ko.applyBindingsToDescendants(childContext, element);
} else {
ko.virtualElements.emptyNode(element);
if (!completeOnRender) {
ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);
}
}
didDisplayOnLastUpdate = shouldDisplay;
}, null, { disposeWhenNodeIsRemoved: element });
return { 'controlsDescendantBindings': true };
}
};
ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
ko.virtualElements.allowedBindings[bindingKey] = true;
}
// Construct the actual binding handlers
makeWithIfBinding('if');
makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
makeWithIfBinding('with', true /* isWith */);
})();

View file

@ -1,10 +0,0 @@
ko.bindingHandlers['let'] = {
'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// Make a modified binding context, with extra properties, and apply it to descendant elements
var innerContext = bindingContext['extend'](valueAccessor);
ko.applyBindingsToDescendants(innerContext, element);
return { 'controlsDescendantBindings': true };
}
};
ko.virtualElements.allowedBindings['let'] = true;

View file

@ -1,6 +1,6 @@
var captionPlaceholder = {};
ko.bindingHandlers['options'] = {
'init': function(element) {
'init': element => {
if (ko.utils.tagNameLower(element) !== "select")
throw new Error("options binding applies only to SELECT elements");
@ -12,9 +12,9 @@ ko.bindingHandlers['options'] = {
// Ensures that the binding processor doesn't try to bind the options
return { 'controlsDescendantBindings': true };
},
'update': function (element, valueAccessor, allBindings) {
'update': (element, valueAccessor, allBindings) => {
function selectedOptions() {
return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });
return ko.utils.arrayFilter(element.options, node => node.selected);
}
var selectWasPreviouslyEmpty = element.length == 0,
@ -41,9 +41,9 @@ ko.bindingHandlers['options'] = {
unwrappedArray = [unwrappedArray];
// Filter out any entries marked as destroyed
filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
});
filteredArray = ko.utils.arrayFilter(unwrappedArray, item =>
includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy'])
);
// If caption is included, add it to the array
if (allBindings['has']('optionsCaption')) {
@ -95,10 +95,7 @@ ko.bindingHandlers['options'] = {
// 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'] =
function (option) {
element.removeChild(option);
};
arrayToDomNodeChildrenOptions['beforeRemove'] = option => element.removeChild(option);
function setSelectionCallback(arrayEntry, newOptions) {
if (itemUpdate && valueAllowUnset) {
@ -119,7 +116,7 @@ ko.bindingHandlers['options'] = {
var callback = setSelectionCallback;
if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') == "function") {
callback = function(arrayEntry, newOptions) {
callback = (arrayEntry, newOptions) => {
setSelectionCallback(arrayEntry, newOptions);
ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);
}

View file

@ -1,41 +0,0 @@
ko.bindingHandlers['selectedOptions'] = {
'init': function (element, valueAccessor, allBindings) {
function updateFromView() {
var value = valueAccessor(), valueToWrite = [];
ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
if (node.selected)
valueToWrite.push(ko.selectExtensions.readValue(node));
});
ko.expressionRewriting.writeValueToProperty(value, allBindings, 'selectedOptions', valueToWrite);
}
function updateFromModel() {
var newValue = ko.utils.unwrapObservable(valueAccessor()),
previousScrollTop = element.scrollTop;
if (newValue && typeof newValue.length == "number") {
ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
node.selected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
});
}
element.scrollTop = previousScrollTop;
}
if (ko.utils.tagNameLower(element) != "select") {
throw new Error("selectedOptions binding applies only to SELECT elements");
}
var updateFromModelComputed;
ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, function () {
if (!updateFromModelComputed) {
ko.utils.registerEventHandler(element, "change", updateFromView);
updateFromModelComputed = ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });
} else {
updateFromView();
}
}, null, { 'notifyImmediately': true });
},
'update': function() {} // Keep for backwards compatibility with code that may have wrapped binding
};
ko.expressionRewriting.twoWayBindings['selectedOptions'] = true;

View file

@ -1,7 +1,7 @@
ko.bindingHandlers['style'] = {
'update': function (element, valueAccessor) {
'update': (element, valueAccessor) => {
var value = ko.utils.unwrapObservable(valueAccessor() || {});
ko.utils.objectForEach(value, function(styleName, styleValue) {
ko.utils.objectForEach(value, (styleName, styleValue) => {
styleValue = ko.utils.unwrapObservable(styleValue);
if (styleValue === null || styleValue === undefined || styleValue === false) {
@ -13,9 +13,7 @@ ko.bindingHandlers['style'] = {
// Is styleName a custom CSS property?
element.style.setProperty(styleName, styleValue);
} else {
styleName = styleName.replace(/-(\w)/g, function (all, letter) {
return letter.toUpperCase();
});
styleName = styleName.replace(/-(\w)/g, (all, letter) => letter.toUpperCase());
var previousStyle = element.style[styleName];
element.style[styleName] = styleValue;

View file

@ -1,8 +1,8 @@
ko.bindingHandlers['submit'] = {
'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
'init': (element, valueAccessor, allBindings, viewModel, bindingContext) => {
if (typeof valueAccessor() != "function")
throw new Error("The value for a submit binding must be a function");
ko.utils.registerEventHandler(element, "submit", function (event) {
ko.utils.registerEventHandler(element, "submit", event => {
var handlerReturnValue;
var value = valueAccessor();
try { handlerReturnValue = value.call(bindingContext['$data'], element); }

View file

@ -1,11 +1,10 @@
ko.bindingHandlers['text'] = {
'init': function() {
'init': () => {
// Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).
// It should also make things faster, as we no longer have to consider whether the text node might be bindable.
return { 'controlsDescendantBindings': true };
},
'update': function (element, valueAccessor) {
ko.utils.setTextContent(element, valueAccessor());
}
'update': (element, valueAccessor) =>
ko.utils.setTextContent(element, valueAccessor())
};
ko.virtualElements.allowedBindings['text'] = true;

View file

@ -1,13 +1,11 @@
(function () {
ko.bindingHandlers['textInput'] = {
'init': function (element, valueAccessor, allBindings) {
'init': (element, valueAccessor, allBindings) => {
var previousElementValue = element.value,
timeoutHandle,
elementValueBeforeEvent;
var updateModel = function (event) {
var updateModel = event => {
clearTimeout(timeoutHandle);
elementValueBeforeEvent = timeoutHandle = undefined;
@ -20,7 +18,7 @@ ko.bindingHandlers['textInput'] = {
}
};
var deferUpdateModel = function (event) {
var deferUpdateModel = event => {
if (!timeoutHandle) {
// The elementValueBeforeEvent variable is set *only* during the brief gap between an
// event firing and the updateModel function running. This allows us to ignore model
@ -32,11 +30,7 @@ ko.bindingHandlers['textInput'] = {
}
};
// IE9 will mess up the DOM if you handle events synchronously which results in DOM changes (such as other bindings);
// so we'll make sure all updates are asynchronous
var ourUpdate = false;
var updateView = function () {
var updateView = () => {
var modelValue = ko.utils.unwrapObservable(valueAccessor());
if (modelValue === null || modelValue === undefined) {
@ -51,20 +45,17 @@ ko.bindingHandlers['textInput'] = {
// Update the element only if the element and model are different. On some browsers, updating the value
// will move the cursor to the end of the input, which would be bad while the user is typing.
if (element.value !== modelValue) {
ourUpdate = true; // Make sure we ignore events (propertychange) that result from updating the value
element.value = modelValue;
ourUpdate = false;
previousElementValue = element.value; // In case the browser changes the value (see #2281)
}
};
var onEvent = function (event, handler) {
var onEvent = (event, handler) =>
ko.utils.registerEventHandler(element, event, handler);
};
if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {
// Provide a way for tests to specify exactly which events are bound
ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], function(eventName) {
ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], eventName => {
if (eventName.slice(0,5) == 'after') {
onEvent(eventName.slice(5), deferUpdateModel);
} else {
@ -89,9 +80,5 @@ ko.expressionRewriting.twoWayBindings['textInput'] = true;
// textinput is an alias for textInput
ko.bindingHandlers['textinput'] = {
// preprocess is the only way to set up a full alias
'preprocess': function (value, name, addBinding) {
addBinding('textInput', value);
}
'preprocess': (value, name, addBinding) => addBinding('textInput', value)
};
})();

View file

@ -1,8 +0,0 @@
ko.bindingHandlers['uniqueName'] = {
'init': function (element, valueAccessor) {
if (valueAccessor()) {
element.name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
}
}
};
ko.bindingHandlers['uniqueName'].currentIndex = 0;

View file

@ -1,15 +0,0 @@
ko.bindingHandlers['using'] = {
'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var options;
if (allBindings['has']('as')) {
options = { 'as': allBindings.get('as'), 'noChildContext': allBindings.get('noChildContext') };
}
var innerContext = bindingContext['createChildContext'](valueAccessor, options);
ko.applyBindingsToDescendants(innerContext, element);
return { 'controlsDescendantBindings': true };
}
};
ko.virtualElements.allowedBindings['using'] = true;

View file

@ -1,5 +1,5 @@
ko.bindingHandlers['value'] = {
'init': function (element, valueAccessor, allBindings) {
'init': (element, valueAccessor, allBindings) => {
var tagName = ko.utils.tagNameLower(element),
isInputElement = tagName == "input";
@ -18,27 +18,27 @@ ko.bindingHandlers['value'] = {
if (typeof requestedEventsToCatch == "string") {
eventsToCatch = [requestedEventsToCatch];
} else {
eventsToCatch = requestedEventsToCatch ? requestedEventsToCatch.filter(function(item, index) {
return requestedEventsToCatch.indexOf(item) === index;
}) : [];
eventsToCatch = requestedEventsToCatch ? requestedEventsToCatch.filter((item, index) =>
requestedEventsToCatch.indexOf(item) === index
) : [];
}
ko.utils.arrayRemoveItem(eventsToCatch, "change"); // We'll subscribe to "change" events later
}
var valueUpdateHandler = function() {
var valueUpdateHandler = () => {
elementValueBeforeEvent = null;
var modelValue = valueAccessor();
var elementValue = ko.selectExtensions.readValue(element);
ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'value', elementValue);
}
ko.utils.arrayForEach(eventsToCatch, function(eventName) {
ko.utils.arrayForEach(eventsToCatch, eventName => {
// The syntax "after<eventname>" means "run the handler asynchronously after the event"
// This is useful, for example, to catch "keydown" events after the browser has updated the control
// (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
var handler = valueUpdateHandler;
if (ko.utils.stringStartsWith(eventName, "after")) {
handler = function() {
handler = () => {
// The elementValueBeforeEvent variable is non-null *only* during the brief gap between
// a keyX event firing and the valueUpdateHandler running, which is scheduled to happen
// at the earliest asynchronous opportunity. We store this temporary information so that
@ -58,7 +58,7 @@ ko.bindingHandlers['value'] = {
if (isInputElement && element.type == "file") {
// For file input elements, can only write the empty string
updateFromModel = function () {
updateFromModel = () => {
var newValue = ko.utils.unwrapObservable(valueAccessor());
if (newValue === null || newValue === undefined || newValue === "") {
element.value = "";
@ -67,7 +67,7 @@ ko.bindingHandlers['value'] = {
}
}
} else {
updateFromModel = function () {
updateFromModel = () => {
var newValue = ko.utils.unwrapObservable(valueAccessor());
var elementValue = ko.selectExtensions.readValue(element);
@ -96,7 +96,7 @@ ko.bindingHandlers['value'] = {
if (tagName === "select") {
var updateFromModelComputed;
ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, function () {
ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, () => {
if (!updateFromModelComputed) {
ko.utils.registerEventHandler(element, "change", valueUpdateHandler);
updateFromModelComputed = ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });
@ -111,6 +111,6 @@ ko.bindingHandlers['value'] = {
ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });
}
},
'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding
'update': () => {} // Keep for backwards compatibility with code that may have wrapped value binding
};
ko.expressionRewriting.twoWayBindings['value'] = true;

View file

@ -1,5 +1,5 @@
ko.bindingHandlers['visible'] = {
'update': function (element, valueAccessor) {
'update': (element, valueAccessor) => {
var value = ko.utils.unwrapObservable(valueAccessor());
var isCurrentlyVisible = !(element.style.display == "none");
if (value && !isCurrentlyVisible)
@ -10,7 +10,6 @@ ko.bindingHandlers['visible'] = {
};
ko.bindingHandlers['hidden'] = {
'update': function (element, valueAccessor) {
ko.bindingHandlers['visible']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
}
'update': (element, valueAccessor) =>
ko.bindingHandlers['visible']['update'](element, () => !ko.utils.unwrapObservable(valueAccessor()) )
};