2010-09-19 07:54:35 +02:00
|
|
|
|
|
|
|
var eventGUID = 1;
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
function EventManager(options, sources) {
|
2010-09-19 07:54:35 +02:00
|
|
|
var t = this;
|
|
|
|
|
|
|
|
|
|
|
|
// exports
|
|
|
|
t.isFetchNeeded = isFetchNeeded;
|
2010-10-24 22:32:08 +02:00
|
|
|
t.fetchEvents = fetchEvents;
|
2010-09-19 07:54:35 +02:00
|
|
|
t.addEventSource = addEventSource;
|
|
|
|
t.removeEventSource = removeEventSource;
|
|
|
|
t.updateEvent = updateEvent;
|
|
|
|
t.renderEvent = renderEvent;
|
|
|
|
t.removeEvents = removeEvents;
|
|
|
|
t.clientEvents = clientEvents;
|
|
|
|
t.normalizeEvent = normalizeEvent;
|
|
|
|
|
|
|
|
|
|
|
|
// imports
|
|
|
|
var trigger = t.trigger;
|
2010-10-24 22:32:08 +02:00
|
|
|
var getView = t.getView;
|
|
|
|
var reportEvents = t.reportEvents;
|
|
|
|
|
2010-09-19 07:54:35 +02:00
|
|
|
|
|
|
|
// locals
|
2010-10-24 22:32:08 +02:00
|
|
|
var rangeStart, rangeEnd;
|
|
|
|
var currentFetchID = 0;
|
|
|
|
var pendingSourceCnt = 0;
|
2010-09-19 07:54:35 +02:00
|
|
|
var loadingLevel = 0;
|
2010-10-24 22:32:08 +02:00
|
|
|
var dynamicEventSource = [];
|
|
|
|
var cache = [];
|
2010-09-19 07:54:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
/* Fetching
|
2010-09-19 07:54:35 +02:00
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
function isFetchNeeded(start, end) {
|
|
|
|
return !rangeStart || start < rangeStart || end > rangeEnd;
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
function fetchEvents(start, end) {
|
|
|
|
rangeStart = start;
|
|
|
|
rangeEnd = end;
|
|
|
|
currentFetchID++;
|
|
|
|
cache = [];
|
|
|
|
pendingSourceCnt = sources.length;
|
|
|
|
for (var i=0; i<sources.length; i++) {
|
|
|
|
fetchEventSource(sources[i], currentFetchID);
|
|
|
|
}
|
2010-10-11 23:16:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
function fetchEventSource(source, fetchID) {
|
|
|
|
_fetchEventSource(source, function(events) {
|
|
|
|
if (fetchID == currentFetchID) {
|
|
|
|
for (var i=0; i<events.length; i++) {
|
|
|
|
normalizeEvent(events[i]);
|
|
|
|
events[i].source = source;
|
2010-10-11 23:16:34 +02:00
|
|
|
}
|
2010-10-24 22:32:08 +02:00
|
|
|
cache = cache.concat(events);
|
|
|
|
pendingSourceCnt--;
|
|
|
|
if (!pendingSourceCnt) {
|
|
|
|
reportEvents(cache);
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
2010-10-11 23:16:34 +02:00
|
|
|
}
|
2010-10-24 22:32:08 +02:00
|
|
|
});
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
function _fetchEventSource(source, callback) {
|
|
|
|
if (typeof source == 'string') {
|
2010-09-19 07:54:35 +02:00
|
|
|
var params = {};
|
2010-10-24 22:32:08 +02:00
|
|
|
params[options.startParam] = Math.round(rangeStart.getTime() / 1000);
|
|
|
|
params[options.endParam] = Math.round(rangeEnd.getTime() / 1000);
|
2010-09-19 07:54:35 +02:00
|
|
|
if (options.cacheParam) {
|
|
|
|
params[options.cacheParam] = (new Date()).getTime(); // TODO: deprecate cacheParam
|
|
|
|
}
|
|
|
|
pushLoading();
|
|
|
|
// TODO: respect cache param in ajaxSetup
|
|
|
|
$.ajax({
|
2010-10-24 22:32:08 +02:00
|
|
|
url: source,
|
2010-09-19 07:54:35 +02:00
|
|
|
dataType: 'json',
|
|
|
|
data: params,
|
|
|
|
cache: options.cacheParam || false, // don't let jquery prevent caching if cacheParam is being used
|
2010-10-24 22:32:08 +02:00
|
|
|
success: function(events) {
|
|
|
|
popLoading();
|
|
|
|
callback(events);
|
|
|
|
}
|
2010-09-19 07:54:35 +02:00
|
|
|
});
|
|
|
|
}
|
2010-10-24 22:32:08 +02:00
|
|
|
else if ($.isFunction(source)) {
|
2010-09-19 07:54:35 +02:00
|
|
|
pushLoading();
|
2010-10-24 22:32:08 +02:00
|
|
|
source(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
|
|
|
|
popLoading();
|
|
|
|
callback(events);
|
|
|
|
});
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-10-24 22:32:08 +02:00
|
|
|
callback(source); // src is an array
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
|
|
|
|
/* Sources
|
|
|
|
-----------------------------------------------------------------------------*/
|
2010-10-11 23:16:34 +02:00
|
|
|
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
sources.push(dynamicEventSource);
|
2010-09-19 07:54:35 +02:00
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
|
|
|
|
function addEventSource(source) {
|
|
|
|
sources.push(source);
|
|
|
|
pendingSourceCnt++;
|
|
|
|
fetchEventSource(source, currentFetchID); // will eventually call reportEvents
|
|
|
|
}
|
2010-09-19 07:54:35 +02:00
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
|
|
|
|
function removeEventSource(source) {
|
|
|
|
sources = $.grep(sources, function(src) {
|
|
|
|
return src != source;
|
|
|
|
});
|
|
|
|
// remove all client events from that source
|
|
|
|
cache = $.grep(cache, function(e) {
|
|
|
|
return e.source != source;
|
|
|
|
});
|
|
|
|
reportEvents(cache);
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Manipulation
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
|
|
function updateEvent(event) { // update an existing event
|
2010-10-24 22:32:08 +02:00
|
|
|
var i, len = cache.length, e,
|
|
|
|
defaultEventEnd = getView().defaultEventEnd, // getView???
|
2010-09-19 07:54:35 +02:00
|
|
|
startDelta = event.start - event._start,
|
|
|
|
endDelta = event.end ?
|
|
|
|
(event.end - (event._end || defaultEventEnd(event))) // event._end would be null if event.end
|
|
|
|
: 0; // was null and event was just resized
|
|
|
|
for (i=0; i<len; i++) {
|
2010-10-24 22:32:08 +02:00
|
|
|
e = cache[i];
|
2010-09-19 07:54:35 +02:00
|
|
|
if (e._id == event._id && e != event) {
|
|
|
|
e.start = new Date(+e.start + startDelta);
|
|
|
|
if (event.end) {
|
|
|
|
if (e.end) {
|
|
|
|
e.end = new Date(+e.end + endDelta);
|
|
|
|
}else{
|
|
|
|
e.end = new Date(+defaultEventEnd(e) + endDelta);
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
e.end = null;
|
|
|
|
}
|
|
|
|
e.title = event.title;
|
|
|
|
e.url = event.url;
|
|
|
|
e.allDay = event.allDay;
|
|
|
|
e.className = event.className;
|
|
|
|
e.editable = event.editable;
|
|
|
|
normalizeEvent(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
normalizeEvent(event);
|
2010-10-24 22:32:08 +02:00
|
|
|
reportEvents(cache);
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-24 22:32:08 +02:00
|
|
|
function renderEvent(event, stick) {
|
2010-09-19 07:54:35 +02:00
|
|
|
normalizeEvent(event);
|
|
|
|
if (!event.source) {
|
|
|
|
if (stick) {
|
2010-10-24 22:32:08 +02:00
|
|
|
dynamicEventSource.push(event);
|
|
|
|
event.source = dynamicEventSource;
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
2010-10-24 22:32:08 +02:00
|
|
|
cache.push(event);
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
2010-10-24 22:32:08 +02:00
|
|
|
reportEvents(cache);
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function removeEvents(filter) {
|
|
|
|
if (!filter) { // remove all
|
2010-10-24 22:32:08 +02:00
|
|
|
cache = [];
|
2010-09-19 07:54:35 +02:00
|
|
|
// clear all array sources
|
2010-10-24 22:32:08 +02:00
|
|
|
for (var i=0; i<sources.length; i++) {
|
|
|
|
if (typeof sources[i] == 'object') {
|
|
|
|
sources[i] = [];
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if (!$.isFunction(filter)) { // an event ID
|
|
|
|
var id = filter + '';
|
|
|
|
filter = function(e) {
|
|
|
|
return e._id == id;
|
|
|
|
};
|
|
|
|
}
|
2010-10-24 22:32:08 +02:00
|
|
|
cache = $.grep(cache, filter, true);
|
2010-09-19 07:54:35 +02:00
|
|
|
// remove events from array sources
|
2010-10-24 22:32:08 +02:00
|
|
|
for (var i=0; i<sources.length; i++) {
|
|
|
|
if (typeof sources[i] == 'object') {
|
|
|
|
sources[i] = $.grep(sources[i], filter, true);
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-10-24 22:32:08 +02:00
|
|
|
reportEvents(cache);
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function clientEvents(filter) {
|
|
|
|
if ($.isFunction(filter)) {
|
2010-10-24 22:32:08 +02:00
|
|
|
return $.grep(cache, filter);
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
else if (filter) { // an event ID
|
|
|
|
filter += '';
|
2010-10-24 22:32:08 +02:00
|
|
|
return $.grep(cache, function(e) {
|
2010-09-19 07:54:35 +02:00
|
|
|
return e._id == filter;
|
|
|
|
});
|
|
|
|
}
|
2010-10-24 22:32:08 +02:00
|
|
|
return cache; // else, return all
|
2010-09-19 07:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Loading State
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
|
|
function pushLoading() {
|
|
|
|
if (!loadingLevel++) {
|
|
|
|
trigger('loading', null, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function popLoading() {
|
|
|
|
if (!--loadingLevel) {
|
|
|
|
trigger('loading', null, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Event Normalization
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
|
|
function normalizeEvent(event) {
|
|
|
|
event._id = event._id || (event.id === undefined ? '_fc' + eventGUID++ : event.id + '');
|
|
|
|
if (event.date) {
|
|
|
|
if (!event.start) {
|
|
|
|
event.start = event.date;
|
|
|
|
}
|
|
|
|
delete event.date;
|
|
|
|
}
|
2010-09-27 02:45:34 +02:00
|
|
|
event._start = cloneDate(event.start = parseDate(event.start, options.ignoreTimezone));
|
|
|
|
event.end = parseDate(event.end, options.ignoreTimezone);
|
2010-09-19 07:54:35 +02:00
|
|
|
if (event.end && event.end <= event.start) {
|
|
|
|
event.end = null;
|
|
|
|
}
|
|
|
|
event._end = event.end ? cloneDate(event.end) : null;
|
|
|
|
if (event.allDay === undefined) {
|
|
|
|
event.allDay = options.allDayDefault;
|
|
|
|
}
|
|
|
|
if (event.className) {
|
|
|
|
if (typeof event.className == 'string') {
|
|
|
|
event.className = event.className.split(/\s+/);
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
event.className = [];
|
|
|
|
}
|
|
|
|
// TODO: if there is no start date, return false to indicate an invalid event
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|