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

I've added a basic resource month view to your fullcalendar folk #53

Open
wants to merge 5 commits into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions demos/resource-views.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,resourceDay'
right: 'month,agendaWeek,resourceDay,resourceMonth'
},
defaultView: 'resourceDay',
defaultView: 'resourceMonth',
editable: true,
droppable: true,
resources: [
Expand Down Expand Up @@ -77,26 +77,30 @@
title: 'R1-R2: Lunch 12.15-14.45',
start: new Date(y, m, d, 12, 15),
end: new Date(y, m, d, 14, 45),
allDay: false,
resources: ['resource1', 'resource2']
color: '#C22326',
allDay: false /*,
resources: ['resource1', 'resource2'] */
},
{
title: 'R1: All day',
start: new Date(y, m, d, 10, 30),
end: new Date(y, m, d, 11, 0),
color: '#F37338',
allDay: true,
resources: 'resource1'
},
{
title: 'R2: Meeting 11.00',
start: new Date(y, m, d, 11, 0),
color: '#FDB632',
allDay: true,
resources: 'resource2'
},
{
title: 'R1/R2: Lunch 12-14',
start: new Date(y, m, d, 12, 0),
end: new Date(y, m, d, 14, 0),
color: '#027878',
allDay: false,
resources: ['resource1', 'resource2']
},
Expand All @@ -105,27 +109,31 @@
title: 'R1: Lunch',
start: new Date(y, m, d, 12, 0),
end: new Date(y, m, d, 14, 0),
color: '#801638',
allDay: false,
resources: ['resource1']
},
{
title: 'R3: Breakfast',
start: new Date(y, m, d, 8, 0),
end: new Date(y, m, d, 8, 30),
color: '#EBC137',
allDay: false,
resources: ['resource3']
},
{
id: 999,
title: 'Repeating Event',
start: new Date(y, m, d - 3, 16, 0),
color: '#E38C2D',
allDay: false,
resources: 'resource2'
},
{
id: 999,
title: 'Repeating Event',
start: new Date(y, m, d + 4, 16, 0),
color: '#DB4C2C',
allDay: false,
resources: 'resource2'
}
Expand Down
2 changes: 2 additions & 0 deletions lumbar.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
"src/agenda/AgendaEventRenderer.js",
"src/resource/ResourceDayView.js",
"src/resource/ResourceView.js",
"src/resource/ResourceMonthView.js",
"src/resource/ResourceEventRenderer.js",
"src/resource/ResourceMonthEventRenderer.js",
"src/common/View.js",
"src/common/DayEventRenderer.js",
"src/common/SelectionManager.js",
Expand Down
27 changes: 4 additions & 23 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,7 @@
[![Build Status](https://travis-ci.org/seankenny/fullcalendar.png?branch=v2)](https://travis-ci.org/seankenny/fullcalendar)

#FORK INFO
#Resource Month Calendar View fork
This fork adds a vertical resource view to FullCalendar. Some details on usage, etc are available here:
<a href="http://www.seankenny.me/blog/2013/08/14/fullcalendar-with-a-resource-day-view/" target="_blank">http://www.seankenny.me/blog/2013/08/14/fullcalendar-with-a-resource-day-view/</a>
<a href="http://www.seankenny.me/blog/2014/07/24/resource-fullcalendar-dragging-and-clicking/" target="_blank">http://www.seankenny.me/blog/2014/07/24/resource-fullcalendar-dragging-and-clicking/</a>
<a href="ttp://www.seankenny.me/blog/2014/08/11/fullcalendar-with-a-resource-day-view-v2-0-2/" target="_blank">http://www.seankenny.me/blog/2014/08/11/fullcalendar-with-a-resource-day-view-v2-0-2/</a>

[plunkr demo](http://plnkr.co/KRXcK2oNd9eX2IMBM6yY).

# FullCalendar

A full-sized drag & drop event calendar (jQuery plugin).

- [Project website and demos](http://arshaw.com/fullcalendar/)
- [Documentation](http://arshaw.com/fullcalendar/docs/)
- [Support](http://arshaw.com/fullcalendar/support/)
- [Changelog](changelog.md)
- [License](license.txt)

For contributors:
![screenshot](https://cloud.githubusercontent.com/assets/3748334/6966722/0996aeee-d953-11e4-9d97-0d83fcf6b25e.png)

- [Ways to contribute](http://arshaw.com/fullcalendar/wiki/Contributing/)
- [General coding guidelines](https://github.com/arshaw/fullcalendar/wiki/Contributing-Code)
- [Contributing features](https://github.com/arshaw/fullcalendar/wiki/Contributing-Features)
- [Contributing bugfixes](https://github.com/arshaw/fullcalendar/wiki/Contributing-Bugfixes)
- [Original Project website and demos](https://github.com/fullcalendar/fullcalendar)
- [This project is a fork of] (https://github.com/seankenny/fullcalendar)
5 changes: 5 additions & 0 deletions src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,8 @@ html .fc,
}



.fcDayContentResource {
float:left;
height:50px;
}
171 changes: 171 additions & 0 deletions src/resource/ResourceMonthEventRenderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
function ResourceEventMonthRenderer() {
var t = this;

// imports
BasicEventRenderer.call(t);

// exports
t.renderEvents = renderEvents;
t.dayStart = moment.duration("07:00:00");
t.dayEnd = moment.duration("18:00:00");
t.hoursInDay = t.dayEnd.asHours() - t.dayStart.asHours();
t.getSegmentsForEvent = getSegmentsForEvent;
t.getCellForDateAndResource = getCellForDateAndResource;
t.resources = t.calendar.fetchResources(true, t);

/* Rendering
----------------------------------------------------------------------------*/

function renderEvents(events, modifiedEventId) {
events.forEach(function(event, eventIndex) {
var segments = t.getSegmentsForEvent(event);

segments.forEach(function(segment, segmentIndex) {

var divForResource = t.getCellForDateAndResource(segment.date, segment.resourceIndex);

if (divForResource.length > 0) {
var resourceBookingDivTable = $('<div></div>');
divForResource.append(resourceBookingDivTable);
var resourceDivHeight = divForResource.height();
var bookingStart = segment.startHour;
var bookingEnd = segment.endHour;
var divtop = (resourceDivHeight * (bookingStart - t.dayStart.asHours())) / (t.hoursInDay);
var divheight = (resourceDivHeight * (bookingEnd - bookingStart)) / (t.hoursInDay);
if (divheight === 0) {
divheight = 2;
}
resourceBookingDivTable.attr("title", event.title + ' - ' + bookingStart + ' - ' + bookingEnd);
resourceBookingDivTable.css("top", divtop + "px");
resourceBookingDivTable.css("height", divheight + "px");
resourceBookingDivTable.css("width", Math.floor(100 / t.resources.length) + "%");
resourceBookingDivTable.css("background-color", event.color);
resourceBookingDivTable.css("position", "absolute");
resourceBookingDivTable.css("opacity","0.3");
}
});
});
}


function getCellForDateAndResource(date, resourceIndex) {
var dataDate = '.fc-day[data-date="' + date.format("YYYY-MM-DD") + '"]';
var resourceContent = $(dataDate).find('#resourceContent' + date.format("YYYYMMDD") + "R" + resourceIndex);
return resourceContent;
}

function getSegmentsForEvent(event) {
var segments = [];

var mStart = moment(event.start);
var mEnd = moment(event.end);
if (!mEnd.isValid()) {
mEnd = moment(mStart).add(2,'hour');
}
if (event.allDay) {
mEnd = moment(event.start).add(t.dayEnd.asHours(), 'hour');
}
var numDays = Math.ceil(moment.duration(mEnd.diff(mStart)).asDays());
if (numDays === 0) {
numDays = 1;
}
var startDate = moment(mStart).startOf('day');

if(event.resources.length === 0) {
// resources property on event is not specified, assume event uses all resources!
t.calendar.options.resources.forEach(function(resource, resourceIndex) {

//console.info("resource:" + resource +"; index:"+resourceIndex);
if (resourceIndex > -1) {
segments = segments.concat(createSegmentsForResource(resource, resourceIndex, numDays, mStart, mEnd, startDate, event.allDay));
}

});

} else
if (event.resources instanceof Array) {

event.resources.forEach(function(resource, resourceIndex) {
segments = segments.concat(createSegmentsForResource(resource, resourceIndex, numDays, mStart, mEnd, startDate, event.allDay));
});

} else {
var resourceIndex = getResourceIndexFromId(event.resources, t.calendar.options.resources);
segments = segments.concat(createSegmentsForResource(event.resources, resourceIndex, numDays, mStart, mEnd, startDate, event.allDay));
}
return segments;
}

function getResourceIndexFromId(resourceId, list) {
var result = -1;
list.forEach(function(resource,resourceIndex) {
if (resourceId == resource.id) {
result = resourceIndex;
}
});
return result;
}

// creates a segment per resource per day.
function createSegmentsForResource(resource, resourceIndex, numDays, mStart, mEnd, startDate, allDay) {
var results = [];
if (allDay) {
for (var dayIndex=0;dayIndex<numDays;dayIndex++) {
var allDaySegment = {};
allDaySegment.date = moment(startDate).add(dayIndex, 'd');
allDaySegment.resource = resource;
allDaySegment.resourceIndex = resourceIndex;
allDaySegment.startHour = t.dayStart.asHours();
allDaySegment.endHour = t.dayEnd.asHours();
results.push(allDaySegment);
}

} else {

for (var i=0;i<numDays;i++) {
var dateInc = moment(startDate).add(i, 'd');
var segment = {};
segment.date = moment(dateInc);
segment.resource = resource;
segment.resourceIndex = resourceIndex;
if (i===0) {
// segment for first day of event
if (numDays == 1) {
// event does not span multiple days
segment.startHour = moment.duration(mStart).asHours();
segment.endHour = moment.duration(mEnd).asHours();
} else if (numDays > 1){
// event spans multiple days
var startOfSegmentDay = moment(mStart).startOf('day');
segment.startHour = moment.duration(moment(mStart).diff(startOfSegmentDay)).asHours();
segment.endHour = t.dayEnd.asHours();
}
} else
{
if (i==numDays-1) {
// segment for last day of event
segment.startHour = moment.duration(t.dayStart).asHours();
segment.endHour = moment.duration(mEnd).asHours();
} else
{
// segment for day between start and end of event
segment.startHour = moment.duration(t.dayStart).asHours();
segment.endHour = moment.duration(t.dayEnd).asHours();
}
}

if (segment.startHour < t.dayStart.asHours()) {
segment.startHour = t.dayStart.asHours();
}

if (segment.endHour > t.dayEnd.asHours()) {
segment.endHour = t.dayEnd.asHours();
}

results.push(segment);
}
}
return results;
}

}
64 changes: 64 additions & 0 deletions src/resource/ResourceMonthView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

fcViews.resourceMonth = ResourceMonthView;

function ResourceMonthView(element, calendar) {
var t = this;

// exports
t.incrementDate = incrementDate;
t.render = render;

// imports
BasicView.call(t, element, calendar, 'resourceMonth');
ResourceEventMonthRenderer.call(t);
t.calendar.options.dayRender = dayRender;

function incrementDate(date, delta) {
return date.clone().stripTime().add('months', delta).startOf('month');
}

function render(date) {
t.intervalStart = date.clone().stripTime().startOf('month');
t.intervalEnd = t.intervalStart.clone().add('months', 1);

t.start = t.intervalStart.clone();
t.start = t.skipHiddenDays(t.start); // move past the first week if no visible days
t.start.startOf('week');
t.start = t.skipHiddenDays(t.start); // move past the first invisible days of the week

t.end = t.intervalEnd.clone();
t.end = t.skipHiddenDays(t.end, -1, true); // move in from the last week if no visible days
t.end.add((7 - t.end.weekday()) % 7, 'days'); // move to end of week if not already
t.end = t.skipHiddenDays(t.end, -1, true); // move in from the last invisible days of the week

var rowCnt = Math.ceil( // need to ceil in case there are hidden days
t.end.diff(t.start, 'weeks', true) // returnfloat=true
);
if (t.opt('weekMode') == 'fixed') {
t.end.add('weeks', 6 - rowCnt);
rowCnt = 6;
}

t.title = calendar.formatDate(t.intervalStart, t.opt('titleFormat'));

t.renderBasic(rowCnt, t.getCellsPerWeek(), true);
}

function dayRender(date, cell) {
var mContainer = moment(date);
var datePostfix = mContainer.format("YYYYMMDD");
var idString = "wxx" + datePostfix;
var fcDayContent = $(cell).find('.fc-day-content');
fcDayContent.children().empty();
var wrapper = $('<div id="' + idString + '" class="fcDayContentWrapper"></div>');
fcDayContent.children().append(wrapper);

t.resources.forEach(function(resource, resourceIndex) {
var resourceDiv = $('<div id="resourceContent' + datePostfix +"R"+ resourceIndex + '" class="fcDayContentResource"></div>');
resourceDiv.css("width", Math.floor(100 / t.resources.length) + "%");
resourceDiv.css("height", "80px");

wrapper.append(resourceDiv);
});
}
}