diff --git a/src/resizable.directive.ts b/src/resizable.directive.ts index 338fa03..d62cc71 100644 --- a/src/resizable.directive.ts +++ b/src/resizable.directive.ts @@ -283,9 +283,15 @@ export const MOUSE_MOVE_THROTTLE_MS: number = 50; * [enableGhostResize]="true"> * * ``` + * Or in case they are sibling elements: + * ```html + *
+ *
+ * ``` */ @Directive({ - selector: '[mwlResizable]' + selector: '[mwlResizable]', + exportAs: 'mwlResizable' }) export class ResizableDirective implements OnInit, OnChanges, OnDestroy { /** @@ -417,7 +423,12 @@ export class ResizableDirective implements OnInit, OnChanges, OnDestroy { ).pipe( tap(({ event }) => { if (currentResize) { - event.preventDefault(); + try { + event.preventDefault(); + } catch (e) { + // just adding try-catch not to see errors in console if there is a passive listener for same event somewhere + // browser does nothing except of writing errors to console + } } }), share() diff --git a/src/resize-handle.directive.ts b/src/resize-handle.directive.ts index 544b49a..3f2fee7 100644 --- a/src/resize-handle.directive.ts +++ b/src/resize-handle.directive.ts @@ -5,7 +5,8 @@ import { ElementRef, OnInit, OnDestroy, - NgZone + NgZone, + Optional } from '@angular/core'; import { fromEvent, merge, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -23,6 +24,11 @@ import { IS_TOUCH_DEVICE } from './is-touch-device'; *
* * ``` + * Or in case they are sibling elements: + * ```html + *
+ *
+ * ``` */ @Directive({ selector: '[mwlResizeHandle]' @@ -32,6 +38,10 @@ export class ResizeHandleDirective implements OnInit, OnDestroy { * The `Edges` object that contains the edges of the parent element that dragging the handle will trigger a resize on */ @Input() resizeEdges: Edges = {}; + /** + * Reference to ResizableDirective in case if handle is not located inside of element with ResizableDirective + */ + @Input() resizableContainer: ResizableDirective; private eventListeners: { touchmove?: () => void; @@ -45,7 +55,7 @@ export class ResizeHandleDirective implements OnInit, OnDestroy { private renderer: Renderer2, private element: ElementRef, private zone: NgZone, - private resizable: ResizableDirective + @Optional() private resizableDirective: ResizableDirective ) {} ngOnInit(): void { @@ -139,6 +149,11 @@ export class ResizeHandleDirective implements OnInit, OnDestroy { }); } + // directive might be passed from DI or as an input + private get resizable(): ResizableDirective { + return this.resizableDirective || this.resizableContainer; + } + private onMousemove( event: MouseEvent | TouchEvent, clientX: number, diff --git a/test/resizable.spec.ts b/test/resizable.spec.ts index 45a292a..e8826f4 100644 --- a/test/resizable.spec.ts +++ b/test/resizable.spec.ts @@ -1,8 +1,8 @@ /* tslint:disable:max-inline-declarations enforce-component-selector */ -import { Component, ViewChild } from '@angular/core'; +import { Component, ElementRef, ViewChild } from '@angular/core'; import { ResizableDirective } from '../src/resizable.directive'; import { Edges } from '../src/interfaces/edges.interface'; -import { ResizeEvent, ResizableModule } from '../src'; +import { ResizeEvent, ResizableModule, ResizeHandleDirective } from '../src'; import { MOUSE_MOVE_THROTTLE_MS } from '../src/resizable.directive'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { expect } from 'chai'; @@ -44,6 +44,7 @@ describe('resizable directive', () => { }) class TestComponent { @ViewChild(ResizableDirective) resizable: ResizableDirective; + @ViewChild('handle') handle: ElementRef; style: object = {}; resizeStart: sinon.SinonSpy = sinon.spy(); resizing: sinon.SinonSpy = sinon.spy(); @@ -570,6 +571,72 @@ describe('resizable directive', () => { }); }); + describe('handle outside of element', () => { + let domEvents: any[]; + let spyName: string; + let expectedEvent: object; + + it('should emit a starting resize event', () => { + domEvents = [ + { + name: 'mousedown', + data: { + clientX: 150, + clientY: 200 + } + } + ]; + spyName = 'resizeStart'; + expectedEvent = { + edges: { + right: 0 + }, + rectangle: { + top: 200, + left: 100, + width: 300, + height: 150, + right: 400, + bottom: 350 + } + }; + }); + + afterEach(() => { + const template: string = ` +
+
+ + + `; + const fixture: ComponentFixture = createComponent( + template + ); + const handleElem: HTMLElement = + fixture.componentInstance.handle.nativeElement; + + domEvents.forEach(event => { + triggerDomEvent(event.name, handleElem, event.data); + }); + + expect( + (fixture.componentInstance as any)[spyName] + ).to.have.been.calledWith(expectedEvent); + }); + }); + it('should not resize when clicking and dragging outside of the element edges', () => { const fixture: ComponentFixture = createComponent(); const elm: HTMLElement =