From 0b502588147fce6da5633898cdb357a44107394a Mon Sep 17 00:00:00 2001 From: Pouria Alimirzaei Date: Fri, 26 Jun 2015 00:22:36 +0430 Subject: [PATCH] feat(pipes): add limitTo pipe --- modules/angular2/pipes.ts | 1 + .../src/change_detection/change_detection.ts | 14 ++- .../change_detection/pipes/limit_to_pipe.ts | 87 +++++++++++++++++++ .../pipes/limit_to_pipe_spec.ts | 57 ++++++++++++ 4 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 modules/angular2/src/change_detection/pipes/limit_to_pipe.ts create mode 100644 modules/angular2/test/change_detection/pipes/limit_to_pipe_spec.ts diff --git a/modules/angular2/pipes.ts b/modules/angular2/pipes.ts index a67506c292..84309712fa 100644 --- a/modules/angular2/pipes.ts +++ b/modules/angular2/pipes.ts @@ -12,3 +12,4 @@ export {ObservablePipe} from './src/change_detection/pipes/observable_pipe'; export {JsonPipe} from './src/change_detection/pipes/json_pipe'; export {IterableChanges} from './src/change_detection/pipes/iterable_changes'; export {KeyValueChanges} from './src/change_detection/pipes/keyvalue_changes'; +export {LimitToPipe} from './src/change_detection/pipes/limit_to_pipe'; diff --git a/modules/angular2/src/change_detection/change_detection.ts b/modules/angular2/src/change_detection/change_detection.ts index 8d61656755..167caa1551 100644 --- a/modules/angular2/src/change_detection/change_detection.ts +++ b/modules/angular2/src/change_detection/change_detection.ts @@ -10,6 +10,7 @@ import {PromisePipeFactory} from './pipes/promise_pipe'; import {UpperCaseFactory} from './pipes/uppercase_pipe'; import {LowerCaseFactory} from './pipes/lowercase_pipe'; import {JsonPipe} from './pipes/json_pipe'; +import {LimitToPipeFactory} from './pipes/limit_to_pipe'; import {NullPipeFactory} from './pipes/null_pipe'; import {ChangeDetection, ProtoChangeDetector, ChangeDetectorDefinition} from './interfaces'; import {Inject, Injectable, OpaqueToken, Optional} from 'angular2/di'; @@ -64,16 +65,25 @@ export const lowercase: List = * * @exportedAs angular2/pipes */ -export const json: List = +export const json: List = CONST_EXPR([CONST_EXPR(new JsonPipe()), CONST_EXPR(new NullPipeFactory())]); +/** + * LimitTo text transform. + * + * @exportedAs angular2/pipes + */ +export const limitTo: List = + CONST_EXPR([CONST_EXPR(new LimitToPipeFactory()), CONST_EXPR(new NullPipeFactory())]); + export const defaultPipes = CONST_EXPR({ "iterableDiff": iterableDiff, "keyValDiff": keyValDiff, "async": async, "uppercase": uppercase, "lowercase": lowercase, - "json": json + "json": json, + "limitTo": limitTo }); /** diff --git a/modules/angular2/src/change_detection/pipes/limit_to_pipe.ts b/modules/angular2/src/change_detection/pipes/limit_to_pipe.ts new file mode 100644 index 0000000000..f79e95047f --- /dev/null +++ b/modules/angular2/src/change_detection/pipes/limit_to_pipe.ts @@ -0,0 +1,87 @@ +import { + isBlank, + isString, + isArray, + StringWrapper, + BaseException, + CONST +} from 'angular2/src/facade/lang'; +import {ListWrapper} from 'angular2/src/facade/collection'; +import {Math} from 'angular2/src/facade/math'; +import {WrappedValue, Pipe, PipeFactory} from './pipe'; +import {ChangeDetectorRef} from '../change_detector_ref'; + +/** + * Creates a new List or String containing only a prefix/suffix of the + * elements. + * + * The number of elements to return is specified by the `limitTo` parameter. + * + * # Usage + * + * expression | limitTo:number + * + * Where the input expression is a [List] or [String], and `limitTo` is: + * + * - **a positive integer**: return _number_ items from the beginning of the list or string + * expression. + * - **a negative integer**: return _number_ items from the end of the list or string expression. + * - **`|limitTo|` greater than the size of the expression**: return the entire expression. + * + * When operating on a [List], the returned list is always a copy even when all + * the elements are being returned. + * + * # Examples + * + * ## List Example + * + * Assuming `var collection = ['a', 'b', 'c']`, this `ng-for` directive: + * + *
  • {{i}}
  • + * + * produces the following: + * + *
  • a
  • + *
  • b
  • + * + * ## String Examples + * + * {{ 'abcdefghij' | limitTo: 4 }} // output is 'abcd' + * {{ 'abcdefghij' | limitTo: -4 }} // output is 'ghij' + * {{ 'abcdefghij' | limitTo: -100 }} // output is 'abcdefghij' + * + * @exportedAs angular2/pipes + */ +export class LimitToPipe implements Pipe { + static supportsObj(obj): boolean { return isString(obj) || isArray(obj); } + + supports(obj): boolean { return LimitToPipe.supportsObj(obj); } + + transform(value, args: List = null): any { + if (isBlank(args) || args.length == 0) { + throw new BaseException('limitTo pipe requires one argument'); + } + var limit: int = args[0]; + var left = 0, right = Math.min(limit, value.length); + if (limit < 0) { + left = Math.max(0, value.length + limit); + right = value.length; + } + if (isString(value)) { + return StringWrapper.substring(value, left, right); + } + return ListWrapper.slice(value, left, right); + } + + onDestroy(): void {} +} + +/** + * @exportedAs angular2/pipes + */ +@CONST() +export class LimitToPipeFactory implements PipeFactory { + supports(obj): boolean { return LimitToPipe.supportsObj(obj); } + + create(cdRef: ChangeDetectorRef): Pipe { return new LimitToPipe(); } +} diff --git a/modules/angular2/test/change_detection/pipes/limit_to_pipe_spec.ts b/modules/angular2/test/change_detection/pipes/limit_to_pipe_spec.ts new file mode 100644 index 0000000000..c4a7870cd8 --- /dev/null +++ b/modules/angular2/test/change_detection/pipes/limit_to_pipe_spec.ts @@ -0,0 +1,57 @@ +import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib'; + +import {LimitToPipe} from 'angular2/src/change_detection/pipes/limit_to_pipe'; + +export function main() { + describe("LimitToPipe", () => { + var list; + var str; + var pipe; + + beforeEach(() => { + list = [1, 2, 3, 4, 5]; + str = 'tuvwxyz'; + pipe = new LimitToPipe(); + }); + + describe("supports", () => { + it("should support strings", () => { expect(pipe.supports(str)).toBe(true); }); + it("should support lists", () => { expect(pipe.supports(list)).toBe(true); }); + + it("should not support other objects", () => { + expect(pipe.supports(new Object())).toBe(false); + expect(pipe.supports(null)).toBe(false); + }); + }); + + describe("transform", () => { + + it('should return the first X items when X is positive', () => { + expect(pipe.transform(list, [3])).toEqual([1, 2, 3]); + expect(pipe.transform(str, [3])).toEqual('tuv'); + }); + + it('should return the last X items when X is negative', () => { + expect(pipe.transform(list, [-3])).toEqual([3, 4, 5]); + expect(pipe.transform(str, [-3])).toEqual('xyz'); + }); + + it('should return a copy of input array if X is exceeds array length', () => { + expect(pipe.transform(list, [20])).toEqual(list); + expect(pipe.transform(list, [-20])).toEqual(list); + }); + + it('should return the entire string if X exceeds input length', () => { + expect(pipe.transform(str, [20])).toEqual(str); + expect(pipe.transform(str, [-20])).toEqual(str); + }); + + it('should not modify the input list', () => { + expect(pipe.transform(list, [3])).toEqual([1, 2, 3]); + expect(list).toEqual([1, 2, 3, 4, 5]); + }); + + }); + + }); +}