Skip to content

Commit c034a9d

Browse files
author
Matt Lewis
committed
feat(weekView): support resizing of events
Closes #9
1 parent 95b9033 commit c034a9d

5 files changed

+156
-6
lines changed

demo/demo.component.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ const colors: any = {
8585
*ngSwitchCase="'week'"
8686
[viewDate]="viewDate"
8787
[events]="events"
88-
[refresh]="refresh">
88+
[refresh]="refresh"
89+
(eventTimesChanged)="eventTimesChanged($event)">
8990
</mwl-calendar-week-view>
9091
<mwl-calendar-day-view
9192
*ngSwitchCase="'day'"

src/components/day/calendarDayView.component.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import { getDayView, getDayViewHourGrid, CalendarEvent, DayView, DayViewHour } from 'calendar-utils';
1515
import { Subject } from 'rxjs/Subject';
1616
import { Subscription } from 'rxjs/Subscription';
17+
import { CalendarEventTimesChangedEvent } from './../../interfaces/calendarEventTimesChangedEvent.interface';
1718

1819
const SEGMENT_HEIGHT: number = 30;
1920

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

132132
hours: DayViewHour[] = [];
133133
view: DayView;

src/components/week/calendarWeekView.component.ts

+69-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@ import { Subscription } from 'rxjs/Subscription';
1616
import {
1717
WeekDay,
1818
CalendarEvent,
19+
WeekViewEvent,
1920
WeekViewEventRow,
2021
getWeekViewHeader,
2122
getWeekView
2223
} from 'calendar-utils';
24+
import { ResizeEvent } from 'angular-resizable-element';
25+
import addDays from 'date-fns/add_days';
26+
import { CalendarEventTimesChangedEvent } from './../../interfaces/calendarEventTimesChangedEvent.interface';
2327

2428
@Component({
2529
selector: 'mwl-calendar-week-view',
@@ -34,12 +38,18 @@ import {
3438
(click)="dayClicked.emit({date: day.date})">
3539
</mwl-calendar-week-view-header>
3640
</div>
37-
<div *ngFor="let eventRow of eventRows">
41+
<div *ngFor="let eventRow of eventRows" #container>
3842
<div
3943
class="cal-event-container"
4044
*ngFor="let weekEvent of eventRow.row"
4145
[style.width]="((100 / 7) * weekEvent.span) + '%'"
42-
[style.marginLeft]="((100 / 7) * weekEvent.offset) + '%'">
46+
[style.marginLeft]="((100 / 7) * weekEvent.offset) + '%'"
47+
mwlResizable
48+
[resizeEdges]="{left: weekEvent.event?.resizable?.beforeStart, right: weekEvent.event?.resizable?.afterEnd}"
49+
[resizeSnapGrid]="{left: container.offsetWidth / 7, right: container.offsetWidth / 7}"
50+
(resizeStart)="resizeStarted(weekEvent, $event)"
51+
(resizing)="resizing(weekEvent, $event, container.offsetWidth / 7)"
52+
(resizeEnd)="resizeEnded(weekEvent)">
4353
<mwl-calendar-week-view-event
4454
[weekEvent]="weekEvent"
4555
[tooltipPlacement]="tooltipPlacement"
@@ -92,10 +102,23 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
92102
*/
93103
@Output() eventClicked: EventEmitter<{event: CalendarEvent}> = new EventEmitter<{event: CalendarEvent}>();
94104

105+
/**
106+
* Called when an event is resized or dragged and dropped
107+
*/
108+
@Output() eventTimesChanged: EventEmitter<CalendarEventTimesChangedEvent> = new EventEmitter<CalendarEventTimesChangedEvent>();
109+
95110
days: WeekDay[];
111+
96112
eventRows: WeekViewEventRow[] = [];
113+
97114
refreshSubscription: Subscription;
98115

116+
currentResize: {
117+
originalOffset: number,
118+
originalSpan: number,
119+
edge: string
120+
};
121+
99122
constructor(private cdr: ChangeDetectorRef, @Inject(LOCALE_ID) locale: string) {
100123
this.locale = locale;
101124
}
@@ -127,6 +150,50 @@ export class CalendarWeekViewComponent implements OnChanges, OnInit, OnDestroy {
127150
}
128151
}
129152

153+
resizeStarted(weekEvent: WeekViewEvent, resizeEvent: ResizeEvent): void {
154+
this.currentResize = {
155+
originalOffset: weekEvent.offset,
156+
originalSpan: weekEvent.span,
157+
edge: typeof resizeEvent.edges.left !== 'undefined' ? 'left' : 'right'
158+
};
159+
}
160+
161+
resizing(weekEvent: WeekViewEvent, resizeEvent: ResizeEvent, dayWidth: number): void {
162+
if (resizeEvent.edges.left) {
163+
const diff: number = Math.round(+resizeEvent.edges.left / dayWidth);
164+
weekEvent.offset = this.currentResize.originalOffset + diff;
165+
weekEvent.span = this.currentResize.originalSpan - diff;
166+
} else if (resizeEvent.edges.right) {
167+
const diff: number = Math.round(+resizeEvent.edges.right / dayWidth);
168+
weekEvent.span = this.currentResize.originalSpan + diff;
169+
}
170+
171+
}
172+
173+
resizeEnded(weekEvent: WeekViewEvent): void {
174+
175+
let daysDiff: number;
176+
if (this.currentResize.edge === 'left') {
177+
daysDiff = weekEvent.offset - this.currentResize.originalOffset;
178+
} else {
179+
daysDiff = weekEvent.span - this.currentResize.originalSpan;
180+
}
181+
182+
weekEvent.offset = this.currentResize.originalOffset;
183+
weekEvent.span = this.currentResize.originalSpan;
184+
185+
let newStart: Date = weekEvent.event.start;
186+
let newEnd: Date = weekEvent.event.end;
187+
if (this.currentResize.edge === 'left') {
188+
newStart = addDays(newStart, daysDiff);
189+
} else if (newEnd) {
190+
newEnd = addDays(newEnd, daysDiff);
191+
}
192+
193+
this.eventTimesChanged.emit({newStart, newEnd, event: weekEvent.event});
194+
195+
}
196+
130197
private refreshHeader(): void {
131198
this.days = getWeekViewHeader({
132199
viewDate: this.viewDate,

test/calendarWeekView.component.spec.ts

+78-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
CalendarMomentDateFormatter,
1212
CalendarDateFormatter,
1313
CalendarModule,
14-
MOMENT
14+
MOMENT,
15+
CalendarEventTimesChangedEvent
1516
} from './../src';
1617
import { CalendarWeekViewComponent } from './../src/components/week/calendarWeekView.component';
1718
import { Subject } from 'rxjs/Rx';
@@ -217,4 +218,80 @@ describe('calendarWeekView component', () => {
217218
fixture.destroy();
218219
});
219220

221+
it('should resize the event by dragging from the left edge', () => {
222+
const fixture: ComponentFixture<CalendarWeekViewComponent> = TestBed.createComponent(CalendarWeekViewComponent);
223+
fixture.componentInstance.viewDate = new Date('2016-06-27');
224+
fixture.componentInstance.events = [{
225+
title: 'foo',
226+
color: {primary: '', secondary: ''},
227+
start: moment('2016-06-27').add(4, 'hours').toDate(),
228+
end: moment('2016-06-27').add(6, 'hours').toDate(),
229+
resizable: {
230+
beforeStart: true
231+
}
232+
}];
233+
fixture.componentInstance.ngOnChanges({viewDate: {}, events: {}});
234+
fixture.detectChanges();
235+
document.body.appendChild(fixture.nativeElement);
236+
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event-container');
237+
const dayWidth: number = event.parentElement.offsetWidth / 7;
238+
const rect: ClientRect = event.getBoundingClientRect();
239+
let resizeEvent: CalendarEventTimesChangedEvent;
240+
fixture.componentInstance.eventTimesChanged.subscribe(event => {
241+
resizeEvent = event;
242+
});
243+
triggerDomEvent('mousedown', document.body, {clientX: rect.left, clientY: rect.top});
244+
fixture.detectChanges();
245+
triggerDomEvent('mousemove', document.body, {clientX: rect.left - dayWidth, clientY: rect.top});
246+
fixture.detectChanges();
247+
expect(Math.round(event.getBoundingClientRect().left)).to.equal(Math.round(rect.left - dayWidth));
248+
expect(Math.round(event.getBoundingClientRect().width)).to.equal(Math.round(rect.width + dayWidth));
249+
triggerDomEvent('mouseup', document.body, {clientX: rect.left - dayWidth, clientY: rect.top});
250+
fixture.detectChanges();
251+
fixture.destroy();
252+
expect(resizeEvent).to.deep.equal({
253+
event: fixture.componentInstance.events[0],
254+
newStart: moment('2016-06-27').add(4, 'hours').subtract(1, 'day').toDate(),
255+
newEnd: moment('2016-06-27').add(6, 'hours').toDate()
256+
});
257+
});
258+
259+
it('should resize the event by dragging from the right edge', () => {
260+
const fixture: ComponentFixture<CalendarWeekViewComponent> = TestBed.createComponent(CalendarWeekViewComponent);
261+
fixture.componentInstance.viewDate = new Date('2016-06-27');
262+
fixture.componentInstance.events = [{
263+
title: 'foo',
264+
color: {primary: '', secondary: ''},
265+
start: moment('2016-06-27').add(4, 'hours').toDate(),
266+
end: moment('2016-06-27').add(6, 'hours').toDate(),
267+
resizable: {
268+
afterEnd: true
269+
}
270+
}];
271+
fixture.componentInstance.ngOnChanges({viewDate: {}, events: {}});
272+
fixture.detectChanges();
273+
document.body.appendChild(fixture.nativeElement);
274+
const event: HTMLElement = fixture.nativeElement.querySelector('.cal-event-container');
275+
const dayWidth: number = event.parentElement.offsetWidth / 7;
276+
const rect: ClientRect = event.getBoundingClientRect();
277+
let resizeEvent: CalendarEventTimesChangedEvent;
278+
fixture.componentInstance.eventTimesChanged.subscribe(event => {
279+
resizeEvent = event;
280+
});
281+
triggerDomEvent('mousedown', document.body, {clientX: rect.right, clientY: rect.top});
282+
fixture.detectChanges();
283+
triggerDomEvent('mousemove', document.body, {clientX: rect.right + dayWidth, clientY: rect.top});
284+
fixture.detectChanges();
285+
expect(Math.round(event.getBoundingClientRect().left)).to.equal(Math.round(rect.left));
286+
expect(Math.round(event.getBoundingClientRect().width)).to.equal(Math.round(rect.width + dayWidth));
287+
triggerDomEvent('mouseup', document.body, {clientX: rect.right + dayWidth, clientY: rect.top});
288+
fixture.detectChanges();
289+
fixture.destroy();
290+
expect(resizeEvent).to.deep.equal({
291+
event: fixture.componentInstance.events[0],
292+
newStart: moment('2016-06-27').add(4, 'hours').toDate(),
293+
newEnd: moment('2016-06-27').add(6, 'hours').add(1, 'day').toDate()
294+
});
295+
});
296+
220297
});

webpack.config.umd.ts

+5
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ module.exports = {
6464
commonjs: 'date-fns/add_minutes/index',
6565
commonjs2: 'date-fns/add_minutes/index'
6666
},
67+
'date-fns/add_days': {
68+
root: ['dateFns', 'addDays'],
69+
commonjs: 'date-fns/add_days/index',
70+
commonjs2: 'date-fns/add_days/index'
71+
},
6772
'angular-resizable-element': {
6873
root: 'angularResizableElement',
6974
commonjs: 'angular-resizable-element',

0 commit comments

Comments
 (0)