mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-06-27 16:10:13 +08:00
313 lines
9.1 KiB
JavaScript
313 lines
9.1 KiB
JavaScript
function ResourceManager(options) {
|
|
var t = this;
|
|
// exports
|
|
t.fetchResources = fetchResources;
|
|
t.setResources = setResources;
|
|
t.mutateResourceEvent = mutateResourceEvent;
|
|
// locals
|
|
var resourceSources = [];
|
|
var cache;
|
|
// initialize the resources.
|
|
setResources(options.resources);
|
|
// add the resource sources
|
|
|
|
function setResources(sources) {
|
|
resourceSources = [];
|
|
var resource;
|
|
if ($.isFunction(sources)) {
|
|
// is it a function?
|
|
resource = {
|
|
resources: sources
|
|
};
|
|
resourceSources.push(resource);
|
|
cache = undefined;
|
|
} else if (typeof sources == 'string') {
|
|
// is it a URL string?
|
|
resource = {
|
|
url: sources
|
|
};
|
|
resourceSources.push(resource);
|
|
cache = undefined;
|
|
} else if (typeof sources == 'object' && sources != null) {
|
|
// is it json object?
|
|
for (var i = 0; i < sources.length; i++) {
|
|
var s = sources[i];
|
|
normalizeSource(s);
|
|
resource = {
|
|
resources: s
|
|
};
|
|
resourceSources.push(resource);
|
|
}
|
|
cache = undefined;
|
|
}
|
|
}
|
|
/**
|
|
* ----------------------------------------------------------------
|
|
* Fetch resources from source array
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
|
|
function fetchResources(useCache, currentView) {
|
|
// if useCache is not defined, default to true
|
|
useCache = (typeof useCache !== 'undefined' ? useCache : true);
|
|
if (!useCache || cache === undefined) {
|
|
// do a fetch resource from source, rebuild cache
|
|
cache = [];
|
|
var len = resourceSources.length;
|
|
for (var i = 0; i < len; i++) {
|
|
var resources = fetchResourceSource(resourceSources[i], currentView);
|
|
cache = cache.concat(resources);
|
|
}
|
|
}
|
|
|
|
if($.isFunction(options.resourceFilter)) {
|
|
return $.grep(cache, options.resourceFilter);
|
|
}
|
|
|
|
return cache;
|
|
}
|
|
|
|
/**
|
|
* ----------------------------------------------------------------
|
|
* Fetch resources from each source. If source is a function, call
|
|
* the function and return the resource. If source is a URL, get
|
|
* the data via synchronized ajax call. If the source is an
|
|
* object, return it as is.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
|
|
function fetchResourceSource(source, currentView) {
|
|
var resources = source.resources;
|
|
if (resources) {
|
|
if ($.isFunction(resources)) {
|
|
return resources();
|
|
}
|
|
} else {
|
|
var url = source.url;
|
|
if (url) {
|
|
var data = {};
|
|
if (typeof currentView === 'object') {
|
|
var startParam = options.startParam;
|
|
var endParam = options.endParam;
|
|
if (startParam) {
|
|
data[startParam] = Math.round(+currentView.intervalStart / 1000);
|
|
}
|
|
if (endParam) {
|
|
data[endParam] = Math.round(+currentView.intervalEnd / 1000);
|
|
}
|
|
}
|
|
$.ajax($.extend({}, ajaxDefaults, source, {
|
|
data: data,
|
|
dataType: 'json',
|
|
cache: false,
|
|
success: function(res) {
|
|
res = res || [];
|
|
resources = res;
|
|
},
|
|
error: function() {
|
|
// TODO - need to rewrite callbacks, etc.
|
|
//alert("ajax error getting json from " + url);
|
|
},
|
|
async: false // too much work coordinating callbacks so dumb it down
|
|
}));
|
|
}
|
|
}
|
|
return resources;
|
|
}
|
|
/**
|
|
* ----------------------------------------------------------------
|
|
* normalize the source object
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
|
|
function normalizeSource(source) {
|
|
if (source.className) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* Event Modification Math
|
|
-----------------------------------------------------------------------------------------*/
|
|
|
|
|
|
// Modify the date(s) of an event and make this change propagate to all other events with
|
|
// the same ID (related repeating events).
|
|
//
|
|
// If `newStart`/`newEnd` are not specified, the "new" dates are assumed to be `event.start` and `event.end`.
|
|
// The "old" dates to be compare against are always `event._start` and `event._end` (set by EventManager).
|
|
//
|
|
// Returns an object with delta information and a function to undo all operations.
|
|
//
|
|
function mutateResourceEvent(event, newResources, newStart, newEnd) {
|
|
var oldAllDay = event._allDay;
|
|
var oldStart = event._start;
|
|
var oldEnd = event._end;
|
|
var clearEnd = false;
|
|
var newAllDay;
|
|
var dateDelta;
|
|
var durationDelta;
|
|
var undoFunc;
|
|
|
|
// if no new dates were passed in, compare against the event's existing dates
|
|
if (!newStart && !newEnd) {
|
|
newStart = event.start;
|
|
newEnd = event.end;
|
|
}
|
|
|
|
// NOTE: throughout this function, the initial values of `newStart` and `newEnd` are
|
|
// preserved. These values may be undefined.
|
|
|
|
// detect new allDay
|
|
if (event.allDay != oldAllDay) { // if value has changed, use it
|
|
newAllDay = event.allDay;
|
|
}
|
|
else { // otherwise, see if any of the new dates are allDay
|
|
newAllDay = !(newStart || newEnd).hasTime();
|
|
}
|
|
|
|
// normalize the new dates based on allDay
|
|
if (newAllDay) {
|
|
if (newStart) {
|
|
newStart = newStart.clone().stripTime();
|
|
}
|
|
if (newEnd) {
|
|
newEnd = newEnd.clone().stripTime();
|
|
}
|
|
}
|
|
|
|
// compute dateDelta
|
|
if (newStart) {
|
|
if (newAllDay) {
|
|
dateDelta = dayishDiff(newStart, oldStart.clone().stripTime()); // treat oldStart as allDay
|
|
}
|
|
else {
|
|
dateDelta = dayishDiff(newStart, oldStart);
|
|
}
|
|
}
|
|
|
|
if (newAllDay != oldAllDay) {
|
|
// if allDay has changed, always throw away the end
|
|
clearEnd = true;
|
|
}
|
|
else if (newEnd) {
|
|
durationDelta = dayishDiff(
|
|
// new duration
|
|
newEnd || t.getDefaultEventEnd(newAllDay, newStart || oldStart),
|
|
newStart || oldStart
|
|
).subtract(dayishDiff(
|
|
// subtract old duration
|
|
oldEnd || t.getDefaultEventEnd(oldAllDay, oldStart),
|
|
oldStart
|
|
));
|
|
}
|
|
|
|
undoFunc = mutateResourceEvents(
|
|
t.clientEvents(event._id), // get events with this ID
|
|
clearEnd,
|
|
newAllDay,
|
|
dateDelta,
|
|
durationDelta,
|
|
newResources
|
|
);
|
|
|
|
return {
|
|
dateDelta: dateDelta,
|
|
durationDelta: durationDelta,
|
|
undo: undoFunc
|
|
};
|
|
}
|
|
|
|
|
|
// Modifies an array of events in the following ways (operations are in order):
|
|
// - clear the event's `end`
|
|
// - convert the event to allDay
|
|
// - add `dateDelta` to the start and end
|
|
// - add `durationDelta` to the event's duration
|
|
//
|
|
// Returns a function that can be called to undo all the operations.
|
|
//
|
|
function mutateResourceEvents(events, clearEnd, forceAllDay, dateDelta, durationDelta, newResources) {
|
|
var isAmbigTimezone = t.getIsAmbigTimezone();
|
|
var undoFunctions = [];
|
|
|
|
$.each(events, function(i, event) {
|
|
var oldResources = event.resources;
|
|
var oldAllDay = event._allDay;
|
|
var oldStart = event._start;
|
|
var oldEnd = event._end;
|
|
var newAllDay = forceAllDay != null ? forceAllDay : oldAllDay;
|
|
var newStart = oldStart.clone();
|
|
var newEnd = (!clearEnd && oldEnd) ? oldEnd.clone() : null;
|
|
|
|
// NOTE: this function is responsible for transforming `newStart` and `newEnd`,
|
|
// which were initialized to the OLD values first. `newEnd` may be null.
|
|
|
|
// normlize newStart/newEnd to be consistent with newAllDay
|
|
if (newAllDay) {
|
|
newStart.stripTime();
|
|
if (newEnd) {
|
|
newEnd.stripTime();
|
|
}
|
|
}
|
|
else {
|
|
if (!newStart.hasTime()) {
|
|
newStart = t.rezoneDate(newStart);
|
|
}
|
|
if (newEnd && !newEnd.hasTime()) {
|
|
newEnd = t.rezoneDate(newEnd);
|
|
}
|
|
}
|
|
|
|
// ensure we have an end date if necessary
|
|
if (!newEnd && (options.forceEventDuration || +durationDelta)) {
|
|
newEnd = t.getDefaultEventEnd(newAllDay, newStart);
|
|
}
|
|
|
|
// translate the dates
|
|
newStart.add(dateDelta);
|
|
if (newEnd) {
|
|
newEnd.add(dateDelta).add(durationDelta);
|
|
}
|
|
|
|
// if the dates have changed, and we know it is impossible to recompute the
|
|
// timezone offsets, strip the zone.
|
|
if (isAmbigTimezone) {
|
|
if (+dateDelta || +durationDelta) {
|
|
newStart.stripZone();
|
|
if (newEnd) {
|
|
newEnd.stripZone();
|
|
}
|
|
}
|
|
}
|
|
|
|
event.allDay = newAllDay;
|
|
event.start = newStart;
|
|
event.end = newEnd;
|
|
event.resources = newResources;
|
|
backupEventDates(event);
|
|
|
|
undoFunctions.push(function() {
|
|
event.allDay = oldAllDay;
|
|
event.start = oldStart;
|
|
event.end = oldEnd;
|
|
event.resources = oldResources;
|
|
backupEventDates(event);
|
|
});
|
|
});
|
|
|
|
return function() {
|
|
for (var i=0; i<undoFunctions.length; i++) {
|
|
undoFunctions[i]();
|
|
}
|
|
};
|
|
}
|
|
}
|