refactor(common): pipe code cleanup

This commit is contained in:
Victor Berchet 2016-09-11 00:27:56 -07:00 committed by Alex Eagle
parent 70488ed382
commit 5509453e72
7 changed files with 53 additions and 72 deletions

View File

@ -8,7 +8,6 @@
import {ChangeDetectorRef, OnDestroy, Pipe, WrappedValue} from '@angular/core'; import {ChangeDetectorRef, OnDestroy, Pipe, WrappedValue} from '@angular/core';
import {EventEmitter, Observable} from '../facade/async'; import {EventEmitter, Observable} from '../facade/async';
import {isBlank, isPresent} from '../facade/lang';
import {isPromise} from '../private_import_core'; import {isPromise} from '../private_import_core';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@ -38,9 +37,8 @@ class PromiseStrategy implements SubscriptionStrategy {
onDestroy(subscription: any): void {} onDestroy(subscription: any): void {}
} }
var _promiseStrategy = new PromiseStrategy(); const _promiseStrategy = new PromiseStrategy();
var _observableStrategy = new ObservableStrategy(); const _observableStrategy = new ObservableStrategy();
var __unused: Promise<any>; // avoid unused import when Promise union types are erased
/** /**
* @ngModule CommonModule * @ngModule CommonModule
@ -69,30 +67,24 @@ var __unused: Promise<any>; // avoid unused import when Promise union types are
*/ */
@Pipe({name: 'async', pure: false}) @Pipe({name: 'async', pure: false})
export class AsyncPipe implements OnDestroy { export class AsyncPipe implements OnDestroy {
/** @internal */ private _latestValue: Object = null;
_latestValue: Object = null; private _latestReturnedValue: Object = null;
/** @internal */
_latestReturnedValue: Object = null;
/** @internal */ private _subscription: Object = null;
_subscription: Object = null; private _obj: Observable<any>|Promise<any>|EventEmitter<any> = null;
/** @internal */
_obj: Observable<any>|Promise<any>|EventEmitter<any> = null;
/** @internal */
_ref: ChangeDetectorRef;
private _strategy: SubscriptionStrategy = null; private _strategy: SubscriptionStrategy = null;
constructor(_ref: ChangeDetectorRef) { this._ref = _ref; } constructor(private _ref: ChangeDetectorRef) {}
ngOnDestroy(): void { ngOnDestroy(): void {
if (isPresent(this._subscription)) { if (this._subscription) {
this._dispose(); this._dispose();
} }
} }
transform(obj: Observable<any>|Promise<any>|EventEmitter<any>): any { transform(obj: Observable<any>|Promise<any>|EventEmitter<any>): any {
if (isBlank(this._obj)) { if (!this._obj) {
if (isPresent(obj)) { if (obj) {
this._subscribe(obj); this._subscribe(obj);
} }
this._latestReturnedValue = this._latestValue; this._latestReturnedValue = this._latestValue;
@ -106,33 +98,32 @@ export class AsyncPipe implements OnDestroy {
if (this._latestValue === this._latestReturnedValue) { if (this._latestValue === this._latestReturnedValue) {
return this._latestReturnedValue; return this._latestReturnedValue;
} else { }
this._latestReturnedValue = this._latestValue; this._latestReturnedValue = this._latestValue;
return WrappedValue.wrap(this._latestValue); return WrappedValue.wrap(this._latestValue);
} }
}
/** @internal */ private _subscribe(obj: Observable<any>|Promise<any>|EventEmitter<any>): void {
_subscribe(obj: Observable<any>|Promise<any>|EventEmitter<any>): void {
this._obj = obj; this._obj = obj;
this._strategy = this._selectStrategy(obj); this._strategy = this._selectStrategy(obj);
this._subscription = this._strategy.createSubscription( this._subscription = this._strategy.createSubscription(
obj, (value: Object) => this._updateLatestValue(obj, value)); obj, (value: Object) => this._updateLatestValue(obj, value));
} }
/** @internal */ private _selectStrategy(obj: Observable<any>|Promise<any>|EventEmitter<any>): any {
_selectStrategy(obj: Observable<any>|Promise<any>|EventEmitter<any>): any {
if (isPromise(obj)) { if (isPromise(obj)) {
return _promiseStrategy; return _promiseStrategy;
} else if ((<any>obj).subscribe) {
return _observableStrategy;
} else {
throw new InvalidPipeArgumentError(AsyncPipe, obj);
}
} }
/** @internal */ if ((<any>obj).subscribe) {
_dispose(): void { return _observableStrategy;
}
throw new InvalidPipeArgumentError(AsyncPipe, obj);
}
private _dispose(): void {
this._strategy.dispose(this._subscription); this._strategy.dispose(this._subscription);
this._latestValue = null; this._latestValue = null;
this._latestReturnedValue = null; this._latestReturnedValue = null;
@ -140,8 +131,7 @@ export class AsyncPipe implements OnDestroy {
this._obj = null; this._obj = null;
} }
/** @internal */ private _updateLatestValue(async: any, value: Object) {
_updateLatestValue(async: any, value: Object) {
if (async === this._obj) { if (async === this._obj) {
this._latestValue = value; this._latestValue = value;
this._ref.markForCheck(); this._ref.markForCheck();

View File

@ -7,10 +7,8 @@
*/ */
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core'; import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {DateFormatter} from '../facade/intl'; import {DateFormatter} from '../facade/intl';
import {DateWrapper, NumberWrapper, isBlank, isDate, isString} from '../facade/lang'; import {NumberWrapper, isBlank, isDate} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@ -83,7 +81,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@Pipe({name: 'date', pure: true}) @Pipe({name: 'date', pure: true})
export class DatePipe implements PipeTransform { export class DatePipe implements PipeTransform {
/** @internal */ /** @internal */
static _ALIASES: {[key: string]: String} = { static _ALIASES: {[key: string]: string} = {
'medium': 'yMMMdjms', 'medium': 'yMMMdjms',
'short': 'yMdjm', 'short': 'yMdjm',
'fullDate': 'yMMMMEEEEd', 'fullDate': 'yMMMMEEEEd',
@ -104,23 +102,15 @@ export class DatePipe implements PipeTransform {
} }
if (NumberWrapper.isNumeric(value)) { if (NumberWrapper.isNumeric(value)) {
value = DateWrapper.fromMillis(parseFloat(value)); value = parseFloat(value);
} else if (isString(value)) {
value = DateWrapper.fromISOString(value);
} }
if (StringMapWrapper.contains(DatePipe._ALIASES, pattern)) {
pattern = <string>StringMapWrapper.get(DatePipe._ALIASES, pattern); return DateFormatter.format(
} new Date(value), this._locale, DatePipe._ALIASES[pattern] || pattern);
return DateFormatter.format(value, this._locale, pattern);
} }
private supports(obj: any): boolean { private supports(obj: any): boolean {
if (isDate(obj) || NumberWrapper.isNumeric(obj)) { return isDate(obj) || NumberWrapper.isNumeric(obj) ||
return true; (typeof obj === 'string' && isDate(new Date(obj)));
}
if (isString(obj) && isDate(DateWrapper.fromISOString(obj))) {
return true;
}
return false;
} }
} }

View File

@ -7,7 +7,7 @@
*/ */
import {Pipe, PipeTransform} from '@angular/core'; import {Pipe, PipeTransform} from '@angular/core';
import {StringWrapper, isBlank, isStringMap} from '../facade/lang'; import {isBlank, isStringMap} from '../facade/lang';
import {NgLocalization, getPluralCategory} from '../localization'; import {NgLocalization, getPluralCategory} from '../localization';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@ -43,6 +43,6 @@ export class I18nPluralPipe implements PipeTransform {
const key = getPluralCategory(value, Object.keys(pluralMap), this._localization); const key = getPluralCategory(value, Object.keys(pluralMap), this._localization);
return StringWrapper.replaceAll(pluralMap[key], _INTERPOLATION_REGEXP, value.toString()); return pluralMap[key].replace(_INTERPOLATION_REGEXP, value.toString());
} }
} }

View File

@ -7,7 +7,7 @@
*/ */
import {Pipe, PipeTransform} from '@angular/core'; import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isString} from '../facade/lang'; import {isBlank} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@ -29,7 +29,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
export class LowerCasePipe implements PipeTransform { export class LowerCasePipe implements PipeTransform {
transform(value: string): string { transform(value: string): string {
if (isBlank(value)) return value; if (isBlank(value)) return value;
if (!isString(value)) { if (typeof value !== 'string') {
throw new InvalidPipeArgumentError(LowerCasePipe, value); throw new InvalidPipeArgumentError(LowerCasePipe, value);
} }
return value.toLowerCase(); return value.toLowerCase();

View File

@ -9,21 +9,23 @@
import {Inject, LOCALE_ID, Pipe, PipeTransform, Type} from '@angular/core'; import {Inject, LOCALE_ID, Pipe, PipeTransform, Type} from '@angular/core';
import {NumberFormatStyle, NumberFormatter} from '../facade/intl'; import {NumberFormatStyle, NumberFormatter} from '../facade/intl';
import {NumberWrapper, isBlank, isNumber, isPresent, isString} from '../facade/lang'; import {NumberWrapper, isBlank, isPresent} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(\-(\d+))?)?$/; const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/;
function formatNumber( function formatNumber(
pipe: Type<any>, locale: string, value: number | string, style: NumberFormatStyle, pipe: Type<any>, locale: string, value: number | string, style: NumberFormatStyle,
digits: string, currency: string = null, currencyAsSymbol: boolean = false): string { digits: string, currency: string = null, currencyAsSymbol: boolean = false): string {
if (isBlank(value)) return null; if (isBlank(value)) return null;
// Convert strings to numbers // Convert strings to numbers
value = isString(value) && NumberWrapper.isNumeric(value) ? +value : value; value = typeof value === 'string' && NumberWrapper.isNumeric(value) ? +value : value;
if (!isNumber(value)) { if (typeof value !== 'number') {
throw new InvalidPipeArgumentError(pipe, value); throw new InvalidPipeArgumentError(pipe, value);
} }
let minInt: number; let minInt: number;
let minFraction: number; let minFraction: number;
let maxFraction: number; let maxFraction: number;
@ -34,8 +36,8 @@ function formatNumber(
maxFraction = 3; maxFraction = 3;
} }
if (isPresent(digits)) { if (digits) {
var parts = digits.match(_NUMBER_FORMAT_REGEXP); let parts = digits.match(_NUMBER_FORMAT_REGEXP);
if (parts === null) { if (parts === null) {
throw new Error(`${digits} is not a valid digit info for number pipes`); throw new Error(`${digits} is not a valid digit info for number pipes`);
} }
@ -49,12 +51,13 @@ function formatNumber(
maxFraction = NumberWrapper.parseIntAutoRadix(parts[5]); maxFraction = NumberWrapper.parseIntAutoRadix(parts[5]);
} }
} }
return NumberFormatter.format(value as number, locale, style, { return NumberFormatter.format(value as number, locale, style, {
minimumIntegerDigits: minInt, minimumIntegerDigits: minInt,
minimumFractionDigits: minFraction, minimumFractionDigits: minFraction,
maximumFractionDigits: maxFraction, maximumFractionDigits: maxFraction,
currency: currency, currency: currency,
currencyAsSymbol: currencyAsSymbol currencyAsSymbol: currencyAsSymbol,
}); });
} }

View File

@ -7,8 +7,7 @@
*/ */
import {Pipe, PipeTransform} from '@angular/core'; import {Pipe, PipeTransform} from '@angular/core';
import {ListWrapper} from '../facade/collection'; import {isBlank} from '../facade/lang';
import {StringWrapper, isArray, isBlank, isString} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/** /**
@ -58,16 +57,15 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@Pipe({name: 'slice', pure: false}) @Pipe({name: 'slice', pure: false})
export class SlicePipe implements PipeTransform { export class SlicePipe implements PipeTransform {
transform(value: any, start: number, end: number = null): any { transform(value: any, start: number, end?: number): any {
if (isBlank(value)) return value; if (isBlank(value)) return value;
if (!this.supports(value)) { if (!this.supports(value)) {
throw new InvalidPipeArgumentError(SlicePipe, value); throw new InvalidPipeArgumentError(SlicePipe, value);
} }
if (isString(value)) {
return StringWrapper.slice(value, start, end); return value.slice(start, end);
}
return ListWrapper.slice(value, start, end);
} }
private supports(obj: any): boolean { return isString(obj) || isArray(obj); } private supports(obj: any): boolean { return typeof obj === 'string' || Array.isArray(obj); }
} }

View File

@ -7,7 +7,7 @@
*/ */
import {Pipe, PipeTransform} from '@angular/core'; import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isString} from '../facade/lang'; import {isBlank} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/** /**
@ -28,7 +28,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
export class UpperCasePipe implements PipeTransform { export class UpperCasePipe implements PipeTransform {
transform(value: string): string { transform(value: string): string {
if (isBlank(value)) return value; if (isBlank(value)) return value;
if (!isString(value)) { if (typeof value !== 'string') {
throw new InvalidPipeArgumentError(UpperCasePipe, value); throw new InvalidPipeArgumentError(UpperCasePipe, value);
} }
return value.toUpperCase(); return value.toUpperCase();