@@ -2207,7 +2207,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
2207
2207
// it was cloned therefore we have to clone as well.
2208
2208
linkNode = jqLiteClone ( compileNode ) ;
2209
2209
}
2210
- replaceWith ( linkRootElement , jqLite ( beforeTemplateLinkNode ) , linkNode ) ;
2210
+ replaceWith ( linkRootElement , [ beforeTemplateLinkNode ] , linkNode ) ;
2211
2211
2212
2212
// Copy in CSS classes from original node
2213
2213
safeAddClass ( jqLite ( linkNode ) , oldClasses ) ;
@@ -2389,60 +2389,56 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
2389
2389
*
2390
2390
* @param {JqLite= } $rootElement The root of the compile tree. Used so that we can replace nodes
2391
2391
* in the root of the tree.
2392
- * @param {JqLite } elementsToRemove The jqLite element which we are going to replace. We keep
2393
- * the shell, but replace its DOM node reference.
2392
+ * @param {JqLite|Array } elementsToRemove The elements which we are going to replace. We keep
2393
+ * the shell, but replace its DOM node reference.
2394
2394
* @param {Node } newNode The new DOM node.
2395
2395
*/
2396
2396
function replaceWith ( $rootElement , elementsToRemove , newNode ) {
2397
2397
var firstElementToRemove = elementsToRemove [ 0 ] ,
2398
2398
removeCount = elementsToRemove . length ,
2399
2399
parent = firstElementToRemove . parentNode ,
2400
- i , ii ;
2401
-
2402
- if ( $rootElement ) {
2403
- for ( i = 0 , ii = $rootElement . length ; i < ii ; i ++ ) {
2404
- if ( $rootElement [ i ] == firstElementToRemove ) {
2405
- $rootElement [ i ++ ] = newNode ;
2406
- for ( var j = i , j2 = j + removeCount - 1 ,
2407
- jj = $rootElement . length ;
2408
- j < jj ; j ++ , j2 ++ ) {
2409
- if ( j2 < jj ) {
2410
- $rootElement [ j ] = $rootElement [ j2 ] ;
2411
- } else {
2412
- delete $rootElement [ j ] ;
2413
- }
2414
- }
2415
- $rootElement . length -= removeCount - 1 ;
2400
+ i ;
2416
2401
2417
- // If the replaced element is also the jQuery .context then replace it
2418
- // .context is a deprecated jQuery api, so we should set it only when jQuery set it
2419
- // http://api.jquery.com/context/
2420
- if ( $rootElement . context === firstElementToRemove ) {
2421
- $rootElement . context = newNode ;
2422
- }
2423
- break ;
2424
- }
2402
+ if ( $rootElement && ( i = indexOf . call ( $rootElement , firstElementToRemove ) ) !== - 1 ) {
2403
+ $rootElement . splice ( i , removeCount , newNode ) ;
2404
+
2405
+ // If the replaced element is also the jQuery .context then replace it
2406
+ // .context is a deprecated jQuery api, so we should set it only when jQuery set it
2407
+ // http://api.jquery.com/context/
2408
+ if ( $rootElement . context === firstElementToRemove ) {
2409
+ $rootElement . context = newNode ;
2425
2410
}
2426
2411
}
2427
2412
2413
+ // Add new node to the parent in place of the firstElementToRemove
2428
2414
if ( parent ) {
2429
2415
parent . replaceChild ( newNode , firstElementToRemove ) ;
2430
2416
}
2431
2417
2432
- // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
2433
- var fragment = document . createDocumentFragment ( ) ;
2434
- fragment . appendChild ( firstElementToRemove ) ;
2418
+ // If multiple elements are being replaced they will be placed into a temporary fragment
2419
+ // so they can still be traversed via .nextSibling or .parent.children while detached.
2420
+ // This also detaches the elementsToRemove if they have a parent.
2421
+ if ( removeCount > 1 ) {
2422
+ var fragment = document . createDocumentFragment ( ) ;
2423
+ for ( i = 0 ; i < removeCount ; i ++ ) {
2424
+ fragment . appendChild ( elementsToRemove [ i ] ) ;
2425
+ }
2426
+ }
2435
2427
2436
2428
// Copy over user data (that includes Angular's $scope etc.). Don't copy private
2437
2429
// data here because there's no public interface in jQuery to do that and copying over
2438
2430
// event listeners (which is the main use of private data) wouldn't work anyway.
2439
- jqLite ( newNode ) . data ( jqLite ( firstElementToRemove ) . data ( ) ) ;
2431
+ if ( jqLite . hasData ( firstElementToRemove ) ) {
2432
+ jqLite . data ( newNode , jqLite . data ( firstElementToRemove ) ) ;
2433
+ }
2440
2434
2441
2435
// Remove data of the replaced element. We cannot just call .remove()
2442
2436
// on the element it since that would deallocate scope that is needed
2443
2437
// for the new node. Instead, remove the data "manually".
2444
2438
if ( ! jQuery ) {
2445
- delete jqLite . cache [ firstElementToRemove [ jqLite . expando ] ] ;
2439
+ for ( i = 0 ; i < removeCount ; i ++ ) {
2440
+ delete jqLite . cache [ elementsToRemove [ i ] [ jqLite . expando ] ] ;
2441
+ }
2446
2442
} else {
2447
2443
// jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
2448
2444
// the replaced element. The cleanData version monkey-patched by Angular would cause
@@ -2452,18 +2448,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
2452
2448
// example is jQuery UI). Instead, set a flag indicating scope destroying should be
2453
2449
// skipped this one time.
2454
2450
skipDestroyOnNextJQueryCleanData = true ;
2455
- jQuery . cleanData ( [ firstElementToRemove ] ) ;
2456
- }
2457
-
2458
- for ( var k = 1 , kk = elementsToRemove . length ; k < kk ; k ++ ) {
2459
- var element = elementsToRemove [ k ] ;
2460
- jqLite ( element ) . remove ( ) ; // must do this way to clean up expando
2461
- fragment . appendChild ( element ) ;
2462
- delete elementsToRemove [ k ] ;
2451
+ jQuery . cleanData ( elementsToRemove ) ;
2463
2452
}
2464
2453
2465
- elementsToRemove [ 0 ] = newNode ;
2466
- elementsToRemove . length = 1 ;
2454
+ //Modify elementsToRemove jqLite/Array replacing all content with the newnode
2455
+ elementsToRemove . splice ( 0 , removeCount , newNode ) ;
2467
2456
}
2468
2457
2469
2458
0 commit comments