manipulation.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
  2. rtagName = /<([\w:]+)/,
  3. rhtml = /<|&#?\w+;/,
  4. rnoInnerhtml = /<(?:script|style|link)/i,
  5. manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
  6. // checked="checked" or checked
  7. rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
  8. rscriptType = /^$|\/(?:java|ecma)script/i,
  9. rscriptTypeMasked = /^true\/(.*)/,
  10. rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
  11. // We have to close these tags to support XHTML (#13200)
  12. wrapMap = {
  13. // Support: IE 9
  14. option: [ 1, "<select multiple='multiple'>", "</select>" ],
  15. thead: [ 1, "<table>", "</table>" ],
  16. col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
  17. tr: [ 2, "<table><tbody>", "</tbody></table>" ],
  18. td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
  19. _default: [ 0, "", "" ]
  20. };
  21. // Support: IE 9
  22. wrapMap.optgroup = wrapMap.option;
  23. wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
  24. wrapMap.th = wrapMap.td;
  25. jQuery.fn.extend({
  26. text: function( value ) {
  27. return jQuery.access( this, function( value ) {
  28. return value === undefined ?
  29. jQuery.text( this ) :
  30. this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) );
  31. }, null, value, arguments.length );
  32. },
  33. append: function() {
  34. return this.domManip( arguments, function( elem ) {
  35. if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
  36. var target = manipulationTarget( this, elem );
  37. target.appendChild( elem );
  38. }
  39. });
  40. },
  41. prepend: function() {
  42. return this.domManip( arguments, function( elem ) {
  43. if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
  44. var target = manipulationTarget( this, elem );
  45. target.insertBefore( elem, target.firstChild );
  46. }
  47. });
  48. },
  49. before: function() {
  50. return this.domManip( arguments, function( elem ) {
  51. if ( this.parentNode ) {
  52. this.parentNode.insertBefore( elem, this );
  53. }
  54. });
  55. },
  56. after: function() {
  57. return this.domManip( arguments, function( elem ) {
  58. if ( this.parentNode ) {
  59. this.parentNode.insertBefore( elem, this.nextSibling );
  60. }
  61. });
  62. },
  63. // keepData is for internal use only--do not document
  64. remove: function( selector, keepData ) {
  65. var elem,
  66. elems = selector ? jQuery.filter( selector, this ) : this,
  67. i = 0;
  68. for ( ; (elem = elems[i]) != null; i++ ) {
  69. if ( !keepData && elem.nodeType === 1 ) {
  70. jQuery.cleanData( getAll( elem ) );
  71. }
  72. if ( elem.parentNode ) {
  73. if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
  74. setGlobalEval( getAll( elem, "script" ) );
  75. }
  76. elem.parentNode.removeChild( elem );
  77. }
  78. }
  79. return this;
  80. },
  81. empty: function() {
  82. var elem,
  83. i = 0;
  84. for ( ; (elem = this[i]) != null; i++ ) {
  85. if ( elem.nodeType === 1 ) {
  86. // Prevent memory leaks
  87. jQuery.cleanData( getAll( elem, false ) );
  88. // Remove any remaining nodes
  89. elem.textContent = "";
  90. }
  91. }
  92. return this;
  93. },
  94. clone: function( dataAndEvents, deepDataAndEvents ) {
  95. dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
  96. deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
  97. return this.map( function () {
  98. return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
  99. });
  100. },
  101. html: function( value ) {
  102. return jQuery.access( this, function( value ) {
  103. var elem = this[ 0 ] || {},
  104. i = 0,
  105. l = this.length;
  106. if ( value === undefined && elem.nodeType === 1 ) {
  107. return elem.innerHTML;
  108. }
  109. // See if we can take a shortcut and just use innerHTML
  110. if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
  111. !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
  112. value = value.replace( rxhtmlTag, "<$1></$2>" );
  113. try {
  114. for ( ; i < l; i++ ) {
  115. elem = this[ i ] || {};
  116. // Remove element nodes and prevent memory leaks
  117. if ( elem.nodeType === 1 ) {
  118. jQuery.cleanData( getAll( elem, false ) );
  119. elem.innerHTML = value;
  120. }
  121. }
  122. elem = 0;
  123. // If using innerHTML throws an exception, use the fallback method
  124. } catch( e ) {}
  125. }
  126. if ( elem ) {
  127. this.empty().append( value );
  128. }
  129. }, null, value, arguments.length );
  130. },
  131. replaceWith: function() {
  132. var
  133. // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
  134. args = jQuery.map( this, function( elem ) {
  135. return [ elem.nextSibling, elem.parentNode ];
  136. }),
  137. i = 0;
  138. // Make the changes, replacing each context element with the new content
  139. this.domManip( arguments, function( elem ) {
  140. var next = args[ i++ ],
  141. parent = args[ i++ ];
  142. if ( parent ) {
  143. // Don't use the snapshot next if it has moved (#13810)
  144. if ( next && next.parentNode !== parent ) {
  145. next = this.nextSibling;
  146. }
  147. jQuery( this ).remove();
  148. parent.insertBefore( elem, next );
  149. }
  150. // Allow new content to include elements from the context set
  151. }, true );
  152. // Force removal if there was no new content (e.g., from empty arguments)
  153. return i ? this : this.remove();
  154. },
  155. detach: function( selector ) {
  156. return this.remove( selector, true );
  157. },
  158. domManip: function( args, callback, allowIntersection ) {
  159. // Flatten any nested arrays
  160. args = core_concat.apply( [], args );
  161. var fragment, first, scripts, hasScripts, node, doc,
  162. i = 0,
  163. l = this.length,
  164. set = this,
  165. iNoClone = l - 1,
  166. value = args[ 0 ],
  167. isFunction = jQuery.isFunction( value );
  168. // We can't cloneNode fragments that contain checked, in WebKit
  169. if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
  170. return this.each(function( index ) {
  171. var self = set.eq( index );
  172. if ( isFunction ) {
  173. args[ 0 ] = value.call( this, index, self.html() );
  174. }
  175. self.domManip( args, callback, allowIntersection );
  176. });
  177. }
  178. if ( l ) {
  179. fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
  180. first = fragment.firstChild;
  181. if ( fragment.childNodes.length === 1 ) {
  182. fragment = first;
  183. }
  184. if ( first ) {
  185. scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
  186. hasScripts = scripts.length;
  187. // Use the original fragment for the last item instead of the first because it can end up
  188. // being emptied incorrectly in certain situations (#8070).
  189. for ( ; i < l; i++ ) {
  190. node = fragment;
  191. if ( i !== iNoClone ) {
  192. node = jQuery.clone( node, true, true );
  193. // Keep references to cloned scripts for later restoration
  194. if ( hasScripts ) {
  195. // Support: QtWebKit
  196. // jQuery.merge because core_push.apply(_, arraylike) throws
  197. jQuery.merge( scripts, getAll( node, "script" ) );
  198. }
  199. }
  200. callback.call( this[ i ], node, i );
  201. }
  202. if ( hasScripts ) {
  203. doc = scripts[ scripts.length - 1 ].ownerDocument;
  204. // Reenable scripts
  205. jQuery.map( scripts, restoreScript );
  206. // Evaluate executable scripts on first document insertion
  207. for ( i = 0; i < hasScripts; i++ ) {
  208. node = scripts[ i ];
  209. if ( rscriptType.test( node.type || "" ) &&
  210. !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
  211. if ( node.src ) {
  212. // Hope ajax is available...
  213. jQuery._evalUrl( node.src );
  214. } else {
  215. jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
  216. }
  217. }
  218. }
  219. }
  220. }
  221. }
  222. return this;
  223. }
  224. });
  225. jQuery.each({
  226. appendTo: "append",
  227. prependTo: "prepend",
  228. insertBefore: "before",
  229. insertAfter: "after",
  230. replaceAll: "replaceWith"
  231. }, function( name, original ) {
  232. jQuery.fn[ name ] = function( selector ) {
  233. var elems,
  234. ret = [],
  235. insert = jQuery( selector ),
  236. last = insert.length - 1,
  237. i = 0;
  238. for ( ; i <= last; i++ ) {
  239. elems = i === last ? this : this.clone( true );
  240. jQuery( insert[ i ] )[ original ]( elems );
  241. // Support: QtWebKit
  242. // .get() because core_push.apply(_, arraylike) throws
  243. core_push.apply( ret, elems.get() );
  244. }
  245. return this.pushStack( ret );
  246. };
  247. });
  248. jQuery.extend({
  249. clone: function( elem, dataAndEvents, deepDataAndEvents ) {
  250. var i, l, srcElements, destElements,
  251. clone = elem.cloneNode( true ),
  252. inPage = jQuery.contains( elem.ownerDocument, elem );
  253. // Support: IE >= 9
  254. // Fix Cloning issues
  255. if ( !jQuery.support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) {
  256. // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
  257. destElements = getAll( clone );
  258. srcElements = getAll( elem );
  259. for ( i = 0, l = srcElements.length; i < l; i++ ) {
  260. fixInput( srcElements[ i ], destElements[ i ] );
  261. }
  262. }
  263. // Copy the events from the original to the clone
  264. if ( dataAndEvents ) {
  265. if ( deepDataAndEvents ) {
  266. srcElements = srcElements || getAll( elem );
  267. destElements = destElements || getAll( clone );
  268. for ( i = 0, l = srcElements.length; i < l; i++ ) {
  269. cloneCopyEvent( srcElements[ i ], destElements[ i ] );
  270. }
  271. } else {
  272. cloneCopyEvent( elem, clone );
  273. }
  274. }
  275. // Preserve script evaluation history
  276. destElements = getAll( clone, "script" );
  277. if ( destElements.length > 0 ) {
  278. setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
  279. }
  280. // Return the cloned set
  281. return clone;
  282. },
  283. buildFragment: function( elems, context, scripts, selection ) {
  284. var elem, tmp, tag, wrap, contains, j,
  285. i = 0,
  286. l = elems.length,
  287. fragment = context.createDocumentFragment(),
  288. nodes = [];
  289. for ( ; i < l; i++ ) {
  290. elem = elems[ i ];
  291. if ( elem || elem === 0 ) {
  292. // Add nodes directly
  293. if ( jQuery.type( elem ) === "object" ) {
  294. // Support: QtWebKit
  295. // jQuery.merge because core_push.apply(_, arraylike) throws
  296. jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
  297. // Convert non-html into a text node
  298. } else if ( !rhtml.test( elem ) ) {
  299. nodes.push( context.createTextNode( elem ) );
  300. // Convert html into DOM nodes
  301. } else {
  302. tmp = tmp || fragment.appendChild( context.createElement("div") );
  303. // Deserialize a standard representation
  304. tag = ( rtagName.exec( elem ) || ["", ""] )[ 1 ].toLowerCase();
  305. wrap = wrapMap[ tag ] || wrapMap._default;
  306. tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
  307. // Descend through wrappers to the right content
  308. j = wrap[ 0 ];
  309. while ( j-- ) {
  310. tmp = tmp.lastChild;
  311. }
  312. // Support: QtWebKit
  313. // jQuery.merge because core_push.apply(_, arraylike) throws
  314. jQuery.merge( nodes, tmp.childNodes );
  315. // Remember the top-level container
  316. tmp = fragment.firstChild;
  317. // Fixes #12346
  318. // Support: Webkit, IE
  319. tmp.textContent = "";
  320. }
  321. }
  322. }
  323. // Remove wrapper from fragment
  324. fragment.textContent = "";
  325. i = 0;
  326. while ( (elem = nodes[ i++ ]) ) {
  327. // #4087 - If origin and destination elements are the same, and this is
  328. // that element, do not do anything
  329. if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
  330. continue;
  331. }
  332. contains = jQuery.contains( elem.ownerDocument, elem );
  333. // Append to fragment
  334. tmp = getAll( fragment.appendChild( elem ), "script" );
  335. // Preserve script evaluation history
  336. if ( contains ) {
  337. setGlobalEval( tmp );
  338. }
  339. // Capture executables
  340. if ( scripts ) {
  341. j = 0;
  342. while ( (elem = tmp[ j++ ]) ) {
  343. if ( rscriptType.test( elem.type || "" ) ) {
  344. scripts.push( elem );
  345. }
  346. }
  347. }
  348. }
  349. return fragment;
  350. },
  351. cleanData: function( elems ) {
  352. var data, elem, events, type, key, j,
  353. special = jQuery.event.special,
  354. i = 0;
  355. for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
  356. if ( Data.accepts( elem ) ) {
  357. key = elem[ data_priv.expando ];
  358. if ( key && (data = data_priv.cache[ key ]) ) {
  359. events = Object.keys( data.events || {} );
  360. if ( events.length ) {
  361. for ( j = 0; (type = events[j]) !== undefined; j++ ) {
  362. if ( special[ type ] ) {
  363. jQuery.event.remove( elem, type );
  364. // This is a shortcut to avoid jQuery.event.remove's overhead
  365. } else {
  366. jQuery.removeEvent( elem, type, data.handle );
  367. }
  368. }
  369. }
  370. if ( data_priv.cache[ key ] ) {
  371. // Discard any remaining `private` data
  372. delete data_priv.cache[ key ];
  373. }
  374. }
  375. }
  376. // Discard any remaining `user` data
  377. delete data_user.cache[ elem[ data_user.expando ] ];
  378. }
  379. },
  380. _evalUrl: function( url ) {
  381. return jQuery.ajax({
  382. url: url,
  383. type: "GET",
  384. dataType: "script",
  385. async: false,
  386. global: false,
  387. "throws": true
  388. });
  389. }
  390. });
  391. // Support: 1.x compatibility
  392. // Manipulating tables requires a tbody
  393. function manipulationTarget( elem, content ) {
  394. return jQuery.nodeName( elem, "table" ) &&
  395. jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
  396. elem.getElementsByTagName("tbody")[0] ||
  397. elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
  398. elem;
  399. }
  400. // Replace/restore the type attribute of script elements for safe DOM manipulation
  401. function disableScript( elem ) {
  402. elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
  403. return elem;
  404. }
  405. function restoreScript( elem ) {
  406. var match = rscriptTypeMasked.exec( elem.type );
  407. if ( match ) {
  408. elem.type = match[ 1 ];
  409. } else {
  410. elem.removeAttribute("type");
  411. }
  412. return elem;
  413. }
  414. // Mark scripts as having already been evaluated
  415. function setGlobalEval( elems, refElements ) {
  416. var l = elems.length,
  417. i = 0;
  418. for ( ; i < l; i++ ) {
  419. data_priv.set(
  420. elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
  421. );
  422. }
  423. }
  424. function cloneCopyEvent( src, dest ) {
  425. var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
  426. if ( dest.nodeType !== 1 ) {
  427. return;
  428. }
  429. // 1. Copy private data: events, handlers, etc.
  430. if ( data_priv.hasData( src ) ) {
  431. pdataOld = data_priv.access( src );
  432. pdataCur = data_priv.set( dest, pdataOld );
  433. events = pdataOld.events;
  434. if ( events ) {
  435. delete pdataCur.handle;
  436. pdataCur.events = {};
  437. for ( type in events ) {
  438. for ( i = 0, l = events[ type ].length; i < l; i++ ) {
  439. jQuery.event.add( dest, type, events[ type ][ i ] );
  440. }
  441. }
  442. }
  443. }
  444. // 2. Copy user data
  445. if ( data_user.hasData( src ) ) {
  446. udataOld = data_user.access( src );
  447. udataCur = jQuery.extend( {}, udataOld );
  448. data_user.set( dest, udataCur );
  449. }
  450. }
  451. function getAll( context, tag ) {
  452. var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
  453. context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
  454. [];
  455. return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
  456. jQuery.merge( [ context ], ret ) :
  457. ret;
  458. }
  459. // Support: IE >= 9
  460. function fixInput( src, dest ) {
  461. var nodeName = dest.nodeName.toLowerCase();
  462. // Fails to persist the checked state of a cloned checkbox or radio button.
  463. if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
  464. dest.checked = src.checked;
  465. // Fails to return the selected option to the default selected state when cloning options
  466. } else if ( nodeName === "input" || nodeName === "textarea" ) {
  467. dest.defaultValue = src.defaultValue;
  468. }
  469. }