UNPKG

12.7 kBJavaScriptView Raw
1define( [
2 "./core",
3 "./core/isAttached",
4 "./var/flat",
5 "./var/isFunction",
6 "./var/push",
7 "./var/rcheckableType",
8 "./core/access",
9 "./manipulation/var/rtagName",
10 "./manipulation/var/rscriptType",
11 "./manipulation/wrapMap",
12 "./manipulation/getAll",
13 "./manipulation/setGlobalEval",
14 "./manipulation/buildFragment",
15 "./manipulation/support",
16
17 "./data/var/dataPriv",
18 "./data/var/dataUser",
19 "./data/var/acceptData",
20 "./core/DOMEval",
21 "./core/nodeName",
22
23 "./core/init",
24 "./traversing",
25 "./selector",
26 "./event"
27], function( jQuery, isAttached, flat, isFunction, push, rcheckableType,
28 access, rtagName, rscriptType,
29 wrapMap, getAll, setGlobalEval, buildFragment, support,
30 dataPriv, dataUser, acceptData, DOMEval, nodeName ) {
31
32"use strict";
33
34var
35
36 // Support: IE <=10 - 11, Edge 12 - 13 only
37 // In IE/Edge using regex groups here causes severe slowdowns.
38 // See https://connect.microsoft.com/IE/feedback/details/1736512/
39 rnoInnerhtml = /<script|<style|<link/i,
40
41 // checked="checked" or checked
42 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
43
44 rcleanScript = /^\s*<!\[CDATA\[|\]\]>\s*$/g;
45
46// Prefer a tbody over its parent table for containing new rows
47function manipulationTarget( elem, content ) {
48 if ( nodeName( elem, "table" ) &&
49 nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
50
51 return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
52 }
53
54 return elem;
55}
56
57// Replace/restore the type attribute of script elements for safe DOM manipulation
58function disableScript( elem ) {
59 elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
60 return elem;
61}
62function restoreScript( elem ) {
63 if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
64 elem.type = elem.type.slice( 5 );
65 } else {
66 elem.removeAttribute( "type" );
67 }
68
69 return elem;
70}
71
72function cloneCopyEvent( src, dest ) {
73 var i, l, type, pdataOld, udataOld, udataCur, events;
74
75 if ( dest.nodeType !== 1 ) {
76 return;
77 }
78
79 // 1. Copy private data: events, handlers, etc.
80 if ( dataPriv.hasData( src ) ) {
81 pdataOld = dataPriv.get( src );
82 events = pdataOld.events;
83
84 if ( events ) {
85 dataPriv.remove( dest, "handle events" );
86
87 for ( type in events ) {
88 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
89 jQuery.event.add( dest, type, events[ type ][ i ] );
90 }
91 }
92 }
93 }
94
95 // 2. Copy user data
96 if ( dataUser.hasData( src ) ) {
97 udataOld = dataUser.access( src );
98 udataCur = jQuery.extend( {}, udataOld );
99
100 dataUser.set( dest, udataCur );
101 }
102}
103
104// Fix IE bugs, see support tests
105function fixInput( src, dest ) {
106 var nodeName = dest.nodeName.toLowerCase();
107
108 // Fails to persist the checked state of a cloned checkbox or radio button.
109 if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
110 dest.checked = src.checked;
111
112 // Fails to return the selected option to the default selected state when cloning options
113 } else if ( nodeName === "input" || nodeName === "textarea" ) {
114 dest.defaultValue = src.defaultValue;
115 }
116}
117
118function domManip( collection, args, callback, ignored ) {
119
120 // Flatten any nested arrays
121 args = flat( args );
122
123 var fragment, first, scripts, hasScripts, node, doc,
124 i = 0,
125 l = collection.length,
126 iNoClone = l - 1,
127 value = args[ 0 ],
128 valueIsFunction = isFunction( value );
129
130 // We can't cloneNode fragments that contain checked, in WebKit
131 if ( valueIsFunction ||
132 ( l > 1 && typeof value === "string" &&
133 !support.checkClone && rchecked.test( value ) ) ) {
134 return collection.each( function( index ) {
135 var self = collection.eq( index );
136 if ( valueIsFunction ) {
137 args[ 0 ] = value.call( this, index, self.html() );
138 }
139 domManip( self, args, callback, ignored );
140 } );
141 }
142
143 if ( l ) {
144 fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
145 first = fragment.firstChild;
146
147 if ( fragment.childNodes.length === 1 ) {
148 fragment = first;
149 }
150
151 // Require either new content or an interest in ignored elements to invoke the callback
152 if ( first || ignored ) {
153 scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
154 hasScripts = scripts.length;
155
156 // Use the original fragment for the last item
157 // instead of the first because it can end up
158 // being emptied incorrectly in certain situations (trac-8070).
159 for ( ; i < l; i++ ) {
160 node = fragment;
161
162 if ( i !== iNoClone ) {
163 node = jQuery.clone( node, true, true );
164
165 // Keep references to cloned scripts for later restoration
166 if ( hasScripts ) {
167
168 // Support: Android <=4.0 only, PhantomJS 1 only
169 // push.apply(_, arraylike) throws on ancient WebKit
170 jQuery.merge( scripts, getAll( node, "script" ) );
171 }
172 }
173
174 callback.call( collection[ i ], node, i );
175 }
176
177 if ( hasScripts ) {
178 doc = scripts[ scripts.length - 1 ].ownerDocument;
179
180 // Reenable scripts
181 jQuery.map( scripts, restoreScript );
182
183 // Evaluate executable scripts on first document insertion
184 for ( i = 0; i < hasScripts; i++ ) {
185 node = scripts[ i ];
186 if ( rscriptType.test( node.type || "" ) &&
187 !dataPriv.access( node, "globalEval" ) &&
188 jQuery.contains( doc, node ) ) {
189
190 if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
191
192 // Optional AJAX dependency, but won't run scripts if not present
193 if ( jQuery._evalUrl && !node.noModule ) {
194 jQuery._evalUrl( node.src, {
195 nonce: node.nonce || node.getAttribute( "nonce" )
196 }, doc );
197 }
198 } else {
199
200 // Unwrap a CDATA section containing script contents. This shouldn't be
201 // needed as in XML documents they're already not visible when
202 // inspecting element contents and in HTML documents they have no
203 // meaning but we're preserving that logic for backwards compatibility.
204 // This will be removed completely in 4.0. See gh-4904.
205 DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
206 }
207 }
208 }
209 }
210 }
211 }
212
213 return collection;
214}
215
216function remove( elem, selector, keepData ) {
217 var node,
218 nodes = selector ? jQuery.filter( selector, elem ) : elem,
219 i = 0;
220
221 for ( ; ( node = nodes[ i ] ) != null; i++ ) {
222 if ( !keepData && node.nodeType === 1 ) {
223 jQuery.cleanData( getAll( node ) );
224 }
225
226 if ( node.parentNode ) {
227 if ( keepData && isAttached( node ) ) {
228 setGlobalEval( getAll( node, "script" ) );
229 }
230 node.parentNode.removeChild( node );
231 }
232 }
233
234 return elem;
235}
236
237jQuery.extend( {
238 htmlPrefilter: function( html ) {
239 return html;
240 },
241
242 clone: function( elem, dataAndEvents, deepDataAndEvents ) {
243 var i, l, srcElements, destElements,
244 clone = elem.cloneNode( true ),
245 inPage = isAttached( elem );
246
247 // Fix IE cloning issues
248 if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
249 !jQuery.isXMLDoc( elem ) ) {
250
251 // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
252 destElements = getAll( clone );
253 srcElements = getAll( elem );
254
255 for ( i = 0, l = srcElements.length; i < l; i++ ) {
256 fixInput( srcElements[ i ], destElements[ i ] );
257 }
258 }
259
260 // Copy the events from the original to the clone
261 if ( dataAndEvents ) {
262 if ( deepDataAndEvents ) {
263 srcElements = srcElements || getAll( elem );
264 destElements = destElements || getAll( clone );
265
266 for ( i = 0, l = srcElements.length; i < l; i++ ) {
267 cloneCopyEvent( srcElements[ i ], destElements[ i ] );
268 }
269 } else {
270 cloneCopyEvent( elem, clone );
271 }
272 }
273
274 // Preserve script evaluation history
275 destElements = getAll( clone, "script" );
276 if ( destElements.length > 0 ) {
277 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
278 }
279
280 // Return the cloned set
281 return clone;
282 },
283
284 cleanData: function( elems ) {
285 var data, elem, type,
286 special = jQuery.event.special,
287 i = 0;
288
289 for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
290 if ( acceptData( elem ) ) {
291 if ( ( data = elem[ dataPriv.expando ] ) ) {
292 if ( data.events ) {
293 for ( type in data.events ) {
294 if ( special[ type ] ) {
295 jQuery.event.remove( elem, type );
296
297 // This is a shortcut to avoid jQuery.event.remove's overhead
298 } else {
299 jQuery.removeEvent( elem, type, data.handle );
300 }
301 }
302 }
303
304 // Support: Chrome <=35 - 45+
305 // Assign undefined instead of using delete, see Data#remove
306 elem[ dataPriv.expando ] = undefined;
307 }
308 if ( elem[ dataUser.expando ] ) {
309
310 // Support: Chrome <=35 - 45+
311 // Assign undefined instead of using delete, see Data#remove
312 elem[ dataUser.expando ] = undefined;
313 }
314 }
315 }
316 }
317} );
318
319jQuery.fn.extend( {
320 detach: function( selector ) {
321 return remove( this, selector, true );
322 },
323
324 remove: function( selector ) {
325 return remove( this, selector );
326 },
327
328 text: function( value ) {
329 return access( this, function( value ) {
330 return value === undefined ?
331 jQuery.text( this ) :
332 this.empty().each( function() {
333 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
334 this.textContent = value;
335 }
336 } );
337 }, null, value, arguments.length );
338 },
339
340 append: function() {
341 return domManip( this, arguments, function( elem ) {
342 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
343 var target = manipulationTarget( this, elem );
344 target.appendChild( elem );
345 }
346 } );
347 },
348
349 prepend: function() {
350 return domManip( this, arguments, function( elem ) {
351 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
352 var target = manipulationTarget( this, elem );
353 target.insertBefore( elem, target.firstChild );
354 }
355 } );
356 },
357
358 before: function() {
359 return domManip( this, arguments, function( elem ) {
360 if ( this.parentNode ) {
361 this.parentNode.insertBefore( elem, this );
362 }
363 } );
364 },
365
366 after: function() {
367 return domManip( this, arguments, function( elem ) {
368 if ( this.parentNode ) {
369 this.parentNode.insertBefore( elem, this.nextSibling );
370 }
371 } );
372 },
373
374 empty: function() {
375 var elem,
376 i = 0;
377
378 for ( ; ( elem = this[ i ] ) != null; i++ ) {
379 if ( elem.nodeType === 1 ) {
380
381 // Prevent memory leaks
382 jQuery.cleanData( getAll( elem, false ) );
383
384 // Remove any remaining nodes
385 elem.textContent = "";
386 }
387 }
388
389 return this;
390 },
391
392 clone: function( dataAndEvents, deepDataAndEvents ) {
393 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
394 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
395
396 return this.map( function() {
397 return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
398 } );
399 },
400
401 html: function( value ) {
402 return access( this, function( value ) {
403 var elem = this[ 0 ] || {},
404 i = 0,
405 l = this.length;
406
407 if ( value === undefined && elem.nodeType === 1 ) {
408 return elem.innerHTML;
409 }
410
411 // See if we can take a shortcut and just use innerHTML
412 if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
413 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
414
415 value = jQuery.htmlPrefilter( value );
416
417 try {
418 for ( ; i < l; i++ ) {
419 elem = this[ i ] || {};
420
421 // Remove element nodes and prevent memory leaks
422 if ( elem.nodeType === 1 ) {
423 jQuery.cleanData( getAll( elem, false ) );
424 elem.innerHTML = value;
425 }
426 }
427
428 elem = 0;
429
430 // If using innerHTML throws an exception, use the fallback method
431 } catch ( e ) {}
432 }
433
434 if ( elem ) {
435 this.empty().append( value );
436 }
437 }, null, value, arguments.length );
438 },
439
440 replaceWith: function() {
441 var ignored = [];
442
443 // Make the changes, replacing each non-ignored context element with the new content
444 return domManip( this, arguments, function( elem ) {
445 var parent = this.parentNode;
446
447 if ( jQuery.inArray( this, ignored ) < 0 ) {
448 jQuery.cleanData( getAll( this ) );
449 if ( parent ) {
450 parent.replaceChild( elem, this );
451 }
452 }
453
454 // Force callback invocation
455 }, ignored );
456 }
457} );
458
459jQuery.each( {
460 appendTo: "append",
461 prependTo: "prepend",
462 insertBefore: "before",
463 insertAfter: "after",
464 replaceAll: "replaceWith"
465}, function( name, original ) {
466 jQuery.fn[ name ] = function( selector ) {
467 var elems,
468 ret = [],
469 insert = jQuery( selector ),
470 last = insert.length - 1,
471 i = 0;
472
473 for ( ; i <= last; i++ ) {
474 elems = i === last ? this : this.clone( true );
475 jQuery( insert[ i ] )[ original ]( elems );
476
477 // Support: Android <=4.0 only, PhantomJS 1 only
478 // .get() because push.apply(_, arraylike) throws on ancient WebKit
479 push.apply( ret, elems.get() );
480 }
481
482 return this.pushStack( ret );
483 };
484} );
485
486return jQuery;
487} );