KnockoutJS to ES2015/ES6

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

View file

@ -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'])