- commit
- cddee052173f6a3a7ab401963a9f78f92016f8ad
- parent
- 37db3ac93095dea97f496ba0f0fa94bc03440395
- Author
- Tobias Bengfort <tobias.bengfort@gmx.net>
- Date
- 2015-08-28 19:31
Merge branch 'feature-refactor-template'
Diffstat
| M | src/muu-template.js | 194 | +++++++++++++++++++++++++++++++------------------------------ |
1 files changed, 100 insertions, 94 deletions
diff --git a/src/muu-template.js b/src/muu-template.js
@@ -68,19 +68,28 @@ define('muu-template', ['muu-js-helpers', 'muu-dom-helpers'], function(_, $) {
68 68 var openTag = '{{';
69 69 var closeTag = '}}';
70 70
-1 71 /**
-1 72 * @param {string} key
-1 73 * @param {Object} data
-1 74 * @return {*}
-1 75 * @nosideeffects
-1 76 */
71 77 var getValue = function(key, data) {
72 78 return key === 'this' ? data : data[key];
73 79 };
74 80
75 -1 var parseVariableTemplate = function(template) {
76 -1 var content = template.slice(2, -2);
77 -1
78 -1 if (template.indexOf(':') === -1) {
-1 81 /**
-1 82 * @param {string} tag
-1 83 * @return {function(*): string}
-1 84 * @nosideeffects
-1 85 */
-1 86 var parseVariable = function(tag) {
-1 87 if (tag.indexOf(':') === -1) {
79 88 return function(data) {
80 -1 return $.escapeHtml(getValue(content, data) || '');
-1 89 return $.escapeHtml(getValue(tag, data) || '');
81 90 };
82 91 } else {
83 -1 var pairs = content.split(',').map(function(pair) {
-1 92 var pairs = _.map(tag.split(','), function(pair) {
84 93 var v = pair.split(':');
85 94 var key = v[0].trim();
86 95 var value = v.slice(1).join(':').trim();
@@ -88,81 +97,65 @@ define('muu-template', ['muu-js-helpers', 'muu-dom-helpers'], function(_, $) {
88 97 });
89 98
90 99 return function(data) {
91 -1 var results = [];
92 -1
93 -1 for (var i = 0; i < pairs.length; i++) {
94 -1 var key = pairs[i][0];
95 -1 var value = pairs[i][1];
96 -1
97 -1 if (getValue(value, data)) {
98 -1 results.push(key);
99 -1 }
100 -1 }
-1 100 var results = _.map(_.filter(pairs, function(pair) {
-1 101 return getValue(pair[1], data);
-1 102 }), function(pair) {
-1 103 return pair[0];
-1 104 });
101 105
102 106 return $.escapeHtml(results.join(' '));
103 107 };
104 108 }
105 109 };
106 110
107 -1 var parseLoopTemplate = function(tag, afterTag, inverted) {
108 -1 var tagName = tag.slice(3, -2);
109 -1
110 -1 var v = parseTemplate(afterTag, tagName);
111 -1 var inner = v[0];
112 -1 var afterLoop = v[1];
113 -1
114 -1 var render = function(data) {
115 -1 if (inverted) {
116 -1 if (getValue(tagName, data)) {
117 -1 return '';
118 -1 } else {
119 -1 return inner(data);
120 -1 }
121 -1 } else {
122 -1 if (_.isArray(getValue(tagName, data))) {
123 -1 var result = '';
124 -1 for (var i = 0; i < getValue(tagName, data).length; i++) {
125 -1 result += inner(getValue(tagName, data)[i]);
-1 111 /**
-1 112 * @param {string} tag
-1 113 * @param {string} afterTag
-1 114 * @param {boolean} [inverted]
-1 115 * @return {{render: function(*): string, afterBlock: string}}
-1 116 * @nosideeffects
-1 117 */
-1 118 var parseLoop = function(tag, afterTag, inverted) {
-1 119 var inner = parseTemplate(afterTag, tag);
-1 120
-1 121 return {
-1 122 render: function(data) {
-1 123 var value = getValue(tag, data);
-1 124 var result = '';
-1 125
-1 126 if (inverted) {
-1 127 if (!value) {
-1 128 result += inner.render(data);
126 129 }
127 -1 return result;
128 -1 } else if (getValue(tagName, data)) {
129 -1 return inner(data);
130 130 } else {
131 -1 return '';
-1 131 if (_.isArray(value)) {
-1 132 for (var i = 0; i < value.length; i++) {
-1 133 result += inner.render(value[i]);
-1 134 }
-1 135 } else if (value) {
-1 136 result += inner.render(data);
-1 137 }
132 138 }
133 -1 }
134 -1 };
135 139
136 -1 return [render, afterLoop];
137 -1 };
138 -1
139 -1 var concat = function(a) {
140 -1 var last = a.pop();
141 -1
142 -1 if (_.isArray(last)) {
143 -1 a.push(last[0]);
144 -1 return [concat(a), last[1]];
145 -1 } else {
146 -1 a.push(last);
147 -1
148 -1 return function(data) {
149 -1 return a.map(function(item) {
150 -1 if (_.isString(item)) {
151 -1 return item;
152 -1 } else if (_.isFunction(item)) {
153 -1 return item(data);
154 -1 }
155 -1 }).join('');
156 -1 };
157 -1 }
-1 140 return result;
-1 141 },
-1 142 afterBlock: inner.afterBlock
-1 143 };
158 144 };
159 145
-1 146 /**
-1 147 * @param {string} template
-1 148 * @param {string} [loopName]
-1 149 * @return {{render: function(*): string, afterBlock: string}}
-1 150 * @nosideeffects
-1 151 */
160 152 var parseTemplate = function(template, loopName) {
161 153 var openIndex = template.indexOf(openTag);
162 154 if (openIndex === -1) {
163 155 if (loopName === undefined) {
164 -1 return function() {
165 -1 return template;
-1 156 return {
-1 157 render: function() { return template; },
-1 158 afterBlock: ''
166 159 };
167 160 } else {
168 161 throw new Error('unclosed loop: ' + loopName);
@@ -171,44 +164,57 @@ define('muu-template', ['muu-js-helpers', 'muu-dom-helpers'], function(_, $) {
171 164 var beforeTag = template.slice(0, openIndex);
172 165 var tmp = template.slice(openIndex);
173 166
174 -1 var closeIndex = tmp.indexOf(closeTag) + 2;
175 -1 if (closeIndex === 1) {
-1 167 var closeIndex = tmp.indexOf(closeTag);
-1 168 if (closeIndex === -1) {
176 169 throw new Error('unclosed tag: ' + tmp);
177 170 }
178 -1 var tag = tmp.slice(0, closeIndex);
179 -1 var afterTag = tmp.slice(closeIndex);
180 -1
181 -1 if (tag.lastIndexOf('{{#', 0) === 0) {
182 -1 var v = parseLoopTemplate(tag, afterTag);
183 -1 var loop = v[0];
184 -1 var after = parseTemplate(v[1], loopName);
185 -1 return concat([beforeTag, loop, after]);
186 -1 } else if (tag.lastIndexOf('{{^', 0) === 0) {
187 -1 var v = parseLoopTemplate(tag, afterTag, true);
188 -1 var loop = v[0];
189 -1 var after = parseTemplate(v[1], loopName);
190 -1 return concat([beforeTag, loop, after]);
191 -1 } else if (tag.lastIndexOf('{{!', 0) === 0) {
192 -1 var after = parseTemplate(afterTag, loopName);
193 -1 return concat([beforeTag, after]);
194 -1 } else if (tag.lastIndexOf('{{/', 0) === 0) {
195 -1 if (tag.slice(3, -2) === loopName) {
196 -1 var render = function() {
197 -1 return beforeTag;
198 -1 };
199 -1 return [render, afterTag];
200 -1 } else {
-1 171 var tag = tmp.slice(openTag.length, closeIndex);
-1 172 var afterTag = tmp.slice(closeIndex + closeTag.length);
-1 173
-1 174 var loadNext = true;
-1 175 var current = {
-1 176 render: function() { return ''; },
-1 177 afterBlock: afterTag
-1 178 };
-1 179
-1 180 if (tag.lastIndexOf('#', 0) === 0) {
-1 181 current = parseLoop(tag.substr(1), afterTag);
-1 182 } else if (tag.lastIndexOf('^', 0) === 0) {
-1 183 current = parseLoop(tag.substr(1), afterTag, true);
-1 184 } else if (tag.lastIndexOf('/', 0) === 0) {
-1 185 loadNext = false;
-1 186 if (tag.substr(1) !== loopName) {
201 187 throw new Error('unexpected closing loop: ' + tag);
202 188 }
-1 189 } else if (tag.lastIndexOf('!', 0) !== 0) {
-1 190 current.render = parseVariable(tag);
-1 191 }
-1 192
-1 193 if (loadNext) {
-1 194 var next = parseTemplate(current.afterBlock, loopName);
-1 195 return {
-1 196 render: function(data) {
-1 197 return beforeTag + current.render(data) + next.render(data);
-1 198 },
-1 199 afterBlock: next.afterBlock
-1 200 };
203 201 } else {
204 -1 var render = parseVariableTemplate(tag);
205 -1 var after = parseTemplate(afterTag, loopName);
206 -1 return concat([beforeTag, render, after]);
-1 202 return {
-1 203 render: function(data) {
-1 204 return beforeTag + current.render(data);
-1 205 },
-1 206 afterBlock: current.afterBlock
-1 207 };
207 208 }
208 209 }
209 210 };
210 211
-1 212 var cache = {};
-1 213
211 214 return function(template, data) {
212 -1 return parseTemplate(template)(data);
-1 215 if (cache[template] === undefined) {
-1 216 cache[template] = parseTemplate(template);
-1 217 }
-1 218 return cache[template].render(data);
213 219 };
214 220 });