aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Angular.js3
-rw-r--r--src/directives.js2
-rw-r--r--src/service/filter.js27
-rw-r--r--src/service/filter/filters.js182
-rw-r--r--src/service/parse.js26
5 files changed, 137 insertions, 103 deletions
diff --git a/src/Angular.js b/src/Angular.js
index d8a726c0..17aa2d4a 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -109,8 +109,6 @@ var _undefined = undefined,
angularDirective = extensionMap(angular, 'directive', lowercase),
/** @name angular.widget */
angularWidget = extensionMap(angular, 'widget', shivForIE),
- /** @name angular.filter */
- angularFilter = extensionMap(angular, 'filter'),
/** @name angular.service */
angularInputType = extensionMap(angular, 'inputType', lowercase),
/** @name angular.service */
@@ -1054,6 +1052,7 @@ function ngModule($provide, $injector) {
$provide.service('$defer', $DeferProvider);
$provide.service('$document', $DocumentProvider);
$provide.service('$exceptionHandler', $ExceptionHandlerProvider);
+ $provide.service('$filter', $FilterProvider);
$provide.service('$formFactory', $FormFactoryProvider);
$provide.service('$locale', $LocaleProvider);
$provide.service('$location', $LocationProvider);
diff --git a/src/directives.js b/src/directives.js
index 20235f64..b511541f 100644
--- a/src/directives.js
+++ b/src/directives.js
@@ -236,7 +236,7 @@ angularDirective("ng:controller", function(expression){
angularDirective("ng:bind", function(expression, element){
element.addClass('ng-binding');
return ['$exceptionHandler', '$parse', '$element', function($exceptionHandler, $parse, element) {
- var exprFn = parser(expression),
+ var exprFn = $parse(expression),
lastValue = Number.NaN;
this.$watch(function(scope) {
diff --git a/src/service/filter.js b/src/service/filter.js
new file mode 100644
index 00000000..7b85c23d
--- /dev/null
+++ b/src/service/filter.js
@@ -0,0 +1,27 @@
+'use strict';
+
+$FilterProvider.$inject = ['$provide'];
+function $FilterProvider($provide) {
+ var suffix = '$Filter';
+
+ $provide.filter = function(name, factory) {
+ return $provide.factory(name + suffix, factory);
+ };
+
+ this.$get = ['$injector', function($injector) {
+ return function(name) {
+ return $injector(name + suffix);
+ }
+ }];
+
+ ////////////////////////////////////////
+
+ $provide.filter('currency', currencyFilter);
+ $provide.filter('number', numberFilter);
+ $provide.filter('date', dateFilter);
+ $provide.filter('json', jsonFilter);
+ $provide.filter('lowercase', lowercaseFilter);
+ $provide.filter('uppercase', uppercaseFilter);
+ $provide.filter('html', htmlFilter);
+ $provide.filter('linky', linkyFilter);
+}
diff --git a/src/service/filter/filters.js b/src/service/filter/filters.js
index b9c3d2ef..eea3cbf2 100644
--- a/src/service/filter/filters.js
+++ b/src/service/filter/filters.js
@@ -72,13 +72,15 @@
</doc:scenario>
</doc:example>
*/
-angularFilter.currency = function(amount, currencySymbol){
- var formats = this.$service('$locale').NUMBER_FORMATS;
- this.$element.toggleClass('ng-format-negative', amount < 0);
- if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
- return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
- replace(/\u00A4/g, currencySymbol);
-};
+currencyFilter.$inject = ['$locale'];
+function currencyFilter($locale) {
+ var formats = $locale.NUMBER_FORMATS;
+ return function(amount, currencySymbol){
+ if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
+ return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
+ replace(/\u00A4/g, currencySymbol);
+ };
+}
/**
* @ngdoc filter
@@ -126,14 +128,17 @@ angularFilter.currency = function(amount, currencySymbol){
</doc:example>
*/
-var DECIMAL_SEP = '.';
-angularFilter.number = function(number, fractionSize) {
- var formats = this.$service('$locale').NUMBER_FORMATS;
- return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP,
- formats.DECIMAL_SEP, fractionSize);
-};
+numberFilter.$inject = ['$locale'];
+function numberFilter($locale) {
+ var formats = $locale.NUMBER_FORMATS;
+ return function(number, fractionSize) {
+ return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
+ fractionSize);
+ };
+}
+var DECIMAL_SEP = '.';
function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
if (isNaN(number) || !isFinite(number)) return '';
@@ -260,9 +265,7 @@ var DATE_FORMATS = {
Z: timeZoneGetter
};
-var GET_TIME_ZONE = /[A-Z]{3}(?![+\-])/,
- DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
- OPERA_TOSTRING_PATTERN = /^[\d].*Z$/,
+var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
NUMBER_STRING = /^\d+$/;
/**
@@ -343,49 +346,51 @@ var GET_TIME_ZONE = /[A-Z]{3}(?![+\-])/,
</doc:scenario>
</doc:example>
*/
-angularFilter.date = function(date, format) {
- var $locale = this.$service('$locale'),
- text = '',
- parts = [],
- fn, match;
-
- format = format || 'mediumDate'
- format = $locale.DATETIME_FORMATS[format] || format;
- if (isString(date)) {
- if (NUMBER_STRING.test(date)) {
- date = parseInt(date, 10);
- } else {
- date = angularString.toDate(date);
+dateFilter.$inject = ['$locale'];
+function dateFilter($locale) {
+ return function(date, format) {
+ var text = '',
+ parts = [],
+ fn, match;
+
+ format = format || 'mediumDate'
+ format = $locale.DATETIME_FORMATS[format] || format;
+ if (isString(date)) {
+ if (NUMBER_STRING.test(date)) {
+ date = parseInt(date, 10);
+ } else {
+ date = angularString.toDate(date);
+ }
}
- }
- if (isNumber(date)) {
- date = new Date(date);
- }
+ if (isNumber(date)) {
+ date = new Date(date);
+ }
- if (!isDate(date)) {
- return date;
- }
+ if (!isDate(date)) {
+ return date;
+ }
- while(format) {
- match = DATE_FORMATS_SPLIT.exec(format);
- if (match) {
- parts = concat(parts, match, 1);
- format = parts.pop();
- } else {
- parts.push(format);
- format = null;
+ while(format) {
+ match = DATE_FORMATS_SPLIT.exec(format);
+ if (match) {
+ parts = concat(parts, match, 1);
+ format = parts.pop();
+ } else {
+ parts.push(format);
+ format = null;
+ }
}
- }
- forEach(parts, function(value){
- fn = DATE_FORMATS[value];
- text += fn ? fn(date, $locale.DATETIME_FORMATS)
- : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
- });
+ forEach(parts, function(value){
+ fn = DATE_FORMATS[value];
+ text += fn ? fn(date, $locale.DATETIME_FORMATS)
+ : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
+ });
- return text;
-};
+ return text;
+ };
+}
/**
@@ -417,10 +422,11 @@ angularFilter.date = function(date, format) {
</doc:example>
*
*/
-angularFilter.json = function(object) {
- this.$element.addClass("ng-monospace");
- return toJson(object, true, /^(\$|this$)/);
-};
+function jsonFilter() {
+ return function(object) {
+ return toJson(object, true);
+ };
+}
/**
@@ -430,7 +436,7 @@ angularFilter.json = function(object) {
*
* @see angular.lowercase
*/
-angularFilter.lowercase = lowercase;
+var lowercaseFilter = valueFn(lowercase);
/**
@@ -440,7 +446,7 @@ angularFilter.lowercase = lowercase;
*
* @see angular.uppercase
*/
-angularFilter.uppercase = uppercase;
+var uppercaseFilter = valueFn(uppercase);
/**
@@ -537,9 +543,11 @@ angularFilter.uppercase = uppercase;
</doc:scenario>
</doc:example>
*/
-angularFilter.html = function(html, option){
- return new HTML(html, option);
-};
+function htmlFilter() {
+ return function(html, option){
+ return new HTML(html, option);
+ };
+}
/**
@@ -619,29 +627,31 @@ angularFilter.html = function(html, option){
</doc:scenario>
</doc:example>
*/
-var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
- MAILTO_REGEXP = /^mailto:/;
-
-angularFilter.linky = function(text) {
- if (!text) return text;
- var match;
- var raw = text;
- var html = [];
- var writer = htmlSanitizeWriter(html);
- var url;
- var i;
- while ((match = raw.match(LINKY_URL_REGEXP))) {
- // We can not end in these as they are sometimes found at the end of the sentence
- url = match[0];
- // if we did not match ftp/http/mailto then assume mailto
- if (match[2] == match[3]) url = 'mailto:' + url;
- i = match.index;
- writer.chars(raw.substr(0, i));
- writer.start('a', {href:url});
- writer.chars(match[0].replace(MAILTO_REGEXP, ''));
- writer.end('a');
- raw = raw.substring(i + match[0].length);
- }
- writer.chars(raw);
- return new HTML(html.join(''));
+function linkyFilter() {
+ var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
+ MAILTO_REGEXP = /^mailto:/;
+
+ return function(text) {
+ if (!text) return text;
+ var match;
+ var raw = text;
+ var html = [];
+ var writer = htmlSanitizeWriter(html);
+ var url;
+ var i;
+ while ((match = raw.match(LINKY_URL_REGEXP))) {
+ // We can not end in these as they are sometimes found at the end of the sentence
+ url = match[0];
+ // if we did not match ftp/http/mailto then assume mailto
+ if (match[2] == match[3]) url = 'mailto:' + url;
+ i = match.index;
+ writer.chars(raw.substr(0, i));
+ writer.start('a', {href:url});
+ writer.chars(match[0].replace(MAILTO_REGEXP, ''));
+ writer.end('a');
+ raw = raw.substring(i + match[0].length);
+ }
+ writer.chars(raw);
+ return new HTML(html.join(''));
+ };
};
diff --git a/src/service/parse.js b/src/service/parse.js
index 465f416e..36f6b715 100644
--- a/src/service/parse.js
+++ b/src/service/parse.js
@@ -217,7 +217,7 @@ function lex(text){
/////////////////////////////////////////
-function parser(text, json){
+function parser(text, json, $filter){
var ZERO = valueFn(0),
value,
tokens = lex(text),
@@ -227,8 +227,7 @@ function parser(text, json){
fieldAccess = _fieldAccess,
objectIndex = _objectIndex,
filterChain = _filterChain,
- functionIdent = _functionIdent,
- pipeFunction = _pipeFunction;
+ functionIdent = _functionIdent;
if(json){
// The extra level of aliasing is here, just in case the lexer misses something, so that
// we prevent any accidental execution in JSON.
@@ -239,7 +238,6 @@ function parser(text, json){
assignable =
filterChain =
functionIdent =
- pipeFunction =
function() { throwError("is not valid json", {text:text, index:0}); };
value = primary();
} else {
@@ -346,13 +344,9 @@ function parser(text, json){
}
function filter() {
- return pipeFunction(angularFilter);
- }
-
- function _pipeFunction(fnScope){
- var fn = functionIdent(fnScope);
+ var token = expect();
+ var fn = $filter(token.text);
var argsFn = [];
- var token;
while(true) {
if ((token = expect(':'))) {
argsFn.push(expression());
@@ -719,13 +713,13 @@ function getterFn(path) {
function $ParseProvider() {
var cache = {};
- this.$get = ['$injector', function($injector) {
+ this.$get = ['$filter', function($filter) {
return function(exp) {
switch(typeof exp) {
case 'string':
return cache.hasOwnProperty(exp)
? cache[exp]
- : cache[exp] = parser(exp);
+ : cache[exp] = parser(exp, false, $filter);
case 'function':
return exp;
default:
@@ -735,10 +729,14 @@ function $ParseProvider() {
}];
}
+function noFilters(){
+ throw Error('Filters not supported!');
+}
+
// This is a special access for JSON parser which bypasses the injector
var parseJson = function(json) {
- return parser(json, true);
+ return parser(json, true, noFilters);
};
// TODO(misko): temporary hack, until we get rid of the type augmentation
-var expressionCompile = new $ParseProvider().$get[1](null);
+var expressionCompile = new $ParseProvider().$get[1](noFilters);