traversing: Optimise .add by not using makeArray
[jquery.git] / src / traversing.js
blob943d16cb6a60c1be1f14231639b580a88b216c6e
1 define([
2         "./core",
3         "./var/indexOf",
4         "./traversing/var/rneedsContext",
5         "./core/init",
6         "./traversing/findFilter",
7         "./selector"
8 ], function( jQuery, indexOf, rneedsContext ) {
10 var rparentsprev = /^(?:parents|prev(?:Until|All))/,
11         // methods guaranteed to produce a unique set when starting from a unique set
12         guaranteedUnique = {
13                 children: true,
14                 contents: true,
15                 next: true,
16                 prev: true
17         };
19 jQuery.extend({
20         dir: function( elem, dir, until ) {
21                 var matched = [],
22                         truncate = until !== undefined;
24                 while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
25                         if ( elem.nodeType === 1 ) {
26                                 if ( truncate && jQuery( elem ).is( until ) ) {
27                                         break;
28                                 }
29                                 matched.push( elem );
30                         }
31                 }
32                 return matched;
33         },
35         sibling: function( n, elem ) {
36                 var matched = [];
38                 for ( ; n; n = n.nextSibling ) {
39                         if ( n.nodeType === 1 && n !== elem ) {
40                                 matched.push( n );
41                         }
42                 }
44                 return matched;
45         }
46 });
48 jQuery.fn.extend({
49         has: function( target ) {
50                 var targets = jQuery( target, this ),
51                         l = targets.length;
53                 return this.filter(function() {
54                         var i = 0;
55                         for ( ; i < l; i++ ) {
56                                 if ( jQuery.contains( this, targets[i] ) ) {
57                                         return true;
58                                 }
59                         }
60                 });
61         },
63         closest: function( selectors, context ) {
64                 var cur,
65                         i = 0,
66                         l = this.length,
67                         matched = [],
68                         pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
69                                 jQuery( selectors, context || this.context ) :
70                                 0;
72                 for ( ; i < l; i++ ) {
73                         for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
74                                 // Always skip document fragments
75                                 if ( cur.nodeType < 11 && (pos ?
76                                         pos.index(cur) > -1 :
78                                         // Don't pass non-elements to Sizzle
79                                         cur.nodeType === 1 &&
80                                                 jQuery.find.matchesSelector(cur, selectors)) ) {
82                                         matched.push( cur );
83                                         break;
84                                 }
85                         }
86                 }
88                 return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
89         },
91         // Determine the position of an element within
92         // the matched set of elements
93         index: function( elem ) {
95                 // No argument, return index in parent
96                 if ( !elem ) {
97                         return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
98                 }
100                 // index in selector
101                 if ( typeof elem === "string" ) {
102                         return indexOf.call( jQuery( elem ), this[ 0 ] );
103                 }
105                 // Locate the position of the desired element
106                 return indexOf.call( this,
108                         // If it receives a jQuery object, the first element is used
109                         elem.jquery ? elem[ 0 ] : elem
110                 );
111         },
113         add: function( selector, context ) {
114                 return this.pushStack(
115                         jQuery.unique(
116                                 jQuery.merge( this.get(), jQuery( selector, context ) )
117                         )
118                 );
119         },
121         addBack: function( selector ) {
122                 return this.add( selector == null ?
123                         this.prevObject : this.prevObject.filter(selector)
124                 );
125         }
128 function sibling( cur, dir ) {
129         while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
130         return cur;
133 jQuery.each({
134         parent: function( elem ) {
135                 var parent = elem.parentNode;
136                 return parent && parent.nodeType !== 11 ? parent : null;
137         },
138         parents: function( elem ) {
139                 return jQuery.dir( elem, "parentNode" );
140         },
141         parentsUntil: function( elem, i, until ) {
142                 return jQuery.dir( elem, "parentNode", until );
143         },
144         next: function( elem ) {
145                 return sibling( elem, "nextSibling" );
146         },
147         prev: function( elem ) {
148                 return sibling( elem, "previousSibling" );
149         },
150         nextAll: function( elem ) {
151                 return jQuery.dir( elem, "nextSibling" );
152         },
153         prevAll: function( elem ) {
154                 return jQuery.dir( elem, "previousSibling" );
155         },
156         nextUntil: function( elem, i, until ) {
157                 return jQuery.dir( elem, "nextSibling", until );
158         },
159         prevUntil: function( elem, i, until ) {
160                 return jQuery.dir( elem, "previousSibling", until );
161         },
162         siblings: function( elem ) {
163                 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
164         },
165         children: function( elem ) {
166                 return jQuery.sibling( elem.firstChild );
167         },
168         contents: function( elem ) {
169                 return elem.contentDocument || jQuery.merge( [], elem.childNodes );
170         }
171 }, function( name, fn ) {
172         jQuery.fn[ name ] = function( until, selector ) {
173                 var matched = jQuery.map( this, fn, until );
175                 if ( name.slice( -5 ) !== "Until" ) {
176                         selector = until;
177                 }
179                 if ( selector && typeof selector === "string" ) {
180                         matched = jQuery.filter( selector, matched );
181                 }
183                 if ( this.length > 1 ) {
184                         // Remove duplicates
185                         if ( !guaranteedUnique[ name ] ) {
186                                 jQuery.unique( matched );
187                         }
189                         // Reverse order for parents* and prev-derivatives
190                         if ( rparentsprev.test( name ) ) {
191                                 matched.reverse();
192                         }
193                 }
195                 return this.pushStack( matched );
196         };
199 return jQuery;