Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 45fae71

Browse files
fix(cdk/drag-drop): only block dragstart event on event targets (#24581)
Currently we block the `dragstart` event on the entire drag element which doesn't account for its disabled state and for any existing handles. Fixes #24533.
1 parent d8b5665 commit 45fae71

File tree

2 files changed

+59
-12
lines changed

2 files changed

+59
-12
lines changed

‎src/cdk/drag-drop/directives/drag.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,19 @@ describe('CdkDrag', () => {
271271

272272
expect(event.defaultPrevented).toBe(true);
273273
}));
274+
275+
it('should not prevent the default dragstart action when dragging is disabled', fakeAsync(() => {
276+
const fixture = createComponent(StandaloneDraggable);
277+
fixture.detectChanges();
278+
fixture.componentInstance.dragInstance.disabled = true;
279+
const event = dispatchFakeEvent(
280+
fixture.componentInstance.dragElement.nativeElement,
281+
'dragstart',
282+
);
283+
fixture.detectChanges();
284+
285+
expect(event.defaultPrevented).toBe(false);
286+
}));
274287
});
275288

276289
describe('touch dragging', () => {
@@ -1619,6 +1632,27 @@ describe('CdkDrag', () => {
16191632
dragElementViaMouse(fixture, handleChild, 50, 100);
16201633
expect(dragElement.style.transform).toBe('translate3d(50px, 100px, 0px)');
16211634
}));
1635+
1636+
it('should prevent default dragStart on handle, not on entire draggable', fakeAsync(() => {
1637+
const fixture = createComponent(StandaloneDraggableWithHandle);
1638+
fixture.detectChanges();
1639+
1640+
const draggableEvent = dispatchFakeEvent(
1641+
fixture.componentInstance.dragElement.nativeElement,
1642+
'dragstart',
1643+
);
1644+
fixture.detectChanges();
1645+
1646+
const handleEvent = dispatchFakeEvent(
1647+
fixture.componentInstance.handleElement.nativeElement,
1648+
'dragstart',
1649+
true,
1650+
);
1651+
fixture.detectChanges();
1652+
1653+
expect(draggableEvent.defaultPrevented).toBe(false);
1654+
expect(handleEvent.defaultPrevented).toBe(true);
1655+
}));
16221656
});
16231657

16241658
describe('in a drop container', () => {

‎src/cdk/drag-drop/drag-ref.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -448,9 +448,7 @@ export class DragRef<T = any> {
448448
this._ngZone.runOutsideAngular(() => {
449449
element.addEventListener('mousedown', this._pointerDown, activeEventListenerOptions);
450450
element.addEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
451-
// Usually this isn't necessary since the we prevent the default action in `pointerDown`,
452-
// but some cases like dragging of links can slip through (see #24403).
453-
element.addEventListener('dragstart', preventDefault, activeEventListenerOptions);
451+
element.addEventListener('dragstart', this._nativeDragStart, activeEventListenerOptions);
454452
});
455453
this._initialTransform = undefined;
456454
this._rootElement = element;
@@ -637,9 +635,7 @@ export class DragRef<T = any> {
637635

638636
// Delegate the event based on whether it started from a handle or the element itself.
639637
if (this._handles.length) {
640-
const targetHandle = this._handles.find(handle => {
641-
return event.target && (event.target === handle || handle.contains(event.target as Node));
642-
});
638+
const targetHandle = this._getTargetHandle(event);
643639

644640
if (targetHandle && !this._disabledHandles.has(targetHandle) && !this.disabled) {
645641
this._initializeDragSequence(targetHandle, event);
@@ -1295,7 +1291,7 @@ export class DragRef<T = any> {
12951291
private _removeRootElementListeners(element: HTMLElement) {
12961292
element.removeEventListener('mousedown', this._pointerDown, activeEventListenerOptions);
12971293
element.removeEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
1298-
element.removeEventListener('dragstart', preventDefault, activeEventListenerOptions);
1294+
element.removeEventListener('dragstart', this._nativeDragStart, activeEventListenerOptions);
12991295
}
13001296

13011297
/**
@@ -1520,6 +1516,28 @@ export class DragRef<T = any> {
15201516

15211517
return this._previewRect;
15221518
}
1519+
1520+
/** Handles a native `dragstart` event. */
1521+
private _nativeDragStart = (event: DragEvent) => {
1522+
if (this._handles.length) {
1523+
const targetHandle = this._getTargetHandle(event);
1524+
1525+
if (targetHandle && !this._disabledHandles.has(targetHandle) && !this.disabled) {
1526+
event.preventDefault();
1527+
}
1528+
} else if (!this.disabled) {
1529+
// Usually this isn't necessary since the we prevent the default action in `pointerDown`,
1530+
// but some cases like dragging of links can slip through (see #24403).
1531+
event.preventDefault();
1532+
}
1533+
};
1534+
1535+
/** Gets a handle that is the target of an event. */
1536+
private _getTargetHandle(event: Event): HTMLElement | undefined {
1537+
return this._handles.find(handle => {
1538+
return event.target && (event.target === handle || handle.contains(event.target as Node));
1539+
});
1540+
}
15231541
}
15241542

15251543
/**
@@ -1572,8 +1590,3 @@ function matchElementSize(target: HTMLElement, sourceRect: ClientRect): void {
15721590
target.style.height = `${sourceRect.height}px`;
15731591
target.style.transform = getTransform(sourceRect.left, sourceRect.top);
15741592
}
1575-
1576-
/** Utility to prevent the default action of an event. */
1577-
function preventDefault(event: Event): void {
1578-
event.preventDefault();
1579-
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /