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

67
vendors/knockout/src/binding/bindingAttributeSyntax.js vendored Executable file → Normal file
View file

@ -1,4 +1,4 @@
(function () {
(() => {
// Hide or don't minify context properties, see https://github.com/knockout/knockout/issues/2294
var contextSubscribable = Symbol('_subscribable');
var contextAncestorBindingInfo = Symbol('_ancestorBindingInfo');
@ -19,9 +19,7 @@
};
// Use an overridable method for retrieving binding handlers so that plugins may support dynamically created handlers
ko['getBindingHandler'] = function(bindingKey) {
return ko.bindingHandlers[bindingKey];
};
ko['getBindingHandler'] = bindingKey => ko.bindingHandlers[bindingKey];
var inheritParentVm = {};
@ -93,7 +91,6 @@
shouldInheritData = dataItemOrAccessor === inheritParentVm,
realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor,
isFunc = typeof(realDataItemOrAccessor) == "function" && !ko.isObservable(realDataItemOrAccessor),
nodes,
subscribable,
dataDependency = options && options['dataDependency'];
@ -132,14 +129,14 @@
if (dataItemAlias && options && options['noChildContext']) {
var isFunc = typeof(dataItemOrAccessor) == "function" && !ko.isObservable(dataItemOrAccessor);
return new ko.bindingContext(inheritParentVm, this, null, function (self) {
return new ko.bindingContext(inheritParentVm, this, null, self => {
if (extendCallback)
extendCallback(self);
self[dataItemAlias] = isFunc ? dataItemOrAccessor() : dataItemOrAccessor;
}, options);
}
return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, function (self, parentContext) {
return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, (self, parentContext) => {
// Extend the context hierarchy by setting the appropriate pointers
self['$parentContext'] = parentContext;
self['$parent'] = parentContext['$data'];
@ -154,9 +151,9 @@
// Similarly to "child" contexts, provide a function here to make sure that the correct values are set
// when an observable view model is updated.
ko.bindingContext.prototype['extend'] = function(properties, options) {
return new ko.bindingContext(inheritParentVm, this, null, function(self, parentContext) {
ko.utils.extend(self, typeof(properties) == "function" ? properties(self) : properties);
}, options);
return new ko.bindingContext(inheritParentVm, this, null, self =>
ko.utils.extend(self, typeof(properties) == "function" ? properties(self) : properties)
, options);
};
var boundElementDomDataKey = ko.utils.domData.nextKey();
@ -209,7 +206,7 @@
childrenComplete: "childrenComplete",
descendantsComplete : "descendantsComplete",
subscribe: function (node, event, callback, context, options) {
subscribe: (node, event, callback, context, options) => {
var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});
if (!bindingInfo.eventSubscribable) {
bindingInfo.eventSubscribable = new ko.subscribable;
@ -220,7 +217,7 @@
return bindingInfo.eventSubscribable.subscribe(callback, context, event);
},
notify: function (node, event) {
notify: (node, event) => {
var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);
if (bindingInfo) {
bindingInfo.notifiedEvents[event] = true;
@ -239,7 +236,7 @@
}
},
startPossiblyAsyncContentBinding: function (node, bindingContext) {
startPossiblyAsyncContentBinding: (node, bindingContext) => {
var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});
if (!bindingInfo.asyncContext) {
@ -251,7 +248,7 @@
return bindingContext;
}
return bindingContext['extend'](function (ctx) {
return bindingContext['extend'](ctx => {
ctx[contextAncestorBindingInfo] = bindingInfo;
});
}
@ -439,28 +436,19 @@
// context update), just return the value accessor from the binding. Otherwise, return a function that always gets
// the latest binding value and registers a dependency on the binding updater.
var getValueAccessor = bindingsUpdater
? function(bindingKey) {
return function() {
return evaluateValueAccessor(bindingsUpdater()[bindingKey]);
};
} : function(bindingKey) {
return bindings[bindingKey];
};
? bindingKey => () => evaluateValueAccessor(bindingsUpdater()[bindingKey])
: bindingKey => bindings[bindingKey];
// Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated
function allBindings() {
return ko.utils.objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor);
}
// The following is the 3.x allBindings API
allBindings['get'] = function(key) {
return bindings[key] && evaluateValueAccessor(getValueAccessor(key));
};
allBindings['has'] = function(key) {
return key in bindings;
};
allBindings['get'] = key => bindings[key] && evaluateValueAccessor(getValueAccessor(key));
allBindings['has'] = key => key in bindings;
if (ko.bindingEvent.childrenComplete in bindings) {
ko.bindingEvent.subscribe(node, ko.bindingEvent.childrenComplete, function () {
ko.bindingEvent.subscribe(node, ko.bindingEvent.childrenComplete, () => {
var callback = evaluateValueAccessor(bindings[ko.bindingEvent.childrenComplete]);
if (callback) {
var nodes = ko.virtualElements.childNodes(node);
@ -499,7 +487,7 @@
try {
// Run init, ignoring any dependencies
if (typeof handlerInitFn == "function") {
ko.dependencyDetection.ignore(function() {
ko.dependencyDetection.ignore(() => {
var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);
// If this binding handler claims to control descendant bindings, make a note of this
@ -514,9 +502,7 @@
// Run update in its own computed wrapper
if (typeof handlerUpdateFn == "function") {
ko.dependentObservable(
function() {
handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);
},
() => handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend),
null,
{ disposeWhenNodeIsRemoved: node }
);
@ -533,9 +519,9 @@
'shouldBindDescendants': shouldBindDescendants,
'bindingContextForDescendants': shouldBindDescendants && contextToExtend
};
};
}
ko.storedBindingContextForNode = function (node) {
ko.storedBindingContextForNode = node => {
var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);
return bindingInfo && bindingInfo.context;
}
@ -546,16 +532,15 @@
: new ko.bindingContext(viewModelOrBindingContext, undefined, undefined, extendContextCallback);
}
ko.applyBindingAccessorsToNode = function (node, bindings, viewModelOrBindingContext) {
return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext));
};
ko.applyBindingAccessorsToNode = (node, bindings, viewModelOrBindingContext) =>
applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext));
ko.applyBindingsToNode = function (node, bindings, viewModelOrBindingContext) {
ko.applyBindingsToNode = (node, bindings, viewModelOrBindingContext) => {
var context = getBindingContext(viewModelOrBindingContext);
return ko.applyBindingAccessorsToNode(node, makeBindingAccessors(bindings, context, node), context);
};
ko.applyBindingsToDescendants = function(viewModelOrBindingContext, rootNode) {
ko.applyBindingsToDescendants = (viewModelOrBindingContext, rootNode) => {
if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode);
};
@ -574,13 +559,13 @@
};
// Retrieving binding context from arbitrary nodes
ko.contextFor = function(node) {
ko.contextFor = node => {
// We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
if (node && (node.nodeType === 1 || node.nodeType === 8)) {
return ko.storedBindingContextForNode(node);
}
};
ko.dataFor = function(node) {
ko.dataFor = node => {
var context = ko.contextFor(node);
return context ? context['$data'] : undefined;
};

View file

@ -6,7 +6,7 @@
};
ko.utils.extend(ko.bindingProvider.prototype, {
'nodeHasBindings': function(node) {
'nodeHasBindings': node => {
switch (node.nodeType) {
case 1: // Element
return node.getAttribute(defaultBindingAttributeName) != null
@ -31,12 +31,12 @@
// The following function is only used internally by this default provider.
// It's not part of the interface definition for a general binding provider.
'getBindingsString': function(node, bindingContext) {
'getBindingsString': (node, bindingContext) => {
switch (node.nodeType) {
case 1: return node.getAttribute(defaultBindingAttributeName); // Element
case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
default: return null;
}
return null;
},
// The following function is only used internally by this default provider.

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()) )
};

View file

@ -1,4 +1,4 @@
(function () {
(() => {
// Objective:
// * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
// map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
@ -12,7 +12,7 @@
function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
// Map this array value inside a dependentObservable so we re-map when any dependency changes
var mappedNodes = [];
var dependentObservable = ko.dependentObservable(function() {
var dependentObservable = ko.dependentObservable(() => {
var newMappedNodes = mapping(valueToMap, index, ko.utils.fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];
// On subsequent evaluations, just replace the previously-inserted DOM nodes
@ -33,7 +33,7 @@
var lastMappingResultDomDataKey = ko.utils.domData.nextKey(),
deletedItemDummyValue = ko.utils.domData.nextKey();
ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes, editScript) {
ko.utils.setDomNodeChildrenFromArrayMapping = (domNode, array, mapping, options, callbackAfterAddingNodes, editScript) => {
array = array || [];
if (typeof array.length == "undefined") // Coerce single value into array
array = [array];
@ -88,7 +88,7 @@
} else {
if (!editScript || (lastMappingResult && lastMappingResult['_countWaitingForRemove'])) {
// Compare the provided array against the previous one
var lastArray = Array.prototype.map.call(lastMappingResult, function (x) { return x.arrayEntry; }),
var lastArray = Array.prototype.map.call(lastMappingResult, x => x.arrayEntry),
compareOptions = {
'dontLimitMoves': options['dontLimitMoves'],
'sparse': true
@ -96,7 +96,7 @@
editScript = ko.utils.compareArrays(lastArray, array, compareOptions);
}
for (var i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {
for (let i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {
movedIndex = editScriptItem['moved'];
itemIndex = editScriptItem['index'];
switch (editScriptItem['status']) {

View file

@ -1,5 +1,5 @@
// Go through the items that have been added and deleted and try to find matches between them.
ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares) {
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) {
@ -17,7 +17,7 @@ ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares
}
};
ko.utils.compareArrays = (function () {
ko.utils.compareArrays = (() => {
var statusNotInOld = 'added', statusNotInNew = 'deleted';
// Simple calculation based on Levenshtein distance.

View file

@ -1,4 +1,4 @@
ko.expressionRewriting = (function () {
ko.expressionRewriting = (() => {
var javaScriptReservedWords = ["true", "false", "null", "undefined"];
// Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
@ -28,7 +28,7 @@ ko.expressionRewriting = (function () {
"//.*\n",
// Match a regular expression (text enclosed by slashes), but will also match sets of divisions
// as a regular expression (this is handled by the parsing loop below).
'/(?:\\\\.|[^/])+/\w*',
'/(?:\\\\.|[^/])+/w*',
// Match text (at least two characters) that does not contain any of the above special characters,
// although some of the special characters are allowed to start it (all but the colon and comma).
// The text can contain spaces, but leading or trailing spaces are skipped.
@ -143,9 +143,9 @@ ko.expressionRewriting = (function () {
keyValueArray = typeof bindingsStringOrKeyValueArray === "string" ?
parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;
ko.utils.arrayForEach(keyValueArray, function(keyValue) {
processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value);
});
ko.utils.arrayForEach(keyValueArray, keyValue =>
processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value)
);
if (propertyAccessorResultStrings.length)
processKeyValue('_ko_property_writers', "{" + propertyAccessorResultStrings.join(",") + " }");
@ -162,7 +162,7 @@ ko.expressionRewriting = (function () {
preProcessBindings: preProcessBindings,
keyValueArrayContainsKey: function(keyValueArray, key) {
keyValueArrayContainsKey: (keyValueArray, key) => {
for (var i = 0; i < keyValueArray.length; i++)
if (keyValueArray[i]['key'] == key)
return true;
@ -178,7 +178,7 @@ ko.expressionRewriting = (function () {
// value: The value to be written
// checkIfDifferent: If true, and if the property being written is a writable observable, the value will only be written if
// it is !== existing value on that writable observable
writeValueToProperty: function(property, allBindings, key, value, checkIfDifferent) {
writeValueToProperty: (property, allBindings, key, value, checkIfDifferent) => {
if (!property || !ko.isObservable(property)) {
var propWriters = allBindings.get('_ko_property_writers');
if (propWriters && propWriters[key])
@ -194,17 +194,3 @@ ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
// Making bindings explicitly declare themselves as "two way" isn't ideal in the long term (it would be better if
// all bindings could use an official 'property writer' API without needing to declare that they might). However,
// since this is not, and has never been, a public API (_ko_property_writers was never documented), it's acceptable
// as an internal implementation detail in the short term.
// For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an
// undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official
// public API, and we reserve the right to remove it at any time if we create a real public property writers API.
ko.exportSymbol('expressionRewriting._twoWayBindings', ko.expressionRewriting.twoWayBindings);
// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);

View file

@ -1,11 +1,11 @@
(function () {
(() => {
var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
// Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
// are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
// that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
ko.selectExtensions = {
readValue : function(element) {
readValue : element => {
switch (ko.utils.tagNameLower(element)) {
case 'option':
if (element[hasDomDataExpandoProperty] === true)
@ -18,7 +18,7 @@
}
},
writeValue: function(element, value, allowUnset) {
writeValue: (element, value, allowUnset) => {
switch (ko.utils.tagNameLower(element)) {
case 'option':
if (typeof value === "string") {

View file

@ -1,12 +1,12 @@
(function(undefined) {
(() => {
var componentLoadingOperationUniqueId = 0;
ko.bindingHandlers['component'] = {
'init': function(element, valueAccessor, ignored1, ignored2, bindingContext) {
'init': (element, valueAccessor, ignored1, ignored2, bindingContext) => {
var currentViewModel,
currentLoadingOperationId,
afterRenderSub,
disposeAssociatedComponentViewModel = function () {
disposeAssociatedComponentViewModel = () => {
var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];
if (typeof currentViewModelDispose === 'function') {
currentViewModelDispose.call(currentViewModel);
@ -24,7 +24,7 @@
ko.virtualElements.emptyNode(element);
ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);
ko.computed(function () {
ko.computed(() => {
var value = ko.utils.unwrapObservable(valueAccessor()),
componentName, componentParams;
@ -42,7 +42,7 @@
var asyncContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);
var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;
ko.components.get(componentName, function(componentDefinition) {
ko.components.get(componentName, componentDefinition => {
// If this is not the current load operation for this element, ignore it.
if (currentLoadingOperationId !== loadingOperationId) {
return;
@ -64,7 +64,7 @@
var componentViewModel = createViewModel(componentDefinition, componentParams, componentInfo),
childBindingContext = asyncContext['createChildContext'](componentViewModel, {
'extend': function(ctx) {
'extend': ctx => {
ctx['$component'] = componentViewModel;
ctx['$componentTemplateNodes'] = originalChildNodes;
}

View file

@ -1,7 +1,7 @@
(function (undefined) {
(() => {
// Overridable API for determining which component name applies to a given node. By overriding this,
// you can for example map specific tagNames to components that are not preregistered.
ko.components['getComponentNameForNode'] = function(node) {
ko.components['getComponentNameForNode'] = node => {
var tagNameLower = ko.utils.tagNameLower(node);
if (ko.components.isRegistered(tagNameLower)) {
// Try to determine that this node can be considered a *custom* element; see https://github.com/knockout/knockout/issues/1603
@ -11,7 +11,7 @@
}
};
ko.components.addBindingsForCustomElement = function(allBindings, node, bindingContext, valueAccessors) {
ko.components.addBindingsForCustomElement = (allBindings, node, bindingContext, valueAccessors) => {
// Determine if it's really a custom element matching a component
if (node.nodeType === 1) {
var componentName = ko.components['getComponentNameForNode'](node);
@ -27,7 +27,7 @@
var componentBindingValue = { 'name': componentName, 'params': getComponentParamsFromCustomElement(node, bindingContext) };
allBindings['component'] = valueAccessors
? function() { return componentBindingValue; }
? () => componentBindingValue
: componentBindingValue;
}
}
@ -42,10 +42,10 @@
if (paramsAttribute) {
var params = nativeBindingProviderInstance['parseBindingsString'](paramsAttribute, bindingContext, elem, { 'valueAccessors': true, 'bindingParams': true }),
rawParamComputedValues = ko.utils.objectMap(params, function(paramValue, paramName) {
return ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem });
}),
result = ko.utils.objectMap(rawParamComputedValues, function(paramValueComputed, paramName) {
rawParamComputedValues = ko.utils.objectMap(params, paramValue =>
ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem })
),
result = ko.utils.objectMap(rawParamComputedValues, paramValueComputed => {
var paramValue = paramValueComputed.peek();
// Does the evaluation of the parameter value unwrap any observables?
if (!paramValueComputed.isActive()) {
@ -58,12 +58,8 @@
// This means the component doesn't have to worry about multiple unwrapping. If the value is a
// writable observable, the computed will also be writable and pass the value on to the observable.
return ko.computed({
'read': function() {
return ko.utils.unwrapObservable(paramValueComputed());
},
'write': ko.isWriteableObservable(paramValue) && function(value) {
paramValueComputed()(value);
},
'read': () => ko.utils.unwrapObservable(paramValueComputed()),
'write': ko.isWriteableObservable(paramValue) && (value => paramValueComputed()(value)),
disposeWhenNodeIsRemoved: elem
});
}
@ -77,11 +73,10 @@
}
return result;
} else {
// For consistency, absence of a "params" attribute is treated the same as the presence of
// any empty one. Otherwise component viewmodels need special code to check whether or not
// 'params' or 'params.$raw' is null/undefined before reading subproperties, which is annoying.
return { '$raw': {} };
}
// For consistency, absence of a "params" attribute is treated the same as the presence of
// any empty one. Otherwise component viewmodels need special code to check whether or not
// 'params' or 'params.$raw' is null/undefined before reading subproperties, which is annoying.
return { '$raw': {} };
}
})();

View file

@ -1,4 +1,4 @@
(function(undefined) {
(() => {
// The default loader is responsible for two things:
// 1. Maintaining the default in-memory registry of component configuration objects
@ -12,7 +12,7 @@
var defaultConfigRegistry = {};
ko.components.register = function(componentName, config) {
ko.components.register = (componentName, config) => {
if (!config) {
throw new Error('Invalid configuration for ' + componentName);
}
@ -24,37 +24,35 @@
defaultConfigRegistry[componentName] = config;
};
ko.components.isRegistered = function(componentName) {
return Object.prototype.hasOwnProperty.call(defaultConfigRegistry, componentName);
};
ko.components.isRegistered = componentName =>
Object.prototype.hasOwnProperty.call(defaultConfigRegistry, componentName);
ko.components.unregister = function(componentName) {
ko.components.unregister = componentName => {
delete defaultConfigRegistry[componentName];
ko.components.clearCachedDefinition(componentName);
};
ko.components.defaultLoader = {
'getConfig': function(componentName, callback) {
'getConfig': (componentName, callback) => {
var result = ko.components.isRegistered(componentName)
? defaultConfigRegistry[componentName]
: null;
callback(result);
},
'loadComponent': function(componentName, config, callback) {
'loadComponent': (componentName, config, callback) => {
var errorCallback = makeErrorCallback(componentName);
possiblyGetConfigFromAmd(errorCallback, config, function(loadedConfig) {
resolveConfig(componentName, errorCallback, loadedConfig, callback);
});
possiblyGetConfigFromAmd(errorCallback, config, loadedConfig =>
resolveConfig(componentName, errorCallback, loadedConfig, callback)
);
},
'loadTemplate': function(componentName, templateConfig, callback) {
resolveTemplate(makeErrorCallback(componentName), templateConfig, callback);
},
'loadTemplate': (componentName, templateConfig, callback) =>
resolveTemplate(makeErrorCallback(componentName), templateConfig, callback)
,
'loadViewModel': function(componentName, viewModelConfig, callback) {
resolveViewModel(makeErrorCallback(componentName), viewModelConfig, callback);
}
'loadViewModel': (componentName, viewModelConfig, callback) =>
resolveViewModel(makeErrorCallback(componentName), viewModelConfig, callback)
};
var createViewModelKey = 'createViewModel';
@ -68,7 +66,7 @@
function resolveConfig(componentName, errorCallback, config, callback) {
var result = {},
makeCallBackWhenZero = 2,
tryIssueCallback = function() {
tryIssueCallback = () => {
if (--makeCallBackWhenZero === 0) {
callback(result);
}
@ -77,23 +75,23 @@
viewModelConfig = config['viewModel'];
if (templateConfig) {
possiblyGetConfigFromAmd(errorCallback, templateConfig, function(loadedConfig) {
ko.components._getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], function(resolvedTemplate) {
possiblyGetConfigFromAmd(errorCallback, templateConfig, loadedConfig =>
ko.components._getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], resolvedTemplate => {
result['template'] = resolvedTemplate;
tryIssueCallback();
});
});
})
);
} else {
tryIssueCallback();
}
if (viewModelConfig) {
possiblyGetConfigFromAmd(errorCallback, viewModelConfig, function(loadedConfig) {
ko.components._getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], function(resolvedViewModel) {
possiblyGetConfigFromAmd(errorCallback, viewModelConfig, loadedConfig =>
ko.components._getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], resolvedViewModel => {
result[createViewModelKey] = resolvedViewModel;
tryIssueCallback();
});
});
})
);
} else {
tryIssueCallback();
}
@ -106,12 +104,12 @@
} else if (templateConfig instanceof Array) {
// Assume already an array of DOM nodes - pass through unchanged
callback(templateConfig);
} else if (isDocumentFragment(templateConfig)) {
} else if (templateConfig instanceof DocumentFragment) {
// Document fragment - use its child nodes
callback(ko.utils.makeArray(templateConfig.childNodes));
} else if (templateConfig['element']) {
var element = templateConfig['element'];
if (isDomElement(element)) {
if (element instanceof HTMLElement) {
// Element instance - copy its child nodes
callback(cloneNodesFromTemplateSourceElement(element));
} else if (typeof element === 'string') {
@ -136,18 +134,14 @@
// By design, this does *not* supply componentInfo to the constructor, as the intent is that
// componentInfo contains non-viewmodel data (e.g., the component's element) that should only
// be used in factory functions, not viewmodel constructors.
callback(function (params /*, componentInfo */) {
return new viewModelConfig(params);
});
callback(params => new viewModelConfig(params));
} else if (typeof viewModelConfig[createViewModelKey] === 'function') {
// Already a factory function - use it as-is
callback(viewModelConfig[createViewModelKey]);
} else if ('instance' in viewModelConfig) {
// Fixed object instance - promote to createViewModel format for API consistency
var fixedInstance = viewModelConfig['instance'];
callback(function (params, componentInfo) {
return fixedInstance;
});
callback(() => fixedInstance);
} else if ('viewModel' in viewModelConfig) {
// Resolved AMD module whose value is of the form { viewModel: ... }
resolveViewModel(errorCallback, viewModelConfig['viewModel'], callback);
@ -160,34 +154,18 @@
if ('template' == ko.utils.tagNameLower(elemInstance)) {
// For browsers with proper <template> element support (i.e., where the .content property
// gives a document fragment), use that document fragment.
if (isDocumentFragment(elemInstance.content)) {
if (elemInstance.content instanceof DocumentFragment) {
return ko.utils.cloneNodes(elemInstance.content.childNodes);
}
}
throw 'Template Source Element not a <template>';
}
function isDomElement(obj) {
if (window['HTMLElement']) {
return obj instanceof HTMLElement;
} else {
return obj && obj.tagName && obj.nodeType === 1;
}
}
function isDocumentFragment(obj) {
if (window['DocumentFragment']) {
return obj instanceof DocumentFragment;
} else {
return obj && obj.nodeType === 11;
}
}
function possiblyGetConfigFromAmd(errorCallback, config, callback) {
if (typeof config['require'] === 'string') {
// The config is the value of an AMD module
if (amdRequire || window['require']) {
(amdRequire || window['require'])([config['require']], function (module) {
(amdRequire || window['require'])([config['require']], module => {
if (module && typeof module === 'object' && module.__esModule && module['default']) {
module = module['default'];
}
@ -202,8 +180,8 @@
}
function makeErrorCallback(componentName) {
return function (message) {
throw new Error('Component \'' + componentName + '\': ' + message);
return message => {
throw new Error('Component \'' + componentName + '\': ' + message)
};
}

View file

@ -1,20 +1,20 @@
(function(undefined) {
(() => {
var loadingSubscribablesCache = {}, // Tracks component loads that are currently in flight
loadedDefinitionsCache = {}; // Tracks component loads that have already completed
ko.components = {
get: function(componentName, callback) {
get: (componentName, callback) => {
var cachedDefinition = getObjectOwnProperty(loadedDefinitionsCache, componentName);
if (cachedDefinition) {
// It's already loaded and cached. Reuse the same definition object.
// Note that for API consistency, even cache hits complete asynchronously by default.
// You can bypass this by putting synchronous:true on your component config.
if (cachedDefinition.isSynchronousComponent) {
ko.dependencyDetection.ignore(function() { // See comment in loaderRegistryBehaviors.js for reasoning
callback(cachedDefinition.definition);
});
ko.dependencyDetection.ignore(() => // See comment in loaderRegistryBehaviors.js for reasoning
callback(cachedDefinition.definition)
);
} else {
ko.tasks.schedule(function() { callback(cachedDefinition.definition); });
ko.tasks.schedule(() => callback(cachedDefinition.definition) );
}
} else {
// Join the loading process that is already underway, or start a new one.
@ -22,9 +22,9 @@
}
},
clearCachedDefinition: function(componentName) {
delete loadedDefinitionsCache[componentName];
},
clearCachedDefinition: componentName =>
delete loadedDefinitionsCache[componentName]
,
_getFirstResultFromLoaders: getFirstResultFromLoaders
};
@ -41,7 +41,7 @@
subscribable = loadingSubscribablesCache[componentName] = new ko.subscribable();
subscribable.subscribe(callback);
beginLoadingComponent(componentName, function(definition, config) {
beginLoadingComponent(componentName, (definition, config) => {
var isSynchronousComponent = !!(config && config['synchronous']);
loadedDefinitionsCache[componentName] = { definition: definition, isSynchronousComponent: isSynchronousComponent };
delete loadingSubscribablesCache[componentName];
@ -57,9 +57,7 @@
// See comment in loaderRegistryBehaviors.js for reasoning
subscribable['notifySubscribers'](definition);
} else {
ko.tasks.schedule(function() {
subscribable['notifySubscribers'](definition);
});
ko.tasks.schedule(() => subscribable['notifySubscribers'](definition));
}
});
completedAsync = true;
@ -69,12 +67,12 @@
}
function beginLoadingComponent(componentName, callback) {
getFirstResultFromLoaders('getConfig', [componentName], function(config) {
getFirstResultFromLoaders('getConfig', [componentName], config => {
if (config) {
// We have a config, so now load its definition
getFirstResultFromLoaders('loadComponent', [componentName, config], function(definition) {
callback(definition, config);
});
getFirstResultFromLoaders('loadComponent', [componentName, config], definition =>
callback(definition, config)
);
} else {
// The component has no config - it's unknown to all the loaders.
// Note that this is not an error (e.g., a module loading error) - that would abort the

View file

@ -22,7 +22,7 @@ ko.memoization = (function () {
}
return {
memoize: function (callback) {
memoize: callback => {
if (typeof callback != "function")
throw new Error("You can only pass a function to ko.memoization.memoize()");
var memoId = generateRandomId();
@ -30,7 +30,7 @@ ko.memoization = (function () {
return "<!--[ko_memo:" + memoId + "]-->";
},
unmemoize: function (memoId, callbackParams) {
unmemoize: (memoId, callbackParams) => {
var callback = memos[memoId];
if (callback === undefined)
throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
@ -41,7 +41,7 @@ ko.memoization = (function () {
finally { delete memos[memoId]; }
},
unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
unmemoizeDomNodeAndDescendants: (domNode, extraCallbackParamsArray) => {
var memos = [];
findMemoNodes(domNode, memos);
for (var i = 0, j = memos.length; i < j; i++) {
@ -56,8 +56,8 @@ ko.memoization = (function () {
}
},
parseMemoText: function (memoText) {
var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
parseMemoText: memoText => {
var match = memoText.match(/^\[ko_memo:(.*?)\]$/);
return match ? match[1] : null;
}
};

View file

@ -1,19 +1,9 @@
ko.computedContext = ko.dependencyDetection = (function () {
ko.computedContext = ko.dependencyDetection = (() => {
var outerFrames = [],
currentFrame,
lastId = 0;
// Return a unique ID that can be assigned to an observable for dependency tracking.
// Theoretically, you could eventually overflow the number storage size, resulting
// in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53
// or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would
// take over 285 years to reach that number.
// Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html
function getId() {
return ++lastId;
}
function begin(options) {
outerFrames.push(currentFrame);
currentFrame = options;
@ -28,15 +18,15 @@ ko.computedContext = ko.dependencyDetection = (function () {
end: end,
registerDependency: function (subscribable) {
registerDependency: subscribable => {
if (currentFrame) {
if (!ko.isSubscribable(subscribable))
throw new Error("Only subscribable things can act as dependencies");
currentFrame.callback.call(currentFrame.callbackTarget, subscribable, subscribable._id || (subscribable._id = getId()));
currentFrame.callback.call(currentFrame.callbackTarget, subscribable, subscribable._id || (subscribable._id = ++lastId));
}
},
ignore: function (callback, callbackTarget, callbackArgs) {
ignore: (callback, callbackTarget, callbackArgs) => {
try {
begin();
return callback.apply(callbackTarget, callbackArgs || []);
@ -45,22 +35,22 @@ ko.computedContext = ko.dependencyDetection = (function () {
}
},
getDependenciesCount: function () {
getDependenciesCount: () => {
if (currentFrame)
return currentFrame.computed.getDependenciesCount();
},
getDependencies: function () {
getDependencies: () => {
if (currentFrame)
return currentFrame.computed.getDependencies();
},
isInitial: function() {
isInitial: () => {
if (currentFrame)
return currentFrame.isInitial;
},
computed: function() {
computed: () => {
if (currentFrame)
return currentFrame.computed;
}

View file

@ -153,9 +153,9 @@ var computedFn = {
getDependencies: function () {
var dependencyTracking = this[computedState].dependencyTracking, dependentObservables = [];
ko.utils.objectForEach(dependencyTracking, function (id, dependency) {
dependentObservables[dependency._order] = dependency._target;
});
ko.utils.objectForEach(dependencyTracking, (id, dependency) =>
dependentObservables[dependency._order] = dependency._target
);
return dependentObservables;
},
@ -167,9 +167,9 @@ var computedFn = {
if (ko.utils.arrayIndexOf(dependencies, obs) !== -1) {
return true;
}
return !!ko.utils.arrayFirst(dependencies, function (dep) {
return dep.hasAncestorDependency && dep.hasAncestorDependency(obs);
});
return !!ko.utils.arrayFirst(dependencies, dep =>
dep.hasAncestorDependency && dep.hasAncestorDependency(obs)
);
},
addDependencyTracking: function (id, target, trackingObj) {
if (this[computedState].pure && target === this) {
@ -215,7 +215,7 @@ var computedFn = {
changeSub = target.subscribe(this.respondToChange, this);
return {
_target: target,
dispose: function () {
dispose: () => {
dirtySub.dispose();
changeSub.dispose();
}
@ -229,9 +229,9 @@ var computedFn = {
throttleEvaluationTimeout = computedObservable['throttleEvaluation'];
if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
clearTimeout(this[computedState].evaluationTimeoutInstance);
this[computedState].evaluationTimeoutInstance = ko.utils.setTimeout(function () {
computedObservable.evaluateImmediate(true /*notifyChange*/);
}, throttleEvaluationTimeout);
this[computedState].evaluationTimeoutInstance = ko.utils.setTimeout(() =>
computedObservable.evaluateImmediate(true /*notifyChange*/)
, throttleEvaluationTimeout);
} else if (computedObservable._evalDelayed) {
computedObservable._evalDelayed(true /*isChange*/);
} else {
@ -340,7 +340,7 @@ var computedFn = {
return changed;
},
evaluateImmediate_CallReadThenEndDependencyDetection: function (state, dependencyDetectionContext) {
evaluateImmediate_CallReadThenEndDependencyDetection: (state, dependencyDetectionContext) => {
// This function is really part of the evaluateImmediate_CallReadWithDependencyDetection logic.
// You'd never call it from anywhere else. Factoring it out means that evaluateImmediate_CallReadWithDependencyDetection
// can be independent of try/finally blocks, which contributes to saving about 40% off the CPU
@ -399,10 +399,9 @@ var computedFn = {
dispose: function () {
var state = this[computedState];
if (!state.isSleeping && state.dependencyTracking) {
ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {
if (dependency.dispose)
dependency.dispose();
});
ko.utils.objectForEach(state.dependencyTracking, (id, dependency) =>
dependency.dispose && dependency.dispose()
);
}
if (state.disposeWhenNodeIsRemoved && state.domNodeDisposalCallback) {
ko.utils.domNodeDisposal.removeDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback);
@ -438,11 +437,11 @@ var pureComputedOverrides = {
} else {
// First put the dependencies in order
var dependenciesOrder = [];
ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {
dependenciesOrder[dependency._order] = id;
});
ko.utils.objectForEach(state.dependencyTracking, (id, dependency) =>
dependenciesOrder[dependency._order] = id
);
// Next, subscribe to each one
ko.utils.arrayForEach(dependenciesOrder, function (id, order) {
ko.utils.arrayForEach(dependenciesOrder, (id, order) => {
var dependency = state.dependencyTracking[id],
subscription = computedObservable.subscribeToDependency(dependency._target);
subscription._order = order;
@ -465,7 +464,7 @@ var pureComputedOverrides = {
afterSubscriptionRemove: function (event) {
var state = this[computedState];
if (!state.isDisposed && event == 'change' && !this.hasSubscriptionsForEvent('change')) {
ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {
ko.utils.objectForEach(state.dependencyTracking, (id, dependency) => {
if (dependency.dispose) {
state.dependencyTracking[id] = {
_target: dependency._target,
@ -510,13 +509,9 @@ if (ko.utils.canSetPrototype) {
var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
computedFn[protoProp] = ko.computed;
ko.isComputed = function (instance) {
return (typeof instance == 'function' && instance[protoProp] === computedFn[protoProp]);
};
ko.isComputed = instance => (typeof instance == 'function' && instance[protoProp] === computedFn[protoProp]);
ko.isPureComputed = function (instance) {
return ko.isComputed(instance) && instance[computedState] && instance[computedState].pure;
};
ko.isPureComputed = instance => ko.isComputed(instance) && instance[computedState] && instance[computedState].pure;
ko.exportSymbol('computed', ko.computed);
ko.exportSymbol('dependentObservable', ko.computed); // export ko.dependentObservable for backwards compatibility (1.x)
@ -529,13 +524,12 @@ ko.exportProperty(computedFn, 'isActive', computedFn.isActive);
ko.exportProperty(computedFn, 'getDependenciesCount', computedFn.getDependenciesCount);
ko.exportProperty(computedFn, 'getDependencies', computedFn.getDependencies);
ko.pureComputed = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget) {
ko.pureComputed = (evaluatorFunctionOrOptions, evaluatorFunctionTarget) => {
if (typeof evaluatorFunctionOrOptions === 'function') {
return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {'pure':true});
} else {
evaluatorFunctionOrOptions = ko.utils.extend({}, evaluatorFunctionOrOptions); // make a copy of the parameter object
evaluatorFunctionOrOptions['pure'] = true;
return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);
}
}
evaluatorFunctionOrOptions = ko.utils.extend({}, evaluatorFunctionOrOptions); // make a copy of the parameter object
evaluatorFunctionOrOptions['pure'] = true;
return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);
};
ko.exportSymbol('pureComputed', ko.pureComputed);

View file

@ -1,5 +1,5 @@
ko.extenders = {
'throttle': function(target, timeout) {
'throttle': (target, timeout) => {
// Throttling means two things:
// (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
@ -11,16 +11,14 @@ ko.extenders = {
var writeTimeoutInstance = null;
return ko.dependentObservable({
'read': target,
'write': function(value) {
'write': value => {
clearTimeout(writeTimeoutInstance);
writeTimeoutInstance = ko.utils.setTimeout(function() {
target(value);
}, timeout);
writeTimeoutInstance = ko.utils.setTimeout(() => target(value), timeout);
}
});
},
'rateLimit': function(target, options) {
'rateLimit': (target, options) => {
var timeout, method, limitFunction;
if (typeof options == 'number') {
@ -34,22 +32,20 @@ ko.extenders = {
target._deferUpdates = false;
limitFunction = typeof method == 'function' ? method : method == 'notifyWhenChangesStop' ? debounce : throttle;
target.limit(function(callback) {
return limitFunction(callback, timeout, options);
});
target.limit(callback => limitFunction(callback, timeout, options));
},
'deferred': function(target, options) {
'deferred': (target, options) => {
if (options !== true) {
throw new Error('The \'deferred\' extender only accepts the value \'true\', because it is not supported to turn deferral off once enabled.')
}
if (!target._deferUpdates) {
target._deferUpdates = true;
target.limit(function (callback) {
target.limit(callback => {
var handle,
ignoreUpdates = false;
return function () {
return () => {
if (!ignoreUpdates) {
ko.tasks.cancel(handle);
handle = ko.tasks.schedule(callback);
@ -66,7 +62,7 @@ ko.extenders = {
}
},
'notify': function(target, notifyWhen) {
'notify': (target, notifyWhen) => {
target["equalityComparer"] = notifyWhen == "always" ?
null : // null equalityComparer means to always notify
valuesArePrimitiveAndEqual;
@ -81,9 +77,9 @@ function valuesArePrimitiveAndEqual(a, b) {
function throttle(callback, timeout) {
var timeoutInstance;
return function () {
return () => {
if (!timeoutInstance) {
timeoutInstance = ko.utils.setTimeout(function () {
timeoutInstance = ko.utils.setTimeout(() => {
timeoutInstance = undefined;
callback();
}, timeout);
@ -93,7 +89,7 @@ function throttle(callback, timeout) {
function debounce(callback, timeout) {
var timeoutInstance;
return function () {
return () => {
clearTimeout(timeoutInstance);
timeoutInstance = ko.utils.setTimeout(callback, timeout);
};
@ -102,7 +98,7 @@ function debounce(callback, timeout) {
function applyExtenders(requestedExtenders) {
var target = this;
if (requestedExtenders) {
ko.utils.objectForEach(requestedExtenders, function(key, value) {
ko.utils.objectForEach(requestedExtenders, (key, value) => {
var extenderHandler = ko.extenders[key];
if (typeof extenderHandler == 'function') {
target = extenderHandler(target, value) || target;

View file

@ -1,6 +1,6 @@
var observableLatestValue = Symbol('_latestValue');
ko.observable = function (initialValue) {
ko.observable = initialValue => {
function observable() {
if (arguments.length > 0) {
// Write
@ -59,7 +59,7 @@ if (ko.utils.canSetPrototype) {
var protoProperty = ko.observable.protoProperty = '__ko_proto__';
observableFn[protoProperty] = ko.observable;
ko.isObservable = function (instance) {
ko.isObservable = instance => {
var proto = typeof instance == 'function' && instance[protoProperty];
if (proto && proto !== observableFn[protoProperty] && proto !== ko.computed['fn'][protoProperty]) {
throw Error("Invalid object that looks like an observable; possibly from another Knockout instance");
@ -67,7 +67,7 @@ ko.isObservable = function (instance) {
return !!proto;
};
ko.isWriteableObservable = function (instance) {
ko.isWriteableObservable = instance => {
return (typeof instance == 'function' && (
(instance[protoProperty] === observableFn[protoProperty]) || // Observable
(instance[protoProperty] === ko.computed['fn'][protoProperty] && instance.hasWriteFunction))); // Writable computed observable

View file

@ -1,5 +1,5 @@
var arrayChangeEventName = 'arrayChange';
ko.extenders['trackArrayChanges'] = function(target, options) {
ko.extenders['trackArrayChanges'] = (target, options) => {
// Use the provided options--each call to trackArrayChanges overwrites the previously set options
target.compareArrayOptions = {};
if (options && typeof options == "object") {
@ -21,7 +21,7 @@ ko.extenders['trackArrayChanges'] = function(target, options) {
underlyingAfterSubscriptionRemoveFunction = target.afterSubscriptionRemove;
// Watch "subscribe" calls, and for array change events, ensure change tracking is enabled
target.beforeSubscriptionAdd = function (event) {
target.beforeSubscriptionAdd = event => {
if (underlyingBeforeSubscriptionAddFunction) {
underlyingBeforeSubscriptionAddFunction.call(target, event);
}
@ -30,7 +30,7 @@ ko.extenders['trackArrayChanges'] = function(target, options) {
}
};
// Watch "dispose" calls, and for array change events, ensure change tracking is disabled when all are disposed
target.afterSubscriptionRemove = function (event) {
target.afterSubscriptionRemove = event => {
if (underlyingAfterSubscriptionRemoveFunction) {
underlyingAfterSubscriptionRemoveFunction.call(target, event);
}
@ -58,9 +58,7 @@ ko.extenders['trackArrayChanges'] = function(target, options) {
trackingChanges = true;
// Track how many times the array actually changed value
spectateSubscription = target.subscribe(function () {
++pendingChanges;
}, null, "spectate");
spectateSubscription = target.subscribe(() => ++pendingChanges, null, "spectate");
// Each time the array changes value, capture a clone so that on the next
// change it's possible to produce a diff
@ -102,7 +100,7 @@ ko.extenders['trackArrayChanges'] = function(target, options) {
return cachedDiff;
}
target.cacheDiffForKnownOperation = function(rawArray, operationName, args) {
target.cacheDiffForKnownOperation = (rawArray, operationName, args) => {
// Only run if we're currently tracking changes for this observable array
// and there aren't any pending deferred notifications.
if (!trackingChanges || pendingChanges) {

View file

@ -1,4 +1,4 @@
ko.observableArray = function (initialValues) {
ko.observableArray = initialValues => {
initialValues = initialValues || [];
if (typeof initialValues != 'object' || !('length' in initialValues))
@ -66,7 +66,7 @@ if (ko.utils.canSetPrototype) {
// Populate ko.observableArray.fn with read/write functions from native arrays
// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], methodName => {
ko.observableArray['fn'][methodName] = function () {
// Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
// (for consistency with mutating regular observables)
@ -81,14 +81,14 @@ ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "uns
});
// Populate ko.observableArray.fn with read-only functions from native arrays
ko.utils.arrayForEach(["slice"], function (methodName) {
ko.utils.arrayForEach(["slice"], methodName => {
ko.observableArray['fn'][methodName] = function () {
var underlyingArray = this();
return underlyingArray[methodName].apply(underlyingArray, arguments);
};
});
ko.isObservableArray = function (instance) {
ko.isObservableArray = instance => {
return ko.isObservable(instance)
&& typeof instance["remove"] == "function"
&& typeof instance["push"] == "function";

View file

@ -1,7 +1,7 @@
ko.when = function(predicate, callback, context) {
ko.when = (predicate, callback, context) => {
function kowhen (resolve) {
var observable = ko.pureComputed(predicate, context).extend({notify:'always'});
var subscription = observable.subscribe(function(value) {
var subscription = observable.subscribe(value => {
if (value) {
subscription.dispose();
resolve(value);
@ -12,10 +12,7 @@ ko.when = function(predicate, callback, context) {
return subscription;
}
if (callback) {
return kowhen(callback.bind(context));
}
return new Promise(kowhen);
return callback ? kowhen(callback.bind(context)) : new Promise(kowhen);
};
ko.exportSymbol('when', ko.when);

View file

@ -45,7 +45,7 @@ function limitNotifySubscribers(value, event) {
}
var ko_subscribable_fn = {
init: function(instance) {
init: instance => {
instance._subscriptions = { "change": [] };
instance._versionNumber = 1;
},
@ -56,7 +56,7 @@ var ko_subscribable_fn = {
event = event || defaultEvent;
var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
var subscription = new ko.subscription(self, boundCallback, function () {
var subscription = new ko.subscription(self, boundCallback, () => {
ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);
if (self.afterSubscriptionRemove)
self.afterSubscriptionRemove(event);
@ -115,7 +115,7 @@ var ko_subscribable_fn = {
self["notifySubscribers"] = limitNotifySubscribers;
}
var finish = limitFunction(function() {
var finish = limitFunction(() => {
self._notificationIsPending = false;
// If an observable provided a reference to itself, access it to get the latest value.
@ -132,7 +132,7 @@ var ko_subscribable_fn = {
}
});
self._limitChange = function(value, isDirty) {
self._limitChange = (value, isDirty) => {
if (!isDirty || !self._notificationIsPending) {
didUpdate = !isDirty;
}
@ -141,16 +141,16 @@ var ko_subscribable_fn = {
pendingValue = value;
finish();
};
self._limitBeforeChange = function(value) {
self._limitBeforeChange = value => {
if (!ignoreBeforeChange) {
previousValue = value;
self._origNotifySubscribers(value, beforeChange);
}
};
self._recordUpdate = function() {
self._recordUpdate = () => {
didUpdate = true;
};
self._notifyNextChangeIfValueIsDifferent = function() {
self._notifyNextChangeIfValueIsDifferent = () => {
if (self.isDifferent(previousValue, self.peek(true /*evaluate*/))) {
notifyNextChange = true;
}
@ -164,23 +164,20 @@ var ko_subscribable_fn = {
getSubscriptionsCount: function (event) {
if (event) {
return this._subscriptions[event] && this._subscriptions[event].length || 0;
} else {
var total = 0;
ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {
if (eventName !== 'dirty')
total += subscriptions.length;
});
return total;
}
var total = 0;
ko.utils.objectForEach(this._subscriptions, (eventName, subscriptions) => {
if (eventName !== 'dirty')
total += subscriptions.length;
});
return total;
},
isDifferent: function(oldValue, newValue) {
return !this['equalityComparer'] || !this['equalityComparer'](oldValue, newValue);
},
toString: function() {
return '[object Object]'
},
toString: () => '[object Object]',
extend: applyExtenders
};
@ -200,9 +197,8 @@ if (ko.utils.canSetPrototype) {
ko.subscribable['fn'] = ko_subscribable_fn;
ko.isSubscribable = function (instance) {
return instance != null && typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
};
ko.isSubscribable = instance =>
instance != null && typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
ko.exportSymbol('subscribable', ko.subscribable);
ko.exportSymbol('isSubscribable', ko.isSubscribable);

View file

@ -1,16 +1,15 @@
ko.tasks = (function () {
var scheduler,
taskQueue = [],
ko.tasks = (() => {
var taskQueue = [],
taskQueueLength = 0,
nextHandle = 1,
nextIndexToProcess = 0;
nextIndexToProcess = 0,
// Chrome 27+, Firefox 14+, IE 11+, Opera 15+, Safari 6.1+
// From https://github.com/petkaantonov/bluebird * Copyright (c) 2014 Petka Antonov * License: MIT
scheduler = (function (callback) {
scheduler = (callback => {
var div = document.createElement("div");
new MutationObserver(callback).observe(div, {attributes: true});
return function () { div.classList.toggle("foo"); };
return () => div.classList.toggle("foo");
})(scheduledProcess);
function processTasks() {
@ -47,37 +46,22 @@ ko.tasks = (function () {
nextIndexToProcess = taskQueueLength = taskQueue.length = 0;
}
function scheduleTaskProcessing() {
ko.tasks['scheduler'](scheduledProcess);
}
var tasks = {
'scheduler': scheduler, // Allow overriding the scheduler
schedule: function (func) {
schedule: func => {
if (!taskQueueLength) {
scheduleTaskProcessing();
scheduler(scheduledProcess);
}
taskQueue[taskQueueLength++] = func;
return nextHandle++;
},
cancel: function (handle) {
cancel: handle => {
var index = handle - (nextHandle - taskQueueLength);
if (index >= nextIndexToProcess && index < taskQueueLength) {
taskQueue[index] = null;
}
},
// For testing only: reset the queue and return the previous queue length
'resetForTesting': function () {
var length = taskQueueLength - nextIndexToProcess;
nextIndexToProcess = taskQueueLength = taskQueue.length = 0;
return length;
},
runEarly: processTasks
}
};
return tasks;
@ -86,4 +70,3 @@ ko.tasks = (function () {
ko.exportSymbol('tasks', ko.tasks);
ko.exportSymbol('tasks.schedule', ko.tasks.schedule);
//ko.exportSymbol('tasks.cancel', ko.tasks.cancel); "cancel" isn't minified
ko.exportSymbol('tasks.runEarly', ko.tasks.runEarly);

View file

@ -4,7 +4,7 @@ ko.nativeTemplateEngine = function () {
ko.nativeTemplateEngine.prototype = new ko.templateEngine();
ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;
ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {
ko.nativeTemplateEngine.prototype['renderTemplateSource'] = (templateSource, bindingContext, options, templateDocument) => {
var templateNodesFunc = templateSource.nodes,
templateNodes = templateNodesFunc ? templateSource.nodes() : null;
if (templateNodes) {

View file

@ -27,15 +27,15 @@
ko.templateEngine = function () { };
ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {
ko.templateEngine.prototype['renderTemplateSource'] = (templateSource, bindingContext, options, templateDocument) => {
throw new Error("Override renderTemplateSource");
};
ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = script => {
throw new Error("Override createJavaScriptEvaluatorBlock");
};
ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
ko.templateEngine.prototype['makeTemplateSource'] = (template, templateDocument) => {
// Named template
if (typeof template == "string") {
templateDocument = templateDocument || document;

View file

@ -1,5 +1,5 @@
ko.templateRewriting = (function () {
ko.templateRewriting = (() => {
var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
@ -35,23 +35,23 @@ ko.templateRewriting = (function () {
}
return {
ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
ensureTemplateIsRewritten: (template, templateEngine, templateDocument) => {
if (!templateEngine['isTemplateRewritten'](template, templateDocument))
templateEngine['rewriteTemplate'](template, function (htmlString) {
return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
}, templateDocument);
templateEngine['rewriteTemplate'](template, htmlString =>
ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine)
, templateDocument);
},
memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[4], /* tagToRetain: */ arguments[1], /* nodeName: */ arguments[2], templateEngine);
}).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", /* nodeName: */ "#comment", templateEngine);
});
memoizeBindingAttributeSyntax: (htmlString, templateEngine) => {
return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, (...args) =>
constructMemoizedTagReplacement(/* dataBindAttributeValue: */ args[4], /* tagToRetain: */ args[1], /* nodeName: */ args[2], templateEngine)
).replace(memoizeVirtualContainerBindingSyntaxRegex, (...args) =>
constructMemoizedTagReplacement(/* dataBindAttributeValue: */ args[1], /* tagToRetain: */ "<!-- ko -->", /* nodeName: */ "#comment", templateEngine)
);
},
applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {
return ko.memoization.memoize(function (domNode, bindingContext) {
applyMemoizedBindingsToNextSibling: (bindings, nodeName) => {
return ko.memoization.memoize((domNode, bindingContext) => {
var nodeToBind = domNode.nextSibling;
if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {
ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);

View file

@ -1,4 +1,4 @@
(function() {
(() => {
// A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
// logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
//
@ -54,22 +54,20 @@
if (arguments.length == 0) {
return this.domElement[elemContentsProperty];
} else {
var valueToWrite = arguments[0];
if (elemContentsProperty === "innerHTML")
ko.utils.setHtml(this.domElement, valueToWrite);
else
this.domElement[elemContentsProperty] = valueToWrite;
}
var valueToWrite = arguments[0];
if (elemContentsProperty === "innerHTML")
ko.utils.setHtml(this.domElement, valueToWrite);
else
this.domElement[elemContentsProperty] = valueToWrite;
};
var dataDomDataPrefix = ko.utils.domData.nextKey() + "_";
ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
if (arguments.length === 1) {
return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);
} else {
ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);
}
ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);
};
var templatesDomDataKey = ko.utils.domData.nextKey();
@ -99,13 +97,12 @@
}
}
return nodes;
} else {
var valueToWrite = arguments[0];
if (this.templateType !== undefined) {
this['text'](""); // clear the text from the node
}
setTemplateDomData(element, {containerData: valueToWrite});
}
var valueToWrite = arguments[0];
if (this.templateType !== undefined) {
this['text'](""); // clear the text from the node
}
setTemplateDomData(element, {containerData: valueToWrite});
};
// ---- ko.templateSources.anonymousTemplate -----
@ -115,7 +112,7 @@
ko.templateSources.anonymousTemplate = function(element) {
this.domElement = element;
}
};
ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;
ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
@ -124,10 +121,9 @@
if (templateData.textData === undefined && templateData.containerData)
templateData.textData = templateData.containerData.innerHTML;
return templateData.textData;
} else {
var valueToWrite = arguments[0];
setTemplateDomData(this.domElement, {textData: valueToWrite});
}
var valueToWrite = arguments[0];
setTemplateDomData(this.domElement, {textData: valueToWrite});
};
ko.exportSymbol('templateSources', ko.templateSources);

View file

@ -1,10 +1,10 @@
(function () {
var _templateEngine;
ko.setTemplateEngine = function (templateEngine) {
ko.setTemplateEngine = templateEngine => {
if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
throw new Error("templateEngine must inherit from ko.templateEngine");
_templateEngine = templateEngine;
}
};
function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {
var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
@ -29,7 +29,7 @@
preprocessNode = provider['preprocessNode'];
if (preprocessNode) {
invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {
invokeForEachNodeInContinuousRange(firstNode, lastNode, (node, nextNodeInRange) => {
var nodePreviousSibling = node.previousSibling;
var newNodes = preprocessNode.call(provider, node);
if (newNodes) {
@ -57,11 +57,11 @@
// Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
// whereas a regular applyBindings won't introduce new memoized nodes
invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
invokeForEachNodeInContinuousRange(firstNode, lastNode, node => {
if (node.nodeType === 1 || node.nodeType === 8)
ko.applyBindings(bindingContext, node);
});
invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
invokeForEachNodeInContinuousRange(firstNode, lastNode, node => {
if (node.nodeType === 1 || node.nodeType === 8)
ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
});
@ -122,13 +122,9 @@
if (ko.isObservable(template)) {
// 1. An observable, with string value
return template();
} else if (typeof template === 'function') {
// 2. A function of (data, context) returning a string
return template(data, context);
} else {
// 3. A string
return template;
}
// 2. A function of (data, context) returning a string ELSE 3. A string
return (typeof template === 'function') ? template(data, context) : template;
}
ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
@ -140,11 +136,11 @@
if (targetNodeOrNodeArray) {
var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
var whenToDispose = () => (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); // Passive disposal (on next evaluation)
var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
function () {
() => {
// Ensure we've got a proper binding context to work with
var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
? dataOrBindingContext
@ -163,24 +159,24 @@
);
} else {
// We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
return ko.memoization.memoize(function (domNode) {
ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
});
return ko.memoization.memoize(domNode =>
ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode")
);
}
};
ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
ko.renderTemplateForEach = (template, arrayOrObservableArray, options, targetNode, parentBindingContext) => {
// Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
// activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
var arrayItemContext, asName = options['as'];
// This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
var executeTemplateForArrayItem = function (arrayValue, index) {
var executeTemplateForArrayItem = (arrayValue, index) => {
// Support selecting template as a function of the data being rendered
arrayItemContext = parentBindingContext['createChildContext'](arrayValue, {
'as': asName,
'noChildContext': options['noChildContext'],
'extend': function(context) {
'extend': context => {
context['$index'] = index;
if (asName) {
context[asName + "Index"] = index;
@ -193,7 +189,7 @@
};
// This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
var activateBindingsCallback = (arrayValue, addedNodesArray) => {
activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
if (options['afterRender'])
options['afterRender'](addedNodesArray, arrayValue);
@ -215,21 +211,21 @@
if (!shouldHideDestroyed && !options['beforeRemove'] && ko.isObservableArray(arrayOrObservableArray)) {
setDomNodeChildrenFromArrayMapping(arrayOrObservableArray.peek());
var subscription = arrayOrObservableArray.subscribe(function (changeList) {
var subscription = arrayOrObservableArray.subscribe(changeList => {
setDomNodeChildrenFromArrayMapping(arrayOrObservableArray(), changeList);
}, null, "arrayChange");
subscription.disposeWhenNodeIsRemoved(targetNode);
return subscription;
} else {
return ko.dependentObservable(function () {
return ko.dependentObservable(() => {
var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
unwrappedArray = [unwrappedArray];
if (shouldHideDestroyed) {
// Filter out any entries marked as destroyed
unwrappedArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
unwrappedArray = ko.utils.arrayFilter(unwrappedArray, item => {
return item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
});
}
@ -249,7 +245,7 @@
var cleanContainerDomDataKey = ko.utils.domData.nextKey();
ko.bindingHandlers['template'] = {
'init': function(element, valueAccessor) {
'init': (element, valueAccessor) => {
// Support anonymous templates
var bindingValue = ko.utils.unwrapObservable(valueAccessor());
if (typeof bindingValue == "string" || 'name' in bindingValue) {
@ -267,7 +263,7 @@
// If the nodes are already attached to a KO-generated container, we reuse that container without moving the
// elements to a new one (we check only the first node, as the nodes are always moved together)
var container = nodes[0] && nodes[0].parentNode;
let container = nodes[0] && nodes[0].parentNode;
if (!container || !ko.utils.domData.get(container, cleanContainerDomDataKey)) {
container = ko.utils.moveCleanedNodesToContainerElement(nodes);
ko.utils.domData.set(container, cleanContainerDomDataKey, true);
@ -278,7 +274,7 @@
// It's an anonymous template - store the element contents, then clear the element
var templateNodes = ko.virtualElements.childNodes(element);
if (templateNodes.length > 0) {
var container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
let container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
new ko.templateSources.anonymousTemplate(element)['nodes'](container);
} else {
throw new Error("Anonymous template defined, but no template content was provided");
@ -286,7 +282,7 @@
}
return { 'controlsDescendantBindings': true };
},
'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
'update': (element, valueAccessor, allBindings, viewModel, bindingContext) => {
var value = valueAccessor(),
options = ko.utils.unwrapObservable(value),
shouldDisplay = true,
@ -336,7 +332,7 @@
};
// Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
ko.expressionRewriting.bindingRewriteValidators['template'] = bindingValue => {
var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])

View file

@ -3,18 +3,18 @@ ko.utils.domData = new (function () {
var uniqueId = 0;
var dataStoreKeyExpandoPropertyName = "__ko__" + (Date.now());
var getDataForNode, clear;
var
// We considered using WeakMap, but it has a problem in IE 11 and Edge that prevents using
// it cross-window, so instead we just store the data directly on the node.
// See https://github.com/knockout/knockout/issues/2141
getDataForNode = function (node, createIfNotFound) {
getDataForNode = (node, createIfNotFound) => {
var dataForNode = node[dataStoreKeyExpandoPropertyName];
if (!dataForNode && createIfNotFound) {
dataForNode = node[dataStoreKeyExpandoPropertyName] = {};
}
return dataForNode;
};
clear = function (node) {
},
clear = node => {
if (node[dataStoreKeyExpandoPropertyName]) {
delete node[dataStoreKeyExpandoPropertyName];
return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
@ -23,24 +23,22 @@ ko.utils.domData = new (function () {
};
return {
get: function (node, key) {
get: (node, key) => {
var dataForNode = getDataForNode(node, false);
return dataForNode && dataForNode[key];
},
set: function (node, key, value) {
set: (node, key, value) => {
// Make sure we don't actually create a new domData key if we are actually deleting a value
var dataForNode = getDataForNode(node, value !== undefined /* createIfNotFound */);
dataForNode && (dataForNode[key] = value);
},
getOrSet: function (node, key, value) {
getOrSet: (node, key, value) => {
var dataForNode = getDataForNode(node, true /* createIfNotFound */);
return dataForNode[key] || (dataForNode[key] = value);
},
clear: clear,
nextKey: function () {
return (uniqueId++) + dataStoreKeyExpandoPropertyName;
}
nextKey: () => (uniqueId++) + dataStoreKeyExpandoPropertyName
};
})();

View file

@ -1,4 +1,4 @@
(function () {
(() => {
var none = [0, "", ""],
table = [1, "<table>", "</table>"],
tbody = [2, "<table><tbody>", "</tbody></table>"],
@ -50,16 +50,15 @@
return ko.utils.makeArray(div.lastChild.childNodes);
}
ko.utils.parseHtmlFragment = function(html, documentContext) {
return simpleHtmlParse(html, documentContext); // ... otherwise, this simple logic will do in most common cases.
};
ko.utils.parseHtmlFragment = (html, documentContext) =>
simpleHtmlParse(html, documentContext); // ... otherwise, this simple logic will do in most common cases.
ko.utils.parseHtmlForTemplateNodes = function(html, documentContext) {
ko.utils.parseHtmlForTemplateNodes = (html, documentContext) => {
var nodes = ko.utils.parseHtmlFragment(html, documentContext);
return (nodes.length && nodes[0].parentElement) || ko.utils.moveCleanedNodesToContainerElement(nodes);
};
ko.utils.setHtml = function(node, html) {
ko.utils.setHtml = (node, html) => {
ko.utils.emptyDomNode(node);
// There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it

View file

@ -41,20 +41,20 @@ ko.utils.domNodeDisposal = new (function () {
if (!onlyComments || nodeList[i].nodeType === 8) {
cleanSingleNode(cleanedNodes[cleanedNodes.length] = lastCleanedNode = nodeList[i]);
if (nodeList[i] !== lastCleanedNode) {
while (i-- && ko.utils.arrayIndexOf(cleanedNodes, nodeList[i]) == -1) {}
while (i-- && ko.utils.arrayIndexOf(cleanedNodes, nodeList[i]) == -1);
}
}
}
}
return {
addDisposeCallback : function(node, callback) {
addDisposeCallback : (node, callback) => {
if (typeof callback != "function")
throw new Error("Callback must be a function");
getDisposeCallbacksCollection(node, true).push(callback);
},
removeDisposeCallback : function(node, callback) {
removeDisposeCallback : (node, callback) => {
var callbacksCollection = getDisposeCallbacksCollection(node, false);
if (callbacksCollection) {
ko.utils.arrayRemoveItem(callbacksCollection, callback);
@ -63,8 +63,8 @@ ko.utils.domNodeDisposal = new (function () {
}
},
cleanNode : function(node) {
ko.dependencyDetection.ignore(function () {
cleanNode : node => {
ko.dependencyDetection.ignore(() => {
// First clean this node, where applicable
if (cleanableNodeTypes[node.nodeType]) {
cleanSingleNode(node);
@ -79,7 +79,7 @@ ko.utils.domNodeDisposal = new (function () {
return node;
},
removeNode : function(node) {
removeNode : node => {
ko.cleanNode(node);
if (node.parentNode)
node.parentNode.removeChild(node);

View file

@ -1,20 +1,16 @@
ko.utils = (function () {
ko.utils = (() => {
function arrayCall(name, arr, p1, p2) {
return Array.prototype[name].call(arr, p1, p2);
}
function objectForEach(obj, action) {
obj && Object.entries(obj).forEach(function(prop) {
action(prop[0], prop[1]);
});
obj && Object.entries(obj).forEach(prop => action(prop[0], prop[1]));
}
function extend(target, source) {
if (source) {
Object.entries(source).forEach(function(prop) {
target[prop[0]] = prop[1];
});
Object.entries(source).forEach(prop => target[prop[0]] = prop[1]);
}
return target;
}
@ -31,22 +27,20 @@ ko.utils = (function () {
function toggleDomNodeCssClass(node, classNames, shouldHaveClass) {
if (classNames) {
var addOrRemoveFn = shouldHaveClass ? 'add' : 'remove';
classNames.split(/\s+/).forEach(function(className) {
node.classList[addOrRemoveFn](className);
});
classNames.split(/\s+/).forEach(className =>
node.classList[addOrRemoveFn](className)
);
}
}
return {
arrayForEach: function (array, action, actionOwner) {
arrayCall('forEach', array, action, actionOwner);
},
arrayForEach: (array, action, actionOwner) =>
arrayCall('forEach', array, action, actionOwner),
arrayIndexOf: function (array, item) {
return arrayCall('indexOf', array, item);
},
arrayIndexOf: (array, item) =>
arrayCall('indexOf', array, item),
arrayFirst: function (array, predicate, predicateOwner) {
arrayFirst: (array, predicate, predicateOwner) => {
for (var i = 0, j = array.length; i < j; i++) {
if (predicate.call(predicateOwner, array[i], i, array))
return array[i];
@ -54,7 +48,7 @@ ko.utils = (function () {
return undefined;
},
arrayRemoveItem: function (array, itemToRemove) {
arrayRemoveItem: (array, itemToRemove) => {
var index = ko.utils.arrayIndexOf(array, itemToRemove);
if (index > 0) {
array.splice(index, 1);
@ -64,11 +58,10 @@ ko.utils = (function () {
}
},
arrayFilter: function (array, predicate, predicateOwner) {
return array ? arrayCall('filter', array, predicate, predicateOwner) : [];
},
arrayFilter: (array, predicate, predicateOwner) =>
array ? arrayCall('filter', array, predicate, predicateOwner) : [],
arrayPushAll: function (array, valuesToPush) {
arrayPushAll: (array, valuesToPush) => {
if (valuesToPush instanceof Array)
array.push.apply(array, valuesToPush);
else
@ -87,48 +80,45 @@ ko.utils = (function () {
objectForEach: objectForEach,
objectMap: function(source, mapping, mappingOwner) {
objectMap: (source, mapping, mappingOwner) => {
if (!source)
return source;
var target = {};
Object.entries(source).forEach(function(prop) {
target[prop[0]] = mapping.call(mappingOwner, prop[1], prop[0], source);
});
Object.entries(source).forEach(prop =>
target[prop[0]] = mapping.call(mappingOwner, prop[1], prop[0], source)
);
return target;
},
emptyDomNode: function (domNode) {
emptyDomNode: domNode => {
while (domNode.firstChild) {
ko.removeNode(domNode.firstChild);
}
},
moveCleanedNodesToContainerElement: function(nodes) {
moveCleanedNodesToContainerElement: nodes => {
// Ensure it's a real array, as we're about to reparent the nodes and
// we don't want the underlying collection to change while we're doing that.
var nodesArray = ko.utils.makeArray(nodes);
var templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document;
var container = templateDocument.createElement('div');
nodes.forEach(function(node){container.append(ko.cleanNode(node));});
nodes.forEach(node => container.append(ko.cleanNode(node)));
return container;
},
cloneNodes: function (nodesArray, shouldCleanNodes) {
return arrayCall('map', nodesArray, shouldCleanNodes
? function(node){return ko.cleanNode(node.cloneNode(true));}
: function(node){return node.cloneNode(true);}
);
},
cloneNodes: (nodesArray, shouldCleanNodes) =>
arrayCall('map', nodesArray, shouldCleanNodes
? node => ko.cleanNode(node.cloneNode(true))
: node => node.cloneNode(true)
),
setDomNodeChildren: function (domNode, childNodes) {
setDomNodeChildren: (domNode, childNodes) => {
ko.utils.emptyDomNode(domNode);
if (childNodes) {
domNode.append.apply(domNode, childNodes);
}
childNodes && domNode.append.apply(domNode, childNodes);
},
replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
replaceDomNodes: (nodeToReplaceOrNodeArray, newNodesArray) => {
var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType
? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
if (nodesToReplaceArray.length > 0) {
@ -143,7 +133,7 @@ ko.utils = (function () {
}
},
fixUpContinuousNodeArray: function(continuousNodeArray, parentNode) {
fixUpContinuousNodeArray: (continuousNodeArray, parentNode) => {
// Before acting on a set of nodes that were previously outputted by a template function, we have to reconcile
// them against what is in the DOM right now. It may be that some of the nodes have already been removed, or that
// new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
@ -188,40 +178,31 @@ ko.utils = (function () {
return continuousNodeArray;
},
stringTrim: function (string) {
return string === null || string === undefined ? '' :
stringTrim: string => string === null || string === undefined ? '' :
string.trim ?
string.trim() :
string.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
},
string.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''),
stringStartsWith: function (string, startsWith) {
stringStartsWith: (string, startsWith) => {
string = string || "";
if (startsWith.length > string.length)
return false;
return string.substring(0, startsWith.length) === startsWith;
},
domNodeIsContainedBy: function (node, containedByNode) {
return containedByNode.contains(node.nodeType !== 1 ? node.parentNode : node);
},
domNodeIsContainedBy: (node, containedByNode) =>
containedByNode.contains(node.nodeType !== 1 ? node.parentNode : node),
domNodeIsAttachedToDocument: function (node) {
return ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement);
},
domNodeIsAttachedToDocument: node => ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement),
anyDomNodeIsAttachedToDocument: function(nodes) {
return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);
},
anyDomNodeIsAttachedToDocument: nodes => !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument),
tagNameLower: function(element) {
// For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
// Possible future optimization: If we know it's an element from an XHTML document (not HTML),
// we don't need to do the .toLowerCase() as it will always be lower case anyway.
return element && element.tagName && element.tagName.toLowerCase();
},
// For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
// Possible future optimization: If we know it's an element from an XHTML document (not HTML),
// we don't need to do the .toLowerCase() as it will always be lower case anyway.
tagNameLower: element => element && element.tagName && element.tagName.toLowerCase(),
catchFunctionErrors: function (delegate) {
catchFunctionErrors: delegate => {
return ko['onError'] ? function () {
try {
return delegate.apply(this, arguments);
@ -232,41 +213,33 @@ ko.utils = (function () {
} : delegate;
},
setTimeout: function (handler, timeout) {
return setTimeout(ko.utils.catchFunctionErrors(handler), timeout);
},
setTimeout: (handler, timeout) => setTimeout(ko.utils.catchFunctionErrors(handler), timeout),
deferError: function (error) {
setTimeout(function () {
deferError: error => setTimeout(() => {
ko['onError'] && ko['onError'](error);
throw error;
}, 0);
},
}, 0),
registerEventHandler: function (element, eventType, handler) {
registerEventHandler: (element, eventType, handler) => {
var wrappedHandler = ko.utils.catchFunctionErrors(handler);
element.addEventListener(eventType, wrappedHandler, false);
},
triggerEvent: function (element, eventType) {
triggerEvent: (element, eventType) => {
if (!(element && element.nodeType))
throw new Error("element must be a DOM node when calling triggerEvent");
element.dispatchEvent(new Event(eventType));
},
unwrapObservable: function (value) {
return ko.isObservable(value) ? value() : value;
},
unwrapObservable: value => ko.isObservable(value) ? value() : value,
peekObservable: function (value) {
return ko.isObservable(value) ? value.peek() : value;
},
peekObservable: value => ko.isObservable(value) ? value.peek() : value,
toggleDomNodeCssClass: toggleDomNodeCssClass,
setTextContent: function(element, textContent) {
setTextContent: (element, textContent) => {
var value = ko.utils.unwrapObservable(textContent);
if ((value === null) || (value === undefined))
value = "";
@ -282,11 +255,9 @@ ko.utils = (function () {
}
},
makeArray: function(arrayLikeObject) {
return Array['from'](arrayLikeObject);
}
makeArray: arrayLikeObject => Array['from'](arrayLikeObject)
}
}());
})();
ko.exportSymbol('utils', ko.utils);
ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);

View file

@ -1,4 +1,4 @@
(function() {
(() => {
// "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
// may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
// If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
@ -52,18 +52,16 @@
if (allVirtualChildren.length > 0)
return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
return startComment.nextSibling;
} else
return null; // Must have no matching end comment, and allowUnbalanced is true
}
return null; // Must have no matching end comment, and allowUnbalanced is true
}
ko.virtualElements = {
allowedBindings: {},
childNodes: function(node) {
return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
},
childNodes: node => isStartComment(node) ? getVirtualChildren(node) : node.childNodes,
emptyNode: function(node) {
emptyNode: node => {
if (!isStartComment(node))
ko.utils.emptyDomNode(node);
else {
@ -73,7 +71,7 @@
}
},
setDomNodeChildren: function(node, childNodes) {
setDomNodeChildren: (node, childNodes) => {
if (!isStartComment(node))
ko.utils.setDomNodeChildren(node, childNodes);
else {
@ -84,7 +82,7 @@
}
},
prepend: function(containerNode, nodeToPrepend) {
prepend: (containerNode, nodeToPrepend) => {
var insertBeforeNode;
if (isStartComment(containerNode)) {
@ -98,7 +96,7 @@
containerNode.insertBefore(nodeToPrepend, insertBeforeNode);
},
insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
insertAfter: (containerNode, nodeToInsert, insertAfterNode) => {
if (!insertAfterNode) {
ko.virtualElements.prepend(containerNode, nodeToInsert);
} else {
@ -113,20 +111,17 @@
}
},
firstChild: function(node) {
firstChild: node => {
if (!isStartComment(node)) {
if (node.firstChild && isEndComment(node.firstChild)) {
throw new Error("Found invalid end comment, as the first child of " + node);
}
return node.firstChild;
} else if (!node.nextSibling || isEndComment(node.nextSibling)) {
return null;
} else {
return node.nextSibling;
}
return (!node.nextSibling || isEndComment(node.nextSibling)) ? null : node.nextSibling;
},
nextSibling: function(node) {
nextSibling: node => {
if (isStartComment(node)) {
node = getMatchingEndComment(node);
}
@ -134,17 +129,15 @@
if (node.nextSibling && isEndComment(node.nextSibling)) {
if (isUnmatchedEndComment(node.nextSibling)) {
throw Error("Found end comment without a matching opening comment, as child of " + node);
} else {
return null;
}
} else {
return node.nextSibling;
return null;
}
return node.nextSibling;
},
hasBindingValue: isStartComment,
virtualNodeBindingValue: function(node) {
virtualNodeBindingValue: node => {
var regexMatch = (node.nodeValue).match(startCommentRegex);
return regexMatch ? regexMatch[1] : null;
}