Skip to content

Commit

Permalink
feat(mwlResizeHandle): add resizableContainer input
Browse files Browse the repository at this point in the history
  • Loading branch information
cakeinpanic committed Jun 2, 2021
1 parent c187e69 commit 862249f
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 6 deletions.
15 changes: 13 additions & 2 deletions src/resizable.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,15 @@ export const MOUSE_MOVE_THROTTLE_MS: number = 50;
* [enableGhostResize]="true">
* </div>
* ```
* Or in case they are sibling elements:
* ```html
* <div mwlResizable #resizableElement="mwlResizable"></div>
* <div mwlResizeHandle [resizableContainer]="resizableElement" [resizeEdges]="{bottom: true, right: true}"></div>
* ```
*/
@Directive({
selector: '[mwlResizable]'
selector: '[mwlResizable]',
exportAs: 'mwlResizable'
})
export class ResizableDirective implements OnInit, OnChanges, OnDestroy {
/**
Expand Down Expand Up @@ -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()
Expand Down
19 changes: 17 additions & 2 deletions src/resize-handle.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -23,6 +24,11 @@ import { IS_TOUCH_DEVICE } from './is-touch-device';
* <div mwlResizeHandle [resizeEdges]="{bottom: true, right: true}"></div>
* </div>
* ```
* Or in case they are sibling elements:
* ```html
* <div mwlResizable #resizableElement="mwlResizable"></div>
* <div mwlResizeHandle [resizableContainer]="resizableElement" [resizeEdges]="{bottom: true, right: true}"></div>
* ```
*/
@Directive({
selector: '[mwlResizeHandle]'
Expand All @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
71 changes: 69 additions & 2 deletions test/resizable.spec.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 = `
<div
class="rectangle"
[ngStyle]="style"
mwlResizable
#container='mwlResizable'
(resizeStart)="resizeStart($event)"
>
</div>
<span
style="width: 5px; height: 5px; position: absolute; bottom: 5px; right: 5px"
class="resize-handle"
mwlResizeHandle
#handle
[resizableContainer]='container'
[resizeEdges]="{right: true}">
</span>
`;
const fixture: ComponentFixture<TestComponent> = 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<TestComponent> = createComponent();
const elm: HTMLElement =
Expand Down

0 comments on commit 862249f

Please sign in to comment.