Bug 1633772 - End date, entry date and due date of last occurrence and exceptions are now considered when computing recurrence end date. r=pmorris
authorChris <chris@birdiesync.com>
Thu, 07 May 2020 11:49:11 +0200
changeset 38241 d57944ea052e2e067d7ee2b096e0613e8d86b074
parent 38240 7ae3a50f2816e6508e1e2f806a480ce6c3eebd07
child 38242 03319b23c7f92ce298c64e305641e5e6bbda4926
push id2607
push userclokep@gmail.com
push dateMon, 01 Jun 2020 20:50:20 +0000
treeherdercomm-beta@9d45cd34927b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspmorris
bugs1633772
Bug 1633772 - End date, entry date and due date of last occurrence and exceptions are now considered when computing recurrence end date. r=pmorris
calendar/base/src/CalRecurrenceInfo.jsm
--- a/calendar/base/src/CalRecurrenceInfo.jsm
+++ b/calendar/base/src/CalRecurrenceInfo.jsm
@@ -132,35 +132,70 @@ CalRecurrenceInfo.prototype = {
     for (let ritem of this.mRecurrenceItems) {
       if (!ritem.isFinite) {
         return false;
       }
     }
     return true;
   },
 
+  /**
+   * Get the item ending date (end date for an event, due date or entry date if available for a task).
+   *
+   * @param {calIEvent | calITodo} item - The item.
+   * @return {calIDateTime | null} The ending date or null.
+   */
+  getItemEndingDate(item) {
+    if (cal.item.isEvent(item)) {
+      if (item.endDate) {
+        return item.endDate;
+      }
+    } else if (cal.item.isToDo(item)) {
+      // Due date must be considered since it is used when displaying the task in agenda view.
+      if (item.dueDate) {
+        return item.dueDate;
+      } else if (item.entryDate) {
+        return item.entryDate;
+      }
+    }
+    return null;
+  },
+
   get recurrenceEndDate() {
     // The lowest and highest possible values of a PRTime (64-bit integer) when in javascript,
     // which stores them as floating-point values.
     const MIN_PRTIME = -0x7ffffffffffffdff;
     const MAX_PRTIME = 0x7ffffffffffffdff;
 
     // If this object is mutable, skip this optimisation, so that we don't have to work out every
     // possible modification and invalidate the cached value. Immutable objects are unlikely to
     // exist for long enough to really benefit anyway.
     if (this.isMutable) {
       return MAX_PRTIME;
     }
 
     if (this.mEndDate === null) {
       if (this.isFinite) {
         this.mEndDate = MIN_PRTIME;
-        let lastRecurrence = this.getPreviousOccurrence(cal.createDateTime("99991231T235959Z"));
-        if (lastRecurrence) {
-          this.mEndDate = lastRecurrence.endDate.nativeTime;
+        let lastOccurrence = this.getPreviousOccurrence(cal.createDateTime("99991231T235959Z"));
+        if (lastOccurrence) {
+          let endingDate = this.getItemEndingDate(lastOccurrence);
+          if (endingDate) {
+            this.mEndDate = endingDate.nativeTime;
+          }
+        }
+
+        // A modified occurrence may have a new ending date positioned after last occurrence one.
+        for (let rid in this.mExceptionMap) {
+          let item = this.mExceptionMap[rid];
+
+          let endingDate = this.getItemEndingDate(item);
+          if (endingDate && this.mEndDate < endingDate.nativeTime) {
+            this.mEndDate = endingDate.nativeTime;
+          }
         }
       } else {
         this.mEndDate = MAX_PRTIME;
       }
     }
 
     return this.mEndDate;
   },