Skip to content

Commit 52718c6

Browse files
committed
refactor(drag-drop): expose more private apis as protected
Exposes more of the private drag&drop APIs as protected ones, in order to make it easier for people to implement their custom directives based on the CDK ones. Also moves out some of the private helper methods into functions. Fixes #14113.
1 parent 141afcf commit 52718c6

File tree

4 files changed

+76
-56
lines changed

4 files changed

+76
-56
lines changed

src/cdk/drag-drop/drag.ts

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
310310
rootElement.addEventListener('mousedown', this._pointerDown, activeEventListenerOptions);
311311
rootElement.addEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
312312
this._handles.changes.pipe(startWith(null)).subscribe(() =>
313-
toggleNativeDragInteractions(rootElement, this.getChildHandles().length > 0));
313+
toggleNativeDragInteractions(rootElement, this._getChildHandles().length > 0));
314314
});
315315
}
316316

@@ -327,7 +327,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
327327
if (this._isDragging()) {
328328
// Since we move out the element to the end of the body while it's being
329329
// dragged, we have to make sure that it's removed if it gets destroyed.
330-
this._removeElement(this._rootElement);
330+
removeElement(this._rootElement);
331331
}
332332
}
333333

@@ -346,13 +346,13 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
346346
}
347347

348348
/** Gets only handles that are not inside descendant `CdkDrag` instances. */
349-
private getChildHandles() {
349+
protected _getChildHandles() {
350350
return this._handles.filter(handle => handle._parentDrag === this);
351351
}
352352

353353
/** Handler for the `mousedown`/`touchstart` events. */
354354
_pointerDown = (event: MouseEvent | TouchEvent) => {
355-
const handles = this.getChildHandles();
355+
const handles = this._getChildHandles();
356356

357357
// Delegate the event based on whether it started from a handle or the element itself.
358358
if (handles.length) {
@@ -376,16 +376,16 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
376376
* @param referenceElement Element that started the drag sequence.
377377
* @param event Browser event object that started the sequence.
378378
*/
379-
private _initializeDragSequence(referenceElement: HTMLElement, event: MouseEvent | TouchEvent) {
379+
protected _initializeDragSequence(referenceElement: HTMLElement, event: MouseEvent | TouchEvent) {
380380
// Always stop propagation for the event that initializes
381381
// the dragging sequence, in order to prevent it from potentially
382382
// starting another sequence for a draggable parent somewhere up the DOM tree.
383383
event.stopPropagation();
384384

385385
const isDragging = this._isDragging();
386-
const isTouchEvent = this._isTouchEvent(event);
387-
const isAuxiliaryMouseButton = !isTouchEvent && (event as MouseEvent).button !== 0;
388-
const isSyntheticEvent = !isTouchEvent && this._lastTouchEventTime &&
386+
const wasTouchEvent = isTouchEvent(event);
387+
const isAuxiliaryMouseButton = !wasTouchEvent && (event as MouseEvent).button !== 0;
388+
const isSyntheticEvent = !wasTouchEvent && this._lastTouchEventTime &&
389389
this._lastTouchEventTime + MOUSE_EVENT_IGNORE_TIME > Date.now();
390390

391391
// If the event started from an element with the native HTML drag&drop, it'll interfere
@@ -426,11 +426,11 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
426426
}
427427

428428
/** Starts the dragging sequence. */
429-
private _startDragSequence(event: MouseEvent | TouchEvent) {
429+
protected _startDragSequence(event: MouseEvent | TouchEvent) {
430430
// Emit the event on the item before the one on the container.
431431
this.started.emit({source: this});
432432

433-
if (this._isTouchEvent(event)) {
433+
if (isTouchEvent(event)) {
434434
this._lastTouchEventTime = Date.now();
435435
}
436436

@@ -455,7 +455,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
455455
}
456456

457457
/** Handler that is invoked when the user moves their pointer after they've initiated a drag. */
458-
private _pointerMove = (event: MouseEvent | TouchEvent) => {
458+
protected _pointerMove = (event: MouseEvent | TouchEvent) => {
459459
const pointerPosition = this._getConstrainedPointerPosition(event);
460460

461461
if (!this._hasStartedDragging) {
@@ -515,7 +515,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
515515
}
516516

517517
/** Handler that is invoked when the user lifts their pointer up, after initiating a drag. */
518-
private _pointerUp = () => {
518+
protected _pointerUp = () => {
519519
if (!this._isDragging()) {
520520
return;
521521
}
@@ -678,7 +678,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
678678
const elementRect = this._rootElement.getBoundingClientRect();
679679
const handleElement = referenceElement === this._rootElement ? null : referenceElement;
680680
const referenceRect = handleElement ? handleElement.getBoundingClientRect() : elementRect;
681-
const point = this._isTouchEvent(event) ? event.targetTouches[0] : event;
681+
const point = isTouchEvent(event) ? event.targetTouches[0] : event;
682682
const x = point.pageX - referenceRect.left - this._scrollPosition.left;
683683
const y = point.pageY - referenceRect.top - this._scrollPosition.top;
684684

@@ -735,19 +735,9 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
735735
});
736736
}
737737

738-
/**
739-
* Helper to remove an element from the DOM and to do all the necessary null checks.
740-
* @param element Element to be removed.
741-
*/
742-
private _removeElement(element: HTMLElement | null) {
743-
if (element && element.parentNode) {
744-
element.parentNode.removeChild(element);
745-
}
746-
}
747-
748738
/** Determines the point of the page that was touched by the user. */
749739
private _getPointerPositionOnPage(event: MouseEvent | TouchEvent): Point {
750-
const point = this._isTouchEvent(event) ? event.touches[0] : event;
740+
const point = isTouchEvent(event) ? event.touches[0] : event;
751741

752742
return {
753743
x: point.pageX - this._scrollPosition.left,
@@ -769,15 +759,10 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
769759
return point;
770760
}
771761

772-
/** Determines whether an event is a touch event. */
773-
private _isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {
774-
return event.type.startsWith('touch');
775-
}
776-
777762
/** Destroys the preview element and its ViewRef. */
778763
private _destroyPreview() {
779764
if (this._preview) {
780-
this._removeElement(this._preview);
765+
removeElement(this._preview);
781766
}
782767

783768
if (this._previewRef) {
@@ -790,7 +775,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
790775
/** Destroys the placeholder element and its ViewRef. */
791776
private _destroyPlaceholder() {
792777
if (this._placeholder) {
793-
this._removeElement(this._placeholder);
778+
removeElement(this._placeholder);
794779
}
795780

796781
if (this._placeholderRef) {
@@ -828,7 +813,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
828813
}
829814

830815
/** Gets the root draggable element, based on the `rootElementSelector`. */
831-
private _getRootElement(): HTMLElement {
816+
protected _getRootElement(): HTMLElement {
832817
if (this.rootElementSelector) {
833818
const selector = this.rootElementSelector;
834819
let currentElement = this.element.nativeElement.parentElement as HTMLElement | null;
@@ -876,3 +861,18 @@ function deepCloneNode(node: HTMLElement): HTMLElement {
876861
clone.removeAttribute('id');
877862
return clone;
878863
}
864+
865+
/**
866+
* Helper to remove an element from the DOM and to do all the necessary null checks.
867+
* @param element Element to be removed.
868+
*/
869+
function removeElement(element: HTMLElement | null) {
870+
if (element && element.parentNode) {
871+
element.parentNode.removeChild(element);
872+
}
873+
}
874+
875+
/** Determines whether an event is a touch event. */
876+
function isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {
877+
return event.type.startsWith('touch');
878+
}

src/cdk/drag-drop/drop-list.ts

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,14 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
182182
_dragging = false;
183183

184184
/** Cache of the dimensions of all the items and the sibling containers. */
185-
private _positionCache: PositionCache = {items: [], siblings: [], self: {} as ClientRect};
185+
protected _positionCache: PositionCache = {items: [], siblings: [], self: {} as ClientRect};
186186

187187
/**
188188
* Draggable items that are currently active inside the container. Includes the items
189189
* from `_draggables`, as well as any items that have been dragged in, but haven't
190190
* been dropped yet.
191191
*/
192-
private _activeDraggables: CdkDrag[];
192+
protected _activeDraggables: CdkDrag[];
193193

194194
/**
195195
* Keeps track of the item that was last swapped with the dragged item, as
@@ -363,10 +363,10 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
363363
// elements may be mid-animation which will give us a wrong result.
364364
if (isHorizontal) {
365365
elementToOffset.style.transform = `translate3d(${sibling.offset}px, 0, 0)`;
366-
this._adjustClientRect(sibling.clientRect, 0, offset);
366+
adjustClientRect(sibling.clientRect, 0, offset);
367367
} else {
368368
elementToOffset.style.transform = `translate3d(0, ${sibling.offset}px, 0)`;
369-
this._adjustClientRect(sibling.clientRect, offset, 0);
369+
adjustClientRect(sibling.clientRect, offset, 0);
370370
}
371371
});
372372
}
@@ -438,7 +438,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
438438
}
439439

440440
/** Resets the container to its initial state. */
441-
private _reset() {
441+
protected _reset() {
442442
this._dragging = false;
443443

444444
// TODO(crisbeto): may have to wait for the animations to finish.
@@ -450,28 +450,14 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
450450
this._previousSwap.delta = 0;
451451
}
452452

453-
/**
454-
* Updates the top/left positions of a `ClientRect`, as well as their bottom/right counterparts.
455-
* @param clientRect `ClientRect` that should be updated.
456-
* @param top Amount to add to the `top` position.
457-
* @param left Amount to add to the `left` position.
458-
*/
459-
private _adjustClientRect(clientRect: ClientRect, top: number, left: number) {
460-
clientRect.top += top;
461-
clientRect.bottom = clientRect.top + clientRect.height;
462-
463-
clientRect.left += left;
464-
clientRect.right = clientRect.left + clientRect.width;
465-
}
466-
467453
/**
468454
* Gets the index of an item in the drop container, based on the position of the user's pointer.
469455
* @param item Item that is being sorted.
470456
* @param pointerX Position of the user's pointer along the X axis.
471457
* @param pointerY Position of the user's pointer along the Y axis.
472458
* @param delta Direction in which the user is moving their pointer.
473459
*/
474-
private _getItemIndexFromPointerPosition(item: CdkDrag, pointerX: number, pointerY: number,
460+
protected _getItemIndexFromPointerPosition(item: CdkDrag, pointerX: number, pointerY: number,
475461
delta?: {x: number, y: number}) {
476462

477463
const isHorizontal = this.orientation === 'horizontal';
@@ -506,7 +492,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
506492
* @param pointerX Coordinates along the X axis.
507493
* @param pointerY Coordinates along the Y axis.
508494
*/
509-
private _isPointerNearDropContainer(pointerX: number, pointerY: number): boolean {
495+
protected _isPointerNearDropContainer(pointerX: number, pointerY: number): boolean {
510496
const {top, right, bottom, left, width, height} = this._positionCache.self;
511497
const xThreshold = width * DROP_PROXIMITY_THRESHOLD;
512498
const yThreshold = height * DROP_PROXIMITY_THRESHOLD;
@@ -521,7 +507,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
521507
* @param newPosition Position of the item where the current item should be moved.
522508
* @param delta Direction in which the user is moving.
523509
*/
524-
private _getItemOffsetPx(currentPosition: ClientRect, newPosition: ClientRect, delta: 1 | -1) {
510+
protected _getItemOffsetPx(currentPosition: ClientRect, newPosition: ClientRect, delta: 1 | -1) {
525511
const isHorizontal = this.orientation === 'horizontal';
526512
let itemOffset = isHorizontal ? newPosition.left - currentPosition.left :
527513
newPosition.top - currentPosition.top;
@@ -541,7 +527,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
541527
* @param siblings All of the items in the list.
542528
* @param delta Direction in which the user is moving.
543529
*/
544-
private _getSiblingOffsetPx(currentIndex: number,
530+
protected _getSiblingOffsetPx(currentIndex: number,
545531
siblings: ItemPositionCacheEntry[],
546532
delta: 1 | -1) {
547533

@@ -569,7 +555,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
569555
}
570556

571557
/** Gets an array of unique drop lists that the current list is connected to. */
572-
private _getConnectedLists(): CdkDropList[] {
558+
protected _getConnectedLists(): CdkDropList[] {
573559
const siblings = coerceArray(this.connectedTo).map(drop => {
574560
return typeof drop === 'string' ? this._dragDropRegistry.getDropContainer(drop)! : drop;
575561
});
@@ -616,3 +602,17 @@ function isInsideClientRect(clientRect: ClientRect, x: number, y: number) {
616602
const {top, bottom, left, right} = clientRect;
617603
return y >= top && y <= bottom && x >= left && x <= right;
618604
}
605+
606+
/**
607+
* Updates the top/left positions of a `ClientRect`, as well as their bottom/right counterparts.
608+
* @param clientRect `ClientRect` that should be updated.
609+
* @param top Amount to add to the `top` position.
610+
* @param left Amount to add to the `left` position.
611+
*/
612+
function adjustClientRect(clientRect: ClientRect, top: number, left: number) {
613+
clientRect.top += top;
614+
clientRect.bottom = clientRect.top + clientRect.height;
615+
616+
clientRect.left += left;
617+
clientRect.right = clientRect.left + clientRect.width;
618+
}

src/cdk/drag-drop/public-api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ export * from './drag-preview';
1717
export * from './drag-placeholder';
1818
export * from './drag-drop-module';
1919
export * from './drag-drop-registry';
20+
export * from './drag-parent';

tools/public_api_guard/cdk/drag-drop.d.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ export declare const CDK_DRAG_CONFIG: InjectionToken<CdkDragConfig>;
22

33
export declare function CDK_DRAG_CONFIG_FACTORY(): CdkDragConfig;
44

5+
export declare const CDK_DRAG_PARENT: InjectionToken<{}>;
6+
57
export declare const CDK_DROP_LIST_CONTAINER: InjectionToken<CdkDropListContainer<any>>;
68

79
export declare class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
810
_handles: QueryList<CdkDragHandle>;
911
_hasStartedDragging: boolean;
1012
_placeholderTemplate: CdkDragPlaceholder;
1113
_pointerDown: (event: TouchEvent | MouseEvent) => void;
14+
protected _pointerMove: (event: TouchEvent | MouseEvent) => void;
15+
protected _pointerUp: () => void;
1216
_previewTemplate: CdkDragPreview;
1317
data: T;
1418
disabled: boolean;
@@ -25,7 +29,11 @@ export declare class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
2529
constructor(
2630
element: ElementRef<HTMLElement>,
2731
dropContainer: CdkDropListContainer, document: any, _ngZone: NgZone, _viewContainerRef: ViewContainerRef, _viewportRuler: ViewportRuler, _dragDropRegistry: DragDropRegistry<CdkDrag<T>, CdkDropListContainer>, _config: CdkDragConfig, _dir: Directionality);
32+
protected _getChildHandles(): CdkDragHandle[];
33+
protected _getRootElement(): HTMLElement;
34+
protected _initializeDragSequence(referenceElement: HTMLElement, event: MouseEvent | TouchEvent): void;
2835
_isDragging(): boolean;
36+
protected _startDragSequence(event: MouseEvent | TouchEvent): void;
2937
getPlaceholderElement(): HTMLElement;
3038
getRootElement(): HTMLElement;
3139
ngAfterViewInit(): void;
@@ -104,8 +112,10 @@ export interface CdkDragStart<T = any> {
104112
}
105113

106114
export declare class CdkDropList<T = any> implements OnInit, OnDestroy {
115+
protected _activeDraggables: CdkDrag[];
107116
_draggables: QueryList<CdkDrag>;
108117
_dragging: boolean;
118+
protected _positionCache: PositionCache;
109119
connectedTo: (CdkDropList | string)[] | CdkDropList | string;
110120
data: T;
111121
disabled: boolean;
@@ -120,7 +130,16 @@ export declare class CdkDropList<T = any> implements OnInit, OnDestroy {
120130
sorted: EventEmitter<CdkDragSortEvent<T>>;
121131
constructor(element: ElementRef<HTMLElement>, _dragDropRegistry: DragDropRegistry<CdkDrag, CdkDropList<T>>, _changeDetectorRef: ChangeDetectorRef, _dir?: Directionality | undefined, _group?: CdkDropListGroup<CdkDropList<any>> | undefined);
122132
_canReturnItem(x: number, y: number): boolean;
133+
protected _getConnectedLists(): CdkDropList[];
134+
protected _getItemIndexFromPointerPosition(item: CdkDrag, pointerX: number, pointerY: number, delta?: {
135+
x: number;
136+
y: number;
137+
}): number;
138+
protected _getItemOffsetPx(currentPosition: ClientRect, newPosition: ClientRect, delta: 1 | -1): number;
123139
_getSiblingContainerFromPosition(item: CdkDrag, x: number, y: number): CdkDropList | null;
140+
protected _getSiblingOffsetPx(currentIndex: number, siblings: ItemPositionCacheEntry[], delta: 1 | -1): number;
141+
protected _isPointerNearDropContainer(pointerX: number, pointerY: number): boolean;
142+
protected _reset(): void;
124143
_sortItem(item: CdkDrag, pointerX: number, pointerY: number, pointerDelta: {
125144
x: number;
126145
y: number;

0 commit comments

Comments
 (0)