Skip to content

Commit

Permalink
feat(weekView): Allow drag outside calendar view (#214)
Browse files Browse the repository at this point in the history
Closes #214
  • Loading branch information
ElieSauveterre authored and mattlewis92 committed May 27, 2017
1 parent 8553aa6 commit dcff88a
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 13 deletions.
13 changes: 13 additions & 0 deletions demos/demo-modules/draggable-external-events/component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CalendarEvent, CalendarEventTimesChangedEvent } from 'angular-calendar';
import { Subject } from 'rxjs/Subject';
import { colors } from '../demo-utils/colors';

@Component({
Expand Down Expand Up @@ -28,6 +29,7 @@ export class DemoComponent {
events: CalendarEvent[] = [];

activeDayIsOpen: boolean = false;
refresh: Subject<any> = new Subject();

eventDropped({event, newStart, newEnd}: CalendarEventTimesChangedEvent): void {
const externalIndex: number = this.externalEvents.indexOf(event);
Expand All @@ -43,5 +45,16 @@ export class DemoComponent {
this.activeDayIsOpen = true;
}

droppedBack(event: CalendarEvent): void {

const internalIndex: number = this.events.indexOf(event);

if (internalIndex > -1) {
this.events.splice(internalIndex, 1);
this.externalEvents.push(event);

this.refresh.next();
}
}
}

14 changes: 10 additions & 4 deletions demos/demo-modules/draggable-external-events/template.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<div class="row">

<div class="col-md-3">
<div class="card">
<div class="card"
mwlDroppable
(drop)="droppedBack($event.dropData.event)">
<div class="card-block">
<ul>
<li
Expand Down Expand Up @@ -32,19 +34,23 @@
[viewDate]="viewDate"
[events]="events"
[activeDayIsOpen]="activeDayIsOpen"
(eventTimesChanged)="eventDropped($event)">
(eventTimesChanged)="eventDropped($event)"
[refresh]="refresh">
</mwl-calendar-month-view>
<mwl-calendar-week-view
*ngSwitchCase="'week'"
[viewDate]="viewDate"
[events]="events"
(eventTimesChanged)="eventDropped($event)">
(eventTimesChanged)="eventDropped($event)"
[refresh]="refresh"
[allowDragOutside]="true">
</mwl-calendar-week-view>
<mwl-calendar-day-view
*ngSwitchCase="'day'"
[viewDate]="viewDate"
[events]="events"
(eventTimesChanged)="eventDropped($event)">
(eventTimesChanged)="eventDropped($event)"
[refresh]="refresh">
</mwl-calendar-day-view>
</div>
</div>
Expand Down
42 changes: 33 additions & 9 deletions src/components/week/calendarWeekView.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
} from 'calendar-utils';
import { ResizeEvent } from 'angular-resizable-element';
import addDays from 'date-fns/add_days';
import differenceInDays from 'date-fns/difference_in_days';
import startOfDay from 'date-fns/start_of_day';
import { CalendarDragHelper } from '../../providers/calendarDragHelper.provider';
import { CalendarResizeHelper } from '../../providers/calendarResizeHelper.provider';
import { CalendarEventTimesChangedEvent } from '../../interfaces/calendarEventTimesChangedEvent.interface';
Expand All @@ -47,7 +49,7 @@ import { CalendarUtils } from '../../providers/calendarUtils.provider';
(dayClicked)="dayClicked.emit($event)"
(eventDropped)="eventTimesChanged.emit($event)">
</mwl-calendar-week-view-header>
<div *ngFor="let eventRow of eventRows" #eventRowContainer>
<div *ngFor="let eventRow of eventRows" #eventRowContainer class="cal-events-row">
<div
class="cal-event-container"
#event
Expand All @@ -63,11 +65,12 @@ import { CalendarUtils } from '../../providers/calendarUtils.provider';
(resizing)="resizing(weekEvent, $event, getDayColumnWidth(eventRowContainer))"
(resizeEnd)="resizeEnded(weekEvent)"
mwlDraggable
[dragAxis]="{x: weekEvent.event.draggable && !currentResize, y: false}"
[dragSnapGrid]="{x: getDayColumnWidth(eventRowContainer)}"
[dragSnapGrid]="{x: allowDragOutside ? 0 : getDayColumnWidth(eventRowContainer)}"
[validateDrag]="validateDrag"
(dragStart)="dragStart(weekViewContainer, event)"
(dragEnd)="eventDragged(weekEvent, $event.x, getDayColumnWidth(eventRowContainer))">
[dragAxis]="{x: weekEvent.event.draggable && !currentResize, y: allowDragOutside}"
(dragEnd)="eventDragged(weekEvent, $event.x, getDayColumnWidth(eventRowContainer))"
[dropData]="{event: weekEvent.event}">
<mwl-calendar-week-view-event
[weekEvent]="weekEvent"
[tooltipPlacement]="tooltipPlacement"
Expand Down Expand Up @@ -132,6 +135,11 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
*/
@Input() precision: 'days' | 'minutes' = 'days';

/**
* Allow events to be dragged outside of the calendar
*/
@Input() allowDragOutside: boolean = false;

/**
* Called when a header week day is clicked
*/
Expand Down Expand Up @@ -285,8 +293,22 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
*/
eventDragged(weekEvent: WeekViewEvent, draggedByPx: number, dayWidth: number): void {

const daysDragged: number = draggedByPx / dayWidth;
const newStart: Date = addDays(weekEvent.event.start, daysDragged);
let daysDragged: number = Math.round(draggedByPx / dayWidth);
let newStart: Date = addDays(weekEvent.event.start, daysDragged);

if (this.allowDragOutside) {
// Restrict start to first and last day on current week
if (newStart < this.days[0].date) {
daysDragged += differenceInDays(startOfDay(this.days[0].date), startOfDay(newStart));
}
const lastDate: Date = this.days[this.days.length - 1].date;
if (newStart > lastDate) {
daysDragged -= differenceInDays(startOfDay(newStart), startOfDay(lastDate));
}
}

newStart = addDays(weekEvent.event.start, daysDragged);

let newEnd: Date;
if (weekEvent.event.end) {
newEnd = addDays(weekEvent.event.end, daysDragged);
Expand All @@ -307,9 +329,11 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
* @hidden
*/
dragStart(weekViewContainer: HTMLElement, event: HTMLElement): void {
const dragHelper: CalendarDragHelper = new CalendarDragHelper(weekViewContainer, event);
this.validateDrag = ({x, y}) => !this.currentResize && dragHelper.validateDrag({x, y});
this.cdr.markForCheck();
if (!this.allowDragOutside) {
const dragHelper: CalendarDragHelper = new CalendarDragHelper(weekViewContainer, event);
this.validateDrag = ({x, y}) => !this.currentResize && dragHelper.validateDrag({x, y});
this.cdr.markForCheck();
}
}

private refreshHeader(): void {
Expand Down
70 changes: 70 additions & 0 deletions test/calendarWeekView.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,4 +473,74 @@ describe('calendarWeekView component', () => {
});
});

it('should allow the events to be dragged outside of the week view to the left', () => {
const fixture: ComponentFixture<CalendarWeekViewComponent> = TestBed.createComponent(CalendarWeekViewComponent);
fixture.componentInstance.viewDate = new Date('2016-12-08');
fixture.componentInstance.events = [{
title: 'foo',
color: {primary: '', secondary: ''},
start: moment('2016-12-08').add(4, 'hours').toDate(),
end: moment('2016-12-08').add(6, 'hours').toDate(),
draggable: true
}];
fixture.componentInstance.allowDragOutside = true;
fixture.componentInstance.ngOnChanges({viewDate: {}, events: {}});
fixture.detectChanges();
document.body.appendChild(fixture.nativeElement);
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event-container');
const dayWidth: number = event.parentElement.offsetWidth / 7;
const eventPosition: ClientRect = event.getBoundingClientRect();
let dragEvent: CalendarEventTimesChangedEvent;
fixture.componentInstance.eventTimesChanged.subscribe(event => {
dragEvent = event;
});
triggerDomEvent('mousedown', event, {clientX: eventPosition.left, clientY: eventPosition.top});
fixture.detectChanges();
triggerDomEvent('mousemove', document.body, {clientX: -10000, clientY: eventPosition.top});
fixture.detectChanges();
triggerDomEvent('mouseup', document.body, {clientX: -1000, clientY: eventPosition.top});
fixture.detectChanges();
fixture.destroy();
expect(dragEvent).to.deep.equal({
event: fixture.componentInstance.events[0],
newStart: moment('2016-12-07').startOf('week').add(4, 'hours').toDate(),
newEnd: moment('2016-12-07').startOf('week').add(6, 'hours').toDate()
});
});

it('should allow the events to be dragged outside of the week view to the right', () => {
const fixture: ComponentFixture<CalendarWeekViewComponent> = TestBed.createComponent(CalendarWeekViewComponent);
fixture.componentInstance.viewDate = new Date('2016-12-08');
fixture.componentInstance.events = [{
title: 'foo',
color: {primary: '', secondary: ''},
start: moment('2016-12-08').add(4, 'hours').toDate(),
end: moment('2016-12-08').add(6, 'hours').toDate(),
draggable: true
}];
fixture.componentInstance.allowDragOutside = true;
fixture.componentInstance.ngOnChanges({viewDate: {}, events: {}});
fixture.detectChanges();
document.body.appendChild(fixture.nativeElement);
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event-container');
const dayWidth: number = event.parentElement.offsetWidth / 7;
const eventPosition: ClientRect = event.getBoundingClientRect();
let dragEvent: CalendarEventTimesChangedEvent;
fixture.componentInstance.eventTimesChanged.subscribe(event => {
dragEvent = event;
});
triggerDomEvent('mousedown', event, {clientX: eventPosition.left, clientY: eventPosition.top});
fixture.detectChanges();
triggerDomEvent('mousemove', document.body, {clientX: document.body.clientWidth + 1000, clientY: eventPosition.top});
fixture.detectChanges();
triggerDomEvent('mouseup', document.body, {clientX: document.body.clientWidth + 1000, clientY: eventPosition.top});
fixture.detectChanges();
fixture.destroy();
expect(dragEvent).to.deep.equal({
event: fixture.componentInstance.events[0],
newStart: moment('2016-12-07').startOf('week').add(6, 'days').add(4, 'hours').toDate(),
newEnd: moment('2016-12-07').startOf('week').add(6, 'days').add(6, 'hours').toDate()
});
});

});

0 comments on commit dcff88a

Please sign in to comment.