var fc = $.fullCalendar = {}; var views = fc.views = {}; /* Defaults -----------------------------------------------------------------------------*/ var defaults = { // display defaultView: 'month', aspectRatio: 1.35, header: { left: 'prev,next today', center: 'title', right: 'month,basicWeek,basicDay' }, // event ajax startParam: 'start', endParam: 'end', cacheParam: '_', // time formats eventTimeFormat: 'h(:mm)t', 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' }, // regional isRTL: false, weekStart: 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: '►', today: 'today', month: 'month', week: 'week', day: 'day' }, // jquery-ui theming theme: false, buttonIcons: { prev: 'circle-triangle-w', next: 'circle-triangle-e' } }; // right-to-left defaults var rtlDefaults = { header: { left: 'basicDay,basicWeek,month', center: 'title', right: 'today next,prev' }, buttonText: { prev: '►', next: '◄' } }; // 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 r = $.data(this, 'fullCalendar')[options].apply(this, args); if (typeof res == 'undefined') res = r; }); if (typeof 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.event; } // first event source reserved for 'sticky' events eventSources.unshift([]); // initialize options options = $.extend(true, {}, defaults, (options.isRTL || typeof options.isRTL == 'undefined' && defaults.isRTL) ? rtlDefaults : {}, options ); var tm = options.theme ? 'ui' : 'fc'; this.each(function() { /* Instance Initialization -----------------------------------------------------------------------------*/ // element var _element = this, element = $(this).addClass('fc'), content = $("
").appendTo(this); if (options.isRTL) { element.addClass('fc-rtl'); } if (options.theme) { element.addClass('ui-widget'); } // view managing var date = new Date(), viewName, view, // the current view prevView, viewInstances = {}; if (options.year) { date.setYear(options.year); } if (options.month) { date.setMonth(options.month); } if (options.date) { date.setDate(options.date); } /* View Rendering -----------------------------------------------------------------------------*/ function switchView(v) { if (v != viewName) { prevView = view; if (viewInstances[v]) { (view = viewInstances[v]).element.show(); }else{ view = viewInstances[v] = $.fullCalendar.views[v]( $("
").appendTo(content), options); } if (prevView) { prevView.element.hide(); if (prevView.eventsChanged) { eventsDirtyExcept(prevView); prevView.eventsChanged = false; } } if (header) { 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(); } } function render(inc) { if (inc || !view.date || +view.date != +date) { ignoreResizes = true; view.render(date, inc || 0, function(callback) { if (!eventStart || view.visStart < eventStart || view.visEnd > eventEnd) { fetchEvents(callback); }else{ callback(events); } }); ignoreResizes = false; view.date = cloneDate(date); if (header) { 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'); } } } else if (view.eventsDirty) { view.rerenderEvents(); } if (header) { header.find('h2.fc-header-title').html(view.title); } view.eventsDirty = false; view.trigger('viewDisplay', _element, date); } function eventsDirtyExcept(exceptView) { $.each(viewInstances, function() { if (this != exceptView) { this.eventsDirty = true; } }); } function eventsChanged() { view.clearEvents(); view.renderEvents(events); eventsDirtyExcept(view); } /* 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 == 0) { 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 = $(""), prevTitle = false; $.each(buttonStr.split(' '), function(i) { if (i > 0) { tr.append(""); } $.each(this.split(','), function(j) { var buttonName = this, buttonNameShort = this.replace(/^(basic|agenda)/, '').toLowerCase(); if (buttonName == 'title') { tr.find('> :last div').addClass(tm + '-corner-right'); tr.append("

"); prevTitle = true; }else{ var button, icon = options.theme ? options.buttonIcons[buttonNameShort] : null, text = options.buttonText[buttonNameShort]; if (icon) { button = $("
" + "
"); } else if (text) { button = $(""); } if (button) { button .mousedown(function() { button.addClass(tm + '-state-down'); }) .mouseup(function() { button.removeClass(tm + '-state-down'); }) .hover(function() { button.addClass(tm + '-state-hover'); }, function() { button.removeClass(tm + '-state-hover') .removeClass(tm + '-state-down'); }) .appendTo($("").appendTo(tr)); if (publicMethods[buttonNameShort]) { button.click(publicMethods[buttonNameShort]); } else if (views[buttonName]) { button.click(function() { switchView(buttonName); }); } if (j == 0 || prevTitle) { button.addClass(tm + '-corner-left'); }else{ button.addClass(tm + '-no-left'); } prevTitle = false; } } }); tr.find('> :last div').addClass(tm + '-corner-right'); }); return $("").append(tr); } } /* Resizing -----------------------------------------------------------------------------*/ var elementWidth, ignoreResizes = false, resizeCnt = 0; $(window).resize(function() { if (!ignoreResizes) { var rcnt = ++resizeCnt; // add a delay setTimeout(function() { if (rcnt == resizeCnt) { var newWidth = element.width(); if (newWidth != elementWidth) { elementWidth = newWidth; view.updateSize(); view.rerenderEvents(true); view.trigger('windowResize', _element); } } }, 200); } }); // let's begin... switchView(options.defaultView); elementWidth = element.width(); }); }; /* Important Event Utilities -----------------------------------------------------------------------------*/ var fakeID = 0; function normalizeEvent(event) { event._id = event._id || (typeof event.id == 'undefined' ? '_fc' + fakeID++ : event.id + ''); event._start = cloneDate(event.start = parseDate(event.start)); event.end = parseDate(event.end); }