aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMisko Hevery2011-12-07 21:01:19 -0800
committerMisko Hevery2012-01-25 11:46:36 -0800
commit5001c1a1217772d2bffe108bafd475b24badf559 (patch)
tree8c16f111ae4bfcf4b098b14d395b327443917501 /src
parent0f6b2ef9823953533dd98849fc29c08e6a05c4a4 (diff)
downloadangular.js-5001c1a1217772d2bffe108bafd475b24badf559.tar.bz2
refactor($interpolate): improve interpolation service add documentation
Diffstat (limited to 'src')
-rw-r--r--src/service/interpolate.js205
1 files changed, 134 insertions, 71 deletions
diff --git a/src/service/interpolate.js b/src/service/interpolate.js
index 03692824..6d3ae868 100644
--- a/src/service/interpolate.js
+++ b/src/service/interpolate.js
@@ -1,82 +1,145 @@
'use strict';
-function $InterpolateProvider(){
- this.$get = ['$parse', function($parse){
- return function(text, templateOnly) {
- var bindings = parseBindings(text);
- if (hasBindings(bindings) || !templateOnly) {
- return compileBindTemplate(text);
- }
- };
- }];
-}
+/**
+ * @ngdoc function
+ * @name angular.module.ng.$interpolateProvider
+ * @function
+ *
+ * @description
+ *
+ * Used for configuring the interpolation markup. Deafults to `{{` and `}}`.
+ */
+function $InterpolateProvider() {
+ var startSymbol = '{{';
+ var endSymbol = '}}';
-var bindTemplateCache = {};
-function compileBindTemplate(template){
- var fn = bindTemplateCache[template];
- if (!fn) {
- var bindings = [];
- forEach(parseBindings(template), function(text){
- var exp = binding(text);
- bindings.push(exp
- ? function(scope, element) { return scope.$eval(exp); }
- : function() { return text; });
- });
- bindTemplateCache[template] = fn = function(scope, element, prettyPrintJson) {
- var parts = [],
- hadOwnElement = scope.hasOwnProperty('$element'),
- oldElement = scope.$element;
+ /**
+ * @ngdoc method
+ * @name angular.module.ng.$interpolateProvider#startSymbol
+ * @methodOf angular.module.ng.$interpolateProvider
+ * @description
+ * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
+ *
+ * @prop {string=} value new value to set the starting symbol to.
+ */
+ this.startSymbol = function(value){
+ if (value) {
+ startSymbol = value;
+ return this;
+ } else {
+ return startSymbol;
+ }
+ };
- // TODO(misko): get rid of $element
- scope.$element = element;
- try {
- for (var i = 0; i < bindings.length; i++) {
- var value = bindings[i](scope, element);
- if (isElement(value))
- value = '';
- else if (isObject(value))
- value = toJson(value, prettyPrintJson);
- parts.push(value);
- }
- return parts.join('');
- } finally {
- if (hadOwnElement) {
- scope.$element = oldElement;
- } else {
- delete scope.$element;
- }
- }
- };
- }
- return fn;
-}
+ /**
+ * @ngdoc method
+ * @name angular.module.ng.$interpolateProvider#endSymbol
+ * @methodOf angular.module.ng.$interpolateProvider
+ * @description
+ * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
+ *
+ * @prop {string=} value new value to set the ending symbol to.
+ */
+ this.endSymbol = function(value){
+ if (value) {
+ endSymbol = value;
+ return this;
+ } else {
+ return startSymbol;
+ }
+ };
-function parseBindings(string) {
- var results = [];
- var lastIndex = 0;
- var index;
- while((index = string.indexOf('{{', lastIndex)) > -1) {
- if (lastIndex < index)
- results.push(string.substr(lastIndex, index - lastIndex));
- lastIndex = index;
+ this.$get = ['$parse', function($parse) {
+ var startSymbolLength = startSymbol.length,
+ endSymbolLength = endSymbol.length;
- index = string.indexOf('}}', index);
- index = index < 0 ? string.length : index + 2;
+ /**
+ * @ngdoc function
+ * @name angular.module.ng.$interpolate
+ * @function
+ *
+ * @requires $parse
+ *
+ * @description
+ *
+ * Compiles a string with markup into an interpolation function. This service is used by the
+ * HTML {@link angular.module.ng.$compile $compile} service for data binding. See
+ * {@link angular.module.ng.$interpolateProvider $interpolateProvider} for configuring the
+ * interpolation markup.
+ *
+ *
+ <pre>
+ var $interpolate = ...; // injected
+ var exp = $interpolate('Hello {{name}}!');
+ expect(exp({name:'Angular'}).toEqual('Hello Angular!');
+ </pre>
+ *
+ *
+ * @param {string} text The text with markup to interpolate.
+ * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
+ * embedded expression in order to return an interpolation function. Strings with no
+ * embedded expression will return null for the interpolation function.
+ * @returns {function(context)} an interpolation function which is used to compute the interpolated
+ * string. The function has these parameters:
+ *
+ * * `context`: an object against which any expressions embedded in the strings are evaluated
+ * against.
+ *
+ */
+ return function(text, mustHaveExpression) {
+ var startIndex,
+ endIndex,
+ index = 0,
+ parts = [],
+ length = text.length,
+ hasInterpolation = false,
+ fn,
+ exp,
+ concat = [];
- results.push(string.substr(lastIndex, index - lastIndex));
- lastIndex = index;
- }
- if (lastIndex != string.length)
- results.push(string.substr(lastIndex, string.length - lastIndex));
- return results.length === 0 ? [ string ] : results;
-}
+ while(index < length) {
+ if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
+ ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
+ (index != startIndex) && parts.push(text.substring(index, startIndex));
+ parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
+ fn.exp = exp;
+ index = endIndex + endSymbolLength;
+ hasInterpolation = true;
+ } else {
+ // we did not find anything, so we have to add the remainder to the parts array
+ (index != length) && parts.push(text.substring(index));
+ index = length;
+ }
+ }
-function binding(string) {
- var binding = string.replace(/\n/gm, ' ').match(/^\{\{(.*)\}\}$/);
- return binding ? binding[1] : null;
-}
+ if (!(length = parts.length)) {
+ // we added, nothing, must have been an empty string.
+ parts.push('');
+ length = 1;
+ }
-function hasBindings(bindings) {
- return bindings.length > 1 || binding(bindings[0]) !== null;
+ if (!mustHaveExpression || hasInterpolation) {
+ concat.length = length;
+ fn = function(context) {
+ for(var i = 0, ii = length, part; i<ii; i++) {
+ if (typeof (part = parts[i]) == 'function') {
+ part = part(context);
+ if (part == null || part == undefined) {
+ part = '';
+ } else if (typeof part != 'string') {
+ part = toJson(part);
+ }
+ }
+ concat[i] = part;
+ }
+ return concat.join('');
+ };
+ fn.exp = text;
+ fn.parts = parts;
+ return fn;
+ }
+ };
+ }];
}
+