Parcourir la source

fully hook up new event rendering

Adam Shaw il y a 9 ans
Parent
commit
4e6d9b86c3
3 fichiers modifiés avec 105 ajouts et 129 suppressions
  1. 5 54
      src/Calendar.js
  2. 77 69
      src/EventManager.js
  3. 23 6
      src/common/View.js

+ 5 - 54
src/Calendar.js

@@ -271,11 +271,7 @@ function Calendar_constructor(element, overrides) {
 
 
 	t.render = render;
 	t.render = render;
 	t.destroy = destroy;
 	t.destroy = destroy;
-	t.refetchEvents = refetchEvents;
-	t.refetchEventSources = refetchEventSources;
-	t.reportEvents = reportEvents;
-	t.reportEventChange = reportEventChange;
-	t.rerenderEvents = renderEvents; // `renderEvents` serves as a rerender. an API method
+	t.rerenderEvents = rerenderEvents;
 	t.changeView = renderView; // `renderView` will switch to another view
 	t.changeView = renderView; // `renderView` will switch to another view
 	t.select = select;
 	t.select = select;
 	t.unselect = unselect;
 	t.unselect = unselect;
@@ -511,7 +507,6 @@ function Calendar_constructor(element, overrides) {
 	var suggestedViewHeight;
 	var suggestedViewHeight;
 	var windowResizeProxy; // wraps the windowResize function
 	var windowResizeProxy; // wraps the windowResize function
 	var ignoreWindowResize = 0;
 	var ignoreWindowResize = 0;
-	var events = [];
 	var date; // unzoned
 	var date; // unzoned
 
 
 
 
@@ -674,8 +669,6 @@ function Calendar_constructor(element, overrides) {
 					// need to do this after View::render, so dates are calculated
 					// need to do this after View::render, so dates are calculated
 					// NOTE: view updates title text proactively
 					// NOTE: view updates title text proactively
 					updateToolbarsTodayButton();
 					updateToolbarsTodayButton();
-
-					getAndRenderEvents();
 				}
 				}
 			}
 			}
 		}
 		}
@@ -800,56 +793,14 @@ function Calendar_constructor(element, overrides) {
 
 
 
 
 
 
-	/* Event Fetching/Rendering
+	/* Event Rendering
 	-----------------------------------------------------------------------------*/
 	-----------------------------------------------------------------------------*/
-	// TODO: going forward, most of this stuff should be directly handled by the view
-
-
-	function refetchEvents() { // can be called as an API method
-		fetchAndRenderEvents();
-	}
-
 
 
-	// TODO: move this into EventManager?
-	function refetchEventSources(matchInputs) {
-		fetchEventSources(t.getEventSourcesByMatchArray(matchInputs));
-	}
 
 
-
-	function renderEvents() { // destroys old events if previously rendered
+	function rerenderEvents() { // API method. destroys old events if previously rendered.
 		if (elementVisible()) {
 		if (elementVisible()) {
-			//currentView.displayEvents(events);
-		}
-	}
-
-
-	function getAndRenderEvents() {
-		if (!t.options.lazyFetching || isFetchNeeded(currentView.start, currentView.end)) {
-			fetchAndRenderEvents();
+			currentView.displayEvents();
 		}
 		}
-		else {
-			renderEvents();
-		}
-	}
-
-
-	function fetchAndRenderEvents() {
-		fetchEvents(currentView.start, currentView.end);
-			// ... will call reportEvents
-			// ... which will call renderEvents
-	}
-
-
-	// called when event data arrives
-	function reportEvents(_events) {
-		events = _events;
-		renderEvents();
-	}
-
-
-	// called when a single event's data has been changed
-	function reportEventChange() {
-		renderEvents();
 	}
 	}
 
 
 
 
@@ -1101,7 +1052,7 @@ function Calendar_constructor(element, overrides) {
 			}
 			}
 			else if (optionName === 'timezone') {
 			else if (optionName === 'timezone') {
 				t.rezoneArrayEventSources();
 				t.rezoneArrayEventSources();
-				refetchEvents();
+				t.refetchEvents();
 				return;
 				return;
 			}
 			}
 		}
 		}

+ 77 - 69
src/EventManager.js

@@ -15,13 +15,15 @@ function EventManager() { // assumed to be a calendar
 
 
 
 
 	// exports
 	// exports
+	t.requestEvents = requestEvents;
+	t.reportEventChange = reportEventChange;
 	t.isFetchNeeded = isFetchNeeded;
 	t.isFetchNeeded = isFetchNeeded;
 	t.fetchEvents = fetchEvents;
 	t.fetchEvents = fetchEvents;
 	t.fetchEventSources = fetchEventSources;
 	t.fetchEventSources = fetchEventSources;
+	t.refetchEvents = refetchEvents;
+	t.refetchEventSources = refetchEventSources;
 	t.getEventSources = getEventSources;
 	t.getEventSources = getEventSources;
 	t.getEventSourceById = getEventSourceById;
 	t.getEventSourceById = getEventSourceById;
-	t.getEventSourcesByMatchArray = getEventSourcesByMatchArray;
-	t.getEventSourcesByMatch = getEventSourcesByMatch;
 	t.addEventSource = addEventSource;
 	t.addEventSource = addEventSource;
 	t.removeEventSource = removeEventSource;
 	t.removeEventSource = removeEventSource;
 	t.removeEventSources = removeEventSources;
 	t.removeEventSources = removeEventSources;
@@ -36,15 +38,10 @@ function EventManager() { // assumed to be a calendar
 	t.normalizeEventTimes = normalizeEventTimes;
 	t.normalizeEventTimes = normalizeEventTimes;
 
 
 
 
-	// imports
-	var reportEvents = t.reportEvents;
-
-
 	// locals
 	// locals
 	var stickySource = { events: [] };
 	var stickySource = { events: [] };
 	var sources = [ stickySource ];
 	var sources = [ stickySource ];
 	var rangeStart, rangeEnd;
 	var rangeStart, rangeEnd;
-	var pendingSourceCnt = 0; // outstanding fetch requests, max one per source
 	var cache = []; // holds events that have already been expanded
 	var cache = []; // holds events that have already been expanded
 
 
 
 
@@ -60,6 +57,22 @@ function EventManager() { // assumed to be a calendar
 
 
 
 
 
 
+	function requestEvents(start, end) {
+		if (!t.options.lazyFetching || isFetchNeeded(start, end)) {
+			return fetchEvents(start, end);
+		}
+		else {
+			return Promise.resolve(cache);
+		}
+	}
+
+
+	function reportEventChange() {
+		t.triggerWith('resetEvents', t, [ cache ]); // NOTE: wish we could use .trigger, but Calendar overrides it :(
+	}
+
+
+
 	/* Fetching
 	/* Fetching
 	-----------------------------------------------------------------------------*/
 	-----------------------------------------------------------------------------*/
 
 
@@ -74,7 +87,19 @@ function EventManager() { // assumed to be a calendar
 	function fetchEvents(start, end) {
 	function fetchEvents(start, end) {
 		rangeStart = start;
 		rangeStart = start;
 		rangeEnd = end;
 		rangeEnd = end;
-		fetchEventSources(sources, 'reset');
+		return refetchEvents();
+	}
+
+
+	// poorly named. fetches all sources with current `rangeStart` and `rangeEnd`.
+	function refetchEvents() {
+		return fetchEventSources(sources, 'reset');
+	}
+
+
+	// poorly named. fetches a subset of event sources.
+	function refetchEventSources(matchInputs) {
+		return fetchEventSources(getEventSourcesByMatchArray(matchInputs));
 	}
 	}
 
 
 
 
@@ -82,6 +107,7 @@ function EventManager() { // assumed to be a calendar
 	// `specialFetchType` is an optimization parameter that affects purging of the event cache.
 	// `specialFetchType` is an optimization parameter that affects purging of the event cache.
 	function fetchEventSources(specificSources, specialFetchType) {
 	function fetchEventSources(specificSources, specialFetchType) {
 		var i, source;
 		var i, source;
+		var promises = [];
 
 
 		if (specialFetchType === 'reset') {
 		if (specialFetchType === 'reset') {
 			cache = [];
 			cache = [];
@@ -92,83 +118,65 @@ function EventManager() { // assumed to be a calendar
 
 
 		for (i = 0; i < specificSources.length; i++) {
 		for (i = 0; i < specificSources.length; i++) {
 			source = specificSources[i];
 			source = specificSources[i];
-
-			// already-pending sources have already been accounted for in pendingSourceCnt
-			if (source._status !== 'pending') {
-				pendingSourceCnt++;
-			}
-
 			source._fetchId = (source._fetchId || 0) + 1;
 			source._fetchId = (source._fetchId || 0) + 1;
-			source._status = 'pending';
 		}
 		}
 
 
 		for (i = 0; i < specificSources.length; i++) {
 		for (i = 0; i < specificSources.length; i++) {
 			source = specificSources[i];
 			source = specificSources[i];
-
-			tryFetchEventSource(source, source._fetchId);
+			promises.push(tryFetchEventSource(source, source._fetchId));
 		}
 		}
-	}
 
 
+		return Promise.all(promises).then(function(sourcesResults) {
 
 
-	// fetches an event source and processes its result ONLY if it is still the current fetch.
-	// caller is responsible for incrementing pendingSourceCnt first.
-	function tryFetchEventSource(source, fetchId) {
-		_fetchEventSource(source, function(eventInputs) {
-			var isArraySource = $.isArray(source.events);
-			var i, eventInput;
-			var abstractEvent;
+			for (i = 0; i < sourcesResults.length; i++) {
+				cache.push.apply(cache, // append
+					sourcesResults[i]);
+			}
 
 
-			if (
-				// is this the source's most recent fetch?
-				// if not, rely on an upcoming fetch of this source to decrement pendingSourceCnt
-				fetchId === source._fetchId &&
-				// event source no longer valid?
-				source._status !== 'rejected'
-			) {
-				source._status = 'resolved';
+			reportEventChange();
 
 
-				if (eventInputs) {
-					for (i = 0; i < eventInputs.length; i++) {
-						eventInput = eventInputs[i];
+			return cache;
+		});
+	}
 
 
-						if (isArraySource) { // array sources have already been convert to Event Objects
-							abstractEvent = eventInput;
-						}
-						else {
-							abstractEvent = buildEventFromInput(eventInput, source);
-						}
 
 
-						if (abstractEvent) { // not false (an invalid event)
-							cache.push.apply(
-								cache,
-								expandEvent(abstractEvent) // add individual expanded events to the cache
-							);
+	// fetches an event source and processes its result ONLY if it is still the current fetch.
+	function tryFetchEventSource(source, fetchId) {
+		return new Promise(function(resolve) {
+			_fetchEventSource(source, function(eventInputs) {
+				var processedEvents = [];
+				var isArraySource = $.isArray(source.events);
+				var i, eventInput;
+				var abstractEvent;
+
+				if (fetchId === source._fetchId) { // still a valid fetch?
+					if (eventInputs) {
+						for (i = 0; i < eventInputs.length; i++) {
+							eventInput = eventInputs[i];
+
+							if (isArraySource) { // array sources have already been convert to Event Objects
+								abstractEvent = eventInput;
+							}
+							else {
+								abstractEvent = buildEventFromInput(eventInput, source);
+							}
+
+							if (abstractEvent) { // not false (an invalid event)
+								processedEvents.push.apply(processedEvents, // append
+									expandEvent(abstractEvent));
+							}
 						}
 						}
 					}
 					}
 				}
 				}
 
 
-				decrementPendingSourceCnt();
-			}
+				resolve(processedEvents);
+			});
 		});
 		});
 	}
 	}
 
 
 
 
 	function rejectEventSource(source) {
 	function rejectEventSource(source) {
-		var wasPending = source._status === 'pending';
-
-		source._status = 'rejected';
-
-		if (wasPending) {
-			decrementPendingSourceCnt();
-		}
-	}
-
-
-	function decrementPendingSourceCnt() {
-		pendingSourceCnt--;
-		if (!pendingSourceCnt) {
-			reportEvents(cache);
-		}
+		source._fetchId++; // invalidates current fetch // TODO: don't wait for it!
 	}
 	}
 
 
 
 
@@ -291,7 +299,7 @@ function EventManager() { // assumed to be a calendar
 		var source = buildEventSource(sourceInput);
 		var source = buildEventSource(sourceInput);
 		if (source) {
 		if (source) {
 			sources.push(source);
 			sources.push(source);
-			fetchEventSources([ source ], 'add'); // will eventually call reportEvents
+			fetchEventSources([ source ], 'add'); // will eventually call reportEventChange
 		}
 		}
 	}
 	}
 
 
@@ -387,7 +395,7 @@ function EventManager() { // assumed to be a calendar
 			cache = excludeEventsBySources(cache, targetSources);
 			cache = excludeEventsBySources(cache, targetSources);
 		}
 		}
 
 
-		reportEvents(cache);
+		reportEventChange();
 	}
 	}
 
 
 
 
@@ -513,7 +521,7 @@ function EventManager() { // assumed to be a calendar
 			mutateEvent(event, getMiscEventProps(event)); // will handle start/end/allDay normalization
 			mutateEvent(event, getMiscEventProps(event)); // will handle start/end/allDay normalization
 		}
 		}
 
 
-		reportEvents(cache); // reports event modifications (so we can redraw)
+		reportEventChange(); // reports event modifications (so we can redraw)
 	}
 	}
 
 
 
 
@@ -574,7 +582,7 @@ function EventManager() { // assumed to be a calendar
 		}
 		}
 
 
 		if (renderedEvents.length) { // any new events rendered?
 		if (renderedEvents.length) { // any new events rendered?
-			reportEvents(cache);
+			reportEventChange();
 		}
 		}
 
 
 		return renderedEvents;
 		return renderedEvents;
@@ -607,7 +615,7 @@ function EventManager() { // assumed to be a calendar
 			}
 			}
 		}
 		}
 
 
-		reportEvents(cache);
+		reportEventChange();
 	}
 	}
 
 
 
 

+ 23 - 6
src/common/View.js

@@ -814,16 +814,34 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
 	// Returns a potentially-asynchronous promise.
 	// Returns a potentially-asynchronous promise.
 	displayEvents: function() {
 	displayEvents: function() {
 		var _this = this;
 		var _this = this;
+
+		return this.displayGivenEvents(this.requestEvents()).then(function() {
+			_this.listenTo(_this.calendar, 'resetEvents', _this.displayGivenEvents); // react to changes
+		});
+	},
+
+
+	clearEvents: function() {
+		var _this = this;
+
+		return this.clearGivenEvents().then(function() {
+			_this.stopListeningTo(_this.calendar, 'resetEvents'); // stop reacting to changes
+		});
+	},
+
+
+	displayGivenEvents: function(eventArg) { // eventArg can be an array or a promise
+		var _this = this;
 		var scrollState = this.queryScroll();
 		var scrollState = this.queryScroll();
 
 
 		this.calendar.freezeContentHeight();
 		this.calendar.freezeContentHeight();
 
 
-		return this.displayingEvents = this.clearEvents().then(function() {
+		return this.displayingEvents = this.clearGivenEvents().then(function() {
 			return Promise.all([
 			return Promise.all([
-				_this.requestEvents(),
+				eventArg,
 				_this.displayDates()
 				_this.displayDates()
 			]).then(function(values) {
 			]).then(function(values) {
-				_this.renderEvents(values[0]); // value[0] is the events array
+				_this.renderEvents(values[0]); // values[0] is the resolved event argument
 				_this.calendar.unfreezeContentHeight();
 				_this.calendar.unfreezeContentHeight();
 				_this.setScroll(scrollState);
 				_this.setScroll(scrollState);
 				_this.triggerEventRender();
 				_this.triggerEventRender();
@@ -834,7 +852,7 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
 
 
 	// Does everything necessary to clear the view's currently-rendered events.
 	// Does everything necessary to clear the view's currently-rendered events.
 	// Returns a potentially-asynchronous promise.
 	// Returns a potentially-asynchronous promise.
-	clearEvents: function() {
+	clearGivenEvents: function() {
 		var _this = this;
 		var _this = this;
 		// TODO: optimize: if we know this is part of a displayEvents call, don't queryScroll/setScroll
 		// TODO: optimize: if we know this is part of a displayEvents call, don't queryScroll/setScroll
 		var scrollState = this.queryScroll();
 		var scrollState = this.queryScroll();
@@ -856,9 +874,8 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
 	},
 	},
 
 
 
 
-	// stub
 	requestEvents: function() {
 	requestEvents: function() {
-		return Promise.resolve([]);
+		return this.calendar.requestEvents(this.start, this.end);
 	},
 	},