diff --git a/src/Calendar.js b/src/Calendar.js index e5f8842..4e2553c 100644 --- a/src/Calendar.js +++ b/src/Calendar.js @@ -8,10 +8,12 @@ function Calendar(element, options, eventSources) { t.options = options; t.render = render; t.destroy = destroy; + t.refetchEvents = refetchEvents; + t.reportEvents = reportEvents; + t.reportEventChange = reportEventChange; t.changeView = changeView; t.select = select; t.unselect = unselect; - t.rerenderEvents = rerenderEvents; // todo: seems liks an EventManager thing t.prev = prev; t.next = next; t.prevYear = prevYear; @@ -29,9 +31,8 @@ function Calendar(element, options, eventSources) { // imports EventManager.call(t, options, eventSources); - var fetchEvents = t.fetchEvents; var isFetchNeeded = t.isFetchNeeded; - var clientEvents = t.clientEvents; + var fetchEvents = t.fetchEvents; // locals @@ -48,6 +49,7 @@ function Calendar(element, options, eventSources) { var resizeUID = 0; var ignoreWindowResize = 0; var date = new Date(); + var events = []; @@ -63,8 +65,8 @@ function Calendar(element, options, eventSources) { initialRender(); }else{ calcSize(); - sizesDirty(); - eventsDirty(); + markSizesDirty(); + markEventsDirty(); renderView(inc); } } @@ -140,10 +142,6 @@ function Calendar(element, options, eventSources) { var newViewElement; if (oldView) { - if (oldView.eventsChanged) { - eventsDirty(); - oldView.eventDirty = oldView.eventsChanged = false; - } (oldView.beforeHide || noop)(); // called before changing min-height. if called after, scroll state is reset (in Opera) setMinHeight(content, content.height()); oldView.element.hide(); @@ -196,29 +194,28 @@ function Calendar(element, options, eventSources) { calcSize(); } + var forceEventRender = false; if (!currentView.start || inc || date < currentView.start || date >= currentView.end) { + // view must render an entire new date range (and refetch/render events) currentView.render(date, inc || 0); // responsible for clearing events setSize(true); - if (!options.lazyFetching || isFetchNeeded()) { - fetchAndRenderEvents(); - }else{ - currentView.renderEvents(clientEvents()); // don't refetch - } + forceEventRender = true; } - else if (currentView.sizeDirty || currentView.eventsDirty || !options.lazyFetching) { + else if (currentView.sizeDirty) { + // view must resize (and rerender events) currentView.clearEvents(); - if (currentView.sizeDirty) { - setSize(); - } - if (!options.lazyFetching || isFetchNeeded()) { - fetchAndRenderEvents(); - }else{ - currentView.renderEvents(clientEvents()); // don't refetch - } + setSize(); + forceEventRender = true; + } + else if (currentView.eventsDirty) { + currentView.clearEvents(); + forceEventRender = true; } - elementOuterWidth = element.outerWidth(); currentView.sizeDirty = false; currentView.eventsDirty = false; + updateEvents(forceEventRender); + + elementOuterWidth = element.outerWidth(); header.updateTitle(currentView.title); var today = new Date(); @@ -239,6 +236,25 @@ function Calendar(element, options, eventSources) { -----------------------------------------------------------------------------*/ + function updateSize() { + markSizesDirty(); + if (elementVisible()) { + calcSize(); + setSize(); + unselect(); + currentView.renderEvents(events); + currentView.sizeDirty = false; + } + } + + + function markSizesDirty() { + $.each(viewInstances, function(i, inst) { + inst.sizeDirty = true; + }); + } + + function calcSize() { if (options.contentHeight) { suggestedViewHeight = options.contentHeight; @@ -272,7 +288,7 @@ function Calendar(element, options, eventSources) { if (uid == resizeUID && !ignoreWindowResize && elementVisible()) { if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) { ignoreWindowResize++; // in case the windowResize callback changes the height - sizeChanged(); + updateSize(); currentView.trigger('windowResize', _element); ignoreWindowResize--; } @@ -286,58 +302,57 @@ function Calendar(element, options, eventSources) { } - // called when we know the element size has changed - function sizeChanged() { - sizesDirty(); - if (elementVisible()) { - calcSize(); - setSize(); - unselect(); - currentView.rerenderEvents(); - currentView.sizeDirty = false; + + /* Event Fetching/Rendering + -----------------------------------------------------------------------------*/ + + + // fetches events if necessary, rerenders events if necessary (or if forced) + function updateEvents(forceRender) { + if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) { + refetchEvents(); + } + else if (forceRender) { + rerenderEvents(); } } - // marks other views' sizes as dirty - function sizesDirty() { - $.each(viewInstances, function(i, inst) { - inst.sizeDirty = true; - }); + function refetchEvents() { + fetchEvents(currentView.visStart, currentView.visEnd); // will call reportEvents } - - /* Event Rendering - -----------------------------------------------------------------------------*/ + // called when event data arrives + function reportEvents(_events) { + events = _events; + rerenderEvents(); + } - // called when any event objects have been added/removed/changed, rerenders - function rerenderEvents() { - eventsDirty(); + // called when a single event's data has been changed + function reportEventChange(eventID) { + rerenderEvents(eventID); + } + + + // attempts to rerenderEvents + function rerenderEvents(modifiedEventID) { + markEventsDirty(); if (elementVisible()) { currentView.clearEvents(); - currentView.renderEvents(clientEvents()); + currentView.renderEvents(events, modifiedEventID); currentView.eventsDirty = false; } } - // marks every views' events as dirty - function eventsDirty() { + function markEventsDirty() { $.each(viewInstances, function(i, inst) { inst.eventsDirty = true; }); } - - // for convenience - function fetchAndRenderEvents() { - fetchEvents(function(events) { - currentView.renderEvents(events); // maintain `this` in view - }); - } - /* Selection @@ -434,7 +449,7 @@ function Calendar(element, options, eventSources) { } if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') { options[name] = value; - sizeChanged(); + updateSize(); } } diff --git a/src/EventManager.js b/src/EventManager.js index e339feb..51a52b5 100644 --- a/src/EventManager.js +++ b/src/EventManager.js @@ -1,14 +1,13 @@ var eventGUID = 1; -function EventManager(options, eventSources) { +function EventManager(options, sources) { var t = this; // exports - t.fetchEvents = fetchEvents; - t.refetchEvents = refetchEvents; t.isFetchNeeded = isFetchNeeded; + t.fetchEvents = fetchEvents; t.addEventSource = addEventSource; t.removeEventSource = removeEventSource; t.updateEvent = updateEvent; @@ -19,17 +18,91 @@ function EventManager(options, eventSources) { // imports - var getDate = t.getDate; - var getView = t.getView; var trigger = t.trigger; - var rerenderEvents = t.rerenderEvents; - + var getView = t.getView; + var reportEvents = t.reportEvents; + // locals - var fetchID = 0; - var eventStart, eventEnd; - var events = []; + var rangeStart, rangeEnd; + var currentFetchID = 0; + var pendingSourceCnt = 0; var loadingLevel = 0; + var dynamicEventSource = []; + var cache = []; + + + + /* Fetching + -----------------------------------------------------------------------------*/ + + + function isFetchNeeded(start, end) { + return !rangeStart || start < rangeStart || end > rangeEnd; + } + + + function fetchEvents(start, end) { + rangeStart = start; + rangeEnd = end; + currentFetchID++; + cache = []; + pendingSourceCnt = sources.length; + for (var i=0; i= currentView.visEnd) { - // same fetchEventSources call, and still in correct date range - if ($.inArray(source, eventSources) != -1) { // source hasn't been removed since we started - for (var i=0; i eventEnd; + reportEvents(cache); } @@ -161,14 +138,14 @@ function EventManager(options, eventSources) { function updateEvent(event) { // update an existing event - var i, len = events.length, e, - defaultEventEnd = getView().defaultEventEnd, + var i, len = cache.length, e, + defaultEventEnd = getView().defaultEventEnd, // getView??? 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 + + + + + + + + + +
+ +