Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit f467dc3

Browse files
wesleychogkalpak
authored andcommitted
feat(limitTo): add support for array-like objects
Fixes #14657 Closes #14694
1 parent 3360b44 commit f467dc3

File tree

2 files changed

+95
-20
lines changed

2 files changed

+95
-20
lines changed

src/ng/filter/limitTo.js

+21-14
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@
66
* @kind function
77
*
88
* @description
9-
* Creates a new array or string containing only a specified number of elements. The elements
10-
* are taken from either the beginning or the end of the source array, string or number, as specified by
11-
* the value and sign (positive or negative) of `limit`. If a number is used as input, it is
12-
* converted to a string.
9+
* Creates a new array or string containing only a specified number of elements. The elements are
10+
* taken from either the beginning or the end of the source array, string or number, as specified by
11+
* the value and sign (positive or negative) of `limit`. Other array-like objects are also supported
12+
* (e.g. array subclasses, NodeLists, jqLite/jQuery collections etc). If a number is used as input,
13+
* it is converted to a string.
1314
*
14-
* @param {Array|string|number} input Source array, string or number to be limited.
15-
* @param {string|number} limit The length of the returned array or string. If the `limit` number
15+
* @param {Array|ArrayLike|string|number} input - Array/array-like, string or number to be limited.
16+
* @param {string|number} limit - The length of the returned array or string. If the `limit` number
1617
* is positive, `limit` number of items from the beginning of the source array/string are copied.
1718
* If the number is negative, `limit` number of items from the end of the source array/string
1819
* are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
1920
* the input will be returned unchanged.
20-
* @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
21-
* indicates an offset from the end of `input`. Defaults to `0`.
22-
* @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
23-
* had less than `limit` elements.
21+
* @param {(string|number)=} begin - Index at which to begin limitation. As a negative index,
22+
* `begin` indicates an offset from the end of `input`. Defaults to `0`.
23+
* @returns {Array|string} A new sub-array or substring of length `limit` or less if the input had
24+
* less than `limit` elements.
2425
*
2526
* @example
2627
<example module="limitToExample">
@@ -108,19 +109,25 @@ function limitToFilter() {
108109
if (isNaN(limit)) return input;
109110

110111
if (isNumber(input)) input = input.toString();
111-
if (!isArray(input) && !isString(input)) return input;
112+
if (!isArrayLike(input)) return input;
112113

113114
begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
114115
begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
115116

116117
if (limit >= 0) {
117-
return input.slice(begin, begin + limit);
118+
return sliceFn(input, begin, begin + limit);
118119
} else {
119120
if (begin === 0) {
120-
return input.slice(limit, input.length);
121+
return sliceFn(input, limit, input.length);
121122
} else {
122-
return input.slice(Math.max(0, begin + limit), begin);
123+
return sliceFn(input, Math.max(0, begin + limit), begin);
123124
}
124125
}
125126
};
126127
}
128+
129+
function sliceFn(input, begin, end) {
130+
if (isString(input)) return input.slice(begin, end);
131+
132+
return slice.call(input, begin, end);
133+
}

test/ng/filter/limitToSpec.js

+74-6
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,26 @@ describe('Filter: limitTo', function() {
44
var items;
55
var str;
66
var number;
7+
var arrayLike;
78
var limitTo;
89

910
beforeEach(inject(function($filter) {
1011
items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
1112
str = "tuvwxyz";
1213
number = 100.045;
14+
arrayLike = {
15+
0: 'a',
16+
1: 'b',
17+
2: 'c',
18+
3: 'd',
19+
4: 'e',
20+
5: 'f',
21+
6: 'g',
22+
7: 'h',
23+
get length() {
24+
return Object.keys(this).length - 1;
25+
}
26+
};
1327
limitTo = $filter('limitTo');
1428
}));
1529

@@ -21,20 +35,26 @@ describe('Filter: limitTo', function() {
2135
expect(limitTo(str, '3')).toEqual("tuv");
2236
expect(limitTo(number, 3)).toEqual("100");
2337
expect(limitTo(number, '3')).toEqual("100");
38+
expect(limitTo(arrayLike, 3)).toEqual(['a', 'b', 'c']);
39+
expect(limitTo(arrayLike, '3')).toEqual(['a', 'b', 'c']);
2440
});
2541

2642
it('should return the first X items beginning from index Y when X and Y are positive', function() {
2743
expect(limitTo(items, 3, '3')).toEqual(['d', 'e', 'f']);
2844
expect(limitTo(items, '3', 3)).toEqual(['d', 'e', 'f']);
2945
expect(limitTo(str, 3, 3)).toEqual("wxy");
3046
expect(limitTo(str, '3', '3')).toEqual("wxy");
47+
expect(limitTo(arrayLike, 3, 3)).toEqual(['d', 'e', 'f']);
48+
expect(limitTo(arrayLike, '3', '3')).toEqual(['d', 'e', 'f']);
3149
});
3250

3351
it('should return the first X items beginning from index Y when X is positive and Y is negative', function() {
3452
expect(limitTo(items, 3, '-3')).toEqual(['f', 'g', 'h']);
3553
expect(limitTo(items, '3', -3)).toEqual(['f', 'g', 'h']);
3654
expect(limitTo(str, 3, -3)).toEqual("xyz");
3755
expect(limitTo(str, '3', '-3')).toEqual("xyz");
56+
expect(limitTo(arrayLike, 3, '-3')).toEqual(['f', 'g', 'h']);
57+
expect(limitTo(arrayLike, '3', -3)).toEqual(['f', 'g', 'h']);
3858
});
3959

4060
it('should return the last X items when X is negative', function() {
@@ -44,33 +64,46 @@ describe('Filter: limitTo', function() {
4464
expect(limitTo(str, '-3')).toEqual("xyz");
4565
expect(limitTo(number, -3)).toEqual("045");
4666
expect(limitTo(number, '-3')).toEqual("045");
67+
expect(limitTo(arrayLike, -3)).toEqual(['f', 'g', 'h']);
68+
expect(limitTo(arrayLike, '-3')).toEqual(['f', 'g', 'h']);
4769
});
4870

4971
it('should return the last X items until index Y when X and Y are negative', function() {
5072
expect(limitTo(items, -3, '-3')).toEqual(['c', 'd', 'e']);
5173
expect(limitTo(items, '-3', -3)).toEqual(['c', 'd', 'e']);
5274
expect(limitTo(str, -3, -3)).toEqual("uvw");
5375
expect(limitTo(str, '-3', '-3')).toEqual("uvw");
76+
expect(limitTo(arrayLike, -3, '-3')).toEqual(['c', 'd', 'e']);
77+
expect(limitTo(arrayLike, '-3', -3)).toEqual(['c', 'd', 'e']);
5478
});
5579

5680
it('should return the last X items until index Y when X is negative and Y is positive', function() {
5781
expect(limitTo(items, -3, '4')).toEqual(['b', 'c', 'd']);
5882
expect(limitTo(items, '-3', 4)).toEqual(['b', 'c', 'd']);
5983
expect(limitTo(str, -3, 4)).toEqual("uvw");
6084
expect(limitTo(str, '-3', '4')).toEqual("uvw");
85+
expect(limitTo(arrayLike, -3, '4')).toEqual(['b', 'c', 'd']);
86+
expect(limitTo(arrayLike, '-3', 4)).toEqual(['b', 'c', 'd']);
6187
});
6288

6389
it('should return an empty array when X = 0', function() {
6490
expect(limitTo(items, 0)).toEqual([]);
6591
expect(limitTo(items, '0')).toEqual([]);
92+
expect(limitTo(arrayLike, 0)).toEqual([]);
93+
expect(limitTo(arrayLike, '0')).toEqual([]);
6694
});
6795

6896
it('should return entire array when X cannot be parsed', function() {
69-
expect(limitTo(items, 'bogus')).toEqual(items);
70-
expect(limitTo(items, 'null')).toEqual(items);
71-
expect(limitTo(items, 'undefined')).toEqual(items);
72-
expect(limitTo(items, null)).toEqual(items);
73-
expect(limitTo(items, undefined)).toEqual(items);
97+
expect(limitTo(items, 'bogus')).toBe(items);
98+
expect(limitTo(items, 'null')).toBe(items);
99+
expect(limitTo(items, 'undefined')).toBe(items);
100+
expect(limitTo(items, null)).toBe(items);
101+
expect(limitTo(items, undefined)).toBe(items);
102+
expect(limitTo(arrayLike, 'bogus')).toBe(arrayLike);
103+
expect(limitTo(arrayLike, 'null')).toBe(arrayLike);
104+
expect(limitTo(arrayLike, 'undefined')).toBe(arrayLike);
105+
expect(limitTo(arrayLike, null)).toBe(arrayLike);
106+
expect(limitTo(arrayLike, undefined)).toBe(arrayLike);
74107
});
75108

76109
it('should return an empty string when X = 0', function() {
@@ -97,9 +130,14 @@ describe('Filter: limitTo', function() {
97130
expect(limitTo(str, '3', 'undefined')).toEqual(limitTo(str, '3'));
98131
expect(limitTo(str, '-3', null)).toEqual(limitTo(str, '-3', 0));
99132
expect(limitTo(str, 3, undefined)).toEqual(limitTo(str, 3));
133+
expect(limitTo(arrayLike, 3, 'bogus')).toEqual(limitTo(arrayLike, 3, 0));
134+
expect(limitTo(arrayLike, -3, 'null')).toEqual(limitTo(arrayLike, -3));
135+
expect(limitTo(arrayLike, '3', 'undefined')).toEqual(limitTo(arrayLike, '3', 0));
136+
expect(limitTo(arrayLike, '-3', null)).toEqual(limitTo(arrayLike, '-3'));
137+
expect(limitTo(arrayLike, 3, undefined)).toEqual(limitTo(arrayLike, 3, 0));
100138
});
101139

102-
it('should return input if not String or Array or Number', function() {
140+
it('should return input if not array-like or Number', function() {
103141
expect(limitTo(null, 1)).toEqual(null);
104142
expect(limitTo(undefined, 1)).toEqual(undefined);
105143
expect(limitTo({}, 1)).toEqual({});
@@ -111,8 +149,13 @@ describe('Filter: limitTo', function() {
111149
expect(limitTo(items, '9')).toEqual(items);
112150
expect(limitTo(items, -9)).toEqual(items);
113151
expect(limitTo(items, '-9')).toEqual(items);
152+
expect(limitTo(arrayLike, 9)).toEqual(items);
153+
expect(limitTo(arrayLike, '9')).toEqual(items);
154+
expect(limitTo(arrayLike, -9)).toEqual(items);
155+
expect(limitTo(arrayLike, '-9')).toEqual(items);
114156

115157
expect(limitTo(items, 9)).not.toBe(items);
158+
expect(limitTo(arrayLike, 9)).not.toBe(arrayLike);
116159
});
117160

118161
it('should return the entire string if X exceeds input length', function() {
@@ -129,6 +172,10 @@ describe('Filter: limitTo', function() {
129172
expect(limitTo(items, 'Infinity')).toEqual(items);
130173
expect(limitTo(items, -Infinity)).toEqual(items);
131174
expect(limitTo(items, '-Infinity')).toEqual(items);
175+
expect(limitTo(arrayLike, Infinity)).toEqual(items);
176+
expect(limitTo(arrayLike, 'Infinity')).toEqual(items);
177+
expect(limitTo(arrayLike, -Infinity)).toEqual(items);
178+
expect(limitTo(arrayLike, '-Infinity')).toEqual(items);
132179
});
133180

134181
it('should return the entire string when limited by Infinity', function() {
@@ -141,6 +188,8 @@ describe('Filter: limitTo', function() {
141188
it('should return an empty array if Y exceeds input length', function() {
142189
expect(limitTo(items, '3', 12)).toEqual([]);
143190
expect(limitTo(items, -3, '12')).toEqual([]);
191+
expect(limitTo(arrayLike, '3', 12)).toEqual([]);
192+
expect(limitTo(arrayLike, -3, '12')).toEqual([]);
144193
});
145194

146195
it('should return an empty string if Y exceeds input length', function() {
@@ -153,19 +202,38 @@ describe('Filter: limitTo', function() {
153202
expect(limitTo(items, '-4', -12)).toEqual(['e', 'f', 'g', 'h']);
154203
expect(limitTo(str, 4, '-12')).toEqual("tuvw");
155204
expect(limitTo(str, '-4', -12)).toEqual("wxyz");
205+
expect(limitTo(arrayLike, 4, '-12')).toEqual(['a', 'b', 'c', 'd']);
206+
expect(limitTo(arrayLike, '-4', -12)).toEqual(['e', 'f', 'g', 'h']);
156207
});
157208

158209
it('should return the entire string beginning from Y if X is positive and X+Y exceeds input length', function() {
159210
expect(limitTo(items, 7, 3)).toEqual(['d', 'e', 'f', 'g', 'h']);
160211
expect(limitTo(items, 7, -3)).toEqual(['f', 'g', 'h']);
161212
expect(limitTo(str, 6, 3)).toEqual("wxyz");
162213
expect(limitTo(str, 6, -3)).toEqual("xyz");
214+
expect(limitTo(arrayLike, 7, 3)).toEqual(['d', 'e', 'f', 'g', 'h']);
215+
expect(limitTo(arrayLike, 7, -3)).toEqual(['f', 'g', 'h']);
163216
});
164217

165218
it('should return the entire string until index Y if X is negative and X+Y exceeds input length', function() {
166219
expect(limitTo(items, -7, 3)).toEqual(['a', 'b', 'c']);
167220
expect(limitTo(items, -7, -3)).toEqual(['a', 'b', 'c', 'd', 'e']);
168221
expect(limitTo(str, -6, 3)).toEqual("tuv");
169222
expect(limitTo(str, -6, -3)).toEqual("tuvw");
223+
expect(limitTo(arrayLike, -7, 3)).toEqual(['a', 'b', 'c']);
224+
expect(limitTo(arrayLike, -7, -3)).toEqual(['a', 'b', 'c', 'd', 'e']);
225+
});
226+
227+
it('should not throw an error if used with an array like object', function() {
228+
function getArguments() {
229+
return arguments;
230+
}
231+
var argsObj = getArguments({name: 'Misko'}, {name: 'Igor'}, {name: 'Brad'});
232+
233+
var nodeList = jqLite("<p><span>Misko</span><span>Igor</span><span>Brad</span></p>")[0].childNodes;
234+
235+
expect(limitTo(argsObj, 2).length).toBe(2);
236+
expect(limitTo('abc', 1).length).toBe(1);
237+
expect(limitTo(nodeList, 2).length).toBe(2);
170238
});
171239
});

0 commit comments

Comments
 (0)