Skip to content

Commit ab1033e

Browse files
author
Matt Lewis
committed
fix(dayView): dont allow events to be resized outside of the calendar
Closes #99
1 parent 1c5e74f commit ab1033e

5 files changed

+101
-17
lines changed

src/calendar.module.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NgModule, ModuleWithProviders } from '@angular/core';
1+
import { NgModule, ModuleWithProviders, Provider } from '@angular/core';
22
import { CommonModule } from '@angular/common';
33
import { ResizableModule } from 'angular-resizable-element';
44
import { DragAndDropModule } from 'angular-draggable-droppable';
@@ -54,14 +54,20 @@ import { CalendarDateFormatter } from './providers/calendarDateFormatter.provide
5454
})
5555
export class CalendarModule {
5656

57-
static forRoot(): ModuleWithProviders {
57+
static forRoot({eventTitleFormatter, dateFormatter}:
58+
{eventTitleFormatter?: Provider, dateFormatter?: Provider} = {}): ModuleWithProviders {
59+
60+
eventTitleFormatter = eventTitleFormatter || CalendarEventTitleProvider;
61+
dateFormatter = dateFormatter || CalendarDateFormatter;
62+
5863
return {
5964
ngModule: CalendarModule,
6065
providers: [
61-
CalendarEventTitleProvider,
62-
CalendarDateFormatter
66+
eventTitleFormatter,
67+
dateFormatter
6368
]
6469
};
70+
6571
}
6672

6773
}

src/components/day/calendarDayViewEvent.component.ts

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { DayViewEvent } from 'calendar-utils';
33
import { ResizeEvent } from 'angular-resizable-element';
44
import addMinutes from 'date-fns/add_minutes';
55
import { CalendarDragHelper } from '../../providers/calendarDragHelper.provider';
6+
import { CalendarResizeHelper } from '../../providers/calendarResizeHelper.provider';
67

78
@Component({
89
selector: 'mwl-calendar-day-view-event',
@@ -25,6 +26,7 @@ import { CalendarDragHelper } from '../../providers/calendarDragHelper.provider'
2526
mwlResizable
2627
[resizeEdges]="{top: dayEvent.event?.resizable?.beforeStart, bottom: dayEvent.event?.resizable?.afterEnd}"
2728
[resizeSnapGrid]="{top: eventSnapSize, bottom: eventSnapSize}"
29+
[validateResize]="validateResize"
2830
(resizeStart)="resizeStarted(dayEvent, $event)"
2931
(resizing)="resizing(dayEvent, $event)"
3032
(resizeEnd)="resizeEnded(dayEvent)"
@@ -67,6 +69,8 @@ export class CalendarDayViewEventComponent {
6769

6870
validateDrag: Function;
6971

72+
validateResize: Function;
73+
7074
constructor(private cdr: ChangeDetectorRef) {}
7175

7276
resizeStarted(event: DayViewEvent, resizeEvent: ResizeEvent): void {
@@ -75,6 +79,9 @@ export class CalendarDayViewEventComponent {
7579
originalHeight: event.height,
7680
edge: typeof resizeEvent.edges.top !== 'undefined' ? 'top' : 'bottom'
7781
};
82+
const resizeHelper: CalendarResizeHelper = new CalendarResizeHelper(this.dayViewContainer);
83+
this.validateResize = ({rectangle}) => resizeHelper.validateResize({rectangle});
84+
this.cdr.markForCheck();
7885
}
7986

8087
resizing(event: DayViewEvent, resizeEvent: ResizeEvent): void {

src/providers/calendarResizeHelper.provider.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ import { isInside } from './calendarUtils.provider';
22

33
export class CalendarResizeHelper {
44

5-
constructor(private resizeContainerElement: HTMLElement, private dayColumnWidth: number) {}
5+
constructor(private resizeContainerElement: HTMLElement, private minWidth?: number) {}
66

77
validateResize({rectangle}: {rectangle: ClientRect}): boolean {
8-
return isInside(this.resizeContainerElement.getBoundingClientRect(), rectangle) && rectangle.width >= this.dayColumnWidth;
8+
9+
if (this.minWidth && rectangle.width < this.minWidth) {
10+
return false;
11+
}
12+
13+
return isInside(this.resizeContainerElement.getBoundingClientRect(), rectangle);
914
}
1015

1116
}

test/calendarDayView.component.spec.ts

+35
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ describe('CalendarDayViewComponent component', () => {
266266
fixture.detectChanges();
267267
document.body.appendChild(fixture.nativeElement);
268268
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event');
269+
event.style.position = 'absolute';
269270
const rect: ClientRect = event.getBoundingClientRect();
270271
let resizeEvent: CalendarEventTimesChangedEvent;
271272
fixture.componentInstance.eventTimesChanged.subscribe(event => {
@@ -303,6 +304,7 @@ describe('CalendarDayViewComponent component', () => {
303304
fixture.detectChanges();
304305
document.body.appendChild(fixture.nativeElement);
305306
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event');
307+
event.style.position = 'absolute';
306308
const rect: ClientRect = event.getBoundingClientRect();
307309
let resizeEvent: CalendarEventTimesChangedEvent;
308310
fixture.componentInstance.eventTimesChanged.subscribe(event => {
@@ -443,4 +445,37 @@ describe('CalendarDayViewComponent component', () => {
443445
fixture.destroy();
444446
});
445447

448+
it('should not allow events to be resized outside of the container', () => {
449+
const fixture: ComponentFixture<CalendarDayViewComponent> = TestBed.createComponent(CalendarDayViewComponent);
450+
fixture.componentInstance.viewDate = new Date('2016-06-27');
451+
fixture.componentInstance.events = [{
452+
title: 'foo',
453+
color: {primary: '', secondary: ''},
454+
start: moment('2016-06-27').add(1, 'hours').toDate(),
455+
end: moment('2016-06-27').add(6, 'hours').toDate(),
456+
resizable: {
457+
beforeStart: true
458+
}
459+
}];
460+
fixture.componentInstance.ngOnChanges({viewDate: {}, events: {}});
461+
fixture.detectChanges();
462+
document.body.appendChild(fixture.nativeElement);
463+
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event');
464+
event.style.position = 'absolute';
465+
const rect: ClientRect = event.getBoundingClientRect();
466+
triggerDomEvent('mousedown', document.body, {clientY: rect.top, clientX: rect.left + 10});
467+
fixture.detectChanges();
468+
triggerDomEvent('mousemove', document.body, {clientY: rect.top - 60, clientX: rect.left + 10});
469+
fixture.detectChanges();
470+
expect(event.getBoundingClientRect().top).to.equal(rect.top - 60);
471+
expect(event.getBoundingClientRect().height).to.equal(rect.height + 60);
472+
triggerDomEvent('mousemove', document.body, {clientY: rect.top - 120, clientX: rect.left + 10});
473+
fixture.detectChanges();
474+
expect(event.getBoundingClientRect().top).to.equal(rect.top - 60);
475+
expect(event.getBoundingClientRect().height).to.equal(rect.height + 60);
476+
triggerDomEvent('mouseup', document.body, {clientY: rect.top - 60, clientX: rect.left + 10});
477+
fixture.detectChanges();
478+
fixture.destroy();
479+
});
480+
446481
});

test/calendarModule.spec.ts

+42-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,53 @@
1-
import {
2-
inject,
3-
TestBed
4-
} from '@angular/core/testing';
1+
import { TestBed } from '@angular/core/testing';
52
import { expect } from 'chai';
63
import {
74
CalendarModule,
8-
CalendarDateFormatter
5+
CalendarDateFormatter,
6+
CalendarEventTitle
97
} from './../src';
108

119
describe('calendar module', () => {
1210

13-
beforeEach(() => {
14-
TestBed.configureTestingModule({imports: [CalendarModule.forRoot()]});
11+
it('should not require providers to be specified when using CalendarModule.forRoot()', () => {
12+
TestBed.configureTestingModule({
13+
imports: [
14+
CalendarModule.forRoot()
15+
]
16+
});
17+
const dateFormatter: CalendarDateFormatter = TestBed.get(CalendarDateFormatter);
18+
expect(dateFormatter instanceof CalendarDateFormatter).to.be.true;
1519
});
1620

17-
it('should not require providers to be specified when using CalendarModule.forRoot()',
18-
inject([CalendarDateFormatter], (dateFormatter) => {
19-
expect(dateFormatter instanceof CalendarDateFormatter).to.be.true;
20-
}));
21+
it('should allow a custom date formatter to be used', () => {
22+
class MyDateFormatter extends CalendarDateFormatter {}
23+
TestBed.configureTestingModule({
24+
imports: [
25+
CalendarModule.forRoot({
26+
dateFormatter: {
27+
provide: CalendarDateFormatter,
28+
useClass: MyDateFormatter
29+
}
30+
})
31+
]
32+
});
33+
const dateFormatter: MyDateFormatter = TestBed.get(CalendarDateFormatter);
34+
expect(dateFormatter instanceof MyDateFormatter).to.be.true;
35+
});
36+
37+
it('should allow a custom title formatter to be used', () => {
38+
class MyEventTitle extends CalendarEventTitle {}
39+
TestBed.configureTestingModule({
40+
imports: [
41+
CalendarModule.forRoot({
42+
dateFormatter: {
43+
provide: CalendarEventTitle,
44+
useClass: MyEventTitle
45+
}
46+
})
47+
]
48+
});
49+
const eventTitle: MyEventTitle = TestBed.get(CalendarEventTitle);
50+
expect(eventTitle instanceof MyEventTitle).to.be.true;
51+
});
2152

2253
});

0 commit comments

Comments
 (0)