2012-07-19 36 views
2

如果我有一个从JavaScript对象生成HTML代码的prototype.js Template,如何让它自动转义JavaScript对象数据中的HTML实体,以便HTML不会中断?我怎样才能有一个prototype.js模板编码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)); 

JSFiddle code for the above

以上代码生成格式错误<input>标签因为data.statement包含一个引号"。如何在上面的示例中自动转义HTML实体Template而不修改data对象,也不克隆data对象?

回答

1

为了做到这一点,有两两件事需要发生:

  1. Template类的escape方法必须知道逃跑HTML实体
  2. escapeHTML method which Prototype.js adds to the String object必须扩展到编码引号成&quot;实体。 (甚至更多它现在方式太简单了......。)

二者皆可以用下面的代码来实现:

String.prototype.escapeHTML = String.prototype.escapeHTML.wrap(function(proceed){ 
    return proceed().replace(/"/g,'&quot;'); 
}); 

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)); 

JSFiddle to test this

注意,我不得不复制Template整个evaluate方法从的prototype.js 1.7版本。这有一个主要的缺点,如果未来版本的evaluate方法得到改进,我的代码也需要改进。然而,我找不到更好的方法来做到这一点。

的具体修改的evaluate方法,我做是为了改变这一行:

return before + String.interpret(ctx); 

到:

return before + String.interpret(ctx).escapeHTML(); 

这一切,这就是为什么它是这样一个耻辱,我不能不知何故extendwrap其余的代码...

1

阅读源代码,在模板中没有什么会转义html。此外,提供的String#escapeHTML是非常可怕的,因为它试图剥离标签(wtf)与正则表达式(wtf2),甚至不会引号。

您可以手动与此逃脱你的字符串:

function escapeHTML(text) { 
    var map = { 
     "&" : "amp", 
     "'": "#39", 
     '"': "quot", 
     "<": "lt", 
     ">": "gt" 

    }; 

    return text.replace(/[&'"<>]/g, function(m) { 
     return "&" + map[m] + ";"; 
    }); 
} 
+1

我只是写我自己的代码,并在escapeHTML'多么可怕'是很惊讶。你有更好的建议吗?如果不是,我喜欢你提供的代码。 (也欢迎我的解决方案的想法) – Josh 2012-07-19 19:58:46

+0

@Josh为了转义html,我认为这个函数应该很好地完成这项工作。我不太熟悉原型足以将其注入到模板的核心功能中。所以我不能说这些。我只是使用一个真正的模板引擎,它不像它们缺乏。 :P – Esailija 2012-07-19 20:00:28

+0

我很熟悉原型,足以将其注入到Template的核心功能中,而且我也这么做了。 ':-)'感谢您的功能,我会很好地使用它。 – Josh 2012-07-19 20:02:26