Skip to content
This repository has been archived by the owner on Jun 19, 2018. It is now read-only.

Commit

Permalink
feat(WeekViewWithTimes): Combine WeekView and DayView
Browse files Browse the repository at this point in the history
  • Loading branch information
asurinov committed Nov 12, 2015
1 parent 2a5a51a commit cb62228
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 43 deletions.
32 changes: 29 additions & 3 deletions src/directives/mwlCalendarWeek.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ angular
vm.dayViewEnd,
vm.dayViewSplit
);

vm.view = calendarHelper.getWeekView(vm.events, vm.currentDay, vm.showTimes);
if (vm.showTimes) {
vm.view = calendarHelper.getWeekViewWithTimes(
vm.viewWithTimes = calendarHelper.getWeekViewWithTimes(
vm.events,
vm.currentDay,
vm.dayViewStart,
vm.dayViewEnd,
vm.dayViewSplit
);
} else {
vm.view = calendarHelper.getWeekView(vm.events, vm.currentDay);
}
});

Expand Down Expand Up @@ -74,6 +74,32 @@ angular
event.tempStartsAt = moment(event.startsAt).add(minutesDiff, 'minutes').toDate();
};

vm.eventResizeComplete = function(event, edge, minuteChunksMoved) {
var minutesDiff = minuteChunksMoved * vm.dayViewSplit;
var start = moment(event.startsAt);
var end = moment(event.endsAt);
if (edge === 'start') {
start.add(minutesDiff, 'minutes');
} else {
end.add(minutesDiff, 'minutes');
}
delete event.tempStartsAt;

vm.onEventTimesChanged({
calendarEvent: event,
calendarNewEventStart: start.toDate(),
calendarNewEventEnd: end.toDate()
});
};

vm.eventResized = function(event, edge, minuteChunksMoved) {
var minutesDiff = minuteChunksMoved * vm.dayViewSplit;
if (edge === 'start') {
event.tempStartsAt = moment(event.startsAt).add(minutesDiff, 'minutes').toDate();
}
};


})
.directive('mwlCalendarWeek', function(calendarUseTemplates) {

Expand Down
84 changes: 69 additions & 15 deletions src/services/calendarHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ angular

}

function getWeekView(events, currentDay) {
function getWeekView(events, currentDay, filterOneDayEvents) {

var startOfWeek = moment(currentDay).startOf('week');
var endOfWeek = moment(currentDay).endOf('week');
Expand All @@ -181,6 +181,12 @@ angular
dayCounter.add(1, 'day');
}

if (filterOneDayEvents) {
events = events.filter(function(event) {
return !moment(event.startsAt).isSame(moment(event.endsAt), 'day');
});
}

var eventsSorted = filterEventsInPeriod(events, startOfWeek, endOfWeek).map(function(event) {

var eventStart = moment(event.startsAt).startOf('day');
Expand Down Expand Up @@ -215,8 +221,45 @@ angular

}

function getDayView(events, currentDay, dayViewStart, dayViewEnd, dayViewSplit) {
function getCrossingsCount(event, dayEvents) {
var eventStart = moment(event.startsAt);
var eventEnd = moment(event.endsAt);

return dayEvents.filter(function(ev) {

return event.$id !== ev.$id &&
(moment(ev.startsAt).isBetween(eventStart, eventEnd) ||
moment(ev.startsAt).isSame(eventStart) ||
moment(ev.endsAt).isBetween(eventStart, eventEnd) ||
moment(ev.endsAt).isSame(eventEnd) ||
moment(ev.startsAt).isBefore(eventStart) && moment(ev.endsAt).isAfter(eventEnd));
}).length;
}

function eventsComparer(a, b) {
var aStart = moment(a.startsAt);
var bStart = moment(b.startsAt);

if (aStart.isBefore(bStart)) {
return -1;
}

if (aStart.isSame(bStart)) {
var aEnd = moment(a.endsAt);
var bEnd = moment(b.endsAt);

if(aEnd.isSame(bEnd)){
return 0;
}
else if (aEnd.isAfter(bEnd)) {
return -1;
}
return 1;
}
}

function getDayView(events, currentDay, dayViewStart, dayViewEnd, dayViewSplit, isWeekViewWithTimes) {
var baseBucketWidth = isWeekViewWithTimes ? 14.285714285714285 : 150;
var dayStartHour = moment(dayViewStart || '00:00', 'HH:mm').hours();
var dayEndHour = moment(dayViewEnd || '23:00', 'HH:mm').hours();
var hourHeight = (60 / dayViewSplit) * 30;
Expand All @@ -231,7 +274,7 @@ angular
moment(currentDay).endOf('day').toDate()
);

return eventsInPeriod.map(function(event) {
return eventsInPeriod.sort(eventsComparer).map(function(event) {
if (moment(event.startsAt).isBefore(calendarStart)) {
event.top = 0;
} else {
Expand All @@ -257,12 +300,10 @@ angular
}

event.left = 0;

return event;
}).filter(function(event) {
return event.height > 0;
}).map(function(event) {

var cannotFitInABucket = true;
buckets.forEach(function(bucket, bucketIndex) {
var canFitInThisBucket = true;
Expand All @@ -276,36 +317,47 @@ angular

if (canFitInThisBucket && cannotFitInABucket) {
cannotFitInABucket = false;
event.left = bucketIndex * 150;
event.left = bucketIndex * baseBucketWidth;
if (isWeekViewWithTimes) {
event.bucketIndex = buckets.length;
}
buckets[bucketIndex].push(event);
}

});

if (cannotFitInABucket) {
event.left = buckets.length * 150;
event.left = buckets.length * baseBucketWidth;
if (isWeekViewWithTimes) {
event.bucketIndex = buckets.length;
}
buckets.push([event]);
}

return event;

}).map(function(event) {
if (isWeekViewWithTimes) {
event.width = getCrossingsCount(event, eventsInPeriod) > 0 ? baseBucketWidth / buckets.length : baseBucketWidth;
event.left = event.bucketIndex * baseBucketWidth / (buckets.length);
delete event.bucketIndex;
}
return event;
});

}

function getWeekViewWithTimes(events, currentDay, dayViewStart, dayViewEnd, dayViewSplit) {
var weekView = getWeekView(events, currentDay);
var weekView = getWeekView(events, currentDay, false);
var newEvents = [];
weekView.days.forEach(function(day) {
var dayEvents = weekView.events.filter(function(event) {
return moment(event.startsAt).startOf('day').isSame(moment(day.date).startOf('day'));
return moment(event.startsAt).isSame(moment(day.date), 'day') &&
moment(event.endsAt).isSame(moment(day.date), 'day');
});
var newDayEvents = getDayView(
dayEvents,
day.date,
dayViewStart,
dayViewEnd,
dayViewSplit
dayViewSplit,
true
);
newEvents = newEvents.concat(newDayEvents);
});
Expand All @@ -330,7 +382,9 @@ angular
getDayViewHeight: getDayViewHeight,
adjustEndDateFromStartDiff: adjustEndDateFromStartDiff,
formatDate: formatDate,
eventIsInPeriod: eventIsInPeriod //expose for testing only
eventIsInPeriod: eventIsInPeriod, //expose for testing only
getCrossingsCount: getCrossingsCount, //expose for testing only
eventsComparer: eventsComparer //expose for testing only
};

});
54 changes: 43 additions & 11 deletions src/templates/calendarWeekView.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,38 @@
</div>

<div class="cal-day-panel clearfix" ng-style="{height: vm.showTimes ? (vm.dayViewHeight + 'px') : 'auto'}">
<div class="row">
<div class="col-xs-12">
<div
class="cal-row-fluid"
ng-repeat="event in vm.view.events track by event.$id">
<div
ng-class="'cal-cell' + event.daySpan + ' cal-offset' + event.dayOffset + ' day-highlight dh-event-' + event.type + ' ' + event.cssClass"
ng-style="{top: 'auto', position: 'inherit'}"
data-event-class
mwl-draggable="event.draggable === true"
axis="'x'"
snap-grid="{x: vm.dayColumnDimensions.width}"
on-drag="vm.tempTimeChanged(event, y)"
on-drag-end="vm.weekDragged(event, x, y)"
mwl-resizable="event.resizable === true && event.endsAt"
resize-edges="{left: true, right: true}"
on-resize-end="vm.weekResized(event, edge, x)">
<strong ng-bind="(event.tempStartsAt || event.startsAt) | calendarDate:'time':true" ng-show="vm.showTimes"></strong>
<a
href="javascript:;"
ng-click="vm.onEventClick({calendarEvent: event})"
class="event-item"
ng-bind-html="vm.$sce.trustAsHtml(event.title)"
tooltip-html-unsafe="{{ event.title }}"
tooltip-placement="left"
tooltip-append-to-body="true">
</a>
</div>
</div>
</div>

</div>

<mwl-calendar-hour-list
day-view-start="vm.dayViewStart"
Expand All @@ -35,25 +67,25 @@
current-day="vm.currentDay"
ng-if="vm.showTimes">
</mwl-calendar-hour-list>

<div class="row">
<div class="row" ng-if="vm.showTimes">
<div class="col-xs-12">
<div
class="cal-row-fluid "
ng-repeat="event in vm.view.events track by event.$id">
class="cal-row-fluid"
ng-repeat="event in vm.viewWithTimes.events track by event.$id">
<div
ng-class="'cal-cell' + (vm.showTimes ? 1 : event.daySpan) + ' cal-offset' + event.dayOffset + ' day-highlight dh-event-' + event.type + ' ' + event.cssClass"
ng-style="{top: vm.showTimes ? ((event.top + 2) + 'px') : 'auto', position: vm.showTimes ? 'absolute' : 'inherit'}"
ng-class="'cal-cell' + 1 + ' cal-offset' + event.dayOffset + ' day-highlight dh-event-' + event.type + ' ' + event.cssClass"
ng-style="{top: ((event.top + 2) + 'px'), position: 'absolute', height: event.height + 'px', left: event.left + '%', width: event.width + '%'}"
data-event-class
mwl-draggable="event.draggable === true"
axis="vm.showTimes ? 'xy' : 'x'"
snap-grid="vm.showTimes ? {x: vm.dayColumnDimensions.width, y: 30} : {x: vm.dayColumnDimensions.width}"
snap-grid="{x: vm.dayColumnDimensions.width, y: 30}"
on-drag="vm.tempTimeChanged(event, y)"
on-drag-end="vm.weekDragged(event, x, y)"
mwl-resizable="event.resizable === true && event.endsAt && !vm.showTimes"
resize-edges="{left: true, right: true}"
on-resize-end="vm.weekResized(event, edge, x)">
<strong ng-bind="(event.tempStartsAt || event.startsAt) | calendarDate:'time':true" ng-show="vm.showTimes"></strong>
mwl-resizable="event.resizable === true && event.endsAt"
resize-edges="{top: true, bottom: true}"
on-resize="vm.eventResized(event, edge, y)"
on-resize-end="vm.eventResizeComplete(event, edge, y)">
<strong ng-bind="(event.tempStartsAt || event.startsAt) | calendarDate:'time':true"></strong>
<a
href="javascript:;"
ng-click="vm.onEventClick({calendarEvent: event})"
Expand Down
11 changes: 6 additions & 5 deletions test/unit/directives/mwlCalendarWeek.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,19 @@ describe('mwlCalendarWeek directive', function() {

it('should get the new week view when calendar refreshes', function() {
sinon.stub(calendarHelper, 'getDayViewHeight').returns(1000);
sinon.stub(calendarHelper, 'getWeekView').returns({event: 'event1'});
sinon.stub(calendarHelper, 'getWeekViewWithTimes').returns({event: 'event2'});
sinon.stub(calendarHelper, 'getWeekView').returns({events: [{title: 'event1'}, {title: 'oneDayEvent'}]});
sinon.stub(calendarHelper, 'getWeekViewWithTimes').returns({events: [{title: 'oneDayEvent'}]});
scope.$broadcast('calendar.refreshView');
expect(calendarHelper.getDayViewHeight).to.have.been.calledWith('06:00', '22:00', 30);
expect(MwlCalendarCtrl.dayViewHeight).to.equal(1000);
expect(calendarHelper.getWeekView).to.have.been.calledWith(scope.events, scope.currentDay);
expect(MwlCalendarCtrl.view).to.eql({event: 'event1'});
expect(calendarHelper.getWeekView).to.have.been.calledWith(scope.events, scope.currentDay, false);
expect(MwlCalendarCtrl.view).to.eql({events: [{title: 'event1'}, {title: 'oneDayEvent'}]});

MwlCalendarCtrl.showTimes = true;
scope.$broadcast('calendar.refreshView');
expect(calendarHelper.getWeekView).to.have.been.calledWith(scope.events, scope.currentDay, true);
expect(calendarHelper.getWeekViewWithTimes).to.have.been.calledWith(scope.events, scope.currentDay, '06:00', '22:00', 30);
expect(MwlCalendarCtrl.view).to.eql({event: 'event2'});
expect(MwlCalendarCtrl.viewWithTimes).to.eql({events: [{title: 'oneDayEvent'}]});
});

it('should call the callback function when you finish dragging and event', function() {
Expand Down
Loading

0 comments on commit cb62228

Please sign in to comment.