Skip to content

Commit bd2405c

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 3982e9e commit bd2405c

File tree

4 files changed

+76
-56
lines changed

4 files changed

+76
-56
lines changed

src/cdk/drag-drop/drag.ts

+32-32
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 = (event: MouseEvent | TouchEvent) => {
518+
protected _pointerUp = (event: MouseEvent | TouchEvent) => {
519519
if (!this._isDragging()) {
520520
return;
521521
}
@@ -681,7 +681,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
681681
const elementRect = this._rootElement.getBoundingClientRect();
682682
const handleElement = referenceElement === this._rootElement ? null : referenceElement;
683683
const referenceRect = handleElement ? handleElement.getBoundingClientRect() : elementRect;
684-
const point = this._isTouchEvent(event) ? event.targetTouches[0] : event;
684+
const point = isTouchEvent(event) ? event.targetTouches[0] : event;
685685
const x = point.pageX - referenceRect.left - this._scrollPosition.left;
686686
const y = point.pageY - referenceRect.top - this._scrollPosition.top;
687687

@@ -738,19 +738,9 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
738738
});
739739
}
740740

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

755745
return {
756746
x: point.pageX - this._scrollPosition.left,
@@ -772,15 +762,10 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
772762
return point;
773763
}
774764

775-
/** Determines whether an event is a touch event. */
776-
private _isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {
777-
return event.type.startsWith('touch');
778-
}
779-
780765
/** Destroys the preview element and its ViewRef. */
781766
private _destroyPreview() {
782767
if (this._preview) {
783-
this._removeElement(this._preview);
768+
removeElement(this._preview);
784769
}
785770

786771
if (this._previewRef) {
@@ -793,7 +778,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
793778
/** Destroys the placeholder element and its ViewRef. */
794779
private _destroyPlaceholder() {
795780
if (this._placeholder) {
796-
this._removeElement(this._placeholder);
781+
removeElement(this._placeholder);
797782
}
798783

799784
if (this._placeholderRef) {
@@ -831,7 +816,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
831816
}
832817

833818
/** Gets the root draggable element, based on the `rootElementSelector`. */
834-
private _getRootElement(): HTMLElement {
819+
protected _getRootElement(): HTMLElement {
835820
if (this.rootElementSelector) {
836821
const selector = this.rootElementSelector;
837822
let currentElement = this.element.nativeElement.parentElement as HTMLElement | null;
@@ -881,3 +866,18 @@ function deepCloneNode(node: HTMLElement): HTMLElement {
881866
clone.removeAttribute('id');
882867
return clone;
883868
}
869+
870+
/**
871+
* Helper to remove an element from the DOM and to do all the necessary null checks.
872+
* @param element Element to be removed.
873+
*/
874+
function removeElement(element: HTMLElement | null) {
875+
if (element && element.parentNode) {
876+
element.parentNode.removeChild(element);
877+
}
878+
}
879+
880+
/** Determines whether an event is a touch event. */
881+
function isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {
882+
return event.type.startsWith('touch');
883+
}

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

+24-24
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
@@ -368,10 +368,10 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
368368
// Round the transforms since some browsers will
369369
// blur the elements, for sub-pixel transforms.
370370
elementToOffset.style.transform = `translate3d(${Math.round(sibling.offset)}px, 0, 0)`;
371-
this._adjustClientRect(sibling.clientRect, 0, offset);
371+
adjustClientRect(sibling.clientRect, 0, offset);
372372
} else {
373373
elementToOffset.style.transform = `translate3d(0, ${Math.round(sibling.offset)}px, 0)`;
374-
this._adjustClientRect(sibling.clientRect, offset, 0);
374+
adjustClientRect(sibling.clientRect, offset, 0);
375375
}
376376
});
377377
}
@@ -442,7 +442,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
442442
}
443443

444444
/** Resets the container to its initial state. */
445-
private _reset() {
445+
protected _reset() {
446446
this._dragging = false;
447447

448448
// TODO(crisbeto): may have to wait for the animations to finish.
@@ -454,28 +454,14 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
454454
this._previousSwap.delta = 0;
455455
}
456456

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

481467
const isHorizontal = this.orientation === 'horizontal';
@@ -510,7 +496,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
510496
* @param pointerX Coordinates along the X axis.
511497
* @param pointerY Coordinates along the Y axis.
512498
*/
513-
private _isPointerNearDropContainer(pointerX: number, pointerY: number): boolean {
499+
protected _isPointerNearDropContainer(pointerX: number, pointerY: number): boolean {
514500
const {top, right, bottom, left, width, height} = this._positionCache.self;
515501
const xThreshold = width * DROP_PROXIMITY_THRESHOLD;
516502
const yThreshold = height * DROP_PROXIMITY_THRESHOLD;
@@ -525,7 +511,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
525511
* @param newPosition Position of the item where the current item should be moved.
526512
* @param delta Direction in which the user is moving.
527513
*/
528-
private _getItemOffsetPx(currentPosition: ClientRect, newPosition: ClientRect, delta: 1 | -1) {
514+
protected _getItemOffsetPx(currentPosition: ClientRect, newPosition: ClientRect, delta: 1 | -1) {
529515
const isHorizontal = this.orientation === 'horizontal';
530516
let itemOffset = isHorizontal ? newPosition.left - currentPosition.left :
531517
newPosition.top - currentPosition.top;
@@ -545,7 +531,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
545531
* @param siblings All of the items in the list.
546532
* @param delta Direction in which the user is moving.
547533
*/
548-
private _getSiblingOffsetPx(currentIndex: number,
534+
protected _getSiblingOffsetPx(currentIndex: number,
549535
siblings: ItemPositionCacheEntry[],
550536
delta: 1 | -1) {
551537

@@ -573,7 +559,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
573559
}
574560

575561
/** Gets an array of unique drop lists that the current list is connected to. */
576-
private _getConnectedLists(): CdkDropList[] {
562+
protected _getConnectedLists(): CdkDropList[] {
577563
const siblings = coerceArray(this.connectedTo).map(drop => {
578564
return typeof drop === 'string' ? this._dragDropRegistry.getDropContainer(drop)! : drop;
579565
});
@@ -620,3 +606,17 @@ function isInsideClientRect(clientRect: ClientRect, x: number, y: number) {
620606
const {top, bottom, left, right} = clientRect;
621607
return y >= top && y <= bottom && x >= left && x <= right;
622608
}
609+
610+
/**
611+
* Updates the top/left positions of a `ClientRect`, as well as their bottom/right counterparts.
612+
* @param clientRect `ClientRect` that should be updated.
613+
* @param top Amount to add to the `top` position.
614+
* @param left Amount to add to the `left` position.
615+
*/
616+
function adjustClientRect(clientRect: ClientRect, top: number, left: number) {
617+
clientRect.top += top;
618+
clientRect.bottom = clientRect.top + clientRect.height;
619+
620+
clientRect.left += left;
621+
clientRect.right = clientRect.left + clientRect.width;
622+
}

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

+1
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

+19
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: (event: TouchEvent | MouseEvent) => 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;
@@ -105,8 +113,10 @@ export interface CdkDragStart<T = any> {
105113
}
106114

107115
export declare class CdkDropList<T = any> implements OnInit, OnDestroy {
116+
protected _activeDraggables: CdkDrag[];
108117
_draggables: QueryList<CdkDrag>;
109118
_dragging: boolean;
119+
protected _positionCache: PositionCache;
110120
connectedTo: (CdkDropList | string)[] | CdkDropList | string;
111121
data: T;
112122
disabled: boolean;
@@ -120,8 +130,17 @@ export declare class CdkDropList<T = any> implements OnInit, OnDestroy {
120130
orientation: 'horizontal' | 'vertical';
121131
sorted: EventEmitter<CdkDragSortEvent<T>>;
122132
constructor(element: ElementRef<HTMLElement>, _dragDropRegistry: DragDropRegistry<CdkDrag, CdkDropList<T>>, _changeDetectorRef: ChangeDetectorRef, _dir?: Directionality | undefined, _group?: CdkDropListGroup<CdkDropList<any>> | undefined);
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;
124141
_isOverContainer(x: number, y: number): boolean;
142+
protected _isPointerNearDropContainer(pointerX: number, pointerY: number): boolean;
143+
protected _reset(): void;
125144
_sortItem(item: CdkDrag, pointerX: number, pointerY: number, pointerDelta: {
126145
x: number;
127146
y: number;

0 commit comments

Comments
 (0)