Merge branch 'v1.4-speedup'

This commit is contained in:
Adam Shaw 2010-01-26 18:56:11 -08:00
commit 7158fc3470
10 changed files with 7064 additions and 429 deletions

View file

@ -21,7 +21,7 @@ setDefaults({
views.agendaWeek = function(element, options) { views.agendaWeek = function(element, options) {
return new Agenda(element, options, { return new Agenda(element, options, {
render: function(date, delta, height, fetchEvents) { render: function(date, delta, width, height, fetchEvents) {
if (delta) { if (delta) {
addDays(date, delta * 7); addDays(date, delta * 7);
} }
@ -41,14 +41,19 @@ views.agendaWeek = function(element, options) {
this.option('titleFormat'), this.option('titleFormat'),
options options
); );
this.renderAgenda(options.weekends ? 7 : 5, this.option('columnFormat'), height, fetchEvents); this.renderAgenda(
options.weekends ? 7 : 5,
this.option('columnFormat'),
width, height,
fetchEvents
);
} }
}); });
}; };
views.agendaDay = function(element, options) { views.agendaDay = function(element, options) {
return new Agenda(element, options, { return new Agenda(element, options, {
render: function(date, delta, height, fetchEvents) { render: function(date, delta, width, height, fetchEvents) {
if (delta) { if (delta) {
addDays(date, delta); addDays(date, delta);
if (!options.weekends) { if (!options.weekends) {
@ -58,7 +63,12 @@ views.agendaDay = function(element, options) {
this.title = formatDate(date, this.option('titleFormat'), options); this.title = formatDate(date, this.option('titleFormat'), options);
this.start = this.visStart = cloneDate(date, true); this.start = this.visStart = cloneDate(date, true);
this.end = this.visEnd = addDays(cloneDate(this.start), 1); this.end = this.visEnd = addDays(cloneDate(this.start), 1);
this.renderAgenda(1, this.option('columnFormat'), height, fetchEvents); this.renderAgenda(
1,
this.option('columnFormat'),
width, height,
fetchEvents
);
} }
}); });
}; };
@ -68,18 +78,26 @@ function Agenda(element, options, methods) {
var head, body, bodyContent, bodyTable, bg, var head, body, bodyContent, bodyTable, bg,
colCnt, colCnt,
axisWidth, colWidth, slotHeight, axisWidth, colWidth, slotHeight,
cachedDaySegs=[], cachedSlotSegs=[], viewWidth, viewHeight,
cachedHeight, 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,
colContentPositions = new HorizontalPositionCache(function(col) {
return bg.find('td:eq(' + col + ') div div');
}),
// ... // ...
view = $.extend(this, viewMethods, methods, { view = $.extend(this, viewMethods, methods, {
renderAgenda: renderAgenda, renderAgenda: renderAgenda,
renderEvents: renderEvents, renderEvents: renderEvents,
rerenderEvents: rerenderEvents, rerenderEvents: rerenderEvents,
clearEvents: clearEvents,
updateSize: updateSize, updateSize: updateSize,
shown: resetScroll, shown: resetScroll,
defaultEventEnd: function(event) { defaultEventEnd: function(event) {
@ -88,21 +106,6 @@ function Agenda(element, options, methods) {
return start; return start;
} }
return addMinutes(start, options.defaultEventMinutes); return addMinutes(start, options.defaultEventMinutes);
},
visEventEnd: function(event) {
if (event.allDay) {
if (event.end) {
var end = cloneDate(event.end);
return (event.allDay || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
}else{
return addDays(cloneDate(event.start), 1);
}
}
if (event.end) {
return cloneDate(event.end);
}else{
return addMinutes(cloneDate(event.start), options.defaultEventMinutes);
}
} }
}); });
view.init(element, options); view.init(element, options);
@ -118,7 +121,7 @@ function Agenda(element, options, methods) {
element.disableSelection(); element.disableSelection();
} }
function renderAgenda(c, colFormat, height, fetchEvents) { function renderAgenda(c, colFormat, width, height, fetchEvents) {
colCnt = c; colCnt = c;
// update option-derived variables // update option-derived variables
@ -175,6 +178,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);
@ -197,6 +203,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'>" +
@ -218,7 +227,7 @@ function Agenda(element, options, methods) {
}else{ // skeleton already built, just modify it }else{ // skeleton already built, just modify it
view.clearEvents(); clearEvents();
// redo column header text and class // redo column header text and class
head.find('tr:first th').slice(1, -1).each(function() { head.find('tr:first th').slice(1, -1).each(function() {
@ -253,7 +262,7 @@ function Agenda(element, options, methods) {
} }
updateSize(height); updateSize(width, height);
resetScroll(); resetScroll();
fetchEvents(renderEvents); fetchEvents(renderEvents);
@ -276,19 +285,19 @@ function Agenda(element, options, methods) {
} }
function updateSize(height) { function updateSize(width, height) {
cachedHeight = height; viewWidth = width;
viewHeight = height;
colContentPositions.clear();
bodyTable.width(''); body.width(width);
body.height(height - head.height()); body.height(height - head.height());
bodyTable.width('');
// need this for IE6/7. triggers clientWidth to be calculated for
// later user in this function. this is ridiculous
body[0].clientWidth;
var topTDs = head.find('tr:first th'), var topTDs = head.find('tr:first th'),
stripeTDs = bg.find('td'), stripeTDs = bg.find('td'),
contentWidth = body[0].clientWidth; contentWidth = slotSegmentContainer.width(); // body[0].clientWidth isn't reliable here in IE6
bodyTable.width(contentWidth); bodyTable.width(contentWidth);
// time-axis width // time-axis width
@ -316,10 +325,6 @@ function Agenda(element, options, methods) {
}); });
slotHeight = body.find('tr:first div').height() + 1; slotHeight = body.find('tr:first div').height() + 1;
// TODO:
//reportTBody(bodyTable.find('tbody'));
// Opera 9.25 doesn't detect the bug when called from agenda
} }
function slotClick(ev) { function slotClick(ev) {
@ -342,10 +347,8 @@ function Agenda(element, options, methods) {
/* Event Rendering /* Event Rendering
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
function renderEvents(events) { function renderEvents(events) {
view.reportEvents(events); view.reportEvents(cachedEvents = events);
var i, len=events.length, var i, len=events.length,
dayEvents=[], dayEvents=[],
slotEvents=[]; slotEvents=[];
@ -356,30 +359,32 @@ function Agenda(element, options, methods) {
slotEvents.push(events[i]); slotEvents.push(events[i]);
} }
} }
renderDaySegs(daySegments = stackSegs(view.sliceSegs(dayEvents, $.map(dayEvents, visEventEnd), view.visStart, view.visEnd)));
renderDaySegs(cachedDaySegs = stackSegs(view.sliceSegs(dayEvents, view.visStart, view.visEnd))); renderSlotSegs(slotSegments = compileSlotSegs(slotEvents));
renderSlotSegs(cachedSlotSegs = compileSlotSegs(slotEvents));
} }
function rerenderEvents(skipCompile) { function rerenderEvents() {
view.clearEvents(); clearEvents();
if (skipCompile) { renderEvents(cachedEvents);
renderDaySegs(cachedDaySegs); }
renderSlotSegs(cachedSlotSegs);
}else{
renderEvents(view.cachedEvents); function clearEvents() {
} daySegmentContainer.empty();
slotSegmentContainer.empty();
view._clearEvents(); // only clears the hashes
} }
function compileSlotSegs(events) { function compileSlotSegs(events) {
var d = addMinutes(cloneDate(view.visStart), minMinute), var d = addMinutes(cloneDate(view.visStart), minMinute),
ends = $.map(events, visEventEnd),
levels, levels,
segCols = [], segCols = [],
i=0; i=0;
for (; i<colCnt; i++) { for (; i<colCnt; i++) {
levels = stackSegs(view.sliceSegs(events, d, addMinutes(cloneDate(d), maxMinute-minMinute))); levels = stackSegs(view.sliceSegs(events, ends, d, addMinutes(cloneDate(d), maxMinute-minMinute)));
countForwardSegs(levels); countForwardSegs(levels);
segCols.push(levels); segCols.push(levels);
addDays(d, 1, true); addDays(d, 1, true);
@ -389,94 +394,29 @@ function Agenda(element, options, methods) {
// renders 'all-day' events at the top // renders 'all-day' events at the top
function renderDaySegs(segRow) { function renderDaySegs(segRow) {
if (options.allDaySlot) { if (options.allDaySlot) {
var td = head.find('td'), _renderDaySegs(
tdInner = td.find('div div'), [segRow],
tr = td.parent(), view,
top = safePosition(tdInner, td, tr, tr.parent()).top, axisWidth,
rowContentHeight = 0, viewWidth,
i, len=segRow.length, level, function() {
levelHeight, return head.find('tr.fc-all-day')
j, seg, },
event, function(dayOfWeek) {
className, return axisWidth + colContentPositions.left(day2col(dayOfWeek));
leftDay, leftRounded, },
rightDay, rightRounded, function(dayOfWeek) {
left, right, return axisWidth + colContentPositions.right(day2col(dayOfWeek));
eventElement, anchorElement, },
triggerRes; daySegmentContainer,
for (i=0; i<len; i++) { bootstrapDayEventHandlers
level = segRow[i]; );
levelHeight = 0; updateSize(viewWidth, viewHeight); // might have pushed the body down, so resize
for (j=0; j<level.length; j++) {
seg = level[j];
event = seg.event;
className = 'fc-event fc-event-hori ';
if (rtl) {
leftDay = seg.end.getDay() - 1;
leftRounded = seg.isEnd;
rightDay = seg.start.getDay();
rightRounded = seg.isStart;
}else{
leftDay = seg.start.getDay();
leftRounded = seg.isStart;
rightDay = seg.end.getDay() - 1;
rightRounded = seg.isEnd;
}
if (leftRounded) {
className += 'fc-corner-left ';
left = bg.find('td:eq('+(((leftDay-Math.max(firstDay,nwe)+colCnt)%colCnt)*dis+dit)+') div div').position().left + axisWidth;
}else{
left = axisWidth;
}
if (rightRounded) {
className += 'fc-corner-right ';
right = bg.find('td:eq('+(((rightDay-Math.max(firstDay,nwe)+colCnt)%colCnt)*dis+dit)+') div div');
right = right.position().left + right.width() + axisWidth;
}else{
right = axisWidth + bg.width();
}
eventElement = $("<div class='" + className + event.className.join(' ') + "'/>")
.append(anchorElement = $("<a/>")
.append($("<span class='fc-event-title' />")
.text(event.title)));
if (event.url) {
anchorElement.attr('href', event.url);
}
triggerRes = view.trigger('eventRender', event, event, eventElement);
if (triggerRes !== false) {
if (triggerRes && typeof triggerRes != 'boolean') {
eventElement = $(triggerRes);
}
eventElement
.css({
position: 'absolute',
top: top,
left: left,
zIndex: 8
})
.appendTo(head);
setOuterWidth(eventElement, right-left, true);
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableDayEvent(event, eventElement, seg.isStart);
if (seg.isEnd) {
view.resizableDayEvent(event, eventElement, colWidth);
}
}
view.reportEventElement(event, eventElement);
view.trigger('eventAfterRender', event, event, eventElement);
levelHeight = Math.max(levelHeight, eventElement.outerHeight(true));
}
}
top += levelHeight;
rowContentHeight += levelHeight;
}
tdInner.height(rowContentHeight);
updateSize(cachedHeight); // tdInner might have pushed the body down, so resize
} }
} }
@ -485,94 +425,182 @@ function Agenda(element, options, methods) {
// renders events in the 'time slots' at the bottom // renders events in the 'time slots' at the bottom
function renderSlotSegs(segCols) { function renderSlotSegs(segCols) {
var colI, colLen=segCols.length, col,
levelI, level, var event,
segI, seg,
forward,
event,
top, bottom,
tdInner,
width, left,
className, className,
eventElement, anchorElement, timeElement, titleElement, top,
triggerRes; bottom,
for (colI=0; colI<colLen; colI++) { leftmost,
col = segCols[colI]; availWidth,
for (levelI=0; levelI<col.length; levelI++) { forward,
level = col[levelI]; width,
for (segI=0; segI<level.length; segI++) { left,
seg = level[segI]; eventTops=[],
forward = seg.forward || 0; eventLefts=[],
event = seg.event; eventOuterWidths=[],
top = timePosition(seg.start, seg.start); eventOuterHeights=[],
bottom = timePosition(seg.start, seg.end); html='',
tdInner = bg.find('td:eq(' + (colI*dis + dit) + ') div div'); eventElements,
availWidth = tdInner.width(); eventElement,
availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS triggerRes,
if (levelI) { eventVSides=[],
// indented and thin eventHSides=[],
width = availWidth / (levelI + forward + 1); eventTitleTops=[],
}else{ height;
if (forward) {
// moderately wide, aligned left still // calculate desired position/dimensions, create html
width = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer = eachLeaf(segCols, function(l, seg, segI, levelI, colI) {
}else{ event = seg.event;
// can be entire width, aligned left className = 'fc-event fc-event-vert ';
width = availWidth; if (seg.isStart) {
} className += 'fc-corner-top ';
} }
left = axisWidth + tdInner.position().left + // leftmost possible if (seg.isEnd) {
(availWidth / (levelI + forward + 1) * levelI) // indentation className += 'fc-corner-bottom ';
* dis + (rtl ? availWidth - width : 0); // rtl }
className = 'fc-event fc-event-vert '; top = timePosition(seg.start, seg.start);
if (seg.isStart) { bottom = timePosition(seg.start, seg.end);
className += 'fc-corner-top '; leftmost = axisWidth + colContentPositions.left(colI*dis + dit);
} availWidth = axisWidth + colContentPositions.right(colI*dis + dit) - leftmost;
if (seg.isEnd) { availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS
className += 'fc-corner-bottom '; forward = seg.forward || 0;
} if (levelI) {
eventElement = $("<div class='" + className + event.className.join(' ') + "' />") // indented and thin
.append(anchorElement = $("<a><span class='fc-event-bg'/></a>") width = availWidth / (levelI + forward + 1);
.append(timeElement = $("<span class='fc-event-time'/>") }else{
.text(formatDates(event.start, event.end, view.option('timeFormat')))) if (forward) {
.append(titleElement = $("<span class='fc-event-title'/>") // moderately wide, aligned left still
.text(event.title))) width = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =
if (event.url) { }else{
anchorElement.attr('href', event.url); // can be entire width, aligned left
} width = availWidth;
triggerRes = view.trigger('eventRender', event, event, eventElement);
if (triggerRes !== false) {
if (triggerRes && typeof triggerRes != 'boolean') {
eventElement = $(triggerRes);
}
eventElement
.css({
position: 'absolute',
zIndex: 8,
top: top,
left: left
})
.appendTo(bodyContent);
setOuterWidth(eventElement, width, true);
setOuterHeight(eventElement, bottom-top, true);
if (eventElement.height() - titleElement.position().top < 10) {
// event title doesn't have enough room, put next to the time
timeElement.text(formatDate(event.start, view.option('timeFormat')) + ' - ' + event.title);
titleElement.remove();
}
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableSlotEvent(event, eventElement, timeElement);
if (seg.isEnd) {
resizableSlotEvent(event, eventElement, timeElement);
}
}
}
view.reportEventElement(event, eventElement);
view.trigger('eventAfterRender', event, event, eventElement);
} }
} }
left = leftmost + // leftmost possible
(availWidth / (levelI + forward + 1) * levelI) // indentation
* dis + (rtl ? availWidth - width : 0); // rtl
eventTops[l] = top;
eventLefts[l] = left;
eventOuterWidths[l] = width;
eventOuterHeights[l] = bottom - top;
html +=
"<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;top:" + top + "px;left:" + left + "px'>" +
"<a" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" +
"<span class='fc-event-time'>" + htmlEscape(formatDates(event.start, event.end, view.option('timeFormat'))) + "</span>" +
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
"<span class='fc-event-bg'/>" +
"</a>" +
((event.editable || event.editable == undefined && options.editable) && !options.disableResizing && $.fn.resizable ?
"<div class='ui-resizable-handle ui-resizable-s'>=</div>"
: '') +
"</div>";
});
slotSegmentContainer.html(html);
eventElements = slotSegmentContainer.children();
// retrieve elements, run through eventRender callback, record outer-edge dimensions
eachLeaf(segCols, function(l, seg) {
event = seg.event;
eventElement = eventElements.eq(l);
triggerRes = view.trigger('eventRender', event, event, eventElement);
if (triggerRes === false) {
eventElement.remove();
}else{
if (triggerRes && triggerRes !== true) {
eventElement.remove();
eventElement = $(triggerRes)
.css({
top: eventTops[l],
left: eventLefts[l]
})
.appendTo(slotSegmentContainer);
}
seg.element = eventElement;
eventVSides[l] = vsides(eventElement, true);
eventHSides[l] = hsides(eventElement, true);
eventTitleTops[l] = eventElement.find('span.fc-event-title').position().top;
bootstrapSlotEventHandlers(event, seg, eventElement);
view.reportEventElement(event, eventElement);
}
});
// set all positions/dimensions at once
eachLeaf(segCols, function(l, seg) {
if (eventElement = seg.element) {
eventElement
.width(eventOuterWidths[l] - eventHSides[l])
.height(height = eventOuterHeights[l] - eventVSides[l]);
event = seg.event;
if (height - eventTitleTops[l] < 10) {
// not enough room for title, put it in the time header
eventElement.find('span.fc-event-time')
.text(formatDate(event.start, view.option('timeFormat')) + ' - ' + event.title);
eventElement.find('span.fc-event-title')
.remove();
}
view.trigger('eventAfterRender', event, event, eventElement);
}
});
}
function visEventEnd(event) { // returns exclusive 'visible' end, for rendering
if (event.allDay) {
if (event.end) {
var end = cloneDate(event.end);
return (event.allDay || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
}else{
return addDays(cloneDate(event.start), 1);
}
} }
if (event.end) {
return cloneDate(event.end);
}else{
return addMinutes(cloneDate(event.start), options.defaultEventMinutes);
}
}
function bootstrapDayEventHandlers(event, seg, eventElement) {
var attached = false;
eventElement.mouseover(function(ev) {
if (!attached) {
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableDayEvent(event, eventElement, seg.isStart);
if (seg.isEnd) {
view.resizableDayEvent(event, eventElement, colWidth);
}
}
attached = true;
view.trigger('eventMouseover', this, event, ev);
}
});
}
function bootstrapSlotEventHandlers(event, seg, eventElement) {
var attached = false;
eventElement.mouseover(function(ev) {
if (!attached) {
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
var timeElement = eventElement.find('span.fc-event-time');
draggableSlotEvent(event, eventElement, timeElement);
if (seg.isEnd) {
resizableSlotEvent(event, eventElement, timeElement);
}
}
attached = true;
view.trigger('eventMouseover', this, event, ev);
}
});
} }
@ -798,7 +826,9 @@ function Agenda(element, options, methods) {
var slotDelta, prevSlotDelta; var slotDelta, prevSlotDelta;
eventElement eventElement
.resizable({ .resizable({
handles: 's', handles: {
s: 'div.ui-resizable-s'
},
grid: slotHeight, grid: slotHeight,
start: function(ev, ui) { start: function(ev, ui) {
slotDelta = prevSlotDelta = 0; slotDelta = prevSlotDelta = 0;
@ -834,15 +864,11 @@ function Agenda(element, options, methods) {
// BUG: if event was really short, need to put title back in span // BUG: if event was really short, need to put title back in span
} }
} }
}) });
.find('div.ui-resizable-s').text('=');
} }
} }
// ALL-DAY event resizing w/ 'view' methods...
/* Misc /* Misc
@ -865,9 +891,16 @@ function Agenda(element, options, methods) {
td = tr.find('td'), td = tr.find('td'),
innerDiv = td.find('div'); innerDiv = td.find('div');
return Math.max(0, Math.round( return Math.max(0, Math.round(
safePosition(innerDiv, td, tr, tr.parent()).top - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes) innerDiv.position().top + topCorrect(td) - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)
)); ));
} }
function day2col(dayOfWeek) {
return ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt)*dis+dit;
}
} }

View file

@ -8,7 +8,7 @@ setDefaults({
views.month = function(element, options) { views.month = function(element, options) {
return new Grid(element, options, { return new Grid(element, options, {
render: function(date, delta, height, fetchEvents) { render: function(date, delta, width, height, fetchEvents) {
if (delta) { if (delta) {
addMonths(date, delta); addMonths(date, delta);
date.setDate(1); date.setDate(1);
@ -44,7 +44,7 @@ views.month = function(element, options) {
rowCnt, options.weekends ? 7 : 5, rowCnt, options.weekends ? 7 : 5,
this.option('columnFormat'), this.option('columnFormat'),
true, true,
height, width, height,
fetchEvents fetchEvents
); );
} }
@ -53,7 +53,7 @@ views.month = function(element, options) {
views.basicWeek = function(element, options) { views.basicWeek = function(element, options) {
return new Grid(element, options, { return new Grid(element, options, {
render: function(date, delta, height, fetchEvents) { render: function(date, delta, width, height, fetchEvents) {
if (delta) { if (delta) {
addDays(date, delta * 7); addDays(date, delta * 7);
} }
@ -77,7 +77,7 @@ views.basicWeek = function(element, options) {
1, options.weekends ? 7 : 5, 1, options.weekends ? 7 : 5,
this.option('columnFormat'), this.option('columnFormat'),
false, false,
height, width, height,
fetchEvents fetchEvents
); );
} }
@ -86,7 +86,7 @@ views.basicWeek = function(element, options) {
views.basicDay = function(element, options) { views.basicDay = function(element, options) {
return new Grid(element, options, { return new Grid(element, options, {
render: function(date, delta, height, fetchEvents) { render: function(date, delta, width, height, fetchEvents) {
if (delta) { if (delta) {
addDays(date, delta); addDays(date, delta);
if (!options.weekends) { if (!options.weekends) {
@ -96,7 +96,13 @@ views.basicDay = function(element, options) {
this.title = formatDate(date, this.option('titleFormat'), options); this.title = formatDate(date, this.option('titleFormat'), options);
this.start = this.visStart = cloneDate(date, true); this.start = this.visStart = cloneDate(date, true);
this.end = this.visEnd = addDays(cloneDate(this.start), 1); this.end = this.visEnd = addDays(cloneDate(this.start), 1);
this.renderGrid(1, 1, this.option('columnFormat'), false, height, fetchEvents); this.renderGrid(
1, 1,
this.option('columnFormat'),
false,
width, height,
fetchEvents
);
} }
}); });
} }
@ -104,7 +110,7 @@ views.basicDay = function(element, options) {
// rendering bugs // rendering bugs
var tdHeightBug, rtlLeftDiff; var tdHeightBug;
function Grid(element, options, methods) { function Grid(element, options, methods) {
@ -112,27 +118,27 @@ function Grid(element, options, methods) {
var tm, firstDay, var tm, firstDay,
nwe, // no weekends (int) nwe, // no weekends (int)
rtl, dis, dit, // day index sign / translate rtl, dis, dit, // day index sign / translate
viewWidth, viewHeight,
rowCnt, colCnt, rowCnt, colCnt,
colWidth, colWidth,
thead, tbody, thead, tbody,
cachedSegs=[], //... cachedEvents=[],
segments=[],
segmentContainer,
dayContentPositions = new HorizontalPositionCache(function(dayOfWeek) {
return tbody.find('td:eq(' + ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt) + ') div div')
}),
// ...
// initialize superclass // initialize superclass
view = $.extend(this, viewMethods, methods, { view = $.extend(this, viewMethods, methods, {
renderGrid: renderGrid, renderGrid: renderGrid,
renderEvents: renderEvents, renderEvents: renderEvents,
rerenderEvents: rerenderEvents, rerenderEvents: rerenderEvents,
clearEvents: clearEvents,
updateSize: updateSize, updateSize: updateSize,
defaultEventEnd: function(event) { // calculates an end if event doesnt have one, mostly for resizing defaultEventEnd: function(event) { // calculates an end if event doesnt have one, mostly for resizing
return cloneDate(event.start); return cloneDate(event.start);
},
visEventEnd: function(event) { // returns exclusive 'visible' end, for rendering
if (event.end) {
var end = cloneDate(event.end);
return (event.allDay || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
}else{
return addDays(cloneDate(event.start), 1);
}
} }
}); });
view.init(element, options); view.init(element, options);
@ -148,7 +154,7 @@ function Grid(element, options, methods) {
element.disableSelection(); element.disableSelection();
} }
function renderGrid(r, c, colFormat, showNumbers, height, fetchEvents) { function renderGrid(r, c, colFormat, showNumbers, width, height, fetchEvents) {
rowCnt = r; rowCnt = r;
colCnt = c; colCnt = c;
@ -210,10 +216,12 @@ function Grid(element, options, methods) {
} }
tbody = $(s + "</tbody>").appendTo(table); tbody = $(s + "</tbody>").appendTo(table);
tbody.find('td').click(dayClick); tbody.find('td').click(dayClick);
segmentContainer = $("<div/>").appendTo(element);
}else{ // NOT first time, reuse as many cells as possible }else{ // NOT first time, reuse as many cells as possible
view.clearEvents(); clearEvents();
var prevRowCnt = tbody.find('tr').length; var prevRowCnt = tbody.find('tr').length;
if (rowCnt < prevRowCnt) { if (rowCnt < prevRowCnt) {
@ -296,7 +304,7 @@ function Grid(element, options, methods) {
} }
updateSize(height); updateSize(width, height);
fetchEvents(renderEvents); fetchEvents(renderEvents);
}; };
@ -312,10 +320,13 @@ function Grid(element, options, methods) {
} }
function updateSize(height) { function updateSize(width, height) { // does not render/position the events
viewWidth = width;
viewHeight = height;
dayContentPositions.clear();
var leftTDs = tbody.find('tr td:first-child'), var leftTDs = tbody.find('tr td:first-child'),
tbodyHeight = height - thead.height(), tbodyHeight = viewHeight - thead.height(),
rowHeight1, rowHeight2; rowHeight1, rowHeight2;
if (options.weekMode == 'variable') { if (options.weekMode == 'variable') {
@ -325,8 +336,6 @@ function Grid(element, options, methods) {
rowHeight2 = tbodyHeight - rowHeight1*(rowCnt-1); rowHeight2 = tbodyHeight - rowHeight1*(rowCnt-1);
} }
reportTBody(tbody);
if (tdHeightBug == undefined) { if (tdHeightBug == undefined) {
// bug in firefox where cell height includes padding // bug in firefox where cell height includes padding
var tr = tbody.find('tr:first'), var tr = tbody.find('tr:first'),
@ -345,11 +354,11 @@ function Grid(element, options, methods) {
setOuterWidth( setOuterWidth(
thead.find('th').slice(0, -1), thead.find('th').slice(0, -1),
colWidth = Math.floor(element.width() / colCnt) colWidth = Math.floor(viewWidth / colCnt)
); );
} }
/* Event Rendering /* Event Rendering
@ -357,18 +366,20 @@ function Grid(element, options, methods) {
function renderEvents(events) { function renderEvents(events) {
view.reportEvents(events); view.reportEvents(cachedEvents = events);
renderSegs(cachedSegs = compileSegs(events)); renderSegs(segments = compileSegs(events));
} }
function rerenderEvents(skipCompile) { function rerenderEvents() {
view.clearEvents(); clearEvents();
if (skipCompile) { renderSegs(segments = compileSegs(cachedEvents));
renderSegs(cachedSegs); }
}else{
renderEvents(view.cachedEvents);
} function clearEvents() {
view._clearEvents(); // only clears the hashes
segmentContainer.empty();
} }
@ -378,7 +389,7 @@ function Grid(element, options, methods) {
rows = [], rows = [],
i=0; i=0;
for (; i<rowCnt; i++) { for (; i<rowCnt; i++) {
rows.push(stackSegs(view.sliceSegs(events, d1, d2))); rows.push(stackSegs(view.sliceSegs(events, $.map(events, visEventEnd), d1, d2)));
addDays(d1, 7); addDays(d1, 7);
addDays(d2, 7); addDays(d2, 7);
} }
@ -386,108 +397,51 @@ function Grid(element, options, methods) {
} }
function renderSegs(segRows) {
var i, len = segRows.length, levels, function renderSegs(segCols) {
tr, td, _renderDaySegs(
innerDiv, segCols,
top, view,
rowContentHeight, 0,
j, segs, viewWidth,
levelHeight, function(i) {
k, seg, return tbody.find('tr:eq('+i+')');
event, },
className, dayContentPositions.left,
startElm, endElm, dayContentPositions.right,
left, right, segmentContainer,
eventElement, eventAnchor, bootstrapEventHandlers
triggerRes; );
for (i=0; i<len; i++) { }
levels = segRows[i];
tr = tbody.find('tr:eq('+i+')');
td = tr.find('td:first');
innerDiv = td.find('div.fc-day-content div').css('position', 'relative'); function visEventEnd(event) { // returns exclusive 'visible' end, for rendering
top = safePosition(innerDiv, td, tr, tbody).top; if (event.end) {
rowContentHeight = 0; var end = cloneDate(event.end);
for (j=0; j<levels.length; j++) { return (event.allDay || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
segs = levels[j]; }else{
levelHeight = 0; return addDays(cloneDate(event.start), 1);
for (k=0; k<segs.length; k++) { }
seg = segs[k]; }
event = seg.event;
className = 'fc-event fc-event-hori ';
startElm = seg.isStart ?
tr.find('td:eq('+((seg.start.getDay()-Math.max(firstDay,nwe)+colCnt)%colCnt)+') div div') : function bootstrapEventHandlers(event, seg, eventElement) {
tbody; var attached = false;
endElm = seg.isEnd ? eventElement.mouseover(function(ev) {
tr.find('td:eq('+((seg.end.getDay()-Math.max(firstDay,nwe)+colCnt-1)%colCnt)+') div div') : if (!attached) {
tbody; view.eventElementHandlers(event, eventElement);
if (rtl) { if (event.editable || event.editable == undefined && options.editable) {
left = endElm.position().left; draggableEvent(event, eventElement);
right = startElm.position().left + startElm.width(); if (seg.isEnd) {
if (seg.isStart) { view.resizableDayEvent(event, eventElement, colWidth);
className += 'fc-corner-right ';
}
if (seg.isEnd) {
className += 'fc-corner-left ';
}
}else{
left = startElm.position().left;
right = endElm.position().left + endElm.width();
if (seg.isStart) {
className += 'fc-corner-left ';
}
if (seg.isEnd) {
className += 'fc-corner-right ';
}
}
eventElement = $("<div class='" + className + event.className.join(' ') + "'/>")
.append(eventAnchor = $("<a/>")
.append(event.allDay || !seg.isStart ? null :
$("<span class='fc-event-time'/>")
.html(formatDates(event.start, event.end, view.option('timeFormat'), options)))
.append($("<span class='fc-event-title'/>")
.text(event.title)));
if (event.url) {
eventAnchor.attr('href', event.url);
}
triggerRes = view.trigger('eventRender', event, event, eventElement);
if (triggerRes !== false) {
if (triggerRes && typeof triggerRes != 'boolean') {
eventElement = $(triggerRes);
}
eventElement
.css({
position: 'absolute',
top: top,
left: left + (rtlLeftDiff||0),
zIndex: 8
})
.appendTo(element);
setOuterWidth(eventElement, right-left, true);
if (rtl && rtlLeftDiff == undefined) {
// bug in IE6 where offsets are miscalculated with direction:rtl
rtlLeftDiff = left - eventElement.position().left;
if (rtlLeftDiff) {
eventElement.css('left', left + rtlLeftDiff);
}
}
view.eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableEvent(event, eventElement);
if (seg.isEnd) {
view.resizableDayEvent(event, eventElement, colWidth);
}
}
view.reportEventElement(event, eventElement);
view.trigger('eventAfterRender', event, event, eventElement);
levelHeight = Math.max(levelHeight, eventElement.outerHeight(true));
} }
} }
rowContentHeight += levelHeight; attached = true;
top += levelHeight; view.trigger('eventMouseover', this, event, ev); // TODO: make sure this isn't being fired twice
} }
innerDiv.height(rowContentHeight); });
}
} }
@ -553,3 +507,131 @@ function Grid(element, options, methods) {
}; };
function _renderDaySegs(segRows, view, minLeft, maxLeft, getTr, dayContentLeft, dayContentRight, segmentContainer, bootstrapEventHandlers) {
var options=view.options,
rtl=options.isRTL,
event,
className,
left,
right,
eventLefts=[],
eventRights=[],
html='',
eventElements,
eventElement,
triggerRes,
eventOuterHeights=[],
eventHSides=[],
l=0,
i=0, len=segRows.length, levels,
tr,
td,
innerDiv,
top,
rowContentHeight,
j, segs,
k, seg;
// calculate desired position/dimensions, create html
eachLeaf(segRows, function(l, seg) {
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 ? dayContentLeft(seg.end.getDay()-1) : minLeft;
right = seg.isStart ? dayContentRight(seg.start.getDay()) : maxLeft;
}else{
if (seg.isStart) {
className += 'fc-corner-left ';
}
if (seg.isEnd) {
className += 'fc-corner-right ';
}
left = seg.isStart ? dayContentLeft(seg.start.getDay()) : minLeft;
right = seg.isEnd ? dayContentRight(seg.end.getDay()-1) : maxLeft;
}
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>";
});
segmentContainer.html(html);
eventElements = segmentContainer.children();
// retrieve elements, run through eventRender callback, record outer-edge dimensions
eachLeaf(segRows, function(l, seg) {
event = seg.event;
eventElement = eventElements.eq(l);
triggerRes = view.trigger('eventRender', event, event, eventElement);
if (triggerRes === false) {
eventElement.remove();
}else{
if (triggerRes && triggerRes !== true) {
eventElement.remove();
eventElement = $(triggerRes)
.css('left', eventLefts[l])
.appendTo(segmentContainer);
}
seg.element = eventElement;
eventOuterHeights[l] = eventElement.outerHeight(true);
eventHSides[l] = hsides(eventElement, true);
bootstrapEventHandlers(event, seg, eventElement);
view.reportEventElement(event, eventElement);
}
});
// set all positions/dimensions at once
for (; i<len; i++) {
levels = segRows[i];
tr = getTr(i);
td = tr.find('td:first');
innerDiv = td.find('div.fc-day-content div')
.css('position', 'relative')
.height(''); // this is needed for IE7 to get an accurate position
top = innerDiv.position().top + topCorrect(td);
rowContentHeight = 0;
for (j=0; j<levels.length; j++) {
segs = levels[j];
levelHeight = 0;
for (k=0; k<segs.length; k++) {
seg = segs[k];
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]);
event = seg.event;
view.trigger('eventAfterRender', event, event, eventElement);
levelHeight = Math.max(levelHeight, eventOuterHeights[l]);
}
l++;
}
rowContentHeight += levelHeight;
top += levelHeight;
}
innerDiv.height(rowContentHeight);
}
}

4376
src/jquery/jquery-uncompressed.js vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -149,7 +149,9 @@ $.fn.fullCalendar = function(options) {
element = $(_element).addClass('fc'), element = $(_element).addClass('fc'),
elementWidth, elementWidth,
content = $("<div class='fc-content " + tm + "-widget-content' style='position:relative'/>").prependTo(_element), // relative for ie6 content = $("<div class='fc-content " + tm + "-widget-content' style='position:relative'/>").prependTo(_element), // relative for ie6
contentWidth,
contentHeight; contentHeight;
if (options.isRTL) { if (options.isRTL) {
element.addClass('fc-rtl'); element.addClass('fc-rtl');
} }
@ -214,11 +216,12 @@ $.fn.fullCalendar = function(options) {
function render(inc, forceUpdateSize) { function render(inc, forceUpdateSize) {
if ((elementWidth = _element.offsetWidth) !== 0) { // visible on the screen if ((elementWidth = _element.offsetWidth) !== 0) { // visible on the screen
if (!contentHeight) { if (!contentHeight) {
contentWidth = content.width();
contentHeight = calculateContentHeight(); contentHeight = calculateContentHeight();
} }
if (inc || !view.date || date < view.visStart || date > view.visEnd ) { // !view.date means it hasn't been rendered yet if (inc || !view.date || date < view.visStart || date > view.visEnd ) { // !view.date means it hasn't been rendered yet
fixContentSize(); fixContentSize();
view.render(date, inc || 0, contentHeight, function(callback) { view.render(date, inc || 0, contentWidth, contentHeight, function(callback) {
// dont refetch if new view contains the same events (or a subset) // dont refetch if new view contains the same events (or a subset)
if (!eventStart || view.visStart < eventStart || view.visEnd > eventEnd) { if (!eventStart || view.visStart < eventStart || view.visEnd > eventEnd) {
fetchEvents(callback); fetchEvents(callback);
@ -230,12 +233,14 @@ $.fn.fullCalendar = function(options) {
view.date = cloneDate(date); view.date = cloneDate(date);
} }
else if (view.sizeDirty || forceUpdateSize) { else if (view.sizeDirty || forceUpdateSize) {
view.updateSize(contentHeight); view.updateSize(contentWidth, contentHeight);
view.rerenderEvents(); view.rerenderEvents(); // TODO: could probably skip recompile??
} }
else if (view.eventsDirty) { else if (view.eventsDirty) {
// ensure events are rerendered if another view messed with them // ensure events are rerendered if another view messed with them
// pass in 'events' b/c event might have been added/removed // pass in 'events' b/c event might have been added/removed
// executed on a switchView
// TODO: should this be inclusive with sizeDirty and forceUpdateSize??
view.clearEvents(); view.clearEvents();
view.renderEvents(events); view.renderEvents(events);
} }
@ -257,7 +262,7 @@ $.fn.fullCalendar = function(options) {
} }
// marks other views' events as dirty // marks other views' events as dirty
function eventsDirtyExcept(exceptView) { function eventsDirtyExcept(exceptView) { // TODO: otherViewsEventsDirty
$.each(viewInstances, function() { $.each(viewInstances, function() {
if (this != exceptView) { if (this != exceptView) {
this.eventsDirty = true; this.eventsDirty = true;
@ -283,16 +288,17 @@ $.fn.fullCalendar = function(options) {
// called when we know the element size has changed // called when we know the element size has changed
function sizeChanged(fix) { function sizeChanged(fix) {
contentWidth = content.width();
contentHeight = calculateContentHeight(); contentHeight = calculateContentHeight();
if (fix) { if (fix) {
fixContentSize(); fixContentSize();
} }
view.updateSize(contentHeight); view.updateSize(contentWidth, contentHeight);
if (fix) { if (fix) {
unfixContentSize(); unfixContentSize();
} }
sizesDirtyExcept(view); sizesDirtyExcept(view);
view.rerenderEvents(true); view.rerenderEvents();
} }
// calculate what the height of the content should be // calculate what the height of the content should be
@ -301,9 +307,9 @@ $.fn.fullCalendar = function(options) {
return options.contentHeight; return options.contentHeight;
} }
else if (options.height) { else if (options.height) {
return options.height - (header ? header.height() : 0) - horizontalSides(content); return options.height - (header ? header.height() : 0) - horizontalSides(content); // TODO: shouldn't this be vertical sides??
} }
return elementWidth / Math.max(options.aspectRatio, .5); return Math.round(contentWidth / Math.max(options.aspectRatio, .5));
} }
@ -776,7 +782,7 @@ $.fn.fullCalendar = function(options) {
} }
} }
}; };
$(window).resize(windowResize); //$(window).resize(windowResize);
// let's begin... // let's begin...
@ -787,7 +793,7 @@ $.fn.fullCalendar = function(options) {
setTimeout(function() { setTimeout(function() {
render(); render();
content.hide().show(); // needed for IE 6 content.hide().show(); // needed for IE 6
view.rerenderEvents(); // needed for IE 7 view.rerenderEvents(); // needed for IE 7 // TODO: could probably skip recompile
}, 0); }, 0);
} }

View file

@ -4,7 +4,8 @@
var DAY_MS = 86400000, var DAY_MS = 86400000,
HOUR_MS = 3600000, HOUR_MS = 3600000,
MINUTE_MS = 60000; MINUTE_MS = 60000,
arrayPop = Array.prototype.pop; // for eachLeaf
function addYears(d, n, keepTime) { function addYears(d, n, keepTime) {
d.setFullYear(d.getFullYear() + n); d.setFullYear(d.getFullYear() + n);
@ -300,39 +301,35 @@ var dateFormatters = {
function setOuterWidth(element, width, includeMargins) { function setOuterWidth(element, width, includeMargins) {
element.each(function() { element.each(function() {
var e = $(this); var e = $(this);
var w = width - horizontalSides(e); e.width(width - hsides(e, includeMargins));
if (includeMargins) {
w -= (parseInt(e.css('margin-left')) || 0) +
(parseInt(e.css('margin-right')) || 0);
}
e.width(w);
}); });
} }
function horizontalSides(e) { function hsides(e, includeMargins) {
return (parseInt(e.css('border-left-width')) || 0) + return (parseInt(e.css('border-left-width')) || 0) +
(parseInt(e.css('padding-left')) || 0) + (parseInt(e.css('padding-left')) || 0) +
(parseInt(e.css('padding-right')) || 0) + (parseInt(e.css('padding-right')) || 0) +
(parseInt(e.css('border-right-width')) || 0); (parseInt(e.css('border-right-width')) || 0) +
(includeMargins ?
(parseInt(e.css('margin-left')) || 0) + (parseInt(e.css('margin-right')) || 0)
: 0);
} }
function setOuterHeight(element, height, includeMargins) { function setOuterHeight(element, height, includeMargins) {
element.each(function() { element.each(function() {
var e = $(this); var e = $(this);
var h = height - verticalSides(e); e.height(height - vsides(e, includeMargins));
if (includeMargins) {
h -= (parseInt(e.css('margin-top')) || 0) +
(parseInt(e.css('margin-bottom')) || 0);
}
e.height(h);
}); });
} }
function verticalSides(e) { function vsides(e, includeMargins) {
return (parseInt(e.css('border-top-width')) || 0) + return (parseInt(e.css('border-top-width')) || 0) +
(parseInt(e.css('padding-top')) || 0) + (parseInt(e.css('padding-top')) || 0) +
(parseInt(e.css('padding-bottom')) || 0) + (parseInt(e.css('padding-bottom')) || 0) +
(parseInt(e.css('border-bottom-width')) || 0); (parseInt(e.css('border-bottom-width')) || 0) +
(includeMargins ?
(parseInt(e.css('margin-top')) || 0) + (parseInt(e.css('margin-bottom')) || 0)
: 0);
} }
@ -340,22 +337,24 @@ function verticalSides(e) {
/* Position Calculation /* Position Calculation
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
// nasty bugs in opera 9.25 // nasty bugs in opera 9.25
// position() returning relative to direct parent // position()'s top returning incorrectly with TR/TD or elements within TD
var operaPositionBug; var topBug;
function reportTBody(tbody) { function topCorrect(tr) { // tr/th/td or anything else
if (operaPositionBug == undefined) { if (topBug !== false) {
operaPositionBug = tbody.position().top != tbody.find('tr').position().top; var cell;
if (tr.is('th,td')) {
tr = (cell = tr).parent();
}
if (topBug == undefined && tr.is('tr')) {
topBug = tr.position().top != tr.children().position().top;
}
if (topBug) {
return tr.parent().position().top + (cell ? tr.position().top - cell.position().top : 0);
}
} }
} return 0;
function safePosition(element, td, tr, tbody) {
var position = element.position();
if (operaPositionBug) {
position.top += tbody.position().top + tr.position().top - td.position().top;
}
return position;
} }
@ -365,24 +364,23 @@ function safePosition(element, td, tr, tbody) {
function HoverMatrix(changeCallback) { function HoverMatrix(changeCallback) {
var tops=[], lefts=[], var t=this,
tops=[], lefts=[],
prevRowE, prevColE, prevRowE, prevColE,
origRow, origCol, origRow, origCol,
currRow, currCol; currRow, currCol;
this.row = function(e, topBug) { t.row = function(e) {
prevRowE = $(e); prevRowE = $(e);
tops.push(prevRowE.offset().top + ( tops.push(prevRowE.offset().top + topCorrect(prevRowE));
(operaPositionBug && prevRowE.is('tr')) ? prevRowE.parent().position().top : 0
));
}; };
this.col = function(e) { t.col = function(e) {
prevColE = $(e); prevColE = $(e);
lefts.push(prevColE.offset().left); lefts.push(prevColE.offset().left);
}; };
this.mouse = function(x, y) { t.mouse = function(x, y) {
if (origRow == undefined) { if (origRow == undefined) {
tops.push(tops[tops.length-1] + prevRowE.outerHeight()); tops.push(tops[tops.length-1] + prevRowE.outerHeight());
lefts.push(lefts[lefts.length-1] + prevColE.outerWidth()); lefts.push(lefts[lefts.length-1] + prevColE.outerWidth());
@ -397,13 +395,13 @@ function HoverMatrix(changeCallback) {
currRow = r; currRow = r;
currCol = c; currCol = c;
if (r == -1 || c == -1) { if (r == -1 || c == -1) {
this.cell = null; t.cell = null;
}else{ }else{
if (origRow == undefined) { if (origRow == undefined) {
origRow = r; origRow = r;
origCol = c; origCol = c;
} }
this.cell = { t.cell = {
row: r, row: r,
col: c, col: c,
top: tops[r], top: tops[r],
@ -415,7 +413,7 @@ function HoverMatrix(changeCallback) {
colDelta: c-origCol colDelta: c-origCol
}; };
} }
changeCallback(this.cell); changeCallback(t.cell);
} }
}; };
@ -433,7 +431,7 @@ function zeroPad(n) {
return (n < 10 ? '0' : '') + n; return (n < 10 ? '0' : '') + n;
} }
function smartProperty(obj, name) { // get a camel-cased/namespaced property function smartProperty(obj, name) { // get a camel-cased/namespaced property of an object
if (obj[name] != undefined) { if (obj[name] != undefined) {
return obj[name]; return obj[name];
} }
@ -448,4 +446,59 @@ function smartProperty(obj, name) { // get a camel-cased/namespaced property
return obj['']; return obj[''];
} }
function htmlEscape(s) {
return s
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/'/g, '&#039;')
.replace(/"/g, '&quot;')
}
function eachLeaf(node, callback, leafIndex, indexTrail) {
if (node.pop == arrayPop) { // is an array?
for (var i=0, len=node.length; i<len; i++) {
leafIndex = eachLeaf(node[i], callback, leafIndex||0, [i].concat(indexTrail||[]));
}
return leafIndex;
}
callback.apply(node, [leafIndex, node].concat(indexTrail));
return leafIndex + 1;
}
function HorizontalPositionCache(getElement) {
var t = this,
elements = {},
lefts = {},
rights = {};
function e(i) {
return elements[i] =
elements[i] || getElement(i);
}
t.left = function(i) {
return lefts[i] =
lefts[i] == undefined ? e(i).position().left : lefts[i];
};
t.right = function(i) {
return rights[i] =
rights[i] == undefined ? t.left(i) + e(i).width() : rights[i];
};
t.clear = function() {
elements = {};
lefts = {};
rights = {};
};
}

View file

@ -14,7 +14,6 @@ var viewMethods = {
* - visStart * - visStart
* - visEnd * - visEnd
* - defaultEventEnd(event) * - defaultEventEnd(event)
* - visEventEnd(event)
* - render(events) * - render(events)
* - rerenderEvents() * - rerenderEvents()
* *
@ -31,7 +30,6 @@ var viewMethods = {
init: function(element, options) { init: function(element, options) {
this.element = element; this.element = element;
this.options = options; this.options = options;
this.cachedEvents = [];
this.eventsByID = {}; this.eventsByID = {};
this.eventElements = []; this.eventElements = [];
this.eventElementsByID = {}; this.eventElementsByID = {};
@ -61,8 +59,7 @@ var viewMethods = {
reportEvents: function(events) { // events are already normalized at this point reportEvents: function(events) { // events are already normalized at this point
var i, len=events.length, event, var i, len=events.length, event,
eventsByID = this.eventsByID = {}, eventsByID = this.eventsByID = {};
cachedEvents = this.cachedEvents = [];
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
event = events[i]; event = events[i];
if (eventsByID[event._id]) { if (eventsByID[event._id]) {
@ -70,7 +67,6 @@ var viewMethods = {
}else{ }else{
eventsByID[event._id] = [event]; eventsByID[event._id] = [event];
} }
cachedEvents.push(event);
} }
}, },
@ -92,10 +88,7 @@ var viewMethods = {
// event element manipulation // event element manipulation
clearEvents: function() { // only remove ELEMENTS _clearEvents: function() { // only resets hashes
$.each(this.eventElements, function() {
this.remove();
});
this.eventElements = []; this.eventElements = [];
this.eventElementsByID = {}; this.eventElementsByID = {};
}, },
@ -273,7 +266,7 @@ var viewMethods = {
// event rendering utilities // event rendering utilities
sliceSegs: function(events, start, end) { sliceSegs: function(events, visEventEnds, start, end) {
var segs = [], var segs = [],
i, len=events.length, event, i, len=events.length, event,
eventStart, eventEnd, eventStart, eventEnd,
@ -282,7 +275,7 @@ var viewMethods = {
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
event = events[i]; event = events[i];
eventStart = event.start; eventStart = event.start;
eventEnd = this.visEventEnd(event); eventEnd = visEventEnds[i];
if (eventEnd > start && eventStart < end) { if (eventEnd > start && eventStart < end) {
if (eventStart < start) { if (eventStart < start) {
segStart = cloneDate(start); segStart = cloneDate(start);
@ -359,3 +352,5 @@ function segsCollide(seg1, seg2) {
return seg1.end > seg2.start && seg1.start < seg2.end; return seg1.end > seg2.start && seg1.start < seg2.end;
} }

View file

@ -63,7 +63,7 @@ else if (_build) {
includeJS('../build/fullcalendar/jquery/ui.resizable.js'); includeJS('../build/fullcalendar/jquery/ui.resizable.js');
} }
else { else {
includeJS('../src/jquery/jquery.js'); includeJS('../src/jquery/jquery-uncompressed.js');
includeJS('../src/jquery/ui.core.js'); includeJS('../src/jquery/ui.core.js');
includeJS('../src/jquery/ui.draggable.js'); includeJS('../src/jquery/ui.draggable.js');
includeJS('../src/jquery/ui.resizable.js'); includeJS('../src/jquery/ui.resizable.js');

View 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>

File diff suppressed because it is too large Load diff

View file

@ -7,19 +7,16 @@
<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',
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay' right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
}, },
//editable: true, editable: true,
events: 'many_events_json.txt' events: 'many_events_json.txt'
}); });