diff --git a/test/utility.js b/test/utility.js index 30ba3a940..7bc5cb44b 100644 --- a/test/utility.js +++ b/test/utility.js @@ -57,6 +57,9 @@ $(document).ready(function() { var backslashTemplate = _.template("<%= thing %> is \\ridanculous"); equals(backslashTemplate({thing: 'This'}), "This is \\ridanculous"); + var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>'); + equals(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.'); + var fancyTemplate = _.template(""); @@ -65,7 +68,7 @@ $(document).ready(function() { var escapedCharsInJavascriptTemplate = _.template(""); result = escapedCharsInJavascriptTemplate({numbers: "one\ntwo\nthree\nfour"}); - equals(result, "", 'Can use escaped characters (e.g. \\n) in Javascript') + equals(result, "", 'Can use escaped characters (e.g. \\n) in Javascript'); var namespaceCollisionTemplate = _.template("<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %>
\">
<% }); %>"); result = namespaceCollisionTemplate({ diff --git a/underscore.js b/underscore.js index debc3481d..6687ded01 100644 --- a/underscore.js +++ b/underscore.js @@ -897,6 +897,12 @@ // guaranteed not to match. var noMatch = /.^/; + // Within an interpolation, evaluation, or escaping, remove HTML escaping + // that had been previously added. + var unescape = function(code) { + return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'"); + }; + // JavaScript micro-templating, similar to John Resig's implementation. // Underscore templating handles arbitrary delimiters, preserves whitespace, // and correctly escapes quotes within interpolated code. @@ -907,15 +913,13 @@ str.replace(/\\/g, '\\\\') .replace(/'/g, "\\'") .replace(c.escape || noMatch, function(match, code) { - return "',_.escape(" + code.replace(/\\'/g, "'") + "),'"; + return "',_.escape(" + unescape(code) + "),'"; }) .replace(c.interpolate || noMatch, function(match, code) { - return "'," + code.replace(/\\'/g, "'") + ",'"; + return "'," + unescape(code) + ",'"; }) .replace(c.evaluate || noMatch, function(match, code) { - return "');" + code.replace(/\\'/g, "'") - .replace(/[\r\n\t]/g, ' ') - .replace(/\\\\/g, '\\') + ";__p.push('"; + return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('"; }) .replace(/\r/g, '\\r') .replace(/\n/g, '\\n')