@@ -24,6 +24,7 @@ import {CdkDrag} from './drag';
24
24
import { CdkDragExit , CdkDragEnter , CdkDragDrop } from './drag-events' ;
25
25
import { CDK_DROP_CONTAINER } from './drop-container' ;
26
26
import { DragDropRegistry } from './drag-drop-registry' ;
27
+ import { moveItemInArray } from './drag-utils' ;
27
28
28
29
/** Counter used to generate unique ids for drop zones. */
29
30
let _uniqueIdCounter = 0 ;
@@ -214,45 +215,59 @@ export class CdkDrop<T = any> implements OnInit, OnDestroy {
214
215
*/
215
216
_sortItem ( item : CdkDrag , xOffset : number , yOffset : number ) : void {
216
217
const siblings = this . _positionCache . items ;
217
- const isHorizontal = this . orientation === 'horizontal' ;
218
218
const newIndex = this . _getItemIndexFromPointerPosition ( item , xOffset , yOffset ) ;
219
- const placeholder = item . getPlaceholderElement ( ) ;
220
219
221
220
if ( newIndex === - 1 && siblings . length > 0 ) {
222
221
return ;
223
222
}
224
223
224
+ const isHorizontal = this . orientation === 'horizontal' ;
225
225
const currentIndex = siblings . findIndex ( currentItem => currentItem . drag === item ) ;
226
- const currentPosition = siblings [ currentIndex ] ;
227
- const newPosition = siblings [ newIndex ] ;
228
-
229
- // Figure out the offset necessary for the items to be swapped.
230
- const offset = isHorizontal ?
231
- currentPosition . clientRect . left - newPosition . clientRect . left :
232
- currentPosition . clientRect . top - newPosition . clientRect . top ;
233
- const topAdjustment = isHorizontal ? 0 : offset ;
234
- const leftAdjustment = isHorizontal ? offset : 0 ;
235
-
236
- // Since we've moved the items with a `transform`, we need to adjust their cached
237
- // client rects to reflect their new position, as well as swap their positions in the cache.
238
- // Note that we shouldn't use `getBoundingClientRect` here to update the cache, because the
239
- // elements may be mid-animation which will give us a wrong result.
240
- this . _adjustClientRect ( currentPosition . clientRect , - topAdjustment , - leftAdjustment ) ;
241
- currentPosition . offset -= offset ;
242
- siblings [ currentIndex ] = newPosition ;
243
-
244
- this . _adjustClientRect ( newPosition . clientRect , topAdjustment , leftAdjustment ) ;
245
- newPosition . offset += offset ;
246
- siblings [ newIndex ] = currentPosition ;
247
-
248
- // Swap the placeholder's position with the one of the target draggable.
249
- placeholder . style . transform = isHorizontal ?
250
- `translate3d(${ currentPosition . offset } px, 0, 0)` :
251
- `translate3d(0, ${ currentPosition . offset } px, 0)` ;
252
-
253
- newPosition . drag . element . nativeElement . style . transform = isHorizontal ?
254
- `translate3d(${ newPosition . offset } px, 0, 0)` :
255
- `translate3d(0, ${ newPosition . offset } px, 0)` ;
226
+ const currentPosition = siblings [ currentIndex ] . clientRect ;
227
+ const newPosition = siblings [ newIndex ] . clientRect ;
228
+ const delta = currentIndex > newIndex ? 1 : - 1 ;
229
+
230
+ // How many pixels the item's placeholder should be offset.
231
+ const itemOffset = isHorizontal ? newPosition . left - currentPosition . left :
232
+ newPosition . top - currentPosition . top ;
233
+
234
+ // How many pixels all the other items should be offset.
235
+ const siblingOffset = isHorizontal ? currentPosition . width * delta :
236
+ currentPosition . height * delta ;
237
+
238
+ // Save the previous order of the items before moving the item to its new index.
239
+ // We use this to check whether an item has been moved as a result of the sorting.
240
+ const oldOrder = siblings . slice ( ) ;
241
+
242
+ // Shuffle the array in place.
243
+ moveItemInArray ( siblings , currentIndex , newIndex ) ;
244
+
245
+ siblings . forEach ( ( sibling , index ) => {
246
+ // Don't do anything if the position hasn't changed.
247
+ if ( oldOrder [ index ] === sibling ) {
248
+ return ;
249
+ }
250
+
251
+ const isDraggedItem = sibling . drag === item ;
252
+ const offset = isDraggedItem ? itemOffset : siblingOffset ;
253
+ const elementToOffset = isDraggedItem ? item . getPlaceholderElement ( ) :
254
+ sibling . drag . element . nativeElement ;
255
+
256
+ // Update the offset to reflect the new position.
257
+ sibling . offset += offset ;
258
+
259
+ // Since we're moving the items with a `transform`, we need to adjust their cached
260
+ // client rects to reflect their new position, as well as swap their positions in the cache.
261
+ // Note that we shouldn't use `getBoundingClientRect` here to update the cache, because the
262
+ // elements may be mid-animation which will give us a wrong result.
263
+ if ( isHorizontal ) {
264
+ elementToOffset . style . transform = `translate3d(${ sibling . offset } px, 0, 0)` ;
265
+ this . _adjustClientRect ( sibling . clientRect , 0 , offset ) ;
266
+ } else {
267
+ elementToOffset . style . transform = `translate3d(0, ${ sibling . offset } px, 0)` ;
268
+ this . _adjustClientRect ( sibling . clientRect , offset , 0 ) ;
269
+ }
270
+ } ) ;
256
271
}
257
272
258
273
/**
@@ -321,8 +336,8 @@ export class CdkDrop<T = any> implements OnInit, OnDestroy {
321
336
/**
322
337
* Updates the top/left positions of a `ClientRect`, as well as their bottom/right counterparts.
323
338
* @param clientRect `ClientRect` that should be updated.
324
- * @param top New value for the `top` position.
325
- * @param left New value for the `left` position.
339
+ * @param top Amount to add to the `top` position.
340
+ * @param left Amount to add to the `left` position.
326
341
*/
327
342
private _adjustClientRect ( clientRect : ClientRect , top : number , left : number ) {
328
343
clientRect . top += top ;
0 commit comments