1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399 |
- /**
- * jTemplates 0.8.4 (http://jtemplates.tpython.com)
- * Copyright (c) 2007-2013 Tomasz Gloc (http://www.tpython.com)
- *
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and/or GPL (GPL-LICENSE.txt) licenses.
- *
- * Id: $Id: jquery-jtemplates_uncompressed.js 203 2013-02-03 13:28:34Z tom $
- */
- /**
- * @fileOverview Template engine in JavaScript.
- * @name jTemplates
- * @author Tomasz Gloc
- * @date $Date: 2013-02-03 14:28:34 +0100 (N, 03 lut 2013) $
- */
- if (window.jQuery && !window.jQuery.createTemplate) {
- (function (jQuery) {
- /**
- * [abstract]
- * @name BaseNode
- * @class Abstract node. [abstract]
- */
- /**
- * Process node and get the html string. [abstract]
- * @name get
- * @function
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String}
- * @memberOf BaseNode
- */
- /**
- * [abstract]
- * @name BaseArray
- * @augments BaseNode
- * @class Abstract array/collection. [abstract]
- */
- /**
- * Add node 'e' to array.
- * @name push
- * @function
- * @param {BaseNode} e a node
- * @memberOf BaseArray
- */
- /**
- * See (http://jquery.com/).
- * @name jQuery
- * @class jQuery Library (http://jquery.com/)
- */
- /**
- * See (http://jquery.com/)
- * @name fn
- * @class jQuery Library (http://jquery.com/)
- * @memberOf jQuery
- */
- /**
- * Create new template from string s.
- * @name Template
- * @class A template or multitemplate.
- * @param {string} s A template string (like: "Text: {$T.txt}.").
- * @param {array} [includes] Array of included templates.
- * @param {object} [settings] Settings.
- * @config {boolean} [disallow_functions] Do not allow use function in data (default: true).
- * @config {boolean} [filter_data] Enable filter data using escapeHTML (default: true).
- * @config {boolean} [filter_params] Enable filter parameters using escapeHTML (default: false).
- * @config {boolean} [runnable_functions] Automatically run function (from data) inside {} [default: false].
- * @config {boolean} [clone_data] Clone input data [default: true]
- * @config {boolean} [clone_params] Clone input parameters [default: true]
- * @config {Function} [f_cloneData] Function used to data cloning
- * @config {Function} [f_escapeString] Function used to escape strings
- * @config {Function} [f_parseJSON] Function used to parse JSON
- * @augments BaseNode
- */
- var Template = function (s, includes, settings) {
- this._tree = [];
- this._param = {};
- this._includes = null;
- this._templates = {};
- this._templates_code = {};
- //default parameters
- this.settings = jQuery.extend({
- disallow_functions: false,
- filter_data: true,
- filter_params: false,
- runnable_functions: false,
- clone_data: true,
- clone_params: true
- }, settings);
- //set handlers
- this.f_cloneData = (this.settings.f_cloneData !== undefined) ? (this.settings.f_cloneData) : (TemplateUtils.cloneData);
- this.f_escapeString = (this.settings.f_escapeString !== undefined) ? (this.settings.f_escapeString) : (TemplateUtils.escapeHTML);
- this.f_parseJSON = (this.settings.f_parseJSON !== undefined) ? (this.settings.f_parseJSON) : ((this.settings.disallow_functions) ? (jQuery.parseJSON) : (TemplateUtils.parseJSON));
- if (s == null) {
- return;
- }
- //split multiteplate
- this.splitTemplates(s, includes);
- if (s) {
- //set main template
- this.setTemplate(this._templates_code['MAIN'], includes, this.settings);
- }
- this._templates_code = null;
- };
- /**
- * jTemplates version
- * @type string
- */
- Template.version = '0.8.4';
- /**
- * Debug mode (all errors are on), default: off
- * @type Boolean
- */
- Template.DEBUG_MODE = false;
- /**
- * Foreach loop limit (enable only when DEBUG_MODE = true)
- * @type integer
- */
- Template.FOREACH_LOOP_LIMIT = 10000;
- /**
- * Global guid
- * @type integer
- */
- Template.guid = 0;
- /**
- * Split multitemplate into multiple templates.
- * @param {string} s A template string (like: "Text: {$T.txt}.").
- * @param {array} includes Array of included templates.
- */
- Template.prototype.splitTemplates = function (s, includes) {
- var reg = /\{#template *(\w+) *(.*?) *\}/g, //split multitemplate into subtemplates
- iter, tname, se, lastIndex = null, _template_settings = [], i;
- //while find new subtemplate
- while ((iter = reg.exec(s)) !== null) {
- lastIndex = reg.lastIndex;
- tname = iter[1];
- se = s.indexOf('{#/template ' + tname + '}', lastIndex);
- if (se === -1) {
- throw new Error('jTemplates: Template "' + tname + '" is not closed.');
- }
- //save a subtemplate and parse options
- this._templates_code[tname] = s.substring(lastIndex, se);
- _template_settings[tname] = TemplateUtils.optionToObject(iter[2]);
- }
- //when no subtemplates, use all as main template
- if (lastIndex === null) {
- this._templates_code['MAIN'] = s;
- return;
- }
- //create a new object for every subtemplates
- for (i in this._templates_code) {
- if (i !== 'MAIN') {
- this._templates[i] = new Template();
- }
- }
- for (i in this._templates_code) {
- if (i !== 'MAIN') {
- this._templates[i].setTemplate(this._templates_code[i],
- jQuery.extend({}, includes || {}, this._templates || {}),
- jQuery.extend({}, this.settings, _template_settings[i]));
- this._templates_code[i] = null;
- }
- }
- };
- /**
- * Parse template. (should be template, not multitemplate).
- * @param {string} s A template string (like: "Text: {$T.txt}.").
- * @param {array} includes Array of included templates.
- * @param {object} [settings] Settings.
- */
- Template.prototype.setTemplate = function (s, includes, settings) {
- if (s == undefined) {
- this._tree.push(new TextNode('', 1, this));
- return;
- }
- s = s.replace(/[\n\r]/g, ''); //remove endlines
- s = s.replace(/\{\*.*?\*\}/g, ''); //remove comments
- this._includes = jQuery.extend({}, this._templates || {}, includes || {});
- this.settings = new Object(settings);
- var node = this._tree,
- op = s.match(/\{#.*?\}/g), //find operators
- ss = 0, se = 0, e, literalMode = 0, i, l;
- //loop operators
- for (i = 0, l = (op) ? (op.length) : (0); i < l; ++i) {
- var this_op = op[i];
- //when literal mode is on, treat operator like a text
- if (literalMode) {
- se = s.indexOf('{#/literal}', ss); //find end of block
- if (se === -1) {
- throw new Error("jTemplates: No end of literal.");
- }
- if (se > ss) {
- node.push(new TextNode(s.substring(ss, se), 1, this));
- }
- ss = se + 11; //strlen '{#/literal}'
- literalMode = 0;
- while (i < l && op[i] !== '{#/literal}') { //skip all operators until literal end
- i++;
- }
- continue;
- }
- se = s.indexOf(this_op, ss);
- if (se > ss) {
- node.push(new TextNode(s.substring(ss, se), literalMode, this));
- }
- this_op.match(/\{#([\w\/]+).*?\}/); //find operator name
- var op_ = RegExp.$1;
- switch (op_) {
- case 'elseif':
- node.addCond(this_op);
- break;
- case 'if':
- e = new opIF(node, this);
- e.addCond(this_op);
- node.push(e);
- node = e;
- break;
- case 'else':
- node.switchToElse();
- break;
- case '/if':
- case '/for':
- case '/foreach':
- node = node.getParent();
- break;
- case 'foreach':
- e = new opFOREACH(this_op, node, this);
- node.push(e);
- node = e;
- break;
- case 'for':
- e = opFORFactory(this_op, node, this);
- node.push(e);
- node = e;
- break;
- case 'continue':
- case 'break':
- node.push(new JTException(op_));
- break;
- case 'include':
- node.push(new Include(this_op, this._includes, this));
- break;
- case 'param':
- node.push(new UserParam(this_op, this));
- break;
- case 'var':
- node.push(new UserVariable(this_op, this));
- break;
- case 'cycle':
- node.push(new Cycle(this_op));
- break;
- case 'ldelim':
- node.push(new TextNode('{', 1, this));
- break;
- case 'rdelim':
- node.push(new TextNode('}', 1, this));
- break;
- case 'literal':
- literalMode = 1;
- break;
- case '/literal':
- if (Template.DEBUG_MODE) {
- throw new Error("jTemplates: Missing begin of literal.");
- }
- break;
- default:
- if (Template.DEBUG_MODE) {
- throw new Error('jTemplates: unknown tag: ' + op_ + '.');
- }
- }
- ss = se + this_op.length;
- }
- if (s.length > ss) {
- node.push(new TextNode(s.substr(ss), literalMode, this));
- }
- };
- /**
- * Process template and get the html string.
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String}
- */
- Template.prototype.get = function (d, param, element, deep) {
- ++deep;
- if (deep == 1 && element != undefined) {
- jQuery.removeData(element, "jTemplatesRef");
- }
- var $T = d, $P, ret = '';
- //create clone of data
- if (this.settings.clone_data) {
- $T = this.f_cloneData(d, { escapeData: (this.settings.filter_data && deep == 1), noFunc: this.settings.disallow_functions }, this.f_escapeString);
- }
- //create clone of parameters
- if (!this.settings.clone_params) {
- $P = jQuery.extend({}, this._param, param);
- } else {
- $P = jQuery.extend({},
- this.f_cloneData(this._param, { escapeData: (this.settings.filter_params), noFunc: false }, this.f_escapeString),
- this.f_cloneData(param, { escapeData: (this.settings.filter_params && deep == 1), noFunc: false }, this.f_escapeString));
- }
- for (var i = 0, l = this._tree.length; i < l; ++i) {
- ret += this._tree[i].get($T, $P, element, deep);
- }
- this.EvalObj = null;
- --deep;
- return ret;
- };
- /**
- * Create and return EvalClass object
- * @return {EvalClass}
- */
- Template.prototype.getBin = function () {
- if (this.EvalObj == null) {
- this.EvalObj = new EvalClass(this);
- }
- return this.EvalObj;
- };
- /**
- * Set to parameter 'name' value 'value'.
- * @param {string} name
- * @param {object} value
- */
- Template.prototype.setParam = function (name, value) {
- this._param[name] = value;
- };
- /**
- * Template utilities.
- * @namespace Template utilities.
- */
- TemplateUtils = function () {
- };
- /**
- * Replace chars &, >, <, ", ' with html entities.
- * To disable function set settings: filter_data=false, filter_params=false
- * @param {string} string
- * @return {string}
- * @static
- * @memberOf TemplateUtils
- */
- TemplateUtils.escapeHTML = function (txt) {
- return txt.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''');
- };
- /**
- * Make a copy od data 'd'. It also filters data (depend on 'filter').
- * @param {object} d input data
- * @param {object} filter a filters
- * @config {boolean} [escapeData] Use escapeHTML on every string.
- * @config {boolean} [noFunc] Do not allow to use function (throws exception).
- * @param {Function} f_escapeString function using to filter string (usually: TemplateUtils.escapeHTML)
- * @return {object} output data (filtered)
- * @static
- * @memberOf TemplateUtils
- */
- TemplateUtils.cloneData = function (d, filter, f_escapeString) {
- if (d == null) {
- return d;
- }
- switch (d.constructor) {
- case Object:
- var o = {};
- for (var i in d) {
- o[i] = TemplateUtils.cloneData(d[i], filter, f_escapeString);
- }
- if (!filter.noFunc) {
- if (d.hasOwnProperty("toString")) {
- o.toString = d.toString;
- }
- }
- return o;
- case Array:
- var a = [];
- for (var i = 0, l = d.length; i < l; ++i) {
- a[i] = TemplateUtils.cloneData(d[i], filter, f_escapeString);
- }
- return a;
- case String:
- return (filter.escapeData) ? (f_escapeString(d)) : (d);
- case Function:
- if (filter.noFunc) {
- if (Template.DEBUG_MODE) {
- throw new Error("jTemplates: Functions are not allowed.");
- }
- else {
- return undefined;
- }
- }
- }
- return d;
- };
- /**
- * Convert text-based option string to Object
- * @param {string} optionText text-based option string
- * @return {Object}
- * @static
- * @memberOf TemplateUtils
- */
- TemplateUtils.optionToObject = function (optionText) {
- if (optionText === null || optionText === undefined) {
- return {};
- }
- var o = optionText.split(/[= ]/);
- if (o[0] === '') {
- o.shift();
- }
- var obj = {};
- for (var i = 0, l = o.length; i < l; i += 2) {
- obj[o[i]] = o[i + 1];
- }
- return obj;
- };
- /**
- * Parse JSON string into object
- * @param {string} data Text JSON
- * @return {Object}
- * @static
- */
- TemplateUtils.parseJSON = function (data) {
- if (typeof data !== "string" || !data) {
- return null;
- }
- try {
- return (new Function("return " + jQuery.trim(data)))();
- } catch (e) {
- if (Template.DEBUG_MODE) {
- throw new Error("jTemplates: Invalid JSON");
- }
- return {};
- }
- };
- /**
- * Find parents nodes for a reference value and return it
- * @param {Element} el html element
- * @param {int} guid template process unique identificator
- * @param {int} id index
- * @return {object}
- * @static
- */
- TemplateUtils.ReturnRefValue = function (el, guid, id) {
- //search element with stored data
- while (el != null) {
- var d = jQuery.data(el, 'jTemplatesRef');
- if (d != undefined && d.guid == guid && d.d[id] != undefined) {
- return d.d[id];
- }
- el = el.parentNode;
- }
- return null;
- };
- /**
- * Create a new text node.
- * @name TextNode
- * @class All text (block {..}) between control's block "{#..}".
- * @param {string} val text string
- * @param {boolean} literalMode When enable (true) template does not process blocks {..}.
- * @param {Template} Template object
- * @augments BaseNode
- */
- var TextNode = function (val, literalMode, template) {
- this._value = val;
- this._literalMode = literalMode;
- this._template = template;
- };
- /**
- * Get the html string for a text node.
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String}
- */
- TextNode.prototype.get = function (d, param, element, deep) {
- if (this._literalMode) {
- return this._value;
- }
- var s = this._value;
- var result = "";
- var i = -1;
- var nested = 0;
- var sText = -1;
- var sExpr = 0;
- while (true) {
- var lm = s.indexOf("{", i + 1);
- var rm = s.indexOf("}", i + 1);
- if (lm < 0 && rm < 0) {
- break;
- }
- if ((lm != -1 && lm < rm) || (rm == -1)) {
- i = lm;
- if (++nested == 1) {
- sText = lm;
- result += s.substring(sExpr, i);
- sExpr = -1;
- }
- } else {
- i = rm;
- if (--nested === 0) {
- if (sText >= 0) {
- result += this._template.getBin().evaluateContent(d, param, element, s.substring(sText, rm + 1));
- sText = -1;
- sExpr = i + 1;
- }
- } else if (nested < 0) {
- nested = 0;
- }
- }
- }
- if (sExpr > -1) {
- result += s.substr(sExpr);
- }
- return result;
- };
- /**
- * Virtual context for eval() (internal class)
- * @name EvalClass
- * @class Virtual bin for eval() evaluation
- * @param {Template} t template
- * @private
- */
- EvalClass = function (t) {
- this.__templ = t;
- };
- /**
- * Evaluate expression (template content)
- * @param {object} $T data
- * @param {object} $P parameters
- * @param {object} $Q element
- * @param {String} __value Template content
- * @return {String}
- */
- EvalClass.prototype.evaluateContent = function ($T, $P, $Q, __value) {
- try {
- var result = eval(__value);
- if (jQuery.isFunction(result)) {
- if (this.__templ.settings.disallow_functions || !this.__templ.settings.runnable_functions) {
- return '';
- }
- result = result($T, $P, $Q);
- }
- return (result === undefined) ? ("") : (String(result));
- } catch (e) {
- if (Template.DEBUG_MODE) {
- if (e instanceof JTException) {
- e.type = "subtemplate";
- }
- throw e;
- }
- return "";
- }
- };
- /**
- * Evaluate expression (simple eval)
- * @param {object} $T data
- * @param {object} $P parameters
- * @param {object} $Q element
- * @param {String} __value content to evaluate
- * @return {String}
- */
- EvalClass.prototype.evaluate = function ($T, $P, $Q, __value) {
- return eval(__value);
- };
- /**
- * Create a new conditional node.
- * @name opIF
- * @class A class represent: {#if}.
- * @param {object} par parent node
- * @param {Template} templ template
- * @augments BaseArray
- */
- var opIF = function (par, templ) {
- this._parent = par;
- this._templ = templ;
- this._cond = []; //conditions
- this._tree = []; //conditions subtree
- this._curr = null; //current subtree
- };
- /**
- * Add node 'e' to array.
- * @param {BaseNode} e a node
- */
- opIF.prototype.push = function (e) {
- this._curr.push(e);
- };
- /**
- * Get a parent node.
- * @return {BaseNode}
- */
- opIF.prototype.getParent = function () {
- return this._parent;
- };
- /**
- * Add condition
- * @param {string} oper content of operator {#..}
- */
- opIF.prototype.addCond = function (oper) {
- oper.match(/\{#(?:else)*if (.*?)\}/);
- this._cond.push(RegExp.$1);
- this._curr = [];
- this._tree.push(this._curr);
- };
- /**
- * Switch to else
- */
- opIF.prototype.switchToElse = function () {
- this._cond.push(true); //else is the last condition and its always true
- this._curr = [];
- this._tree.push(this._curr);
- };
- /**
- * Process node depend on conditional and get the html string.
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String}
- */
- opIF.prototype.get = function (d, param, element, deep) {
- var ret = ''; //result
- try {
- //foreach condition
- for (var ci = 0, cl = this._cond.length; ci < cl; ++ci) {
- //if condition is true
- if (this._templ.getBin().evaluate(d, param, element, this._cond[ci])) {
- //execute and exit
- var t = this._tree[ci];
- for (var i = 0, l = t.length; i < l; ++i) {
- ret += t[i].get(d, param, element, deep);
- }
- return ret;
- }
- }
- } catch (e) {
- if (Template.DEBUG_MODE || (e instanceof JTException)) {
- throw e;
- }
- }
- return ret;
- };
- /**
- * Handler for a tag 'FOR'. Create new and return relative opFOREACH object.
- * @name opFORFactory
- * @class Handler for a tag 'FOR'. Create new and return relative opFOREACH object.
- * @param {string} oper content of operator {#..}
- * @param {object} par parent node
- * @param {Template} template a pointer to Template object
- * @return {opFOREACH}
- */
- opFORFactory = function (oper, par, template) {
- //create operator FOREACH with function as iterator
- if (oper.match(/\{#for (\w+?) *= *(\S+?) +to +(\S+?) *(?:step=(\S+?))*\}/)) {
- var f = new opFOREACH(null, par, template);
- f._name = RegExp.$1;
- f._option = { 'begin': (RegExp.$2 || 0), 'end': (RegExp.$3 || -1), 'step': (RegExp.$4 || 1), 'extData': '$T' };
- f._runFunc = (function (i) { return i; });
- return f;
- } else {
- throw new Error('jTemplates: Operator failed "find": ' + oper);
- }
- };
- /**
- * Create a new loop node.
- * @name opFOREACH
- * @class A class represent: {#foreach}.
- * @param {string} oper content of operator {#..}
- * @param {object} par parent node
- * @param {Template} template a pointer to Template object
- * @augments BaseArray
- */
- var opFOREACH = function (oper, par, template) {
- this._parent = par;
- this._template = template;
- if (oper != null) {
- oper.match(/\{#foreach +(.+?) +as +(\w+?)( .+)*\}/);
- this._arg = RegExp.$1;
- this._name = RegExp.$2;
- this._option = RegExp.$3 || null;
- this._option = TemplateUtils.optionToObject(this._option);
- }
- this._onTrue = [];
- this._onFalse = [];
- this._currentState = this._onTrue;
- //this._runFunc = null;
- };
- /**
- * Add node 'e' to array.
- * @param {BaseNode} e
- */
- opFOREACH.prototype.push = function (e) {
- this._currentState.push(e);
- };
- /**
- * Get a parent node.
- * @return {BaseNode}
- */
- opFOREACH.prototype.getParent = function () {
- return this._parent;
- };
- /**
- * Switch from collection onTrue to onFalse.
- */
- opFOREACH.prototype.switchToElse = function () {
- this._currentState = this._onFalse;
- };
- /**
- * Process loop and get the html string.
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String}
- */
- opFOREACH.prototype.get = function (d, param, element, deep) {
- try {
- //array of elements in foreach (or function)
- var fcount = (this._runFunc === undefined) ? (this._template.getBin().evaluate(d, param, element, this._arg)) : (this._runFunc);
- if (fcount === $) {
- throw new Error("jTemplate: Variable '$' cannot be used as loop-function");
- }
- var key = []; //only for objects
- var mode = typeof fcount;
- if (mode == 'object') {
- //transform object to array
- var arr = [];
- jQuery.each(fcount, function (k, v) {
- key.push(k);
- arr.push(v);
- });
- fcount = arr;
- }
- //setup primary iterator, iterator can get data from options (using by operator FOR) or from data "$T"
- var extData = (this._option.extData !== undefined) ? (this._template.getBin().evaluate(d, param, element, this._option.extData)) : ((d != null) ? (d) : ({}));
- if (extData == null) {
- extData = {};
- }
- //start, end and step
- var s = Number(this._template.getBin().evaluate(d, param, element, this._option.begin) || 0), e; //start, end
- var step = Number(this._template.getBin().evaluate(d, param, element, this._option.step) || 1);
- if (mode != 'function') {
- e = fcount.length;
- } else {
- if (this._option.end === undefined || this._option.end === null) {
- e = Number.MAX_VALUE;
- } else {
- e = Number(this._template.getBin().evaluate(d, param, element, this._option.end)) + ((step > 0) ? (1) : (-1));
- }
- }
- var ret = ''; //result string
- var i, l; //local iterators
- if (this._option.count) {
- //limit number of loops
- var tmp = s + Number(this._template.getBin().evaluate(d, param, element, this._option.count));
- e = (tmp > e) ? (e) : (tmp);
- }
- if ((e > s && step > 0) || (e < s && step < 0)) {
- var iteration = 0;
- var _total = (mode != 'function') ? (Math.ceil((e - s) / step)) : undefined;
- var ckey, cval; //current key, current value
- var loopCounter = 0;
- for (; ((step > 0) ? (s < e) : (s > e)); s += step, ++iteration, ++loopCounter) {
- if (Template.DEBUG_MODE && loopCounter > Template.FOREACH_LOOP_LIMIT) {
- throw new Error("jTemplate: Foreach loop limit was exceed");
- }
- ckey = key[s];
- if (mode != 'function') {
- cval = fcount[s]; //get value from array
- } else {
- cval = fcount(s); //calc function
- //if no result from function then stop foreach
- if (cval === undefined || cval === null) {
- break;
- }
- }
- if ((typeof cval == 'function') && (this._template.settings.disallow_functions || !this._template.settings.runnable_functions)) {
- continue;
- }
- if ((mode == 'object') && (ckey in Object) && (cval === Object[ckey])) {
- continue;
- }
- //backup on value
- var prevValue = extData[this._name];
- //set iterator properties
- extData[this._name] = cval;
- extData[this._name + '$index'] = s;
- extData[this._name + '$iteration'] = iteration;
- extData[this._name + '$first'] = (iteration === 0);
- extData[this._name + '$last'] = (s + step >= e);
- extData[this._name + '$total'] = _total;
- extData[this._name + '$key'] = (ckey !== undefined && ckey.constructor == String) ? (this._template.f_escapeString(ckey)) : (ckey);
- extData[this._name + '$typeof'] = typeof cval;
- for (i = 0, l = this._onTrue.length; i < l; ++i) {
- try {
- ret += this._onTrue[i].get(extData, param, element, deep);
- } catch (ex) {
- if (ex instanceof JTException) {
- switch (ex.type) {
- case 'continue':
- i = l; //force skip to next node
- break;
- case 'break':
- i = l; //force skip to next node
- s = e; //force skip outsite foreach
- break;
- default:
- throw ex;
- }
- } else {
- throw ex;
- }
- }
- }
- //restore values
- delete extData[this._name + '$index'];
- delete extData[this._name + '$iteration'];
- delete extData[this._name + '$first'];
- delete extData[this._name + '$last'];
- delete extData[this._name + '$total'];
- delete extData[this._name + '$key'];
- delete extData[this._name + '$typeof'];
- delete extData[this._name];
- extData[this._name] = prevValue;
- }
- } else {
- //no items to loop ("foreach->else")
- for (i = 0, l = this._onFalse.length; i < l; ++i) {
- ret += this._onFalse[i].get(d, param, element, deep);
- }
- }
- return ret;
- } catch (e) {
- if (Template.DEBUG_MODE || (e instanceof JTException)) {
- throw e;
- }
- return "";
- }
- };
- /**
- * Template-control exceptions
- * @name JTException
- * @class A class used internals for a template-control exceptions
- * @param type {string} Type of exception
- * @augments Error
- * @augments BaseNode
- */
- var JTException = function (type) {
- this.type = type;
- };
- JTException.prototype = Error;
- /**
- * Throw a template-control exception
- * @throws It throws itself
- */
- JTException.prototype.get = function (d) {
- throw this;
- };
- /**
- * Create a new entry for included template.
- * @name Include
- * @class A class represent: {#include}.
- * @param {string} oper content of operator {#..}
- * @param {array} includes
- * @param {Template} templ template
- * @augments BaseNode
- */
- var Include = function (oper, includes, templ) {
- oper.match(/\{#include (.*?)(?: root=(.*?))?\}/);
- this._template = includes[RegExp.$1];
- if (this._template == undefined) {
- if (Template.DEBUG_MODE) {
- throw new Error('jTemplates: Cannot find include: ' + RegExp.$1);
- }
- }
- this._root = RegExp.$2;
- this._mainTempl = templ;
- };
- /**
- * Run method get on included template.
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String}
- */
- Include.prototype.get = function (d, param, element, deep) {
- try {
- //run a subtemplates with a new root node
- return this._template.get(this._mainTempl.getBin().evaluate(d, param, element, this._root), param, element, deep);
- } catch (e) {
- if (Template.DEBUG_MODE || (e instanceof JTException)) {
- throw e;
- }
- }
- return '';
- };
- /**
- * Create new node for {#param}.
- * @name UserParam
- * @class A class represent: {#param}.
- * @param {string} oper content of operator {#..}
- * @param {Template} templ template
- * @augments BaseNode
- */
- var UserParam = function (oper, templ) {
- oper.match(/\{#param name=(\w*?) value=(.*?)\}/);
- this._name = RegExp.$1;
- this._value = RegExp.$2;
- this._templ = templ;
- };
- /**
- * Return value of selected parameter.
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String} empty string
- */
- UserParam.prototype.get = function (d, param, element, deep) {
- try {
- param[this._name] = this._templ.getBin().evaluate(d, param, element, this._value);
- } catch (e) {
- if (Template.DEBUG_MODE || (e instanceof JTException)) {
- throw e;
- }
- param[this._name] = undefined;
- }
- return '';
- };
- /**
- * Create new node for {#var}.
- * @name UserVariable
- * @class A class represent: {#var}.
- * @param {string} oper content of operator {#..}
- * @param {Template} templ template
- * @augments BaseNode
- */
- var UserVariable = function (oper, templ) {
- oper.match(/\{#var (.*?)\}/);
- this._id = RegExp.$1;
- this._templ = templ;
- };
- /**
- * Return value of selected variable.
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String} calling of function ReturnRefValue (as text string)
- */
- UserVariable.prototype.get = function (d, param, element, deep) {
- try {
- if (element == undefined) {
- return "";
- }
- var obj = this._templ.getBin().evaluate(d, param, element, this._id);
- var refobj = jQuery.data(element, "jTemplatesRef");
- if (refobj == undefined) {
- refobj = { guid: (++Template.guid), d: [] };
- }
- var i = refobj.d.push(obj);
- jQuery.data(element, "jTemplatesRef", refobj);
- return "(TemplateUtils.ReturnRefValue(this," + refobj.guid + "," + (i - 1) + "))";
- } catch (e) {
- if (Template.DEBUG_MODE || (e instanceof JTException)) {
- throw e;
- }
- return '';
- }
- };
- /**
- * Create a new cycle node.
- * @name Cycle
- * @class A class represent: {#cycle}.
- * @param {string} oper content of operator {#..}
- * @augments BaseNode
- */
- var Cycle = function (oper) {
- oper.match(/\{#cycle values=(.*?)\}/);
- this._values = eval(RegExp.$1);
- this._length = this._values.length;
- if (this._length <= 0) {
- throw new Error('jTemplates: no elements for cycle');
- }
- this._index = 0;
- this._lastSessionID = -1;
- };
- /**
- * Do a step on cycle and return value.
- * @param {object} d data
- * @param {object} param parameters
- * @param {Element} element a HTML element
- * @param {Number} deep
- * @return {String}
- */
- Cycle.prototype.get = function (d, param, element, deep) {
- var sid = jQuery.data(element, 'jTemplateSID');
- if (sid != this._lastSessionID) {
- this._lastSessionID = sid;
- this._index = 0;
- }
- var i = this._index++ % this._length;
- return this._values[i];
- };
- /**
- * Add a Template to HTML Elements.
- * @param {Template/string} s a Template or a template string
- * @param {array} [includes] Array of included templates.
- * @param {object} [settings] Settings (see Template)
- * @return {jQuery} chainable jQuery class
- * @memberOf jQuery.fn
- */
- jQuery.fn.setTemplate = function (s, includes, settings) {
- return jQuery(this).each(function () {
- var t = (s && s.constructor == Template) ? s : new Template(s, includes, settings);
- jQuery.data(this, 'jTemplate', t);
- jQuery.data(this, 'jTemplateSID', 0);
- });
- };
- /**
- * Add a Template (from URL) to HTML Elements.
- * @param {string} url_ URL to template
- * @param {array} [includes] Array of included templates.
- * @param {object} [settings] Settings (see Template)
- * @return {jQuery} chainable jQuery class
- * @memberOf jQuery.fn
- */
- jQuery.fn.setTemplateURL = function (url_, includes, settings) {
- var s = jQuery.ajax({
- url: url_,
- dataType: 'text',
- async: false,
- type: 'GET'
- }).responseText;
- return jQuery(this).setTemplate(s, includes, settings);
- };
- /**
- * Create a Template from element's content.
- * @param {string} elementName an ID of element
- * @param {array} [includes] Array of included templates.
- * @param {object} [settings] Settings (see Template)
- * @return {jQuery} chainable jQuery class
- * @memberOf jQuery.fn
- */
- jQuery.fn.setTemplateElement = function (elementName, includes, settings) {
- var s = jQuery('#' + elementName).val();
- if (s == null) {
- s = jQuery('#' + elementName).html();
- s = s.replace(/</g, "<").replace(/>/g, ">");
- }
- s = jQuery.trim(s);
- s = s.replace(/^<\!\[CDATA\[([\s\S]*)\]\]>$/im, '$1');
- s = s.replace(/^<\!--([\s\S]*)-->$/im, '$1');
- return jQuery(this).setTemplate(s, includes, settings);
- };
- /**
- * Check it HTML Elements have a template. Return count of templates.
- * @return {number} Number of templates.
- * @memberOf jQuery.fn
- */
- jQuery.fn.hasTemplate = function () {
- var count = 0;
- jQuery(this).each(function () {
- if (jQuery.getTemplate(this)) {
- ++count;
- }
- });
- return count;
- };
- /**
- * Remote Template from HTML Element(s)
- * @return {jQuery} chainable jQuery class
- */
- jQuery.fn.removeTemplate = function () {
- jQuery(this).processTemplateStop();
- return jQuery(this).each(function () {
- jQuery.removeData(this, 'jTemplate');
- });
- };
- /**
- * Set to parameter 'name' value 'value'.
- * @param {string} name
- * @param {object} value
- * @return {jQuery} chainable jQuery class
- * @memberOf jQuery.fn
- */
- jQuery.fn.setParam = function (name, value) {
- return jQuery(this).each(function () {
- var t = jQuery.getTemplate(this);
- if (t != null) {
- t.setParam(name, value);
- } else if (Template.DEBUG_MODE) {
- throw new Error('jTemplates: Template is not defined.');
- }
- });
- };
- /**
- * Process template using data 'd' and parameters 'param'. Update HTML code.
- * @param {object} d data
- * @param {object} [param] parameters
- * @option {object} [options] internal use only
- * @return {jQuery} chainable jQuery class
- * @memberOf jQuery.fn
- */
- jQuery.fn.processTemplate = function (d, param, options) {
- return jQuery(this).each(function () {
- var t = jQuery.getTemplate(this);
- if (t != null) {
- if (options != undefined && options.StrToJSON) {
- d = t.f_parseJSON(d);
- }
- jQuery.data(this, 'jTemplateSID', jQuery.data(this, 'jTemplateSID') + 1);
- jQuery(this).html(t.get(d, param, this, 0));
- } else if (Template.DEBUG_MODE) {
- throw new Error('jTemplates: Template is not defined.');
- }
- });
- };
- /**
- * Process template using data from URL 'url_' (only format JSON) and parameters 'param'. Update HTML code.
- * @param {string} url_ URL to data (in JSON)
- * @param {object} [param] parameters
- * @param {object} options options (over ajaxSettings) and callbacks
- * @return {jQuery} chainable jQuery class
- * @memberOf jQuery.fn
- */
- jQuery.fn.processTemplateURL = function (url_, param, options) {
- var that = this;
- var o = jQuery.extend({ cache: false }, jQuery.ajaxSettings);
- o = jQuery.extend(o, options);
- jQuery.ajax({
- url: url_,
- type: o.type,
- data: o.data,
- dataFilter: o.dataFilter,
- async: o.async,
- headers: o.headers,
- cache: o.cache,
- timeout: o.timeout,
- dataType: 'text',
- success: function (d) {
- var r = jQuery(that).processTemplate(d, param, { StrToJSON: true });
- if (o.on_success) {
- o.on_success(r);
- }
- },
- error: o.on_error,
- complete: o.on_complete
- });
- return this;
- };
- /**
- * Create new Updater.
- * @name Updater
- * @class This class is used for 'Live Refresh!'.
- * @param {string} url A destination URL
- * @param {object} param Parameters (for template)
- * @param {number} interval Time refresh interval
- * @param {object} args Additional URL parameters (in URL alter ?) as assoc array.
- * @param {array} objs An array of HTMLElement which will be modified by Updater.
- * @param {object} options options and callbacks
- */
- var Updater = function (url, param, interval, args, objs, options) {
- this._url = url;
- this._param = param;
- this._interval = interval;
- this._args = args;
- this.objs = objs;
- this.timer = null;
- this._options = options || {};
- var that = this;
- jQuery(objs).each(function () {
- jQuery.data(this, 'jTemplateUpdater', that);
- });
- this.run();
- };
- /**
- * Create new HTTP request to server, get data (as JSON) and send it to templates. Also check does HTMLElements still exists in Document.
- */
- Updater.prototype.run = function () {
- //remove deleted node
- this.objs = jQuery.grep(this.objs, function (elem) {
- return (jQuery.contains(document.body, elem.jquery ? elem[0] : elem));
- });
- //if no node then do nothing
- if (this.objs.length === 0) {
- return;
- }
- //ajax call
- var that = this;
- jQuery.ajax({
- url: this._url,
- dataType: 'text',
- data: this._args,
- cache: false,
- headers: that._options.headers,
- success: function (d) {
- try {
- var r = jQuery(that.objs).processTemplate(d, that._param, { StrToJSON: true });
- if (that._options.on_success) {
- that._options.on_success(r); //callback
- }
- } catch (ex) { }
- }
- });
- //schedule next run
- this.timer = setTimeout(function () { that.run(); }, this._interval);
- };
- /**
- * Start 'Live Refresh!'.
- * @param {string} url A destination URL
- * @param {object} param Parameters (for template)
- * @param {number} interval Time refresh interval
- * @param {object} args Additional URL parameters (in URL alter ?) as assoc array.
- * @param {object} options options and callbacks
- * @return {Updater} an Updater object
- * @memberOf jQuery.fn
- */
- jQuery.fn.processTemplateStart = function (url, param, interval, args, options) {
- return new Updater(url, param, interval, args, this, options);
- };
- /**
- * Stop 'Live Refresh!'.
- * @return {jQuery} chainable jQuery class
- * @memberOf jQuery.fn
- */
- jQuery.fn.processTemplateStop = function () {
- return jQuery(this).each(function () {
- var updater = jQuery.data(this, 'jTemplateUpdater');
- if (updater == null) {
- return;
- }
- var that = this;
- updater.objs = jQuery.grep(updater.objs, function (o) {
- return o != that;
- });
- jQuery.removeData(this, 'jTemplateUpdater');
- });
- };
- jQuery.extend(/** @scope jQuery.prototype */{
- /**
- * Create new Template.
- * @param {string} s A template string (like: "Text: {$T.txt}.").
- * @param {array} includes Array of included templates.
- * @param {object} settings Settings. (see Template)
- * @return {Template}
- */
- createTemplate: function (s, includes, settings) {
- return new Template(s, includes, settings);
- },
- /**
- * Create new Template from URL.
- * @param {string} url_ URL to template
- * @param {array} includes Array of included templates.
- * @param {object} settings Settings. (see Template)
- * @return {Template}
- */
- createTemplateURL: function (url_, includes, settings) {
- var s = jQuery.ajax({
- url: url_,
- dataType: 'text',
- async: false,
- type: 'GET'
- }).responseText;
- return new Template(s, includes, settings);
- },
- /**
- * Get a Template for HTML node
- * @param {Element} HTML node
- * @return {Template} a Template or "undefined"
- */
- getTemplate: function (element) {
- return jQuery.data(element, 'jTemplate');
- },
- /**
- * Process template and return text content.
- * @param {Template} template A Template
- * @param {object} data data
- * @param {object} param parameters
- * @return {string} Content of template
- */
- processTemplateToText: function (template, data, parameter) {
- return template.get(data, parameter, undefined, 0);
- },
- /**
- * Set Debug Mode
- * @param {Boolean} value
- */
- jTemplatesDebugMode: function (value) {
- Template.DEBUG_MODE = value;
- }
- });
- })(jQuery);
- };
|