manipulation.js 15 KB

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