fullcalendar/src/common/DayEventRenderer.js

233 lines
6.7 KiB
JavaScript

function DayEventRenderer() {
var t = this;
// exports
t.renderDaySegs = renderDaySegs;
t.resizableDayEvent = resizableDayEvent;
// imports
var opt = t.opt;
var trigger = t.trigger;
var reportEventElement = t.reportEventElement;
var showEvents = t.showEvents;
var hideEvents = t.hideEvents;
var eventResize = t.eventResize;
var getRowCnt = t.getRowCnt;
var getColCnt = t.getColCnt;
var getColWidth = t.getColWidth;
var allDayTR = t.allDayTR;
var allDayBounds = t.allDayBounds;
var colContentLeft = t.colContentLeft;
var colContentRight = t.colContentRight;
var dayOfWeekCol = t.dayOfWeekCol;
var getDaySegmentContainer = t.getDaySegmentContainer;
var bindDaySeg = t.bindDaySeg; //TODO: streamline this
var formatDates = t.calendar.formatDates;
/* Rendering
-----------------------------------------------------------------------------*/
function renderDaySegs(segs, modifiedEventId) {
var rtl=opt('isRTL'),
i, segCnt=segs.length, seg,
event,
className,
left, right,
html='',
eventElements,
eventElement,
triggerRes,
hsideCache={},
vmarginCache={},
key, val,
rowI, top, levelI, levelHeight,
rowDivs=[],
rowDivTops=[],
bounds = allDayBounds(),
minLeft = bounds.left,
maxLeft = bounds.right,
rowCnt = getRowCnt(),
colCnt = getColCnt(),
segmentContainer = getDaySegmentContainer();
// calculate desired position/dimensions, create html
for (i=0; i<segCnt; i++) {
seg = segs[i];
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 ? colContentLeft(dayOfWeekCol(seg.end.getDay()-1)) : minLeft;
right = seg.isStart ? colContentRight(dayOfWeekCol(seg.start.getDay())) : maxLeft;
}else{
if (seg.isStart) {
className += 'fc-corner-left ';
}
if (seg.isEnd) {
className += 'fc-corner-right ';
}
left = seg.isStart ? colContentLeft(dayOfWeekCol(seg.start.getDay())) : minLeft;
right = seg.isEnd ? colContentRight(dayOfWeekCol(seg.end.getDay()-1)) : maxLeft;
}
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, opt('timeFormat'))) +
"</span>"
:'') +
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
"</a>" +
((event.editable || event.editable === undefined && opt('editable')) && !opt('disableResizing') && $.fn.resizable ?
"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>"
: '') +
"</div>";
seg.left = left;
seg.outerWidth = right - left;
}
segmentContainer[0].innerHTML = html; // faster than html()
eventElements = segmentContainer.children();
// retrieve elements, run through eventRender callback, bind handlers
for (i=0; i<segCnt; i++) {
seg = segs[i];
eventElement = $(eventElements[i]); // faster than eq()
event = seg.event;
triggerRes = trigger('eventRender', event, event, eventElement);
if (triggerRes === false) {
eventElement.remove();
}else{
if (triggerRes && triggerRes !== true) {
eventElement.remove();
eventElement = $(triggerRes)
.css({
position: 'absolute',
left: seg.left
})
.appendTo(segmentContainer);
}
seg.element = eventElement;
if (event._id === modifiedEventId) {
bindDaySeg(event, eventElement, seg);
}else{
eventElement[0]._fci = i; // for lazySegBind
}
reportEventElement(event, eventElement);
}
}
lazySegBind(segmentContainer, segs, bindDaySeg);
// record event horizontal sides
for (i=0; i<segCnt; i++) {
seg = segs[i];
if (eventElement = seg.element) {
val = hsideCache[key = seg.key = cssKey(eventElement[0])];
seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement[0], true)) : val;
}
}
// set event widths
for (i=0; i<segCnt; i++) {
seg = segs[i];
if (eventElement = seg.element) {
eventElement[0].style.width = seg.outerWidth - seg.hsides + 'px';
}
}
// record event heights
for (i=0; i<segCnt; i++) {
seg = segs[i];
if (eventElement = seg.element) {
val = vmarginCache[key = seg.key];
seg.outerHeight = eventElement[0].offsetHeight + (
val === undefined ? (vmarginCache[key] = vmargins(eventElement[0])) : val
);
}
}
// set row heights, calculate event tops (in relation to row top)
for (i=0, rowI=0; rowI<rowCnt; rowI++) {
top = levelI = levelHeight = 0;
while (i<segCnt && (seg = segs[i]).row == rowI) {
if (seg.level != levelI) {
top += levelHeight;
levelHeight = 0;
levelI++;
}
levelHeight = Math.max(levelHeight, seg.outerHeight||0);
seg.top = top;
i++;
}
rowDivs[rowI] = allDayTR(rowI).find('td:first div.fc-day-content > div') // optimal selector?
.height(top + levelHeight);
}
// calculate row tops
for (rowI=0; rowI<rowCnt; rowI++) {
rowDivTops[rowI] = rowDivs[rowI][0].offsetTop;
}
// set event tops
for (i=0; i<segCnt; i++) {
seg = segs[i];
if (eventElement = seg.element) {
eventElement[0].style.top = rowDivTops[seg.row] + seg.top + 'px';
event = seg.event;
trigger('eventAfterRender', event, event, eventElement);
}
}
}
/* Resizing
-----------------------------------------------------------------------------------*/
function resizableDayEvent(event, eventElement) {
if (!opt('disableResizing') && eventElement.resizable) {
var colWidth = getColWidth();
eventElement.resizable({
handles: opt('isRTL') ? {w:'div.ui-resizable-w'} : {e:'div.ui-resizable-e'},
grid: colWidth,
minWidth: colWidth/2, // need this or else IE throws errors when too small
containment: t.element.parent().parent(), // the main element...
// ... a fix. wouldn't allow extending to last column in agenda views (jq ui bug?)
start: function(ev, ui) {
eventElement.css('z-index', 9);
hideEvents(event, eventElement);
trigger('eventResizeStart', this, event, ev, ui);
},
stop: function(ev, ui) {
trigger('eventResizeStop', this, event, ev, ui);
// ui.size.width wasn't working with grid correctly, use .width()
var dayDelta = Math.round((eventElement.width() - ui.originalSize.width) / colWidth);
if (dayDelta) {
eventResize(this, event, dayDelta, 0, ev, ui);
}else{
eventElement.css('z-index', 8);
showEvents(event, eventElement);
}
}
});
}
}
}