- commit
- b9ede1986fab336dc43c2a93fdeec5a896f7ea68
- parent
- 37db3ac93095dea97f496ba0f0fa94bc03440395
- Author
- Tobias Bengfort <tobias.bengfort@gmx.net>
- Date
- 2015-08-28 17:05
refactor template
Diffstat
| M | src/muu-template.js | 209 | ++++++++++++++++++++++++++++++++++++------------------------- |
1 files changed, 125 insertions, 84 deletions
diff --git a/src/muu-template.js b/src/muu-template.js
@@ -68,26 +68,40 @@ 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) {
79 -1 return function(data) {
80 -1 return $.escapeHtml(getValue(content, data) || '');
-1 81 /**
-1 82 * @param {string} tag
-1 83 * @param {string} afterTag
-1 84 * @param {string} loopName
-1 85 * @return {{render: function(*): string, afterBlock: string}}
-1 86 * @nosideeffects
-1 87 */
-1 88 var parseVariable = function(tag, afterTag, loopName) {
-1 89 var next = parseTemplate(afterTag, loopName);
-1 90 var render;
-1 91
-1 92 if (tag.indexOf(':') === -1) {
-1 93 render = function(data) {
-1 94 return $.escapeHtml(getValue(tag, data) || '');
81 95 };
82 96 } else {
83 -1 var pairs = content.split(',').map(function(pair) {
-1 97 var pairs = _.map(tag.split(','), function(pair) {
84 98 var v = pair.split(':');
85 99 var key = v[0].trim();
86 100 var value = v.slice(1).join(':').trim();
87 101 return [key, value];
88 102 });
89 103
90 -1 return function(data) {
-1 104 render = function(data) {
91 105 var results = [];
92 106
93 107 for (var i = 0; i < pairs.length; i++) {
@@ -102,67 +116,98 @@ define('muu-template', ['muu-js-helpers', 'muu-dom-helpers'], function(_, $) {
102 116 return $.escapeHtml(results.join(' '));
103 117 };
104 118 }
105 -1 };
106 119
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];
-1 120 return {
-1 121 render: function(data) {
-1 122 return render(data) + next.render(data, loopName);
-1 123 },
-1 124 afterBlock: next.afterBlock
-1 125 };
-1 126 };
113 127
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 128 /**
-1 129 * @param {string} tag
-1 130 * @param {string} afterTag
-1 131 * @param {string} loopName
-1 132 * @param {boolean} [inverted]
-1 133 * @return {{render: function(*): string, afterBlock: string}}
-1 134 * @nosideeffects
-1 135 */
-1 136 var parseLoop = function(tag, afterTag, loopName, inverted) {
-1 137 var inner = parseTemplate(afterTag, tag);
-1 138 var next = parseTemplate(inner.afterBlock, loopName);
-1 139
-1 140 return {
-1 141 render: function(data) {
-1 142 var value = getValue(tag, data);
-1 143 var result = '';
-1 144
-1 145 if (inverted) {
-1 146 if (!value) {
-1 147 result += inner.render(data);
126 148 }
127 -1 return result;
128 -1 } else if (getValue(tagName, data)) {
129 -1 return inner(data);
130 149 } else {
131 -1 return '';
-1 150 if (_.isArray(value)) {
-1 151 for (var i = 0; i < value.length; i++) {
-1 152 result += inner.render(value[i]);
-1 153 }
-1 154 } else if (value) {
-1 155 result += inner.render(data);
-1 156 }
132 157 }
133 -1 }
134 -1 };
135 158
136 -1 return [render, afterLoop];
-1 159 return result + next.render(data);
-1 160 },
-1 161 afterBlock: next.afterBlock
-1 162 };
137 163 };
138 164
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('');
-1 165 /**
-1 166 * @param {string} tag
-1 167 * @param {string} afterTag
-1 168 * @param {string} loopName
-1 169 * @return {{render: function(*): string, afterBlock: string}}
-1 170 * @nosideeffects
-1 171 */
-1 172 var parseClose = function(tag, afterTag, loopName) {
-1 173 if (tag === loopName) {
-1 174 return {
-1 175 render: function(data) {
-1 176 return '';
-1 177 },
-1 178 afterBlock: afterTag
156 179 };
-1 180 } else {
-1 181 throw new Error('unexpected closing loop: ' + tag);
157 182 }
158 183 };
159 184
-1 185 /**
-1 186 * @param {string} tag
-1 187 * @param {string} afterTag
-1 188 * @param {string} loopName
-1 189 * @return {{render: function(*): string, afterBlock: string}}
-1 190 * @nosideeffects
-1 191 */
-1 192 var parseComment = function(tag, afterTag, loopName) {
-1 193 return parseTemplate(afterTag, loopName);
-1 194 };
-1 195
-1 196 /**
-1 197 * @param {string} template
-1 198 * @param {string} loopName
-1 199 * @return {{render: function(*): string, afterBlock: string}}
-1 200 * @nosideeffects
-1 201 */
160 202 var parseTemplate = function(template, loopName) {
161 203 var openIndex = template.indexOf(openTag);
162 204 if (openIndex === -1) {
163 205 if (loopName === undefined) {
164 -1 return function() {
165 -1 return template;
-1 206 return {
-1 207 render: function(data) {
-1 208 return template;
-1 209 },
-1 210 afterBlock: ''
166 211 };
167 212 } else {
168 213 throw new Error('unclosed loop: ' + loopName);
@@ -171,44 +216,40 @@ define('muu-template', ['muu-js-helpers', 'muu-dom-helpers'], function(_, $) {
171 216 var beforeTag = template.slice(0, openIndex);
172 217 var tmp = template.slice(openIndex);
173 218
174 -1 var closeIndex = tmp.indexOf(closeTag) + 2;
175 -1 if (closeIndex === 1) {
-1 219 var closeIndex = tmp.indexOf(closeTag);
-1 220 if (closeIndex === -1) {
176 221 throw new Error('unclosed tag: ' + tmp);
177 222 }
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 {
201 -1 throw new Error('unexpected closing loop: ' + tag);
202 -1 }
-1 223 var tag = tmp.slice(openTag.length, closeIndex);
-1 224 var afterTag = tmp.slice(closeIndex + closeTag.length);
-1 225
-1 226 var next;
-1 227 if (tag.lastIndexOf('#', 0) === 0) {
-1 228 next = parseLoop(tag.substr(1), afterTag, loopName);
-1 229 } else if (tag.lastIndexOf('^', 0) === 0) {
-1 230 next = parseLoop(tag.substr(1), afterTag, loopName, true);
-1 231 } else if (tag.lastIndexOf('!', 0) === 0) {
-1 232 next = parseComment(tag.substr(1), afterTag, loopName);
-1 233 } else if (tag.lastIndexOf('/', 0) === 0) {
-1 234 next = parseClose(tag.substr(1), afterTag, loopName);
203 235 } else {
204 -1 var render = parseVariableTemplate(tag);
205 -1 var after = parseTemplate(afterTag, loopName);
206 -1 return concat([beforeTag, render, after]);
-1 236 next = parseVariable(tag, afterTag, loopName);
207 237 }
-1 238
-1 239 return {
-1 240 render: function(data) {
-1 241 return beforeTag + next.render(data);
-1 242 },
-1 243 afterBlock: next.afterBlock
-1 244 };
208 245 }
209 246 };
210 247
211 248 return function(template, data) {
212 -1 return parseTemplate(template)(data);
-1 249 var parsed = parseTemplate(template);
-1 250 if (parsed.afterBlock) {
-1 251 throw new Error('non-empty afterBlock');
-1 252 }
-1 253 return parsed.render(data);
213 254 };
214 255 });