3 function createSafeFragment( document ) {
4 var list = nodeNames.split( "|" ),
5 safeFrag = document.createDocumentFragment();
7 if ( safeFrag.createElement ) {
8 while ( list.length ) {
9 safeFrag.createElement(
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:]+)/,
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\[|\-\-)/,
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, "", "" ]
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>" ];
56 text: function( value ) {
57 return jQuery.access( this, function( value ) {
58 return value === undefined ?
60 this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
61 }, null, value, arguments.length );
64 wrapAll: function( html ) {
65 if ( jQuery.isFunction( html ) ) {
66 return this.each(function(i) {
67 jQuery(this).wrapAll( html.call(this, i) );
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] );
82 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
83 elem = elem.firstChild;
93 wrapInner: function( html ) {
94 if ( jQuery.isFunction( html ) ) {
95 return this.each(function(i) {
96 jQuery(this).wrapInner( html.call(this, i) );
100 return this.each(function() {
101 var self = jQuery( this ),
102 contents = self.contents();
104 if ( contents.length ) {
105 contents.wrapAll( html );
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 );
122 return this.parent().each(function() {
123 if ( !jQuery.nodeName( this, "body" ) ) {
124 jQuery( this ).replaceWith( this.childNodes );
130 return this.domManip(arguments, true, function( elem ) {
131 if ( this.nodeType === 1 ) {
132 this.appendChild( elem );
137 prepend: function() {
138 return this.domManip(arguments, true, function( elem ) {
139 if ( this.nodeType === 1 ) {
140 this.insertBefore( elem, this.firstChild );
146 if ( this[0] && this[0].parentNode ) {
147 return this.domManip(arguments, false, function( elem ) {
148 this.parentNode.insertBefore( elem, this );
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 );
158 if ( this[0] && this[0].parentNode ) {
159 return this.domManip(arguments, false, function( elem ) {
160 this.parentNode.insertBefore( elem, this.nextSibling );
162 } else if ( arguments.length ) {
163 var set = this.pushStack( this, "after", arguments );
164 set.push.apply( set, jQuery.clean(arguments) );
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 ] );
178 if ( elem.parentNode ) {
179 elem.parentNode.removeChild( elem );
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("*") );
194 // Remove any remaining nodes
195 while ( elem.firstChild ) {
196 elem.removeChild( elem.firstChild );
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 );
212 html: function( value ) {
213 return jQuery.access( this, function( value ) {
214 var elem = this[0] || {},
218 if ( value === undefined ) {
219 return elem.nodeType === 1 ?
220 elem.innerHTML.replace( rinlinejQuery, "" ) :
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>" );
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;
244 // If using innerHTML throws an exception, use the fallback method
249 this.empty().append( value );
251 }, null, value, arguments.length );
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 ) );
265 if ( typeof value !== "string" ) {
266 value = jQuery( value ).detach();
269 return this.each(function() {
270 var next = this.nextSibling,
271 parent = this.parentNode;
273 jQuery( this ).remove();
276 jQuery(next).before( value );
278 jQuery(parent).append( value );
284 this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
288 detach: function( selector ) {
289 return this.remove( selector, true );
292 domManip: function( args, table, callback ) {
293 var results, first, fragment, iNoClone,
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 );
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 );
315 results = jQuery.buildFragment( args, this, scripts );
316 fragment = results.fragment;
318 first = fragment.firstChild;
319 if ( fragment.childNodes.length === 1 ) {
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++ ) {
331 table && jQuery.nodeName( this[i], "table" ) ?
332 findOrAppend( this[i], "tbody" ) :
336 jQuery.clone( fragment, true, true )
341 if ( scripts.length ) {
342 jQuery.each( scripts, function( i, elem ) {
352 jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
355 if ( elem.parentNode ) {
356 elem.parentNode.removeChild( elem );
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 ) ) {
377 oldData = jQuery._data( src ),
378 curData = jQuery._data( dest, oldData ),
379 events = oldData.events;
382 delete curData.handle;
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 ] );
392 // make the cloned public data object a copy from the original
393 if ( curData.data ) {
394 curData.data = jQuery.extend( {}, curData.data );
398 function cloneFixAttributes( src, dest ) {
401 // We do not need to do anything for non-Elements
402 if ( dest.nodeType !== 1 ) {
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();
412 // mergeAttributes, in contrast, only merges back on the
413 // original attributes, not the events
414 if ( dest.mergeAttributes ) {
415 dest.mergeAttributes( src );
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
431 dest.defaultChecked = dest.checked = src.checked;
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;
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;
455 // Event data gets referenced instead of copied if the expando
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,
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
476 if ( typeof context.createDocumentFragment === "undefined" ) {
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
492 fragment = jQuery.fragments[ first ];
493 cachehit = fragment !== undefined;
497 fragment = context.createDocumentFragment();
498 jQuery.clean( args, context, fragment, scripts );
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;
506 return { fragment: fragment, cacheable: cacheable };
509 jQuery.fragments = {};
513 prependTo: "prepend",
514 insertBefore: "before",
515 insertAfter: "after",
516 replaceAll: "replaceWith"
517 }, function( name, original ) {
518 jQuery.fn[ name ] = function( selector ) {
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] );
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 );
534 return this.pushStack( ret, name, insert.selector );
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( "*" );
551 // Used in clean, fixes the defaultChecked property
552 function fixDefaultChecked( elem ) {
553 if ( rcheckableType.test( elem.type ) ) {
554 elem.defaultChecked = elem.checked;
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;
568 clone: function( elem, dataAndEvents, deepDataAndEvents ) {
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] );
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] );
616 srcElements = destElements = null;
618 // Return the cloned set
622 clean: function( elems, context, fragment, scripts ) {
623 var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
627 // Ensure that context is a document
628 if ( !context || typeof context.createDocumentFragment === "undefined" ) {
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" ) {
642 // Convert html string into DOM nodes
643 if ( typeof elem === "string" ) {
644 if ( !rhtml.test( elem ) ) {
645 elem = context.createTextNode( elem );
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;
658 div.innerHTML = wrap[1] + elem + wrap[2];
660 // Move to the right depth
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 ?
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 ] );
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 );
690 elem = div.childNodes;
692 // Remember the top-level container for proper cleanup
693 div = safe.lastChild;
697 if ( elem.nodeType ) {
700 ret = jQuery.merge( ret, elem );
704 // Fix #11356: Clear elements from safeFragment
706 safe.removeChild( div );
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 );
722 // Append elements to a provided document 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
731 scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
732 fragment.appendChild( elem );
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 ) );
756 cleanData: function( elems ) {
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()] ) {
767 id = elem[ jQuery.expando ];
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
779 jQuery.removeEvent( elem, type, data.handle );
784 // Remove cache only if jQuery.event.remove was not removed it before
786 if ( deleteExpando ) {
787 delete elem[ jQuery.expando ];
789 } else if ( elem.removeAttribute ) {
790 elem.removeAttribute( jQuery.expando );
793 jQuery.deletedIds.push( id );