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
|
@ -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;
|
var eventGUID = 1;
|
||||||
|
|
||||||
function EventManager(options, sources) {
|
function EventManager(options, _sources) {
|
||||||
var t = this;
|
var t = this;
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +32,8 @@ function EventManager(options, sources) {
|
||||||
|
|
||||||
|
|
||||||
// locals
|
// locals
|
||||||
|
var stickySource = { events: [] };
|
||||||
|
var sources = [ stickySource ];
|
||||||
var rangeStart, rangeEnd;
|
var rangeStart, rangeEnd;
|
||||||
var currentFetchID = 0;
|
var currentFetchID = 0;
|
||||||
var pendingSourceCnt = 0;
|
var pendingSourceCnt = 0;
|
||||||
|
@ -31,6 +41,11 @@ function EventManager(options, sources) {
|
||||||
var cache = [];
|
var cache = [];
|
||||||
|
|
||||||
|
|
||||||
|
for (var i=0; i<_sources.length; i++) {
|
||||||
|
_addEventSource(_sources[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Fetching
|
/* Fetching
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
@ -57,11 +72,13 @@ function EventManager(options, sources) {
|
||||||
function fetchEventSource(source, fetchID) {
|
function fetchEventSource(source, fetchID) {
|
||||||
_fetchEventSource(source, function(events) {
|
_fetchEventSource(source, function(events) {
|
||||||
if (fetchID == currentFetchID) {
|
if (fetchID == currentFetchID) {
|
||||||
|
if (events) {
|
||||||
for (var i=0; i<events.length; i++) {
|
for (var i=0; i<events.length; i++) {
|
||||||
normalizeEvent(events[i]);
|
normalizeEvent(events[i], source);
|
||||||
events[i].source = source;
|
events[i].source = source;
|
||||||
}
|
}
|
||||||
cache = cache.concat(events);
|
cache = cache.concat(events);
|
||||||
|
}
|
||||||
pendingSourceCnt--;
|
pendingSourceCnt--;
|
||||||
if (!pendingSourceCnt) {
|
if (!pendingSourceCnt) {
|
||||||
reportEvents(cache);
|
reportEvents(cache);
|
||||||
|
@ -72,35 +89,76 @@ function EventManager(options, sources) {
|
||||||
|
|
||||||
|
|
||||||
function _fetchEventSource(source, callback) {
|
function _fetchEventSource(source, callback) {
|
||||||
if (typeof source == 'string') {
|
var i;
|
||||||
var params = {};
|
var fetchers = fc.sourceFetchers;
|
||||||
params[options.startParam] = Math.round(rangeStart.getTime() / 1000);
|
var res;
|
||||||
params[options.endParam] = Math.round(rangeEnd.getTime() / 1000);
|
for (i=0; i<fetchers.length; i++) {
|
||||||
if (options.cacheParam) {
|
res = fetchers[i](source, rangeStart, rangeEnd, callback);
|
||||||
params[options.cacheParam] = (new Date()).getTime(); // TODO: deprecate cacheParam
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var events = source.events;
|
||||||
|
if (events) {
|
||||||
|
if ($.isFunction(events)) {
|
||||||
pushLoading();
|
pushLoading();
|
||||||
// TODO: respect cache param in ajaxSetup
|
events(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
|
||||||
$.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);
|
callback(events);
|
||||||
}
|
popLoading();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if ($.isFunction(source)) {
|
else if ($.isArray(events)) {
|
||||||
pushLoading();
|
|
||||||
source(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
|
|
||||||
popLoading();
|
|
||||||
callback(events);
|
callback(events);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
callback(source); // src is an array
|
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();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,24 +168,37 @@ function EventManager(options, sources) {
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
// first event source is reserved for "sticky" events
|
|
||||||
sources.unshift([]);
|
|
||||||
|
|
||||||
|
|
||||||
function addEventSource(source) {
|
function addEventSource(source) {
|
||||||
sources.push(source);
|
source = _addEventSource(source);
|
||||||
|
if (source) {
|
||||||
pendingSourceCnt++;
|
pendingSourceCnt++;
|
||||||
fetchEventSource(source, currentFetchID); // will eventually call reportEvents
|
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) {
|
function removeEventSource(source) {
|
||||||
sources = $.grep(sources, function(src) {
|
sources = $.grep(sources, function(src) {
|
||||||
return src != source;
|
return !isSourcesEqual(src, source);
|
||||||
});
|
});
|
||||||
// remove all client events from that source
|
// remove all client events from that source
|
||||||
cache = $.grep(cache, function(e) {
|
cache = $.grep(cache, function(e) {
|
||||||
return e.source != source;
|
return !isSourcesEqual(e.source, source);
|
||||||
});
|
});
|
||||||
reportEvents(cache);
|
reportEvents(cache);
|
||||||
}
|
}
|
||||||
|
@ -163,20 +234,20 @@ function EventManager(options, sources) {
|
||||||
e.allDay = event.allDay;
|
e.allDay = event.allDay;
|
||||||
e.className = event.className;
|
e.className = event.className;
|
||||||
e.editable = event.editable;
|
e.editable = event.editable;
|
||||||
normalizeEvent(e);
|
normalizeEvent(e, e.source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
normalizeEvent(event);
|
normalizeEvent(event, event.source);
|
||||||
reportEvents(cache);
|
reportEvents(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function renderEvent(event, stick) {
|
function renderEvent(event, stick) {
|
||||||
normalizeEvent(event);
|
normalizeEvent(event, event.source || stickySource);
|
||||||
if (!event.source) {
|
if (!event.source) {
|
||||||
if (stick) {
|
if (stick) {
|
||||||
sources[0].push(event);
|
stickySource.events.push(event);
|
||||||
event.source = sources[0];
|
event.source = stickySource;
|
||||||
}
|
}
|
||||||
cache.push(event);
|
cache.push(event);
|
||||||
}
|
}
|
||||||
|
@ -189,8 +260,8 @@ function EventManager(options, sources) {
|
||||||
cache = [];
|
cache = [];
|
||||||
// clear all array sources
|
// clear all array sources
|
||||||
for (var i=0; i<sources.length; i++) {
|
for (var i=0; i<sources.length; i++) {
|
||||||
if (typeof sources[i] == 'object') {
|
if ($.isArray(sources[i].events)) {
|
||||||
sources[i] = [];
|
sources[i].events = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
@ -203,9 +274,8 @@ function EventManager(options, sources) {
|
||||||
cache = $.grep(cache, filter, true);
|
cache = $.grep(cache, filter, true);
|
||||||
// remove events from array sources
|
// remove events from array sources
|
||||||
for (var i=0; i<sources.length; i++) {
|
for (var i=0; i<sources.length; i++) {
|
||||||
if (typeof sources[i] == 'object') {
|
if ($.isArray(sources[i].events)) {
|
||||||
sources[i] = $.grep(sources[i], filter, true);
|
sources[i].events = $.grep(sources[i].events, filter, true);
|
||||||
// TODO: event objects' sources will no longer be correct reference :(
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 + '');
|
event._id = event._id || (event.id === undefined ? '_fc' + eventGUID++ : event.id + '');
|
||||||
if (event.date) {
|
if (event.date) {
|
||||||
if (!event.start) {
|
if (!event.start) {
|
||||||
|
@ -259,14 +329,14 @@ function EventManager(options, sources) {
|
||||||
}
|
}
|
||||||
delete 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);
|
event.end = parseDate(event.end, options.ignoreTimezone);
|
||||||
if (event.end && event.end <= event.start) {
|
if (event.end && event.end <= event.start) {
|
||||||
event.end = null;
|
event.end = null;
|
||||||
}
|
}
|
||||||
event._end = event.end ? cloneDate(event.end) : null;
|
event._end = event.end ? cloneDate(event.end) : null;
|
||||||
if (event.allDay === undefined) {
|
if (event.allDay === undefined) {
|
||||||
event.allDay = options.allDayDefault;
|
event.allDay = firstDefined(source.allDayDefault, options.allDayDefault);
|
||||||
}
|
}
|
||||||
if (event.className) {
|
if (event.className) {
|
||||||
if (typeof event.className == 'string') {
|
if (typeof event.className == 'string') {
|
||||||
|
@ -279,4 +349,35 @@ function EventManager(options, sources) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ function AgendaEventRenderer() {
|
||||||
|
|
||||||
var i, segCnt=segs.length, seg,
|
var i, segCnt=segs.length, seg,
|
||||||
event,
|
event,
|
||||||
className,
|
classes,
|
||||||
top, bottom,
|
top, bottom,
|
||||||
colI, levelI, forward,
|
colI, levelI, forward,
|
||||||
leftmost,
|
leftmost,
|
||||||
|
@ -171,12 +171,12 @@ function AgendaEventRenderer() {
|
||||||
for (i=0; i<segCnt; i++) {
|
for (i=0; i<segCnt; i++) {
|
||||||
seg = segs[i];
|
seg = segs[i];
|
||||||
event = seg.event;
|
event = seg.event;
|
||||||
className = 'fc-event fc-event-vert ';
|
classes = ['fc-event', 'fc-event-vert'];
|
||||||
if (seg.isStart) {
|
if (seg.isStart) {
|
||||||
className += 'fc-corner-top ';
|
classes.push('fc-corner-top');
|
||||||
}
|
}
|
||||||
if (seg.isEnd) {
|
if (seg.isEnd) {
|
||||||
className += 'fc-corner-bottom ';
|
classes.push('fc-corner-bottom');
|
||||||
}
|
}
|
||||||
top = timePosition(seg.start, seg.start);
|
top = timePosition(seg.start, seg.start);
|
||||||
bottom = timePosition(seg.start, seg.end);
|
bottom = timePosition(seg.start, seg.end);
|
||||||
|
@ -205,7 +205,7 @@ function AgendaEventRenderer() {
|
||||||
seg.left = left;
|
seg.left = left;
|
||||||
seg.outerWidth = outerWidth;
|
seg.outerWidth = outerWidth;
|
||||||
seg.outerHeight = bottom - top;
|
seg.outerHeight = bottom - top;
|
||||||
html += slotSegHtml(event, seg, className);
|
html += slotSegHtml(event, seg, classes);
|
||||||
}
|
}
|
||||||
slotSegmentContainer[0].innerHTML = html; // faster than html()
|
slotSegmentContainer[0].innerHTML = html; // faster than html()
|
||||||
eventElements = slotSegmentContainer.children();
|
eventElements = slotSegmentContainer.children();
|
||||||
|
@ -278,10 +278,16 @@ function AgendaEventRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function slotSegHtml(event, seg, className) {
|
function slotSegHtml(event, seg, classes) {
|
||||||
return "<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px'>" +
|
classes = classes.concat(event.className, event.source.className);
|
||||||
"<a class='fc-event-inner'" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" + // good for escaping quotes?
|
var skinCss = getSkinCss(event, opt);
|
||||||
"<div class='fc-event-head'>" +
|
var skinCssAttr = (skinCss ? " style='" + skinCss + "'" : '');
|
||||||
|
return "<div class='" + classes.join(' ') + "' style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px;" + skinCss + "'>" +
|
||||||
|
"<a class='fc-event-inner'" +
|
||||||
|
(event.url ? " href='" + htmlEscape(event.url) + "'" : '') + // good for escaping quotes?
|
||||||
|
skinCssAttr +
|
||||||
|
">" +
|
||||||
|
"<div class='fc-event-head'" + skinCssAttr + ">" +
|
||||||
"<div class='fc-event-time'>" +
|
"<div class='fc-event-time'>" +
|
||||||
htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
|
htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
|
||||||
"</div>" +
|
"</div>" +
|
||||||
|
@ -293,16 +299,22 @@ function AgendaEventRenderer() {
|
||||||
"</div>" +
|
"</div>" +
|
||||||
"<div class='fc-event-bg'></div>" +
|
"<div class='fc-event-bg'></div>" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
((event.editable || event.editable === undefined && opt('editable')) && !opt('disableResizing') && $.fn.resizable ?
|
((seg.isEnd &&
|
||||||
|
isEventEditable(event) &&
|
||||||
|
!opt('disableResizing') && // TODO: make like other source properties
|
||||||
|
$.fn.resizable)
|
||||||
|
?
|
||||||
"<div class='ui-resizable-handle ui-resizable-s'>=</div>"
|
"<div class='ui-resizable-handle ui-resizable-s'>=</div>"
|
||||||
: '') +
|
:
|
||||||
|
''
|
||||||
|
) +
|
||||||
"</div>";
|
"</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function bindDaySeg(event, eventElement, seg) {
|
function bindDaySeg(event, eventElement, seg) {
|
||||||
eventElementHandlers(event, eventElement);
|
eventElementHandlers(event, eventElement);
|
||||||
if (event.editable || event.editable === undefined && opt('editable')) {
|
if (isEventEditable(event)) {
|
||||||
draggableDayEvent(event, eventElement, seg.isStart);
|
draggableDayEvent(event, eventElement, seg.isStart);
|
||||||
if (seg.isEnd) {
|
if (seg.isEnd) {
|
||||||
resizableDayEvent(event, eventElement, seg);
|
resizableDayEvent(event, eventElement, seg);
|
||||||
|
@ -313,7 +325,7 @@ function AgendaEventRenderer() {
|
||||||
|
|
||||||
function bindSlotSeg(event, eventElement, seg) {
|
function bindSlotSeg(event, eventElement, seg) {
|
||||||
eventElementHandlers(event, eventElement);
|
eventElementHandlers(event, eventElement);
|
||||||
if (event.editable || event.editable === undefined && opt('editable')) {
|
if (isEventEditable(event)) {
|
||||||
var timeElement = eventElement.find('span.fc-event-time');
|
var timeElement = eventElement.find('span.fc-event-time');
|
||||||
draggableSlotEvent(event, eventElement, timeElement);
|
draggableSlotEvent(event, eventElement, timeElement);
|
||||||
if (seg.isEnd) {
|
if (seg.isEnd) {
|
||||||
|
@ -323,6 +335,11 @@ function AgendaEventRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function isEventEditable(event) {
|
||||||
|
return firstDefined(event.editable, event.source.editable, opt('editable'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Dragging
|
/* Dragging
|
||||||
-----------------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------------*/
|
||||||
|
@ -330,6 +347,10 @@ function AgendaEventRenderer() {
|
||||||
|
|
||||||
// when event starts out FULL-DAY
|
// when event starts out FULL-DAY
|
||||||
|
|
||||||
|
// TODO: bug when dragging an event that occupies first day, but is not the event's start (no rounded left side)
|
||||||
|
|
||||||
|
// TODO: bug when dragging from day to slot, outer container doesn't seem to change height
|
||||||
|
|
||||||
function draggableDayEvent(event, eventElement, isStart) {
|
function draggableDayEvent(event, eventElement, isStart) {
|
||||||
if (!opt('disableDragging') && eventElement.draggable) {
|
if (!opt('disableDragging') && eventElement.draggable) {
|
||||||
var origWidth;
|
var origWidth;
|
||||||
|
|
|
@ -701,10 +701,11 @@ function AgendaView(element, calendar, viewName) {
|
||||||
start: startDate,
|
start: startDate,
|
||||||
end: endDate,
|
end: endDate,
|
||||||
className: [],
|
className: [],
|
||||||
editable: false
|
editable: false,
|
||||||
|
source: {}
|
||||||
},
|
},
|
||||||
rect,
|
rect,
|
||||||
'fc-event fc-event-vert fc-corner-top fc-corner-bottom '
|
['fc-event', 'fc-event-vert', 'fc-corner-top', 'fc-corner-bottom']
|
||||||
));
|
));
|
||||||
if ($.browser.msie) {
|
if ($.browser.msie) {
|
||||||
selectionHelper.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
|
selectionHelper.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
|
||||||
|
|
|
@ -77,7 +77,7 @@ function BasicEventRenderer() {
|
||||||
|
|
||||||
function bindDaySeg(event, eventElement, seg) {
|
function bindDaySeg(event, eventElement, seg) {
|
||||||
eventElementHandlers(event, eventElement);
|
eventElementHandlers(event, eventElement);
|
||||||
if (event.editable || event.editable === undefined && opt('editable')) {
|
if (firstDefined(event.editable, event.source.editable, opt('editable'))) {
|
||||||
draggableDayEvent(event, eventElement);
|
draggableDayEvent(event, eventElement);
|
||||||
if (seg.isEnd) {
|
if (seg.isEnd) {
|
||||||
resizableDayEvent(event, eventElement, seg);
|
resizableDayEvent(event, eventElement, seg);
|
||||||
|
|
|
@ -119,25 +119,26 @@ function DayEventRenderer() {
|
||||||
var segCnt=segs.length;
|
var segCnt=segs.length;
|
||||||
var seg;
|
var seg;
|
||||||
var event;
|
var event;
|
||||||
var className;
|
var classes;
|
||||||
var bounds = allDayBounds();
|
var bounds = allDayBounds();
|
||||||
var minLeft = bounds.left;
|
var minLeft = bounds.left;
|
||||||
var maxLeft = bounds.right;
|
var maxLeft = bounds.right;
|
||||||
var cols = []; // don't really like this system (but have to do this b/c RTL works differently in basic vs agenda)
|
var cols = []; // don't really like this system (but have to do this b/c RTL works differently in basic vs agenda)
|
||||||
var left;
|
var left;
|
||||||
var right;
|
var right;
|
||||||
|
var skinCss;
|
||||||
var html = '';
|
var html = '';
|
||||||
// calculate desired position/dimensions, create html
|
// calculate desired position/dimensions, create html
|
||||||
for (i=0; i<segCnt; i++) {
|
for (i=0; i<segCnt; i++) {
|
||||||
seg = segs[i];
|
seg = segs[i];
|
||||||
event = seg.event;
|
event = seg.event;
|
||||||
className = 'fc-event fc-event-hori ';
|
classes = ['fc-event', 'fc-event-hori'];
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
if (seg.isStart) {
|
if (seg.isStart) {
|
||||||
className += 'fc-corner-right ';
|
classes.push('fc-corner-right');
|
||||||
}
|
}
|
||||||
if (seg.isEnd) {
|
if (seg.isEnd) {
|
||||||
className += 'fc-corner-left ';
|
classes.push('fc-corner-left');
|
||||||
}
|
}
|
||||||
cols[0] = dayOfWeekCol(seg.end.getDay()-1);
|
cols[0] = dayOfWeekCol(seg.end.getDay()-1);
|
||||||
cols[1] = dayOfWeekCol(seg.start.getDay());
|
cols[1] = dayOfWeekCol(seg.start.getDay());
|
||||||
|
@ -145,19 +146,26 @@ function DayEventRenderer() {
|
||||||
right = seg.isStart ? colContentRight(cols[1]) : maxLeft;
|
right = seg.isStart ? colContentRight(cols[1]) : maxLeft;
|
||||||
}else{
|
}else{
|
||||||
if (seg.isStart) {
|
if (seg.isStart) {
|
||||||
className += 'fc-corner-left ';
|
classes.push('fc-corner-left');
|
||||||
}
|
}
|
||||||
if (seg.isEnd) {
|
if (seg.isEnd) {
|
||||||
className += 'fc-corner-right ';
|
classes.push('fc-corner-right');
|
||||||
}
|
}
|
||||||
cols[0] = dayOfWeekCol(seg.start.getDay());
|
cols[0] = dayOfWeekCol(seg.start.getDay());
|
||||||
cols[1] = dayOfWeekCol(seg.end.getDay()-1);
|
cols[1] = dayOfWeekCol(seg.end.getDay()-1);
|
||||||
left = seg.isStart ? colContentLeft(cols[0]) : minLeft;
|
left = seg.isStart ? colContentLeft(cols[0]) : minLeft;
|
||||||
right = seg.isEnd ? colContentRight(cols[1]) : maxLeft;
|
right = seg.isEnd ? colContentRight(cols[1]) : maxLeft;
|
||||||
}
|
}
|
||||||
|
classes = classes.concat(event.className, event.source.className);
|
||||||
|
skinCss = getSkinCss(event, opt);
|
||||||
html +=
|
html +=
|
||||||
"<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;left:"+left+"px'>" +
|
"<div class='" + classes.join(' ') + "' " +
|
||||||
"<a class='fc-event-inner'" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" +
|
"style='position:absolute;z-index:8;left:"+left+"px;" + skinCss + "'" +
|
||||||
|
">" +
|
||||||
|
"<a class='fc-event-inner'" +
|
||||||
|
(event.url ? " href='" + htmlEscape(event.url) + "'" : '') +
|
||||||
|
(skinCss ? " style='" + skinCss + "'" : '') +
|
||||||
|
">" +
|
||||||
(!event.allDay && seg.isStart ?
|
(!event.allDay && seg.isStart ?
|
||||||
"<span class='fc-event-time'>" +
|
"<span class='fc-event-time'>" +
|
||||||
htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
|
htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
|
||||||
|
@ -165,9 +173,14 @@ function DayEventRenderer() {
|
||||||
:'') +
|
:'') +
|
||||||
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
|
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
(seg.isEnd && (event.editable || event.editable === undefined && opt('editable')) && !opt('disableResizing') ?
|
((seg.isEnd &&
|
||||||
|
firstDefined(event.editable, event.source.editable, opt('editable')) &&
|
||||||
|
!opt('disableResizing')) // TODO: make this like the other source options
|
||||||
|
?
|
||||||
"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>"
|
"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>"
|
||||||
: '') +
|
:
|
||||||
|
''
|
||||||
|
) +
|
||||||
"</div>";
|
"</div>";
|
||||||
seg.left = left;
|
seg.left = left;
|
||||||
seg.outerWidth = right - left;
|
seg.outerWidth = right - left;
|
||||||
|
|
63
src/util.js
63
src/util.js
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
fc.applyAll = applyAll;
|
||||||
|
|
||||||
|
|
||||||
/* Event Date Math
|
/* Event Date Math
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
@ -305,3 +307,64 @@ function setDayID(cell, date) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getSkinCss(event, opt) {
|
||||||
|
var source = event.source;
|
||||||
|
var eventColor = event.color;
|
||||||
|
var sourceColor = source.color;
|
||||||
|
var optionColor = opt('eventColor');
|
||||||
|
var backgroundColor =
|
||||||
|
event.backgroundColor ||
|
||||||
|
eventColor ||
|
||||||
|
source.backgroundColor ||
|
||||||
|
sourceColor ||
|
||||||
|
opt('eventBackgroundColor') ||
|
||||||
|
optionColor;
|
||||||
|
var borderColor =
|
||||||
|
event.borderColor ||
|
||||||
|
eventColor ||
|
||||||
|
source.borderColor ||
|
||||||
|
sourceColor ||
|
||||||
|
opt('eventBorderColor') ||
|
||||||
|
optionColor;
|
||||||
|
var textColor =
|
||||||
|
event.textColor ||
|
||||||
|
source.textColor ||
|
||||||
|
opt('textColor');
|
||||||
|
var statements = [];
|
||||||
|
if (backgroundColor) {
|
||||||
|
statements.push('background-color:' + backgroundColor);
|
||||||
|
}
|
||||||
|
if (borderColor) {
|
||||||
|
statements.push('border-color:' + borderColor);
|
||||||
|
}
|
||||||
|
if (textColor) {
|
||||||
|
statements.push('color:' + textColor);
|
||||||
|
}
|
||||||
|
return statements.join(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function applyAll(functions, thisObj, args) {
|
||||||
|
if ($.isFunction(functions)) {
|
||||||
|
functions = [ functions ];
|
||||||
|
}
|
||||||
|
if (functions) {
|
||||||
|
var i;
|
||||||
|
var ret;
|
||||||
|
for (i=0; i<functions.length; i++) {
|
||||||
|
ret = functions[i].apply(thisObj, args) || ret;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function firstDefined() {
|
||||||
|
for (var i=0; i<arguments.length; i++) {
|
||||||
|
if (arguments[i] !== undefined) {
|
||||||
|
return arguments[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
171
tests/sources_new.html
Normal file
171
tests/sources_new.html
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type='text/javascript' src='../src/_loader.js?debug'></script>
|
||||||
|
<script type='text/javascript' src='../src/gcal/_loader.js'></script>
|
||||||
|
<script type='text/javascript'>
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
(main options)
|
||||||
|
startParam
|
||||||
|
endParam
|
||||||
|
cacheParam
|
||||||
|
ignoreTimezone
|
||||||
|
allDayDefault
|
||||||
|
editable
|
||||||
|
eventColor
|
||||||
|
eventTextColor
|
||||||
|
eventBorderColor
|
||||||
|
eventBackgroundColor
|
||||||
|
|
||||||
|
(event source)
|
||||||
|
startParam
|
||||||
|
endParam
|
||||||
|
cacheParam
|
||||||
|
ignoreTimezone
|
||||||
|
allDayDefault
|
||||||
|
className
|
||||||
|
editable
|
||||||
|
color
|
||||||
|
textColor
|
||||||
|
borderColor
|
||||||
|
backgroundColor
|
||||||
|
|
||||||
|
(event)
|
||||||
|
className
|
||||||
|
editable
|
||||||
|
color
|
||||||
|
textColor
|
||||||
|
borderColor
|
||||||
|
backgroundColor
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
var date = new Date();
|
||||||
|
var d = date.getDate();
|
||||||
|
var m = date.getMonth();
|
||||||
|
var y = date.getFullYear();
|
||||||
|
|
||||||
|
$('#calendar').fullCalendar({
|
||||||
|
header: {
|
||||||
|
left: 'prev,next today',
|
||||||
|
center: 'title',
|
||||||
|
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
|
||||||
|
},
|
||||||
|
editable: true,
|
||||||
|
selectable: true,
|
||||||
|
selectHelper: true,
|
||||||
|
eventSources: [
|
||||||
|
|
||||||
|
{
|
||||||
|
url: 'http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic',
|
||||||
|
color: 'orange',
|
||||||
|
className: 'gcal',
|
||||||
|
success: function(events) {
|
||||||
|
console.log('successfully loaded gcal event data!', events);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
$.fullCalendar.gcalFeed('http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic', {
|
||||||
|
color: 'orange',
|
||||||
|
className: 'gcal'
|
||||||
|
}),
|
||||||
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "../demos/json-events.php",
|
||||||
|
//editable: false,
|
||||||
|
color: 'red',
|
||||||
|
data: {
|
||||||
|
something: 'cool'
|
||||||
|
},
|
||||||
|
success: function() {
|
||||||
|
console.log('json-events.php is done!!!', arguments);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
color: 'purple',
|
||||||
|
events: [
|
||||||
|
{
|
||||||
|
title: 'All Day Event',
|
||||||
|
start: new Date(y, m, 1)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Long Event',
|
||||||
|
start: new Date(y, m, d-5),
|
||||||
|
end: new Date(y, m, d-2)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 999,
|
||||||
|
title: 'Repeating Event',
|
||||||
|
start: new Date(y, m, d-3, 16, 0),
|
||||||
|
allDay: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 999,
|
||||||
|
title: 'Repeating Event',
|
||||||
|
start: new Date(y, m, d+4, 16, 0),
|
||||||
|
allDay: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
events: [
|
||||||
|
{
|
||||||
|
title: 'Meeting',
|
||||||
|
start: new Date(y, m, d, 10, 30),
|
||||||
|
allDay: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Lunch',
|
||||||
|
start: new Date(y, m, d, 12, 5),
|
||||||
|
end: new Date(y, m, d, 14, 43),
|
||||||
|
allDay: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Birthday Party',
|
||||||
|
start: new Date(y, m, d+1, 19, 0),
|
||||||
|
end: new Date(y, m, d+1, 22, 30),
|
||||||
|
allDay: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Click for Google',
|
||||||
|
start: new Date(y, m, 28),
|
||||||
|
end: new Date(y, m, 29),
|
||||||
|
url: 'http://google.com/'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style type='text/css'>
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin-top: 40px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#calendar {
|
||||||
|
width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id='calendar'></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue