🌐 AI搜索 & 代理 主页
Skip to content

Commit 2b481b9

Browse files
cowboyjeresig
authored andcommitted
Landing Ben Alman's patch to add nextUntil, prevUntil, and parentsUntil. Also adds some tests for prevAll and nextAll, and fixes an test edge case in parents.
1 parent bbd933c commit 2b481b9

File tree

3 files changed

+98
-11
lines changed

3 files changed

+98
-11
lines changed

src/core.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,13 +484,14 @@ jQuery.extend({
484484
return ret;
485485
},
486486

487-
map: function( elems, callback ) {
487+
// arg is for internal usage only
488+
map: function( elems, callback, arg ) {
488489
var ret = [], value;
489490

490491
// Go through the array, translating each of the items to their
491492
// new value (or values).
492493
for ( var i = 0, length = elems.length; i < length; i++ ) {
493-
value = callback( elems[ i ], i );
494+
value = callback( elems[ i ], i, arg );
494495

495496
if ( value != null ) {
496497
ret[ ret.length ] = value;

src/traversing.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
var runtil = /Until$/,
2+
rparentsprev = /^(?:parents|prevUntil|prevAll)/,
3+
// Note: This RegExp should be improved, or likely pulled from Sizzle
4+
rmultiselector = /,/,
5+
slice = Array.prototype.slice,
6+
join = Array.prototype.join;
7+
18
// Implement the identical functionality for filter and not
29
var winnow = function( elements, qualifier, keep ) {
310
if ( jQuery.isFunction( qualifier ) ) {
@@ -130,8 +137,8 @@ jQuery.fn.extend({
130137
},
131138

132139
slice: function() {
133-
return this.pushStack( Array.prototype.slice.apply( this, arguments ),
134-
"slice", Array.prototype.slice.call(arguments).join(",") );
140+
return this.pushStack( slice.apply( this, arguments ),
141+
"slice", join.call(arguments, ",") );
135142
},
136143

137144
map: function( callback ) {
@@ -152,28 +159,35 @@ jQuery.fn.extend({
152159
jQuery.each({
153160
parent: function(elem){return elem.parentNode;},
154161
parents: function(elem){return jQuery.dir(elem,"parentNode");},
162+
parentsUntil: function(elem,i,until){return jQuery.dir(elem,"parentNode",until);},
155163
next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
156164
prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
157165
nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
158166
prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
167+
nextUntil: function(elem,i,until){return jQuery.dir(elem,"nextSibling",until);},
168+
prevUntil: function(elem,i,until){return jQuery.dir(elem,"previousSibling",until);},
159169
siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
160170
children: function(elem){return jQuery.sibling(elem.firstChild);},
161171
contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
162172
}, function(name, fn){
163-
jQuery.fn[ name ] = function( selector ) {
164-
var ret = jQuery.map( this, fn );
173+
jQuery.fn[ name ] = function( until, selector ) {
174+
var ret = jQuery.map( this, fn, until );
175+
176+
if ( !runtil.test( name ) ) {
177+
selector = until;
178+
}
165179

166180
if ( selector && typeof selector === "string" ) {
167181
ret = jQuery.filter( selector, ret );
168182
}
169183

170184
ret = this.length > 1 ? jQuery.unique( ret ) : ret;
171185

172-
if ( name === "parents" && this.length > 1 ) {
186+
if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
173187
ret = ret.reverse();
174188
}
175189

176-
return this.pushStack( ret, name, selector );
190+
return this.pushStack( ret, name, join.call(arguments, ",") );
177191
};
178192
});
179193

@@ -186,9 +200,9 @@ jQuery.extend({
186200
return jQuery.find.matches(expr, elems);
187201
},
188202

189-
dir: function( elem, dir ) {
203+
dir: function( elem, dir, until ) {
190204
var matched = [], cur = elem[dir];
191-
while ( cur && cur.nodeType !== 9 ) {
205+
while ( cur && cur.nodeType !== 9 && (until === undefined || !jQuery( cur ).is( until )) ) {
192206
if ( cur.nodeType === 1 ) {
193207
matched.push( cur );
194208
}

test/unit/traversing.js

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,26 @@ test("parents([String])", function() {
193193
equals( jQuery("#groups").parents()[0].id, "ap", "Simple parents check" );
194194
equals( jQuery("#groups").parents("p")[0].id, "ap", "Filtered parents check" );
195195
equals( jQuery("#groups").parents("div")[0].id, "main", "Filtered parents check2" );
196-
same( jQuery("#groups").parents("p, div").get(), q("main", "ap"), "Check for multiple filters" );
196+
same( jQuery("#groups").parents("p, div").get(), q("ap", "main"), "Check for multiple filters" );
197197
same( jQuery("#en, #sndp").parents().get(), q("foo", "main", "dl", "body", "html"), "Check for unique results from parents" );
198198
});
199199

200+
test("parentsUntil([String])", function() {
201+
expect(9);
202+
203+
var parents = jQuery("#groups").parents();
204+
205+
same( jQuery("#groups").parentsUntil().get(), parents.get(), "parentsUntil with no selector (nextAll)" );
206+
same( jQuery("#groups").parentsUntil(".foo").get(), parents.get(), "parentsUntil with invalid selector (nextAll)" );
207+
same( jQuery("#groups").parentsUntil("#html").get(), parents.not(':last').get(), "Simple parentsUntil check" );
208+
equals( jQuery("#groups").parentsUntil("#ap").length, 0, "Simple parentsUntil check" );
209+
same( jQuery("#groups").parentsUntil("#html, #body").get(), parents.slice( 0, 3 ).get(), "Less simple parentsUntil check" );
210+
same( jQuery("#groups").parentsUntil("#html", "div").get(), jQuery("#main").get(), "Filtered parentsUntil check" );
211+
same( jQuery("#groups").parentsUntil("#html", "p,div,dl").get(), parents.slice( 0, 3 ).get(), "Multiple-filtered parentsUntil check" );
212+
equals( jQuery("#groups").parentsUntil("#html", "span").length, 0, "Filtered parentsUntil check, no match" );
213+
same( jQuery("#groups, #ap").parentsUntil("#html", "p,div,dl").get(), parents.slice( 0, 3 ).get(), "Multi-source, multiple-filtered parentsUntil check" );
214+
});
215+
200216
test("next([String])", function() {
201217
expect(4);
202218
equals( jQuery("#ap").next()[0].id, "foo", "Simple next check" );
@@ -213,6 +229,62 @@ test("prev([String])", function() {
213229
equals( jQuery("#foo").prev("p, div")[0].id, "ap", "Multiple filters" );
214230
});
215231

232+
test("nextAll([String])", function() {
233+
expect(4);
234+
235+
var elems = jQuery('#form').children();
236+
237+
same( jQuery("#label-for").nextAll().get(), elems.not(':first').get(), "Simple nextAll check" );
238+
same( jQuery("#label-for").nextAll('input').get(), elems.not(':first').filter('input').get(), "Filtered nextAll check" );
239+
same( jQuery("#label-for").nextAll('input,select').get(), elems.not(':first').filter('input,select').get(), "Multiple-filtered nextAll check" );
240+
same( jQuery("#label-for, #hidden1").nextAll('input,select').get(), elems.not(':first').filter('input,select').get(), "Multi-source, multiple-filtered nextAll check" );
241+
});
242+
243+
test("prevAll([String])", function() {
244+
expect(4);
245+
246+
var elems = jQuery( jQuery('#form').children().slice(0, 12).get().reverse() );
247+
248+
same( jQuery("#area1").prevAll().get(), elems.get(), "Simple prevAll check" );
249+
same( jQuery("#area1").prevAll('input').get(), elems.filter('input').get(), "Filtered prevAll check" );
250+
same( jQuery("#area1").prevAll('input,select').get(), elems.filter('input,select').get(), "Multiple-filtered prevAll check" );
251+
same( jQuery("#area1, #hidden1").prevAll('input,select').get(), elems.filter('input,select').get(), "Multi-source, multiple-filtered prevAll check" );
252+
});
253+
254+
test("nextUntil([String])", function() {
255+
expect(10);
256+
257+
var elems = jQuery('#form').children().slice( 2, 12 );
258+
259+
same( jQuery("#text1").nextUntil().get(), jQuery("#text1").nextAll().get(), "nextUntil with no selector (nextAll)" );
260+
same( jQuery("#text1").nextUntil(".foo").get(), jQuery("#text1").nextAll().get(), "nextUntil with invalid selector (nextAll)" );
261+
same( jQuery("#text1").nextUntil("#area1").get(), elems.get(), "Simple nextUntil check" );
262+
equals( jQuery("#text1").nextUntil("#text2").length, 0, "Simple nextUntil check" );
263+
same( jQuery("#text1").nextUntil("#area1, #radio1").get(), jQuery("#text1").next().get(), "Less simple nextUntil check" );
264+
same( jQuery("#text1").nextUntil("#area1", "input").get(), elems.not("button").get(), "Filtered nextUntil check" );
265+
same( jQuery("#text1").nextUntil("#area1", "button").get(), elems.not("input").get(), "Filtered nextUntil check" );
266+
same( jQuery("#text1").nextUntil("#area1", "button,input").get(), elems.get(), "Multiple-filtered nextUntil check" );
267+
equals( jQuery("#text1").nextUntil("#area1", "div").length, 0, "Filtered nextUntil check, no match" );
268+
same( jQuery("#text1, #hidden1").nextUntil("#area1", "button,input").get(), elems.get(), "Multi-source, multiple-filtered nextUntil check" );
269+
});
270+
271+
test("prevUntil([String])", function() {
272+
expect(10);
273+
274+
var elems = jQuery("#area1").prevAll();
275+
276+
same( jQuery("#area1").prevUntil().get(), elems.get(), "prevUntil with no selector (prevAll)" );
277+
same( jQuery("#area1").prevUntil(".foo").get(), elems.get(), "prevUntil with invalid selector (prevAll)" );
278+
same( jQuery("#area1").prevUntil("label").get(), elems.not(':last').get(), "Simple prevUntil check" );
279+
equals( jQuery("#area1").prevUntil("#button").length, 0, "Simple prevUntil check" );
280+
same( jQuery("#area1").prevUntil("label, #search").get(), jQuery("#area1").prev().get(), "Less simple prevUntil check" );
281+
same( jQuery("#area1").prevUntil("label", "input").get(), elems.not(':last').not("button").get(), "Filtered prevUntil check" );
282+
same( jQuery("#area1").prevUntil("label", "button").get(), elems.not(':last').not("input").get(), "Filtered prevUntil check" );
283+
same( jQuery("#area1").prevUntil("label", "button,input").get(), elems.not(':last').get(), "Multiple-filtered prevUntil check" );
284+
equals( jQuery("#area1").prevUntil("label", "div").length, 0, "Filtered prevUntil check, no match" );
285+
same( jQuery("#area1, #hidden1").prevUntil("label", "button,input").get(), elems.not(':last').get(), "Multi-source, multiple-filtered prevUntil check" );
286+
});
287+
216288
test("slice()", function() {
217289
expect(7);
218290

0 commit comments

Comments
 (0)