PageSourceSearch

https://minduu.fi/static/57/js/fullcalendar/fullcalendar.min.js

js minduu.fi collected 2026-10-07 11:20:52 UTC 231,774 bytes, 2,482 lines download raw bytes

1/*!
2 * FullCalendar v2.7.1
3 * Docs & License: http://fullcalendar.io/
4 * (c) 2016 Adam Shaw
5 */
6!function(a){"function"==typeof define&&define.amd?define(["jquery","moment"],a):"object"==typeof exports?// Node/CommonJS
7module.exports=a(require("jquery"),require("moment")):a(jQuery,moment)}(function(a,b){
8// Merges an array of option objects into a single object
9function c(a){return U(a,Va)}
10// Given options specified for the calendar's constructor, massages any legacy options into a non-legacy form.
11// Converts View-Option-Hashes into the View-Specific-Options format.
12function d(b){var c,d={views:b.views||{}};
13// iterate through all option override properties (except `views`)
14return a.each(b,function(b,e){"views"!=b&&(
15// could the value be a legacy View-Option-Hash?
16a.isPlainObject(e)&&!/(time|duration|interval)$/i.test(b)&&-1==a.inArray(b,Va)?(c=null,a.each(e,function(a,e){/^(month|week|day|default|basic(Week|Day)?|agenda(Week|Day)?)$/.test(a)?(d.views[a]||(d.views[a]={}),d.views[a][b]=e):(c||(c={}),c[a]=e)}),c&&(d[b]=c)):d[b]=e)}),d}/* FullCalendar-specific DOM Utilities
17----------------------------------------------------------------------------------------------------------------------*/
18// Given the scrollbar widths of some other container, create borders/margins on rowEls in order to match the left
19// and right space that was offset by the scrollbars. A 1-pixel border first, then margin beyond that.
20function e(a,b){b.left&&a.css({"border-left-width":1,"margin-left":b.left-1}),b.right&&a.css({"border-right-width":1,"margin-right":b.right-1})}
21// Undoes compensateScroll and restores all borders/margins
22function f(a){a.css({"margin-left":"","margin-right":"","border-left-width":"","border-right-width":""})}
23// Make the mouse cursor express that an event is not allowed in the current area
24function g(){a("body").addClass("fc-not-allowed")}
25// Returns the mouse cursor to its original look
26function h(){a("body").removeClass("fc-not-allowed")}
27// Given a total available height to fill, have `els` (essentially child rows) expand to accomodate.
28// By default, all elements that are shorter than the recommended height are expanded uniformly, not considering
29// any other els that are already too tall. if `shouldRedistribute` is on, it considers these tall rows and 
30// reduces the available height.
31function i(b,c,d){
32// *FLOORING NOTE*: we floor in certain places because zoom can give inaccurate floating-point dimensions,
33// and it is better to be shorter than taller, to avoid creating unnecessary scrollbars.
34var e=Math.floor(c/b.length),f=Math.floor(c-e*(b.length-1)),g=[],h=[],i=[],k=0;j(b),// give all elements their natural height
35// find elements that are below the recommended height (expandable).
36// important to query for heights in a single first pass (to avoid reflow oscillation).
37b.each(function(c,d){var j=c===b.length-1?f:e,l=a(d).outerHeight(!0);j>l?(g.push(d),h.push(l),i.push(a(d).height())):
38// this element stretches past recommended height (non-expandable). mark the space as occupied.
39k+=l}),
40// readjust the recommended height to only consider the height available to non-maxed-out rows.
41d&&(c-=k,e=Math.floor(c/g.length),f=Math.floor(c-e*(g.length-1))),
42// assign heights to all expandable elements
43a(g).each(function(b,c){var d=b===g.length-1?f:e,j=h[b],k=i[b],l=d-(j-k);// subtract the margin/padding
44d>j&&// we check this again because redistribution might have changed things
45a(c).height(l)})}
46// Undoes distrubuteHeight, restoring all els to their natural height
47function j(a){a.height("")}
48// Given `els`, a jQuery set of <td> cells, find the cell with the largest natural width and set the widths of all the
49// cells to be that width.
50// PREREQUISITE: if you want a cell to take up width, it needs to have a single inner element w/ display:inline
51function k(b){var c=0;// sometimes not accurate of width the text needs to stay on one line. insurance
52return b.find("> span").each(function(b,d){var e=a(d).outerWidth();e>c&&(c=e)}),c++,b.width(c),c}
53// Given one element that resides inside another,
54// Subtracts the height of the inner element from the outer element.
55function l(a,b){var c,d=a.add(b);// undo hack
56// effin' IE8/9/10/11 sometimes returns 0 for dimensions. this weird hack was the only thing that worked
57// grab the dimensions
58return d.css({position:"relative",// cause a reflow, which will force fresh dimension recalculation
59left:-1}),c=a.outerHeight()-b.outerHeight(),d.css({position:"",left:""}),c}
60// borrowed from https://github.com/jquery/jquery-ui/blob/1.11.0
60/ui/core.js#L51
61function m(b){var c=b.css("position"),d=b.parents().filter(function(){var b=a(this);return/(auto|scroll)/.test(b.css("overflow")+b.css("overflow-y")+b.css("overflow-x"))}).eq(0);return"fixed"!==c&&d.length?d:a(b[0].ownerDocument||document)}
62// Queries the outer bounding area of a jQuery element.
63// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
64// Origin is optional.
65function n(a,b){var c=a.offset(),d=c.left-(b?b.left:0),e=c.top-(b?b.top:0);return{left:d,right:d+a.outerWidth(),top:e,bottom:e+a.outerHeight()}}
66// Queries the area within the margin/border/scrollbars of a jQuery element. Does not go within the padding.
67// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
68// Origin is optional.
69// NOTE: should use clientLeft/clientTop, but very unreliable cross-browser.
70function o(a,b){var c=a.offset(),d=q(a),e=c.left+t(a,"border-left-width")+d.left-(b?b.left:0),f=c.top+t(a,"border-top-width")+d.top-(b?b.top:0);return{left:e,right:e+a[0].clientWidth,// clientWidth includes padding but NOT scrollbars
71top:f,bottom:f+a[0].clientHeight}}
72// Queries the area within the margin/border/padding of a jQuery element. Assumed not to have scrollbars.
73// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
74// Origin is optional.
75function p(a,b){var c=a.offset(),d=c.left+t(a,"border-left-width")+t(a,"padding-left")-(b?b.left:0),e=c.top+t(a,"border-top-width")+t(a,"padding-top")-(b?b.top:0);return{left:d,right:d+a.width(),top:e,bottom:e+a.height()}}
76// Returns the computed left/right/top/bottom scrollbar widths for the given jQuery element.
77// NOTE: should use clientLeft/clientTop, but very unreliable cross-browser.
78function q(a){var b=a.innerWidth()-a[0].clientWidth,c={left:0,right:0,top:0,bottom:a.innerHeight()-a[0].clientHeight};// is the scrollbar on the left side?
79return r()&&"rtl"==a.css("direction")?c.left=b:c.right=b,c}function r(){// responsible for caching the computation
80return null===Wa&&(Wa=s()),Wa}function s(){// creates an offscreen test element, then removes it
81var b=a("<div><div/></div>").css({position:"absolute",top:-1e3,left:0,border:0,padding:0,overflow:"scroll",direction:"rtl"}).appendTo("body"),c=b.children(),d=c.offset().left>b.offset().left;// is the inner div shifted to accommodate a left scrollbar?
82return b.remove(),d}
83// Retrieves a jQuery element's computed CSS value as a floating-point number.
84// If the queried value is non-numeric (ex: IE can return "medium" for border width), will just return zero.
85function t(a,b){return parseFloat(a.css(b))||0}
86// Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac)
87function u(a){return 1==a.which&&!a.ctrlKey}function v(a){if(void 0!==a.pageX)return a.pageX;var b=a.originalEvent.touches;return b?b[0].pageX:void 0}function w(a){if(void 0!==a.pageY)return a.pageY;var b=a.originalEvent.touches;return b?b[0].pageY:void 0}function x(a){return/^touch/.test(a.type)}function y(a){a.addClass("fc-unselectable").on("selectstart",z)}
88// Stops a mouse/touch event from doing it's native browser action
89function z(a){a.preventDefault()}
90// Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false
91function A(a,b){var c={left:Math.max(a.left,b.left),right:Math.min(a.right,b.right),top:Math.max(a.top,b.top),bottom:Math.min(a.bottom,b.bottom)};return c.left<c.right&&c.top<c.bottom?c:!1}
92// Returns a new point that will have been moved to reside within the given rectangle
93function B(a,b){return{left:Math.min(Math.max(a.left,b.left),b.right),top:Math.min(Math.max(a.top,b.top),b.bottom)}}
94// Returns a point that is the center of the given rectangle
95function C(a){return{left:(a.left+a.right)/2,top:(a.top+a.bottom)/2}}
96// Subtracts point2's coordinates from point1's coordinates, returning a delta
97function D(a,b){return{left:a.left-b.left,top:a.top-b.top}}function E(b){var c,d,e=[],f=[];for("string"==typeof b?f=b.split(/\s*,\s*/):"function"==typeof b?f=[b]:a.isArray(b)&&(f=b),c=0;c<f.length;c++)d=f[c],"string"==typeof d?e.push("-"==d.charAt(0)?{field:d.substring(1),order:-1}:{field:d,order:1}):"function"==typeof d&&e.push({func:d});return e}function F(a,b,c){var d,e;for(d=0;d<c.length;d++)if(e=G(a,b,c[d]))return e;return 0}function G(a,b,c){return c.func?c.func(a,b):H(a[c.field],b[c.field])*(c.order||1)}function H(b,c){return b||c?null==c?-1:null==b?1:"string"===a.type(b)||"string"===a.type(c)?String(b).localeCompare(String(c)):b-c:0}/* FullCalendar-specific Misc Utilities
98----------------------------------------------------------------------------------------------------------------------*/
99// Computes the intersection of the two ranges. Returns undefined if no intersection.
100// Expects all dates to be normalized to the same timezone beforehand.
101// TODO: move to date section?
102function I(a,b){var c,d,e,f,g=a.start,h=a.end,i=b.start,j=b.end;// in bounds at all?
103return h>i&&j>g?(g>=i?(c=g.clone(),e=!0):(c=i.clone(),e=!1),j>=h?(d=h.clone(),f=!0):(d=j.clone(),f=!1),{start:c,end:d,isStart:e,isEnd:f}):void 0}
104// Diffs the two moments into a Duration where full-days are recorded first, then the remaining time.
105// Moments will have their timezones normalized.
106function J(a,c){return b.duration({days:a.clone().stripTime().diff(c.clone().stripTime(),"days"),ms:a.time()-c.time()})}
107// Diffs the two moments via their start-of-day (regardless of timezone). Produces whole-day durations.
108function K(a,c){return b.duration({days:a.clone().stripTime().diff(c.clone().stripTime(),"days")})}
109// Diffs two moments, producing a duration, made of a whole-unit-increment of the given unit. Uses rounding.
110function L(a,c,d){// returnFloat=true
111return b.duration(Math.round(a.diff(c,d,!0)),d)}
112// Computes the unit name of the largest whole-unit period of time.
113// For example, 48 hours will be "days" whereas 49 hours will be "hours".
114// Accepts start/end, a range object, or an original duration object.
115function M(a,b){var c,d,e;for(c=0;c<Ya.length&&(d=Ya[c],e=N(d,a,b),!(e>=1&&fa(e)));c++);return d}
116// Computes the number of units (like "hours") in the given range.
117// Range can be a {start,end} object, separate start/end args, or a Duration.
118// Results are based on Moment's .as() and .diff() methods, so results can depend on internal handling
119// of month-diffing logic (which tends to vary from version to version).
120function N(a,c,d){return null!=d?d.diff(c,a,!0):b.isDuration(c)?c.as(a):c.end.diff(c.start,a,!0)}
121// Intelligently divides a range (specified by a start/end params) by a duration
122function O(a,b,c){var d;return R(c)?(b-a)/c:(d=c.asMonths(),Math.abs(d)>=1&&fa(d)?b.diff(a,"months",!0)/d:b.diff(a,"days",!0)/c.asDays())}
123// Intelligently divides one duration by another
124function P(a,b){var c,d;return R(a)||R(b)?a/b:(c=a.asMonths(),d=b.asMonths(),Math.abs(c)>=1&&fa(c)&&Math.abs(d)>=1&&fa(d)?c/d:a.asDays()/b.asDays())}
125// Intelligently multiplies a duration by a number
126function Q(a,c){var d;
126return R(a)?b.duration(a*c):(d=a.asMonths(),Math.abs(d)>=1&&fa(d)?b.duration({months:d*c}):b.duration({days:a.asDays()*c}))}
127// Returns a boolean about whether the given duration has any time parts (hours/minutes/seconds/ms)
128function R(a){return Boolean(a.hours()||a.minutes()||a.seconds()||a.milliseconds())}function S(a){return"[object Date]"===Object.prototype.toString.call(a)||a instanceof Date}
129// Returns a boolean about whether the given input is a time string, like "06:40:00" or "06:00"
130function T(a){return/^\d+\:\d+(?:\:\d+\.?(?:\d{3})?)?$/.test(a)}
131// Merges an array of objects into a single object.
132// The second argument allows for an array of property names who's object values will be merged together.
133function U(a,b){var c,d,e,f,g,h,i={};if(b)for(c=0;c<b.length;c++){
134// collect the trailing object values, stopping when a non-object is discovered
135for(d=b[c],e=[],f=a.length-1;f>=0;f--)if(g=a[f][d],"object"==typeof g)e.unshift(g);else if(void 0!==g){i[d]=g;// if there were no objects, this value will be used
136break}
137// if the trailing values were objects, use the merged value
138e.length&&(i[d]=U(e))}
139// copy values into the destination, going from last to first
140for(c=a.length-1;c>=0;c--){h=a[c];for(d in h)d in i||(// if already assigned by previous props or complex props, don't reassign
141i[d]=h[d])}return i}
142// Create an object that has the given prototype. Just like Object.create
143function V(a){var b=function(){};return b.prototype=a,new b}function W(a,b){for(var c in a)Y(a,c)&&(b[c]=a[c])}
144// Copies over certain methods with the same names as Object.prototype methods. Overcomes an IE<=8 bug:
145// https://developer.mozilla.org/en-US/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
146function X(a,b){var c,d,e=["constructor","toString","valueOf"];for(c=0;c<e.length;c++)d=e[c],a[d]!==Object.prototype[d]&&(b[d]=a[d])}function Y(a,b){return ab.call(a,b)}
147// Is the given value a non-object non-function value?
148function Z(b){return/undefined|null|boolean|number|string/.test(a.type(b))}function $(b,c,d){if(a.isFunction(b)&&(b=[b]),b){var e,f;for(e=0;e<b.length;e++)f=b[e].apply(c,d)||f;return f}}function _(){for(var a=0;a<arguments.length;a++)if(void 0!==arguments[a])return arguments[a]}function aa(a){return(a+"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#039;").replace(/"/g,"&quot;").replace(/\n/g,"<br />")}function ba(a){return a.replace(/&.*?;/g,"")}
149// Given a hash of CSS properties, returns a string of CSS.
150// Uses property names as-is (no camel-case conversion). Will not make statements for null/undefined values.
151function ca(b){var c=[];return a.each(b,function(a,b){null!=b&&c.push(a+":"+b)}),c.join(";")}function da(a){return a.charAt(0).toUpperCase()+a.slice(1)}function ea(a,b){// for .sort()
152return a-b}function fa(a){return a%1===0}
153// Returns a method bound to the given object context.
154// Just like one of the jQuery.proxy signatures, but without the undesired behavior of treating the same method with
155// different contexts as identical when binding/unbinding events.
156function ga(a,b){var c=a[b];return function(){return c.apply(a,arguments)}}
157// Returns a function, that, as long as it continues to be invoked, will not
158// be triggered. The function will be called after it stops being called for
159// N milliseconds. If `immediate` is passed, trigger the function on the
160// leading edge, instead of the trailing.
161// https://github.com/jashkenas/underscore/blob/1.6.0/underscore.js#L714
162function ha(a,b,c){var d,e,f,g,h,i=function(){var j=+new Date-g;b>j?d=setTimeout(i,b-j):(d=null,c||(h=a.apply(f,e),f=e=null))};return function(){f=this,e=arguments,g=+new Date;var j=c&&!d;return d||(d=setTimeout(i,b)),j&&(h=a.apply(f,e),f=e=null),h}}
163// Builds an enhanced moment from args. When given an existing moment, it clones. When given a
164// native Date, or called with no arguments (the current time), the resulting moment will be local.
165// Anything else needs to be "parsed" (a string or an array), and will be affected by:
166//    parseAsUTC - if there is no zone information, should we parse the input in UTC?
167//    parseZone - if there is zone information, should we force the zone of the moment?
168function ia(c,d,e){var f,g,h,i,j=c[0],k=1==c.length&&"string"==typeof j;// flag for extended functionality
169// clone it
170// "parsing" is required
171// accept strings like '2014-05', but convert to the first of the month
172// for when we pass it on to moment's constructor
173// no time part?
174// arrays have no timezone information, so assume ambiguous zone
175// otherwise, probably a string with a format
176// let's record the inputted zone somehow
177return b.isMoment(j)?(i=b.apply(null,c),ka(j,i)):S(j)||void 0===j?i=b.apply(null,c):(f=!1,g=!1,k?bb.test(j)?(j+="-01",c=[j],f=!0,g=!0):(h=cb.exec(j))&&(f=!h[5],g=!0):a.isArray(j)&&(g=!0),i=d||f?b.utc.apply(b,c):b.apply(null,c),f?(i._ambigTime=!0,i._ambigZone=!0):e&&(g?i._ambigZone=!0:k&&(i.utcOffset?i.utcOffset(j):i.zone(j)))),i._fullCalendar=!0,i}
178// Misc Internals
179// -------------------------------------------------------------------------------------------------
180// given an array of moment-like inputs, return a parallel array w/ moments similarly ambiguated.
181// for example, of one moment has ambig time, but not others, all moments will have their time stripped.
182// set `preserveTime` to `true` to keep times, but only normalize zone ambiguity.
183// returns the original moments if no modifications are necessary.
184function ja(a,c){var d,e,f=!1,g=!1,h=a.length,i=[];
185// parse inputs into real moments and query their ambig flags
186for(d=0;h>d;d++)e=a[d],b.isMoment(e)||(e=Ta.moment.parseZone(e)),f=f||e._ambigTime,g=g||e._ambigZone,i.push(e);
187// strip each moment down to lowest common ambiguity
188// use clones to avoid modifying the original moments
189for(d=0;h>d;d++)e=i[d],c||!f||e._ambigTime?g&&!e._ambigZone&&(i[d]=e.clone().stripZone()):i[d]=e.clone().stripTime();return i}
190// Transfers all the flags related to ambiguous time/zone from the `src` moment to the `dest` moment
191// TODO: look into moment.momentProperties for this.
192function ka(a,b){a._ambigTime?b._ambigTime=!0:b._ambigTime&&(b._ambigTime=!1),a._ambigZone?b._ambigZone=!0:b._ambigZone&&(b._ambigZone=!1)}
193// Sets the year/month/date/etc values of the moment from the given array.
194// Inefficient because it calls each individual setter.
195function la(a,b){a.year(b[0]||0).month(b[1]||0).date(b[2]||0).hours(b[3]||0).minutes(b[4]||0).seconds(b[5]||0).milliseconds(b[6]||0)}
196// Single Date Formatting
197// -------------------------------------------------------------------------------------------------
198// call this if you want Moment's original format method to be used
199function ma(a,b){return eb.format.call(a,b)}
200// Formats `date` with a Moment formatting string, but allow our non-zero areas and
201// additional token.
202function na(a,b){return oa(a,ta(b))}function oa(a,b){var c,d="";for(c=0;c<b.length;c++)d+=pa(a,b[c]);return d}function pa(a,b){var c,d;// a token, like "YYYY"
203// a grouping of other chunks that must be non-zero
204return"string"==typeof b?b:(c=b.token)?fb[c]?fb[c](a):ma(a,c):b.maybe&&(d=oa(a,b.maybe),d.match(/[1-9]/))?d:""}
205// Date Range Formatting
206// -------------------------------------------------------------------------------------------------
207// TODO: make it work with timezone offset
208// Using a formatting string meant for a single date, generate a range string, like
209// "Sep 2 - 9 2013", that intelligently inserts a separator where the dates differ.
210// If the dates are the same as far as the format string is concerned, just return a single
211// rendering of one date, without any separator.
212function qa(a,b,c,d,e){var f;// works with moment-pre-2.8
213// Expand localized format strings, like "LL" -> "MMMM D YYYY"
214// BTW, this is not important for `formatDate` because it is impossible to put custom tokens
215// or non-zero areas in Moment's localized format strings.
216return a=Ta.moment.parseZone(a),b=Ta.moment.parseZone(b),f=(a.localeData||a.lang).call(a),c=f.longDateFormat(c)||c,d=d||" - ",ra(a,b,ta(c),d,e)}// expose
217function ra(a,b,c,d,e){var f,g,h,i,j=a.clone().stripZone(),k=b.clone().stripZone(),l="",m="",n="",o="",p="";
218// Start at the leftmost side of the formatting string and continue until you hit a token
219// that is not the same between dates.
220for(g=0;g<c.length&&(f=sa(a,b,j,k,c[g]),f!==!1);g++)l+=f;
221// Similarly, start at the rightmost side of the formatting string and move left
222for(h=c.length-1;h>g&&(f=sa(a,b,j,k,c[h]),f!==!1);h--)m=f+m;
223// The area in the middle is different for both of the dates.
224// Collect them distinctly so we can jam them together later.
225for(i=g;h>=i;i++)n+=pa(a,c[i]),o+=pa(b,c[i]);return(n||o)&&(p=e?o+d+n:n+d+o),l+p+m}
226// TODO: week maybe?
227// Given a formatting chunk, and given that both dates are similar in the regard the
228// formatting chunk is concerned, format date1 against `chunk`. Otherwise, return `false`.
229function sa(a,b,c,d,e){var f,g;return"string"==typeof e?e:(f=e.token)&&(g=gb[f.charAt(0)],g&&c.isSame(d,g))?ma(a,f):!1}function ta(a){return a in hb?hb[a]:hb[a]=ua(a)}
230// Break the formatting string into an array of chunks
231function ua(a){for(var b,c=[],d=/\[([^\]]*)\]|\(([^\)]*)\)|(LTS|LT|(\w)\4*o?)|([^\w\[\(]+)/g;b=d.exec(a);)b[1]?// a literal string inside [ ... ]
232c.push(b[1]):b[2]?// non-zero formatting inside ( ... )
233c.push({maybe:ua(b[2])}):b[3]?// a formatting token
234c.push({token:b[3]}):b[5]&&// an unenclosed literal string
235c.push(b[5]);return c}// export
236// Class that all other classes will inherit from
237function va(){}function wa(a,b){var c;
238// ensure a constructor for the subclass, forwarding all arguments to the super-constructor if it doesn't exist
239// build the base prototype for the subclass, which is an new object chained to the superclass's prototype
240// copy each member variable/method onto the the subclass's prototype
241// hack for IE8
242// copy over all class variables/methods to the subclass, such as `extend` and `mixin`
243return Y(b,"constructor")&&(c=b.constructor),"function"!=typeof c&&(c=b.constructor=function(){a.apply(this,arguments)}),c.prototype=V(a.prototype),W(b,c.prototype),X(b,c.prototype),W(a,c),c}function xa(a,b){W(b,a.prototype)}
244// Returns `true` if the hits are identically equal. `false` otherwise. Must be from the same component.
245// Two null values will be considered equal, as two "out of the component" states are the same.
246function ya(a,b){return a||b?a&&b?a.component===b.component&&za(a,b)&&za(b,a):!1:!0}
247// Returns true if all of subHit's non-standard properties are within superHit
248function za(a,b){for(var c in a)if(!/^(component|left|right|top|bottom)$/.test(c)&&a[c]!==b[c])return!1;return!0}/* Utilities
249----------------------------------------------------------------------------------------------------------------------*/
250function Aa(a){// returns true if background OR inverse-background
251var b=Ca(a);return"background"===b||"inverse-background"===b}
251// export
252function Ba(a){return"inverse-background"===Ca(a)}function Ca(a){return _((a.source||{}).rendering,a.rendering)}function Da(a){var b,c,d={};for(b=0;b<a.length;b++)c=a[b],(d[c._id]||(d[c._id]=[])).push(c);return d}
253// A cmp function for determining which non-inverted "ranges" (see above) happen earlier
254function Ea(a,b){return a.start-b.start}
255// Given a jQuery element that might represent a dragged FullCalendar event, returns an intermediate data structure
256// to be used for Event Object creation.
257// A defined `.eventProps`, even when empty, indicates that an event should be created.
258function Fa(c){var d,e,f,g,h=Ta.dataAttrPrefix;
259// pluck special-cased date/time properties
260// accept 'time' as well
261// fallback to standalone attribute values for each of the date/time properties
262// accept 'time' as well
263// massage into correct data types
264return h&&(h+="-"),d=c.data(h+"event")||null,d&&(d="object"==typeof d?a.extend({},d):{},e=d.start,null==e&&(e=d.time),f=d.duration,g=d.stick,delete d.start,delete d.time,delete d.duration,delete d.stick),null==e&&(e=c.data(h+"start")),null==e&&(e=c.data(h+"time")),null==f&&(f=c.data(h+"duration")),null==g&&(g=c.data(h+"stick")),e=null!=e?b.duration(e):null,f=null!=f?b.duration(f):null,g=Boolean(g),{eventProps:d,startTime:e,duration:f,stick:g}}
265// Computes whether two segments' columns collide. They are assumed to be in the same row.
266function Ga(a,b){var c,d;for(c=0;c<b.length;c++)if(d=b[c],d.leftCol<=a.rightCol&&d.rightCol>=a.leftCol)return!0;return!1}
267// A cmp function for determining the leftmost event
268function Ha(a,b){return a.leftCol-b.leftCol}
269// Builds an array of segments "levels". The first level will be the leftmost tier of segments if the calendar is
270// left-to-right, or the rightmost if the calendar is right-to-left. Assumes the segments are already ordered by date.
271function Ia(a){var b,c,d,e=[];for(b=0;b<a.length;b++){
272// go through all the levels and stop on the first level where there are no collisions
273for(c=a[b],d=0;d<e.length&&La(c,e[d]).length;d++);c.level=d,(e[d]||(e[d]=[])).push(c)}return e}
274// For every segment, figure out the other segments that are in subsequent
275// levels that also occupy the same vertical space. Accumulate in seg.forwardSegs
276function Ja(a){var b,c,d,e,f;for(b=0;b<a.length;b++)for(c=a[b],d=0;d<c.length;d++)for(e=c[d],e.forwardSegs=[],f=b+1;f<a.length;f++)La(e,a[f],e.forwardSegs)}
277// Figure out which path forward (via seg.forwardSegs) results in the longest path until
278// the furthest edge is reached. The number of segments in this path will be seg.forwardPressure
279function Ka(a){var b,c,d=a.forwardSegs,e=0;if(void 0===a.forwardPressure){// not already computed
280for(b=0;b<d.length;b++)c=d[b],Ka(c),e=Math.max(e,1+c.forwardPressure);a.forwardPressure=e}}
281// Find all the segments in `otherSegs` that vertically collide with `seg`.
282// Append into an optionally-supplied `results` array and return.
283function La(a,b,c){c=c||[];for(var d=0;d<b.length;d++)Ma(a,b[d])&&c.push(b[d]);return c}
284// Do these segments occupy the same vertical space?
285function Ma(a,b){return a.bottom>b.top&&a.top<b.bottom}function Na(c,d){function e(){T?h()&&(
286// mainly for the public API
287k(),i()):f()}function f(){U=O.theme?"ui":"fc",c.addClass("fc"),c.addClass(N.isTouch?"fc-touch":"fc-cursor"),O.isRTL?c.addClass("fc-rtl"):c.addClass("fc-ltr"),O.theme?c.addClass("ui-widget"):c.addClass("fc-unthemed"),T=a("<div class='fc-view-container'/>").prependTo(c),R=N.header=new Qa(N,O),S=R.render(),S&&c.prepend(S),i(O.defaultView),O.handleWindowResize&&(Y=ha(m,O.windowResizeDelay),a(window).resize(Y))}function g(){W&&W.removeElement(),R.removeElement(),T.remove(),c.removeClass("fc fc-touch fc-cursor fc-ltr fc-rtl fc-unthemed ui-widget"),Y&&a(window).unbind("resize",Y)}function h(){return c.is(":visible")}
288// View Rendering
289// -----------------------------------------------------------------------------------
290// Renders a view because of a date change, view-type change, or for the first time.
291// If not given a viewType, keep the current view but render different dates.
292function i(b){ca++,
293// if viewType is changing, remove the old view's rendering
294W&&b&&W.type!==b&&(R.deactivateButton(W.type),H(),// prevent a scroll jump when view element is removed
295W.removeElement(),W=N.view=null),
296// if viewType changed, or the view was never created, create a fresh view
297!W&&b&&(W=N.view=ba[b]||(ba[b]=N.instantiateView(b)),W.setElement(a("<div class='fc-view fc-"+b+"-view' />").appendTo(T)),R.activateButton(b)),W&&(Z=W.massageCurrentDate(Z),W.displaying&&Z.isWithin(W.intervalStart,W.intervalEnd)||h()&&(W.display(Z),I(),u(),v(),q())),I(),// undo any lone freezeContentHeight calls
298ca--}function j(a){// isResize=true. will poll getSuggestedViewHeight() and isHeightAuto()
299return h()?(a&&l(),ca++,W.updateSize(!0),ca--,!0):void 0}function k(){h()&&l()}function l(){// assumes elementVisible
300X="number"==typeof O.contentHeight?O.contentHeight:"number"==typeof O.height?O.height-(S?S.outerHeight(!0):0):Math.round(T.width()/Math.max(O.aspectRatio,.5))}function m(a){!ca&&a.target===window&&W.start&&j(!0)&&W.trigger("windowResize",aa)}/* Event Fetching/Rendering
301	-----------------------------------------------------------------------------*/
302// TODO: going forward, most of this stuff should be directly handled by the view
303function n(){// can be called as an API method
304p(),// so that events are cleared before user starts waiting for AJAX
305r()}function o(){// destroys old events if previously rendered
306h()&&(H(),W.displayEvents(da),I())}function p(){H(),W.clearEvents(),I()}function q(){!O.lazyFetching||$(W.start,W.end)?r():o()}function r(){_(W.start,W.end)}
307// called when event data arrives
308function s(a){da=a,o()}
309// called when a single event's data has been changed
310function t(){o()}/* Header Updating
311	-----------------------------------------------------------------------------*/
312function u(){R.updateTitle(W.title)}function v(){var a=N.getNow();a.isWithin(W.intervalStart,W.intervalEnd)?R.disableButton("today"):R.enableButton("today")}/* Selection
313	-----------------------------------------------------------------------------*/
314// this public method receives start/end dates in any format, with any timezone
315function w(a,b){W.select(N.buildSelectSpan.apply(N,arguments))}function x(){// safe to be called before renderView
316W&&W.unselect()}/* Date
317	-----------------------------------------------------------------------------*/
318function y(){Z=W.computePrevDate(Z),i()}function z(){Z=W.computeNextDate(Z),i()}function A(){Z.add(-1,"years"),i()}function B(){Z.add(1,"years"),i()}function C(){Z=N.getNow(),i()}function D(a){Z=N.moment(a).stripZone(),i()}function E(a){Z.add(b.duration(a)),i()}
319// Forces navigation to a view for the given date.
320// `viewType` can be a specific view name or a generic one like "week" or "day".
321function F(a,b){var c;b=b||"day",c=N.getViewSpec(b)||N.getUnitViewSpec(b),Z=a.clone(),i(c?c.type:null)}
322// for external API
323function G(){return N.applyTimezone(Z)}function H(){T.css({width:"100%",height:T.height(),overflow:"hidden"})}function I(){T.css({width:"",height:"",overflow:""})}/* Misc
324	-----------------------------------------------------------------------------*/
325function J(){return N}function K(){return W}function L(a,b){return void 0===b?O[a]:void("height"!=a&&"contentHeight"!=a&&"aspectRatio"!=a||(O[a]=b,j(!0)))}function M(a,b){// overrides the Emitter's trigger method :(
326var c=Array.prototype.slice.call(arguments,2);return b=b||aa,this.triggerWith(a,b,c),O[a]?O[a].apply(b,c):void 0}var N=this;N.initOptions(d||{});var O=this.options;
327// Exports
328// -----------------------------------------------------------------------------------
329N.render=e,N.destroy=g,N.refetchEvents=n,N.reportEvents=s,N.reportEventChange=t,N.rerenderEvents=o,// `renderEvents` serves as a rerender. an API method
330N.changeView=i,// `renderView` will switch to another view
331N.select=w,N.unselect=x,N.prev=y,N.next=z,N.prevYear=A,N.nextYear=B,N.today=C,N.gotoDate=D,N.incrementDate=E,N.zoomTo=F,N.getDate=G,N.getCalendar=J,N.getView=K,N.option=L,N.trigger=M;
332// Language-data Internals
333// -----------------------------------------------------------------------------------
334// Apply overrides to the current language's data
335var P=V(// make a cheap copy
336Pa(O.lang));if(O.monthNames&&(P._months=O.monthNames),O.monthNamesShort&&(P._monthsShort=O.monthNamesShort),O.dayNames&&(P._weekdays=O.dayNames),O.dayNamesShort&&(P._weekdaysShort=O.dayNamesShort),null!=O.firstDay){var Q=V(P._week);// _week: { dow: # }
337Q.dow=O.firstDay,P._week=Q}
338// assign a normalized value, to be used by our .week() moment extension
339P._fullCalendar_weekCalc=function(a){return"function"==typeof a?a:"local"===a?a:"iso"===a||"ISO"===a?"ISO":void 0}(O.weekNumberCalculation),
340// Calendar-specific Date Utilities
341// -----------------------------------------------------------------------------------
342N.defaultAllDayEventDuration=b.duration(O.defaultAllDayEventDuration),N.defaultTimedEventDuration=b.duration(O.defaultTimedEventDuration),
343// Builds a moment using the settings of the current calendar: timezone and language.
344// Accepts anything the vanilla moment() constructor accepts.
345N.moment=function(){var a;
346// Force the moment to be local, because FC.moment doesn't guarantee it.
347// don't give ambiguously-timed moments a local zone
348// moment 2.8 and above
349// pre-moment-2.8
350return"local"===O.timezone?(a=Ta.moment.apply(null,arguments),a.hasTime()&&a.local()):a="UTC"===O.timezone?Ta.moment.utc.apply(null,arguments):Ta.moment.parseZone.apply(null,arguments),"_locale"in a?a._locale=P:a._lang=P,a},
351// Returns a boolean about whether or not the calendar knows how to calculate
352// the timezone offset of arbitrary dates in the current timezone.
353N.getIsAmbigTimezone=function(){return"local"!==O.timezone&&"UTC"!==O.timezone},
354// Returns a copy of the given date in the current timezone. Has no effect on dates without times.
355N.applyTimezone=function(a){if(!a.hasTime())return a.clone();var b,c=N.moment(a.toArray()),d=a.time()-c.time();
356// Safari sometimes has problems with this coersion when near DST. Adjust if necessary. (bug #2396)
357// is the time result different than expected?
358// add milliseconds
359// does it match perfectly now?
360return d&&(b=c.clone().add(d),a.time()-b.time()===0&&(c=b)),c},
361// Returns a moment for the current date, as defined by the client's computer or from the `now` option.
362// Will return an moment with an ambiguous timezone.
363N.getNow=function(){var a=O.now;return"function"==typeof a&&(a=a()),N.moment(a).stripZone()},
364// Get an event's normalized end date. If not present, calculate it from the defaults.
365N.getEventEnd=function(a){return a.end?a.end.clone():N.getDefaultEventEnd(a.allDay,a.start)},
366// Given an event's allDay status and start date, return what its fallback end date should be.
367// TODO: rename to computeDefaultEventEnd
368N.getDefaultEventEnd=function(a,b){var c=b.clone();return a?c.stripTime().add(N.defaultAllDayEventDuration):c.add(N.defaultTimedEventDuration),N.getIsAmbigTimezone()&&c.stripZone(),c},
369// Produces a human-readable string for the given duration.
370// Side-effect: changes the locale of the given duration.
371N.humanizeDuration=function(a){return(a.locale||a.lang).call(a,O.lang).humanize()},
372// Imports
373// -----------------------------------------------------------------------------------
374Ra.call(N,O);var R,S,T,U,W,X,Y,Z,$=N.isFetchNeeded,_=N.fetchEvents,aa=c[0],ba={},ca=0,da=[];// unzoned
375// Main Rendering
376// -----------------------------------------------------------------------------------
377// compute the initial ambig-timezone date
378Z=null!=O.defaultDate?N.moment(O.defaultDate).stripZone():N.getNow(),N.getSuggestedViewHeight=function(){return void 0===X&&k(),X},N.isHeightAuto=function(){return"auto"===O.contentHeight||"auto"===O.height},N.freezeContentHeight=H,N.unfreezeContentHeight=I,N.initialize()}function Oa(b){a.each(zb,function(a,c){null==b[a]&&(b[a]=c(b))})}
379// Returns moment's internal locale data. If doesn't exist, returns English.
380// Works with moment-pre-2.8
381function Pa(a){var c=b.localeData||b.langData;return c.call(b,a)||c.call(b,"en")}/* Top toolbar area with buttons and title
382----------------------------------------------------------------------------------------------------------------------*/
383// TODO: rename all header-related things to "toolbar"
384function Qa(b,c){function d(){var b=c.header;return n=c.theme?"ui":"fc",b?o=a("<div class='fc-toolbar'/>").append(f("left")).append(f("right")).append(f("center")).append('<div class="fc-clear"/>'):void 0}function e(){o.remove(),o=a()}function f(d){var e=a('<div class="fc-'+d+'"/>'),f=c.header[d];return f&&a.each(f.split(" "),function(d){var f,g=a(),h=!0;a.each(this.split(","),function(d,e){var f,i,j,k,l,m,o,q,r,s;// the element
385"title"==e?(g=g.add(a("<h2>&nbsp;</h2>")),h=!1):((f=(b.options.customButtons||{})[e])?(j=function(a){f.click&&f.click.call(s[0],a)},k="",l=f.text):(i=b.getViewSpec(e))?(j=function(){b.changeView(e)},p.push(e),k=i.buttonTextOverride,l=i.buttonTextDefault):b[e]&&(j=function(){b[e]()},k=(b.overrides.buttonText||{})[e],l=c.buttonText[e]),j&&(m=f?f.themeIcon:c.themeButtonIcons[e],o=f?f.icon:c.buttonIcons[e],q=k?aa(k):m&&c.theme?"<span class='ui-icon ui-icon-"+m+"'></span>":o&&!c.theme?"<span class='fc-icon fc-icon-"+o+"'></span>":aa(l),r=["fc-"+e+"-button",n+"-button",n+"-state-default"],s=a('<button type="button" class="'+r.join(" ")+'">'+q+"</button>").click(function(a){s.hasClass(n+"-state-disabled")||(j(a),(s.hasClass(n+"-state-active")||s.hasClass(n+"-state-disabled"))&&s.removeClass(n+"-state-hover"))}).mousedown(function(){s.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-down")}).mouseup(function(){s.removeClass(n+"-state-down")}).hover(function(){s.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-hover")},function(){s.removeClass(n+"-state-hover").removeClass(n+"-state-down")}),g=g.add(s)))}
385),h&&g.first().addClass(n+"-corner-left").end().last().addClass(n+"-corner-right").end(),g.length>1?(f=a("<div/>"),h&&f.addClass("fc-button-group"),f.append(g),e.append(f)):e.append(g)}),e}function g(a){o.find("h2").text(a)}function h(a){o.find(".fc-"+a+"-button").addClass(n+"-state-active")}function i(a){o.find(".fc-"+a+"-button").removeClass(n+"-state-active")}function j(a){o.find(".fc-"+a+"-button").attr("disabled","disabled").addClass(n+"-state-disabled")}function k(a){o.find(".fc-"+a+"-button").removeAttr("disabled").removeClass(n+"-state-disabled")}function l(){return p}var m=this;
386// exports
387m.render=d,m.removeElement=e,m.updateTitle=g,m.activateButton=h,m.deactivateButton=i,m.disableButton=j,m.enableButton=k,m.getViewsWithButtons=l;
388// locals
389var n,o=a(),p=[]}function Ra(c){/* Fetching
390	-----------------------------------------------------------------------------*/
391// start and end are assumed to be unzoned
392function d(a,b){// nothing has been fetched yet?
393return!I||I>a||b>M}function e(a,b){I=a,M=b,S=[];var c=++Q,d=P.length;R=d;for(var e=0;d>e;e++)f(P[e],c)}function f(b,c){g(b,function(d){var e,f,g,h=a.isArray(b.events);if(c==Q){if(d)for(e=0;e<d.length;e++)f=d[e],g=h?f:s(f,b),g&&S.push.apply(S,w(g));R--,R||N(S)}})}function g(b,d){var e,f,h=Ta.sourceFetchers;for(e=0;e<h.length;e++){if(f=h[e].call(H,// this, the Calendar object
394b,I.clone(),M.clone(),c.timezone,d),f===!0)
395// the fetcher is in charge. made its own async request
396return;if("object"==typeof f)
397// the fetcher returned a new source. process it
398return void g(f,d)}var i=b.events;if(i)a.isFunction(i)?(H.pushLoading(),i.call(H,// this, the Calendar object
399I.clone(),M.clone(),c.timezone,function(a){d(a),H.popLoading()})):a.isArray(i)?d(i):d();else{var j=b.url;if(j){var k,l=b.success,m=b.error,n=b.complete;k=a.isFunction(b.data)?b.data():b.data;
400// use a copy of the custom data so we can modify the parameters
401// and not affect the passed-in object.
402var o=a.extend({},k||{}),p=_(b.startParam,c.startParam),q=_(b.endParam,c.endParam),r=_(b.timezoneParam,c.timezoneParam);p&&(o[p]=I.format()),q&&(o[q]=M.format()),c.timezone&&"local"!=c.timezone&&(o[r]=c.timezone),H.pushLoading(),a.ajax(a.extend({},Ab,b,{data:o,success:function(b){b=b||[];var c=$(l,this,arguments);a.isArray(c)&&(b=c),d(b)},error:function(){$(m,this,arguments),d()},complete:function(){$(n,this,arguments),H.popLoading()}}))}else d()}}/* Sources
403	-----------------------------------------------------------------------------*/
404function h(a){var b=i(a);b&&(P.push(b),R++,f(b,Q))}function i(b){// will return undefined if invalid source
405var c,d,e=Ta.sourceNormalizers;if(a.isFunction(b)||a.isArray(b)?c={events:b}:"string"==typeof b?c={url:b}:"object"==typeof b&&(c=a.extend({},b)),c){for(
406// TODO: repeat code, same code for event classNames
407c.className?"string"==typeof c.className&&(c.className=c.className.split(/\s+/)):c.className=[],
408// for array sources, we convert to standard Event Objects up front
409a.isArray(c.events)&&(c.origArray=c.events,// for removeEventSource
410c.events=a.map(c.events,function(a){return s(a,c)})),d=0;d<e.length;d++)e[d].call(H,c);return c}}function j(b){P=a.grep(P,function(a){return!k(a,b)}),S=a.grep(S,function(a){return!k(a.source,b)}),N(S)}function k(a,b){return a&&b&&l(a)==l(b)}function l(a){// a normalized event source?
411// get the primitive
412return("object"==typeof a?a.origArray||a.googleCalendarId||a.url||a.events:null)||a}/* Manipulation
413	-----------------------------------------------------------------------------*/
414// Only ever called from the externally-facing API
415function m(a){
416// massage start/end values, even if date string values
417a.start=H.moment(a.start),a.end?a.end=H.moment(a.end):a.end=null,x(a,n(a)),// will handle start/end/allDay normalization
418N(S)}
419// Returns a hash of misc event properties that should be copied over to related events.
420function n(b){var c={};return a.each(b,function(a,b){o(a)&&void 0!==b&&Z(b)&&(// a defined non-object
421c[a]=b)}),c}
422// non-date-related, non-id-related, non-secret
423function o(a){return!/^_|^(id|allDay|start|end)$/.test(a)}
424// returns the expanded events that were created
425function p(a,b){var c,d,e,f=s(a);if(f){for(c=w(f),d=0;d<c.length;d++)e=c[d],e.source||(b&&(O.events.push(e),e.source=O),S.push(e));return N(S),c}return[]}function q(b){var c,d;// inverse=true
426// Remove events from array sources.
427// This works because they have been converted to official Event Objects up front.
428// (and as a result, event._id has been calculated).
429for(null==b?// null or undefined. remove all events
430b=function(){return!0}:a.isFunction(b)||(c=b+"",b=function(a){return a._id==c}),S=a.grep(S,b,!0),d=0;d<P.length;d++)a.isArray(P[d].events)&&(P[d].events=a.grep(P[d].events,b,!0));N(S)}function r(b){// not null, not undefined. an event ID
431return a.isFunction(b)?a.grep(S,b):null!=b?(b+="",a.grep(S,function(a){return a._id==b})):S}/* Event Normalization
432	-----------------------------------------------------------------------------*/
433// Given a raw object with key/value properties, returns an "abstract" Event object.
434// An "abstract" event is an event that, if recurring, will not have been expanded yet.
435// Will return `false` when input is invalid.
436// `source` is optional
437function s(d,e){var f,g,h,i={};if(c.eventDataTransform&&(d=c.eventDataTransform(d)),e&&e.eventDataTransform&&(d=e.eventDataTransform(d)),
438// Copy all properties over to the resulting object.
439// The special-case properties will be copied over afterwards.
440a.extend(i,d),e&&(i.source=e),i._id=d._id||(void 0===d.id?"_fc"+Bb++:d.id+""),d.className?"string"==typeof d.className?i.className=d.className.split(/\s+/):i.className=d.className:i.className=[],f=d.start||d.date,g=d.end,T(f)&&(f=b.duration(f)),T(g)&&(g=b.duration(g)),d.dow||b.isDuration(f)||b.isDuration(g))
441// the event is "abstract" (recurring) so don't calculate exact start/end dates just yet
442i.start=f?b.duration(f):null,// will be a Duration or null
443i.end=g?b.duration(g):null,// will be a Duration or null
444i._recurring=!0;else{if(f&&(f=H.moment(f),!f.isValid()))return!1;g&&(g=H.moment(g),g.isValid()||(g=null)),h=d.allDay,void 0===h&&(// still undefined? fallback to default
445h=_(e?e.allDayDefault:void 0,c.allDayDefault)),t(f,g,h,i)}return i}
446// Normalizes and assigns the given dates to the given partially-formed event object.
447// NOTE: mutates the given start/end moments. does not make a copy.
448function t(a,b,c,d){d.start=a,d.end=b,d.allDay=c,u(d),Sa(d)}
449// Ensures proper values for allDay/start/end. Accepts an Event object, or a plain object with event-ish properties.
450// NOTE: Will modify the given object.
451function u(a){v(a),a.end&&!a.end.isAfter(a.start)&&(a.end=null),a.end||(c.forceEventDuration?a.end=H.getDefaultEventEnd(a.allDay,a.start):a.end=null)}
452// Ensures the allDay property exists and the timeliness of the start/end dates are consistent
453function v(a){null==a.allDay&&(a.allDay=!(a.start.hasTime()||a.end&&a.end.hasTime())),a.allDay?(a.start.stripTime(),a.end&&
454// TODO: consider nextDayThreshold here? If so, will require a lot of testing and adjustment
455a.end.stripTime()):(a.start.hasTime()||(a.start=H.applyTimezone(a.start.time(0))),a.end&&!a.end.hasTime()&&(a.end=H.applyTimezone(a.end.time(0))))}
456// If the given event is a recurring event, break it down into an array of individual instances.
457// If not a recurring event, return an array with the single original event.
458// If given a falsy input (probably because of a failed buildEventFromInput call), returns an empty array.
459// HACK: can override the recurring window by providing custom rangeStart/rangeEnd (for businessHours).
460function w(b,c,d){var e,f,g,h,i,j,k,l,m,n=[];if(c=c||I,d=d||M,b)if(b._recurring){
461// make a boolean hash as to whether the event occurs on each day-of-week
462if(f=b.dow)for(e={},g=0;g<f.length;g++)e[f[g]]=!0;// holds the date of the current day
463for(
464// iterate through every day in the current range
465h=c.clone().stripTime();h.isBefore(d);)e&&!e[h.day()]||(i=b.start,j=b.end,k=h.clone(),l=null,i&&(k=k.time(i)),j&&(l=h.clone().time(j)),m=a.extend({},b),t(k,l,!i&&!j,m),n.push(m)),h.add(1,"days")}else n.push(b);return n}/* Event Modification Math
466	-----------------------------------------------------------------------------------------*/
467// Modifies an event and all related events by applying the given properties.
468// Special date-diffing logic is used for manipulation of dates.
469// If `props` does not contain start/end dates, the updated values are assumed to be the event's current start/end.
470// All date comparisons are done against the event's pristine _start and _end dates.
471// Returns an object with delta information and a function to undo all operations.
472// For making computations in a granularity greater than day/time, specify largeUnit.
473// NOTE: The given `newProps` might be mutated for normalization purposes.
474function x(b,c,d){
475// diffs the dates in the appropriate way, returning a duration
476function e(a,b){// date1 - date0
477// date1 - date0
478return d?L(a,b,d):c.allDay?K(a,b):J(a,b)}var f,g,h,i,j,k,l={};
479// normalize new date-related properties
480// is null or undefined?
481// create normalized versions of the original props to compare against
482// need a real end value, for diffing
483// need to clear the end date if explicitly changed to null
484// compute the delta for moving the start date
485// compute the delta for moving the end date
486// gather all non-date-related properties
487// apply the operations to the event and all related events
488// get events with this ID
489return c=c||{},c.start||(c.start=b.start.clone()),void 0===c.end&&(c.end=b.end?b.end.clone():null),null==c.allDay&&(c.allDay=b.allDay),u(c),f={start:b._start.clone(),end:b._end?b._end.clone():H.getDefaultEventEnd(b._allDay,b._start),allDay:c.allDay},u(f),g=null!==b._end&&null===c.end,h=e(c.start,f.start),c.end?(i=e(c.end,f.end),j=i.subtract(h)):j=null,a.each(c,function(a,b){o(a)&&void 0!==b&&(l[a]=b)}),k=y(r(b._id),g,c.allDay,h,j,l),{dateDelta:h,durationDelta:j,undo:k}}
490// Modifies an array of events in the following ways (operations are in order):
491// - clear the event's `end`
492// - convert the event to allDay
493// - add `dateDelta` to the start and end
494// - add `durationDelta` to the event's duration
495// - assign `miscProps` to the event
496//
497// Returns a function that can be called to undo all the operations.
498//
499// TODO: don't use so many closures. possible memory issues when lots of events with same ID.
500//
501function y(b,c,d,e,f,g){var h=H.getIsAmbigTimezone(),i=[];
502// normalize zero-length deltas to be null
503return e&&!e.valueOf()&&(e=null),f&&!f.valueOf()&&(f=null),a.each(b,function(b,j){var k,l;k={start:j.start.clone(),end:j.end?j.end.clone():null,allDay:j.allDay},a.each(g,function(a){k[a]=j[a]}),l={start:j._start,end:j._end,allDay:d},u(l),c?l.end=null:f&&!l.end&&(l.end=H.getDefaultEventEnd(l.allDay,l.start)),e&&(l.start.add(e),l.end&&l.end.add(e)),f&&l.end.add(f),h&&!l.allDay&&(e||f)&&(l.start.stripZone(),l.end&&l.end.stripZone()),a.extend(j,g,l),Sa(j),i.push(function(){a.extend(j,k),Sa(j)})}),function(){for(var a=0;a<i.length;a++)i[a]()}}
504// Returns an array of events as to when the business hours occur in the given view.
505// Abuse of our event system :(
506function z(b){var d,e=c.businessHours,f={className:"fc-nonbusiness",start:"09:00",end:"17:00",dow:[1,2,3,4,5],// monday - friday
507rendering:"inverse-background"},g=H.getView();// `true` (which means "use the defaults") or an override object
508// copy to a new object in either case
509// if a whole-day series is requested, clear the start/end times
510return e&&(d=a.extend({},f,"object"==typeof e?e:{})),d?(b&&(d.start=null,d.end=null),w(s(d),g.start,g.end)):[]}
511// Determines if the given event can be relocated to the given span (unzoned start/end with other misc data)
512function A(a,b){var d=b.source||{},e=_(b.constraint,d.constraint,c.eventConstraint),f=_(b.overlap,d.overlap,c.eventOverlap);return D(a,e,f,b)}
513// Determines if an external event can be relocated to the given span (unzoned start/end with other misc data)
514function B(b,c,d){var e,f;
515// note: very similar logic is in View's reportExternalDrop
516return d&&(e=a.extend({},d,c),f=w(s(e))[0]),f?A(b,f):C(b)}
517// Determines the given span (unzoned start/end with other misc data) can be selected.
518function C(a){return D(a,c.selectConstraint,c.selectOverlap)}
519// Returns true if the given span (caused by an event drop/resize or a selection) is allowed to exist
520// according to the constraint/overlap settings.
521// `event` is not required if checking a selection.
522function D(a,b,c,d){var e,f,g,h,i,j;
523// the range must be fully contained by at least one of produced constraint events
524if(null!=b){for(e=E(b),f=!1,h=0;h<e.length;h++)if(F(e[h],a)){f=!0;break}if(!f)return!1}for(g=H.getPeerEvents(a,d),h=0;h<g.length;h++)
525// there needs to be an actual intersection before disallowing anything
526if(i=g[h],G(i,a)){
527// evaluate overlap for the given range and short-circuit if necessary
528if(c===!1)return!1;if("function"==typeof c&&!c(i,d))return!1;
529// if we are computing if the given range is allowable for an event, consider the other event's
530// EventObject-specific or Source-specific `overlap` property
531if(d){if(j=_(i.overlap,(i.source||{}).overlap),j===!1)return!1;
532// if the peer event's overlap is a test function, pass the subject event as the first param
533if("function"==typeof j&&!j(d,i))return!1}}return!0}
534// Given an event input from the API, produces an array of event objects. Possible event inputs:
535// 'businessHours'
536// An event ID (number or string)
537// An object with specific start/end dates or a recurring event (like what businessHours accepts)
538function E(a){return"businessHours"===a?z():"object"==typeof a?w(s(a)):r(a)}
539// Does the event's date range fully contain the given range?
540// start/end already assumed to have stripped zones :(
541function F(a,b){var c=a.start.clone().stripZone(),d=H.getEventEnd(a).stripZone();return b.start>=c&&b.end<=d}
542// Does the event's date range intersect with the given range?
543// start/end already assumed to have stripped zones :(
544function G(a,b){var c=a.start.clone().stripZone(),d=H.getEventEnd(a).stripZone();return b.start<d&&b.end>c}// assumed to be a calendar
545var H=this;
546// exports
547H.isFetchNeeded=d,H.fetchEvents=e,H.addEventSource=h,H.removeEventSource=j,H.updateEvent=m,H.renderEvent=p,H.removeEvents=q,H.clientEvents=r,H.mutateEvent=x,H.normalizeEventDates=u,H.normalizeEventTimes=v;
548// imports
549var I,M,N=H.reportEvents,O={events:[]},P=[O],Q=0,R=0,S=[];// holds events that have already been expanded
550a.each((c.events?[c.events]:[]).concat(c.eventSources||[]),function(a,b){var c=i(b);c&&P.push(c)}),/* Business Hours
551	-----------------------------------------------------------------------------------------*/
552H.getBusinessHoursEvents=z,/* Overlapping / Constraining
553	-----------------------------------------------------------------------------------------*/
554H.isEventSpanAllowed=A,H.isExternalSpanAllowed=B,H.isSelectionSpanAllowed=C,H.getEventCache=function(){return S}}
555// updates the "backup" properties, which are preserved in order to compute diffs later on.
556function Sa(a){a._allDay=a.allDay,a._start=a.start.clone(),a._end=a.end?a.end.clone():null}var Ta=a.fullCalendar={version:"2.7.1",internalApiVersion:3},Ua=Ta.views={};Ta.isTouch="ontouchstart"in document,a.fn.fullCalendar=function(b){var c=Array.prototype.slice.call(arguments,1),d=this;// what this function will return (this jQuery object by default)
557return this.each(function(e,f){// loop each DOM element involved
558var g,h=a(f),i=h.data("fullCalendar");// the returned value of this single method call
559// a method call
560"string"==typeof b?i&&a.isFunction(i[b])&&(g=i[b].apply(i,c),e||(d=g),"destroy"===b&&h.removeData("fullCalendar")):i||(i=new vb(h,b),h.data("fullCalendar",i),i.render())}),d};var Va=[// names of options that are objects whose properties should be combined
561"header","buttonText","buttonIcons","themeButtonIcons"];
562// exports
563Ta.intersectRanges=I,Ta.applyAll=$,Ta.debounce=ha,Ta.isInt=fa,Ta.htmlEscape=aa,Ta.cssToStr=ca,Ta.proxy=ga,Ta.capitaliseFirstLetter=da,/* Element Geom Utilities
564----------------------------------------------------------------------------------------------------------------------*/
565Ta.getOuterRect=n,Ta.getClientRect=o,Ta.getContentRect=p,Ta.getScrollbarWidths=q;
566// Logic for determining if, when the element is right-to-left, the scrollbar appears on the left side
567var Wa=null;/* Mouse / Touch Utilities
568----------------------------------------------------------------------------------------------------------------------*/
569Ta.preventDefault=z,/* General Geometry Utils
570----------------------------------------------------------------------------------------------------------------------*/
571Ta.intersectRects=A,/* Object Ordering by Field
572----------------------------------------------------------------------------------------------------------------------*/
573Ta.parseFieldSpecs=E,Ta.compareByFieldSpecs=F,Ta.compareByFieldSpec=G,Ta.flexibleCompare=H,/* Date Utilities
574----------------------------------------------------------------------------------------------------------------------*/
575Ta.computeIntervalUnit=M,Ta.divideRangeByDuration=O,Ta.divideDurationByDuration=P,Ta.multiplyDuration=Q,Ta.durationHasTime=R;var Xa=["sun","mon","tue","wed","thu","fri","sat"],Ya=["year","month","week","day","hour","minute","second","millisecond"];/* Logging and Debug
576----------------------------------------------------------------------------------------------------------------------*/
577Ta.log=function(){var a=window.console;return a&&a.log?a.log.apply(a,arguments):void 0},Ta.warn=function(){var a=window.console;return a&&a.warn?a.warn.apply(a,arguments):Ta.log.apply(Ta,arguments)};/* General Utilities
578----------------------------------------------------------------------------------------------------------------------*/
579var Za,$a,_a,ab={}.hasOwnProperty,bb=/^\s*\d{4}-\d\d$/,cb=/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/,db=b.fn,eb=a.extend({},db);// function defined below
580// Creating
581// -------------------------------------------------------------------------------------------------
582// Creates a new moment, similar to the vanilla moment(...) constructor, but with
583// extra features (ambiguous time, enhanced formatting). When given an existing moment,
584// it will function as a clone (and retain the zone of the moment). Anything else will
585// result in a moment in the local zone.
586Ta.moment=function(){return ia(arguments)},
587// Sames as FC.moment, but forces the resulting moment to be in the UTC timezone.
588Ta.moment.utc=function(){var a=ia(arguments,!0);
589// Force it into UTC because makeMoment doesn't guarantee it
590// (if given a pre-existing moment for example)
591// don't give ambiguously-timed moments a UTC zone
592return a.hasTime()&&a.utc(),a},
593// Same as FC.moment, but when given an ISO8601 string, the timezone offset is preserved.
594// ISO8601 strings with no timezone offset will become ambiguously zoned.
595Ta.moment.parseZone=function(){return ia(arguments,!0,!0)},
596// A clone method that works with the flags related to our enhanced functionality.
597// In the future, use moment.momentProperties
598db.clone=function(){var a=eb.clone.apply(this,arguments);
599// these flags weren't transfered with the clone
600return ka(this,a),this._fullCalendar&&(a._fullCalendar=!0),a},
601// Week Number
602// -------------------------------------------------------------------------------------------------
603// Returns the week number, considering the locale's custom week number calcuation
604// `weeks` is an alias for `week`
605db.week=db.weeks=function(a){var b=(this._locale||this._lang)._fullCalendar_weekCalc;return null==a&&"function"==typeof b?b(this):"ISO"===b?eb.isoWeek.apply(this,arguments):eb.week.apply(this,arguments)},
606// Time-of-day
607// -------------------------------------------------------------------------------------------------
608// GETTER
609// Returns a Duration with the hours/minutes/seconds/ms values of the moment.
610// If the moment has an ambiguous time, a duration of 00:00 will be returned.
611//
612// SETTER
613// You can supply a Duration, a Moment, or a Duration-like argument.
614// When setting the time, and the moment has an ambiguous time, it then becomes unambiguous.
615db.time=function(a){
616// Fallback to the original method (if there is one) if this moment wasn't created via FullCalendar.
617// `time` is a generic enough method name where this precaution is necessary to avoid collisions w/ other plugins.
618if(!this._fullCalendar)return eb.time.apply(this,arguments);if(null==a)// getter
619return b.duration({hours:this.hours(),minutes:this.minutes(),seconds:this.seconds(),milliseconds:this.milliseconds()});// setter
620this._ambigTime=!1,// mark that the moment now has a time
621b.isDuration(a)||b.isMoment(a)||(a=b.duration(a));
622// The day value should cause overflow (so 24 hours becomes 00:00:00 of next day).
623// Only for Duration times, not Moment times.
624var c=0;
625// We need to set the individual fields.
626// Can't use startOf('day') then add duration. In case of DST at start of day.
627return b.isDuration(a)&&(c=24*Math.floor(a.asDays())),this.hours(c+a.hours()).minutes(a.minutes()).seconds(a.seconds()).milliseconds(a.milliseconds())},
628// Converts the moment to UTC, stripping out its time-of-day and timezone offset,
629// but preserving its YMD. A moment with a stripped time will display no time
630// nor timezone offset when .format() is called.
631db.stripTime=function(){var a;
632// get the values before any conversion happens
633// array of y/m/d/h/m/s/ms
634// TODO: use keepLocalTime in the future
635// set the internal UTC flag (will clear the ambig flags)
636// set the year/month/date. time will be zero
637// Mark the time as ambiguous. This needs to happen after the .utc() call, which might call .utcOffset(),
638// which clears all ambig flags. Same with setUTCValues with moment-timezone.
639return this._ambigTime||(a=this.toArray(),this.utc(),$a(this,a.slice(0,3)),this._ambigTime=!0,this._ambigZone=!0),this},
640// Returns if the moment has a non-ambiguous time (boolean)
641db.hasTime=function(){return!this._ambigTime},
642// Timezone
643// -------------------------------------------------------------------------------------------------
644// Converts the moment to UTC, stripping out its timezone offset, but preserving its
645// YMD and time-of-day. A moment with a stripped timezone offset will display no
646// timezone offset when .format() is called.
647// TODO: look into Moment's keepLocalTime functionality
648db.stripZone=function(){var a,b;
649// get the values before any conversion happens
650// array of y/m/d/h/m/s/ms
651// set the internal UTC flag (might clear the ambig flags, depending on Moment internals)
652// will set the year/month/date/hours/minutes/seconds/ms
653// the above call to .utc()/.utcOffset() unfortunately might clear the ambig flags, so restore
654// Mark the zone as ambiguous. This needs to happen after the .utc() call, which might call .utcOffset(),
655// which clears the ambig flags. Same with setUTCValues with moment-timezone.
656return this._ambigZone||(a=this.toArray(),b=this._ambigTime,this.utc(),$a(this,a),this._ambigTime=b||!1,this._ambigZone=!0),this},
657// Returns of the moment has a non-ambiguous timezone offset (boolean)
658db.hasZone=function(){return!this._ambigZone},
659// this method implicitly marks a zone
660db.local=function(){var a=this.toArray(),b=this._ambigZone;
661// ensure non-ambiguous
662// this probably already happened via local() -> utcOffset(), but don't rely on Moment's internals
663// If the moment was ambiguously zoned, the date fields were stored as UTC.
664// We want to preserve these, but in local time.
665// TODO: look into Moment's keepLocalTime functionality
666return eb.local.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,b&&_a(this,a),this},
667// implicitly marks a zone
668db.utc=function(){
669// ensure non-ambiguous
670// this probably already happened via utc() -> utcOffset(), but don't rely on Moment's internals
671return eb.utc.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,this},
672// methods for arbitrarily manipulating timezone offset.
673// should clear time/zone ambiguity when called.
674a.each(["zone",// only in moment-pre-2.9. deprecated afterwards
675"utcOffset"],function(a,b){eb[b]&&(// original method exists?
676// this method implicitly marks a zone (will probably get called upon .utc() and .local())
677db[b]=function(a){// setter
678// these assignments needs to happen before the original zone method is called.
679// I forget why, something to do with a browser crash.
680return null!=a&&(this._ambigTime=!1,this._ambigZone=!1),eb[b].apply(this,arguments)})}),
681// Formatting
682// -------------------------------------------------------------------------------------------------
683db.format=function(){return this._fullCalendar&&arguments[0]?na(this,arguments[0]):this._ambigTime?ma(this,"YYYY-MM-DD"):this._ambigZone?ma(this,"YYYY-MM-DD[T]HH:mm:ss"):eb.format.apply(this,arguments)},db.toISOString=function(){return this._ambigTime?ma(this,"YYYY-MM-DD"):this._ambigZone?ma(this,"YYYY-MM-DD[T]HH:mm:ss"):eb.toISOString.apply(this,arguments)},
684// Querying
685// -------------------------------------------------------------------------------------------------
686// Is the moment within the specified range? `end` is exclusive.
687// FYI, this method is not a standard Moment method, so always do our enhanced logic.
688db.isWithin=function(a,b){var c=ja([this,a,b]);return c[0]>=c[1]&&c[0]<c[2]},
689// When isSame is called with units, timezone ambiguity is normalized before the comparison happens.
690// If no units specified, the two moments must be identically the same, with matching ambig flags.
691db.isSame=function(a,b){var c;
692// only do custom logic if this is an enhanced moment
693// only do custom logic if this is an enhanced moment
694return this._fullCalendar?b?(c=ja([this,a],!0),eb.isSame.call(c[0],c[1],b)):(a=Ta.moment.parseZone(a),eb.isSame.call(this,a)&&Boolean(this._ambigTime)===Boolean(a._ambigTime)&&Boolean(this._ambigZone)===Boolean(a._ambigZone)):eb.isSame.apply(this,arguments)},
695// Make these query methods work with ambiguous moments
696a.each(["isBefore","isAfter"],function(a,b){db[b]=function(a,c){var d;
697// only do custom logic if this is an enhanced moment
698// only do custom logic if this is an enhanced moment
699return this._fullCalendar?(d=ja([this,a]),eb[b].call(d[0],d[1],c)):eb[b].apply(this,arguments)}}),Za="_d"in b()&&"updateOffset"in b,$a=Za?function(a,c){a._d.setTime(Date.UTC.apply(Date,c)),b.updateOffset(a,!1)}:la,_a=Za?function(a,c){a._d.setTime(+new Date(c[0]||0,c[1]||0,c[2]||0,c[3]||0,c[4]||0,c[5]||0,c[6]||0)),b.updateOffset(a,!1)}:la;
700// addition formatting tokens we want recognized
701var fb={t:function(a){// "a" or "p"
702return ma(a,"a").charAt(0)},T:function(a){// "A" or "P"
703return ma(a,"A").charAt(0)}};Ta.formatRange=qa;var gb={Y:"year",M:"month",D:"day",// day of month
704d:"day",// day of week
705// prevents a separator between anything time-related...
706A:"second",// AM/PM
707a:"second",// am/pm
708T:"second",// A/P
709t:"second",// a/p
710H:"second",// hour (24)
711h:"second",// hour (12)
712m:"second",// minute
713s:"second"},hb={};Ta.Class=va,
714// Called on a class to create a subclass.
715// Last argument contains instance methods. Any argument before the last are considered mixins.
716va.extend=function(){var a,b,c=arguments.length;for(a=0;c>a;a++)b=arguments[a],c-1>a&&xa(this,b);return wa(this,b||{})},
717// Adds new member variables/methods to the class's prototype.
718// Can be called with another class, or a plain object hash containing new members.
719va.mixin=function(a){xa(this,a)};var ib=Ta.EmitterMixin={callbackHash:null,on:function(a,b){return this.loopCallbacks(a,"add",[b]),this},off:function(a,b){return this.loopCallbacks(a,"remove",[b]),this},trigger:function(a){// args...
720var b=Array.prototype.slice.call(arguments,1);return this.triggerWith(a,this,b),this},triggerWith:function(a,b,c){return this.loopCallbacks(a,"fireWith",[b,c]),this},/*
721	Given an event name string with possible namespaces,
722	call the given methodName on all the internal Callback object with the given arguments.
723	*/
724loopCallbacks:function(a,b,c){var d,e,f,g=a.split(".");for(d=0;d<g.length;d++)e=g[d],e&&(f=this.ensureCallbackObj((d?".":"")+e),f[b].apply(f,c))},ensureCallbackObj:function(b){return this.callbackHash||(this.callbackHash={}),this.callbackHash[b]||(this.callbackHash[b]=a.Callbacks()),this.callbackHash[b]}},jb=Ta.ListenerMixin=function(){var b=0,c={listenerId:null,/*
725		Given an `other` object that has on/off methods, bind the given `callback` to an event by the given name.
726		The `callback` will be called with the `this` context of the object that .listenTo is being called on.
727		Can be called:
728			.listenTo(other, eventName, callback)
729		OR
730			.listenTo(other, {
731				eventName1: callback1,
732				eventName2: callback2
733			})
734		*/
735listenTo:function(b,c,d){if("object"==typeof c)// given dictionary of callbacks
736for(var e in c)c.hasOwnProperty(e)&&this.listenTo(b,e,c[e]);else"string"==typeof c&&b.on(c+"."+this.getListenerNamespace(),// use event namespacing to identify this object
737a.proxy(d,this))},/*
738		Causes the current object to stop listening to events on the `other` object.
739		`eventName` is optional. If omitted, will stop listening to ALL events on `other`.
740		*/
741stopListeningTo:function(a,b){a.off((b||"")+"."+this.getListenerNamespace())},/*
742		Returns a string, unique to this object, to be used for event namespacing
743		*/
744getListenerNamespace:function(){return null==this.listenerId&&(this.listenerId=b++),"_listener"+this.listenerId}};return c}(),kb=va.extend(jb,{isHidden:!0,options:null,el:null,// the container element for the popover. generated by this object
745margin:10,// the space required between the popover and the edges of the scroll container
746constructor:function(a){this.options=a||{}},
747// Shows the popover on the specified position. Renders it if not already
748show:function(){this.isHidden&&(this.el||this.render(),this.el.show(),this.position(),this.isHidden=!1,this.trigger("show"))},
749// Hides the popover, through CSS, but does not remove it from the DOM
750hide:function(){this.isHidden||(this.el.hide(),this.isHidden=!0,this.trigger("hide"))},
751// Creates `this.el` and renders content inside of it
752render:function(){var b=this,c=this.options;this.el=a('<div class="fc-popover"/>').addClass(c.className||"").css({
753// position initially to the top left to avoid creating scrollbars
754top:0,left:0}).append(c.content).appendTo(c.parentEl),
755// when a click happens on anything inside with a 'fc-close' className, hide the popover
756this.el.on("click",".fc-close",function(){b.hide()}),c.autoHide&&this.listenTo(a(document),"mousedown",this.documentMousedown)},
757// Triggered when the user clicks *anywhere* in the document, for the autoHide feature
758documentMousedown:function(b){
759// only hide the popover if the click happened outside the popover
760this.el&&!a(b.target).closest(this.el).length&&this.hide()},
761// Hides and unregisters any handlers
762removeElement:function(){this.hide(),this.el&&(this.el.remove(),this.el=null),this.stopListeningTo(a(document),"mousedown")},
763// Positions the popover optimally, using the top/left/right options
764position:function(){var b,c,d,e,f,g=this.options,h=this.el.offsetParent().offset(),i=this.el.outerWidth(),j=this.el.outerHeight(),k=a(window),l=m(this.el);e=g.top||0,f=void 0!==g.left?g.left:void 0!==g.right?g.right-i:0,l.is(window)||l.is(document)?(l=k,b=0,c=0):(d=l.offset(),b=d.top,c=d.left),b+=k.scrollTop(),c+=k.scrollLeft(),g.viewportConstrain!==!1&&(e=Math.min(e,b+l.outerHeight()-j-this.margin),e=Math.max(e,b+this.margin),f=Math.min(f,c+l.outerWidth()-i-this.margin),f=Math.max(f,c+this.margin)),this.el.css({top:e-h.top,left:f-h.left})},
765// Triggers a callback. Calls a function in the option hash of the same name.
766// Arguments beyond the first `name` are forwarded on.
767// TODO: better code reuse for this. Repeat code
768trigger:function(a){this.options[a]&&this.options[a].apply(this,Array.prototype.slice.call(arguments,1
768))}}),lb=Ta.CoordCache=va.extend({els:null,// jQuery set (assumed to be siblings)
769forcedOffsetParentEl:null,// options can override the natural offsetParent
770origin:null,// {left,top} position of offsetParent of els
771boundingRect:null,// constrain cordinates to this rectangle. {left,right,top,bottom} or null
772isHorizontal:!1,// whether to query for left/right/width
773isVertical:!1,// whether to query for top/bottom/height
774// arrays of coordinates (offsets from topleft of document)
775lefts:null,rights:null,tops:null,bottoms:null,constructor:function(b){this.els=a(b.els),this.isHorizontal=b.isHorizontal,this.isVertical=b.isVertical,this.forcedOffsetParentEl=b.offsetParent?a(b.offsetParent):null},
776// Queries the els for coordinates and stores them.
777// Call this method before using and of the get* methods below.
778build:function(){var a=this.forcedOffsetParentEl||this.els.eq(0).offsetParent();this.origin=a.offset(),this.boundingRect=this.queryBoundingRect(),this.isHorizontal&&this.buildElHorizontals(),this.isVertical&&this.buildElVerticals()},
779// Destroys all internal data about coordinates, freeing memory
780clear:function(){this.origin=null,this.boundingRect=null,this.lefts=null,this.rights=null,this.tops=null,this.bottoms=null},
781// When called, if coord caches aren't built, builds them
782ensureBuilt:function(){this.origin||this.build()},
783// Compute and return what the elements' bounding rectangle is, from the user's perspective.
784// Right now, only returns a rectangle if constrained by an overflow:scroll element.
785queryBoundingRect:function(){var a=m(this.els.eq(0));return a.is(document)?void 0:o(a)},
786// Populates the left/right internal coordinate arrays
787buildElHorizontals:function(){var b=[],c=[];this.els.each(function(d,e){var f=a(e),g=f.offset().left,h=f.outerWidth();b.push(g),c.push(g+h)}),this.lefts=b,this.rights=c},
788// Populates the top/bottom internal coordinate arrays
789buildElVerticals:function(){var b=[],c=[];this.els.each(function(d,e){var f=a(e),g=f.offset().top,h=f.outerHeight();b.push(g),c.push(g+h)}),this.tops=b,this.bottoms=c},
790// Given a left offset (from document left), returns the index of the el that it horizontally intersects.
791// If no intersection is made, or outside of the boundingRect, returns undefined.
792getHorizontalIndex:function(a){this.ensureBuilt();var b,c=this.boundingRect,d=this.lefts,e=this.rights,f=d.length;if(!c||a>=c.left&&a<c.right)for(b=0;f>b;b++)if(a>=d[b]&&a<e[b])return b},
793// Given a top offset (from document top), returns the index of the el that it vertically intersects.
794// If no intersection is made, or outside of the boundingRect, returns undefined.
795getVerticalIndex:function(a){this.ensureBuilt();var b,c=this.boundingRect,d=this.tops,e=this.bottoms,f=d.length;if(!c||a>=c.top&&a<c.bottom)for(b=0;f>b;b++)if(a>=d[b]&&a<e[b])return b},
796// Gets the left offset (from document left) of the element at the given index
797getLeftOffset:function(a){return this.ensureBuilt(),this.lefts[a]},
798// Gets the left position (from offsetParent left) of the element at the given index
799getLeftPosition:function(a){return this.ensureBuilt(),this.lefts[a]-this.origin.left},
800// Gets the right offset (from document left) of the element at the given index.
801// This value is NOT relative to the document's right edge, like the CSS concept of "right" would be.
802getRightOffset:function(a){return this.ensureBuilt(),this.rights[a]},
803// Gets the right position (from offsetParent left) of the element at the given index.
804// This value is NOT relative to the offsetParent's right edge, like the CSS concept of "right" would be.
805getRightPosition:function(a){return this.ensureBuilt(),this.rights[a]-this.origin.left},
806// Gets the width of the element at the given index
807getWidth:function(a){return this.ensureBuilt(),this.rights[a]-this.lefts[a]},
808// Gets the top offset (from document top) of the element at the given index
809getTopOffset:function(a){return this.ensureBuilt(),this.tops[a]},
810// Gets the top position (from offsetParent top) of the element at the given position
811getTopPosition:function(a){return this.ensureBuilt(),this.tops[a]-this.origin.top},
812// Gets the bottom offset (from the document top) of the element at the given index.
813// This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
814getBottomOffset:function(a){return this.ensureBuilt(),this.bottoms[a]},
815// Gets the bottom position (from the offsetParent top) of the element at the given index.
816// This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
817getBottomPosition:function(a){return this.ensureBuilt(),this.bottoms[a]-this.origin.top},
818// Gets the height of the element at the given index
819getHeight:function(a){return this.ensureBuilt(),this.bottoms[a]-this.tops[a]}}),mb=Ta.DragListener=va.extend(jb,{options:null,
820// for IE8 bug-fighting behavior
821subjectEl:null,subjectHref:null,
822// coordinates of the initial mousedown
823originX:null,originY:null,scrollEl:null,isInteracting:!1,isDistanceSurpassed:!1,isDelayEnded:!1,isDragging:!1,isTouch:!1,delay:null,delayTimeoutId:null,minDistance:null,constructor:function(a){this.options=a||{}},
824// Interaction (high-level)
825// -----------------------------------------------------------------------------------------------------------------
826startInteraction:function(b,c){var d=x(b);if("mousedown"===b.type){if(!u(b))return;b.preventDefault()}this.isInteracting||(c=c||{},this.delay=_(c.delay,this.options.delay,0),this.minDistance=_(c.distance,this.options.distance,0),this.subjectEl=this.options.subjectEl,this.isInteracting=!0,this.isTouch=d,this.isDelayEnded=!1,this.isDistanceSurpassed=!1,this.originX=v(b),this.originY=w(b),this.scrollEl=m(a(b.target)),this.bindHandlers(),this.initAutoScroll(),this.handleInteractionStart(b),this.startDelay(b),this.minDistance||this.handleDistanceSurpassed(b))},handleInteractionStart:function(a){this.trigger("interactionStart",a)},endInteraction:function(a){this.isInteracting&&(this.endDrag(a),this.delayTimeoutId&&(clearTimeout(this.delayTimeoutId),this.delayTimeoutId=null),this.destroyAutoScroll(),this.unbindHandlers(),this.isInteracting=!1,this.handleInteractionEnd(a))},handleInteractionEnd:function(a){this.trigger("interactionEnd",a)},
827// Binding To DOM
828// -----------------------------------------------------------------------------------------------------------------
829bindHandlers:function(){var b=this,c=1;this.isTouch?(this.listenTo(a(document),{touchmove:this.handleTouchMove,touchend:this.endInteraction,touchcancel:this.endInteraction,
830// Sometimes touchend doesn't fire
831// (can't figure out why. touchcancel doesn't fire either. has to do with scrolling?)
832// If another touchstart happens, we know it's bogus, so cancel the drag.
833// touchend will continue to be broken until user does a shorttap/scroll, but this is best we can do.
834touchstart:function(a){c?// bindHandlers is called from within a touchstart,
835c--:b.endInteraction(a)}}),this.scrollEl&&this.listenTo(this.scrollEl,"scroll",this.handleTouchScroll)):this.listenTo(a(document),{mousemove:this.handleMouseMove,mouseup:this.endInteraction}),this.listenTo(a(document),{selectstart:z,// don't allow selection while dragging
836contextmenu:z})},unbindHandlers:function(){this.stopListeningTo(a(document)),this.scrollEl&&this.stopListeningTo(this.scrollEl)},
837// Drag (high-level)
838// -----------------------------------------------------------------------------------------------------------------
839// extraOptions ignored if drag already started
840startDrag:function(a,b){this.startInteraction(a,b),// ensure interaction began
841this.isDragging||(this.isDragging=!0,this.handleDragStart(a))},handleDragStart:function(a){this.trigger("dragStart",a),this.initHrefHack()},handleMove:function(a){var b,c=v(a)-this.originX,d=w(a)-this.originY,e=this.minDistance;// current distance from the origin, squared
842this.isDistanceSurpassed||(b=c*c+d*d,b>=e*e&&this.handleDistanceSurpassed(a)),this.isDragging&&this.handleDrag(c,d,a)},
843// Called while the mouse is being moved and when we know a legitimate drag is taking place
844handleDrag:function(a,b,c){this.trigger("drag",a,b,c),this.updateAutoScroll(c)},endDrag:function(a){this.isDragging&&(this.isDragging=!1,this.handleDragEnd(a))},handleDragEnd:function(a){this.trigger("dragEnd",a),this.destroyHrefHack()},
845// Delay
846// -----------------------------------------------------------------------------------------------------------------
847startDelay:function(a){var b=this;this.delay?this.delayTimeoutId=setTimeout(function(){b.handleDelayEnd(a)},this.delay):this.handleDelayEnd(a)},handleDelayEnd:function(a){this.isDelayEnded=!0,this.isDistanceSurpassed&&this.startDrag(a)},
848// Distance
849// -----------------------------------------------------------------------------------------------------------------
850handleDistanceSurpassed:function(a){this.isDistanceSurpassed=!0,this.isDelayEnded&&this.startDrag(a)},
851// Mouse / Touch
852// -----------------------------------------------------------------------------------------------------------------
853handleTouchMove:function(a){
854// prevent inertia and touchmove-scrolling while dragging
855this.isDragging&&a.preventDefault(),this.handleMove(a)},handleMouseMove:function(a){this.handleMove(a)},
856// Scrolling (unrelated to auto-scroll)
857// -----------------------------------------------------------------------------------------------------------------
858handleTouchScroll:function(a){
859// if the drag is being initiated by touch, but a scroll happens before
860// the drag-initiating delay is over, cancel the drag
861this.isDragging||this.endInteraction(a)},
862// <A> HREF Hack
863// -----------------------------------------------------------------------------------------------------------------
864initHrefHack:function(){var a=this.subjectEl;
865// remove a mousedown'd <a>'s href so it is not visited (IE8 bug)
866(this.subjectHref=a?a.attr("href"):null)&&a.removeAttr("href")},destroyHrefHack:function(){var a=this.subjectEl,b=this.subjectHref;
867// restore a mousedown'd <a>'s href (for IE8 bug)
868setTimeout(function(){// must be outside of the click's execution
869b&&a.attr("href",b)},0)},
870// Utils
871// -----------------------------------------------------------------------------------------------------------------
872// Triggers a callback. Calls a function in the option hash of the same name.
873// Arguments beyond the first `name` are forwarded on.
874trigger:function(a){this.options[a]&&this.options[a].apply(this,Array.prototype.slice.call(arguments,1)),
875// makes _methods callable by event name. TODO: kill this
876this["_"+a]&&this["_"+a].apply(this,Array.prototype.slice.call(arguments,1))}});/*
877this.scrollEl is set in DragListener
878*/
879mb.mixin({isAutoScroll:!1,scrollBounds:null,// { top, bottom, left, right }
880scrollTopVel:null,// pixels per second
881scrollLeftVel:null,// pixels per second
882scrollIntervalId:null,// ID of setTimeout for scrolling animation loop
883// defaults
884scrollSensitivity:30,// pixels from edge for scrolling to start
885scrollSpeed:200,// pixels per second, at maximum speed
886scrollIntervalMs:50,// millisecond wait between scroll increment
887initAutoScroll:function(){var a=this.scrollEl;this.isAutoScroll=this.options.scroll&&a&&!a.is(window)&&!a.is(document),this.isAutoScroll&&
888// debounce makes sure rapid calls don't happen
889this.listenTo(a,"scroll",ha(this.handleDebouncedScroll,100))},destroyAutoScroll:function(){this.endAutoScroll(),// kill any animation loop
890// remove the scroll handler if there is a scrollEl
891this.isAutoScroll&&this.stopListeningTo(this.scrollEl,"scroll")},
892// Computes and stores the bounding rectangle of scrollEl
893computeScrollBounds:function(){this.isAutoScroll&&(this.scrollBounds=n(this.scrollEl))},
894// Called when the dragging is in progress and scrolling should be updated
895updateAutoScroll:function(a){var b,c,d,e,f=this.scrollSensitivity,g=this.scrollBounds,h=0,i=0;g&&(b=(f-(w(a)-g.top))/f,c=(f-(g.bottom-w(a)))/f,d=(f-(v(a)-g.left))/f,e=(f-(g.right-v(a)))/f,b>=0&&1>=b?h=b*this.scrollSpeed*-1:c>=0&&1>=c&&(h=c*this.scrollSpeed),d>=0&&1>=d?i=d*this.scrollSpeed*-1:e>=0&&1>=e&&(i=e*this.scrollSpeed)),this.setScrollVel(h,i)},
896// Sets the speed-of-scrolling for the scrollEl
897setScrollVel:function(a,b){this.scrollTopVel=a,this.scrollLeftVel=b,this.constrainScrollVel(),// massages into realistic values
898// if there is non-zero velocity, and an animation loop hasn't already started, then START
899!this.scrollTopVel&&!this.scrollLeftVel||this.scrollIntervalId||(this.scrollIntervalId=setInterval(ga(this,"scrollIntervalFunc"),// scope to `this`
900this.scrollIntervalMs))},
901// Forces scrollTopVel and scrollLeftVel to be zero if scrolling has already gone all the way
902constrainScrollVel:function(){var a=this.scrollEl;this.scrollTopVel<0?// scrolling up?
903a.scrollTop()<=0&&(// already scrolled all the way up?
904this.scrollTopVel=0):this.scrollTopVel>0&&a.scrollTop()+a[0].clientHeight>=a[0].scrollHeight&&(// already scrolled all the way down?
905this.scrollTopVel=0),this.scrollLeftVel<0?// scrolling left?
906a.scrollLeft()<=0&&(// already scrolled all the left?
907this.scrollLeftVel=0):this.scrollLeftVel>0&&a.scrollLeft()+a[0].clientWidth>=a[0].scrollWidth&&(// already scrolled all the way right?
908this.scrollLeftVel=0)},
909// This function gets called during every iteration of the scrolling animation loop
910scrollIntervalFunc:function(){var a=this.scrollEl,b=this.scrollIntervalMs/1e3;// considering animation frequency, what the vel should be mult'd by
911// change the value of scrollEl's scroll
912this.scrollTopVel&&a.scrollTop(a.scrollTop()+this.scrollTopVel*b),this.scrollLeftVel&&a.scrollLeft(a.scrollLeft()+this.scrollLeftVel*b),this.constrainScrollVel(),// since the scroll values changed, recompute the velocities
913// if scrolled all the way, which causes the vels to be zero, stop the animation loop
914this.scrollTopVel||this.scrollLeftVel||this.endAutoScroll()},
915// Kills any existing scrolling animation loop
916endAutoScroll:function(){this.scrollIntervalId&&(clearInterval(this.scrollIntervalId),this.scrollIntervalId=null,this.handleScrollEnd())},
917// Get called when the scrollEl is scrolled (NOTE: this is delayed via debounce)
918handleDebouncedScroll:function(){
919// recompute all coordinates, but *only* if this is *not* part of our scrolling animation
920this.scrollIntervalId||this.handleScrollEnd()},
921// Called when scrolling has stopped, whether through auto scroll, or the user scrolling
922handleScrollEnd:function(){}});/* Tracks mouse movements over a component and raises events about which hit the mouse is over.
923------------------------------------------------------------------------------------------------------------------------
924options:
925- subjectEl
926- subjectCenter
927*/
928var nb=mb.extend({component:null,// converts coordinates to hits
929// methods: prepareHits, releaseHits, queryHit
930origHit:null,// the hit the mouse was over when listening started
931hit:null,// the hit the mouse is over
932coordAdjust:null,// delta that will be added to the mouse coordinates when computing collisions
933constructor:function(a,b){mb.call(this,b),// call the super-constructor
934this.component=a},
935// Called when drag listening starts (but a real drag has not necessarily began).
936// ev might be undefined if dragging was started manually.
937handleInteractionStart:function(a){var b,c,d,e=this.subjectEl;this.computeCoords(),a?(c={left:v(a),top:w(a)},d=c,e&&(b=n(e),d=B(d,b)),this.origHit=this.queryHit(d.left,d.top),e&&this.options.subjectCenter&&(this.origHit&&(b=A(this.origHit,b)||b),d=C(b)),this.coordAdjust=D(d,c)):(this.origHit=null,this.coordAdjust=null),
938// call the super-method. do it after origHit has been computed
939mb.prototype.handleInteractionStart.apply(this,arguments)},
940// Recomputes the drag-critical positions of elements
941computeCoords:function(){this.component.prepareHits(),this.computeScrollBounds()},
942// Called when the actual drag has started
943handleDragStart:function(a){var b;mb.prototype.handleDragStart.apply(this,arguments),b=this.queryHit(v(a),w(a)),b&&this.handleHitOver(b)},
944// Called when the drag moves
945handleDrag:function(a,b,c){var d;mb.prototype.handleDrag.apply(this,arguments),d=this.queryHit(v(c),w(c)),ya(d,this.hit)||(this.hit&&this.handleHitOut(),d&&this.handleHitOver(d))},
946// Called when dragging has been stopped
947handleDragEnd:function(){this.handleHitDone(),mb.prototype.handleDragEnd.apply(this,arguments)},
948// Called when a the mouse has just moved over a new hit
949handleHitOver:function(a){var b=ya(a,this.origHit);this.hit=a,this.trigger("hitOver",this.hit,b,this.origHit)},
950// Called when the mouse has just moved out of a hit
951handleHitOut:function(){this.hit&&(this.trigger("hitOut",this.hit),this.handleHitDone(),this.hit=null)},
952// Called after a hitOut. Also called before a dragStop
953handleHitDone:function(){this.hit&&this.trigger("hitDone",this.hit)},
954// Called when the interaction ends, whether there was a real drag or not
955handleInteractionEnd:function(){mb.prototype.handleInteractionEnd.apply(this,arguments),// call the super-method
956this.origHit=null,this.hit=null,this.component.releaseHits()},
957// Called when scrolling has stopped, whether through auto scroll, or the user scrolling
958handleScrollEnd:function(){mb.prototype.handleScrollEnd.apply(this,arguments),// call the super-method
959this.computeCoords()},
960// Gets the hit underneath the coordinates for the given mouse event
961queryHit:function(a,b){return this.coordAdjust&&(a+=this.coordAdjust.left,b+=this.coordAdjust.top),this.component.queryHit(a,b)}}),ob=va.extend(jb,{options:null,sourceEl:null,// the element that will be cloned and made to look like it is dragging
962el:null,// the clone of `sourceEl` that will track the mouse
963parentEl:null,// the element that `el` (the clone) will be attached to
964// the initial position of el, relative to the offset parent. made to match the initial offset of sourceEl
965top0:null,left0:null,
966// the absolute coordinates of the initiating touch/mouse action
967y0:null,x0:null,
968// the number of pixels the mouse has moved from its initial position
969topDelta:null,leftDelta:null,isFollowing:!1,isHidden:!1,isAnimating:!1,// doing the revert animation?
970constructor:function(b,c){this.options=c=c||{},this.sourceEl=b,this.parentEl=c.parentEl?a(c.parentEl):b.parent()},
971// Causes the element to start following the mouse
972start:function(b){this.isFollowing||(this.isFollowing=!0,this.y0=w(b),this.x0=v(b),this.topDelta=0,this.leftDelta=0,this.isHidden||this.updatePosition(),x(b)?this.listenTo(a(document),"touchmove",this.handleMove):this.listenTo(a(document),"mousemove",this.handleMove))},
973// Causes the element to stop following the mouse. If shouldRevert is true, will animate back to original position.
974// `callback` gets invoked when the animation is complete. If no animation, it is invoked immediately.
975stop:function(b,c){function d(){this.isAnimating=!1,e.removeElement(),this.top0=this.left0=null,// reset state for future updatePosition calls
976c&&c()}var e=this,f=this.options.revertDuration;this.isFollowing&&!this.isAnimating&&(// disallow more than one stop animation at a time
977this.isFollowing=!1,this.stopListeningTo(a(document)),b&&f&&!this.isHidden?(// do a revert animation?
978this.isAnimating=!0,this.el.animate({top:this.top0,left:this.left0},{duration:f,complete:d})):d())},
979// Gets the tracking element. Create it if necessary
980getEl:function(){var a=this.el;// hack to force IE8 to compute correct bounding box
981// we don't want long taps or any mouse interaction causing selection/menus.
982// would use preventSelection(), but that prevents selectstart, causing problems.
983return a||(this.sourceEl.width(),a=this.el=this.sourceEl.clone().addClass(this.options.additionalClass||"").css({position:"absolute",visibility:"",// in case original element was hidden (commonly through hideEvents())
984display:this.isHidden?"none":"",// for when initially hidden
985margin:0,right:"auto",// erase and set width instead
986bottom:"auto",// erase and set height instead
987width:this.sourceEl.width(),// explicit height in case there was a 'right' value
988height:this.sourceEl.height(),// explicit width in case there was a 'bottom' value
989opacity:this.options.opacity||"",zIndex:this.options.zIndex}),a.addClass("fc-unselectable"),a.appendTo(this.parentEl)),a},
990// Removes the tracking element if it has already been created
991removeElement:function(){this.el&&(this.el.remove(),this.el=null)},
992// Update the CSS position of the tracking element
993updatePosition:function(){var a,b;this.getEl(),// ensure this.el
994// make sure origin info was computed
995null===this.top0&&(this.sourceEl.width(),a=this.sourceEl.offset(),b=this.el.offsetParent().offset(),this.top0=a.top-b.top,this.left0=a.left-b.left),this.el.css({top:this.top0+this.topDelta,left:this.left0+this.leftDelta})},
996// Gets called when the user moves the mouse
997handleMove:function(a){this.topDelta=w(a)-this.y0,this.leftDelta=v(a)-this.x0,this.isHidden||this.updatePosition()},
998// Temporarily makes the tracking element invisible. Can be called before following starts
999hide:function(){this.isHidden||(this.isHidden=!0,this.el&&this.el.hide())},
1000// Show the tracking element after it has been temporarily hidden
1001show:function(){this.isHidden&&(this.isHidden=!1,this.updatePosition(),this.getEl().show())}}),pb=Ta.Grid=va.extend(jb,{view:null,// a View object
1002isRTL:null,// shortcut to the view's isRTL option
1003start:null,end:null,el:null,// the containing element
1004elsByFill:null,// a hash of jQuery element sets used for rendering each fill. Keyed by fill name.
1005// derived from options
1006eventTimeFormat:null,displayEventTime:null,displayEventEnd:null,minResizeDuration:null,// TODO: hack. set by subclasses. minumum event resize duration
1007// if defined, holds the unit identified (ex: "year" or "month") that determines the level of granularity
1008// of the date areas. if not defined, assumes to be day and time granularity.
1009// TODO: port isTimeScale into same system?
1010largeUnit:null,dayDragListener:null,segDragListener:null,segResizeListener:null,externalDragListener:null,constructor:function(a){this.view=a,this.isRTL=a.opt("isRTL"),this.elsByFill={}},/* Options
1011	------------------------------------------------------------------------------------------------------------------*/
1012// Generates the format string used for event time text, if not explicitly defined by 'timeFormat'
1013computeEventTimeFormat:function(){return this.view.opt("smallTimeFormat")},
1014// Determines whether events should have their end times displayed, if not explicitly defined by 'displayEventTime'.
1015// Only applies to non-all-day events.
1016computeDisplayEventTime:function(){return!0},
1017// Determines whether events should have their end times displayed, if not explicitly defined by 'displayEventEnd'
1018computeDisplayEventEnd:function(){return!0},/* Dates
1019	------------------------------------------------------------------------------------------------------------------*/
1020// Tells the grid about what period of time to display.
1021// Any date-related internal data should be generated.
1022setRange:function(a){this.start=a.start.clone(),this.end=a.end.clone(),this.rangeUpdated(),this.processRangeOptions()},
1023// Called when internal variables that rely on the range should be updated
1024rangeUpdated:function(){},
1025// Updates values that rely on options and also relate to range
1026processRangeOptions:function(){var a,b,c=this.view;this.eventTimeFormat=c.opt("eventTimeFormat")||c.opt("timeFormat")||// deprecated
1027this.computeEventTimeFormat(),a=c.opt("displayEventTime"),null==a&&(a=this.computeDisplayEventTime()),b=c.opt("displayEventEnd"),null==b&&(b=this.computeDisplayEventEnd()),this.displayEventTime=a,this.displayEventEnd=b},
1028// Converts a span (has unzoned start/end and any other grid-specific location information)
1029// into an array of segments (pieces of events whose format is decided by the grid).
1030spanToSegs:function(a){},
1031// Diffs the two dates, returning a duration, based on granularity of the grid
1032// TODO: port isTimeScale into this system?
1033diffDates:function(a,b){return this.largeUnit?L(a,b,this.largeUnit):J(a,b)},/* Hit Area
1034	------------------------------------------------------------------------------------------------------------------*/
1035// Called before one or more queryHit calls might happen. Should prepare any cached coordinates for queryHit
1036prepareHits:function(){},
1037// Called when queryHit calls have subsided. Good place to clear any coordinate caches.
1038releaseHits:function(){},
1039// Given coordinates from the topleft of the document, return data about the date-related area underneath.
1040// Can return an object with arbitrary properties (although top/right/left/bottom are encouraged).
1041// Must have a `grid` property, a reference to this current grid. TODO: avoid this
1042// The returned object will be processed by getHitSpan and getHitEl.
1043queryHit:function(a,b){},
1044// Given position-level information about a date-related area within the grid,
1045// should return an object with at least a start/end date. Can provide other information as well.
1046getHitSpan:function(a){},
1047// Given position-level information about a date-related area within the grid,
1048// should return a jQuery element that best represents it. passed to dayClick callback.
1049getHitEl:function(a){},/* Rendering
1050	------------------------------------------------------------------------------------------------------------------*/
1051// Sets the container element that the grid should render inside of.
1052// Does other DOM-related initializations.
1053setElement:function(a){this.el=a,y(a),this.view.calendar.isTouch?this.bindDayHandler("touchstart",this.dayTouchStart):this.bindDayHandler("mousedown",this.dayMousedown),
1054// attach event-element-related handlers. in Grid.events
1055// same garbage collection note as above.
1056this.bindSegHandlers(),this.bindGlobalHandlers()},bindDayHandler:function(b,c){var d=this;
1057// attach a handler to the grid's root element.
1058// jQuery will take care of unregistering them when removeElement gets called.
1059this.el.on(b,function(b){return a(b.target).is(".fc-event-container *, .fc-more")||a(b.target).closest(".fc-popover").length?void 0:c.call(d,b)})},
1060// Removes the grid's container element from the DOM. Undoes any other DOM-related attachments.
1061// DOES NOT remove any content beforehand (doesn't clear events or call unrenderDates), unlike View
1062removeElement:function(){this.unbindGlobalHandlers(),this.clearDragListeners(),this.el.remove()},
1063// Renders the basic structure of grid view before any content is rendered
1064renderSkeleton:function(){},
1065// Renders the grid's date-related content (like areas that represent days/times).
1066// Assumes setRange has already been called and the skeleton has already been rendered.
1067renderDates:function(){},
1068// Unrenders the grid's date-related content
1069unrenderDates:function(){},/* Handlers
1070	------------------------------------------------------------------------------------------------------------------*/
1071// Binds DOM handlers to elements that reside outside the grid, such as the document
1072bindGlobalHandlers:function(){this.listenTo(a(document),{dragstart:this.externalDragStart,// jqui
1073sortstart:this.externalDragStart})},
1074// Unbinds DOM handlers from elements that reside outside the grid
1075unbindGlobalHandlers:function(){this.stopListeningTo(a(document))},
1076// Process a mousedown on an element that represents a day. For day clicking and selecting.
1077dayMousedown:function(a){this.clearDragListeners(),this.buildDayDragListener().startInteraction(a,{})},dayTouchStart:function(a){this.clearDragListeners(),this.buildDayDragListener().startInteraction(a,{delay:this.view.opt("longPressDelay")})},
1078// Creates a listener that tracks the user's drag across day elements.
1079// For day clicking and selecting.
1080buildDayDragListener:function(){var a,b,c=this,d=this.view,e=d.opt("selectable"),f=this.dayDragListener=new nb(this,{scroll:d.opt("dragScroll"),interactionStart:function(){a=f.origHit},dragStart:function(){d.unselect()},hitOver:function(d,f,h){h&&(// click needs to have started on a hit
1081// if user dragged to another cell at any point, it can no longer be a dayClick
1082f||(a=null),e&&(b=c.computeSelection(c.getHitSpan(h),c.getHitSpan(d)),b?c.renderSelection(b):b===!1&&g()))},hitOut:function(){a=null,b=null,c.unrenderSelection(),h()},interactionEnd:function(e){a&&d.triggerDayClick(c.getHitSpan(a),c.getHitEl(a),e),b&&
1083// the selection will already have been rendered. just report it
1084d.reportSelection(b,e),h(),c.dayDragListener=null}});return f},
1085// Kills all in-progress dragging.
1086// Useful for when public API methods that result in re-rendering are invoked during a drag.
1087// Also useful for when touch devices misbehave and don't fire their touchend.
1088clearDragListeners:function(){this.dayDragListener&&this.dayDragListener.endInteraction(),this.segDragListener&&this.segDragListener.endInteraction(),this.segResizeListener&&this.segResizeListener.endInteraction(),this.externalDragListener&&this.externalDragListener.endInteraction()},/* Event Helper
1089	------------------------------------------------------------------------------------------------------------------*/
1090// TODO: should probably move this to Grid.events, like we did event dragging / resizing
1091// Renders a mock event at the given event location, which contains zoned start/end properties.
1092// Returns all mock event elements.
1093renderEventLocationHelper:function(a,b){var c=this.fabricateHelperEvent(a,b);return this.renderHelper(c,b)},
1094// Builds a fake event given zoned event date properties and a segment is should be inspired from.
1095// The range's end can be null, in which case the mock event that is rendered will have a null end time.
1096// `sourceSeg` is the internal segment object involved in the drag. If null, something external is dragging.
1097fabricateHelperEvent:function(a,b){var c=b?V(b.event):{};// mask the original event object if possible
1098// force it to be freshly computed by normalizeEventDates
1099// this extra className will be useful for differentiating real events from mock events in CSS
1100// if something external is being dragged in, don't render a resizer
1101return c.start=a.start.clone(),c.end=a.end?a.end.clone():null,c.allDay=null,this.view.calendar.normalizeEventDates(c),c.className=(c.className||[]).concat("fc-helper"),b||(c.editable=!1),c},
1102// Renders a mock event. Given zoned event date properties.
1103// Must return all mock event elements.
1104renderHelper:function(a,b){},
1105// Unrenders a mock event
1106unrenderHelper:function(){},/* Selection
1107	------------------------------------------------------------------------------------------------------------------*/
1108// Renders a visual indication of a selection. Will highlight by default but can be overridden by subclasses.
1109// Given a span (unzoned start/end and other misc data)
1110renderSelection:function(a){this.renderHighlight(a)},
1111// Unrenders any visual indications of a selection. Will unrender a highlight by default.
1112unrenderSelection:function(){this.unrenderHighlight()},
1113// Given the first and last date-spans of a selection, returns another date-span object.
1114// Subclasses can override and provide additional data in the span object. Will be passed to render
1114Selection().
1115// Will return false if the selection is invalid and this should be indicated to the user.
1116// Will return null/undefined if a selection invalid but no error should be reported.
1117computeSelection:function(a,b){var c=this.computeSelectionSpan(a,b);return c&&!this.view.calendar.isSelectionSpanAllowed(c)?!1:c},
1118// Given two spans, must return the combination of the two.
1119// TODO: do this separation of concerns (combining VS validation) for event dnd/resize too.
1120computeSelectionSpan:function(a,b){var c=[a.start,a.end,b.start,b.end];// sorts chronologically. works with Moments
1121return c.sort(ea),{start:c[0].clone(),end:c[3].clone()}},/* Highlight
1122	------------------------------------------------------------------------------------------------------------------*/
1123// Renders an emphasis on the given date range. Given a span (unzoned start/end and other misc data)
1124renderHighlight:function(a){this.renderFill("highlight",this.spanToSegs(a))},
1125// Unrenders the emphasis on a date range
1126unrenderHighlight:function(){this.unrenderFill("highlight")},
1127// Generates an array of classNames for rendering the highlight. Used by the fill system.
1128highlightSegClasses:function(){return["fc-highlight"]},/* Business Hours
1129	------------------------------------------------------------------------------------------------------------------*/
1130renderBusinessHours:function(){},unrenderBusinessHours:function(){},/* Now Indicator
1131	------------------------------------------------------------------------------------------------------------------*/
1132getNowIndicatorUnit:function(){},renderNowIndicator:function(a){},unrenderNowIndicator:function(){},/* Fill System (highlight, background events, business hours)
1133	--------------------------------------------------------------------------------------------------------------------
1134	TODO: remove this system. like we did in TimeGrid
1135	*/
1136// Renders a set of rectangles over the given segments of time.
1137// MUST RETURN a subset of segs, the segs that were actually rendered.
1138// Responsible for populating this.elsByFill. TODO: better API for expressing this requirement
1139renderFill:function(a,b){},
1140// Unrenders a specific type of fill that is currently rendered on the grid
1141unrenderFill:function(a){var b=this.elsByFill[a];b&&(b.remove(),delete this.elsByFill[a])},
1142// Renders and assigns an `el` property for each fill segment. Generic enough to work with different types.
1143// Only returns segments that successfully rendered.
1144// To be harnessed by renderFill (implemented by subclasses).
1145// Analagous to renderFgSegEls.
1146renderFillSegEls:function(b,c){var d,e=this,f=this[b+"SegEl"],g="",h=[];if(c.length){
1147// build a large concatenation of segment HTML
1148for(d=0;d<c.length;d++)g+=this.fillSegHtml(b,c[d]);
1149// Grab individual elements from the combined HTML string. Use each as the default rendering.
1150// Then, compute the 'el' for each segment.
1151a(g).each(function(b,d){var g=c[b],i=a(d);
1152// allow custom filter methods per-type
1153f&&(i=f.call(e,g,i)),i&&(i=a(i),i.is(e.fillSegTag)&&(g.el=i,h.push(g)))})}return h},fillSegTag:"div",// subclasses can override
1154// Builds the HTML needed for one fill segment. Generic enought o work with different types.
1155fillSegHtml:function(a,b){
1156// custom hooks per-type
1157var c=this[a+"SegClasses"],d=this[a+"SegCss"],e=c?c.call(this,b):[],f=ca(d?d.call(this,b):{});return"<"+this.fillSegTag+(e.length?' class="'+e.join(" ")+'"':"")+(f?' style="'+f+'"':"")+" />"},/* Generic rendering utilities for subclasses
1158	------------------------------------------------------------------------------------------------------------------*/
1159// Computes HTML classNames for a single-day element
1160getDayClasses:function(a){var b=this.view,c=b.calendar.getNow(),d=["fc-"+Xa[a.day()]];return 1==b.intervalDuration.as("months")&&a.month()!=b.intervalStart.month()&&d.push("fc-other-month"),a.isSame(c,"day")?d.push("fc-today",b.highlightStateClass):c>a?d.push("fc-past"):d.push("fc-future"),d}});/* Event-rendering and event-interaction methods for the abstract Grid class
1161----------------------------------------------------------------------------------------------------------------------*/
1162pb.mixin({mousedOverSeg:null,// the segment object the user's mouse is over. null if over nothing
1163isDraggingSeg:!1,// is a segment being dragged? boolean
1164isResizingSeg:!1,// is a segment being resized? boolean
1165isDraggingExternal:!1,// jqui-dragging an external element? boolean
1166segs:null,// the *event* segments currently rendered in the grid. TODO: rename to `eventSegs`
1167// Renders the given events onto the grid
1168renderEvents:function(a){var b,c=[],d=[];for(b=0;b<a.length;b++)(Aa(a[b])?c:d).push(a[b]);this.segs=[].concat(// record all segs
1169this.renderBgEvents(c),this.renderFgEvents(d))},renderBgEvents:function(a){var b=this.eventsToSegs(a);
1170// renderBgSegs might return a subset of segs, segs that were actually rendered
1171return this.renderBgSegs(b)||b},renderFgEvents:function(a){var b=this.eventsToSegs(a);
1172// renderFgSegs might return a subset of segs, segs that were actually rendered
1173return this.renderFgSegs(b)||b},
1174// Unrenders all events currently rendered on the grid
1175unrenderEvents:function(){this.handleSegMouseout(),// trigger an eventMouseout if user's mouse is over an event
1176this.clearDragListeners(),this.unrenderFgSegs(),this.unrenderBgSegs(),this.segs=null},
1177// Retrieves all rendered segment objects currently rendered on the grid
1178getEventSegs:function(){return this.segs||[]},/* Foreground Segment Rendering
1179	------------------------------------------------------------------------------------------------------------------*/
1180// Renders foreground event segments onto the grid. May return a subset of segs that were rendered.
1181renderFgSegs:function(a){},
1182// Unrenders all currently rendered foreground segments
1183unrenderFgSegs:function(){},
1184// Renders and assigns an `el` property for each foreground event segment.
1185// Only returns segments that successfully rendered.
1186// A utility that subclasses may use.
1187renderFgSegEls:function(b,c){var d,e=this.view,f="",g=[];if(b.length){// don't build an empty html string
1188// build a large concatenation of event segment HTML
1189for(d=0;d<b.length;d++)f+=this.fgSegHtml(b[d],c);
1190// Grab individual elements from the combined HTML string. Use each as the default rendering.
1191// Then, compute the 'el' for each segment. An el might be null if the eventRender callback returned false.
1192a(f).each(function(c,d){var f=b[c],h=e.resolveEventEl(f.event,a(d));h&&(h.data("fc-seg",f),// used by handlers
1193f.el=h,g.push(f))})}return g},
1194// Generates the HTML for the default rendering of a foreground event segment. Used by renderFgSegEls()
1195fgSegHtml:function(a,b){},/* Background Segment Rendering
1196	------------------------------------------------------------------------------------------------------------------*/
1197// Renders the given background event segments onto the grid.
1198// Returns a subset of the segs that were actually rendered.
1199renderBgSegs:function(a){return this.renderFill("bgEvent",a)},
1200// Unrenders all the currently rendered background event segments
1201unrenderBgSegs:function(){this.unrenderFill("bgEvent")},
1202// Renders a background event element, given the default rendering. Called by the fill system.
1203bgEventSegEl:function(a,b){return this.view.resolveEventEl(a.event,b)},
1204// Generates an array of classNames to be used for the default rendering of a background event.
1205// Called by the fill system.
1206bgEventSegClasses:function(a){var b=a.event,c=b.source||{};return["fc-bgevent"].concat(b.className,c.className||[])},
1207// Generates a semicolon-separated CSS string to be used for the default rendering of a background event.
1208// Called by the fill system.
1209bgEventSegCss:function(a){return{"background-color":this.getSegSkinCss(a)["background-color"]}},
1210// Generates an array of classNames to be used for the rendering business hours overlay. Called by the fill system.
1211businessHoursSegClasses:function(a){return["fc-nonbusiness","fc-bgevent"]},/* Handlers
1212	------------------------------------------------------------------------------------------------------------------*/
1213// Attaches event-element-related handlers to the container element and leverage bubbling
1214bindSegHandlers:function(){this.view.calendar.isTouch?this.bindSegHandler("touchstart",this.handleSegTouchStart):(this.bindSegHandler("mouseenter",this.handleSegMouseover),this.bindSegHandler("mouseleave",this.handleSegMouseout),this.bindSegHandler("mousedown",this.handleSegMousedown)),this.bindSegHandler("click",this.handleSegClick)},
1215// Executes a handler for any a user-interaction on a segment.
1216// Handler gets called with (seg, ev), and with the `this` context of the Grid
1217bindSegHandler:function(b,c){var d=this;this.el.on(b,".fc-event-container > *",function(b){var e=a(this).data("fc-seg");// grab segment data. put there by View::renderEvents
1218// only call the handlers if there is not a drag/resize in progress
1219// grab segment data. put there by View::renderEvents
1220// only call the handlers if there is not a drag/resize in progress
1221return!e||d.isDraggingSeg||d.isResizingSeg?void 0:c.call(d,e,b)})},handleSegClick:function(a,b){return this.view.trigger("eventClick",a.el[0],a.event,b)},
1222// Updates internal state and triggers handlers for when an event element is moused over
1223handleSegMouseover:function(a,b){this.mousedOverSeg||(this.mousedOverSeg=a,this.view.trigger("eventMouseover",a.el[0],a.event,b))},
1224// Updates internal state and triggers handlers for when an event element is moused out.
1225// Can be given no arguments, in which case it will mouseout the segment that was previously moused over.
1226handleSegMouseout:function(a,b){b=b||{},this.mousedOverSeg&&(a=a||this.mousedOverSeg,this.mousedOverSeg=null,this.view.trigger("eventMouseout",a.el[0],a.event,b))},handleSegTouchStart:function(a,b){var c,d=this.view,e=a.event,f=d.isEventSelected(e),g=d.isEventDraggable(e),h=d.isEventResizable(e),i=!1;f&&h&&(
1227// only allow resizing of the event is selected
1228i=this.startSegResize(a,b)),i||!g&&!h||(// allowed to be selected?
1229this.clearDragListeners(),c=g?this.buildSegDragListener(a):new mb,c._dragStart=function(){f||d.selectEvent(e)},c.startInteraction(b,{delay:f?0:this.view.opt("longPressDelay")}))},handleSegMousedown:function(a,b){var c=this.startSegResize(a,b,{distance:5});!c&&this.view.isEventDraggable(a.event)&&(this.clearDragListeners(),this.buildSegDragListener(a).startInteraction(b,{distance:5}))},
1230// returns boolean whether resizing actually started or not.
1231// assumes the seg allows resizing.
1232// `dragOptions` are optional.
1233startSegResize:function(b,c,d){return a(c.target).is(".fc-resizer")?(this.clearDragListeners(),this.buildSegResizeListener(b,a(c.target).is(".fc-start-resizer")).startInteraction(c,d),!0):!1},/* Event Dragging
1234	------------------------------------------------------------------------------------------------------------------*/
1235// Builds a listener that will track user-dragging on an event segment.
1236// Generic enough to work with any type of Grid.
1237buildSegDragListener:function(a){var b,c,d,e=this,f=this.view,i=f.calendar,j=a.el,k=a.event,l=this.segDragListener=new nb(f,{scroll:f.opt("dragScroll"),subjectEl:j,subjectCenter:!0,interactionStart:function(d){b=!1,c=new ob(a.el,{additionalClass:"fc-dragging",parentEl:f.el,opacity:l.isTouch?null:f.opt("dragOpacity"),revertDuration:f.opt("dragRevertDuration"),zIndex:2}),c.hide(),c.start(d)},dragStart:function(c){b=!0,e.handleSegMouseout(a,c),e.segDragStart(a,c),f.hideEvent(k)},hitOver:function(b,h,j){var m;
1238// starting hit could be forced (DayGrid.limit)
1239a.hit&&(j=a.hit),d=e.computeEventDrop(j.component.getHitSpan(j),b.component.getHitSpan(b),k),d&&!i.isEventSpanAllowed(e.eventToSpan(d),k)&&(g(),d=null),d&&(m=f.renderDrag(d,a))?(m.addClass("fc-dragging"),l.isTouch||e.applyDragOpacity(m),c.hide()):c.show(),h&&(d=null)},hitOut:function(){// called before mouse moves to a different hit OR moved out of all hits
1240f.unrenderDrag(),// unrender whatever was done in renderDrag
1241c.show(),// show in case we are moving out of all hits
1242d=null},hitDone:function(){// Called after a hitOut OR before a dragEnd
1243h()},interactionEnd:function(g){
1244// do revert animation if hasn't changed. calls a callback when finished (whether animation or not)
1245c.stop(!d,function(){b&&(f.unrenderDrag(),f.showEvent(k),e.segDragStop(a,g)),d&&f.reportEventDrop(k,d,this.largeUnit,j,g)}),e.segDragListener=null}});return l},
1246// Called before event segment dragging starts
1247segDragStart:function(a,b){this.isDraggingSeg=!0,this.view.trigger("eventDragStart",a.el[0],a.event,b,{})},
1248// Called after event segment dragging stops
1249segDragStop:function(a,b){this.isDraggingSeg=!1,this.view.trigger("eventDragStop",a.el[0],a.event,b,{})},
1250// Given the spans an event drag began, and the span event was dropped, calculates the new zoned start/end/allDay
1251// values for the event. Subclasses may override and set additional properties to be used by renderDrag.
1252// A falsy returned value indicates an invalid drop.
1253// DOES NOT consider overlap/constraint.
1254computeEventDrop:function(a,b,c){var d,e,f=this.view.calendar,g=a.start,h=b.start;// zoned event date properties
1255// if an all-day event was in a timed area and it was dragged to a different time,
1256// guarantee an end and adjust start/end to have times
1257// if switching from day <-> timed, start should be reset to the dropped date, and the end cleared
1258return g.hasTime()===h.hasTime()?(d=this.diffDates(h,g),c.allDay&&R(d)?(e={start:c.start.clone(),end:f.getEventEnd(c),allDay:!1},f.normalizeEventTimes(e)):e={start:c.start.clone(),end:c.end?c.end.clone():null,allDay:c.allDay},e.start.add(d),e.end&&e.end.add(d)):e={start:h.clone(),end:null,// end should be cleared
1259allDay:!h.hasTime()},e},
1260// Utility for apply dragOpacity to a jQuery set
1261applyDragOpacity:function(a){var b=this.view.opt("dragOpacity");null!=b&&a.each(function(a,c){
1262// Don't use jQuery (will set an IE filter), do it the old fashioned way.
1263// In IE8, a helper element will disappears if there's a filter.
1264c.style.opacity=b})},/* External Element Dragging
1265	------------------------------------------------------------------------------------------------------------------*/
1266// Called when a jQuery UI drag is initiated anywhere in the DOM
1267externalDragStart:function(b,c){var d,e,f=this.view;f.opt("droppable")&&(d=a((c?c.item:null)||b.target),e=f.opt("dropAccept"),(a.isFunction(e)?e.call(d[0],d):d.is(e))&&(this.isDraggingExter
1267nal||this.listenToExternalDrag(d,b,c)))},
1268// Called when a jQuery UI drag starts and it needs to be monitored for dropping
1269listenToExternalDrag:function(a,b,c){var d,e=this,f=this.view.calendar,i=Fa(a),j=e.externalDragListener=new nb(this,{interactionStart:function(){e.isDraggingExternal=!0},hitOver:function(a){d=e.computeExternalDrop(a.component.getHitSpan(a),// since we are querying the parent view, might not belong to this grid
1270i),d&&!f.isExternalSpanAllowed(e.eventToSpan(d),d,i.eventProps)&&(g(),d=null),d&&e.renderDrag(d)},hitOut:function(){d=null},hitDone:function(){// Called after a hitOut OR before a dragEnd
1271h(),e.unrenderDrag()},interactionEnd:function(b){d&&// element was dropped on a valid hit
1272e.view.reportExternalDrop(i,d,a,b,c),e.isDraggingExternal=!1,e.externalDragListener=null}});j.startDrag(b)},
1273// Given a hit to be dropped upon, and misc data associated with the jqui drag (guaranteed to be a plain object),
1274// returns the zoned start/end dates for the event that would result from the hypothetical drop. end might be null.
1275// Returning a null value signals an invalid drop hit.
1276// DOES NOT consider overlap/constraint.
1277computeExternalDrop:function(a,b){var c=this.view.calendar,d={start:c.applyTimezone(a.start),// simulate a zoned event start date
1278end:null};
1279// if dropped on an all-day span, and element's metadata specified a time, set it
1280return b.startTime&&!d.start.hasTime()&&d.start.time(b.startTime),b.duration&&(d.end=d.start.clone().add(b.duration)),d},/* Drag Rendering (for both events and an external elements)
1281	------------------------------------------------------------------------------------------------------------------*/
1282// Renders a visual indication of an event or external element being dragged.
1283// `dropLocation` contains hypothetical start/end/allDay values the event would have if dropped. end can be null.
1284// `seg` is the internal segment object that is being dragged. If dragging an external element, `seg` is null.
1285// A truthy returned value indicates this method has rendered a helper element.
1286// Must return elements used for any mock events.
1287renderDrag:function(a,b){},
1288// Unrenders a visual indication of an event or external element being dragged
1289unrenderDrag:function(){},/* Resizing
1290	------------------------------------------------------------------------------------------------------------------*/
1291// Creates a listener that tracks the user as they resize an event segment.
1292// Generic enough to work with any type of Grid.
1293buildSegResizeListener:function(a,b){var c,d,e=this,f=this.view,i=f.calendar,j=a.el,k=a.event,l=i.getEventEnd(k),m=this.segResizeListener=new nb(this,{scroll:f.opt("dragScroll"),subjectEl:j,interactionStart:function(){c=!1},dragStart:function(b){c=!0,e.handleSegMouseout(a,b),e.segResizeStart(a,b)},hitOver:function(c,h,j){var m=e.getHitSpan(j),n=e.getHitSpan(c);d=b?e.computeEventStartResize(m,n,k):e.computeEventEndResize(m,n,k),d&&(i.isEventSpanAllowed(e.eventToSpan(d),k)?d.start.isSame(k.start)&&d.end.isSame(l)&&(d=null):(g(),d=null)),d&&(f.hideEvent(k),e.renderEventResize(d,a))},hitOut:function(){// called before mouse moves to a different hit OR moved out of all hits
1294d=null},hitDone:function(){// resets the rendering to show the original event
1295e.unrenderEventResize(),f.showEvent(k),h()},interactionEnd:function(b){c&&e.segResizeStop(a,b),d&&// valid date to resize to?
1296f.reportEventResize(k,d,this.largeUnit,j,b),e.segResizeListener=null}});return m},
1297// Called before event segment resizing starts
1298segResizeStart:function(a,b){this.isResizingSeg=!0,this.view.trigger("eventResizeStart",a.el[0],a.event,b,{})},
1299// Called after event segment resizing stops
1300segResizeStop:function(a,b){this.isResizingSeg=!1,this.view.trigger("eventResizeStop",a.el[0],a.event,b,{})},
1301// Returns new date-information for an event segment being resized from its start
1302computeEventStartResize:function(a,b,c){return this.computeEventResize("start",a,b,c)},
1303// Returns new date-information for an event segment being resized from its end
1304computeEventEndResize:function(a,b,c){return this.computeEventResize("end",a,b,c)},
1305// Returns new zoned date information for an event segment being resized from its start OR end
1306// `type` is either 'start' or 'end'.
1307// DOES NOT consider overlap/constraint.
1308computeEventResize:function(a,b,c,d){var e,f,g=this.view.calendar,h=this.diffDates(c[a],b[a]);
1309// build original values to work from, guaranteeing a start and end
1310// if an all-day event was in a timed area and was resized to a time, adjust start/end to have times
1311// apply delta to start or end
1312// if the event was compressed too small, find a new reasonable duration for it
1313// TODO: hack
1314// resizing the start?
1315// resizing the end?
1316return e={start:d.start.clone(),end:g.getEventEnd(d),allDay:d.allDay},e.allDay&&R(h)&&(e.allDay=!1,g.normalizeEventTimes(e)),e[a].add(h),e.start.isBefore(e.end)||(f=this.minResizeDuration||(d.allDay?g.defaultAllDayEventDuration:g.defaultTimedEventDuration),"start"==a?e.start=e.end.clone().subtract(f):e.end=e.start.clone().add(f)),e},
1317// Renders a visual indication of an event being resized.
1318// `range` has the updated dates of the event. `seg` is the original segment object involved in the drag.
1319// Must return elements used for any mock events.
1320renderEventResize:function(a,b){},
1321// Unrenders a visual indication of an event being resized.
1322unrenderEventResize:function(){},/* Rendering Utils
1323	------------------------------------------------------------------------------------------------------------------*/
1324// Compute the text that should be displayed on an event's element.
1325// `range` can be the Event object itself, or something range-like, with at least a `start`.
1326// If event times are disabled, or the event has no time, will return a blank string.
1327// If not specified, formatStr will default to the eventTimeFormat setting,
1328// and displayEnd will default to the displayEventEnd setting.
1329getEventTimeText:function(a,b,c){return null==b&&(b=this.eventTimeFormat),null==c&&(c=this.displayEventEnd),this.displayEventTime&&a.start.hasTime()?c&&a.end?this.view.formatRange(a,b):a.start.format(b):""},
1330// Generic utility for generating the HTML classNames for an event segment's element
1331getSegClasses:function(a,b,c){var d=this.view,e=a.event,f=["fc-event",a.isStart?"fc-start":"fc-not-start",a.isEnd?"fc-end":"fc-not-end"].concat(e.className,e.source?e.source.className:[]);
1332// event is currently selected? attach a className.
1333return b&&f.push("fc-draggable"),c&&f.push("fc-resizable"),d.isEventSelected(e)&&f.push("fc-selected"),f},
1334// Utility for generating event skin-related CSS properties
1335getSegSkinCss:function(a){var b=a.event,c=this.view,d=b.source||{},e=b.color,f=d.color,g=c.opt("eventColor");return{"background-color":b.backgroundColor||e||d.backgroundColor||f||c.opt("eventBackgroundColor")||g,"border-color":b.borderColor||e||d.borderColor||f||c.opt("eventBorderColor")||g,color:b.textColor||d.textColor||c.opt("eventTextColor")}},/* Converting events -> eventRange -> eventSpan -> eventSegs
1336	------------------------------------------------------------------------------------------------------------------*/
1337// Generates an array of segments for the given single event
1338// Can accept an event "location" as well (which only has start/end and no allDay)
1339eventToSegs:function(a){return this.eventsToSegs([a])},eventToSpan:function(a){return this.eventToSpans(a)[0]},
1340// Generates spans (always unzoned) for the given event.
1341// Does not do any inverting for inverse-background events.
1342// Can accept an event "location" as well (which only has start/end and no allDay)
1343eventToSpans:function(a){var b=this.eventToRange(a);return this.eventRangeToSpans(b,a)},
1344// Converts an array of event objects into an array of event segment objects.
1345// A custom `segSliceFunc` may be given for arbitrarily slicing up events.
1346// Doesn't guarantee an order for the resulting array.
1347eventsToSegs:function(b,c){var d=this,e=Da(b),f=[];return a.each(e,function(a,b){var e,g=[];for(e=0;e<b.length;e++)g.push(d.eventToRange(b[e]));
1348// inverse-background events (utilize only the first event in calculations)
1349if(Ba(b[0]))for(g=d.invertRanges(g),e=0;e<g.length;e++)f.push.apply(f,// append to
1350d.eventRangeToSegs(g[e],b[0],c));else for(e=0;e<g.length;e++)f.push.apply(f,// append to
1351d.eventRangeToSegs(g[e],b[e],c))}),f},
1352// Generates the unzoned start/end dates an event appears to occupy
1353// Can accept an event "location" as well (which only has start/end and no allDay)
1354eventToRange:function(a){return{start:a.start.clone().stripZone(),end:(a.end?a.end.clone():
1355// derive the end from the start and allDay. compute allDay if necessary
1356this.view.calendar.getDefaultEventEnd(null!=a.allDay?a.allDay:!a.start.hasTime(),a.start)).stripZone()}},
1357// Given an event's range (unzoned start/end), and the event itself,
1358// slice into segments (using the segSliceFunc function if specified)
1359eventRangeToSegs:function(a,b,c){var d,e=this.eventRangeToSpans(a,b),f=[];for(d=0;d<e.length;d++)f.push.apply(f,// append to
1360this.eventSpanToSegs(e[d],b,c));return f},
1361// Given an event's unzoned date range, return an array of "span" objects.
1362// Subclasses can override.
1363eventRangeToSpans:function(b,c){return[a.extend({},b)]},
1364// Given an event's span (unzoned start/end and other misc data), and the event itself,
1365// slices into segments and attaches event-derived properties to them.
1366eventSpanToSegs:function(a,b,c){var d,e,f=c?c(a):this.spanToSegs(a);for(d=0;d<f.length;d++)e=f[d],e.event=b,e.eventStartMS=+a.start,e.eventDurationMS=a.end-a.start;return f},
1367// Produces a new array of range objects that will cover all the time NOT covered by the given ranges.
1368// SIDE EFFECT: will mutate the given array and will use its date references.
1369invertRanges:function(a){var b,c,d=this.view,e=d.start.clone(),f=d.end.clone(),g=[],h=e;for(
1370// ranges need to be in order. required for our date-walking algorithm
1371a.sort(Ea),b=0;b<a.length;b++)c=a[b],c.start>h&&g.push({start:h,end:c.start}),h=c.end;
1372// add the span of time after the last event (if there is any)
1373// compare millisecond time (skip any ambig logic)
1374return f>h&&g.push({start:h,end:f}),g},sortEventSegs:function(a){a.sort(ga(this,"compareEventSegs"))},
1375// A cmp function for determining which segments should take visual priority
1376compareEventSegs:function(a,b){// earlier events go first
1377// tie? longer events go first
1378// tie? put all-day events first (booleans cast to 0/1)
1379return a.eventStartMS-b.eventStartMS||b.eventDurationMS-a.eventDurationMS||b.event.allDay-a.event.allDay||F(a.event,b.event,this.view.eventOrderSpecs)}}),Ta.isBgEvent=Aa,/* External-Dragging-Element Data
1380----------------------------------------------------------------------------------------------------------------------*/
1381// Require all HTML5 data-* attributes used by FullCalendar to have this prefix.
1382// A value of '' will query attributes like data-event. A value of 'fc' will query attributes like data-fc-event.
1383Ta.dataAttrPrefix="";/*
1384A set of rendering and date-related methods for a visual component comprised of one or more rows of day columns.
1385Prerequisite: the object being mixed into needs to be a *Grid*
1386*/
1387var qb=Ta.DayTableMixin={breakOnWeeks:!1,// should create a new row for each week?
1388dayDates:null,// whole-day dates for each column. left to right
1389dayIndices:null,// for each day from start, the offset
1390daysPerRow:null,rowCnt:null,colCnt:null,colHeadFormat:null,
1391// Populates internal variables used for date calculation and rendering
1392updateDayTable:function(){for(var a,b,c,d=this.view,e=this.start.clone(),f=-1,g=[],h=[];e.isBefore(this.end);)// loop each day from start to end
1393d.isHiddenDay(e)?g.push(f+.5):(f++,g.push(f),h.push(e.clone())),e.add(1,"days");if(this.breakOnWeeks){for(b=h[0].day(),a=1;a<h.length&&h[a].day()!=b;a++);c=Math.ceil(h.length/a)}else c=1,a=h.length;this.dayDates=h,this.dayIndices=g,this.daysPerRow=a,this.rowCnt=c,this.updateDayTableCols()},
1394// Computes and assigned the colCnt property and updates any options that may be computed from it
1395updateDayTableCols:function(){this.colCnt=this.computeColCnt(),this.colHeadFormat=this.view.opt("columnFormat")||this.computeColHeadFormat()},
1396// Determines how many columns there should be in the table
1397computeColCnt:function(){return this.daysPerRow},
1398// Computes the ambiguously-timed moment for the given cell
1399getCellDate:function(a,b){return this.dayDates[this.getCellDayIndex(a,b)].clone()},
1400// Computes the ambiguously-timed date range for the given cell
1401getCellRange:function(a,b){var c=this.getCellDate(a,b),d=c.clone().add(1,"days");return{start:c,end:d}},
1402// Returns the number of day cells, chronologically, from the first of the grid (0-based)
1403getCellDayIndex:function(a,b){return a*this.daysPerRow+this.getColDayIndex(b)},
1404// Returns the numner of day cells, chronologically, from the first cell in *any given row*
1405getColDayIndex:function(a){return this.isRTL?this.colCnt-1-a:a},
1406// Given a date, returns its chronolocial cell-index from the first cell of the grid.
1407// If the date lies between cells (because of hiddenDays), returns a floating-point value between offsets.
1408// If before the first offset, returns a negative number.
1409// If after the last offset, returns an offset past the last cell offset.
1410// Only works for *start* dates of cells. Will not work for exclusive end dates for cells.
1411getDateDayIndex:function(a){var b=this.dayIndices,c=a.diff(this.start,"days");return 0>c?b[0]-1:c>=b.length?b[b.length-1]+1:b[c]},/* Options
1412	------------------------------------------------------------------------------------------------------------------*/
1413// Computes a default column header formatting string if `colFormat` is not explicitly defined
1414computeColHeadFormat:function(){
1415// if more than one week row, or if there are a lot of columns with not much space,
1416// put just the day numbers will be in each cell
1417// if more than one week row, or if there are a lot of columns with not much space,
1418// put just the day numbers will be in each cell
1419return this.rowCnt>1||this.colCnt>10?"ddd":this.colCnt>1?this.view.opt("dayOfMonthFormat"):"dddd"},/* Slicing
1420	------------------------------------------------------------------------------------------------------------------*/
1421// Slices up a date range into a segment for every week-row it intersects with
1422sliceRangeByRow:function(a){var b,c,d,e,f,g=this.daysPerRow,h=this.view.computeDayRange(a),i=this.getDateDayIndex(h.start),j=this.getDateDayIndex(h.end.clone().subtract(1,"days")),k=[];// inclusive day-index range for segment
1423for(b=0;b<this.rowCnt;b++)c=b*g,d=c+g-1,e=Math.max(i,c),f=Math.min(j,d),e=Math.ceil(e),f=Math.floor(f),f>=e&&k.push({row:b,firstRowDayIndex:e-c,lastRowDayIndex:f-c,isStart:e===i,isEnd:f===j});return k},
1424// Slices up a date range into a segment for every day-cell it intersects with.
1425// TODO: make more DRY with sliceRangeByRow somehow.
1426sliceRangeByDay:function(a){var b,c,d,e,f,g,h=this.daysPerRow,i=this.view.computeDayRange(a),j=this.getDateDayIndex(i.start),k=this.getDateDayIndex(i.end.clone().subtract(1,"days")),l=[];// inclusive day-index range for segment
1427for(b=0;b<this.rowCnt;b++)for(c=b*h,d=c+h-1,e=c;d>=e;e++)f=Math.max(j,e),g=Math.min(k,e),f=Math.ceil(f),g=Math.floor(g),g>=f&&l.push({row:b,firstRowDayIndex:f-c,lastRowDayIndex:g-c,isStart:f===j,isEnd:g===k});return l},/* Header Rendering
1428	------------------------------------------------------------------------------------------------------------------*/
1429renderHeadHtml:function(){var a=this.view;return'<div class="fc-row '+a.widgetHeaderClass+'"><table><thead>'+this.renderHeadTrHtml()+"</thead></table></div>"},renderHeadIntroHtml:function(){return this.renderIntroHtml()},renderHeadTrHtml:function(){return"<tr>"+(this.isRTL?"":this.renderHeadIntroHtml())+this.renderHeadDateCellsHtml()+(this.isRTL?this.renderHeadIntroHtml():"")+"</tr>"},renderHeadDateCellsHtml:function(){var a,b,c=[];for(a=0;a<this.colCnt;a++)b=this.getCellDate(0,a),c.push(this.renderHeadDateCellHtml(b));return c.join("")},
1430// TODO: when internalApiVersion, accept an object for HTML attributes
1431// (colspan should be no different)
1432renderHeadDateCellHtml:function(a,b,c){var d=this.view;return'<th class="fc-day-header '+d.widgetHeaderClass+" fc-"+Xa[a.day()]+'"'+(1==this.rowCnt?' data-date="'+a.format("YYYY-MM-DD")+'"':"")+(b>1?' colspan="'+b+'"':"")+(c?" "+c:"")+">"+aa(a.format(this.colHeadFormat))+"</th>"}
1432,/* Background Rendering
1433	------------------------------------------------------------------------------------------------------------------*/
1434renderBgTrHtml:function(a){return"<tr>"+(this.isRTL?"":this.renderBgIntroHtml(a))+this.renderBgCellsHtml(a)+(this.isRTL?this.renderBgIntroHtml(a):"")+"</tr>"},renderBgIntroHtml:function(a){return this.renderIntroHtml()},renderBgCellsHtml:function(a){var b,c,d=[];for(b=0;b<this.colCnt;b++)c=this.getCellDate(a,b),d.push(this.renderBgCellHtml(c));return d.join("")},renderBgCellHtml:function(a,b){var c=this.view,d=this.getDayClasses(a);// if date has a time, won't format it
1435return d.unshift("fc-day",c.widgetContentClass),'<td class="'+d.join(" ")+'" data-date="'+a.format("YYYY-MM-DD")+'"'+(b?" "+b:"")+"></td>"},/* Generic
1436	------------------------------------------------------------------------------------------------------------------*/
1437// Generates the default HTML intro for any row. User classes should override
1438renderIntroHtml:function(){},
1439// TODO: a generic method for dealing with <tr>, RTL, intro
1440// when increment internalApiVersion
1441// wrapTr (scheduler)
1442/* Utils
1443	------------------------------------------------------------------------------------------------------------------*/
1444// Applies the generic "intro" and "outro" HTML to the given cells.
1445// Intro means the leftmost cell when the calendar is LTR and the rightmost cell when RTL. Vice-versa for outro.
1446bookendCells:function(a){var b=this.renderIntroHtml();b&&(this.isRTL?a.append(b):a.prepend(b))}},rb=Ta.DayGrid=pb.extend(qb,{numbersVisible:!1,// should render a row for day/week numbers? set by outside view. TODO: make internal
1447bottomCoordPadding:0,// hack for extending the hit area for the last row of the coordinate grid
1448rowEls:null,// set of fake row elements
1449cellEls:null,// set of whole-day elements comprising the row's background
1450helperEls:null,// set of cell skeleton elements for rendering the mock event "helper"
1451rowCoordCache:null,colCoordCache:null,
1452// Renders the rows and columns into the component's `this.el`, which should already be assigned.
1453// isRigid determins whether the individual rows should ignore the contents and be a constant height.
1454// Relies on the view's colCnt and rowCnt. In the future, this component should probably be self-sufficient.
1455renderDates:function(a){var b,c,d=this.view,e=this.rowCnt,f=this.colCnt,g="";for(b=0;e>b;b++)g+=this.renderDayRowHtml(b,a);
1456// trigger dayRender with each cell's element
1457for(this.el.html(g),this.rowEls=this.el.find(".fc-row"),this.cellEls=this.el.find(".fc-day"),this.rowCoordCache=new lb({els:this.rowEls,isVertical:!0}),this.colCoordCache=new lb({els:this.cellEls.slice(0,this.colCnt),// only the first row
1458isHorizontal:!0}),b=0;e>b;b++)for(c=0;f>c;c++)d.trigger("dayRender",null,this.getCellDate(b,c),this.getCellEl(b,c))},unrenderDates:function(){this.removeSegPopover()},renderBusinessHours:function(){var a=this.view.calendar.getBusinessHoursEvents(!0),b=this.eventsToSegs(a);this.renderFill("businessHours",b,"bgevent")},
1459// Generates the HTML for a single row, which is a div that wraps a table.
1460// `row` is the row number.
1461renderDayRowHtml:function(a,b){var c=this.view,d=["fc-row","fc-week",c.widgetContentClass];return b&&d.push("fc-rigid"),'<div class="'+d.join(" ")+'"><div class="fc-bg"><table>'+this.renderBgTrHtml(a)+'</table></div><div class="fc-content-skeleton"><table>'+(this.numbersVisible?"<thead>"+this.renderNumberTrHtml(a)+"</thead>":"")+"</table></div></div>"},/* Grid Number Rendering
1462	------------------------------------------------------------------------------------------------------------------*/
1463renderNumberTrHtml:function(a){return"<tr>"+(this.isRTL?"":this.renderNumberIntroHtml(a))+this.renderNumberCellsHtml(a)+(this.isRTL?this.renderNumberIntroHtml(a):"")+"</tr>"},renderNumberIntroHtml:function(a){return this.renderIntroHtml()},renderNumberCellsHtml:function(a){var b,c,d=[];for(b=0;b<this.colCnt;b++)c=this.getCellDate(a,b),d.push(this.renderNumberCellHtml(c));return d.join("")},
1464// Generates the HTML for the <td>s of the "number" row in the DayGrid's content skeleton.
1465// The number row will only exist if either day numbers or week numbers are turned on.
1466renderNumberCellHtml:function(a){var b;return this.view.dayNumbersVisible?(b=this.getDayClasses(a),b.unshift("fc-day-number"),'<td class="'+b.join(" ")+'" data-date="'+a.format()+'">'+a.date()+"</td>"):"<td/>"},/* Options
1467	------------------------------------------------------------------------------------------------------------------*/
1468// Computes a default event time formatting string if `timeFormat` is not explicitly defined
1469computeEventTimeFormat:function(){return this.view.opt("extraSmallTimeFormat")},
1470// Computes a default `displayEventEnd` value if one is not expliclty defined
1471computeDisplayEventEnd:function(){return 1==this.colCnt},/* Dates
1472	------------------------------------------------------------------------------------------------------------------*/
1473rangeUpdated:function(){this.updateDayTable()},
1474// Slices up the given span (unzoned start/end with other misc data) into an array of segments
1475spanToSegs:function(a){var b,c,d=this.sliceRangeByRow(a);for(b=0;b<d.length;b++)c=d[b],this.isRTL?(c.leftCol=this.daysPerRow-1-c.lastRowDayIndex,c.rightCol=this.daysPerRow-1-c.firstRowDayIndex):(c.leftCol=c.firstRowDayIndex,c.rightCol=c.lastRowDayIndex);return d},/* Hit System
1476	------------------------------------------------------------------------------------------------------------------*/
1477prepareHits:function(){this.colCoordCache.build(),this.rowCoordCache.build(),this.rowCoordCache.bottoms[this.rowCnt-1]+=this.bottomCoordPadding},releaseHits:function(){this.colCoordCache.clear(),this.rowCoordCache.clear()},queryHit:function(a,b){var c=this.colCoordCache.getHorizontalIndex(a),d=this.rowCoordCache.getVerticalIndex(b);return null!=d&&null!=c?this.getCellHit(d,c):void 0},getHitSpan:function(a){return this.getCellRange(a.row,a.col)},getHitEl:function(a){return this.getCellEl(a.row,a.col)},/* Cell System
1478	------------------------------------------------------------------------------------------------------------------*/
1479// FYI: the first column is the leftmost column, regardless of date
1480getCellHit:function(a,b){return{row:a,col:b,component:this,// needed unfortunately :(
1481left:this.colCoordCache.getLeftOffset(b),right:this.colCoordCache.getRightOffset(b),top:this.rowCoordCache.getTopOffset(a
1481),bottom:this.rowCoordCache.getBottomOffset(a)}},getCellEl:function(a,b){return this.cellEls.eq(a*this.colCnt+b)},/* Event Drag Visualization
1482	------------------------------------------------------------------------------------------------------------------*/
1483// TODO: move to DayGrid.event, similar to what we did with Grid's drag methods
1484// Renders a visual indication of an event or external element being dragged.
1485// `eventLocation` has zoned start and end (optional)
1486renderDrag:function(a,b){
1487// if a segment from the same calendar but another component is being dragged, render a helper event
1488// always render a highlight underneath
1489// if a segment from the same calendar but another component is being dragged, render a helper event
1490return this.renderHighlight(this.eventToSpan(a)),b&&!b.el.closest(this.el).length?this.renderEventLocationHelper(a,b):void 0},
1491// Unrenders any visual indication of a hovering event
1492unrenderDrag:function(){this.unrenderHighlight(),this.unrenderHelper()},/* Event Resize Visualization
1493	------------------------------------------------------------------------------------------------------------------*/
1494// Renders a visual indication of an event being resized
1495renderEventResize:function(a,b){return this.renderHighlight(this.eventToSpan(a)),this.renderEventLocationHelper(a,b)},
1496// Unrenders a visual indication of an event being resized
1497unrenderEventResize:function(){this.unrenderHighlight(),this.unrenderHelper()},/* Event Helper
1498	------------------------------------------------------------------------------------------------------------------*/
1499// Renders a mock "helper" event. `sourceSeg` is the associated internal segment object. It can be null.
1500renderHelper:function(b,c){var d,e=[],f=this.eventToSegs(b);// assigns each seg's el and returns a subset of segs that were rendered
1501// inject each new event skeleton into each associated row
1502// must return the elements rendered
1503return f=this.renderFgSegEls(f),d=this.renderSegRows(f),this.rowEls.each(function(b,f){var g,h=a(f),i=a('<div class="fc-helper-skeleton"><table/></div>');g=c&&c.row===b?c.el.position().top:h.find(".fc-content-skeleton tbody").position().top,i.css("top",g).find("table").append(d[b].tbodyEl),h.append(i),e.push(i[0])}),this.helperEls=a(e)},
1504// Unrenders any visual indication of a mock helper event
1505unrenderHelper:function(){this.helperEls&&(this.helperEls.remove(),this.helperEls=null)},/* Fill System (highlight, background events, business hours)
1506	------------------------------------------------------------------------------------------------------------------*/
1507fillSegTag:"td",// override the default tag name
1508// Renders a set of rectangles over the given segments of days.
1509// Only returns segments that successfully rendered.
1510renderFill:function(b,c,d){var e,f,g,h=[];// assignes `.el` to each seg. returns successfully rendered segs
1511for(c=this.renderFillSegEls(b,c),e=0;e<c.length;e++)f=c[e],g=this.renderFillRow(b,f,d),this.rowEls.eq(f.row).append(g),h.push(g[0]);return this.elsByFill[b]=a(h),c},
1512// Generates the HTML needed for one row of a fill. Requires the seg's el to be rendered.
1513renderFillRow:function(b,c,d){var e,f,g=this.colCnt,h=c.leftCol,i=c.rightCol+1;return d=d||b.toLowerCase(),e=a('<div class="fc-'+d+'-skeleton"><table><tr/></table></div>'),f=e.find("tr"),h>0&&f.append('<td colspan="'+h+'"/>'),f.append(c.el.attr("colspan",i-h)),g>i&&f.append('<td colspan="'+(g-i)+'"/>'),this.bookendCells(f),e}});/* Event-rendering methods for the DayGrid class
1514----------------------------------------------------------------------------------------------------------------------*/
1515rb.mixin({rowStructs:null,// an array of objects, each holding information about a row's foreground event-rendering
1516// Unrenders all events currently rendered on the grid
1517unrenderEvents:function(){this.removeSegPopover(),// removes the "more.." events popover
1518pb.prototype.unrenderEvents.apply(this,arguments)},
1519// Retrieves all rendered segment objects currently rendered on the grid
1520getEventSegs:function(){return pb.prototype.getEventSegs.call(this).concat(this.popoverSegs||[])},
1521// Renders the given background event segments onto the grid
1522renderBgSegs:function(b){
1523// don't render timed background events
1524var c=a.grep(b,function(a){return a.event.allDay});return pb.prototype.renderBgSegs.call(this,c)},
1525// Renders the given foreground event segments onto the grid
1526renderFgSegs:function(b){var c;
1527// render an `.el` on each seg
1528// returns a subset of the segs. segs that were actually rendered
1529// append to each row's content skeleton
1530return b=this.renderFgSegEls(b),c=this.rowStructs=this.renderSegRows(b),this.rowEls.each(function(b,d){a(d).find(".fc-content-skeleton > table").append(c[b].tbodyEl)}),b},
1531// Unrenders all currently rendered foreground event segments
1532unrenderFgSegs:function(){for(var a,b=this.rowStructs||[];a=b.pop();)a.tbodyEl.remove();this.rowStructs=null},
1533// Uses the given events array to generate <tbody> elements that should be appended to each row's content skeleton.
1534// Returns an array of rowStruct objects (see the bottom of `renderSegRow`).
1535// PRECONDITION: each segment shoud already have a rendered and assigned `.el`
1536renderSegRows:function(a){var b,c,d=[];// group into nested arrays
1537// iterate each row of segment groupings
1538for(b=this.groupSegRows(a),c=0;c<b.length;c++)d.push(this.renderSegRow(c,b[c]));return d},
1539// Builds the HTML to be used for the default element for an individual segment
1540fgSegHtml:function(a,b){var c,d,e=this.view,f=a.event,g=e.isEventDraggable(f),h=!b&&f.allDay&&a.isStart&&e.isEventResizableFromStart(f),i=!b&&f.allDay&&a.isEnd&&e.isEventResizableFromEnd(f),j=this.getSegClasses(a,g,h||i),k=ca(this.getSegSkinCss(a)),l="";
1541// Only display a timed events time if it is the starting segment
1542// we always want one line of height
1543// put a natural space in between
1544return j.unshift("fc-day-grid-event","fc-h-event"),a.isStart&&(c=this.getEventTimeText(f),c&&(l='<span class="fc-time">'+aa(c)+"</span>")),d='<span class="fc-title">'+(aa(f.title||"")||"&nbsp;")+"</span>",'<a class="'+j.join(" ")+'"'+(f.url?' href="'+aa(f.url)+'"':"")+(k?' style="'+k+'"':"")+'><div class="fc-content">'+(this.isRTL?d+" "+l:l+" "+d)+"</div>"+(h?'<div class="fc-resizer fc-start-resizer" />':"")+(i?'<div class="fc-resizer fc-end-resizer" />':"")+"</a>"},
1545// Given a row # and an array of segments all in the same row, render a <tbody> element, a skeleton that contains
1546// the segments. Returns object with a bunch of internal data about how the render was calculated.
1547// NOTE: modifies rowSegs
1548renderSegRow:function(b,c){
1549// populates empty cells from the current column (`col`) to `endCol`
1550function d(b){for(;b>g;)k=(r[e-1]||[])[g],k?k.attr("rowspan",parseInt(k.attr("rowspan")||1,10)+1):(k=a("<td/>"),h.append(k)),q[e][g]=k,r[e][g]=k,g++}var e,f,g,h,i,j,k,l=this.colCnt,m=this.buildSegLevels(c),n=Math.max(1,m.length),o=a("<tbody/>"),p=[],q=[],r=[];for(e=0;
1550n>e;e++){
1551// levelCnt might be 1 even though there are no actual levels. protect against this.
1552// this single empty row is useful for styling.
1553if(f=m[e],g=0,h=a("<tr/>"),p.push([]),q.push([]),r.push([]),f)for(i=0;i<f.length;i++){for(// iterate through segments in level
1554j=f[i],d(j.leftCol),
1555// create a container that occupies or more columns. append the event element.
1556k=a('<td class="fc-event-container"/>').append(j.el),j.leftCol!=j.rightCol?k.attr("colspan",j.rightCol-j.leftCol+1):// a single-column segment
1557r[e][g]=k;g<=j.rightCol;)q[e][g]=k,p[e][g]=j,g++;h.append(k)}d(l),// finish off the row
1558this.bookendCells(h),o.append(h)}return{// a "rowStruct"
1559row:b,// the row number
1560tbodyEl:o,cellMatrix:q,segMatrix:p,segLevels:m,segs:c}},
1561// Stacks a flat array of segments, which are all assumed to be in the same row, into subarrays of vertical levels.
1562// NOTE: modifies segs
1563buildSegLevels:function(a){var b,c,d,e=[];for(
1564// Give preference to elements with certain criteria, so they have
1565// a chance to be closer to the top.
1566this.sortEventSegs(a),b=0;b<a.length;b++){
1567// loop through levels, starting with the topmost, until the segment doesn't collide with other segments
1568for(c=a[b],d=0;d<e.length&&Ga(c,e[d]);d++);
1569// `j` now holds the desired subrow index
1570c.level=d,
1571// create new level array if needed and append segment
1572(e[d]||(e[d]=[])).push(c)}
1573// order segments left-to-right. very important if calendar is RTL
1574for(d=0;d<e.length;d++)e[d].sort(Ha);return e},
1575// Given a flat array of segments, return an array of sub-arrays, grouped by each segment's row
1576groupSegRows:function(a){var b,c=[];for(b=0;b<this.rowCnt;b++)c.push([]);for(b=0;b<a.length;b++)c[a[b].row].push(a[b]);return c}}),/* Methods relate to limiting the number events for a given day on a DayGrid
1577----------------------------------------------------------------------------------------------------------------------*/
1578// NOTE: all the segs being passed around in here are foreground segs
1579rb.mixin({segPopover:null,// the Popover that holds events that can't fit in a cell. null when not visible
1580popoverSegs:null,// an array of segment objects that the segPopover holds. null when not visible
1581removeSegPopover:function(){this.segPopover&&this.segPopover.hide()},
1582// Limits the number of "levels" (vertically stacking layers of events) for each row of the grid.
1583// `levelLimit` can be false (don't limit), a number, or true (should be computed).
1584limitRows:function(a){var b,c,d=this.rowStructs||[];for(b=0;b<d.length;b++)this.unlimitRow(b),c=a?"number"==typeof a?a:this.computeRowLevelLimit(b):!1,c!==!1&&this.limitRow(b,c)},
1585// Computes the number of levels a row will accomodate without going outside its bounds.
1586// Assumes the row is "rigid" (maintains a constant height regardless of what is inside).
1587// `row` is the row number.
1588computeRowLevelLimit:function(b){function c(b,c){f=Math.max(f,a(c).outerHeight())}var d,e,f,g=this.rowEls.eq(b),h=g.height(),i=this.rowStructs[b].tbodyEl.children();
1589// Reveal one level <tr> at a time and stop when we find one out of bounds
1590for(d=0;d<i.length;d++)if(e=i.eq(d).removeClass("fc-limited"),f=0,e.find("> td > :first-child").each(c),e.position().top+f>h)return d;return!1},
1591// Limits the given grid row to the maximum number of levels and injects "more" links if necessary.
1592// `row` is the row number.
1593// `levelLimit` is a number for the maximum (inclusive) number of levels allowed.
1594limitRow:function(b,c){
1595// Iterates through empty level cells and places "more" links inside if need be
1596function d(d){// goes from current `col` to `endCol`
1597for(;d>w;)j=t.getCellSegs(b,w,c),j.length&&(m=f[c-1][w],s=t.renderMoreLink(b,w,j),r=a("<div/>").append(s),m.append(r),v.push(r[0])),w++}var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t=this,u=this.rowStructs[b],v=[],w=0;if(c&&c<u.segLevels.length){// hide elements and get a simple DOM-nodes array
1598// iterate though segments in the last allowable level
1599for(e=u.segLevels[c-1],f=u.cellMatrix,g=u.tbodyEl.children().slice(c).addClass("fc-limited").get(),h=0;h<e.length;h++){for(i=e[h],d(i.leftCol),// process empty cells before the segment
1600// determine *all* segments below `seg` that occupy the same columns
1601l=[],k=0;w<=i.rightCol;)j=this.getCellSegs(b,w,c),l.push(j),k+=j.length,w++;if(k){
1602// make a replacement <td> for each column the segment occupies. will be one for each colspan
1603for(m=f[c-1][i.leftCol],n=m.attr("rowspan")||1,o=[],p=0;p<l.length;p++)q=a('<td class="fc-more-cell"/>').attr("rowspan",n),j=l[p],s=this.renderMoreLink(b,i.leftCol+p,[i].concat(j)),r=a("<div/>").append(s),q.append(r),o.push(q[0]),v.push(q[0]);m.addClass("fc-limited").after(a(o)),// hide original <td> and inject replacements
1604g.push(m[0])}}
1604d(this.colCnt),// finish off the level
1605u.moreEls=a(v),// for easy undoing later
1606u.limitedEls=a(g)}},
1607// Reveals all levels and removes all "more"-related elements for a grid's row.
1608// `row` is a row number.
1609unlimitRow:function(a){var b=this.rowStructs[a];b.moreEls&&(b.moreEls.remove(),b.moreEls=null),b.limitedEls&&(b.limitedEls.removeClass("fc-limited"),b.limitedEls=null)},
1610// Renders an <a> element that represents hidden event element for a cell.
1611// Responsible for attaching click handler as well.
1612renderMoreLink:function(b,c,d){var e=this,f=this.view;return a('<a class="fc-more"/>').text(this.getMoreLinkText(d.length)).on("click",function(g){var h=f.opt("eventLimitClick"),i=e.getCellDate(b,c),j=a(this),k=e.getCellEl(b,c),l=e.getCellSegs(b,c),m=e.resliceDaySegs(l,i),n=e.resliceDaySegs(d,i);"function"==typeof h&&(
1613// the returned value can be an atomic option
1614h=f.trigger("eventLimitClick",null,{date:i,dayEl:k,moreEl:j,segs:m,hiddenSegs:n},g)),"popover"===h?e.showSegPopover(b,c,j,m):"string"==typeof h&&// a view name
1615f.calendar.zoomTo(i,h)})},
1616// Reveals the popover that displays all events within a cell
1617showSegPopover:function(a,b,c,d){var e,f,g=this,h=this.view,i=c.parent();e=1==this.rowCnt?h.el:this.rowEls.eq(a),f={className:"fc-more-popover",content:this.renderSegPopoverContent(a,b,d),parentEl:this.el,top:e.offset().top,autoHide:!0,viewportConstrain:h.opt("popoverViewportConstrain"),hide:function(){g.segPopover.removeElement(),g.segPopover=null,g.popoverSegs=null}},this.isRTL?f.right=i.offset().left+i.outerWidth()+1:f.left=i.offset().left-1,this.segPopover=new kb(f),this.segPopover.show()},
1618// Builds the inner DOM contents of the segment popover
1619renderSegPopoverContent:function(b,c,d){var e,f=this.view,g=f.opt("theme"),h=this.getCellDate(b,c).format(f.opt("dayPopoverFormat")),i=a('<div class="fc-header '+f.widgetHeaderClass+'"><span class="fc-close '+(g?"ui-icon ui-icon-closethick":"fc-icon fc-icon-x")+'"></span><span class="fc-title">'+aa(h)+'</span><div class="fc-clear"/></div><div class="fc-body '+f.widgetContentClass+'"><div class="fc-event-container"></div></div>'),j=i.find(".fc-event-container");for(d=this.renderFgSegEls(d,!0),this.popoverSegs=d,e=0;e<d.length;e++)
1620// because segments in the popover are not part of a grid coordinate system, provide a hint to any
1621// grids that want to do drag-n-drop about which cell it came from
1622this.prepareHits(),d[e].hit=this.getCellHit(b,c),this.releaseHits(),j.append(d[e].el);return i},
1623// Given the events within an array of segment objects, reslice them to be in a single day
1624resliceDaySegs:function(b,c){
1625// build an array of the original events
1626var d=a.map(b,function(a){return a.event}),e=c.clone(),f=e.clone().add(1,"days"),g={start:e,end:f};
1627// slice the events with a custom slicing function
1628// force an order because eventsToSegs doesn't guarantee one
1629return b=this.eventsToSegs(d,function(a){var b=I(a,g);// undefind if no intersection
1630return b?[b]:[]}),this.sortEventSegs(b),b},
1631// Generates the text that should be inside a "more" link, given the number of events it represents
1632getMoreLinkText:function(a){var b=this.view.opt("eventLimitText");return"function"==typeof b?b(a):"+"+a+" "+b},
1633// Returns segments within a given cell.
1634// If `startLevel` is specified, returns only events including and below that level. Otherwise returns all segs.
1635getCellSegs:function(a,b,c){for(var d,e=this.rowStructs[a].segMatrix,f=c||0,g=[];f<e.length;)d=e[f][b],d&&g.push(d),f++;return g}});/* A component that renders one or more columns of vertical time slots
1636----------------------------------------------------------------------------------------------------------------------*/
1637// We mixin DayTable, even though there is only a single row of days
1638var sb=Ta.TimeGrid=pb.extend(qb,{slotDuration:null,// duration of a "slot", a distinct time segment on given day, visualized by lines
1639snapDuration:null,// granularity of time for dragging and selecting
1640snapsPerSlot:null,minTime:null,// Duration object that denotes the first visible time of any given day
1641maxTime:null,// Duration object that denotes the exclusive visible end time of any given day
1642labelFormat:null,// formatting string for times running along vertical axis
1643labelInterval:null,// duration of how often a label should be displayed for a slot
1644colEls:null,// cells elements in the day-row background
1645slatContainerEl:null,// div that wraps all the slat rows
1646slatEls:null,// elements running horizontally across all columns
1647nowIndicatorEls:null,colCoordCache:null,slatCoordCache:null,constructor:function(){pb.apply(this,arguments),// call the super-constructor
1648this.processOptions()},
1649// Renders the time grid into `this.el`, which should already be assigned.
1650// Relies on the view's colCnt. In the future, this component should probably be self-sufficient.
1651renderDates:function(){this.el.html(this.renderHtml()),this.colEls=this.el.find(".fc-day"),this.slat
1651ContainerEl=this.el.find(".fc-slats"),this.slatEls=this.slatContainerEl.find("tr"),this.colCoordCache=new lb({els:this.colEls,isHorizontal:!0}),this.slatCoordCache=new lb({els:this.slatEls,isVertical:!0}),this.renderContentSkeleton()},
1652// Renders the basic HTML skeleton for the grid
1653renderHtml:function(){// row=0
1654return'<div class="fc-bg"><table>'+this.renderBgTrHtml(0)+'</table></div><div class="fc-slats"><table>'+this.renderSlatRowHtml()+"</table></div>"},
1655// Generates the HTML for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL.
1656renderSlatRowHtml:function(){
1657// Calculate the time for each slot
1658for(var a,c,d,e=this.view,f=this.isRTL,g="",h=b.duration(+this.minTime);h<this.maxTime;)a=this.start.clone().time(h),c=fa(P(h,this.labelInterval)),d='<td class="fc-axis fc-time '+e.widgetContentClass+'" '+e.axisStyleAttr()+">"+(c?"<span>"+aa(a.format(this.labelFormat))+"</span>":"")+"</td>",g+='<tr data-time="'+a.format("HH:mm:ss")+'"'+(c?"":' class="fc-minor"')+">"+(f?"":d)+'<td class="'+e.widgetContentClass+'"/>'+(f?d:"")+"</tr>",h.add(this.slotDuration);return g},/* Options
1659	------------------------------------------------------------------------------------------------------------------*/
1660// Parses various options into properties of this object
1661processOptions:function(){var c,d=this.view,e=d.opt("slotDuration"),f=d.opt("snapDuration");e=b.duration(e),f=f?b.duration(f):e,this.slotDuration=e,this.snapDuration=f,this.snapsPerSlot=e/f,this.minResizeDuration=f,this.minTime=b.duration(d.opt("minTime")),this.maxTime=b.duration(d.opt("maxTime")),c=d.opt("slotLabelFormat"),a.isArray(c)&&(c=c[c.length-1]),this.labelFormat=c||d.opt("axisFormat")||d.opt("smallTimeFormat"),c=d.opt("slotLabelInterval"),this.labelInterval=c?b.duration(c):this.computeLabelInterval(e)},
1662// Computes an automatic value for slotLabelInterval
1663computeLabelInterval:function(a){var c,d,e;
1664// find the smallest stock label interval that results in more than one slots-per-label
1665for(c=Jb.length-1;c>=0;c--)if(d=b.duration(Jb[c]),e=P(d,a),fa(e)&&e>1)return d;return b.duration(a)},
1666// Computes a default event time formatting string if `timeFormat` is not explicitly defined
1667computeEventTimeFormat:function(){return this.view.opt("noMeridiemTimeFormat")},
1668// Computes a default `displayEventEnd` value if one is not expliclty defined
1669computeDisplayEventEnd:function(){return!0},/* Hit System
1670	------------------------------------------------------------------------------------------------------------------*/
1671prepareHits:function(){this.colCoordCache.build(),this.slatCoordCache.build()},releaseHits:function(){this.colCoordCache.clear()},queryHit:function(a,b){var c=this.snapsPerSlot,d=this.colCoordCache,e=this.slatCoordCache,f=d.getHorizontalIndex(a),g=e.getVerticalIndex(b);if(null!=f&&null!=g){var h=e.getTopOffset(g),i=e.getHeight(g),j=(b-h)/i,k=Math.floor(j*c),l=g*c+k,m=h+k/c*i,n=h+(k+1)/c*i;return{col:f,snap:l,component:this,// needed unfortunately :(
1672left:d.getLeftOffset(f),right:d.getRightOffset(f),top:m,bottom:n}}},getHitSpan:function(a){var b,c=this.getCellDate(0,a.col),d=this.computeSnapTime(a.snap);return c.time(d),b=c.clone().add(this.snapDuration),{start:c,end:b}},getHitEl:function(a){return this.colEls.eq(a.col)},/* Dates
1673	------------------------------------------------------------------------------------------------------------------*/
1674rangeUpdated:function(){this.updateDayTable()},
1675// Given a row number of the grid, representing a "snap", returns a time (Duration) from its start-of-day
1676computeSnapTime:function(a){return b.duration(this.minTime+this.snapDuration*a)},
1677// Slices up the given span (unzoned start/end with other misc data) into an array of segments
1678spanToSegs:function(a){var b,c=this.sliceRangeByTimes(a);for(b=0;b<c.length;b++)this.isRTL?c[b].col=this.daysPerRow-1-c[b].dayIndex:c[b].col=c[b].dayIndex;return c},sliceRangeByTimes:function(a){var b,c,d,e,f=[];for(c=0;c<this.daysPerRow;c++)d=this.dayDates[c].clone(),e={start:d.clone().time(this.minTime),end:d.clone().time(this.maxTime)},b=I(a,e),b&&(b.dayIndex=c,f.push(b));return f},/* Coordinates
1679	------------------------------------------------------------------------------------------------------------------*/
1680updateSize:function(a){// NOT a standard Grid method
1681this.slatCoordCache.build(),a&&this.updateSegVerticals([].concat(this.fgSegs||[],this.bgSegs||[],this.businessSegs||[]))},getTotalSlatHeight:function(){return this.slatContainerEl.outerHeight()},
1682// Computes the top coordinate, relative to the bounds of the grid, of the given date.
1683// A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight.
1684computeDateTop:function(a,c){return this.computeTimeTop(b.duration(a-c.clone().stripTime()))},
1685// Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration).
1686computeTimeTop:function(a){var b,c,d=this.slatEls.length,e=(a-this.minTime)/this.slotDuration;
1687// compute a floating-point number for how many slats should be progressed through.
1688// from 0 to number of slats (inclusive)
1689// constrained because minTime/maxTime might be customized.
1690// an integer index of the furthest whole slat
1691// from 0 to number slats (*exclusive*, so len-1)
1692// how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition.
1693// could be 1.0 if slatCoverage is covering *all* the slots
1694return e=Math.max(0,e),e=Math.min(d,e),b=Math.floor(e),b=Math.min(b,d-1),c=e-b,this.slatCoordCache.getTopPosition(b)+this.slatCoordCache.getHeight(b)*c},/* Event Drag Visualization
1695	------------------------------------------------------------------------------------------------------------------*/
1696// Renders a visual indication of an event being dragged over the specified date(s).
1697// A returned value of `true` signals that a mock "helper" event has been rendered.
1698renderDrag:function(a,b){
1699// otherwise, just render a highlight
1700return b?this.renderEventLocationHelper(a,b):void this.renderHighlight(this.eventToSpan(a))},
1701// Unrenders any visual indication of an event being dragged
1702unrenderDrag:function(){this.unrenderHelper(),this.unrenderHighlight()},/* Event Resize Visualization
1703	------------------------------------------------------------------------------------------------------------------*/
1704// Renders a visual indication of an event being resized
1705renderEventResize:function(a,b){return this.renderEventLocationHelper(a,b)},
1706// Unrenders any visual indication of an event being resized
1707unrenderEventResize:function(){this.unrenderHelper()},/* Event Helper
1708	------------------------------------------------------------------------------------------------------------------*/
1709// Renders a mock "helper" event. `sourceSeg` is the original segment object and might be null (an external drag)
1710renderHelper:function(a,b){return this.renderHelperSegs(this.eventToSegs(a),b)},
1711// Unrenders any mock helper event
1712unrenderHelper:function(){this.unrenderHelperSegs()},/* Business Hours
1713	------------------------------------------------------------------------------------------------------------------*/
1714renderBusinessHours:function(){var a=this.view.calendar.getBusinessHoursEvents(),b=this.eventsToSegs(a);this.renderBusinessSegs(b)},unrenderBusinessHours:function(){this.unrenderBusinessSegs()},/* Now Indicator
1715	------------------------------------------------------------------------------------------------------------------*/
1716getNowIndicatorUnit:function(){return"minute"},renderNowIndicator:function(b){
1717// seg system might be overkill, but it handles scenario where line needs to be rendered
1718//  more than once because of columns with the same date (resources columns for example)
1719var c,d=this.spanToSegs({start:b,end:b}),e=this.computeDateTop(b,b),f=[];
1720// render lines within the columns
1721for(c=0;c<d.length;c++)f.push(a('<div class="fc-now-indicator fc-now-indicator-line"></div>').css("top",e).appendTo(this.colContainerEls.eq(d[c].col))[0]);
1722// render an arrow over the axis
1723d.length>0&&// is the current time in view?
1724f.push(a('<div class="fc-now-indicator fc-now-indicator-arrow"></div>').css("top",e).appendTo(this.el.find(".fc-content-skeleton"))[0]),this.nowIndicatorEls=a(f)},unrenderNowIndicator:function(){this.nowIndicatorEls&&(this.nowIndicatorEls.remove(),this.nowIndicatorEls=null)},/* Selection
1725	------------------------------------------------------------------------------------------------------------------*/
1726// Renders a visual indication of a selection. Overrides the default, which was to simply render a highlight.
1727renderSelection:function(a){this.view.opt("selectHelper")?// this setting signals that a mock helper event should be rendered
1728// normally acceps an eventLocation, span has a start/end, which is good enough
1729this.renderEventLocationHelper(a):this.renderHighlight(a)},
1730// Unrenders any visual indication of a selection
1731unrenderSelection:function(){this.unrenderHelper(),this.unrenderHighlight()},/* Highlight
1732	------------------------------------------------------------------------------------------------------------------*/
1733renderHighlight:function(a){this.renderHighlightSegs(this.spanToSegs(a))},unrenderHighlight:function(){this.unrenderHighlightSegs()}});/* Methods for rendering SEGMENTS, pieces of content that live on the view
1734 ( this file is no longer just for events )
1735----------------------------------------------------------------------------------------------------------------------*/
1736sb.mixin({colContainerEls:null,// containers for each column
1737// inner-containers for each column where different types of segs live
1738fgContainerEls:null,bgContainerEls:null,helperContainerEls:null,highlightContainerEls:null,businessContainerEls:null,
1739// arrays of different types of displayed segments
1740fgSegs:null,bgSegs:null,helperSegs:null,highlightSegs:null,businessSeg
1740s:null,
1741// Renders the DOM that the view's content will live in
1742renderContentSkeleton:function(){var b,c,d="";for(b=0;b<this.colCnt;b++)d+='<td><div class="fc-content-col"><div class="fc-event-container fc-helper-container"></div><div class="fc-event-container"></div><div class="fc-highlight-container"></div><div class="fc-bgevent-container"></div><div class="fc-business-container"></div></div></td>';c=a('<div class="fc-content-skeleton"><table><tr>'+d+"</tr></table></div>"),this.colContainerEls=c.find(".fc-content-col"),this.helperContainerEls=c.find(".fc-helper-container"),this.fgContainerEls=c.find(".fc-event-container:not(.fc-helper-container)"),this.bgContainerEls=c.find(".fc-bgevent-container"),this.highlightContainerEls=c.find(".fc-highlight-container"),this.businessContainerEls=c.find(".fc-business-container"),this.bookendCells(c.find("tr")),this.el.append(c)},/* Foreground Events
1743	------------------------------------------------------------------------------------------------------------------*/
1744renderFgSegs:function(a){return a=this.renderFgSegsIntoContainers(a,this.fgContainerEls),this.fgSegs=a,a},unrenderFgSegs:function(){this.unrenderNamedSegs("fgSegs")},/* Foreground Helper Events
1745	------------------------------------------------------------------------------------------------------------------*/
1746renderHelperSegs:function(b,c){var d,e,f,g=[];
1747// Try to make the segment that is in the same row as sourceSeg look the same
1748for(b=this.renderFgSegsIntoContainers(b,this.helperContainerEls),d=0;d<b.length;d++)e=b[d],c&&c.col===e.col&&(f=c.el,e.el.css({left:f.css("left"),right:f.css("right"),"margin-left":f.css("margin-left"),"margin-right":f.css("margin-right")})),g.push(e.el[0]);return this.helperSegs=b,a(g)},unrenderHelperSegs:function(){this.unrenderNamedSegs("helperSegs")},/* Background Events
1749	------------------------------------------------------------------------------------------------------------------*/
1750renderBgSegs:function(a){// TODO: old fill system
1751return a=this.renderFillSegEls("bgEvent",a),this.updateSegVerticals(a),this.attachSegsByCol(this.groupSegsByCol(a),this.bgContainerEls),this.bgSegs=a,a},unrenderBgSegs:function(){this.unrenderNamedSegs("bgSegs")},/* Highlight
1752	------------------------------------------------------------------------------------------------------------------*/
1753renderHighlightSegs:function(a){a=this.renderFillSegEls("highlight",a),this.updateSegVerticals(a),this.attachSegsByCol(this.groupSegsByCol(a),this.highlightContainerEls),this.highlightSegs=a},unrenderHighlightSegs:function(){this.unrenderNamedSegs("highlightSegs")},/* Business Hours
1754	------------------------------------------------------------------------------------------------------------------*/
1755renderBusinessSegs:function(a){a=this.renderFillSegEls("businessHours",a),this.updateSegVerticals(a),this.attachSegsByCol(this.groupSegsByCol(a),this.businessContainerEls),this.businessSegs=a},unrenderBusinessSegs:function(){this.unrenderNamedSegs("businessSegs")},/* Seg Rendering Utils
1756	------------------------------------------------------------------------------------------------------------------*/
1757// Given a flat array of segments, return an array of sub-arrays, grouped by each segment's col
1758groupSegsByCol:function(a){var b,c=[];for(b=0;b<this.colCnt;b++)c.push([]);for(b=0;b<a.length;b++)c[a[b].col].push(a[b]);return c},
1759// Given segments grouped by column, insert the segments' elements into a parallel array of container
1760// elements, each living within a column.
1761attachSegsByCol:function(a,b){var c,d,e;for(c=0;c<this.colCnt;c++)for(d=a[c],e=0;e<d.length;e++)b.eq(c).append(d[e].el)},
1762// Given the name of a property of `this` object, assumed to be an array of segments,
1763// loops through each segment and removes from DOM. Will null-out the property afterwards.
1764unrenderNamedSegs:function(a){var b,c=this[a];if(c){for(b=0;b<c.length;b++)c[b].el.remove();this[a]=null}},/* Foreground Event Rendering Utils
1765	------------------------------------------------------------------------------------------------------------------*/
1766// Given an array of foreground segments, render a DOM element for each, computes position,
1767// and attaches to the column inner-container elements.
1768renderFgSegsIntoContainers:function(a,b){var c,d;for(a=this.renderFgSegEls(a),c=this.groupSegsByCol(a),d=0;d<this.colCnt;d++)this.updateFgSegCoords(c[d]);return this.attachSegsByCol(c,b),a},
1769// Renders the HTML for a single event segment's default rendering
1770fgSegHtml:function(a,b){var c,d,e,f=this.view,g=a.event,h=f.isEventDraggable(g),i=!b&&a.isStart&&f.isEventResizableFromStart(g),j=!b&&a.isEnd&&f.isEventResizableFromEnd(g),k=this.getSegClasses(a,h,i||j),l=ca(this.getSegSkinCss(a));// just the start time text
1771// if the event appears to span more than one day...
1772// Don't display time text on segments that run entirely through a day.
1773// That would appear as midnight-midnight and would look dumb.
1774// Otherwise, display the time text for the *segment's* times (like 6pm-midnight or midnight-10am)
1775// Display the normal time text for the *event's* times
1776/* TODO: write CSS for this
1777				(isResizableFromStart ?
1778					'<div class="fc-resizer fc-start-resizer" />' :
1779					''
1780					) +
1781				*/
1782return k.unshift("fc-time-grid-event","fc-v-event"),f.isMultiDayEvent(g)?(a.isStart||a.isEnd)&&(c=this.getEventTimeText(a),d=this.getEventTimeText(a,"LT"),e=this.getEventTimeText(a,null,!1)):(c=this.getEventTimeText(g),d=this.getEventTimeText(g,"LT"),e=this.getEventTimeText(g,null,!1)),'<a class="'+k.join(" ")+'"'+(g.url?' href="'+aa(g.url)+'"':"")+(l?' style="'+l+'"':"")+'><div class="fc-content">'+(c?'<div class="fc-time" data-start="'+aa(e)+'" data-full="'+aa(d)+'"><span>'+aa(c)+"</span></div>":"")+(g.title?'<div class="fc-title">'+aa(g.title)+"</div>":"")+'</div><div class="fc-bg"/>'+(j?'<div class="fc-resizer fc-end-resizer" />':"")+"</a>"},/* Seg Position Utils
1783	------------------------------------------------------------------------------------------------------------------*/
1784// Refreshes the CSS top/bottom coordinates for each segment element.
1785// Works when called after initial render, after a window resize/zoom for example.
1786updateSegVerticals:function(a){this.computeSegVerticals(a),this.assignSegVerticals(a)},
1787// For each segment in an array, computes and assigns its top and bottom properties
1788computeSegVerticals:function(a){var b,c;for(b=0;b<a.length;b++)c=a[b],c.top=this.computeDateTop(c.start,c.start),c.bottom=this.computeDateTop(c.end,c.start)},
1789// Given segments that already have their top/bottom properties computed, applies those values to
1790// the segments' elements.
1791assignSegVerticals:function(a){var b,c;for(b=0;b<a.length;b++)c=a[b],c.el.css(this.generateSegVerticalCss(c))},
1792// Generates an object with CSS properties for the top/bottom coordinates of a segment element
1793generateSegVerticalCss:function(a){return{top:a.top,bottom:-a.bottom}},/* Foreground Event Positioning Utils
1794	------------------------------------------------------------------------------------------------------------------*/
1795// Given segments that are assumed to all live in the *same column*,
1796// compute their verical/horizontal coordinates and assign to their elements.
1797updateFgSegCoords:function(a){this.computeSegVerticals(a),// horizontals relies on this
1798this.computeFgSegHorizontals(a),// compute horizontal coordinates, z-index's, and reorder the array
1799this.assignSegVerticals(a),this.assignFgSegHorizontals(a)},
1800// Given an array of segments that are all in the same column, sets the backwardCoord and forwardCoord on each.
1801// NOTE: Also reorders the given array by date!
1802computeFgSegHorizontals:function(a){var b,c,d;if(this.sortEventSegs(a),b=Ia(a),Ja(b),c=b[0]){for(d=0;d<c.length;d++)Ka(c[d]);for(d=0;d<c.length;d++)this.computeFgSegForwardBack(c[d],0,0)}},
1803// Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range
1804// from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to "left" and
1805// seg.forwardCoord maps to "right" (via percentage). Vice-versa if the calendar is right-to-left.
1806//
1807// The segment might be part of a "series", which means consecutive segments with the same pressure
1808// who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of
1809// segments behind this one in the current series, and `seriesBackwardCoord` is the starting
1810// coordinate of the first segment in the series.
1811computeFgSegForwardBack:function(a,b,c){var d,e=a.forwardSegs;if(void 0===a.forwardCoord)// # of segments in the series
1812// use this segment's coordinates to computed the coordinates of the less-pressurized
1813// forward segments
1814for(// not already computed
1815e.length?(
1816// sort highest pressure first
1817this.sortForwardSegs(e),
1818// this segment's forwardCoord will be calculated from the backwardCoord of the
1819// highest-pressure forward segment.
1820this.computeFgSegForwardBack(e[0],b+1,c),a.forwardCoord=e[0].backwardCoord):
1821// if there are no forward segments, this segment should butt up against the edge
1822a.forwardCoord=1,
1823// calculate the backwardCoord from the forwardCoord. consider the series
1824a.backwardCoord=a.forwardCoord-(a.forwardCoord-c)/(// available width for series
1825b+1),d=0;d<e.length;d++)this.computeFgSegForwardBack(e[d],0,a.forwardCoord)},sortForwardSegs:function(a){a.sort(ga(this,"compareForwardSegs"))},
1826// A cmp function for determining which forward segment to rely on more when computing coordinates.
1827compareForwardSegs:function(a,b){
1828// put higher-pressure first
1829// put segments that are closer to initial edge first (and favor ones with no coords yet)
1830// do normal sorting...
1831return b.forwardPressure-a.forwardPressure||(a.backwardCoord||0)-(b.backwardCoord||0)||this.compareEventSegs(a,b)},
1832// Given foreground event segments that have already had their position coordinates computed,
1833// assigns position-related CSS values to their elements.
1834assignFgSegHorizontals:function(a){var b,c;for(b=0;b<a.length;b++)c=a[b],c.el.css(this.generateFgSegHorizontalCss(c)),c.bottom-c.top<30&&c.el.addClass("fc-short")},
1835// Generates an object with CSS properties/values that should be applied to an event segment element.
1836// Contains important positioning-related properties that should be applied to any event element, customized or not.
1837generateFgSegHorizontalCss:function(a){var b,c,d=this.view.opt("slotEventOverlap"),e=a.backwardCoord,f=a.forwardCoord,g=this.generateSegVerticalCss(a);// amount of space from right edge, a fraction of the total width
1838// double the width, but don't go beyond the maximum forward coordinate (1.0)
1839// convert from 0-base to 1-based
1840// add padding to the edge so that forward stacked events don't cover the resizer's icon
1841return d&&(f=Math.min(1,e+2*(f-e))),this.isRTL?(b=1-f,c=e):(b=e,c=1-f),g.zIndex=a.level+1,g.left=100*b+"%",g.right=100*c+"%",d&&a.forwardPressure&&(g[this.isRTL?"marginLeft":"marginRight"]=20),g}});/* An abstract class from which other views inherit from
1842----------------------------------------------------------------------------------------------------------------------*/
1843var tb=Ta.View=va.extend(ib,jb,{type:null,// subclass' view name (string)
1844name:null,// deprecated. use `type` instead
1845title:null,// the text that will be displayed in the header's title
1846calendar:null,// owner Calendar object
1847options:null,// hash containing all options. already merged with view-specific-options
1848el:null,// the view's containing element. set by Calendar
1849displaying:null,// a promise representing the state of rendering. null if no render requested
1850isSkeletonRendered:!1,isEventsRendered:!1,
1851// range the view is actually displaying (moments)
1852start:null,end:null,// exclusive
1853// range the view is formally responsible for (moments)
1854// may be different from start/end. for example, a month view might have 1st-31st, excluding padded dates
1855intervalStart:null,intervalEnd:null,// exclusive
1856intervalDuration:null,intervalUnit:null,// name of largest unit being displayed, like "month" or "week"
1857isRTL:!1,isSelected:!1,// boolean whether a range of time is user-selected or not
1858selectedEvent:null,eventOrderSpecs:null,// criteria for ordering events when they have same date/time
1859// classNames styled by jqui themes
1860widgetHeaderClass:null,widgetContentClass:null,highlightStateClass:null,
1861// for date utils, computed from options
1862nextDayThreshold:null,isHiddenDayHash:null,
1863// now indicator
1864isNowIndicatorRendered:null,initialNowDate:null,// result first getNow call
1865initialNowQueriedMs:null,// ms time the getNow was called
1866nowIndicatorTimeoutID:null,// for refresh timing of now indicator
1867nowIndicatorIntervalID:null,// "
1868constructor:function(a,c,d,e){this.calendar=a,this.type=this.name=c,// .name is deprecated
1869this.options=d,this.intervalDuration=e||b.duration(1,"day"),this.nextDayThreshold=b.duration(this.opt("nextDayThreshold")),this.initThemingProps(),this.initHiddenDays(),this.isRTL=this.opt("isRTL"),this.eventOrderSpecs=E(this.opt("eventOrder")),this.initialize()},
1870// A good place for subclasses to initialize member variables
1871initialize:function(){},
1872// Retrieves an option with the given name
1873opt:function(a){return this.options[a]},
1874// Triggers handlers that are view-related. Modifies args before passing to calendar.
1875trigger:function(a,b){// arguments beyond thisObj are passed along
1876var c=this.calendar;// arguments beyond thisObj
1877return c.trigger.apply(c,[a,b||this].concat(Array.prototype.slice.call(arguments,2),[this]))},/* Dates
1878	------------------------------------------------------------------------------------------------------------------*/
1879// Updates all internal dates to center around the given current unzoned date.
1880setDate:function(a){this.setRange(this.computeRange(a))},
1881// Updates all internal dates for displaying the given unzoned range.
1882setRange:function(b){a.extend(this,b),// assigns every property to this object's member variables
1883this.updateTitle()},
1884// Given a single current unzoned date, produce information about what range to display.
1885// Subclasses can override. Must return all properties.
1886computeRange:function(a){var b,c,d=M(this.intervalDuration),e=a.clone().startOf(d),f=e.clone().add(this.intervalDuration);// exclusively move backwards
1887// normalize the range's time-ambiguity
1888// whole-days?
1889// needs to have a time?
1890return/year|month|week|day/.test(d)?(e.stripTime(),f.stripTime()):(e.hasTime()||(e=this.calendar.time(0)),f.hasTime()||(f=this.calendar.time(0))),b=e.clone(),b=this.skipHiddenDays(b),c=f.clone(),c=this.skipHiddenDays(c,-1,!0),{intervalUnit:d,intervalStart:e,intervalEnd:f,start:b,end:c}},
1891// Computes the new date when the user hits the prev button, given the current date
1892computePrevDate:function(a){return this.massageCurrentDate(a.clone().startOf(this.intervalUnit).subtract(this.intervalDuration),-1)},
1893// Computes the new date when the user hits the next button, given the current date
1894computeNextDate:function(a){return this.massageCurrentDate(a.clone().startOf(this.intervalUnit).add(this.intervalDuration))},
1895// Given an arbitrarily calculated current date of the calendar, returns a date that is ensured to be completely
1896// visible. `direction` is optional and indicates which direction the current date was being
1897// incremented or decremented (1 or -1).
1898massageCurrentDate:function(a,b){return this.intervalDuration.as("days")<=1&&this.isHiddenDay(a)&&(a=this.skipHiddenDays(a,b),a.startOf("day")),a},/* Title and Date Formatting
1899	------------------------------------------------------------------------------------------------------------------*/
1900// Sets the view's title property to the most updated computed value
1901updateTitle:function(){this.title=this.computeTitle()},
1902// Computes what the title at the top of the calendar should be for this view
1903computeTitle:function(){return this.formatRange({
1904// in case intervalStart/End has a time, make sure timezone is correct
1905start:this.calendar.applyTimezone(this.intervalStart),end:this.calendar.applyTimezone(this.intervalEnd)},this.opt("titleFormat")||this.computeTitleFormat(),this.opt("titleRangeSeparator"))},
1906// Generates the format string that should be used to generate the title for the current date range.
1907// Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`.
1908computeTitleFormat:function(){return"year"==this.intervalUnit?"YYYY":"month"==this.intervalUnit?this.opt("monthYearFormat"):this.intervalDuration.as("days")>1?"ll":"LL"},
1909// Utility for formatting a range. Accepts a range object, formatting string, and optional separator.
1910// Displays all-day ranges naturally, with an inclusive end. Takes the current isRTL into account.
1911// The timezones of the dates within `range` will be respected.
1912formatRange:function(a,b,c){var d=a.end;// all-day?
1913return d.hasTime()||(d=d.clone().subtract(1)),qa(a.start,d,b,c,this.opt("isRTL"))},/* Rendering
1914	------------------------------------------------------------------------------------------------------------------*/
1915// Sets the container element that the view should render inside of.
1916// Does other DOM-related initializations.
1917setElement:function(a){this.el=a,this.bindGlobalHandlers()},
1918// Removes the view's container element from the DOM, clearing any content beforehand.
1919// Undoes any other DOM-related attachments.
1920removeElement:function(){this.clear(),// clears all content
1921// clean up the skeleton
1922this.isSkeletonRendered&&(this.unrenderSkeleton(),this.isSkeletonRendered=!1),this.unbindGlobalHandlers(),this.el.remove()},
1923// Does everything necessary to display the view centered around the given unzoned date.
1924// Does every type of rendering EXCEPT rendering events.
1925// Is asychronous and returns a promise.
1926display:function(b){var c=this,d=null;return this.displaying&&(d=this.queryScroll()),this.calendar.freezeContentHeight(),this.clear().then(function(){// clear the content first (async)
1927return c.displaying=a.when(c.displayView(b)).then(function(){c.forceScroll(c.computeInitialScroll(d)),c.calendar.unfreezeContentHeight(),c.triggerRe
1927nder()})})},
1928// Does everything necessary to clear the content of the view.
1929// Clears dates and events. Does not clear the skeleton.
1930// Is asychronous and returns a promise.
1931clear:function(){var b=this,c=this.displaying;return c?c.then(function(){// wait for the display to finish
1932return b.displaying=null,b.clearEvents(),b.clearView()}):a.when()},
1933// Displays the view's non-event content, such as date-related content or anything required by events.
1934// Renders the view's non-content skeleton if necessary.
1935// Can be asynchronous and return a promise.
1936displayView:function(a){this.isSkeletonRendered||(this.renderSkeleton(),this.isSkeletonRendered=!0),a&&this.setDate(a),this.render&&this.render(),this.renderDates(),this.updateSize(),this.renderBusinessHours(),// might need coordinates, so should go after updateSize()
1937this.startNowIndicator()},
1938// Unrenders the view content that was rendered in displayView.
1939// Can be asynchronous and return a promise.
1940clearView:function(){this.unselect(),this.stopNowIndicator(),this.triggerUnrender(),this.unrenderBusinessHours(),this.unrenderDates(),this.destroy&&this.destroy()},
1941// Renders the basic structure of the view before any content is rendered
1942renderSkeleton:function(){},
1943// Unrenders the basic structure of the view
1944unrenderSkeleton:function(){},
1945// Renders the view's date-related content.
1946// Assumes setRange has already been called and the skeleton has already been rendered.
1947renderDates:function(){},
1948// Unrenders the view's date-related content
1949unrenderDates:function(){},
1950// Signals that the view's content has been rendered
1951triggerRender:function(){this.trigger("viewRender",this,this,this.el)},
1952// Signals that the view's content is about to be unrendered
1953triggerUnrender:function(){this.trigger("viewDestroy",this,this,this.el)},
1954// Binds DOM handlers to elements that reside outside the view container, such as the document
1955bindGlobalHandlers:function(){this.listenTo(a(document),"mousedown",this.handleDocumentMousedown),this.listenTo(a(document),"touchstart",this.handleDocumentTouchStart),this.listenTo(a(document),"touchend",this.handleDocumentTouchEnd)},
1956// Unbinds DOM handlers from elements that reside outside the view container
1957unbindGlobalHandlers:function(){this.stopListeningTo(a(document))},
1958// Initializes internal variables related to theming
1959initThemingProps:function(){var a=this.opt("theme")?"ui":"fc";this.widgetHeaderClass=a+"-widget-header",this.widgetContentClass=a+"-widget-content",this.highlightStateClass=a+"-state-highlight"},/* Business Hours
1960	------------------------------------------------------------------------------------------------------------------*/
1961// Renders business-hours onto the view. Assumes updateSize has already been called.
1962renderBusinessHours:function(){},
1963// Unrenders previously-rendered business-hours
1964unrenderBusinessHours:function(){},/* Now Indicator
1965	------------------------------------------------------------------------------------------------------------------*/
1966// Immediately render the current time indicator and begins re-rendering it at an interval,
1967// which is defined by this.getNowIndicatorUnit().
1968// TODO: somehow do this for the current whole day's background too
1969startNowIndicator:function(){var a,c,d,e=this;// ms wait value
1970this.opt("nowIndicator")&&(a=this.getNowIndicatorUnit(),a&&(c=ga(this,"updateNowIndicator"),this.initialNowDate=this.calendar.getNow(),this.initialNowQueriedMs=+new Date,this.renderNowIndicator(this.initialNowDate),this.isNowIndicatorRendered=!0,d=this.initialNowDate.clone().startOf(a).add(1,a)-this.initialNowDate,this.nowIndicatorTimeoutID=setTimeout(function(){e.nowIndicatorTimeoutID=null,c(),d=+b.duration(1,a),d=Math.max(100,d),e.nowIndicatorIntervalID=setInterval(c,d)},d)))},
1971// rerenders the now indicator, computing the new current time from the amount of time that has passed
1972// since the initial getNow call.
1973updateNowIndicator:function(){this.isNowIndicatorRendered&&(this.unrenderNowIndicator(),this.renderNowIndicator(this.initialNowDate.clone().add(new Date-this.initialNowQueriedMs)))},
1974// Immediately unrenders the view's current time indicator and stops any re-rendering timers.
1975// Won't cause side effects if indicator isn't rendered.
1976stopNowIndicator:function(){this.isNowIndicatorRendered&&(this.nowIndicatorTimeoutID&&(clearTimeout(this.nowIndicatorTimeoutID),this.nowIndicatorTimeoutID=null),this.nowIndicatorIntervalID&&(clearTimeout(this.nowIndicatorIntervalID),this.nowIndicatorIntervalID=null),this.unrenderNowIndicator(),this.isNowIndicatorRendered=!1)},
1977// Returns a string unit, like 'second' or 'minute' that defined how often the current time indicator
1978// should be refreshed. If something falsy is returned, no time indicator is rendered at all.
1979getNowIndicatorUnit:function(){},
1980// Renders a current time indicator at the given datetime
1981renderNowIndicator:function(a){},
1982// Undoes the rendering actions from renderNowIndicator
1983unrenderNowIndicator:function(){},/* Dimensions
1984	------------------------------------------------------------------------------------------------------------------*/
1985// Refreshes anything dependant upon sizing of the container element of the grid
1986updateSize:function(a){var b;a&&(b=this.queryScroll()),this.updateHeight(a),this.updateWidth(a),this.updateNowIndicator(),a&&this.setScroll(b)},
1987// Refreshes the horizontal dimensions of the calendar
1988updateWidth:function(a){},
1989// Refreshes the vertical dimensions of the calendar
1990updateHeight:function(a){var b=this.calendar;// we poll the calendar for height information
1991this.setHeight(b.getSuggestedViewHeight(),b.isHeightAuto())},
1992// Updates the vertical dimensions of the calendar to the specified height.
1993// if `isAuto` is set to true, height becomes merely a suggestion and the view should use its "natural" height.
1994setHeight:function(a,b){},/* Scroller
1995	------------------------------------------------------------------------------------------------------------------*/
1996// Computes the initial pre-configured scroll state prior to allowing the user to change it.
1997// Given the scroll state from the previous rendering. If first time rendering, given null.
1998computeInitialScroll:function(a){return 0},
1999// Retrieves the view's current natural scroll state. Can return an arbitrary format.
2000queryScroll:function(){},
2001// Sets the view's scroll state. Will accept the same format computeInitialScroll and queryScroll produce.
2002setScroll:function(a){},
2003// Sets the scroll state, making sure to overcome any predefined scroll value the browser has in mind
2004forceScroll:function(a){var b=this;this.setScroll(a),setTimeout(function(){b.setScroll(a)},0)},/* Event Elements / Segments
2005	------------------------------------------------------------------------------------------------------------------*/
2006// Does everything necessary to display the given events onto the current view
2007displayEvents:function(a){var b=this.queryScroll();this.clearEvents(),this.renderEvents(a),this.isEventsRendered=!0,this.setScroll(b),this.triggerEventRender()},
2008// Does everything necessary to clear the view's currently-rendered events
2009clearEvents:function(){var a;this.isEventsRendered&&(a=this.queryScroll(),this.triggerEventUnrender(),this.destroyEvents&&this.destroyEvents(),this.unrenderEvents(),this.setScroll(a),this.isEventsRendered=!1)},
2010// Renders the events onto the view.
2011renderEvents:function(a){},
2012// Removes event elements from the view.
2013unrenderEvents:function(){},
2014// Signals that all events have been rendered
2015triggerEventRender:function(){this.renderedEventSegEach(function(a){this.trigger("eventAfterRender",a.event,a.event,a.el)}),this.trigger("eventAfterAllRender")},
2016// Signals that all event elements are about to be removed
2017triggerEventUnrender:function(){this.renderedEventSegEach(function(a){this.trigger("eventDestroy",a.event,a.event,a.el)})},
2018// Given an event and the default element used for rendering, returns the element that should actually be used.
2019// Basically runs events and elements through the eventRender hook.
2020resolveEventEl:function(b,c){var d=this.trigger("eventRender",b,b,c);// means don't render at all
2021return d===!1?c=null:d&&d!==!0&&(c=a(d)),c},
2022// Hides all rendered event segments linked to the given event
2023showEvent:function(a){this.renderedEventSegEach(function(a){a.el.css("visibility","")},a)},
2024// Shows all rendered event segments linked to the given event
2025hideEvent:function(a){this.renderedEventSegEach(function(a){a.el.css("visibility","hidden")},a)},
2026// Iterates through event segments that have been rendered (have an el). Goes through all by default.
2027// If the optional `event` argument is specified, only iterates through segments linked to that event.
2028// The `this` value of the callback function will be the view.
2029renderedEventSegEach:function(a,b){var c,d=this.getEventSegs();for(c=0;c<d.length;c++)b&&d[c].event._id!==b._id||d[c].el&&a.call(this,d[c])},
2030// Retrieves all the rendered segment objects for the view
2031getEventSegs:function(){
2032// subclasses must implement
2033return[]},/* Event Drag-n-Drop
2034	------------------------------------------------------------------------------------------------------------------*/
2035// Computes if the given event is allowed to be dragged by the user
2036isEventDraggable:function(a){var b=a.source||{};return _(a.startEditable,b.startEditable,this.opt("eventStartEditable"),a.editable,b.editable,this.opt("editable"))},
2037// Must be called when an event in the view is dropped onto new location.
2038// `dropLocation` is an object that contains the new zoned start/end/allDay values for the event.
2039reportEventDrop:function(a,b,c,d,e){var f=this.calendar,g=f.mutateEvent(a,b,c),h=function(){g.undo(),f.reportEventChange()};this.triggerEventDrop(a,g.dateDelta,h,d,e),f.reportEventChange()},
2040// Triggers event-drop handlers that have subscribed via the API
2041triggerEventDrop:function(a,b,c,d,e){this.trigger("eventDrop",d[0],a,b,c,e,{})},/* External Element Drag-n-Drop
2042	------------------------------------------------------------------------------------------------------------------*/
2043// Must be called when an external element, via jQuery UI, has been dropped onto the calendar.
2044// `meta` is the parsed data that has been embedded into the dragging event.
2045// `dropLocation` is an object that contains the new zoned start/end/allDay values for the event.
2046reportExternalDrop:function(b,c,d,e,f){var g,h,i=b.eventProps;
2047// Try to build an event object and render it. TODO: decouple the two
2048i&&(g=a.extend({},i,c),h=this.calendar.renderEvent(g,b.stick)[0]),this.triggerExternalDrop(h,c,d,e,f)},
2049// Triggers external-drop handlers that have subscribed via the API
2050triggerExternalDrop:function(a,b,c,d,e){
2051// trigger 'drop' regardless of whether element represents an event
2052this.trigger("drop",c[0],b.start,d,e),a&&this.trigger("eventReceive",null,a)},/* Drag-n-Drop Rendering (for both events and external elements)
2053	------------------------------------------------------------------------------------------------------------------*/
2054// Renders a visual indication of a event or external-element drag over the given drop zone.
2055// If an external-element, seg will be `null`.
2056// Must return elements used for any mock events.
2057renderDrag:function(a,b){},
2058// Unrenders a visual indication of an event or external-element being dragged.
2059unrenderDrag:function(){},/* Event Resizing
2060	------------------------------------------------------------------------------------------------------------------*/
2061// Computes if the given event is allowed to be resized from its starting edge
2062isEventResizableFromStart:function(a){return this.opt("eventResizableFromStart")&&this.isEventResizable(a)},
2063// Computes if the given event is allowed to be resized from its ending edge
2064isEventResizableFromEnd:function(a){return this.isEventResizable(a)},
2065// Computes if the given event is allowed to be resized by the user at all
2066isEventResizable:function(a){var b=a.source||{};return _(a.durationEditable,b.durationEditable,this.opt("eventDurationEditable"),a.editable,b.editable,this.opt("editable"))},
2067// Must be called when an event in the view has been resized to a new length
2068reportEventResize:function(a,b,c,d,e){var f=this.calendar,g=f.mutateEvent(a,b,c),h=function(){g.undo(),f.reportEventChange()};this.triggerEventResize(a,g.durationDelta,h,d,e),f.reportEventChange()},
2069// Triggers event-resize handlers that have subscribed via the API
2070triggerEventResize:function(a,b,c,d,e){this.trigger("eventResize",d[0],a,b,c,e,{})},/* Selection (time range)
2071	------------------------------------------------------------------------------------------------------------------*/
2072// Selects a date span on the view. `start` and `end` are both Moments.
2073// `ev` is the native mouse event that begin the interaction.
2074select:function(a,b){this.unselect(b),this.renderSelection(a),this.reportSelection(a,b)},
2075// Renders a visual indication of the selection
2076renderSelection:function(a){},
2077// Called when a new selection is made. Updates internal state and triggers handlers.
2078reportSelection:function(a,b){this.isSelected=!0,this.triggerSelect(a,b)},
2079// Triggers handlers to 'select'
2080triggerSelect:function(a,b){this.trigger("select",null,this.calendar.applyTimezone(a.start),// convert to calendar's tz for external API
2081this.calendar.applyTimezone(a.end),// "
2082b)},
2083// Undoes a selection. updates in the internal state and triggers handlers.
2084// `ev` is the native mouse event that began the interaction.
2085unselect:function(a){this.isSelected&&(this.isSelected=!1,this.destroySelection&&this.destroySelection(),this.unrenderSelection(),this.trigger("unselect",null,a))},
2086// Unrenders a visual indication of selection
2087unrenderSelection:function(){},/* Event Selection
2088	------------------------------------------------------------------------------------------------------------------*/
2089selectEvent:function(a){this.selectedEvent&&this.selectedEvent===a||(this.unselectEvent(),this.renderedEventSegEach(function(a){a.el.addClass("fc-selected")},a),this.selectedEvent=a)},unselectEvent:function(){this.selectedEvent&&(this.renderedEventSegEach(function(a){a.el.removeClass("fc-selected")},this.selectedEvent),this.selectedEvent=null)},isEventSelected:function(a){
2090// event references might change on refetchEvents(), while selectedEvent doesn't,
2091// so compare IDs
2092return this.selectedEvent&&this.selectedEvent._id===a._id},/* Mouse / Touch Unselecting (time range & event unselection)
2093	------------------------------------------------------------------------------------------------------------------*/
2094// TODO: move consistently to down/start or up/end?
2095handleDocumentMousedown:function(a){
2096// touch devices fire simulated mouse events on a "click".
2097// only process mousedown if we know this isn't a touch device.
2098!this.calendar.isTouch&&u(a)&&(this.processRangeUnselect(a),this.processEventUnselect(a))},handleDocumentTouchStart:function(a){this.processRangeUnselect(a)},handleDocumentTouchEnd:function(a){
2099// TODO: don't do this if because of touch-scrolling
2100this.processEventUnselect(a)},processRangeUnselect:function(b){var c;
2101// is there a time-range selection?
2102this.isSelected&&this.opt("unselectAuto")&&(c=this.opt("unselectCancel"),c&&a(b.target).closest(c).length||this.unselect(b))},processEventUnselect:function(b){this.selectedEvent&&(a(b.target).closest(".fc-selected").length||this.unselectEvent())},/* Day Click
2103	------------------------------------------------------------------------------------------------------------------*/
2104// Triggers handlers to 'dayClick'
2105// Span has start/end of the clicked area. Only the start is useful.
2106triggerDayClick:function(a,b,c){this.trigger("dayClick",b,this.calendar.applyTimezone(a.start),// convert to calendar's timezone for external API
2107c)},/* Date Utils
2108	------------------------------------------------------------------------------------------------------------------*/
2109// Initializes internal variables related to calculating hidden days-of-week
2110initHiddenDays:function(){var b,c=this.opt("hiddenDays")||[],d=[],e=0;for(this.opt("weekends")===!1&&c.push(0,6),b=0;7>b;b++)(d[b]=-1!==a.inArray(b,c))||e++;if(!e)throw"invalid hiddenDays";this.isHiddenDayHash=d},
2111// Is the current day hidden?
2112// `day` is a day-of-week index (0-6), or a Moment
2113isHiddenDay:function(a){return b.isMoment(a)&&(a=a.day()),this.isHiddenDayHash[a]},
2114// Incrementing the current day until it is no longer a hidden day, returning a copy.
2115// If the initial value of `date` is not a hidden day, don't do anything.
2116// Pass `isExclusive` as `true` if you are dealing with an end date.
2117// `inc` defaults to `1` (increment one day forward each time)
2118skipHiddenDays:function(a,b,c){var d=a.clone();for(b=b||1;this.isHiddenDayHash[(d.day()+(c?b:0)+7)%7];)d.add(b,"days");return d},
2119// Returns the date range of the full days the given range visually appears to occupy.
2120// Returns a new range object.
2121computeDayRange:function(a){var b,c=a.start.clone().stripTime(),d=a.end,e=null;// the beginning of the day the range exclusively ends
2122// # of milliseconds into `endDay`
2123// If the end time is actually inclusively part of the next day and is equal to or
2124// beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.
2125// Otherwise, leaving it as inclusive will cause it to exclude `endDay`.
2126// If no end was specified, or if it is within `startDay` but not past nextDayThreshold,
2127// assign the default duration of one day.
2128return d&&(e=d.clone().stripTime(),b=+d.time(),b&&b>=this.nextDayThreshold&&e.add(1,"days")),(!d||c>=e)&&(e=c.clone().add(1,"days")),{start:c,end:e}},
2129// Does the given event visually appear to occupy more than one day?
2130isMultiDayEvent:function(a){var b=this.computeDayRange(a);// event is range-ish
2131return b.end.diff(b.start,"days")>1}}),ub=Ta.Scroller=va.extend({el:null,// the guaranteed outer element
2132scrollEl:null,// the element with the scrollbars
2133overflowX:null,overflowY:null,constructor:function(a){a=a||{},this.overflowX=a.overflowX||a.overflow||"auto",this.overflowY=a.overflowY||a.overflow||"auto"},render:function(){this.el=this.renderEl(),this.applyOverflow()},renderEl:function(){return this.scrollEl=a('<div class="fc-scroller"></div>')},
2134// sets to natural height, unlocks overflow
2135clear:function(){this.setHeight("auto"),this.applyOverflow()},destroy:function(){this.el.remove()},
2136// Overflow
2137// -----------------------------------------------------------------------------------------------------------------
2138applyOverflow:function(){this.scrollEl.css({"overflow-x":this.overflowX,"overflow-y":this.overflowY})},
2139// Causes any 'auto' overflow values to resolves to 'scroll' or 'hidden'.
2140// Useful for preserving scrollbar widths regardless of future resizes.
2141// Can pass in scrollbarWidths for optimization.
2142lockOverflow:function(a){var b=this.overflowX,c=this.overflowY;a=a||this.getScrollbarWidths(),"auto"===b&&(b=a.top||a.bottom||this.scrollEl[0].scrollWidth-1>this.scrollEl[0].clientWidth?"scroll":"hidden"),"auto"===c&&(c=a.left||a.right||this.scrollEl[0].scrollHeight-1>this.scrollEl[0].clientHeight?"scroll":"hidden"),this.scrollEl.css({"overflow-x":b,"overflow-y":c})},
2143// Getters / Setters
2144// -----------------------------------------------------------------------------------------------------------------
2145setHeight:function(a){this.scrollEl.height(a)},getScrollTop:function(){return this.scrollEl.scrollTop()},setScrollTop:function(a){this.scrollEl.scrollTop(a)},getClientWidth:function(){return this.scrollEl[0].clientWidth},getClientHeight:function(){return this.scrollEl[0].clientHeight},getScrollbarWidths:function(){return q(this.scrollEl)}}),vb=Ta.Calendar=va.extend({dirDefaults:null,// option defaults related to LTR or RTL
2146langDefaults:null,// option defaults related to current locale
2147overrides:null,// option overrides given to the fullCalendar constructor
2148options:null,// all defaults combined with overrides
2149viewSpecCache:null,// cache of view definitions
2150view:null,// current View object
2151header:null,loadingLevel:0,// number of simultaneous loading tasks
2152isTouch:!1,
2153// a lot of this class' OOP logic is scoped within this constructor function,
2154// but in the future, write individual methods on the prototype.
2155constructor:Na,
2156// Subclasses can override this for initialization logic after the constructor has been called
2157initialize:function(){},
2158// Initializes `this.options` and other important options-related objects
2159initOptions:function(a){var b,e,f,g;a=d(a),b=a.lang,e=wb[b],e||(b=vb.defaults.lang,e=wb[b]||{}),f=_(a.isRTL,e.isRTL,vb.defaults.isRTL),g=f?vb.rtlDefaults:{},this.dirDefaults=g,this.langDefaults=e,this.overrides=a,this.options=c([vb.defaults,g,e,a]),Oa(this.options),this.isTouch=null!=this.options.isTouch?this.options.isTouch:Ta.isTouch,this.viewSpecCache={}},
2160// Gets information about how to create a view. Will use a cache.
2161getViewSpec:function(a){var b=this.viewSpecCache;return b[a]||(b[a]=this.buildViewSpec(a))},
2162// Given a duration singular unit, like "week" or "day", finds a matching view spec.
2163// Preference is given to views that have corresponding buttons.
2164getUnitViewSpec:function(b){var c,d,e;if(-1!=a.inArray(b,Ya))for(c=this.header.getViewsWithButtons(),a.each(Ta.views,function(a){c.push(a)}),d=0;d<c.length;d++)if(e=this.getViewSpec(c[d]),e&&e.singleUnit==b)return e},
2165// Builds an object with information on how to create a given view
2166buildViewSpec:function(a){
2167// iterate from the specific view definition to a more general one until we hit an actual View class
2168for(var d,e,f,g,h=this.overrides.views||{},i=[],j=[],k=[],l=a;l;)d=Ua[l],e=h[l],l=null,"function"==typeof d&&(d={"class":d}),d&&(i.unshift(d),j.unshift(d.defaults||{}),f=f||d.duration,l=l||d.type),e&&(k.unshift(e),f=f||e.duration,l=l||e.type);// valid?
2169// view is a single-unit duration, like "week" or "day"
2170// incorporate options for this. lowest priority
2171return d=U(i),d.type=a,d["class"]?(f&&(f=b.duration(f),f.valueOf()&&(d.duration=f,g=M(f),1===f.as(g)&&(d.singleUnit=g,k.unshift(h[g]||{})))),d.defaults=c(j),d.overrides=c(k),this.buildViewSpecOptions(d),this.buildViewSpecButtonText(d,a),d):!1},
2172// Builds and assigns a view spec's options object from its already-assigned defaults and overrides
2173buildViewSpecOptions:function(a){a.options=c([// lowest to highest priority
2174vb.defaults,// global defaults
2175a.defaults,// view's defaults (from ViewSubclass.defaults)
2176this.dirDefaults,this.langDefaults,// locale and dir take precedence over view's defaults!
2177this.overrides,// calendar's overrides (options given to constructor)
2178a.overrides]),Oa(a.options)},
2179// Computes and assigns a view spec's buttonText-related options
2180buildViewSpecButtonText:function(a,b){
2181// given an options object with a possible `buttonText` hash, lookup the buttonText for the
2182// requested view, falling back to a generic unit entry like "week" or "day"
2183function c(c){var d=c.buttonText||{};return d[b]||(a.singleUnit?d[a.singleUnit]:null)}
2184// highest to lowest priority
2185a.buttonTextOverride=c(this.overrides)||// constructor-specified buttonText lookup hash takes precedence
2186a.overrides.buttonText,// `buttonText` for view-specific options is a string
2187// highest to lowest priority. mirrors buildViewSpecOptions
2188a.buttonTextDefault=c(this.langDefaults)||c(this.dirDefaults)||a.defaults.buttonText||// a single str
2188ing. from ViewSubclass.defaults
2189c(vb.defaults)||(a.duration?this.humanizeDuration(a.duration):null)||// like "3 days"
2190b},
2191// Given a view name for a custom view or a standard view, creates a ready-to-go View object
2192instantiateView:function(a){var b=this.getViewSpec(a);return new b["class"](this,a,b.options,b.duration)},
2193// Returns a boolean about whether the view is okay to instantiate at some point
2194isValidViewType:function(a){return Boolean(this.getViewSpec(a))},
2195// Should be called when any type of async data fetching begins
2196pushLoading:function(){this.loadingLevel++||this.trigger("loading",null,!0,this.view)},
2197// Should be called when any type of async data fetching completes
2198popLoading:function(){--this.loadingLevel||this.trigger("loading",null,!1,this.view)},
2199// Given arguments to the select method in the API, returns a span (unzoned start/end and other info)
2200buildSelectSpan:function(a,b){var c,d=this.moment(a).stripZone();return c=b?this.moment(b).stripZone():d.hasTime()?d.clone().add(this.defaultTimedEventDuration):d.clone().add(this.defaultAllDayEventDuration),{start:d,end:c}}});vb.mixin(ib),vb.defaults={titleRangeSeparator:" — ",// emphasized dash
2201monthYearFormat:"MMMM YYYY",// required for en. other languages rely on datepicker computable option
2202defaultTimedEventDuration:"02:00:00",defaultAllDayEventDuration:{days:1},forceEventDuration:!1,nextDayThreshold:"09:00:00",// 9am
2203// display
2204defaultView:"month",aspectRatio:1.35,header:{left:"title",center:"",right:"today prev,next"},weekends:!0,weekNumbers:!1,weekNumberTitle:"W",weekNumberCalculation:"local",
2205//editable: false,
2206//nowIndicator: false,
2207scrollTime:"06:00:00",
2208// event ajax
2209lazyFetching:!0,startParam:"start",endParam:"end",timezoneParam:"timezone",timezone:!1,
2210//allDayDefault: undefined,
2211// locale
2212isRTL:!1,buttonText:{prev:"prev",next:"next",prevYear:"prev year",nextYear:"next year",year:"year",// TODO: locale files need to specify this
2213today:"today",month:"month",week:"week",day:"day"},buttonIcons:{prev:"left-single-arrow",next:"right-single-arrow",prevYear:"left-double-arrow",nextYear:"right-double-arrow"},
2214// jquery-ui theming
2215theme:!1,themeButtonIcons:{prev:"circle-triangle-w",next:"circle-triangle-e",prevYear:"seek-prev",nextYear:"seek-next"},
2216//eventResizableFromStart: false,
2217dragOpacity:.75,dragRevertDuration:500,dragScroll:!0,
2218//selectable: false,
2219unselectAuto:!0,dropAccept:"*",eventOrder:"title",eventLimit:!1,eventLimitText:"more",eventLimitClick:"popover",dayPopoverFormat:"LL",handleWindowResize:!0,windowResizeDelay:200,// milliseconds before an updateSize happens
2220longPressDelay:1e3},vb.englishDefaults={// used by lang.js
2221dayPopoverFormat:"dddd, MMMM D"},vb.rtlDefaults={// right-to-left defaults
2222header:{// TODO: smarter solution (first/center/last ?)
2223left:"next,prev today",center:"",right:"title"},buttonIcons:{prev:"right-single-arrow",next:"left-single-arrow",prevYear:"right-double-arrow",nextYear:"left-double-arrow"},themeButtonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w",nextYear:"seek-prev",prevYear:"seek-next"}};var wb=Ta.langs={};// initialize and expose
2224// TODO: document the structure and ordering of a FullCalendar lang file
2225// TODO: rename everything "lang" to "locale", like what the moment project did
2226// Initialize jQuery UI datepicker translations while using some of the translations
2227// Will set this as the default language for datepicker.
2228Ta.datepickerLang=function(b,c,d){
2229// get the FullCalendar internal option hash for this language. create if necessary
2230var e=wb[b]||(wb[b]={});
2231// transfer some simple options from datepicker to fc
2232e.isRTL=d.isRTL,e.weekNumberTitle=d.weekHeader,
2233// compute some more complex options from datepicker
2234a.each(xb,function(a,b){e[a]=b(d)}),
2235// is jQuery UI Datepicker is on the page?
2236a.datepicker&&(
2237// Register the language data.
2238// FullCalendar and MomentJS use language codes like "pt-br" but Datepicker
2239// does it like "pt-BR" or if it doesn't have the language, maybe just "pt".
2240// Make an alias so the language can be referenced either way.
2241a.datepicker.regional[c]=a.datepicker.regional[b]=// alias
2242d,
2243// Alias 'en' to the default language data. Do this every time.
2244a.datepicker.regional.en=a.datepicker.regional[""],
2245// Set as Datepicker's global defaults.
2246a.datepicker.setDefaults(d))},
2247// Sets FullCalendar-specific translations. Will set the language as the global default.
2248Ta.lang=function(b,d){var e,f;e=wb[b]||(wb[b]={}),d&&(e=wb[b]=c([e,d])),f=Pa(b),a.each(yb,function(a,b){null==e[a]&&(e[a]=b(f,e))}),vb.defaults.lang=b};
2249// NOTE: can't guarantee any of these computations will run because not every language has datepicker
2250// configs, so make sure there are English fallbacks for these in the defaults file.
2251var xb={buttonText:function(a){return{
2252// the translations sometimes wrongly contain HTML entities
2253prev:ba(a.prevText),next:ba(a.nextText),today:ba(a.currentText)}},
2254// Produces format strings like "MMMM YYYY" -> "September 2014"
2255monthYearFormat:function(a){return a.showMonthAfterYear?"YYYY["+a.yearSuffix+"] MMMM":"MMMM YYYY["+a.yearSuffix+"]"}},yb={
2256// Produces format strings like "ddd M/D" -> "Fri 9/15"
2257dayOfMonthFormat:function(a,b){var c=a.longDateFormat("l");// for the format like "M/D/YYYY"
2258// strip the year off the edge, as well as other misc non-whitespace chars
2259return c=c.replace(/^Y+[^\w\s]*|[^\w\s]*Y+$/g,""),b.isRTL?c+=" ddd":c="ddd "+c,c},
2260// Produces format strings like "h:mma" -> "6:00pm"
2261mediumTimeFormat:function(a){// can't be called `timeFormat` because collides with option
2262return a.longDateFormat("LT").replace(/\s*a$/i,"a")},
2263// Produces format strings like "h(:mm)a" -> "6pm" / "6:30pm"
2264smallTimeFormat:function(a){return a.longDateFormat("LT").replace(":mm","(:mm)").replace(/(\Wmm)$/,"($1)").replace(/\s*a$/i,"a")},
2265// Produces format strings like "h(:mm)t" -> "6p" / "6:30p"
2266extraSmallTimeFormat:function(a){return a.longDateFormat("LT").replace(":mm","(:mm)").replace(/(\Wmm)$/,"($1)").replace(/\s*a$/i,"t")},
2267// Produces format strings like "ha" / "H" -> "6pm" / "18"
2268hourFormat:function(a){return a.longDateFormat("LT").replace(":mm","").replace(/(\Wmm)$/,"").replace(/\s*a$/i,"a")},
2269// Produces format strings like "h:mm" -> "6:30" (with no AM/PM)
2270noMeridiemTimeFormat:function(a){return a.longDateFormat("LT").replace(/\s*a$/i,"")}},zb={
2271// Produces format strings for results like "Mo 16"
2272smallDayDateFormat:function(a){return a.isRTL?"D dd":"dd D"},
2273// Produces format strings for results like "Wk 5"
2274weekFormat:function(a){return a.isRTL?"w[ "+a.weekNumberTitle+"]":"["+a.weekNumberTitle+" ]w"},
2275// Produces format strings for results like "Wk5"
2276smallWeekFormat:function(a){return a.isRTL?"w["+a.weekNumberTitle+"]":"["+a.weekNumberTitle+"]w"}};
2277// Initialize English by forcing computation of moment-derived options.
2278// Also, sets it as the default.
2279Ta.lang("en",vb.englishDefaults),Ta.sourceNormalizers=[],Ta.sourceFetchers=[];var Ab={dataType:"json",cache:!1},Bb=1;
2280// Returns a list of events that the given event should be compared against when being considered for a move to
2281// the specified span. Attached to the Calendar's prototype because EventManager is a mixin for a Calendar.
2282vb.prototype.getPeerEvents=function(a,b){var c,d,e=this.getEventCache(),f=[];for(c=0;c<e.length;c++)d=e[c],b&&b._id===d._id||f.push(d);return f};/* An abstract class for the "basic" views, as well as month view. Renders one or more rows of day cells.
2283----------------------------------------------------------------------------------------------------------------------*/
2284// It is a manager for a DayGrid subcomponent, which does most of the heavy lifting.
2285// It is responsible for managing width/height.
2286var Cb=Ta.BasicView=tb.extend({scroller:null,dayGridClass:rb,// class the dayGrid will be instantiated from (overridable by subclasses)
2287dayGrid:null,// the main subcomponent that does most of the heavy lifting
2288dayNumbersVisible:!1,// display day numbers on each day cell?
2289weekNumbersVisible:!1,// display week numbers along the side?
2290weekNumberWidth:null,// width of all the week-number cells running down the side
2291headContainerEl:null,// div that hold's the dayGrid's rendered date header
2292headRowEl:null,// the fake row element of the day-of-week header
2293initialize:function(){this.dayGrid=this.instantiateDayGrid(),this.scroller=new ub({overflowX:"hidden",overflowY:"auto"})},
2294// Generates the DayGrid object this view needs. Draws from this.dayGridClass
2295instantiateDayGrid:function(){
2296// generate a subclass on the fly with BasicView-specific behavior
2297// TODO: cache this subclass
2298var a=this.dayGridClass.extend(Db);return new a(this)},
2299// Sets the display range and computes all necessary dates
2300setRange:function(a){tb.prototype.setRange.call(this,a),// call the super-method
2301this.dayGrid.breakOnWeeks=/year|month|week/.test(this.intervalUnit),// do before setRange
2302this.dayGrid.setRange(a)},
2303// Compute the value to feed into setRange. Overrides superclass.
2304computeRange:function(a){var b=tb.prototype.computeRange.call(this,a);// get value from the super-method
2305// year and month views should be aligned with weeks. this is already done for week
2306// make end-of-week if not already
2307return/year|month/.test(b.intervalUnit)&&(b.start.startOf("week"),b.start=this.skipHiddenDays(b.start),b.end.weekday()&&(b.end.add(1,"week").startOf("week"),b.end=this.skipHiddenDays(b.end,-1,!0))),b},
2308// Renders the view into `this.el`, which should already be assigned
2309renderDates:function(){this.dayNumbersVisible=this.dayGrid.rowCnt>1,// TODO: make grid responsible
2310this.weekNumbersVisible=this.opt("weekNumbers"),this.dayGrid.numbersVisible=this.dayNumbersVisible||this.weekNumbersVisible,this.el.addClass("fc-basic-view").html(this.renderSkeletonHtml()),this.renderHead(),this.scroller.render();var b=this.scroller.el.addClass("fc-day-grid-container"),c=a('<div class="fc-day-grid" />').appendTo(b);this.el.find(".fc-body > tr > td").append(b),this.dayGrid.setElement(c),this.dayGrid.renderDates(this.hasRigidRows())},
2311// render the day-of-week headers
2312renderHead:function(){this.headContainerEl=this.el.find(".fc-head-container").html(this.dayGrid.renderHeadHtml()),this.headRowEl=this.headContainerEl.find(".fc-row")},
2313// Unrenders the content of the view. Since we haven't separated skeleton rendering from date rendering,
2314// always completely kill the dayGrid's rendering.
2315unrenderDates:function(){this.dayGrid.unrenderDates(),this.dayGrid.removeElement(),this.scroller.destroy()},renderBusinessHours:function(){this.dayGrid.renderBusinessHours()},
2316// Builds the HTML skeleton for the view.
2317// The day-grid component will render inside of a container defined by this HTML.
2318renderSkeletonHtml:function(){return'<table><thead class="fc-head"><tr><td class="fc-head-container '+this.widgetHeaderClass+'"></td></tr></thead><tbody class="fc-body"><tr><td class="'+this.widgetContentClass+'"></td></tr></tbody></table>'},
2319// Generates an HTML attribute string for setting the width of the week number column, if it is known
2320weekNumberStyleAttr:function(){return null!==this.weekNumberWidth?'style="width:'+this.weekNumberWidth+'px"':""},
2321// Determines whether each row should have a constant height
2322hasRigidRows:function(){var a=this.opt("eventLimit");return a&&"number"!=typeof a},/* Dimensions
2323	------------------------------------------------------------------------------------------------------------------*/
2324// Refreshes the horizontal dimensions of the view
2325updateWidth:function(){this.weekNumbersVisible&&(
2326// Make sure all week number cells running down the side have the same width.
2327// Record the width for cells created later.
2328this.weekNumberWidth=k(this.el.find(".fc-week-number")))},
2329// Adjusts the vertical dimensions of the view to the specified values
2330setHeight:function(a,b){var c,d,g=this.opt("eventLimit");
2331// reset all heights to be natural
2332this.scroller.clear(),f(this.headRowEl),this.dayGrid.removeSegPopover(),// kill the "more" popover if displayed
2333// is the event limit a constant level number?
2334g&&"number"==typeof g&&this.dayGrid.limitRows(g),c=this.computeScrollerHeight(a),this.setGridHeight(c,b),g&&"number"!=typeof g&&this.dayGrid.limitRows(g),b||(this.scroller.setHeight(c),d=this.scroller.getScrollbarWidths(),(d.left||d.right)&&(e(this.headRowEl,d),c=this.computeScrollerHeight(a),this.scroller.setHeight(c)),this.scroller.lockOverflow(d))},
2335// given a desired total height of the view, returns what the height of the scroller should be
2336computeScrollerHeight:function(a){return a-l(this.el,this.scroller.el)},
2337// Sets the height of just the DayGrid component in this view
2338setGridHeight:function(a,b){b?j(this.dayGrid.rowEls):i(this.dayGrid.rowEls,a,!0)},/* Scroll
2339	------------------------------------------------------------------------------------------------------------------*/
2340queryScroll:function(){return this.scroller.getScrollTop()},setScroll:function(a){this.scroller.setScrollTop(a)},/* Hit Areas
2341	------------------------------------------------------------------------------------------------------------------*/
2342// forward all hit-related method calls to dayGrid
2343prepareHits:function(){this.dayGrid.prepareHits()},releaseHits:function(){this.dayGrid.releaseHits()},queryHit:function(a,b){return this.dayGrid.queryHit(a,b)},getHitSpan:function(a){return this.dayGrid.getHitSpan(a)},getHitEl:function(a){return this.dayGrid.getHitEl(a)},/* Events
2344	------------------------------------------------------------------------------------------------------------------*/
2345// Renders the given events onto the view and populates the segments array
2346renderEvents:function(a){this.dayGrid.renderEvents(a),this.updateHeight()},
2347// Retrieves all segment objects that are rendered in the view
2348getEventSegs:function(){return this.dayGrid.getEventSegs()},
2349// Unrenders all event elements and clears internal segment data
2350unrenderEvents:function(){this.dayGrid.unrenderEvents()},/* Dragging (for both events and external elements)
2351	------------------------------------------------------------------------------------------------------------------*/
2352// A returned value of `true` signals that a mock "helper" event has been rendered.
2353renderDrag:function(a,b){return this.dayGrid.renderDrag(a,b)},unrenderDrag:function(){this.dayGrid.unrenderDrag()},/* Selection
2354	------------------------------------------------------------------------------------------------------------------*/
2355// Renders a visual indication of a selection
2356renderSelection:function(a){this.dayGrid.renderSelection(a)},
2357// Unrenders a visual indications of a selection
2358unrenderSelection:function(){this.dayGrid.unrenderSelection()}}),Db={
2359// Generates the HTML that will go before the day-of week header cells
2360renderHeadIntroHtml:function(){var a=this.view;// needed for matchCellWidths
2361return a.weekNumbersVisible?'<th class="fc-week-number '+a.widgetHeaderClass+'" '+a.weekNumberStyleAttr()+"><span>"+aa(a.opt("weekNumberTitle"))+"</span></th>":""},
2362// Generates the HTML that will go before content-skeleton cells that display the day/week numbers
2363renderNumberIntroHtml:function(a){var b=this.view;// needed for matchCellWidths
2364return b.weekNumbersVisible?'<td class="fc-week-number" '+b.weekNumberStyleAttr()+"><span>"+this.getCellDate(a,0).format("w")+"</span></td>":""},
2365// Generates the HTML that goes before the day bg cells for each day-row
2366renderBgIntroHtml:function(){var a=this.view;return a.weekNumbersVisible?'<td class="fc-week-number '+a.widgetContentClass+'" '+a.weekNumberStyleAttr()+"></td>":""},
2367// Generates the HTML that goes before every other type of row generated by DayGrid.
2368// Affects helper-skeleton and highlight-skeleton rows.
2369renderIntroHtml:function(){var a=this.view;return a.weekNumbersVisible?'<td class="fc-week-number" '+a.weekNumberStyleAttr()+"></td>":""}},Eb=Ta.MonthView=Cb.extend({
2370// Produces information about what range to display
2371computeRange:function(a){var b,c=Cb.prototype.computeRange.call(this,a);
2372// ensure 6 weeks
2373// could be partial weeks due to hiddenDays
2374return this.isFixedWeeks()&&(b=Math.ceil(c.end.diff(c.start,"weeks",!0)),c.end.add(6-b,"weeks")),c},
2375// Overrides the default BasicView behavior to have special multi-week auto-height logic
2376setGridHeight:function(a,b){b=b||"variable"===this.opt("weekMode"),b&&(a*=this.rowCnt/6),i(this.dayGrid.rowEls,a,!b)},isFixedWeeks:function(){var a=this.opt("weekMode");// LEGACY: weekMode is deprecated
2377// LEGACY: weekMode is deprecated
2378return a?"fixed"===a:this.opt("fixedWeekCount")}});Ua.basic={"class":Cb},Ua.basicDay={type:"basic",duration:{days:1}},Ua.basicWeek={type:"basic",duration:{weeks:1}},Ua.month={"class":Eb,duration:{months:1},// important for prev/next
2379defaults:{fixedWeekCount:!0}};/* An abstract class for all agenda-related views. Displays one more columns with time slots running vertically.
2380----------------------------------------------------------------------------------------------------------------------*/
2381// Is a manager for the TimeGrid subcomponent and possibly the DayGrid subcomponent (if allDaySlot is on).
2382// Responsible for managing width/height.
2383var Fb=Ta.AgendaView=tb.extend({scroller:null,timeGridClass:sb,// class used to instantiate the timeGrid. subclasses can override
2384timeGrid:null,// the main time-grid subcomponent of this view
2385dayGridClass:rb,// class used to instantiate the dayGrid. subclasses can override
2386dayGrid:null,// the "all-day" subcomponent. if all-day is turned off, this will be null
2387axisWidth:null,// the width of the time axis running down the side
2388headContainerEl:null,// div that hold's the timeGrid's rendered date header
2389noScrollRowEls:null,// set of fake row elements that must compensate when scroller has scrollbars
2390// when the time-grid isn't tall enough to occupy the given height, we render an <hr> underneath
2391bottomRuleEl:null,initialize:function(){this.timeGrid=this.instantiateTimeGrid(),this.opt("allDaySlot")&&(// should we display the "all-day" area?
2392this.dayGrid=this.instantiateDayGrid()),this.scroller=new ub({overflowX:"hidden",overflowY:"auto"})},
2393// Instantiates the TimeGrid object this view needs. Draws from this.timeGridClass
2394instantiateTimeGrid:function(){var a=this.timeGridClass.extend(Gb);return new a(this)},
2395// Instantiates the DayGrid object this view might need. Draws from this.dayGridClass
2396instantiateDayGrid:function(){var a=this.dayGridClass.extend(Hb);return new a(this)},/* Rendering
2397	------------------------------------------------------------------------------------------------------------------*/
2398// Sets the display range and computes all necessary dates
2399setRange:function(a){tb.prototype.setRange.call(this,a),// call the super-method
2400this.timeGrid.setRange(a),this.dayGrid&&this.dayGrid.setRange(a)},
2401// Renders the view into `this.el`, which has already been assigned
2402renderDates:function(){this.el.addClass("fc-agenda-view").html(this.renderSkeletonHtml()),this.renderHead(),this.scroller.render();var b=this.scroller.el.addClass("fc-time-grid-container"),c=a('<div class="fc-time-grid" />').appendTo(b);this.el.find(".fc-body > tr > td").append(b),this.timeGrid.setElement(c),this.timeGrid.renderDates(),
2403// the <hr> that sometimes displays under the time-grid
2404this.bottomRuleEl=a('<hr class="fc-divider '+this.widgetHeaderClass+'"/>').appendTo(this.timeGrid.el),// inject it into the time-grid
2405this.dayGrid&&(this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.renderDates(),
2406// have the day-grid extend it's coordinate area over the <hr> dividing the two grids
2407this.dayGrid.bottomCoordPadding=this.dayGrid.el.next("hr").outerHeight()),this.noScrollRowEls=this.el.find(".fc-row:not(.fc-scroller *)")},
2408// render the day-of-week headers
2409renderHead:function(){this.headContainerEl=this.el.find(".fc-head-container").html(this.timeGrid.renderHeadHtml())},
2410// Unrenders the content of the view. Since we haven't separated skeleton rendering from date rendering,
2411// always completely kill each grid's rendering.
2412unrenderDates:function(){this.timeGrid.unrenderDates(),this.timeGrid.removeElement(),this.dayGrid&&(this.dayGrid.unrenderDates(),this.dayGrid.removeElement()),this.scroller.destroy()},
2413// Builds the HTML skeleton for the view.
2414// The day-grid and time-grid components will render inside containers defined by this HTML.
2415renderSkeletonHtml:function(){return'<table><thead class="fc-head"><tr><td class="fc-head-container '+this.widgetHeaderClass+'"></td></tr></thead><tbody class="fc-body"><tr><td class="'+this.widgetContentClass+'">'+(this.dayGrid?'<div class="fc-day-grid"/><hr class="fc-divider '+this.widgetHeaderClass+'"/>':"")+"</td></tr></tbody></table>"},
2416// Generates an HTML attribute string for setting the width of the axis, if it is known
2417axisStyleAttr:function(){return null!==this.axisWidth?'style="width:'+this.axisWidth+'px"':""},/* Business Hours
2418	------------------------------------------------------------------------------------------------------------------*/
2419renderBusinessHours:function(){this.timeGrid.renderBusinessHours(),this.dayGrid&&this.dayGrid.renderBusinessHours()},unrenderBusinessHours:function(){this.timeGrid.unrenderBusinessHours(),this.dayGrid&&this.dayGrid.unrenderBusinessHours()},/* Now Indicator
2420	------------------------------------------------------------------------------------------------------------------*/
2421getNowIndicatorUnit:function(){return this.timeGrid.getNowIndicatorUnit()},renderNowIndicator:function(a){this.timeGrid.renderNowIndicator(a)},unrenderNowIndicator:function(){this.timeGrid.unrenderNowIndicator()},/* Dimensions
2422	------------------------------------------------------------------------------------------------------------------*/
2423updateSize:function(a){this.timeGrid.updateSize(a),tb.prototype.updateSize.call(this,a)},
2424// Refreshes the horizontal dimensions of the view
2425updateWidth:function(){
2426// make all axis cells line up, and record the width so newly created axis cells will have it
2427this.axisWidth=k(this.el.find(".fc-axis"))},
2428// Adjusts the vertical dimensions of the view to the specified values
2429setHeight:function(a,b){var c,d,g;
2430// reset all dimensions back to the original state
2431this.bottomRuleEl.hide(),// .show() will be called later if this <hr> is necessary
2432this.scroller.clear(),// sets height to 'auto' and clears overflow
2433f(this.noScrollRowEls),
2434// limit number of events in the all-day area
2435this.dayGrid&&(this.dayGrid.removeSegPopover(),c=this.opt("eventLimit"),c&&"number"!=typeof c&&(c=Ib),c&&this.dayGrid.limitRows(c)),b||(d=this.computeScrollerHeight(a),this.scroller.setHeight(d),g=this.scroller.getScrollbarWidths(),(g.left||g.right)&&(e(this.noScrollRowEls,g),d=this.computeScrollerHeight(a),this.scroller.setHeight(d)),this.scroller.lockOverflow(g),this.timeGrid.getTotalSlatHeight()<d&&this.bottomRuleEl.show())},
2436// given a desired total height of the view, returns what the height of the scroller should be
2437computeScrollerHeight:function(a){return a-l(this.el,this.scroller.el)},/* Scroll
2438	------------------------------------------------------------------------------------------------------------------*/
2439// Computes the initial pre-configured scroll state prior to allowing the user to change it
2440computeInitialScroll:function(){var a=b.duration(this.opt("scrollTime")),c=this.timeGrid.computeTimeTop(a);
2441// zoom can give weird floating-point values. rather scroll a little bit further
2442return c=Math.ceil(c),c&&c++,c},queryScroll:function(){return this.scroller.getScrollTop()},setScroll:function(a){this.scroller.setScrollTop(a)},/* Hit Areas
2443	------------------------------------------------------------------------------------------------------------------*/
2444// forward all hit-related method calls to the grids (dayGrid might not be defined)
2445prepareHits:function(){this.timeGrid.prepareHits(),this.dayGrid&&this.dayGrid.prepareHits()},releaseHits:function(){this.timeGrid.releaseHits(),this.dayGrid&&this.dayGrid.releaseHits()},queryHit:function(a,b){var c=this.timeGrid.queryHit(a,b);return!c&&this.dayGrid&&(c=this.dayGrid.queryHit(a,b)),c},getHitSpan:function(a){
2446// TODO: hit.component is set as a hack to identify where the hit came from
2447return a.component.getHitSpan(a)},getHitEl:function(a){
2448// TODO: hit.component is set as a hack to identify where the hit came from
2449return a.component.getHitEl(a)},/* Events
2450	------------------------------------------------------------------------------------------------------------------*/
2451// Renders events onto the view and populates the View's segment array
2452renderEvents:function(a){var b,c,d=[],e=[],f=[];
2453// separate the events into all-day and timed
2454for(c=0;c<a.length;c++)a[c].allDay?d.push(a[c]):e.push(a[c]);b=this.timeGrid.renderEvents(e),this.dayGrid&&(f=this.dayGrid.renderEvents(d)),this.updateHeight()},
2455// Retrieves all segment objects that are rendered in the view
2456getEventSegs:function(){return this.timeGrid.getEventSegs().concat(this.dayGrid?this.dayGrid.getEventSegs():[])},
2457// Unrenders all event elements and clears internal segment data
2458unrenderEvents:function(){
2459// unrender the events in the subcomponents
2460this.timeGrid.unrenderEvents(),this.dayGrid&&this.dayGrid.unrenderEvents()},/* Dragging (for events and external elements)
2461	------------------------------------------------------------------------------------------------------------------*/
2462// A returned value of `true` signals that a mock "helper" event has been rendered.
2463renderDrag:function(a,b){return a.start.hasTime()?this.timeGrid.renderDrag(a,b):this.dayGrid?this.dayGrid.renderDrag(a,b):void 0},unrenderDrag:function(){this.timeGrid.unrenderDrag(),this.dayGrid&&this.dayGrid.unrenderDrag()},/* Selection
2464	------------------------------------------------------------------------------------------------------------------*/
2465// Renders a visual indication of a selection
2466renderSelection:function(a){a.start.hasTime()||a.end.hasTime()?this.timeGrid.renderSelection(a):this.dayGrid&&this.dayGrid.renderSelection(a)},
2467// Unrenders a visual indications of a selection
2468unrenderSelection:function(){this.timeGrid.unrenderSelection(),this.dayGrid&&this.dayGrid.unrenderSelection()}}),Gb={
2469// Generates the HTML that will go before the day-of week header cells
2470renderHeadIntroHtml:function(){var a,b=this.view;// needed for matchCellWidths
2471return b.opt("weekNumbers")?(a=this.start.format(b.opt("smallWeekFormat")),'<th class="fc-axis fc-week-number '+b.widgetHeaderClass+'" '+b.axisStyleAttr()+"><span>"+aa(a)+"</span></th>"):'<th class="fc-axis '+b.widgetHeaderClass+'" '+b.axisStyleAttr()+"></th>"},
2472// Generates the HTML that goes before the bg of the TimeGrid slot area. Long vertical column.
2473renderBgIntroHtml:function(){var a=this.view;return'<td class="fc-axis '+a.widgetContentClass+'" '+a.axisStyleAttr()+"></td>"},
2474// Generates the HTML that goes before all other types of cells.
2475// Affects content-skeleton, helper-skeleton, highlight-skeleton for both the time-grid and day-grid.
2476renderIntroHtml:function(){var a=this.view;return'<td class="fc-axis" '+a.axisStyleAttr()+"></td>"}},Hb={
2477// Generates the HTML that goes before the all-day cells
2478renderBgIntroHtml:function(){var a=this.view;// needed for matchCellWidths
2479return'<td class="fc-axis '+a.widgetContentClass+'" '+a.axisStyleAttr()+"><span>"+(a.opt("allDayHtml")||aa(a.opt("allDayText")))+"</span></td>"},
2480// Generates the HTML that goes before all other types of cells.
2481// Affects content-skeleton, helper-skeleton, highlight-skeleton for both the time-grid and day-grid.
2482renderIntroHtml:function(){var a=this.view;return'<td class="fc-axis" '+a.axisStyleAttr()+"></td>"}},Ib=5,Jb=[{hours:1},{minutes:30},{minutes:15},{seconds:30},{seconds:15}];return Ua.agenda={"class":Fb,defaults:{allDaySlot:!0,allDayText:"all-day",slotDuration:"00:30:00",minTime:"00:00:00",maxTime:"24:00:00",slotEventOverlap:!0}},Ua.agendaDay={type:"agenda",duration:{days:1}},Ua.agendaWeek={type:"agenda",duration:{weeks:1}},Ta});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.