Skip to content

Commit

Permalink
feat: add drag and drop support (#100)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:

A dependency on the `angular-draggable-droppable` library has been added. System.js users will need to add this to their config:

```
'angular-draggable-droppable': 'npm:angular-draggable-droppable/dist/umd/angular-draggable-droppable.js'
```

Closes #10
Closes #102
  • Loading branch information
mattlewis92 authored Dec 18, 2016
1 parent 36458ab commit bbc02f3
Show file tree
Hide file tree
Showing 20 changed files with 428 additions and 42 deletions.
8 changes: 5 additions & 3 deletions demo/demo.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ const colors: any = {
[events]="events"
[refresh]="refresh"
[activeDayIsOpen]="activeDayIsOpen"
(dayClicked)="dayClicked($event.day)">
(dayClicked)="dayClicked($event.day)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-month-view>
<mwl-calendar-week-view
*ngSwitchCase="'week'"
Expand Down Expand Up @@ -139,13 +140,14 @@ export class DemoComponent {
}, {
start: addHours(startOfDay(new Date()), 2),
end: new Date(),
title: 'A resizable event',
title: 'A draggable and resizable event',
color: colors.yellow,
actions: this.actions,
resizable: {
beforeStart: true,
afterEnd: true
}
},
draggable: true
}];

activeDayIsOpen: boolean = true;
Expand Down
5 changes: 4 additions & 1 deletion karma.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ module.exports = function(config) {
}
}),
new FixDefaultImportPlugin()
]
],
performance: {
hints: false
}
},

remapIstanbulReporter: {
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@
},
"dependencies": {
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.0",
"angular-resizable-element": "~0.5.0",
"calendar-utils": "0.0.38",
"angular-draggable-droppable": "^0.4.0",
"angular-resizable-element": "^0.5.4",
"calendar-utils": "0.0.39",
"date-fns": "^1.15.1"
}
}
4 changes: 4 additions & 0 deletions scss/day-view.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
white-space: nowrap;
}

.cal-draggable {
cursor: move;
}

.cal-event.cal-starts-within-day {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
Expand Down
4 changes: 4 additions & 0 deletions scss/month-view.scss
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@
font-size: 1.9em;
}

.cal-day-cell.cal-drag-over {
background-color: darken(#ededed, 5%) !important;
}

.cal-open-day-events {
padding: 15px;
color: white;
Expand Down
4 changes: 4 additions & 0 deletions scss/week-view.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
line-height: 30px;
}

.cal-draggable {
cursor: move;
}

.cal-event.cal-starts-within-week {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
Expand Down
14 changes: 12 additions & 2 deletions src/calendar.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ResizableModule } from 'angular-resizable-element';
import { DragAndDropModule } from 'angular-draggable-droppable';
import { CalendarDayViewComponent } from './components/day/calendarDayView.component';
import { CalendarWeekViewComponent } from './components/week/calendarWeekView.component';
import { CalendarMonthViewComponent } from './components/month/calendarMonthView.component';
Expand Down Expand Up @@ -38,8 +39,17 @@ import { CalendarDateFormatter } from './providers/calendarDateFormatter.provide
CalendarDate,
CalendarEventTitlePipe
],
imports: [CommonModule, ResizableModule],
exports: [CalendarDayViewComponent, CalendarWeekViewComponent, CalendarMonthViewComponent, CalendarDate],
imports: [
CommonModule,
ResizableModule,
DragAndDropModule
],
exports: [
CalendarDayViewComponent,
CalendarWeekViewComponent,
CalendarMonthViewComponent,
CalendarDate
],
entryComponents: [CalendarTooltipWindowComponent]
})
export class CalendarModule {
Expand Down
5 changes: 3 additions & 2 deletions src/components/day/calendarDayView.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import {
import { getDayView, getDayViewHourGrid, CalendarEvent, DayView, DayViewHour } from 'calendar-utils';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import { CalendarEventTimesChangedEvent } from './../../interfaces/calendarEventTimesChangedEvent.interface';
import { CalendarEventTimesChangedEvent } from '../../interfaces/calendarEventTimesChangedEvent.interface';

const SEGMENT_HEIGHT: number = 30;

@Component({
selector: 'mwl-calendar-day-view',
template: `
<div class="cal-day-view">
<div class="cal-day-view" #dayViewContainer>
<mwl-calendar-all-day-event
*ngFor="let event of view.allDayEvents"
[event]="event"
Expand All @@ -34,6 +34,7 @@ const SEGMENT_HEIGHT: number = 30;
[hourSegments]="hourSegments"
[tooltipPlacement]="tooltipPlacement"
[eventSnapSize]="eventSnapSize"
[dayViewContainer]="dayViewContainer"
(eventClicked)="eventClicked.emit({event: dayEvent.event})"
(eventResized)="eventTimesChanged.emit($event)">
</mwl-calendar-day-view-event>
Expand Down
38 changes: 36 additions & 2 deletions src/components/day/calendarDayViewEvent.component.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Component, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
import { DayViewEvent } from 'calendar-utils';
import { ResizeEvent } from 'angular-resizable-element';
import addMinutes from 'date-fns/add_minutes';
import { CalendarDragHelper } from '../../providers/calendarDragHelper.provider';

@Component({
selector: 'mwl-calendar-day-view-event',
template: `
<div
class="cal-event"
#event
[style.marginTop.px]="dayEvent.top"
[style.marginLeft.px]="dayEvent.left + 70"
[style.height.px]="dayEvent.height"
Expand All @@ -16,6 +18,7 @@ import addMinutes from 'date-fns/add_minutes';
[style.borderColor]="dayEvent.event.color.primary"
[class.cal-starts-within-day]="!dayEvent.startsBeforeDay"
[class.cal-ends-within-day]="!dayEvent.endsAfterDay"
[class.cal-draggable]="dayEvent.event.draggable"
[ngClass]="dayEvent.event.cssClass"
[mwlCalendarTooltip]="dayEvent.event | calendarEventTitle:'dayTooltip'"
[tooltipPlacement]="tooltipPlacement"
Expand All @@ -24,7 +27,13 @@ import addMinutes from 'date-fns/add_minutes';
[resizeSnapGrid]="{top: eventSnapSize, bottom: eventSnapSize}"
(resizeStart)="resizeStarted(dayEvent, $event)"
(resizing)="resizing(dayEvent, $event)"
(resizeEnd)="resizeEnded(dayEvent)">
(resizeEnd)="resizeEnded(dayEvent)"
mwlDraggable
[dragAxis]="{x: false, y: dayEvent.event.draggable && !currentResize}"
[dragSnapGrid]="{y: eventSnapSize}"
[validateDrag]="validateDrag"
(dragStart)="dragStart(event)"
(dragEnd)="eventDragged(dayEvent, $event.y)">
<mwl-calendar-event-title
[event]="dayEvent.event"
view="day"
Expand All @@ -44,6 +53,8 @@ export class CalendarDayViewEventComponent {

@Input() tooltipPlacement: string;

@Input() dayViewContainer: HTMLElement;

@Output() eventClicked: EventEmitter<any> = new EventEmitter();

@Output() eventResized: EventEmitter<any> = new EventEmitter();
Expand All @@ -54,6 +65,10 @@ export class CalendarDayViewEventComponent {
edge: string
};

validateDrag: Function;

constructor(private cdr: ChangeDetectorRef) {}

resizeStarted(event: DayViewEvent, resizeEvent: ResizeEvent): void {
this.currentResize = {
originalTop: event.top,
Expand Down Expand Up @@ -93,7 +108,26 @@ export class CalendarDayViewEventComponent {
}

this.eventResized.emit({newStart, newEnd, event: dayEvent.event});
this.currentResize = null;

}

dragStart(event: HTMLElement): void {
const dragHelper: CalendarDragHelper = new CalendarDragHelper(this.dayViewContainer, event);
this.validateDrag = ({x, y}) => dragHelper.validateDrag({x, y});
this.cdr.markForCheck();
}

eventDragged(dayEvent: DayViewEvent, draggedInPixels: number): void {
const segments: number = draggedInPixels / this.eventSnapSize;
const segmentAmountInMinutes: number = 60 / this.hourSegments;
const minutesMoved: number = segments * segmentAmountInMinutes;
const newStart: Date = addMinutes(dayEvent.event.start, minutesMoved);
let newEnd: Date;
if (dayEvent.event.end) {
newEnd = addMinutes(dayEvent.event.end, minutesMoved);
}
this.eventResized.emit({newStart, newEnd, event: dayEvent.event});
}

}
9 changes: 6 additions & 3 deletions src/components/month/calendarMonthCell.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@ import { MonthViewDay } from 'calendar-utils';
<span class="cal-day-number">{{ day.date | calendarDate:'monthViewDayNumber':locale }}</span>
</div>
<div class="cal-events">
<span
<div
class="cal-event"
*ngFor="let event of day.events"
[style.backgroundColor]="event.color.primary"
[ngClass]="event?.cssClass"
(mouseenter)="highlightDay.emit({event: event})"
(mouseleave)="unhighlightDay.emit({event: event})"
[mwlCalendarTooltip]="event | calendarEventTitle:'monthTooltip'"
[tooltipPlacement]="tooltipPlacement">
</span>
[tooltipPlacement]="tooltipPlacement"
mwlDraggable
[dropData]="{event: event}"
[dragAxis]="{x: event.draggable, y: event.draggable}">
</div>
</div>
`,
host: {
Expand Down
37 changes: 36 additions & 1 deletion src/components/month/calendarMonthView.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ import {
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import isSameDay from 'date-fns/is_same_day';
import setDate from 'date-fns/set_date';
import setMonth from 'date-fns/set_month';
import setYear from 'date-fns/set_year';
import getDate from 'date-fns/get_date';
import getMonth from 'date-fns/get_month';
import getYear from 'date-fns/get_year';
import differenceInSeconds from 'date-fns/difference_in_seconds';
import addSeconds from 'date-fns/add_seconds';
import { CalendarEventTimesChangedEvent } from '../../interfaces/calendarEventTimesChangedEvent.interface';

@Component({
selector: 'mwl-calendar-month-view',
Expand All @@ -36,13 +45,18 @@ import isSameDay from 'date-fns/is_same_day';
<div class="cal-cell-row">
<mwl-calendar-month-cell
*ngFor="let day of view.days | slice : rowIndex : rowIndex + 7"
[class.cal-drag-over]="day.dragOver"
[day]="day"
[openDay]="openDay"
[locale]="locale"
[tooltipPlacement]="tooltipPlacement"
(click)="dayClicked.emit({day: day})"
(highlightDay)="toggleDayHighlight($event.event, true)"
(unhighlightDay)="toggleDayHighlight($event.event, false)">
(unhighlightDay)="toggleDayHighlight($event.event, false)"
mwlDroppable
(dragEnter)="day.dragOver = true"
(dragLeave)="day.dragOver = false"
(drop)="day.dragOver = false; eventDropped(day, $event.dropData.event)">
</mwl-calendar-month-cell>
</div>
<mwl-calendar-open-day-events
Expand Down Expand Up @@ -108,6 +122,11 @@ export class CalendarMonthViewComponent implements OnChanges, OnInit, OnDestroy
*/
@Output() eventClicked: EventEmitter<{event: CalendarEvent}> = new EventEmitter<{event: CalendarEvent}>();

/**
* Called when an event is dragged and dropped
*/
@Output() eventTimesChanged: EventEmitter<CalendarEventTimesChangedEvent> = new EventEmitter<CalendarEventTimesChangedEvent>();

/**
* @private
*/
Expand Down Expand Up @@ -193,6 +212,22 @@ export class CalendarMonthViewComponent implements OnChanges, OnInit, OnDestroy
});
}

/**
* @private
*/
eventDropped(day: MonthViewDay, event: CalendarEvent): void {
const year: number = getYear(day.date);
const month: number = getMonth(day.date);
const date: number = getDate(day.date);
const newStart: Date = setYear(setMonth(setDate(event.start, date), month), year);
let newEnd: Date;
if (event.end) {
const secondsDiff: number = differenceInSeconds(newStart, event.start);
newEnd = addSeconds(event.end, secondsDiff);
}
this.eventTimesChanged.emit({event, newStart, newEnd});
}

private refreshHeader(): void {
this.columnHeaders = getWeekViewHeader({
viewDate: this.viewDate,
Expand Down
10 changes: 8 additions & 2 deletions src/components/month/calendarOpenDayEvents.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ import { CalendarEvent } from 'calendar-utils';
<div class="cal-open-day-events" [@collapse] *ngIf="isOpen">
<div
*ngFor="let event of events"
[ngClass]="event?.cssClass">
<span class="cal-event" [style.backgroundColor]="event.color.primary"></span>
[ngClass]="event?.cssClass"
mwlDraggable
[dropData]="{event: event}"
[dragAxis]="{x: event.draggable, y: event.draggable}">
<span
class="cal-event"
[style.backgroundColor]="event.color.primary">
</span>
<mwl-calendar-event-title
[event]="event"
view="month"
Expand Down
Loading

0 comments on commit bbc02f3

Please sign in to comment.