Skip to content

Commit efee461

Browse files
committed
Making Interpolation Symbols Configurable
1 parent 20f3dc5 commit efee461

File tree

4 files changed

+112
-12
lines changed

4 files changed

+112
-12
lines changed

src/compile.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ function $CompileProvider($provide) {
8787
this.$get = ['$injector', '$parse', '$controller', '$rootScope', '$http', '$interpolate',
8888
function($injector, $parse, $controller, $rootScope, $http, $interpolate) {
8989

90+
var startSymbol = $interpolate.startSymbol();
91+
var endSymbol = $interpolate.endSymbol();
92+
var denormalizeTemplate = (startSymbol === '{{' && endSymbol === '}}') ?
93+
_.identity :
94+
function(template) {
95+
return template.replace(/\{\{/g, startSymbol)
96+
.replace(/\}\}/g, endSymbol);
97+
};
98+
9099
function Attributes(element) {
91100
this.$$element = element;
92101
this.$attr = {};
@@ -239,9 +248,14 @@ function $CompileProvider($provide) {
239248
if (!transcludedScope) {
240249
transcludedScope = scope.$new(false, containingScope);
241250
}
242-
return linkFn.nodeLinkFn.transclude(transcludedScope, cloneAttachFn, {
243-
transcludeControllers: transcludeControllers
251+
var didTransclude = linkFn.nodeLinkFn.transclude(transcludedScope, cloneAttachFn, {
252+
transcludeControllers: transcludeControllers,
253+
parentBoundTranscludeFn: parentBoundTranscludeFn
244254
});
255+
if (didTransclude.length === 0 && parentBoundTranscludeFn) {
256+
didTransclude = parentBoundTranscludeFn(transcludedScope, cloneAttachFn);
257+
}
258+
return didTransclude;
245259
};
246260
} else if (parentBoundTranscludeFn) {
247261
boundTranscludeFn = parentBoundTranscludeFn;
@@ -403,7 +417,7 @@ function $CompileProvider($provide) {
403417
if (/^(on[a-z]+|formaction)$/.test(name)) {
404418
throw 'Interpolations for HTML DOM event attributes not allowed';
405419
}
406-
420+
407421
var newValue = attrs[name];
408422
if (newValue !== value) {
409423
interpolateFn = newValue && $interpolate(newValue, true);
@@ -437,6 +451,7 @@ function $CompileProvider($provide) {
437451
var linkQueue = [];
438452
$compileNode.empty();
439453
$http.get(templateUrl).success(function(template) {
454+
template = denormalizeTemplate(template);
440455
directives.unshift(derivedSyncDirective);
441456
$compileNode.html(template);
442457
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, $compileNode, attrs, previousCompileContext);
@@ -575,9 +590,11 @@ function $CompileProvider($provide) {
575590
throw 'Multiple directives asking for template';
576591
}
577592
templateDirective = directive;
578-
$compileNode.html(_.isFunction(directive.template) ?
593+
var template = _.isFunction(directive.template) ?
579594
directive.template($compileNode, attrs) :
580-
directive.template);
595+
directive.template;
596+
template = denormalizeTemplate(template);
597+
$compileNode.html(template);
581598
}
582599
if (directive.templateUrl) {
583600
if (templateDirective) {

src/interpolate.js

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,26 @@
22
'use strict';
33

44
function $InterpolateProvider() {
5+
var startSymbol = '{{';
6+
var endSymbol = '}}';
7+
8+
this.startSymbol = function(value) {
9+
if (value) {
10+
startSymbol = value;
11+
return this;
12+
} else {
13+
return startSymbol;
14+
}
15+
};
16+
17+
this.endSymbol = function(value) {
18+
if (value) {
19+
endSymbol = value;
20+
return this;
21+
} else {
22+
return endSymbol;
23+
}
24+
};
525

626
function stringify(value) {
727
if (_.isNull(value) || _.isUndefined(value)) {
@@ -13,12 +33,18 @@ function $InterpolateProvider() {
1333
}
1434
}
1535

16-
function unescapeText(text) {
17-
return text.replace(/\\{\\{/g, '{{')
18-
.replace(/\\}\\}/g, '}}');
36+
function escapeChar(char) {
37+
return '\\\\\\' + char;
1938
}
2039

2140
this.$get = ['$parse', function($parse) {
41+
var escapedStartMatcher = new RegExp(startSymbol.replace(/./g, escapeChar), 'g');
42+
var escapedEndMatcher = new RegExp(endSymbol.replace(/./g, escapeChar), 'g');
43+
44+
function unescapeText(text) {
45+
return text.replace(escapedStartMatcher, startSymbol)
46+
.replace(escapedEndMatcher, endSymbol);
47+
}
2248

2349
function $interpolate(text, mustHaveExpressions) {
2450
var index = 0;
@@ -28,21 +54,21 @@ function $InterpolateProvider() {
2854
var expressionPositions = [];
2955
var startIndex, endIndex, exp, expFn;
3056
while (index < text.length) {
31-
startIndex = text.indexOf('{{', index);
57+
startIndex = text.indexOf(startSymbol, index);
3258
if (startIndex !== -1) {
33-
endIndex = text.indexOf('}}', startIndex + 2);
59+
endIndex = text.indexOf(endSymbol, startIndex + startSymbol.length);
3460
}
3561
if (startIndex !== -1 && endIndex !== -1) {
3662
if (startIndex !== index) {
3763
parts.push(unescapeText(text.substring(index, startIndex)));
3864
}
39-
exp = text.substring(startIndex + 2, endIndex);
65+
exp = text.substring(startIndex + startSymbol.length, endIndex);
4066
expFn = $parse(exp);
4167
expressions.push(exp);
4268
expressionFns.push(expFn);
4369
expressionPositions.push(parts.length);
4470
parts.push(expFn);
45-
index = endIndex + 2;
71+
index = endIndex + endSymbol.length;
4672
} else {
4773
parts.push(unescapeText(text.substring(index)));
4874
break;
@@ -82,6 +108,9 @@ function $InterpolateProvider() {
82108

83109
}
84110

111+
$interpolate.startSymbol = _.constant(startSymbol);
112+
$interpolate.endSymbol = _.constant(endSymbol);
113+
85114
return $interpolate;
86115
}];
87116

test/compile_spec.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3702,6 +3702,24 @@ describe('$compile', function() {
37023702
});
37033703
});
37043704

3705+
it('denormalizes directive templates', function() {
3706+
var injector = createInjector(['ng', function($interpolateProvider, $compileProvider) {
3707+
$interpolateProvider.startSymbol('[[').endSymbol(']]');
3708+
$compileProvider.directive('myDirective', function() {
3709+
return {
3710+
template: 'Value is {{myExpr}}'
3711+
};
3712+
});
3713+
}]);
3714+
injector.invoke(function($compile, $rootScope) {
3715+
var el = $('<div my-directive></div>');
3716+
$rootScope.myExpr = 42;
3717+
$compile(el)($rootScope);
3718+
$rootScope.$apply();
3719+
3720+
expect(el.html()).toEqual('Value is 42');
3721+
});
3722+
});
37053723

37063724
});
37073725

test/interpolate_spec.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,40 @@ describe('$interpolate', function() {
143143
expect(listenerSpy.calls.mostRecent().args[1]).toEqual('42');
144144
});
145145

146+
it('allows configuring start and end symbols', function() {
147+
var injector = createInjector(['ng', function($interpolateProvider) {
148+
$interpolateProvider.startSymbol('FOO').endSymbol('OOF');
149+
}]);
150+
var $interpolate = injector.get('$interpolate');
151+
expect($interpolate.startSymbol()).toEqual('FOO');
152+
expect($interpolate.endSymbol()).toEqual('OOF');
153+
});
154+
155+
it('works with start and end symbols that differ from default', function() {
156+
var injector = createInjector(['ng', function($interpolateProvider) {
157+
$interpolateProvider.startSymbol('FOO').endSymbol('OOF');
158+
}]);
159+
var $interpolate = injector.get('$interpolate');
160+
var interpFn = $interpolate('FOOmyExprOOF');
161+
expect(interpFn({myExpr: 42})).toEqual('42');
162+
});
163+
164+
it('does not work with default start and end symbols when reconfigured', function() {
165+
var injector = createInjector(['ng', function($interpolateProvider) {
166+
$interpolateProvider.startSymbol('FOO').endSymbol('OOF');
167+
}]);
168+
var $interpolate = injector.get('$interpolate');
169+
var interpFn = $interpolate('{{myExpr}}');
170+
expect(interpFn({myExpr: 42})).toEqual('{{myExpr}}');
171+
});
172+
173+
it('supports unescaping for reconfigured symbols', function() {
174+
var injector = createInjector(['ng', function($interpolateProvider) {
175+
$interpolateProvider.startSymbol('FOO').endSymbol('OOF');
176+
}]);
177+
var $interpolate = injector.get('$interpolate');
178+
var interpFn = $interpolate('\\F\\O\\OmyExpr\\O\\O\\F');
179+
expect(interpFn({})).toEqual('FOOmyExprOOF');
180+
});
181+
146182
});

0 commit comments

Comments
 (0)