throw { name: 'FatalError', message: 'Do not call this file. If you want to use it, remove this line.' };
/**
* @preserve
* FullCalendar v1.4.6
* http://arshaw.com/fullcalendar/
*
* Use fullcalendar.css for basic styling.
* For event drag & drop, required jQuery UI draggable.
* For event resizing, requires jQuery UI resizable.
*
* Copyright (c) 2009 Adam Shaw
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Date: Mon May 31 10:18:29 2010 -0700
*
* Modified by Christian Wengg
*
*/
(function($) {
var fc = $.fullCalendar = {};
var views = fc.views = {};
/* Defaults
-----------------------------------------------------------------------------*/
var defaults = {
// display
defaultView: 'month',
aspectRatio: 1.35,
header: {
left: 'title',
center: '',
right: 'today prev,next'
},
weekends: true,
// editing
//editable: false,
//disableDragging: false,
//disableResizing: false,
allDayDefault: true,
// event ajax
lazyFetching: true,
startParam: 'start',
endParam: 'end',
// time formats
titleFormat: {
month: 'MMMM yyyy',
week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}",
day: 'dddd, MMM d, yyyy'
},
columnFormat: {
month: 'ddd',
week: 'ddd M/d',
day: 'dddd M/d'
},
timeFormat: { // for event elements
'': 'h(:mm)t' // default
},
// locale
isRTL: false,
firstDay: 0,
monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
buttonText: {
prev: ' ◄ ',
next: ' ► ',
prevYear: ' << ',
nextYear: ' >> ',
today: 'today',
month: 'month',
week: 'week',
day: 'day'
},
// jquery-ui theming
theme: false,
buttonIcons: {
prev: 'circle-triangle-w',
next: 'circle-triangle-e'
},
//selectable: false,
unselectAuto: true
};
// right-to-left defaults
var rtlDefaults = {
header: {
left: 'next,prev today',
center: '',
right: 'title'
},
buttonText: {
prev: ' ► ',
next: ' ◄ ',
prevYear: ' >> ',
nextYear: ' << '
},
buttonIcons: {
prev: 'circle-triangle-e',
next: 'circle-triangle-w'
}
};
// function for adding/overriding defaults
var setDefaults = fc.setDefaults = function(d) {
$.extend(true, defaults, d);
};
/* .fullCalendar jQuery function
-----------------------------------------------------------------------------*/
$.fn.fullCalendar = function(options) {
// method calling
if (typeof options == 'string') {
var args = Array.prototype.slice.call(arguments, 1),
res;
this.each(function() {
var data = $.data(this, 'fullCalendar');
if (data) {
var meth = data[options];
if (meth) {
var r = meth.apply(this, args);
if (res === undefined) {
res = r;
}
}
}
});
if (res !== undefined) {
return res;
}
return this;
}
// pluck the 'events' and 'eventSources' options
var eventSources = options.eventSources || [];
delete options.eventSources;
if (options.events) {
eventSources.push(options.events);
delete options.events;
}
// first event source reserved for 'sticky' events
eventSources.unshift([]);
// initialize options
options = $.extend(true, {},
defaults,
(options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {},
options
);
var tm = options.theme ? 'ui' : 'fc'; // for making theme classes
this.each(function() {
/* Instance Initialization
-----------------------------------------------------------------------------*/
// element
var _element = this,
element = $(_element).addClass('fc'),
elementOuterWidth,
content = $("
").prependTo(_element),
suggestedViewHeight,
resizeUID = 0,
ignoreWindowResize = 0,
date = new Date(),
viewName, // the current view name (TODO: look into getting rid of)
view, // the current view
viewInstances = {},
absoluteViewElement;
if (options.isRTL) {
element.addClass('fc-rtl');
}
if (options.theme) {
element.addClass('ui-widget');
}
if (options.year !== undefined && options.year != date.getFullYear()) {
date.setDate(1);
date.setMonth(0);
date.setFullYear(options.year);
}
if (options.month !== undefined && options.month != date.getMonth()) {
date.setDate(1);
date.setMonth(options.month);
}
if (options.date !== undefined) {
date.setDate(options.date);
}
/* View Rendering
-----------------------------------------------------------------------------*/
function changeView(v) {
if (v != viewName) {
ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached
viewUnselect();
var oldView = view,
newViewElement;
if (oldView) {
if (oldView.eventsChanged) {
eventsDirty();
oldView.eventDirty = oldView.eventsChanged = false;
}
if (oldView.beforeHide) {
oldView.beforeHide(); // called before changing min-height. if called after, scroll state is reset (in Opera)
}
setMinHeight(content, content.height());
oldView.element.hide();
}else{
setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated
}
content.css('overflow', 'hidden');
if (viewInstances[v]) {
(view = viewInstances[v]).element.show();
}else{
view = viewInstances[v] = fc.views[v](
newViewElement = absoluteViewElement =
$("")
.appendTo(content),
options
);
}
if (header) {
// update 'active' view button
header.find('div.fc-button-' + viewName).removeClass(tm + '-state-active');
header.find('div.fc-button-' + v).addClass(tm + '-state-active');
}
view.name = viewName = v;
render(); // after height has been set, will make absoluteViewElement's position=relative, then set to null
content.css('overflow', '');
if (oldView) {
setMinHeight(content, 1);
}
if (!newViewElement && view.afterShow) {
view.afterShow(); // called after setting min-height/overflow, so in final scroll state (for Opera)
}
ignoreWindowResize--;
}
}
function render(inc) {
if (elementVisible()) {
ignoreWindowResize++; // because view.renderEvents might temporarily change the height before setSize is reached
viewUnselect();
if (suggestedViewHeight === undefined) {
calcSize();
}
if (!view.start || inc || date < view.start || date >= view.end) {
view.render(date, inc || 0); // responsible for clearing events
setSize(true);
if (!eventStart || !options.lazyFetching || view.visStart < eventStart || view.visEnd > eventEnd) {
fetchAndRenderEvents();
}else{
view.renderEvents(events); // don't refetch
}
}
else if (view.sizeDirty || view.eventsDirty || !options.lazyFetching) {
view.clearEvents();
if (view.sizeDirty) {
setSize();
}
if (options.lazyFetching) {
view.renderEvents(events); // don't refetch
}else{
fetchAndRenderEvents();
}
}
elementOuterWidth = element.outerWidth();
view.sizeDirty = false;
view.eventsDirty = false;
if (header) {
// update title text
header.find('h2.fc-header-title').html(view.title);
// enable/disable 'today' button
var today = new Date();
if (today >= view.start && today < view.end) {
header.find('div.fc-button-today').addClass(tm + '-state-disabled');
}else{
header.find('div.fc-button-today').removeClass(tm + '-state-disabled');
}
}
ignoreWindowResize--;
view.trigger('viewDisplay', _element);
}
}
function elementVisible() {
return _element.offsetWidth !== 0;
}
function bodyVisible() {
return $('body')[0].offsetWidth !== 0;
}
function viewUnselect() {
if (view) {
view.unselect();
}
}
// called when any event objects have been added/removed/changed, rerenders
function eventsChanged() {
eventsDirty();
if (elementVisible()) {
view.clearEvents();
view.renderEvents(events);
view.eventsDirty = false;
}
}
// marks other views' events as dirty
function eventsDirty() {
$.each(viewInstances, function() {
this.eventsDirty = true;
});
}
// called when we know the element size has changed
function sizeChanged() {
sizesDirty();
if (elementVisible()) {
calcSize();
setSize();
viewUnselect();
view.rerenderEvents();
view.sizeDirty = false;
}
}
// marks other views' sizes as dirty
function sizesDirty() {
$.each(viewInstances, function() {
this.sizeDirty = true;
});
}
/* Event Sources and Fetching
-----------------------------------------------------------------------------*/
var events = [],
eventStart, eventEnd;
// Fetch from ALL sources. Clear 'events' array and populate
function fetchEvents(callback) {
events = [];
eventStart = cloneDate(view.visStart);
eventEnd = cloneDate(view.visEnd);
var queued = eventSources.length,
sourceDone = function() {
if (!--queued) {
if (callback) {
callback(events);
}
}
}, i=0;
for (; i")
.append($("
")
.append($("").append(buildSection(sections.left)))
.append($("").append(buildSection(sections.center)))
.append($("").append(buildSection(sections.right))))
.prependTo(element);
}
function buildSection(buttonStr) {
if (buttonStr) {
var tr = $("
");
$.each(buttonStr.split(' '), function(i) {
if (i > 0) {
tr.append(" | ");
}
var prevButton;
$.each(this.split(','), function(j, buttonName) {
if (buttonName == 'title') {
tr.append(" | ");
if (prevButton) {
prevButton.addClass(tm + '-corner-right');
}
prevButton = null;
}else{
var buttonClick;
if (publicMethods[buttonName]) {
buttonClick = publicMethods[buttonName];
}
else if (views[buttonName]) {
buttonClick = function() {
button.removeClass(tm + '-state-hover');
changeView(buttonName);
};
}
if (buttonClick) {
if (prevButton) {
prevButton.addClass(tm + '-no-right');
}
var button,
icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null,
text = smartProperty(options.buttonText, buttonName);
if (icon) {
button = $("");
}
else if (text) {
button = $("");
}
if (button) {
button
.click(function() {
if (!button.hasClass(tm + '-state-disabled')) {
buttonClick();
}
})
.mousedown(function() {
button
.not('.' + tm + '-state-active')
.not('.' + tm + '-state-disabled')
.addClass(tm + '-state-down');
})
.mouseup(function() {
button.removeClass(tm + '-state-down');
})
.hover(
function() {
button
.not('.' + tm + '-state-active')
.not('.' + tm + '-state-disabled')
.addClass(tm + '-state-hover');
},
function() {
button
.removeClass(tm + '-state-hover')
.removeClass(tm + '-state-down');
}
)
.appendTo($(" | ").appendTo(tr));
if (prevButton) {
prevButton.addClass(tm + '-no-right');
}else{
button.addClass(tm + '-corner-left');
}
prevButton = button;
}
}
}
});
if (prevButton) {
prevButton.addClass(tm + '-corner-right');
}
});
return $("").append(tr);
}
}
/* Resizing
-----------------------------------------------------------------------------*/
function calcSize() {
if (options.contentHeight) {
suggestedViewHeight = options.contentHeight;
}
else if (options.height) {
suggestedViewHeight = options.height - (header ? header.height() : 0) - vsides(content[0]);
}
else {
suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));
}
}
function setSize(dateChanged) {
ignoreWindowResize++;
view.setHeight(suggestedViewHeight, dateChanged);
if (absoluteViewElement) {
absoluteViewElement.css('position', 'relative');
absoluteViewElement = null;
}
view.setWidth(content.width(), dateChanged);
ignoreWindowResize--;
}
function windowResize() {
if (!ignoreWindowResize) {
if (view.start) { // view has already been rendered
var uid = ++resizeUID;
setTimeout(function() { // add a delay
if (uid == resizeUID && !ignoreWindowResize && elementVisible()) {
if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {
ignoreWindowResize++; // in case the windowResize callback changes the height
sizeChanged();
view.trigger('windowResize', _element);
ignoreWindowResize--;
}
}
}, 200);
}else{
// calendar must have been initialized in a 0x0 iframe that has just been resized
lateRender();
}
}
}
$(window).resize(windowResize);
// let's begin...
changeView(options.defaultView);
// needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize
if (!bodyVisible()) {
lateRender();
}
// called when we know the calendar couldn't be rendered when it was initialized,
// but we think it's ready now
function lateRender() {
setTimeout(function() { // IE7 needs this so dimensions are calculated correctly
if (!view.start && bodyVisible()) { // !view.start makes sure this never happens more than once
render();
}
},0);
}
});
return this;
};
/* Important Event Utilities
-----------------------------------------------------------------------------*/
var fakeID = 0;
function normalizeEvent(event, options) {
event._id = event._id || (event.id === undefined ? '_fc' + fakeID++ : event.id + '');
if (event.date) {
if (!event.start) {
event.start = event.date;
}
delete event.date;
}
event._start = cloneDate(event.start = parseDate(event.start));
event.end = parseDate(event.end);
if (event.end && event.end <= event.start) {
event.end = null;
}
event._end = event.end ? cloneDate(event.end) : null;
if (event.allDay === undefined) {
event.allDay = options.allDayDefault;
}
if (event.className) {
if (typeof event.className == 'string') {
event.className = event.className.split(/\s+/);
}
}else{
event.className = [];
}
}
// TODO: if there is no start date, return false to indicate an invalid event
/* Grid-based Views: month, basicWeek, basicDay
-----------------------------------------------------------------------------*/
setDefaults({
weekMode: 'fixed'
});
views.month = function(element, options) {
return new Grid(element, options, {
render: function(date, delta) {
if (delta) {
addMonths(date, delta);
date.setDate(1);
}
// start/end
var start = this.start = cloneDate(date, true);
start.setDate(1);
this.end = addMonths(cloneDate(start), 1);
// visStart/visEnd
var visStart = this.visStart = cloneDate(start),
visEnd = this.visEnd = cloneDate(this.end),
nwe = options.weekends ? 0 : 1;
if (nwe) {
skipWeekend(visStart);
skipWeekend(visEnd, -1, true);
}
addDays(visStart, -((visStart.getDay() - Math.max(options.firstDay, nwe) + 7) % 7));
addDays(visEnd, (7 - visEnd.getDay() + Math.max(options.firstDay, nwe)) % 7);
// row count
var rowCnt = Math.round((visEnd - visStart) / (DAY_MS * 7));
if (options.weekMode == 'fixed') {
addDays(visEnd, (6 - rowCnt) * 7);
rowCnt = 6;
}
// title
this.title = formatDate(
start,
this.option('titleFormat'),
options
);
// render
this.renderGrid(
rowCnt, options.weekends ? 7 : 5,
this.option('columnFormat'),
true
);
}
});
};
views.basicWeek = function(element, options) {
return new Grid(element, options, {
render: function(date, delta) {
if (delta) {
addDays(date, delta * 7);
}
var visStart = this.visStart = cloneDate(
this.start = addDays(cloneDate(date), -((date.getDay() - options.firstDay + 7) % 7))
),
visEnd = this.visEnd = cloneDate(
this.end = addDays(cloneDate(visStart), 7)
);
if (!options.weekends) {
skipWeekend(visStart);
skipWeekend(visEnd, -1, true);
}
this.title = formatDates(
visStart,
addDays(cloneDate(visEnd), -1),
this.option('titleFormat'),
options
);
this.renderGrid(
1, options.weekends ? 7 : 5,
this.option('columnFormat'),
false
);
}
});
};
views.basicDay = function(element, options) {
return new Grid(element, options, {
render: function(date, delta) {
if (delta) {
addDays(date, delta);
if (!options.weekends) {
skipWeekend(date, delta < 0 ? -1 : 1);
}
}
this.title = formatDate(date, this.option('titleFormat'), options);
this.start = this.visStart = cloneDate(date, true);
this.end = this.visEnd = addDays(cloneDate(this.start), 1);
this.renderGrid(
1, 1,
this.option('columnFormat'),
false
);
}
});
};
// rendering bugs
var tdHeightBug;
function Grid(element, options, methods) {
var tm, firstDay,
nwe, // no weekends (int)
rtl, dis, dit, // day index sign / translate
viewWidth, viewHeight,
rowCnt, colCnt,
colWidth,
thead, tbody,
cachedEvents=[],
segmentContainer,
dayContentPositions = new HorizontalPositionCache(function(dayOfWeek) {
return tbody.find('td:eq(' + ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt) + ') div div');
}),
selectionManager,
selectionMatrix,
// ...
// initialize superclass
view = $.extend(this, viewMethods, methods, {
renderGrid: renderGrid,
renderEvents: renderEvents,
rerenderEvents: rerenderEvents,
clearEvents: clearEvents,
setHeight: setHeight,
setWidth: setWidth,
defaultEventEnd: function(event) { // calculates an end if event doesnt have one, mostly for resizing
return cloneDate(event.start);
}
});
view.init(element, options);
/* Grid Rendering
-----------------------------------------------------------------------------*/
disableTextSelection(element.addClass('fc-grid'));
function renderGrid(r, c, colFormat, showNumbers) {
rowCnt = r;
colCnt = c;
// update option-derived variables
tm = options.theme ? 'ui' : 'fc';
nwe = options.weekends ? 0 : 1;
firstDay = options.firstDay;
if (rtl = options.isRTL) {
dis = -1;
dit = colCnt - 1;
}else{
dis = 1;
dit = 0;
}
var month = view.start.getMonth(),
today = clearTime(new Date()),
s, i, j, d = cloneDate(view.visStart);
if (!tbody) { // first time, build all cells from scratch
var table = $("").appendTo(element);
s = "";
for (i=0; i" + formatDate(d, colFormat, options) + "";
addDays(d, 1);
if (nwe) {
skipWeekend(d);
}
}
thead = $(s + "
").appendTo(table);
s = "";
d = cloneDate(view.visStart);
for (i=0; i";
for (j=0; j1 && d.getMonth() != month ? ' fc-other-month' : '') +
(+d == +today ?
' fc-today '+tm+'-state-highlight' :
' fc-not-today') + "'>" +
(showNumbers ? "" + d.getDate() + "
" : '') +
"";
addDays(d, 1);
if (nwe) {
skipWeekend(d);
}
}
s += "";
}
tbody = $(s + "").appendTo(table);
dayBind(tbody.find('td'));
segmentContainer = $("").appendTo(element);
}else{ // NOT first time, reuse as many cells as possible
clearEvents();
var prevRowCnt = tbody.find('tr').length;
if (rowCnt < prevRowCnt) {
tbody.find('tr:gt(' + (rowCnt-1) + ')').remove(); // remove extra rows
}
else if (rowCnt > prevRowCnt) { // needs to create new rows...
s = '';
for (i=prevRowCnt; i";
for (j=0; j" +
(showNumbers ? "" : '') +
"" +
"";
addDays(d, 1);
if (nwe) {
skipWeekend(d);
}
}
s += "";
}
tbody.append(s);
}
dayBind(tbody.find('td.fc-new').removeClass('fc-new'));
// re-label and re-class existing cells
d = cloneDate(view.visStart);
tbody.find('td').each(function() {
var td = $(this);
if (rowCnt > 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 (nwe) {
skipWeekend(d);
}
});
if (rowCnt == 1) { // more changes likely (week or day view)
// redo column header text and class
d = cloneDate(view.visStart);
thead.find('th').each(function() {
$(this).text(formatDate(d, colFormat, options));
this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
addDays(d, 1);
if (nwe) {
skipWeekend(d);
}
});
// redo cell day-of-weeks
d = cloneDate(view.visStart);
tbody.find('td').each(function() {
this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
addDays(d, 1);
if (nwe) {
skipWeekend(d);
}
});
}
}
}
function setHeight(height) {
viewHeight = height;
var leftTDs = tbody.find('tr td:first-child'),
tbodyHeight = viewHeight - thead.height(),
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 (tdHeightBug === undefined) {
// bug in firefox where cell height includes padding
var tr = tbody.find('tr:first'),
td = tr.find('td:first');
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);
}
}
function setWidth(width) {
viewWidth = width;
dayContentPositions.clear();
setOuterWidth(
thead.find('th').slice(0, -1),
colWidth = Math.floor(viewWidth / colCnt)
);
}
/* Event Rendering
-----------------------------------------------------------------------------*/
function renderEvents(events) {
view.reportEvents(cachedEvents = events);
renderSegs(compileSegs(events));
}
function rerenderEvents(modifiedEventId) {
clearEvents();
renderSegs(compileSegs(cachedEvents), modifiedEventId);
}
function clearEvents() {
view._clearEvents(); // only clears the hashes
segmentContainer.empty();
}
function compileSegs(events) {
var d1 = cloneDate(view.visStart),
d2 = addDays(cloneDate(d1), colCnt),
visEventsEnds = $.map(events, exclEndDay),
i, row,
j, level,
k, seg,
segs=[];
for (i=0; i" +
"" +
(!event.allDay && seg.isStart ?
"" +
htmlEscape(formatDates(event.start, event.end, view.option('timeFormat'), options)) +
""
:'') +
"" + htmlEscape(event.title) + "" +
"" +
((event.editable || event.editable === undefined && options.editable) && !options.disableResizing && $.fn.resizable ?
""
: '') +
"";
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 div') // optimal selector?
.height(top + levelHeight);
}
// calculate row tops
for (rowI=0; rowI" +
"" +
" | ";
for (i=0; i" + formatDate(d, colFormat, options) + "";
addDays(d, dis);
if (nwe) {
skipWeekend(d, dis);
}
}
s += " |
";
if (options.allDaySlot) {
s += "" +
"" + options.allDayText + " | " +
"" +
" | " +
" | " +
"
|
";
}
s+= "";
head = $(s).appendTo(element);
dayBind(head.find('td'));
// all-day event container
daySegmentContainer = $("").appendTo(head);
// body
d = zeroDate();
var maxd = addMinutes(cloneDate(d), maxMinute);
addMinutes(d, minMinute);
s = "";
for (i=0; d < maxd; i++) {
minutes = d.getMinutes();
s += "" +
((!slotNormal || !minutes) ? formatDate(d, options.axisFormat) : ' ') +
" | |
";
addMinutes(d, options.slotMinutes);
slotCnt++;
}
s += "
";
body = $("")
.append(bodyContent = $("")
.append(bodyTable = $(s)))
.appendTo(element);
slotBind(body.find('td'));
// slot event container
slotSegmentContainer = $("
").appendTo(bodyContent);
// background stripes
d = cloneDate(d0);
s = "
" +
"
";
for (i=0; i";
addDays(d, dis);
if (nwe) {
skipWeekend(d, dis);
}
}
s += "
";
bg = $(s).appendTo(element);
}else{ // skeleton already built, just modify it
clearEvents();
// redo column header text and class
head.find('tr:first th').slice(1, -1).each(function() {
$(this).text(formatDate(d, colFormat, options));
this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
addDays(d, dis);
if (nwe) {
skipWeekend(d, dis);
}
});
// change classes of background stripes
d = cloneDate(d0);
bg.find('td').each(function() {
this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
if (+d == +today) {
$(this)
.removeClass('fc-not-today')
.addClass('fc-today')
.addClass(tm + '-state-highlight');
}else{
$(this)
.addClass('fc-not-today')
.removeClass('fc-today')
.removeClass(tm + '-state-highlight');
}
addDays(d, dis);
if (nwe) {
skipWeekend(d, dis);
}
});
}
}
function resetScroll() {
var d0 = zeroDate(),
scrollDate = cloneDate(d0);
scrollDate.setHours(options.firstHour);
var top = timePosition(d0, scrollDate) + 1, // +1 for the border
scroll = function() {
body.scrollTop(top);
};
scroll();
setTimeout(scroll, 0); // overrides any previous scroll state made by the browser
}
function setHeight(height, dateChanged) {
viewHeight = height;
slotTopCache = {};
body.height(height - head.height());
slotHeight = body.find('tr:first div').height() + 1;
bg.css({
top: head.find('tr').height(),
height: height
});
if (dateChanged) {
resetScroll();
}
}
function setWidth(width) {
viewWidth = width;
colContentPositions.clear();
body.width(width);
bodyTable.width('');
var topTDs = head.find('tr:first th'),
stripeTDs = bg.find('td'),
clientWidth = body[0].clientWidth;
bodyTable.width(clientWidth);
// time-axis width
axisWidth = 0;
setOuterWidth(
head.find('tr:lt(2) th:first').add(body.find('tr:first th'))
.width('')
.each(function() {
axisWidth = Math.max(axisWidth, $(this).outerWidth());
}),
axisWidth
);
// column width
colWidth = Math.floor((clientWidth - axisWidth) / colCnt);
setOuterWidth(stripeTDs.slice(0, -1), colWidth);
setOuterWidth(topTDs.slice(1, -2), colWidth);
setOuterWidth(topTDs.slice(-2, -1), clientWidth - axisWidth - colWidth*(colCnt-1));
bg.css({
left: axisWidth,
width: clientWidth - axisWidth
});
}
/* Slot/Day clicking and binding
-----------------------------------------------------------------------*/
function dayBind(tds) {
tds.click(slotClick)
.mousedown(daySelectionMousedown);
}
function slotBind(tds) {
tds.click(slotClick)
.mousedown(slotSelectionMousedown);
}
function slotClick(ev) {
if (!view.option('selectable')) { // SelectionManager will worry about dayClick
var col = Math.floor((ev.pageX - bg.offset().left) / colWidth),
date = addDays(cloneDate(view.visStart), dit + dis*col),
rowMatch = this.className.match(/fc-slot(\d+)/);
if (rowMatch) {
var mins = parseInt(rowMatch[1]) * options.slotMinutes,
hours = Math.floor(mins/60);
date.setHours(hours);
date.setMinutes(mins%60 + minMinute);
view.trigger('dayClick', this, date, false, ev);
}else{
view.trigger('dayClick', this, date, true, ev);
}
}
}
/* Event Rendering
-----------------------------------------------------------------------------*/
function renderEvents(events, modifiedEventId) {
view.reportEvents(cachedEvents = events);
var i, len=events.length,
dayEvents=[],
slotEvents=[];
for (i=0; i
" +
"" +
"" +
"" + htmlEscape(formatDates(event.start, event.end, view.option('timeFormat'))) + "" +
"" + htmlEscape(event.title) + "" +
"" +
((event.editable || event.editable === undefined && options.editable) && !options.disableResizing && $.fn.resizable ?
"=
"
: '') +
" ";
}
function daySegBind(event, eventElement, seg) {
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);
}
}
}
function slotSegBind(event, eventElement, seg) {
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);
}
}
}
/* Event Dragging
-----------------------------------------------------------------------------*/
// when event starts out FULL-DAY
function draggableDayEvent(event, eventElement, isStart) {
if (!options.disableDragging && eventElement.draggable) {
var origPosition, origWidth,
resetElement,
allDay=true,
matrix;
eventElement.draggable({
zIndex: 9,
opacity: view.option('dragOpacity', 'month'), // use whatever the month view was using
revertDuration: options.dragRevertDuration,
start: function(ev, ui) {
view.hideEvents(event, eventElement);
view.trigger('eventDragStart', eventElement, event, ev, ui);
origPosition = eventElement.position();
origWidth = eventElement.width();
resetElement = function() {
if (!allDay) {
eventElement
.width(origWidth)
.height('')
.draggable('option', 'grid', null);
allDay = true;
}
};
matrix = buildDayMatrix(function(cell) {
eventElement.draggable('option', 'revert', !cell || !cell.rowDelta && !cell.colDelta);
view.clearOverlays();
if (cell) {
if (!cell.row) {
// on full-days
renderDayOverlay(
matrix,
addDays(cloneDate(event.start), cell.colDelta),
addDays(exclEndDay(event), cell.colDelta)
);
resetElement();
}else{
// mouse is over bottom slots
if (isStart && allDay) {
// convert event to temporary slot-event
setOuterHeight(
eventElement.width(colWidth - 10), // don't use entire width
slotHeight * Math.round(
(event.end ? ((event.end - event.start)/MINUTE_MS) : options.defaultEventMinutes)
/options.slotMinutes)
);
eventElement.draggable('option', 'grid', [colWidth, 1]);
allDay = false;
}
}
}
},true);
matrix.mouse(ev);
},
drag: function(ev, ui) {
matrix.mouse(ev);
},
stop: function(ev, ui) {
view.trigger('eventDragStop', eventElement, event, ev, ui);
view.clearOverlays();
var cell = matrix.cell;
var dayDelta = dis * (
allDay ? // can't trust cell.colDelta when using slot grid
(cell ? cell.colDelta : 0) :
Math.floor((ui.position.left - origPosition.left) / colWidth)
);
if (!cell || !dayDelta && !cell.rowDelta) {
// over nothing (has reverted)
resetElement();
if ($.browser.msie) {
eventElement.css('filter', ''); // clear IE opacity side-effects
}
view.showEvents(event, eventElement);
}else{
eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link
view.eventDrop(
this, event, dayDelta,
allDay ? 0 : // minute delta
Math.round((eventElement.offset().top - bodyContent.offset().top) / slotHeight)
* options.slotMinutes
+ minMinute
- (event.start.getHours() * 60 + event.start.getMinutes()),
allDay, ev, ui
);
}
}
});
}
}
// when event starts out IN TIMESLOTS
function draggableSlotEvent(event, eventElement, timeElement) {
if (!options.disableDragging && eventElement.draggable) {
var origPosition,
resetElement,
prevSlotDelta, slotDelta,
allDay=false,
matrix;
eventElement.draggable({
zIndex: 9,
scroll: false,
grid: [colWidth, slotHeight],
axis: colCnt==1 ? 'y' : false,
opacity: view.option('dragOpacity'),
revertDuration: options.dragRevertDuration,
start: function(ev, ui) {
view.hideEvents(event, eventElement);
view.trigger('eventDragStart', eventElement, event, ev, ui);
if ($.browser.msie) {
eventElement.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
}
origPosition = eventElement.position();
resetElement = function() {
// convert back to original slot-event
if (allDay) {
timeElement.css('display', ''); // show() was causing display=inline
eventElement.draggable('option', 'grid', [colWidth, slotHeight]);
allDay = false;
}
};
prevSlotDelta = 0;
matrix = buildDayMatrix(function(cell) {
eventElement.draggable('option', 'revert', !cell);
view.clearOverlays();
if (cell) {
if (!cell.row && options.allDaySlot) { // over full days
if (!allDay) {
// convert to temporary all-day event
allDay = true;
timeElement.hide();
eventElement.draggable('option', 'grid', null);
}
renderDayOverlay(
matrix,
addDays(cloneDate(event.start), cell.colDelta),
addDays(exclEndDay(event), cell.colDelta)
);
}else{ // on slots
resetElement();
}
}
},true);
matrix.mouse(ev);
},
drag: function(ev, ui) {
slotDelta = Math.round((ui.position.top - origPosition.top) / slotHeight);
if (slotDelta != prevSlotDelta) {
if (!allDay) {
// update time header
var minuteDelta = slotDelta*options.slotMinutes,
newStart = addMinutes(cloneDate(event.start), minuteDelta),
newEnd;
if (event.end) {
newEnd = addMinutes(cloneDate(event.end), minuteDelta);
}
timeElement.text(formatDates(newStart, newEnd, view.option('timeFormat')));
}
prevSlotDelta = slotDelta;
}
matrix.mouse(ev);
},
stop: function(ev, ui) {
view.clearOverlays();
view.trigger('eventDragStop', eventElement, event, ev, ui);
var cell = matrix.cell,
dayDelta = dis * (
allDay ? // can't trust cell.colDelta when using slot grid
(cell ? cell.colDelta : 0) :
Math.floor((ui.position.left - origPosition.left) / colWidth)
);
if (!cell || !slotDelta && !dayDelta) {
resetElement();
if ($.browser.msie) {
eventElement
.css('filter', '') // clear IE opacity side-effects
.find('span.fc-event-bg').css('display', ''); // .show() made display=inline
}
eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position
view.showEvents(event, eventElement);
}else{
view.eventDrop(
this, event, dayDelta,
allDay ? 0 : slotDelta * options.slotMinutes, // minute delta
allDay, ev, ui
);
}
}
});
}
}
/* Event Resizing
-----------------------------------------------------------------------------*/
// for TIMESLOT events
function resizableSlotEvent(event, eventElement, timeElement) {
if (!options.disableResizing && eventElement.resizable) {
var slotDelta, prevSlotDelta;
eventElement.resizable({
handles: {
s: 'div.ui-resizable-s'
},
grid: slotHeight,
start: function(ev, ui) {
slotDelta = prevSlotDelta = 0;
view.hideEvents(event, eventElement);
if ($.browser.msie && $.browser.version == '6.0') {
eventElement.css('overflow', 'hidden');
}
eventElement.css('z-index', 9);
view.trigger('eventResizeStart', this, event, ev, ui);
},
resize: function(ev, ui) {
// don't rely on ui.size.height, doesn't take grid into account
slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight);
if (slotDelta != prevSlotDelta) {
timeElement.text(
formatDates(
event.start,
(!slotDelta && !event.end) ? null : // no change, so don't display time range
addMinutes(view.eventEnd(event), options.slotMinutes*slotDelta),
view.option('timeFormat')
)
);
prevSlotDelta = slotDelta;
}
},
stop: function(ev, ui) {
view.trigger('eventResizeStop', this, event, ev, ui);
if (slotDelta) {
view.eventResize(this, event, 0, options.slotMinutes*slotDelta, ev, ui);
}else{
eventElement.css('z-index', 8);
view.showEvents(event, eventElement);
// BUG: if event was really short, need to put title back in span
}
}
});
}
}
/* Selecting
-----------------------------------------------------------------------------*/
daySelectionManager = new SelectionManager(
view,
unselect,
function(startDate, endDate, allDay) {
renderDayOverlay(
selectionMatrix,
startDate,
addDays(cloneDate(endDate), 1)
);
},
clearSelection
);
function daySelectionMousedown(ev) {
if (view.option('selectable')) {
selectionMatrix = buildDayMatrix(function(cell) {
if (cell) {
var d = dayColDate(cell.col);
daySelectionManager.drag(d, d, true);
}else{
daySelectionManager.drag();
}
});
documentDragHelp(
function(ev) {
selectionMatrix.mouse(ev);
},
function(ev) {
daySelectionManager.dragStop(ev);
}
);
daySelectionManager.dragStart(ev);
selectionMatrix.mouse(ev);
return false; // prevent auto-unselect and text selection
}
}
slotSelectionManager = new SelectionManager(
view,
unselect,
renderSlotSelection,
clearSelection
);
function slotSelectionMousedown(ev) {
if (view.option('selectable')) {
selectionMatrix = buildSlotMatrix(function(cell) {
if (cell) {
var d = slotCellDate(cell.row, cell.origCol);
slotSelectionManager.drag(d, addMinutes(cloneDate(d), options.slotMinutes), false);
}else{
slotSelectionManager.drag();
}
});
documentDragHelp(
function(ev) {
selectionMatrix.mouse(ev);
},
function(ev) {
slotSelectionManager.dragStop(ev);
}
);
slotSelectionManager.dragStart(ev);
selectionMatrix.mouse(ev);
return false; // prevent auto-unselect and text selection
}
}
documentUnselectAuto(view, unselect);
this.select = function(start, end, allDay) {
if (allDay) {
if (options.allDaySlot) {
if (!end) {
end = cloneDate(start);
}
selectionMatrix = buildDayMatrix();
daySelectionManager.select(start, end, allDay);
}
}else{
if (!end) {
end = addMinutes(cloneDate(start), options.slotMinutes);
}
selectionMatrix = buildSlotMatrix();
slotSelectionManager.select(start, end, allDay);
}
};
function unselect() {
slotSelectionManager.unselect();
daySelectionManager.unselect();
}
this.unselect = unselect;
/* Selecting drawing utils
-----------------------------------------------------------------------------*/
function renderSlotSelection(startDate, endDate) {
var helperOption = view.option('selectHelper');
if (helperOption) {
var col = dayDiff(startDate, view.visStart);
if (col >= 0 && col < colCnt) { // only works when times are on same day
var rect = selectionMatrix.rect(0, col*dis+dit, 1, col*dis+dit+1, bodyContent); // only for horizontal coords
var top = timePosition(startDate, startDate);
var bottom = timePosition(startDate, endDate);
if (bottom > top) { // protect against selections that are entirely before or after visible range
rect.top = top;
rect.height = bottom - top;
rect.left += 2;
rect.width -= 5;
if ($.isFunction(helperOption)) {
var helperRes = helperOption(startDate, endDate);
if (helperRes) {
rect.position = 'absolute';
rect.zIndex = 8;
selectionHelper = $(helperRes)
.css(rect)
.appendTo(bodyContent);
}
}else{
selectionHelper = $(slotSegHtml(
{
title: '',
start: startDate,
end: endDate,
className: [],
editable: false
},
rect,
'fc-event fc-event-vert fc-corner-top fc-corner-bottom '
));
if ($.browser.msie) {
selectionHelper.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
}
selectionHelper.css('opacity', view.option('dragOpacity'));
}
if (selectionHelper) {
slotBind(selectionHelper);
bodyContent.append(selectionHelper);
setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended
setOuterHeight(selectionHelper, rect.height, true);
}
}
}
}else{
renderSlotOverlay(selectionMatrix, startDate, endDate);
}
}
function clearSelection() {
clearOverlays();
if (selectionHelper) {
selectionHelper.remove();
selectionHelper = null;
}
}
/* Semi-transparent Overlay Helpers
-----------------------------------------------------*/
function renderDayOverlay(matrix, startDate, endDate) {
var startCol, endCol;
if (rtl) {
startCol = dayDiff(endDate, view.visStart)*dis+dit+1;
endCol = dayDiff(startDate, view.visStart)*dis+dit+1;
}else{
startCol = dayDiff(startDate, view.visStart);
endCol = dayDiff(endDate, view.visStart);
}
startCol = Math.max(0, startCol);
endCol = Math.min(colCnt, endCol);
if (startCol < endCol) {
var rect = matrix.rect(0, startCol, 1, endCol, head);
dayBind(
view.renderOverlay(rect, head)
);
}
}
function renderSlotOverlay(matrix, overlayStart, overlayEnd) {
var dayStart = cloneDate(view.visStart);
var dayEnd = addDays(cloneDate(dayStart), 1);
for (var i=0; i= addMinutes(cloneDate(day), maxMinute)) {
return bodyContent.height();
}
var slotMinutes = options.slotMinutes,
minutes = time.getHours()*60 + time.getMinutes() - minMinute,
slotI = Math.floor(minutes / slotMinutes),
slotTop = slotTopCache[slotI];
if (slotTop === undefined) {
slotTop = slotTopCache[slotI] = body.find('tr:eq(' + slotI + ') td div')[0].offsetTop;
}
return Math.max(0, Math.round(
slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)
));
}
function buildDayMatrix(changeCallback, includeSlotArea) {
var rowElements = options.allDaySlot ? head.find('td') : $([]);
if (includeSlotArea) {
rowElements = rowElements.add(body);
}
return new HoverMatrix(rowElements, bg.find('td'), changeCallback);
}
function buildSlotMatrix(changeCallback) {
return new HoverMatrix(bodyTable.find('td'), bg.find('td'), changeCallback);
}
/* Date Utilities
----------------------------------------------------*/
function slotEventEnd(event) {
if (event.end) {
return cloneDate(event.end);
}else{
return addMinutes(cloneDate(event.start), options.defaultEventMinutes);
}
}
function dayOfWeekCol(dayOfWeek) {
return ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt)*dis+dit;
}
// generating dates from cell row & columns
function dayColDate(col) {
return addDays(cloneDate(view.visStart), col*dis+dit);
}
function slotCellDate(row, col) {
var d = dayColDate(col);
addMinutes(d, minMinute + row*options.slotMinutes);
return d;
}
}
// count the number of colliding, higher-level segments (for event squishing)
function countForwardSegs(levels) {
var i, j, k, level, segForward, segBack;
for (i=levels.length-1; i>0; i--) {
level = levels[i];
for (j=0; j");
}
if (e[0].parentNode != parent[0]) {
e.appendTo(parent);
}
this.usedOverlays.push(e.css(rect).show());
return e;
},
clearOverlays: function() {
var e;
while (e = this.usedOverlays.shift()) {
this.unusedOverlays.push(e.hide().unbind());
}
},
// common horizontal event resizing
resizableDayEvent: function(event, eventElement, colWidth) {
var view = this;
if (!view.options.disableResizing && eventElement.resizable) {
eventElement.resizable({
handles: view.options.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: view.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);
view.hideEvents(event, eventElement);
view.trigger('eventResizeStart', this, event, ev, ui);
},
stop: function(ev, ui) {
view.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) {
view.eventResize(this, event, dayDelta, 0, ev, ui);
}else{
eventElement.css('z-index', 8);
view.showEvents(event, eventElement);
}
}
});
}
},
// attaches eventClick, eventMouseover, eventMouseout
eventElementHandlers: function(event, eventElement) {
var view = this;
eventElement
.click(function(ev) {
if (!eventElement.hasClass('ui-draggable-dragging') &&
!eventElement.hasClass('ui-resizable-resizing')) {
return view.trigger('eventClick', this, event, ev);
}
})
.hover(
function(ev) {
view.trigger('eventMouseover', this, event, ev);
},
function(ev) {
view.trigger('eventMouseout', this, event, ev);
}
)
//Added by Christian Wengg - untermStrich: dblclick-event
.dblclick(function(ev) {
if (!eventElement.hasClass('ui-draggable-dragging') &&
!eventElement.hasClass('ui-resizable-resizing')) {
return view.trigger('eventDblClick', this, event, ev);
}
});
// end dblclick-event
},
// get a property from the 'options' object, using smart view naming
option: function(name, viewName) {
var v = this.options[name];
if (typeof v == 'object') {
return smartProperty(v, viewName || this.name);
}
return v;
},
// event rendering utilities
sliceSegs: function(events, visEventEnds, start, end) {
var segs = [],
i, len=events.length, event,
eventStart, eventEnd,
segStart, segEnd,
isStart, isEnd;
for (i=0; i start && eventStart < end) {
if (eventStart < start) {
segStart = cloneDate(start);
isStart = false;
}else{
segStart = eventStart;
isStart = true;
}
if (eventEnd > end) {
segEnd = cloneDate(end);
isEnd = false;
}else{
segEnd = eventEnd;
isEnd = true;
}
segs.push({
event: event,
start: segStart,
end: segEnd,
isStart: isStart,
isEnd: isEnd,
msLength: segEnd - segStart
});
}
}
return segs.sort(segCmp);
}
};
function lazySegBind(container, segs, bindHandlers) {
container.unbind('mouseover').mouseover(function(ev) {
var parent=ev.target, e,
i, seg;
while (parent != this) {
e = parent;
parent = parent.parentNode;
}
if ((i = e._fci) !== undefined) {
e._fci = undefined;
seg = segs[i];
bindHandlers(seg.event, seg.element, seg);
$(ev.target).trigger(ev);
}
ev.stopPropagation();
});
}
// event rendering calculation utilities
function stackSegs(segs) {
var levels = [],
i, len = segs.length, seg,
j, collide, k;
for (i=0; i seg2.start && seg1.start < seg2.end;
}
function SelectionManager(view, initFunc, displayFunc, clearFunc) {
var t = this;
var selected = false;
var initialElement;
var initialRange;
var start;
var end;
var allDay;
t.dragStart = function(ev) {
initFunc();
start = end = undefined;
initialRange = undefined;
initialElement = ev.currentTarget;
};
t.drag = function(currentStart, currentEnd, currentAllDay) {
if (currentStart) {
var range = [currentStart, currentEnd];
if (!initialRange) {
initialRange = range;
}
var dates = initialRange.concat(range).sort(cmp);
start = dates[0];
end = dates[3];
allDay = currentAllDay;
clearFunc();
displayFunc(cloneDate(start), cloneDate(end), allDay);
}else{
// called with no arguments
start = end = undefined;
clearFunc();
}
};
t.dragStop = function(ev) {
if (start) {
if (+initialRange[0] == +start && +initialRange[1] == +end) {
view.trigger('dayClick', initialElement, start, allDay, ev);
}
_select();
}
};
t.select = function(newStart, newEnd, newAllDay) {
initFunc();
start = newStart;
end = newEnd;
allDay = newAllDay;
displayFunc(cloneDate(start), cloneDate(end), allDay);
_select();
};
function _select() { // just set the selected flag, and trigger
selected = true;
view.trigger('select', view, start, end, allDay);
}
function unselect() {
if (selected) {
selected = false;
start = end = undefined;
clearFunc();
view.trigger('unselect', view);
}
}
t.unselect = unselect;
}
function documentDragHelp(mousemove, mouseup) {
function _mouseup(ev) {
mouseup(ev);
$(document)
.unbind('mousemove', mousemove)
.unbind('mouseup', _mouseup);
}
$(document)
.mousemove(mousemove)
.mouseup(_mouseup);
}
function documentUnselectAuto(view, unselectFunc) {
if (view.option('selectable') && view.option('unselectAuto')) {
$(document).mousedown(function(ev) {
var ignore = view.option('unselectCancel');
if (ignore) {
if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match
return;
}
}
unselectFunc();
});
}
}
/* Date Math
-----------------------------------------------------------------------------*/
var DAY_MS = 86400000,
HOUR_MS = 3600000,
MINUTE_MS = 60000;
function addYears(d, n, keepTime) {
d.setFullYear(d.getFullYear() + n);
if (!keepTime) {
clearTime(d);
}
return d;
}
function addMonths(d, n, keepTime) { // prevents day overflow/underflow
if (+d) { // prevent infinite looping on invalid dates
var m = d.getMonth() + n,
check = cloneDate(d);
check.setDate(1);
check.setMonth(m);
d.setMonth(m);
if (!keepTime) {
clearTime(d);
}
while (d.getMonth() != check.getMonth()) {
d.setDate(d.getDate() + (d < check ? 1 : -1));
}
}
return d;
}
function addDays(d, n, keepTime) { // deals with daylight savings
if (+d) {
var dd = d.getDate() + n,
check = cloneDate(d);
check.setHours(9); // set to middle of day
check.setDate(dd);
d.setDate(dd);
if (!keepTime) {
clearTime(d);
}
fixDate(d, check);
}
return d;
}
fc.addDays = addDays;
function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes
if (+d) { // prevent infinite looping on invalid dates
while (d.getDate() != check.getDate()) {
d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);
}
}
}
function addMinutes(d, n) {
d.setMinutes(d.getMinutes() + n);
return d;
}
function clearTime(d) {
d.setHours(0);
d.setMinutes(0);
d.setSeconds(0);
d.setMilliseconds(0);
return d;
}
function cloneDate(d, dontKeepTime) {
if (dontKeepTime) {
return clearTime(new Date(+d));
}
return new Date(+d);
}
fc.cloneDate = cloneDate;
function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
var i=0, d;
do {
d = new Date(1970, i++, 1);
} while (d.getHours()); // != 0
return d;
}
function skipWeekend(date, inc, excl) {
inc = inc || 1;
while (!date.getDay() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {
addDays(date, inc);
}
return date;
}
function dayDiff(d1, d2) { // d1 - d2
return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);
}
/* Date Parsing
-----------------------------------------------------------------------------*/
var parseDate = fc.parseDate = function(s) {
if (typeof s == 'object') { // already a Date object
return s;
}
if (typeof s == 'number') { // a UNIX timestamp
return new Date(s * 1000);
}
if (typeof s == 'string') {
if (s.match(/^\d+$/)) { // a UNIX timestamp
return new Date(parseInt(s) * 1000);
}
return parseISO8601(s, true) || (s ? new Date(s) : null);
}
// TODO: never return invalid dates (like from new Date()), return null instead
return null;
};
var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) {
// derived from http://delete.me.uk/2005/03/iso8601.html
// TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/);
if (!m) {
return null;
}
var date = new Date(m[1], 0, 1),
check = new Date(m[1], 0, 1, 9, 0),
offset = 0;
if (m[3]) {
date.setMonth(m[3] - 1);
check.setMonth(m[3] - 1);
}
if (m[5]) {
date.setDate(m[5]);
check.setDate(m[5]);
}
fixDate(date, check);
if (m[7]) {
date.setHours(m[7]);
}
if (m[8]) {
date.setMinutes(m[8]);
}
if (m[10]) {
date.setSeconds(m[10]);
}
if (m[12]) {
date.setMilliseconds(Number("0." + m[12]) * 1000);
}
fixDate(date, check);
if (!ignoreTimezone) {
if (m[14]) {
offset = Number(m[16]) * 60 + Number(m[17]);
offset *= m[15] == '-' ? 1 : -1;
}
offset -= date.getTimezoneOffset();
}
return new Date(+date + (offset * 60 * 1000));
};
var parseTime = fc.parseTime = function(s) { // returns minutes since start of day
if (typeof s == 'number') { // an hour
return s * 60;
}
if (typeof s == 'object') { // a Date object
return s.getHours() * 60 + s.getMinutes();
}
var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);
if (m) {
var h = parseInt(m[1]);
if (m[3]) {
h %= 12;
if (m[3].toLowerCase().charAt(0) == 'p') {
h += 12;
}
}
return h * 60 + (m[2] ? parseInt(m[2]) : 0);
}
};
/* Date Formatting
-----------------------------------------------------------------------------*/
var formatDate = fc.formatDate = function(date, format, options) {
return formatDates(date, null, format, options);
};
var formatDates = fc.formatDates = function(date1, date2, format, options) {
options = options || defaults;
var date = date1,
otherDate = date2,
i, len = format.length, c,
i2, formatter,
res = '';
for (i=0; ii; i2--) {
if (formatter = dateFormatters[format.substring(i, i2)]) {
if (date) {
res += formatter(date, options);
}
i = i2 - 1;
break;
}
}
if (i2 == i) {
if (date) {
res += c;
}
}
}
}
return res;
};
//Added by Christian Koller - untermStrich
fc.getDateFormatters = function() {
return dateFormatters;
};
//END Added by Christian Koller - untermStrich
var dateFormatters = {
s : function(d) { return d.getSeconds() },
ss : function(d) { return zeroPad(d.getSeconds()) },
m : function(d) { return d.getMinutes() },
mm : function(d) { return zeroPad(d.getMinutes()) },
h : function(d) { return d.getHours() % 12 || 12 },
hh : function(d) { return zeroPad(d.getHours() % 12 || 12) },
H : function(d) { return d.getHours() },
HH : function(d) { return zeroPad(d.getHours()) },
d : function(d) { return d.getDate() },
dd : function(d) { return zeroPad(d.getDate()) },
ddd : function(d,o) { return o.dayNamesShort[d.getDay()] },
dddd: function(d,o) { return o.dayNames[d.getDay()] },
M : function(d) { return d.getMonth() + 1 },
MM : function(d) { return zeroPad(d.getMonth() + 1) },
MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] },
MMMM: function(d,o) { return o.monthNames[d.getMonth()] },
yy : function(d) { return (d.getFullYear()+'').substring(2) },
yyyy: function(d) { return d.getFullYear() },
t : function(d) { return d.getHours() < 12 ? 'a' : 'p' },
tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' },
T : function(d) { return d.getHours() < 12 ? 'A' : 'P' },
TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' },
u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") },
S : function(d) {
var date = d.getDate();
if (date > 10 && date < 20) {
return 'th';
}
return ['st', 'nd', 'rd'][date%10-1] || 'th';
}
};
/* Element Dimensions
-----------------------------------------------------------------------------*/
function setOuterWidth(element, width, includeMargins) {
element.each(function(i, _element) {
_element.style.width = width - hsides(_element, includeMargins) + 'px';
});
}
function setOuterHeight(element, height, includeMargins) {
element.each(function(i, _element) {
_element.style.height = height - vsides(_element, includeMargins) + 'px';
});
}
function hsides(_element, includeMargins) {
return (parseFloat(jQuery.curCSS(_element, 'paddingLeft', true)) || 0) +
(parseFloat(jQuery.curCSS(_element, 'paddingRight', true)) || 0) +
(parseFloat(jQuery.curCSS(_element, 'borderLeftWidth', true)) || 0) +
(parseFloat(jQuery.curCSS(_element, 'borderRightWidth', true)) || 0) +
(includeMargins ? hmargins(_element) : 0);
}
function hmargins(_element) {
return (parseFloat(jQuery.curCSS(_element, 'marginLeft', true)) || 0) +
(parseFloat(jQuery.curCSS(_element, 'marginRight', true)) || 0);
}
function vsides(_element, includeMargins) {
return (parseFloat(jQuery.curCSS(_element, 'paddingTop', true)) || 0) +
(parseFloat(jQuery.curCSS(_element, 'paddingBottom', true)) || 0) +
(parseFloat(jQuery.curCSS(_element, 'borderTopWidth', true)) || 0) +
(parseFloat(jQuery.curCSS(_element, 'borderBottomWidth', true)) || 0) +
(includeMargins ? vmargins(_element) : 0);
}
function vmargins(_element) {
return (parseFloat(jQuery.curCSS(_element, 'marginTop', true)) || 0) +
(parseFloat(jQuery.curCSS(_element, 'marginBottom', true)) || 0);
}
function setMinHeight(element, h) {
h = typeof h == 'number' ? h + 'px' : h;
element[0].style.cssText += ';min-height:' + h + ';_height:' + h;
}
/* Position Calculation
-----------------------------------------------------------------------------*/
// nasty bugs in opera 9.25
// position()'s top returning incorrectly with TR/TD or elements within TD
var topBug;
function topCorrect(tr) { // tr/th/td or anything else
if (topBug !== false) {
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;
}
/* Hover Matrix
-----------------------------------------------------------------------------*/
function HoverMatrix(rowElements, colElements, changeCallback) {
var t=this,
tops=[], lefts=[],
origRow, origCol,
currRow, currCol,
e;
$.each(rowElements, function(i, _e) {
e = $(_e);
tops.push(e.offset().top + topCorrect(e));
});
tops.push(tops[tops.length-1] + e.outerHeight());
$.each(colElements, function(i, _e) {
e = $(_e);
lefts.push(e.offset().left);
});
lefts.push(lefts[lefts.length-1] + e.outerWidth());
t.mouse = function(ev) {
var x = ev.pageX;
var y = ev.pageY;
var r, c;
for (r=0; r=tops[r]; r++) {}
for (c=0; c=lefts[c]; c++) {}
r = r >= tops.length ? -1 : r - 1;
c = c >= lefts.length ? -1 : c - 1;
if (r != currRow || c != currCol) {
currRow = r;
currCol = c;
if (r == -1 || c == -1) {
t.cell = null;
}else{
if (origRow === undefined) {
origRow = r;
origCol = c;
}
t.cell = {
row: r,
col: c,
top: tops[r],
left: lefts[c],
width: lefts[c+1] - lefts[c],
height: tops[r+1] - tops[r],
origRow: origRow,
origCol: origCol,
isOrig: r==origRow && c==origCol,
rowDelta: r-origRow,
colDelta: c-origCol
};
}
changeCallback(t.cell);
}
};
t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 are exclusive
var origin = originElement.offset();
return {
top: tops[row0] - origin.top,
left: lefts[col0] - origin.left,
width: lefts[col1] - lefts[col0],
height: tops[row1] - tops[row0]
};
};
}
/* Misc Utils
-----------------------------------------------------------------------------*/
var undefined,
dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
function zeroPad(n) {
return (n < 10 ? '0' : '') + n;
}
function smartProperty(obj, name) { // get a camel-cased/namespaced property of an object
if (obj[name] !== undefined) {
return obj[name];
}
var parts = name.split(/(?=[A-Z])/),
i=parts.length-1, res;
for (; i>=0; i--) {
res = obj[parts[i].toLowerCase()];
if (res !== undefined) {
return res;
}
}
return obj[''];
}
function htmlEscape(s) {
return s
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/'/g, ''')
.replace(/"/g, '"');
}
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 = {};
};
}
function cssKey(_element) {
return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, '');
}
function cmp(a, b) {
return a - b;
}
function exclEndDay(event) {
if (event.end) {
return _exclEndDay(event.end, event.allDay);
}else{
return addDays(cloneDate(event.start), 1);
}
}
function _exclEndDay(end, allDay) {
end = cloneDate(end);
return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : end;
}
function disableTextSelection(element) {
element
.attr('unselectable', 'on')
.css('MozUserSelect', 'none')
.bind('selectstart.ui', function() { return false; });
}
/*
function enableTextSelection(element) {
element
.attr('unselectable', 'off')
.css('MozUserSelect', '')
.unbind('selectstart.ui');
}
*/
})(jQuery);