Blame | Last modification | View Log | RSS feed
/*** @preserve* FullCalendar v1.5.4* http://arshaw.com/fullcalendar/** Use fullcalendar.css for basic styling.* For event drag & drop, requires jQuery UI draggable.* For event resizing, requires jQuery UI resizable.** Copyright (c) 2011 Adam Shaw* Dual licensed under the MIT and GPL licenses, located in* MIT-LICENSE.txt and GPL-LICENSE.txt respectively.** Date: Tue Sep 4 23:38:33 2012 -0700**/(function($, undefined) {var defaults = {// displaydefaultView: 'month',aspectRatio: 1.35,header: {left: 'title',center: '',right: 'today prev,next'},weekends: true,// editing//editable: false,//disableDragging: false,//disableResizing: false,allDayDefault: true,ignoreTimezone: true,// event ajaxlazyFetching: true,startParam: 'start',endParam: 'end',// time formatstitleFormat: {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},// localeisRTL: 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 themingtheme: false,buttonIcons: {prev: 'circle-triangle-w',next: 'circle-triangle-e'},//selectable: false,unselectAuto: true,dropAccept: '*'};// right-to-left defaultsvar rtlDefaults = {header: {left: 'next,prev today',center: '',right: 'title'},buttonText: {prev: ' ► ',next: ' ◄ ',prevYear: ' >> ',nextYear: ' << '},buttonIcons: {prev: 'circle-triangle-e',next: 'circle-triangle-w'}};var fc = $.fullCalendar = { version: "1.5.4" };var fcViews = fc.views = {};$.fn.fullCalendar = function(options) {// method callingif (typeof options == 'string') {var args = Array.prototype.slice.call(arguments, 1);var res;this.each(function() {var calendar = $.data(this, 'fullCalendar');if (calendar && $.isFunction(calendar[options])) {var r = calendar[options].apply(calendar, args);if (res === undefined) {res = r;}if (options == 'destroy') {$.removeData(this, 'fullCalendar');}}});if (res !== undefined) {return res;}return this;}// would like to have this logic in EventManager, but needs to happen before options are recursively extendedvar eventSources = options.eventSources || [];delete options.eventSources;if (options.events) {eventSources.push(options.events);delete options.events;}options = $.extend(true, {},defaults,(options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {},options);this.each(function(i, _element) {var element = $(_element);var calendar = new Calendar(element, options, eventSources);element.data('fullCalendar', calendar); // TODO: look into memory leak implicationscalendar.render();});return this;};// function for adding/overriding defaultsfunction setDefaults(d) {$.extend(true, defaults, d);}function Calendar(element, options, eventSources) {var t = this;// exportst.options = options;t.render = render;t.destroy = destroy;t.refetchEvents = refetchEvents;t.reportEvents = reportEvents;t.reportEventChange = reportEventChange;t.rerenderEvents = rerenderEvents;t.changeView = changeView;t.select = select;t.unselect = unselect;t.prev = prev;t.next = next;t.prevYear = prevYear;t.nextYear = nextYear;t.today = today;t.gotoDate = gotoDate;t.incrementDate = incrementDate;t.formatDate = function(format, date) { return formatDate(format, date, options) };t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) };t.getDate = getDate;t.getView = getView;t.option = option;t.trigger = trigger;// importsEventManager.call(t, options, eventSources);var isFetchNeeded = t.isFetchNeeded;var fetchEvents = t.fetchEvents;// localsvar _element = element[0];var header;var headerElement;var content;var tm; // for making theme classesvar currentView;var viewInstances = {};var elementOuterWidth;var suggestedViewHeight;var absoluteViewElement;var resizeUID = 0;var ignoreWindowResize = 0;var date = new Date();var events = [];var _dragElement;/* Main Rendering-----------------------------------------------------------------------------*/setYMD(date, options.year, options.month, options.date);function render(inc) {if (!content) {initialRender();}else{calcSize();markSizesDirty();markEventsDirty();renderView(inc);}}function initialRender() {tm = options.theme ? 'ui' : 'fc';element.addClass('fc');if (options.isRTL) {element.addClass('fc-rtl');}if (options.theme) {element.addClass('ui-widget');}content = $("<div class='fc-content' style='position:relative'/>").prependTo(element);header = new Header(t, options);headerElement = header.render();if (headerElement) {element.prepend(headerElement);}changeView(options.defaultView);$(window).resize(windowResize);// needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResizeif (!bodyVisible()) {lateRender();}}// called when we know the calendar couldn't be rendered when it was initialized,// but we think it's ready nowfunction lateRender() {setTimeout(function() { // IE7 needs this so dimensions are calculated correctlyif (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than oncerenderView();}},0);}function destroy() {$(window).unbind('resize', windowResize);header.destroy();content.remove();element.removeClass('fc fc-rtl ui-widget');}function elementVisible() {return _element.offsetWidth !== 0;}function bodyVisible() {return $('body')[0].offsetWidth !== 0;}/* View Rendering-----------------------------------------------------------------------------*/// TODO: improve view switching (still weird transition in IE, and FF has whiteout problem)function changeView(newViewName) {if (!currentView || newViewName != currentView.name) {ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reachedunselect();var oldView = currentView;var newViewElement;if (oldView) {(oldView.beforeHide || noop)(); // 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');currentView = viewInstances[newViewName];if (currentView) {currentView.element.show();}else{currentView = viewInstances[newViewName] = new fcViews[newViewName](newViewElement = absoluteViewElement =$("<div class='fc-view fc-view-" + newViewName + "' style='position:absolute'/>").appendTo(content),t // the calendar object);}if (oldView) {header.deactivateButton(oldView.name);}header.activateButton(newViewName);renderView(); // after height has been set, will make absoluteViewElement's position=relative, then set to nullcontent.css('overflow', '');if (oldView) {setMinHeight(content, 1);}if (!newViewElement) {(currentView.afterShow || noop)(); // called after setting min-height/overflow, so in final scroll state (for Opera)}ignoreWindowResize--;}}function renderView(inc) {if (elementVisible()) {ignoreWindowResize++; // because renderEvents might temporarily change the height before setSize is reachedunselect();if (suggestedViewHeight === undefined) {calcSize();}var forceEventRender = false;if (!currentView.start || inc || date < currentView.start || date >= currentView.end) {// view must render an entire new date range (and refetch/render events)currentView.render(date, inc || 0); // responsible for clearing eventssetSize(true);forceEventRender = true;}else if (currentView.sizeDirty) {// view must resize (and rerender events)currentView.clearEvents();setSize();forceEventRender = true;}else if (currentView.eventsDirty) {currentView.clearEvents();forceEventRender = true;}currentView.sizeDirty = false;currentView.eventsDirty = false;updateEvents(forceEventRender);elementOuterWidth = element.outerWidth();header.updateTitle(currentView.title);var today = new Date();if (today >= currentView.start && today < currentView.end) {header.disableButton('today');}else{header.enableButton('today');}ignoreWindowResize--;currentView.trigger('viewDisplay', _element);}}/* Resizing-----------------------------------------------------------------------------*/function updateSize() {markSizesDirty();if (elementVisible()) {calcSize();setSize();unselect();currentView.clearEvents();currentView.renderEvents(events);currentView.sizeDirty = false;}}function markSizesDirty() {$.each(viewInstances, function(i, inst) {inst.sizeDirty = true;});}function calcSize() {if (options.contentHeight) {suggestedViewHeight = options.contentHeight;}else if (options.height) {suggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content);}else {suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));}}function setSize(dateChanged) { // todo: dateChanged?ignoreWindowResize++;currentView.setHeight(suggestedViewHeight, dateChanged);if (absoluteViewElement) {absoluteViewElement.css('position', 'relative');absoluteViewElement = null;}currentView.setWidth(content.width(), dateChanged);ignoreWindowResize--;}function windowResize() {if (!ignoreWindowResize) {if (currentView.start) { // view has already been renderedvar uid = ++resizeUID;setTimeout(function() { // add a delayif (uid == resizeUID && !ignoreWindowResize && elementVisible()) {if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {ignoreWindowResize++; // in case the windowResize callback changes the heightupdateSize();currentView.trigger('windowResize', _element);ignoreWindowResize--;}}}, 200);}else{// calendar must have been initialized in a 0x0 iframe that has just been resizedlateRender();}}}/* Event Fetching/Rendering-----------------------------------------------------------------------------*/// fetches events if necessary, rerenders events if necessary (or if forced)function updateEvents(forceRender) {if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) {refetchEvents();}else if (forceRender) {rerenderEvents();}}function refetchEvents() {fetchEvents(currentView.visStart, currentView.visEnd); // will call reportEvents}// called when event data arrivesfunction reportEvents(_events) {events = _events;rerenderEvents();}// called when a single event's data has been changedfunction reportEventChange(eventID) {rerenderEvents(eventID);}// attempts to rerenderEventsfunction rerenderEvents(modifiedEventID) {markEventsDirty();if (elementVisible()) {currentView.clearEvents();currentView.renderEvents(events, modifiedEventID);currentView.eventsDirty = false;}}function markEventsDirty() {$.each(viewInstances, function(i, inst) {inst.eventsDirty = true;});}/* Selection-----------------------------------------------------------------------------*/function select(start, end, allDay) {currentView.select(start, end, allDay===undefined ? true : allDay);}function unselect() { // safe to be called before renderViewif (currentView) {currentView.unselect();}}/* Date-----------------------------------------------------------------------------*/function prev() {renderView(-1);}function next() {renderView(1);}function prevYear() {addYears(date, -1);renderView();}function nextYear() {addYears(date, 1);renderView();}function today() {date = new Date();renderView();}function gotoDate(year, month, dateOfMonth) {if (year instanceof Date) {date = cloneDate(year); // provided 1 argument, a Date}else{setYMD(date, year, month, dateOfMonth);}renderView();}function incrementDate(years, months, days) {if (years !== undefined) {addYears(date, years);}if (months !== undefined) {addMonths(date, months);}if (days !== undefined) {addDays(date, days);}renderView();}function getDate() {return cloneDate(date);}/* Misc-----------------------------------------------------------------------------*/function getView() {return currentView;}function option(name, value) {if (value === undefined) {return options[name];}if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {options[name] = value;updateSize();}}function trigger(name, thisObj) {if (options[name]) {return options[name].apply(thisObj || _element,Array.prototype.slice.call(arguments, 2));}}/* External Dragging------------------------------------------------------------------------*/if (options.droppable) {$(document).bind('dragstart', function(ev, ui) {var _e = ev.target;var e = $(_e);if (!e.parents('.fc').length) { // not already inside a calendarvar accept = options.dropAccept;if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) {_dragElement = _e;currentView.dragStart(_dragElement, ev, ui);}}}).bind('dragstop', function(ev, ui) {if (_dragElement) {currentView.dragStop(_dragElement, ev, ui);_dragElement = null;}});}}function Header(calendar, options) {var t = this;// exportst.render = render;t.destroy = destroy;t.updateTitle = updateTitle;t.activateButton = activateButton;t.deactivateButton = deactivateButton;t.disableButton = disableButton;t.enableButton = enableButton;// localsvar element = $([]);var tm;function render() {tm = options.theme ? 'ui' : 'fc';var sections = options.header;if (sections) {element = $("<table class='fc-header' style='width:100%'/>").append($("<tr/>").append(renderSection('left')).append(renderSection('center')).append(renderSection('right')));return element;}}function destroy() {element.remove();}function renderSection(position) {var e = $("<td class='fc-header-" + position + "'/>");var buttonStr = options.header[position];if (buttonStr) {$.each(buttonStr.split(' '), function(i) {if (i > 0) {e.append("<span class='fc-header-space'/>");}var prevButton;$.each(this.split(','), function(j, buttonName) {if (buttonName == 'title') {e.append("<span class='fc-header-title'><h2> </h2></span>");if (prevButton) {prevButton.addClass(tm + '-corner-right');}prevButton = null;}else{var buttonClick;if (calendar[buttonName]) {buttonClick = calendar[buttonName]; // calendar method}else if (fcViews[buttonName]) {buttonClick = function() {button.removeClass(tm + '-state-hover'); // forget whycalendar.changeView(buttonName);};}if (buttonClick) {var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here?var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here?var button = $("<span class='fc-button fc-button-" + buttonName + " " + tm + "-state-default'>" +"<span class='fc-button-inner'>" +"<span class='fc-button-content'>" +(icon ?"<span class='fc-icon-wrap'>" +"<span class='ui-icon ui-icon-" + icon + "'/>" +"</span>" :text) +"</span>" +"<span class='fc-button-effect'><span></span></span>" +"</span>" +"</span>");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(e);if (!prevButton) {button.addClass(tm + '-corner-left');}prevButton = button;}}}});if (prevButton) {prevButton.addClass(tm + '-corner-right');}});}return e;}function updateTitle(html) {element.find('h2').html(html);}function activateButton(buttonName) {element.find('span.fc-button-' + buttonName).addClass(tm + '-state-active');}function deactivateButton(buttonName) {element.find('span.fc-button-' + buttonName).removeClass(tm + '-state-active');}function disableButton(buttonName) {element.find('span.fc-button-' + buttonName).addClass(tm + '-state-disabled');}function enableButton(buttonName) {element.find('span.fc-button-' + buttonName).removeClass(tm + '-state-disabled');}}fc.sourceNormalizers = [];fc.sourceFetchers = [];var ajaxDefaults = {dataType: 'json',cache: false};var eventGUID = 1;function EventManager(options, _sources) {var t = this;// exportst.isFetchNeeded = isFetchNeeded;t.fetchEvents = fetchEvents;t.addEventSource = addEventSource;t.removeEventSource = removeEventSource;t.updateEvent = updateEvent;t.renderEvent = renderEvent;t.removeEvents = removeEvents;t.clientEvents = clientEvents;t.normalizeEvent = normalizeEvent;// importsvar trigger = t.trigger;var getView = t.getView;var reportEvents = t.reportEvents;// localsvar stickySource = { events: [] };var sources = [ stickySource ];var rangeStart, rangeEnd;var currentFetchID = 0;var pendingSourceCnt = 0;var loadingLevel = 0;var cache = [];for (var i=0; i<_sources.length; i++) {_addEventSource(_sources[i]);}/* Fetching-----------------------------------------------------------------------------*/function isFetchNeeded(start, end) {return !rangeStart || start < rangeStart || end > rangeEnd;}function fetchEvents(start, end) {rangeStart = start;rangeEnd = end;cache = [];var fetchID = ++currentFetchID;var len = sources.length;pendingSourceCnt = len;for (var i=0; i<len; i++) {fetchEventSource(sources[i], fetchID);}}function fetchEventSource(source, fetchID) {_fetchEventSource(source, function(events) {if (fetchID == currentFetchID) {if (events) {for (var i=0; i<events.length; i++) {events[i].source = source;normalizeEvent(events[i]);}cache = cache.concat(events);}pendingSourceCnt--;if (!pendingSourceCnt) {reportEvents(cache);}}});}function _fetchEventSource(source, callback) {var i;var fetchers = fc.sourceFetchers;var res;for (i=0; i<fetchers.length; i++) {res = fetchers[i](source, rangeStart, rangeEnd, callback);if (res === true) {// the fetcher is in charge. made its own async requestreturn;}else if (typeof res == 'object') {// the fetcher returned a new source. process it_fetchEventSource(res, callback);return;}}var events = source.events;if (events) {if ($.isFunction(events)) {pushLoading();events(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {callback(events);popLoading();});}else if ($.isArray(events)) {callback(events);}else {callback();}}else{var url = source.url;if (url) {var success = source.success;var error = source.error;var complete = source.complete;var data = $.extend({}, source.data || {});var startParam = firstDefined(source.startParam, options.startParam);var endParam = firstDefined(source.endParam, options.endParam);if (startParam) {data[startParam] = Math.round(+rangeStart / 1000);}if (endParam) {data[endParam] = Math.round(+rangeEnd / 1000);}pushLoading();$.ajax($.extend({}, ajaxDefaults, source, {data: data,success: function(events) {events = events || [];var res = applyAll(success, this, arguments);if ($.isArray(res)) {events = res;}callback(events);},error: function() {applyAll(error, this, arguments);callback();},complete: function() {applyAll(complete, this, arguments);popLoading();}}));}else{callback();}}}/* Sources-----------------------------------------------------------------------------*/function addEventSource(source) {source = _addEventSource(source);if (source) {pendingSourceCnt++;fetchEventSource(source, currentFetchID); // will eventually call reportEvents}}function _addEventSource(source) {if ($.isFunction(source) || $.isArray(source)) {source = { events: source };}else if (typeof source == 'string') {source = { url: source };}if (typeof source == 'object') {normalizeSource(source);sources.push(source);return source;}}function removeEventSource(source) {sources = $.grep(sources, function(src) {return !isSourcesEqual(src, source);});// remove all client events from that sourcecache = $.grep(cache, function(e) {return !isSourcesEqual(e.source, source);});reportEvents(cache);}/* Manipulation-----------------------------------------------------------------------------*/function updateEvent(event) { // update an existing eventvar i, len = cache.length, e,defaultEventEnd = getView().defaultEventEnd, // getView???startDelta = event.start - event._start,endDelta = event.end ?(event.end - (event._end || defaultEventEnd(event))) // event._end would be null if event.end: 0; // was null and event was just resizedfor (i=0; i<len; i++) {e = cache[i];if (e._id == event._id && e != event) {e.start = new Date(+e.start + startDelta);if (event.end) {if (e.end) {e.end = new Date(+e.end + endDelta);}else{e.end = new Date(+defaultEventEnd(e) + endDelta);}}else{e.end = null;}e.title = event.title;e.url = event.url;e.allDay = event.allDay;e.className = event.className;e.editable = event.editable;e.color = event.color;e.backgroudColor = event.backgroudColor;e.borderColor = event.borderColor;e.textColor = event.textColor;normalizeEvent(e);}}normalizeEvent(event);reportEvents(cache);}function renderEvent(event, stick) {normalizeEvent(event);if (!event.source) {if (stick) {stickySource.events.push(event);event.source = stickySource;}cache.push(event);}reportEvents(cache);}function removeEvents(filter) {if (!filter) { // remove allcache = [];// clear all array sourcesfor (var i=0; i<sources.length; i++) {if ($.isArray(sources[i].events)) {sources[i].events = [];}}}else{if (!$.isFunction(filter)) { // an event IDvar id = filter + '';filter = function(e) {return e._id == id;};}cache = $.grep(cache, filter, true);// remove events from array sourcesfor (var i=0; i<sources.length; i++) {if ($.isArray(sources[i].events)) {sources[i].events = $.grep(sources[i].events, filter, true);}}}reportEvents(cache);}function clientEvents(filter) {if ($.isFunction(filter)) {return $.grep(cache, filter);}else if (filter) { // an event IDfilter += '';return $.grep(cache, function(e) {return e._id == filter;});}return cache; // else, return all}/* Loading State-----------------------------------------------------------------------------*/function pushLoading() {if (!loadingLevel++) {trigger('loading', null, true);}}function popLoading() {if (!--loadingLevel) {trigger('loading', null, false);}}/* Event Normalization-----------------------------------------------------------------------------*/function normalizeEvent(event) {var source = event.source || {};var ignoreTimezone = firstDefined(source.ignoreTimezone, options.ignoreTimezone);event._id = event._id || (event.id === undefined ? '_fc' + eventGUID++ : event.id + '');if (event.date) {if (!event.start) {event.start = event.date;}delete event.date;}event._start = cloneDate(event.start = parseDate(event.start, ignoreTimezone));event.end = parseDate(event.end, ignoreTimezone);if (event.end && event.end <= event.start) {event.end = null;}event._end = event.end ? cloneDate(event.end) : null;if (event.allDay === undefined) {event.allDay = firstDefined(source.allDayDefault, 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}/* Utils------------------------------------------------------------------------------*/function normalizeSource(source) {if (source.className) {// TODO: repeat code, same code for event classNamesif (typeof source.className == 'string') {source.className = source.className.split(/\s+/);}}else{source.className = [];}var normalizers = fc.sourceNormalizers;for (var i=0; i<normalizers.length; i++) {normalizers[i](source);}}function isSourcesEqual(source1, source2) {return source1 && source2 && getSourcePrimitive(source1) == getSourcePrimitive(source2);}function getSourcePrimitive(source) {return ((typeof source == 'object') ? (source.events || source.url) : '') || source;}}fc.addDays = addDays;fc.cloneDate = cloneDate;fc.parseDate = parseDate;fc.parseISO8601 = parseISO8601;fc.parseTime = parseTime;fc.formatDate = formatDate;fc.formatDates = formatDates;/* Date Math-----------------------------------------------------------------------------*/var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],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/underflowif (+d) { // prevent infinite looping on invalid datesvar 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 savingsif (+d) {var dd = d.getDate() + n,check = cloneDate(d);check.setHours(9); // set to middle of daycheck.setDate(dd);d.setDate(dd);if (!keepTime) {clearTime(d);}fixDate(d, check);}return d;}function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposesif (+d) { // prevent infinite looping on invalid dateswhile (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);}function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1var i=0, d;do {d = new Date(1970, i++, 1);} while (d.getHours()); // != 0return 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 - d2return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);}function setYMD(date, y, m, d) {if (y !== undefined && y != date.getFullYear()) {date.setDate(1);date.setMonth(0);date.setFullYear(y);}if (m !== undefined && m != date.getMonth()) {date.setDate(1);date.setMonth(m);}if (d !== undefined) {date.setDate(d);}}/* Date Parsing-----------------------------------------------------------------------------*/function parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to trueif (typeof s == 'object') { // already a Date objectreturn s;}if (typeof s == 'number') { // a UNIX timestampreturn new Date(s * 1000);}if (typeof s == 'string') {if (s.match(/^\d+(\.\d+)?$/)) { // a UNIX timestampreturn new Date(parseFloat(s) * 1000);}if (ignoreTimezone === undefined) {ignoreTimezone = true;}return parseISO8601(s, ignoreTimezone) || (s ? new Date(s) : null);}// TODO: never return invalid dates (like from new Date(<string>)), return null insteadreturn null;}function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false// derived from http://delete.me.uk/2005/03/iso8601.html// TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.htmlvar 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);if (ignoreTimezone || !m[13]) {var check = new Date(m[1], 0, 1, 9, 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);}else{date.setUTCFullYear(m[1],m[3] ? m[3] - 1 : 0,m[5] || 1);date.setUTCHours(m[7] || 0,m[8] || 0,m[10] || 0,m[12] ? Number("0." + m[12]) * 1000 : 0);if (m[14]) {var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0);offset *= m[15] == '-' ? 1 : -1;date = new Date(+date + (offset * 60 * 1000));}}return date;}function parseTime(s) { // returns minutes since start of dayif (typeof s == 'number') { // an hourreturn s * 60;}if (typeof s == 'object') { // a Date objectreturn s.getHours() * 60 + s.getMinutes();}var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);if (m) {var h = parseInt(m[1], 10);if (m[3]) {h %= 12;if (m[3].toLowerCase().charAt(0) == 'p') {h += 12;}}return h * 60 + (m[2] ? parseInt(m[2], 10) : 0);}}/* Date Formatting-----------------------------------------------------------------------------*/// TODO: use same function formatDate(date, [date2], format, [options])function formatDate(date, format, options) {return formatDates(date, null, format, options);}function formatDates(date1, date2, format, options) {options = options || defaults;var date = date1,otherDate = date2,i, len = format.length, c,i2, formatter,res = '';for (i=0; i<len; i++) {c = format.charAt(i);if (c == "'") {for (i2=i+1; i2<len; i2++) {if (format.charAt(i2) == "'") {if (date) {if (i2 == i+1) {res += "'";}else{res += format.substring(i+1, i2);}i = i2;}break;}}}else if (c == '(') {for (i2=i+1; i2<len; i2++) {if (format.charAt(i2) == ')') {var subres = formatDate(date, format.substring(i+1, i2), options);if (parseInt(subres.replace(/\D/, ''), 10)) {res += subres;}i = i2;break;}}}else if (c == '[') {for (i2=i+1; i2<len; i2++) {if (format.charAt(i2) == ']') {var subformat = format.substring(i+1, i2);var subres = formatDate(date, subformat, options);if (subres != formatDate(otherDate, subformat, options)) {res += subres;}i = i2;break;}}}else if (c == '{') {date = date2;otherDate = date1;}else if (c == '}') {date = date1;otherDate = date2;}else {for (i2=len; i2>i; 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;};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';}};fc.applyAll = applyAll;/* Event Date Math-----------------------------------------------------------------------------*/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) : clearTime(end);}function segCmp(a, b) {return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);}function segsCollide(seg1, seg2) {return seg1.end > seg2.start && seg1.start < seg2.end;}/* Event Sorting-----------------------------------------------------------------------------*/// event rendering utilitiesfunction sliceSegs(events, visEventEnds, start, end) {var segs = [],i, len=events.length, event,eventStart, eventEnd,segStart, segEnd,isStart, isEnd;for (i=0; i<len; i++) {event = events[i];eventStart = event.start;eventEnd = visEventEnds[i];if (eventEnd > 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);}// event rendering calculation utilitiesfunction stackSegs(segs) {var levels = [],i, len = segs.length, seg,j, collide, k;for (i=0; i<len; i++) {seg = segs[i];j = 0; // the level index where seg should belongwhile (true) {collide = false;if (levels[j]) {for (k=0; k<levels[j].length; k++) {if (segsCollide(levels[j][k], seg)) {collide = true;break;}}}if (collide) {j++;}else{break;}}if (levels[j]) {levels[j].push(seg);}else{levels[j] = [seg];}}return levels;}/* Event Element Binding-----------------------------------------------------------------------------*/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();});}/* Element Dimensions-----------------------------------------------------------------------------*/function setOuterWidth(element, width, includeMargins) {for (var i=0, e; i<element.length; i++) {e = $(element[i]);e.width(Math.max(0, width - hsides(e, includeMargins)));}}function setOuterHeight(element, height, includeMargins) {for (var i=0, e; i<element.length; i++) {e = $(element[i]);e.height(Math.max(0, height - vsides(e, includeMargins)));}}function hsides(element, includeMargins) {return hpadding(element) + hborders(element) + (includeMargins ? hmargins(element) : 0);}function hpadding(element) {return (parseFloat($.css(element[0], 'paddingLeft', true)) || 0) +(parseFloat($.css(element[0], 'paddingRight', true)) || 0);}function hmargins(element) {return (parseFloat($.css(element[0], 'marginLeft', true)) || 0) +(parseFloat($.css(element[0], 'marginRight', true)) || 0);}function hborders(element) {return (parseFloat($.css(element[0], 'borderLeftWidth', true)) || 0) +(parseFloat($.css(element[0], 'borderRightWidth', true)) || 0);}function vsides(element, includeMargins) {return vpadding(element) + vborders(element) + (includeMargins ? vmargins(element) : 0);}function vpadding(element) {return (parseFloat($.css(element[0], 'paddingTop', true)) || 0) +(parseFloat($.css(element[0], 'paddingBottom', true)) || 0);}function vmargins(element) {return (parseFloat($.css(element[0], 'marginTop', true)) || 0) +(parseFloat($.css(element[0], 'marginBottom', true)) || 0);}function vborders(element) {return (parseFloat($.css(element[0], 'borderTopWidth', true)) || 0) +(parseFloat($.css(element[0], 'borderBottomWidth', true)) || 0);}function setMinHeight(element, height) {height = (typeof height == 'number' ? height + 'px' : height);element.each(function(i, _element) {_element.style.cssText += ';min-height:' + height + ';_height:' + height;// why can't we just use .css() ? i forget});}/* Misc Utils-----------------------------------------------------------------------------*///TODO: arraySlice//TODO: isFunction, grep ?function noop() { }function cmp(a, b) {return a - b;}function arrayMax(a) {return Math.max.apply(Math, a);}function zeroPad(n) {return (n < 10 ? '0' : '') + n;}function smartProperty(obj, name) { // get a camel-cased/namespaced property of an objectif (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, ''').replace(/"/g, '"').replace(/\n/g, '<br />');}function cssKey(_element) {return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, '');}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');}*/function markFirstLast(e) {e.children().removeClass('fc-first fc-last').filter(':first-child').addClass('fc-first').end().filter(':last-child').addClass('fc-last');}function setDayID(cell, date) {cell.each(function(i, _cell) {_cell.className = _cell.className.replace(/^fc-\w*/, 'fc-' + dayIDs[date.getDay()]);// TODO: make a way that doesn't rely on order of classes});}function getSkinCss(event, opt) {var source = event.source || {};var eventColor = event.color;var sourceColor = source.color;var optionColor = opt('eventColor');var backgroundColor =event.backgroundColor ||eventColor ||source.backgroundColor ||sourceColor ||opt('eventBackgroundColor') ||optionColor;var borderColor =event.borderColor ||eventColor ||source.borderColor ||sourceColor ||opt('eventBorderColor') ||optionColor;var textColor =event.textColor ||source.textColor ||opt('eventTextColor');var statements = [];if (backgroundColor) {statements.push('background-color:' + backgroundColor);}if (borderColor) {statements.push('border-color:' + borderColor);}if (textColor) {statements.push('color:' + textColor);}return statements.join(';');}function applyAll(functions, thisObj, args) {if ($.isFunction(functions)) {functions = [ functions ];}if (functions) {var i;var ret;for (i=0; i<functions.length; i++) {ret = functions[i].apply(thisObj, args) || ret;}return ret;}}function firstDefined() {for (var i=0; i<arguments.length; i++) {if (arguments[i] !== undefined) {return arguments[i];}}}fcViews.month = MonthView;function MonthView(element, calendar) {var t = this;// exportst.render = render;// importsBasicView.call(t, element, calendar, 'month');var opt = t.opt;var renderBasic = t.renderBasic;var formatDate = calendar.formatDate;function render(date, delta) {if (delta) {addMonths(date, delta);date.setDate(1);}var start = cloneDate(date, true);start.setDate(1);var end = addMonths(cloneDate(start), 1);var visStart = cloneDate(start);var visEnd = cloneDate(end);var firstDay = opt('firstDay');var nwe = opt('weekends') ? 0 : 1;if (nwe) {skipWeekend(visStart);skipWeekend(visEnd, -1, true);}addDays(visStart, -((visStart.getDay() - Math.max(firstDay, nwe) + 7) % 7));addDays(visEnd, (7 - visEnd.getDay() + Math.max(firstDay, nwe)) % 7);var rowCnt = Math.round((visEnd - visStart) / (DAY_MS * 7));if (opt('weekMode') == 'fixed') {addDays(visEnd, (6 - rowCnt) * 7);rowCnt = 6;}t.title = formatDate(start, opt('titleFormat'));t.start = start;t.end = end;t.visStart = visStart;t.visEnd = visEnd;renderBasic(6, rowCnt, nwe ? 5 : 7, true);}}fcViews.basicWeek = BasicWeekView;function BasicWeekView(element, calendar) {var t = this;// exportst.render = render;// importsBasicView.call(t, element, calendar, 'basicWeek');var opt = t.opt;var renderBasic = t.renderBasic;var formatDates = calendar.formatDates;function render(date, delta) {if (delta) {addDays(date, delta * 7);}var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));var end = addDays(cloneDate(start), 7);var visStart = cloneDate(start);var visEnd = cloneDate(end);var weekends = opt('weekends');if (!weekends) {skipWeekend(visStart);skipWeekend(visEnd, -1, true);}t.title = formatDates(visStart,addDays(cloneDate(visEnd), -1),opt('titleFormat'));t.start = start;t.end = end;t.visStart = visStart;t.visEnd = visEnd;renderBasic(1, 1, weekends ? 7 : 5, false);}}fcViews.basicDay = BasicDayView;//TODO: when calendar's date starts out on a weekend, shouldn't happenfunction BasicDayView(element, calendar) {var t = this;// exportst.render = render;// importsBasicView.call(t, element, calendar, 'basicDay');var opt = t.opt;var renderBasic = t.renderBasic;var formatDate = calendar.formatDate;function render(date, delta) {if (delta) {addDays(date, delta);if (!opt('weekends')) {skipWeekend(date, delta < 0 ? -1 : 1);}}t.title = formatDate(date, opt('titleFormat'));t.start = t.visStart = cloneDate(date, true);t.end = t.visEnd = addDays(cloneDate(t.start), 1);renderBasic(1, 1, 1, false);}}setDefaults({weekMode: 'fixed'});function BasicView(element, calendar, viewName) {var t = this;// exportst.renderBasic = renderBasic;t.setHeight = setHeight;t.setWidth = setWidth;t.renderDayOverlay = renderDayOverlay;t.defaultSelectionEnd = defaultSelectionEnd;t.renderSelection = renderSelection;t.clearSelection = clearSelection;t.reportDayClick = reportDayClick; // for selection (kinda hacky)t.dragStart = dragStart;t.dragStop = dragStop;t.defaultEventEnd = defaultEventEnd;t.getHoverListener = function() { return hoverListener };t.colContentLeft = colContentLeft;t.colContentRight = colContentRight;t.dayOfWeekCol = dayOfWeekCol;t.dateCell = dateCell;t.cellDate = cellDate;t.cellIsAllDay = function() { return true };t.allDayRow = allDayRow;t.allDayBounds = allDayBounds;t.getRowCnt = function() { return rowCnt };t.getColCnt = function() { return colCnt };t.getColWidth = function() { return colWidth };t.getDaySegmentContainer = function() { return daySegmentContainer };// importsView.call(t, element, calendar, viewName);OverlayManager.call(t);SelectionManager.call(t);BasicEventRenderer.call(t);var opt = t.opt;var trigger = t.trigger;var clearEvents = t.clearEvents;var renderOverlay = t.renderOverlay;var clearOverlays = t.clearOverlays;var daySelectionMousedown = t.daySelectionMousedown;var formatDate = calendar.formatDate;// localsvar head;var headCells;var body;var bodyRows;var bodyCells;var bodyFirstCells;var bodyCellTopInners;var daySegmentContainer;var viewWidth;var viewHeight;var colWidth;var rowCnt, colCnt;var coordinateGrid;var hoverListener;var colContentPositions;var rtl, dis, dit;var firstDay;var nwe;var tm;var colFormat;/* Rendering------------------------------------------------------------*/disableTextSelection(element.addClass('fc-grid'));function renderBasic(maxr, r, c, showNumbers) {rowCnt = r;colCnt = c;updateOptions();var firstTime = !body;if (firstTime) {buildSkeleton(maxr, showNumbers);}else{clearEvents();}updateCells(firstTime);}function updateOptions() {rtl = opt('isRTL');if (rtl) {dis = -1;dit = colCnt - 1;}else{dis = 1;dit = 0;}firstDay = opt('firstDay');nwe = opt('weekends') ? 0 : 1;tm = opt('theme') ? 'ui' : 'fc';colFormat = opt('columnFormat');}function buildSkeleton(maxRowCnt, showNumbers) {var s;var headerClass = tm + "-widget-header";var contentClass = tm + "-widget-content";var i, j;var table;s ="<table class='fc-border-separate' style='width:100%' cellspacing='0'>" +"<thead>" +"<tr>";for (i=0; i<colCnt; i++) {s +="<th class='fc- " + headerClass + "'/>"; // need fc- for setDayID}s +="</tr>" +"</thead>" +"<tbody>";for (i=0; i<maxRowCnt; i++) {s +="<tr class='fc-week" + i + "'>";for (j=0; j<colCnt; j++) {s +="<td class='fc- " + contentClass + " fc-day" + (i*colCnt+j) + "'>" + // need fc- for setDayID"<div>" +(showNumbers ?"<div class='fc-day-number'/>" :'') +"<div class='fc-day-content'>" +"<div style='position:relative'> </div>" +"</div>" +"</div>" +"</td>";}s +="</tr>";}s +="</tbody>" +"</table>";table = $(s).appendTo(element);head = table.find('thead');headCells = head.find('th');body = table.find('tbody');bodyRows = body.find('tr');bodyCells = body.find('td');bodyFirstCells = bodyCells.filter(':first-child');bodyCellTopInners = bodyRows.eq(0).find('div.fc-day-content div');markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th'smarkFirstLast(bodyRows); // marks first+last td'sbodyRows.eq(0).addClass('fc-first'); // fc-last is done in updateCellsdayBind(bodyCells);daySegmentContainer =$("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(element);}function updateCells(firstTime) {var dowDirty = firstTime || rowCnt == 1; // could the cells' day-of-weeks need updating?var month = t.start.getMonth();var today = clearTime(new Date());var cell;var date;var row;if (dowDirty) {headCells.each(function(i, _cell) {cell = $(_cell);date = indexDate(i);cell.html(formatDate(date, colFormat));setDayID(cell, date);});}bodyCells.each(function(i, _cell) {cell = $(_cell);date = indexDate(i);if (date.getMonth() == month) {cell.removeClass('fc-other-month');}else{cell.addClass('fc-other-month');}if (+date == +today) {cell.addClass(tm + '-state-highlight fc-today');}else{cell.removeClass(tm + '-state-highlight fc-today');}cell.find('div.fc-day-number').text(date.getDate());if (dowDirty) {setDayID(cell, date);}});bodyRows.each(function(i, _row) {row = $(_row);if (i < rowCnt) {row.show();if (i == rowCnt-1) {row.addClass('fc-last');}else{row.removeClass('fc-last');}}else{row.hide();}});}function setHeight(height) {viewHeight = height;var bodyHeight = viewHeight - head.height();var rowHeight;var rowHeightLast;var cell;if (opt('weekMode') == 'variable') {rowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6));}else{rowHeight = Math.floor(bodyHeight / rowCnt);rowHeightLast = bodyHeight - rowHeight * (rowCnt-1);}bodyFirstCells.each(function(i, _cell) {if (i < rowCnt) {cell = $(_cell);setMinHeight(cell.find('> div'),(i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell));}});}function setWidth(width) {viewWidth = width;colContentPositions.clear();colWidth = Math.floor(viewWidth / colCnt);setOuterWidth(headCells.slice(0, -1), colWidth);}/* Day clicking and binding-----------------------------------------------------------*/function dayBind(days) {days.click(dayClick).mousedown(daySelectionMousedown);}function dayClick(ev) {if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClickvar index = parseInt(this.className.match(/fc\-day(\d+)/)[1]); // TODO: maybe use .datavar date = indexDate(index);trigger('dayClick', this, date, true, ev);}}/* Semi-transparent Overlay Helpers------------------------------------------------------*/function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusiveif (refreshCoordinateGrid) {coordinateGrid.build();}var rowStart = cloneDate(t.visStart);var rowEnd = addDays(cloneDate(rowStart), colCnt);for (var i=0; i<rowCnt; i++) {var stretchStart = new Date(Math.max(rowStart, overlayStart));var stretchEnd = new Date(Math.min(rowEnd, overlayEnd));if (stretchStart < stretchEnd) {var colStart, colEnd;if (rtl) {colStart = dayDiff(stretchEnd, rowStart)*dis+dit+1;colEnd = dayDiff(stretchStart, rowStart)*dis+dit+1;}else{colStart = dayDiff(stretchStart, rowStart);colEnd = dayDiff(stretchEnd, rowStart);}dayBind(renderCellOverlay(i, colStart, i, colEnd-1));}addDays(rowStart, 7);addDays(rowEnd, 7);}}function renderCellOverlay(row0, col0, row1, col1) { // row1,col1 is inclusivevar rect = coordinateGrid.rect(row0, col0, row1, col1, element);return renderOverlay(rect, element);}/* Selection-----------------------------------------------------------------------*/function defaultSelectionEnd(startDate, allDay) {return cloneDate(startDate);}function renderSelection(startDate, endDate, allDay) {renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); // rebuild every time???}function clearSelection() {clearOverlays();}function reportDayClick(date, allDay, ev) {var cell = dateCell(date);var _element = bodyCells[cell.row*colCnt + cell.col];trigger('dayClick', _element, date, allDay, ev);}/* External Dragging-----------------------------------------------------------------------*/function dragStart(_dragElement, ev, ui) {hoverListener.start(function(cell) {clearOverlays();if (cell) {renderCellOverlay(cell.row, cell.col, cell.row, cell.col);}}, ev);}function dragStop(_dragElement, ev, ui) {var cell = hoverListener.stop();clearOverlays();if (cell) {var d = cellDate(cell);trigger('drop', _dragElement, d, true, ev, ui);}}/* Utilities--------------------------------------------------------*/function defaultEventEnd(event) {return cloneDate(event.start);}coordinateGrid = new CoordinateGrid(function(rows, cols) {var e, n, p;headCells.each(function(i, _e) {e = $(_e);n = e.offset().left;if (i) {p[1] = n;}p = [n];cols[i] = p;});p[1] = n + e.outerWidth();bodyRows.each(function(i, _e) {if (i < rowCnt) {e = $(_e);n = e.offset().top;if (i) {p[1] = n;}p = [n];rows[i] = p;}});p[1] = n + e.outerHeight();});hoverListener = new HoverListener(coordinateGrid);colContentPositions = new HorizontalPositionCache(function(col) {return bodyCellTopInners.eq(col);});function colContentLeft(col) {return colContentPositions.left(col);}function colContentRight(col) {return colContentPositions.right(col);}function dateCell(date) {return {row: Math.floor(dayDiff(date, t.visStart) / 7),col: dayOfWeekCol(date.getDay())};}function cellDate(cell) {return _cellDate(cell.row, cell.col);}function _cellDate(row, col) {return addDays(cloneDate(t.visStart), row*7 + col*dis+dit);// what about weekends in middle of week?}function indexDate(index) {return _cellDate(Math.floor(index/colCnt), index%colCnt);}function dayOfWeekCol(dayOfWeek) {return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt) * dis + dit;}function allDayRow(i) {return bodyRows.eq(i);}function allDayBounds(i) {return {left: 0,right: viewWidth};}}function BasicEventRenderer() {var t = this;// exportst.renderEvents = renderEvents;t.compileDaySegs = compileSegs; // for DayEventRenderert.clearEvents = clearEvents;t.bindDaySeg = bindDaySeg;// importsDayEventRenderer.call(t);var opt = t.opt;var trigger = t.trigger;//var setOverflowHidden = t.setOverflowHidden;var isEventDraggable = t.isEventDraggable;var isEventResizable = t.isEventResizable;var reportEvents = t.reportEvents;var reportEventClear = t.reportEventClear;var eventElementHandlers = t.eventElementHandlers;var showEvents = t.showEvents;var hideEvents = t.hideEvents;var eventDrop = t.eventDrop;var getDaySegmentContainer = t.getDaySegmentContainer;var getHoverListener = t.getHoverListener;var renderDayOverlay = t.renderDayOverlay;var clearOverlays = t.clearOverlays;var getRowCnt = t.getRowCnt;var getColCnt = t.getColCnt;var renderDaySegs = t.renderDaySegs;var resizableDayEvent = t.resizableDayEvent;/* Rendering--------------------------------------------------------------------*/function renderEvents(events, modifiedEventId) {reportEvents(events);renderDaySegs(compileSegs(events), modifiedEventId);}function clearEvents() {reportEventClear();getDaySegmentContainer().empty();}function compileSegs(events) {var rowCnt = getRowCnt(),colCnt = getColCnt(),d1 = cloneDate(t.visStart),d2 = addDays(cloneDate(d1), colCnt),visEventsEnds = $.map(events, exclEndDay),i, row,j, level,k, seg,segs=[];for (i=0; i<rowCnt; i++) {row = stackSegs(sliceSegs(events, visEventsEnds, d1, d2));for (j=0; j<row.length; j++) {level = row[j];for (k=0; k<level.length; k++) {seg = level[k];seg.row = i;seg.level = j; // not needed anymoresegs.push(seg);}}addDays(d1, 7);addDays(d2, 7);}return segs;}function bindDaySeg(event, eventElement, seg) {if (isEventDraggable(event)) {draggableDayEvent(event, eventElement);}if (seg.isEnd && isEventResizable(event)) {resizableDayEvent(event, eventElement, seg);}eventElementHandlers(event, eventElement);// needs to be after, because resizableDayEvent might stopImmediatePropagation on click}/* Dragging----------------------------------------------------------------------------*/function draggableDayEvent(event, eventElement) {var hoverListener = getHoverListener();var dayDelta;eventElement.draggable({zIndex: 9,delay: 50,opacity: opt('dragOpacity'),revertDuration: opt('dragRevertDuration'),start: function(ev, ui) {trigger('eventDragStart', eventElement, event, ev, ui);hideEvents(event, eventElement);hoverListener.start(function(cell, origCell, rowDelta, colDelta) {eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);clearOverlays();if (cell) {//setOverflowHidden(true);dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1);renderDayOverlay(addDays(cloneDate(event.start), dayDelta),addDays(exclEndDay(event), dayDelta));}else{//setOverflowHidden(false);dayDelta = 0;}}, ev, 'drag');},stop: function(ev, ui) {hoverListener.stop();clearOverlays();trigger('eventDragStop', eventElement, event, ev, ui);if (dayDelta) {eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui);}else{eventElement.css('filter', ''); // clear IE opacity side-effectsshowEvents(event, eventElement);}//setOverflowHidden(false);}});}}fcViews.agendaWeek = AgendaWeekView;function AgendaWeekView(element, calendar) {var t = this;// exportst.render = render;// importsAgendaView.call(t, element, calendar, 'agendaWeek');var opt = t.opt;var renderAgenda = t.renderAgenda;var formatDates = calendar.formatDates;function render(date, delta) {if (delta) {addDays(date, delta * 7);}var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));var end = addDays(cloneDate(start), 7);var visStart = cloneDate(start);var visEnd = cloneDate(end);var weekends = opt('weekends');if (!weekends) {skipWeekend(visStart);skipWeekend(visEnd, -1, true);}t.title = formatDates(visStart,addDays(cloneDate(visEnd), -1),opt('titleFormat'));t.start = start;t.end = end;t.visStart = visStart;t.visEnd = visEnd;renderAgenda(weekends ? 7 : 5);}}fcViews.agendaDay = AgendaDayView;function AgendaDayView(element, calendar) {var t = this;// exportst.render = render;// importsAgendaView.call(t, element, calendar, 'agendaDay');var opt = t.opt;var renderAgenda = t.renderAgenda;var formatDate = calendar.formatDate;function render(date, delta) {if (delta) {addDays(date, delta);if (!opt('weekends')) {skipWeekend(date, delta < 0 ? -1 : 1);}}var start = cloneDate(date, true);var end = addDays(cloneDate(start), 1);t.title = formatDate(date, opt('titleFormat'));t.start = t.visStart = start;t.end = t.visEnd = end;renderAgenda(1);}}setDefaults({allDaySlot: true,allDayText: 'all-day',firstHour: 6,slotMinutes: 30,defaultEventMinutes: 120,axisFormat: 'h(:mm)tt',timeFormat: {agenda: 'h:mm{ - h:mm}'},dragOpacity: {agenda: .5},minTime: 0,maxTime: 24});// TODO: make it work in quirks mode (event corners, all-day height)// TODO: test liquid width, especially in IE6function AgendaView(element, calendar, viewName) {var t = this;// exportst.renderAgenda = renderAgenda;t.setWidth = setWidth;t.setHeight = setHeight;t.beforeHide = beforeHide;t.afterShow = afterShow;t.defaultEventEnd = defaultEventEnd;t.timePosition = timePosition;t.dayOfWeekCol = dayOfWeekCol;t.dateCell = dateCell;t.cellDate = cellDate;t.cellIsAllDay = cellIsAllDay;t.allDayRow = getAllDayRow;t.allDayBounds = allDayBounds;t.getHoverListener = function() { return hoverListener };t.colContentLeft = colContentLeft;t.colContentRight = colContentRight;t.getDaySegmentContainer = function() { return daySegmentContainer };t.getSlotSegmentContainer = function() { return slotSegmentContainer };t.getMinMinute = function() { return minMinute };t.getMaxMinute = function() { return maxMinute };t.getBodyContent = function() { return slotContent }; // !!??t.getRowCnt = function() { return 1 };t.getColCnt = function() { return colCnt };t.getColWidth = function() { return colWidth };t.getSlotHeight = function() { return slotHeight };t.defaultSelectionEnd = defaultSelectionEnd;t.renderDayOverlay = renderDayOverlay;t.renderSelection = renderSelection;t.clearSelection = clearSelection;t.reportDayClick = reportDayClick; // selection mousedown hackt.dragStart = dragStart;t.dragStop = dragStop;// importsView.call(t, element, calendar, viewName);OverlayManager.call(t);SelectionManager.call(t);AgendaEventRenderer.call(t);var opt = t.opt;var trigger = t.trigger;var clearEvents = t.clearEvents;var renderOverlay = t.renderOverlay;var clearOverlays = t.clearOverlays;var reportSelection = t.reportSelection;var unselect = t.unselect;var daySelectionMousedown = t.daySelectionMousedown;var slotSegHtml = t.slotSegHtml;var formatDate = calendar.formatDate;// localsvar dayTable;var dayHead;var dayHeadCells;var dayBody;var dayBodyCells;var dayBodyCellInners;var dayBodyFirstCell;var dayBodyFirstCellStretcher;var slotLayer;var daySegmentContainer;var allDayTable;var allDayRow;var slotScroller;var slotContent;var slotSegmentContainer;var slotTable;var slotTableFirstInner;var axisFirstCells;var gutterCells;var selectionHelper;var viewWidth;var viewHeight;var axisWidth;var colWidth;var gutterWidth;var slotHeight; // TODO: what if slotHeight changes? (see issue 650)var savedScrollTop;var colCnt;var slotCnt;var coordinateGrid;var hoverListener;var colContentPositions;var slotTopCache = {};var tm;var firstDay;var nwe; // no weekends (int)var rtl, dis, dit; // day index sign / translatevar minMinute, maxMinute;var colFormat;/* Rendering-----------------------------------------------------------------------------*/disableTextSelection(element.addClass('fc-agenda'));function renderAgenda(c) {colCnt = c;updateOptions();if (!dayTable) {buildSkeleton();}else{clearEvents();}updateCells();}function updateOptions() {tm = opt('theme') ? 'ui' : 'fc';nwe = opt('weekends') ? 0 : 1;firstDay = opt('firstDay');if (rtl = opt('isRTL')) {dis = -1;dit = colCnt - 1;}else{dis = 1;dit = 0;}minMinute = parseTime(opt('minTime'));maxMinute = parseTime(opt('maxTime'));colFormat = opt('columnFormat');}function buildSkeleton() {var headerClass = tm + "-widget-header";var contentClass = tm + "-widget-content";var s;var i;var d;var maxd;var minutes;var slotNormal = opt('slotMinutes') % 15 == 0;s ="<table style='width:100%' class='fc-agenda-days fc-border-separate' cellspacing='0'>" +"<thead>" +"<tr>" +"<th class='fc-agenda-axis " + headerClass + "'> </th>";for (i=0; i<colCnt; i++) {s +="<th class='fc- fc-col" + i + ' ' + headerClass + "'/>"; // fc- needed for setDayID}s +="<th class='fc-agenda-gutter " + headerClass + "'> </th>" +"</tr>" +"</thead>" +"<tbody>" +"<tr>" +"<th class='fc-agenda-axis " + headerClass + "'> </th>";for (i=0; i<colCnt; i++) {s +="<td class='fc- fc-col" + i + ' ' + contentClass + "'>" + // fc- needed for setDayID"<div>" +"<div class='fc-day-content'>" +"<div style='position:relative'> </div>" +"</div>" +"</div>" +"</td>";}s +="<td class='fc-agenda-gutter " + contentClass + "'> </td>" +"</tr>" +"</tbody>" +"</table>";dayTable = $(s).appendTo(element);dayHead = dayTable.find('thead');dayHeadCells = dayHead.find('th').slice(1, -1);dayBody = dayTable.find('tbody');dayBodyCells = dayBody.find('td').slice(0, -1);dayBodyCellInners = dayBodyCells.find('div.fc-day-content div');dayBodyFirstCell = dayBodyCells.eq(0);dayBodyFirstCellStretcher = dayBodyFirstCell.find('> div');markFirstLast(dayHead.add(dayHead.find('tr')));markFirstLast(dayBody.add(dayBody.find('tr')));axisFirstCells = dayHead.find('th:first');gutterCells = dayTable.find('.fc-agenda-gutter');slotLayer =$("<div style='position:absolute;z-index:2;left:0;width:100%'/>").appendTo(element);if (opt('allDaySlot')) {daySegmentContainer =$("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(slotLayer);s ="<table style='width:100%' class='fc-agenda-allday' cellspacing='0'>" +"<tr>" +"<th class='" + headerClass + " fc-agenda-axis'>" + opt('allDayText') + "</th>" +"<td>" +"<div class='fc-day-content'><div style='position:relative'/></div>" +"</td>" +"<th class='" + headerClass + " fc-agenda-gutter'> </th>" +"</tr>" +"</table>";allDayTable = $(s).appendTo(slotLayer);allDayRow = allDayTable.find('tr');dayBind(allDayRow.find('td'));axisFirstCells = axisFirstCells.add(allDayTable.find('th:first'));gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter'));slotLayer.append("<div class='fc-agenda-divider " + headerClass + "'>" +"<div class='fc-agenda-divider-inner'/>" +"</div>");}else{daySegmentContainer = $([]); // in jQuery 1.4, we can just do $()}slotScroller =$("<div style='position:absolute;width:100%;overflow-x:hidden;overflow-y:auto'/>").appendTo(slotLayer);slotContent =$("<div style='position:relative;width:100%;overflow:hidden'/>").appendTo(slotScroller);slotSegmentContainer =$("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(slotContent);s ="<table class='fc-agenda-slots' style='width:100%' cellspacing='0'>" +"<tbody>";d = zeroDate();maxd = addMinutes(cloneDate(d), maxMinute);addMinutes(d, minMinute);slotCnt = 0;for (i=0; d < maxd; i++) {minutes = d.getMinutes();s +="<tr class='fc-slot" + i + ' ' + (!minutes ? '' : 'fc-minor') + "'>" +"<th class='fc-agenda-axis " + headerClass + "'>" +((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : ' ') +"</th>" +"<td class='" + contentClass + "'>" +"<div style='position:relative'> </div>" +"</td>" +"</tr>";addMinutes(d, opt('slotMinutes'));slotCnt++;}s +="</tbody>" +"</table>";slotTable = $(s).appendTo(slotContent);slotTableFirstInner = slotTable.find('div:first');slotBind(slotTable.find('td'));axisFirstCells = axisFirstCells.add(slotTable.find('th:first'));}function updateCells() {var i;var headCell;var bodyCell;var date;var today = clearTime(new Date());for (i=0; i<colCnt; i++) {date = colDate(i);headCell = dayHeadCells.eq(i);headCell.html(formatDate(date, colFormat));bodyCell = dayBodyCells.eq(i);if (+date == +today) {bodyCell.addClass(tm + '-state-highlight fc-today');}else{bodyCell.removeClass(tm + '-state-highlight fc-today');}setDayID(headCell.add(bodyCell), date);}}function setHeight(height, dateChanged) {if (height === undefined) {height = viewHeight;}viewHeight = height;slotTopCache = {};var headHeight = dayBody.position().top;var allDayHeight = slotScroller.position().top; // including dividervar bodyHeight = Math.min( // total body height, including bordersheight - headHeight, // when scrollbarsslotTable.height() + allDayHeight + 1 // when no scrollbars. +1 for bottom border);dayBodyFirstCellStretcher.height(bodyHeight - vsides(dayBodyFirstCell));slotLayer.css('top', headHeight);slotScroller.height(bodyHeight - allDayHeight - 1);slotHeight = slotTableFirstInner.height() + 1; // +1 for borderif (dateChanged) {resetScroll();}}function setWidth(width) {viewWidth = width;colContentPositions.clear();axisWidth = 0;setOuterWidth(axisFirstCells.width('').each(function(i, _cell) {axisWidth = Math.max(axisWidth, $(_cell).outerWidth());}),axisWidth);var slotTableWidth = slotScroller[0].clientWidth; // needs to be done after axisWidth (for IE7)//slotTable.width(slotTableWidth);gutterWidth = slotScroller.width() - slotTableWidth;if (gutterWidth) {setOuterWidth(gutterCells, gutterWidth);gutterCells.show().prev().removeClass('fc-last');}else{gutterCells.hide().prev().addClass('fc-last');}colWidth = Math.floor((slotTableWidth - axisWidth) / colCnt);setOuterWidth(dayHeadCells.slice(0, -1), colWidth);}function resetScroll() {var d0 = zeroDate();var scrollDate = cloneDate(d0);scrollDate.setHours(opt('firstHour'));var top = timePosition(d0, scrollDate) + 1; // +1 for the borderfunction scroll() {slotScroller.scrollTop(top);}scroll();setTimeout(scroll, 0); // overrides any previous scroll state made by the browser}function beforeHide() {savedScrollTop = slotScroller.scrollTop();}function afterShow() {slotScroller.scrollTop(savedScrollTop);}/* Slot/Day clicking and binding-----------------------------------------------------------------------*/function dayBind(cells) {cells.click(slotClick).mousedown(daySelectionMousedown);}function slotBind(cells) {cells.click(slotClick).mousedown(slotSelectionMousedown);}function slotClick(ev) {if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClickvar col = Math.min(colCnt-1, Math.floor((ev.pageX - dayTable.offset().left - axisWidth) / colWidth));var date = colDate(col);var rowMatch = this.parentNode.className.match(/fc-slot(\d+)/); // TODO: maybe use dataif (rowMatch) {var mins = parseInt(rowMatch[1]) * opt('slotMinutes');var hours = Math.floor(mins/60);date.setHours(hours);date.setMinutes(mins%60 + minMinute);trigger('dayClick', dayBodyCells[col], date, false, ev);}else{trigger('dayClick', dayBodyCells[col], date, true, ev);}}}/* Semi-transparent Overlay Helpers-----------------------------------------------------*/function renderDayOverlay(startDate, endDate, refreshCoordinateGrid) { // endDate is exclusiveif (refreshCoordinateGrid) {coordinateGrid.build();}var visStart = cloneDate(t.visStart);var startCol, endCol;if (rtl) {startCol = dayDiff(endDate, visStart)*dis+dit+1;endCol = dayDiff(startDate, visStart)*dis+dit+1;}else{startCol = dayDiff(startDate, visStart);endCol = dayDiff(endDate, visStart);}startCol = Math.max(0, startCol);endCol = Math.min(colCnt, endCol);if (startCol < endCol) {dayBind(renderCellOverlay(0, startCol, 0, endCol-1));}}function renderCellOverlay(row0, col0, row1, col1) { // only for all-day?var rect = coordinateGrid.rect(row0, col0, row1, col1, slotLayer);return renderOverlay(rect, slotLayer);}function renderSlotOverlay(overlayStart, overlayEnd) {var dayStart = cloneDate(t.visStart);var dayEnd = addDays(cloneDate(dayStart), 1);for (var i=0; i<colCnt; i++) {var stretchStart = new Date(Math.max(dayStart, overlayStart));var stretchEnd = new Date(Math.min(dayEnd, overlayEnd));if (stretchStart < stretchEnd) {var col = i*dis+dit;var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only use it for horizontal coordsvar top = timePosition(dayStart, stretchStart);var bottom = timePosition(dayStart, stretchEnd);rect.top = top;rect.height = bottom - top;slotBind(renderOverlay(rect, slotContent));}addDays(dayStart, 1);addDays(dayEnd, 1);}}/* Coordinate Utilities-----------------------------------------------------------------------------*/coordinateGrid = new CoordinateGrid(function(rows, cols) {var e, n, p;dayHeadCells.each(function(i, _e) {e = $(_e);n = e.offset().left;if (i) {p[1] = n;}p = [n];cols[i] = p;});p[1] = n + e.outerWidth();if (opt('allDaySlot')) {e = allDayRow;n = e.offset().top;rows[0] = [n, n+e.outerHeight()];}var slotTableTop = slotContent.offset().top;var slotScrollerTop = slotScroller.offset().top;var slotScrollerBottom = slotScrollerTop + slotScroller.outerHeight();function constrain(n) {return Math.max(slotScrollerTop, Math.min(slotScrollerBottom, n));}for (var i=0; i<slotCnt; i++) {rows.push([constrain(slotTableTop + slotHeight*i),constrain(slotTableTop + slotHeight*(i+1))]);}});hoverListener = new HoverListener(coordinateGrid);colContentPositions = new HorizontalPositionCache(function(col) {return dayBodyCellInners.eq(col);});function colContentLeft(col) {return colContentPositions.left(col);}function colContentRight(col) {return colContentPositions.right(col);}function dateCell(date) { // "cell" terminology is now confusingreturn {row: Math.floor(dayDiff(date, t.visStart) / 7),col: dayOfWeekCol(date.getDay())};}function cellDate(cell) {var d = colDate(cell.col);var slotIndex = cell.row;if (opt('allDaySlot')) {slotIndex--;}if (slotIndex >= 0) {addMinutes(d, minMinute + slotIndex * opt('slotMinutes'));}return d;}function colDate(col) { // returns dates with 00:00:00return addDays(cloneDate(t.visStart), col*dis+dit);}function cellIsAllDay(cell) {return opt('allDaySlot') && !cell.row;}function dayOfWeekCol(dayOfWeek) {return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt)*dis+dit;}// get the Y coordinate of the given time on the given day (both Date objects)function timePosition(day, time) { // both date objects. day holds 00:00 of current dayday = cloneDate(day, true);if (time < addMinutes(cloneDate(day), minMinute)) {return 0;}if (time >= addMinutes(cloneDate(day), maxMinute)) {return slotTable.height();}var slotMinutes = opt('slotMinutes'),minutes = time.getHours()*60 + time.getMinutes() - minMinute,slotI = Math.floor(minutes / slotMinutes),slotTop = slotTopCache[slotI];if (slotTop === undefined) {slotTop = slotTopCache[slotI] = slotTable.find('tr:eq(' + slotI + ') td div')[0].offsetTop; //.position().top; // need this optimization???}return Math.max(0, Math.round(slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)));}function allDayBounds() {return {left: axisWidth,right: viewWidth - gutterWidth}}function getAllDayRow(index) {return allDayRow;}function defaultEventEnd(event) {var start = cloneDate(event.start);if (event.allDay) {return start;}return addMinutes(start, opt('defaultEventMinutes'));}/* Selection---------------------------------------------------------------------------------*/function defaultSelectionEnd(startDate, allDay) {if (allDay) {return cloneDate(startDate);}return addMinutes(cloneDate(startDate), opt('slotMinutes'));}function renderSelection(startDate, endDate, allDay) { // only for all-dayif (allDay) {if (opt('allDaySlot')) {renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true);}}else{renderSlotSelection(startDate, endDate);}}function renderSlotSelection(startDate, endDate) {var helperOption = opt('selectHelper');coordinateGrid.build();if (helperOption) {var col = dayDiff(startDate, t.visStart) * dis + dit;if (col >= 0 && col < colCnt) { // only works when times are on same dayvar rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only for horizontal coordsvar top = timePosition(startDate, startDate);var bottom = timePosition(startDate, endDate);if (bottom > top) { // protect against selections that are entirely before or after visible rangerect.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(slotContent);}}else{rect.isStart = true; // conside rect a "seg" nowrect.isEnd = true; //selectionHelper = $(slotSegHtml({title: '',start: startDate,end: endDate,className: ['fc-select-helper'],editable: false},rect));selectionHelper.css('opacity', opt('dragOpacity'));}if (selectionHelper) {slotBind(selectionHelper);slotContent.append(selectionHelper);setOuterWidth(selectionHelper, rect.width, true); // needs to be after appendedsetOuterHeight(selectionHelper, rect.height, true);}}}}else{renderSlotOverlay(startDate, endDate);}}function clearSelection() {clearOverlays();if (selectionHelper) {selectionHelper.remove();selectionHelper = null;}}function slotSelectionMousedown(ev) {if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse buttonunselect(ev);var dates;hoverListener.start(function(cell, origCell) {clearSelection();if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) {var d1 = cellDate(origCell);var d2 = cellDate(cell);dates = [d1,addMinutes(cloneDate(d1), opt('slotMinutes')),d2,addMinutes(cloneDate(d2), opt('slotMinutes'))].sort(cmp);renderSlotSelection(dates[0], dates[3]);}else{dates = null;}}, ev);$(document).one('mouseup', function(ev) {hoverListener.stop();if (dates) {if (+dates[0] == +dates[1]) {reportDayClick(dates[0], false, ev);}reportSelection(dates[0], dates[3], false, ev);}});}}function reportDayClick(date, allDay, ev) {trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date, allDay, ev);}/* External Dragging--------------------------------------------------------------------------------*/function dragStart(_dragElement, ev, ui) {hoverListener.start(function(cell) {clearOverlays();if (cell) {if (cellIsAllDay(cell)) {renderCellOverlay(cell.row, cell.col, cell.row, cell.col);}else{var d1 = cellDate(cell);var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes'));renderSlotOverlay(d1, d2);}}}, ev);}function dragStop(_dragElement, ev, ui) {var cell = hoverListener.stop();clearOverlays();if (cell) {trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui);}}}function AgendaEventRenderer() {var t = this;// exportst.renderEvents = renderEvents;t.compileDaySegs = compileDaySegs; // for DayEventRenderert.clearEvents = clearEvents;t.slotSegHtml = slotSegHtml;t.bindDaySeg = bindDaySeg;// importsDayEventRenderer.call(t);var opt = t.opt;var trigger = t.trigger;//var setOverflowHidden = t.setOverflowHidden;var isEventDraggable = t.isEventDraggable;var isEventResizable = t.isEventResizable;var eventEnd = t.eventEnd;var reportEvents = t.reportEvents;var reportEventClear = t.reportEventClear;var eventElementHandlers = t.eventElementHandlers;var setHeight = t.setHeight;var getDaySegmentContainer = t.getDaySegmentContainer;var getSlotSegmentContainer = t.getSlotSegmentContainer;var getHoverListener = t.getHoverListener;var getMaxMinute = t.getMaxMinute;var getMinMinute = t.getMinMinute;var timePosition = t.timePosition;var colContentLeft = t.colContentLeft;var colContentRight = t.colContentRight;var renderDaySegs = t.renderDaySegs;var resizableDayEvent = t.resizableDayEvent; // TODO: streamline binding architecturevar getColCnt = t.getColCnt;var getColWidth = t.getColWidth;var getSlotHeight = t.getSlotHeight;var getBodyContent = t.getBodyContent;var reportEventElement = t.reportEventElement;var showEvents = t.showEvents;var hideEvents = t.hideEvents;var eventDrop = t.eventDrop;var eventResize = t.eventResize;var renderDayOverlay = t.renderDayOverlay;var clearOverlays = t.clearOverlays;var calendar = t.calendar;var formatDate = calendar.formatDate;var formatDates = calendar.formatDates;/* Rendering----------------------------------------------------------------------------*/function renderEvents(events, modifiedEventId) {reportEvents(events);var i, len=events.length,dayEvents=[],slotEvents=[];for (i=0; i<len; i++) {if (events[i].allDay) {dayEvents.push(events[i]);}else{slotEvents.push(events[i]);}}if (opt('allDaySlot')) {renderDaySegs(compileDaySegs(dayEvents), modifiedEventId);setHeight(); // no params means set to viewHeight}renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);}function clearEvents() {reportEventClear();getDaySegmentContainer().empty();getSlotSegmentContainer().empty();}function compileDaySegs(events) {var levels = stackSegs(sliceSegs(events, $.map(events, exclEndDay), t.visStart, t.visEnd)),i, levelCnt=levels.length, level,j, seg,segs=[];for (i=0; i<levelCnt; i++) {level = levels[i];for (j=0; j<level.length; j++) {seg = level[j];seg.row = 0;seg.level = i; // not needed anymoresegs.push(seg);}}return segs;}function compileSlotSegs(events) {var colCnt = getColCnt(),minMinute = getMinMinute(),maxMinute = getMaxMinute(),d = addMinutes(cloneDate(t.visStart), minMinute),visEventEnds = $.map(events, slotEventEnd),i, col,j, level,k, seg,segs=[];for (i=0; i<colCnt; i++) {col = stackSegs(sliceSegs(events, visEventEnds, d, addMinutes(cloneDate(d), maxMinute-minMinute)));countForwardSegs(col);for (j=0; j<col.length; j++) {level = col[j];for (k=0; k<level.length; k++) {seg = level[k];seg.col = i;seg.level = j;segs.push(seg);}}addDays(d, 1, true);}return segs;}function slotEventEnd(event) {if (event.end) {return cloneDate(event.end);}else{return addMinutes(cloneDate(event.start), opt('defaultEventMinutes'));}}// renders events in the 'time slots' at the bottomfunction renderSlotSegs(segs, modifiedEventId) {var i, segCnt=segs.length, seg,event,classes,top, bottom,colI, levelI, forward,leftmost,availWidth,outerWidth,left,html='',eventElements,eventElement,triggerRes,vsideCache={},hsideCache={},key, val,contentElement,height,slotSegmentContainer = getSlotSegmentContainer(),rtl, dis, dit,colCnt = getColCnt();if (rtl = opt('isRTL')) {dis = -1;dit = colCnt - 1;}else{dis = 1;dit = 0;}// calculate position/dimensions, create htmlfor (i=0; i<segCnt; i++) {seg = segs[i];event = seg.event;top = timePosition(seg.start, seg.start);bottom = timePosition(seg.start, seg.end);colI = seg.col;levelI = seg.level;forward = seg.forward || 0;leftmost = colContentLeft(colI*dis + dit);availWidth = colContentRight(colI*dis + dit) - leftmost;availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSSif (levelI) {// indented and thinouterWidth = availWidth / (levelI + forward + 1);}else{if (forward) {// moderately wide, aligned left stillouterWidth = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =}else{// can be entire width, aligned leftouterWidth = availWidth;}}left = leftmost + // leftmost possible(availWidth / (levelI + forward + 1) * levelI) // indentation* dis + (rtl ? availWidth - outerWidth : 0); // rtlseg.top = top;seg.left = left;seg.outerWidth = outerWidth;seg.outerHeight = bottom - top;html += slotSegHtml(event, seg);}slotSegmentContainer[0].innerHTML = html; // faster than html()eventElements = slotSegmentContainer.children();// retrieve elements, run through eventRender callback, bind event handlersfor (i=0; i<segCnt; i++) {seg = segs[i];event = seg.event;eventElement = $(eventElements[i]); // faster than eq()triggerRes = trigger('eventRender', event, event, eventElement);if (triggerRes === false) {eventElement.remove();}else{if (triggerRes && triggerRes !== true) {eventElement.remove();eventElement = $(triggerRes).css({position: 'absolute',top: seg.top,left: seg.left}).appendTo(slotSegmentContainer);}seg.element = eventElement;if (event._id === modifiedEventId) {bindSlotSeg(event, eventElement, seg);}else{eventElement[0]._fci = i; // for lazySegBind}reportEventElement(event, eventElement);}}lazySegBind(slotSegmentContainer, segs, bindSlotSeg);// record event sides and title positionsfor (i=0; i<segCnt; i++) {seg = segs[i];if (eventElement = seg.element) {val = vsideCache[key = seg.key = cssKey(eventElement[0])];seg.vsides = val === undefined ? (vsideCache[key] = vsides(eventElement, true)) : val;val = hsideCache[key];seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement, true)) : val;contentElement = eventElement.find('div.fc-event-content');if (contentElement.length) {seg.contentTop = contentElement[0].offsetTop;}}}// set all positions/dimensions at oncefor (i=0; i<segCnt; i++) {seg = segs[i];if (eventElement = seg.element) {eventElement[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';height = Math.max(0, seg.outerHeight - seg.vsides);eventElement[0].style.height = height + 'px';event = seg.event;if (seg.contentTop !== undefined && height - seg.contentTop < 10) {// not enough room for title, put it in the time headereventElement.find('div.fc-event-time').text(formatDate(event.start, opt('timeFormat')) + ' - ' + event.title);eventElement.find('div.fc-event-title').remove();}trigger('eventAfterRender', event, event, eventElement);}}}function slotSegHtml(event, seg) {var html = "<";var url = event.url;var skinCss = getSkinCss(event, opt);var skinCssAttr = (skinCss ? " style='" + skinCss + "'" : '');var classes = ['fc-event', 'fc-event-skin', 'fc-event-vert'];if (isEventDraggable(event)) {classes.push('fc-event-draggable');}if (seg.isStart) {classes.push('fc-corner-top');}if (seg.isEnd) {classes.push('fc-corner-bottom');}classes = classes.concat(event.className);if (event.source) {classes = classes.concat(event.source.className || []);}if (url) {html += "a href='" + htmlEscape(event.url) + "'";}else{html += "div";}html +=" class='" + classes.join(' ') + "'" +" style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px;" + skinCss + "'" +">" +"<div class='fc-event-inner fc-event-skin'" + skinCssAttr + ">" +"<div class='fc-event-head fc-event-skin'" + skinCssAttr + ">" +"<div class='fc-event-time'>" +htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +"</div>" +"</div>" +"<div class='fc-event-content'>" +"<div class='fc-event-title'>" +htmlEscape(event.title) +"</div>" +"</div>" +"<div class='fc-event-bg'></div>" +"</div>"; // close innerif (seg.isEnd && isEventResizable(event)) {html +="<div class='ui-resizable-handle ui-resizable-s'>=</div>";}html +="</" + (url ? "a" : "div") + ">";return html;}function bindDaySeg(event, eventElement, seg) {if (isEventDraggable(event)) {draggableDayEvent(event, eventElement, seg.isStart);}if (seg.isEnd && isEventResizable(event)) {resizableDayEvent(event, eventElement, seg);}eventElementHandlers(event, eventElement);// needs to be after, because resizableDayEvent might stopImmediatePropagation on click}function bindSlotSeg(event, eventElement, seg) {var timeElement = eventElement.find('div.fc-event-time');if (isEventDraggable(event)) {draggableSlotEvent(event, eventElement, timeElement);}if (seg.isEnd && isEventResizable(event)) {resizableSlotEvent(event, eventElement, timeElement);}eventElementHandlers(event, eventElement);}/* Dragging-----------------------------------------------------------------------------------*/// when event starts out FULL-DAYfunction draggableDayEvent(event, eventElement, isStart) {var origWidth;var revert;var allDay=true;var dayDelta;var dis = opt('isRTL') ? -1 : 1;var hoverListener = getHoverListener();var colWidth = getColWidth();var slotHeight = getSlotHeight();var minMinute = getMinMinute();eventElement.draggable({zIndex: 9,opacity: opt('dragOpacity', 'month'), // use whatever the month view was usingrevertDuration: opt('dragRevertDuration'),start: function(ev, ui) {trigger('eventDragStart', eventElement, event, ev, ui);hideEvents(event, eventElement);origWidth = eventElement.width();hoverListener.start(function(cell, origCell, rowDelta, colDelta) {clearOverlays();if (cell) {//setOverflowHidden(true);revert = false;dayDelta = colDelta * dis;if (!cell.row) {// on full-daysrenderDayOverlay(addDays(cloneDate(event.start), dayDelta),addDays(exclEndDay(event), dayDelta));resetElement();}else{// mouse is over bottom slotsif (isStart) {if (allDay) {// convert event to temporary slot-eventeventElement.width(colWidth - 10); // don't use entire widthsetOuterHeight(eventElement,slotHeight * Math.round((event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes'))/ opt('slotMinutes')));eventElement.draggable('option', 'grid', [colWidth, 1]);allDay = false;}}else{revert = true;}}revert = revert || (allDay && !dayDelta);}else{resetElement();//setOverflowHidden(false);revert = true;}eventElement.draggable('option', 'revert', revert);}, ev, 'drag');},stop: function(ev, ui) {hoverListener.stop();clearOverlays();trigger('eventDragStop', eventElement, event, ev, ui);if (revert) {// hasn't moved or is out of bounds (draggable has already reverted)resetElement();eventElement.css('filter', ''); // clear IE opacity side-effectsshowEvents(event, eventElement);}else{// changed!var minuteDelta = 0;if (!allDay) {minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / slotHeight)* opt('slotMinutes')+ minMinute- (event.start.getHours() * 60 + event.start.getMinutes());}eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);}//setOverflowHidden(false);}});function resetElement() {if (!allDay) {eventElement.width(origWidth).height('').draggable('option', 'grid', null);allDay = true;}}}// when event starts out IN TIMESLOTSfunction draggableSlotEvent(event, eventElement, timeElement) {var origPosition;var allDay=false;var dayDelta;var minuteDelta;var prevMinuteDelta;var dis = opt('isRTL') ? -1 : 1;var hoverListener = getHoverListener();var colCnt = getColCnt();var colWidth = getColWidth();var slotHeight = getSlotHeight();eventElement.draggable({zIndex: 9,scroll: false,grid: [colWidth, slotHeight],axis: colCnt==1 ? 'y' : false,opacity: opt('dragOpacity'),revertDuration: opt('dragRevertDuration'),start: function(ev, ui) {trigger('eventDragStart', eventElement, event, ev, ui);hideEvents(event, eventElement);origPosition = eventElement.position();minuteDelta = prevMinuteDelta = 0;hoverListener.start(function(cell, origCell, rowDelta, colDelta) {eventElement.draggable('option', 'revert', !cell);clearOverlays();if (cell) {dayDelta = colDelta * dis;if (opt('allDaySlot') && !cell.row) {// over full daysif (!allDay) {// convert to temporary all-day eventallDay = true;timeElement.hide();eventElement.draggable('option', 'grid', null);}renderDayOverlay(addDays(cloneDate(event.start), dayDelta),addDays(exclEndDay(event), dayDelta));}else{// on slotsresetElement();}}}, ev, 'drag');},drag: function(ev, ui) {minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * opt('slotMinutes');if (minuteDelta != prevMinuteDelta) {if (!allDay) {updateTimeText(minuteDelta);}prevMinuteDelta = minuteDelta;}},stop: function(ev, ui) {var cell = hoverListener.stop();clearOverlays();trigger('eventDragStop', eventElement, event, ev, ui);if (cell && (dayDelta || minuteDelta || allDay)) {// changed!eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui);}else{// either no change or out-of-bounds (draggable has already reverted)resetElement();eventElement.css('filter', ''); // clear IE opacity side-effectseventElement.css(origPosition); // sometimes fast drags make event revert to wrong positionupdateTimeText(0);showEvents(event, eventElement);}}});function updateTimeText(minuteDelta) {var newStart = addMinutes(cloneDate(event.start), minuteDelta);var newEnd;if (event.end) {newEnd = addMinutes(cloneDate(event.end), minuteDelta);}timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));}function resetElement() {// convert back to original slot-eventif (allDay) {timeElement.css('display', ''); // show() was causing display=inlineeventElement.draggable('option', 'grid', [colWidth, slotHeight]);allDay = false;}}}/* Resizing--------------------------------------------------------------------------------------*/function resizableSlotEvent(event, eventElement, timeElement) {var slotDelta, prevSlotDelta;var slotHeight = getSlotHeight();eventElement.resizable({handles: {s: 'div.ui-resizable-s'},grid: slotHeight,start: function(ev, ui) {slotDelta = prevSlotDelta = 0;hideEvents(event, eventElement);eventElement.css('z-index', 9);trigger('eventResizeStart', this, event, ev, ui);},resize: function(ev, ui) {// don't rely on ui.size.height, doesn't take grid into accountslotDelta = 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 rangeaddMinutes(eventEnd(event), opt('slotMinutes')*slotDelta),opt('timeFormat')));prevSlotDelta = slotDelta;}},stop: function(ev, ui) {trigger('eventResizeStop', this, event, ev, ui);if (slotDelta) {eventResize(this, event, 0, opt('slotMinutes')*slotDelta, ev, ui);}else{eventElement.css('z-index', 8);showEvents(event, eventElement);// BUG: if event was really short, need to put title back in span}}});}}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<level.length; j++) {segForward = level[j];for (k=0; k<levels[i-1].length; k++) {segBack = levels[i-1][k];if (segsCollide(segForward, segBack)) {segBack.forward = Math.max(segBack.forward||0, (segForward.forward||0)+1);}}}}}function View(element, calendar, viewName) {var t = this;// exportst.element = element;t.calendar = calendar;t.name = viewName;t.opt = opt;t.trigger = trigger;//t.setOverflowHidden = setOverflowHidden;t.isEventDraggable = isEventDraggable;t.isEventResizable = isEventResizable;t.reportEvents = reportEvents;t.eventEnd = eventEnd;t.reportEventElement = reportEventElement;t.reportEventClear = reportEventClear;t.eventElementHandlers = eventElementHandlers;t.showEvents = showEvents;t.hideEvents = hideEvents;t.eventDrop = eventDrop;t.eventResize = eventResize;// t.title// t.start, t.end// t.visStart, t.visEnd// importsvar defaultEventEnd = t.defaultEventEnd;var normalizeEvent = calendar.normalizeEvent; // in EventManagervar reportEventChange = calendar.reportEventChange;// localsvar eventsByID = {};var eventElements = [];var eventElementsByID = {};var options = calendar.options;function opt(name, viewNameOverride) {var v = options[name];if (typeof v == 'object') {return smartProperty(v, viewNameOverride || viewName);}return v;}function trigger(name, thisObj) {return calendar.trigger.apply(calendar,[name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t]));}/*function setOverflowHidden(bool) {element.css('overflow', bool ? 'hidden' : '');}*/function isEventDraggable(event) {return isEventEditable(event) && !opt('disableDragging');}function isEventResizable(event) { // but also need to make sure the seg.isEnd == truereturn isEventEditable(event) && !opt('disableResizing');}function isEventEditable(event) {return firstDefined(event.editable, (event.source || {}).editable, opt('editable'));}/* Event Data------------------------------------------------------------------------------*/// report when view receives new eventsfunction reportEvents(events) { // events are already normalized at this pointeventsByID = {};var i, len=events.length, event;for (i=0; i<len; i++) {event = events[i];if (eventsByID[event._id]) {eventsByID[event._id].push(event);}else{eventsByID[event._id] = [event];}}}// returns a Date object for an event's endfunction eventEnd(event) {return event.end ? cloneDate(event.end) : defaultEventEnd(event);}/* Event Elements------------------------------------------------------------------------------*/// report when view creates an element for an eventfunction reportEventElement(event, element) {eventElements.push(element);if (eventElementsByID[event._id]) {eventElementsByID[event._id].push(element);}else{eventElementsByID[event._id] = [element];}}function reportEventClear() {eventElements = [];eventElementsByID = {};}// attaches eventClick, eventMouseover, eventMouseoutfunction eventElementHandlers(event, eventElement) {eventElement.click(function(ev) {if (!eventElement.hasClass('ui-draggable-dragging') &&!eventElement.hasClass('ui-resizable-resizing')) {return trigger('eventClick', this, event, ev);}}).hover(function(ev) {trigger('eventMouseover', this, event, ev);},function(ev) {trigger('eventMouseout', this, event, ev);});// TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)// TODO: same for resizing}function showEvents(event, exceptElement) {eachEventElement(event, exceptElement, 'show');}function hideEvents(event, exceptElement) {eachEventElement(event, exceptElement, 'hide');}function eachEventElement(event, exceptElement, funcName) {var elements = eventElementsByID[event._id],i, len = elements.length;for (i=0; i<len; i++) {if (!exceptElement || elements[i][0] != exceptElement[0]) {elements[i][funcName]();}}}/* Event Modification Reporting---------------------------------------------------------------------------------*/function eventDrop(e, event, dayDelta, minuteDelta, allDay, ev, ui) {var oldAllDay = event.allDay;var eventId = event._id;moveEvents(eventsByID[eventId], dayDelta, minuteDelta, allDay);trigger('eventDrop',e,event,dayDelta,minuteDelta,allDay,function() {// TODO: investigate cases where this inverse technique might not workmoveEvents(eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);reportEventChange(eventId);},ev,ui);reportEventChange(eventId);}function eventResize(e, event, dayDelta, minuteDelta, ev, ui) {var eventId = event._id;elongateEvents(eventsByID[eventId], dayDelta, minuteDelta);trigger('eventResize',e,event,dayDelta,minuteDelta,function() {// TODO: investigate cases where this inverse technique might not workelongateEvents(eventsByID[eventId], -dayDelta, -minuteDelta);reportEventChange(eventId);},ev,ui);reportEventChange(eventId);}/* Event Modification Math---------------------------------------------------------------------------------*/function moveEvents(events, dayDelta, minuteDelta, allDay) {minuteDelta = minuteDelta || 0;for (var e, len=events.length, i=0; i<len; i++) {e = events[i];if (allDay !== undefined) {e.allDay = allDay;}addMinutes(addDays(e.start, dayDelta, true), minuteDelta);if (e.end) {e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);}normalizeEvent(e, options);}}function elongateEvents(events, dayDelta, minuteDelta) {minuteDelta = minuteDelta || 0;for (var e, len=events.length, i=0; i<len; i++) {e = events[i];e.end = addMinutes(addDays(eventEnd(e), dayDelta, true), minuteDelta);normalizeEvent(e, options);}}}function DayEventRenderer() {var t = this;// exportst.renderDaySegs = renderDaySegs;t.resizableDayEvent = resizableDayEvent;// importsvar opt = t.opt;var trigger = t.trigger;var isEventDraggable = t.isEventDraggable;var isEventResizable = t.isEventResizable;var eventEnd = t.eventEnd;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 allDayRow = t.allDayRow;var allDayBounds = t.allDayBounds;var colContentLeft = t.colContentLeft;var colContentRight = t.colContentRight;var dayOfWeekCol = t.dayOfWeekCol;var dateCell = t.dateCell;var compileDaySegs = t.compileDaySegs;var getDaySegmentContainer = t.getDaySegmentContainer;var bindDaySeg = t.bindDaySeg; //TODO: streamline thisvar formatDates = t.calendar.formatDates;var renderDayOverlay = t.renderDayOverlay;var clearOverlays = t.clearOverlays;var clearSelection = t.clearSelection;/* Rendering-----------------------------------------------------------------------------*/function renderDaySegs(segs, modifiedEventId) {var segmentContainer = getDaySegmentContainer();var rowDivs;var rowCnt = getRowCnt();var colCnt = getColCnt();var i = 0;var rowI;var levelI;var colHeights;var j;var segCnt = segs.length;var seg;var top;var k;segmentContainer[0].innerHTML = daySegHTML(segs); // faster than .html()daySegElementResolve(segs, segmentContainer.children());daySegElementReport(segs);daySegHandlers(segs, segmentContainer, modifiedEventId);daySegCalcHSides(segs);daySegSetWidths(segs);daySegCalcHeights(segs);rowDivs = getRowDivs();// set row heights, calculate event tops (in relation to row top)for (rowI=0; rowI<rowCnt; rowI++) {levelI = 0;colHeights = [];for (j=0; j<colCnt; j++) {colHeights[j] = 0;}while (i<segCnt && (seg = segs[i]).row == rowI) {// loop through segs in a rowtop = arrayMax(colHeights.slice(seg.startCol, seg.endCol));seg.top = top;top += seg.outerHeight;for (k=seg.startCol; k<seg.endCol; k++) {colHeights[k] = top;}i++;}rowDivs[rowI].height(arrayMax(colHeights));}daySegSetTops(segs, getRowTops(rowDivs));}function renderTempDaySegs(segs, adjustRow, adjustTop) {var tempContainer = $("<div/>");var elements;var segmentContainer = getDaySegmentContainer();var i;var segCnt = segs.length;var element;tempContainer[0].innerHTML = daySegHTML(segs); // faster than .html()elements = tempContainer.children();segmentContainer.append(elements);daySegElementResolve(segs, elements);daySegCalcHSides(segs);daySegSetWidths(segs);daySegCalcHeights(segs);daySegSetTops(segs, getRowTops(getRowDivs()));elements = [];for (i=0; i<segCnt; i++) {element = segs[i].element;if (element) {if (segs[i].row === adjustRow) {element.css('top', adjustTop);}elements.push(element[0]);}}return $(elements);}function daySegHTML(segs) { // also sets seg.left and seg.outerWidthvar rtl = opt('isRTL');var i;var segCnt=segs.length;var seg;var event;var url;var classes;var bounds = allDayBounds();var minLeft = bounds.left;var maxLeft = bounds.right;var leftCol;var rightCol;var left;var right;var skinCss;var html = '';// calculate desired position/dimensions, create htmlfor (i=0; i<segCnt; i++) {seg = segs[i];event = seg.event;classes = ['fc-event', 'fc-event-skin', 'fc-event-hori'];if (isEventDraggable(event)) {classes.push('fc-event-draggable');}if (rtl) {if (seg.isStart) {classes.push('fc-corner-right');}if (seg.isEnd) {classes.push('fc-corner-left');}leftCol = dayOfWeekCol(seg.end.getDay()-1);rightCol = dayOfWeekCol(seg.start.getDay());left = seg.isEnd ? colContentLeft(leftCol) : minLeft;right = seg.isStart ? colContentRight(rightCol) : maxLeft;}else{if (seg.isStart) {classes.push('fc-corner-left');}if (seg.isEnd) {classes.push('fc-corner-right');}leftCol = dayOfWeekCol(seg.start.getDay());rightCol = dayOfWeekCol(seg.end.getDay()-1);left = seg.isStart ? colContentLeft(leftCol) : minLeft;right = seg.isEnd ? colContentRight(rightCol) : maxLeft;}classes = classes.concat(event.className);if (event.source) {classes = classes.concat(event.source.className || []);}url = event.url;skinCss = getSkinCss(event, opt);if (url) {html += "<a href='" + htmlEscape(url) + "'";}else{html += "<div";}html +=" class='" + classes.join(' ') + "'" +" style='position:absolute;z-index:8;left:"+left+"px;" + skinCss + "'" +">" +"<div" +" class='fc-event-inner fc-event-skin'" +(skinCss ? " style='" + skinCss + "'" : '') +">";if (!event.allDay && seg.isStart) {html +="<span class='fc-event-time'>" +htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +"</span>";}html +="<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +"</div>";if (seg.isEnd && isEventResizable(event)) {html +="<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'>" +" " + // makes hit area a lot better for IE6/7"</div>";}html +="</" + (url ? "a" : "div" ) + ">";seg.left = left;seg.outerWidth = right - left;seg.startCol = leftCol;seg.endCol = rightCol + 1; // needs to be exclusive}return html;}function daySegElementResolve(segs, elements) { // sets seg.elementvar i;var segCnt = segs.length;var seg;var event;var element;var triggerRes;for (i=0; i<segCnt; i++) {seg = segs[i];event = seg.event;element = $(elements[i]); // faster than .eq()triggerRes = trigger('eventRender', event, event, element);if (triggerRes === false) {element.remove();}else{if (triggerRes && triggerRes !== true) {triggerRes = $(triggerRes).css({position: 'absolute',left: seg.left});element.replaceWith(triggerRes);element = triggerRes;}seg.element = element;}}}function daySegElementReport(segs) {var i;var segCnt = segs.length;var seg;var element;for (i=0; i<segCnt; i++) {seg = segs[i];element = seg.element;if (element) {reportEventElement(seg.event, element);}}}function daySegHandlers(segs, segmentContainer, modifiedEventId) {var i;var segCnt = segs.length;var seg;var element;var event;// retrieve elements, run through eventRender callback, bind handlersfor (i=0; i<segCnt; i++) {seg = segs[i];element = seg.element;if (element) {event = seg.event;if (event._id === modifiedEventId) {bindDaySeg(event, element, seg);}else{element[0]._fci = i; // for lazySegBind}}}lazySegBind(segmentContainer, segs, bindDaySeg);}function daySegCalcHSides(segs) { // also sets seg.keyvar i;var segCnt = segs.length;var seg;var element;var key, val;var hsideCache = {};// record event horizontal sidesfor (i=0; i<segCnt; i++) {seg = segs[i];element = seg.element;if (element) {key = seg.key = cssKey(element[0]);val = hsideCache[key];if (val === undefined) {val = hsideCache[key] = hsides(element, true);}seg.hsides = val;}}}function daySegSetWidths(segs) {var i;var segCnt = segs.length;var seg;var element;for (i=0; i<segCnt; i++) {seg = segs[i];element = seg.element;if (element) {element[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';}}}function daySegCalcHeights(segs) {var i;var segCnt = segs.length;var seg;var element;var key, val;var vmarginCache = {};// record event heightsfor (i=0; i<segCnt; i++) {seg = segs[i];element = seg.element;if (element) {key = seg.key; // created in daySegCalcHSidesval = vmarginCache[key];if (val === undefined) {val = vmarginCache[key] = vmargins(element);}seg.outerHeight = element[0].offsetHeight + val;}}}function getRowDivs() {var i;var rowCnt = getRowCnt();var rowDivs = [];for (i=0; i<rowCnt; i++) {rowDivs[i] = allDayRow(i).find('td:first div.fc-day-content > div'); // optimal selector?}return rowDivs;}function getRowTops(rowDivs) {var i;var rowCnt = rowDivs.length;var tops = [];for (i=0; i<rowCnt; i++) {tops[i] = rowDivs[i][0].offsetTop; // !!?? but this means the element needs position:relative if in a table cell!!!!}return tops;}function daySegSetTops(segs, rowTops) { // also triggers eventAfterRendervar i;var segCnt = segs.length;var seg;var element;var event;for (i=0; i<segCnt; i++) {seg = segs[i];element = seg.element;if (element) {element[0].style.top = rowTops[seg.row] + (seg.top||0) + 'px';event = seg.event;trigger('eventAfterRender', event, event, element);}}}/* Resizing-----------------------------------------------------------------------------------*/function resizableDayEvent(event, element, seg) {var rtl = opt('isRTL');var direction = rtl ? 'w' : 'e';var handle = element.find('div.ui-resizable-' + direction);var isResizing = false;// TODO: look into using jquery-ui mouse widget for this stuffdisableTextSelection(element); // prevent native <a> selection for IEelement.mousedown(function(ev) { // prevent native <a> selection for othersev.preventDefault();}).click(function(ev) {if (isResizing) {ev.preventDefault(); // prevent link from being visited (only method that worked in IE6)ev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called// (eventElementHandlers needs to be bound after resizableDayEvent)}});handle.mousedown(function(ev) {if (ev.which != 1) {return; // needs to be left mouse button}isResizing = true;var hoverListener = t.getHoverListener();var rowCnt = getRowCnt();var colCnt = getColCnt();var dis = rtl ? -1 : 1;var dit = rtl ? colCnt-1 : 0;var elementTop = element.css('top');var dayDelta;var helpers;var eventCopy = $.extend({}, event);var minCell = dateCell(event.start);clearSelection();$('body').css('cursor', direction + '-resize').one('mouseup', mouseup);trigger('eventResizeStart', this, event, ev);hoverListener.start(function(cell, origCell) {if (cell) {var r = Math.max(minCell.row, cell.row);var c = cell.col;if (rowCnt == 1) {r = 0; // hack for all-day area in agenda views}if (r == minCell.row) {if (rtl) {c = Math.min(minCell.col, c);}else{c = Math.max(minCell.col, c);}}dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit);var newEnd = addDays(eventEnd(event), dayDelta, true);if (dayDelta) {eventCopy.end = newEnd;var oldHelpers = helpers;helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop);helpers.find('*').css('cursor', direction + '-resize');if (oldHelpers) {oldHelpers.remove();}hideEvents(event);}else{if (helpers) {showEvents(event);helpers.remove();helpers = null;}}clearOverlays();renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start}}, ev);function mouseup(ev) {trigger('eventResizeStop', this, event, ev);$('body').css('cursor', '');hoverListener.stop();clearOverlays();if (dayDelta) {eventResize(this, event, dayDelta, 0, ev);// event redraw will clear helpers}// otherwise, the drag handler already restored the old eventssetTimeout(function() { // make this happen after the element's click eventisResizing = false;},0);}});}}//BUG: unselect needs to be triggered when events are dragged+droppedfunction SelectionManager() {var t = this;// exportst.select = select;t.unselect = unselect;t.reportSelection = reportSelection;t.daySelectionMousedown = daySelectionMousedown;// importsvar opt = t.opt;var trigger = t.trigger;var defaultSelectionEnd = t.defaultSelectionEnd;var renderSelection = t.renderSelection;var clearSelection = t.clearSelection;// localsvar selected = false;// unselectAutoif (opt('selectable') && opt('unselectAuto')) {$(document).mousedown(function(ev) {var ignore = opt('unselectCancel');if (ignore) {if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first matchreturn;}}unselect(ev);});}function select(startDate, endDate, allDay) {unselect();if (!endDate) {endDate = defaultSelectionEnd(startDate, allDay);}renderSelection(startDate, endDate, allDay);reportSelection(startDate, endDate, allDay);}function unselect(ev) {if (selected) {selected = false;clearSelection();trigger('unselect', null, ev);}}function reportSelection(startDate, endDate, allDay, ev) {selected = true;trigger('select', null, startDate, endDate, allDay, ev);}function daySelectionMousedown(ev) { // not really a generic manager method, oh wellvar cellDate = t.cellDate;var cellIsAllDay = t.cellIsAllDay;var hoverListener = t.getHoverListener();var reportDayClick = t.reportDayClick; // this is hacky and sort of weirdif (ev.which == 1 && opt('selectable')) { // which==1 means left mouse buttonunselect(ev);var _mousedownElement = this;var dates;hoverListener.start(function(cell, origCell) { // TODO: maybe put cellDate/cellIsAllDay info in cellclearSelection();if (cell && cellIsAllDay(cell)) {dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp);renderSelection(dates[0], dates[1], true);}else{dates = null;}}, ev);$(document).one('mouseup', function(ev) {hoverListener.stop();if (dates) {if (+dates[0] == +dates[1]) {reportDayClick(dates[0], true, ev);}reportSelection(dates[0], dates[1], true, ev);}});}}}function OverlayManager() {var t = this;// exportst.renderOverlay = renderOverlay;t.clearOverlays = clearOverlays;// localsvar usedOverlays = [];var unusedOverlays = [];function renderOverlay(rect, parent) {var e = unusedOverlays.shift();if (!e) {e = $("<div class='fc-cell-overlay' style='position:absolute;z-index:3'/>");}if (e[0].parentNode != parent[0]) {e.appendTo(parent);}usedOverlays.push(e.css(rect).show());return e;}function clearOverlays() {var e;while (e = usedOverlays.shift()) {unusedOverlays.push(e.hide().unbind());}}}function CoordinateGrid(buildFunc) {var t = this;var rows;var cols;t.build = function() {rows = [];cols = [];buildFunc(rows, cols);};t.cell = function(x, y) {var rowCnt = rows.length;var colCnt = cols.length;var i, r=-1, c=-1;for (i=0; i<rowCnt; i++) {if (y >= rows[i][0] && y < rows[i][1]) {r = i;break;}}for (i=0; i<colCnt; i++) {if (x >= cols[i][0] && x < cols[i][1]) {c = i;break;}}return (r>=0 && c>=0) ? { row:r, col:c } : null;};t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusivevar origin = originElement.offset();return {top: rows[row0][0] - origin.top,left: cols[col0][0] - origin.left,width: cols[col1][1] - cols[col0][0],height: rows[row1][1] - rows[row0][0]};};}function HoverListener(coordinateGrid) {var t = this;var bindType;var change;var firstCell;var cell;t.start = function(_change, ev, _bindType) {change = _change;firstCell = cell = null;coordinateGrid.build();mouse(ev);bindType = _bindType || 'mousemove';$(document).bind(bindType, mouse);};function mouse(ev) {_fixUIEvent(ev); // see belowvar newCell = coordinateGrid.cell(ev.pageX, ev.pageY);if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) {if (newCell) {if (!firstCell) {firstCell = newCell;}change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col);}else{change(newCell, firstCell);}cell = newCell;}}t.stop = function() {$(document).unbind(bindType, mouse);return cell;};}// this fix was only necessary for jQuery UI 1.8.16 (and jQuery 1.7 or 1.7.1)// upgrading to jQuery UI 1.8.17 (and using either jQuery 1.7 or 1.7.1) fixed the problem// but keep this in here for 1.8.16 users// and maybe remove it down the linefunction _fixUIEvent(event) { // for issue 1168if (event.pageX === undefined) {event.pageX = event.originalEvent.pageX;event.pageY = event.originalEvent.pageY;}}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 = {};};}})(jQuery);