/* * FullCalendar * http://arshaw.com/fullcalendar/ * * use fullcalendar.css for basic styling * requires jQuery UI core and draggables ONLY if you plan to do drag & drop * * 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: * Revision: */ (function($) { $.fn.fullCalendar = function(options) { if (typeof options == 'string') { var args = Array.prototype.slice.call(arguments, 1); var ret; // ugly this.each(function() { var r = $.data(this, 'fullCalendar')[options].apply(this, args); if (typeof ret == 'undefined') ret = r; }); if (typeof ret == 'undefined') return this; return ret; } options = options || {}; var r2l = options.rightToLeft; var dis, dit; // day index sign / translate if (r2l) { dis = -1; dit = 6; this.addClass('r2l'); }else{ dis = 1; dit = 0; } var showTime = typeof options.showTime == 'undefined' ? 'guess' : options.showTime; var bo = typeof options.buttons == 'undefined' ? true : options.buttons; var weekStart = (options.weekStart || 0) % 7; var timeFormat = options.timeFormat || 'gx'; var titleFormat = options.titleFormat || (r2l ? 'Y F' : 'F Y'); var tdTopBug, trTopBug, tbodyTopBug, sniffBugs = true; this.each(function() { var date = options.year ? new Date(options.year, options.month || 0, 1) : new Date(); var start, end, today, numWeeks; var ignoreResizes = false; var events = []; var eventSources; var eo = options.events; if (eo) { if (typeof eo == 'string' || $.isFunction(eo)) { eventSources = [eo]; }else{ var item = eo[0]; if (item) { if (typeof item == 'string' || $.isFunction(item)) eventSources = eo; else { eventSources = [eo]; } } } } else eventSources = []; function updateMonth() { clearEvents(); render(); } function today() { date = new Date(); updateMonth(); } function prevMonth() { addMonths(date, -1); updateMonth(); } function nextMonth() { addMonths(date, 1); updateMonth(); } function gotoMonth(year, month) { date = new Date(year, month, 1); updateMonth(); } $.data(this, 'fullCalendar', { today: today, prevMonth: prevMonth, nextMonth: nextMonth, gotoMonth: gotoMonth, refresh: updateMonth, // event crud addEvent: function(event) { events.push(normalizeEvent(event)); clearEvents(); renderEvents(); }, updateEvent: function(event) { event.start = cleanDate(event.start); event.end = cleanDate(event.end); var startDelta = event.start - event._start; var msLength = event.end - event.start; event._start = cloneDate(event.start); for (var i=0; i").appendTo(this); if (bo) { var buttons = $("
").appendTo(header); var prevButton, nextButton; if (bo == true || bo.today != false) { todayButton = $("") .click(today); if (typeof bo.today == 'string') todayButton.val(bo.today); buttons.append(todayButton); } if (bo == true || bo.prev != false) { prevButton = $("") .click(prevMonth); if (typeof bo.prev == 'string') prevButton.val(bo.prev); if (r2l) buttons.prepend(prevButton); else buttons.append(prevButton); } if (bo == true || bo.next != false) { nextButton = $("") .click(nextMonth); if (typeof bo.next == 'string') nextButton.val(bo.next); if (r2l) buttons.prepend(nextButton); else buttons.append(nextButton); } } if (options.title !== false) titleElement = $("

").appendTo(header); monthElement = $("
") .appendTo($("
").appendTo(this)); var thead, tbody, glass, monthTitle; function render() { ignoreResizes = true; date.setDate(1); clearTime(date); var year = date.getFullYear(); var month = date.getMonth(); monthTitle = formatTitle(date); if (titleElement) titleElement.text(monthTitle); clearTime(date); start = cloneDate(date); addDays(start, -((start.getDay() - weekStart + 7) % 7)); end = cloneDate(date); addMonths(end, 1); addDays(end, (7 - end.getDay() + weekStart) % 7); numWeeks = Math.round((end.getTime() - start.getTime()) / 604800000); if (options.fixedWeeks != false) { addDays(end, (6 - numWeeks) * 7); numWeeks = 6; } today = clearTime(new Date()); if (todayButton) { if (today.getFullYear() == year && today.getMonth() == month) { todayButton.css('visibility', 'hidden'); }else{ todayButton.css('visibility', 'visible'); } } if (!tbody) { var table = $("").appendTo(monthElement); thead = ""; for (var i=0; i<7; i++) { var j = (i * dis + dit + weekStart) % 7; thead += ""; } thead = $(thead + "").appendTo(table); tbody = ""; var d = cloneDate(start); for (var i=0; i"; var tds = ""; for (var j=0; j<7; j++) { var s = ""; if (r2l) tds = s + tds; else tds += s; addDays(d, 1); } tbody += tds + ""; } tbody = $(tbody + "").appendTo(table); glass = $("
") .appendTo(monthElement) .click(function(ev, ui) { if (options.dayClick) { buildDayGrid(); var td = dayTD(ev.pageX, ev.pageY); if (td) return options.dayClick.call(td, dayDate(td)); } }); }else{ var diff = numWeeks - tbody.find('tr').length; if (diff < 0) { tbody.find('tr:gt(' + (numWeeks-1) + ')').remove(); } else if (diff > 0) { var trs = ""; for (var i=0; i"; for (var j=0; j<7; j++) { trs += "
"; } trs += ""; } if (trs) tbody.append(trs); } var d = cloneDate(start); tbody.find('tr').each(function() { for (var i=0; i<7; i++) { var td = this.childNodes[i * dis + dit]; if (d.getMonth() == month) { $(td).removeClass('other-month'); }else{ $(td).addClass('other-month'); } if (d.getTime() == today.getTime()) { $(td).addClass('today'); }else{ $(td).removeClass('today'); } $(td.childNodes[0]).text(d.getDate()); addDays(d, 1); } }); } resizeTable(); if (sniffBugs) { var tr = tbody.find('tr'); var td = tr.find('td'); var trTop = tr.position().top; var tdTop = td.position().top; tdTopBug = tdTop < 0; trTopBug = trTop != tdTop; tbodyTopBug = tbody.position().top != trTop; sniffBugs = false; } events = []; var completed = eventSources.length; var reportEvents = function(a) { for (var i=0; i ws.getTime() && event.start.getTime() < we.getTime()) { var ss, se, isStart, isEnd; if (event.start.getTime() < ws.getTime()) { ss = cloneDate(ws); isStart = false; }else{ ss = cloneDate(event.start); isStart = true; } if (event.end.getTime() > we.getTime()) { se = cloneDate(we); isEnd = false; }else{ se = cloneDate(event.end); isEnd = true; } ss = clearTime(ss); se = clearTime((se.getHours()==0 && se.getMinutes()==0) ? se : addDays(se, 1)); segs.push({ event: event, start: ss, end: se, isStart: isStart, isEnd: isEnd, msLength: se - ss }); } }); segs.sort(segSort); var levels = []; $.each(segs, function(j, seg) { var l = 0; // level index while (true) { var collide = false; if (levels[l]) { for (var k=0; k levels[l][k].start.getTime() && seg.start.getTime() < levels[l][k].end.getTime()) { collide = true; break; } } } if (collide) { l++; continue; }else{ break; } } if (levels[l]) levels[l].push(seg); else levels[l] = [seg]; }); eventMatrix[i] = levels; addDays(ws, 7); addDays(we, 7); i++; } _renderEvents(); } var eventElements = []; // [[event, element], ...] function _renderEvents() { for (var i=0; i") .append("" + (roundW ? "") .append("" + (roundW ? "") .append("" + (roundW ? ""); buildEventText(event, element.find('td.c')); if (event.cssClass) element.addClass(event.cssClass); if (options.eventRender) { var res = options.eventRender(event, element); if (typeof res != 'undefined') { if (res === false) continue; if (res !== true) element = $(res); } } element .css({ position: 'absolute', top: top, left: left1, width: left2 - left1, 'z-index': 3 }) .appendTo(monthElement); initEventElement(event, element); var h = element.outerHeight({margin:true}); if (h > maxh) maxh = h; } height += maxh; top += maxh; } innerDiv.height(height); } } function initEventElement(event, element) { element.click(function(ev) { if (!element.hasClass('ui-draggable-dragging')) { if (options.eventClick) { var res = options.eventClick.call(this, event, ev); if (res === false) return false; } if (event.url) window.location.href = event.url; } }); if (options.eventMouseover) element.mouseover(function(ev) { options.eventMouseover.call(this, event, ev); }); if (options.eventMouseout) element.mouseout(function(ev) { options.eventMouseout.call(this, event, ev); }); if (typeof event.draggable != 'undefined') { if (event.draggable) draggableEvent(event, element); } else if (options.draggable) { draggableEvent(event, element); } eventElements.push([event, element]); } var dragStartTD, dragTD; var dayOverlay; function draggableEvent(event, element) { element.draggable({ zIndex: 4, delay: 50, opacity: options.eventDragOpacity, revertDuration: options.eventRevertDuration, start: function(ev, ui) { // hide other elements with same event for (var i=0; i") .appendTo(monthElement); buildDayGrid(); dragTD = dragStartTD = null; eventDrag(this, ev, ui); if (options.eventDragStart) options.eventDragStart.call(this, event, ev, ui); }, drag: function(ev, ui) { eventDrag(this, ev, ui); }, stop: function(ev, ui) { if (!dragTD || dragTD == dragStartTD) { // show all events for (var i=0; i dayY0 + dayY[r+1]) r++; while (c < cmax && x > dayX0 + dayX[c+1]) c++; if (r < 0 || r >= rmax || c < 0 || c >= cmax) return currTD = null; else if (!currTD || r != currR || c != currC) { currR = r; currC = c; currTD = tbody.find('tr:eq('+r+') td:eq('+c+')').get(0); currTDX = dayX[c]; currTDY = dayY[r]; currTDW = dayX[c+1] - currTDX; currTDH = dayY[r+1] - currTDY; return currTD; } return currTD; } function dayDate(node) { var i, tds = tbody.get(0).getElementsByTagName('td'); for (i=0; i") .text(event.title) .appendTo(element); var st = typeof event.showTime == 'undefined' ? showTime : event.showTime; if (st != false) { var h = event.start.getHours(); var m = event.start.getMinutes(); if (st == true || st == 'guess' && (h || m || event.end.getHours() || event.end.getMinutes())) { var s = ''; for (var i=0; i"); if (r2l) element.append(timeElement.text(' ' + s)); else element.prepend(timeElement.text(s + ' ')); } } } function formatTitle(d) { var m = d.getMonth(); var s = ''; for (var i=0; i
" + (options.abbrevDayHeadings!=false ? dayAbbrevs[j] : dayNames[j]) + "
" + d.getDate() + "
" + "
" + "
" + "
" + "
" : '') + "" + (roundE ? "" : '') + "
" : '') + "" + (roundE ? "" : '') + "
" : '') + "" + (roundE ? "" : '') + "