Beefed up event sources: Control over all $.ajax options. Event coloring through options. All event-level options available as "source" options. Event fetching more resilient to errors.
This commit is contained in:
parent
f3fcd57530
commit
06e4734b05
7 changed files with 449 additions and 79 deletions
|
@ -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;
|
||||
|
||||
|
||||
|
@ -24,6 +32,8 @@ function EventManager(options, sources) {
|
|||
|
||||
|
||||
// locals
|
||||
var stickySource = { events: [] };
|
||||
var sources = [ stickySource ];
|
||||
var rangeStart, rangeEnd;
|
||||
var currentFetchID = 0;
|
||||
var pendingSourceCnt = 0;
|
||||
|
@ -31,6 +41,11 @@ function EventManager(options, sources) {
|
|||
var cache = [];
|
||||
|
||||
|
||||
for (var i=0; i<_sources.length; i++) {
|
||||
_addEventSource(_sources[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Fetching
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
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();
|
||||
else if (typeof res == 'object') {
|
||||
// the fetcher returned a new source. process it
|
||||
_fetchEventSource(res, callback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
var events = source.events;
|
||||
if (events) {
|
||||
if ($.isFunction(events)) {
|
||||
pushLoading();
|
||||
events(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
|
||||
callback(events);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if ($.isFunction(source)) {
|
||||
pushLoading();
|
||||
source(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
|
||||
popLoading();
|
||||
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();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +321,7 @@ 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) {
|
||||
|
@ -259,14 +329,14 @@ function EventManager(options, sources) {
|
|||
}
|
||||
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') {
|
||||
|
@ -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…
Add table
Add a link
Reference in a new issue