Offset: allow offset setter to throw for disconnected elements
[jquery.git] / src / traversing.js
blob19f8d24e752038a45ed071ccc4b2f61694bd3eb8
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.uniqueSort( matched ) : matched );
89         },
91         // Determine the position of an element within the set
92         index: function( elem ) {
94                 // No argument, return index in parent
95                 if ( !elem ) {
96                         return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
97                 }
99                 // Index in selector
100                 if ( typeof elem === "string" ) {
101                         return indexOf.call( jQuery( elem ), this[ 0 ] );
102                 }
104                 // Locate the position of the desired element
105                 return indexOf.call( this,
107                         // If it receives a jQuery object, the first element is used
108                         elem.jquery ? elem[ 0 ] : elem
109                 );
110         },
112         add: function( selector, context ) {
113                 return this.pushStack(
114                         jQuery.uniqueSort(
115                                 jQuery.merge( this.get(), jQuery( selector, context ) )
116                         )
117                 );
118         },
120         addBack: function( selector ) {
121                 return this.add( selector == null ?
122                         this.prevObject : this.prevObject.filter(selector)
123                 );
124         }
127 function sibling( cur, dir ) {
128         while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
129         return cur;
132 jQuery.each({
133         parent: function( elem ) {
134                 var parent = elem.parentNode;
135                 return parent && parent.nodeType !== 11 ? parent : null;
136         },
137         parents: function( elem ) {
138                 return jQuery.dir( elem, "parentNode" );
139         },
140         parentsUntil: function( elem, i, until ) {
141                 return jQuery.dir( elem, "parentNode", until );
142         },
143         next: function( elem ) {
144                 return sibling( elem, "nextSibling" );
145         },
146         prev: function( elem ) {
147                 return sibling( elem, "previousSibling" );
148         },
149         nextAll: function( elem ) {
150                 return jQuery.dir( elem, "nextSibling" );
151         },
152         prevAll: function( elem ) {
153                 return jQuery.dir( elem, "previousSibling" );
154         },
155         nextUntil: function( elem, i, until ) {
156                 return jQuery.dir( elem, "nextSibling", until );
157         },
158         prevUntil: function( elem, i, until ) {
159                 return jQuery.dir( elem, "previousSibling", until );
160         },
161         siblings: function( elem ) {
162                 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
163         },
164         children: function( elem ) {
165                 return jQuery.sibling( elem.firstChild );
166         },
167         contents: function( elem ) {
168                 return elem.contentDocument || jQuery.merge( [], elem.childNodes );
169         }
170 }, function( name, fn ) {
171         jQuery.fn[ name ] = function( until, selector ) {
172                 var matched = jQuery.map( this, fn, until );
174                 if ( name.slice( -5 ) !== "Until" ) {
175                         selector = until;
176                 }
178                 if ( selector && typeof selector === "string" ) {
179                         matched = jQuery.filter( selector, matched );
180                 }
182                 if ( this.length > 1 ) {
183                         // Remove duplicates
184                         if ( !guaranteedUnique[ name ] ) {
185                                 jQuery.uniqueSort( matched );
186                         }
188                         // Reverse order for parents* and prev-derivatives
189                         if ( rparentsprev.test( name ) ) {
190                                 matched.reverse();
191                         }
192                 }
194                 return this.pushStack( matched );
195         };
198 return jQuery;