forked from knockout/knockout
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtemplateRewriting.js
66 lines (56 loc) · 3.76 KB
/
templateRewriting.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
ko.templateRewriting = (function () {
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;
function validateDataBindValuesForRewriting(keyValueArray) {
var allValidators = ko.expressionRewriting.bindingRewriteValidators;
for (var i = 0; i < keyValueArray.length; i++) {
var key = keyValueArray[i]['key'];
if (allValidators.hasOwnProperty(key)) {
var validator = allValidators[key];
if (typeof validator === "function") {
var possibleErrorMessage = validator(keyValueArray[i]['value']);
if (possibleErrorMessage)
throw new Error(possibleErrorMessage);
} else if (!validator) {
throw new Error("This template engine does not support the '" + key + "' binding within its templates");
}
}
}
}
function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, nodeName, templateEngine) {
var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
validateDataBindValuesForRewriting(dataBindKeyValueArray);
var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray, {'valueAccessors':true});
// For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
// anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
// extra indirection.
var applyBindingsToNextSiblingScript =
"ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()},'" + nodeName.toLowerCase() + "')";
return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
}
return {
ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
if (!templateEngine['isTemplateRewritten'](template, templateDocument))
templateEngine['rewriteTemplate'](template, function (htmlString) {
return 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);
});
},
applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {
return ko.memoization.memoize(function (domNode, bindingContext) {
var nodeToBind = domNode.nextSibling;
if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {
ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);
}
});
}
}
})();
// Exported only because it has to be referenced by string lookup from within rewritten template
ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);