Skip to content

Commit

Permalink
feat(weekView): support resizing of events
Browse files Browse the repository at this point in the history
Closes #9
  • Loading branch information
Matt Lewis committed Nov 3, 2016
1 parent 95b9033 commit c034a9d
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 6 deletions.
3 changes: 2 additions & 1 deletion demo/demo.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ const colors: any = {
*ngSwitchCase="'week'"
[viewDate]="viewDate"
[events]="events"
[refresh]="refresh">
[refresh]="refresh"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-week-view>
<mwl-calendar-day-view
*ngSwitchCase="'day'"
Expand Down
4 changes: 2 additions & 2 deletions src/components/day/calendarDayView.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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';

const SEGMENT_HEIGHT: number = 30;

Expand Down Expand Up @@ -126,8 +127,7 @@ export class CalendarDayViewComponent implements OnChanges, OnInit, OnDestroy {
/**
* Called when an event is resized or dragged and dropped
*/
@Output() eventTimesChanged: EventEmitter<{newStart: Date, newEnd: Date, event: CalendarEvent}>
= new EventEmitter<{newStart: Date, newEnd: Date, event: CalendarEvent}>();
@Output() eventTimesChanged: EventEmitter<CalendarEventTimesChangedEvent> = new EventEmitter<CalendarEventTimesChangedEvent>();

hours: DayViewHour[] = [];
view: DayView;
Expand Down
71 changes: 69 additions & 2 deletions src/components/week/calendarWeekView.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ import { Subscription } from 'rxjs/Subscription';
import {
WeekDay,
CalendarEvent,
WeekViewEvent,
WeekViewEventRow,
getWeekViewHeader,
getWeekView
} from 'calendar-utils';
import { ResizeEvent } from 'angular-resizable-element';
import addDays from 'date-fns/add_days';
import { CalendarEventTimesChangedEvent } from './../../interfaces/calendarEventTimesChangedEvent.interface';

@Component({
selector: 'mwl-calendar-week-view',
Expand All @@ -34,12 +38,18 @@ import {
(click)="dayClicked.emit({date: day.date})">
</mwl-calendar-week-view-header>
</div>
<div *ngFor="let eventRow of eventRows">
<div *ngFor="let eventRow of eventRows" #container>
<div
class="cal-event-container"
*ngFor="let weekEvent of eventRow.row"
[style.width]="((100 / 7) * weekEvent.span) + '%'"
[style.marginLeft]="((100 / 7) * weekEvent.offset) + '%'">
[style.marginLeft]="((100 / 7) * weekEvent.offset) + '%'"
mwlResizable
[resizeEdges]="{left: weekEvent.event?.resizable?.beforeStart, right: weekEvent.event?.resizable?.afterEnd}"
[resizeSnapGrid]="{left: container.offsetWidth / 7, right: container.offsetWidth / 7}"
(resizeStart)="resizeStarted(weekEvent, $event)"
(resizing)="resizing(weekEvent, $event, container.offsetWidth / 7)"
(resizeEnd)="resizeEnded(weekEvent)">
<mwl-calendar-week-view-event
[weekEvent]="weekEvent"
[tooltipPlacement]="tooltipPlacement"
Expand Down Expand Up @@ -92,10 +102,23 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
*/
@Output() eventClicked: EventEmitter<{event: CalendarEvent}> = new EventEmitter<{event: CalendarEvent}>();

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

days: WeekDay[];

eventRows: WeekViewEventRow[] = [];

refreshSubscription: Subscription;

currentResize: {
originalOffset: number,
originalSpan: number,
edge: string
};

constructor(private cdr: ChangeDetectorRef, @Inject(LOCALE_ID) locale: string) {
this.locale = locale;
}
Expand Down Expand Up @@ -127,6 +150,50 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
}
}

resizeStarted(weekEvent: WeekViewEvent, resizeEvent: ResizeEvent): void {
this.currentResize = {
originalOffset: weekEvent.offset,
originalSpan: weekEvent.span,
edge: typeof resizeEvent.edges.left !== 'undefined' ? 'left' : 'right'
};
}

resizing(weekEvent: WeekViewEvent, resizeEvent: ResizeEvent, dayWidth: number): void {
if (resizeEvent.edges.left) {
const diff: number = Math.round(+resizeEvent.edges.left / dayWidth);
weekEvent.offset = this.currentResize.originalOffset + diff;
weekEvent.span = this.currentResize.originalSpan - diff;
} else if (resizeEvent.edges.right) {
const diff: number = Math.round(+resizeEvent.edges.right / dayWidth);
weekEvent.span = this.currentResize.originalSpan + diff;
}

}

resizeEnded(weekEvent: WeekViewEvent): void {

let daysDiff: number;
if (this.currentResize.edge === 'left') {
daysDiff = weekEvent.offset - this.currentResize.originalOffset;
} else {
daysDiff = weekEvent.span - this.currentResize.originalSpan;
}

weekEvent.offset = this.currentResize.originalOffset;
weekEvent.span = this.currentResize.originalSpan;

let newStart: Date = weekEvent.event.start;
let newEnd: Date = weekEvent.event.end;
if (this.currentResize.edge === 'left') {
newStart = addDays(newStart, daysDiff);
} else if (newEnd) {
newEnd = addDays(newEnd, daysDiff);
}

this.eventTimesChanged.emit({newStart, newEnd, event: weekEvent.event});

}

private refreshHeader(): void {
this.days = getWeekViewHeader({
viewDate: this.viewDate,
Expand Down
79 changes: 78 additions & 1 deletion test/calendarWeekView.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
CalendarMomentDateFormatter,
CalendarDateFormatter,
CalendarModule,
MOMENT
MOMENT,
CalendarEventTimesChangedEvent
} from './../src';
import { CalendarWeekViewComponent } from './../src/components/week/calendarWeekView.component';
import { Subject } from 'rxjs/Rx';
Expand Down Expand Up @@ -217,4 +218,80 @@ describe('calendarWeekView component', () => {
fixture.destroy();
});

it('should resize the event by dragging from the left edge', () => {
const fixture: ComponentFixture<CalendarWeekViewComponent> = TestBed.createComponent(CalendarWeekViewComponent);
fixture.componentInstance.viewDate = new Date('2016-06-27');
fixture.componentInstance.events = [{
title: 'foo',
color: {primary: '', secondary: ''},
start: moment('2016-06-27').add(4, 'hours').toDate(),
end: moment('2016-06-27').add(6, 'hours').toDate(),
resizable: {
beforeStart: 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 rect: ClientRect = event.getBoundingClientRect();
let resizeEvent: CalendarEventTimesChangedEvent;
fixture.componentInstance.eventTimesChanged.subscribe(event => {
resizeEvent = event;
});
triggerDomEvent('mousedown', document.body, {clientX: rect.left, clientY: rect.top});
fixture.detectChanges();
triggerDomEvent('mousemove', document.body, {clientX: rect.left - dayWidth, clientY: rect.top});
fixture.detectChanges();
expect(Math.round(event.getBoundingClientRect().left)).to.equal(Math.round(rect.left - dayWidth));
expect(Math.round(event.getBoundingClientRect().width)).to.equal(Math.round(rect.width + dayWidth));
triggerDomEvent('mouseup', document.body, {clientX: rect.left - dayWidth, clientY: rect.top});
fixture.detectChanges();
fixture.destroy();
expect(resizeEvent).to.deep.equal({
event: fixture.componentInstance.events[0],
newStart: moment('2016-06-27').add(4, 'hours').subtract(1, 'day').toDate(),
newEnd: moment('2016-06-27').add(6, 'hours').toDate()
});
});

it('should resize the event by dragging from the right edge', () => {
const fixture: ComponentFixture<CalendarWeekViewComponent> = TestBed.createComponent(CalendarWeekViewComponent);
fixture.componentInstance.viewDate = new Date('2016-06-27');
fixture.componentInstance.events = [{
title: 'foo',
color: {primary: '', secondary: ''},
start: moment('2016-06-27').add(4, 'hours').toDate(),
end: moment('2016-06-27').add(6, 'hours').toDate(),
resizable: {
afterEnd: 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 rect: ClientRect = event.getBoundingClientRect();
let resizeEvent: CalendarEventTimesChangedEvent;
fixture.componentInstance.eventTimesChanged.subscribe(event => {
resizeEvent = event;
});
triggerDomEvent('mousedown', document.body, {clientX: rect.right, clientY: rect.top});
fixture.detectChanges();
triggerDomEvent('mousemove', document.body, {clientX: rect.right + dayWidth, clientY: rect.top});
fixture.detectChanges();
expect(Math.round(event.getBoundingClientRect().left)).to.equal(Math.round(rect.left));
expect(Math.round(event.getBoundingClientRect().width)).to.equal(Math.round(rect.width + dayWidth));
triggerDomEvent('mouseup', document.body, {clientX: rect.right + dayWidth, clientY: rect.top});
fixture.detectChanges();
fixture.destroy();
expect(resizeEvent).to.deep.equal({
event: fixture.componentInstance.events[0],
newStart: moment('2016-06-27').add(4, 'hours').toDate(),
newEnd: moment('2016-06-27').add(6, 'hours').add(1, 'day').toDate()
});
});

});
5 changes: 5 additions & 0 deletions webpack.config.umd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ module.exports = {
commonjs: 'date-fns/add_minutes/index',
commonjs2: 'date-fns/add_minutes/index'
},
'date-fns/add_days': {
root: ['dateFns', 'addDays'],
commonjs: 'date-fns/add_days/index',
commonjs2: 'date-fns/add_days/index'
},
'angular-resizable-element': {
root: 'angularResizableElement',
commonjs: 'angular-resizable-element',
Expand Down

0 comments on commit c034a9d

Please sign in to comment.