X Tutup
Skip to content

Commit cb6f832

Browse files
committed
refactor(filter): filters are now injectable and services
BREAK: - removed CSS support from filters
1 parent 6022f3d commit cb6f832

File tree

9 files changed

+179
-178
lines changed

9 files changed

+179
-178
lines changed

css/angular.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
display: none;
55
}
66

7-
.ng-format-negative {
8-
color: red;
9-
}
10-
117
ng\:form {
128
display: block;
139
}

src/Angular.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ var _undefined = undefined,
109109
angularDirective = extensionMap(angular, 'directive', lowercase),
110110
/** @name angular.widget */
111111
angularWidget = extensionMap(angular, 'widget', shivForIE),
112-
/** @name angular.filter */
113-
angularFilter = extensionMap(angular, 'filter'),
114112
/** @name angular.service */
115113
angularInputType = extensionMap(angular, 'inputType', lowercase),
116114
/** @name angular.service */
@@ -1054,6 +1052,7 @@ function ngModule($provide, $injector) {
10541052
$provide.service('$defer', $DeferProvider);
10551053
$provide.service('$document', $DocumentProvider);
10561054
$provide.service('$exceptionHandler', $ExceptionHandlerProvider);
1055+
$provide.service('$filter', $FilterProvider);
10571056
$provide.service('$formFactory', $FormFactoryProvider);
10581057
$provide.service('$locale', $LocaleProvider);
10591058
$provide.service('$location', $LocationProvider);

src/directives.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ angularDirective("ng:controller", function(expression){
236236
angularDirective("ng:bind", function(expression, element){
237237
element.addClass('ng-binding');
238238
return ['$exceptionHandler', '$parse', '$element', function($exceptionHandler, $parse, element) {
239-
var exprFn = parser(expression),
239+
var exprFn = $parse(expression),
240240
lastValue = Number.NaN;
241241

242242
this.$watch(function(scope) {

src/service/filter.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
$FilterProvider.$inject = ['$provide'];
4+
function $FilterProvider($provide) {
5+
var suffix = '$Filter';
6+
7+
$provide.filter = function(name, factory) {
8+
return $provide.factory(name + suffix, factory);
9+
};
10+
11+
this.$get = ['$injector', function($injector) {
12+
return function(name) {
13+
return $injector(name + suffix);
14+
}
15+
}];
16+
17+
////////////////////////////////////////
18+
19+
$provide.filter('currency', currencyFilter);
20+
$provide.filter('number', numberFilter);
21+
$provide.filter('date', dateFilter);
22+
$provide.filter('json', jsonFilter);
23+
$provide.filter('lowercase', lowercaseFilter);
24+
$provide.filter('uppercase', uppercaseFilter);
25+
$provide.filter('html', htmlFilter);
26+
$provide.filter('linky', linkyFilter);
27+
}

src/service/filter/filters.js

Lines changed: 96 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,15 @@
7272
</doc:scenario>
7373
</doc:example>
7474
*/
75-
angularFilter.currency = function(amount, currencySymbol){
76-
var formats = this.$service('$locale').NUMBER_FORMATS;
77-
this.$element.toggleClass('ng-format-negative', amount < 0);
78-
if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
79-
return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
80-
replace(/\u00A4/g, currencySymbol);
81-
};
75+
currencyFilter.$inject = ['$locale'];
76+
function currencyFilter($locale) {
77+
var formats = $locale.NUMBER_FORMATS;
78+
return function(amount, currencySymbol){
79+
if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
80+
return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
81+
replace(/\u00A4/g, currencySymbol);
82+
};
83+
}
8284

8385
/**
8486
* @ngdoc filter
@@ -126,14 +128,17 @@ angularFilter.currency = function(amount, currencySymbol){
126128
</doc:example>
127129
*/
128130

129-
var DECIMAL_SEP = '.';
130131

131-
angularFilter.number = function(number, fractionSize) {
132-
var formats = this.$service('$locale').NUMBER_FORMATS;
133-
return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP,
134-
formats.DECIMAL_SEP, fractionSize);
135-
};
132+
numberFilter.$inject = ['$locale'];
133+
function numberFilter($locale) {
134+
var formats = $locale.NUMBER_FORMATS;
135+
return function(number, fractionSize) {
136+
return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
137+
fractionSize);
138+
};
139+
}
136140

141+
var DECIMAL_SEP = '.';
137142
function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
138143
if (isNaN(number) || !isFinite(number)) return '';
139144

@@ -260,9 +265,7 @@ var DATE_FORMATS = {
260265
Z: timeZoneGetter
261266
};
262267

263-
var GET_TIME_ZONE = /[A-Z]{3}(?![+\-])/,
264-
DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
265-
OPERA_TOSTRING_PATTERN = /^[\d].*Z$/,
268+
var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
266269
NUMBER_STRING = /^\d+$/;
267270

268271
/**
@@ -343,49 +346,51 @@ var GET_TIME_ZONE = /[A-Z]{3}(?![+\-])/,
343346
</doc:scenario>
344347
</doc:example>
345348
*/
346-
angularFilter.date = function(date, format) {
347-
var $locale = this.$service('$locale'),
348-
text = '',
349-
parts = [],
350-
fn, match;
351-
352-
format = format || 'mediumDate'
353-
format = $locale.DATETIME_FORMATS[format] || format;
354-
if (isString(date)) {
355-
if (NUMBER_STRING.test(date)) {
356-
date = parseInt(date, 10);
357-
} else {
358-
date = angularString.toDate(date);
349+
dateFilter.$inject = ['$locale'];
350+
function dateFilter($locale) {
351+
return function(date, format) {
352+
var text = '',
353+
parts = [],
354+
fn, match;
355+
356+
format = format || 'mediumDate'
357+
format = $locale.DATETIME_FORMATS[format] || format;
358+
if (isString(date)) {
359+
if (NUMBER_STRING.test(date)) {
360+
date = parseInt(date, 10);
361+
} else {
362+
date = angularString.toDate(date);
363+
}
359364
}
360-
}
361365

362-
if (isNumber(date)) {
363-
date = new Date(date);
364-
}
366+
if (isNumber(date)) {
367+
date = new Date(date);
368+
}
365369

366-
if (!isDate(date)) {
367-
return date;
368-
}
370+
if (!isDate(date)) {
371+
return date;
372+
}
369373

370-
while(format) {
371-
match = DATE_FORMATS_SPLIT.exec(format);
372-
if (match) {
373-
parts = concat(parts, match, 1);
374-
format = parts.pop();
375-
} else {
376-
parts.push(format);
377-
format = null;
374+
while(format) {
375+
match = DATE_FORMATS_SPLIT.exec(format);
376+
if (match) {
377+
parts = concat(parts, match, 1);
378+
format = parts.pop();
379+
} else {
380+
parts.push(format);
381+
format = null;
382+
}
378383
}
379-
}
380384

381-
forEach(parts, function(value){
382-
fn = DATE_FORMATS[value];
383-
text += fn ? fn(date, $locale.DATETIME_FORMATS)
384-
: value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
385-
});
385+
forEach(parts, function(value){
386+
fn = DATE_FORMATS[value];
387+
text += fn ? fn(date, $locale.DATETIME_FORMATS)
388+
: value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
389+
});
386390

387-
return text;
388-
};
391+
return text;
392+
};
393+
}
389394

390395

391396
/**
@@ -417,10 +422,11 @@ angularFilter.date = function(date, format) {
417422
</doc:example>
418423
*
419424
*/
420-
angularFilter.json = function(object) {
421-
this.$element.addClass("ng-monospace");
422-
return toJson(object, true, /^(\$|this$)/);
423-
};
425+
function jsonFilter() {
426+
return function(object) {
427+
return toJson(object, true);
428+
};
429+
}
424430

425431

426432
/**
@@ -430,7 +436,7 @@ angularFilter.json = function(object) {
430436
*
431437
* @see angular.lowercase
432438
*/
433-
angularFilter.lowercase = lowercase;
439+
var lowercaseFilter = valueFn(lowercase);
434440

435441

436442
/**
@@ -440,7 +446,7 @@ angularFilter.lowercase = lowercase;
440446
*
441447
* @see angular.uppercase
442448
*/
443-
angularFilter.uppercase = uppercase;
449+
var uppercaseFilter = valueFn(uppercase);
444450

445451

446452
/**
@@ -537,9 +543,11 @@ angularFilter.uppercase = uppercase;
537543
</doc:scenario>
538544
</doc:example>
539545
*/
540-
angularFilter.html = function(html, option){
541-
return new HTML(html, option);
542-
};
546+
function htmlFilter() {
547+
return function(html, option){
548+
return new HTML(html, option);
549+
};
550+
}
543551

544552

545553
/**
@@ -619,29 +627,31 @@ angularFilter.html = function(html, option){
619627
</doc:scenario>
620628
</doc:example>
621629
*/
622-
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
623-
MAILTO_REGEXP = /^mailto:/;
624-
625-
angularFilter.linky = function(text) {
626-
if (!text) return text;
627-
var match;
628-
var raw = text;
629-
var html = [];
630-
var writer = htmlSanitizeWriter(html);
631-
var url;
632-
var i;
633-
while ((match = raw.match(LINKY_URL_REGEXP))) {
634-
// We can not end in these as they are sometimes found at the end of the sentence
635-
url = match[0];
636-
// if we did not match ftp/http/mailto then assume mailto
637-
if (match[2] == match[3]) url = 'mailto:' + url;
638-
i = match.index;
639-
writer.chars(raw.substr(0, i));
640-
writer.start('a', {href:url});
641-
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
642-
writer.end('a');
643-
raw = raw.substring(i + match[0].length);
644-
}
645-
writer.chars(raw);
646-
return new HTML(html.join(''));
630+
function linkyFilter() {
631+
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
632+
MAILTO_REGEXP = /^mailto:/;
633+
634+
return function(text) {
635+
if (!text) return text;
636+
var match;
637+
var raw = text;
638+
var html = [];
639+
var writer = htmlSanitizeWriter(html);
640+
var url;
641+
var i;
642+
while ((match = raw.match(LINKY_URL_REGEXP))) {
643+
// We can not end in these as they are sometimes found at the end of the sentence
644+
url = match[0];
645+
// if we did not match ftp/http/mailto then assume mailto
646+
if (match[2] == match[3]) url = 'mailto:' + url;
647+
i = match.index;
648+
writer.chars(raw.substr(0, i));
649+
writer.start('a', {href:url});
650+
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
651+
writer.end('a');
652+
raw = raw.substring(i + match[0].length);
653+
}
654+
writer.chars(raw);
655+
return new HTML(html.join(''));
656+
};
647657
};

src/service/parse.js

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ function lex(text){
217217

218218
/////////////////////////////////////////
219219

220-
function parser(text, json){
220+
function parser(text, json, $filter){
221221
var ZERO = valueFn(0),
222222
value,
223223
tokens = lex(text),
@@ -227,8 +227,7 @@ function parser(text, json){
227227
fieldAccess = _fieldAccess,
228228
objectIndex = _objectIndex,
229229
filterChain = _filterChain,
230-
functionIdent = _functionIdent,
231-
pipeFunction = _pipeFunction;
230+
functionIdent = _functionIdent;
232231
if(json){
233232
// The extra level of aliasing is here, just in case the lexer misses something, so that
234233
// we prevent any accidental execution in JSON.
@@ -239,7 +238,6 @@ function parser(text, json){
239238
assignable =
240239
filterChain =
241240
functionIdent =
242-
pipeFunction =
243241
function() { throwError("is not valid json", {text:text, index:0}); };
244242
value = primary();
245243
} else {
@@ -346,13 +344,9 @@ function parser(text, json){
346344
}
347345

348346
function filter() {
349-
return pipeFunction(angularFilter);
350-
}
351-
352-
function _pipeFunction(fnScope){
353-
var fn = functionIdent(fnScope);
347+
var token = expect();
348+
var fn = $filter(token.text);
354349
var argsFn = [];
355-
var token;
356350
while(true) {
357351
if ((token = expect(':'))) {
358352
argsFn.push(expression());
@@ -719,13 +713,13 @@ function getterFn(path) {
719713

720714
function $ParseProvider() {
721715
var cache = {};
722-
this.$get = ['$injector', function($injector) {
716+
this.$get = ['$filter', function($filter) {
723717
return function(exp) {
724718
switch(typeof exp) {
725719
case 'string':
726720
return cache.hasOwnProperty(exp)
727721
? cache[exp]
728-
: cache[exp] = parser(exp);
722+
: cache[exp] = parser(exp, false, $filter);
729723
case 'function':
730724
return exp;
731725
default:
@@ -735,10 +729,14 @@ function $ParseProvider() {
735729
}];
736730
}
737731

732+
function noFilters(){
733+
throw Error('Filters not supported!');
734+
}
735+
738736
// This is a special access for JSON parser which bypasses the injector
739737
var parseJson = function(json) {
740-
return parser(json, true);
738+
return parser(json, true, noFilters);
741739
};
742740

743741
// TODO(misko): temporary hack, until we get rid of the type augmentation
744-
var expressionCompile = new $ParseProvider().$get[1](null);
742+
var expressionCompile = new $ParseProvider().$get[1](noFilters);

0 commit comments

Comments
 (0)
X Tutup