Skip to content

Commit 494adb5

Browse files
committed
fix(week-view): prevent dropping external events on adjacent time slots
BREAKING CHANGE: if using a custom `headerTemplate` on the week view, then you must now add `let-dragEnter="dragEnter"` to the templates variables and `(dragEnter)="dragEnter.emit({ date: day.date })"` onto the `mwlDroppable` element. Closes #1062
1 parent d1a2b78 commit 494adb5

File tree

4 files changed

+105
-21
lines changed

4 files changed

+105
-21
lines changed

projects/angular-calendar/src/modules/week/calendar-week-view-header.component.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { trackByWeekDayHeaderDate } from '../common/util';
1818
let-dayHeaderClicked="dayHeaderClicked"
1919
let-eventDropped="eventDropped"
2020
let-trackByWeekDayHeaderDate="trackByWeekDayHeaderDate"
21+
let-dragEnter="dragEnter"
2122
>
2223
<div class="cal-day-headers" role="row">
2324
<div
@@ -37,6 +38,7 @@ import { trackByWeekDayHeaderDate } from '../common/util';
3738
newStart: day.date
3839
})
3940
"
41+
(dragEnter)="dragEnter.emit({ date: day.date })"
4042
tabindex="0"
4143
role="columnheader"
4244
>
@@ -55,6 +57,7 @@ import { trackByWeekDayHeaderDate } from '../common/util';
5557
locale: locale,
5658
dayHeaderClicked: dayHeaderClicked,
5759
eventDropped: eventDropped,
60+
dragEnter: dragEnter,
5861
trackByWeekDayHeaderDate: trackByWeekDayHeaderDate
5962
}"
6063
>
@@ -68,17 +71,17 @@ export class CalendarWeekViewHeaderComponent {
6871

6972
@Input() customTemplate: TemplateRef<any>;
7073

71-
@Output()
72-
dayHeaderClicked = new EventEmitter<{
74+
@Output() dayHeaderClicked = new EventEmitter<{
7375
day: WeekDay;
7476
sourceEvent: MouseEvent;
7577
}>();
7678

77-
@Output()
78-
eventDropped: EventEmitter<{
79+
@Output() eventDropped = new EventEmitter<{
7980
event: CalendarEvent;
8081
newStart: Date;
81-
}> = new EventEmitter<{ event: CalendarEvent; newStart: Date }>();
82+
}>();
83+
84+
@Output() dragEnter = new EventEmitter<{ date: Date }>();
8285

8386
trackByWeekDayHeaderDate = trackByWeekDayHeaderDate;
8487
}

projects/angular-calendar/src/modules/week/calendar-week-view.component.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export interface CalendarWeekViewBeforeRenderEvent extends WeekView {
8888
(eventDropped)="
8989
eventDropped({ dropData: $event }, $event.newStart, true)
9090
"
91+
(dragEnter)="dateDragEnter($event.date)"
9192
>
9293
</mwl-calendar-week-view-header>
9394
<div
@@ -109,6 +110,7 @@ export interface CalendarWeekViewBeforeRenderEvent extends WeekView {
109110
mwlDroppable
110111
dragOverClass="cal-drag-over"
111112
(drop)="eventDropped($event, day.date, true)"
113+
(dragEnter)="dateDragEnter(day.date)"
112114
></div>
113115
</div>
114116
<div
@@ -367,6 +369,7 @@ export interface CalendarWeekViewBeforeRenderEvent extends WeekView {
367369
"
368370
dragActiveClass="cal-drag-active"
369371
(drop)="eventDropped($event, segment.date, false)"
372+
(dragEnter)="dateDragEnter(segment.date)"
370373
>
371374
</mwl-calendar-week-view-hour-segment>
372375
</div>
@@ -644,6 +647,11 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
644647
*/
645648
trackByDayOrWeekEvent = trackByDayOrWeekEvent;
646649

650+
/**
651+
* @hidden
652+
*/
653+
private lastDragEnterDate: Date;
654+
647655
/**
648656
* @hidden
649657
*/
@@ -893,6 +901,13 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
893901
return Math.floor(eventRowContainer.offsetWidth / this.days.length);
894902
}
895903

904+
/**
905+
* @hidden
906+
*/
907+
dateDragEnter(date: Date) {
908+
this.lastDragEnterDate = date;
909+
}
910+
896911
/**
897912
* @hidden
898913
*/
@@ -901,7 +916,10 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
901916
date: Date,
902917
allDay: boolean
903918
): void {
904-
if (shouldFireDroppedEvent(dropEvent, date, allDay, this.calendarId)) {
919+
if (
920+
shouldFireDroppedEvent(dropEvent, date, allDay, this.calendarId) &&
921+
this.lastDragEnterDate.getTime() === date.getTime()
922+
) {
905923
this.eventTimesChanged.emit({
906924
type: CalendarEventTimesChangedEventType.Drop,
907925
event: dropEvent.dropData.event,

projects/angular-calendar/test/calendar-week-view.component.spec.ts

+77-15
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,24 @@ import * as sinon from 'sinon';
2626
import { triggerDomEvent, ExternalEventComponent } from './util';
2727
import { take } from 'rxjs/operators';
2828
import { adapterFactory } from '../src/date-adapters/date-fns';
29+
import { Component } from '@angular/core';
30+
import { By } from '@angular/platform-browser';
31+
32+
@Component({
33+
template: `
34+
<mwl-calendar-week-view
35+
[viewDate]="viewDate"
36+
[events]="events"
37+
(eventTimesChanged)="eventTimesChanged($event)"
38+
></mwl-calendar-week-view>
39+
<mwl-external-event></mwl-external-event>
40+
`
41+
})
42+
class TestComponent {
43+
viewDate: Date;
44+
events: CalendarEvent[];
45+
eventTimesChanged = sinon.spy();
46+
}
2947

3048
describe('calendarWeekView component', () => {
3149
beforeEach(() => {
@@ -45,7 +63,7 @@ describe('calendarWeekView component', () => {
4563
),
4664
DragAndDropModule
4765
],
48-
declarations: [ExternalEventComponent],
66+
declarations: [ExternalEventComponent, TestComponent],
4967
providers: [{ provide: MOMENT, useValue: moment }]
5068
});
5169
});
@@ -912,20 +930,14 @@ describe('calendarWeekView component', () => {
912930
});
913931

914932
it('should allow external events to be dropped on the week view headers', () => {
915-
const fixture: ComponentFixture<
916-
CalendarWeekViewComponent
917-
> = TestBed.createComponent(CalendarWeekViewComponent);
933+
const fixture = TestBed.createComponent(TestComponent);
918934
fixture.componentInstance.viewDate = new Date('2016-06-27');
919935
fixture.componentInstance.events = [];
920-
fixture.componentInstance.ngOnChanges({ viewDate: {}, events: {} });
921936
fixture.detectChanges();
922937
document.body.appendChild(fixture.nativeElement);
923-
924-
const externalEventFixture: ComponentFixture<
925-
ExternalEventComponent
926-
> = TestBed.createComponent(ExternalEventComponent);
927-
externalEventFixture.detectChanges();
928-
document.body.appendChild(externalEventFixture.nativeElement);
938+
const externalEventFixture = fixture.debugElement.query(
939+
By.directive(ExternalEventComponent)
940+
);
929941

930942
const event: HTMLElement = externalEventFixture.nativeElement.querySelector(
931943
'.external-event'
@@ -938,8 +950,7 @@ describe('calendarWeekView component', () => {
938950
const header: HTMLElement = headers[2];
939951
const headerPosition: ClientRect = header.getBoundingClientRect();
940952

941-
const eventDropped: sinon.SinonSpy = sinon.spy();
942-
fixture.componentInstance.eventTimesChanged.subscribe(eventDropped);
953+
const eventDropped = fixture.componentInstance.eventTimesChanged;
943954
triggerDomEvent('mousedown', event, {
944955
clientY: eventPosition.top,
945956
clientX: eventPosition.left
@@ -955,8 +966,6 @@ describe('calendarWeekView component', () => {
955966
clientX: headerPosition.left
956967
});
957968
fixture.detectChanges();
958-
fixture.destroy();
959-
externalEventFixture.destroy();
960969
expect(eventDropped).to.have.been.calledWith({
961970
type: 'drop',
962971
event: externalEventFixture.componentInstance.event,
@@ -966,6 +975,7 @@ describe('calendarWeekView component', () => {
966975
.toDate(),
967976
allDay: true
968977
});
978+
expect(eventDropped).to.have.been.calledOnce;
969979
});
970980

971981
it('should allow the weekend days to be customised', () => {
@@ -2336,4 +2346,56 @@ describe('calendarWeekView component', () => {
23362346
);
23372347
document.head.appendChild(style);
23382348
});
2349+
2350+
it('should allow external events to be dropped on the hour segments', () => {
2351+
const fixture = TestBed.createComponent(TestComponent);
2352+
fixture.componentInstance.viewDate = new Date('2016-06-27');
2353+
fixture.componentInstance.events = [];
2354+
fixture.detectChanges();
2355+
document.body.appendChild(fixture.nativeElement);
2356+
const externalEventFixture = fixture.debugElement.query(
2357+
By.directive(ExternalEventComponent)
2358+
);
2359+
2360+
const event: HTMLElement = externalEventFixture.nativeElement.querySelector(
2361+
'.external-event'
2362+
);
2363+
const eventPosition: ClientRect = event.getBoundingClientRect();
2364+
2365+
const segments: HTMLElement[] = Array.from(
2366+
fixture.nativeElement.querySelectorAll(
2367+
'.cal-day-columns .cal-hour-segment'
2368+
)
2369+
);
2370+
const segment = segments[1];
2371+
const segmentPosition: ClientRect = segment.getBoundingClientRect();
2372+
2373+
const eventDropped = fixture.componentInstance.eventTimesChanged;
2374+
2375+
triggerDomEvent('mousedown', event, {
2376+
clientY: eventPosition.top,
2377+
clientX: eventPosition.left
2378+
});
2379+
fixture.detectChanges();
2380+
triggerDomEvent('mousemove', document.body, {
2381+
clientY: segmentPosition.top,
2382+
clientX: segmentPosition.left
2383+
});
2384+
fixture.detectChanges();
2385+
triggerDomEvent('mouseup', document.body, {
2386+
clientY: segmentPosition.top,
2387+
clientX: segmentPosition.left
2388+
});
2389+
fixture.detectChanges();
2390+
expect(eventDropped).to.have.been.calledWith({
2391+
type: 'drop',
2392+
event: externalEventFixture.componentInstance.event,
2393+
newStart: moment('2016-06-27')
2394+
.startOf('week')
2395+
.add(30, 'minutes')
2396+
.toDate(),
2397+
allDay: false
2398+
});
2399+
expect(eventDropped).to.have.been.calledOnce;
2400+
});
23392401
});

projects/angular-calendar/test/util.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export function triggerDomEvent(
1414
}
1515

1616
@Component({
17+
selector: 'mwl-external-event',
1718
template:
1819
'<div class="external-event" mwlDraggable [dropData]="{event: event}">{{ event.title }}</div>',
1920
styles: [

0 commit comments

Comments
 (0)