imported patch documentation3.diff
authorPhilipp Kewisch <mozilla@kewis.ch>
Tue, 20 Jan 2009 13:28:11 +0100
changeset 1698 84e9c5177712642bda6894f260c9310f4aaec932
parent 1697 825f066d21c273854ce1b49b278c39b6f1f258de
child 1699 ef7223d5becb8d0367b5d52947dc3d2566970095
push id1362
push usermozilla@kewis.ch
push dateTue, 20 Jan 2009 12:29:34 +0000
treeherdercomm-central@84e9c5177712 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
imported patch documentation3.diff
calendar/base/content/calendar-alarm-dialog.js
calendar/base/content/calendar-task-tree.js
calendar/base/content/preferences/advanced.js
calendar/base/content/preferences/alarms.js
calendar/base/content/preferences/categories.js
calendar/base/content/preferences/connection.js
calendar/base/content/preferences/general.js
calendar/base/content/preferences/timezones.js
calendar/base/content/preferences/views.js
calendar/base/public/calIItemBase.idl
calendar/base/src/calItemBase.js
calendar/base/src/calRelation.js
--- a/calendar/base/content/calendar-alarm-dialog.js
+++ b/calendar/base/content/calendar-alarm-dialog.js
@@ -86,17 +86,17 @@ function onDismissAllAlarms() {
         if (alarmRichlist.childNodes[i].item) {
             getAlarmService().dismissAlarm(alarmRichlist.childNodes[i].item);
         }
     }
 }
 
 /**
  * Event handler fired when the alarm widget's "Details..." label was clicked.
- * Open the event dialog in the most recent sunbird or thunderbird window
+ * Open the event dialog in the most recent Sunbird or Thunderbird window
  *
  * @param event     The itemdetails event.
  */
 function onItemDetails(event) {
     // We want this to happen in a calendar window.
     var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                        .getService(Components.interfaces.nsIWindowMediator);
     var calWindow = wm.getMostRecentWindow("calendarMainWindow") ||
@@ -106,28 +106,28 @@ function onItemDetails(event) {
 
 /**
  * Sets up the alarm dialog, initializing the default snooze length and setting
  * up the relative date update timer.
  */
 var gRelativeDateUpdateTimer;
 function setupWindow() {
     // We want to update when we are at 0 seconds past the minute. To do so, use
-    // setTimeout to wait until we are there, then setInterval to exectue every
+    // setTimeout to wait until we are there, then setInterval to execute every
     // minute. Since setInterval is not totally exact, we may run into problems
     // here. I hope not!
     var current = new Date();
 
     var timeout = (60 - current.getSeconds()) * 1000;
     gRelativeDateUpdateTimer = setTimeout(function wait_until_next_minute() {
         updateRelativeDates();
         gRelativeDateUpdateTimer = setInterval(updateRelativeDates, 60 * 1000);
     }, timeout);
 
-    // Give focus to the alarm richlist after onload completes. see bug 103197
+    // Give focus to the alarm richlist after onload completes. See bug 103197
     setTimeout(onFocusWindow, 0);
 }
 
 /**
  * Unload function for the alarm dialog. If applicable, snooze the remaining
  * alarms and clean up the relative date update timer.
  */
 function finishWindow() {
--- a/calendar/base/content/calendar-task-tree.js
+++ b/calendar/base/content/calendar-task-tree.js
@@ -39,64 +39,101 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+/**
+ * Add registered calendars to the given menupopup. Removes all previous
+ * children.
+ *
+ * XXX Either replace the existing items using replaceNode, or use helper
+ * functions (cal.removeChildren).
+ *
+ * @param aEvent    The popupshowing event of the opening menu
+ */
 function addCalendarNames(aEvent) {
     var calendarMenuPopup = aEvent.target;
     var calendars = getCalendarManager().getCalendars({});
     while (calendarMenuPopup.hasChildNodes()) {
         calendarMenuPopup.removeChild(calendarMenuPopup.lastChild);
     }
     var tasks = getSelectedTasks(aEvent);
     var tasksSelected = (tasks.length > 0);
     if (tasksSelected) {
         var selIndex = appendCalendarItems(tasks[0], calendarMenuPopup, null, "contextChangeTaskCalendar(event);");
         if (isPropertyValueSame(tasks, "calendar") && (selIndex > -1)) {
             calendarMenuPopup.childNodes[selIndex].setAttribute("checked", "true");
         }
     }
 }
 
+/**
+ * Add categories to the given menupopup.
+ *
+ * XXX Either replace the existing items using replaceNode, or use helper
+ * functions (cal.removeChildren).
+ * XXX Shouldn't we be removing previous children here?
+ *
+ * @param aEvent    The popupshowing event of the opening menu
+ */
 function addCategoryNames(aEvent) {
     var tasks = getSelectedTasks(aEvent);
     var tasksSelected = (tasks.length > 0);
     if (tasksSelected) {
         var index = appendCategoryItems(tasks[0], aEvent.target, document.getElementById("calendar_task_category_command"));
         aEvent.target.childNodes[index].setAttribute("checked","true");
     } else {
         appendCategoryItems(null, aEvent.target);
         applyAttributeToMenuChildren(aEvent.target, "disabled", (!tasksSelected));
     }
 }
 
+/**
+ * Change the opening context menu for the selected tasks.
+ *
+ * @param aEvent    The popupshowing event of the opening menu.
+ */
 function changeContextMenuForTask(aEvent) {
     var tasks = getSelectedTasks(aEvent);
     var task = null;
     var tasksSelected = (tasks.length > 0);
     applyAttributeToMenuChildren(aEvent.target, "disabled", (!tasksSelected));
     document.getElementById("calendar_new_todo_command").removeAttribute("disabled");
     if (tasksSelected) {
         if (isPropertyValueSame(tasks, "isCompleted")) {
             setBooleanAttribute(document.getElementById("calendar-context-markcompleted"), "checked", tasks[0].isCompleted);
         } else {
             document.getElementById("calendar-context-markcompleted").setAttribute("checked", false);
         }
     }
 }
 
+/**
+ * Handler function to mark selected tasks as completed.
+ *
+ * XXXberend Please explain more and rename to something easier to understand.
+ *
+ * @param aEvent      The DOM event that triggered this command.
+ * @param aProgress   The progress percentage to set.
+ */
 function contextChangeTaskProgress2(aEvent, aProgress) {
     contextChangeTaskProgress(aEvent, aProgress);
     document.getElementById("calendar_percentComplete-100_command2").checked = false;
 }
 
+/**
+ * Handler function to change the progress of all selected tasks.
+ *
+ * @param aEvent      The DOM event that triggered this command.
+ * @param aProgress   The progress percentage to set.
+ */
 function contextChangeTaskProgress(aEvent, aProgress) {
     startBatchTransaction();
     var tasks = getSelectedTasks(aEvent);
     for (var t = 0; t < tasks.length; t++) {
         var task = tasks[t];
         var newTask = task.clone().QueryInterface( Components.interfaces.calITodo );
         newTask.percentComplete = aProgress;
         switch (aProgress) {
@@ -111,101 +148,154 @@ function contextChangeTaskProgress(aEven
                 newTask.completedDate = null;
                 break;
         }
         doTransaction('modify', newTask, newTask.calendar, task, null);
     }
     endBatchTransaction();
 }
 
+/**
+ * Handler function to change the category of the selected tasks. The targeted
+ * menuitem must have a cateogory value as described in setCateogry.
+ *
+ * @see setCategory
+ * @param aEvent      The DOM event that triggered this command.
+ */
 function contextChangeTaskCategory(aEvent) {
     startBatchTransaction();
     var tasks = getSelectedTasks(aEvent);
     var tasksSelected = (tasks.length > 0);
     if (tasksSelected) {
         var menuItem = aEvent.target;
         for (var t = 0; t < tasks.length; t++) {
             var newTask = tasks[t].clone().QueryInterface( Components.interfaces.calITodo );
             setCategory(newTask, menuItem);
             doTransaction('modify', newTask, newTask.calendar, tasks[t], null);
         }
     }
     endBatchTransaction();
 }
 
+/**
+ * Handler function to change the calendar of the selected tasks. The targeted
+ * menuitem must have "calendar" property that implements calICalendar.
+ *
+ * @param aEvent      The DOM event that triggered this command.
+ */
 function contextChangeTaskCalendar(aEvent) {
    startBatchTransaction();
    var tasks = getSelectedTasks(aEvent);
    for (var t = 0; t < tasks.length; t++) {
        var task = tasks[t];
        var newTask = task.clone().QueryInterface( Components.interfaces.calITodo );
        newTask.calendar = aEvent.target.calendar;
        doTransaction('modify', newTask, newTask.calendar, task, null);
     }
     endBatchTransaction();
 }
 
+/**
+ * Handler function to change the priority of the selected tasks.
+ *
+ * @param aEvent      The DOM event that triggered this command.
+ * @param aPriority   The priority to set on the selected tasks.
+ */
 function contextChangeTaskPriority(aEvent, aPriority) {
     startBatchTransaction();
     var tasks = getSelectedTasks(aEvent);
     for (var t = 0; t < tasks.length; t++) {
         var task = tasks[t];
         var newTask = task.clone().QueryInterface( Components.interfaces.calITodo );
         newTask.priority = aPriority;
         doTransaction('modify', newTask, newTask.calendar, task, null);
-     }
-     endBatchTransaction();
-  }
+    }
+    endBatchTransaction();
+}
 
+/**
+ * Modifies the selected tasks with the event dialog
+ *
+ * @param aEvent      The DOM event that triggered this command.
+ */
 function modifyTaskFromContext(aEvent) {
     var tasks = getSelectedTasks(aEvent);
     for (var t = 0; t < tasks.length; t++) {
         modifyEventWithDialog(tasks[t], null, true);
     }
  }
 
 /**
  *  Delete the current selected item with focus from the task tree
+ *
+ * @param aEvent          The DOM event that triggered this command.
+ * @param aDoNotConfirm   If true, the user will not be asked to delete.
  */
 function deleteToDoCommand(aEvent, aDoNotConfirm) {
     var tasks = getSelectedTasks(aEvent);
     calendarViewController.deleteOccurrences(tasks.length,
                                              tasks,
                                              false,
                                              aDoNotConfirm);
 }
 
+/**
+ * Gets the currently visible task tree
+ *
+ * @return    The XUL task tree element.
+ */
 function getTaskTree() {
     var currentMode = document.getElementById("modeBroadcaster").getAttribute("mode");
     if (currentMode == "task") {
         return document.getElementById("calendar-task-tree");
     } else {
         return document.getElementById("unifinder-todo-tree");
     }
 }
 
+/**
+ * Gets the tasks selected in the currently visible task tree.
+ *
+ * XXX Parameter aEvent is unused, needs to be removed here and in calling
+ * functions.
+ *
+ * @param aEvent      Unused
+ */
 function getSelectedTasks(aEvent) {
     var taskTree = getTaskTree();
     if (taskTree != null) {
         return taskTree.selectedTasks;
     }
     else  {
         return [];
     }
 }
 
+/**
+ * Convert selected tasks to emails.
+ */
 function tasksToMail(aEvent) {
     var tasks = getSelectedTasks(aEvent);
     calendarMailButtonDNDObserver.onDropItems(tasks);
 }
 
+/**
+ * Convert selected tasks to events.
+ */
 function tasksToEvents(aEvent) {
     var tasks = getSelectedTasks(aEvent);
     calendarCalendarButtonDNDObserver.onDropItems(tasks);
 }
 
+/**
+ * Toggle the completed state on tasks retrieved from the given event.
+ *
+ * XXXberend Please clarify if this is correct and describe more clearly.
+ *
+ * @param aEvent    The command event that holds information about the tasks.
+ */
 function toggleCompleted(aEvent) {
     if (aEvent.target.getAttribute("checked") == "true") {
         contextChangeTaskProgress(aEvent, 100);
     } else {
         contextChangeTaskProgress(aEvent, 0);
     }
 }
--- a/calendar/base/content/preferences/advanced.js
+++ b/calendar/base/content/preferences/advanced.js
@@ -34,50 +34,67 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK *****
  */
 
+/**
+ * Global Object to hold methods for the advanced pref pane
+ */
 var gAdvancedPane = {
     _inited: false,
+    /**
+     * Initialize the advanced pref pane. Sets up dialog controls to match the
+     * values set in prefs.
+     */
     init: function advPaneInit() {
         this._inited = true;
         this._initMasterPasswordUI();
 
         var advancedPrefs = document.getElementById("advancedPrefs");
         var preference = document.getElementById("calendar.preferences.advanced.selectedTabIndex");
         if (preference.value === null) {
             return;
         }
         advancedPrefs.selectedIndex = preference.value;
 
         this.updateAppUpdateItems();
         this.updateAutoItems();
         this.updateModeItems();
     },
 
+    /**
+     * Handler function to call when the tab in the advanced pane has been
+     * changed.
+     */
     tabSelectionChanged: function advPaneTabSelectionChanged() {
         if (!this._inited) {
             return;
         }
         var advancedPrefs = document.getElementById("advancedPrefs");
         var preference = document.getElementById("calendar.preferences.advanced.selectedTabIndex");
         preference.valueFromPreferences = advancedPrefs.selectedIndex;
     },
 
     // GENERAL TAB
 
+    /**
+     * Show the connections dialog
+     */
     showConnections: function advPaneShowConnections() {
         var url = "chrome://calendar/content/preferences/connection.xul";
         document.documentElement.openSubDialog(url, "", "chrome,dialog");
     },
 
+    /**
+     * Show the config editor dialog
+     */
     showConfigEdit: function advPaneShowConfigEdit() {
         document.documentElement.openWindow("Preferences:ConfigManager",
                                             "chrome://global/content/config.xul",
                                             "", null);
     },
 
     // PASSWORDS TAB
 
--- a/calendar/base/content/preferences/alarms.js
+++ b/calendar/base/content/preferences/alarms.js
@@ -33,28 +33,41 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK *****
  */
 
+/**
+ * Global Object to hold methods for the alarms pref pane
+ */
 var gAlarmsPane = {
-
-    init: function () {
+    /**
+     * Initialize the alarms pref pane. Sets up dialog controls to match the
+     * values set in prefs.
+     */
+    init: function gAP_init() {
         // Enable/disable the alarm sound URL box and buttons
         this.alarmsPlaySoundPrefChanged();
 
         // Set the correct singular/plural for the time units
         this.updateMenuPlural("eventdefalarmlen", "eventdefalarmunit");
         this.updateMenuPlural("tododefalarmlen",  "tododefalarmunit");
     },
 
-    updateMenuPlural: function (lengthFieldId, menuId) {
+    /**
+     * Update the given menu to show the correct plural form in the unit
+     * menulist.
+     *
+     * @param lengthFieldId     The ID of the length field textbox.
+     * @param menuId            The ID of the unit menu to update.
+     */
+    updateMenuPlural: function gAP_updateMenuPlural(lengthFieldId, menuId) {
         var field = document.getElementById(lengthFieldId);
         var menu  = document.getElementById(menuId);
 
         var length = field.value;
         var newLabelNumber;
         if (Number(length) > 1) {
             newLabelNumber = "labelplural";
         } else {
@@ -79,48 +92,64 @@ var gAlarmsPane = {
 
             // force the menu selection to redraw
             var saveSelectedIndex = menu.selectedIndex;
             menu.selectedIndex = -1;
             menu.selectedIndex = saveSelectedIndex;
         }
     },
 
-    convertURLToLocalFile: function (aFileURL) {
-        // convert the file url into a nsILocalFile
+    /**
+     * Converts the given file url to a nsILocalFile
+     *
+     * @param aFileURL    A string with a file:// url.
+     * @return            The corresponding nsILocalFile.
+     */
+    convertURLToLocalFile: function gAP_convertURLToLocalFile(aFileURL) {
+        // Convert the file url into a nsILocalFile
         if (aFileURL) {
             var ios = Components.classes["@mozilla.org/network/io-service;1"]
                                 .getService(Components.interfaces.nsIIOService);
             var fph = ios.getProtocolHandler("file")
                          .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
             return fph.getFileFromURLSpec(aFileURL);
         } else {
             return null;
         }
     },
 
-    readSoundLocation: function () {
+    /**
+     * Handler function to be called when the calendar.alarms.soundURL pref has
+     * changed. Updates the label in the dialog.
+     */
+    readSoundLocation: function gAP_readSoundLocation() {
         var soundUrl = document.getElementById("alarmSoundFileField");
         soundUrl.value = document.getElementById("calendar.alarms.soundURL").value;
         if (soundUrl.value.indexOf("file://") == 0) {
             soundUrl.label = this.convertURLToLocalFile(soundUrl.value).leafName;
         } else {
             soundUrl.label = soundUrl.value;
         }
         return undefined;
     },
 
-    useDefaultSound: function () {
+    /**
+     * Causes the default sound to be selected in the dialog controls
+     */
+    useDefaultSound: function gAP_useDefaultSound() {
         var defaultSoundUrl = "chrome://calendar/content/sound.wav";
         document.getElementById("calendar.alarms.soundURL").value = defaultSoundUrl;
         document.getElementById("alarmSoundCheckbox").checked = true;
         this.readSoundLocation();
     },
 
-    browseAlarm: function () {
+    /**
+     * Opens a filepicker to open a local sound for the alarm.
+     */
+    browseAlarm: function gAP_browseAlarm() {
         const nsIFilePicker = Components.interfaces.nsIFilePicker;
         var fp = Components.classes["@mozilla.org/filepicker;1"]
                     .createInstance(nsIFilePicker);
 
         var bundlePreferences = document.getElementById("bundleCalendarPreferences");
         var title = bundlePreferences.getString("Open");
         var wildmat = "*.wav";
         var label = bundlePreferences.getFormattedString("filterWav", [wildmat], 1);
@@ -133,17 +162,20 @@ var gAlarmsPane = {
 
         if (ret == nsIFilePicker.returnOK) {
             document.getElementById("calendar.alarms.soundURL").value = fp.fileURL.spec;
             document.getElementById("alarmSoundCheckbox").checked = true;
             this.readSoundLocation();
         }
     },
 
-    previewAlarm: function () {
+    /**
+     * Plays the alarm sound currently selected.
+     */
+    previewAlarm: function gAP_previewAlarm() {
         var soundUrl = document.getElementById("alarmSoundFileField").value;
         var soundIfc = Components.classes["@mozilla.org/sound;1"]
                             .createInstance(Components.interfaces.nsISound);
         var ios = Components.classes["@mozilla.org/network/io-service;1"]
                             .getService(Components.interfaces.nsIIOService);
         var url;
         try {
             soundIfc.init();
@@ -153,23 +185,27 @@ var gAlarmsPane = {
             } else {
                 soundIfc.beep();
             }
         } catch (ex) {
             dump("alarms.js previewAlarm Exception caught! " + ex + "\n");
         }
     },
 
-    alarmsPlaySoundPrefChanged: function () {
+    /**
+     * Handler function to call when the calendar.alarms.playsound preference
+     * has been changed. Updates the disabled state of fields that depend on
+     * playing a sound.
+     */
+    alarmsPlaySoundPrefChanged: function gAP_alarmsPlaySoundPrefChanged() {
         var alarmsPlaySoundPref =
             document.getElementById("calendar.alarms.playsound");
 
         var items = [document.getElementById("alarmSoundFileField"),
                      document.getElementById("calendar.prefs.alarm.sound.useDefault"),
                      document.getElementById("calendar.prefs.alarm.sound.browse"),
                      document.getElementById("calendar.prefs.alarm.sound.preview")];
 
         for (var i=0; i < items.length; i++) {
             items[i].disabled = !alarmsPlaySoundPref.value;
         }
     }
-
 };
--- a/calendar/base/content/preferences/categories.js
+++ b/calendar/base/content/preferences/categories.js
@@ -41,19 +41,26 @@
  */
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 
 var gCategoryList;
 var prefService = Components.classes["@mozilla.org/preferences-service;1"]
                     .getService(Components.interfaces.nsIPrefService);
 var categoryPrefBranch = prefService.getBranch("calendar.category.color.");
 
+/**
+ * Global Object to hold methods for the categories pref pane
+ */
 var gCategoriesPane = {
 
-    init: function () {
+    /**
+     * Initialize the categories pref pane. Sets up dialog controls to show the
+     * categories saved in preferences.
+     */
+    init: function gCP_init() {
         // On non-instant-apply platforms, once this pane has been loaded,
         // attach our "revert all changes" function to the parent prefwindow's
         // "ondialogcancel" event.
         var parentPrefWindow = document.getElementById("CalendarPreferences") ||
                                document.getElementById("MailPreferences");
         if (!parentPrefWindow.instantApply) {
             var existingOnDialogCancel = parentPrefWindow.getAttribute("ondialogcancel");
             parentPrefWindow.setAttribute("ondialogcancel",
@@ -82,17 +89,21 @@ var gCategoriesPane = {
         // child with no corresponding category.
         if (gCategoryList.length == 1 && !gCategoryList[0].length) {
             gCategoryList.pop();
         }
 
         this.updateCategoryList();
     },
 
-    updateCategoryList: function () {
+    /**
+     * Updates the listbox containing the categories from the categories saved
+     * in preferences.
+     */
+    updateCategoryList: function gCP_updateCategoryList () {
         cal.sortArrayByLocaleCollator(gCategoryList);
         document.getElementById("calendar.categories.names").value =
             categoriesArrayToString(gCategoryList);
 
         var listbox = document.getElementById("categorieslist");
 
         listbox.clearSelection();
         document.getElementById("editCButton").disabled = "true";
@@ -117,57 +128,73 @@ var gCategoriesPane = {
             }
  
             newListItem.appendChild(categoryName);
             newListItem.appendChild(categoryColor);
             listbox.appendChild(newListItem);
         }
     },
 
-    addCategory: function () {
+    /**
+     * Adds a category, opening the edit category dialog to prompt the user to
+     * set up the category.
+     */
+    addCategory: function gCP_addCategory() {
         var list = document.getElementById("categorieslist");
         list.selectedIndex = -1;
         document.getElementById("editCButton").disabled = "true";
         document.getElementById("deleteCButton").disabled = "true";
         window.openDialog("chrome://calendar/content/preferences/editCategory.xul",
                           "addCategory", "modal,centerscreen,chrome,resizable=no",
                           "", null, addTitle);
     },
 
-    editCategory: function () {
+    /**
+     * Edits the currently selected category using the edit category dialog.
+     */
+    editCategory: function gCP_editCategory() {
         var list = document.getElementById("categorieslist");
         var categoryNameFix = formatStringForCSSRule(gCategoryList[list.selectedIndex]);
         try {
             var currentColor = categoryPrefBranch.getCharPref(categoryNameFix);
         } catch (ex) {
             var currentColor = null;
         }
  
         if (list.selectedItem) {
             window.openDialog("chrome://calendar/content/preferences/editCategory.xul",
                               "editCategory", "modal,centerscreen,chrome,resizable=no",
                               gCategoryList[list.selectedIndex], currentColor, editTitle);
         }
     },
 
-    deleteCategory: function () {
+    /**
+     * Removes the selected category.
+     */
+    deleteCategory: function gCP_deleteCategory() {
         var list = document.getElementById("categorieslist");
         if (list.selectedItem) {
             var categoryNameFix = formatStringForCSSRule(gCategoryList[list.selectedIndex]);
             this.backupData(categoryNameFix);
             try {
                 categoryPrefBranch.clearUserPref(categoryNameFix);
             } catch (ex) {
             }
             gCategoryList.splice(list.selectedIndex, 1);
             this.updateCategoryList();
         }
     },
 
-    saveCategory: function (categoryName, categoryColor) {
+    /**
+     * Saves the given category to the preferences.
+     *
+     * @param categoryName      The name of the category.
+     * @param categoryColor     The color of the category
+     */
+    saveCategory: function gCP_saveCateogry(categoryName, categoryColor) {
         var list = document.getElementById("categorieslist");
         // Check to make sure another category doesn't have the same name
         var toBeDeleted = -1;
         var promptService = 
              Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                        .getService(Components.interfaces.nsIPromptService);
         for (var i=0; i < gCategoryList.length; i++) {
             if (i == list.selectedIndex)
@@ -213,22 +240,31 @@ var gCategoriesPane = {
         if (toBeDeleted != -1) {
             list.selectedIndex = toBeDeleted;
             this.deleteCategory();
         }
 
         this.updateCategoryList();
     },
 
-    enableButtons: function () {
+    /**
+     * Enable the edit and delete category buttons.
+     */
+    enableButtons: function  gCP_enableButtons() {
         document.getElementById("editCButton").disabled = null;
         document.getElementById("deleteCButton").disabled = null;
     },
 
-    backupData: function (categoryNameFix) {
+    /**
+     * Backs up the category name in case the dialog is canceled.
+     *
+     * @see formatStringForCSSRule
+     * @param categoryNameFix     The formatted category name.
+     */
+    backupData: function gCP_backupData(categoryNameFix) {
         var currentColor;
         try {
             currentColor = categoryPrefBranch.getCharPref(categoryNameFix);
         } catch (ex) {
             dump("Exception caught in 'backupData': " + ex + "\n");
             currentColor = "##NEW";
         }
 
@@ -236,24 +272,26 @@ var gCategoriesPane = {
             if (categoryNameFix == parent.backupPrefList[i].name) {
                 return;
             }
         }
         parent.backupPrefList[parent.backupPrefList.length] =
             { name : categoryNameFix, color : currentColor };
     },
 
-    panelOnCancel: function () {
+    /**
+     * Reverts category preferences in case the cancel button is pressed.
+     */
+    panelOnCancel: function gCP_panelOnCancel() {
         for (var i=0; i < parent.backupPrefList.length; i++) {
             if (parent.backupPrefList[i].color == "##NEW") {
                 try {
                    categoryPrefBranch.clearUserPref(parent.backupPrefList[i].name);
                 } catch (ex) {
                     dump("Exception caught in 'panelOnCancel': " + ex + "\n");
                 }
             } else {
                 categoryPrefBranch.setCharPref(parent.backupPrefList[i].name,
                                                parent.backupPrefList[i].color);
             }
         }
     }
-
 };
--- a/calendar/base/content/preferences/connection.js
+++ b/calendar/base/content/preferences/connection.js
@@ -1,10 +1,9 @@
-/**
- * ***** BEGIN LICENSE BLOCK *****
+/* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -28,22 +27,27 @@
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
- * ***** END LICENSE BLOCK *****
- */
+ * ***** END LICENSE BLOCK *****/
 
+/**
+ * Global Object to hold methods for the connections dialog.
+ */
 var gConnectionsDialog = {
-  beforeAccept: function ()
-  {
+  /**
+   * Handler function to be called before the pref window is closed (i.e
+   * onbeforeaccept attribute).
+   */
+  beforeAccept: function gCD_beforeAccept() {
     var proxyTypePref = document.getElementById("network.proxy.type");
     if (proxyTypePref.value == 2) {
       this.doAutoconfigURLFixup();
       return true;
     }
 
     if (proxyTypePref.value != 1)
       return true;
@@ -66,18 +70,22 @@ var gConnectionsDialog = {
     }
     
     var noProxiesPref = document.getElementById("network.proxy.no_proxies_on");
     noProxiesPref.value = noProxiesPref.value.replace(/[;]/g,',');
     
     return true;
   },
   
-  proxyTypeChanged: function ()
-  {
+
+  /**
+   * Handler function to be called when the network.proxy.type preference has
+   * changed while the connection preferences dialog is open.
+   */
+  proxyTypeChanged: function gCD_proxyTypeChanged() {
     var proxyTypePref = document.getElementById("network.proxy.type");
     
     // Update http
     var httpProxyURLPref = document.getElementById("network.proxy.http");
     httpProxyURLPref.disabled = proxyTypePref.value != 1;
     var httpProxyPortPref = document.getElementById("network.proxy.http_port");
     httpProxyPortPref.disabled = proxyTypePref.value != 1;
 
@@ -91,46 +99,56 @@ var gConnectionsDialog = {
     noProxiesPref.disabled = proxyTypePref.value != 1;
     
     var autoconfigURLPref = document.getElementById("network.proxy.autoconfig_url");
     autoconfigURLPref.disabled = proxyTypePref.value != 2;
 
     this.updateReloadButton();
   },
 
-  updateReloadButton: function ()
-  {
-    // Disable the "Reload PAC" button if the selected proxy type is not PAC or
-    // if the current value of the PAC textbox does not match the value stored
-    // in prefs.  Likewise, disable the reload button if PAC is not configured
-    // in prefs.
-
+  /**
+   * Updates the disabled state of the Reload button depending on the selected
+   * proxy option.
+   * 
+   * Disable the "Reload PAC" button if the selected proxy type is not PAC or
+   * if the current value of the PAC textbox does not match the value stored
+   * in prefs.  Likewise, disable the reload button if PAC is not configured
+   * in prefs.
+   */
+  updateReloadButton: function gCD_updateReloadButton() {
     var typedURL = document.getElementById("networkProxyAutoconfigURL").value;
     var proxyTypeCur = document.getElementById("network.proxy.type").value;
 
     var prefs =
         Components.classes["@mozilla.org/preferences-service;1"].
         getService(Components.interfaces.nsIPrefBranch);
     var pacURL = prefs.getCharPref("network.proxy.autoconfig_url");
     var proxyType = prefs.getIntPref("network.proxy.type");
 
     var disableReloadPref =
         document.getElementById("pref.advanced.proxies.disable_button.reload");
     disableReloadPref.disabled =
         (proxyTypeCur != 2 || proxyType != 2 || typedURL != pacURL);
   },
 
-  readProxyType: function ()
-  {
+  /**
+   * Handler function to be called when the network proxy type radiogroup
+   * receives a 'syncfrompreference' event. Updates the proxy type and disables
+   * controls related to this if needed (i.e Reload button)
+   */
+  readProxyType: function gCD_readProxyType() {
     this.proxyTypeChanged();
     return undefined;
   },
   
-  updateProtocolPrefs: function ()
-  {
+  /**
+   * Handler function to be called when the shareAllProxies checkbox receives a
+   * 'syncfrompreference' event.
+   */
+  updateProtocolPrefs: function gCD_updateProtocolPrefs() {
     var proxyTypePref = document.getElementById("network.proxy.type");
     var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
     var proxyPrefs = ["ssl", "ftp", "socks"];
     for (var i = 0; i < proxyPrefs.length; ++i) {
       var proxyServerURLPref = document.getElementById("network.proxy." + proxyPrefs[i]);
       var proxyPortPref = document.getElementById("network.proxy." + proxyPrefs[i] + "_port");
       
       // Restore previous per-proxy custom settings, if present. 
@@ -153,53 +171,71 @@ var gConnectionsDialog = {
       proxyPortPref.disabled = proxyServerURLPref.disabled;
     }
     var socksVersionPref = document.getElementById("network.proxy.socks_version");
     socksVersionPref.disabled = proxyTypePref.value != 1 || shareProxiesPref.value;
     
     return undefined;
   },
   
-  readProxyProtocolPref: function (aProtocol, aIsPort)
-  {
+  /**
+   * Handler function to be called when a proxy server host/port textbox
+   * receives a 'syncfrompreference' event.
+   *
+   * @param aProtocol       The protocol to be updated. This is the string
+   *                          contained in the respective preference.
+   * @param aIsPort         If true, the update comes from the port textbox.
+   */
+  readProxyProtocolPref: function gCD_readProxyProtocolPref (aProtocol, aIsPort) {
     var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
     if (shareProxiesPref.value) {
       var pref = document.getElementById("network.proxy.http" + (aIsPort ? "_port" : ""));    
       return pref.value;
     }
     
     var backupPref = document.getElementById("network.proxy.backup." + aProtocol + (aIsPort ? "_port" : ""));
     return backupPref.hasUserValue ? backupPref.value : undefined;
   },
 
-  reloadPAC: function ()
-  {
+  /**
+   * Reloads the proxy.pac that is set in the preferences.
+   */
+  reloadPAC: function gCD_reloadPAC() {
     Components.classes["@mozilla.org/network/protocol-proxy-service;1"]
               .getService().reloadPAC();
   },
   
-  doAutoconfigURLFixup: function ()
-  {
+  /**
+   * Use nsIURIFixup to fix the url entered in the autoconfig url field and the
+   * respective preference element.
+   */
+  doAutoconfigURLFixup: function gCD_doAutoconfigURLFixup() {
     var autoURL = document.getElementById("networkProxyAutoconfigURL");
     var autoURLPref = document.getElementById("network.proxy.autoconfig_url");
     var URIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
                              .getService(Components.interfaces.nsIURIFixup);
     try {
       autoURLPref.value = autoURL.value = URIFixup.createFixupURI(autoURL.value, 0).spec;
     } catch(ex) {}
   },
   
-  readHTTPProxyServer: function ()
-  {
+  /**
+   * Special case handler function to be called when a HTTP proxy server host
+   * textbox receives a 'syncfrompreference' event.
+   */
+  readHTTPProxyServer: function gCD_readHTTPProxyServer() {
     var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
     if (shareProxiesPref.value)
       this.updateProtocolPrefs();
     return undefined;
   },
   
-  readHTTPProxyPort: function ()
-  {
+  /**
+   * Special case handler function to be called when a HTTP proxy server port
+   * textbox receives a 'syncfrompreference' event.
+   */
+  readHTTPProxyPort: function gCD_readHTTPProxyPort() {
     var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
     if (shareProxiesPref.value)
       this.updateProtocolPrefs();
     return undefined;
   }
 };
--- a/calendar/base/content/preferences/general.js
+++ b/calendar/base/content/preferences/general.js
@@ -33,34 +33,44 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK *****
  */
 
+/**
+ * Global Object to hold methods for the general pref pane
+ */
 var gCalendarGeneralPane = {
-
-    init: function () {
+    /**
+     * Initialize the general pref pane. Sets up dialog controls to match the
+     * values set in prefs.
+     */
+    init: function gCGP_init() {
         var df = Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
                     .getService(Components.interfaces.calIDateTimeFormatter);
 
         var dateFormattedLong  = df.formatDateLong(now());
         var dateFormattedShort = df.formatDateShort(now());
 
         // menu items include examples of current date formats.
         document.getElementById("dateformat-long-menuitem")
                 .setAttribute("label", labelLong + ": " + dateFormattedLong);
         document.getElementById("dateformat-short-menuitem")
                 .setAttribute("label", labelShort + ": " + dateFormattedShort);
 
         // deselect and reselect to update visible item title
         updateSelectedLabel("dateformat");
     },
 
-    autoRefreshPrefChanged: function() {
+    /**
+     * Update disabled state of the controls that depend on the
+     * calendar.autorefresh.enabled preference.
+     */
+    autoRefreshPrefChanged: function gCGP_autoRefreshPrefChanged() {
         var autoRefreshPref =
             document.getElementById("calendar.autorefresh.enabled").value;
         document.getElementById("calendar.autorefresh.timeout").disabled = 
             !autoRefreshPref;
     }
 };
--- a/calendar/base/content/preferences/timezones.js
+++ b/calendar/base/content/preferences/timezones.js
@@ -1,10 +1,9 @@
-/**
- * ***** BEGIN LICENSE BLOCK *****
+/* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -31,21 +30,27 @@
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
- * ***** END LICENSE BLOCK *****
- */
+ * ***** END LICENSE BLOCK *****/
 
+/**
+ * Global Object to hold methods for the timezones dialog.
+ */
 var gTimezonesPane = {
-    init: function () {
+    /**
+     * Initialize the timezones pref pane. Sets up dialog controls to match the
+     * values set in prefs.
+     */
+    init: function gTP_init() {
         var tzMenuList = document.getElementById("calendar-timezone-menulist");
         var tzMenuPopup = document.getElementById("calendar-timezone-menupopup");
 
         var tzService = getTimezoneService();
         var enumerator = tzService.timezoneIds;
         var tzids = {};
         var displayNames = [];
         // don't rely on what order the timezone-service gives you
--- a/calendar/base/content/preferences/views.js
+++ b/calendar/base/content/preferences/views.js
@@ -31,25 +31,36 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK *****
  */
 
+/**
+ * Global Object to hold methods for the views pref pane
+ */
 var gViewsPane = {
-    init: function prefViewInit() {
+    /**
+     * Initialize the views pref pane. Sets up dialog controls to match the
+     * values set in prefs.
+     */
+    init: function gVP_init() {
         this.updateViewEndMenu(document.getElementById("daystarthour").value);
         this.updateViewStartMenu(document.getElementById("dayendhour").value);
         this.updateViewWorkDayCheckboxes(document.getElementById("weekstarts").value);
         this.initializeViewStartEndMenus();
     },
 
-    initializeViewStartEndMenus: function() {
+    /**
+     * Initialize the strings for the  "day starts at" and "day ends at"
+     * menulists. This is needed to respect locales that use AM/PM.
+     */
+    initializeViewStartEndMenus: function gVP_initializeViewStartEndMenus() {
         var labelIdStart;
         var labelIdEnd;
         var timeFormatter = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
                                       .getService(Components.interfaces.nsIScriptableDateFormat);
         // 1 to 23 instead of 0 to 24 to keep midnight & noon as the localized strings
         for (var theHour = 1; theHour <= 23; theHour++) {
             var time = timeFormatter.FormatTime("", Components.interfaces.nsIScriptableDateFormat
                                     .timeFormatNoSeconds, theHour, 0, 0);
@@ -62,40 +73,59 @@ var gViewsPane = {
                 document.getElementById(labelIdEnd).setAttribute("label", time);
             }
         }
         // Deselect and reselect to update visible item title
         updateSelectedLabel("daystarthour");
         updateSelectedLabel("dayendhour");
     },
 
-    updateViewEndMenu: function prefUpdateViewEnd(aStartValue) {
+
+    /**
+     * Updates the view end menu to only display hours after the selected view
+     * start.
+     *
+     * @param aStartValue       The value selected for view start.
+     */
+    updateViewEndMenu: function gVP_updateViewEndMenu(aStartValue) {
         var endMenuKids = document.getElementById("dayendhourpopup")
                                   .childNodes;
         for (var i = 0; i < endMenuKids.length; i++) {
             if (Number(endMenuKids[i].value) <= Number(aStartValue)) {
                 endMenuKids[i].setAttribute("hidden", true);
             } else {
                 endMenuKids[i].removeAttribute("hidden");
             }
         }
     },
 
-    updateViewStartMenu: function prefUpdateViewStart(aEndValue) {
+    /**
+     * Updates the view start menu to only display hours before the selected view
+     * end.
+     *
+     * @param aEndValue         The value selected for view end.
+     */
+    updateViewStartMenu: function gVP_updateViewStartMenu(aEndValue) {
         var startMenuKids = document.getElementById("daystarthourpopup")
                                   .childNodes;
         for (var i = 0; i < startMenuKids.length; i++) {
             if (Number(startMenuKids[i].value) >= Number(aEndValue)) {
                 startMenuKids[i].setAttribute("hidden", true);
             } else {
                 startMenuKids[i].removeAttribute("hidden");
             }
         }
     },
 
-    updateViewWorkDayCheckboxes: function prefUpdateViewWorkDays(weekStart) {
+    /**
+     * Update the workday checkboxes based on the start of the week.
+     *
+     * @Param weekStart         The (0-based) index of the weekday the week
+     *                            should start at.
+     */
+    updateViewWorkDayCheckboxes: function gVP_updateViewWorkDayCheckboxes(weekStart) {
         weekStart = Number(weekStart);
         for (var i = weekStart; i < weekStart + 7; i++) {
             var checkbox = document.getElementById("dayoff" + (i % 7));
             checkbox.parentNode.appendChild(checkbox);
         }
     }
 };
--- a/calendar/base/public/calIItemBase.idl
+++ b/calendar/base/public/calIItemBase.idl
@@ -262,27 +262,27 @@ interface calIItemBase : nsISupports
                     [array,size_is(count),retval] out calIAttendee attendees);
 
   /**
    * getAttendeeById's matching is done in a case-insensitive manner to handle
    * places where "MAILTO:" or similar properties are capitalized arbitrarily
    * by different calendar clients.
    */
   calIAttendee getAttendeeById(in AUTF8String id);
+  void addAttendee(in calIAttendee attendee);
   void removeAttendee(in calIAttendee attendee);
-  void addAttendee(in calIAttendee attendee);
   void removeAllAttendees();
 
   //
   // Attachments
   //
   void getAttachments(out PRUint32 count,
                       [array,size_is(count),retval] out calIAttachment attachments);
+  void addAttachment(in calIAttachment attachment);
   void removeAttachment(in calIAttachment attachment);
-  void addAttachment(in calIAttachment attachment);
   void removeAllAttachments();
 
   //
   // Categories
   //
 
   /**
    * Gets the array of categories this item belongs to.
@@ -300,33 +300,33 @@ interface calIItemBase : nsISupports
   // Relations
   //
 
   /**
    * This gives back every relation where the item is neighter the owner of the
    * relation nor the referred relation
    */
   void getRelations(out PRUint32 count,
-                      [array,size_is(count),retval] out calIRelation relations);
+                    [array,size_is(count),retval] out calIRelation relations);
+
+  /**
+   * Adds a relation to the item
+   */
+  void addRelation(in calIRelation relation);
 
   /**
    * Removes the relation for this item and the referred item
    */
   void removeRelation(in calIRelation relation);
   
   /**
    * Removes every relation for this item (in this items and also where it is referred
    */
   void removeAllRelations();
 
-  /**
-   * Adds a relation to the item
-   */
-  void addRelation(in calIRelation relation);
-
   // Occurrence querying
   //
 
   /**
    * Return a list of occurrences of this item between the given dates.  The items
    * returned are the same type as this one, as proxies.
    */
   void getOccurrencesBetween (in calIDateTime aStartDate, in calIDateTime aEndDate,
--- a/calendar/base/src/calItemBase.js
+++ b/calendar/base/src/calItemBase.js
@@ -38,124 +38,165 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 Components.utils.import("resource://calendar/modules/calIteratorUtils.jsm");
 
-//
-// calItemBase.js
-//
-
+/**
+ * calItemBase prototype definition
+ *
+ * @implements calIItemBase
+ * @constructor
+ */
 function calItemBase() {
     cal.ASSERT(false, "Inheriting objects call initItemBase()!");
 }
 
 calItemBase.prototype = {
     mPropertyParams: null,
     mIsProxy: false,
     mAlarms: null,
+    mHashId: null,
+    mImmutable: false,
+    mDirty: false,
+    mAlarmLastAck: null,
+    mCalendar: null,
 
-    // initialize this class's members
-    initItemBase: function cib_initItemBase() {
+    /**
+     * Initialize the base item's attributes. Can be called from inheriting
+     * objects in their constructor.
+     */
+    initItemBase: function cIB_initItemBase() {
         this.wrappedJSObject = this;
         this.mProperties = new calPropertyBag();
         this.mPropertyParams = {};
         this.mProperties.setProperty("CREATED", jsDateToDateTime(new Date()));
         this.mAlarms = [];
     },
 
-    QueryInterface: function (aIID) {
+    /**
+     * @see nsISupports
+     */
+    QueryInterface: function cIB_QueryInterface(aIID) {
         return doQueryInterface(this, calItemBase.prototype, aIID,
                                 [Components.interfaces.calIItemBase]);
     },
 
-    mHashId: null,
-    get hashId() {
+    /**
+     * @see calIItemBase
+     */
+
+    // readonly attribute AUTF8String hashId;
+    get hashId cIB_get_hashId() {
         if (this.mHashId === null) {
             var rid = this.recurrenceId;
             var cal = this.calendar;
             // some unused delim character:
             this.mHashId = [encodeURIComponent(this.id),
                             rid ? rid.getInTimezone(UTC()).icalString : "",
                             cal ? encodeURIComponent(cal.id) : ""].join("#");
         }
         return this.mHashId;
     },
 
-    get id() {
+    // attribute AUTF8String id;
+    get id cIB_get_id() {
         return this.getProperty("UID");
     },
-    set id(uid) {
+    set id cIB_set_id(uid) {
         this.mHashId = null; // recompute hashId
         return this.setProperty("UID", uid);
     },
 
-    get recurrenceId() {
+    // attribute calIDateTime recurrenceId;
+    get recurrenceId cIB_get_recurrenceId() {
         return this.getProperty("RECURRENCE-ID");
     },
-    set recurrenceId(rid) {
+    set recurrenceId cIB_set_recurrenceId(rid) {
         this.mHashId = null; // recompute hashId
         return this.setProperty("RECURRENCE-ID", rid);
     },
 
-    get recurrenceInfo() {
+    // attribute calIRecurrenceInfo recurrenceInfo;
+    get recurrenceInfo cIB_get_recurrenceInfo() {
         return this.mRecurrenceInfo;
     },
-    set recurrenceInfo(value) {
+    set recurrenceInfo cIB_set_recurrenceInfo(value) {
         this.modify();
         return (this.mRecurrenceInfo = calTryWrappedJSObject(value));
     },
 
+    // attribute calIItemBase parentItem;
     mParentItem: null,
-    get parentItem() {
+    get parentItem cIB_get_parentItem() {
         return (this.mParentItem || this);
     },
-    set parentItem(value) {
+    set parentItem cIB_set_parentItem(value) {
         if (this.mImmutable)
             throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
         return (this.mParentItem = calTryWrappedJSObject(value));
     },
 
+    /**
+     * Initializes the base item to be an item proxy. Used by inheriting
+     * objects createProxy() method.
+     *
+     * XXXdbo Explain proxy a bit better, either here or in
+     * calIInternalShallowCopy.
+     *
+     * @see calIInternalShallowCopy
+     * @param aParentItem     The parent item to initialize the proxy on.
+     * @param aRecurrenceId   The recurrence id to initialize the proxy for.
+     */
     initializeProxy: function cib_initializeProxy(aParentItem, aRecurrenceId) {
         this.mIsProxy = true;
 
         aParentItem = calTryWrappedJSObject(aParentItem);
         this.mParentItem = aParentItem;
         this.mCalendar = aParentItem.mCalendar;
         this.recurrenceId = aRecurrenceId;
 
         this.mImmutable = aParentItem.mImmutable;
     },
 
-    //
-    // calIItemBase
-    //
-    mImmutable: false,
-    get isMutable() { return !this.mImmutable; },
+    // readonly attribute boolean isMutable;
+    get isMutable cIB_get_isMutable() { return !this.mImmutable; },
 
-    mDirty: false,
-    modify: function() {
+    /**
+     * This function should be called by all members that modify the item. It
+     * checks if the item is immutable and throws accordingly, and sets the
+     * mDirty property.
+     */
+    modify: function cIB_modify() {
         if (this.mImmutable)
             throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
         this.mDirty = true;
     },
 
-    ensureNotDirty: function() {
+    /**
+     * Makes sure the item is not dirty. If the item is dirty, properties like
+     * LAST-MODIFIED and DTSTAMP are set to now.
+     */
+    ensureNotDirty: function cIB_ensureNotDirty() {
         if (this.mDirty) {
             let now = jsDateToDateTime(new Date());
             this.setProperty("LAST-MODIFIED", now);
             this.setProperty("DTSTAMP", now);
             this.mDirty = false;
         }
     },
 
-    makeItemBaseImmutable: function() {
+    /**
+     * Makes all properties of the base item immutable. Can be called by
+     * inheriting objects' makeImmutable method.
+     */
+    makeItemBaseImmutable: function cIB_makeItemBaseImmutable() {
         if (this.mImmutable) {
             return;
         }
 
         // make all our components immutable
         if (this.mRecurrenceInfo)
             this.mRecurrenceInfo.makeImmutable();
 
@@ -180,30 +221,37 @@ calItemBase.prototype = {
         if (this.mAlarmLastAck) {
             this.mAlarmLastAck.makeImmutable();
         }
 
         this.ensureNotDirty();
         this.mImmutable = true;
     },
 
-    hasSameIds: function(that) {
+     // boolean hasSameIds(in calIItemBase aItem);
+    hasSameIds: function cIB_hasSameIds(that) {
         return (that && this.id == that.id &&
                 (this.recurrenceId == that.recurrenceId || // both null
                  (this.recurrenceId && that.recurrenceId &&
                   this.recurrenceId.compare(that.recurrenceId) == 0)));
     },
 
-    clone: function () {
+    // calIItemBase clone();
+    clone: function cIB_clone() {
         return this.cloneShallow(this.mParentItem);
     },
 
-    // for subclasses to use; copies the ItemBase's values
-    // into m. aNewParent is optional
-    cloneItemBaseInto: function (m, aNewParent) {
+    /**
+     * Clones the base item's properties into the passed object, potentially
+     * setting a new parent item.
+     *
+     * @param m     The item to clone this item into
+     * @param aNewParent    (optional) The new parent item to set on m.
+     */
+    cloneItemBaseInto: function cIB_cloneItemBaseInto(m, aNewParent) {
         m.mImmutable = false;
         m.mIsProxy = this.mIsProxy;
         m.mParentItem = (calTryWrappedJSObject(aNewParent) || this.mParentItem);
         m.mHashId = this.mHashId;
         m.mCalendar = this.mCalendar;
         if (this.mRecurrenceInfo) {
             m.mRecurrenceInfo = calTryWrappedJSObject(this.mRecurrenceInfo.clone());
             m.mRecurrenceInfo.item = m;
@@ -258,40 +306,42 @@ calItemBase.prototype = {
         }
         m.mAlarmLastAck = alarmLastAck;
 
         m.mDirty = this.mDirty;
 
         return m;
     },
 
-    mAlarmLastAck: null,
+    // attribute calIDateTime alarmLastAck;
     get alarmLastAck cIB_get_alarmLastAck() {
         return this.mAlarmLastAck;
     },
-
     set alarmLastAck cIB_set_alarmLastAck(aValue) {
         this.modify();
         if (aValue && !aValue.timezone.isUTC) {
             aValue = aValue.getInTimezone(UTC());
         }
         return (this.mAlarmLastAck = aValue);
     },
 
-    get lastModifiedTime() {
+    // readonly attribute calIDateTime lastModifiedTime;
+    get lastModifiedTime cIB_get_lastModifiedTime() {
         this.ensureNotDirty();
         return this.getProperty("LAST-MODIFIED");
     },
 
-    get stampTime() {
+    // readonly attribute calIDateTime stampTime;
+    get stampTime cIB_get_stampTime() {
         this.ensureNotDirty();
         return this.getProperty("DTSTAMP");
     },
 
-    get propertyEnumerator() {
+    // readonly attribute nsISimpleEnumerator propertyEnumerator;
+    get propertyEnumerator cIB_get_propertyEnumerator() {
         if (this.mIsProxy) {
             cal.ASSERT(this.parentItem != this);
             return { // nsISimpleEnumerator:
                 mProxyEnum: this.mProperties.enumerator,
                 mParentEnum: this.mParentItem.propertyEnumerator,
                 mHandledProps: { },
                 mCurrentProp: null,
 
@@ -330,88 +380,96 @@ calItemBase.prototype = {
                     return ret;
                 }
             };
         } else {
             return this.mProperties.enumerator;
         }
     },
 
-    // The has/get/set/deleteProperty methods are case-insensitive.
-    getProperty: function (aName) {
+    // nsIVariant getProperty(in AString name);
+    getProperty: function cIB_getProperty(aName) {
         aName = aName.toUpperCase();
         var aValue = this.mProperties.getProperty_(aName);
         if (aValue === undefined) {
             aValue = (this.mIsProxy ? this.mParentItem.getProperty(aName) : null);
         }
         return aValue;
     },
 
-    hasProperty: function (aName) {
+    // boolean hasProperty(in AString name);
+    hasProperty: function cIB_hasProperty(aName) {
         return (this.getProperty(aName.toUpperCase()) != null);
     },
 
-    setProperty: function (aName, aValue) {
+    // void setProperty(in AString name, in nsIVariant value);
+    setProperty: function cIB_setProperty(aName, aValue) {
         this.modify();
         aName = aName.toUpperCase();
         if (aValue || !isNaN(parseInt(aValue, 10))) {
             this.mProperties.setProperty(aName, aValue);
         } else {
             this.deleteProperty(aName);
         }
         if (aName == "LAST-MODIFIED") {
             // setting LAST-MODIFIED cleans/undirties the item, we use this for preserving DTSTAMP
             this.mDirty = false;
         }
     },
 
-    deleteProperty: function (aName) {
+    // void deleteProperty(in AString name);
+    deleteProperty: function cIB_deleteProperty(aName) {
         this.modify();
         aName = aName.toUpperCase();
         if (this.mIsProxy) {
             // deleting a proxy's property will mark the bag's item as null, so we could
             // distinguish it when enumerating/getting properties from the undefined ones.
             this.mProperties.setProperty(aName, null);
         } else {
             this.mProperties.deleteProperty(aName);
         }
     },
 
+    // AString getPropertyParameter(in AString aPropertyName, 
     getPropertyParameter: function getPP(aPropName, aParamName) {
         return this.mPropertyParams[aPropName][aParamName];
     },
 
-    getAttendees: function (countObj) {
+    // void getAttendees(out PRUint32 count,
+    //                   [array,size_is(count),retval] out calIAttendee attendees);
+    getAttendees: function cIB_getAttendees(countObj) {
         if (!this.mAttendees && this.mIsProxy) {
             this.mAttendees = this.mParentItem.getAttendees(countObj);
         }
         if (this.mAttendees) {
             countObj.value = this.mAttendees.length;
             return this.mAttendees.concat([]); // clone
         }
         else {
             countObj.value = 0;
             return [];
         }
     },
 
-    getAttendeeById: function (id) {
+    // calIAttendee getAttendeeById(in AUTF8String id);
+    getAttendeeById: function cIB_getAttendeeById(id) {
         var attendees = this.getAttendees({});
         var lowerCaseId = id.toLowerCase();
         for each (var attendee in attendees) {
             // This match must be case insensitive to deal with differing
             // cases of things like MAILTO:
             if (attendee.id.toLowerCase() == lowerCaseId) {
                 return attendee;
             }
         }
         return null;
     },
 
-    removeAttendee: function (attendee) {
+    // void removeAttendee(in calIAttendee attendee);
+    removeAttendee: function cIB_removeAttendee(attendee) {
         this.modify();
         var found = false, newAttendees = [];
         var attendees = this.getAttendees({});
         var attIdLowerCase = attendee.id.toLowerCase();
 
         for (var i = 0; i < attendees.length; i++) {
             if (attendees[i].id.toLowerCase() != attIdLowerCase) {
                 newAttendees.push(attendees[i]);
@@ -419,160 +477,178 @@ calItemBase.prototype = {
                 found = true;
             }
         }
         if (found) {
             this.mAttendees = newAttendees;
         }
     },
 
-    removeAllAttendees: function() {
+    // void removeAllAttendees();
+    removeAllAttendees: function cIB_removeAllAttendees() {
         this.modify();
         this.mAttendees = [];
     },
 
-    addAttendee: function (attendee) {
+    // void addAttendee(in calIAttendee attendee);
+    addAttendee: function cIB_addAttendee(attendee) {
         this.modify();
         this.mAttendees = this.getAttendees({});
         this.mAttendees.push(attendee);
         // XXX ensure that the attendee isn't already there?
     },
 
+    // void getAttachments(out PRUint32 count,
+    //                     [array,size_is(count),retval] out calIAttachment attachments);
     getAttachments: function cIB_getAttachments(aCount) {
         if (!this.mAttachments && this.mIsProxy) {
             this.mAttachments = this.mParentItem.getAttachments(aCount);
         }
         if (this.mAttachments) {
             aCount.value = this.mAttachments.length;
             return this.mAttachments.concat([]); // clone
         } else {
             aCount.value = 0;
             return [];
         }
     },
 
-    removeAttachment: function (aAttachment) {
+    // void removeAttachment(in calIAttachment attachment);
+    removeAttachment: function cIB_removeAttachment(aAttachment) {
         this.modify();
         for (var attIndex in this.mAttachments) {
             if (this.mAttachments[attIndex].uri.spec == aAttachment.uri.spec) {
                 this.modify();
                 this.mAttachments.splice(attIndex, 1);
                 break;
             }
         }
     },
 
-    addAttachment: function (attachment) {
+    // void addAttachment(in calIAttachment attachment);
+    addAttachment: function cIB_addAttachment(attachment) {
         this.modify();
         this.mAttachments = this.getAttachments({});
         this.mAttachments.push(attachment);
         // XXX ensure that the attachment isn't already there?
     },
 
-    removeAllAttachments: function () {
+    // void removeAllAttachments();
+    removeAllAttachments: function cIB_removeAllAttachments() {
         this.modify();
         this.mAttachments = [];
     },
 
+    // void getRelations(out PRUint32 count,
+    //                   [array,size_is(count),retval] out calIRelation relations);
     getRelations: function cIB_getRelations(aCount) {
         if (!this.mRelations && this.mIsProxy) {
             this.mRelations = this.mParentItem.getRelations(aCount);
         }
         if (this.mRelations) {
             aCount.value = this.mRelations.length;
             return this.mRelations.concat([]);
         } else {
             aCount.value = 0;
             return [];
         }
     },
 
-    removeRelation: function (aRelation) {
+    // void removeRelation(in calIRelation relation);
+    removeRelation: function cIB_removeRelation(aRelation) {
         this.modify();
         for (var attIndex in this.mRelations) {
             // Could we have the same item as parent and as child ?
             if (this.mRelations[attIndex].relId == aRelation.relId &&
                 this.mRelations[attIndex].relType == aRelation.relType) {
                 this.modify();
                 this.mRelations.splice(attIndex, 1);
                 break;
             }
         }
     },
 
-    addRelation: function (aRelation) {
+    // void addRelation(in calIRelation relation);
+    addRelation: function cIB_addRelation(aRelation) {
         this.modify();
         this.mRelations = this.getRelations({});
         this.mRelations.push(aRelation);
         // XXX ensure that the relation isn't already there?
     },
 
-    removeAllRelations: function () {
+    // void removeAllRelations();
+    removeAllRelations: function cIB_removeAllRelations() {
         this.modify();
         this.mRelations = [];
     },
 
-    mCalendar: null,
-    get calendar () {
+    // attribute calICalendar calendar;
+    get calendar cIB_get_calendar() {
         if (!this.mCalendar && (this.parentItem != this)) {
             return this.parentItem.calendar;
         } else {
             return this.mCalendar;
         }
     },
-
-    set calendar (v) {
+    set calendar cIB_set_calendar(v) {
         if (this.mImmutable)
             throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
         this.mHashId = null; // recompute hashId
         this.mCalendar = v;
     },
 
-    get organizer() {
+    // attribute calIAttendee organizer;
+    get organizer cIB_get_organizer() {
         if (this.mIsProxy && (this.mOrganizer === undefined)) {
             return this.mParentItem.organizer;
         } else {
             return this.mOrganizer;
         }
     },
-
-    set organizer(v) {
+    set organizer cIB_set_organizer(v) {
         this.modify();
         this.mOrganizer = v;
     },
 
+    // void getCategories(out PRUint32 aCount,
+    //                    [array, size_is(aCount), retval] out wstring aCategories);
     getCategories: function cib_getCategories(aCount) {
         if (!this.mCategories && this.mIsProxy) {
             this.mCategories = this.mParentItem.getCategories(aCount);
         }
         if (this.mCategories) {
             aCount.value = this.mCategories.length;
             return this.mCategories.concat([]); // clone
         } else {
             aCount.value = 0;
             return [];
         }
     },
 
+    // void setCategories(in PRUint32 aCount,
+    //                    [array, size_is(aCount)] in wstring aCategories);
     setCategories: function cib_setCategories(aCount, aCategories) {
         this.mCategories = aCategories.concat([]);
     },
 
-    /* MEMBER_ATTR(mIcalString, "", icalString), */
-    get icalString() {
+    // attribute AUTF8String icalString;
+    get icalString cIB_get_icalString() {
+        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    },
+    set icalString cIB_set_icalString() {
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
     },
 
-    set icalString() {
-        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-    },
-
-    // All of these property names must be in upper case for isPropertyPromoted to
-    // function correctly. The has/get/set/deleteProperty interfaces
-    // are case-insensitive, but these are not.
+    /**
+     * The map of promoted properties is a list of those properties that are
+     * represented directly by getters/setters.
+     * All of these property names must be in upper case isPropertyPromoted to
+     * function correctly. The has/get/set/deleteProperty interfaces
+     * are case-insensitive, but these are not.
+     */
     itemBasePromotedProps: {
         "CREATED": true,
         "UID": true,
         "LAST-MODIFIED": true,
         "SUMMARY": true,
         "PRIORITY": true,
         "STATUS": true,
         "DTSTAMP": true,
@@ -582,45 +658,72 @@ calItemBase.prototype = {
         "ATTENDEE": true,
         "ATTACH": true,
         "CATEGORIES": true,
         "ORGANIZER": true,
         "RECURRENCE-ID": true,
         "X-MOZ-LASTACK": true
     },
 
+    /**
+     * A map of properties that need translation between the ical component
+     * property and their ICS counterpart.
+     */
     icsBasePropMap: [
-    { cal: "CREATED", ics: "createdTime" },
-    { cal: "LAST-MODIFIED", ics: "lastModified" },
-    { cal: "DTSTAMP", ics: "stampTime" },
-    { cal: "UID", ics: "uid" },
-    { cal: "SUMMARY", ics: "summary" },
-    { cal: "PRIORITY", ics: "priority" },
-    { cal: "STATUS", ics: "status" },
-    { cal: "RECURRENCE-ID", ics: "recurrenceId" } ],
+        { cal: "CREATED", ics: "createdTime" },
+        { cal: "LAST-MODIFIED", ics: "lastModified" },
+        { cal: "DTSTAMP", ics: "stampTime" },
+        { cal: "UID", ics: "uid" },
+        { cal: "SUMMARY", ics: "summary" },
+        { cal: "PRIORITY", ics: "priority" },
+        { cal: "STATUS", ics: "status" },
+        { cal: "RECURRENCE-ID", ics: "recurrenceId" }
+    ],
 
-    mapPropsFromICS: function(icalcomp, propmap) {
+    /**
+     * Walks through the propmap and sets all properties on this item from the
+     * given icalcomp.
+     * 
+     * @param icalcomp      The calIIcalComponent to read from.
+     * @param propmap       The property map to walk through.
+     */
+    mapPropsFromICS: function cIB_mapPropsFromICS(icalcomp, propmap) {
         for (var i = 0; i < propmap.length; i++) {
             var prop = propmap[i];
             var val = icalcomp[prop.ics];
             if (val != null && val != Components.interfaces.calIIcalComponent.INVALID_VALUE)
                 this.setProperty(prop.cal, val);
         }
     },
 
-    mapPropsToICS: function(icalcomp, propmap) {
+    /**
+     * Walks through the propmap and sets all properties on the given icalcomp
+     * from the properties set on this item.
+     * given icalcomp.
+     * 
+     * @param icalcomp      The calIIcalComponent to write to.
+     * @param propmap       The property map to walk through.
+     */
+    mapPropsToICS: function cIB_mapPropsToICS(icalcomp, propmap) {
         for (var i = 0; i < propmap.length; i++) {
             var prop = propmap[i];
             var val = this.getProperty(prop.cal);
             if (val != null && val != Components.interfaces.calIIcalComponent.INVALID_VALUE)
                 icalcomp[prop.ics] = val;
         }
     },
 
-    setItemBaseFromICS: function (icalcomp) {
+
+    /**
+     * Reads an ical component and sets up the base item's properties to match
+     * it.
+     *
+     * @param icalcomp      The ical component to read.
+     */
+    setItemBaseFromICS: function cIB_setItemBaseFromICS(icalcomp) {
         this.modify();
 
         // re-initializing from scratch -- no light proxy anymore:
         this.mIsProxy = false;
         this.mProperties = new calPropertyBag();
         this.mPropertyParams = {};
 
         this.mapPropsFromICS(icalcomp, this.icsBasePropMap);
@@ -709,49 +812,66 @@ calItemBase.prototype = {
         this.mAlarmLastAck = null;
         if (lastAck) {
             this.mAlarmLastAck = cal.createDateTime(lastAck.value);
         }
 
         this.mDirty = false;
     },
 
-    importUnpromotedProperties: function (icalcomp, promoted) {
+    /**
+     * Import all properties not in the promoted map into this item's extended
+     * properties bag.
+     *
+     * @param icalcomp      The ical component to read.
+     * @param promoted      The map of promoted properties.
+     */
+    importUnpromotedProperties: function cIB_importUnpromotedProperties(icalcomp, promoted) {
         for (let prop in cal.ical.propertyIterator(icalcomp)) {
             let propName = prop.propertyName;
             if (!promoted[propName]) {
                 this.setProperty(propName, prop.value);
                 for each (let [paramName, paramValue] in cal.ical.paramIterator(prop)) {
                     if (!(propName in this.mPropertyParams)) {
                         this.mPropertyParams[propName] = {};
                     }
                     this.mPropertyParams[propName][paramName] = paramValue;
                 }
             }
         }
     },
 
-    // This method is case-insensitive.
-    isPropertyPromoted: function (name) {
+    // boolean isPropertyPromoted(in AString name);
+    isPropertyPromoted: function cIB_isPropertyPromoted(name) {
         return (this.itemBasePromotedProps[name.toUpperCase()]);
     },
 
-    get icalComponent() {
+    // attribute calIIcalComponent icalComponent;
+    get icalComponent cIB_get_icalComponent() {
+        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    },
+    set icalComponent cIB_set_icalComponent() {
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
     },
 
-    get generation() {
+    // attribute PRUint32 generation;
+    get generation cIB_get_generation() {
         let gen = this.getProperty("X-MOZ-GENERATION");
         return (gen ? parseInt(gen, 10) : 0);
     },
-    set generation(aValue) {
+    set generation cIB_set_generation(aValue) {
         return this.setProperty("X-MOZ-GENERATION", String(aValue));
     },
 
-    fillIcalComponentFromBase: function (icalcomp) {
+    /**
+     * Fills the passed ical component with the base item's properties.
+     *
+     * @param icalcomp    The ical component to write to.
+     */
+    fillIcalComponentFromBase: function cIB_fillIcalComponentFromBase(icalcomp) {
         this.ensureNotDirty();
         let icssvc = cal.getIcsService();
 
         this.mapPropsToICS(icalcomp, this.icsBasePropMap);
 
         let org = this.organizer;
         if (org) {
             icalcomp.addProperty(org.icalProperty);
@@ -789,61 +909,68 @@ calItemBase.prototype = {
         if (alarmLastAck) {
             let lastAck = cal.getIcsService().createIcalProperty("X-MOZ-LASTACK");
             // - should we further ensure that those are UTC or rely on calAlarmService doing so?
             lastAck.value = alarmLastAck.icalString;
             icalcomp.addProperty(lastAck);
         }
     },
 
+    // void getAlarms(out PRUint32 count, [array, size_is(count), retval] out calIAlarm aAlarms);
     getAlarms: function cIB_getAlarms(aCount) {
         if (typeof aCount != "object") {
             throw Components.results.NS_ERROR_XPC_NEED_OUT_OBJECT;
         }
 
         aCount.value = this.mAlarms.length;
         return this.mAlarms;
     },
 
     /**
      * Adds an alarm. The second parameter is for internal use only, i.e not
      * provided on the interface.
      *
-     * @parm aDoNotValidate     Don't serialize the component to check for
+     * @see calIItemBase
+     * @param aDoNotValidate    Don't serialize the component to check for
      *                            errors.
      */
     addAlarm: function cIB_addAlarm(aAlarm, aDoNotValidate) {
         if (!aDoNotValidate) {
             try {
                 // Trigger the icalComponent getter to make sure the alarm is valid.
                 aAlarm.icalComponent;
             } catch (e) {
                 throw Components.results.NS_ERROR_INVALID_ARG;
             }
         }
 
         this.modify();
         this.mAlarms.push(aAlarm);
     },
 
+    // void deleteAlarm(in calIAlarm aAlarm);
     deleteAlarm: function cIB_deleteAlarm(aAlarm) {
         this.modify();
         for (let i = 0; i < this.mAlarms.length; i++) {
             if (compareObjects(this.mAlarms[i], aAlarm, Components.interfaces.calIAlarm)) {
                 this.mAlarms.splice(i, 1);
                 break;
             }
         }
     },
 
+    // void clearAlarms();
     clearAlarms: function cIB_clearAlarms() {
         this.modify();
         this.mAlarms = [];
     },
 
+    // void getOccurrencesBetween (in calIDateTime aStartDate, in calIDateTime aEndDate,
+    //                             out PRUint32 aCount,
+    //                             [array,size_is(aCount),retval] out calIItemBase aOccurrences);
     getOccurrencesBetween: function cIB_getOccurrencesBetween(aStartDate, aEndDate, aCount) {
         if (this.recurrenceInfo) {
             return this.recurrenceInfo.getOccurrences(aStartDate, aEndDate, 0, aCount);
         }
 
         if (checkIfInRange(this, aStartDate, aEndDate)) {
             aCount.value = 1;
             return [this];
@@ -858,18 +985,28 @@ makeMemberAttr(calItemBase, "CREATED", n
 makeMemberAttr(calItemBase, "SUMMARY", null, "title", true);
 makeMemberAttr(calItemBase, "PRIORITY", 0, "priority", true);
 makeMemberAttr(calItemBase, "CLASS", "PUBLIC", "privacy", true);
 makeMemberAttr(calItemBase, "STATUS", null, "status", true);
 makeMemberAttr(calItemBase, "ALARMTIME", null, "alarmTime", true);
 
 makeMemberAttr(calItemBase, "mProperties", null, "properties");
 
-function makeMemberAttr(ctor, varname, dflt, attr, asProperty)
-{
+/**
+ * Helper function to add a member attribute on the given prototype
+ *
+ * @param ctor          The constructor function of the prototype
+ * @param varname       The local variable name to get/set, or the property in
+ *                        case asProperty is true.
+ * @param dflt          The default value in case none is set
+ * @param attr          The attribute name to be used
+ * @param asProperty    If true, getProperty will be used to get/set the
+ *                        member. 
+ */
+function makeMemberAttr(ctor, varname, dflt, attr, asProperty) {
     // XXX handle defaults!
     var getter = function () {
         if (asProperty)
             return this.getProperty(varname);
         else
             return this[varname];
     };
     var setter = function (v) {
--- a/calendar/base/src/calRelation.js
+++ b/calendar/base/src/calRelation.js
@@ -31,41 +31,46 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 Components.utils.import("resource://calendar/modules/calIteratorUtils.jsm");
 
-//
-// calRelation.js
-//
+/**
+ * calRelation prototype definition
+ *
+ * @implements calIRelation
+ * @constructor
+ */
 function calRelation() {
     this.wrappedJSObject = this;
     this.mProperties = new calPropertyBag();
 }
 
 calRelation.prototype = {
     mItem: null,
     mType: null,
     mId: null,
 
+    /**
+     * @see nsISupports
+     */
     QueryInterface: function (aIID) {
         return doQueryInterface(this,
                                 calRelation.prototype,
                                 aIID,
                                 null,
                                 this);
     },
 
     /**
-     * nsIClassInfo
+     * @see nsIClassInfo
      */
-
     getInterfaces: function cR_getInterfaces(aCount) {
         var ifaces = [
             Components.interfaces.nsISupports,
             Components.interfaces.calIRelation,
             Components.interfaces.nsIClassInfo
         ];
         aCount.value = ifaces.length;
         return ifaces;
@@ -77,17 +82,17 @@ calRelation.prototype = {
 
     contractID: "@mozilla.org/calendar/relation;1",
     classDescription: "Calendar Item Relation",
     classID: Components.ID("{76810fae-abad-4019-917a-08e95d5bbd68}"),
     implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
     flags: 0,
 
     /**
-     * calIRelation
+     * @see calIRelation
      */
 
     get item cR_get_item() {
         return this.mItem;
     },
     set item cR_set_item(aItem) {
         return (this.mItem = aItem);
     },