AMD-ify jQuery sourcegit s! Woo! Fixes #14113, #14163.
[jquery.git] / src / traversing.js
blob84b8af09f92f5c37a8e20a28e8e692b0cafe94ce
1 define([
2         "./core",
3         "./var/indexOf",
4         "./selector"
5 ], function( jQuery, indexOf ) {
6 var isSimple = /^.[^:#\[\.,]*$/,
7         rparentsprev = /^(?:parents|prev(?:Until|All))/,
8         rneedsContext = jQuery.expr.match.needsContext,
9         // methods guaranteed to produce a unique set when starting from a unique set
10         guaranteedUnique = {
11                 children: true,
12                 contents: true,
13                 next: true,
14                 prev: true
15         };
17 jQuery.fn.extend({
18         find: function( selector ) {
19                 var i,
20                         ret = [],
21                         self = this,
22                         len = self.length;
24                 if ( typeof selector !== "string" ) {
25                         return this.pushStack( jQuery( selector ).filter(function() {
26                                 for ( i = 0; i < len; i++ ) {
27                                         if ( jQuery.contains( self[ i ], this ) ) {
28                                                 return true;
29                                         }
30                                 }
31                         }) );
32                 }
34                 for ( i = 0; i < len; i++ ) {
35                         jQuery.find( selector, self[ i ], ret );
36                 }
38                 // Needed because $( selector, context ) becomes $( context ).find( selector )
39                 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
40                 ret.selector = this.selector ? this.selector + " " + selector : selector;
41                 return ret;
42         },
44         has: function( target ) {
45                 var i,
46                         targets = jQuery( target, this ),
47                         len = targets.length;
49                 return this.filter(function() {
50                         for ( i = 0; i < len; i++ ) {
51                                 if ( jQuery.contains( this, targets[i] ) ) {
52                                         return true;
53                                 }
54                         }
55                 });
56         },
58         not: function( selector ) {
59                 return this.pushStack( winnow(this, selector || [], true) );
60         },
62         filter: function( selector ) {
63                 return this.pushStack( winnow(this, selector || [], false) );
64         },
66         is: function( selector ) {
67                 return !!winnow(
68                         this,
70                         // If this is a positional/relative selector, check membership in the returned set
71                         // so $("p:first").is("p:last") won't return true for a doc with two "p".
72                         typeof selector === "string" && rneedsContext.test( selector ) ?
73                                 jQuery( selector ) :
74                                 selector || [],
75                         false
76                 ).length;
77         },
79         closest: function( selectors, context ) {
80                 var cur,
81                         i = 0,
82                         l = this.length,
83                         ret = [],
84                         pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
85                                 jQuery( selectors, context || this.context ) :
86                                 0;
88                 for ( ; i < l; i++ ) {
89                         for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
90                                 // Always skip document fragments
91                                 if ( cur.nodeType < 11 && (pos ?
92                                         pos.index(cur) > -1 :
94                                         // Don't pass non-elements to Sizzle
95                                         cur.nodeType === 1 &&
96                                                 jQuery.find.matchesSelector(cur, selectors)) ) {
98                                         cur = ret.push( cur );
99                                         break;
100                                 }
101                         }
102                 }
104                 return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
105         },
107         // Determine the position of an element within
108         // the matched set of elements
109         index: function( elem ) {
111                 // No argument, return index in parent
112                 if ( !elem ) {
113                         return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
114                 }
116                 // index in selector
117                 if ( typeof elem === "string" ) {
118                         return jQuery.inArray( this[0], jQuery( elem ) );
119                 }
121                 // Locate the position of the desired element
122                 return jQuery.inArray(
123                         // If it receives a jQuery object, the first element is used
124                         elem.jquery ? elem[0] : elem, this );
125         },
127         add: function( selector, context ) {
128                 var set = typeof selector === "string" ?
129                                 jQuery( selector, context ) :
130                                 jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
131                         all = jQuery.merge( this.get(), set );
133                 return this.pushStack( jQuery.unique(all) );
134         },
136         addBack: function( selector ) {
137                 return this.add( selector == null ?
138                         this.prevObject : this.prevObject.filter(selector)
139                 );
140         }
143 function sibling( cur, dir ) {
144         do {
145                 cur = cur[ dir ];
146         } while ( cur && cur.nodeType !== 1 );
148         return cur;
151 jQuery.each({
152         parent: function( elem ) {
153                 var parent = elem.parentNode;
154                 return parent && parent.nodeType !== 11 ? parent : null;
155         },
156         parents: function( elem ) {
157                 return jQuery.dir( elem, "parentNode" );
158         },
159         parentsUntil: function( elem, i, until ) {
160                 return jQuery.dir( elem, "parentNode", until );
161         },
162         next: function( elem ) {
163                 return sibling( elem, "nextSibling" );
164         },
165         prev: function( elem ) {
166                 return sibling( elem, "previousSibling" );
167         },
168         nextAll: function( elem ) {
169                 return jQuery.dir( elem, "nextSibling" );
170         },
171         prevAll: function( elem ) {
172                 return jQuery.dir( elem, "previousSibling" );
173         },
174         nextUntil: function( elem, i, until ) {
175                 return jQuery.dir( elem, "nextSibling", until );
176         },
177         prevUntil: function( elem, i, until ) {
178                 return jQuery.dir( elem, "previousSibling", until );
179         },
180         siblings: function( elem ) {
181                 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
182         },
183         children: function( elem ) {
184                 return jQuery.sibling( elem.firstChild );
185         },
186         contents: function( elem ) {
187                 return jQuery.nodeName( elem, "iframe" ) ?
188                         elem.contentDocument || elem.contentWindow.document :
189                         jQuery.merge( [], elem.childNodes );
190         }
191 }, function( name, fn ) {
192         jQuery.fn[ name ] = function( until, selector ) {
193                 var ret = jQuery.map( this, fn, until );
195                 if ( name.slice( -5 ) !== "Until" ) {
196                         selector = until;
197                 }
199                 if ( selector && typeof selector === "string" ) {
200                         ret = jQuery.filter( selector, ret );
201                 }
203                 if ( this.length > 1 ) {
204                         // Remove duplicates
205                         if ( !guaranteedUnique[ name ] ) {
206                                 ret = jQuery.unique( ret );
207                         }
209                         // Reverse order for parents* and prev-derivatives
210                         if ( rparentsprev.test( name ) ) {
211                                 ret = ret.reverse();
212                         }
213                 }
215                 return this.pushStack( ret );
216         };
219 jQuery.extend({
220         filter: function( expr, elems, not ) {
221                 var elem = elems[ 0 ];
223                 if ( not ) {
224                         expr = ":not(" + expr + ")";
225                 }
227                 return elems.length === 1 && elem.nodeType === 1 ?
228                         jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
229                         jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
230                                 return elem.nodeType === 1;
231                         }));
232         },
234         dir: function( elem, dir, until ) {
235                 var matched = [],
236                         cur = elem[ dir ];
238                 while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
239                         if ( cur.nodeType === 1 ) {
240                                 matched.push( cur );
241                         }
242                         cur = cur[dir];
243                 }
244                 return matched;
245         },
247         sibling: function( n, elem ) {
248                 var r = [];
250                 for ( ; n; n = n.nextSibling ) {
251                         if ( n.nodeType === 1 && n !== elem ) {
252                                 r.push( n );
253                         }
254                 }
256                 return r;
257         }
260 // Implement the identical functionality for filter and not
261 function winnow( elements, qualifier, not ) {
262         if ( jQuery.isFunction( qualifier ) ) {
263                 return jQuery.grep( elements, function( elem, i ) {
264                         /* jshint -W018 */
265                         return !!qualifier.call( elem, i, elem ) !== not;
266                 });
268         }
270         if ( qualifier.nodeType ) {
271                 return jQuery.grep( elements, function( elem ) {
272                         return ( elem === qualifier ) !== not;
273                 });
275         }
277         if ( typeof qualifier === "string" ) {
278                 if ( isSimple.test( qualifier ) ) {
279                         return jQuery.filter( qualifier, elements, not );
280                 }
282                 qualifier = jQuery.filter( qualifier, elements );
283         }
285         return jQuery.grep( elements, function( elem ) {
286                 return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
287         });