2 // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
3 // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
5 // Two are provided by default:
6 // 1. ko.templateSources.domElement - reads/writes the text content of an arbitrary DOM element
7 // 2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
8 // without reading/writing the actual element text content, since it will be overwritten
9 // with the rendered template output.
10 // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
11 // Template sources need to have the following functions:
12 // text() - returns the template text from your storage location
13 // text(value) - writes the supplied template text to your storage location
14 // data(key) - reads values stored using data(key, value) - see below
15 // data(key, value) - associates "value" with this template and the key "key". Is used to store information like "isRewritten".
17 // Optionally, template sources can also have the following functions:
18 // nodes() - returns a DOM element containing the nodes of this template, where available
19 // nodes(value) - writes the given DOM element to your storage location
20 // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
21 // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
23 // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
24 // using and overriding "makeTemplateSource" to return an instance of your custom template source.
26 ko.templateSources = {};
28 // ---- ko.templateSources.domElement -----
31 var templateScript = 1,
36 ko.templateSources.domElement = function(element) {
37 this.domElement = element;
40 var tagNameLower = ko.utils.tagNameLower(element);
42 tagNameLower === "script" ? templateScript :
43 tagNameLower === "textarea" ? templateTextArea :
44 // For browsers with proper <template> element support, where the .content property gives a document fragment
45 tagNameLower == "template" && element.content && element.content.nodeType === 11 ? templateTemplate :
50 ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
51 var elemContentsProperty = this.templateType === templateScript ? "text"
52 : this.templateType === templateTextArea ? "value"
55 if (arguments.length == 0) {
56 return this.domElement[elemContentsProperty];
58 var valueToWrite = arguments[0];
59 if (elemContentsProperty === "innerHTML")
60 ko.utils.setHtml(this.domElement, valueToWrite);
62 this.domElement[elemContentsProperty] = valueToWrite;
66 var dataDomDataPrefix = ko.utils.domData.nextKey() + "_";
67 ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
68 if (arguments.length === 1) {
69 return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);
71 ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);
75 var templatesDomDataKey = ko.utils.domData.nextKey();
76 function getTemplateDomData(element) {
77 return ko.utils.domData.get(element, templatesDomDataKey) || {};
79 function setTemplateDomData(element, data) {
80 ko.utils.domData.set(element, templatesDomDataKey, data);
83 ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
84 var element = this.domElement;
85 if (arguments.length == 0) {
86 var templateData = getTemplateDomData(element),
87 containerData = templateData.containerData;
88 return containerData || (
89 this.templateType === templateTemplate ? element.content :
90 this.templateType === templateElement ? element :
93 var valueToWrite = arguments[0];
94 setTemplateDomData(element, {containerData: valueToWrite});
98 // ---- ko.templateSources.anonymousTemplate -----
99 // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
100 // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
101 // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
103 ko.templateSources.anonymousTemplate = function(element) {
104 this.domElement = element;
106 ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
107 ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;
108 ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
109 if (arguments.length == 0) {
110 var templateData = getTemplateDomData(this.domElement);
111 if (templateData.textData === undefined && templateData.containerData)
112 templateData.textData = templateData.containerData.innerHTML;
113 return templateData.textData;
115 var valueToWrite = arguments[0];
116 setTemplateDomData(this.domElement, {textData: valueToWrite});
120 ko.exportSymbol('templateSources', ko.templateSources);
121 ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
122 ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);