Skip to content

Commit

Permalink
fix(week-view): prevent dropping external events on adjacent time slots
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mattlewis92 committed Oct 19, 2019
1 parent d1a2b78 commit 494adb5
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { trackByWeekDayHeaderDate } from '../common/util';
let-dayHeaderClicked="dayHeaderClicked"
let-eventDropped="eventDropped"
let-trackByWeekDayHeaderDate="trackByWeekDayHeaderDate"
let-dragEnter="dragEnter"
>
<div class="cal-day-headers" role="row">
<div
Expand All @@ -37,6 +38,7 @@ import { trackByWeekDayHeaderDate } from '../common/util';
newStart: day.date
})
"
(dragEnter)="dragEnter.emit({ date: day.date })"
tabindex="0"
role="columnheader"
>
Expand All @@ -55,6 +57,7 @@ import { trackByWeekDayHeaderDate } from '../common/util';
locale: locale,
dayHeaderClicked: dayHeaderClicked,
eventDropped: eventDropped,
dragEnter: dragEnter,
trackByWeekDayHeaderDate: trackByWeekDayHeaderDate
}"
>
Expand All @@ -68,17 +71,17 @@ export class CalendarWeekViewHeaderComponent {

@Input() customTemplate: TemplateRef<any>;

@Output()
dayHeaderClicked = new EventEmitter<{
@Output() dayHeaderClicked = new EventEmitter<{
day: WeekDay;
sourceEvent: MouseEvent;
}>();

@Output()
eventDropped: EventEmitter<{
@Output() eventDropped = new EventEmitter<{
event: CalendarEvent;
newStart: Date;
}> = new EventEmitter<{ event: CalendarEvent; newStart: Date }>();
}>();

@Output() dragEnter = new EventEmitter<{ date: Date }>();

trackByWeekDayHeaderDate = trackByWeekDayHeaderDate;
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export interface CalendarWeekViewBeforeRenderEvent extends WeekView {
(eventDropped)="
eventDropped({ dropData: $event }, $event.newStart, true)
"
(dragEnter)="dateDragEnter($event.date)"
>
</mwl-calendar-week-view-header>
<div
Expand All @@ -109,6 +110,7 @@ export interface CalendarWeekViewBeforeRenderEvent extends WeekView {
mwlDroppable
dragOverClass="cal-drag-over"
(drop)="eventDropped($event, day.date, true)"
(dragEnter)="dateDragEnter(day.date)"
></div>
</div>
<div
Expand Down Expand Up @@ -367,6 +369,7 @@ export interface CalendarWeekViewBeforeRenderEvent extends WeekView {
"
dragActiveClass="cal-drag-active"
(drop)="eventDropped($event, segment.date, false)"
(dragEnter)="dateDragEnter(segment.date)"
>
</mwl-calendar-week-view-hour-segment>
</div>
Expand Down Expand Up @@ -644,6 +647,11 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
*/
trackByDayOrWeekEvent = trackByDayOrWeekEvent;

/**
* @hidden
*/
private lastDragEnterDate: Date;

/**
* @hidden
*/
Expand Down Expand Up @@ -893,6 +901,13 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
return Math.floor(eventRowContainer.offsetWidth / this.days.length);
}

/**
* @hidden
*/
dateDragEnter(date: Date) {
this.lastDragEnterDate = date;
}

/**
* @hidden
*/
Expand All @@ -901,7 +916,10 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
date: Date,
allDay: boolean
): void {
if (shouldFireDroppedEvent(dropEvent, date, allDay, this.calendarId)) {
if (
shouldFireDroppedEvent(dropEvent, date, allDay, this.calendarId) &&
this.lastDragEnterDate.getTime() === date.getTime()
) {
this.eventTimesChanged.emit({
type: CalendarEventTimesChangedEventType.Drop,
event: dropEvent.dropData.event,
Expand Down
92 changes: 77 additions & 15 deletions projects/angular-calendar/test/calendar-week-view.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ import * as sinon from 'sinon';
import { triggerDomEvent, ExternalEventComponent } from './util';
import { take } from 'rxjs/operators';
import { adapterFactory } from '../src/date-adapters/date-fns';
import { Component } from '@angular/core';
import { By } from '@angular/platform-browser';

@Component({
template: `
<mwl-calendar-week-view
[viewDate]="viewDate"
[events]="events"
(eventTimesChanged)="eventTimesChanged($event)"
></mwl-calendar-week-view>
<mwl-external-event></mwl-external-event>
`
})
class TestComponent {
viewDate: Date;
events: CalendarEvent[];
eventTimesChanged = sinon.spy();
}

describe('calendarWeekView component', () => {
beforeEach(() => {
Expand All @@ -45,7 +63,7 @@ describe('calendarWeekView component', () => {
),
DragAndDropModule
],
declarations: [ExternalEventComponent],
declarations: [ExternalEventComponent, TestComponent],
providers: [{ provide: MOMENT, useValue: moment }]
});
});
Expand Down Expand Up @@ -912,20 +930,14 @@ describe('calendarWeekView component', () => {
});

it('should allow external events to be dropped on the week view headers', () => {
const fixture: ComponentFixture<
CalendarWeekViewComponent
> = TestBed.createComponent(CalendarWeekViewComponent);
const fixture = TestBed.createComponent(TestComponent);
fixture.componentInstance.viewDate = new Date('2016-06-27');
fixture.componentInstance.events = [];
fixture.componentInstance.ngOnChanges({ viewDate: {}, events: {} });
fixture.detectChanges();
document.body.appendChild(fixture.nativeElement);

const externalEventFixture: ComponentFixture<
ExternalEventComponent
> = TestBed.createComponent(ExternalEventComponent);
externalEventFixture.detectChanges();
document.body.appendChild(externalEventFixture.nativeElement);
const externalEventFixture = fixture.debugElement.query(
By.directive(ExternalEventComponent)
);

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

const eventDropped: sinon.SinonSpy = sinon.spy();
fixture.componentInstance.eventTimesChanged.subscribe(eventDropped);
const eventDropped = fixture.componentInstance.eventTimesChanged;
triggerDomEvent('mousedown', event, {
clientY: eventPosition.top,
clientX: eventPosition.left
Expand All @@ -955,8 +966,6 @@ describe('calendarWeekView component', () => {
clientX: headerPosition.left
});
fixture.detectChanges();
fixture.destroy();
externalEventFixture.destroy();
expect(eventDropped).to.have.been.calledWith({
type: 'drop',
event: externalEventFixture.componentInstance.event,
Expand All @@ -966,6 +975,7 @@ describe('calendarWeekView component', () => {
.toDate(),
allDay: true
});
expect(eventDropped).to.have.been.calledOnce;
});

it('should allow the weekend days to be customised', () => {
Expand Down Expand Up @@ -2336,4 +2346,56 @@ describe('calendarWeekView component', () => {
);
document.head.appendChild(style);
});

it('should allow external events to be dropped on the hour segments', () => {
const fixture = TestBed.createComponent(TestComponent);
fixture.componentInstance.viewDate = new Date('2016-06-27');
fixture.componentInstance.events = [];
fixture.detectChanges();
document.body.appendChild(fixture.nativeElement);
const externalEventFixture = fixture.debugElement.query(
By.directive(ExternalEventComponent)
);

const event: HTMLElement = externalEventFixture.nativeElement.querySelector(
'.external-event'
);
const eventPosition: ClientRect = event.getBoundingClientRect();

const segments: HTMLElement[] = Array.from(
fixture.nativeElement.querySelectorAll(
'.cal-day-columns .cal-hour-segment'
)
);
const segment = segments[1];
const segmentPosition: ClientRect = segment.getBoundingClientRect();

const eventDropped = fixture.componentInstance.eventTimesChanged;

triggerDomEvent('mousedown', event, {
clientY: eventPosition.top,
clientX: eventPosition.left
});
fixture.detectChanges();
triggerDomEvent('mousemove', document.body, {
clientY: segmentPosition.top,
clientX: segmentPosition.left
});
fixture.detectChanges();
triggerDomEvent('mouseup', document.body, {
clientY: segmentPosition.top,
clientX: segmentPosition.left
});
fixture.detectChanges();
expect(eventDropped).to.have.been.calledWith({
type: 'drop',
event: externalEventFixture.componentInstance.event,
newStart: moment('2016-06-27')
.startOf('week')
.add(30, 'minutes')
.toDate(),
allDay: false
});
expect(eventDropped).to.have.been.calledOnce;
});
});
1 change: 1 addition & 0 deletions projects/angular-calendar/test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function triggerDomEvent(
}

@Component({
selector: 'mwl-external-event',
template:
'<div class="external-event" mwlDraggable [dropData]="{event: event}">{{ event.title }}</div>',
styles: [
Expand Down

0 comments on commit 494adb5

Please sign in to comment.