diff --git a/library/fullcalendar/CHANGELOG.txt b/library/fullcalendar/CHANGELOG.txt
index e91ce3bd6..ed2eddb8a 100644
--- a/library/fullcalendar/CHANGELOG.txt
+++ b/library/fullcalendar/CHANGELOG.txt
@@ -1,4 +1,27 @@
+v3.1.0 (2016-12-05)
+-------------------
+
+- experimental support for implicitly batched ("debounced") event rendering (#2938)
+ - `eventRenderWait` (off by default)
+- new `footer` option, similar to header toolbar (#654, #3299)
+- event rendering batch methods (#3351):
+ - `renderEvents`
+ - `updateEvents`
+- more granular touch settings (#3377):
+ - `eventLongPressDelay`
+ - `selectLongPressDelay`
+- eventDestroy not called when removing the popover (#3416, #3419)
+- print stylesheet and gcal extension now offered as minified (#3415)
+- fc-today in agenda header cells (#3361, #3365)
+- height-related options in tandem with other options (#3327, #3384)
+- Kazakh locale (#3394)
+- Afrikaans locale (#3390)
+- internal refactor related to timing of rendering and firing handlers.
+ calls to rerender the current date-range and events from within handlers
+ might not execute immediately. instead, will execute after handler finishes.
+
+
v3.0.1 (2016-09-26)
-------------------
diff --git a/library/fullcalendar/fullcalendar.css b/library/fullcalendar/fullcalendar.css
index 7a3f39923..5620e0bd6 100644
--- a/library/fullcalendar/fullcalendar.css
+++ b/library/fullcalendar/fullcalendar.css
@@ -1,5 +1,5 @@
/*!
- * FullCalendar v3.0.1 Stylesheet
+ * FullCalendar v3.1.0 Stylesheet
* Docs & License: http://fullcalendar.io/
* (c) 2016 Adam Shaw
*/
@@ -49,7 +49,7 @@ body .fc { /* extra precedence to overcome jqui */
color: #666;
}
-.fc-unthemed .fc-today {
+.fc-unthemed td.fc-today {
background: #fcf8e3;
}
@@ -811,9 +811,16 @@ a.fc-more:hover {
.fc-toolbar {
text-align: center;
+}
+
+.fc-toolbar.fc-header-toolbar {
margin-bottom: 1em;
}
+.fc-toolbar.fc-footer-toolbar {
+ margin-top: 1em;
+}
+
.fc-toolbar .fc-left {
float: left;
}
diff --git a/library/fullcalendar/fullcalendar.js b/library/fullcalendar/fullcalendar.js
index 3c2c380bc..b7371e25f 100644
--- a/library/fullcalendar/fullcalendar.js
+++ b/library/fullcalendar/fullcalendar.js
@@ -1,5 +1,5 @@
/*!
- * FullCalendar v3.0.1
+ * FullCalendar v3.1.0
* Docs & License: http://fullcalendar.io/
* (c) 2016 Adam Shaw
*/
@@ -19,8 +19,8 @@
;;
var FC = $.fullCalendar = {
- version: "3.0.1",
- internalApiVersion: 6
+ version: "3.1.0",
+ internalApiVersion: 7
};
var fcViews = FC.views = {};
@@ -53,13 +53,14 @@ $.fn.fullCalendar = function(options) {
calendar.render();
}
});
-
+
return res;
};
var complexOptions = [ // names of options that are objects whose properties should be combined
'header',
+ 'footer',
'buttonText',
'buttonIcons',
'themeButtonIcons'
@@ -848,6 +849,7 @@ function createObject(proto) {
f.prototype = proto;
return new f();
}
+FC.createObject = createObject;
function copyOwnProps(src, dest) {
@@ -1004,20 +1006,6 @@ function debounce(func, wait, immediate) {
};
}
-
-// HACK around jQuery's now A+ promises: execute callback synchronously if already resolved.
-// thenFunc shouldn't accept args.
-// similar to whenResources in Scheduler plugin.
-function syncThen(promise, thenFunc) {
- // not a promise, or an already-resolved promise?
- if (!promise || !promise.then || promise.state() === 'resolved') {
- return $.when(thenFunc()); // resolve immediately
- }
- else if (thenFunc) {
- return promise.then(thenFunc);
- }
-}
-
;;
/*
@@ -1681,6 +1669,201 @@ function mixIntoClass(theClass, members) {
}
;;
+/*
+Wrap jQuery's Deferred Promise object to be slightly more Promise/A+ compliant.
+With the added non-standard feature of synchronously executing handlers on resolved promises,
+which doesn't always happen otherwise (esp with nested .then handlers!?),
+so, this makes things a lot easier, esp because jQuery 3 changed the synchronicity for Deferred objects.
+
+TODO: write tests and more comments
+*/
+
+function Promise(executor) {
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+
+ if (typeof executor === 'function') {
+ executor(
+ function(value) { // resolve
+ if (Promise.immediate) {
+ promise._value = value;
+ }
+ deferred.resolve(value);
+ },
+ function() { // reject
+ deferred.reject();
+ }
+ );
+ }
+
+ if (Promise.immediate) {
+ var origThen = promise.then;
+
+ promise.then = function(onFulfilled, onRejected) {
+ var state = promise.state();
+
+ if (state === 'resolved') {
+ if (typeof onFulfilled === 'function') {
+ return Promise.resolve(onFulfilled(promise._value));
+ }
+ }
+ else if (state === 'rejected') {
+ if (typeof onRejected === 'function') {
+ onRejected();
+ return promise; // already rejected
+ }
+ }
+
+ return origThen.call(promise, onFulfilled, onRejected);
+ };
+ }
+
+ return promise; // instanceof Promise will break :( TODO: make Promise a real class
+}
+
+FC.Promise = Promise;
+
+Promise.immediate = true;
+
+
+Promise.resolve = function(value) {
+ if (value && typeof value.resolve === 'function') {
+ return value.promise();
+ }
+ if (value && typeof value.then === 'function') {
+ return value;
+ }
+ else {
+ var deferred = $.Deferred().resolve(value);
+ var promise = deferred.promise();
+
+ if (Promise.immediate) {
+ var origThen = promise.then;
+
+ promise._value = value;
+
+ promise.then = function(onFulfilled, onRejected) {
+ if (typeof onFulfilled === 'function') {
+ return Promise.resolve(onFulfilled(value));
+ }
+ return origThen.call(promise, onFulfilled, onRejected);
+ };
+ }
+
+ return promise;
+ }
+};
+
+
+Promise.reject = function() {
+ return $.Deferred().reject().promise();
+};
+
+
+Promise.all = function(inputs) {
+ var hasAllValues = false;
+ var values;
+ var i, input;
+
+ if (Promise.immediate) {
+ hasAllValues = true;
+ values = [];
+
+ for (i = 0; i < inputs.length; i++) {
+ input = inputs[i];
+
+ if (input && typeof input.state === 'function' && input.state() === 'resolved' && ('_value' in input)) {
+ values.push(input._value);
+ }
+ else if (input && typeof input.then === 'function') {
+ hasAllValues = false;
+ break;
+ }
+ else {
+ values.push(input);
+ }
+ }
+ }
+
+ if (hasAllValues) {
+ return Promise.resolve(values);
+ }
+ else {
+ return $.when.apply($.when, inputs).then(function() {
+ return $.when($.makeArray(arguments));
+ });
+ }
+};
+
+;;
+
+// TODO: write tests and clean up code
+
+function TaskQueue(debounceWait) {
+ var q = []; // array of runFuncs
+
+ function addTask(taskFunc) {
+ return new Promise(function(resolve) {
+
+ // should run this function when it's taskFunc's turn to run.
+ // responsible for popping itself off the queue.
+ var runFunc = function() {
+ Promise.resolve(taskFunc()) // result might be async, coerce to promise
+ .then(resolve) // resolve TaskQueue::push's promise, for the caller. will receive result of taskFunc.
+ .then(function() {
+ q.shift(); // pop itself off
+
+ // run the next task, if any
+ if (q.length) {
+ q[0]();
+ }
+ });
+ };
+
+ // always put the task at the end of the queue, BEFORE running the task
+ q.push(runFunc);
+
+ // if it's the only task in the queue, run immediately
+ if (q.length === 1) {
+ runFunc();
+ }
+ });
+ }
+
+ this.add = // potentially debounce, for the public method
+ typeof debounceWait === 'number' ?
+ debounce(addTask, debounceWait) :
+ addTask; // if not a number (null/undefined/false), no debounce at all
+
+ this.addQuickly = addTask; // guaranteed no debounce
+}
+
+FC.TaskQueue = TaskQueue;
+
+/*
+q = new TaskQueue();
+
+function work(i) {
+ return q.push(function() {
+ trigger();
+ console.log('work' + i);
+ });
+}
+
+var cnt = 0;
+
+function trigger() {
+ if (cnt < 5) {
+ cnt++;
+ work(cnt);
+ }
+}
+
+work(9);
+*/
+
+;;
+
var EmitterMixin = FC.EmitterMixin = {
// jQuery-ification via $(this) allows a non-DOM object to have
@@ -1688,7 +1871,18 @@ var EmitterMixin = FC.EmitterMixin = {
on: function(types, handler) {
+ $(this).on(types, this._prepareIntercept(handler));
+ return this; // for chaining
+ },
+
+ one: function(types, handler) {
+ $(this).one(types, this._prepareIntercept(handler));
+ return this; // for chaining
+ },
+
+
+ _prepareIntercept: function(handler) {
// handlers are always called with an "event" object as their first param.
// sneak the `this` context and arguments into the extra parameter object
// and forward them on to the original handler.
@@ -1708,9 +1902,7 @@ var EmitterMixin = FC.EmitterMixin = {
}
intercept.guid = handler.guid;
- $(this).on(types, intercept);
-
- return this; // for chaining
+ return intercept;
},
@@ -2039,9 +2231,15 @@ var CoordCache = FC.CoordCache = Class.extend({
// Queries the els for coordinates and stores them.
// Call this method before using and of the get* methods below.
build: function() {
- var offsetParentEl = this.forcedOffsetParentEl || this.els.eq(0).offsetParent();
+ var offsetParentEl = this.forcedOffsetParentEl;
+ if (!offsetParentEl && this.els.length > 0) {
+ offsetParentEl = this.els.eq(0).offsetParent();
+ }
+
+ this.origin = offsetParentEl ?
+ offsetParentEl.offset() :
+ null;
- this.origin = offsetParentEl.offset();
this.boundingRect = this.queryBoundingRect();
if (this.isHorizontal) {
@@ -2224,12 +2422,19 @@ var CoordCache = FC.CoordCache = Class.extend({
// Compute and return what the elements' bounding rectangle is, from the user's perspective.
// Right now, only returns a rectangle if constrained by an overflow:scroll element.
+ // Returns null if there are no elements
queryBoundingRect: function() {
- var scrollParentEl = getScrollParent(this.els.eq(0));
+ var scrollParentEl;
- if (!scrollParentEl.is(document)) {
- return getClientRect(scrollParentEl);
+ if (this.els.length > 0) {
+ scrollParentEl = getScrollParent(this.els.eq(0));
+
+ if (!scrollParentEl.is(document)) {
+ return getClientRect(scrollParentEl);
+ }
}
+
+ return null;
},
isPointInBounds: function(leftOffset, topOffset) {
@@ -3448,6 +3653,7 @@ var Grid = FC.Grid = Class.extend(ListenerMixin, MouseIgnorerMixin, {
dayTouchStart: function(ev) {
var view = this.view;
+ var selectLongPressDelay = view.opt('selectLongPressDelay');
// HACK to prevent a user's clickaway for unselecting a range or an event
// from causing a dayClick.
@@ -3455,8 +3661,12 @@ var Grid = FC.Grid = Class.extend(ListenerMixin, MouseIgnorerMixin, {
this.tempIgnoreMouse();
}
+ if (selectLongPressDelay == null) {
+ selectLongPressDelay = view.opt('longPressDelay'); // fallback
+ }
+
this.dayDragListener.startInteraction(ev, {
- delay: this.view.opt('longPressDelay')
+ delay: selectLongPressDelay
});
},
@@ -3793,7 +4003,7 @@ var Grid = FC.Grid = Class.extend(ListenerMixin, MouseIgnorerMixin, {
// Computes HTML classNames for a single-day element
- getDayClasses: function(date) {
+ getDayClasses: function(date, noThemeHighlight) {
var view = this.view;
var today = view.calendar.getNow();
var classes = [ 'fc-' + dayIDs[date.day()] ];
@@ -3806,10 +4016,11 @@ var Grid = FC.Grid = Class.extend(ListenerMixin, MouseIgnorerMixin, {
}
if (date.isSame(today, 'day')) {
- classes.push(
- 'fc-today',
- view.highlightStateClass
- );
+ classes.push('fc-today');
+
+ if (noThemeHighlight !== true) {
+ classes.push(view.highlightStateClass);
+ }
}
else if (date < today) {
classes.push('fc-past');
@@ -4005,16 +4216,33 @@ Grid.mixin({
// Compute business hour segs for the grid's current date range.
// Caller must ask if whole-day business hours are needed.
- buildBusinessHourSegs: function(wholeDay) {
- var events = this.view.calendar.getCurrentBusinessHourEvents(wholeDay);
+ // If no `businessHours` configuration value is specified, assumes the calendar default.
+ buildBusinessHourSegs: function(wholeDay, businessHours) {
+ return this.eventsToSegs(
+ this.buildBusinessHourEvents(wholeDay, businessHours)
+ );
+ },
+
+
+ // Compute business hour *events* for the grid's current date range.
+ // Caller must ask if whole-day business hours are needed.
+ // If no `businessHours` configuration value is specified, assumes the calendar default.
+ buildBusinessHourEvents: function(wholeDay, businessHours) {
+ var calendar = this.view.calendar;
+ var events;
+
+ if (businessHours == null) {
+ // fallback
+ // access from calendawr. don't access from view. doesn't update with dynamic options.
+ businessHours = calendar.options.businessHours;
+ }
+
+ events = calendar.computeBusinessHourEvents(wholeDay, businessHours);
// HACK. Eventually refactor business hours "events" system.
// If no events are given, but businessHours is activated, this means the entire visible range should be
// marked as *not* business-hours, via inverse-background rendering.
- if (
- !events.length &&
- this.view.calendar.options.businessHours // don't access view option. doesn't update with dynamic options
- ) {
+ if (!events.length && businessHours) {
events = [
$.extend({}, BUSINESS_HOUR_EVENT_DEFAULTS, {
start: this.view.end, // guaranteed out-of-range
@@ -4024,7 +4252,7 @@ Grid.mixin({
];
}
- return this.eventsToSegs(events);
+ return events;
},
@@ -4066,7 +4294,7 @@ Grid.mixin({
handleSegClick: function(seg, ev) {
- var res = this.view.trigger('eventClick', seg.el[0], seg.event, ev); // can return `false` to cancel
+ var res = this.view.publiclyTrigger('eventClick', seg.el[0], seg.event, ev); // can return `false` to cancel
if (res === false) {
ev.preventDefault();
}
@@ -4083,7 +4311,7 @@ Grid.mixin({
if (this.view.isEventResizable(seg.event)) {
seg.el.addClass('fc-allow-mouse-resize');
}
- this.view.trigger('eventMouseover', seg.el[0], seg.event, ev);
+ this.view.publiclyTrigger('eventMouseover', seg.el[0], seg.event, ev);
}
},
@@ -4099,7 +4327,7 @@ Grid.mixin({
if (this.view.isEventResizable(seg.event)) {
seg.el.removeClass('fc-allow-mouse-resize');
}
- this.view.trigger('eventMouseout', seg.el[0], seg.event, ev);
+ this.view.publiclyTrigger('eventMouseout', seg.el[0], seg.event, ev);
}
},
@@ -4124,6 +4352,7 @@ Grid.mixin({
var isResizable = view.isEventResizable(event);
var isResizing = false;
var dragListener;
+ var eventLongPressDelay;
if (isSelected && isResizable) {
// only allow resizing of the event is selected
@@ -4132,12 +4361,17 @@ Grid.mixin({
if (!isResizing && (isDraggable || isResizable)) { // allowed to be selected?
+ eventLongPressDelay = view.opt('eventLongPressDelay');
+ if (eventLongPressDelay == null) {
+ eventLongPressDelay = view.opt('longPressDelay'); // fallback
+ }
+
dragListener = isDraggable ?
this.buildSegDragListener(seg) :
this.buildSegSelectListener(seg); // seg isn't draggable, but still needs to be selected
dragListener.startInteraction(ev, { // won't start if already started
- delay: isSelected ? 0 : this.view.opt('longPressDelay') // do delay if not already selected
+ delay: isSelected ? 0 : eventLongPressDelay // do delay if not already selected
});
}
@@ -4270,11 +4504,15 @@ Grid.mixin({
mouseFollower.stop(!dropLocation, function() {
if (isDragging) {
view.unrenderDrag();
- view.showEvent(event);
_this.segDragStop(seg, ev);
}
+
if (dropLocation) {
- view.reportEventDrop(event, dropLocation, this.largeUnit, el, ev);
+ // no need to re-show original, will rerender all anyways. esp important if eventRenderWait
+ view.reportEventDrop(event, dropLocation, _this.largeUnit, el, ev);
+ }
+ else {
+ view.showEvent(event);
}
});
_this.segDragListener = null;
@@ -4316,14 +4554,14 @@ Grid.mixin({
// Called before event segment dragging starts
segDragStart: function(seg, ev) {
this.isDraggingSeg = true;
- this.view.trigger('eventDragStart', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
+ this.view.publiclyTrigger('eventDragStart', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
},
// Called after event segment dragging stops
segDragStop: function(seg, ev) {
this.isDraggingSeg = false;
- this.view.trigger('eventDragStop', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
+ this.view.publiclyTrigger('eventDragStop', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
},
@@ -4561,18 +4799,23 @@ Grid.mixin({
},
hitOut: function() { // called before mouse moves to a different hit OR moved out of all hits
resizeLocation = null;
+ view.showEvent(event); // for when out-of-bounds. show original
},
hitDone: function() { // resets the rendering to show the original event
_this.unrenderEventResize();
- view.showEvent(event);
enableCursor();
},
interactionEnd: function(ev) {
if (isDragging) {
_this.segResizeStop(seg, ev);
}
+
if (resizeLocation) { // valid date to resize to?
- view.reportEventResize(event, resizeLocation, this.largeUnit, el, ev);
+ // no need to re-show original, will rerender all anyways. esp important if eventRenderWait
+ view.reportEventResize(event, resizeLocation, _this.largeUnit, el, ev);
+ }
+ else {
+ view.showEvent(event);
}
_this.segResizeListener = null;
}
@@ -4585,14 +4828,14 @@ Grid.mixin({
// Called before event segment resizing starts
segResizeStart: function(seg, ev) {
this.isResizingSeg = true;
- this.view.trigger('eventResizeStart', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
+ this.view.publiclyTrigger('eventResizeStart', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
},
// Called after event segment resizing stops
segResizeStop: function(seg, ev) {
this.isResizingSeg = false;
- this.view.trigger('eventResizeStop', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
+ this.view.publiclyTrigger('eventResizeStop', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
},
@@ -5143,7 +5386,7 @@ var DayTableMixin = FC.DayTableMixin = {
this.dayIndices = dayIndices;
this.daysPerRow = daysPerRow;
this.rowCnt = rowCnt;
-
+
this.updateDayTableCols();
},
@@ -5381,9 +5624,25 @@ var DayTableMixin = FC.DayTableMixin = {
// (colspan should be no different)
renderHeadDateCellHtml: function(date, colspan, otherAttrs) {
var view = this.view;
+ var classNames = [
+ 'fc-day-header',
+ view.widgetHeaderClass
+ ];
+
+ // if only one row of days, the classNames on the header can represent the specific days beneath
+ if (this.rowCnt === 1) {
+ classNames = classNames.concat(
+ // includes the day-of-week class
+ // noThemeHighlight=true (don't highlight the header)
+ this.getDayClasses(date, true)
+ );
+ }
+ else {
+ classNames.push('fc-' + dayIDs[date.day()]); // only add the day-of-week class
+ }
return '' +
- '
");
+ }
+ else {
+ el.empty();
+ }
+ el.append(renderSection('left'))
+ .append(renderSection('right'))
+ .append(renderSection('center'))
+ .append('');
+ }
+ else {
+ removeElement();
+ }
+ }
+
+
+ function removeElement() {
+ if (el) {
+ el.remove();
+ el = t.el = null;
+ }
+ }
+
+
+ function renderSection(position) {
+ var sectionEl = $('');
+ var buttonStr = toolbarOptions.layout[position];
+
+ if (buttonStr) {
+ $.each(buttonStr.split(' '), function(i) {
+ var groupChildren = $();
+ var isOnlyButtons = true;
+ var groupEl;
+
+ $.each(this.split(','), function(j, buttonName) {
+ var customButtonProps;
+ var viewSpec;
+ var buttonClick;
+ var overrideText; // text explicitly set by calendar's constructor options. overcomes icons
+ var defaultText;
+ var themeIcon;
+ var normalIcon;
+ var innerHtml;
+ var classes;
+ var button; // the element
+
+ if (buttonName == 'title') {
+ groupChildren = groupChildren.add($('
')); // we always want it to take up height
+ isOnlyButtons = false;
+ }
+ else {
+ if ((customButtonProps = (calendar.options.customButtons || {})[buttonName])) {
+ buttonClick = function(ev) {
+ if (customButtonProps.click) {
+ customButtonProps.click.call(button[0], ev);
+ }
+ };
+ overrideText = ''; // icons will override text
+ defaultText = customButtonProps.text;
+ }
+ else if ((viewSpec = calendar.getViewSpec(buttonName))) {
+ buttonClick = function() {
+ calendar.changeView(buttonName);
+ };
+ viewsWithButtons.push(buttonName);
+ overrideText = viewSpec.buttonTextOverride;
+ defaultText = viewSpec.buttonTextDefault;
+ }
+ else if (calendar[buttonName]) { // a calendar method
+ buttonClick = function() {
+ calendar[buttonName]();
+ };
+ overrideText = (calendar.overrides.buttonText || {})[buttonName];
+ defaultText = calendar.options.buttonText[buttonName]; // everything else is considered default
+ }
+
+ if (buttonClick) {
+
+ themeIcon =
+ customButtonProps ?
+ customButtonProps.themeIcon :
+ calendar.options.themeButtonIcons[buttonName];
+
+ normalIcon =
+ customButtonProps ?
+ customButtonProps.icon :
+ calendar.options.buttonIcons[buttonName];
+
+ if (overrideText) {
+ innerHtml = htmlEscape(overrideText);
+ }
+ else if (themeIcon && calendar.options.theme) {
+ innerHtml = "";
+ }
+ else if (normalIcon && !calendar.options.theme) {
+ innerHtml = "";
+ }
+ else {
+ innerHtml = htmlEscape(defaultText);
+ }
+
+ classes = [
+ 'fc-' + buttonName + '-button',
+ tm + '-button',
+ tm + '-state-default'
+ ];
+
+ button = $( // type="button" so that it doesn't submit a form
+ ''
+ )
+ .click(function(ev) {
+ // don't process clicks for disabled buttons
+ if (!button.hasClass(tm + '-state-disabled')) {
+
+ buttonClick(ev);
+
+ // after the click action, if the button becomes the "active" tab, or disabled,
+ // it should never have a hover class, so remove it now.
+ if (
+ button.hasClass(tm + '-state-active') ||
+ button.hasClass(tm + '-state-disabled')
+ ) {
+ button.removeClass(tm + '-state-hover');
+ }
+ }
+ })
+ .mousedown(function() {
+ // the *down* effect (mouse pressed in).
+ // only on buttons that are not the "active" tab, or disabled
+ button
+ .not('.' + tm + '-state-active')
+ .not('.' + tm + '-state-disabled')
+ .addClass(tm + '-state-down');
+ })
+ .mouseup(function() {
+ // undo the *down* effect
+ button.removeClass(tm + '-state-down');
+ })
+ .hover(
+ function() {
+ // the *hover* effect.
+ // only on buttons that are not the "active" tab, or disabled
+ button
+ .not('.' + tm + '-state-active')
+ .not('.' + tm + '-state-disabled')
+ .addClass(tm + '-state-hover');
+ },
+ function() {
+ // undo the *hover* effect
+ button
+ .removeClass(tm + '-state-hover')
+ .removeClass(tm + '-state-down'); // if mouseleave happens before mouseup
+ }
+ );
+
+ groupChildren = groupChildren.add(button);
+ }
+ }
+ });
+
+ if (isOnlyButtons) {
+ groupChildren
+ .first().addClass(tm + '-corner-left').end()
+ .last().addClass(tm + '-corner-right').end();
+ }
+
+ if (groupChildren.length > 1) {
+ groupEl = $('');
+ if (isOnlyButtons) {
+ groupEl.addClass('fc-button-group');
+ }
+ groupEl.append(groupChildren);
+ sectionEl.append(groupEl);
+ }
+ else {
+ sectionEl.append(groupChildren); // 1 or 0 children
+ }
+ });
+ }
+
+ return sectionEl;
+ }
+
+
+ function updateTitle(text) {
+ if (el) {
+ el.find('h2').text(text);
+ }
+ }
+
+
+ function activateButton(buttonName) {
+ if (el) {
+ el.find('.fc-' + buttonName + '-button')
+ .addClass(tm + '-state-active');
+ }
+ }
+
+
+ function deactivateButton(buttonName) {
+ if (el) {
+ el.find('.fc-' + buttonName + '-button')
+ .removeClass(tm + '-state-active');
+ }
+ }
+
+
+ function disableButton(buttonName) {
+ if (el) {
+ el.find('.fc-' + buttonName + '-button')
+ .prop('disabled', true)
+ .addClass(tm + '-state-disabled');
+ }
+ }
+
+
+ function enableButton(buttonName) {
+ if (el) {
+ el.find('.fc-' + buttonName + '-button')
+ .prop('disabled', false)
+ .removeClass(tm + '-state-disabled');
+ }
+ }
+
+
+ function getViewsWithButtons() {
+ return viewsWithButtons;
+ }
+
+}
+
;;
var Calendar = FC.Calendar = Class.extend({
@@ -9087,6 +9946,7 @@ var Calendar = FC.Calendar = Class.extend({
viewSpecCache: null, // cache of view definitions
view: null, // current View object
header: null,
+ footer: null,
loadingLevel: 0, // number of simultaneous loading tasks
@@ -9155,7 +10015,7 @@ var Calendar = FC.Calendar = Class.extend({
if ($.inArray(unit, intervalUnits) != -1) {
// put views that have buttons first. there will be duplicates, but oh well
- viewTypes = this.header.getViewsWithButtons();
+ viewTypes = this.header.getViewsWithButtons(); // TODO: include footer as well?
$.each(FC.views, function(viewType) { // all views
viewTypes.push(viewType);
});
@@ -9302,7 +10162,7 @@ var Calendar = FC.Calendar = Class.extend({
// Should be called when any type of async data fetching begins
pushLoading: function() {
if (!(this.loadingLevel++)) {
- this.trigger('loading', null, true, this.view);
+ this.publiclyTrigger('loading', null, true, this.view);
}
},
@@ -9310,7 +10170,7 @@ var Calendar = FC.Calendar = Class.extend({
// Should be called when any type of async data fetching completes
popLoading: function() {
if (!(--this.loadingLevel)) {
- this.trigger('loading', null, false, this.view);
+ this.publiclyTrigger('loading', null, false, this.view);
}
},
@@ -9348,11 +10208,7 @@ function Calendar_constructor(element, overrides) {
t.render = render;
t.destroy = destroy;
- t.refetchEvents = refetchEvents;
- t.refetchEventSources = refetchEventSources;
- t.reportEvents = reportEvents;
- t.reportEventChange = reportEventChange;
- t.rerenderEvents = renderEvents; // `renderEvents` serves as a rerender. an API method
+ t.rerenderEvents = rerenderEvents;
t.changeView = renderView; // `renderView` will switch to another view
t.select = select;
t.unselect = unselect;
@@ -9368,7 +10224,7 @@ function Calendar_constructor(element, overrides) {
t.getCalendar = getCalendar;
t.getView = getView;
t.option = option; // getter/setter method
- t.trigger = trigger;
+ t.publiclyTrigger = publiclyTrigger;
// Options
@@ -9561,15 +10417,12 @@ function Calendar_constructor(element, overrides) {
};
-
+
// Imports
// -----------------------------------------------------------------------------------
EventManager.call(t);
- var isFetchNeeded = t.isFetchNeeded;
- var fetchEvents = t.fetchEvents;
- var fetchEventSources = t.fetchEventSources;
@@ -9578,7 +10431,9 @@ function Calendar_constructor(element, overrides) {
var _element = element[0];
+ var toolbarsManager;
var header;
+ var footer;
var content;
var tm; // for making theme classes
var currentView; // NOTE: keep this in sync with this.view
@@ -9586,11 +10441,10 @@ function Calendar_constructor(element, overrides) {
var suggestedViewHeight;
var windowResizeProxy; // wraps the windowResize function
var ignoreWindowResize = 0;
- var events = [];
var date; // unzoned
-
-
-
+
+
+
// Main Rendering
// -----------------------------------------------------------------------------------
@@ -9602,8 +10456,8 @@ function Calendar_constructor(element, overrides) {
else {
date = t.getNow(); // getNow already returns unzoned
}
-
-
+
+
function render() {
if (!content) {
initialRender();
@@ -9614,8 +10468,8 @@ function Calendar_constructor(element, overrides) {
renderView();
}
}
-
-
+
+
function initialRender() {
element.addClass('fc');
@@ -9656,9 +10510,14 @@ function Calendar_constructor(element, overrides) {
content = $("").prependTo(element);
- header = t.header = new Header(t);
- renderHeader();
+ var toolbars = buildToolbars();
+ toolbarsManager = new Iterator(toolbars);
+ header = t.header = toolbars[0];
+ footer = t.footer = toolbars[1];
+
+ renderHeader();
+ renderFooter();
renderView(t.options.defaultView);
if (t.options.handleWindowResize) {
@@ -9668,15 +10527,6 @@ function Calendar_constructor(element, overrides) {
}
- // can be called repeatedly and Header will rerender
- function renderHeader() {
- header.render();
- if (header.el) {
- element.prepend(header.el);
- }
- }
-
-
function destroy() {
if (currentView) {
@@ -9686,7 +10536,7 @@ function Calendar_constructor(element, overrides) {
// It is still the "current" view, just not rendered.
}
- header.removeElement();
+ toolbarsManager.proxyCall('removeElement');
content.remove();
element.removeClass('fc fc-ltr fc-rtl fc-unthemed ui-widget');
@@ -9696,13 +10546,13 @@ function Calendar_constructor(element, overrides) {
$(window).unbind('resize', windowResizeProxy);
}
}
-
-
+
+
function elementVisible() {
return element.is(':visible');
}
-
-
+
+
// View Rendering
// -----------------------------------------------------------------------------------
@@ -9711,11 +10561,13 @@ function Calendar_constructor(element, overrides) {
// Renders a view because of a date change, view-type change, or for the first time.
// If not given a viewType, keep the current view but render different dates.
// Accepts an optional scroll state to restore to.
- function renderView(viewType, explicitScrollState) {
+ function renderView(viewType, forcedScroll) {
ignoreWindowResize++;
+ var needsClearView = currentView && viewType && currentView.type !== viewType;
+
// if viewType is changing, remove the old view's rendering
- if (currentView && viewType && currentView.type !== viewType) {
+ if (needsClearView) {
freezeContentHeight(); // prevent a scroll jump when view element is removed
clearView();
}
@@ -9729,7 +10581,7 @@ function Calendar_constructor(element, overrides) {
currentView.setElement(
$("").appendTo(content)
);
- header.activateButton(viewType);
+ toolbarsManager.proxyCall('activateButton', viewType);
}
if (currentView) {
@@ -9739,7 +10591,7 @@ function Calendar_constructor(element, overrides) {
// render or rerender the view
if (
- !currentView.displaying ||
+ !currentView.isDateSet ||
!( // NOT within interval range signals an implicit date window change
date >= currentView.intervalStart &&
date < currentView.intervalEnd
@@ -9747,19 +10599,27 @@ function Calendar_constructor(element, overrides) {
) {
if (elementVisible()) {
- currentView.display(date, explicitScrollState); // will call freezeContentHeight
- unfreezeContentHeight(); // immediately unfreeze regardless of whether display is async
+ if (forcedScroll) {
+ currentView.captureInitialScroll(forcedScroll);
+ }
+
+ currentView.setDate(date, forcedScroll);
+
+ if (forcedScroll) {
+ currentView.releaseScroll();
+ }
// need to do this after View::render, so dates are calculated
- updateHeaderTitle();
- updateTodayButton();
-
- getAndRenderEvents();
+ // NOTE: view updates title text proactively
+ updateToolbarsTodayButton();
}
}
}
- unfreezeContentHeight(); // undo any lone freezeContentHeight calls
+ if (needsClearView) {
+ thawContentHeight();
+ }
+
ignoreWindowResize--;
}
@@ -9767,7 +10627,7 @@ function Calendar_constructor(element, overrides) {
// Unrenders the current view and reflects this change in the Header.
// Unregsiters the `currentView`, but does not remove from viewByType hash.
function clearView() {
- header.deactivateButton(currentView.type);
+ toolbarsManager.proxyCall('deactivateButton', currentView.type);
currentView.removeElement();
currentView = t.view = null;
}
@@ -9783,13 +10643,14 @@ function Calendar_constructor(element, overrides) {
var viewType = currentView.type;
var scrollState = currentView.queryScroll();
clearView();
+ calcSize();
renderView(viewType, scrollState);
- unfreezeContentHeight();
+ thawContentHeight();
ignoreWindowResize--;
}
-
+
// Resizing
// -----------------------------------------------------------------------------------
@@ -9806,8 +10667,8 @@ function Calendar_constructor(element, overrides) {
t.isHeightAuto = function() {
return t.options.contentHeight === 'auto' || t.options.height === 'auto';
};
-
-
+
+
function updateSize(shouldRecalc) {
if (elementVisible()) {
@@ -9829,8 +10690,8 @@ function Calendar_constructor(element, overrides) {
_calcSize();
}
}
-
-
+
+
function _calcSize() { // assumes elementVisible
var contentHeightInput = t.options.contentHeight;
var heightInput = t.options.height;
@@ -9842,13 +10703,13 @@ function Calendar_constructor(element, overrides) {
suggestedViewHeight = contentHeightInput();
}
else if (typeof heightInput === 'number') { // exists and not 'auto'
- suggestedViewHeight = heightInput - queryHeaderHeight();
+ suggestedViewHeight = heightInput - queryToolbarsHeight();
}
else if (typeof heightInput === 'function') { // exists and is a function
- suggestedViewHeight = heightInput() - queryHeaderHeight();
+ suggestedViewHeight = heightInput() - queryToolbarsHeight();
}
else if (heightInput === 'parent') { // set to height of parent element
- suggestedViewHeight = element.parent().height() - queryHeaderHeight();
+ suggestedViewHeight = element.parent().height() - queryToolbarsHeight();
}
else {
suggestedViewHeight = Math.round(content.width() / Math.max(t.options.aspectRatio, .5));
@@ -9856,11 +10717,14 @@ function Calendar_constructor(element, overrides) {
}
- function queryHeaderHeight() {
- return header.el ? header.el.outerHeight(true) : 0; // includes margin
+ function queryToolbarsHeight() {
+ return toolbarsManager.items.reduce(function(accumulator, toolbar) {
+ var toolbarHeight = toolbar.el ? toolbar.el.outerHeight(true) : 0; // includes margin
+ return accumulator + toolbarHeight;
+ }, 0);
}
-
-
+
+
function windowResize(ev) {
if (
!ignoreWindowResize &&
@@ -9868,94 +10732,93 @@ function Calendar_constructor(element, overrides) {
currentView.start // view has already been rendered
) {
if (updateSize(true)) {
- currentView.trigger('windowResize', _element);
+ currentView.publiclyTrigger('windowResize', _element);
}
}
}
-
-
-
- /* Event Fetching/Rendering
+
+
+
+ /* Event Rendering
-----------------------------------------------------------------------------*/
- // TODO: going forward, most of this stuff should be directly handled by the view
- function refetchEvents() { // can be called as an API method
- fetchAndRenderEvents();
- }
-
-
- // TODO: move this into EventManager?
- function refetchEventSources(matchInputs) {
- fetchEventSources(t.getEventSourcesByMatchArray(matchInputs));
- }
-
-
- function renderEvents() { // destroys old events if previously rendered
+ function rerenderEvents() { // API method. destroys old events if previously rendered.
if (elementVisible()) {
- freezeContentHeight();
- currentView.displayEvents(events);
- unfreezeContentHeight();
- }
- }
-
-
- function getAndRenderEvents() {
- if (!t.options.lazyFetching || isFetchNeeded(currentView.start, currentView.end)) {
- fetchAndRenderEvents();
- }
- else {
- renderEvents();
+ t.reportEventChange(); // will re-trasmit events to the view, causing a rerender
}
}
- function fetchAndRenderEvents() {
- fetchEvents(currentView.start, currentView.end);
- // ... will call reportEvents
- // ... which will call renderEvents
- }
-
- // called when event data arrives
- function reportEvents(_events) {
- events = _events;
- renderEvents();
- }
-
-
- // called when a single event's data has been changed
- function reportEventChange() {
- renderEvents();
- }
-
-
-
- /* Header Updating
+ /* Toolbars
-----------------------------------------------------------------------------*/
- function updateHeaderTitle() {
- header.updateTitle(currentView.title);
+ function buildToolbars() {
+ return [
+ new Toolbar(t, computeHeaderOptions()),
+ new Toolbar(t, computeFooterOptions())
+ ];
}
- function updateTodayButton() {
- var now = t.getNow();
+ function computeHeaderOptions() {
+ return {
+ extraClasses: 'fc-header-toolbar',
+ layout: t.options.header
+ };
+ }
+
+ function computeFooterOptions() {
+ return {
+ extraClasses: 'fc-footer-toolbar',
+ layout: t.options.footer
+ };
+ }
+
+
+ // can be called repeatedly and Header will rerender
+ function renderHeader() {
+ header.setToolbarOptions(computeHeaderOptions());
+ header.render();
+ if (header.el) {
+ element.prepend(header.el);
+ }
+ }
+
+
+ // can be called repeatedly and Footer will rerender
+ function renderFooter() {
+ footer.setToolbarOptions(computeFooterOptions());
+ footer.render();
+ if (footer.el) {
+ element.append(footer.el);
+ }
+ }
+
+
+ t.setToolbarsTitle = function(title) {
+ toolbarsManager.proxyCall('updateTitle', title);
+ };
+
+
+ function updateToolbarsTodayButton() {
+ var now = t.getNow();
if (now >= currentView.intervalStart && now < currentView.intervalEnd) {
- header.disableButton('today');
+ toolbarsManager.proxyCall('disableButton', 'today');
}
else {
- header.enableButton('today');
+ toolbarsManager.proxyCall('enableButton', 'today');
}
}
-
+
/* Selection
-----------------------------------------------------------------------------*/
-
+
// this public method receives start/end dates in any format, with any timezone
function select(zonedStartInput, zonedEndInput) {
@@ -9963,56 +10826,56 @@ function Calendar_constructor(element, overrides) {
t.buildSelectSpan.apply(t, arguments)
);
}
-
+
function unselect() { // safe to be called before renderView
if (currentView) {
currentView.unselect();
}
}
-
-
-
+
+
+
/* Date
-----------------------------------------------------------------------------*/
-
-
+
+
function prev() {
date = currentView.computePrevDate(date);
renderView();
}
-
-
+
+
function next() {
date = currentView.computeNextDate(date);
renderView();
}
-
-
+
+
function prevYear() {
date.add(-1, 'years');
renderView();
}
-
-
+
+
function nextYear() {
date.add(1, 'years');
renderView();
}
-
-
+
+
function today() {
date = t.getNow();
renderView();
}
-
-
+
+
function gotoDate(zonedDateInput) {
date = t.moment(zonedDateInput).stripZone();
renderView();
}
-
-
+
+
function incrementDate(delta) {
date.add(moment.duration(delta));
renderView();
@@ -10030,8 +10893,8 @@ function Calendar_constructor(element, overrides) {
date = newDate.clone();
renderView(spec ? spec.type : null);
}
-
-
+
+
// for external API
function getDate() {
return t.applyTimezone(date); // infuse the calendar's timezone
@@ -10041,45 +10904,51 @@ function Calendar_constructor(element, overrides) {
/* Height "Freezing"
-----------------------------------------------------------------------------*/
- // TODO: move this into the view
+
t.freezeContentHeight = freezeContentHeight;
- t.unfreezeContentHeight = unfreezeContentHeight;
+ t.thawContentHeight = thawContentHeight;
+
+ var freezeContentHeightDepth = 0;
function freezeContentHeight() {
- content.css({
- width: '100%',
- height: content.height(),
- overflow: 'hidden'
- });
+ if (!(freezeContentHeightDepth++)) {
+ content.css({
+ width: '100%',
+ height: content.height(),
+ overflow: 'hidden'
+ });
+ }
}
- function unfreezeContentHeight() {
- content.css({
- width: '',
- height: '',
- overflow: ''
- });
+ function thawContentHeight() {
+ if (!(--freezeContentHeightDepth)) {
+ content.css({
+ width: '',
+ height: '',
+ overflow: ''
+ });
+ }
}
-
-
-
+
+
+
/* Misc
-----------------------------------------------------------------------------*/
-
+
function getCalendar() {
return t;
}
-
+
function getView() {
return currentView;
}
-
-
+
+
function option(name, value) {
var newOptionHash;
@@ -10135,19 +11004,20 @@ function Calendar_constructor(element, overrides) {
}
else if (optionName === 'timezone') {
t.rezoneArrayEventSources();
- refetchEvents();
+ t.refetchEvents();
return;
}
}
- // catch-all. rerender the header and rebuild/rerender the current view
+ // catch-all. rerender the header and footer and rebuild/rerender the current view
renderHeader();
+ renderFooter();
viewsByType = {}; // even non-current views will be affected by this option change. do before rerender
reinitView();
}
-
-
- function trigger(name, thisObj) { // overrides the Emitter's trigger method :(
+
+
+ function publiclyTrigger(name, thisObj) {
var args = Array.prototype.slice.call(arguments, 2);
thisObj = thisObj || _element;
@@ -10310,6 +11180,7 @@ Calendar.defaults = {
dropAccept: '*',
eventOrder: 'title',
+ //eventRenderWait: null,
eventLimit: false,
eventLimitText: 'more',
@@ -10549,275 +11420,6 @@ FC.locale('en', Calendar.englishDefaults);
;;
-/* Top toolbar area with buttons and title
-----------------------------------------------------------------------------------------------------------------------*/
-// TODO: rename all header-related things to "toolbar"
-
-function Header(calendar) {
- var t = this;
-
- // exports
- t.render = render;
- t.removeElement = removeElement;
- t.updateTitle = updateTitle;
- t.activateButton = activateButton;
- t.deactivateButton = deactivateButton;
- t.disableButton = disableButton;
- t.enableButton = enableButton;
- t.getViewsWithButtons = getViewsWithButtons;
- t.el = null; // mirrors local `el`
-
- // locals
- var el;
- var viewsWithButtons = [];
- var tm;
-
-
- // can be called repeatedly and will rerender
- function render() {
- var options = calendar.options;
- var sections = options.header;
-
- tm = options.theme ? 'ui' : 'fc';
-
- if (sections) {
- if (!el) {
- el = this.el = $("");
- }
- else {
- el.empty();
- }
- el.append(renderSection('left'))
- .append(renderSection('right'))
- .append(renderSection('center'))
- .append('');
- }
- else {
- removeElement();
- }
- }
-
-
- function removeElement() {
- if (el) {
- el.remove();
- el = t.el = null;
- }
- }
-
-
- function renderSection(position) {
- var sectionEl = $('');
- var options = calendar.options;
- var buttonStr = options.header[position];
-
- if (buttonStr) {
- $.each(buttonStr.split(' '), function(i) {
- var groupChildren = $();
- var isOnlyButtons = true;
- var groupEl;
-
- $.each(this.split(','), function(j, buttonName) {
- var customButtonProps;
- var viewSpec;
- var buttonClick;
- var overrideText; // text explicitly set by calendar's constructor options. overcomes icons
- var defaultText;
- var themeIcon;
- var normalIcon;
- var innerHtml;
- var classes;
- var button; // the element
-
- if (buttonName == 'title') {
- groupChildren = groupChildren.add($('
')); // we always want it to take up height
- isOnlyButtons = false;
- }
- else {
- if ((customButtonProps = (options.customButtons || {})[buttonName])) {
- buttonClick = function(ev) {
- if (customButtonProps.click) {
- customButtonProps.click.call(button[0], ev);
- }
- };
- overrideText = ''; // icons will override text
- defaultText = customButtonProps.text;
- }
- else if ((viewSpec = calendar.getViewSpec(buttonName))) {
- buttonClick = function() {
- calendar.changeView(buttonName);
- };
- viewsWithButtons.push(buttonName);
- overrideText = viewSpec.buttonTextOverride;
- defaultText = viewSpec.buttonTextDefault;
- }
- else if (calendar[buttonName]) { // a calendar method
- buttonClick = function() {
- calendar[buttonName]();
- };
- overrideText = (calendar.overrides.buttonText || {})[buttonName];
- defaultText = options.buttonText[buttonName]; // everything else is considered default
- }
-
- if (buttonClick) {
-
- themeIcon =
- customButtonProps ?
- customButtonProps.themeIcon :
- options.themeButtonIcons[buttonName];
-
- normalIcon =
- customButtonProps ?
- customButtonProps.icon :
- options.buttonIcons[buttonName];
-
- if (overrideText) {
- innerHtml = htmlEscape(overrideText);
- }
- else if (themeIcon && options.theme) {
- innerHtml = "";
- }
- else if (normalIcon && !options.theme) {
- innerHtml = "";
- }
- else {
- innerHtml = htmlEscape(defaultText);
- }
-
- classes = [
- 'fc-' + buttonName + '-button',
- tm + '-button',
- tm + '-state-default'
- ];
-
- button = $( // type="button" so that it doesn't submit a form
- ''
- )
- .click(function(ev) {
- // don't process clicks for disabled buttons
- if (!button.hasClass(tm + '-state-disabled')) {
-
- buttonClick(ev);
-
- // after the click action, if the button becomes the "active" tab, or disabled,
- // it should never have a hover class, so remove it now.
- if (
- button.hasClass(tm + '-state-active') ||
- button.hasClass(tm + '-state-disabled')
- ) {
- button.removeClass(tm + '-state-hover');
- }
- }
- })
- .mousedown(function() {
- // the *down* effect (mouse pressed in).
- // only on buttons that are not the "active" tab, or disabled
- button
- .not('.' + tm + '-state-active')
- .not('.' + tm + '-state-disabled')
- .addClass(tm + '-state-down');
- })
- .mouseup(function() {
- // undo the *down* effect
- button.removeClass(tm + '-state-down');
- })
- .hover(
- function() {
- // the *hover* effect.
- // only on buttons that are not the "active" tab, or disabled
- button
- .not('.' + tm + '-state-active')
- .not('.' + tm + '-state-disabled')
- .addClass(tm + '-state-hover');
- },
- function() {
- // undo the *hover* effect
- button
- .removeClass(tm + '-state-hover')
- .removeClass(tm + '-state-down'); // if mouseleave happens before mouseup
- }
- );
-
- groupChildren = groupChildren.add(button);
- }
- }
- });
-
- if (isOnlyButtons) {
- groupChildren
- .first().addClass(tm + '-corner-left').end()
- .last().addClass(tm + '-corner-right').end();
- }
-
- if (groupChildren.length > 1) {
- groupEl = $('');
- if (isOnlyButtons) {
- groupEl.addClass('fc-button-group');
- }
- groupEl.append(groupChildren);
- sectionEl.append(groupEl);
- }
- else {
- sectionEl.append(groupChildren); // 1 or 0 children
- }
- });
- }
-
- return sectionEl;
- }
-
-
- function updateTitle(text) {
- if (el) {
- el.find('h2').text(text);
- }
- }
-
-
- function activateButton(buttonName) {
- if (el) {
- el.find('.fc-' + buttonName + '-button')
- .addClass(tm + '-state-active');
- }
- }
-
-
- function deactivateButton(buttonName) {
- if (el) {
- el.find('.fc-' + buttonName + '-button')
- .removeClass(tm + '-state-active');
- }
- }
-
-
- function disableButton(buttonName) {
- if (el) {
- el.find('.fc-' + buttonName + '-button')
- .prop('disabled', true)
- .addClass(tm + '-state-disabled');
- }
- }
-
-
- function enableButton(buttonName) {
- if (el) {
- el.find('.fc-' + buttonName + '-button')
- .prop('disabled', false)
- .removeClass(tm + '-state-disabled');
- }
- }
-
-
- function getViewsWithButtons() {
- return viewsWithButtons;
- }
-
-}
-
-;;
-
FC.sourceNormalizers = [];
FC.sourceFetchers = [];
@@ -10831,38 +11433,39 @@ var eventGUID = 1;
function EventManager() { // assumed to be a calendar
var t = this;
-
-
+
+
// exports
+ t.requestEvents = requestEvents;
+ t.reportEventChange = reportEventChange;
t.isFetchNeeded = isFetchNeeded;
t.fetchEvents = fetchEvents;
t.fetchEventSources = fetchEventSources;
+ t.refetchEvents = refetchEvents;
+ t.refetchEventSources = refetchEventSources;
t.getEventSources = getEventSources;
t.getEventSourceById = getEventSourceById;
- t.getEventSourcesByMatchArray = getEventSourcesByMatchArray;
- t.getEventSourcesByMatch = getEventSourcesByMatch;
t.addEventSource = addEventSource;
t.removeEventSource = removeEventSource;
t.removeEventSources = removeEventSources;
t.updateEvent = updateEvent;
+ t.updateEvents = updateEvents;
t.renderEvent = renderEvent;
+ t.renderEvents = renderEvents;
t.removeEvents = removeEvents;
t.clientEvents = clientEvents;
t.mutateEvent = mutateEvent;
t.normalizeEventDates = normalizeEventDates;
t.normalizeEventTimes = normalizeEventTimes;
-
-
- // imports
- var reportEvents = t.reportEvents;
-
-
+
+
// locals
var stickySource = { events: [] };
var sources = [ stickySource ];
var rangeStart, rangeEnd;
var pendingSourceCnt = 0; // outstanding fetch requests, max one per source
var cache = []; // holds events that have already been expanded
+ var prunedCache; // like cache, but only events that intersect with rangeStart/rangeEnd
$.each(
@@ -10874,9 +11477,55 @@ function EventManager() { // assumed to be a calendar
}
}
);
-
-
-
+
+
+
+ function requestEvents(start, end) {
+ if (!t.options.lazyFetching || isFetchNeeded(start, end)) {
+ return fetchEvents(start, end);
+ }
+ else {
+ return Promise.resolve(prunedCache);
+ }
+ }
+
+
+ function reportEventChange() {
+ prunedCache = filterEventsWithinRange(cache);
+ t.trigger('eventsReset', prunedCache);
+ }
+
+
+ function filterEventsWithinRange(events) {
+ var filteredEvents = [];
+ var i, event;
+
+ for (i = 0; i < events.length; i++) {
+ event = events[i];
+
+ if (
+ event.start.clone().stripZone() < rangeEnd &&
+ t.getEventEnd(event).stripZone() > rangeStart
+ ) {
+ filteredEvents.push(event);
+ }
+ }
+
+ return filteredEvents;
+ }
+
+
+ t.getEventCache = function() {
+ return cache;
+ };
+
+
+ t.getPrunedEventCache = function() {
+ return prunedCache;
+ };
+
+
+
/* Fetching
-----------------------------------------------------------------------------*/
@@ -10886,12 +11535,24 @@ function EventManager() { // assumed to be a calendar
return !rangeStart || // nothing has been fetched yet?
start < rangeStart || end > rangeEnd; // is part of the new range outside of the old range?
}
-
-
+
+
function fetchEvents(start, end) {
rangeStart = start;
rangeEnd = end;
- fetchEventSources(sources, 'reset');
+ return refetchEvents();
+ }
+
+
+ // poorly named. fetches all sources with current `rangeStart` and `rangeEnd`.
+ function refetchEvents() {
+ return fetchEventSources(sources, 'reset');
+ }
+
+
+ // poorly named. fetches a subset of event sources.
+ function refetchEventSources(matchInputs) {
+ return fetchEventSources(getEventSourcesByMatchArray(matchInputs));
}
@@ -10921,9 +11582,17 @@ function EventManager() { // assumed to be a calendar
for (i = 0; i < specificSources.length; i++) {
source = specificSources[i];
-
tryFetchEventSource(source, source._fetchId);
}
+
+ if (pendingSourceCnt) {
+ return new Promise(function(resolve) {
+ t.one('eventsReceived', resolve); // will send prunedCache
+ });
+ }
+ else { // executed all synchronously, or no sources at all
+ return Promise.resolve(prunedCache);
+ }
}
@@ -10956,7 +11625,7 @@ function EventManager() { // assumed to be a calendar
}
if (abstractEvent) { // not false (an invalid event)
- cache.push.apply(
+ cache.push.apply( // append
cache,
expandEvent(abstractEvent) // add individual expanded events to the cache
);
@@ -10984,11 +11653,12 @@ function EventManager() { // assumed to be a calendar
function decrementPendingSourceCnt() {
pendingSourceCnt--;
if (!pendingSourceCnt) {
- reportEvents(cache);
+ reportEventChange(cache); // updates prunedCache
+ t.trigger('eventsReceived', prunedCache);
}
}
-
-
+
+
function _fetchEventSource(source, callback) {
var i;
var fetchers = FC.sourceFetchers;
@@ -11097,9 +11767,9 @@ function EventManager() { // assumed to be a calendar
}
}
}
-
-
-
+
+
+
/* Sources
-----------------------------------------------------------------------------*/
@@ -11108,7 +11778,7 @@ function EventManager() { // assumed to be a calendar
var source = buildEventSource(sourceInput);
if (source) {
sources.push(source);
- fetchEventSources([ source ], 'add'); // will eventually call reportEvents
+ fetchEventSources([ source ], 'add'); // will eventually call reportEventChange
}
}
@@ -11204,7 +11874,7 @@ function EventManager() { // assumed to be a calendar
cache = excludeEventsBySources(cache, targetSources);
}
- reportEvents(cache);
+ reportEventChange();
}
@@ -11298,27 +11968,39 @@ function EventManager() { // assumed to be a calendar
return true; // keep
});
}
-
-
-
+
+
+
/* Manipulation
-----------------------------------------------------------------------------*/
// Only ever called from the externally-facing API
function updateEvent(event) {
+ updateEvents([ event ]);
+ }
- // massage start/end values, even if date string values
- event.start = t.moment(event.start);
- if (event.end) {
- event.end = t.moment(event.end);
- }
- else {
- event.end = null;
+
+ // Only ever called from the externally-facing API
+ function updateEvents(events) {
+ var i, event;
+
+ for (i = 0; i < events.length; i++) {
+ event = events[i];
+
+ // massage start/end values, even if date string values
+ event.start = t.moment(event.start);
+ if (event.end) {
+ event.end = t.moment(event.end);
+ }
+ else {
+ event.end = null;
+ }
+
+ mutateEvent(event, getMiscEventProps(event)); // will handle start/end/allDay normalization
}
- mutateEvent(event, getMiscEventProps(event)); // will handle start/end/allDay normalization
- reportEvents(cache); // reports event modifications (so we can redraw)
+ reportEventChange(); // reports event modifications (so we can redraw)
}
@@ -11342,37 +12024,50 @@ function EventManager() { // assumed to be a calendar
return !/^_|^(id|allDay|start|end)$/.test(name);
}
-
+
// returns the expanded events that were created
function renderEvent(eventInput, stick) {
- var abstractEvent = buildEventFromInput(eventInput);
- var events;
- var i, event;
+ return renderEvents([ eventInput ], stick);
+ }
- if (abstractEvent) { // not false (a valid input)
- events = expandEvent(abstractEvent);
- for (i = 0; i < events.length; i++) {
- event = events[i];
+ // returns the expanded events that were created
+ function renderEvents(eventInputs, stick) {
+ var renderedEvents = [];
+ var renderableEvents;
+ var abstractEvent;
+ var i, j, event;
- if (!event.source) {
- if (stick) {
- stickySource.events.push(event);
- event.source = stickySource;
+ for (i = 0; i < eventInputs.length; i++) {
+ abstractEvent = buildEventFromInput(eventInputs[i]);
+
+ if (abstractEvent) { // not false (a valid input)
+ renderableEvents = expandEvent(abstractEvent);
+
+ for (j = 0; j < renderableEvents.length; j++) {
+ event = renderableEvents[j];
+
+ if (!event.source) {
+ if (stick) {
+ stickySource.events.push(event);
+ event.source = stickySource;
+ }
+ cache.push(event);
}
- cache.push(event);
}
+
+ renderedEvents = renderedEvents.concat(renderableEvents);
}
-
- reportEvents(cache);
-
- return events;
}
- return [];
+ if (renderedEvents.length) { // any new events rendered?
+ reportEventChange();
+ }
+
+ return renderedEvents;
}
-
-
+
+
function removeEvents(filter) {
var eventID;
var i;
@@ -11399,10 +12094,10 @@ function EventManager() { // assumed to be a calendar
}
}
- reportEvents(cache);
+ reportEventChange();
}
-
+
function clientEvents(filter) {
if ($.isFunction(filter)) {
return $.grep(cache, filter);
@@ -11442,8 +12137,8 @@ function EventManager() { // assumed to be a calendar
}
backupEventDates(event);
}
-
-
+
+
/* Event Normalization
-----------------------------------------------------------------------------*/
@@ -11853,11 +12548,6 @@ function EventManager() { // assumed to be a calendar
};
}
-
- t.getEventCache = function() {
- return cache;
- };
-
}
@@ -12386,13 +13076,18 @@ var BasicView = FC.BasicView = View.extend({
------------------------------------------------------------------------------------------------------------------*/
- queryScroll: function() {
- return this.scroller.getScrollTop();
+ computeInitialScroll: function() {
+ return { top: 0 };
},
- setScroll: function(top) {
- this.scroller.setScrollTop(top);
+ queryScroll: function() {
+ return { top: this.scroller.getScrollTop() };
+ },
+
+
+ setScroll: function(scroll) {
+ this.scroller.setScrollTop(scroll.top);
},
@@ -12909,17 +13604,17 @@ var AgendaView = FC.AgendaView = View.extend({
top++; // to overcome top border that slots beyond the first have. looks better
}
- return top;
+ return { top: top };
},
queryScroll: function() {
- return this.scroller.getScrollTop();
+ return { top: this.scroller.getScrollTop() };
},
- setScroll: function(top) {
- this.scroller.setScrollTop(top);
+ setScroll: function(scroll) {
+ this.scroller.setScrollTop(scroll.top);
},
diff --git a/library/fullcalendar/fullcalendar.min.css b/library/fullcalendar/fullcalendar.min.css
index 87ee16e69..1339120b4 100644
--- a/library/fullcalendar/fullcalendar.min.css
+++ b/library/fullcalendar/fullcalendar.min.css
@@ -1,5 +1,5 @@
/*!
- * FullCalendar v3.0.1 Stylesheet
+ * FullCalendar v3.1.0 Stylesheet
* Docs & License: http://fullcalendar.io/
* (c) 2016 Adam Shaw
- */.fc-icon,body .fc{font-size:1em}.fc-button-group,.fc-icon{display:inline-block}.fc-bg,.fc-row .fc-bgevent-skeleton,.fc-row .fc-highlight-skeleton{bottom:0}.fc-icon,.fc-unselectable{-khtml-user-select:none;-webkit-touch-callout:none}.fc{direction:ltr;text-align:left}.fc-rtl{text-align:right}.fc th,.fc-basic-view td.fc-week-number,.fc-icon,.fc-toolbar{text-align:center}.fc-unthemed .fc-content,.fc-unthemed .fc-divider,.fc-unthemed .fc-list-heading td,.fc-unthemed .fc-list-view,.fc-unthemed .fc-popover,.fc-unthemed .fc-row,.fc-unthemed tbody,.fc-unthemed td,.fc-unthemed th,.fc-unthemed thead{border-color:#ddd}.fc-unthemed .fc-popover{background-color:#fff}.fc-unthemed .fc-divider,.fc-unthemed .fc-list-heading td,.fc-unthemed .fc-popover .fc-header{background:#eee}.fc-unthemed .fc-popover .fc-header .fc-close{color:#666}.fc-unthemed .fc-today{background:#fcf8e3}.fc-highlight{background:#bce8f1;opacity:.3}.fc-bgevent{background:#8fdf82;opacity:.3}.fc-nonbusiness{background:#d7d7d7}.fc-icon{height:1em;line-height:1em;overflow:hidden;font-family:"Courier New",Courier,monospace;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fc-icon:after{position:relative}.fc-icon-left-single-arrow:after{content:"\02039";font-weight:700;font-size:200%;top:-7%}.fc-icon-right-single-arrow:after{content:"\0203A";font-weight:700;font-size:200%;top:-7%}.fc-icon-left-double-arrow:after{content:"\000AB";font-size:160%;top:-7%}.fc-icon-right-double-arrow:after{content:"\000BB";font-size:160%;top:-7%}.fc-icon-left-triangle:after{content:"\25C4";font-size:125%;top:3%}.fc-icon-right-triangle:after{content:"\25BA";font-size:125%;top:3%}.fc-icon-down-triangle:after{content:"\25BC";font-size:125%;top:2%}.fc-icon-x:after{content:"\000D7";font-size:200%;top:6%}.fc button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;height:2.1em;padding:0 .6em;font-size:1em;white-space:nowrap;cursor:pointer}.fc button::-moz-focus-inner{margin:0;padding:0}.fc-state-default{border:1px solid;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#333;text-shadow:0 1px 1px rgba(255,255,255,.75);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.fc-state-default.fc-corner-left{border-top-left-radius:4px;border-bottom-left-radius:4px}.fc-state-default.fc-corner-right{border-top-right-radius:4px;border-bottom-right-radius:4px}.fc button .fc-icon{position:relative;top:-.05em;margin:0 .2em;vertical-align:middle}.fc-state-active,.fc-state-disabled,.fc-state-down,.fc-state-hover{color:#333;background-color:#e6e6e6}.fc-state-hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.fc-state-active,.fc-state-down{background-color:#ccc;background-image:none;box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.fc-state-disabled{cursor:default;background-image:none;opacity:.65;box-shadow:none}.fc-event.fc-draggable,.fc-event[href],.fc-popover .fc-header .fc-close,a[data-goto]{cursor:pointer}.fc .fc-button-group>*{float:left;margin:0 0 0 -1px}.fc .fc-button-group>:first-child{margin-left:0}.fc-popover{position:absolute;box-shadow:0 2px 6px rgba(0,0,0,.15)}.fc-popover .fc-header{padding:2px 4px}.fc-popover .fc-header .fc-title{margin:0 2px}.fc-ltr .fc-popover .fc-header .fc-title,.fc-rtl .fc-popover .fc-header .fc-close{float:left}.fc-ltr .fc-popover .fc-header .fc-close,.fc-rtl .fc-popover .fc-header .fc-title{float:right}.fc-unthemed .fc-popover{border-width:1px;border-style:solid}.fc-unthemed .fc-popover .fc-header .fc-close{font-size:.9em;margin-top:2px}.fc-popover>.ui-widget-header+.ui-widget-content{border-top:0}.fc-divider{border-style:solid;border-width:1px}hr.fc-divider{height:0;margin:0;padding:0 0 2px;border-width:1px 0}.fc-bg table,.fc-row .fc-bgevent-skeleton table,.fc-row .fc-highlight-skeleton table{height:100%}.fc-clear{clear:both}.fc-bg,.fc-bgevent-skeleton,.fc-helper-skeleton,.fc-highlight-skeleton{position:absolute;top:0;left:0;right:0}.fc table{width:100%;box-sizing:border-box;table-layout:fixed;border-collapse:collapse;border-spacing:0;font-size:1em}.fc td,.fc th{border-style:solid;border-width:1px;padding:0;vertical-align:top}.fc td.fc-today{border-style:double}a[data-goto]:hover{text-decoration:underline}.fc .fc-row{border-style:solid;border-width:0}.fc-row table{border-left:0 hidden transparent;border-right:0 hidden transparent;border-bottom:0 hidden transparent}.fc-row:first-child table{border-top:0 hidden transparent}.fc-row{position:relative}.fc-row .fc-bg{z-index:1}.fc-row .fc-bgevent-skeleton td,.fc-row .fc-highlight-skeleton td{border-color:transparent}.fc-row .fc-bgevent-skeleton{z-index:2}.fc-row .fc-highlight-skeleton{z-index:3}.fc-row .fc-content-skeleton{position:relative;z-index:4;padding-bottom:2px}.fc-row .fc-helper-skeleton{z-index:5}.fc-row .fc-content-skeleton td,.fc-row .fc-helper-skeleton td{background:0 0;border-color:transparent;border-bottom:0}.fc-row .fc-content-skeleton tbody td,.fc-row .fc-helper-skeleton tbody td{border-top:0}.fc-scroller{-webkit-overflow-scrolling:touch}.fc-row.fc-rigid,.fc-time-grid-event{overflow:hidden}.fc-scroller>.fc-day-grid,.fc-scroller>.fc-time-grid{position:relative;width:100%}.fc-event{position:relative;display:block;font-size:.85em;line-height:1.3;border-radius:3px;border:1px solid #3a87ad;font-weight:400}.fc-event,.fc-event-dot{background-color:#3a87ad}.fc-event,.fc-event:hover,.ui-widget .fc-event{color:#fff;text-decoration:none}.fc-not-allowed,.fc-not-allowed .fc-event{cursor:not-allowed}.fc-event .fc-bg{z-index:1;background:#fff;opacity:.25}.fc-event .fc-content{position:relative;z-index:2}.fc-event .fc-resizer{position:absolute;z-index:4;display:none}.fc-event.fc-allow-mouse-resize .fc-resizer,.fc-event.fc-selected .fc-resizer{display:block}.fc-event.fc-selected .fc-resizer:before{content:"";position:absolute;z-index:9999;top:50%;left:50%;width:40px;height:40px;margin-left:-20px;margin-top:-20px}.fc-event.fc-selected{z-index:9999!important;box-shadow:0 2px 5px rgba(0,0,0,.2)}.fc-event.fc-selected.fc-dragging{box-shadow:0 2px 7px rgba(0,0,0,.3)}.fc-h-event.fc-selected:before{content:"";position:absolute;z-index:3;top:-10px;bottom:-10px;left:0;right:0}.fc-ltr .fc-h-event.fc-not-start,.fc-rtl .fc-h-event.fc-not-end{margin-left:0;border-left-width:0;padding-left:1px;border-top-left-radius:0;border-bottom-left-radius:0}.fc-ltr .fc-h-event.fc-not-end,.fc-rtl .fc-h-event.fc-not-start{margin-right:0;border-right-width:0;padding-right:1px;border-top-right-radius:0;border-bottom-right-radius:0}.fc-ltr .fc-h-event .fc-start-resizer,.fc-rtl .fc-h-event .fc-end-resizer{cursor:w-resize;left:-1px}.fc-ltr .fc-h-event .fc-end-resizer,.fc-rtl .fc-h-event .fc-start-resizer{cursor:e-resize;right:-1px}.fc-h-event.fc-allow-mouse-resize .fc-resizer{width:7px;top:-1px;bottom:-1px}.fc-h-event.fc-selected .fc-resizer{border-radius:4px;border-width:1px;width:6px;height:6px;border-style:solid;border-color:inherit;background:#fff;top:50%;margin-top:-4px}.fc-ltr .fc-h-event.fc-selected .fc-start-resizer,.fc-rtl .fc-h-event.fc-selected .fc-end-resizer{margin-left:-4px}.fc-ltr .fc-h-event.fc-selected .fc-end-resizer,.fc-rtl .fc-h-event.fc-selected .fc-start-resizer{margin-right:-4px}.fc-day-grid-event{margin:1px 2px 0;padding:0 1px}tr:first-child>td>.fc-day-grid-event{margin-top:2px}.fc-day-grid-event.fc-selected:after{content:"";position:absolute;z-index:1;top:-1px;right:-1px;bottom:-1px;left:-1px;background:#000;opacity:.25}.fc-day-grid-event .fc-content{white-space:nowrap;overflow:hidden}.fc-day-grid-event .fc-time{font-weight:700}.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer,.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer{margin-left:-2px}.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer,.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer{margin-right:-2px}a.fc-more{margin:1px 3px;font-size:.85em;cursor:pointer;text-decoration:none}a.fc-more:hover{text-decoration:underline}.fc-limited{display:none}.fc-day-grid .fc-row{z-index:1}.fc-more-popover{z-index:2;width:220px}.fc-more-popover .fc-event-container{padding:10px}.fc-now-indicator{position:absolute;border:0 solid red}.fc-unselectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}.fc-toolbar{margin-bottom:1em}.fc-toolbar .fc-left{float:left}.fc-toolbar .fc-right{float:right}.fc-toolbar .fc-center{display:inline-block}.fc .fc-toolbar>*>*{float:left;margin-left:.75em}.fc .fc-toolbar>*>:first-child{margin-left:0}.fc-toolbar h2{margin:0}.fc-toolbar button{position:relative}.fc-toolbar .fc-state-hover,.fc-toolbar .ui-state-hover{z-index:2}.fc-toolbar .fc-state-down{z-index:3}.fc-toolbar .fc-state-active,.fc-toolbar .ui-state-active{z-index:4}.fc-toolbar button:focus{z-index:5}.fc-view-container *,.fc-view-container :after,.fc-view-container :before{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.fc-view,.fc-view>table{position:relative;z-index:1}.fc-basicDay-view .fc-content-skeleton,.fc-basicWeek-view .fc-content-skeleton{padding-bottom:1em}.fc-basic-view .fc-body .fc-row{min-height:4em}.fc-row.fc-rigid .fc-content-skeleton{position:absolute;top:0;left:0;right:0}.fc-day-top.fc-other-month{opacity:.3}.fc-basic-view .fc-day-number,.fc-basic-view .fc-week-number{padding:2px}.fc-basic-view th.fc-day-number,.fc-basic-view th.fc-week-number{padding:0 2px}.fc-ltr .fc-basic-view .fc-day-top .fc-day-number{float:right}.fc-rtl .fc-basic-view .fc-day-top .fc-day-number{float:left}.fc-ltr .fc-basic-view .fc-day-top .fc-week-number{float:left;border-radius:0 0 3px}.fc-rtl .fc-basic-view .fc-day-top .fc-week-number{float:right;border-radius:0 0 0 3px}.fc-basic-view .fc-day-top .fc-week-number{min-width:1.5em;text-align:center;background-color:#f2f2f2;color:grey}.fc-basic-view td.fc-week-number>*{display:inline-block;min-width:1.25em}.fc-agenda-view .fc-day-grid{position:relative;z-index:2}.fc-agenda-view .fc-day-grid .fc-row{min-height:3em}.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton{padding-bottom:1em}.fc .fc-axis{vertical-align:middle;padding:0 4px;white-space:nowrap}.fc-ltr .fc-axis{text-align:right}.fc-rtl .fc-axis{text-align:left}.ui-widget td.fc-axis{font-weight:400}.fc-time-grid,.fc-time-grid-container{position:relative;z-index:1}.fc-time-grid{min-height:100%}.fc-time-grid table{border:0 hidden transparent}.fc-time-grid>.fc-bg{z-index:1}.fc-time-grid .fc-slats,.fc-time-grid>hr{position:relative;z-index:2}.fc-time-grid .fc-content-col{position:relative}.fc-time-grid .fc-content-skeleton{position:absolute;z-index:3;top:0;left:0;right:0}.fc-time-grid .fc-business-container{position:relative;z-index:1}.fc-time-grid .fc-bgevent-container{position:relative;z-index:2}.fc-time-grid .fc-highlight-container{z-index:3;position:relative}.fc-time-grid .fc-event-container{position:relative;z-index:4}.fc-time-grid .fc-now-indicator-line{z-index:5}.fc-time-grid .fc-helper-container{position:relative;z-index:6}.fc-time-grid .fc-slats td{height:1.5em;border-bottom:0}.fc-time-grid .fc-slats .fc-minor td{border-top-style:dotted}.fc-time-grid .fc-slats .ui-widget-content{background:0 0}.fc-time-grid .fc-highlight{position:absolute;left:0;right:0}.fc-ltr .fc-time-grid .fc-event-container{margin:0 2.5% 0 2px}.fc-rtl .fc-time-grid .fc-event-container{margin:0 2px 0 2.5%}.fc-time-grid .fc-bgevent,.fc-time-grid .fc-event{position:absolute;z-index:1}.fc-time-grid .fc-bgevent{left:0;right:0}.fc-v-event.fc-not-start{border-top-width:0;padding-top:1px;border-top-left-radius:0;border-top-right-radius:0}.fc-v-event.fc-not-end{border-bottom-width:0;padding-bottom:1px;border-bottom-left-radius:0;border-bottom-right-radius:0}.fc-time-grid-event.fc-selected{overflow:visible}.fc-time-grid-event.fc-selected .fc-bg{display:none}.fc-time-grid-event .fc-content{overflow:hidden}.fc-time-grid-event .fc-time,.fc-time-grid-event .fc-title{padding:0 1px}.fc-time-grid-event .fc-time{font-size:.85em;white-space:nowrap}.fc-time-grid-event.fc-short .fc-content{white-space:nowrap}.fc-time-grid-event.fc-short .fc-time,.fc-time-grid-event.fc-short .fc-title{display:inline-block;vertical-align:top}.fc-time-grid-event.fc-short .fc-time span{display:none}.fc-time-grid-event.fc-short .fc-time:before{content:attr(data-start)}.fc-time-grid-event.fc-short .fc-time:after{content:"\000A0-\000A0"}.fc-time-grid-event.fc-short .fc-title{font-size:.85em;padding:0}.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer{left:0;right:0;bottom:0;height:8px;overflow:hidden;line-height:8px;font-size:11px;font-family:monospace;text-align:center;cursor:s-resize}.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer:after{content:"="}.fc-time-grid-event.fc-selected .fc-resizer{border-radius:5px;border-width:1px;width:8px;height:8px;border-style:solid;border-color:inherit;background:#fff;left:50%;margin-left:-5px;bottom:-5px}.fc-time-grid .fc-now-indicator-line{border-top-width:1px;left:0;right:0}.fc-time-grid .fc-now-indicator-arrow{margin-top:-5px}.fc-ltr .fc-time-grid .fc-now-indicator-arrow{left:0;border-width:5px 0 5px 6px;border-top-color:transparent;border-bottom-color:transparent}.fc-rtl .fc-time-grid .fc-now-indicator-arrow{right:0;border-width:5px 6px 5px 0;border-top-color:transparent;border-bottom-color:transparent}.fc-event-dot{display:inline-block;width:10px;height:10px;border-radius:5px}.fc-rtl .fc-list-view{direction:rtl}.fc-list-view{border-width:1px;border-style:solid}.fc .fc-list-table{table-layout:auto}.fc-list-table td{border-width:1px 0 0;padding:8px 14px}.fc-list-table tr:first-child td{border-top-width:0}.fc-list-heading{border-bottom-width:1px}.fc-list-heading td{font-weight:700}.fc-ltr .fc-list-heading-main{float:left}.fc-ltr .fc-list-heading-alt,.fc-rtl .fc-list-heading-main{float:right}.fc-rtl .fc-list-heading-alt{float:left}.fc-list-item.fc-has-url{cursor:pointer}.fc-list-item:hover td{background-color:#f5f5f5}.fc-list-item-marker,.fc-list-item-time{white-space:nowrap;width:1px}.fc-ltr .fc-list-item-marker{padding-right:0}.fc-rtl .fc-list-item-marker{padding-left:0}.fc-list-item-title a{text-decoration:none;color:inherit}.fc-list-item-title a[href]:hover{text-decoration:underline}.fc-list-empty-wrap2{position:absolute;top:0;left:0;right:0;bottom:0}.fc-list-empty-wrap1{width:100%;height:100%;display:table}.fc-list-empty{display:table-cell;vertical-align:middle;text-align:center}.fc-unthemed .fc-list-empty{background-color:#eee}
\ No newline at end of file
+ */.fc-icon,body .fc{font-size:1em}.fc-button-group,.fc-icon{display:inline-block}.fc-bg,.fc-row .fc-bgevent-skeleton,.fc-row .fc-highlight-skeleton{bottom:0}.fc-icon,.fc-unselectable{-khtml-user-select:none;-webkit-touch-callout:none}.fc{direction:ltr;text-align:left}.fc-rtl{text-align:right}.fc th,.fc-basic-view td.fc-week-number,.fc-icon,.fc-toolbar{text-align:center}.fc-unthemed .fc-content,.fc-unthemed .fc-divider,.fc-unthemed .fc-list-heading td,.fc-unthemed .fc-list-view,.fc-unthemed .fc-popover,.fc-unthemed .fc-row,.fc-unthemed tbody,.fc-unthemed td,.fc-unthemed th,.fc-unthemed thead{border-color:#ddd}.fc-unthemed .fc-popover{background-color:#fff}.fc-unthemed .fc-divider,.fc-unthemed .fc-list-heading td,.fc-unthemed .fc-popover .fc-header{background:#eee}.fc-unthemed .fc-popover .fc-header .fc-close{color:#666}.fc-unthemed td.fc-today{background:#fcf8e3}.fc-highlight{background:#bce8f1;opacity:.3}.fc-bgevent{background:#8fdf82;opacity:.3}.fc-nonbusiness{background:#d7d7d7}.fc-icon{height:1em;line-height:1em;overflow:hidden;font-family:"Courier New",Courier,monospace;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fc-icon:after{position:relative}.fc-icon-left-single-arrow:after{content:"\02039";font-weight:700;font-size:200%;top:-7%}.fc-icon-right-single-arrow:after{content:"\0203A";font-weight:700;font-size:200%;top:-7%}.fc-icon-left-double-arrow:after{content:"\000AB";font-size:160%;top:-7%}.fc-icon-right-double-arrow:after{content:"\000BB";font-size:160%;top:-7%}.fc-icon-left-triangle:after{content:"\25C4";font-size:125%;top:3%}.fc-icon-right-triangle:after{content:"\25BA";font-size:125%;top:3%}.fc-icon-down-triangle:after{content:"\25BC";font-size:125%;top:2%}.fc-icon-x:after{content:"\000D7";font-size:200%;top:6%}.fc button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;height:2.1em;padding:0 .6em;font-size:1em;white-space:nowrap;cursor:pointer}.fc button::-moz-focus-inner{margin:0;padding:0}.fc-state-default{border:1px solid;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#333;text-shadow:0 1px 1px rgba(255,255,255,.75);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.fc-state-default.fc-corner-left{border-top-left-radius:4px;border-bottom-left-radius:4px}.fc-state-default.fc-corner-right{border-top-right-radius:4px;border-bottom-right-radius:4px}.fc button .fc-icon{position:relative;top:-.05em;margin:0 .2em;vertical-align:middle}.fc-state-active,.fc-state-disabled,.fc-state-down,.fc-state-hover{color:#333;background-color:#e6e6e6}.fc-state-hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.fc-state-active,.fc-state-down{background-color:#ccc;background-image:none;box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.fc-state-disabled{cursor:default;background-image:none;opacity:.65;box-shadow:none}.fc-event.fc-draggable,.fc-event[href],.fc-popover .fc-header .fc-close,a[data-goto]{cursor:pointer}.fc .fc-button-group>*{float:left;margin:0 0 0 -1px}.fc .fc-button-group>:first-child{margin-left:0}.fc-popover{position:absolute;box-shadow:0 2px 6px rgba(0,0,0,.15)}.fc-popover .fc-header{padding:2px 4px}.fc-popover .fc-header .fc-title{margin:0 2px}.fc-ltr .fc-popover .fc-header .fc-title,.fc-rtl .fc-popover .fc-header .fc-close{float:left}.fc-ltr .fc-popover .fc-header .fc-close,.fc-rtl .fc-popover .fc-header .fc-title{float:right}.fc-unthemed .fc-popover{border-width:1px;border-style:solid}.fc-unthemed .fc-popover .fc-header .fc-close{font-size:.9em;margin-top:2px}.fc-popover>.ui-widget-header+.ui-widget-content{border-top:0}.fc-divider{border-style:solid;border-width:1px}hr.fc-divider{height:0;margin:0;padding:0 0 2px;border-width:1px 0}.fc-bg table,.fc-row .fc-bgevent-skeleton table,.fc-row .fc-highlight-skeleton table{height:100%}.fc-clear{clear:both}.fc-bg,.fc-bgevent-skeleton,.fc-helper-skeleton,.fc-highlight-skeleton{position:absolute;top:0;left:0;right:0}.fc table{width:100%;box-sizing:border-box;table-layout:fixed;border-collapse:collapse;border-spacing:0;font-size:1em}.fc td,.fc th{border-style:solid;border-width:1px;padding:0;vertical-align:top}.fc td.fc-today{border-style:double}a[data-goto]:hover{text-decoration:underline}.fc .fc-row{border-style:solid;border-width:0}.fc-row table{border-left:0 hidden transparent;border-right:0 hidden transparent;border-bottom:0 hidden transparent}.fc-row:first-child table{border-top:0 hidden transparent}.fc-row{position:relative}.fc-row .fc-bg{z-index:1}.fc-row .fc-bgevent-skeleton td,.fc-row .fc-highlight-skeleton td{border-color:transparent}.fc-row .fc-bgevent-skeleton{z-index:2}.fc-row .fc-highlight-skeleton{z-index:3}.fc-row .fc-content-skeleton{position:relative;z-index:4;padding-bottom:2px}.fc-row .fc-helper-skeleton{z-index:5}.fc-row .fc-content-skeleton td,.fc-row .fc-helper-skeleton td{background:0 0;border-color:transparent;border-bottom:0}.fc-row .fc-content-skeleton tbody td,.fc-row .fc-helper-skeleton tbody td{border-top:0}.fc-scroller{-webkit-overflow-scrolling:touch}.fc-row.fc-rigid,.fc-time-grid-event{overflow:hidden}.fc-scroller>.fc-day-grid,.fc-scroller>.fc-time-grid{position:relative;width:100%}.fc-event{position:relative;display:block;font-size:.85em;line-height:1.3;border-radius:3px;border:1px solid #3a87ad;font-weight:400}.fc-event,.fc-event-dot{background-color:#3a87ad}.fc-event,.fc-event:hover,.ui-widget .fc-event{color:#fff;text-decoration:none}.fc-not-allowed,.fc-not-allowed .fc-event{cursor:not-allowed}.fc-event .fc-bg{z-index:1;background:#fff;opacity:.25}.fc-event .fc-content{position:relative;z-index:2}.fc-event .fc-resizer{position:absolute;z-index:4;display:none}.fc-event.fc-allow-mouse-resize .fc-resizer,.fc-event.fc-selected .fc-resizer{display:block}.fc-event.fc-selected .fc-resizer:before{content:"";position:absolute;z-index:9999;top:50%;left:50%;width:40px;height:40px;margin-left:-20px;margin-top:-20px}.fc-event.fc-selected{z-index:9999!important;box-shadow:0 2px 5px rgba(0,0,0,.2)}.fc-event.fc-selected.fc-dragging{box-shadow:0 2px 7px rgba(0,0,0,.3)}.fc-h-event.fc-selected:before{content:"";position:absolute;z-index:3;top:-10px;bottom:-10px;left:0;right:0}.fc-ltr .fc-h-event.fc-not-start,.fc-rtl .fc-h-event.fc-not-end{margin-left:0;border-left-width:0;padding-left:1px;border-top-left-radius:0;border-bottom-left-radius:0}.fc-ltr .fc-h-event.fc-not-end,.fc-rtl .fc-h-event.fc-not-start{margin-right:0;border-right-width:0;padding-right:1px;border-top-right-radius:0;border-bottom-right-radius:0}.fc-ltr .fc-h-event .fc-start-resizer,.fc-rtl .fc-h-event .fc-end-resizer{cursor:w-resize;left:-1px}.fc-ltr .fc-h-event .fc-end-resizer,.fc-rtl .fc-h-event .fc-start-resizer{cursor:e-resize;right:-1px}.fc-h-event.fc-allow-mouse-resize .fc-resizer{width:7px;top:-1px;bottom:-1px}.fc-h-event.fc-selected .fc-resizer{border-radius:4px;border-width:1px;width:6px;height:6px;border-style:solid;border-color:inherit;background:#fff;top:50%;margin-top:-4px}.fc-ltr .fc-h-event.fc-selected .fc-start-resizer,.fc-rtl .fc-h-event.fc-selected .fc-end-resizer{margin-left:-4px}.fc-ltr .fc-h-event.fc-selected .fc-end-resizer,.fc-rtl .fc-h-event.fc-selected .fc-start-resizer{margin-right:-4px}.fc-day-grid-event{margin:1px 2px 0;padding:0 1px}tr:first-child>td>.fc-day-grid-event{margin-top:2px}.fc-day-grid-event.fc-selected:after{content:"";position:absolute;z-index:1;top:-1px;right:-1px;bottom:-1px;left:-1px;background:#000;opacity:.25}.fc-day-grid-event .fc-content{white-space:nowrap;overflow:hidden}.fc-day-grid-event .fc-time{font-weight:700}.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer,.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer{margin-left:-2px}.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer,.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer{margin-right:-2px}a.fc-more{margin:1px 3px;font-size:.85em;cursor:pointer;text-decoration:none}a.fc-more:hover{text-decoration:underline}.fc-limited{display:none}.fc-day-grid .fc-row{z-index:1}.fc-more-popover{z-index:2;width:220px}.fc-more-popover .fc-event-container{padding:10px}.fc-now-indicator{position:absolute;border:0 solid red}.fc-unselectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}.fc-toolbar.fc-header-toolbar{margin-bottom:1em}.fc-toolbar.fc-footer-toolbar{margin-top:1em}.fc-toolbar .fc-left{float:left}.fc-toolbar .fc-right{float:right}.fc-toolbar .fc-center{display:inline-block}.fc .fc-toolbar>*>*{float:left;margin-left:.75em}.fc .fc-toolbar>*>:first-child{margin-left:0}.fc-toolbar h2{margin:0}.fc-toolbar button{position:relative}.fc-toolbar .fc-state-hover,.fc-toolbar .ui-state-hover{z-index:2}.fc-toolbar .fc-state-down{z-index:3}.fc-toolbar .fc-state-active,.fc-toolbar .ui-state-active{z-index:4}.fc-toolbar button:focus{z-index:5}.fc-view-container *,.fc-view-container :after,.fc-view-container :before{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.fc-view,.fc-view>table{position:relative;z-index:1}.fc-basicDay-view .fc-content-skeleton,.fc-basicWeek-view .fc-content-skeleton{padding-bottom:1em}.fc-basic-view .fc-body .fc-row{min-height:4em}.fc-row.fc-rigid .fc-content-skeleton{position:absolute;top:0;left:0;right:0}.fc-day-top.fc-other-month{opacity:.3}.fc-basic-view .fc-day-number,.fc-basic-view .fc-week-number{padding:2px}.fc-basic-view th.fc-day-number,.fc-basic-view th.fc-week-number{padding:0 2px}.fc-ltr .fc-basic-view .fc-day-top .fc-day-number{float:right}.fc-rtl .fc-basic-view .fc-day-top .fc-day-number{float:left}.fc-ltr .fc-basic-view .fc-day-top .fc-week-number{float:left;border-radius:0 0 3px}.fc-rtl .fc-basic-view .fc-day-top .fc-week-number{float:right;border-radius:0 0 0 3px}.fc-basic-view .fc-day-top .fc-week-number{min-width:1.5em;text-align:center;background-color:#f2f2f2;color:grey}.fc-basic-view td.fc-week-number>*{display:inline-block;min-width:1.25em}.fc-agenda-view .fc-day-grid{position:relative;z-index:2}.fc-agenda-view .fc-day-grid .fc-row{min-height:3em}.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton{padding-bottom:1em}.fc .fc-axis{vertical-align:middle;padding:0 4px;white-space:nowrap}.fc-ltr .fc-axis{text-align:right}.fc-rtl .fc-axis{text-align:left}.ui-widget td.fc-axis{font-weight:400}.fc-time-grid,.fc-time-grid-container{position:relative;z-index:1}.fc-time-grid{min-height:100%}.fc-time-grid table{border:0 hidden transparent}.fc-time-grid>.fc-bg{z-index:1}.fc-time-grid .fc-slats,.fc-time-grid>hr{position:relative;z-index:2}.fc-time-grid .fc-content-col{position:relative}.fc-time-grid .fc-content-skeleton{position:absolute;z-index:3;top:0;left:0;right:0}.fc-time-grid .fc-business-container{position:relative;z-index:1}.fc-time-grid .fc-bgevent-container{position:relative;z-index:2}.fc-time-grid .fc-highlight-container{z-index:3;position:relative}.fc-time-grid .fc-event-container{position:relative;z-index:4}.fc-time-grid .fc-now-indicator-line{z-index:5}.fc-time-grid .fc-helper-container{position:relative;z-index:6}.fc-time-grid .fc-slats td{height:1.5em;border-bottom:0}.fc-time-grid .fc-slats .fc-minor td{border-top-style:dotted}.fc-time-grid .fc-slats .ui-widget-content{background:0 0}.fc-time-grid .fc-highlight{position:absolute;left:0;right:0}.fc-ltr .fc-time-grid .fc-event-container{margin:0 2.5% 0 2px}.fc-rtl .fc-time-grid .fc-event-container{margin:0 2px 0 2.5%}.fc-time-grid .fc-bgevent,.fc-time-grid .fc-event{position:absolute;z-index:1}.fc-time-grid .fc-bgevent{left:0;right:0}.fc-v-event.fc-not-start{border-top-width:0;padding-top:1px;border-top-left-radius:0;border-top-right-radius:0}.fc-v-event.fc-not-end{border-bottom-width:0;padding-bottom:1px;border-bottom-left-radius:0;border-bottom-right-radius:0}.fc-time-grid-event.fc-selected{overflow:visible}.fc-time-grid-event.fc-selected .fc-bg{display:none}.fc-time-grid-event .fc-content{overflow:hidden}.fc-time-grid-event .fc-time,.fc-time-grid-event .fc-title{padding:0 1px}.fc-time-grid-event .fc-time{font-size:.85em;white-space:nowrap}.fc-time-grid-event.fc-short .fc-content{white-space:nowrap}.fc-time-grid-event.fc-short .fc-time,.fc-time-grid-event.fc-short .fc-title{display:inline-block;vertical-align:top}.fc-time-grid-event.fc-short .fc-time span{display:none}.fc-time-grid-event.fc-short .fc-time:before{content:attr(data-start)}.fc-time-grid-event.fc-short .fc-time:after{content:"\000A0-\000A0"}.fc-time-grid-event.fc-short .fc-title{font-size:.85em;padding:0}.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer{left:0;right:0;bottom:0;height:8px;overflow:hidden;line-height:8px;font-size:11px;font-family:monospace;text-align:center;cursor:s-resize}.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer:after{content:"="}.fc-time-grid-event.fc-selected .fc-resizer{border-radius:5px;border-width:1px;width:8px;height:8px;border-style:solid;border-color:inherit;background:#fff;left:50%;margin-left:-5px;bottom:-5px}.fc-time-grid .fc-now-indicator-line{border-top-width:1px;left:0;right:0}.fc-time-grid .fc-now-indicator-arrow{margin-top:-5px}.fc-ltr .fc-time-grid .fc-now-indicator-arrow{left:0;border-width:5px 0 5px 6px;border-top-color:transparent;border-bottom-color:transparent}.fc-rtl .fc-time-grid .fc-now-indicator-arrow{right:0;border-width:5px 6px 5px 0;border-top-color:transparent;border-bottom-color:transparent}.fc-event-dot{display:inline-block;width:10px;height:10px;border-radius:5px}.fc-rtl .fc-list-view{direction:rtl}.fc-list-view{border-width:1px;border-style:solid}.fc .fc-list-table{table-layout:auto}.fc-list-table td{border-width:1px 0 0;padding:8px 14px}.fc-list-table tr:first-child td{border-top-width:0}.fc-list-heading{border-bottom-width:1px}.fc-list-heading td{font-weight:700}.fc-ltr .fc-list-heading-main{float:left}.fc-ltr .fc-list-heading-alt,.fc-rtl .fc-list-heading-main{float:right}.fc-rtl .fc-list-heading-alt{float:left}.fc-list-item.fc-has-url{cursor:pointer}.fc-list-item:hover td{background-color:#f5f5f5}.fc-list-item-marker,.fc-list-item-time{white-space:nowrap;width:1px}.fc-ltr .fc-list-item-marker{padding-right:0}.fc-rtl .fc-list-item-marker{padding-left:0}.fc-list-item-title a{text-decoration:none;color:inherit}.fc-list-item-title a[href]:hover{text-decoration:underline}.fc-list-empty-wrap2{position:absolute;top:0;left:0;right:0;bottom:0}.fc-list-empty-wrap1{width:100%;height:100%;display:table}.fc-list-empty{display:table-cell;vertical-align:middle;text-align:center}.fc-unthemed .fc-list-empty{background-color:#eee}
\ No newline at end of file
diff --git a/library/fullcalendar/fullcalendar.min.js b/library/fullcalendar/fullcalendar.min.js
index bc8b51c8a..8484b7c45 100644
--- a/library/fullcalendar/fullcalendar.min.js
+++ b/library/fullcalendar/fullcalendar.min.js
@@ -1,9 +1,10 @@
/*!
- * FullCalendar v3.0.1
+ * FullCalendar v3.1.0
* Docs & License: http://fullcalendar.io/
* (c) 2016 Adam Shaw
*/
-!function(t){"function"==typeof define&&define.amd?define(["jquery","moment"],t):"object"==typeof exports?module.exports=t(require("jquery"),require("moment")):t(jQuery,moment)}(function(t,e){function n(t){return q(t,qt)}function i(t,e){e.left&&t.css({"border-left-width":1,"margin-left":e.left-1}),e.right&&t.css({"border-right-width":1,"margin-right":e.right-1})}function r(t){t.css({"margin-left":"","margin-right":"","border-left-width":"","border-right-width":""})}function s(){t("body").addClass("fc-not-allowed")}function o(){t("body").removeClass("fc-not-allowed")}function l(e,n,i){var r=Math.floor(n/e.length),s=Math.floor(n-r*(e.length-1)),o=[],l=[],u=[],d=0;a(e),e.each(function(n,i){var a=n===e.length-1?s:r,c=t(i).outerHeight(!0);c *").each(function(e,i){var r=t(i).outerWidth();r>n&&(n=r)}),n++,e.width(n),n}function d(t,e){var n,i=t.add(e);return i.css({position:"relative",left:-1}),n=t.outerHeight()-e.outerHeight(),i.css({position:"",left:""}),n}function c(e){var n=e.css("position"),i=e.parents().filter(function(){var e=t(this);return/(auto|scroll)/.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==n&&i.length?i:t(e[0].ownerDocument||document)}function h(t,e){var n=t.offset(),i=n.left-(e?e.left:0),r=n.top-(e?e.top:0);return{left:i,right:i+t.outerWidth(),top:r,bottom:r+t.outerHeight()}}function f(t,e){var n=t.offset(),i=p(t),r=n.left+y(t,"border-left-width")+i.left-(e?e.left:0),s=n.top+y(t,"border-top-width")+i.top-(e?e.top:0);return{left:r,right:r+t[0].clientWidth,top:s,bottom:s+t[0].clientHeight}}function g(t,e){var n=t.offset(),i=n.left+y(t,"border-left-width")+y(t,"padding-left")-(e?e.left:0),r=n.top+y(t,"border-top-width")+y(t,"padding-top")-(e?e.top:0);return{left:i,right:i+t.width(),top:r,bottom:r+t.height()}}function p(t){var e=t.innerWidth()-t[0].clientWidth,n={left:0,right:0,top:0,bottom:t.innerHeight()-t[0].clientHeight};return v()&&"rtl"==t.css("direction")?n.left=e:n.right=e,n}function v(){return null===Zt&&(Zt=m()),Zt}function m(){var e=t("").css({position:"absolute",top:-1e3,left:0,border:0,padding:0,overflow:"scroll",direction:"rtl"}).appendTo("body"),n=e.children(),i=n.offset().left>e.offset().left;return e.remove(),i}function y(t,e){return parseFloat(t.css(e))||0}function S(t){return 1==t.which&&!t.ctrlKey}function w(t){if(void 0!==t.pageX)return t.pageX;var e=t.originalEvent.touches;return e?e[0].pageX:void 0}function E(t){if(void 0!==t.pageY)return t.pageY;var e=t.originalEvent.touches;return e?e[0].pageY:void 0}function D(t){return/^touch/.test(t.type)}function b(t){t.addClass("fc-unselectable").on("selectstart",C)}function C(t){t.preventDefault()}function H(t){return!!window.addEventListener&&(window.addEventListener("scroll",t,!0),!0)}function T(t){return!!window.removeEventListener&&(window.removeEventListener("scroll",t,!0),!0)}function x(t,e){var n={left:Math.max(t.left,e.left),right:Math.min(t.right,e.right),top:Math.max(t.top,e.top),bottom:Math.min(t.bottom,e.bottom)};return n.lefta&&o=a?(n=o.clone(),r=!0):(n=a.clone(),r=!1),l<=u?(i=l.clone(),s=!0):(i=u.clone(),s=!1),{start:n,end:i,isStart:r,isEnd:s}}function N(t,n){return e.duration({days:t.clone().stripTime().diff(n.clone().stripTime(),"days"),ms:t.time()-n.time()})}function G(t,n){return e.duration({days:t.clone().stripTime().diff(n.clone().stripTime(),"days")})}function A(t,n,i){return e.duration(Math.round(t.diff(n,i,!0)),i)}function O(t,e){var n,i,r;for(n=0;n=1&&ot(r)));n++);return i}function V(t,n,i){return null!=i?i.diff(n,t,!0):e.isDuration(n)?n.as(t):n.end.diff(n.start,t,!0)}function P(t,e,n){var i;return W(n)?(e-t)/n:(i=n.asMonths(),Math.abs(i)>=1&&ot(i)?e.diff(t,"months",!0)/i:e.diff(t,"days",!0)/n.asDays())}function _(t,e){var n,i;return W(t)||W(e)?t/e:(n=t.asMonths(),i=e.asMonths(),Math.abs(n)>=1&&ot(n)&&Math.abs(i)>=1&&ot(i)?n/i:t.asDays()/e.asDays())}function Y(t,n){var i;return W(t)?e.duration(t*n):(i=t.asMonths(),Math.abs(i)>=1&&ot(i)?e.duration({months:i*n}):e.duration({days:t.asDays()*n}))}function W(t){return Boolean(t.hours()||t.minutes()||t.seconds()||t.milliseconds())}function j(t){return"[object Date]"===Object.prototype.toString.call(t)||t instanceof Date}function U(t){return/^\d+\:\d+(?:\:\d+\.?(?:\d{3})?)?$/.test(t)}function q(t,e){var n,i,r,s,o,l,a={};if(e)for(n=0;n=0;s--)if(o=t[s][i],"object"==typeof o)r.unshift(o);else if(void 0!==o){a[i]=o;break}r.length&&(a[i]=q(r))}for(n=t.length-1;n>=0;n--){l=t[n];for(i in l)i in a||(a[i]=l[i])}return a}function Z(t){var e=function(){};return e.prototype=t,new e}function $(t,e){for(var n in t)X(t,n)&&(e[n]=t[n])}function X(t,e){return Kt.call(t,e)}function K(e){return/undefined|null|boolean|number|string/.test(t.type(e))}function Q(e,n,i){if(t.isFunction(e)&&(e=[e]),e){var r,s;for(r=0;r/g,">").replace(/'/g,"'").replace(/"/g,""").replace(/\n/g,"
")}function et(t){return t.replace(/&.*?;/g,"")}function nt(e){var n=[];return t.each(e,function(t,e){null!=e&&n.push(t+":"+e)}),n.join(";")}function it(e){var n=[];return t.each(e,function(t,e){null!=e&&n.push(t+'="'+tt(e)+'"')}),n.join(" ")}function rt(t){return t.charAt(0).toUpperCase()+t.slice(1)}function st(t,e){return t-e}function ot(t){return t%1===0}function lt(t,e){var n=t[e];return function(){return n.apply(t,arguments)}}function at(t,e,n){var i,r,s,o,l,a=function(){var u=+new Date-o;uo&&(s=mt(t,e,u,d,n[l]),s!==!1);l--)h=s+h;for(a=o;a<=l;a++)f+=gt(t,n[a]),g+=gt(e,n[a]);return(f||g)&&(p=r?g+i+f:f+i+g),c+p+h}function mt(t,e,n,i,r){var s,o;return"string"==typeof r?r:!!((s=r.token)&&(o=re[s.charAt(0)],o&&n.isSame(i,o)))&&ct(t,s)}function yt(t){return t in se?se[t]:se[t]=St(t)}function St(t){for(var e,n=[],i=/\[([^\]]*)\]|\(([^\)]*)\)|(LTS|LT|(\w)\4*o?)|([^\w\[\(]+)/g;e=i.exec(t);)e[1]?n.push(e[1]):e[2]?n.push({maybe:St(e[2])}):e[3]?n.push({token:e[3]}):e[5]&&n.push(e[5]);return n}function wt(){}function Et(t,e){var n;return X(e,"constructor")&&(n=e.constructor),"function"!=typeof n&&(n=e.constructor=function(){t.apply(this,arguments)}),n.prototype=Z(t.prototype),$(e,n.prototype),$(t,n),n}function Dt(t,e){$(e,t.prototype)}function bt(t,e){return!t&&!e||!(!t||!e)&&(t.component===e.component&&Ct(t,e)&&Ct(e,t))}function Ct(t,e){for(var n in t)if(!/^(component|left|right|top|bottom)$/.test(n)&&t[n]!==e[n])return!1;return!0}function Ht(t){return{start:t.start.clone(),end:t.end?t.end.clone():null,allDay:t.allDay}}function Tt(t){var e=Rt(t);return"background"===e||"inverse-background"===e}function xt(t){return"inverse-background"===Rt(t)}function Rt(t){return J((t.source||{}).rendering,t.rendering)}function It(t){var e,n,i={};for(e=0;e=t.leftCol)return!0;return!1}function Bt(t,e){return t.leftCol-e.leftCol}function zt(t){var e,n,i,r=[];for(e=0;ee.top&&t.top").prependTo(n),q=j.header=new _t(j),l(),d(j.options.defaultView),j.options.handleWindowResize&&(J=at(m,j.options.windowResizeDelay),t(window).resize(J))}function l(){q.render(),q.el&&n.prepend(q.el)}function a(){K&&K.removeElement(),q.removeElement(),$.remove(),n.removeClass("fc fc-ltr fc-rtl fc-unthemed ui-widget"),n.off(".fc"),J&&t(window).unbind("resize",J)}function u(){return n.is(":visible")}function d(e,n){lt++,K&&e&&K.type!==e&&(A(),c()),!K&&e&&(K=j.view=ot[e]||(ot[e]=j.instantiateView(e)),K.setElement(t("").appendTo($)),q.activateButton(e)),K&&(tt=K.massageCurrentDate(tt),K.displaying&&tt>=K.intervalStart&&tt=K.intervalStart&&t"),h.append(r("left")).append(r("right")).append(r("center")).append('')):i()}function i(){h&&(h.remove(),h=c.el=null)}function r(n){var i=t(''),r=e.options,s=r.header[n];return s&&t.each(s.split(" "),function(n){var s,o=t(),l=!0;t.each(this.split(","),function(n,i){var s,a,u,d,c,h,p,v,m,y;"title"==i?(o=o.add(t("
")),l=!1):((s=(r.customButtons||{})[i])?(u=function(t){s.click&&s.click.call(y[0],t)},d="",c=s.text):(a=e.getViewSpec(i))?(u=function(){e.changeView(i)},g.push(i),d=a.buttonTextOverride,c=a.buttonTextDefault):e[i]&&(u=function(){e[i]()},d=(e.overrides.buttonText||{})[i],c=r.buttonText[i]),u&&(h=s?s.themeIcon:r.themeButtonIcons[i],p=s?s.icon:r.buttonIcons[i],v=d?tt(d):h&&r.theme?"":p&&!r.theme?"":tt(c),m=["fc-"+i+"-button",f+"-button",f+"-state-default"],y=t('").click(function(t){y.hasClass(f+"-state-disabled")||(u(t),(y.hasClass(f+"-state-active")||y.hasClass(f+"-state-disabled"))&&y.removeClass(f+"-state-hover"))}).mousedown(function(){y.not("."+f+"-state-active").not("."+f+"-state-disabled").addClass(f+"-state-down")}).mouseup(function(){y.removeClass(f+"-state-down")}).hover(function(){y.not("."+f+"-state-active").not("."+f+"-state-disabled").addClass(f+"-state-hover")},function(){y.removeClass(f+"-state-hover").removeClass(f+"-state-down")}),o=o.add(y)))}),l&&o.first().addClass(f+"-corner-left").end().last().addClass(f+"-corner-right").end(),o.length>1?(s=t(""),l&&s.addClass("fc-button-group"),s.append(o),i.append(s)):i.append(o)}),i}function s(t){h&&h.find("h2").text(t)}function o(t){h&&h.find(".fc-"+t+"-button").addClass(f+"-state-active")}function l(t){h&&h.find(".fc-"+t+"-button").removeClass(f+"-state-active")}function a(t){h&&h.find(".fc-"+t+"-button").prop("disabled",!0).addClass(f+"-state-disabled")}function u(t){h&&h.find(".fc-"+t+"-button").prop("disabled",!1).removeClass(f+"-state-disabled")}function d(){return g}var c=this;c.render=n,c.removeElement=i,c.updateTitle=s,c.activateButton=o,c.deactivateButton=l,c.disableButton=a,c.enableButton=u,c.getViewsWithButtons=d,c.el=null;var h,f,g=[]}function Yt(){function n(t,e){return!O||tV}function i(t,e){O=t,V=e,r(Y,"reset")}function r(t,e){var n,i;for("reset"===e?j=[]:"add"!==e&&(j=w(j,t)),n=0;nr.value)&&(r=i));return r?r.unit:null},jt.Class=wt,wt.extend=function(){var t,e,n=arguments.length;for(t=0;t').addClass(n.className||"").css({top:0,left:0}).append(n.content).appendTo(n.parentEl),this.el.on("click",".fc-close",function(){e.hide()}),n.autoHide&&this.listenTo(t(document),"mousedown",this.documentMousedown)},documentMousedown:function(e){this.el&&!t(e.target).closest(this.el).length&&this.hide()},removeElement:function(){this.hide(),this.el&&(this.el.remove(),this.el=null),this.stopListeningTo(t(document),"mousedown")},position:function(){var e,n,i,r,s,o=this.options,l=this.el.offsetParent().offset(),a=this.el.outerWidth(),u=this.el.outerHeight(),d=t(window),h=c(this.el);r=o.top||0,s=void 0!==o.left?o.left:void 0!==o.right?o.right-a:0,h.is(window)||h.is(document)?(h=d,e=0,n=0):(i=h.offset(),e=i.top,n=i.left),e+=d.scrollTop(),n+=d.scrollLeft(),o.viewportConstrain!==!1&&(r=Math.min(r,e+h.outerHeight()-u-this.margin),r=Math.max(r,e+this.margin),s=Math.min(s,n+h.outerWidth()-a-this.margin),s=Math.max(s,n+this.margin)),this.el.css({top:r-l.top,left:s-l.left})},trigger:function(t){this.options[t]&&this.options[t].apply(this,Array.prototype.slice.call(arguments,1))}}),ce=jt.CoordCache=wt.extend({els:null,forcedOffsetParentEl:null,origin:null,boundingRect:null,isHorizontal:!1,isVertical:!1,lefts:null,rights:null,tops:null,bottoms:null,constructor:function(e){this.els=t(e.els),this.isHorizontal=e.isHorizontal,this.isVertical=e.isVertical,this.forcedOffsetParentEl=e.offsetParent?t(e.offsetParent):null},build:function(){var t=this.forcedOffsetParentEl||this.els.eq(0).offsetParent();this.origin=t.offset(),this.boundingRect=this.queryBoundingRect(),this.isHorizontal&&this.buildElHorizontals(),this.isVertical&&this.buildElVerticals()},clear:function(){this.origin=null,this.boundingRect=null,this.lefts=null,this.rights=null,this.tops=null,this.bottoms=null},ensureBuilt:function(){this.origin||this.build()},buildElHorizontals:function(){var e=[],n=[];this.els.each(function(i,r){var s=t(r),o=s.offset().left,l=s.outerWidth();e.push(o),n.push(o+l)}),this.lefts=e,this.rights=n},buildElVerticals:function(){var e=[],n=[];this.els.each(function(i,r){var s=t(r),o=s.offset().top,l=s.outerHeight();e.push(o),n.push(o+l)}),this.tops=e,this.bottoms=n},getHorizontalIndex:function(t){this.ensureBuilt();var e,n=this.lefts,i=this.rights,r=n.length;for(e=0;e=n[e]&&t=n[e]&&t=this.boundingRect.left&&t=this.boundingRect.top&&t=r*r&&this.handleDistanceSurpassed(t)),this.isDragging&&this.handleDrag(n,i,t)},handleDrag:function(t,e,n){this.trigger("drag",t,e,n),this.updateAutoScroll(n)},endDrag:function(t){this.isDragging&&(this.isDragging=!1,this.handleDragEnd(t))},handleDragEnd:function(t){this.trigger("dragEnd",t)},startDelay:function(t){var e=this;this.delay?this.delayTimeoutId=setTimeout(function(){e.handleDelayEnd(t)},this.delay):this.handleDelayEnd(t)},handleDelayEnd:function(t){this.isDelayEnded=!0,this.isDistanceSurpassed&&this.startDrag(t)},handleDistanceSurpassed:function(t){this.isDistanceSurpassed=!0,this.isDelayEnded&&this.startDrag(t)},handleTouchMove:function(t){this.isDragging&&t.preventDefault(),this.handleMove(t)},handleMouseMove:function(t){this.handleMove(t)},handleTouchScroll:function(t){this.isDragging||this.endInteraction(t,!0)},trigger:function(t){this.options[t]&&this.options[t].apply(this,Array.prototype.slice.call(arguments,1)),this["_"+t]&&this["_"+t].apply(this,Array.prototype.slice.call(arguments,1))}});he.mixin({isAutoScroll:!1,scrollBounds:null,scrollTopVel:null,scrollLeftVel:null,scrollIntervalId:null,scrollSensitivity:30,scrollSpeed:200,scrollIntervalMs:50,initAutoScroll:function(){var t=this.scrollEl;this.isAutoScroll=this.options.scroll&&t&&!t.is(window)&&!t.is(document),this.isAutoScroll&&this.listenTo(t,"scroll",at(this.handleDebouncedScroll,100))},destroyAutoScroll:function(){this.endAutoScroll(),this.isAutoScroll&&this.stopListeningTo(this.scrollEl,"scroll")},computeScrollBounds:function(){this.isAutoScroll&&(this.scrollBounds=h(this.scrollEl))},updateAutoScroll:function(t){var e,n,i,r,s=this.scrollSensitivity,o=this.scrollBounds,l=0,a=0;o&&(e=(s-(E(t)-o.top))/s,n=(s-(o.bottom-E(t)))/s,i=(s-(w(t)-o.left))/s,r=(s-(o.right-w(t)))/s,e>=0&&e<=1?l=e*this.scrollSpeed*-1:n>=0&&n<=1&&(l=n*this.scrollSpeed),i>=0&&i<=1?a=i*this.scrollSpeed*-1:r>=0&&r<=1&&(a=r*this.scrollSpeed)),this.setScrollVel(l,a)},setScrollVel:function(t,e){this.scrollTopVel=t,this.scrollLeftVel=e,this.constrainScrollVel(),!this.scrollTopVel&&!this.scrollLeftVel||this.scrollIntervalId||(this.scrollIntervalId=setInterval(lt(this,"scrollIntervalFunc"),this.scrollIntervalMs))},constrainScrollVel:function(){var t=this.scrollEl;this.scrollTopVel<0?t.scrollTop()<=0&&(this.scrollTopVel=0):this.scrollTopVel>0&&t.scrollTop()+t[0].clientHeight>=t[0].scrollHeight&&(this.scrollTopVel=0),this.scrollLeftVel<0?t.scrollLeft()<=0&&(this.scrollLeftVel=0):this.scrollLeftVel>0&&t.scrollLeft()+t[0].clientWidth>=t[0].scrollWidth&&(this.scrollLeftVel=0)},scrollIntervalFunc:function(){var t=this.scrollEl,e=this.scrollIntervalMs/1e3;this.scrollTopVel&&t.scrollTop(t.scrollTop()+this.scrollTopVel*e),this.scrollLeftVel&&t.scrollLeft(t.scrollLeft()+this.scrollLeftVel*e),this.constrainScrollVel(),this.scrollTopVel||this.scrollLeftVel||this.endAutoScroll()},endAutoScroll:function(){this.scrollIntervalId&&(clearInterval(this.scrollIntervalId),this.scrollIntervalId=null,this.handleScrollEnd())},handleDebouncedScroll:function(){this.scrollIntervalId||this.handleScrollEnd()},handleScrollEnd:function(){}});var fe=he.extend({component:null,origHit:null,hit:null,coordAdjust:null,constructor:function(t,e){he.call(this,e),this.component=t},handleInteractionStart:function(t){var e,n,i,r=this.subjectEl;this.computeCoords(),t?(n={left:w(t),top:E(t)},i=n,r&&(e=h(r),i=R(i,e)),this.origHit=this.queryHit(i.left,i.top),r&&this.options.subjectCenter&&(this.origHit&&(e=x(this.origHit,e)||e),i=I(e)),this.coordAdjust=k(i,n)):(this.origHit=null,this.coordAdjust=null),he.prototype.handleInteractionStart.apply(this,arguments)},computeCoords:function(){this.component.prepareHits(),this.computeScrollBounds()},handleDragStart:function(t){var e;he.prototype.handleDragStart.apply(this,arguments),e=this.queryHit(w(t),E(t)),e&&this.handleHitOver(e)},handleDrag:function(t,e,n){var i;he.prototype.handleDrag.apply(this,arguments),i=this.queryHit(w(n),E(n)),bt(i,this.hit)||(this.hit&&this.handleHitOut(),i&&this.handleHitOver(i))},handleDragEnd:function(){this.handleHitDone(),he.prototype.handleDragEnd.apply(this,arguments)},handleHitOver:function(t){var e=bt(t,this.origHit);this.hit=t,this.trigger("hitOver",this.hit,e,this.origHit)},handleHitOut:function(){this.hit&&(this.trigger("hitOut",this.hit),this.handleHitDone(),this.hit=null)},handleHitDone:function(){this.hit&&this.trigger("hitDone",this.hit)},handleInteractionEnd:function(){he.prototype.handleInteractionEnd.apply(this,arguments),this.origHit=null,this.hit=null,this.component.releaseHits()},handleScrollEnd:function(){he.prototype.handleScrollEnd.apply(this,arguments),this.computeCoords()},queryHit:function(t,e){return this.coordAdjust&&(t+=this.coordAdjust.left,e+=this.coordAdjust.top),this.component.queryHit(t,e)}}),ge=wt.extend(ae,{options:null,sourceEl:null,el:null,parentEl:null,top0:null,left0:null,y0:null,x0:null,topDelta:null,leftDelta:null,isFollowing:!1,isHidden:!1,isAnimating:!1,constructor:function(e,n){this.options=n=n||{},this.sourceEl=e,this.parentEl=n.parentEl?t(n.parentEl):e.parent()},start:function(e){this.isFollowing||(this.isFollowing=!0,this.y0=E(e),this.x0=w(e),this.topDelta=0,this.leftDelta=0,this.isHidden||this.updatePosition(),D(e)?this.listenTo(t(document),"touchmove",this.handleMove):this.listenTo(t(document),"mousemove",this.handleMove))},stop:function(e,n){function i(){r.isAnimating=!1,r.removeElement(),r.top0=r.left0=null,n&&n()}var r=this,s=this.options.revertDuration;this.isFollowing&&!this.isAnimating&&(this.isFollowing=!1,this.stopListeningTo(t(document)),e&&s&&!this.isHidden?(this.isAnimating=!0,this.el.animate({top:this.top0,left:this.left0},{duration:s,complete:i})):i())},getEl:function(){var t=this.el;return t||(t=this.el=this.sourceEl.clone().addClass(this.options.additionalClass||"").css({position:"absolute",visibility:"",display:this.isHidden?"none":"",margin:0,right:"auto",bottom:"auto",width:this.sourceEl.width(),height:this.sourceEl.height(),opacity:this.options.opacity||"",zIndex:this.options.zIndex}),t.addClass("fc-unselectable"),t.appendTo(this.parentEl)),t},removeElement:function(){this.el&&(this.el.remove(),this.el=null)},updatePosition:function(){var t,e;this.getEl(),null===this.top0&&(t=this.sourceEl.offset(),e=this.el.offsetParent().offset(),this.top0=t.top-e.top,this.left0=t.left-e.left),this.el.css({top:this.top0+this.topDelta,left:this.left0+this.leftDelta})},handleMove:function(t){this.topDelta=E(t)-this.y0,this.leftDelta=w(t)-this.x0,this.isHidden||this.updatePosition()},hide:function(){this.isHidden||(this.isHidden=!0,this.el&&this.el.hide())},show:function(){this.isHidden&&(this.isHidden=!1,this.updatePosition(),this.getEl().show())}}),pe=jt.Grid=wt.extend(ae,ue,{hasDayInteractions:!0,view:null,isRTL:null,start:null,end:null,el:null,elsByFill:null,eventTimeFormat:null,displayEventTime:null,displayEventEnd:null,minResizeDuration:null,largeUnit:null,dayDragListener:null,segDragListener:null,segResizeListener:null,externalDragListener:null,constructor:function(t){this.view=t,this.isRTL=t.opt("isRTL"),this.elsByFill={},this.dayDragListener=this.buildDayDragListener(),this.initMouseIgnoring()},computeEventTimeFormat:function(){return this.view.opt("smallTimeFormat")},computeDisplayEventTime:function(){return!0},computeDisplayEventEnd:function(){return!0},setRange:function(t){this.start=t.start.clone(),this.end=t.end.clone(),this.rangeUpdated(),this.processRangeOptions()},rangeUpdated:function(){},processRangeOptions:function(){var t,e,n=this.view;this.eventTimeFormat=n.opt("eventTimeFormat")||n.opt("timeFormat")||this.computeEventTimeFormat(),t=n.opt("displayEventTime"),null==t&&(t=this.computeDisplayEventTime()),e=n.opt("displayEventEnd"),null==e&&(e=this.computeDisplayEventEnd()),this.displayEventTime=t,this.displayEventEnd=e},spanToSegs:function(t){},diffDates:function(t,e){return this.largeUnit?A(t,e,this.largeUnit):N(t,e)},prepareHits:function(){},releaseHits:function(){},queryHit:function(t,e){},getHitSpan:function(t){},getHitEl:function(t){},setElement:function(t){this.el=t,this.hasDayInteractions&&(b(t),this.bindDayHandler("touchstart",this.dayTouchStart),this.bindDayHandler("mousedown",this.dayMousedown)),this.bindSegHandlers(),this.bindGlobalHandlers()},bindDayHandler:function(e,n){var i=this;this.el.on(e,function(e){if(!t(e.target).is(i.segSelector+","+i.segSelector+" *,.fc-more,a[data-goto]"))return n.call(i,e)})},removeElement:function(){this.unbindGlobalHandlers(),this.clearDragListeners(),this.el.remove()},renderSkeleton:function(){},renderDates:function(){},unrenderDates:function(){},bindGlobalHandlers:function(){this.listenTo(t(document),{dragstart:this.externalDragStart,sortstart:this.externalDragStart})},unbindGlobalHandlers:function(){this.stopListeningTo(t(document))},dayMousedown:function(t){this.isIgnoringMouse||this.dayDragListener.startInteraction(t,{})},dayTouchStart:function(t){var e=this.view;(e.isSelected||e.selectedEvent)&&this.tempIgnoreMouse(),this.dayDragListener.startInteraction(t,{delay:this.view.opt("longPressDelay")})},buildDayDragListener:function(){var t,e,n=this,i=this.view,r=i.opt("selectable"),l=new fe(this,{scroll:i.opt("dragScroll"),interactionStart:function(){t=l.origHit,e=null},dragStart:function(){i.unselect()},hitOver:function(i,o,l){l&&(o||(t=null),r&&(e=n.computeSelection(n.getHitSpan(l),n.getHitSpan(i)),e?n.renderSelection(e):e===!1&&s()))},hitOut:function(){t=null,e=null,n.unrenderSelection()},hitDone:function(){o()},interactionEnd:function(r,s){s||(t&&!n.isIgnoringMouse&&i.triggerDayClick(n.getHitSpan(t),n.getHitEl(t),r),e&&i.reportSelection(e,r))}});return l},clearDragListeners:function(){this.dayDragListener.endInteraction(),this.segDragListener&&this.segDragListener.endInteraction(),this.segResizeListener&&this.segResizeListener.endInteraction(),this.externalDragListener&&this.externalDragListener.endInteraction()},renderEventLocationHelper:function(t,e){var n=this.fabricateHelperEvent(t,e);return this.renderHelper(n,e)},fabricateHelperEvent:function(t,e){var n=e?Z(e.event):{};return n.start=t.start.clone(),n.end=t.end?t.end.clone():null,n.allDay=null,this.view.calendar.normalizeEventDates(n),n.className=(n.className||[]).concat("fc-helper"),e||(n.editable=!1),n},renderHelper:function(t,e){},unrenderHelper:function(){},renderSelection:function(t){this.renderHighlight(t)},unrenderSelection:function(){this.unrenderHighlight()},computeSelection:function(t,e){var n=this.computeSelectionSpan(t,e);return!(n&&!this.view.calendar.isSelectionSpanAllowed(n))&&n},computeSelectionSpan:function(t,e){var n=[t.start,t.end,e.start,e.end];return n.sort(st),{start:n[0].clone(),end:n[3].clone()}},renderHighlight:function(t){this.renderFill("highlight",this.spanToSegs(t))},unrenderHighlight:function(){this.unrenderFill("highlight")},highlightSegClasses:function(){return["fc-highlight"]},renderBusinessHours:function(){},unrenderBusinessHours:function(){},getNowIndicatorUnit:function(){},renderNowIndicator:function(t){},unrenderNowIndicator:function(){},renderFill:function(t,e){},unrenderFill:function(t){var e=this.elsByFill[t];e&&(e.remove(),delete this.elsByFill[t])},renderFillSegEls:function(e,n){var i,r=this,s=this[e+"SegEl"],o="",l=[];if(n.length){for(i=0;i"},getDayClasses:function(t){var e=this.view,n=e.calendar.getNow(),i=["fc-"+$t[t.day()]];return 1==e.intervalDuration.as("months")&&t.month()!=e.intervalStart.month()&&i.push("fc-other-month"),t.isSame(n,"day")?i.push("fc-today",e.highlightStateClass):t *",mousedOverSeg:null,isDraggingSeg:!1,isResizingSeg:!1,isDraggingExternal:!1,segs:null,renderEvents:function(t){var e,n=[],i=[];for(e=0;el&&o.push({start:l,end:n.start}),l=n.end;return l=e.length?e[e.length-1]+1:e[n]},computeColHeadFormat:function(){return this.rowCnt>1||this.colCnt>10?"ddd":this.colCnt>1?this.view.opt("dayOfMonthFormat"):"dddd"},sliceRangeByRow:function(t){var e,n,i,r,s,o=this.daysPerRow,l=this.view.computeDayRange(t),a=this.getDateDayIndex(l.start),u=this.getDateDayIndex(l.end.clone().subtract(1,"days")),d=[];for(e=0;e"},updateSegVerticals:function(t){this.computeSegVerticals(t),this.assignSegVerticals(t)},computeSegVerticals:function(t){var e,n;for(e=0;e1?"ll":"LL"},formatRange:function(t,e,n){var i=t.end;return i.hasTime()||(i=i.clone().subtract(1)),pt(t.start,i,e,n,this.opt("isRTL"))},getAllDayHtml:function(){return this.opt("allDayHtml")||tt(this.opt("allDayText"))},buildGotoAnchorHtml:function(e,n,i){var r,s,o,l;return t.isPlainObject(e)?(r=e.date,s=e.type,o=e.forceOff):r=e,r=jt.moment(r),l={date:r.format("YYYY-MM-DD"),type:s||"day"},"string"==typeof n&&(i=n,n=null),n=n?" "+it(n):"",i=i||"",!o&&this.opt("navLinks")?"'+i+"":""+i+""},setElement:function(t){this.el=t,this.bindGlobalHandlers()},removeElement:function(){this.clear(),this.isSkeletonRendered&&(this.unrenderSkeleton(),this.isSkeletonRendered=!1),this.unbindGlobalHandlers(),this.el.remove()},display:function(t,e){var n=this,i=null;return null!=e&&this.displaying&&(i=this.queryScroll()),this.calendar.freezeContentHeight(),ut(this.clear(),function(){return n.displaying=ut(n.displayView(t),function(){null!=e?n.setScroll(e):n.forceScroll(n.computeInitialScroll(i)),n.calendar.unfreezeContentHeight(),n.triggerRender()})})},clear:function(){var e=this,n=this.displaying;return n?ut(n,function(){return e.displaying=null,e.clearEvents(),e.clearView()}):t.when()},displayView:function(t){this.isSkeletonRendered||(this.renderSkeleton(),this.isSkeletonRendered=!0),t&&this.setDate(t),this.render&&this.render(),this.renderDates(),this.updateSize(),this.renderBusinessHours(),this.startNowIndicator()},clearView:function(){this.unselect(),this.stopNowIndicator(),this.triggerUnrender(),this.unrenderBusinessHours(),this.unrenderDates(),this.destroy&&this.destroy()},renderSkeleton:function(){},unrenderSkeleton:function(){},renderDates:function(){},unrenderDates:function(){},triggerRender:function(){this.trigger("viewRender",this,this,this.el)},triggerUnrender:function(){this.trigger("viewDestroy",this,this,this.el)},bindGlobalHandlers:function(){this.listenTo(t(document),"mousedown",this.handleDocumentMousedown),this.listenTo(t(document),"touchstart",this.processUnselect)},unbindGlobalHandlers:function(){this.stopListeningTo(t(document))},initThemingProps:function(){var t=this.opt("theme")?"ui":"fc";this.widgetHeaderClass=t+"-widget-header",this.widgetContentClass=t+"-widget-content",this.highlightStateClass=t+"-state-highlight"},renderBusinessHours:function(){},unrenderBusinessHours:function(){},startNowIndicator:function(){var t,n,i,r=this;this.opt("nowIndicator")&&(t=this.getNowIndicatorUnit(),t&&(n=lt(this,"updateNowIndicator"),this.initialNowDate=this.calendar.getNow(),this.initialNowQueriedMs=+new Date,this.renderNowIndicator(this.initialNowDate),this.isNowIndicatorRendered=!0,i=this.initialNowDate.clone().startOf(t).add(1,t)-this.initialNowDate,this.nowIndicatorTimeoutID=setTimeout(function(){r.nowIndicatorTimeoutID=null,n(),i=+e.duration(1,t),i=Math.max(100,i),r.nowIndicatorIntervalID=setInterval(n,i)},i)))},updateNowIndicator:function(){this.isNowIndicatorRendered&&(this.unrenderNowIndicator(),this.renderNowIndicator(this.initialNowDate.clone().add(new Date-this.initialNowQueriedMs)))},stopNowIndicator:function(){this.isNowIndicatorRendered&&(this.nowIndicatorTimeoutID&&(clearTimeout(this.nowIndicatorTimeoutID),this.nowIndicatorTimeoutID=null),this.nowIndicatorIntervalID&&(clearTimeout(this.nowIndicatorIntervalID),this.nowIndicatorIntervalID=null),this.unrenderNowIndicator(),this.isNowIndicatorRendered=!1)},getNowIndicatorUnit:function(){},renderNowIndicator:function(t){},unrenderNowIndicator:function(){},updateSize:function(t){var e;t&&(e=this.queryScroll()),this.updateHeight(t),this.updateWidth(t),this.updateNowIndicator(),t&&this.setScroll(e)},updateWidth:function(t){},updateHeight:function(t){var e=this.calendar;this.setHeight(e.getSuggestedViewHeight(),e.isHeightAuto())},setHeight:function(t,e){},computeInitialScroll:function(t){return 0},queryScroll:function(){},setScroll:function(t){},forceScroll:function(t){var e=this;this.setScroll(t),setTimeout(function(){e.setScroll(t)},0)},displayEvents:function(t){var e=this.queryScroll();this.clearEvents(),this.renderEvents(t),this.isEventsRendered=!0,this.setScroll(e),this.triggerEventRender()},clearEvents:function(){var t;this.isEventsRendered&&(t=this.queryScroll(),this.triggerEventUnrender(),this.destroyEvents&&this.destroyEvents(),this.unrenderEvents(),this.setScroll(t),this.isEventsRendered=!1)},renderEvents:function(t){},unrenderEvents:function(){},triggerEventRender:function(){this.renderedEventSegEach(function(t){this.trigger("eventAfterRender",t.event,t.event,t.el)}),this.trigger("eventAfterAllRender")},triggerEventUnrender:function(){this.renderedEventSegEach(function(t){this.trigger("eventDestroy",t.event,t.event,t.el)})},resolveEventEl:function(e,n){var i=this.trigger("eventRender",e,e,n);return i===!1?n=null:i&&i!==!0&&(n=t(i)),n},showEvent:function(t){this.renderedEventSegEach(function(t){t.el.css("visibility","")},t)},hideEvent:function(t){this.renderedEventSegEach(function(t){t.el.css("visibility","hidden")},t)},renderedEventSegEach:function(t,e){var n,i=this.getEventSegs();for(n=0;n=this.nextDayThreshold&&r.add(1,"days")),(!i||r<=n)&&(r=n.clone().add(1,"days")),{start:n,end:r}},isMultiDayEvent:function(t){var e=this.computeDayRange(t);return e.end.diff(e.start,"days")>1}}),we=jt.Scroller=wt.extend({el:null,scrollEl:null,overflowX:null,overflowY:null,constructor:function(t){t=t||{},this.overflowX=t.overflowX||t.overflow||"auto",this.overflowY=t.overflowY||t.overflow||"auto"},render:function(){this.el=this.renderEl(),this.applyOverflow()},renderEl:function(){return this.scrollEl=t('')},clear:function(){this.setHeight("auto"),this.applyOverflow()},destroy:function(){this.el.remove()},applyOverflow:function(){this.scrollEl.css({"overflow-x":this.overflowX,"overflow-y":this.overflowY})},lockOverflow:function(t){var e=this.overflowX,n=this.overflowY;t=t||this.getScrollbarWidths(),"auto"===e&&(e=t.top||t.bottom||this.scrollEl[0].scrollWidth-1>this.scrollEl[0].clientWidth?"scroll":"hidden"),"auto"===n&&(n=t.left||t.right||this.scrollEl[0].scrollHeight-1>this.scrollEl[0].clientHeight?"scroll":"hidden"),this.scrollEl.css({"overflow-x":e,"overflow-y":n})},setHeight:function(t){this.scrollEl.height(t)},getScrollTop:function(){return this.scrollEl.scrollTop()},setScrollTop:function(t){this.scrollEl.scrollTop(t)},getClientWidth:function(){return this.scrollEl[0].clientWidth},getClientHeight:function(){return this.scrollEl[0].clientHeight},getScrollbarWidths:function(){return p(this.scrollEl)}}),Ee=jt.Calendar=wt.extend({dirDefaults:null,localeDefaults:null,overrides:null,dynamicOverrides:null,options:null,viewSpecCache:null,view:null,header:null,loadingLevel:0,constructor:Ot,initialize:function(){},populateOptionsHash:function(){var t,e,i,r;t=J(this.dynamicOverrides.locale,this.overrides.locale),e=De[t],e||(t=Ee.defaults.locale,e=De[t]||{}),i=J(this.dynamicOverrides.isRTL,this.overrides.isRTL,e.isRTL,Ee.defaults.isRTL),r=i?Ee.rtlDefaults:{},this.dirDefaults=r,this.localeDefaults=e,this.options=n([Ee.defaults,r,e,this.overrides,this.dynamicOverrides]),Vt(this.options)},getViewSpec:function(t){var e=this.viewSpecCache;return e[t]||(e[t]=this.buildViewSpec(t))},getUnitViewSpec:function(e){var n,i,r;if(t.inArray(e,Xt)!=-1)for(n=this.header.getViewsWithButtons(),t.each(jt.views,function(t){n.push(t)}),i=0;i=n&&e.end<=i},Ee.prototype.getPeerEvents=function(t,e){var n,i,r=this.getEventCache(),s=[];for(n=0;nn};var Re={id:"_fcBusinessHours",start:"09:00",end:"17:00",dow:[1,2,3,4,5],rendering:"inverse-background"};Ee.prototype.getCurrentBusinessHourEvents=function(t){return this.computeBusinessHourEvents(t,this.options.businessHours)},Ee.prototype.computeBusinessHourEvents=function(e,n){return n===!0?this.expandBusinessHourEvents(e,[{}]):t.isPlainObject(n)?this.expandBusinessHourEvents(e,[n]):t.isArray(n)?this.expandBusinessHourEvents(e,n,!0):[]},Ee.prototype.expandBusinessHourEvents=function(e,n,i){var r,s,o=this.getView(),l=[];for(r=0;r1,this.opt("weekNumbers")&&(this.opt("weekNumbersWithinDays")?(this.cellWeekNumbersVisible=!0,this.colWeekNumbersVisible=!1):(this.cellWeekNumbersVisible=!1,this.colWeekNumbersVisible=!0)),this.dayGrid.numbersVisible=this.dayNumbersVisible||this.cellWeekNumbersVisible||this.colWeekNumbersVisible,this.el.addClass("fc-basic-view").html(this.renderSkeletonHtml()),this.renderHead(),this.scroller.render();var e=this.scroller.el.addClass("fc-day-grid-container"),n=t('').appendTo(e);this.el.find(".fc-body > tr > td").append(e),this.dayGrid.setElement(n),this.dayGrid.renderDates(this.hasRigidRows())},renderHead:function(){this.headContainerEl=this.el.find(".fc-head-container").html(this.dayGrid.renderHeadHtml()),this.headRowEl=this.headContainerEl.find(".fc-row")},unrenderDates:function(){this.dayGrid.unrenderDates(),this.dayGrid.removeElement(),this.scroller.destroy()},renderBusinessHours:function(){this.dayGrid.renderBusinessHours()},unrenderBusinessHours:function(){this.dayGrid.unrenderBusinessHours()},renderSkeletonHtml:function(){return''},weekNumberStyleAttr:function(){return null!==this.weekNumberWidth?'style="width:'+this.weekNumberWidth+'px"':""},hasRigidRows:function(){var t=this.opt("eventLimit");return t&&"number"!=typeof t},updateWidth:function(){this.colWeekNumbersVisible&&(this.weekNumberWidth=u(this.el.find(".fc-week-number")))},setHeight:function(t,e){var n,s,o=this.opt("eventLimit");this.scroller.clear(),r(this.headRowEl),this.dayGrid.removeSegPopover(),o&&"number"==typeof o&&this.dayGrid.limitRows(o),n=this.computeScrollerHeight(t),this.setGridHeight(n,e),o&&"number"!=typeof o&&this.dayGrid.limitRows(o),e||(this.scroller.setHeight(n),s=this.scroller.getScrollbarWidths(),(s.left||s.right)&&(i(this.headRowEl,s),n=this.computeScrollerHeight(t),this.scroller.setHeight(n)),this.scroller.lockOverflow(s))},computeScrollerHeight:function(t){return t-d(this.el,this.scroller.el)},setGridHeight:function(t,e){e?a(this.dayGrid.rowEls):l(this.dayGrid.rowEls,t,!0)},queryScroll:function(){return this.scroller.getScrollTop()},setScroll:function(t){this.scroller.setScrollTop(t)},prepareHits:function(){this.dayGrid.prepareHits()},releaseHits:function(){this.dayGrid.releaseHits()},queryHit:function(t,e){return this.dayGrid.queryHit(t,e)},getHitSpan:function(t){return this.dayGrid.getHitSpan(t)},getHitEl:function(t){return this.dayGrid.getHitEl(t)},renderEvents:function(t){this.dayGrid.renderEvents(t),this.updateHeight()},getEventSegs:function(){return this.dayGrid.getEventSegs()},unrenderEvents:function(){this.dayGrid.unrenderEvents()},renderDrag:function(t,e){return this.dayGrid.renderDrag(t,e)},unrenderDrag:function(){this.dayGrid.unrenderDrag()},renderSelection:function(t){this.dayGrid.renderSelection(t)},unrenderSelection:function(){this.dayGrid.unrenderSelection()}}),ke={renderHeadIntroHtml:function(){var t=this.view;return t.colWeekNumbersVisible?'":""},renderNumberIntroHtml:function(t){var e=this.view,n=this.getCellDate(t,0);return e.colWeekNumbersVisible?'"+e.buildGotoAnchorHtml({date:n,type:"week",forceOff:1===this.colCnt},n.format("w"))+" | ":""},renderBgIntroHtml:function(){var t=this.view;return t.colWeekNumbersVisible?' | ":""},renderIntroHtml:function(){var t=this.view;return t.colWeekNumbersVisible?' | ":""}},Me=jt.MonthView=Ie.extend({computeRange:function(t){var e,n=Ie.prototype.computeRange.call(this,t);return this.isFixedWeeks()&&(e=Math.ceil(n.end.diff(n.start,"weeks",!0)),n.end.add(6-e,"weeks")),n},setGridHeight:function(t,e){e&&(t*=this.rowCnt/6),l(this.dayGrid.rowEls,t,!e)},isFixedWeeks:function(){return this.opt("fixedWeekCount")}});Ut.basic={class:Ie},Ut.basicDay={type:"basic",duration:{days:1}},Ut.basicWeek={type:"basic",duration:{weeks:1}},Ut.month={class:Me,duration:{months:1},defaults:{fixedWeekCount:!0}};var Le=jt.AgendaView=Se.extend({scroller:null,timeGridClass:ye,timeGrid:null,dayGridClass:me,dayGrid:null,axisWidth:null,headContainerEl:null,noScrollRowEls:null,bottomRuleEl:null,initialize:function(){this.timeGrid=this.instantiateTimeGrid(),this.opt("allDaySlot")&&(this.dayGrid=this.instantiateDayGrid()),this.scroller=new we({overflowX:"hidden",overflowY:"auto"})},instantiateTimeGrid:function(){var t=this.timeGridClass.extend(Be);return new t(this)},instantiateDayGrid:function(){var t=this.dayGridClass.extend(ze);return new t(this)},setRange:function(t){Se.prototype.setRange.call(this,t),this.timeGrid.setRange(t),this.dayGrid&&this.dayGrid.setRange(t)},renderDates:function(){this.el.addClass("fc-agenda-view").html(this.renderSkeletonHtml()),this.renderHead(),this.scroller.render();var e=this.scroller.el.addClass("fc-time-grid-container"),n=t('').appendTo(e);this.el.find(".fc-body > tr > td").append(e),this.timeGrid.setElement(n),this.timeGrid.renderDates(),this.bottomRuleEl=t('').appendTo(this.timeGrid.el),this.dayGrid&&(this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.renderDates(),this.dayGrid.bottomCoordPadding=this.dayGrid.el.next("hr").outerHeight()),this.noScrollRowEls=this.el.find(".fc-row:not(.fc-scroller *)")},renderHead:function(){this.headContainerEl=this.el.find(".fc-head-container").html(this.timeGrid.renderHeadHtml())},unrenderDates:function(){this.timeGrid.unrenderDates(),this.timeGrid.removeElement(),this.dayGrid&&(this.dayGrid.unrenderDates(),this.dayGrid.removeElement()),this.scroller.destroy()},renderSkeletonHtml:function(){return'"},axisStyleAttr:function(){return null!==this.axisWidth?'style="width:'+this.axisWidth+'px"':""},renderBusinessHours:function(){this.timeGrid.renderBusinessHours(),this.dayGrid&&this.dayGrid.renderBusinessHours()},unrenderBusinessHours:function(){this.timeGrid.unrenderBusinessHours(),this.dayGrid&&this.dayGrid.unrenderBusinessHours()},getNowIndicatorUnit:function(){return this.timeGrid.getNowIndicatorUnit()},renderNowIndicator:function(t){this.timeGrid.renderNowIndicator(t)},unrenderNowIndicator:function(){this.timeGrid.unrenderNowIndicator()},updateSize:function(t){this.timeGrid.updateSize(t),Se.prototype.updateSize.call(this,t)},updateWidth:function(){this.axisWidth=u(this.el.find(".fc-axis"))},setHeight:function(t,e){var n,s,o;this.bottomRuleEl.hide(),this.scroller.clear(),r(this.noScrollRowEls),this.dayGrid&&(this.dayGrid.removeSegPopover(),n=this.opt("eventLimit"),n&&"number"!=typeof n&&(n=Fe),n&&this.dayGrid.limitRows(n)),e||(s=this.computeScrollerHeight(t),this.scroller.setHeight(s),o=this.scroller.getScrollbarWidths(),(o.left||o.right)&&(i(this.noScrollRowEls,o),s=this.computeScrollerHeight(t),this.scroller.setHeight(s)),this.scroller.lockOverflow(o),this.timeGrid.getTotalSlatHeight()