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("
<% \
for (key in people) { \
%>- <%= people[key] %>
<% } %>
");
@@ -65,7 +68,7 @@ $(document).ready(function() {
var escapedCharsInJavascriptTemplate = _.template("<% _.each(numbers.split('\\n'), function(item) { %>- <%= item %>
<% }) %>
");
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')