Bug 1433156 - Move item related functions into calItemUtils.jsm - automatic changes. r=MakeMyDay
authorPhilipp Kewisch <mozilla@kewis.ch>
Sun, 15 Oct 2017 09:46:41 +0200
changeset 31013 1794487157f7f65e63a8774bca6035e554d2be8d
parent 31012 593b026dc5253ba0426c32f88d519fc9e9aab82c
child 31014 033ede986813abe46b060a294645a46de42b21b1
push id383
push userclokep@gmail.com
push dateMon, 07 May 2018 21:52:48 +0000
reviewersMakeMyDay
bugs1433156
Bug 1433156 - Move item related functions into calItemUtils.jsm - automatic changes. r=MakeMyDay MozReview-Commit-ID: 5zgCtmiv30S
calendar/base/content/agenda-listbox.js
calendar/base/content/calendar-base-view.xml
calendar/base/content/calendar-clipboard.js
calendar/base/content/calendar-common-sets.js
calendar/base/content/calendar-dnd-listener.js
calendar/base/content/calendar-extract.js
calendar/base/content/calendar-item-bindings.xml
calendar/base/content/calendar-item-editing.js
calendar/base/content/calendar-month-view.xml
calendar/base/content/calendar-multiday-view.xml
calendar/base/content/calendar-task-tree.js
calendar/base/content/calendar-task-tree.xml
calendar/base/content/calendar-ui-utils.js
calendar/base/content/calendar-unifinder.js
calendar/base/content/calendar-view-core.xml
calendar/base/content/calendar-views.js
calendar/base/content/dialogs/calendar-dialog-utils.js
calendar/base/content/dialogs/calendar-event-dialog-recurrence.js
calendar/base/content/dialogs/calendar-event-dialog-reminder.js
calendar/base/content/dialogs/calendar-occurrence-prompt.xul
calendar/base/content/dialogs/calendar-print-dialog.js
calendar/base/content/dialogs/calendar-summary-dialog.js
calendar/base/content/widgets/calendar-alarm-widget.xml
calendar/base/content/widgets/calendar-widgets.xml
calendar/base/modules/calAlarmUtils.jsm
calendar/base/modules/calDateTimeUtils.jsm
calendar/base/modules/calItipUtils.jsm
calendar/base/modules/calViewUtils.jsm
calendar/base/src/calAlarm.js
calendar/base/src/calAlarmService.js
calendar/base/src/calEvent.js
calendar/base/src/calFilter.js
calendar/base/src/calIcsParser.js
calendar/base/src/calIcsSerializer.js
calendar/base/src/calItemBase.js
calendar/base/src/calRecurrenceInfo.js
calendar/base/src/calTodo.js
calendar/import-export/calOutlookCSVImportExport.js
calendar/lightning/components/lightningTextCalendarConverter.js
calendar/lightning/content/lightning-item-iframe.js
calendar/lightning/content/lightning-item-panel.js
calendar/lightning/modules/ltnInvitationUtils.jsm
calendar/providers/caldav/calDavCalendar.js
calendar/providers/gdata/components/calGoogleCalendar.js
calendar/providers/gdata/content/gdata-calendar-event-dialog.js
calendar/providers/gdata/modules/gdataUtils.jsm
calendar/providers/memory/calMemoryCalendar.js
calendar/providers/storage/calStorageCalendar.js
calendar/providers/wcap/calWcapCalendarItems.js
calendar/resources/content/mouseoverPreviews.js
calendar/test/unit/test_gdata_provider.js
calendar/test/unit/test_ics_parser.js
--- a/calendar/base/content/agenda-listbox.js
+++ b/calendar/base/content/agenda-listbox.js
@@ -216,17 +216,17 @@ agendaListbox.editSelectedItem = functio
  * item occurrs tomorrow.
  *
  * @param aItem     The item to find the period for.
  */
 agendaListbox.findPeriodsForItem = function(aItem) {
     let retPeriods = [];
     for (let i = 0; i < this.periods.length; i++) {
         if (this.periods[i].open) {
-            if (cal.checkIfInRange(aItem, this.periods[i].start, this.periods[i].end)) {
+            if (cal.item.checkIfInRange(aItem, this.periods[i].start, this.periods[i].end)) {
                 retPeriods.push(this.periods[i]);
             }
         }
     }
     return retPeriods;
 };
 
 /**
@@ -289,17 +289,17 @@ agendaListbox.addItemBefore = function(a
 /**
  * Adds an item to the agenda listbox. This function finds the correct period
  * for the item and inserts it correctly so the period stays sorted.
  *
  * @param aItem         The calIItemBase to add.
  * @return              The newly created XUL element.
  */
 agendaListbox.addItem = function(aItem) {
-    if (!cal.isEvent(aItem)) {
+    if (!cal.item.isEvent(aItem)) {
         return null;
     }
     let periods = this.findPeriodsForItem(aItem);
     if (periods.length == 0) {
         return null;
     }
     let newlistItem = null;
     for (let i = 0; i < periods.length; i++) {
@@ -884,17 +884,17 @@ agendaListbox.calendarObserver.onStartBa
 agendaListbox.calendarObserver.onEndBatch = function() {
 };
 
 agendaListbox.calendarObserver.onLoad = function() {
     this.agendaListbox.refreshCalendarQuery();
 };
 
 agendaListbox.calendarObserver.onAddItem = function(item) {
-    if (!cal.isEvent(item)) {
+    if (!cal.item.isEvent(item)) {
         return;
     }
     // get all sub items if it is a recurring item
     let occs = this.getOccurrencesBetween(item);
     occs.forEach(this.agendaListbox.addItem, this.agendaListbox);
     setCurrentEvent();
 };
 
@@ -908,34 +908,34 @@ agendaListbox.calendarObserver.getOccurr
     return occs;
 };
 
 agendaListbox.calendarObserver.onDeleteItem = function(item, rebuildFlag) {
     this.onLocalDeleteItem(item, true);
 };
 
 agendaListbox.calendarObserver.onLocalDeleteItem = function(item, moveSelection) {
-    if (!cal.isEvent(item)) {
+    if (!cal.item.isEvent(item)) {
         return false;
     }
     let selectedItemHashId = -1;
     // get all sub items if it is a recurring item
     let occs = this.getOccurrencesBetween(item);
     for (let i = 0; i < occs.length; i++) {
         let isSelected = this.agendaListbox.deleteItem(occs[i], moveSelection);
         if (isSelected) {
             selectedItemHashId = occs[i].hashId;
         }
     }
     return selectedItemHashId;
 };
 
 agendaListbox.calendarObserver.onModifyItem = function(newItem, oldItem) {
     let selectedItemHashId = this.onLocalDeleteItem(oldItem, false);
-    if (!cal.isEvent(newItem)) {
+    if (!cal.item.isEvent(newItem)) {
         return;
     }
     this.onAddItem(newItem);
     if (selectedItemHashId != -1) {
         let listItem = agendaListbox.getListItemByHashId(selectedItemHashId);
         if (listItem) {
             agendaListbox.agendaListboxControl.clearSelection();
             agendaListbox.agendaListboxControl.ensureElementIsVisible(listItem);
--- a/calendar/base/content/calendar-base-view.xml
+++ b/calendar/base/content/calendar-base-view.xml
@@ -74,17 +74,17 @@
               onEndBatch: function() {
               },
 
               onLoad: function() {
                   this.calView.refresh();
               },
 
               onAddItem: function(aItem) {
-                  if (cal.isToDo(aItem)) {
+                  if (cal.item.isToDo(aItem)) {
                       if (!aItem.entryDate && !aItem.dueDate) {
                           return;
                       }
                       if (!this.calView.mTasksInView) {
                           return;
                       }
                       if (aItem.isCompleted && !this.calView.mShowCompleted) {
                           return;
@@ -95,31 +95,31 @@
                                                          this.calView.queryEndDate,
                                                          {});
                   for (let occ of occs) {
                       this.calView.doAddItem(occ);
                   }
               },
 
               onModifyItem: function(aNewItem, aOldItem) {
-                  if (cal.isToDo(aNewItem) && cal.isToDo(aOldItem) &&
+                  if (cal.item.isToDo(aNewItem) && cal.item.isToDo(aOldItem) &&
                       !this.calView.mTasksInView) {
                       return;
                   }
                   let occs;
 
-                  if (!cal.isToDo(aOldItem) || aOldItem.entryDate || aOldItem.dueDate) {
+                  if (!cal.item.isToDo(aOldItem) || aOldItem.entryDate || aOldItem.dueDate) {
                       occs = aOldItem.getOccurrencesBetween(this.calView.startDate,
                                                             this.calView.queryEndDate,
                                                             {});
                       for (let occ of occs) {
                           this.calView.doDeleteItem(occ);
                       }
                   }
-                  if (cal.isToDo(aNewItem)) {
+                  if (cal.item.isToDo(aNewItem)) {
                       if ((!aNewItem.entryDate && !aNewItem.dueDate) || !this.calView.mTasksInView) {
                           return;
                       }
                       if (aNewItem.isCompleted && !this.calView.mShowCompleted) {
                           return;
                       }
                   }
 
@@ -127,17 +127,17 @@
                                                         this.calView.queryEndDate,
                                                         {});
                   for (let occ of occs) {
                       this.calView.doAddItem(occ);
                   }
               },
 
               onDeleteItem: function(aItem) {
-                  if (cal.isToDo(aItem)) {
+                  if (cal.item.isToDo(aItem)) {
                       if (!this.calView.mTasksInView) {
                           return;
                       }
                       if (!aItem.entryDate && !aItem.dueDate) {
                           return;
                       }
                       if (aItem.isCompleted && !this.calView.mShowCompleted) {
                           return;
@@ -471,17 +471,17 @@
                 },
 
                 onGetResult: function(aOpCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
                     if (this.cancelled || !Components.isSuccessCode(aStatus)) {
                         return;
                     }
 
                     for (let item of aItems) {
-                        if (!cal.isToDo(item) || item.entryDate || item.dueDate) {
+                        if (!cal.item.isToDo(item) || item.entryDate || item.dueDate) {
                             this.calView.doAddItem(item);
                         }
                     }
                 },
 
                 cancel: function() {
                     this.calView.mLog.info("Refresh cancelled for calendar " + this.calId);
                     this.cancelled = true;
--- a/calendar/base/content/calendar-clipboard.js
+++ b/calendar/base/content/calendar-clipboard.js
@@ -210,17 +210,17 @@ function pasteFromClipboard() {
 
             startBatchTransaction();
             for (let item of items) {
                 let newItem = item.clone();
                 // Set new UID to allow multiple paste actions of the same
                 // clipboard content.
                 newItem.id = cal.getUUID();
                 if (offset) {
-                    cal.shiftItem(newItem, offset);
+                    cal.item.shiftOffset(newItem, offset);
                 }
                 doTransaction("add", newItem, destCal, null, null);
             }
             endBatchTransaction();
             break;
         }
         default:
             break;
--- a/calendar/base/content/calendar-common-sets.js
+++ b/calendar/base/content/calendar-common-sets.js
@@ -813,23 +813,23 @@ function removeCalendarCommandController
 function setupContextItemType(event, items) {
     function adaptModificationMenuItem(aMenuItemId, aItemType) {
         let menuItem = document.getElementById(aMenuItemId);
         if (menuItem) {
             menuItem.setAttribute("label", cal.calGetString("calendar", "delete" + aItemType + "Label"));
             menuItem.setAttribute("accesskey", cal.calGetString("calendar", "delete" + aItemType + "Accesskey"));
         }
     }
-    if (items.some(cal.isEvent) && items.some(cal.isToDo)) {
+    if (items.some(cal.item.isEvent) && items.some(cal.item.isToDo)) {
         event.target.setAttribute("type", "mixed");
         adaptModificationMenuItem("calendar-item-context-menu-delete-menuitem", "Item");
-    } else if (items.length && cal.isEvent(items[0])) {
+    } else if (items.length && cal.item.isEvent(items[0])) {
         event.target.setAttribute("type", "event");
         adaptModificationMenuItem("calendar-item-context-menu-delete-menuitem", "Event");
-    } else if (items.length && cal.isToDo(items[0])) {
+    } else if (items.length && cal.item.isToDo(items[0])) {
         event.target.setAttribute("type", "todo");
         adaptModificationMenuItem("calendar-item-context-menu-delete-menuitem", "Task");
     } else {
         event.target.removeAttribute("type");
         adaptModificationMenuItem("calendar-item-context-menu-delete-menuitem", "Item");
     }
 
     let menu = document.getElementById("calendar-item-context-menu-attendance-menu");
@@ -906,20 +906,20 @@ function calendarUpdateNewItemsCommand()
         "calendar_new_todo_context_command",
         "calendar_new_todo_todaypane_command"
     ];
 
     // re-calculate command status
     CalendarNewEventsCommandEnabled = false;
     CalendarNewTasksCommandEnabled = false;
     let calendars = cal.getCalendarManager().getCalendars({}).filter(cal.acl.isCalendarWritable).filter(cal.acl.userCanAddItemsToCalendar);
-    if (calendars.some(cal.isEventCalendar)) {
+    if (calendars.some(cal.item.isEventCalendar)) {
         CalendarNewEventsCommandEnabled = true;
     }
-    if (calendars.some(cal.isTaskCalendar)) {
+    if (calendars.some(cal.item.isTaskCalendar)) {
         CalendarNewTasksCommandEnabled = true;
     }
 
     // update command status if required
     if (CalendarNewEventsCommandEnabled != oldEventValue) {
         eventCommands.forEach(goUpdateCommand);
     }
     if (CalendarNewTasksCommandEnabled != oldTaskValue) {
--- a/calendar/base/content/calendar-dnd-listener.js
+++ b/calendar/base/content/calendar-dnd-listener.js
@@ -456,17 +456,17 @@ calCalendarButtonDNDObserver.prototype =
      * Gets called in case we're dropping an array of items
      * on the 'calendar mode'-button.
      *
      * @param aItems        An array of items to handle.
      */
     onDropItems: function(aItems) {
         for (var item of aItems) {
             var newItem = item;
-            if (cal.isToDo(item)) {
+            if (cal.item.isToDo(item)) {
                 newItem = itemConversion.eventFromTask(item);
             }
             createEventWithDialog(null, null, null, null, newItem);
         }
     },
 
     /**
      * calCalendarButtonDNDObserver::onDropMessage
@@ -505,17 +505,17 @@ calTaskButtonDNDObserver.prototype = {
      * Gets called in case we're dropping an array of items
      * on the 'task mode'-button.
      *
      * @param aItems        An array of items to handle.
      */
     onDropItems: function(aItems) {
         for (var item of aItems) {
             var newItem = item;
-            if (cal.isEvent(item)) {
+            if (cal.item.isEvent(item)) {
                 newItem = itemConversion.taskFromEvent(item);
             }
             createTodoWithDialog(null, null, null, newItem);
         }
     },
 
     /**
      * calTaskButtonDNDObserver::onDropMessage
@@ -555,20 +555,20 @@ function invokeEventDragSession(aItem, a
                 aOutData.value = aItem;
                 aOutDataLen.value = 1;
             } else {
                 cal.ASSERT(false, "error:" + aInFlavor);
             }
         }
     };
 
-    if (cal.isEvent(aItem)) {
+    if (cal.item.isEvent(aItem)) {
       transfer.addDataFlavor("application/vnd.x-moz-cal-event");
       transfer.setTransferData("application/vnd.x-moz-cal-event", flavourProvider, 0);
-    } else if (cal.isToDo(aItem)) {
+    } else if (cal.item.isToDo(aItem)) {
       transfer.addDataFlavor("application/vnd.x-moz-cal-task");
       transfer.setTransferData("application/vnd.x-moz-cal-task", flavourProvider, 0);
     }
 
     // Also set some normal data-types, in case we drag into another app
     let serializer = Components.classes["@mozilla.org/calendar/ics-serializer;1"]
                                .createInstance(Components.interfaces.calIIcsSerializer);
     serializer.addItems([aItem], 1);
--- a/calendar/base/content/calendar-extract.js
+++ b/calendar/base/content/calendar-extract.js
@@ -187,19 +187,19 @@ var calendarExtract = {
                 }
                 if (endGuess.hour != null) {
                     dueDate.setHours(endGuess.hour);
                 }
                 if (endGuess.minute != null) {
                     dueDate.setMinutes(endGuess.minute);
                 }
 
-                cal.setItemProperty(item, "entryDate", cal.dtz.jsDateToDateTime(date, dtz));
+                cal.item.setItemProperty(item, "entryDate", cal.dtz.jsDateToDateTime(date, dtz));
                 if (endGuess.year != null) {
-                    cal.setItemProperty(item, "dueDate", cal.dtz.jsDateToDateTime(dueDate, dtz));
+                    cal.item.setItemProperty(item, "dueDate", cal.dtz.jsDateToDateTime(dueDate, dtz));
                 }
             }
 
             // if time not guessed set allday for events
             if (allDay) {
                 createEventWithDialog(null, null, null, null, item, true);
             } else {
                 createEventWithDialog(null, null, null, null, item);
--- a/calendar/base/content/calendar-item-bindings.xml
+++ b/calendar/base/content/calendar-item-bindings.xml
@@ -55,28 +55,28 @@
             this.mItem = val;
             let headerLabel = document.getAnonymousElementByAttribute(this, "anonid", "item-datetime-label");
             let itemDateTimeLabel = document.getAnonymousElementByAttribute(this, "anonid", "item-datetime-value");
             let date;
             if (this.mode == "start") {
                 date = this.mItem[cal.dtz.startDateProp(this.mItem)];
                 if (date) {
                     let label;
-                    if (cal.isToDo(this.mItem)) {
+                    if (cal.item.isToDo(this.mItem)) {
                         label = this.getAttribute("taskStartLabel");
                     } else {
                         label = this.getAttribute("eventStartLabel");
                     }
                     headerLabel.value = label;
                 }
             } else {
                 date = this.mItem[cal.dtz.endDateProp(this.mItem)];
                 if (date) {
                     let label;
-                    if (cal.isToDo(this.mItem)) {
+                    if (cal.item.isToDo(this.mItem)) {
                         label = this.getAttribute("taskDueLabel");
                     } else {
                         label = this.getAttribute("eventEndLabel");
                     }
                     headerLabel.value = label;
                 }
             }
             let hideLabels = (date == null);
--- a/calendar/base/content/calendar-item-editing.js
+++ b/calendar/base/content/calendar-item-editing.js
@@ -46,17 +46,17 @@ function setDefaultItemValues(aItem, aCa
         sod.minute = 0;
         sod.second = 0;
         return sod;
     }
 
     let initialDate = aInitialDate ? aInitialDate.clone() : cal.dtz.now();
     initialDate.isDate = true;
 
-    if (cal.isEvent(aItem)) {
+    if (cal.item.isEvent(aItem)) {
         if (aStartDate) {
             aItem.startDate = aStartDate.clone();
             if (aStartDate.isDate && !aForceAllday) {
                 // This is a special case where the date is specified, but the
                 // time is not. To take care, we setup up the time to our
                 // default event start time.
                 aItem.startDate = cal.dtz.getDefaultStartDate(aItem.startDate);
             } else if (aForceAllday) {
@@ -88,18 +88,18 @@ function setDefaultItemValues(aItem, aCa
             } else {
                 // If the event is not all day, then add the default event
                 // length.
                 aItem.endDate.minute += Preferences.get("calendar.event.defaultlength", 60);
             }
         }
 
         // Free/busy status is only valid for events, must not be set for tasks.
-        aItem.setProperty("TRANSP", cal.getEventDefaultTransparency(aForceAllday));
-    } else if (cal.isToDo(aItem)) {
+        aItem.setProperty("TRANSP", cal.item.getEventDefaultTransparency(aForceAllday));
+    } else if (cal.item.isToDo(aItem)) {
         let now = cal.dtz.now();
         let initDate = initialDate ? initialDate.clone() : now;
         initDate.isDate = false;
         initDate.hour = now.hour;
         initDate.minute = now.minute;
         initDate.second = now.second;
 
         if (aStartDate) {
@@ -336,17 +336,17 @@ function createTodoWithDialog(calendar, 
  *            (empty if result.type = "ERROR"|"NODIFF"){Array} differences: [{
  *                property: {String} a property that is subject to the proposal
  *                proposed: {String} the proposed value
  *                original: {String} the original value
  *            }]
  *        }
  */
 function modifyEventWithDialog(aItem, job=null, aPromptOccurrence, initialDate=null, aCounterProposal) {
-    let dlg = cal.findItemWindow(aItem);
+    let dlg = cal.item.findWindow(aItem);
     if (dlg) {
         dlg.focus();
         disposeJob(job);
         return;
     }
 
     let onModifyItem = function(item, calendar, originalItem, listener) {
         doTransaction("modify", item, calendar, originalItem, listener);
@@ -374,35 +374,35 @@ function modifyEventWithDialog(aItem, jo
  * @param mode              The operation the dialog should do ("new", "modify")
  * @param callback          The callback to call when the dialog has completed.
  * @param job               (optional) The job object for the modification.
  * @param initialDate       (optional) The initial date for new task datepickers
  * @param counterProposal   (optional) An object representing the counterproposal - see
  *                                     description for modifyEventWithDialog()
  */
 function openEventDialog(calendarItem, calendar, mode, callback, job=null, initialDate=null, counterProposal) {
-    let dlg = cal.findItemWindow(calendarItem);
+    let dlg = cal.item.findWindow(calendarItem);
     if (dlg) {
         dlg.focus();
         disposeJob(job);
         return;
     }
 
     // Set up some defaults
     mode = mode || "new";
     calendar = calendar || getSelectedCalendar();
     let calendars = cal.getCalendarManager().getCalendars({});
     calendars = calendars.filter(cal.acl.isCalendarWritable);
 
     let isItemSupported;
-    if (cal.isToDo(calendarItem)) {
+    if (cal.item.isToDo(calendarItem)) {
         isItemSupported = function(aCalendar) {
             return (aCalendar.getProperty("capabilities.tasks.supported") !== false);
         };
-    } else if (cal.isEvent(calendarItem)) {
+    } else if (cal.item.isEvent(calendarItem)) {
         isItemSupported = function(aCalendar) {
             return (aCalendar.getProperty("capabilities.events.supported") !== false);
         };
     }
 
     // Filter out calendars that don't support the given calendar item
     calendars = calendars.filter(isItemSupported);
 
@@ -490,17 +490,17 @@ function openEventDialog(calendarItem, c
         args.inTab = false;
     }
 
     if (args.inTab) {
         // open in a tab, currently the read-only summary dialog is
         // never opened in a tab
         args.url = url;
         let tabmail = document.getElementById("tabmail");
-        let tabtype = cal.isEvent(args.calendarEvent) ? "calendarEvent" : "calendarTask";
+        let tabtype = cal.item.isEvent(args.calendarEvent) ? "calendarEvent" : "calendarTask";
         tabmail.openTab(tabtype, args);
     } else {
         // open in a window
 
         // reminder: event dialog should not be modal (cf bug 122671)
         let features;
         // keyword "dependent" should not be used (cf bug 752206)
         if (Services.appinfo.OS == "WINNT") {
--- a/calendar/base/content/calendar-month-view.xml
+++ b/calendar/base/content/calendar-month-view.xml
@@ -75,17 +75,17 @@
 
       <property name="occurrence">
         <getter><![CDATA[
             return this.mOccurrence;
         ]]></getter>
         <setter><![CDATA[
             cal.ASSERT(!this.mOccurrence, "Code changes needed to set the occurrence twice", true);
             this.mOccurrence = val;
-            if (cal.isEvent(val)) {
+            if (cal.item.isEvent(val)) {
                 if (!val.startDate.isDate) {
                     let label = document.getAnonymousElementByAttribute(this, "anonid", "item-label");
                     let formatter = Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
                                               .getService(Components.interfaces.calIDateTimeFormatter);
                     let timezone = this.calendarView ? this.calendarView.mTimezone
                                                      : cal.dtz.defaultTimezone;
                     let parentDate = cal.dtz.ensureDateTime(this.parentBox.date);
                     let startTime = val.startDate.getInTimezone(timezone);
@@ -303,17 +303,17 @@
                 start.isDate = true;
                 startInDefaultTz.isDate = true;
                 startInDefaultTz.timezone = start.timezone;
                 let dayDiff = start.subtractDate(startInDefaultTz);
                 // Change the day where to drop the item.
                 dayboxDate.addDuration(dayDiff);
             }
 
-            return cal.moveItem(aItem, dayboxDate);
+            return cal.item.moveToDate(aItem, dayboxDate);
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="mousedown"><![CDATA[
           event.stopPropagation();
           if (this.mDate) {
@@ -951,20 +951,20 @@
       <method name="findDayBoxesForItem">
         <parameter name="aItem"/>
         <body><![CDATA[
             let targetDate = null;
             let finishDate = null;
             let boxes = [];
 
             // All our boxes are in default tz, so we need these times in them too.
-            if (cal.isEvent(aItem)) {
+            if (cal.item.isEvent(aItem)) {
                 targetDate = aItem.startDate.getInTimezone(this.mTimezone);
                 finishDate = aItem.endDate.getInTimezone(this.mTimezone);
-            } else if (cal.isToDo(aItem)) {
+            } else if (cal.item.isToDo(aItem)) {
                 // Consider tasks without entry OR due date.
                 if (aItem.entryDate || aItem.dueDate) {
                     targetDate = (aItem.entryDate || aItem.dueDate).getInTimezone(this.mTimezone);
                     finishDate = (aItem.dueDate || aItem.entryDate).getInTimezone(this.mTimezone);
                 }
             }
 
             if (!targetDate) {
--- a/calendar/base/content/calendar-multiday-view.xml
+++ b/calendar/base/content/calendar-multiday-view.xml
@@ -1962,17 +1962,17 @@
             let jsTime = new Date();
             jsTime.setHours(starthr, startmin);
             let startstr = timeFormatter.formatTime(cal.dtz.jsDateToDateTime(jsTime, cal.dtz.floating));
             jsTime.setHours(endhr, endmin);
             let endstr = timeFormatter.formatTime(cal.dtz.jsDateToDateTime(jsTime, cal.dtz.floating));
 
             // Tasks without Entry or Due date have a string as first label
             // instead of the time.
-            if (cal.isToDo(this.mDragState.dragOccurrence)) {
+            if (cal.item.isToDo(this.mDragState.dragOccurrence)) {
                 if (!this.mDragState.dragOccurrence.dueDate) {
                     startstr = cal.calGetString("calendar", "dragLabelTasksWithOnlyEntryDate");
                 } else if (!this.mDragState.dragOccurrence.entryDate) {
                     startstr = cal.calGetString("calendar", "dragLabelTasksWithOnlyDueDate");
                 }
             }
             firstColumn.fgboxes.startlabel.setAttribute("value", startstr);
             lastColumn.fgboxes.endlabel.setAttribute("value", endstr);
@@ -2168,18 +2168,18 @@
                 }
             }
         ]]></body>
       </method>
 
       <method name="onDropItem">
         <parameter name="aItem"/>
         <body><![CDATA[
-            let newItem = cal.moveItem(aItem, this.mDate);
-            newItem = cal.setItemToAllDay(newItem, true);
+            let newItem = cal.item.moveToDate(aItem, this.mDate);
+            newItem = cal.item.setToAllDay(newItem, true);
             return newItem;
         ]]></body>
       </method>
 
       <method name="selectOccurrence">
         <parameter name="aItem"/>
         <body><![CDATA[
             for (let itemBox of this.mItemBoxes) {
--- a/calendar/base/content/calendar-task-tree.js
+++ b/calendar/base/content/calendar-task-tree.js
@@ -219,17 +219,17 @@ function contextPostponeTask(aEvent, aDu
         postponeTask(aDuration);
     } else {
         startBatchTransaction();
         let tasks = getSelectedTasks(aEvent);
 
         tasks.forEach((task) => {
             if (task.entryDate || task.dueDate) {
                 let newTask = task.clone();
-                cal.shiftItem(newTask, duration);
+                cal.item.shiftOffset(newTask, duration);
                 doTransaction("modify", newTask, newTask.calendar, task, null);
             }
         });
 
         endBatchTransaction();
     }
 }
 
--- a/calendar/base/content/calendar-task-tree.xml
+++ b/calendar/base/content/calendar-task-tree.xml
@@ -509,17 +509,17 @@
             getRowProperties: function(aRow) {
                 let properties = [];
                 let item = this.binding.mTaskArray[aRow];
                 if (item.priority > 0 && item.priority < 5) {
                     properties.push("highpriority");
                 } else if (item.priority > 5 && item.priority < 10) {
                     properties.push("lowpriority");
                 }
-                properties.push(cal.getProgressAtom(item));
+                properties.push(cal.item.getProgressAtom(item));
 
                 // Add calendar name and id atom
                 properties.push("calendar-" + cal.formatStringForCSSRule(item.calendar.name));
                 properties.push("calendarid-" + cal.formatStringForCSSRule(item.calendar.id));
 
                 // Add item status atom
                 if (item.status) {
                     properties.push("status-" + item.status.toLowerCase());
@@ -818,35 +818,35 @@
             onEndBatch: function() {
             },
 
             onLoad: function() {
                 this.binding.refresh();
             },
 
             onAddItem: function(aItem) {
-                if (cal.isToDo(aItem)) {
+                if (cal.item.isToDo(aItem)) {
                     this.binding.mTreeView.addItems(this.binding.mFilter.getOccurrences(aItem));
                 }
             },
 
             onModifyItem: function(aNewItem, aOldItem) {
-                if (cal.isToDo(aNewItem) || cal.isToDo(aOldItem)) {
+                if (cal.item.isToDo(aNewItem) || cal.item.isToDo(aOldItem)) {
                     this.binding.mTreeView.modifyItems(this.binding.mFilter.getOccurrences(aNewItem),
                                                        this.binding.mFilter.getOccurrences(aOldItem));
 
                     // we also need to notify potential listeners.
                     let event = document.createEvent("Events");
                     event.initEvent("select", true, false);
                     this.binding.dispatchEvent(event);
                 }
             },
 
             onDeleteItem: function(aDeletedItem) {
-                if (cal.isToDo(aDeletedItem)) {
+                if (cal.item.isToDo(aDeletedItem)) {
                     this.binding.mTreeView.removeItems(this.binding.mFilter.getOccurrences(aDeletedItem));
                 }
             },
 
             onError: function(aCalendar, aErrNo, aMessage) {},
             onPropertyChanged: function(aCalendar, aName, aValue, aOldValue) {
                 switch (aName) {
                     case "disabled":
--- a/calendar/base/content/calendar-ui-utils.js
+++ b/calendar/base/content/calendar-ui-utils.js
@@ -290,17 +290,17 @@ function appendCalendarItems(aItem, aCal
     let index = -1;
     for (let i = 0; i < calendars.length; ++i) {
         let calendar = calendars[i];
         if (calendar.id == calendarToUse.id ||
             (calendar &&
              cal.acl.isCalendarWritable(calendar) &&
              (cal.acl.userCanAddItemsToCalendar(calendar) ||
               (calendar == aItem.calendar && cal.acl.userCanModifyItem(aItem))) &&
-             cal.isItemSupported(aItem, calendar))) {
+             cal.item.isItemSupported(aItem, calendar))) {
             let menuitem = addMenuItem(aCalendarMenuParent, calendar.name, calendar.name);
             menuitem.calendar = calendar;
             index++;
             if (aOnCommand) {
                 menuitem.setAttribute("oncommand", aOnCommand);
             }
             if (aCalendarMenuParent.localName == "menupopup") {
                 menuitem.setAttribute("type", "checkbox");
--- a/calendar/base/content/calendar-unifinder.js
+++ b/calendar/base/content/calendar-unifinder.js
@@ -77,31 +77,31 @@ var unifinderObserver = {
             // those operations and refresh as soon as the unifinder is shown
             // again.
             gUnifinderNeedsRefresh = true;
             unifinderTreeView.clearItems();
         }
     },
 
     onAddItem: function(aItem) {
-        if (cal.isEvent(aItem) &&
+        if (cal.item.isEvent(aItem) &&
             !gUnifinderNeedsRefresh &&
             unifinderTreeView.mFilter.isItemInFilters(aItem)
             ) {
             this.addItemToTree(aItem);
         }
     },
 
     onModifyItem: function(aNewItem, aOldItem) {
         this.onDeleteItem(aOldItem);
         this.onAddItem(aNewItem);
     },
 
     onDeleteItem: function(aDeletedItem) {
-        if (cal.isEvent(aDeletedItem) && !gUnifinderNeedsRefresh) {
+        if (cal.item.isEvent(aDeletedItem) && !gUnifinderNeedsRefresh) {
             this.removeItemFromTree(aDeletedItem);
         }
     },
 
     onError: function(aCalendar, aErrNo, aMessage) {},
 
     onPropertyChanged: function(aCalendar, aName, aValue, aOldValue) {
         switch (aName) {
--- a/calendar/base/content/calendar-view-core.xml
+++ b/calendar/base/content/calendar-view-core.xml
@@ -182,24 +182,24 @@
                 classificationBox.setAttribute("classification", item.privacy || "PUBLIC");
             }
 
             // Set up event box attributes for use in css selectors. Note if
             // something is added here, it should also be xbl:inherited correctly
             // in the <content> section of this binding, and all that inherit it.
 
             // Event type specific properties
-            if (cal.isEvent(item)) {
+            if (cal.item.isEvent(item)) {
                 if (item.startDate.isDate) {
                     this.setAttribute("allday", "true");
                 }
                 this.setAttribute("itemType", "event");
-            } else if (cal.isToDo(item)) {
+            } else if (cal.item.isToDo(item)) {
                 // progress attribute
-                this.setAttribute("progress", cal.getProgressAtom(item));
+                this.setAttribute("progress", cal.item.getProgressAtom(item));
                 // Attribute for tasks and tasks image.
                 this.setAttribute("itemType", "todo");
                 if (item.entryDate && !item.dueDate) {
                     this.setAttribute("todoType", "start");
                 } else if (!item.entryDate && item.dueDate) {
                     this.setAttribute("todoType", "end");
                 }
             }
--- a/calendar/base/content/calendar-views.js
+++ b/calendar/base/content/calendar-views.js
@@ -62,17 +62,17 @@ var calendarViewController = {
             // When we made the executive decision (in bug 352862) that
             // dragging an occurrence of a recurring event would _only_ act
             // upon _that_ occurrence, we removed a bunch of code from this
             // function. If we ever revert that decision, check CVS history
             // here to get that code back.
 
             if (aNewStartTime || aNewEndTime) {
                 // Yay for variable names that make this next line look silly
-                if (cal.isEvent(instance)) {
+                if (cal.item.isEvent(instance)) {
                     if (aNewStartTime && instance.startDate) {
                         instance.startDate = aNewStartTime;
                     }
                     if (aNewEndTime && instance.endDate) {
                         instance.endDate = aNewEndTime;
                     }
                 } else {
                     if (aNewStartTime && instance.entryDate) {
--- a/calendar/base/content/dialogs/calendar-dialog-utils.js
+++ b/calendar/base/content/dialogs/calendar-dialog-utils.js
@@ -453,17 +453,17 @@ function commonUpdateReminder(aSuppressD
     reminderList.setAttribute("last-value", reminderList.value);
 
     // possibly the selected reminder conflicts with the item.
     // for example an end-relation combined with a task without duedate
     // is an invalid state we need to take care of. we take the same
     // approach as with recurring tasks. in case the reminder is related
     // to the entry date we check the entry date automatically and disable
     // the checkbox. the same goes for end related reminder and the due date.
-    if (cal.isToDo(window.calendarItem)) {
+    if (cal.item.isToDo(window.calendarItem)) {
         // In general, (re-)enable the due/entry checkboxes. This will be
         // changed in case the alarms are related to START/END below.
         enableElementWithLock("todo-has-duedate", "reminder-lock");
         enableElementWithLock("todo-has-entrydate", "reminder-lock");
 
         let menuitem = reminderList.selectedItem;
         if (menuitem.value != "none") {
             // In case a reminder is selected, retrieve the array of alarms from
--- a/calendar/base/content/dialogs/calendar-event-dialog-recurrence.js
+++ b/calendar/base/content/dialogs/calendar-event-dialog-recurrence.js
@@ -463,17 +463,17 @@ function onChangeCalendar(calendar) {
  *
  * @param item        The item to check.
  */
 function disableOrEnable(item) {
     if (item.parentItem != item) {
         disableRecurrenceFields("disable-on-occurrence");
     } else if (gIsReadOnly) {
         disableRecurrenceFields("disable-on-readonly");
-    } else if (cal.isToDo(item) && !gStartTime) {
+    } else if (cal.item.isToDo(item) && !gStartTime) {
         disableRecurrenceFields("disable-on-readonly");
     } else {
         enableRecurrenceFields("disable-on-readonly");
     }
 }
 
 /**
  * Disables all fields that have an attribute that matches the argument and is
@@ -591,27 +591,27 @@ function updatePreview() {
     }
 
     // TODO: We should better start the whole dialog with a newly cloned item
     // and always pump changes immediately into it. This would eliminate the
     // need to break the encapsulation, as we do it here. But we need the item
     // to contain the startdate in order to calculate the recurrence preview.
     item = item.clone();
     let kDefaultTimezone = cal.dtz.defaultTimezone;
-    if (cal.isEvent(item)) {
+    if (cal.item.isEvent(item)) {
         let startDate = gStartTime.getInTimezone(kDefaultTimezone);
         let endDate = gEndTime.getInTimezone(kDefaultTimezone);
         if (startDate.isDate) {
             endDate.day--;
         }
 
         item.startDate = startDate;
         item.endDate = endDate;
     }
-    if (cal.isToDo(item)) {
+    if (cal.item.isToDo(item)) {
         let entryDate = gStartTime;
         if (entryDate) {
             entryDate = entryDate.getInTimezone(kDefaultTimezone);
         } else {
             item.recurrenceInfo = null;
         }
         item.entryDate = entryDate;
         let dueDate = gEndTime;
--- a/calendar/base/content/dialogs/calendar-event-dialog-reminder.js
+++ b/calendar/base/content/dialogs/calendar-event-dialog-reminder.js
@@ -348,29 +348,29 @@ function updateReminder(event) {
 /**
  * Gets the locale stringname that is dependant on the item type. This function
  * appends the item type, i.e |aPrefix + "Event"|.
  *
  * @param aPrefix       The prefix to prepend to the item type
  * @return              The full string name.
  */
 function getItemBundleStringName(aPrefix) {
-    if (cal.isEvent(window.arguments[0].item)) {
+    if (cal.item.isEvent(window.arguments[0].item)) {
         return aPrefix + "Event";
     } else {
         return aPrefix + "Task";
     }
 }
 
 /**
  * Handler function to be called when the "new" button is pressed, to create a
  * new reminder item.
  */
 function onNewReminder() {
-    let itemType = (cal.isEvent(window.arguments[0].item) ? "event" : "todo");
+    let itemType = (cal.item.isEvent(window.arguments[0].item) ? "event" : "todo");
     let listbox = document.getElementById("reminder-listbox");
 
     let reminder = cal.createAlarm();
     let alarmlen = Preferences.get("calendar.alarms." + itemType + "alarmlen", 15);
 
     // Default is a relative DISPLAY alarm, |alarmlen| minutes before the event.
     // If DISPLAY is not supported by the provider, then pick the provider's
     // first alarm type.
--- a/calendar/base/content/dialogs/calendar-occurrence-prompt.xul
+++ b/calendar/base/content/dialogs/calendar-occurrence-prompt.xul
@@ -27,17 +27,17 @@
     }
 
     function getDialogString(key) {
       return cal.calGetString("calendar-occurrence-prompt", key);
     }
 
     function onLoad() {
       var action = window.arguments[0].action || "edit";
-      var itemType = (cal.isEvent(window.arguments[0].item) ? "event" : "task");
+      var itemType = (cal.item.isEvent(window.arguments[0].item) ? "event" : "task");
 
       // Set up title
       document.title = getDialogString("windowtitle." + itemType + "." + action);
       document.getElementById("title-label").value = window.arguments[0].item.title;
 
       // Set up header
       document.getElementById("isrepeating-label").value =
         getDialogString("header.isrepeating." + itemType + ".label");
--- a/calendar/base/content/dialogs/calendar-print-dialog.js
+++ b/calendar/base/content/dialogs/calendar-print-dialog.js
@@ -92,20 +92,20 @@ function getPrintSettings(receiverFunc) 
             settings.end.day += 1;
             settings.start.isDate = false;
             settings.end.isDate = false;
             break;
         }
         case "selected": {
             let selectedItems = theView.getSelectedItems({});
             settings.eventList = selectedItems.filter((item) => {
-                if (cal.isEvent(item) && !settings.printEvents) {
+                if (cal.item.isEvent(item) && !settings.printEvents) {
                     return false;
                 }
-                if (cal.isToDo(item) && !settings.printTasks) {
+                if (cal.item.isToDo(item) && !settings.printTasks) {
                     return false;
                 }
                 return true;
             });
 
             // If tasks should be printed, also include selected tasks from the
             // opening window.
             if (settings.printTasks) {
--- a/calendar/base/content/dialogs/calendar-summary-dialog.js
+++ b/calendar/base/content/dialogs/calendar-summary-dialog.js
@@ -38,19 +38,19 @@ function onLoad() {
             // ...and close the window.
             window.close();
 
             return calendarItem;
         };
     }
 
     // set the dialog-id to enable the right window-icon to be loaded.
-    if (cal.isEvent(item)) {
+    if (cal.item.isEvent(item)) {
         setDialogId(document.documentElement, "calendar-event-summary-dialog");
-    } else if (cal.isToDo(item)) {
+    } else if (cal.item.isToDo(item)) {
         setDialogId(document.documentElement, "calendar-task-summary-dialog");
     }
 
     window.attendees = item.getAttendees({});
 
     let calendar = cal.wrapInstance(item.calendar, Components.interfaces.calISchedulingSupport);
     window.readOnly = !(cal.acl.isCalendarWritable(calendar) &&
                         (cal.acl.userCanModifyItem(item) ||
@@ -71,17 +71,17 @@ function onLoad() {
             // and add again. Also, this is needed if the attendee doesn't exist
             // (i.e REPLY on a mailing list)
             item.removeAttendee(attendee);
             item.addAttendee(window.attendee);
 
             // make partstat NEEDS-ACTION only available as a option to change to,
             // if the user hasn't ever made a decision prior to opening the dialog
             let partStat = window.attendee.participationStatus || "NEEDS-ACTION";
-            if (partStat == "NEEDS-ACTION" && cal.isEvent(item)) {
+            if (partStat == "NEEDS-ACTION" && cal.item.isEvent(item)) {
                 document.getElementById("item-participation-needs-action").removeAttribute("hidden");
             }
         }
     }
 
     document.getElementById("item-title").value = item.title;
 
     document.getElementById("item-start-row").Item = item;
@@ -145,17 +145,17 @@ function onLoad() {
     }
 
     let status = item.getProperty("STATUS");
     if (status && status.length) {
         let statusRow = document.getElementById("status-row");
         for (let i = 0; i < statusRow.childNodes.length; i++) {
             if (statusRow.childNodes[i].getAttribute("status") == status) {
                 statusRow.removeAttribute("hidden");
-                if (status == "CANCELLED" && cal.isToDo(item)) {
+                if (status == "CANCELLED" && cal.item.isToDo(item)) {
                     // There are two labels for CANCELLED, the second one is for
                     // todo items. Increment the counter here.
                     i++;
                 }
                 statusRow.childNodes[i].removeAttribute("hidden");
                 break;
             }
         }
--- a/calendar/base/content/widgets/calendar-alarm-widget.xml
+++ b/calendar/base/content/widgets/calendar-alarm-widget.xml
@@ -80,19 +80,19 @@
             }
 
             let formatter = cal.getDateFormatter();
             let titleLabel = document.getAnonymousElementByAttribute(this, "anonid", "alarm-title-label");
             let locationDescription = document.getAnonymousElementByAttribute(this, "anonid", "alarm-location-description");
             let dateLabel = document.getAnonymousElementByAttribute(this, "anonid", "alarm-date-label");
 
             // Dates
-            if (cal.isEvent(this.mItem)) {
+            if (cal.item.isEvent(this.mItem)) {
                 dateLabel.textContent = formatter.formatItemInterval(this.mItem);
-            } else if (cal.isToDo(this.mItem)) {
+            } else if (cal.item.isToDo(this.mItem)) {
                 let startDate = this.mItem.entryDate || this.mItem.dueDate;
                 if (startDate) {
                     // A Task with a start or due date, show with label
                     startDate = startDate.getInTimezone(cal.dtz.defaultTimezone);
                     dateLabel.textContent = cal.calGetString("calendar",
                                                              "alarmStarts",
                                                              [formatter.formatDateTime(startDate)]);
                 } else {
--- a/calendar/base/content/widgets/calendar-widgets.xml
+++ b/calendar/base/content/widgets/calendar-widgets.xml
@@ -686,17 +686,17 @@
               return;
           }
           let item = session.sourceNode.sourceObject.clone();
           this.setAttribute("dropbox", "false");
           let transfer = Components.classes["@mozilla.org/widget/transferable;1"]
                                    .createInstance(Components.interfaces.nsITransferable);
           transfer.init(null);
 
-          if (cal.isEvent(item)) {
+          if (cal.item.isEvent(item)) {
               transfer.addDataFlavor("application/x-moz-cal-event");
           } else {
               transfer.addDataFlavor("application/x-moz-cal-task");
           }
 
           session.getData(transfer, 0);
           item = session.sourceNode.sourceObject;
 
--- a/calendar/base/modules/calAlarmUtils.jsm
+++ b/calendar/base/modules/calAlarmUtils.jsm
@@ -10,17 +10,17 @@ cal.alarms = {
     /**
      * Read default alarm settings from user preferences and apply them to the
      * event/todo passed in. The item's calendar should be set to ensure the
      * correct alarm type is set.
      *
      * @param aItem     The item to apply the default alarm values to.
      */
     setDefaultValues: function(aItem) {
-        let type = cal.isEvent(aItem) ? "event" : "todo";
+        let type = cal.item.isEvent(aItem) ? "event" : "todo";
         if (Preferences.get("calendar.alarms.onfor" + type + "s", 0) == 1) {
             let alarmOffset = cal.createDuration();
             let alarm = cal.createAlarm();
             let units = Preferences.get("calendar.alarms." + type + "alarmunit", "minutes");
 
             // Make sure the alarm pref is valid, default to minutes otherwise
             if (!["weeks", "days", "hours", "minutes", "seconds"].includes(units)) {
                 units = "minutes";
--- a/calendar/base/modules/calDateTimeUtils.jsm
+++ b/calendar/base/modules/calDateTimeUtils.jsm
@@ -98,43 +98,43 @@ var caldtz = {
      *
      * @param aItem             The item to set up the start and end date for.
      * @param aReferenceDate    If passed, the time of this date will be modified,
      *                            keeping the date and timezone intact.
      */
     setDefaultStartEndHour: function(aItem, aReferenceDate) {
         aItem[caldtz.startDateProp(aItem)] = caldtz.getDefaultStartDate(aReferenceDate);
 
-        if (cal.isEvent(aItem)) {
+        if (cal.item.isEvent(aItem)) {
             aItem.endDate = aItem.startDate.clone();
             aItem.endDate.minute += Preferences.get("calendar.event.defaultlength", 60);
         }
     },
 
     /**
      * Returns the property name used for the start date of an item, ie either an
      * event's start date or a task's entry date.
      */
     startDateProp: function(aItem) {
-        if (cal.isEvent(aItem)) {
+        if (cal.item.isEvent(aItem)) {
             return "startDate";
-        } else if (cal.isToDo(aItem)) {
+        } else if (cal.item.isToDo(aItem)) {
             return "entryDate";
         }
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
     },
 
     /**
      * Returns the property name used for the end date of an item, ie either an
      * event's end date or a task's due date.
      */
     endDateProp: function(aItem) {
-        if (cal.isEvent(aItem)) {
+        if (cal.item.isEvent(aItem)) {
             return "endDate";
-        } else if (cal.isToDo(aItem)) {
+        } else if (cal.item.isToDo(aItem)) {
             return "dueDate";
         }
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
     },
 
     /**
      * Check if the two dates are on the same day (ignoring time)
      *
--- a/calendar/base/modules/calItipUtils.jsm
+++ b/calendar/base/modules/calItipUtils.jsm
@@ -665,17 +665,17 @@ cal.itip = {
                         })) {
                         exdates.push(wrappedRItem);
                     }
                 }
                 if (exdates.length > 0) {
                     // check whether really only EXDATEs have been added:
                     let recInfo = clonedItem.recurrenceInfo;
                     exdates.forEach(recInfo.deleteRecurrenceItem, recInfo);
-                    if (cal.compareItemContent(clonedItem, aOriginalItem)) { // transition into "delete occurrence(s)"
+                    if (cal.item.compareContent(clonedItem, aOriginalItem)) { // transition into "delete occurrence(s)"
                         // xxx todo: support multiple
                         aItem = aOriginalItem.recurrenceInfo.getOccurrenceFor(exdates[0].date);
                         aOriginalItem = null;
                         aOpType = Components.interfaces.calIOperationListener.DELETE;
                     }
                 }
             }
         }
@@ -806,17 +806,17 @@ cal.itip = {
         // this will be set to false, once the user cancels sending manually
         let sendOut = true;
         // Check to see if some part of the item was updated, if so, re-send REQUEST
         if (!aOriginalItem || (cal.itip.compare(aItem, aOriginalItem) > 0)) { // REQUEST
             // check whether it's a simple UPDATE (no SEQUENCE change) or real (RE)REQUEST,
             // in case of time or location/description change.
             let isMinorUpdate = (aOriginalItem && (cal.itip.getSequence(aItem) == cal.itip.getSequence(aOriginalItem)));
 
-            if (!isMinorUpdate || !cal.compareItemContent(stripUserData(aItem), stripUserData(aOriginalItem))) {
+            if (!isMinorUpdate || !cal.item.compareContent(stripUserData(aItem), stripUserData(aOriginalItem))) {
                 let requestItem = aItem.clone();
                 if (!requestItem.organizer) {
                     requestItem.organizer = createOrganizer(requestItem.calendar);
                 }
 
                 // Fix up our attendees for invitations using some good defaults
                 let recipients = [];
                 let reqItemAtt = requestItem.getAttendees({});
@@ -931,17 +931,17 @@ cal.itip = {
      * @param  {JsObject}     aProps     Properties to be different in the new itipItem
      * @return {calIItipItem}
      */
     getModifiedItipItem: function(aItipItem, aItems=[], aProps={}) {
         let itipItem = Components.classes["@mozilla.org/calendar/itip-item;1"]
                                  .createInstance(Components.interfaces.calIItipItem);
         let serializedItems = "";
         for (let item of aItems) {
-            serializedItems += cal.getSerializedItem(item);
+            serializedItems += cal.item.serialize(item);
         }
         itipItem.init(serializedItems);
 
         itipItem.autoResponse = ("autoResponse" in aProps) ? aProps.autoResponse : aItipItem.autoResponse;
         itipItem.identity = ("identity" in aProps) ? aProps.identity : aItipItem.identity;
         itipItem.isSend = ("isSend" in aProps) ? aProps.isSend : aItipItem.isSend;
         itipItem.localStatus = ("localStatus" in aProps) ? aProps.localStatus : aItipItem.localStatus;
         itipItem.receivedMethod = ("receivedMethod" in aProps) ? aProps.receivedMethod : aItipItem.receivedMethod;
@@ -1140,17 +1140,17 @@ function sendMessage(aItem, aMethod, aRe
         return false;
     }
     transport = transport.QueryInterface(Components.interfaces.calIItipTransport);
 
     let _sendItem = function(aSendToList, aSendItem) {
         let cIII = Components.interfaces.calIItipItem;
         let itipItem = Components.classes["@mozilla.org/calendar/itip-item;1"]
                                  .createInstance(cIII);
-        itipItem.init(cal.getSerializedItem(aSendItem));
+        itipItem.init(cal.item.serialize(aSendItem));
         itipItem.responseMethod = aMethod;
         itipItem.targetCalendar = aSendItem.calendar;
         itipItem.autoResponse = autoResponse && autoResponse.value ? cIII.AUTO : cIII.USER;
         if (autoResponse) {
             autoResponse.value = true; // auto every following
         }
         // XXX I don't know whether the below are used at all, since we don't use the itip processor
         itipItem.isSend = true;
--- a/calendar/base/modules/calViewUtils.jsm
+++ b/calendar/base/modules/calViewUtils.jsm
@@ -16,21 +16,21 @@ cal.view = {
     compareItems: function(a, b) {
         if (!a) {
             return -1;
         }
         if (!b) {
             return 1;
         }
 
-        let aIsEvent = cal.isEvent(a);
-        let aIsTodo = cal.isToDo(a);
+        let aIsEvent = cal.item.isEvent(a);
+        let aIsTodo = cal.item.isToDo(a);
 
-        let bIsEvent = cal.isEvent(b);
-        let bIsTodo = cal.isToDo(b);
+        let bIsEvent = cal.item.isEvent(b);
+        let bIsTodo = cal.item.isToDo(b);
 
         // sort todos before events
         if (aIsTodo && bIsEvent) {
             return -1;
         }
         if (aIsEvent && bIsTodo) {
             return 1;
         }
--- a/calendar/base/src/calAlarm.js
+++ b/calendar/base/src/calAlarm.js
@@ -622,19 +622,19 @@ calAlarm.prototype = {
     },
 
     get propertyEnumerator() {
         return this.mProperties.enumerator;
     },
 
     toString: function(aItem) {
         function getItemBundleStringName(aPrefix) {
-            if (!aItem || cal.isEvent(aItem)) {
+            if (!aItem || cal.item.isEvent(aItem)) {
                 return aPrefix + "Event";
-            } else if (cal.isToDo(aItem)) {
+            } else if (cal.item.isToDo(aItem)) {
                 return aPrefix + "Task";
             } else {
                 return aPrefix;
             }
         }
 
         if (this.related == ALARM_RELATED_ABSOLUTE && this.mAbsoluteDate) {
             // this is an absolute alarm. Use the calendar default timezone and
--- a/calendar/base/src/calAlarmService.js
+++ b/calendar/base/src/calAlarmService.js
@@ -315,17 +315,17 @@ calAlarmService.prototype = {
 
     unobserveCalendar: function(calendar) {
         calendar.removeObserver(this.calendarObserver);
         this.disposeCalendarTimers([calendar]);
         this.mObservers.notify("onRemoveAlarmsByCalendar", [calendar]);
     },
 
     addAlarmsForItem: function(aItem) {
-        if (cal.isToDo(aItem) && aItem.isCompleted) {
+        if (cal.item.isToDo(aItem) && aItem.isCompleted) {
             // If this is a task and it is completed, don't add the alarm.
             return;
         }
 
         let showMissed = Preferences.get("calendar.alarms.showmissed", true);
 
         let alarms = aItem.getAlarms({});
         for (let alarm of alarms) {
@@ -414,17 +414,17 @@ calAlarmService.prototype = {
         // We search 1 month in each direction for alarms.  Therefore,
         // we need occurrences between initial start date and 1 month from now
         let until = nowUTC();
         until.month += 1;
 
         if (aItem && aItem.recurrenceInfo) {
             return aItem.recurrenceInfo.getOccurrences(this.mRangeStart, until, 0, {});
         } else {
-            return cal.checkIfInRange(aItem, this.mRangeStart, until) ? [aItem] : [];
+            return cal.item.checkIfInRange(aItem, this.mRangeStart, until) ? [aItem] : [];
         }
     },
 
     addAlarmsForOccurrences: function(aParentItem) {
         let occs = this.getOccurrencesInRange(aParentItem);
 
         // Add an alarm for each occurrence
         occs.forEach(this.addAlarmsForItem, this);
--- a/calendar/base/src/calEvent.js
+++ b/calendar/base/src/calEvent.js
@@ -81,17 +81,17 @@ calEvent.prototype = {
     { cal: "DTEND", ics: "endTime" }],
 
     set icalString(value) {
         this.icalComponent = cal.getIcsService().parseICS(value, null);
     },
 
     get icalString() {
         let calcomp = cal.getIcsService().createIcalComponent("VCALENDAR");
-        cal.calSetProdidVersion(calcomp);
+        cal.item.setStaticProps(calcomp);
         calcomp.addSubcomponent(this.icalComponent);
         return calcomp.serializeToICS();
     },
 
     get icalComponent() {
         let icssvc = cal.getIcsService();
         let icalcomp = icssvc.createIcalComponent("VEVENT");
         this.fillIcalComponentFromBase(icalcomp);
--- a/calendar/base/src/calFilter.js
+++ b/calendar/base/src/calFilter.js
@@ -369,17 +369,17 @@ calFilter.prototype = {
     /**
      * Checks if the item matches the current filter date range.
      *
      * @param aItem               The item to check.
      * @return                    Returns true if the item falls within the date range
      *                            specified by mStartDate and mEndDate, false otherwise.
      */
     dateRangeFilter: function(aItem) {
-        return cal.checkIfInRange(aItem, this.mStartDate, this.mEndDate);
+        return cal.item.checkIfInRange(aItem, this.mStartDate, this.mEndDate);
     },
 
     /**
      * Checks if the item matches the currently applied filter properties. Filter properties
      * with a value of null or that are not applicable to the item's type are not tested.
      *
      * @param aItem               The item to check.
      * @return                    Returns true if the item matches the filter properties
@@ -418,33 +418,33 @@ calFilter.prototype = {
                 cats.push(props.category);
             } else if (Array.isArray(props.category)) {
                 cats = props.category;
             }
             result = cats.some(cat => aItem.getCategories({}).includes(cat));
         }
 
         // test the status property. Only applies to tasks.
-        if (result && props.status != null && cal.isToDo(aItem)) {
+        if (result && props.status != null && cal.item.isToDo(aItem)) {
             let completed = aItem.isCompleted;
             let current = !aItem.completedDate || today.compare(aItem.completedDate) <= 0;
             let percent = aItem.percentComplete || 0;
 
             result = ((props.status & props.FILTER_STATUS_INCOMPLETE) ||
                       !(!completed && (percent == 0))) &&
                      ((props.status & props.FILTER_STATUS_IN_PROGRESS) ||
                       !(!completed && (percent > 0))) &&
                      ((props.status & props.FILTER_STATUS_COMPLETED_TODAY) ||
                       !(completed && current)) &&
                      ((props.status & props.FILTER_STATUS_COMPLETED_BEFORE) ||
                       !(completed && !current));
         }
 
         // test the due property. Only applies to tasks.
-        if (result && props.due != null && cal.isToDo(aItem)) {
+        if (result && props.due != null && cal.item.isToDo(aItem)) {
             let due = aItem.dueDate;
             let now = cal.dtz.now();
 
             result = ((props.due & props.FILTER_DUE_PAST) ||
                       !(due && (due.compare(now) < 0))) &&
                      ((props.due & props.FILTER_DUE_TODAY) ||
                       !(due && (due.compare(now) >= 0) && (due.compare(tomorrow) < 0))) &&
                      ((props.due & props.FILTER_DUE_FUTURE) ||
--- a/calendar/base/src/calIcsParser.js
+++ b/calendar/base/src/calIcsParser.js
@@ -70,17 +70,17 @@ calIcsParser.prototype = {
 
         state.join(() => {
             let fakedParents = {};
             // tag "exceptions", i.e. items with rid:
             for (let item of state.excItems) {
                 let parent = state.uid2parent[item.id];
 
                 if (!parent) { // a parentless one, fake a master and override it's occurrence
-                    parent = cal.isEvent(item) ? cal.createEvent() : cal.createTodo();
+                    parent = cal.item.isEvent(item) ? cal.createEvent() : cal.createTodo();
                     parent.id = item.id;
                     parent.setProperty("DTSTART", item.recurrenceId);
                     parent.setProperty("X-MOZ-FAKED-MASTER", "1"); // this tag might be useful in the future
                     parent.recurrenceInfo = cal.createRecurrenceInfo(parent);
                     fakedParents[item.id] = true;
                     state.uid2parent[item.id] = parent;
                     state.items.push(parent);
                 }
--- a/calendar/base/src/calIcsSerializer.js
+++ b/calendar/base/src/calIcsSerializer.js
@@ -57,17 +57,17 @@ calIcsSerializer.prototype = {
         convStream.init(aStream, "UTF-8");
 
         convStream.writeString(str);
         convStream.close();
     },
 
     getIcalComponent: function() {
         let calComp = cal.getIcsService().createIcalComponent("VCALENDAR");
-        cal.calSetProdidVersion(calComp);
+        cal.item.setStaticProps(calComp);
 
         // xxx todo: think about that the below code doesn't clone the properties/components,
         //           thus ownership is moved to returned VCALENDAR...
 
         for (let prop of this.mProperties) {
             calComp.addProperty(prop);
         }
         for (let comp of this.mComponents) {
--- a/calendar/base/src/calItemBase.js
+++ b/calendar/base/src/calItemBase.js
@@ -1080,17 +1080,17 @@ calItemBase.prototype = {
     // void getOccurrencesBetween (in calIDateTime aStartDate, in calIDateTime aEndDate,
     //                             out PRUint32 aCount,
     //                             [array,size_is(aCount),retval] out calIItemBase aOccurrences);
     getOccurrencesBetween: function(aStartDate, aEndDate, aCount) {
         if (this.recurrenceInfo) {
             return this.recurrenceInfo.getOccurrences(aStartDate, aEndDate, 0, aCount);
         }
 
-        if (cal.checkIfInRange(this, aStartDate, aEndDate)) {
+        if (cal.item.checkIfInRange(this, aStartDate, aEndDate)) {
             aCount.value = 1;
             return [this];
         }
 
         aCount.value = 0;
         return [];
     }
 };
--- a/calendar/base/src/calRecurrenceInfo.js
+++ b/calendar/base/src/calRecurrenceInfo.js
@@ -454,26 +454,26 @@ calRecurrenceInfo.prototype = {
 
         let dates = [];
 
         // toss in exceptions first. Save a map of all exceptions ids, so we
         // don't add the wrong occurrences later on.
         let occurrenceMap = {};
         for (let ex in this.mExceptionMap) {
             let item = this.mExceptionMap[ex];
-            let occDate = cal.checkIfInRange(item, aRangeStart, aRangeEnd, true);
+            let occDate = cal.item.checkIfInRange(item, aRangeStart, aRangeEnd, true);
             occurrenceMap[ex] = true;
             if (occDate) {
                 cal.binaryInsert(dates, { id: item.recurrenceId, rstart: occDate }, ridDateSortComptor);
             }
         }
 
         // DTSTART/DUE is always part of the (positive) expanded set:
         // DTSTART always equals RECURRENCE-ID for items expanded from RRULE
-        let baseOccDate = cal.checkIfInRange(this.mBaseItem, aRangeStart, aRangeEnd, true);
+        let baseOccDate = cal.item.checkIfInRange(this.mBaseItem, aRangeStart, aRangeEnd, true);
         let baseOccDateKey = getRidKey(baseOccDate);
         if (baseOccDate && !occurrenceMap[baseOccDateKey]) {
             occurrenceMap[baseOccDateKey] = true;
             cal.binaryInsert(dates, { id: baseOccDate, rstart: baseOccDate }, ridDateSortComptor);
         }
 
         // if both range start and end are specified, we ask for all of the occurrences,
         // to make sure we catch all possible exceptions.  If aRangeEnd isn't specified,
@@ -782,17 +782,17 @@ calRecurrenceInfo.prototype = {
                 ex = ex.clone();
                 // track RECURRENCE-IDs in DTSTART's or RDATE's timezone,
                 // otherwise those won't match any longer w.r.t DST:
                 let rid = ex.recurrenceId;
                 let rdate = rdates[getRidKey(rid)];
                 rid = rid.getInTimezone(rdate ? rdate.timezone : startTimezone);
                 rid.addDuration(timeDiff);
                 ex.recurrenceId = rid;
-                cal.shiftItem(ex, timeDiff);
+                cal.item.shiftOffset(ex, timeDiff);
                 modifiedExceptions.push(ex);
                 this.removeExceptionFor(exid);
             }
         }
         for (let modifiedEx of modifiedExceptions) {
             this.modifyException(modifiedEx, true);
         }
     },
--- a/calendar/base/src/calTodo.js
+++ b/calendar/base/src/calTodo.js
@@ -119,17 +119,17 @@ calTodo.prototype = {
     { cal: "COMPLETED", ics: "completedTime" }],
 
     set icalString(value) {
         this.icalComponent = cal.getIcsService().parseICS(value, null);
     },
 
     get icalString() {
         let calcomp = cal.getIcsService().createIcalComponent("VCALENDAR");
-        cal.calSetProdidVersion(calcomp);
+        cal.item.setStaticProps(calcomp);
         calcomp.addSubcomponent(this.icalComponent);
         return calcomp.serializeToICS();
     },
 
     get icalComponent() {
         let icssvc = cal.getIcsService();
         let icalcomp = icssvc.createIcalComponent("VTODO");
         this.fillIcalComponentFromBase(icalcomp);
--- a/calendar/import-export/calOutlookCSVImportExport.js
+++ b/calendar/import-export/calOutlookCSVImportExport.js
@@ -453,17 +453,17 @@ calOutlookCSVExporter.prototype = {
         headers.push(localeEn.headLocation);
         headers.push(localeEn.headPrivate);
         headers = headers.map(hdr => '"' + hdr + '"');
         let str = headers.join(",");
         str += exportLineEnding;
         aStream.write(str, str.length);
 
         for (let item of aItems) {
-            if (!cal.isEvent(item)) {
+            if (!cal.item.isEvent(item)) {
                 // XXX TODO: warn the user (once) that tasks are not supported
                 // (bug 336175)
                 continue;
             }
             let line = [];
             line.push(item.title);
             line.push(dateString(item.startDate));
             line.push(timeString(item.startDate));
--- a/calendar/lightning/components/lightningTextCalendarConverter.js
+++ b/calendar/lightning/components/lightningTextCalendarConverter.js
@@ -29,17 +29,17 @@ ltnMimeConverter.prototype = {
     uri: null,
 
     convertToHTML: function(contentType, data) {
         let parser = Components.classes["@mozilla.org/calendar/ics-parser;1"]
                                .createInstance(Components.interfaces.calIIcsParser);
         parser.parseString(data);
         let event = null;
         for (let item of parser.getItems({})) {
-            if (cal.isEvent(item)) {
+            if (cal.item.isEvent(item)) {
                 if (item.hasProperty("X-MOZ-FAKED-MASTER")) {
                     // if it's a faked master, take any overridden item to get a real occurrence:
                     let exc = item.recurrenceInfo.getExceptionFor(item.startDate);
                     cal.ASSERT(exc, "unexpected!");
                     if (exc) {
                         item = exc;
                     }
                 }
--- a/calendar/lightning/content/lightning-item-iframe.js
+++ b/calendar/lightning/content/lightning-item-iframe.js
@@ -297,24 +297,24 @@ function onLoad() {
 
     window.fbWrapper = args.fbWrapper;
 
     // the most important attribute we expect from the
     // arguments is the item we'll edit in the dialog.
     let item = args.calendarEvent;
 
     // set the iframe's top level id for event vs task
-    if (!cal.isEvent(item)) {
+    if (!cal.item.isEvent(item)) {
         setDialogId(document.documentElement, "calendar-task-dialog-inner");
     }
 
     // new items should have a non-empty title.
     if (item.isMutable && (!item.title || item.title.length <= 0)) {
         item.title = cal.calGetString("calendar-event-dialog",
-                                      cal.isEvent(item) ? "newEvent" : "newTask");
+                                      cal.item.isEvent(item) ? "newEvent" : "newTask");
     }
 
     window.onAcceptCallback = args.onOk;
     window.mode = args.mode;
 
     // we store the item in the window to be able
     // to access this from any location. please note
     // that the item is either an occurrence [proxy]
@@ -361,17 +361,17 @@ function onLoad() {
     }
 
     window.recurrenceInfo = null;
     if (parentItem.recurrenceInfo) {
         window.recurrenceInfo = parentItem.recurrenceInfo.clone();
     }
 
     // Set initial values for datepickers in New Tasks dialog
-    if (cal.isToDo(item)) {
+    if (cal.item.isToDo(item)) {
         let initialDatesValue = cal.dtz.dateTimeToJsDate(args.initialStartDateValue);
         if (!gNewItemUI) {
             setElementValue("completed-date-picker", initialDatesValue);
             setElementValue("todo-entrydate", initialDatesValue);
             setElementValue("todo-duedate", initialDatesValue);
         }
     }
     loadDialog(window.calendarItem);
@@ -452,21 +452,21 @@ function onCommandCancel() {
     if (gInTab && gTabInfoObject) {
         // Switch to the tab that the prompt refers to.
         gTabmail.switchToTab(gTabInfoObject);
     }
 
     let promptService = Components.interfaces.nsIPromptService;
 
     let promptTitle = cal.calGetString("calendar",
-                                       cal.isEvent(window.calendarItem)
+                                       cal.item.isEvent(window.calendarItem)
                                           ? "askSaveTitleEvent"
                                           : "askSaveTitleTask");
     let promptMessage = cal.calGetString("calendar",
-                                         cal.isEvent(window.calendarItem)
+                                         cal.item.isEvent(window.calendarItem)
                                             ? "askSaveMessageEvent"
                                             : "askSaveMessageTask");
 
     let flags = promptService.BUTTON_TITLE_SAVE *
                 promptService.BUTTON_POS_0 +
                 promptService.BUTTON_TITLE_CANCEL *
                 promptService.BUTTON_POS_1 +
                 promptService.BUTTON_TITLE_DONT_SAVE *
@@ -567,17 +567,17 @@ function loadDialog(aItem) {
 
         // filter out calendars that should not be included
         let calendarList = unfilteredList.filter((calendar) =>
            (calendar.id == calendarToUse.id ||
             (calendar &&
              cal.acl.isCalendarWritable(calendar) &&
              (cal.acl.userCanAddItemsToCalendar(calendar) ||
               (calendar == aItem.calendar && cal.acl.userCanModifyItem(aItem))) &&
-             cal.isItemSupported(aItem, calendar))));
+             cal.item.isItemSupported(aItem, calendar))));
 
         itemProps.calendarList = calendarList.map(calendar => [calendar.id, calendar.name]);
 
         if (calendarToUse && calendarToUse.id) {
             let index = itemProps.calendarList.findIndex(
                 calendar => (calendar[0] == calendarToUse.id));
             if (index != -1) {
                 itemProps.initialCalendarId = calendarToUse.id;
@@ -665,17 +665,17 @@ function loadDialog(aItem) {
         if (aItem.completedDate) {
             updateToDoStatus(aItem.status, cal.dtz.dateTimeToJsDate(aItem.completedDate));
         } else {
             updateToDoStatus(aItem.status);
         }
     }
 
     // Task percent complete
-    if (cal.isToDo(aItem)) {
+    if (cal.item.isToDo(aItem)) {
         let percentCompleteInteger = 0;
         let percentCompleteProperty = aItem.getProperty("PERCENT-COMPLETE");
         if (percentCompleteProperty != null) {
             percentCompleteInteger = parseInt(percentCompleteProperty, 10);
         }
         if (percentCompleteInteger < 0) {
             percentCompleteInteger = 0;
         } else if (percentCompleteInteger > 100) {
@@ -686,17 +686,17 @@ function loadDialog(aItem) {
             itemProps.initialPercentComplete = percentCompleteInteger;
         } else {
             setElementValue("percent-complete-textbox", percentCompleteInteger);
         }
     }
 
     // When in a window, set Item-Menu label to Event or Task
     if (!gInTab) {
-        let isEvent = cal.isEvent(aItem);
+        let isEvent = cal.item.isEvent(aItem);
 
         let labelString = isEvent ? "itemMenuLabelEvent" : "itemMenuLabelTask";
         let label = cal.calGetString("calendar-event-dialog", labelString);
 
         let accessKeyString = isEvent ? "itemMenuAccesskeyEvent2" : "itemMenuAccesskeyTask2";
         let accessKey = cal.calGetString("calendar-event-dialog", accessKeyString);
         sendMessage({
             command: "initializeItemMenu",
@@ -762,17 +762,17 @@ function loadDialog(aItem) {
         disallowcounterCheckbox.disabled = !!window.counterProposal;
 
         updateAttendees();
         updateRepeat(true);
         updateReminder(true);
     }
 
     // Status
-    if (cal.isEvent(aItem)) {
+    if (cal.item.isEvent(aItem)) {
         gConfig.status = aItem.hasProperty("STATUS") ?
             aItem.getProperty("STATUS") : "NONE";
         if (gConfig.status == "NONE") {
             sendMessage({ command: "showCmdStatusNone" });
         }
         updateConfigState({ status: gConfig.status });
         if (gNewItemUI) {
             itemProps.initialStatus = gConfig.status;
@@ -887,17 +887,17 @@ function saveCategories(aItem) {
 
 /**
  * Sets up all date related controls from the passed item
  *
  * @param item      The item to parse information out of.
  */
 function loadDateTime(item) {
     let kDefaultTimezone = cal.dtz.defaultTimezone;
-    if (cal.isEvent(item)) {
+    if (cal.item.isEvent(item)) {
         let startTime = item.startDate;
         let endTime = item.endDate;
         let duration = endTime.subtractDate(startTime);
 
         // Check if an all-day event has been passed in (to adapt endDate).
         if (startTime.isDate) {
             startTime = startTime.clone();
             endTime = endTime.clone();
@@ -911,17 +911,17 @@ function loadDateTime(item) {
         // separately.
         gStartTimezone = startTime.timezone;
         gEndTimezone = endTime.timezone;
         gStartTime = startTime.getInTimezone(kDefaultTimezone);
         gEndTime = endTime.getInTimezone(kDefaultTimezone);
         gItemDuration = duration;
     }
 
-    if (cal.isToDo(item)) {
+    if (cal.item.isToDo(item)) {
         let startTime = null;
         let endTime = null;
         let duration = null;
 
         let hasEntryDate = (item.entryDate != null);
         if (hasEntryDate) {
             startTime = item.entryDate;
             gStartTimezone = startTime.timezone;
@@ -987,17 +987,17 @@ function dateTimeControls2State(aStartDa
     if (gIgnoreUpdate) {
         return;
     }
     let keepAttribute = document.getElementById("keepduration-button")
                                 .getAttribute("keep") == "true";
     let allDay = getElementValue("event-all-day", "checked");
     let startWidgetId;
     let endWidgetId;
-    if (cal.isEvent(window.calendarItem)) {
+    if (cal.item.isEvent(window.calendarItem)) {
         startWidgetId = "event-starttime";
         endWidgetId = "event-endtime";
     } else {
         if (!getElementValue("todo-has-entrydate", "checked")) {
             gItemDuration = null;
         }
         if (!getElementValue("todo-has-duedate", "checked")) {
             gItemDuration = null;
@@ -1176,17 +1176,17 @@ function updateDueDate() {
  * @param aDateTime         An object implementing the isValid and setDateTime
  *                            methods. XXX explain.
  */
 function updateDateCheckboxes(aDatePickerId, aCheckboxId, aDateTime) {
     if (gIgnoreUpdate) {
         return;
     }
 
-    if (!cal.isToDo(window.calendarItem)) {
+    if (!cal.item.isToDo(window.calendarItem)) {
         return;
     }
 
     // force something to get set if there was nothing there before
     setElementValue(aDatePickerId, getElementValue(aDatePickerId));
 
     // first of all disable the datetime picker if we don't have a date
     let hasDate = getElementValue(aCheckboxId, "checked");
@@ -1378,64 +1378,64 @@ function updateReminder(aSuppressDialogs
  * Saves all values the user chose on the dialog to the passed item
  *
  * @param item    The item to save to.
  */
 function saveDialog(item) {
     // Calendar
     item.calendar = getCurrentCalendar();
 
-    cal.setItemProperty(item, "title", getElementValue("item-title"));
-    cal.setItemProperty(item, "LOCATION", getElementValue("item-location"));
+    cal.item.setItemProperty(item, "title", getElementValue("item-title"));
+    cal.item.setItemProperty(item, "LOCATION", getElementValue("item-location"));
 
     saveDateTime(item);
 
-    if (cal.isToDo(item)) {
+    if (cal.item.isToDo(item)) {
         let percentCompleteInteger = 0;
         if (getElementValue("percent-complete-textbox") != "") {
             percentCompleteInteger =
                 parseInt(getElementValue("percent-complete-textbox"), 10);
         }
         if (percentCompleteInteger < 0) {
             percentCompleteInteger = 0;
         } else if (percentCompleteInteger > 100) {
             percentCompleteInteger = 100;
         }
-        cal.setItemProperty(item, "PERCENT-COMPLETE", percentCompleteInteger);
+        cal.item.setItemProperty(item, "PERCENT-COMPLETE", percentCompleteInteger);
     }
 
     // Categories
     saveCategories(item);
 
     // Attachment
     // We want the attachments to be up to date, remove all first.
     item.removeAllAttachments();
 
     // Now add back the new ones
     for (let hashId in gAttachMap) {
         let att = gAttachMap[hashId];
         item.addAttachment(att);
     }
 
     // Description
-    cal.setItemProperty(item, "DESCRIPTION", getElementValue("item-description"));
+    cal.item.setItemProperty(item, "DESCRIPTION", getElementValue("item-description"));
 
     // Event Status
-    if (cal.isEvent(item)) {
+    if (cal.item.isEvent(item)) {
         if (gConfig.status && gConfig.status != "NONE") {
             item.setProperty("STATUS", gConfig.status);
         } else {
             item.deleteProperty("STATUS");
         }
     } else {
         let status = getElementValue("todo-status");
         if (status != "COMPLETED") {
             item.completedDate = null;
         }
-        cal.setItemProperty(item, "STATUS", status == "NONE" ? null : status);
+        cal.item.setItemProperty(item, "STATUS", status == "NONE" ? null : status);
     }
 
     // set the "PRIORITY" property if a valid priority has been
     // specified (any integer value except *null*) OR the item
     // already specifies a priority. in any other case we don't
     // need this property and can safely delete it. we need this special
     // handling since the WCAP provider always includes the priority
     // with value *null* and we don't detect changes to this item if
@@ -1450,59 +1450,59 @@ function saveDialog(item) {
     // Transparency
     if (gConfig.showTimeAs) {
         item.setProperty("TRANSP", gConfig.showTimeAs);
     } else {
         item.deleteProperty("TRANSP");
     }
 
     // Privacy
-    cal.setItemProperty(item, "CLASS", gConfig.privacy, "privacy");
-
-    if (item.status == "COMPLETED" && cal.isToDo(item)) {
+    cal.item.setItemProperty(item, "CLASS", gConfig.privacy, "privacy");
+
+    if (item.status == "COMPLETED" && cal.item.isToDo(item)) {
         let elementValue = getElementValue("completed-date-picker");
         item.completedDate = cal.dtz.jsDateToDateTime(elementValue);
     }
 
     saveReminder(item);
 }
 
 /**
  * Save date and time related values from the dialog to the passed item.
  *
  * @param item    The item to save to.
  */
 function saveDateTime(item) {
     // Changes to the start date don't have to change the until date.
     untilDateCompensation(item);
 
-    if (cal.isEvent(item)) {
+    if (cal.item.isEvent(item)) {
         let startTime = gStartTime.getInTimezone(gStartTimezone);
         let endTime = gEndTime.getInTimezone(gEndTimezone);
         let isAllDay = getElementValue("event-all-day", "checked");
         if (isAllDay) {
             startTime = startTime.clone();
             endTime = endTime.clone();
             startTime.isDate = true;
             endTime.isDate = true;
             endTime.day += 1;
         } else {
             startTime = startTime.clone();
             startTime.isDate = false;
             endTime = endTime.clone();
             endTime.isDate = false;
         }
-        cal.setItemProperty(item, "startDate", startTime);
-        cal.setItemProperty(item, "endDate", endTime);
+        cal.item.setItemProperty(item, "startDate", startTime);
+        cal.item.setItemProperty(item, "endDate", endTime);
     }
-    if (cal.isToDo(item)) {
+    if (cal.item.isToDo(item)) {
         let startTime = gStartTime && gStartTime.getInTimezone(gStartTimezone);
         let endTime = gEndTime && gEndTime.getInTimezone(gEndTimezone);
-        cal.setItemProperty(item, "entryDate", startTime);
-        cal.setItemProperty(item, "dueDate", endTime);
+        cal.item.setItemProperty(item, "entryDate", startTime);
+        cal.item.setItemProperty(item, "dueDate", endTime);
     }
 }
 
 /**
  * Changes the until date in the rule in order to compensate the automatic
  * correction caused by the function onStartDateChange() when saving the
  * item.
  * It allows to keep the until date set in the dialog irrespective of the
@@ -1528,19 +1528,19 @@ function untilDateCompensation(aItem) {
 }
 
 /**
  * Updates the dialog title based on item type and if the item is new or to be
  * modified.
  */
 function updateTitle() {
     let strName;
-    if (cal.isEvent(window.calendarItem)) {
+    if (cal.item.isEvent(window.calendarItem)) {
         strName = (window.mode == "new" ? "newEventDialog" : "editEventDialog");
-    } else if (cal.isToDo(window.calendarItem)) {
+    } else if (cal.item.isToDo(window.calendarItem)) {
         strName = (window.mode == "new" ? "newTaskDialog" : "editTaskDialog");
     } else {
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
     }
     let newTitle = cal.calGetString("calendar", strName) + ": " +
                       getElementValue("item-title");
     sendMessage({ command: "updateTitle", argument: newTitle });
 }
@@ -1550,17 +1550,17 @@ function updateTitle() {
  * parts of the dialog have options selected that make sense.
  * constraining factors like
  */
 function updateAccept() {
     let enableAccept = true;
     let kDefaultTimezone = cal.dtz.defaultTimezone;
     let startDate;
     let endDate;
-    let isEvent = cal.isEvent(window.calendarItem);
+    let isEvent = cal.item.isEvent(window.calendarItem);
 
     // don't allow for end dates to be before start dates
     if (isEvent) {
         startDate = cal.dtz.jsDateToDateTime(getElementValue("event-starttime"));
         endDate = cal.dtz.jsDateToDateTime(getElementValue("event-endtime"));
     } else {
         startDate = getElementValue("todo-has-entrydate", "checked") ?
             cal.dtz.jsDateToDateTime(getElementValue("todo-entrydate")) : null;
@@ -1632,17 +1632,17 @@ var gOldEndTime = null;
 var gOldStartTimezone = null;
 var gOldEndTimezone = null;
 
 /**
  * Handler function to update controls and state in consequence of the "all
  * day" checkbox being clicked.
  */
 function onUpdateAllDay() {
-    if (!cal.isEvent(window.calendarItem)) {
+    if (!cal.item.isEvent(window.calendarItem)) {
         return;
     }
     let allDay = getElementValue("event-all-day", "checked");
     let kDefaultTimezone = cal.dtz.defaultTimezone;
 
     if (allDay) {
         // Store date-times and related timezones so we can restore
         // if the user unchecks the "all day" checkbox.
@@ -1701,17 +1701,17 @@ function onUpdateAllDay() {
  * - 'timezone-endtime'
  * the state depends on whether or not the event is configured as 'all-day' or not.
  */
 function updateAllDay() {
     if (gIgnoreUpdate) {
         return;
     }
 
-    if (!cal.isEvent(window.calendarItem)) {
+    if (!cal.item.isEvent(window.calendarItem)) {
         return;
     }
 
     let allDay = getElementValue("event-all-day", "checked");
     setElementValue("event-starttime", allDay, "timepickerdisabled");
     setElementValue("event-endtime", allDay, "timepickerdisabled");
 
     gStartTime.isDate = allDay;
@@ -1746,17 +1746,17 @@ function openNewTask() {
 
 /**
  * Update the transparency status of this dialog, depending on if the event
  * is all-day or not.
  *
  * @param allDay    If true, the event is all-day
  */
 function setShowTimeAs(allDay) {
-    gConfig.showTimeAs = cal.getEventDefaultTransparency(allDay);
+    gConfig.showTimeAs = cal.item.getEventDefaultTransparency(allDay);
     updateConfigState({ showTimeAs: gConfig.showTimeAs });
 }
 
 function editAttendees() {
     let savedWindow = window;
     let calendar = getCurrentCalendar();
 
     let callback = function(attendees, organizer, startTime, endTime) {
@@ -1861,17 +1861,17 @@ function updateConfigState(aArg) {
             hasPrivacy: capSupported("privacy"),
             calendarType: getCurrentCalendar().type,
             privacyValues: capValues("privacy",
                             ["PUBLIC", "CONFIDENTIAL", "PRIVATE"])
         });
     }
 
     // For tasks, do not include showTimeAs
-    if (aArg.hasOwnProperty("showTimeAs") && cal.isToDo(window.calendarItem)) {
+    if (aArg.hasOwnProperty("showTimeAs") && cal.item.isToDo(window.calendarItem)) {
         delete aArg.showTimeAs;
         if (Object.keys(aArg).length == 0) {
             return;
         }
     }
 
     sendMessage({ command: "updateConfigState", argument: aArg });
 }
@@ -2521,17 +2521,17 @@ function editRepeat() {
  * @param aItemRepeatCall      True when the function is being called from
  *                               the item-repeat menu list. It allows to detect
  *                               a change from the "custom" option.
  */
 function updateRepeat(aSuppressDialogs, aItemRepeatCall) {
     function setUpEntrydateForTask(item) {
         // if this item is a task, we need to make sure that it has
         // an entry-date, otherwise we can't create a recurrence.
-        if (cal.isToDo(item)) {
+        if (cal.item.isToDo(item)) {
             // automatically check 'has entrydate' if needed.
             if (!getElementValue("todo-has-entrydate", "checked")) {
                 setElementValue("todo-has-entrydate", "true", "checked");
 
                 // make sure gStartTime is properly initialized
                 updateEntryDate();
             }
 
@@ -2545,17 +2545,17 @@ function updateRepeat(aSuppressDialogs, 
     let repeatMenu = document.getElementById("item-repeat");
     let repeatValue = repeatMenu.selectedItem.getAttribute("value");
     let repeatDeck = document.getElementById("repeat-deck");
 
     if (repeatValue == "none") {
         repeatDeck.selectedIndex = -1;
         window.recurrenceInfo = null;
         let item = window.calendarItem;
-        if (cal.isToDo(item)) {
+        if (cal.item.isToDo(item)) {
             enableElementWithLock("todo-has-entrydate", "repeat-lock");
         }
     } else if (repeatValue == "custom") {
         let lastRepeatDeck = repeatDeck.selectedIndex;
         repeatDeck.selectedIndex = 1;
         // the user selected custom repeat pattern. we now need to bring
         // up the appropriate dialog in order to let the user specify the
         // new rule. First of all, retrieve the item we want to specify
@@ -2594,17 +2594,17 @@ function updateRepeat(aSuppressDialogs, 
         //   - re-enable the 'has entrydate' option in case
         //     we didn't end up with a recurrence rule.
         // 2)  Check whether the new recurrence rule needs the
         //     recurrence details text or it can be displayed
         //     only with the repeat-until-datepicker.
         if (recurrenceInfo == window.recurrenceInfo) {
             repeatMenu.selectedIndex = gLastRepeatSelection;
             repeatDeck.selectedIndex = lastRepeatDeck;
-            if (cal.isToDo(item)) {
+            if (cal.item.isToDo(item)) {
                 if (!window.recurrenceInfo) {
                     enableElementWithLock("todo-has-entrydate", "repeat-lock");
                 }
             }
         } else {
             // From the Edit Recurrence dialog, the rules "every day" and
             // "every weekday" don't need the recurrence details text when they
             // have only the until date. The getRepeatTypeAndUntilDate()
@@ -2693,17 +2693,17 @@ function updateRepeat(aSuppressDialogs, 
         }
 
         setUpEntrydateForTask(item);
         updateUntildateRecRule(recRule);
 
         recurrenceInfo.insertRecurrenceItemAt(recRule, 0);
         window.recurrenceInfo = recurrenceInfo;
 
-        if (cal.isToDo(item)) {
+        if (cal.item.isToDo(item)) {
             if (!getElementValue("todo-has-entrydate", "checked")) {
                 setElementValue("todo-has-entrydate", "true", "checked");
             }
             disableElementWithLock("todo-has-entrydate", "repeat-lock");
         }
 
         // Preset the until-datepicker's minimonth to the start date.
         let startDate = cal.dtz.dateTimeToJsDate(gStartTime.getInTimezone(cal.dtz.floating));
@@ -3019,20 +3019,20 @@ function onCommandSave(aIsClosing) {
  *
  */
 function onCommandDeleteItem() {
     // only ask for confirmation, if the User changed anything on a new item or we modify an existing item
     if (isItemChanged() || window.mode != "new") {
         let promptTitle = "";
         let promptMessage = "";
 
-        if (cal.isEvent(window.calendarItem)) {
+        if (cal.item.isEvent(window.calendarItem)) {
             promptTitle = cal.calGetString("calendar", "deleteEventLabel");
             promptMessage = cal.calGetString("calendar", "deleteEventMessage");
-        } else if (cal.isToDo(window.calendarItem)) {
+        } else if (cal.item.isToDo(window.calendarItem)) {
             promptTitle = cal.calGetString("calendar", "deleteTaskLabel");
             promptMessage = cal.calGetString("calendar", "deleteTaskMessage");
         }
 
         let answerDelete = Services.prompt.confirm(
                                     null,
                                     promptTitle,
                                     promptMessage);
@@ -3242,17 +3242,17 @@ function editTimezone(aElementId, aDateT
 function updateDateTime() {
     gIgnoreUpdate = true;
 
     let item = window.calendarItem;
     // Convert to default timezone if the timezone option
     // is *not* checked, otherwise keep the specific timezone
     // and display the labels in order to modify the timezone.
     if (gTimezonesEnabled) {
-        if (cal.isEvent(item)) {
+        if (cal.item.isEvent(item)) {
             let startTime = gStartTime.getInTimezone(gStartTimezone);
             let endTime = gEndTime.getInTimezone(gEndTimezone);
 
             setElementValue("event-all-day", startTime.isDate, "checked");
 
             // In the case where the timezones are different but
             // the timezone of the endtime is "UTC", we convert
             // the endtime into the timezone of the starttime.
@@ -3269,17 +3269,17 @@ function updateDateTime() {
             // automatic conversion back into the OS timezone.
             startTime.timezone = cal.dtz.floating;
             endTime.timezone = cal.dtz.floating;
 
             setElementValue("event-starttime", cal.dtz.dateTimeToJsDate(startTime));
             setElementValue("event-endtime", cal.dtz.dateTimeToJsDate(endTime));
         }
 
-        if (cal.isToDo(item)) {
+        if (cal.item.isToDo(item)) {
             let startTime = gStartTime && gStartTime.getInTimezone(gStartTimezone);
             let endTime = gEndTime && gEndTime.getInTimezone(gEndTimezone);
             let hasEntryDate = (startTime != null);
             let hasDueDate = (endTime != null);
 
             if (hasEntryDate && hasDueDate) {
                 setElementValue("todo-has-entrydate", hasEntryDate, "checked");
                 startTime.timezone = cal.dtz.floating;
@@ -3309,31 +3309,31 @@ function updateDateTime() {
 
                 setElementValue("todo-entrydate", cal.dtz.dateTimeToJsDate(startTime));
                 setElementValue("todo-duedate", cal.dtz.dateTimeToJsDate(endTime));
             }
         }
     } else {
         let kDefaultTimezone = cal.dtz.defaultTimezone;
 
-        if (cal.isEvent(item)) {
+        if (cal.item.isEvent(item)) {
             let startTime = gStartTime.getInTimezone(kDefaultTimezone);
             let endTime = gEndTime.getInTimezone(kDefaultTimezone);
             setElementValue("event-all-day", startTime.isDate, "checked");
 
             // before feeding the date/time value into the control we need
             // to set the timezone to 'floating' in order to avoid the
             // automatic conversion back into the OS timezone.
             startTime.timezone = cal.dtz.floating;
             endTime.timezone = cal.dtz.floating;
             setElementValue("event-starttime", cal.dtz.dateTimeToJsDate(startTime));
             setElementValue("event-endtime", cal.dtz.dateTimeToJsDate(endTime));
         }
 
-        if (cal.isToDo(item)) {
+        if (cal.item.isToDo(item)) {
             let startTime = gStartTime &&
                             gStartTime.getInTimezone(kDefaultTimezone);
             let endTime = gEndTime && gEndTime.getInTimezone(kDefaultTimezone);
             let hasEntryDate = (startTime != null);
             let hasDueDate = (endTime != null);
 
             if (hasEntryDate && hasDueDate) {
                 setElementValue("todo-has-entrydate", hasEntryDate, "checked");
@@ -3515,17 +3515,17 @@ function updateItemURL(aShow, aUrl) {
 
 /**
  * This function updates dialog controls related to attendees.
  */
 function updateAttendees() {
     // sending email invitations currently only supported for events
     let attendeeTab = document.getElementById("event-grid-tab-attendees");
     let attendeePanel = document.getElementById("event-grid-tabpanel-attendees");
-    if (cal.isEvent(window.calendarItem)) {
+    if (cal.item.isEvent(window.calendarItem)) {
         attendeeTab.removeAttribute("collapsed");
         attendeePanel.removeAttribute("collapsed");
 
         if (window.organizer && window.organizer.id) {
             document.getElementById("item-organizer-row").removeAttribute("collapsed");
             let cell = document.querySelector(".item-organizer-cell");
             let icon = cell.querySelector("img:nth-of-type(1)");
             let text = cell.querySelector("label:nth-of-type(1)");
@@ -3576,17 +3576,17 @@ function updateRepeatDetails() {
         // create a details string, we simply don't show anything.
         // this could happen if the repeat rule is something exotic
         // we don't have any strings prepared for.
         let repeatDetails = document.getElementById("repeat-details");
         repeatDetails.setAttribute("collapsed", "true");
 
         // Try to create a descriptive string from the rule(s).
         let kDefaultTimezone = cal.dtz.defaultTimezone;
-        let event = cal.isEvent(item);
+        let event = cal.item.isEvent(item);
 
         let startDate = getElementValue(event ? "event-starttime" : "todo-entrydate");
         let endDate = getElementValue(event ? "event-endtime" : "todo-duedate");
         startDate = cal.dtz.jsDateToDateTime(startDate, kDefaultTimezone);
         endDate = cal.dtz.jsDateToDateTime(endDate, kDefaultTimezone);
 
         let allDay = getElementValue("event-all-day", "checked");
         let detailsString = recurrenceRule2String(recurrenceInfo, startDate,
@@ -3765,23 +3765,23 @@ function updateCapabilities() {
 function isItemChanged() {
     let newItem = saveItem();
     let oldItem = window.calendarItem.clone();
 
     // we need to guide the description text through the text-field since
     // newlines are getting converted which would indicate changes to the
     // text.
     setElementValue("item-description", oldItem.getProperty("DESCRIPTION"));
-    cal.setItemProperty(oldItem,
+    cal.item.setItemProperty(oldItem,
                         "DESCRIPTION",
                         getElementValue("item-description"));
     setElementValue("item-description", newItem.getProperty("DESCRIPTION"));
 
     if ((newItem.calendar.id == oldItem.calendar.id) &&
-        cal.compareItemContent(newItem, oldItem)) {
+        cal.item.compareContent(newItem, oldItem)) {
         return false;
     }
     return true;
 }
 
 /**
  * Test if a specific capability is supported
  *
--- a/calendar/lightning/content/lightning-item-panel.js
+++ b/calendar/lightning/content/lightning-item-panel.js
@@ -260,17 +260,17 @@ function onLoadLightningItemPanel(aIfram
         // set toolbar icon color for light or dark themes
         if (typeof ToolbarIconColor !== "undefined") {
             ToolbarIconColor.init();
         }
     }
 
     // event or task
     let calendarItem = iframe.contentWindow.arguments[0].calendarEvent;
-    gConfig.isEvent = cal.isEvent(calendarItem);
+    gConfig.isEvent = cal.item.isEvent(calendarItem);
 
     // for tasks in a window dialog, set the dialog id for CSS selection, etc.
     if (!gTabmail && !gConfig.isEvent) {
         setDialogId(document.documentElement, "calendar-task-dialog");
     }
 
     // timezones enabled
     gConfig.timezonesEnabled = getTimezoneCommandState();
--- a/calendar/lightning/modules/ltnInvitationUtils.jsm
+++ b/calendar/lightning/modules/ltnInvitationUtils.jsm
@@ -529,17 +529,17 @@ ltn.invitation = {
      * @return {JSObject}                          Objcet of result and differences of parsing
      * @return {String} JsObject.result.type       Parsing result: OK|OLDVERSION|ERROR|NODIFF
      * @return {String} JsObject.result.descr      Parsing result description
      * @return {Array}  JsObject.differences       Array of objects consisting of property, proposed
      *                                                 and original properties.
      * @return {String} JsObject.comment           A comment of the attendee, if any
      */
     parseCounter: function(aProposedItem, aExistingItem) {
-        let isEvent = cal.isEvent(aProposedItem);
+        let isEvent = cal.item.isEvent(aProposedItem);
         // atm we only support a subset of properties, for a full list see RfC 5546 section 3.2.7
         let properties = ["SUMMARY", "LOCATION", "DTSTART", "DTEND", "COMMENT"];
         if (!isEvent) {
             cal.LOG("Parsing of counterproposals is currently only supported for events.");
             properties = [];
         }
 
         let diff = [];
--- a/calendar/providers/caldav/calDavCalendar.js
+++ b/calendar/providers/caldav/calDavCalendar.js
@@ -641,17 +641,17 @@ calDavCalendar.prototype = {
         }
 
         if (aItem.id == null) {
             notifyListener(Components.results.NS_ERROR_FAILURE,
                            "Can't set ID on non-mutable item to addItem");
             return;
         }
 
-        if (!cal.isItemSupported(aItem, this)) {
+        if (!cal.item.isItemSupported(aItem, this)) {
             notifyListener(Components.results.NS_ERROR_FAILURE,
                            "Server does not support item type");
             return;
         }
 
         let parentItem = aItem.parentItem;
         parentItem.calendar = this.superCalendar;
 
@@ -2413,17 +2413,17 @@ calDavCalendar.prototype = {
         }
         let mailto_aCalId = aCalIdParts.join(":");
 
         let self = this;
 
         let organizer = this.calendarUserAddress;
 
         let fbQuery = cal.getIcsService().createIcalComponent("VCALENDAR");
-        cal.calSetProdidVersion(fbQuery);
+        cal.item.setStaticProps(fbQuery);
         let prop = cal.getIcsService().createIcalProperty("METHOD");
         prop.value = "REQUEST";
         fbQuery.addProperty(prop);
         let fbComp = cal.getIcsService().createIcalComponent("VFREEBUSY");
         fbComp.stampTime = cal.dtz.now().getInTimezone(cal.dtz.UTC);
         prop = cal.getIcsService().createIcalProperty("ORGANIZER");
         prop.value = organizer;
         fbComp.addProperty(prop);
--- a/calendar/providers/gdata/components/calGoogleCalendar.js
+++ b/calendar/providers/gdata/components/calGoogleCalendar.js
@@ -354,29 +354,29 @@ calGoogleCalendar.prototype = {
         (async () => {
             let itemData = ItemToJSON(aItem, this.offlineStorage, isImport);
 
             // Add the calendar to the item, for later use.
             aItem.calendar = this.superCalendar;
 
             request.type = request.ADD;
             request.calendar = this;
-            if (cal.isEvent(aItem)) {
+            if (cal.item.isEvent(aItem)) {
                 if (isImport) {
                     cal.LOG("[calGoogleCalendar] Adding invitation event " + aItem.title);
                     request.uri = this.createEventsURI("events", "import");
                 } else {
                     cal.LOG("[calGoogleCalendar] Adding regular event " + aItem.title);
                     request.uri = this.createEventsURI("events");
                 }
 
                 if (Preferences.get("calendar.google.sendEventNotifications", false)) {
                     request.addQueryParameter("sendNotifications", "true");
                 }
-            } else if (cal.isToDo(aItem)) {
+            } else if (cal.item.isToDo(aItem)) {
                 cal.LOG("[calGoogleCalendar] Adding task " + aItem.title);
                 request.uri = this.createTasksURI("tasks");
                 // Tasks sent with an id will cause a bad request
                 delete itemData.id;
             }
 
             if (!request.uri) {
                 throw Components.Exception("Item type not supported",
@@ -426,31 +426,31 @@ calGoogleCalendar.prototype = {
                 (aNewItem.recurrenceId ? aNewItem.recurrenceId.icalString :
                 "master item") + ")");
 
         // Set up the request
         let request = new calGoogleRequest();
         (async () => {
             request.type = request.MODIFY;
             request.calendar = this;
-            if (cal.isEvent(aNewItem)) {
+            if (cal.item.isEvent(aNewItem)) {
                 let googleId = getGoogleId(aNewItem, this.offlineStorage);
                 request.uri = this.createEventsURI("events", googleId);
 
                 // Updating invitations often causes a forbidden error becase
                 // some parts are not writable. Using PATCH ignores anything
                 // that isn't allowed.
                 if (cal.isInvitation(aNewItem)) {
                     request.type = request.PATCH;
                 }
 
                 if (Preferences.get("calendar.google.sendEventNotifications", false)) {
                     request.addQueryParameter("sendNotifications", "true");
                 }
-            } else if (cal.isToDo(aNewItem)) {
+            } else if (cal.item.isToDo(aNewItem)) {
                 request.uri = this.createTasksURI("tasks", aNewItem.id);
             }
 
             if (!request.uri) {
                 throw Components.Exception("Item type not supported",
                                            Components.results.NS_ERROR_NOT_IMPLEMENTED);
             }
 
@@ -526,22 +526,22 @@ calGoogleCalendar.prototype = {
 
     deleteItem: function(aItem, aListener) {
         cal.LOG("[calGoogleCalendar] Deleting item " + aItem.title + "(" + aItem.id + ")");
 
         let request = new calGoogleRequest();
         (async () => {
             request.type = request.DELETE;
             request.calendar = this;
-            if (cal.isEvent(aItem)) {
+            if (cal.item.isEvent(aItem)) {
                 request.uri = this.createEventsURI("events", getGoogleId(aItem, this.offlineStorage));
                 if (Preferences.get("calendar.google.sendEventNotifications", false)) {
                     request.addQueryParameter("sendNotifications", "true");
                 }
-            } else if (cal.isToDo(aItem)) {
+            } else if (cal.item.isToDo(aItem)) {
                 request.uri = this.createTasksURI("tasks", aItem.id);
             }
 
             if (!request.uri) {
                 throw Components.Exception("Item type not supported",
                                            Components.results.NS_ERROR_NOT_IMPLEMENTED);
             }
 
--- a/calendar/providers/gdata/content/gdata-calendar-event-dialog.js
+++ b/calendar/providers/gdata/content/gdata-calendar-event-dialog.js
@@ -13,18 +13,18 @@ Components.utils.import("resource://gdat
     if (!("gOldEndTimezone" in window)) {
         window.gOldEndTimezone = null;
     }
 
     monkeyPatch(window, "updateCalendar", function(protofunc, ...args) {
         let rv = protofunc.apply(this, args);
         let calendar = getCurrentCalendar();
         let isGoogleCalendar = (calendar.type == "gdata");
-        let isTask = cal.isToDo(window.calendarItem);
-        let isEvent = cal.isEvent(window.calendarItem);
+        let isTask = cal.item.isToDo(window.calendarItem);
+        let isEvent = cal.item.isEvent(window.calendarItem);
         let isGoogleTask = isGoogleCalendar && isTask;
         let isGoogleEvent = isGoogleCalendar && isEvent;
 
         let hideForTaskIds = [
             "event-grid-location-row",
 
             "event-grid-startdate-row",
             "timezone-endtime",
@@ -127,17 +127,17 @@ Components.utils.import("resource://gdat
             }
         }
         return rv;
     });
 
     monkeyPatch(window, "updateCategoryMenulist", function(protofunc, ...args) {
         let rv;
         let calendar = getCurrentCalendar();
-        if (calendar.type == "gdata" && cal.isToDo(window.calendarItem)) {
+        if (calendar.type == "gdata" && cal.item.isToDo(window.calendarItem)) {
             let unwrappedCal = calendar.getProperty("cache.uncachedCalendar").wrappedJSObject;
             unwrappedCal.mProperties['capabilities.categories.maxCount'] = 0;
             rv = protofunc.apply(this, args);
             delete unwrappedCal.mProperties['capabilities.categories.maxCount'];
         } else {
             rv = protofunc.apply(this, args);
         }
         return rv;
--- a/calendar/providers/gdata/modules/gdataUtils.jsm
+++ b/calendar/providers/gdata/modules/gdataUtils.jsm
@@ -543,19 +543,19 @@ function TaskToJSON(aItem, aOfflineStora
 /**
  * Convenience function to convert any item type (task/event) to its JSON
  * representation
  *
  * @param aItem         The item to convert
  * @return              A JS Object representing the item.
  */
 function ItemToJSON(aItem, aOfflineStorage, aIsImport) {
-    if (cal.isEvent(aItem)) {
+    if (cal.item.isEvent(aItem)) {
         return EventToJSON(aItem, aOfflineStorage, aIsImport);
-    } else if (cal.isToDo(aItem)) {
+    } else if (cal.item.isToDo(aItem)) {
         return TaskToJSON(aItem, aOfflineStorage, aIsImport);
     } else {
         cal.ERROR("[calGoogleCalendar] Invalid item type: " + aItem.icalString);
         return null;
     }
 }
 
 /**
--- a/calendar/providers/memory/calMemoryCalendar.js
+++ b/calendar/providers/memory/calMemoryCalendar.js
@@ -221,17 +221,17 @@ calMemoryCalendar.prototype = {
                 return reportError("item ID mismatch between old and new items");
             }
 
             aOldItem = aOldItem.parentItem;
             let storedOldItem = this.mItems[aOldItem.id];
 
             // compareItems is not suitable here. See bug 418805.
             // Cannot compare here due to bug 380060
-            if (!cal.compareItemContent(storedOldItem, aOldItem)) {
+            if (!cal.item.compareContent(storedOldItem, aOldItem)) {
                 return reportError("old item mismatch in modifyItem. storedId:" + storedOldItem.icalComponent + " old item:" + aOldItem.icalComponent);
             }
             // offline bug
 
             if (aOldItem.generation != storedOldItem.generation) {
                 return reportError("generation mismatch in modifyItem");
             }
 
@@ -317,19 +317,19 @@ calMemoryCalendar.prototype = {
                                          aId,
                                          null);
             return;
         }
 
         let item = this.mItems[aId];
         let iid = null;
 
-        if (cal.isEvent(item)) {
+        if (cal.item.isEvent(item)) {
             iid = Components.interfaces.calIEvent;
-        } else if (cal.isToDo(item)) {
+        } else if (cal.item.isToDo(item)) {
             iid = Components.interfaces.calITodo;
         } else {
             this.notifyOperationComplete(aListener,
                                          Components.results.NS_ERROR_FAILURE,
                                          Components.interfaces.calIOperationListener.GET,
                                          aId,
                                          "Can't deduce item type based on QI");
             return;
@@ -441,17 +441,17 @@ calMemoryCalendar.prototype = {
 
             return (!reqFlag &&
                     (!itemFlag ||
                      itemFlag != cICL.OFFLINE_FLAG_DELETED_RECORD)) ||
                    itemFlag == reqFlag;
         };
 
         cal.forEach(this.mItems, ([id, item]) => {
-            let isEvent_ = cal.isEvent(item);
+            let isEvent_ = cal.item.isEvent(item);
             if (isEvent_) {
                 if (!wantEvents) {
                     return cal.forEach.CONTINUE;
                 }
             } else if (!wantTodos) {
                 return cal.forEach.CONTINUE;
             }
 
@@ -460,31 +460,31 @@ calMemoryCalendar.prototype = {
 
             // If the offline flag doesn't match, skip the item
             if (!matchOffline(itemFlag, requestedFlag)) {
                 return cal.forEach.CONTINUE;
             }
 
             if (itemReturnOccurrences && item.recurrenceInfo) {
                 let startDate = aRangeStart;
-                if (!aRangeStart && cal.isToDo(item)) {
+                if (!aRangeStart && cal.item.isToDo(item)) {
                     startDate = item.entryDate;
                 }
                 let occurrences = item.recurrenceInfo.getOccurrences(
                     startDate, aRangeEnd, aCount ? aCount - itemsFound.length : 0, {});
                 if (wantUnrespondedInvitations) {
                     occurrences = occurrences.filter(checkUnrespondedInvitation);
                 }
                 if (!isEvent_) {
                     occurrences = occurrences.filter(checkCompleted);
                 }
                 itemsFound = itemsFound.concat(occurrences);
             } else if ((!wantUnrespondedInvitations || checkUnrespondedInvitation(item)) &&
                        (isEvent_ || checkCompleted(item)) &&
-                       cal.checkIfInRange(item, aRangeStart, aRangeEnd)) {
+                       cal.item.checkIfInRange(item, aRangeStart, aRangeEnd)) {
                 // This needs fixing for recurring items, e.g. DTSTART of parent may occur before aRangeStart.
                 // This will be changed with bug 416975.
                 itemsFound.push(item);
             }
             if (aCount && itemsFound.length >= aCount) {
                 return cal.forEach.BREAK;
             }
             return cal.forEach.CONTINUE;
--- a/calendar/providers/storage/calStorageCalendar.js
+++ b/calendar/providers/storage/calStorageCalendar.js
@@ -627,19 +627,19 @@ calStorageCalendar.prototype = {
                                          Components.results.NS_OK,
                                          Components.interfaces.calIOperationListener.GET,
                                          aId,
                                          null);
             return;
         }
 
         let item_iid = null;
-        if (cal.isEvent(item)) {
+        if (cal.item.isEvent(item)) {
             item_iid = Components.interfaces.calIEvent;
-        } else if (cal.isToDo(item)) {
+        } else if (cal.item.isToDo(item)) {
             item_iid = Components.interfaces.calITodo;
         } else {
             this.notifyOperationComplete(aListener,
                                          Components.results.NS_ERROR_FAILURE,
                                          Components.interfaces.calIOperationListener.GET,
                                          aId,
                                          "Can't deduce item type based on QI");
             return;
@@ -767,17 +767,17 @@ calStorageCalendar.prototype = {
                 // If the item is recurring, get all ocurrences that fall in
                 // the range. If the item doesn't fall into the range at all,
                 // this expands to 0 items.
                 expandedItems = item.recurrenceInfo.getOccurrences(aRangeStart, aRangeEnd, 0, {});
                 if (wantUnrespondedInvitations) {
                     expandedItems = expandedItems.filter(checkUnrespondedInvitation);
                 }
             } else if ((!wantUnrespondedInvitations || checkUnrespondedInvitation(item)) &&
-                       cal.checkIfInRange(item, aRangeStart, aRangeEnd)) {
+                       cal.item.checkIfInRange(item, aRangeStart, aRangeEnd)) {
                 // If no occurrences are wanted, check only the parent item.
                 // This will be changed with bug 416975.
                 expandedItems = [item];
             }
 
             if (expandedItems.length && optionalFilterFunc) {
                 expandedItems = expandedItems.filter(optionalFilterFunc);
             }
@@ -957,46 +957,46 @@ calStorageCalendar.prototype = {
                     aListener.onOperationComplete(self, Components.results.NS_ERROR_FAILURE,
                                                   Components.interfaces.calIOperationListener.GET, aItem.id, aItem);
                 },
                 handleCompletion: function(aReason) {
                     aListener.onOperationComplete(self, Components.results.NS_OK,
                                                   Components.interfaces.calIOperationListener.GET, aItem.id, flag);
                 }
             };
-            if (cal.isEvent(aItem)) {
+            if (cal.item.isEvent(aItem)) {
                 this.prepareStatement(this.mSelectEvent);
                 this.mSelectEvent.params.id = aID;
                 this.mSelectEvent.executeAsync(listener);
-            } else if (cal.isToDo(aItem)) {
+            } else if (cal.item.isToDo(aItem)) {
                 this.prepareStatement(this.mSelectTodo);
                 this.mSelectTodo.params.id = aID;
                 this.mSelectTodo.executeAsync(listener);
             }
         } else {
             // It is possible that aItem can be null, flag provided should be null in this case
             aListener.onOperationComplete(this, Components.results.NS_OK,
                                                Components.interfaces.calIOperationListener.GET, null, flag);
         }
     },
 
     setOfflineJournalFlag: function(aItem, flag) {
         let aID = aItem.id;
-        if (cal.isEvent(aItem)) {
+        if (cal.item.isEvent(aItem)) {
             this.prepareStatement(this.mEditEventOfflineFlag);
             this.mEditEventOfflineFlag.params.id = aID;
             this.mEditEventOfflineFlag.params.offline_journal = flag || null;
             try {
                 this.mEditEventOfflineFlag.executeStep();
             } catch (e) {
                 this.logError("Error setting offline journal flag for " + aItem.title, e);
             } finally {
                 this.mEditEventOfflineFlag.reset();
             }
-        } else if (cal.isToDo(aItem)) {
+        } else if (cal.item.isToDo(aItem)) {
             this.prepareStatement(this.mEditTodoOfflineFlag);
             this.mEditTodoOfflineFlag.params.id = aID;
             this.mEditTodoOfflineFlag.params.offline_journal = flag || null;
             try {
                 this.mEditTodoOfflineFlag.executeStep();
             } catch (e) {
                 this.logError("Error setting offline journal flag for " + aItem.title, e);
             } finally {
@@ -1538,17 +1538,17 @@ calStorageCalendar.prototype = {
         if (row.last_modified) {
             item.setProperty("LAST-MODIFIED", newDateTime(row.last_modified, "UTC"));
         }
     },
 
     cacheItem: function(item) {
         this.mItemCache[item.id] = item;
         if (item.recurrenceInfo) {
-            if (cal.isEvent(item)) {
+            if (cal.item.isEvent(item)) {
                 this.mRecEventCache[item.id] = item;
             } else {
                 this.mRecTodoCache[item.id] = item;
             }
         }
     },
 
     mRecEventCacheOfflineFlags: {},
@@ -1776,32 +1776,32 @@ calStorageCalendar.prototype = {
             // (getAdditionalDataForItem->get[Event|Todo]FromRow->getAdditionalDataForItem):
             // every excepton has a recurrenceId and isn't flagged as CAL_ITEM_FLAG.HAS_EXCEPTIONS
             if (item.recurrenceId) {
                 throw Components.results.NS_ERROR_UNEXPECTED;
             }
 
             let rec = item.recurrenceInfo;
 
-            if (cal.isEvent(item)) {
+            if (cal.item.isEvent(item)) {
                 this.mSelectEventExceptions.params.id = item.id;
                 this.prepareStatement(this.mSelectEventExceptions);
                 try {
                     while (this.mSelectEventExceptions.executeStep()) {
                         let row = this.mSelectEventExceptions.row;
                         let exc = this.getEventFromRow(row, {}, true /* isException */);
                         rec.modifyException(exc, true);
                     }
                 } catch (e) {
                     this.logError("Error getting exceptions for event '" +
                                   item.title + "' (" + item.id + ")!", e);
                 } finally {
                     this.mSelectEventExceptions.reset();
                 }
-            } else if (cal.isToDo(item)) {
+            } else if (cal.item.isToDo(item)) {
                 this.mSelectTodoExceptions.params.id = item.id;
                 this.prepareStatement(this.mSelectTodoExceptions);
                 try {
                     while (this.mSelectTodoExceptions.executeStep()) {
                         let row = this.mSelectTodoExceptions.row;
                         let exc = this.getTodoFromRow(row, {}, true /* isException */);
                         rec.modifyException(exc, true);
                     }
@@ -2000,19 +2000,19 @@ calStorageCalendar.prototype = {
 
         flags |= this.writeAttendees(item, olditem);
         flags |= this.writeRecurrence(item, olditem);
         flags |= this.writeProperties(item, olditem);
         flags |= this.writeAttachments(item, olditem);
         flags |= this.writeRelations(item, olditem);
         flags |= this.writeAlarms(item, olditem);
 
-        if (cal.isEvent(item)) {
+        if (cal.item.isEvent(item)) {
             this.writeEvent(item, olditem, flags);
-        } else if (cal.isToDo(item)) {
+        } else if (cal.item.isToDo(item)) {
             this.writeTodo(item, olditem, flags);
         } else {
             throw Components.results.NS_ERROR_UNEXPECTED;
         }
     },
 
     writeEvent: function(item, olditem, flags) {
         try {
--- a/calendar/providers/wcap/calWcapCalendarItems.js
+++ b/calendar/providers/wcap/calWcapCalendarItems.js
@@ -314,17 +314,17 @@ calWcapCalendar.prototype.storeItem = fu
                 }
             }
             strings.sort();
             ret = strings.join(";");
         }
         return ret || "";
     };
 
-    let bIsEvent = cal.isEvent(item);
+    let bIsEvent = cal.item.isEvent(item);
     let bIsParent = isParent(item);
 
     let method = METHOD_PUBLISH;
     let bNoSmtpNotify = false;
     let params = "";
 
     let calId = this.calId;
     if (!bAddItem && this.isInvitation(item)) { // REPLY
@@ -709,17 +709,17 @@ calWcapCalendar.prototype.modifyItem = f
                                                  }
                                                  // invalidate cached results:
                                                  delete this.m_cachedResults;
                                                  this.storeItem(false /* bAddItem */, newItem, oldItem_, request);
                                              } finally {
                                                  request.unlockPending();
                                              }
                                          },
-                                         stringToXml, cal.isEvent(newItem) ? "deleteevents_by_id" : "deletetodos_by_id",
+                                         stringToXml, cal.item.isEvent(newItem) ? "deleteevents_by_id" : "deletetodos_by_id",
                                          params, calIWcapCalendar.AC_COMP_WRITE);
                 return request;
             }
         } else if (oldItem && !oldItem.parentItem.recurrenceInfo.getExceptionFor(newItem.recurrenceId)) {
             // pass null for oldItem when creating new exceptions, write whole item:
             oldItem_ = null;
         }
         this.storeItem(false /* bAddItem */, newItem, oldItem_, request);
@@ -769,17 +769,17 @@ calWcapCalendar.prototype.deleteItem = f
                                          throw err;
                                      }
                                      // invalidate cached results:
                                      delete this.m_cachedResults;
                                      if (LOG_LEVEL > 0) {
                                          log("deleteItem(): " + getWcapRequestStatusString(xml), this);
                                      }
                                  },
-                                 stringToXml, cal.isEvent(item) ? "deleteevents_by_id" : "deletetodos_by_id",
+                                 stringToXml, cal.item.isEvent(item) ? "deleteevents_by_id" : "deletetodos_by_id",
                                  params, calIWcapCalendar.AC_COMP_WRITE);
     } catch (exc) {
         request.execRespFunc(exc);
     }
     return request;
 };
 
 calWcapCalendar.prototype.patchTimezone = function(subComp, attr, xpropOrTz) {
@@ -894,34 +894,34 @@ calWcapCalendar.prototype.parseItems = f
                         "\nrid=" + getIcalUTC(rid) +
                         "\nitem.id=" + item.id, this);
                 }
                 excItems.push(item);
             } else if (item.recurrenceInfo) {
                 unexpandedItems.push(item);
                 uid2parent[item.id] = item;
             } else if ((maxResults == 0 || items.length < maxResults) &&
-                       cal.checkIfInRange(item, rangeStart, rangeEnd)) {
+                       cal.item.checkIfInRange(item, rangeStart, rangeEnd)) {
                 if (LOG_LEVEL > 2) {
                     log("item: " + item.title + "\n" + item.icalString, this);
                 }
                 if (!bLeaveMutable) {
                     item.makeImmutable();
                 }
                 items.push(item);
             }
         }
     }
 
     // tag "exceptions", i.e. items with rid:
     for (let item of excItems) {
         let parent = uid2parent[item.id];
 
         if (!parent) { // a parentless one, fake a master and override it's occurrence
-            parent = cal.isEvent(item) ? cal.createEvent() : cal.createTodo();
+            parent = cal.item.isEvent(item) ? cal.createEvent() : cal.createTodo();
             parent.id = item.id;
             parent.calendar = this.superCalendar;
             parent.setProperty("DTSTART", item.recurrenceId);
             parent.setProperty("X-MOZ-FAKED-MASTER", "1"); // this tag might be useful in the future
             parent.recurrenceInfo = cal.createRecurrenceInfo(parent);
             fakedParents[item.id] = true;
             uid2parent[item.id] = parent;
             items.push(parent);
--- a/calendar/resources/content/mouseoverPreviews.js
+++ b/calendar/resources/content/mouseoverPreviews.js
@@ -60,19 +60,19 @@ function showToolTip(aToolTip, aItem) {
 /**
  * PUBLIC:  Called when a user hovers over a todo element and the text for the
  * mouse over is changed.
  *
  * @param {calIToDo} toDoItem    the item to create the preview for
  * @param {boolean}  aIsTooltip  enabled if used for tooltip composition (default)
  */
 function getPreviewForItem(aItem, aIsTooltip=true) {
-    if (cal.isEvent(aItem)) {
+    if (cal.item.isEvent(aItem)) {
         return getPreviewForEvent(aItem, aIsTooltip);
-    } else if (cal.isToDo(aItem)) {
+    } else if (cal.item.isToDo(aItem)) {
         return getPreviewForTask(aItem, aIsTooltip);
     } else {
         return null;
     }
 }
 
 /**
  * PUBLIC: Returns the string for status (none), Tentative, Confirmed, or
--- a/calendar/test/unit/test_gdata_provider.js
+++ b/calendar/test/unit/test_gdata_provider.js
@@ -906,17 +906,17 @@ add_task(function* test_basicItems() {
     }];
 
     let client = yield gServer.getClient();
     let pclient = cal.async.promisifyCalendar(client);
 
     let items = yield pclient.getAllItems();
     equal(items.length, 2);
 
-    let event = cal.isEvent(items[0]) ? items[0] : items[1];
+    let event = cal.item.isEvent(items[0]) ? items[0] : items[1];
     equal(event.id, "go6ijb0b46hlpbu4eeu92njevo@google.com");
     equal(event.getProperty("STATUS"), "CONFIRMED");
     equal(event.getProperty("URL"), gServer.baseUri + "/calendar/event?eid=eventhash");
     equal(event.getProperty("CREATED").icalString, "20060608T210452Z");
     equal(event.getProperty("LAST-MODIFIED").icalString, "20060608T210549Z");
     equal(event.title, "New Event");
     equal(event.getProperty("DESCRIPTION"), "description");
     equal(event.getProperty("LOCATION"), "Hard Drive");
@@ -940,17 +940,17 @@ add_task(function* test_basicItems() {
     equal(attendees[0].id, "mailto:attendee@example.com");
     equal(attendees[0].commonName, "attendee name");
     equal(attendees[0].role, "OPT-PARTICIPANT");
     equal(attendees[0].participationStatus, "TENTATIVE");
     equal(event.getCategories({}), "foo,bar");
     equal(event.alarmLastAck.icalString, "20140101T010101Z");
     equal(event.getProperty("X-MOZ-SNOOZE-TIME"), "20140101T020202Z");
 
-    let task = cal.isToDo(items[0]) ? items[0] : items[1];
+    let task = cal.item.isToDo(items[0]) ? items[0] : items[1];
     equal(task.id, "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU");
     equal(task.title, "New Task");
     equal(task.getProperty("LAST-MODIFIED").icalString, "20140908T163027Z");
     equal(task.getProperty("X-GOOGLE-SORTKEY"), "00000000000000130998");
     ok(task.isCompleted);
     equal(task.dueDate.icalString, "20140904");
     equal(task.completedDate.icalString, "20140901T170000Z");
     equal(task.getProperty("DESCRIPTION"), "description");
@@ -1372,33 +1372,33 @@ add_task(function* test_metadata() {
     let client = yield gServer.getClient();
     let offline = client.wrappedJSObject.mCachedCalendar;
     let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
 
     // Check initial metadata
     let items = yield pclient.getAllItems();
     let meta = getAllMeta(offline);
     let [event, task] = items;
-    ok(cal.isEvent(event));
-    ok(cal.isToDo(task));
+    ok(cal.item.isEvent(event));
+    ok(cal.item.isToDo(task));
     equal(meta.size, 2);
     equal(meta.get(event.hashId), ['"1"', "go6ijb0b46hlpbu4eeu92njevo", false].join("\u001A"));
     equal(meta.get(task.hashId), ['"2"', "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU", false].join("\u001A"));
 
     // Modify an event
     gServer.nextEtag = '"3"';
     let newEvent = event.clone();
     newEvent.title = "changed";
     yield pclient.modifyItem(newEvent, event);
 
     items = yield pclient.getAllItems();
     meta = getAllMeta(offline);
     [event, task] = items;
-    ok(cal.isEvent(event));
-    ok(cal.isToDo(task));
+    ok(cal.item.isEvent(event));
+    ok(cal.item.isToDo(task));
     equal(meta.size, 2);
     equal(meta.get(event.hashId), ['"3"', "go6ijb0b46hlpbu4eeu92njevo", false].join("\u001A"));
     equal(meta.get(task.hashId), ['"2"', "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU", false].join("\u001A"));
 
     // Modify a task
     gServer.nextEtag = '"4"';
     let newTask = task.clone();
     newTask.title = "changed";
--- a/calendar/test/unit/test_ics_parser.js
+++ b/calendar/test/unit/test_ics_parser.js
@@ -125,23 +125,23 @@ function test_async() {
         "END:VCALENDAR"].join("\r\n");
 
     do_test_pending();
     parser.parseString(str, null, {
         onParsingComplete: function(rc, opparser) {
             let items = parser.getItems({});
             equal(items.length, 2);
             let item = items[0];
-            ok(cal.isToDo(item));
+            ok(cal.item.isToDo(item));
 
             equal(item.entryDate.icalString, "20120101T010101");
             equal(item.dueDate.icalString, "20120101T010102");
 
             item = items[1];
-            ok(cal.isToDo(item));
+            ok(cal.item.isToDo(item));
 
             equal(item.entryDate.icalString, "20120101T010103");
             equal(item.dueDate.icalString, "20120101T010104");
 
             do_test_finished();
         }
     });
 }