Data: Refactor to reduce size
[jquery.git] / src / manipulation.js
blob41cb8eadbed3ee741bf6a3cc8aaa18b9b8138b5d
1 import { jQuery } from "./core.js";
2 import { isAttached } from "./core/isAttached.js";
3 import { isIE } from "./var/isIE.js";
4 import { push } from "./var/push.js";
5 import { access } from "./core/access.js";
6 import { rtagName } from "./manipulation/var/rtagName.js";
7 import { wrapMap } from "./manipulation/wrapMap.js";
8 import { getAll } from "./manipulation/getAll.js";
9 import { domManip } from "./manipulation/domManip.js";
10 import { setGlobalEval } from "./manipulation/setGlobalEval.js";
11 import { dataPriv } from "./data/var/dataPriv.js";
12 import { dataUser } from "./data/var/dataUser.js";
13 import { acceptData } from "./data/var/acceptData.js";
14 import { nodeName } from "./core/nodeName.js";
16 import "./core/init.js";
17 import "./traversing.js";
18 import "./event.js";
20 var
22         // Support: IE <=10 - 11+
23         // In IE using regex groups here causes severe slowdowns.
24         rnoInnerhtml = /<script|<style|<link/i;
26 // Prefer a tbody over its parent table for containing new rows
27 function manipulationTarget( elem, content ) {
28         if ( nodeName( elem, "table" ) &&
29                 nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
31                 return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
32         }
34         return elem;
37 function cloneCopyEvent( src, dest ) {
38         var type, i, l,
39                 events = dataPriv.get( src, "events" );
41         if ( dest.nodeType !== 1 ) {
42                 return;
43         }
45         // 1. Copy private data: events, handlers, etc.
46         if ( events ) {
47                 dataPriv.remove( dest, "handle events" );
48                 for ( type in events ) {
49                         for ( i = 0, l = events[ type ].length; i < l; i++ ) {
50                                 jQuery.event.add( dest, type, events[ type ][ i ] );
51                         }
52                 }
53         }
55         // 2. Copy user data
56         if ( dataUser.hasData( src ) ) {
57                 dataUser.set( dest, jQuery.extend( {}, dataUser.get( src ) ) );
58         }
61 function remove( elem, selector, keepData ) {
62         var node,
63                 nodes = selector ? jQuery.filter( selector, elem ) : elem,
64                 i = 0;
66         for ( ; ( node = nodes[ i ] ) != null; i++ ) {
67                 if ( !keepData && node.nodeType === 1 ) {
68                         jQuery.cleanData( getAll( node ) );
69                 }
71                 if ( node.parentNode ) {
72                         if ( keepData && isAttached( node ) ) {
73                                 setGlobalEval( getAll( node, "script" ) );
74                         }
75                         node.parentNode.removeChild( node );
76                 }
77         }
79         return elem;
82 jQuery.extend( {
83         htmlPrefilter: function( html ) {
84                 return html;
85         },
87         clone: function( elem, dataAndEvents, deepDataAndEvents ) {
88                 var i, l, srcElements, destElements,
89                         clone = elem.cloneNode( true ),
90                         inPage = isAttached( elem );
92                 // Fix IE cloning issues
93                 if ( isIE && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
94                                 !jQuery.isXMLDoc( elem ) ) {
96                         // We eschew jQuery#find here for performance reasons:
97                         // https://jsperf.com/getall-vs-sizzle/2
98                         destElements = getAll( clone );
99                         srcElements = getAll( elem );
101                         for ( i = 0, l = srcElements.length; i < l; i++ ) {
103                                 // Support: IE <=11+
104                                 // IE fails to set the defaultValue to the correct value when
105                                 // cloning textareas.
106                                 if ( nodeName( destElements[ i ], "textarea" ) ) {
107                                         destElements[ i ].defaultValue = srcElements[ i ].defaultValue;
108                                 }
109                         }
110                 }
112                 // Copy the events from the original to the clone
113                 if ( dataAndEvents ) {
114                         if ( deepDataAndEvents ) {
115                                 srcElements = srcElements || getAll( elem );
116                                 destElements = destElements || getAll( clone );
118                                 for ( i = 0, l = srcElements.length; i < l; i++ ) {
119                                         cloneCopyEvent( srcElements[ i ], destElements[ i ] );
120                                 }
121                         } else {
122                                 cloneCopyEvent( elem, clone );
123                         }
124                 }
126                 // Preserve script evaluation history
127                 destElements = getAll( clone, "script" );
128                 if ( destElements.length > 0 ) {
129                         setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
130                 }
132                 // Return the cloned set
133                 return clone;
134         },
136         cleanData: function( elems ) {
137                 var data, elem, type,
138                         special = jQuery.event.special,
139                         i = 0;
141                 for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
142                         if ( acceptData( elem ) ) {
143                                 if ( ( data = elem[ dataPriv.expando ] ) ) {
144                                         if ( data.events ) {
145                                                 for ( type in data.events ) {
146                                                         if ( special[ type ] ) {
147                                                                 jQuery.event.remove( elem, type );
149                                                         // This is a shortcut to avoid jQuery.event.remove's overhead
150                                                         } else {
151                                                                 jQuery.removeEvent( elem, type, data.handle );
152                                                         }
153                                                 }
154                                         }
156                                         // Support: Chrome <=35 - 45+
157                                         // Assign undefined instead of using delete, see Data#remove
158                                         elem[ dataPriv.expando ] = undefined;
159                                 }
160                                 if ( elem[ dataUser.expando ] ) {
162                                         // Support: Chrome <=35 - 45+
163                                         // Assign undefined instead of using delete, see Data#remove
164                                         elem[ dataUser.expando ] = undefined;
165                                 }
166                         }
167                 }
168         }
169 } );
171 jQuery.fn.extend( {
172         detach: function( selector ) {
173                 return remove( this, selector, true );
174         },
176         remove: function( selector ) {
177                 return remove( this, selector );
178         },
180         text: function( value ) {
181                 return access( this, function( value ) {
182                         return value === undefined ?
183                                 jQuery.text( this ) :
184                                 this.empty().each( function() {
185                                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
186                                                 this.textContent = value;
187                                         }
188                                 } );
189                 }, null, value, arguments.length );
190         },
192         append: function() {
193                 return domManip( this, arguments, function( elem ) {
194                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
195                                 var target = manipulationTarget( this, elem );
196                                 target.appendChild( elem );
197                         }
198                 } );
199         },
201         prepend: function() {
202                 return domManip( this, arguments, function( elem ) {
203                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
204                                 var target = manipulationTarget( this, elem );
205                                 target.insertBefore( elem, target.firstChild );
206                         }
207                 } );
208         },
210         before: function() {
211                 return domManip( this, arguments, function( elem ) {
212                         if ( this.parentNode ) {
213                                 this.parentNode.insertBefore( elem, this );
214                         }
215                 } );
216         },
218         after: function() {
219                 return domManip( this, arguments, function( elem ) {
220                         if ( this.parentNode ) {
221                                 this.parentNode.insertBefore( elem, this.nextSibling );
222                         }
223                 } );
224         },
226         empty: function() {
227                 var elem,
228                         i = 0;
230                 for ( ; ( elem = this[ i ] ) != null; i++ ) {
231                         if ( elem.nodeType === 1 ) {
233                                 // Prevent memory leaks
234                                 jQuery.cleanData( getAll( elem, false ) );
236                                 // Remove any remaining nodes
237                                 elem.textContent = "";
238                         }
239                 }
241                 return this;
242         },
244         clone: function( dataAndEvents, deepDataAndEvents ) {
245                 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
246                 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
248                 return this.map( function() {
249                         return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
250                 } );
251         },
253         html: function( value ) {
254                 return access( this, function( value ) {
255                         var elem = this[ 0 ] || {},
256                                 i = 0,
257                                 l = this.length;
259                         if ( value === undefined && elem.nodeType === 1 ) {
260                                 return elem.innerHTML;
261                         }
263                         // See if we can take a shortcut and just use innerHTML
264                         if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
265                                 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
267                                 value = jQuery.htmlPrefilter( value );
269                                 try {
270                                         for ( ; i < l; i++ ) {
271                                                 elem = this[ i ] || {};
273                                                 // Remove element nodes and prevent memory leaks
274                                                 if ( elem.nodeType === 1 ) {
275                                                         jQuery.cleanData( getAll( elem, false ) );
276                                                         elem.innerHTML = value;
277                                                 }
278                                         }
280                                         elem = 0;
282                                 // If using innerHTML throws an exception, use the fallback method
283                                 } catch ( e ) {}
284                         }
286                         if ( elem ) {
287                                 this.empty().append( value );
288                         }
289                 }, null, value, arguments.length );
290         },
292         replaceWith: function() {
293                 var ignored = [];
295                 // Make the changes, replacing each non-ignored context element with the new content
296                 return domManip( this, arguments, function( elem ) {
297                         var parent = this.parentNode;
299                         if ( jQuery.inArray( this, ignored ) < 0 ) {
300                                 jQuery.cleanData( getAll( this ) );
301                                 if ( parent ) {
302                                         parent.replaceChild( elem, this );
303                                 }
304                         }
306                 // Force callback invocation
307                 }, ignored );
308         }
309 } );
311 jQuery.each( {
312         appendTo: "append",
313         prependTo: "prepend",
314         insertBefore: "before",
315         insertAfter: "after",
316         replaceAll: "replaceWith"
317 }, function( name, original ) {
318         jQuery.fn[ name ] = function( selector ) {
319                 var elems,
320                         ret = [],
321                         insert = jQuery( selector ),
322                         last = insert.length - 1,
323                         i = 0;
325                 for ( ; i <= last; i++ ) {
326                         elems = i === last ? this : this.clone( true );
327                         jQuery( insert[ i ] )[ original ]( elems );
328                         push.apply( ret, elems );
329                 }
331                 return this.pushStack( ret );
332         };
333 } );
335 export { jQuery, jQuery as $ };