You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
3.4 KiB

/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/**
* Template class implements token replacement logic for strings containing HTML and tokens.
*
* The following format is used for tokens: #{token_name}.
* When found in template String, token will be replaced with value of the key "token_name" of object passed to
* evaluate function. All occurrences of tokens are replaced by values from object with HTML entities escaped.
* Token name should be prefixed with character '*' to avoid escaping of HTML entities (for example, #{*test}).
* Backslash character (\\) can be used to escape token (such tokens will not be affected).
*
* Nested object properties could be used in templated by using square bracket token syntax (for example, #{a[b][c]}).
* Previous example will look for nested value a->b->c ({'a': {'b': {'c': 'value'}}}).
*
* @param {string} template template string
*
* @return {Template}
*/
var Template = function(template) {
this.template = template;
};
Template.prototype = {
/**
* Helper function called when match is found in template.
*
* @param {array} match result of regex matching
* @param {object} object object containing data
*
* @return {string}
*/
onMatch: function (match, object) {
if (object == null) {
return match[1] + '';
}
var before = match[1] || '';
if (before == '\\') {
return match[2];
}
var ctx = object,
expr = match[3],
escape = (expr.substring(0, 1) !== '*');
if(!escape) {
expr = expr.substring(1);
}
var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
match = pattern.exec(expr);
if (match == null) {
return before;
}
while (match != null) {
var comp = match[1].substring(0, 1) === '[' ? match[2].replace(/\\\\]/g, ']') : match[1];
ctx = ctx[comp];
if (null == ctx || '' == match[3]) {
break;
}
expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
match = pattern.exec(expr);
}
ctx = '' + (((typeof ctx === 'undefined') || (ctx === null)) ? '' : ctx);
return before + (escape ? ctx.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
.replace(/\"/g,'&quot;').replace(/\'/g,'&apos;') : ctx);
},
/**
* Fill template with data defined in object.
*
* @param {object} object object containing data
*
* @return {string}
*/
evaluate: function(object) {
var result = '',
source = this.template;
while (source.length > 0) {
var match = source.match(/(^|.|\r|\n)(#\{(.*?)\})/);
if (match) {
result += source.substring(0, match.index);
result += this.onMatch(match, object);
source = source.substring(match.index + match[0].length);
}
else {
result += source;
break;
}
}
return result;
}
};