Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mwlResizeHandle): add resizableContainer input #128

Merged
merged 2 commits into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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
21 changes: 18 additions & 3 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 @@ -43,9 +53,9 @@ export class ResizeHandleDirective implements OnInit, OnDestroy {

constructor(
private renderer: Renderer2,
private element: ElementRef,
public element: ElementRef,
Copy link
Owner

Choose a reason for hiding this comment

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

Does this need to be public?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

just made it public for unit tests sake
no real need, just saw same pattern in ResizableDirective and decided to shortcut same way

Copy link
Owner

Choose a reason for hiding this comment

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

OK can we keep it private and get the element a different way in the test (via querySelector or debugElement). Users have an annoying way of using all the apis you didn't expect to expose 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

totally agree, updated

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
69 changes: 68 additions & 1 deletion test/resizable.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { Component, 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(ResizeHandleDirective) handle: ResizeHandleDirective;
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
id='handle'
[resizableContainer]='container'
[resizeEdges]="{right: true}">
</span>
`;
const fixture: ComponentFixture<TestComponent> = createComponent(
template
);
const handleElem: HTMLElement =
fixture.componentInstance.handle.element.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