Skip to content

Commit

Permalink
Beefed up event sources: Control over all $.ajax options. Event color…
Browse files Browse the repository at this point in the history
…ing through options. All event-level options available as "source" options. Event fetching more resilient to errors.
  • Loading branch information
arshaw committed Feb 11, 2011
1 parent f3fcd57 commit 06e4734
Show file tree
Hide file tree
Showing 7 changed files with 449 additions and 79 deletions.
207 changes: 154 additions & 53 deletions src/EventManager.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@

fc.sourceNormalizers = [];
fc.sourceFetchers = [];

var ajaxDefaults = {
dataType: 'json',
cache: true // because we are using the cacheParam option (TODO: deprecate)
};

var eventGUID = 1;

function EventManager(options, sources) {
function EventManager(options, _sources) {
var t = this;


Expand All @@ -24,13 +32,20 @@ function EventManager(options, sources) {


// locals
var stickySource = { events: [] };
var sources = [ stickySource ];
var rangeStart, rangeEnd;
var currentFetchID = 0;
var pendingSourceCnt = 0;
var loadingLevel = 0;
var cache = [];


for (var i=0; i<_sources.length; i++) {
_addEventSource(_sources[i]);
}



/* Fetching
-----------------------------------------------------------------------------*/
Expand All @@ -57,11 +72,13 @@ function EventManager(options, sources) {
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;
if (events) {
for (var i=0; i<events.length; i++) {
normalizeEvent(events[i], source);
events[i].source = source;
}
cache = cache.concat(events);
}
cache = cache.concat(events);
pendingSourceCnt--;
if (!pendingSourceCnt) {
reportEvents(cache);
Expand All @@ -72,35 +89,76 @@ function EventManager(options, sources) {


function _fetchEventSource(source, callback) {
if (typeof source == 'string') {
var params = {};
params[options.startParam] = Math.round(rangeStart.getTime() / 1000);
params[options.endParam] = Math.round(rangeEnd.getTime() / 1000);
if (options.cacheParam) {
params[options.cacheParam] = (new Date()).getTime(); // TODO: deprecate cacheParam
var i;
var fetchers = fc.sourceFetchers;
var res;
for (i=0; i<fetchers.length; i++) {
res = fetchers[i](source, rangeStart, rangeEnd, callback);
if (res === true) {
// the fetcher is in charge. made its own async request
return;
}
else if (typeof res == 'object') {
// the fetcher returned a new source. process it
_fetchEventSource(res, callback);
return;
}
pushLoading();
// TODO: respect cache param in ajaxSetup
$.ajax({
url: source,
dataType: 'json',
data: params,
cache: options.cacheParam || false, // don't let jquery prevent caching if cacheParam is being used
success: function(events) {
popLoading();
callback(events);
}
});
}
else if ($.isFunction(source)) {
pushLoading();
source(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
popLoading();
var events = source.events;
if (events) {
if ($.isFunction(events)) {
pushLoading();
events(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
callback(events);
popLoading();
});
}
else if ($.isArray(events)) {
callback(events);
});
}
else {
callback(source); // src is an array
}
else {
callback();
}
}else{
var url = source.url;
if (url) {
var success = source.success;
var error = source.error;
var complete = source.complete;
var data = $.extend({}, source.data || {});
var startParam = firstDefined(source.startParam, options.startParam);
var endParam = firstDefined(source.endParam, options.endParam);
var cacheParam = firstDefined(source.cacheParam, options.cacheParam);
if (startParam) {
data[startParam] = Math.round(+rangeStart / 1000);
}
if (endParam) {
data[endParam] = Math.round(+rangeEnd / 1000);
}
if (cacheParam) {
data[cacheParam] = +new Date();
}
pushLoading();
$.ajax($.extend({}, ajaxDefaults, source, {
data: data,
success: function(events) {
events = events || [];
var res = applyAll(success, this, arguments);
if ($.isArray(res)) {
events = res;
}
callback(events);
},
error: function() {
applyAll(error, this, arguments);
callback();
},
complete: function() {
applyAll(complete, this, arguments);
popLoading();
}
}));
}
}
}

Expand All @@ -109,25 +167,38 @@ function EventManager(options, sources) {
/* Sources
-----------------------------------------------------------------------------*/


// first event source is reserved for "sticky" events
sources.unshift([]);


function addEventSource(source) {
sources.push(source);
pendingSourceCnt++;
fetchEventSource(source, currentFetchID); // will eventually call reportEvents
source = _addEventSource(source);
if (source) {
pendingSourceCnt++;
fetchEventSource(source, currentFetchID); // will eventually call reportEvents
}
}


function _addEventSource(source) {
if ($.isFunction(source) || $.isArray(source)) {
source = { events: source };
}
else if (typeof source == 'string') {
source = { url: source };
}
if (typeof source == 'object') {
normalizeSource(source);
sources.push(source);
return source;
}
}


function removeEventSource(source) {
sources = $.grep(sources, function(src) {
return src != source;
return !isSourcesEqual(src, source);
});
// remove all client events from that source
cache = $.grep(cache, function(e) {
return e.source != source;
return !isSourcesEqual(e.source, source);
});
reportEvents(cache);
}
Expand Down Expand Up @@ -163,20 +234,20 @@ function EventManager(options, sources) {
e.allDay = event.allDay;
e.className = event.className;
e.editable = event.editable;
normalizeEvent(e);
normalizeEvent(e, e.source);
}
}
normalizeEvent(event);
normalizeEvent(event, event.source);
reportEvents(cache);
}


function renderEvent(event, stick) {
normalizeEvent(event);
normalizeEvent(event, event.source || stickySource);
if (!event.source) {
if (stick) {
sources[0].push(event);
event.source = sources[0];
stickySource.events.push(event);
event.source = stickySource;
}
cache.push(event);
}
Expand All @@ -189,8 +260,8 @@ function EventManager(options, sources) {
cache = [];
// clear all array sources
for (var i=0; i<sources.length; i++) {
if (typeof sources[i] == 'object') {
sources[i] = [];
if ($.isArray(sources[i].events)) {
sources[i].events = [];
}
}
}else{
Expand All @@ -203,9 +274,8 @@ function EventManager(options, sources) {
cache = $.grep(cache, filter, true);
// remove events from array sources
for (var i=0; i<sources.length; i++) {
if (typeof sources[i] == 'object') {
sources[i] = $.grep(sources[i], filter, true);
// TODO: event objects' sources will no longer be correct reference :(
if ($.isArray(sources[i].events)) {
sources[i].events = $.grep(sources[i].events, filter, true);
}
}
}
Expand Down Expand Up @@ -251,22 +321,22 @@ function EventManager(options, sources) {
-----------------------------------------------------------------------------*/


function normalizeEvent(event) {
function normalizeEvent(event, source) {
event._id = event._id || (event.id === undefined ? '_fc' + eventGUID++ : event.id + '');
if (event.date) {
if (!event.start) {
event.start = event.date;
}
delete event.date;
}
event._start = cloneDate(event.start = parseDate(event.start, options.ignoreTimezone));
event._start = cloneDate(event.start = parseDate(event.start, firstDefined(source.ignoreTimezone, options.ignoreTimezone)));
event.end = parseDate(event.end, options.ignoreTimezone);
if (event.end && event.end <= event.start) {
event.end = null;
}
event._end = event.end ? cloneDate(event.end) : null;
if (event.allDay === undefined) {
event.allDay = options.allDayDefault;
event.allDay = firstDefined(source.allDayDefault, options.allDayDefault);
}
if (event.className) {
if (typeof event.className == 'string') {
Expand All @@ -277,6 +347,37 @@ function EventManager(options, sources) {
}
// TODO: if there is no start date, return false to indicate an invalid event
}



/* Utils
------------------------------------------------------------------------------*/


function normalizeSource(source) {
if (source.className) {
// TODO: repeate code, same code for event classNames
if (typeof source.className == 'string') {
source.className = source.className.split(/\s+/);
}
}else{
source.className = [];
}
var normalizers = fc.sourceNormalizers;
for (var i=0; i<normalizers.length; i++) {
normalizers[i](source);
}
}


function isSourcesEqual(source1, source2) {
return getSourcePrimitive(source1) == getSourcePrimitive(source2);
}


function getSourcePrimitive(source) {
return ((typeof source == 'object') ? (source.events || source.url) : '') || source;
}


}
Loading

0 comments on commit 06e4734

Please sign in to comment.