|
|
@@ -254,10 +254,11 @@ function _parseCalendarEntry(event, knownDomains) {
|
|
254
|
254
|
}
|
|
255
|
255
|
|
|
256
|
256
|
/**
|
|
257
|
|
- * Updates the calendar entries in redux when new list is received. This
|
|
258
|
|
- * function also dedupes the list of entries based on exact match for title, URL
|
|
259
|
|
- * and time of the day and then sorts by time and limits the list
|
|
260
|
|
- * to MAX_LIST_LENGTH.
|
|
|
257
|
+ * Updates the calendar entries in redux when new list is received. The feature
|
|
|
258
|
+ * calendar-sync doesn't display all calendar events, it displays unique
|
|
|
259
|
+ * title, URL, and start time tuples i.e. it doesn't display subsequent
|
|
|
260
|
+ * occurrences of recurring events, and the repetitions of events coming from
|
|
|
261
|
+ * multiple calendars.
|
|
261
|
262
|
*
|
|
262
|
263
|
* XXX The function's {@code this} is the redux store.
|
|
263
|
264
|
*
|
|
|
@@ -266,42 +267,58 @@ function _parseCalendarEntry(event, knownDomains) {
|
|
266
|
267
|
* @returns {void}
|
|
267
|
268
|
*/
|
|
268
|
269
|
function _updateCalendarEntries(events) {
|
|
269
|
|
- if (events && events.length) {
|
|
270
|
|
- // eslint-disable-next-line no-invalid-this
|
|
271
|
|
- const { dispatch, getState } = this;
|
|
272
|
|
- const knownDomains = getState()['features/base/known-domains'];
|
|
273
|
|
- const now = Date.now();
|
|
274
|
|
- const entryMap = new Map();
|
|
275
|
|
-
|
|
276
|
|
- for (const event of events) {
|
|
277
|
|
- const calendarEntry = _parseCalendarEntry(event, knownDomains);
|
|
278
|
|
-
|
|
279
|
|
- if (calendarEntry && calendarEntry.endDate > now) {
|
|
280
|
|
- // This is the data structure we'll try to match all entries to.
|
|
281
|
|
- // The smaller the better, hence the single letter field names.
|
|
282
|
|
- const eventMatchHash = md5.hex(JSON.stringify({
|
|
283
|
|
- d: new Date(calendarEntry.startDate).toTimeString(),
|
|
284
|
|
- t: calendarEntry.title,
|
|
285
|
|
- u: calendarEntry.url
|
|
286
|
|
- }));
|
|
287
|
|
- const existingEntry = entryMap.get(eventMatchHash);
|
|
288
|
|
-
|
|
289
|
|
- // We need to dedupe the list based on title, URL and time of
|
|
290
|
|
- // the day, and only show the first occurence. So if there was
|
|
291
|
|
- // no matcing entry or there was, but its a later event, we
|
|
292
|
|
- // overwrite/save it in the map.
|
|
293
|
|
- if (!existingEntry
|
|
294
|
|
- || existingEntry.startDate > event.startDate) {
|
|
295
|
|
- entryMap.set(eventMatchHash, calendarEntry);
|
|
296
|
|
- }
|
|
|
270
|
+ if (!events || !events.length) {
|
|
|
271
|
+ return;
|
|
|
272
|
+ }
|
|
|
273
|
+
|
|
|
274
|
+ // eslint-disable-next-line no-invalid-this
|
|
|
275
|
+ const { dispatch, getState } = this;
|
|
|
276
|
+ const knownDomains = getState()['features/base/known-domains'];
|
|
|
277
|
+ const now = Date.now();
|
|
|
278
|
+ const entryMap = new Map();
|
|
|
279
|
+
|
|
|
280
|
+ for (const event of events) {
|
|
|
281
|
+ const entry = _parseCalendarEntry(event, knownDomains);
|
|
|
282
|
+
|
|
|
283
|
+ if (entry && entry.endDate > now) {
|
|
|
284
|
+ // As was stated above, we don't display subsequent occurrences of
|
|
|
285
|
+ // recurring events, and the repetitions of events coming from
|
|
|
286
|
+ // multiple calendars.
|
|
|
287
|
+ const key = md5.hex(JSON.stringify([
|
|
|
288
|
+
|
|
|
289
|
+ // Obviously, we want to display different conference/meetings
|
|
|
290
|
+ // URLs. URLs are the very reason why we implemented the feature
|
|
|
291
|
+ // calendar-sync in the first place.
|
|
|
292
|
+ entry.url,
|
|
|
293
|
+
|
|
|
294
|
+ // We probably want to display one and the same URL to people if
|
|
|
295
|
+ // they have it under different titles in their Calendar.
|
|
|
296
|
+ // Because maybe they remember the title of the meeting, not the
|
|
|
297
|
+ // URL so they expect to see the title without realizing that
|
|
|
298
|
+ // they have the same URL already under a different title.
|
|
|
299
|
+ entry.title,
|
|
|
300
|
+
|
|
|
301
|
+ // XXX Eventually, given that the URL and the title are the
|
|
|
302
|
+ // same, what sets one event apart from another is the start
|
|
|
303
|
+ // time of the day (note the use of toTimeString() bellow)! The
|
|
|
304
|
+ // day itself is not important because we don't want multiple
|
|
|
305
|
+ // occurrences of a recurring event or repetitions of an even
|
|
|
306
|
+ // from multiple calendars.
|
|
|
307
|
+ new Date(entry.startDate).toTimeString()
|
|
|
308
|
+ ]));
|
|
|
309
|
+ const existingEntry = entryMap.get(key);
|
|
|
310
|
+
|
|
|
311
|
+ // We want only the earliest occurrence (which hasn't ended in the
|
|
|
312
|
+ // past, that is) of a recurring event.
|
|
|
313
|
+ if (!existingEntry || existingEntry.startDate > entry.startDate) {
|
|
|
314
|
+ entryMap.set(key, entry);
|
|
297
|
315
|
}
|
|
298
|
316
|
}
|
|
299
|
|
-
|
|
300
|
|
- dispatch(
|
|
301
|
|
- setCalendarEvents(
|
|
302
|
|
- Array.from(entryMap.values())
|
|
303
|
|
- .sort((a, b) => a.startDate - b.startDate)
|
|
304
|
|
- .slice(0, MAX_LIST_LENGTH)
|
|
305
|
|
- ));
|
|
306
|
317
|
}
|
|
|
318
|
+
|
|
|
319
|
+ dispatch(
|
|
|
320
|
+ setCalendarEvents(
|
|
|
321
|
+ Array.from(entryMap.values())
|
|
|
322
|
+ .sort((a, b) => a.startDate - b.startDate)
|
|
|
323
|
+ .slice(0, MAX_LIST_LENGTH)));
|
|
307
|
324
|
}
|