diff --git a/modules/angular2/src/core/pipes/slice_pipe.ts b/modules/angular2/src/core/pipes/slice_pipe.ts new file mode 100644 index 0000000000..81adc32c3b --- /dev/null +++ b/modules/angular2/src/core/pipes/slice_pipe.ts @@ -0,0 +1,96 @@ +import { + isBlank, + isString, + isArray, + StringWrapper, + BaseException, + CONST +} from 'angular2/src/core/facade/lang'; +import {ListWrapper} from 'angular2/src/core/facade/collection'; +import {Injectable} from 'angular2/di'; + +import {PipeTransform, WrappedValue} from 'angular2/change_detection'; +import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception'; + +import {Pipe} from '../metadata'; + +/** + * Creates a new List or String containing only a subset (slice) of the + * elements. + * + * The starting index of the subset to return is specified by the `start` parameter. + * + * The ending index of the subset to return is specified by the optional `end` parameter. + * + * # Usage + * + * expression | slice:start[:end] + * + * All behavior is based on the expected behavior of the JavaScript API + * Array.prototype.slice() and String.prototype.slice() + * + * Where the input expression is a [List] or [String], and `start` is: + * + * - **a positive integer**: return the item at _start_ index and all items after + * in the list or string expression. + * - **a negative integer**: return the item at _start_ index from the end and all items after + * in the list or string expression. + * - **`|start|` greater than the size of the expression**: return an empty list or string. + * - **`|start|` negative greater than the size of the expression**: return entire list or + * string expression. + * + * and where `end` is: + * + * - **omitted**: return all items until the end of the input + * - **a positive integer**: return all items before _end_ index of the list or string + * expression. + * - **a negative integer**: return all items before _end_ index from the end of the list + * or string 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', 'd']`, this `ng-for` directive: + * + *
  • {{i}}
  • + * + * produces the following: + * + *
  • b
  • + *
  • c
  • + * + * ## String Examples + * + * {{ 'abcdefghij' | slice:0:4 }} // output is 'abcd' + * {{ 'abcdefghij' | slice:4:0 }} // output is '' + * {{ 'abcdefghij' | slice:-4 }} // output is 'ghij' + * {{ 'abcdefghij' | slice:-4,-2 }} // output is 'gh' + * {{ 'abcdefghij' | slice: -100 }} // output is 'abcdefghij' + * {{ 'abcdefghij' | slice: 100 }} // output is '' + */ + +@Pipe({name: 'slice'}) +@Injectable() +export class SlicePipe implements PipeTransform { + transform(value: any, args: List = null): any { + if (isBlank(args) || args.length == 0) { + throw new BaseException('Slice pipe requires one argument'); + } + if (!this.supports(value)) { + throw new InvalidPipeArgumentException(SlicePipe, value); + } + if (isBlank(value)) return value; + var start: number = args[0]; + var end: number = args.length > 1 ? args[1] : value.length; + if (isString(value)) { + return StringWrapper.slice(value, start, end); + } + return ListWrapper.slice(value, start, end); + } + + private supports(obj: any): boolean { return isString(obj) || isArray(obj); } +} diff --git a/modules/angular2/test/pipes/slice_pipe_spec.ts b/modules/angular2/test/pipes/slice_pipe_spec.ts new file mode 100644 index 0000000000..8c9ef8bd7c --- /dev/null +++ b/modules/angular2/test/pipes/slice_pipe_spec.ts @@ -0,0 +1,75 @@ +import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib'; + +import {SlicePipe} from 'angular2/pipes'; + +export function main() { + describe("SlicePipe", () => { + var list; + var str; + var pipe; + + beforeEach(() => { + list = [1, 2, 3, 4, 5]; + str = 'tuvwxyz'; + pipe = new SlicePipe(); + }); + + 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 all items after START index when START is positive and END is omitted', + () => { + expect(pipe.transform(list, [3])).toEqual([4, 5]); + expect(pipe.transform(str, [3])).toEqual('wxyz'); + }); + + it('should return last START items when START is negative and END is omitted', () => { + expect(pipe.transform(list, [-3])).toEqual([3, 4, 5]); + expect(pipe.transform(str, [-3])).toEqual('xyz'); + }); + + it('should return all items between START and END index when START and END are positive', + () => { + expect(pipe.transform(list, [1, 3])).toEqual([2, 3]); + expect(pipe.transform(str, [1, 3])).toEqual('uv'); + }); + + it('should return all items between START and END from the end when START and END are negative', + () => { + expect(pipe.transform(list, [-4, -2])).toEqual([2, 3]); + expect(pipe.transform(str, [-4, -2])).toEqual('wx'); + }); + + it('should return an empty value if START is greater than END', () => { + expect(pipe.transform(list, [4, 2])).toEqual([]); + expect(pipe.transform(str, [4, 2])).toEqual(''); + }); + + it('should return an empty value if START greater than input length', () => { + expect(pipe.transform(list, [99])).toEqual([]); + expect(pipe.transform(str, [99])).toEqual(''); + }); + + it('should return entire input if START is negative and greater than input length', () => { + expect(pipe.transform(list, [-99])).toEqual([1, 2, 3, 4, 5]); + expect(pipe.transform(str, [-99])).toEqual('tuvwxyz'); + }); + + it('should not modify the input list', () => { + expect(pipe.transform(list, [2])).toEqual([3, 4, 5]); + expect(list).toEqual([1, 2, 3, 4, 5]); + }); + + }); + + }); +} \ No newline at end of file