Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(weekView): Allow drag outside calendar view #214

Merged
merged 12 commits into from
May 27, 2017
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()
});
});

});