Skip to content

Commit dcff88a

Browse files
ElieSauveterremattlewis92
authored andcommitted
feat(weekView): Allow drag outside calendar view (#214)
Closes #214
1 parent 8553aa6 commit dcff88a

File tree

4 files changed

+126
-13
lines changed

4 files changed

+126
-13
lines changed

demos/demo-modules/draggable-external-events/component.ts

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Component, ChangeDetectionStrategy } from '@angular/core';
22
import { CalendarEvent, CalendarEventTimesChangedEvent } from 'angular-calendar';
3+
import { Subject } from 'rxjs/Subject';
34
import { colors } from '../demo-utils/colors';
45

56
@Component({
@@ -28,6 +29,7 @@ export class DemoComponent {
2829
events: CalendarEvent[] = [];
2930

3031
activeDayIsOpen: boolean = false;
32+
refresh: Subject<any> = new Subject();
3133

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

48+
droppedBack(event: CalendarEvent): void {
49+
50+
const internalIndex: number = this.events.indexOf(event);
51+
52+
if (internalIndex > -1) {
53+
this.events.splice(internalIndex, 1);
54+
this.externalEvents.push(event);
55+
56+
this.refresh.next();
57+
}
58+
}
4659
}
4760

demos/demo-modules/draggable-external-events/template.html

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<div class="row">
22

33
<div class="col-md-3">
4-
<div class="card">
4+
<div class="card"
5+
mwlDroppable
6+
(drop)="droppedBack($event.dropData.event)">
57
<div class="card-block">
68
<ul>
79
<li
@@ -32,19 +34,23 @@
3234
[viewDate]="viewDate"
3335
[events]="events"
3436
[activeDayIsOpen]="activeDayIsOpen"
35-
(eventTimesChanged)="eventDropped($event)">
37+
(eventTimesChanged)="eventDropped($event)"
38+
[refresh]="refresh">
3639
</mwl-calendar-month-view>
3740
<mwl-calendar-week-view
3841
*ngSwitchCase="'week'"
3942
[viewDate]="viewDate"
4043
[events]="events"
41-
(eventTimesChanged)="eventDropped($event)">
44+
(eventTimesChanged)="eventDropped($event)"
45+
[refresh]="refresh"
46+
[allowDragOutside]="true">
4247
</mwl-calendar-week-view>
4348
<mwl-calendar-day-view
4449
*ngSwitchCase="'day'"
4550
[viewDate]="viewDate"
4651
[events]="events"
47-
(eventTimesChanged)="eventDropped($event)">
52+
(eventTimesChanged)="eventDropped($event)"
53+
[refresh]="refresh">
4854
</mwl-calendar-day-view>
4955
</div>
5056
</div>

src/components/week/calendarWeekView.component.ts

+33-9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import {
2121
} from 'calendar-utils';
2222
import { ResizeEvent } from 'angular-resizable-element';
2323
import addDays from 'date-fns/add_days';
24+
import differenceInDays from 'date-fns/difference_in_days';
25+
import startOfDay from 'date-fns/start_of_day';
2426
import { CalendarDragHelper } from '../../providers/calendarDragHelper.provider';
2527
import { CalendarResizeHelper } from '../../providers/calendarResizeHelper.provider';
2628
import { CalendarEventTimesChangedEvent } from '../../interfaces/calendarEventTimesChangedEvent.interface';
@@ -47,7 +49,7 @@ import { CalendarUtils } from '../../providers/calendarUtils.provider';
4749
(dayClicked)="dayClicked.emit($event)"
4850
(eventDropped)="eventTimesChanged.emit($event)">
4951
</mwl-calendar-week-view-header>
50-
<div *ngFor="let eventRow of eventRows" #eventRowContainer>
52+
<div *ngFor="let eventRow of eventRows" #eventRowContainer class="cal-events-row">
5153
<div
5254
class="cal-event-container"
5355
#event
@@ -63,11 +65,12 @@ import { CalendarUtils } from '../../providers/calendarUtils.provider';
6365
(resizing)="resizing(weekEvent, $event, getDayColumnWidth(eventRowContainer))"
6466
(resizeEnd)="resizeEnded(weekEvent)"
6567
mwlDraggable
66-
[dragAxis]="{x: weekEvent.event.draggable && !currentResize, y: false}"
67-
[dragSnapGrid]="{x: getDayColumnWidth(eventRowContainer)}"
68+
[dragSnapGrid]="{x: allowDragOutside ? 0 : getDayColumnWidth(eventRowContainer)}"
6869
[validateDrag]="validateDrag"
6970
(dragStart)="dragStart(weekViewContainer, event)"
70-
(dragEnd)="eventDragged(weekEvent, $event.x, getDayColumnWidth(eventRowContainer))">
71+
[dragAxis]="{x: weekEvent.event.draggable && !currentResize, y: allowDragOutside}"
72+
(dragEnd)="eventDragged(weekEvent, $event.x, getDayColumnWidth(eventRowContainer))"
73+
[dropData]="{event: weekEvent.event}">
7174
<mwl-calendar-week-view-event
7275
[weekEvent]="weekEvent"
7376
[tooltipPlacement]="tooltipPlacement"
@@ -132,6 +135,11 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
132135
*/
133136
@Input() precision: 'days' | 'minutes' = 'days';
134137

138+
/**
139+
* Allow events to be dragged outside of the calendar
140+
*/
141+
@Input() allowDragOutside: boolean = false;
142+
135143
/**
136144
* Called when a header week day is clicked
137145
*/
@@ -285,8 +293,22 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
285293
*/
286294
eventDragged(weekEvent: WeekViewEvent, draggedByPx: number, dayWidth: number): void {
287295

288-
const daysDragged: number = draggedByPx / dayWidth;
289-
const newStart: Date = addDays(weekEvent.event.start, daysDragged);
296+
let daysDragged: number = Math.round(draggedByPx / dayWidth);
297+
let newStart: Date = addDays(weekEvent.event.start, daysDragged);
298+
299+
if (this.allowDragOutside) {
300+
// Restrict start to first and last day on current week
301+
if (newStart < this.days[0].date) {
302+
daysDragged += differenceInDays(startOfDay(this.days[0].date), startOfDay(newStart));
303+
}
304+
const lastDate: Date = this.days[this.days.length - 1].date;
305+
if (newStart > lastDate) {
306+
daysDragged -= differenceInDays(startOfDay(newStart), startOfDay(lastDate));
307+
}
308+
}
309+
310+
newStart = addDays(weekEvent.event.start, daysDragged);
311+
290312
let newEnd: Date;
291313
if (weekEvent.event.end) {
292314
newEnd = addDays(weekEvent.event.end, daysDragged);
@@ -307,9 +329,11 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
307329
* @hidden
308330
*/
309331
dragStart(weekViewContainer: HTMLElement, event: HTMLElement): void {
310-
const dragHelper: CalendarDragHelper = new CalendarDragHelper(weekViewContainer, event);
311-
this.validateDrag = ({x, y}) => !this.currentResize && dragHelper.validateDrag({x, y});
312-
this.cdr.markForCheck();
332+
if (!this.allowDragOutside) {
333+
const dragHelper: CalendarDragHelper = new CalendarDragHelper(weekViewContainer, event);
334+
this.validateDrag = ({x, y}) => !this.currentResize && dragHelper.validateDrag({x, y});
335+
this.cdr.markForCheck();
336+
}
313337
}
314338

315339
private refreshHeader(): void {

test/calendarWeekView.component.spec.ts

+70
Original file line numberDiff line numberDiff line change
@@ -473,4 +473,74 @@ describe('calendarWeekView component', () => {
473473
});
474474
});
475475

476+
it('should allow the events to be dragged outside of the week view to the left', () => {
477+
const fixture: ComponentFixture<CalendarWeekViewComponent> = TestBed.createComponent(CalendarWeekViewComponent);
478+
fixture.componentInstance.viewDate = new Date('2016-12-08');
479+
fixture.componentInstance.events = [{
480+
title: 'foo',
481+
color: {primary: '', secondary: ''},
482+
start: moment('2016-12-08').add(4, 'hours').toDate(),
483+
end: moment('2016-12-08').add(6, 'hours').toDate(),
484+
draggable: true
485+
}];
486+
fixture.componentInstance.allowDragOutside = true;
487+
fixture.componentInstance.ngOnChanges({viewDate: {}, events: {}});
488+
fixture.detectChanges();
489+
document.body.appendChild(fixture.nativeElement);
490+
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event-container');
491+
const dayWidth: number = event.parentElement.offsetWidth / 7;
492+
const eventPosition: ClientRect = event.getBoundingClientRect();
493+
let dragEvent: CalendarEventTimesChangedEvent;
494+
fixture.componentInstance.eventTimesChanged.subscribe(event => {
495+
dragEvent = event;
496+
});
497+
triggerDomEvent('mousedown', event, {clientX: eventPosition.left, clientY: eventPosition.top});
498+
fixture.detectChanges();
499+
triggerDomEvent('mousemove', document.body, {clientX: -10000, clientY: eventPosition.top});
500+
fixture.detectChanges();
501+
triggerDomEvent('mouseup', document.body, {clientX: -1000, clientY: eventPosition.top});
502+
fixture.detectChanges();
503+
fixture.destroy();
504+
expect(dragEvent).to.deep.equal({
505+
event: fixture.componentInstance.events[0],
506+
newStart: moment('2016-12-07').startOf('week').add(4, 'hours').toDate(),
507+
newEnd: moment('2016-12-07').startOf('week').add(6, 'hours').toDate()
508+
});
509+
});
510+
511+
it('should allow the events to be dragged outside of the week view to the right', () => {
512+
const fixture: ComponentFixture<CalendarWeekViewComponent> = TestBed.createComponent(CalendarWeekViewComponent);
513+
fixture.componentInstance.viewDate = new Date('2016-12-08');
514+
fixture.componentInstance.events = [{
515+
title: 'foo',
516+
color: {primary: '', secondary: ''},
517+
start: moment('2016-12-08').add(4, 'hours').toDate(),
518+
end: moment('2016-12-08').add(6, 'hours').toDate(),
519+
draggable: true
520+
}];
521+
fixture.componentInstance.allowDragOutside = true;
522+
fixture.componentInstance.ngOnChanges({viewDate: {}, events: {}});
523+
fixture.detectChanges();
524+
document.body.appendChild(fixture.nativeElement);
525+
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event-container');
526+
const dayWidth: number = event.parentElement.offsetWidth / 7;
527+
const eventPosition: ClientRect = event.getBoundingClientRect();
528+
let dragEvent: CalendarEventTimesChangedEvent;
529+
fixture.componentInstance.eventTimesChanged.subscribe(event => {
530+
dragEvent = event;
531+
});
532+
triggerDomEvent('mousedown', event, {clientX: eventPosition.left, clientY: eventPosition.top});
533+
fixture.detectChanges();
534+
triggerDomEvent('mousemove', document.body, {clientX: document.body.clientWidth + 1000, clientY: eventPosition.top});
535+
fixture.detectChanges();
536+
triggerDomEvent('mouseup', document.body, {clientX: document.body.clientWidth + 1000, clientY: eventPosition.top});
537+
fixture.detectChanges();
538+
fixture.destroy();
539+
expect(dragEvent).to.deep.equal({
540+
event: fixture.componentInstance.events[0],
541+
newStart: moment('2016-12-07').startOf('week').add(6, 'days').add(4, 'hours').toDate(),
542+
newEnd: moment('2016-12-07').startOf('week').add(6, 'days').add(6, 'hours').toDate()
543+
});
544+
});
545+
476546
});

0 commit comments

Comments
 (0)