/** * @preserve * FullCalendar v1.4.6 * http://arshaw.com/fullcalendar/ * * Use fullcalendar.css for basic styling. * For event drag & drop, required jQuery UI draggable. * For event resizing, requires jQuery UI resizable. * * Copyright (c) 2009 Adam Shaw * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Date: Mon May 31 10:18:29 2010 -0700 * */(function($){varfc=$.fullCalendar={};varviews=fc.views={};/* Defaults -----------------------------------------------------------------------------*/vardefaults={// displaydefaultView:'month',aspectRatio:1.35,header:{left:'title',center:'',right:'today prev,next'},weekends:true,// editing//editable: false,//disableDragging: false,//disableResizing: false,allDayDefault: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};// right-to-left defaultsvarrtlDefaults={header:{left:'next,prev today',center:'',right:'title'},buttonText:{prev:' ► ',next:' ◄ ',prevYear:' >> ',nextYear:' << '},buttonIcons:{prev:'circle-triangle-e',next:'circle-triangle-w'}};// function for adding/overriding defaultsvarsetDefaults=fc.setDefaults=function(d){$.extend(true,defaults,d);};/* .fullCalendar jQuery function -----------------------------------------------------------------------------*/$.fn.fullCalendar=function(options){// method callingif(typeofoptions=='string'){varargs=Array.prototype.slice.call(arguments,1),res;this.each(function(){vardata=$.data(this,'fullCalendar');if(data){varmeth=data[options];if(meth){varr=meth.apply(this,args);if(res===undefined){res=r;}}}});if(res!==undefined){returnres;}returnthis;}// pluck the 'events' and 'eventSources' optionsvareventSources=options.eventSources||[];deleteoptions.eventSources;if(options.events){eventSources.push(options.events);deleteoptions.events;}// first event source reserved for 'sticky' eventseventSources.unshift([]);// initialize optionsoptions=$.extend(true,{},defaults,(options.isRTL||options.isRTL===undefined&&defaults.isRTL)?rtlDefaults:{},options);vartm=options.theme?'ui':'fc';// for making theme classesthis.each(function(){/* Instance Initialization -----------------------------------------------------------------------------*/// elementvar_element=this,element=$(_element).addClass('fc'),elementOuterWidth,content=$("<div class='fc-content "+tm+"-widget-content' style='position:relative'/>").prependTo(_element),suggestedViewHeight,resizeUID=0,ignoreWindowResize=0,date=newDate(),viewName,// the current view name (TODO: look into getting rid of)view,// the current viewviewInstances={},absoluteViewElement;if(options.isRTL){element.addClass('fc-rtl');}if(options.theme){element.addClass('ui-widget');}if(options.year!==undefined&&options.year!=date.getFullYear()){date.setDate(1);date.setMonth(0);date.setFullYear(options.year);}if(options.month!==undefined&&options.month!=date.getMonth()){date.setDate(1);date.setMonth(options.month);}if(options.date!==undefined){date.setDate(options.date);}/* View Rendering -----------------------------------------------------------------------------*/functionchangeView(v){if(v!=viewName){ignoreWindowResize++;// because setMinHeight might change the height before render (and subsequently setSize) is reachedviewUnselect();varoldView=view,newViewElement;if(oldView){if(oldView.eventsChanged){eventsDirty();oldView.eventDirty=oldView.eventsChanged=false;}if(oldView.beforeHide){oldView.beforeHide();// called before changing min-height. if called after, scroll state is reset (in Opera)}setMinHeight(content,content.height());oldView.element.hide();}else{setMinHeight(content,1);// needs to be 1 (not 0) for IE7, or else view dimensions miscalculated}content.css('overflow','hidden');if(viewInstances[v]){(view=viewInstances[v]).element.show();}else{view=viewInstances[v]=fc.views[v](newViewElement=absoluteViewElement=$("<div class='fc-view fc-view-"+v+"' style='position:absolute'/>").appendTo(content),options);}if(header){// update 'active' view buttonheader.find('div.fc-button-'+viewName).removeClass(tm+'-state-active');header.find('div.fc-button-'+v).addClass(tm+'-state-active');}view.name=viewName=v;render();// after height has been set, will make absoluteViewElement's position=relative, then set to nullcontent.css('overflow','');if(oldView){setMinHeight(content,1);}if(!newViewElement&&view.afterShow){view.afterShow();// called after setting min-height/overflow, so in final scroll state (for Opera)}ignoreWindowResize--;}}functionrender(inc){if(elementVisible()){ignoreWindowResize++;// because view.renderEvents might temporarily change the height before setSize is reachedviewUnselect();if(suggestedViewHeight===undefined){calcSize();}if(!view.start||inc||date<view.start||date>=view.end){view.render(date,inc||0);// responsible for clearing eventssetSize(true);if(!eventStart||!options.lazyFetching||view.visStart<eventStart||view.visEnd>eventEnd){fetchAndRenderEvents();}else{view.renderEvents(events);// don't refetch}}elseif(view.sizeDirty||view.eventsDirty||!options.lazyFetching){view.clearEvents();if(view.sizeDirty){setSize();}if(options.lazyFetching){view.renderEvents(events);// don't refetch}else{fetchAndRenderEvents();}}elementOuterWidth=element.outerWidth();view.sizeDirty=false;view.eventsDirty=false;if(header){// update title textheader.find('h2.fc-header-title').html(view.title);// enable/disable 'today' buttonvartoday=newDate();if(today>=view.start&&today<view.end){header.find('div.fc-button-today').addClass(tm+'-state-disabled');}else{header.find('div.fc-button-today').removeClass(tm+'-state-disabled');}}ignoreWindowResize--;view.trigger('viewDisplay',_element);}}functionelementVisible(){return_element.offsetWidth!==0;}functionbodyVisible(){return$('body')[0].offsetWidth!==0;}functionviewUnselect(){if(view){view.unselect();}}// called when any event objects have been added/removed/changed, rerendersfunctioneventsChanged(){eventsDirty();if(elementVisible()){view.clearEvents();view.renderEvents(events);view.eventsDirty=false;}}// marks other views' events as dirtyfunctioneventsDirty(){$.each(viewInstances,function(){this.eventsDirty=true;});}// called when we know the element size has changedfunctionsizeChanged(){sizesDirty();if(elementVisible()){calcSize();setSize();viewUnselect();view.rerenderEvents();view.sizeDirty=false;}}// marks other views' sizes as dirtyfunctionsizesDirty(){$.each(viewInstances,function(){this.sizeDirty=true;});}/* Event Sources and Fetching -----------------------------------------------------------------------------*/varevents=[],eventStart,eventEnd;// Fetch from ALL sources. Clear 'events' array and populatefunctionfetchEvents(callback){events=[];eventStart=cloneDate(view.visStart);eventEnd=cloneDate(view.visEnd);varqueued=eventSources.length,sourceDone=function(){if(!--queued){if(callback){callback(events);}}},i=0;for(;i<eventSources.length;i++){fetchEventSource(eventSources[i],sourceDone);}}// Fetch from a particular source. Append to the 'events' arrayfunctionfetchEventSource(src,callback){varprevViewName=view.name,prevDate=cloneDate(date),reportEvents=function(a){if(prevViewName==view.name&&+prevDate==+date&&// protects from fast switching$.inArray(src,eventSources)!=-1){// makes sure source hasn't been removedfor(vari=0;i<a.length;i++){normalizeEvent(a[i],options);a[i].source=src;}events=events.concat(a);if(callback){callback(a);}}},reportEventsAndPop=function(a){reportEvents(a);popLoading();};if(typeofsrc=='string'){varparams={};params[options.startParam]=Math.round(eventStart.getTime()/1000);params[options.endParam]=Math.round(eventEnd.getTime()/1000);if(options.cacheParam){params[options.cacheParam]=(newDate()).getTime();// TODO: deprecate cacheParam}pushLoading();$.ajax({url:src,dataType:'json',data:params,cache:options.cacheParam||false,// don't let jquery prevent caching if cacheParam is being usedsuccess:reportEventsAndPop});}elseif($.isFunction(src)){pushLoading();src(cloneDate(eventStart),cloneDate(eventEnd),reportEventsAndPop);}else{reportEvents(src);// src is an array}}// for conveniencefunctionfetchAndRenderEvents(){fetchEvents(function(events){view.renderEvents(events);// maintain `this` in view});}/* Loading State -----------------------------------------------------------------------------*/varloadingLevel=0;functionpushLoading(){if(!loadingLevel++){view.trigger('loading',_element,true);}}functionpopLoading(){if(!--loadingLevel){view.trigger('loading',_element,false);}}/* Public Methods -----------------------------------------------------------------------------*/varpublicMethods={render:function(){calcSize();sizesDirty();eventsDirty();render();},changeView:changeView,getView:function(){returnview;},getDate:function(){returndate;},option:function(name,value){if(value===undefined){returnoptions[name];}if(name=='height'||name=='contentHeight'||name=='aspectRatio'){options[name]=value;sizeChanged();}},destroy:function(){$(window).unbind('resize',windowResize);if(header){header.remove();}content.remove();$.removeData(_element,'fullCalendar');},//// Navigation//prev:function(){render(-1);},next:function(){render(1);},prevYear:function(){addYears(date,-1);render();},nextYear:function(){addYears(date,1);render();},today:function(){date=newDate();render();},gotoDate:function(year,month,dateNum){if(typeofyear=='object'){date=cloneDate(year);// provided 1 argument, a Date}else{if(year!==undefined){date.setFullYear(year);}if(month!==undefined){date.setMonth(month);}if(dateNum!==undefined){date.setDate(dateNum);}}render();},incrementDate:function(years,months,days){if(years!==undefined){addYears(date,years);}if(months!==undefined){addMonths(date,months);}if(days!==undefined){addDays(date,days);}render();},//// Event Manipulation//updateEvent:function(event){// update an existing eventvari,len=events.length,e,startDelta=event.start-event._start,endDelta=event.end?(event.end-(event._end||view.defaultEventEnd(event)))// event._end would be null if event.end:0;// was null and event was just resizedfor(i=0;i<len;i++){e=events[i];if(e._id==event._id&&e!=event){e.start=newDate(+e.start+startDelta);if(event.end){if(e.end){e.end=newDate(+e.end+endDelta);}else{e.end=newDate(+view.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;normalizeEvent(e,options);}}normalizeEvent(event,options);eventsChanged();},renderEvent:function(event,stick){// render a new eventnormalizeEvent(event,options);if(!event.source){if(stick){(event.source=eventSources[0]).push(event);}events.push(event);}eventsChanged();},removeEvents:function(filter){if(!filter){// remove allevents=[];// clear all array sourcesfor(vari=0;i<eventSources.length;i++){if(typeofeventSources[i]=='object'){eventSources[i]=[];}}}else{if(!$.isFunction(filter)){// an event IDvarid=filter+'';filter=function(e){returne._id==id;};}events=$.grep(events,filter,true);// remove events from array sourcesfor(vari=0;i<eventSources.length;i++){if(typeofeventSources[i]=='object'){eventSources[i]=$.grep(eventSources[i],filter,true);}}}eventsChanged();},clientEvents:function(filter){if($.isFunction(filter)){return$.grep(events,filter);}elseif(filter){// an event IDfilter+='';return$.grep(events,function(e){returne._id==filter;});}returnevents;// else, return all},rerenderEvents:eventsChanged,// TODO: think of renaming eventsChanged//// Event Source//addEventSource:function(source){eventSources.push(source);fetchEventSource(source,eventsChanged);},removeEventSource:function(source){eventSources=$.grep(eventSources,function(src){returnsrc!=source;});// remove all client events from that sourceevents=$.grep(events,function(e){returne.source!=source;});eventsChanged();},refetchEvents:function(){fetchEvents(eventsChanged);},//// selection//select:function(start,end,allDay){view.select(start,end,allDay===undefined?true:allDay);},unselect:function(){view.unselect();}};$.data(this,'fullCalendar',publicMethods);// TODO: look into memory leak implications/* Header -----------------------------------------------------------------------------*/varheader,sections=options.header;if(sections){header=$("<table class='fc-header'/>").append($("<tr/>").append($("<td class='fc-header-left'/>").append(buildSection(sections.left))).append($("<td class='fc-header-center'/>").append(buildSection(sections.center))).append($("<td class='fc-header-right'/>").append(buildSection(sections.right)))).prependTo(element);}functionbuildSection(buttonStr){if(buttonStr){vartr=$("<tr/>");$.each(buttonStr.split(' '),function(i){if(i>0){tr.append("<td><span class='fc-header-space'/></td>");}varprevButton;$.each(this.split(','),function(j,buttonName){if(buttonName=='title'){tr.append("<td><h2 class='fc-header-title'> </h2></td>");if(prevButton){prevButton.addClass(tm+'-corner-right');}prevButton=null;}else{varbuttonClick;if(publicMethods[buttonName]){buttonClick=publicMethods[buttonName];}elseif(views[buttonName]){buttonClick=function(){button.removeClass(tm+'-state-hover');changeView(buttonName);};}if(buttonClick){if(prevButton){prevButton.addClass(tm+'-no-right');}varbutton,icon=options.theme?smartProperty(options.buttonIcons,buttonName):null,text=smartProperty(options.buttonText,buttonName);if(icon){button=$("<div class='fc-button-"+buttonName+" ui-state-default'>"+"<a><span class='ui-icon ui-icon-"+icon+"'/></a></div>");}elseif(text){button=$("<div class='fc-button-"+buttonName+" "+tm+"-state-default'>"+"<a><span>"+text+"</span></a></div>");}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($("<td/>").appendTo(tr));if(prevButton){prevButton.addClass(tm+'-no-right');}else{button.addClass(tm+'-corner-left');}prevButton=button;}}}});if(prevButton){prevButton.addClass(tm+'-corner-right');}});return$("<table/>").append(tr);}}/* Resizing -----------------------------------------------------------------------------*/functioncalcSize(){if(options.contentHeight){suggestedViewHeight=options.contentHeight;}elseif(options.height){suggestedViewHeight=options.height-(header?header.height():0)-vsides(content[0]);}else{suggestedViewHeight=Math.round(content.width()/Math.max(options.aspectRatio,.5));}}functionsetSize(dateChanged){ignoreWindowResize++;view.setHeight(suggestedViewHeight,dateChanged);if(absoluteViewElement){absoluteViewElement.css('position','relative');absoluteViewElement=null;}view.setWidth(content.width(),dateChanged);ignoreWindowResize--;}functionwindowResize(){if(!ignoreWindowResize){if(view.start){// view has already been renderedvaruid=++resizeUID;setTimeout(function(){// add a delayif(uid==resizeUID&&!ignoreWindowResize&&elementVisible()){if(elementOuterWidth!=(elementOuterWidth=element.outerWidth())){ignoreWindowResize++;// in case the windowResize callback changes the heightsizeChanged();view.trigger('windowResize',_element);ignoreWindowResize--;}}},200);}else{// calendar must have been initialized in a 0x0 iframe that has just been resizedlateRender();}}}$(window).resize(windowResize);// let's begin...changeView(options.defaultView);// needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResizeif(!bodyVisible()){lateRender();}// called when we know the calendar couldn't be rendered when it was initialized,// but we think it's ready nowfunctionlateRender(){setTimeout(function(){// IE7 needs this so dimensions are calculated correctlyif(!view.start&&bodyVisible()){// !view.start makes sure this never happens more than oncerender();}},0);}});returnthis;};/* Important Event Utilities -----------------------------------------------------------------------------*/varfakeID=0;functionnormalizeEvent(event,options){event._id=event._id||(event.id===undefined?'_fc'+fakeID++:event.id+'');if(event.date){if(!event.start){event.start=event.date;}deleteevent.date;}event._start=cloneDate(event.start=parseDate(event.start));event.end=parseDate(event.end);if(event.end&&event.end<=event.start){event.end=null;}event._end=event.end?cloneDate(event.end):null;if(event.allDay===undefined){event.allDay=options.allDayDefault;}if(event.className){if(typeofevent.className=='string'){event.className=event.className.split(/\s+/);}}else{event.className=[];}}// TODO: if there is no start date, return false to indicate an invalid event/* Grid-based Views: month, basicWeek, basicDay -----------------------------------------------------------------------------*/setDefaults({weekMode:'fixed'});views.month=function(element,options){returnnewGrid(element,options,{render:function(date,delta){if(delta){addMonths(date,delta);date.setDate(1);}// start/endvarstart=this.start=cloneDate(date,true);start.setDate(1);this.end=addMonths(cloneDate(start),1);// visStart/visEndvarvisStart=this.visStart=cloneDate(start),visEnd=this.visEnd=cloneDate(this.end),nwe=options.weekends?0:1;if(nwe){skipWeekend(visStart);skipWeekend(visEnd,-1,true);}addDays(visStart,-((visStart.getDay()-Math.max(options.firstDay,nwe)+7)%7));addDays(visEnd,(7-visEnd.getDay()+Math.max(options.firstDay,nwe))%7);// row countvarrowCnt=Math.round((visEnd-visStart)/(DAY_MS*7));if(options.weekMode=='fixed'){addDays(visEnd,(6-rowCnt)*7);rowCnt=6;}// titlethis.title=formatDate(start,this.option('titleFormat'),options);// renderthis.renderGrid(rowCnt,options.weekends?7:5,this.option('columnFormat'),true);}});};views.basicWeek=function(element,options){returnnewGrid(element,options,{render:function(date,delta){if(delta){addDays(date,delta*7);}varvisStart=this.visStart=cloneDate(this.start=addDays(cloneDate(date),-((date.getDay()-options.firstDay+7)%7))),visEnd=this.visEnd=cloneDate(this.end=addDays(cloneDate(visStart),7));if(!options.weekends){skipWeekend(visStart);skipWeekend(visEnd,-1,true);}this.title=formatDates(visStart,addDays(cloneDate(visEnd),-1),this.option('titleFormat'),options);this.renderGrid(1,options.weekends?7:5,this.option('columnFormat'),false);}});};views.basicDay=function(element,options){returnnewGrid(element,options,{render:function(date,delta){if(delta){addDays(date,delta);if(!options.weekends){skipWeekend(date,delta<0?-1:1);}}this.title=formatDate(date,this.option('titleFormat'),options);this.start=this.visStart=cloneDate(date,true);this.end=this.visEnd=addDays(cloneDate(this.start),1);this.renderGrid(1,1,this.option('columnFormat'),false);}});};// rendering bugsvartdHeightBug;functionGrid(element,options,methods){vartm,firstDay,nwe,// no weekends (int)rtl,dis,dit,// day index sign / translateviewWidth,viewHeight,rowCnt,colCnt,colWidth,thead,tbody,cachedEvents=[],segmentContainer,dayContentPositions=newHorizontalPositionCache(function(dayOfWeek){returntbody.find('td:eq('+((dayOfWeek-Math.max(firstDay,nwe)+colCnt)%colCnt)+') div div');}),selectionManager,selectionMatrix,// ...// initialize superclassview=$.extend(this,viewMethods,methods,{renderGrid:renderGrid,renderEvents:renderEvents,rerenderEvents:rerenderEvents,clearEvents:clearEvents,setHeight:setHeight,setWidth:setWidth,defaultEventEnd:function(event){// calculates an end if event doesnt have one, mostly for resizingreturncloneDate(event.start);}});view.init(element,options);/* Grid Rendering -----------------------------------------------------------------------------*/disableTextSelection(element.addClass('fc-grid'));functionrenderGrid(r,c,colFormat,showNumbers){rowCnt=r;colCnt=c;// update option-derived variablestm=options.theme?'ui':'fc';nwe=options.weekends?0:1;firstDay=options.firstDay;if(rtl=options.isRTL){dis=-1;dit=colCnt-1;}else{dis=1;dit=0;}varmonth=view.start.getMonth(),today=clearTime(newDate()),s,i,j,d=cloneDate(view.visStart);if(!tbody){// first time, build all cells from scratchvartable=$("<table/>").appendTo(element);s="<thead><tr>";for(i=0;i<colCnt;i++){s+="<th class='fc-"+dayIDs[d.getDay()]+' '+// needs to be firsttm+'-state-default'+(i==dit?' fc-leftmost':'')+"'>"+formatDate(d,colFormat,options)+"</th>";addDays(d,1);if(nwe){skipWeekend(d);}}thead=$(s+"</tr></thead>").appendTo(table);s="<tbody>";d=cloneDate(view.visStart);for(i=0;i<rowCnt;i++){s+="<tr class='fc-week"+i+"'>";for(j=0;j<colCnt;j++){s+="<td class='fc-"+dayIDs[d.getDay()]+' '+// needs to be firsttm+'-state-default fc-day'+(i*colCnt+j)+(j==dit?' fc-leftmost':'')+(rowCnt>1&&d.getMonth()!=month?' fc-other-month':'')+(+d==+today?' fc-today '+tm+'-state-highlight':' fc-not-today')+"'>"+(showNumbers?"<div class='fc-day-number'>"+d.getDate()+"</div>":'')+"<div class='fc-day-content'><div style='position:relative'> </div></div></td>";addDays(d,1);if(nwe){skipWeekend(d);}}s+="</tr>";}tbody=$(s+"</tbody>").appendTo(table);dayBind(tbody.find('td'));segmentContainer=$("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(element);}else{// NOT first time, reuse as many cells as possibleclearEvents();varprevRowCnt=tbody.find('tr').length;if(rowCnt<prevRowCnt){tbody.find('tr:gt('+(rowCnt-1)+')').remove();// remove extra rows}elseif(rowCnt>prevRowCnt){// needs to create new rows...s='';for(i=prevRowCnt;i<rowCnt;i++){s+="<tr class='fc-week"+i+"'>";for(j=0;j<colCnt;j++){s+="<td class='fc-"+dayIDs[d.getDay()]+' '+// needs to be firsttm+'-state-default fc-new fc-day'+(i*colCnt+j)+(j==dit?' fc-leftmost':'')+"'>"+(showNumbers?"<div class='fc-day-number'></div>":'')+"<div class='fc-day-content'><div style='position:relative'> </div></div>"+"</td>";addDays(d,1);if(nwe){skipWeekend(d);}}s+="</tr>";}tbody.append(s);}dayBind(tbody.find('td.fc-new').removeClass('fc-new'));// re-label and re-class existing cellsd=cloneDate(view.visStart);tbody.find('td').each(function(){vartd=$(this);if(rowCnt>1){if(d.getMonth()==month){td.removeClass('fc-other-month');}else{td.addClass('fc-other-month');}}if(+d==+today){td.removeClass('fc-not-today').addClass('fc-today').addClass(tm+'-state-highlight');}else{td.addClass('fc-not-today').removeClass('fc-today').removeClass(tm+'-state-highlight');}td.find('div.fc-day-number').text(d.getDate());addDays(d,1);if(nwe){skipWeekend(d);}});if(rowCnt==1){// more changes likely (week or day view)// redo column header text and classd=cloneDate(view.visStart);thead.find('th').each(function(){$(this).text(formatDate(d,colFormat,options));this.className=this.className.replace(/^fc-\w+(?=)/,'fc-'+dayIDs[d.getDay()]);addDays(d,1);if(nwe){skipWeekend(d);}});// redo cell day-of-weeksd=cloneDate(view.visStart);tbody.find('td').each(function(){this.className=this.className.replace(/^fc-\w+(?=)/,'fc-'+dayIDs[d.getDay()]);addDays(d,1);if(nwe){skipWeekend(d);}});}}}functionsetHeight(height){viewHeight=height;varleftTDs=tbody.find('tr td:first-child'),tbodyHeight=viewHeight-thead.height(),rowHeight1,rowHeight2;if(options.weekMode=='variable'){rowHeight1=rowHeight2=Math.floor(tbodyHeight/(rowCnt==1?2:6));}else{rowHeight1=Math.floor(tbodyHeight/rowCnt);rowHeight2=tbodyHeight-rowHeight1*(rowCnt-1);}if(tdHeightBug===undefined){// bug in firefox where cell height includes paddingvartr=tbody.find('tr:first'),td=tr.find('td:first');td.height(rowHeight1);tdHeightBug=rowHeight1!=td.height();}if(tdHeightBug){leftTDs.slice(0,-1).height(rowHeight1);leftTDs.slice(-1).height(rowHeight2);}else{setOuterHeight(leftTDs.slice(0,-1),rowHeight1);setOuterHeight(leftTDs.slice(-1),rowHeight2);}}functionsetWidth(width){viewWidth=width;dayContentPositions.clear();setOuterWidth(thead.find('th').slice(0,-1),colWidth=Math.floor(viewWidth/colCnt));}/* Event Rendering -----------------------------------------------------------------------------*/functionrenderEvents(events){view.reportEvents(cachedEvents=events);renderSegs(compileSegs(events));}functionrerenderEvents(modifiedEventId){clearEvents();renderSegs(compileSegs(cachedEvents),modifiedEventId);}functionclearEvents(){view._clearEvents();// only clears the hashessegmentContainer.empty();}functioncompileSegs(events){vard1=cloneDate(view.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(view.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;segs.push(seg);}}addDays(d1,7);addDays(d2,7);}returnsegs;}functionrenderSegs(segs,modifiedEventId){_renderDaySegs(segs,rowCnt,view,0,viewWidth,function(i){returntbody.find('tr:eq('+i+')')},dayContentPositions.left,dayContentPositions.right,segmentContainer,bindSegHandlers,modifiedEventId);}functionbindSegHandlers(event,eventElement,seg){view.eventElementHandlers(event,eventElement);if(event.editable||event.editable===undefined&&options.editable){draggableEvent(event,eventElement);if(seg.isEnd){view.resizableDayEvent(event,eventElement,colWidth);}}}/* Event Dragging -----------------------------------------------------------------------------*/functiondraggableEvent(event,eventElement){if(!options.disableDragging&&eventElement.draggable){varmatrix,dayDelta=0;eventElement.draggable({zIndex:9,delay:50,opacity:view.option('dragOpacity'),revertDuration:options.dragRevertDuration,start:function(ev,ui){view.hideEvents(event,eventElement);view.trigger('eventDragStart',eventElement,event,ev,ui);matrix=buildDayMatrix(function(cell){eventElement.draggable('option','revert',!cell||!cell.rowDelta&&!cell.colDelta);clearOverlays();if(cell){dayDelta=cell.rowDelta*7+cell.colDelta*dis;renderDayOverlays(matrix,addDays(cloneDate(event.start),dayDelta),addDays(exclEndDay(event),dayDelta));}else{dayDelta=0;}});matrix.mouse(ev);},drag:function(ev){matrix.mouse(ev);},stop:function(ev,ui){clearOverlays();view.trigger('eventDragStop',eventElement,event,ev,ui);if(dayDelta){eventElement.find('a').removeAttr('href');// prevents safari from visiting the linkview.eventDrop(this,event,dayDelta,0,event.allDay,ev,ui);}else{if($.browser.msie){eventElement.css('filter','');// clear IE opacity side-effects}view.showEvents(event,eventElement);}}});}}/* Day clicking and binding ---------------------------------------------------------*/functiondayBind(days){days.click(dayClick).mousedown(selectionMousedown);}functiondayClick(ev){if(!view.option('selectable')){// SelectionManager will worry about dayClickvarn=parseInt(this.className.match(/fc\-day(\d+)/)[1]),date=addDays(cloneDate(view.visStart),Math.floor(n/colCnt)*7+n%colCnt);// TODO: what about weekends in middle of week?view.trigger('dayClick',this,date,true,ev);}}/* Selecting --------------------------------------------------------*/selectionManager=newSelectionManager(view,unselect,function(startDate,endDate,allDay){renderDayOverlays(selectionMatrix,startDate,addDays(cloneDate(endDate),1));},clearOverlays);functionselectionMousedown(ev){if(view.option('selectable')){selectionMatrix=buildDayMatrix(function(cell){if(cell){vard=cellDate(cell.row,cell.col);selectionManager.drag(d,d,true);}else{selectionManager.drag();}});documentDragHelp(function(ev){selectionMatrix.mouse(ev);},function(ev){selectionManager.dragStop(ev);});selectionManager.dragStart(ev);selectionMatrix.mouse(ev);returnfalse;// prevent auto-unselect and text selection}}documentUnselectAuto(view,unselect);view.select=function(start,end,allDay){if(!end){end=cloneDate(start);}selectionMatrix=buildDayMatrix();selectionManager.select(start,end,allDay);};functionunselect(){selectionManager.unselect();}view.unselect=unselect;/* Semi-transparent Overlay Helpers ------------------------------------------------------*/functionrenderDayOverlays(matrix,overlayStart,overlayEnd){// overlayEnd is exclusivevarrowStart=cloneDate(view.visStart);varrowEnd=addDays(cloneDate(rowStart),colCnt);for(vari=0;i<rowCnt;i++){varstretchStart=newDate(Math.max(rowStart,overlayStart));varstretchEnd=newDate(Math.min(rowEnd,overlayEnd));if(stretchStart<stretchEnd){varcolStart,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);}varrect=matrix.rect(i,colStart,i+1,colEnd,element);dayBind(view.renderOverlay(rect,element));}addDays(rowStart,7);addDays(rowEnd,7);}}functionclearOverlays(){view.clearOverlays();}/* Utils ---------------------------------------------------*/functionbuildDayMatrix(changeCallback){vartds=tbody.find('tr:first td');if(rtl){tds=$(tds.get().reverse());}returnnewHoverMatrix(tbody.find('tr'),tds,changeCallback);}functioncellDate(r,c){// convert r,c to datereturnaddDays(cloneDate(view.visStart),r*7+c*dis+dit);// TODO: what about weekends in middle of week?}}function_renderDaySegs(segs,rowCnt,view,minLeft,maxLeft,getRow,dayContentLeft,dayContentRight,segmentContainer,bindSegHandlers,modifiedEventId){varoptions=view.options,rtl=options.isRTL,i,segCnt=segs.length,seg,event,className,left,right,html='',eventElements,eventElement,triggerRes,hsideCache={},vmarginCache={},key,val,rowI,top,levelI,levelHeight,rowDivs=[],rowDivTops=[];// calculate desired position/dimensions, create htmlfor(i=0;i<segCnt;i++){seg=segs[i];event=seg.event;className='fc-event fc-event-hori ';if(rtl){if(seg.isStart){className+='fc-corner-right ';}if(seg.isEnd){className+='fc-corner-left ';}left=seg.isEnd?dayContentLeft(seg.end.getDay()-1):minLeft;right=seg.isStart?dayContentRight(seg.start.getDay()):maxLeft;}else{if(seg.isStart){className+='fc-corner-left ';}if(seg.isEnd){className+='fc-corner-right ';}left=seg.isStart?dayContentLeft(seg.start.getDay()):minLeft;right=seg.isEnd?dayContentRight(seg.end.getDay()-1):maxLeft;}html+="<div class='"+className+event.className.join(' ')+"' style='position:absolute;z-index:8;left:"+left+"px'>"+"<a"+(event.url?" href='"+htmlEscape(event.url)+"'":'')+">"+(!event.allDay&&seg.isStart?"<span class='fc-event-time'>"+htmlEscape(formatDates(event.start,event.end,view.option('timeFormat'),options))+"</span>":'')+"<span class='fc-event-title'>"+htmlEscape(event.title)+"</span>"+"</a>"+((event.editable||event.editable===undefined&&options.editable)&&!options.disableResizing&&$.fn.resizable?"<div class='ui-resizable-handle ui-resizable-"+(rtl?'w':'e')+"'></div>":'')+"</div>";seg.left=left;seg.outerWidth=right-left;}segmentContainer[0].innerHTML=html;// faster than html()eventElements=segmentContainer.children();// retrieve elements, run through eventRender callback, bind handlersfor(i=0;i<segCnt;i++){seg=segs[i];eventElement=$(eventElements[i]);// faster than eq()event=seg.event;triggerRes=view.trigger('eventRender',event,event,eventElement);if(triggerRes===false){eventElement.remove();}else{if(triggerRes&&triggerRes!==true){eventElement.remove();eventElement=$(triggerRes).css({position:'absolute',left:seg.left}).appendTo(segmentContainer);}seg.element=eventElement;if(event._id===modifiedEventId){bindSegHandlers(event,eventElement,seg);}else{eventElement[0]._fci=i;// for lazySegBind}view.reportEventElement(event,eventElement);}}lazySegBind(segmentContainer,segs,bindSegHandlers);// record event horizontal sidesfor(i=0;i<segCnt;i++){seg=segs[i];if(eventElement=seg.element){val=hsideCache[key=seg.key=cssKey(eventElement[0])];seg.hsides=val===undefined?(hsideCache[key]=hsides(eventElement[0],true)):val;}}// set event widthsfor(i=0;i<segCnt;i++){seg=segs[i];if(eventElement=seg.element){eventElement[0].style.width=seg.outerWidth-seg.hsides+'px';}}// record event heightsfor(i=0;i<segCnt;i++){seg=segs[i];if(eventElement=seg.element){val=vmarginCache[key=seg.key];seg.outerHeight=eventElement[0].offsetHeight+(val===undefined?(vmarginCache[key]=vmargins(eventElement[0])):val);}}// set row heights, calculate event tops (in relation to row top)for(i=0,rowI=0;rowI<rowCnt;rowI++){top=levelI=levelHeight=0;while(i<segCnt&&(seg=segs[i]).row==rowI){if(seg.level!=levelI){top+=levelHeight;levelHeight=0;levelI++;}levelHeight=Math.max(levelHeight,seg.outerHeight||0);seg.top=top;i++;}rowDivs[rowI]=getRow(rowI).find('td:first div.fc-day-content > div')// optimal selector?.height(top+levelHeight);}// calculate row topsfor(rowI=0;rowI<rowCnt;rowI++){rowDivTops[rowI]=rowDivs[rowI][0].offsetTop;}// set event topsfor(i=0;i<segCnt;i++){seg=segs[i];if(eventElement=seg.element){eventElement[0].style.top=rowDivTops[seg.row]+seg.top+'px';event=seg.event;view.trigger('eventAfterRender',event,event,eventElement);}}}/* Agenda Views: agendaWeek/agendaDay -----------------------------------------------------------------------------*/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});views.agendaWeek=function(element,options){returnnewAgenda(element,options,{render:function(date,delta){if(delta){addDays(date,delta*7);}varvisStart=this.visStart=cloneDate(this.start=addDays(cloneDate(date),-((date.getDay()-options.firstDay+7)%7))),visEnd=this.visEnd=cloneDate(this.end=addDays(cloneDate(visStart),7));if(!options.weekends){skipWeekend(visStart);skipWeekend(visEnd,-1,true);}this.title=formatDates(visStart,addDays(cloneDate(visEnd),-1),this.option('titleFormat'),options);this.renderAgenda(options.weekends?7:5,this.option('columnFormat'));}});};views.agendaDay=function(element,options){returnnewAgenda(element,options,{render:function(date,delta){if(delta){addDays(date,delta);if(!options.weekends){skipWeekend(date,delta<0?-1:1);}}this.title=formatDate(date,this.option('titleFormat'),options);this.start=this.visStart=cloneDate(date,true);this.end=this.visEnd=addDays(cloneDate(this.start),1);this.renderAgenda(1,this.option('columnFormat'));}});};functionAgenda(element,options,methods){varhead,body,bodyContent,bodyTable,bg,colCnt,slotCnt=0,// spanning all the way acrossaxisWidth,colWidth,slotHeight,viewWidth,viewHeight,savedScrollTop,cachedEvents=[],daySegmentContainer,slotSegmentContainer,tm,firstDay,nwe,// no weekends (int)rtl,dis,dit,// day index sign / translateminMinute,maxMinute,colContentPositions=newHorizontalPositionCache(function(col){returnbg.find('td:eq('+col+') div div');}),slotTopCache={},daySelectionManager,slotSelectionManager,selectionHelper,selectionMatrix,// ...view=$.extend(this,viewMethods,methods,{renderAgenda:renderAgenda,renderEvents:renderEvents,rerenderEvents:rerenderEvents,clearEvents:clearEvents,setHeight:setHeight,setWidth:setWidth,beforeHide:function(){savedScrollTop=body.scrollTop();},afterShow:function(){body.scrollTop(savedScrollTop);},defaultEventEnd:function(event){varstart=cloneDate(event.start);if(event.allDay){returnstart;}returnaddMinutes(start,options.defaultEventMinutes);}});view.init(element,options);/* Time-slot rendering -----------------------------------------------------------------------------*/disableTextSelection(element.addClass('fc-agenda'));functionrenderAgenda(c,colFormat){colCnt=c;// update option-derived variablestm=options.theme?'ui':'fc';nwe=options.weekends?0:1;firstDay=options.firstDay;if(rtl=options.isRTL){dis=-1;dit=colCnt-1;}else{dis=1;dit=0;}minMinute=parseTime(options.minTime);maxMinute=parseTime(options.maxTime);vard0=rtl?addDays(cloneDate(view.visEnd),-1):cloneDate(view.visStart),d=cloneDate(d0),today=clearTime(newDate());if(!head){// first time rendering, build from scratchvari,minutes,slotNormal=options.slotMinutes%15==0,//...// heads="<div class='fc-agenda-head' style='position:relative;z-index:4'>"+"<table style='width:100%'>"+"<tr class='fc-first"+(options.allDaySlot?'':' fc-last')+"'>"+"<th class='fc-leftmost "+tm+"-state-default'> </th>";for(i=0;i<colCnt;i++){s+="<th class='fc-"+dayIDs[d.getDay()]+' '+// needs to be firsttm+'-state-default'+"'>"+formatDate(d,colFormat,options)+"</th>";addDays(d,dis);if(nwe){skipWeekend(d,dis);}}s+="<th class='"+tm+"-state-default'> </th></tr>";if(options.allDaySlot){s+="<tr class='fc-all-day'>"+"<th class='fc-axis fc-leftmost "+tm+"-state-default'>"+options.allDayText+"</th>"+"<td colspan='"+colCnt+"' class='"+tm+"-state-default'>"+"<div class='fc-day-content'><div style='position:relative'> </div></div></td>"+"<th class='"+tm+"-state-default'> </th>"+"</tr><tr class='fc-divider fc-last'><th colspan='"+(colCnt+2)+"' class='"+tm+"-state-default fc-leftmost'><div/></th></tr>";}s+="</table></div>";head=$(s).appendTo(element);dayBind(head.find('td'));// all-day event containerdaySegmentContainer=$("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(head);// bodyd=zeroDate();varmaxd=addMinutes(cloneDate(d),maxMinute);addMinutes(d,minMinute);s="<table>";for(i=0;d<maxd;i++){minutes=d.getMinutes();s+="<tr class='"+(!i?'fc-first':(!minutes?'':'fc-minor'))+"'><th class='fc-axis fc-leftmost "+tm+"-state-default'>"+((!slotNormal||!minutes)?formatDate(d,options.axisFormat):' ')+"</th><td class='fc-slot"+i+' '+tm+"-state-default'><div style='position:relative'> </div></td></tr>";addMinutes(d,options.slotMinutes);slotCnt++;}s+="</table>";body=$("<div class='fc-agenda-body' style='position:relative;z-index:2;overflow:auto'/>").append(bodyContent=$("<div style='position:relative;overflow:hidden'/>").append(bodyTable=$(s))).appendTo(element);slotBind(body.find('td'));// slot event containerslotSegmentContainer=$("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(bodyContent);// background stripesd=cloneDate(d0);s="<div class='fc-agenda-bg' style='position:absolute;z-index:1'>"+"<table style='width:100%;height:100%'><tr class='fc-first'>";for(i=0;i<colCnt;i++){s+="<td class='fc-"+dayIDs[d.getDay()]+' '+// needs to be firsttm+'-state-default '+(!i?'fc-leftmost ':'')+(+d==+today?tm+'-state-highlight fc-today':'fc-not-today')+"'><div class='fc-day-content'><div> </div></div></td>";addDays(d,dis);if(nwe){skipWeekend(d,dis);}}s+="</tr></table></div>";bg=$(s).appendTo(element);}else{// skeleton already built, just modify itclearEvents();// redo column header text and classhead.find('tr:first th').slice(1,-1).each(function(){$(this).text(formatDate(d,colFormat,options));this.className=this.className.replace(/^fc-\w+(?=)/,'fc-'+dayIDs[d.getDay()]);addDays(d,dis);if(nwe){skipWeekend(d,dis);}});// change classes of background stripesd=cloneDate(d0);bg.find('td').each(function(){this.className=this.className.replace(/^fc-\w+(?=)/,'fc-'+dayIDs[d.getDay()]);if(+d==+today){$(this).removeClass('fc-not-today').addClass('fc-today').addClass(tm+'-state-highlight');}else{$(this).addClass('fc-not-today').removeClass('fc-today').removeClass(tm+'-state-highlight');}addDays(d,dis);if(nwe){skipWeekend(d,dis);}});}}functionresetScroll(){vard0=zeroDate(),scrollDate=cloneDate(d0);scrollDate.setHours(options.firstHour);vartop=timePosition(d0,scrollDate)+1,// +1 for the borderscroll=function(){body.scrollTop(top);};scroll();setTimeout(scroll,0);// overrides any previous scroll state made by the browser}functionsetHeight(height,dateChanged){viewHeight=height;slotTopCache={};body.height(height-head.height());slotHeight=body.find('tr:first div').height()+1;bg.css({top:head.find('tr').height(),height:height});if(dateChanged){resetScroll();}}functionsetWidth(width){viewWidth=width;colContentPositions.clear();body.width(width);bodyTable.width('');vartopTDs=head.find('tr:first th'),stripeTDs=bg.find('td'),clientWidth=body[0].clientWidth;bodyTable.width(clientWidth);// time-axis widthaxisWidth=0;setOuterWidth(head.find('tr:lt(2) th:first').add(body.find('tr:first th')).width('').each(function(){axisWidth=Math.max(axisWidth,$(this).outerWidth());}),axisWidth);// column widthcolWidth=Math.floor((clientWidth-axisWidth)/colCnt);setOuterWidth(stripeTDs.slice(0,-1),colWidth);setOuterWidth(topTDs.slice(1,-2),colWidth);setOuterWidth(topTDs.slice(-2,-1),clientWidth-axisWidth-colWidth*(colCnt-1));bg.css({left:axisWidth,width:clientWidth-axisWidth});}/* Slot/Day clicking and binding -----------------------------------------------------------------------*/functiondayBind(tds){tds.click(slotClick).mousedown(daySelectionMousedown);}functionslotBind(tds){tds.click(slotClick).mousedown(slotSelectionMousedown);}functionslotClick(ev){if(!view.option('selectable')){// SelectionManager will worry about dayClickvarcol=Math.floor((ev.pageX-bg.offset().left)/colWidth),date=addDays(cloneDate(view.visStart),dit+dis*col),rowMatch=this.className.match(/fc-slot(\d+)/);if(rowMatch){varmins=parseInt(rowMatch[1])*options.slotMinutes,hours=Math.floor(mins/60);date.setHours(hours);date.setMinutes(mins%60+minMinute);view.trigger('dayClick',this,date,false,ev);}else{view.trigger('dayClick',this,date,true,ev);}}}/* Event Rendering -----------------------------------------------------------------------------*/functionrenderEvents(events,modifiedEventId){view.reportEvents(cachedEvents=events);vari,len=events.length,dayEvents=[],slotEvents=[];for(i=0;i<len;i++){if(events[i].allDay){dayEvents.push(events[i]);}else{slotEvents.push(events[i]);}}renderDaySegs(compileDaySegs(dayEvents),modifiedEventId);renderSlotSegs(compileSlotSegs(slotEvents),modifiedEventId);}functionrerenderEvents(modifiedEventId){clearEvents();renderEvents(cachedEvents,modifiedEventId);}functionclearEvents(){view._clearEvents();// only clears the hashesdaySegmentContainer.empty();slotSegmentContainer.empty();}functioncompileDaySegs(events){varlevels=stackSegs(view.sliceSegs(events,$.map(events,exclEndDay),view.visStart,view.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;segs.push(seg);}}returnsegs;}functioncompileSlotSegs(events){vard=addMinutes(cloneDate(view.visStart),minMinute),visEventEnds=$.map(events,slotEventEnd),i,col,j,level,k,seg,segs=[];for(i=0;i<colCnt;i++){col=stackSegs(view.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);}returnsegs;}// renders 'all-day' events at the topfunctionrenderDaySegs(segs,modifiedEventId){if(options.allDaySlot){_renderDaySegs(segs,1,view,axisWidth,viewWidth,function(){returnhead.find('tr.fc-all-day');},function(dayOfWeek){returnaxisWidth+colContentPositions.left(dayOfWeekCol(dayOfWeek));},function(dayOfWeek){returnaxisWidth+colContentPositions.right(dayOfWeekCol(dayOfWeek));},daySegmentContainer,daySegBind,modifiedEventId);setHeight(viewHeight);// might have pushed the body down, so resize}}// renders events in the 'time slots' at the bottomfunctionrenderSlotSegs(segs,modifiedEventId){vari,segCnt=segs.length,seg,event,className,top,bottom,colI,levelI,forward,leftmost,availWidth,outerWidth,left,html='',eventElements,eventElement,triggerRes,vsideCache={},hsideCache={},key,val,titleSpan,height;// calculate position/dimensions, create htmlfor(i=0;i<segCnt;i++){seg=segs[i];event=seg.event;className='fc-event fc-event-vert ';if(seg.isStart){className+='fc-corner-top ';}if(seg.isEnd){className+='fc-corner-bottom ';}top=timePosition(seg.start,seg.start);bottom=timePosition(seg.start,seg.end);colI=seg.col;levelI=seg.level;forward=seg.forward||0;leftmost=axisWidth+colContentPositions.left(colI*dis+dit);availWidth=axisWidth+colContentPositions.right(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,className);}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=view.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){slotSegBind(event,eventElement,seg);}else{eventElement[0]._fci=i;// for lazySegBind}view.reportEventElement(event,eventElement);}}lazySegBind(slotSegmentContainer,segs,slotSegBind);// 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[0],true)):val;val=hsideCache[key];seg.hsides=val===undefined?(hsideCache[key]=hsides(eventElement[0],true)):val;titleSpan=eventElement.find('span.fc-event-title');if(titleSpan.length){seg.titleTop=titleSpan[0].offsetTop;}}}// set all positions/dimensions at oncefor(i=0;i<segCnt;i++){seg=segs[i];if(eventElement=seg.element){eventElement[0].style.width=seg.outerWidth-seg.hsides+'px';eventElement[0].style.height=(height=seg.outerHeight-seg.vsides)+'px';event=seg.event;if(seg.titleTop!==undefined&&height-seg.titleTop<10){// not enough room for title, put it in the time headereventElement.find('span.fc-event-time').text(formatDate(event.start,view.option('timeFormat'))+' - '+event.title);eventElement.find('span.fc-event-title').remove();}view.trigger('eventAfterRender',event,event,eventElement);}}}functionslotSegHtml(event,seg,className){return"<div class='"+className+event.className.join(' ')+"' style='position:absolute;z-index:8;top:"+seg.top+"px;left:"+seg.left+"px'>"+"<a"+(event.url?" href='"+htmlEscape(event.url)+"'":'')+">"+"<span class='fc-event-bg'></span>"+"<span class='fc-event-time'>"+htmlEscape(formatDates(event.start,event.end,view.option('timeFormat')))+"</span>"+"<span class='fc-event-title'>"+htmlEscape(event.title)+"</span>"+"</a>"+((event.editable||event.editable===undefined&&options.editable)&&!options.disableResizing&&$.fn.resizable?"<div class='ui-resizable-handle ui-resizable-s'>=</div>":'')+"</div>";}functiondaySegBind(event,eventElement,seg){view.eventElementHandlers(event,eventElement);if(event.editable||event.editable===undefined&&options.editable){draggableDayEvent(event,eventElement,seg.isStart);if(seg.isEnd){view.resizableDayEvent(event,eventElement,colWidth);}}}functionslotSegBind(event,eventElement,seg){view.eventElementHandlers(event,eventElement);if(event.editable||event.editable===undefined&&options.editable){vartimeElement=eventElement.find('span.fc-event-time');draggableSlotEvent(event,eventElement,timeElement);if(seg.isEnd){resizableSlotEvent(event,eventElement,timeElement);}}}/* Event Dragging -----------------------------------------------------------------------------*/// when event starts out FULL-DAYfunctiondraggableDayEvent(event,eventElement,isStart){if(!options.disableDragging&&eventElement.draggable){varorigPosition,origWidth,resetElement,allDay=true,matrix;eventElement.draggable({zIndex:9,opacity:view.option('dragOpacity','month'),// use whatever the month view was usingrevertDuration:options.dragRevertDuration,start:function(ev,ui){view.hideEvents(event,eventElement);view.trigger('eventDragStart',eventElement,event,ev,ui);origPosition=eventElement.position();origWidth=eventElement.width();resetElement=function(){if(!allDay){eventElement.width(origWidth).height('').draggable('option','grid',null);allDay=true;}};matrix=buildDayMatrix(function(cell){eventElement.draggable('option','revert',!cell||!cell.rowDelta&&!cell.colDelta);view.clearOverlays();if(cell){if(!cell.row){// on full-daysrenderDayOverlay(matrix,addDays(cloneDate(event.start),cell.colDelta),addDays(exclEndDay(event),cell.colDelta));resetElement();}else{// mouse is over bottom slotsif(isStart&&allDay){// convert event to temporary slot-eventsetOuterHeight(eventElement.width(colWidth-10),// don't use entire widthslotHeight*Math.round((event.end?((event.end-event.start)/MINUTE_MS):options.defaultEventMinutes)/options.slotMinutes));eventElement.draggable('option','grid',[colWidth,1]);allDay=false;}}}},true);matrix.mouse(ev);},drag:function(ev,ui){matrix.mouse(ev);},stop:function(ev,ui){view.trigger('eventDragStop',eventElement,event,ev,ui);view.clearOverlays();varcell=matrix.cell;vardayDelta=dis*(allDay?// can't trust cell.colDelta when using slot grid(cell?cell.colDelta:0):Math.floor((ui.position.left-origPosition.left)/colWidth));if(!cell||!dayDelta&&!cell.rowDelta){// over nothing (has reverted)resetElement();if($.browser.msie){eventElement.css('filter','');// clear IE opacity side-effects}view.showEvents(event,eventElement);}else{eventElement.find('a').removeAttr('href');// prevents safari from visiting the linkview.eventDrop(this,event,dayDelta,allDay?0:// minute deltaMath.round((eventElement.offset().top-bodyContent.offset().top)/slotHeight)*options.slotMinutes+minMinute-(event.start.getHours()*60+event.start.getMinutes()),allDay,ev,ui);}}});}}// when event starts out IN TIMESLOTSfunctiondraggableSlotEvent(event,eventElement,timeElement){if(!options.disableDragging&&eventElement.draggable){varorigPosition,resetElement,prevSlotDelta,slotDelta,allDay=false,matrix;eventElement.draggable({zIndex:9,scroll:false,grid:[colWidth,slotHeight],axis:colCnt==1?'y':false,opacity:view.option('dragOpacity'),revertDuration:options.dragRevertDuration,start:function(ev,ui){view.hideEvents(event,eventElement);view.trigger('eventDragStart',eventElement,event,ev,ui);if($.browser.msie){eventElement.find('span.fc-event-bg').hide();// nested opacities mess up in IE, just hide}origPosition=eventElement.position();resetElement=function(){// convert back to original slot-eventif(allDay){timeElement.css('display','');// show() was causing display=inlineeventElement.draggable('option','grid',[colWidth,slotHeight]);allDay=false;}};prevSlotDelta=0;matrix=buildDayMatrix(function(cell){eventElement.draggable('option','revert',!cell);view.clearOverlays();if(cell){if(!cell.row&&options.allDaySlot){// over full daysif(!allDay){// convert to temporary all-day eventallDay=true;timeElement.hide();eventElement.draggable('option','grid',null);}renderDayOverlay(matrix,addDays(cloneDate(event.start),cell.colDelta),addDays(exclEndDay(event),cell.colDelta));}else{// on slotsresetElement();}}},true);matrix.mouse(ev);},drag:function(ev,ui){slotDelta=Math.round((ui.position.top-origPosition.top)/slotHeight);if(slotDelta!=prevSlotDelta){if(!allDay){// update time headervarminuteDelta=slotDelta*options.slotMinutes,newStart=addMinutes(cloneDate(event.start),minuteDelta),newEnd;if(event.end){newEnd=addMinutes(cloneDate(event.end),minuteDelta);}timeElement.text(formatDates(newStart,newEnd,view.option('timeFormat')));}prevSlotDelta=slotDelta;}matrix.mouse(ev);},stop:function(ev,ui){view.clearOverlays();view.trigger('eventDragStop',eventElement,event,ev,ui);varcell=matrix.cell,dayDelta=dis*(allDay?// can't trust cell.colDelta when using slot grid(cell?cell.colDelta:0):Math.floor((ui.position.left-origPosition.left)/colWidth));if(!cell||!slotDelta&&!dayDelta){resetElement();if($.browser.msie){eventElement.css('filter','')// clear IE opacity side-effects.find('span.fc-event-bg').css('display','');// .show() made display=inline}eventElement.css(origPosition);// sometimes fast drags make event revert to wrong positionview.showEvents(event,eventElement);}else{view.eventDrop(this,event,dayDelta,allDay?0:slotDelta*options.slotMinutes,// minute deltaallDay,ev,ui);}}});}}/* Event Resizing -----------------------------------------------------------------------------*/// for TIMESLOT eventsfunctionresizableSlotEvent(event,eventElement,timeElement){if(!options.disableResizing&&eventElement.resizable){varslotDelta,prevSlotDelta;eventElement.resizable({handles:{s:'div.ui-resizable-s'},grid:slotHeight,start:function(ev,ui){slotDelta=prevSlotDelta=0;view.hideEvents(event,eventElement);if($.browser.msie&&$.browser.version=='6.0'){eventElement.css('overflow','hidden');}eventElement.css('z-index',9);view.trigger('eventResizeStart',this,event,ev,ui);},resize:function(ev,ui){// don't rely on ui.size.height, doesn't take grid into 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(view.eventEnd(event),options.slotMinutes*slotDelta),view.option('timeFormat')));prevSlotDelta=slotDelta;}},stop:function(ev,ui){view.trigger('eventResizeStop',this,event,ev,ui);if(slotDelta){view.eventResize(this,event,0,options.slotMinutes*slotDelta,ev,ui);}else{eventElement.css('z-index',8);view.showEvents(event,eventElement);// BUG: if event was really short, need to put title back in span}}});}}/* Selecting -----------------------------------------------------------------------------*/daySelectionManager=newSelectionManager(view,unselect,function(startDate,endDate,allDay){renderDayOverlay(selectionMatrix,startDate,addDays(cloneDate(endDate),1));},clearSelection);functiondaySelectionMousedown(ev){if(view.option('selectable')){selectionMatrix=buildDayMatrix(function(cell){if(cell){vard=dayColDate(cell.col);daySelectionManager.drag(d,d,true);}else{daySelectionManager.drag();}});documentDragHelp(function(ev){selectionMatrix.mouse(ev);},function(ev){daySelectionManager.dragStop(ev);});daySelectionManager.dragStart(ev);selectionMatrix.mouse(ev);returnfalse;// prevent auto-unselect and text selection}}slotSelectionManager=newSelectionManager(view,unselect,renderSlotSelection,clearSelection);functionslotSelectionMousedown(ev){if(view.option('selectable')){selectionMatrix=buildSlotMatrix(function(cell){if(cell){vard=slotCellDate(cell.row,cell.origCol);slotSelectionManager.drag(d,addMinutes(cloneDate(d),options.slotMinutes),false);}else{slotSelectionManager.drag();}});documentDragHelp(function(ev){selectionMatrix.mouse(ev);},function(ev){slotSelectionManager.dragStop(ev);});slotSelectionManager.dragStart(ev);selectionMatrix.mouse(ev);returnfalse;// prevent auto-unselect and text selection}}documentUnselectAuto(view,unselect);this.select=function(start,end,allDay){if(allDay){if(options.allDaySlot){if(!end){end=cloneDate(start);}selectionMatrix=buildDayMatrix();daySelectionManager.select(start,end,allDay);}}else{if(!end){end=addMinutes(cloneDate(start),options.slotMinutes);}selectionMatrix=buildSlotMatrix();slotSelectionManager.select(start,end,allDay);}};functionunselect(){slotSelectionManager.unselect();daySelectionManager.unselect();}this.unselect=unselect;/* Selecting drawing utils -----------------------------------------------------------------------------*/functionrenderSlotSelection(startDate,endDate){varhelperOption=view.option('selectHelper');if(helperOption){varcol=dayDiff(startDate,view.visStart);if(col>=0&&col<colCnt){// only works when times are on same dayvarrect=selectionMatrix.rect(0,col*dis+dit,1,col*dis+dit+1,bodyContent);// only for horizontal coordsvartop=timePosition(startDate,startDate);varbottom=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)){varhelperRes=helperOption(startDate,endDate);if(helperRes){rect.position='absolute';rect.zIndex=8;selectionHelper=$(helperRes).css(rect).appendTo(bodyContent);}}else{selectionHelper=$(slotSegHtml({title:'',start:startDate,end:endDate,className:[],editable:false},rect,'fc-event fc-event-vert fc-corner-top fc-corner-bottom '));if($.browser.msie){selectionHelper.find('span.fc-event-bg').hide();// nested opacities mess up in IE, just hide}selectionHelper.css('opacity',view.option('dragOpacity'));}if(selectionHelper){slotBind(selectionHelper);bodyContent.append(selectionHelper);setOuterWidth(selectionHelper,rect.width,true);// needs to be after appendedsetOuterHeight(selectionHelper,rect.height,true);}}}}else{renderSlotOverlay(selectionMatrix,startDate,endDate);}}functionclearSelection(){clearOverlays();if(selectionHelper){selectionHelper.remove();selectionHelper=null;}}/* Semi-transparent Overlay Helpers -----------------------------------------------------*/functionrenderDayOverlay(matrix,startDate,endDate){varstartCol,endCol;if(rtl){startCol=dayDiff(endDate,view.visStart)*dis+dit+1;endCol=dayDiff(startDate,view.visStart)*dis+dit+1;}else{startCol=dayDiff(startDate,view.visStart);endCol=dayDiff(endDate,view.visStart);}startCol=Math.max(0,startCol);endCol=Math.min(colCnt,endCol);if(startCol<endCol){varrect=matrix.rect(0,startCol,1,endCol,head);dayBind(view.renderOverlay(rect,head));}}functionrenderSlotOverlay(matrix,overlayStart,overlayEnd){vardayStart=cloneDate(view.visStart);vardayEnd=addDays(cloneDate(dayStart),1);for(vari=0;i<colCnt;i++){varstretchStart=newDate(Math.max(dayStart,overlayStart));varstretchEnd=newDate(Math.min(dayEnd,overlayEnd));if(stretchStart<stretchEnd){varrect=matrix.rect(0,i*dis+dit,1,i*dis+dit+1,bodyContent);// only use it for horizontal coordsvartop=timePosition(dayStart,stretchStart);varbottom=timePosition(dayStart,stretchEnd);rect.top=top;rect.height=bottom-top;slotBind(view.renderOverlay(rect,bodyContent));}addDays(dayStart,1);addDays(dayEnd,1);}}functionclearOverlays(){view.clearOverlays();}/* Coordinate Utilities -----------------------------------------------------------------------------*/// get the Y coordinate of the given time on the given day (both Date objects)functiontimePosition(day,time){// both date objects. day holds 00:00 of current dayday=cloneDate(day,true);if(time<addMinutes(cloneDate(day),minMinute)){return0;}if(time>=addMinutes(cloneDate(day),maxMinute)){returnbodyContent.height();}varslotMinutes=options.slotMinutes,minutes=time.getHours()*60+time.getMinutes()-minMinute,slotI=Math.floor(minutes/slotMinutes),slotTop=slotTopCache[slotI];if(slotTop===undefined){slotTop=slotTopCache[slotI]=body.find('tr:eq('+slotI+') td div')[0].offsetTop;}returnMath.max(0,Math.round(slotTop-1+slotHeight*((minutes%slotMinutes)/slotMinutes)));}functionbuildDayMatrix(changeCallback,includeSlotArea){varrowElements=options.allDaySlot?head.find('td'):$([]);if(includeSlotArea){rowElements=rowElements.add(body);}returnnewHoverMatrix(rowElements,bg.find('td'),changeCallback);}functionbuildSlotMatrix(changeCallback){returnnewHoverMatrix(bodyTable.find('td'),bg.find('td'),changeCallback);}/* Date Utilities ----------------------------------------------------*/functionslotEventEnd(event){if(event.end){returncloneDate(event.end);}else{returnaddMinutes(cloneDate(event.start),options.defaultEventMinutes);}}functiondayOfWeekCol(dayOfWeek){return((dayOfWeek-Math.max(firstDay,nwe)+colCnt)%colCnt)*dis+dit;}// generating dates from cell row & columnsfunctiondayColDate(col){returnaddDays(cloneDate(view.visStart),col*dis+dit);}functionslotCellDate(row,col){vard=dayColDate(col);addMinutes(d,minMinute+row*options.slotMinutes);returnd;}}// count the number of colliding, higher-level segments (for event squishing)functioncountForwardSegs(levels){vari,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);}}}}}/* Methods & Utilities for All Views -----------------------------------------------------------------------------*/varviewMethods={/* * Objects inheriting these methods must implement the following properties/methods: * - title * - start * - end * - visStart * - visEnd * - defaultEventEnd(event) * - render(events) * - rerenderEvents() * * * z-index reservations: * 3 - day-overlay * 8 - events * 9 - dragging/resizing events * */init:function(element,options){this.element=element;this.options=options;this.eventsByID={};this.eventElements=[];this.eventElementsByID={};this.usedOverlays=[];this.unusedOverlays=[];},// triggers an event handler, always append view as last argtrigger:function(name,thisObj){if(this.options[name]){returnthis.options[name].apply(thisObj||this,Array.prototype.slice.call(arguments,2).concat([this]));}},// returns a Date object for an event's endeventEnd:function(event){returnevent.end?cloneDate(event.end):this.defaultEventEnd(event);// TODO: make sure always using copies},// report when view receives new eventsreportEvents:function(events){// events are already normalized at this pointvari,len=events.length,event,eventsByID=this.eventsByID={};for(i=0;i<len;i++){event=events[i];if(eventsByID[event._id]){eventsByID[event._id].push(event);}else{eventsByID[event._id]=[event];}}},// report when view creates an element for an eventreportEventElement:function(event,element){this.eventElements.push(element);vareventElementsByID=this.eventElementsByID;if(eventElementsByID[event._id]){eventElementsByID[event._id].push(element);}else{eventElementsByID[event._id]=[element];}},// event element manipulation_clearEvents:function(){// only resets hashesthis.eventElements=[];this.eventElementsByID={};},showEvents:function(event,exceptElement){this._eee(event,exceptElement,'show');},hideEvents:function(event,exceptElement){this._eee(event,exceptElement,'hide');},_eee:function(event,exceptElement,funcName){// event-element-eachvarelements=this.eventElementsByID[event._id],i,len=elements.length;for(i=0;i<len;i++){if(elements[i][0]!=exceptElement[0]){// AHAHAHAHAHAHAHAHelements[i][funcName]();}}},// event modification reportingeventDrop:function(e,event,dayDelta,minuteDelta,allDay,ev,ui){varview=this,oldAllDay=event.allDay,eventId=event._id;view.moveEvents(view.eventsByID[eventId],dayDelta,minuteDelta,allDay);view.trigger('eventDrop',e,event,dayDelta,minuteDelta,allDay,function(){// TODO: change docs// TODO: investigate cases where this inverse technique might not workview.moveEvents(view.eventsByID[eventId],-dayDelta,-minuteDelta,oldAllDay);view.rerenderEvents();},ev,ui);view.eventsChanged=true;view.rerenderEvents(eventId);},eventResize:function(e,event,dayDelta,minuteDelta,ev,ui){varview=this,eventId=event._id;view.elongateEvents(view.eventsByID[eventId],dayDelta,minuteDelta);view.trigger('eventResize',e,event,dayDelta,minuteDelta,function(){// TODO: investigate cases where this inverse technique might not workview.elongateEvents(view.eventsByID[eventId],-dayDelta,-minuteDelta);view.rerenderEvents();},ev,ui);view.eventsChanged=true;view.rerenderEvents(eventId);},// event modificationmoveEvents:function(events,dayDelta,minuteDelta,allDay){minuteDelta=minuteDelta||0;for(vare,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,this.options);}},elongateEvents:function(events,dayDelta,minuteDelta){minuteDelta=minuteDelta||0;for(vare,len=events.length,i=0;i<len;i++){e=events[i];e.end=addMinutes(addDays(this.eventEnd(e),dayDelta,true),minuteDelta);normalizeEvent(e,this.options);}},// semi-transparent overlay (while dragging or selecting)renderOverlay:function(rect,parent){vare=this.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);}this.usedOverlays.push(e.css(rect).show());returne;},clearOverlays:function(){vare;while(e=this.usedOverlays.shift()){this.unusedOverlays.push(e.hide().unbind());}},// common horizontal event resizingresizableDayEvent:function(event,eventElement,colWidth){varview=this;if(!view.options.disableResizing&&eventElement.resizable){eventElement.resizable({handles:view.options.isRTL?{w:'div.ui-resizable-w'}:{e:'div.ui-resizable-e'},grid:colWidth,minWidth:colWidth/2,// need this or else IE throws errors when too smallcontainment:view.element.parent().parent(),// the main element...// ... a fix. wouldn't allow extending to last column in agenda views (jq ui bug?)start:function(ev,ui){eventElement.css('z-index',9);view.hideEvents(event,eventElement);view.trigger('eventResizeStart',this,event,ev,ui);},stop:function(ev,ui){view.trigger('eventResizeStop',this,event,ev,ui);// ui.size.width wasn't working with grid correctly, use .width()vardayDelta=Math.round((eventElement.width()-ui.originalSize.width)/colWidth);if(dayDelta){view.eventResize(this,event,dayDelta,0,ev,ui);}else{eventElement.css('z-index',8);view.showEvents(event,eventElement);}}});}},// attaches eventClick, eventMouseover, eventMouseouteventElementHandlers:function(event,eventElement){varview=this;eventElement.click(function(ev){if(!eventElement.hasClass('ui-draggable-dragging')&&!eventElement.hasClass('ui-resizable-resizing')){returnview.trigger('eventClick',this,event,ev);}}).hover(function(ev){view.trigger('eventMouseover',this,event,ev);},function(ev){view.trigger('eventMouseout',this,event,ev);});},// get a property from the 'options' object, using smart view namingoption:function(name,viewName){varv=this.options[name];if(typeofv=='object'){returnsmartProperty(v,viewName||this.name);}returnv;},// event rendering utilitiessliceSegs:function(events,visEventEnds,start,end){varsegs=[],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});}}returnsegs.sort(segCmp);}};functionlazySegBind(container,segs,bindHandlers){container.unbind('mouseover').mouseover(function(ev){varparent=ev.target,e,i,seg;while(parent!=this){e=parent;parent=parent.parentNode;}if((i=e._fci)!==undefined){e._fci=undefined;seg=segs[i];bindHandlers(seg.event,seg.element,seg);$(ev.target).trigger(ev);}ev.stopPropagation();});}// event rendering calculation utilitiesfunctionstackSegs(segs){varlevels=[],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];}}returnlevels;}functionsegCmp(a,b){return(b.msLength-a.msLength)*100+(a.event.start-b.event.start);}functionsegsCollide(seg1,seg2){returnseg1.end>seg2.start&&seg1.start<seg2.end;}functionSelectionManager(view,initFunc,displayFunc,clearFunc){vart=this;varselected=false;varinitialElement;varinitialRange;varstart;varend;varallDay;t.dragStart=function(ev){initFunc();start=end=undefined;initialRange=undefined;initialElement=ev.currentTarget;};t.drag=function(currentStart,currentEnd,currentAllDay){if(currentStart){varrange=[currentStart,currentEnd];if(!initialRange){initialRange=range;}vardates=initialRange.concat(range).sort(cmp);start=dates[0];end=dates[3];allDay=currentAllDay;clearFunc();displayFunc(cloneDate(start),cloneDate(end),allDay);}else{// called with no argumentsstart=end=undefined;clearFunc();}};t.dragStop=function(ev){if(start){if(+initialRange[0]==+start&&+initialRange[1]==+end){view.trigger('dayClick',initialElement,start,allDay,ev);}_select();}};t.select=function(newStart,newEnd,newAllDay){initFunc();start=newStart;end=newEnd;allDay=newAllDay;displayFunc(cloneDate(start),cloneDate(end),allDay);_select();};function_select(){// just set the selected flag, and triggerselected=true;view.trigger('select',view,start,end,allDay);}functionunselect(){if(selected){selected=false;start=end=undefined;clearFunc();view.trigger('unselect',view);}}t.unselect=unselect;}functiondocumentDragHelp(mousemove,mouseup){function_mouseup(ev){mouseup(ev);$(document).unbind('mousemove',mousemove).unbind('mouseup',_mouseup);}$(document).mousemove(mousemove).mouseup(_mouseup);}functiondocumentUnselectAuto(view,unselectFunc){if(view.option('selectable')&&view.option('unselectAuto')){$(document).mousedown(function(ev){varignore=view.option('unselectCancel');if(ignore){if($(ev.target).parents(ignore).length){// could be optimized to stop after first matchreturn;}}unselectFunc();});}}/* Date Math -----------------------------------------------------------------------------*/varDAY_MS=86400000,HOUR_MS=3600000,MINUTE_MS=60000;functionaddYears(d,n,keepTime){d.setFullYear(d.getFullYear()+n);if(!keepTime){clearTime(d);}returnd;}functionaddMonths(d,n,keepTime){// prevents day overflow/underflowif(+d){// prevent infinite looping on invalid datesvarm=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));}}returnd;}functionaddDays(d,n,keepTime){// deals with daylight savingsif(+d){vardd=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);}returnd;}fc.addDays=addDays;functionfixDate(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);}}}functionaddMinutes(d,n){d.setMinutes(d.getMinutes()+n);returnd;}functionclearTime(d){d.setHours(0);d.setMinutes(0);d.setSeconds(0);d.setMilliseconds(0);returnd;}functioncloneDate(d,dontKeepTime){if(dontKeepTime){returnclearTime(newDate(+d));}returnnewDate(+d);}fc.cloneDate=cloneDate;functionzeroDate(){// returns a Date with time 00:00:00 and dateOfMonth=1vari=0,d;do{d=newDate(1970,i++,1);}while(d.getHours());// != 0returnd;}functionskipWeekend(date,inc,excl){inc=inc||1;while(!date.getDay()||(excl&&date.getDay()==1||!excl&&date.getDay()==6)){addDays(date,inc);}returndate;}functiondayDiff(d1,d2){// d1 - d2returnMath.round((cloneDate(d1,true)-cloneDate(d2,true))/DAY_MS);}/* Date Parsing -----------------------------------------------------------------------------*/varparseDate=fc.parseDate=function(s){if(typeofs=='object'){// already a Date objectreturns;}if(typeofs=='number'){// a UNIX timestampreturnnewDate(s*1000);}if(typeofs=='string'){if(s.match(/^\d+$/)){// a UNIX timestampreturnnewDate(parseInt(s)*1000);}returnparseISO8601(s,true)||(s?newDate(s):null);}// TODO: never return invalid dates (like from new Date(<string>)), return null insteadreturnnull;};varparseISO8601=fc.parseISO8601=function(s,ignoreTimezone){// derived from http://delete.me.uk/2005/03/iso8601.html// TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.htmlvarm=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){returnnull;}vardate=newDate(m[1],0,1),check=newDate(m[1],0,1,9,0),offset=0;if(m[3]){date.setMonth(m[3]-1);check.setMonth(m[3]-1);}if(m[5]){date.setDate(m[5]);check.setDate(m[5]);}fixDate(date,check);if(m[7]){date.setHours(m[7]);}if(m[8]){date.setMinutes(m[8]);}if(m[10]){date.setSeconds(m[10]);}if(m[12]){date.setMilliseconds(Number("0."+m[12])*1000);}fixDate(date,check);if(!ignoreTimezone){if(m[14]){offset=Number(m[16])*60+Number(m[17]);offset*=m[15]=='-'?1:-1;}offset-=date.getTimezoneOffset();}returnnewDate(+date+(offset*60*1000));};varparseTime=fc.parseTime=function(s){// returns minutes since start of dayif(typeofs=='number'){// an hourreturns*60;}if(typeofs=='object'){// a Date objectreturns.getHours()*60+s.getMinutes();}varm=s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);if(m){varh=parseInt(m[1]);if(m[3]){h%=12;if(m[3].toLowerCase().charAt(0)=='p'){h+=12;}}returnh*60+(m[2]?parseInt(m[2]):0);}};/* Date Formatting -----------------------------------------------------------------------------*/varformatDate=fc.formatDate=function(date,format,options){returnformatDates(date,null,format,options);};varformatDates=fc.formatDates=function(date1,date2,format,options){options=options||defaults;vardate=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;}}}elseif(c=='('){for(i2=i+1;i2<len;i2++){if(format.charAt(i2)==')'){varsubres=formatDate(date,format.substring(i+1,i2),options);if(parseInt(subres.replace(/\D/,''))){res+=subres;}i=i2;break;}}}elseif(c=='['){for(i2=i+1;i2<len;i2++){if(format.charAt(i2)==']'){varsubformat=format.substring(i+1,i2);varsubres=formatDate(date,subformat,options);if(subres!=formatDate(otherDate,subformat,options)){res+=subres;}i=i2;break;}}}elseif(c=='{'){date=date2;otherDate=date1;}elseif(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;}}}}returnres;};vardateFormatters={s:function(d){returnd.getSeconds()},ss:function(d){returnzeroPad(d.getSeconds())},m:function(d){returnd.getMinutes()},mm:function(d){returnzeroPad(d.getMinutes())},h:function(d){returnd.getHours()%12||12},hh:function(d){returnzeroPad(d.getHours()%12||12)},H:function(d){returnd.getHours()},HH:function(d){returnzeroPad(d.getHours())},d:function(d){returnd.getDate()},dd:function(d){returnzeroPad(d.getDate())},ddd:function(d,o){returno.dayNamesShort[d.getDay()]},dddd:function(d,o){returno.dayNames[d.getDay()]},M:function(d){returnd.getMonth()+1},MM:function(d){returnzeroPad(d.getMonth()+1)},MMM:function(d,o){returno.monthNamesShort[d.getMonth()]},MMMM:function(d,o){returno.monthNames[d.getMonth()]},yy:function(d){return(d.getFullYear()+'').substring(2)},yyyy:function(d){returnd.getFullYear()},t:function(d){returnd.getHours()<12?'a':'p'},tt:function(d){returnd.getHours()<12?'am':'pm'},T:function(d){returnd.getHours()<12?'A':'P'},TT:function(d){returnd.getHours()<12?'AM':'PM'},u:function(d){returnformatDate(d,"yyyy-MM-dd'T'HH:mm:ss'Z'")},S:function(d){vardate=d.getDate();if(date>10&&date<20){return'th';}return['st','nd','rd'][date%10-1]||'th';}};/* Element Dimensions -----------------------------------------------------------------------------*/functionsetOuterWidth(element,width,includeMargins){element.each(function(i,_element){_element.style.width=width-hsides(_element,includeMargins)+'px';});}functionsetOuterHeight(element,height,includeMargins){element.each(function(i,_element){_element.style.height=height-vsides(_element,includeMargins)+'px';});}functionhsides(_element,includeMargins){return(parseFloat(jQuery.curCSS(_element,'paddingLeft',true))||0)+(parseFloat(jQuery.curCSS(_element,'paddingRight',true))||0)+(parseFloat(jQuery.curCSS(_element,'borderLeftWidth',true))||0)+(parseFloat(jQuery.curCSS(_element,'borderRightWidth',true))||0)+(includeMargins?hmargins(_element):0);}functionhmargins(_element){return(parseFloat(jQuery.curCSS(_element,'marginLeft',true))||0)+(parseFloat(jQuery.curCSS(_element,'marginRight',true))||0);}functionvsides(_element,includeMargins){return(parseFloat(jQuery.curCSS(_element,'paddingTop',true))||0)+(parseFloat(jQuery.curCSS(_element,'paddingBottom',true))||0)+(parseFloat(jQuery.curCSS(_element,'borderTopWidth',true))||0)+(parseFloat(jQuery.curCSS(_element,'borderBottomWidth',true))||0)+(includeMargins?vmargins(_element):0);}functionvmargins(_element){return(parseFloat(jQuery.curCSS(_element,'marginTop',true))||0)+(parseFloat(jQuery.curCSS(_element,'marginBottom',true))||0);}functionsetMinHeight(element,h){h=typeofh=='number'?h+'px':h;element[0].style.cssText+=';min-height:'+h+';_height:'+h;}/* Position Calculation -----------------------------------------------------------------------------*/// nasty bugs in opera 9.25// position()'s top returning incorrectly with TR/TD or elements within TDvartopBug;functiontopCorrect(tr){// tr/th/td or anything elseif(topBug!==false){varcell;if(tr.is('th,td')){tr=(cell=tr).parent();}if(topBug===undefined&&tr.is('tr')){topBug=tr.position().top!=tr.children().position().top;}if(topBug){returntr.parent().position().top+(cell?tr.position().top-cell.position().top:0);}}return0;}/* Hover Matrix -----------------------------------------------------------------------------*/functionHoverMatrix(rowElements,colElements,changeCallback){vart=this,tops=[],lefts=[],origRow,origCol,currRow,currCol,e;$.each(rowElements,function(i,_e){e=$(_e);tops.push(e.offset().top+topCorrect(e));});tops.push(tops[tops.length-1]+e.outerHeight());$.each(colElements,function(i,_e){e=$(_e);lefts.push(e.offset().left);});lefts.push(lefts[lefts.length-1]+e.outerWidth());t.mouse=function(ev){varx=ev.pageX;vary=ev.pageY;varr,c;for(r=0;r<tops.length&&y>=tops[r];r++){}for(c=0;c<lefts.length&&x>=lefts[c];c++){}r=r>=tops.length?-1:r-1;c=c>=lefts.length?-1:c-1;if(r!=currRow||c!=currCol){currRow=r;currCol=c;if(r==-1||c==-1){t.cell=null;}else{if(origRow===undefined){origRow=r;origCol=c;}t.cell={row:r,col:c,top:tops[r],left:lefts[c],width:lefts[c+1]-lefts[c],height:tops[r+1]-tops[r],origRow:origRow,origCol:origCol,isOrig:r==origRow&&c==origCol,rowDelta:r-origRow,colDelta:c-origCol};}changeCallback(t.cell);}};t.rect=function(row0,col0,row1,col1,originElement){// row1,col1 are exclusivevarorigin=originElement.offset();return{top:tops[row0]-origin.top,left:lefts[col0]-origin.left,width:lefts[col1]-lefts[col0],height:tops[row1]-tops[row0]};};}/* Misc Utils -----------------------------------------------------------------------------*/varundefined,dayIDs=['sun','mon','tue','wed','thu','fri','sat'];functionzeroPad(n){return(n<10?'0':'')+n;}functionsmartProperty(obj,name){// get a camel-cased/namespaced property of an objectif(obj[name]!==undefined){returnobj[name];}varparts=name.split(/(?=[A-Z])/),i=parts.length-1,res;for(;i>=0;i--){res=obj[parts[i].toLowerCase()];if(res!==undefined){returnres;}}returnobj[''];}functionhtmlEscape(s){returns.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/'/g,''').replace(/"/g,'"');}functionHorizontalPositionCache(getElement){vart=this,elements={},lefts={},rights={};functione(i){returnelements[i]=elements[i]||getElement(i);}t.left=function(i){returnlefts[i]=lefts[i]===undefined?e(i).position().left:lefts[i];};t.right=function(i){returnrights[i]=rights[i]===undefined?t.left(i)+e(i).width():rights[i];};t.clear=function(){elements={};lefts={};rights={};};}functioncssKey(_element){return_element.id+'/'+_element.className+'/'+_element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig,'');}functioncmp(a,b){returna-b;}functionexclEndDay(event){if(event.end){return_exclEndDay(event.end,event.allDay);}else{returnaddDays(cloneDate(event.start),1);}}function_exclEndDay(end,allDay){end=cloneDate(end);returnallDay||end.getHours()||end.getMinutes()?addDays(end,1):end;}functiondisableTextSelection(element){element.attr('unselectable','on').css('MozUserSelect','none').bind('selectstart.ui',function(){returnfalse;});}/* function enableTextSelection(element) { element .attr('unselectable', 'off') .css('MozUserSelect', '') .unbind('selectstart.ui'); } */})(jQuery);