如果我有一个prototype.js Template从JavaScript对象生成HTML代码,我怎样才能让它自动转义JavaScript对象数据中的HTML实体,以便HTML不会中断?
示例JavaScript代码:
var data = {
name: 'Josh',
url: 'http://josh.gitlin.name/',
statement: 'I\'m a JavaScript and PHP developer. Find me on Stack Overflow and say "hi"!'
}
var template = new Template(
'<div><label>Name: <input name=\"name\" value=\"#{name}\"></label></div>'+
'<div><label>URL: <input name=\"url\" value=\"#{url}\"></label></div>'+
'<div><label>Personal Statement: <input name=\"statement\" value=\"#{statement}\"></label></div>'
);
$('test').update(template.evaluate(data));
上述代码会生成格式错误的<input>
代码,因为data.statement
包含引号"
。如何在不修改Template
对象或克隆data
对象的情况下让data
自动转义上述示例中的HTML实体?
答案 0 :(得分:1)
为了做到这一点,需要做两件事:
escape
类的Template
方法必须知道转义HTML实体escapeHTML
method which Prototype.js adds to the String
object以将引号编码为"
个实体。 (可能还有更多。现在方式太简单了......)这两个都可以使用以下代码实现:
String.prototype.escapeHTML = String.prototype.escapeHTML.wrap(function(proceed){
return proceed().replace(/"/g,'"');
});
Template.addMethods({
evaluateEscapeHTML: function(object) {
if (object && Object.isFunction(object.toTemplateReplacements))
object = object.toTemplateReplacements();
return this.template.gsub(this.pattern, function(match) {
if (object == null) return (match[1] + '');
var before = match[1] || '';
if (before == '\\') return match[2];
var ctx = object, expr = match[3],
pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
match = pattern.exec(expr);
if (match == null) return before;
while (match != null) {
var comp = match[1].startsWith('[') ? 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);
}
return before + String.interpret(ctx).escapeHTML();
});
}
});
此代码将扩展Prototype.js并向模板添加新的evaluateEscapeHTML
方法,因此此代码应该运行一次,从那时起,任何Template
现在都有一个新的evaluateEscapeHTML
方法:
var template = new Template(
'<div><label>Name: <input name=\"name\" value=\"#{name}\"></label></div>'+
'<div><label>URL: <input name=\"url\" value=\"#{url}\"></label></div>'+
'<div><label>Personal Statement: <input name=\"statement\" value=\"#{statement}\"></label></div>'
);
$('test').update(template.evaluate(data));
请注意,我必须从prototype.js 1.7版的evaluate
类复制 整个 Template
方法。这有一个主要的缺点,如果evaluate
方法的未来版本得到改进,我的代码也需要改进。但是,我无法找到更好的方法。
我对evaluate
方法的具体修改是更改此行:
return before + String.interpret(ctx);
为:
return before + String.interpret(ctx).escapeHTML();
这就是全部,这就是为什么我不能以某种方式extend
或wrap
代码的其余部分......
答案 1 :(得分:1)
阅读源代码,模板中没有任何内容可以逃脱html。此外,提供的String#escapeHTML
非常糟糕,因为它尝试使用正则表达式(wtf2)剥离标记(wtf)并且甚至不会转义引号。
您可以使用以下方法手动转义字符串:
function escapeHTML(text) {
var map = {
"&" : "amp",
"'": "#39",
'"': "quot",
"<": "lt",
">": "gt"
};
return text.replace( /[&'"<>]/g, function(m) {
return "&" + map[m] + ";";
});
}