setDefaults({
weekMode: 'fixed'
});
views.month = function(element, options) {
return new Grid(element, options, {
render: function(date, delta, fetchEvents) {
if (delta) {
addMonths(date, delta);
}
var start = this.start = cloneDate(date, true);
start.setDate(1);
this.title = formatDates(
start,
addDays(cloneDate(this.end = addMonths(cloneDate(start), 1)), -1),
strProp(options.titleFormat, 'month'),
options
);
addDays(this.visStart = cloneDate(start), -((start.getDay() - options.weekStart + 7) % 7));
addDays(this.visEnd = cloneDate(this.end), (7 - this.visEnd.getDay() + options.weekStart) % 7);
var rowCnt = Math.round((this.visEnd - this.visStart) / (DAY_MS * 7));
if (options.weekMode == 'fixed') {
addDays(this.visEnd, (6 - rowCnt) * 7);
rowCnt = 6;
}
this.renderGrid(rowCnt, 7, strProp(options.columnFormat, 'month'), true, fetchEvents);
}
});
}
views.basicWeek = function(element, options) {
return new Grid(element, options, {
render: function(date, delta, fetchEvents) {
if (delta) {
addDays(date, delta * 7);
}
this.title = formatDates(
this.start = this.visStart = addDays(cloneDate(date), -((date.getDay() - options.weekStart + 7) % 7)),
addDays(cloneDate(this.end = this.visEnd = addDays(cloneDate(this.start), 7)), -1),
strProp(options.titleFormat, 'week'),
options
);
this.renderGrid(1, 7, strProp(options.columnFormat, 'week'), false, fetchEvents);
}
});
};
views.basicDay = function(element, options) {
return new Grid(element, options, {
render: function(date, delta, fetchEvents) {
if (delta) {
addDays(date, delta);
}
this.title = formatDate(date, strProp(options.titleFormat, 'day'), options);
this.start = this.visStart = cloneDate(date, true);
this.end = this.visEnd = addDays(cloneDate(this.start), 1);
this.renderGrid(1, 1, strProp(options.columnFormat, 'day'), false, fetchEvents);
}
});
}
// flags for [Opera] rendering bugs
var tdTopBug, trTopBug, tbodyTopBug, sniffBugs = true;
var tdHeightBug;
var sniffedEventLeftBug, eventLeftDiff=0;
function Grid(element, options, methods) {
var tm, weekStart,
rtl, dis, dit, // day index sign / translate
rowCnt, colCnt,
colWidth,
thead, tbody,
cachedSegs, //...
// initialize superclass
view = $.extend(this, viewMethods, methods, {
renderGrid: renderGrid,
rerenderEvents: rerenderEvents,
updateSize: updateSize,
eventEnd: function(event) {
return event.end || cloneDate(event.start);
},
visEventEnd: function(event) {
if (event.end) {
var end = cloneDate(event.end);
return (!event.hasTime || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
}else{
return addDays(cloneDate(event.start), 1);
}
}
});
view.init(element, options);
/********************************* grid rendering *************************************/
element.addClass('fc-grid').css('position', 'relative');
if (element.disableSelection) {
element.disableSelection();
}
function renderGrid(r, c, colFormat, showNumbers, fetchEvents) {
//console.log('renderGrid!');
rowCnt = r;
colCnt = c;
var month = view.start.getMonth(),
today = clearTime(new Date()),
s, s2, s3, i, j, d = cloneDate(view.visStart);
// update option-derived variables
tm = options.theme ? 'ui' : 'fc';
weekStart = options.weekStart;
if (rtl = options.isRTL) {
dis = -1;
dit = colCnt - 1;
}else{
dis = 1;
dit = 0;
}
if (!tbody) { // first time, build all cells from scratch
var table = $("
").appendTo(element);
s = '';
for (i=0; i" + formatDate(d, colFormat, options) + ""; // TODO: optionize
//if (rtl) {
// s = s2 + s;
//}else{
s += s2;
//}
addDays(d, 1);
}
thead = $("" + s + "
").appendTo(table);
s = "";
d = cloneDate(view.visStart);
for (i=0; i1 && d.getMonth() != month ? ' fc-other-month' : '') +
(+d == +today ?
' fc-today '+tm+'-state-highlight' :
' fc-not-today') + "'>" +
(showNumbers ? "" + d.getDate() + "
" : '') +
"";
//if (rtl) {
// s2 = s3 + s2;
//}else{
s2 += s3;
//}
addDays(d, 1);
}
s += "" + s2 + "
";
}
tbody = $(s + "").appendTo(table);
tbody.find('td').click(dayClick);
}else{ // NOT first time, reuse as many cells as possible
view.clearEvents();
var prevRowCnt = tbody.find('tr').length;
if (rowCnt < prevRowCnt) {
tbody.find('tr:gt(' + (rowCnt-1) + ')').remove(); // remove extra rows
}
else if (rowCnt > prevRowCnt) {
s = '';
for (i=prevRowCnt; i" +
(showNumbers ? "" : '') +
"" +
"";
//if (rtl) {
// s2 = s3 + s2;
//}else{
s2 += s3;
//}
}
s += "" + s2 + "
";
}
tbody.append(s);
}
tbody.find('td.fc-new').removeClass('fc-new').click(dayClick);
// re-label and re-class existing cells
tbody.find('tr').each(function() {
for (i=0; i 1) {
if (d.getMonth() == month) {
td.removeClass('fc-other-month');
}else{
td.addClass('fc-other-month');
}
}
if (+d == +today) {
td.removeClass('fc-not-today')
.addClass('fc-today')
.addClass(tm + '-state-highlight');
}else{
td.addClass('fc-not-today')
.removeClass('fc-today')
.removeClass(tm + '-state-highlight');
}
td.find('div.fc-day-number').text(d.getDate());
addDays(d, 1);
}
});
if (colCnt == 1) {
var startDay = this.visStart.getDay();
var td = tbody.find('td')[0];
td.className = td.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[startDay]);
thead.find('th').text(formatDate(this.start, colFormat, options));
}
}
updateSize();
fetchEvents(renderEvents);
};
function updateSize() {
var width = element.width();
var height = Math.round(width / options.aspectRatio);
setOuterWidth(
thead.find('th').slice(0, -1),
colWidth = Math.floor(width / colCnt)
);
var leftTDs = tbody.find('tr td:first-child');
var tbodyHeight = height - thead.height();
var rowHeight1, rowHeight2;
if (options.weekMode == 'variable') {
rowHeight1 = rowHeight2 = Math.floor(tbodyHeight / (rowCnt==1 ? 2 : 6));
}else{
rowHeight1 = Math.floor(tbodyHeight / rowCnt);
rowHeight2 = tbodyHeight - rowHeight1*(rowCnt-1);
}
if (sniffBugs) {
// nasty bugs in opera 9.25
// position() returning relative to direct parent
var tr = tbody.find('tr:first');
var td = tr.find('td:first');
var trTop = tr.position().top;
var tdTop = td.position().top;
tdTopBug = tdTop < 0;
trTopBug = trTop != tdTop;
tbodyTopBug = tbody.position().top != trTop;
sniffBugs = false;
//
td.height(rowHeight1);
tdHeightBug = rowHeight1 != td.height();
}
if (tdHeightBug) {
leftTDs.slice(0, -1).height(rowHeight1);
leftTDs.slice(-1).height(rowHeight2);
}else{
setOuterHeight(leftTDs.slice(0, -1), rowHeight1);
setOuterHeight(leftTDs.slice(-1), rowHeight2);
}
//alert(tbodyHeight + ' === ' + tbody.height());
}
/******************************** event rendering *****************************/
function renderEvents(events) {
view.reportEvents(events);
renderSegs(cachedSegs = compileSegs(events)); // view.visibleEvents(
}
function rerenderEvents(skipCompile) {
//console.log('rerender events');
view.clearEvents();
if (skipCompile) {
renderSegs(cachedSegs);
}else{
renderEvents(view.cachedEvents);
}
}
function compileSegs(events) {
var d1 = cloneDate(view.visStart);
var d2 = addDays(cloneDate(d1), colCnt);
var rows = [];
for (var i=0; i")
.append(eventAnchor = $("")
.append(event.hasTime ?
$("")
.html(formatDate(event.start, options.eventTimeFormat, options)) :
null)
.append($("")
.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: left1 + eventLeftDiff,
zIndex: 3
})
.appendTo(element);
setOuterWidth(eventElement, left2-left1, true);
if (!sniffedEventLeftBug) {
if (rtl) {
eventLeftDiff = left1 - eventElement.position().left;
if (eventLeftDiff) {
eventElement.css('left', left1 + eventLeftDiff);
}
}
sniffedEventLeftBug = true;
}
eventElementHandlers(event, eventElement);
if (event.editable || typeof event.editable == 'undefined' && options.editable) {
draggableEvent(event, eventElement);
resizableEvent(event, eventElement);
}
view.reportEventElement(event, eventElement);
levelHeight = Math.max(levelHeight, eventElement.outerHeight(true));
}
}
weekHeight += levelHeight;
top += levelHeight;
}
innerDiv.height(weekHeight);
}
}
function eventElementHandlers(event, eventElement) {
eventElement
.click(function(ev) {
if (!eventElement.hasClass('ui-draggable-dragging')) {
return view.trigger('eventClick', this, event, ev);
}
})
.hover(
function(ev) {
view.trigger('eventMouseover', this, event, ev);
},
function(ev) {
view.trigger('eventMouseover', this, event, ev);
}
);
}
/***************************** draggable *********************************/
function draggableEvent(event, eventElement) {
if (!options.disableDragging && eventElement.draggable) {
var matrix;
eventElement.draggable({
zIndex: 4,
delay: 50,
opacity: options.dragOpacity,
revertDuration: options.dragRevertDuration,
start: function(ev, ui) {
matrix = new HoverMatrix(function(cell) {
eventElement.draggable('option', 'revert', !cell || !cell.rowDelta && !cell.colDelta);
if (cell) {
view.showOverlay(cell);
}else{
view.hideOverlay();
}
});
tbody.find('tr').each(function() {
matrix.row(this);
});
var tds = tbody.find('tr:first td');
if (rtl) {
tds = $(tds.get().reverse());
}
tds.each(function() {
matrix.col(this);
});
matrix.start();
view.hideEvents(event, eventElement);
view.trigger('eventDragStart', eventElement, event, ev, ui);
},
drag: function(ev) {
matrix.mouse(ev.pageX, ev.pageY);
},
stop: function(ev, ui) {
view.hideOverlay();
view.trigger('eventDragStop', eventElement, event, ev, ui);
var cell = matrix.cell;
if (!cell || !cell.rowDelta && !cell.colDelta) {
view.showEvents(event, eventElement);
}else{
var dayDelta = cell.rowDelta*7 + cell.colDelta*dis;
view.moveEvent(event, dayDelta);
view.trigger('eventDrop', this, event, dayDelta, 0, ev, ui);
rerenderEvents();
}
}
});
}
}
/******************************* resizable *****************************/
function resizableEvent(event, eventElement) {
if (!options.disableResizing && eventElement.resizable) {
eventElement.resizable({
handles: rtl ? 'w' : 'e',
grid: [colWidth, 0],
containment: element,
start: function(ev, ui) {
eventElement.css('z-index', 4);
view.hideEvents(event, eventElement);
view.trigger('eventResizeStart', this, event, ev, ui);
},
stop: function(ev, ui) {
view.trigger('eventResizeStop', this, event, ev, ui);
var dayDelta = Math.round((Math.max(colWidth, ui.size.width) - ui.originalSize.width) / colWidth);
if (dayDelta) {
view.resizeEvent(event, dayDelta);
view.trigger('eventResize', this, event, dayDelta, 0, ev, ui);
rerenderEvents();
}else{
view.showEvents(event, eventElement);
}
eventElement.css('z-index', 3);
}
});
}
}
//
function dayClick() {
var dayIndex = parseInt(this.className.match(/fc\-day(\d+)/)[1]);
var date = addDays(cloneDate(view.visStart), dayIndex);
view.trigger('dayClick', this, date);
}
};