Icontem

File: templ.js

Recommend this page to a friend!
  Classes of Aliaksandr Astashenkau  >  Templ  >  templ.js  >  Download  
File: templ.js
Role: Class source
Content type: text/plain
Description: Source
Class: Templ
Processes templates embedded in the pages
Author: By
Last change: Bug fix
Date: 8 years ago
Size: 4,973 bytes
 

Contents

Class file image Download
/**
 * Copyright (c) 2011 Aliaksandr Astashenkau
 * @author-website http://dfsq.info
 * @license MIT License
 */
(function() {
	this.Templ = function(tmplStr, tmplData) {
		var id = 1;
		var tokens = {};

		var proccessMarkers = function(str) {
			var i = 0;
			while (i < str.length) {
				if (str.charAt(i) + str.charAt(i+1) == '{{') {
					var id = getId();
					var end = str.indexOf('}}', i);
					var buffer = str.slice(i+2, end).replace(/(^\s*)|(\s*$)/g, '').split('|');
					tokens[id] = {
						buffer: buffer.shift(),
						modif: buffer
					};
					str = replaceWith(str, '{__' + id + '}', i, end+2);
				}
				i++;
			}
			return str;
		};

		var proccessControls = function(str, i, lookingFor, exprDescr) {
			var from = i;
			while (i < str.length) {
				if (str.charAt(i) + str.charAt(i+1) == '{%') {
					var expr = str.slice(i+2, str.indexOf('%}', i));

					if (lookingFor && expr.match(lookingFor)) {
						var id = getId();
						var start = from - 2;
						var end = i + expr.length + 4;
						tokens[id] = {
							buffer: str.slice(start, end),
							expr: exprDescr
						};
						return replaceWith(str, '{__' + id + '}', start, end);
					}
					else {
						var exprFor = expr.match(/\s*for\s+((?:\w+\s*,)?\s*\w+)\s+in\s+([\w.]+)\s*/i);
						if (exprFor) {
							str = proccessControls(str, i+2, /\s*endfor\s*/i, {
								type: 'for',
								elem: exprFor[1],
								list: exprFor[2]
							});
						}
						else {
							var exprIf = expr.match(/\s*if\s+(.+)\s*/i);
							if (exprIf) {
								str = proccessControls(str, i+2, /\s*endif\s*/i, {
									type: 'if',
									cond: exprIf[1]
								});
							}
						}
					}
				}
				i++;
			}
			return str;
		};

		var parse = function(str, data) {
			str = str.replace(/{__(\d+?)}/g, function(a, b) {
				var token = tokens[b];
				if (!token.expr) {
					var repl = evl(data, tokens[b].buffer, 'TEMPL ERROR: Undefined variable "' + tokens[b].buffer + '".');
					if (token.modif.length) {
						for (var i in token.modif) {
							var modif = token.modif[i];
							var params = [];
							var check = token.modif[i].match(/(\w+)\(([\s\S]+)\)/);
							if (check) {
								modif  = check[1];
								params = check[2].split(/\s*,\s*/);
								with (data) for (var j in params) {
									params[j] = eval(params[j]);
								}
							}
							params.unshift(repl);
							modif = Templ.modifiers[modif] || window[modif];

							if (typeof modif != 'function') {
								throw new Error('TEMPL ERROR: Unknown modifier "' + token.modif[i] + '".');
							}

							repl = modif.apply(this, params);
						}
					}
					return repl;
				}
				else {
					switch (token.expr.type) {
						case 'if':
							var cond = evl(data, token.expr.cond, 'TEMPL ERROR: invalid condition: ' + token.expr.cond + '.');
							var block = token.buffer.match(cond
								? /{%\s*if\s+.+?\s*%}([\s\S]*?){%/i
								: /{%\s*else\s*%}([\s\S]*?){%/i
							);
							return block ? parse(block[1], data) : '';

						case 'for':
							with (data) {
								var loopData = eval(token.expr.list);
							}
							if (typeof loopData == 'undefined') {
								throw new Error('TEMPL ERROR: Undefined list "' + token.expr.list + '".');
							}
							if (hasElements(loopData)) {
								var block = token.buffer.match(/{%\s*for.*?\s*%}([\s\S]*?){%/i);
								if (block) {
									var key;
									var elem = token.expr.elem;
									var split = elem.split(/\s*,\s*/);
									if (split.length == 2) {
										key = split[0];
										elem = split[1];
									}

									var subStr = '';
									for (var k in loopData) {
										var tmpObj = {};
										if (key) tmpObj[key] = k;
										tmpObj[elem] = loopData[k];
										subStr += parse(block[1], tmpObj);
									}
									return subStr;
								}
								return '';
							}
							else {
								var block = token.buffer.match(/{%\s*else\s*%}([\s\S]*?){%/i);
								return block ? parse(block[1], loopData) : '';
							}
					}
				}
			});
			return str;
		};

		var tokenize = function(str) {
			return proccessControls(proccessMarkers(str), 0);
		};

		var evl = function(data, buffer, err) {
			var ret;
			with (data) try {
				ret = eval(buffer);
			}
			catch (e) {
				try {
					with (tmplData) {
						ret = eval(buffer);
					}
				}
				catch (e) {
					throw new Error(err);
				}
			}
			return ret;
		};

		var getId = function() {
			return id++;
		};

		var replaceWith = function(str, replace, start, end) {
			return str.substr(0, start) + replace + str.substr(end);
		};

		var hasElements = function(obj) {
			if (obj.hasOwnProperty('length')) return Boolean(obj.length);
			for (var k in obj) {
				if (obj.hasOwnProperty(k)) return true;
			}
			return false;
		};

		var init = function() {
			return parse(tokenize(tmplStr), tmplData);
		};

		return init();
	};

	this.Templ.modifiers = {};

	this.Templ.addModifiers = function(obj) {
		for (var i in obj) this.modifiers[i] = obj[i];
	};
})();