Skip to content

Commit ebf7e82

Browse files
fix($compile): correctly denormalize templates that do not use standard interpolation symbols
In order to support third party modules that do not use the same interpolation symbols as the main app, we implemented denormalization (see dfe9983). This required that 3rd party modules always used the standad `{{` and `}}` interpolation symbols, so that we could correctly denormalise them to the current app's symbols. The problem with this became apparent when an app template using new symbols inadvertently contained one of the standard interpolation symbols. E.g. `<div data-context='{"context":{"id":3,"type":"page"}}">` The double closing curly braces were being incorrectly denormalised. This commit fixes this by allowing the compiler to be configured to know what symbols are being used in templates from a given module. Now modules can specify that what interpolation symbols they use and the compiler will denormalize appropriately. Closes angular#6493 Closes angular#6453
1 parent eebbca0 commit ebf7e82

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

src/ng/compile.js

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,29 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
12851285
return TTL;
12861286
};
12871287

1288+
1289+
function escapeRegExp(str) {
1290+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1291+
}
1292+
function createGlobalRegexMatcher(str) {
1293+
return new RegExp(escapeRegExp(str), 'g');
1294+
}
1295+
var moduleSymbolMap = createMap();
1296+
var defaultSymbols = {
1297+
startSymbol: '{{',
1298+
startRegex: /\{\{/g,
1299+
endSymbol: '}}',
1300+
endRegex: /\}\}/g
1301+
};
1302+
this.moduleSymbols = function(moduleName, startSymbol, endSymbol) {
1303+
moduleSymbolMap[moduleName] = {
1304+
startSymbol: startSymbol,
1305+
startRegex: createGlobalRegexMatcher(startSymbol),
1306+
endSymbol: endSymbol,
1307+
endRegex: createGlobalRegexMatcher(endSymbol)
1308+
};
1309+
};
1310+
12881311
this.$get = [
12891312
'$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
12901313
'$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
@@ -1585,10 +1608,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15851608

15861609
var startSymbol = $interpolate.startSymbol(),
15871610
endSymbol = $interpolate.endSymbol(),
1588-
denormalizeTemplate = (startSymbol === '{{' && endSymbol === '}}')
1589-
? identity
1590-
: function denormalizeTemplate(template) {
1591-
return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
1611+
denormalizeTemplate = function(moduleName, template) {
1612+
var moduleSymbols = moduleSymbolMap[moduleName] || defaultSymbols;
1613+
if (moduleSymbols.startSymbol !== startSymbol) {
1614+
template = template.replace(moduleSymbols.startRegex, startSymbol);
1615+
}
1616+
if (moduleSymbols.endSymbol !== endSymbol) {
1617+
template = template.replace(moduleSymbols.endRegex, endSymbol);
1618+
}
1619+
return template;
15921620
},
15931621
NG_ATTR_BINDING = /^ngAttr[A-Z]/;
15941622
var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
@@ -2274,7 +2302,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
22742302
? directive.template($compileNode, templateAttrs)
22752303
: directive.template;
22762304

2277-
directiveValue = denormalizeTemplate(directiveValue);
2305+
directiveValue = denormalizeTemplate(directive.$$moduleName, directiveValue);
22782306

22792307
if (directive.replace) {
22802308
replaceDirective = directive;
@@ -2782,7 +2810,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
27822810
.then(function(content) {
27832811
var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
27842812

2785-
content = denormalizeTemplate(content);
2813+
content = denormalizeTemplate(origAsyncDirective.$$moduleName, content);
27862814

27872815
if (origAsyncDirective.replace) {
27882816
if (jqLiteIsTextNode(content)) {

test/ng/compileSpec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3155,6 +3155,26 @@ describe('$compile', function() {
31553155
});
31563156
});
31573157

3158+
it('should allow modules to specify what interpolation symbol is used in templates', function() {
3159+
angular.module('symbol-test', [])
3160+
.directive('myDirective', function() {
3161+
return {
3162+
template: '<span foo=\'{"ctx":{"id":3}}\'></span>'
3163+
};
3164+
});
3165+
3166+
module('symbol-test', function($interpolateProvider, $compileProvider) {
3167+
$interpolateProvider.startSymbol('##');
3168+
$interpolateProvider.endSymbol(']]');
3169+
$compileProvider.moduleSymbols('symbol-test', '##', ']]');
3170+
});
3171+
3172+
inject(function($compile) {
3173+
element = $compile('<div><div my-directive></div></div>')($rootScope);
3174+
expect(element.children('div').children('span').attr('foo')).toBe('{"ctx":{"id":3}}');
3175+
});
3176+
});
3177+
31583178

31593179
it('should support custom start interpolation symbol, even when `endSymbol` doesn\'t change',
31603180
function() {

0 commit comments

Comments
 (0)