Fix #11543: .has should work on detached elements.
[jquery.git] / src / manipulation.js
blob43bf37746194b0c2a891ee6e7eb99b0628f3a97f
1 (function( jQuery ) {
3 function createSafeFragment( document ) {
4         var list = nodeNames.split( "|" ),
5         safeFrag = document.createDocumentFragment();
7         if ( safeFrag.createElement ) {
8                 while ( list.length ) {
9                         safeFrag.createElement(
10                                 list.pop()
11                         );
12                 }
13         }
14         return safeFrag;
17 var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
18                 "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
19         rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
20         rleadingWhitespace = /^\s+/,
21         rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
22         rtagName = /<([\w:]+)/,
23         rtbody = /<tbody/i,
24         rhtml = /<|&#?\w+;/,
25         rnoInnerhtml = /<(?:script|style|link)/i,
26         rnocache = /<(?:script|object|embed|option|style)/i,
27         rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
28         rcheckableType = /^(?:checkbox|radio)$/,
29         // checked="checked" or checked
30         rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
31         rscriptType = /\/(java|ecma)script/i,
32         rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
33         wrapMap = {
34                 option: [ 1, "<select multiple='multiple'>", "</select>" ],
35                 legend: [ 1, "<fieldset>", "</fieldset>" ],
36                 thead: [ 1, "<table>", "</table>" ],
37                 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
38                 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
39                 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
40                 area: [ 1, "<map>", "</map>" ],
41                 _default: [ 0, "", "" ]
42         },
43         safeFragment = createSafeFragment( document );
45 wrapMap.optgroup = wrapMap.option;
46 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
47 wrapMap.th = wrapMap.td;
49 // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
50 // unless wrapped in a div with non-breaking characters in front of it.
51 if ( !jQuery.support.htmlSerialize ) {
52         wrapMap._default = [ 1, "X<div>", "</div>" ];
55 jQuery.fn.extend({
56         text: function( value ) {
57                 return jQuery.access( this, function( value ) {
58                         return value === undefined ?
59                                 jQuery.text( this ) :
60                                 this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
61                 }, null, value, arguments.length );
62         },
64         wrapAll: function( html ) {
65                 if ( jQuery.isFunction( html ) ) {
66                         return this.each(function(i) {
67                                 jQuery(this).wrapAll( html.call(this, i) );
68                         });
69                 }
71                 if ( this[0] ) {
72                         // The elements to wrap the target around
73                         var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
75                         if ( this[0].parentNode ) {
76                                 wrap.insertBefore( this[0] );
77                         }
79                         wrap.map(function() {
80                                 var elem = this;
82                                 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
83                                         elem = elem.firstChild;
84                                 }
86                                 return elem;
87                         }).append( this );
88                 }
90                 return this;
91         },
93         wrapInner: function( html ) {
94                 if ( jQuery.isFunction( html ) ) {
95                         return this.each(function(i) {
96                                 jQuery(this).wrapInner( html.call(this, i) );
97                         });
98                 }
100                 return this.each(function() {
101                         var self = jQuery( this ),
102                                 contents = self.contents();
104                         if ( contents.length ) {
105                                 contents.wrapAll( html );
107                         } else {
108                                 self.append( html );
109                         }
110                 });
111         },
113         wrap: function( html ) {
114                 var isFunction = jQuery.isFunction( html );
116                 return this.each(function(i) {
117                         jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
118                 });
119         },
121         unwrap: function() {
122                 return this.parent().each(function() {
123                         if ( !jQuery.nodeName( this, "body" ) ) {
124                                 jQuery( this ).replaceWith( this.childNodes );
125                         }
126                 }).end();
127         },
129         append: function() {
130                 return this.domManip(arguments, true, function( elem ) {
131                         if ( this.nodeType === 1 ) {
132                                 this.appendChild( elem );
133                         }
134                 });
135         },
137         prepend: function() {
138                 return this.domManip(arguments, true, function( elem ) {
139                         if ( this.nodeType === 1 ) {
140                                 this.insertBefore( elem, this.firstChild );
141                         }
142                 });
143         },
145         before: function() {
146                 if ( this[0] && this[0].parentNode ) {
147                         return this.domManip(arguments, false, function( elem ) {
148                                 this.parentNode.insertBefore( elem, this );
149                         });
150                 } else if ( arguments.length ) {
151                         var set = jQuery.clean( arguments );
152                         set.push.apply( set, this.toArray() );
153                         return this.pushStack( set, "before", arguments );
154                 }
155         },
157         after: function() {
158                 if ( this[0] && this[0].parentNode ) {
159                         return this.domManip(arguments, false, function( elem ) {
160                                 this.parentNode.insertBefore( elem, this.nextSibling );
161                         });
162                 } else if ( arguments.length ) {
163                         var set = this.pushStack( this, "after", arguments );
164                         set.push.apply( set, jQuery.clean(arguments) );
165                         return set;
166                 }
167         },
169         // keepData is for internal use only--do not document
170         remove: function( selector, keepData ) {
171                 for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
172                         if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
173                                 if ( !keepData && elem.nodeType === 1 ) {
174                                         jQuery.cleanData( elem.getElementsByTagName("*") );
175                                         jQuery.cleanData( [ elem ] );
176                                 }
178                                 if ( elem.parentNode ) {
179                                         elem.parentNode.removeChild( elem );
180                                 }
181                         }
182                 }
184                 return this;
185         },
187         empty: function() {
188                 for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
189                         // Remove element nodes and prevent memory leaks
190                         if ( elem.nodeType === 1 ) {
191                                 jQuery.cleanData( elem.getElementsByTagName("*") );
192                         }
194                         // Remove any remaining nodes
195                         while ( elem.firstChild ) {
196                                 elem.removeChild( elem.firstChild );
197                         }
198                 }
200                 return this;
201         },
203         clone: function( dataAndEvents, deepDataAndEvents ) {
204                 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
205                 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
207                 return this.map( function () {
208                         return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
209                 });
210         },
212         html: function( value ) {
213                 return jQuery.access( this, function( value ) {
214                         var elem = this[0] || {},
215                                 i = 0,
216                                 l = this.length;
218                         if ( value === undefined ) {
219                                 return elem.nodeType === 1 ?
220                                         elem.innerHTML.replace( rinlinejQuery, "" ) :
221                                         null;
222                         }
224                         // See if we can take a shortcut and just use innerHTML
225                         if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
226                                 ( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&
227                                 ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
228                                 !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
230                                 value = value.replace( rxhtmlTag, "<$1></$2>" );
232                                 try {
233                                         for (; i < l; i++ ) {
234                                                 // Remove element nodes and prevent memory leaks
235                                                 elem = this[i] || {};
236                                                 if ( elem.nodeType === 1 ) {
237                                                         jQuery.cleanData( elem.getElementsByTagName( "*" ) );
238                                                         elem.innerHTML = value;
239                                                 }
240                                         }
242                                         elem = 0;
244                                 // If using innerHTML throws an exception, use the fallback method
245                                 } catch(e) {}
246                         }
248                         if ( elem ) {
249                                 this.empty().append( value );
250                         }
251                 }, null, value, arguments.length );
252         },
254         replaceWith: function( value ) {
255                 if ( this[0] && this[0].parentNode && this[0].parentNode.nodeType != 11 ) {
256                         // Make sure that the elements are removed from the DOM before they are inserted
257                         // this can help fix replacing a parent with child elements
258                         if ( jQuery.isFunction( value ) ) {
259                                 return this.each(function(i) {
260                                         var self = jQuery(this), old = self.html();
261                                         self.replaceWith( value.call( this, i, old ) );
262                                 });
263                         }
265                         if ( typeof value !== "string" ) {
266                                 value = jQuery( value ).detach();
267                         }
269                         return this.each(function() {
270                                 var next = this.nextSibling,
271                                         parent = this.parentNode;
273                                 jQuery( this ).remove();
275                                 if ( next ) {
276                                         jQuery(next).before( value );
277                                 } else {
278                                         jQuery(parent).append( value );
279                                 }
280                         });
281                 }
283                 return this.length ?
284                         this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
285                         this;
286         },
288         detach: function( selector ) {
289                 return this.remove( selector, true );
290         },
292         domManip: function( args, table, callback ) {
293                 var results, first, fragment, iNoClone,
294                         i = 0,
295                         value = args[0],
296                         scripts = [],
297                         l = this.length;
299                 // We can't cloneNode fragments that contain checked, in WebKit
300                 if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) {
301                         return this.each(function() {
302                                 jQuery(this).domManip( args, table, callback );
303                         });
304                 }
306                 if ( jQuery.isFunction(value) ) {
307                         return this.each(function(i) {
308                                 var self = jQuery(this);
309                                 args[0] = value.call( this, i, table ? self.html() : undefined );
310                                 self.domManip( args, table, callback );
311                         });
312                 }
314                 if ( this[0] ) {
315                         results = jQuery.buildFragment( args, this, scripts );
316                         fragment = results.fragment;
318                                 first = fragment.firstChild;
319                         if ( fragment.childNodes.length === 1 ) {
320                                 fragment = first;
321                         }
323                         if ( first ) {
324                                 table = table && jQuery.nodeName( first, "tr" );
326                                 // Use the original fragment for the last item instead of the first because it can end up
327                                 // being emptied incorrectly in certain situations (#8070).
328                                 // Fragments from the fragment cache must always be cloned and never used in place.
329                                 for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) {
330                                         callback.call(
331                                                 table && jQuery.nodeName( this[i], "table" ) ?
332                                                         findOrAppend( this[i], "tbody" ) :
333                                                         this[i],
334                                                 i === iNoClone ?
335                                                         fragment :
336                                                         jQuery.clone( fragment, true, true )
337                                         );
338                                 }
339                         }
341                         if ( scripts.length ) {
342                                 jQuery.each( scripts, function( i, elem ) {
343                                         if ( elem.src ) {
344                                                 jQuery.ajax({
345                                                         type: "GET",
346                                                         global: false,
347                                                         url: elem.src,
348                                                         async: false,
349                                                         dataType: "script"
350                                                 });
351                                         } else {
352                                                 jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
353                                         }
355                                         if ( elem.parentNode ) {
356                                                 elem.parentNode.removeChild( elem );
357                                         }
358                                 });
359                         }
360                 }
362                 return this;
363         }
366 function findOrAppend( elem, tag ) {
367         return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
370 function cloneCopyEvent( src, dest ) {
372         if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
373                 return;
374         }
376         var type, i, l,
377                 oldData = jQuery._data( src ),
378                 curData = jQuery._data( dest, oldData ),
379                 events = oldData.events;
381         if ( events ) {
382                 delete curData.handle;
383                 curData.events = {};
385                 for ( type in events ) {
386                         for ( i = 0, l = events[ type ].length; i < l; i++ ) {
387                                 jQuery.event.add( dest, type, events[ type ][ i ] );
388                         }
389                 }
390         }
392         // make the cloned public data object a copy from the original
393         if ( curData.data ) {
394                 curData.data = jQuery.extend( {}, curData.data );
395         }
398 function cloneFixAttributes( src, dest ) {
399         var nodeName;
401         // We do not need to do anything for non-Elements
402         if ( dest.nodeType !== 1 ) {
403                 return;
404         }
406         // clearAttributes removes the attributes, which we don't want,
407         // but also removes the attachEvent events, which we *do* want
408         if ( dest.clearAttributes ) {
409                 dest.clearAttributes();
410         }
412         // mergeAttributes, in contrast, only merges back on the
413         // original attributes, not the events
414         if ( dest.mergeAttributes ) {
415                 dest.mergeAttributes( src );
416         }
418         nodeName = dest.nodeName.toLowerCase();
420         // IE6-8 fail to clone children inside object elements that use
421         // the proprietary classid attribute value (rather than the type
422         // attribute) to identify the type of content to display
423         if ( nodeName === "object" ) {
424                 dest.outerHTML = src.outerHTML;
426         } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
427                 // IE6-8 fails to persist the checked state of a cloned checkbox
428                 // or radio button. Worse, IE6-7 fail to give the cloned element
429                 // a checked appearance if the defaultChecked value isn't also set
430                 if ( src.checked ) {
431                         dest.defaultChecked = dest.checked = src.checked;
432                 }
434                 // IE6-7 get confused and end up setting the value of a cloned
435                 // checkbox/radio button to an empty string instead of "on"
436                 if ( dest.value !== src.value ) {
437                         dest.value = src.value;
438                 }
440         // IE6-8 fails to return the selected option to the default selected
441         // state when cloning options
442         } else if ( nodeName === "option" ) {
443                 dest.selected = src.defaultSelected;
445         // IE6-8 fails to set the defaultValue to the correct value when
446         // cloning other types of input fields
447         } else if ( nodeName === "input" || nodeName === "textarea" ) {
448                 dest.defaultValue = src.defaultValue;
450         // IE blanks contents when cloning scripts
451         } else if ( nodeName === "script" && dest.text !== src.text ) {
452                 dest.text = src.text;
453         }
455         // Event data gets referenced instead of copied if the expando
456         // gets copied too
457         dest.removeAttribute( jQuery.expando );
459         // Clear flags for bubbling special change/submit events, they must
460         // be reattached when the newly cloned events are first activated
461         dest.removeAttribute( "_submit_attached" );
462         dest.removeAttribute( "_change_attached" );
465 jQuery.buildFragment = function( args, context, scripts ) {
466         var fragment, cacheable, cachehit,
467         first = args[ 0 ];
469         // Set context from what may come in as undefined or a jQuery collection or a node
470         context = context || document;
471         context = (context[0] || context).ownerDocument || context[0] || context;
473         // Ensure that an attr object doesn't incorrectly stand in as a document object
474         // Chrome and Firefox seem to allow this to occur and will throw exception
475         // Fixes #8950
476         if ( typeof context.createDocumentFragment === "undefined" ) {
477                 context = document;
478         }
480         // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
481         // Cloning options loses the selected state, so don't cache them
482         // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
483         // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
484         // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
485         if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document &&
486                 first.charAt(0) === "<" && !rnocache.test( first ) &&
487                 (jQuery.support.checkClone || !rchecked.test( first )) &&
488                 (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
490                 // Mark cacheable and look for a hit
491                 cacheable = true;
492                 fragment = jQuery.fragments[ first ];
493                 cachehit = fragment !== undefined;
494                 }
496         if ( !fragment ) {
497                 fragment = context.createDocumentFragment();
498                 jQuery.clean( args, context, fragment, scripts );
499         if ( cacheable ) {
500                         // Update the cache, but only store false
501                         // unless this is a second parsing of the same content
502                         jQuery.fragments[ first ] = cachehit && fragment;
503         }
504         }
506         return { fragment: fragment, cacheable: cacheable };
509 jQuery.fragments = {};
511 jQuery.each({
512         appendTo: "append",
513         prependTo: "prepend",
514         insertBefore: "before",
515         insertAfter: "after",
516         replaceAll: "replaceWith"
517 }, function( name, original ) {
518         jQuery.fn[ name ] = function( selector ) {
519                 var ret = [],
520                         insert = jQuery( selector ),
521                         parent = this.length === 1 && this[0].parentNode;
523                 if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
524                         insert[ original ]( this[0] );
525                         return this;
527                 } else {
528                         for ( var i = 0, l = insert.length; i < l; i++ ) {
529                                 var elems = ( i > 0 ? this.clone(true) : this ).get();
530                                 jQuery( insert[i] )[ original ]( elems );
531                                 ret = ret.concat( elems );
532                         }
534                         return this.pushStack( ret, name, insert.selector );
535                 }
536         };
539 function getAll( elem ) {
540         if ( typeof elem.getElementsByTagName !== "undefined" ) {
541                 return elem.getElementsByTagName( "*" );
543         } else if ( typeof elem.querySelectorAll !== "undefined" ) {
544                 return elem.querySelectorAll( "*" );
546         } else {
547                 return [];
548         }
551 // Used in clean, fixes the defaultChecked property
552 function fixDefaultChecked( elem ) {
553         if ( rcheckableType.test( elem.type ) ) {
554                 elem.defaultChecked = elem.checked;
555         }
558 // Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
559 function shimCloneNode( elem ) {
560         var div = document.createElement( "div" );
561         safeFragment.appendChild( div );
563         div.innerHTML = elem.outerHTML;
564         return div.firstChild;
567 jQuery.extend({
568         clone: function( elem, dataAndEvents, deepDataAndEvents ) {
569                 var srcElements,
570                         destElements,
571                         i,
572                         // IE<=8 does not properly clone detached, unknown element nodes
573                         clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ?
574                                 elem.cloneNode( true ) :
575                                 shimCloneNode( elem );
577                 if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
578                                 (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
579                         // IE copies events bound via attachEvent when using cloneNode.
580                         // Calling detachEvent on the clone will also remove the events
581                         // from the original. In order to get around this, we use some
582                         // proprietary methods to clear the events. Thanks to MooTools
583                         // guys for this hotness.
585                         cloneFixAttributes( elem, clone );
587                         // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
588                         srcElements = getAll( elem );
589                         destElements = getAll( clone );
591                         // Weird iteration because IE will replace the length property
592                         // with an element if you are cloning the body and one of the
593                         // elements on the page has a name or id of "length"
594                         for ( i = 0; srcElements[i]; ++i ) {
595                                 // Ensure that the destination node is not null; Fixes #9587
596                                 if ( destElements[i] ) {
597                                         cloneFixAttributes( srcElements[i], destElements[i] );
598                                 }
599                         }
600                 }
602                 // Copy the events from the original to the clone
603                 if ( dataAndEvents ) {
604                         cloneCopyEvent( elem, clone );
606                         if ( deepDataAndEvents ) {
607                                 srcElements = getAll( elem );
608                                 destElements = getAll( clone );
610                                 for ( i = 0; srcElements[i]; ++i ) {
611                                         cloneCopyEvent( srcElements[i], destElements[i] );
612                                 }
613                         }
614                 }
616                 srcElements = destElements = null;
618                 // Return the cloned set
619                 return clone;
620         },
622         clean: function( elems, context, fragment, scripts ) {
623                 var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
624                         i = 0,
625                                 ret = [];
627                 // Ensure that context is a document
628                 if ( !context || typeof context.createDocumentFragment === "undefined" ) {
629                         context = document;
630                 }
632                 // Use the already-created safe fragment if context permits
633                 for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) {
634                         if ( typeof elem === "number" ) {
635                                 elem += "";
636                         }
638                         if ( !elem ) {
639                                 continue;
640                         }
642                         // Convert html string into DOM nodes
643                         if ( typeof elem === "string" ) {
644                                 if ( !rhtml.test( elem ) ) {
645                                         elem = context.createTextNode( elem );
646                                 } else {
647                                         // Ensure a safe container in which to render the html
648                                         safe = safe || createSafeFragment( context );
649                                         div = div || safe.appendChild( context.createElement("div") );
651                                         // Fix "XHTML"-style tags in all browsers
652                                         elem = elem.replace(rxhtmlTag, "<$1></$2>");
654                                         // Go to html and back, then peel off extra wrappers
655                                         tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
656                                         wrap = wrapMap[ tag ] || wrapMap._default;
657                                         depth = wrap[0];
658                                         div.innerHTML = wrap[1] + elem + wrap[2];
660                                         // Move to the right depth
661                                         while ( depth-- ) {
662                                                 div = div.lastChild;
663                                         }
665                                         // Remove IE's autoinserted <tbody> from table fragments
666                                         if ( !jQuery.support.tbody ) {
668                                                 // String was a <table>, *may* have spurious <tbody>
669                                                 hasBody = rtbody.test(elem);
670                                                         tbody = tag === "table" && !hasBody ?
671                                                                 div.firstChild && div.firstChild.childNodes :
673                                                                 // String was a bare <thead> or <tfoot>
674                                                                 wrap[1] === "<table>" && !hasBody ?
675                                                                         div.childNodes :
676                                                                         [];
678                                                 for ( j = tbody.length - 1; j >= 0 ; --j ) {
679                                                         if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
680                                                                 tbody[ j ].parentNode.removeChild( tbody[ j ] );
681                                                         }
682                                                 }
683                                         }
685                                         // IE completely kills leading whitespace when innerHTML is used
686                                         if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
687                                                 div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
688                                         }
690                                         elem = div.childNodes;
692                                         // Remember the top-level container for proper cleanup
693                                         div = safe.lastChild;
694                                                         }
695                                                 }
697                         if ( elem.nodeType ) {
698                                 ret.push( elem );
699                         } else {
700                                 ret = jQuery.merge( ret, elem );
701                                         }
702                                 }
704                 // Fix #11356: Clear elements from safeFragment
705                 if ( div ) {
706                         safe.removeChild( div );
707                         div = safe = null;
708                         }
710                 // Reset defaultChecked for any radios and checkboxes
711                         // about to be appended to the DOM in IE 6/7 (#8060)
712                         if ( !jQuery.support.appendChecked ) {
713                         for ( i = 0; (elem = ret[i]) != null; i++ ) {
714                                 if ( jQuery.nodeName( elem, "input" ) ) {
715                                         fixDefaultChecked( elem );
716                                 } else if ( typeof elem.getElementsByTagName !== "undefined" ) {
717                                         jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
718                                         }
719                                 }
720                         }
722                 // Append elements to a provided document fragment
723                 if ( fragment ) {
724                         // Special handling of each script element
725                         handleScript = function( elem ) {
726                                 // Check if we consider it executable
727                                 if ( !elem.type || rscriptType.test( elem.type ) ) {
728                                         // Detach the script and store it in the scripts array (if provided) or the fragment
729                                         // Return truthy to indicate that it has been handled
730                                         return scripts ?
731                                                 scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
732                                                 fragment.appendChild( elem );
733                                 }
734                         };
736                         for ( i = 0; (elem = ret[i]) != null; i++ ) {
737                                 // Check if we're done after handling an executable script
738                                 if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
739                                         // Append to fragment and handle embedded scripts
740                                         fragment.appendChild( elem );
741                                         if ( typeof elem.getElementsByTagName !== "undefined" ) {
742                                                 // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
743                                                 jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
745                                                 // Splice the scripts into ret after their former ancestor and advance our index beyond them
746                                                 ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
747                                                 i += jsTags.length;
748                                         }
749                                 }
750                         }
751                 }
753                 return ret;
754         },
756         cleanData: function( elems ) {
757                 var data, id,
758                         cache = jQuery.cache,
759                         special = jQuery.event.special,
760                         deleteExpando = jQuery.support.deleteExpando;
762                 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
763                         if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
764                                 continue;
765                         }
767                         id = elem[ jQuery.expando ];
769                         if ( id ) {
770                                 data = cache[ id ];
772                                 if ( data && data.events ) {
773                                         for ( var type in data.events ) {
774                                                 if ( special[ type ] ) {
775                                                         jQuery.event.remove( elem, type );
777                                                 // This is a shortcut to avoid jQuery.event.remove's overhead
778                                                 } else {
779                                                         jQuery.removeEvent( elem, type, data.handle );
780                                                 }
781                                         }
782                                 }
784                                 // Remove cache only if jQuery.event.remove was not removed it before
785                                 if ( cache[ id ] ) {
786                                         if ( deleteExpando ) {
787                                                 delete elem[ jQuery.expando ];
789                                         } else if ( elem.removeAttribute ) {
790                                                 elem.removeAttribute( jQuery.expando );
791                                         }
793                                         jQuery.deletedIds.push( id );
794                                         delete cache[ id ];
795                                 }
796                         }
797                 }
798         }
801 })( jQuery );