Skip to content

Commit

Permalink
Making Interpolation Symbols Configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
teropa committed Jul 31, 2015
1 parent d206b95 commit 7c67324
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 12 deletions.
27 changes: 22 additions & 5 deletions src/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ function $CompileProvider($provide) {
this.$get = ['$injector', '$parse', '$controller', '$rootScope', '$http', '$interpolate',
function($injector, $parse, $controller, $rootScope, $http, $interpolate) {

var startSymbol = $interpolate.startSymbol();
var endSymbol = $interpolate.endSymbol();
var denormalizeTemplate = (startSymbol === '{{' && endSymbol === '}}') ?
_.identity :
function(template) {
return template.replace(/\{\{/g, startSymbol)
.replace(/\}\}/g, endSymbol);
};

function Attributes(element) {
this.$$element = element;
this.$attr = {};
Expand Down Expand Up @@ -239,9 +248,14 @@ function $CompileProvider($provide) {
if (!transcludedScope) {
transcludedScope = scope.$new(false, containingScope);
}
return linkFn.nodeLinkFn.transclude(transcludedScope, cloneAttachFn, {
transcludeControllers: transcludeControllers
var didTransclude = linkFn.nodeLinkFn.transclude(transcludedScope, cloneAttachFn, {
transcludeControllers: transcludeControllers,
parentBoundTranscludeFn: parentBoundTranscludeFn
});
if (didTransclude.length === 0 && parentBoundTranscludeFn) {
didTransclude = parentBoundTranscludeFn(transcludedScope, cloneAttachFn);
}
return didTransclude;
};
} else if (parentBoundTranscludeFn) {
boundTranscludeFn = parentBoundTranscludeFn;
Expand Down Expand Up @@ -403,7 +417,7 @@ function $CompileProvider($provide) {
if (/^(on[a-z]+|formaction)$/.test(name)) {
throw 'Interpolations for HTML DOM event attributes not allowed';
}

var newValue = attrs[name];
if (newValue !== value) {
interpolateFn = newValue && $interpolate(newValue, true);
Expand Down Expand Up @@ -437,6 +451,7 @@ function $CompileProvider($provide) {
var linkQueue = [];
$compileNode.empty();
$http.get(templateUrl).success(function(template) {
template = denormalizeTemplate(template);
directives.unshift(derivedSyncDirective);
$compileNode.html(template);
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, $compileNode, attrs, previousCompileContext);
Expand Down Expand Up @@ -575,9 +590,11 @@ function $CompileProvider($provide) {
throw 'Multiple directives asking for template';
}
templateDirective = directive;
$compileNode.html(_.isFunction(directive.template) ?
var template = _.isFunction(directive.template) ?
directive.template($compileNode, attrs) :
directive.template);
directive.template;
template = denormalizeTemplate(template);
$compileNode.html(template);
}
if (directive.templateUrl) {
if (templateDirective) {
Expand Down
43 changes: 36 additions & 7 deletions src/interpolate.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@
'use strict';

function $InterpolateProvider() {
var startSymbol = '{{';
var endSymbol = '}}';

this.startSymbol = function(value) {
if (value) {
startSymbol = value;
return this;
} else {
return startSymbol;
}
};

this.endSymbol = function(value) {
if (value) {
endSymbol = value;
return this;
} else {
return endSymbol;
}
};

function stringify(value) {
if (_.isNull(value) || _.isUndefined(value)) {
Expand All @@ -13,12 +33,18 @@ function $InterpolateProvider() {
}
}

function unescapeText(text) {
return text.replace(/\\{\\{/g, '{{')
.replace(/\\}\\}/g, '}}');
function escapeChar(char) {
return '\\\\\\' + char;
}

this.$get = ['$parse', function($parse) {
var escapedStartMatcher = new RegExp(startSymbol.replace(/./g, escapeChar), 'g');
var escapedEndMatcher = new RegExp(endSymbol.replace(/./g, escapeChar), 'g');

function unescapeText(text) {
return text.replace(escapedStartMatcher, startSymbol)
.replace(escapedEndMatcher, endSymbol);
}

function $interpolate(text, mustHaveExpressions) {
var index = 0;
Expand All @@ -28,21 +54,21 @@ function $InterpolateProvider() {
var expressionPositions = [];
var startIndex, endIndex, exp, expFn;
while (index < text.length) {
startIndex = text.indexOf('{{', index);
startIndex = text.indexOf(startSymbol, index);
if (startIndex !== -1) {
endIndex = text.indexOf('}}', startIndex + 2);
endIndex = text.indexOf(endSymbol, startIndex + startSymbol.length);
}
if (startIndex !== -1 && endIndex !== -1) {
if (startIndex !== index) {
parts.push(unescapeText(text.substring(index, startIndex)));
}
exp = text.substring(startIndex + 2, endIndex);
exp = text.substring(startIndex + startSymbol.length, endIndex);
expFn = $parse(exp);
expressions.push(exp);
expressionFns.push(expFn);
expressionPositions.push(parts.length);
parts.push(expFn);
index = endIndex + 2;
index = endIndex + endSymbol.length;
} else {
parts.push(unescapeText(text.substring(index)));
break;
Expand Down Expand Up @@ -82,6 +108,9 @@ function $InterpolateProvider() {

}

$interpolate.startSymbol = _.constant(startSymbol);
$interpolate.endSymbol = _.constant(endSymbol);

return $interpolate;
}];

Expand Down
18 changes: 18 additions & 0 deletions test/compile_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3702,6 +3702,24 @@ describe('$compile', function() {
});
});

it('denormalizes directive templates', function() {
var injector = createInjector(['ng', function($interpolateProvider, $compileProvider) {
$interpolateProvider.startSymbol('[[').endSymbol(']]');
$compileProvider.directive('myDirective', function() {
return {
template: 'Value is {{myExpr}}'
};
});
}]);
injector.invoke(function($compile, $rootScope) {
var el = $('<div my-directive></div>');
$rootScope.myExpr = 42;
$compile(el)($rootScope);
$rootScope.$apply();

expect(el.html()).toEqual('Value is 42');
});
});

});

Expand Down
36 changes: 36 additions & 0 deletions test/interpolate_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,40 @@ describe('$interpolate', function() {
expect(listenerSpy.calls.mostRecent().args[1]).toEqual('42');
});

it('allows configuring start and end symbols', function() {
var injector = createInjector(['ng', function($interpolateProvider) {
$interpolateProvider.startSymbol('FOO').endSymbol('OOF');
}]);
var $interpolate = injector.get('$interpolate');
expect($interpolate.startSymbol()).toEqual('FOO');
expect($interpolate.endSymbol()).toEqual('OOF');
});

it('works with start and end symbols that differ from default', function() {
var injector = createInjector(['ng', function($interpolateProvider) {
$interpolateProvider.startSymbol('FOO').endSymbol('OOF');
}]);
var $interpolate = injector.get('$interpolate');
var interpFn = $interpolate('FOOmyExprOOF');
expect(interpFn({myExpr: 42})).toEqual('42');
});

it('does not work with default start and end symbols when reconfigured', function() {
var injector = createInjector(['ng', function($interpolateProvider) {
$interpolateProvider.startSymbol('FOO').endSymbol('OOF');
}]);
var $interpolate = injector.get('$interpolate');
var interpFn = $interpolate('{{myExpr}}');
expect(interpFn({myExpr: 42})).toEqual('{{myExpr}}');
});

it('supports unescaping for reconfigured symbols', function() {
var injector = createInjector(['ng', function($interpolateProvider) {
$interpolateProvider.startSymbol('FOO').endSymbol('OOF');
}]);
var $interpolate = injector.get('$interpolate');
var interpFn = $interpolate('\\F\\O\\OmyExpr\\O\\O\\F');
expect(interpFn({})).toEqual('FOOmyExprOOF');
});

});

0 comments on commit 7c67324

Please sign in to comment.