optimized all-day events in agenda view, added tests
This commit is contained in:
parent
1667943d1c
commit
f19e54488c
5 changed files with 2326 additions and 11 deletions
234
src/agenda.js
234
src/agenda.js
|
@ -79,11 +79,18 @@ function Agenda(element, options, methods) {
|
||||||
colCnt,
|
colCnt,
|
||||||
axisWidth, colWidth, slotHeight,
|
axisWidth, colWidth, slotHeight,
|
||||||
viewWidth, viewHeight,
|
viewWidth, viewHeight,
|
||||||
cachedDaySegs=[], cachedSlotSegs=[],
|
cachedEvents=[],
|
||||||
|
daySegmentContainer,
|
||||||
|
daySegments=[],
|
||||||
|
slotSegmentContainer,
|
||||||
|
slotSegments=[],
|
||||||
tm, firstDay,
|
tm, firstDay,
|
||||||
nwe, // no weekends (int)
|
nwe, // no weekends (int)
|
||||||
rtl, dis, dit, // day index sign / translate
|
rtl, dis, dit, // day index sign / translate
|
||||||
minMinute, maxMinute,
|
minMinute, maxMinute,
|
||||||
|
dayContentElements=[],
|
||||||
|
dayContentLefts=[],
|
||||||
|
dayContentRights=[],
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
view = $.extend(this, viewMethods, methods, {
|
view = $.extend(this, viewMethods, methods, {
|
||||||
|
@ -170,6 +177,9 @@ function Agenda(element, options, methods) {
|
||||||
head = $(s).appendTo(element);
|
head = $(s).appendTo(element);
|
||||||
head.find('td').click(slotClick);
|
head.find('td').click(slotClick);
|
||||||
|
|
||||||
|
// all-day event container
|
||||||
|
daySegmentContainer = $("<div/>").appendTo(head);
|
||||||
|
|
||||||
// body
|
// body
|
||||||
d = zeroDate();
|
d = zeroDate();
|
||||||
var maxd = addMinutes(cloneDate(d), maxMinute);
|
var maxd = addMinutes(cloneDate(d), maxMinute);
|
||||||
|
@ -192,6 +202,9 @@ function Agenda(element, options, methods) {
|
||||||
.appendTo(element);
|
.appendTo(element);
|
||||||
body.find('td').click(slotClick);
|
body.find('td').click(slotClick);
|
||||||
|
|
||||||
|
// slot event container
|
||||||
|
slotSegmentContainer = $("<div/>").appendTo(bodyContent);
|
||||||
|
|
||||||
// background stripes
|
// background stripes
|
||||||
d = cloneDate(d0);
|
d = cloneDate(d0);
|
||||||
s = "<div class='fc-agenda-bg' style='position:absolute;z-index:1'>" +
|
s = "<div class='fc-agenda-bg' style='position:absolute;z-index:1'>" +
|
||||||
|
@ -274,6 +287,8 @@ function Agenda(element, options, methods) {
|
||||||
function updateSize(width, height) {
|
function updateSize(width, height) {
|
||||||
viewWidth = width;
|
viewWidth = width;
|
||||||
viewHeight = height;
|
viewHeight = height;
|
||||||
|
dayContentLefts = [];
|
||||||
|
dayContentRights = [];
|
||||||
|
|
||||||
bodyTable.width('');
|
bodyTable.width('');
|
||||||
body.height(height - head.height());
|
body.height(height - head.height());
|
||||||
|
@ -338,8 +353,6 @@ function Agenda(element, options, methods) {
|
||||||
/* Event Rendering
|
/* Event Rendering
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
var cachedEvents;
|
|
||||||
|
|
||||||
function renderEvents(events) {
|
function renderEvents(events) {
|
||||||
view.reportEvents(cachedEvents = events);
|
view.reportEvents(cachedEvents = events);
|
||||||
var i, len=events.length,
|
var i, len=events.length,
|
||||||
|
@ -352,8 +365,8 @@ function Agenda(element, options, methods) {
|
||||||
slotEvents.push(events[i]);
|
slotEvents.push(events[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renderDaySegs(cachedDaySegs = stackSegs(view.sliceSegs(dayEvents, $.map(dayEvents, visEventEnd), view.visStart, view.visEnd)));
|
renderDaySegs(daySegments = stackSegs(view.sliceSegs(dayEvents, $.map(dayEvents, visEventEnd), view.visStart, view.visEnd)));
|
||||||
renderSlotSegs(cachedSlotSegs = compileSlotSegs(slotEvents));
|
renderSlotSegs(slotSegments = compileSlotSegs(slotEvents));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -388,9 +401,159 @@ function Agenda(element, options, methods) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* cell/cell-content positioning calculating/caching
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// DERIVED FROM grid.js
|
||||||
|
|
||||||
|
function dayContentElement(dayOfWeek) {
|
||||||
|
if (dayContentElements[dayOfWeek] == undefined) {
|
||||||
|
dayContentElements[dayOfWeek] = bg.find('td:eq(' + ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt) + ') div div');
|
||||||
|
}
|
||||||
|
return dayContentElements[dayOfWeek];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function dayContentLeft(dayOfWeek) {
|
||||||
|
if (dayContentLefts[dayOfWeek] == undefined) {
|
||||||
|
dayContentLefts[dayOfWeek] = dayContentElement(dayOfWeek).position().left + axisWidth;
|
||||||
|
}
|
||||||
|
return dayContentLefts[dayOfWeek];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function dayContentRight(dayOfWeek) {
|
||||||
|
if (dayContentRights[dayOfWeek] == undefined) {
|
||||||
|
dayContentRights[dayOfWeek] = dayContentLeft(dayOfWeek) + dayContentElement(dayOfWeek).width();
|
||||||
|
}
|
||||||
|
return dayContentRights[dayOfWeek];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// renders 'all-day' events at the top
|
// renders 'all-day' events at the top
|
||||||
|
|
||||||
function renderDaySegs(segRow) {
|
function renderDaySegs(segRow) {
|
||||||
|
if (options.allDaySlot) {
|
||||||
|
var html='',
|
||||||
|
td = head.find('td'),
|
||||||
|
tdInner = td.find('div div'),
|
||||||
|
tr = td.parent(),
|
||||||
|
top = safePosition(tdInner, td, tr, tr.parent()).top,
|
||||||
|
rowContentHeight = 0,
|
||||||
|
i, len=segRow.length, level,
|
||||||
|
levelHeight,
|
||||||
|
j, seg,
|
||||||
|
event,
|
||||||
|
className,
|
||||||
|
left, right,
|
||||||
|
triggerRes,
|
||||||
|
l=0,
|
||||||
|
_eventElements,
|
||||||
|
eventLefts=[], eventRights=[],
|
||||||
|
eventHSides=[],
|
||||||
|
eventOuterHeights=[];
|
||||||
|
for (i=0; i<len; i++) {
|
||||||
|
level = segRow[i];
|
||||||
|
for (j=0; j<level.length; j++) {
|
||||||
|
seg = level[j];
|
||||||
|
event = seg.event;
|
||||||
|
className = 'fc-event fc-event-hori ';
|
||||||
|
if (rtl) {
|
||||||
|
if (seg.isStart) {
|
||||||
|
className += 'fc-corner-right ';
|
||||||
|
}
|
||||||
|
if (seg.isEnd) {
|
||||||
|
className += 'fc-corner-left ';
|
||||||
|
}
|
||||||
|
left = seg.isEnd ? 0 : dayContentLeft(seg.end.getDay()-1);
|
||||||
|
right = seg.isStart ? viewWidth : dayContentRight(seg.start.getDay());
|
||||||
|
}else{
|
||||||
|
if (seg.isStart) {
|
||||||
|
className += 'fc-corner-left ';
|
||||||
|
}
|
||||||
|
if (seg.isEnd) {
|
||||||
|
className += 'fc-corner-right ';
|
||||||
|
}
|
||||||
|
left = seg.isStart ? dayContentLeft(seg.start.getDay()) : 0;
|
||||||
|
right = seg.isEnd ? dayContentRight(seg.end.getDay()-1) : viewWidth;
|
||||||
|
}
|
||||||
|
eventLefts[l] = left;
|
||||||
|
eventRights[l] = right;
|
||||||
|
html +=
|
||||||
|
"<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;left:"+left+"px'>" +
|
||||||
|
"<a" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" +
|
||||||
|
(!event.allDay && seg.isStart ?
|
||||||
|
"<span class='fc-event-time'>" +
|
||||||
|
htmlEscape(formatDates(event.start, event.end, view.option('timeFormat'), options)) +
|
||||||
|
"</span>"
|
||||||
|
:'') +
|
||||||
|
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
|
||||||
|
"</a>" +
|
||||||
|
"</div>";
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
daySegmentContainer.html(html);
|
||||||
|
_eventElements = daySegmentContainer[0].childNodes;
|
||||||
|
l = 0;
|
||||||
|
for (i=0; i<len; i++) {
|
||||||
|
level = segRow[i];
|
||||||
|
for (j=0; j<level.length; j++) {
|
||||||
|
seg = level[j];
|
||||||
|
event = seg.event;
|
||||||
|
eventElement = $(_eventElements[l]);
|
||||||
|
triggerRes = view.trigger('eventRender', event, event, eventElement);
|
||||||
|
if (triggerRes !== false) {
|
||||||
|
if (triggerRes && typeof triggerRes != 'boolean') {
|
||||||
|
eventElement = $(triggerRes).appendTo(segmentContainer);
|
||||||
|
}
|
||||||
|
eventOuterHeights[l] = eventElement.outerHeight(true);
|
||||||
|
eventHSides[l] = hsides(eventElement, true);
|
||||||
|
seg.element = eventElement;
|
||||||
|
//bootstrapEventHandlers(event, seg, eventElement);
|
||||||
|
view.reportEventElement(event, eventElement);
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l = 0;
|
||||||
|
for (i=0; i<len; i++) {
|
||||||
|
level = segRow[i];
|
||||||
|
levelHeight = 0;
|
||||||
|
for (j=0; j<level.length; j++) {
|
||||||
|
seg = level[j];
|
||||||
|
if (eventElement = seg.element) {
|
||||||
|
eventElement.css('top', top);
|
||||||
|
if (rtl && rtlLeftDiff == undefined) {
|
||||||
|
// bug in IE6 where offsets are miscalculated with direction:rtl
|
||||||
|
rtlLeftDiff = eventLefts[l] - eventElement.position().left;
|
||||||
|
if (rtlLeftDiff) {
|
||||||
|
eventElement.css('left', eventLefts[l] + rtlLeftDiff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventElement.width(eventRights[l] - eventLefts[l] - eventHSides[l]);
|
||||||
|
view.trigger('eventAfterRender', event, event, eventElement);
|
||||||
|
levelHeight = Math.max(levelHeight, eventOuterHeights[l]);
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
rowContentHeight += levelHeight;
|
||||||
|
top += levelHeight;
|
||||||
|
}
|
||||||
|
tdInner.height(rowContentHeight);
|
||||||
|
updateSize(viewWidth, viewHeight); // tdInner might have pushed the body down, so resize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
// the original function
|
||||||
|
function renderDaySegs2(segRow) {
|
||||||
if (options.allDaySlot) {
|
if (options.allDaySlot) {
|
||||||
var td = head.find('td'),
|
var td = head.find('td'),
|
||||||
tdInner = td.find('div div'),
|
tdInner = td.find('div div'),
|
||||||
|
@ -478,12 +641,70 @@ function Agenda(element, options, methods) {
|
||||||
updateSize(viewWidth, viewHeight); // tdInner might have pushed the body down, so resize
|
updateSize(viewWidth, viewHeight); // tdInner might have pushed the body down, so resize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// renders events in the 'time slots' at the bottom
|
// renders events in the 'time slots' at the bottom
|
||||||
|
|
||||||
function renderSlotSegs(segCols) {
|
function renderSlotSegs(segCols) {
|
||||||
|
renderSlotSegs2(segCols);
|
||||||
|
/*
|
||||||
|
var html='',
|
||||||
|
colI, colLen=segCols.length, col,
|
||||||
|
levelI, level,
|
||||||
|
segI, seg,
|
||||||
|
forward,
|
||||||
|
event,
|
||||||
|
top, bottom,
|
||||||
|
tdInner,
|
||||||
|
width, left,
|
||||||
|
eventElement,
|
||||||
|
className,
|
||||||
|
l=0,
|
||||||
|
eventLefts=[],
|
||||||
|
eventOuterWidths=[],
|
||||||
|
triggerRes;
|
||||||
|
for (colI=0; colI<colLen; colI++) {
|
||||||
|
col = segCols[colI];
|
||||||
|
for (levelI=0; levelI<col.length; levelI++) {
|
||||||
|
level = col[levelI];
|
||||||
|
for (segI=0; segI<level.length; segI++) {
|
||||||
|
seg = level[segI];
|
||||||
|
forward = seg.forward || 0;
|
||||||
|
event = seg.event;
|
||||||
|
top = timePosition(seg.start, seg.start);
|
||||||
|
bottom = timePosition(seg.start, seg.end);
|
||||||
|
tdInner = bg.find('td:eq(' + (colI*dis + dit) + ') div div');
|
||||||
|
availWidth = tdInner.width();
|
||||||
|
availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS
|
||||||
|
if (levelI) {
|
||||||
|
// indented and thin
|
||||||
|
width = availWidth / (levelI + forward + 1);
|
||||||
|
}else{
|
||||||
|
if (forward) {
|
||||||
|
// moderately wide, aligned left still
|
||||||
|
width = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =
|
||||||
|
}else{
|
||||||
|
// can be entire width, aligned left
|
||||||
|
width = availWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
left = axisWidth + tdInner.position().left + // leftmost possible
|
||||||
|
(availWidth / (levelI + forward + 1) * levelI) // indentation
|
||||||
|
* dis + (rtl ? availWidth - width : 0); // rtl
|
||||||
|
eventLefts[l] = left;
|
||||||
|
eventOuterWidths[l] = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// the original function
|
||||||
|
function renderSlotSegs2(segCols) {
|
||||||
var colI, colLen=segCols.length, col,
|
var colI, colLen=segCols.length, col,
|
||||||
levelI, level,
|
levelI, level,
|
||||||
segI, seg,
|
segI, seg,
|
||||||
|
@ -575,6 +796,9 @@ function Agenda(element, options, methods) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function visEventEnd(event) { // returns exclusive 'visible' end, for rendering
|
function visEventEnd(event) { // returns exclusive 'visible' end, for rendering
|
||||||
if (event.allDay) {
|
if (event.allDay) {
|
||||||
if (event.end) {
|
if (event.end) {
|
||||||
|
|
|
@ -127,7 +127,8 @@ function Grid(element, options, methods) {
|
||||||
segmentContainer,
|
segmentContainer,
|
||||||
dayContentElements=[],
|
dayContentElements=[],
|
||||||
dayContentLefts=[],
|
dayContentLefts=[],
|
||||||
dayContentRights=[], // ...
|
dayContentRights=[],
|
||||||
|
// ...
|
||||||
|
|
||||||
// initialize superclass
|
// initialize superclass
|
||||||
view = $.extend(this, viewMethods, methods, {
|
view = $.extend(this, viewMethods, methods, {
|
||||||
|
|
47
tests/many_agenda_events.html
Normal file
47
tests/many_agenda_events.html
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
|
||||||
|
<script type='text/javascript'>DISABLE_FIREBUG_LITE=true</script>
|
||||||
|
<script type='text/javascript' src='loader.js'></script>
|
||||||
|
<script type='text/javascript'>
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
$('#calendar').fullCalendar({
|
||||||
|
defaultView: 'agendaWeek',
|
||||||
|
year: 2009,
|
||||||
|
month: 11,
|
||||||
|
date: 16,
|
||||||
|
header: {
|
||||||
|
left: 'prev,next today',
|
||||||
|
center: 'title',
|
||||||
|
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
|
||||||
|
},
|
||||||
|
editable: true,
|
||||||
|
events: 'many_agenda_events_json.txt'
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style type='text/css'>
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin-top: 40px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#calendar {
|
||||||
|
width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id='calendar'></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
2046
tests/many_agenda_events_json.txt
Normal file
2046
tests/many_agenda_events_json.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,13 +7,10 @@
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
var date = new Date();
|
|
||||||
var d = date.getDate();
|
|
||||||
var m = date.getMonth();
|
|
||||||
var y = date.getFullYear();
|
|
||||||
|
|
||||||
$('#calendar').fullCalendar({
|
$('#calendar').fullCalendar({
|
||||||
|
year: 2009,
|
||||||
|
month: 11,
|
||||||
header: {
|
header: {
|
||||||
left: 'prev,next today',
|
left: 'prev,next today',
|
||||||
center: 'title',
|
center: 'title',
|
||||||
|
|
Loading…
Add table
Reference in a new issue