Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { BoundingRectangle } from './interfaces/bounding-rectangle.interface';
import { ResizeEvent } from './interfaces/resize-event.interface';
import { IS_TOUCH_DEVICE } from './util/is-touch-device';
import { deepCloneNode } from './util/clone-node';
import { isTouchEvent } from './util/is-touch-event';

interface PointerEventCoordinate {
clientX: number;
Expand Down Expand Up @@ -333,7 +334,7 @@ export class ResizableDirective implements OnInit, OnDestroy {
this.mousemove,
).pipe(
tap(({ event }) => {
if (currentResize && event.cancelable) {
if (currentResize && event.cancelable && !isTouchEvent(event)) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this what event.cancelable is meant to do?

https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelable

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

event.cancelable tells us if the event can be cancelled or not, but the touchEvent check is due to https://chromestatus.com/feature/5093566007214080 which now treats touch events as passive and we shouldn't be calling preventDefault on these even if they are cancelable.

event.preventDefault();
}
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { fromEvent, merge, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ResizableDirective } from './resizable.directive';
import { Edges } from './interfaces/edges.interface';
import { getListenOptions } from './util/get-listen-options';
import { IS_TOUCH_DEVICE } from './util/is-touch-device';
import { isTouchEvent } from './util/is-touch-event';

/**
* An element placed inside a `mwlResizable` directive to be used as a drag and resize handle
Expand Down Expand Up @@ -100,7 +100,7 @@ export class ResizeHandleDirective implements OnInit, OnDestroy {
clientX: number,
clientY: number,
): void {
if (event.cancelable) {
if (event.cancelable && !isTouchEvent(event)) {
event.preventDefault();
}
if (!this.eventListeners.touchmove) {
Expand Down Expand Up @@ -174,10 +174,8 @@ export class ResizeHandleDirective implements OnInit, OnDestroy {
}

private listenOnTheHost<T extends Event>(eventName: string) {
return fromEvent<T>(
this.element.nativeElement,
eventName,
getListenOptions(eventName),
).pipe(takeUntil(this.destroy$));
return fromEvent<T>(this.element.nativeElement, eventName).pipe(
takeUntil(this.destroy$),
);
}
}

This file was deleted.

10 changes: 10 additions & 0 deletions projects/angular-resizable-element/src/lib/util/is-touch-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Check if the event is a touch event
* @param event - The event to check
* @returns True if the event is a touch event, false otherwise
* @hidden
*/

export function isTouchEvent(event: Event): boolean {
return event.type.startsWith('touch');
}
36 changes: 27 additions & 9 deletions projects/angular-resizable-element/src/test/resizable.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
ResizeEvent,
ResizeHandleDirective,
} from 'angular-resizable-element';
import { getListenOptions } from '../lib/util/get-listen-options';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { expect } from 'chai';
import * as sinon from 'sinon';
Expand Down Expand Up @@ -104,6 +103,7 @@ import { NgStyle } from '@angular/common';
})
class TestComponent {
@ViewChild(ResizableDirective) resizable: ResizableDirective;
@ViewChild(ResizeHandleDirective) handleDirective: ResizeHandleDirective;
@ViewChild('handle') handle: ElementRef;
style: object = {};
resizeStart: sinon.SinonSpy = sinon.spy();
Expand Down Expand Up @@ -508,16 +508,34 @@ describe('resizable directive', () => {
});

describe('touch event listeners', () => {
['touchstart', 'touchend', 'touchcancel'].forEach((eventName) => {
it(`when eventName is ${eventName}, getListenOptions returns passive: false so fromEvent is called with passive: false`, () => {
expect(getListenOptions(eventName)).to.deep.equal({ passive: false });
});
it('should not call preventDefault for touch events when cancelable', () => {
const fixture: ComponentFixture<TestComponent> = createComponent();
const touchEvent = {
type: 'touchstart',
cancelable: true,
preventDefault: sinon.spy(),
} as unknown as TouchEvent;
fixture.componentInstance.handleDirective.onMousedown(
touchEvent,
100,
200,
);
expect(touchEvent.preventDefault).not.to.have.been.called;
});

['mousedown', 'mouseup'].forEach((eventName) => {
it(`when eventName is ${eventName}, getListenOptions returns empty options`, () => {
expect(getListenOptions(eventName)).to.deep.equal({});
});
it('should call preventDefault for mouse events when cancelable', () => {
const fixture: ComponentFixture<TestComponent> = createComponent();
const mouseEvent = {
type: 'mousedown',
cancelable: true,
preventDefault: sinon.spy(),
} as unknown as MouseEvent;
fixture.componentInstance.handleDirective.onMousedown(
mouseEvent,
100,
200,
);
expect(mouseEvent.preventDefault).to.have.been.calledOnce;
});
});

Expand Down
Loading