Bug 472314 - Add some documentation to calendar code. r=dbo

This commit is contained in:
Philipp Kewisch 2009-01-10 23:14:00 +01:00
Родитель ecc84bdd97
Коммит bd52a99e86
15 изменённых файлов: 1274 добавлений и 161 удалений

Просмотреть файл

@ -48,6 +48,9 @@ var agendaListbox = {
showsToday: false
};
/**
* Initialize the agenda listbox, used on window load.
*/
agendaListbox.init =
function initAgendaListbox() {
this.agendaListboxControl = document.getElementById("agenda-listbox");
@ -71,6 +74,9 @@ function initAgendaListbox() {
false);
};
/**
* Clean up the agenda listbox, used on window unload.
*/
agendaListbox.uninit =
function uninit() {
if (this.calendar) {
@ -87,6 +93,15 @@ function uninit() {
}
};
/**
* Adds a period item to the listbox. This is a section of the today pane like
* "Today", "Tomorrow", and is usually a <agenda-checkbox-richlist-item> tag. A
* copy of the template node is made and added to the agenda listbox.
*
* @param aPeriod The period item to add.
* @param aItemId The id of an <agenda-checkbox-richlist-item> to add to,
* without the "-hidden" suffix.
*/
agendaListbox.addPeriodListItem =
function addPeriodListItem(aPeriod, aItemId) {
aPeriod.listItem = document.getElementById(aItemId + "-hidden").cloneNode(true);
@ -96,6 +111,10 @@ function addPeriodListItem(aPeriod, aItemId) {
aPeriod.listItem.getCheckbox().addEventListener("CheckboxStateChange", this.onCheckboxChange, true);
}
/**
* Remove a period item from the agenda listbox.
* @see agendaListbox::addPeriodListItem
*/
agendaListbox.removePeriodListItem =
function removePeriodListItem(aPeriod) {
if (aPeriod.listItem) {
@ -107,6 +126,11 @@ function removePeriodListItem(aPeriod) {
}
}
/**
* Handler function called when changing the checkbox state on period items.
*
* @param event The DOM event that triggered the checkbox state change.
*/
agendaListbox.onCheckboxChange =
function onCheckboxChange(event) {
var periodCheckbox = event.target;
@ -137,6 +161,11 @@ function onCheckboxChange(event) {
calendarController.onSelectionChanged({detail: []});
};
/**
* Handler function called when an agenda listbox item is selected
*
* @param aListItem The agenda-base-richlist-item that was selected.
*/
agendaListbox.onSelect =
function onSelect(aListItem) {
var listbox = document.getElementById("agenda-listbox");
@ -152,6 +181,9 @@ function onSelect(aListItem) {
calendarController.onSelectionChanged({detail: agendaListbox.getSelectedItems()});
}
/**
* Handler function called when the agenda listbox becomes focused
*/
agendaListbox.onFocus =
function onFocus() {
var listbox = document.getElementById("agenda-listbox");
@ -160,6 +192,9 @@ function onFocus() {
calendarController.onSelectionChanged({detail: agendaListbox.getSelectedItems()});
}
/**
* Handler function called when the agenda listbox loses focus.
*/
agendaListbox.onBlur =
function onBlur() {
var item = document.getElementById("agenda-listbox").selectedItem;
@ -169,6 +204,9 @@ function onBlur() {
calendarController.onSelectionChanged({detail: []});
}
/**
* Enables all child nodes of the agenda listbox
*/
agendaListbox.enableListItems =
function enableListItems() {
var childNodes = document.getElementById("agenda-listbox").childNodes;
@ -178,6 +216,9 @@ function enableListItems() {
}
}
/**
* Handler function called when a key was pressed on the agenda listbox
*/
agendaListbox.onKeyPress =
function onKeyPress(aEvent) {
var listItem = aEvent.target;
@ -206,14 +247,23 @@ function onKeyPress(aEvent) {
}
}
/**
* Calls the event dialog to edit the currently selected item
*/
agendaListbox.editSelectedItem =
function editSelectedItem(aEvent) {
function editSelectedItem() {
var listItem = document.getElementById("agenda-listbox").selectedItem;
if (listItem) {
modifyEventWithDialog(listItem.occurrence, null, true);
}
}
/**
* Finds the appropriate period for the given item, i.e finds "Tomorrow" if the
* item occurrs tomorrow.
*
* @param aItem The item to find the period for.
*/
agendaListbox.findPeriodsForItem =
function findPeriodsForItem(aItem) {
var retPeriods = [];
@ -227,6 +277,9 @@ function findPeriodsForItem(aItem) {
return retPeriods;
};
/**
* Gets the start of the earliest period shown in the agenda listbox
*/
agendaListbox.getStart =
function getStart(){
var retStart = null;
@ -239,6 +292,9 @@ function getStart(){
return retStart;
}
/**
* Gets the end of the latest period shown in the agenda listbox
*/
agendaListbox.getEnd =
function getEnd(){
var retEnd = null;
@ -251,6 +307,15 @@ function getEnd(){
return retEnd;
}
/**
* Adds an item to an agenda period before another existing item.
*
* @param aNewItem The calIItemBase to add.
* @param aAgendaItem The existing item to insert before.
* @param aPeriod The period to add the item to.
* @param visible If true, the item should be visible.
* @return The newly created XUL element.
*/
agendaListbox.addItemBefore =
function addItemBefore(aNewItem, aAgendaItem, aPeriod, visible) {
var newelement = null;
@ -272,6 +337,13 @@ function addItemBefore(aNewItem, aAgendaItem, aPeriod, visible) {
return newelement;
}
/**
* 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 addItem(aItem) {
if (!isEvent(aItem)) {
@ -320,6 +392,13 @@ function addItem(aItem) {
return newlistItem;
};
/**
* Checks if the given item happens before the comparation item.
*
* @param aItem The item to compare.
* @param aCompItem The item to compare with.
* @return True, if the aItem happens before aCompItem.
*/
agendaListbox.isBefore =
function isBefore(aItem, aCompItem) {
if (aCompItem.startDate.day == aItem.startDate.day) {
@ -337,6 +416,13 @@ function isBefore(aItem, aCompItem) {
}
/**
* Gets the listitems for a given item, possibly in a given period.
*
* @param aItem The item to get the list items for.
* @param aPeriod (optional) the period to search in.
* @return An array of list items for the given item.
*/
agendaListbox.getListItems =
function getListItems(aItem, aPeriod) {
var retlistItems = new Array();
@ -363,6 +449,14 @@ function getListItems(aItem, aPeriod) {
return retlistItems;
}
/**
* Removes the given item from the agenda listbox
*
* @param aItem The item to remove.
* @param aMoveSelection If true, the selection will be moved to the next
* sibling that is not an period item.
* @return Returns true if the removed item was selected.
*/
agendaListbox.deleteItem =
function deleteItem(aItem, aMoveSelection) {
var isSelected = false;
@ -383,12 +477,26 @@ function deleteItem(aItem, aMoveSelection) {
return isSelected;
}
/**
* Compares two items to see if they have the same id and their start date
* matches
*
* @param aItem The item to compare.
* @param aCompItem The item to compare with.
* @return True, if the items match with the above noted criteria.
*/
agendaListbox.isSameEvent =
function isSameEvent(aItem, aCompItem) {
return ((aItem.id == aCompItem.id) &&
(aItem[calGetStartDateProp(aItem)].compare(aCompItem[calGetStartDateProp(aCompItem)]) == 0));
}
/**
* Checks if the currently selected node in the listbox is an Event item (not a
* period item).
*
* @return True, if the node is not a period item.
*/
agendaListbox.isEventSelected =
function isEventSelected() {
var listItem = this.agendaListboxControl.selectedItem;
@ -398,6 +506,11 @@ function isEventSelected() {
return false;
}
/**
* Delete the selected item from its calendar (if it is an event item)
*
* @param aDoNotConfirm If true, the user will not be prompted.
*/
agendaListbox.deleteSelectedItem =
function deleteSelectedItem(aDoNotConfirm) {
var listItem = this.agendaListboxControl.selectedItem;
@ -410,6 +523,12 @@ function deleteSelectedItem(aDoNotConfirm) {
}
}
/**
* If a Period item is targeted by the passed DOM event, opens the event dialog
* with the period's start date prefilled.
*
* @param aEvent The DOM event that targets the period.
*/
agendaListbox.createNewEvent =
function createNewEvent(aEvent) {
if (!this.isEventListItem(aEvent.target)){
@ -421,8 +540,15 @@ function createNewEvent(aEvent) {
}
}
/**
* Rebuilds the agenda popup menu from the agenda-menu-box, disabling items if a
* period was selected.
*
* XXX Why is this needed?
*
*/
agendaListbox.buildAgendaPopupMenu =
function enableAgendaPopupMenu(aPopupMenu){
function enableAgendaPopupMenu() {
var listItem = this.agendaListboxControl.selectedItem;
var enabled = this.isEventListItem(listItem);
var popup = document.getElementById("agenda-menu");
@ -434,10 +560,16 @@ function enableAgendaPopupMenu(aPopupMenu){
setBooleanAttribute(menuitems[i], "disabled", !enabled);
popup.appendChild(menuitems[i].cloneNode(true));
}
return true;
}
/**
* Refreshes the agenda listbox. If aStart or aEnd is not passed, the agenda
* listbox's limiting dates will be used.
*
* @param aStart (optional) The start date for the item query.
* @param aEnd (optional) The end date for the item query.
*/
agendaListbox.refreshCalendarQuery =
function refreshCalendarQuery(aStart, aEnd) {
if (this.mBatchCount > 0) {
@ -473,6 +605,9 @@ function refreshCalendarQuery(aStart, aEnd) {
}
};
/**
* Sets up the calendar for the agenda listbox.
*/
agendaListbox.setupCalendar =
function setupCalendar() {
this.init();
@ -489,6 +624,15 @@ function setupCalendar() {
}
};
/**
* Refreshes the period dates, especially when a period is showing "today".
* Usually called at midnight to update the agenda pane. Also retrieves the
* items from the calendar.
*
* @see #refreshCalendarQuery
* @param newDate The first date to show if the agenda pane doesn't show
* today.
*/
agendaListbox.refreshPeriodDates =
function refreshPeriodDates(newDate) {
this.kDefaultTimezone = calendarDefaultTimezone();
@ -518,11 +662,23 @@ function refreshPeriodDates(newDate) {
this.refreshCalendarQuery();
};
/**
* Adds a listener to this agenda listbox.
*
* @param aListener The listener to add.
*/
agendaListbox.addListener =
function addListener(aListener) {
this.mListener = aListener;
}
/**
* Checks if the agenda listbox is showing "today". Without arguments, this
* function assumes the today attribute of the agenda listbox.
*
* @param aStartDate (optional) The day to check if its "today".
* @return Returns true if today is shown.
*/
agendaListbox.showsToday =
function showsToday(aStartDate) {
var lstart = aStartDate;
@ -538,6 +694,10 @@ function showsToday(aStartDate) {
return lshowsToday;
};
/**
* Moves the selection. Moves down unless the next item is a period item, in
* which case the selection moves up.
*/
agendaListbox.moveSelection =
function moveSelection() {
var selindex = this.agendaListboxControl.selectedIndex;
@ -548,6 +708,12 @@ function moveSelection() {
}
}
/**
* Gets an array of selected items. If a period node is selected, it is not
* included.
*
* @return An array with all selected items.
*/
agendaListbox.getSelectedItems =
function getSelectedItems() {
var selindex = this.agendaListboxControl.selectedIndex;
@ -560,6 +726,13 @@ function getSelectedItems() {
return items;
}
/**
* Checks if the passed node in the listbox is an Event item (not a
* period item).
*
* @param aListItem The node to check for.
* @return True, if the node is not a period item.
*/
agendaListbox.isEventListItem =
function isEventListItem(aListItem) {
var isEventListItem = (aListItem != null);
@ -571,6 +744,9 @@ function isEventListItem(aListItem) {
return isEventListItem;
}
/**
* Removes all Event items, keeping the period items intact.
*/
agendaListbox.removeListItems =
function removeListItems() {
var listItem = this.agendaListboxControl.lastChild;
@ -595,6 +771,11 @@ function removeListItems() {
}
}
/**
* Gets the list item node by its associated event's hashId.
*
* @return The XUL node if successful, otherwise null.
*/
agendaListbox.getListItemByHashId =
function getListItemByHashId(ahashId) {
var listItem = this.agendaListboxControl.firstChild;
@ -611,10 +792,18 @@ function getListItemByHashId(ahashId) {
return null;
}
/**
* The operation listener used for calendar queries.
* Implements calIOperationListener.
*/
agendaListbox.calendarOpListener = {
agendaListbox : agendaListbox
};
/**
* Called when all items have been retrieved from the calendar.
* @see calIOperationListener
*/
agendaListbox.calendarOpListener.onOperationComplete =
function listener_onOperationComplete(calendar, status, optype, id,
detail) {
@ -623,6 +812,10 @@ function listener_onOperationComplete(calendar, status, optype, id,
setCurrentEvent();
};
/**
* Called when an item has been retrieved, adds all items to the agenda listbox.
* @see calIOperationListener
*/
agendaListbox.calendarOpListener.onGetResult =
function listener_onGetResult(calendar, status, itemtype, detail, count, items) {
if (!Components.isSuccessCode(status))
@ -630,8 +823,13 @@ function listener_onGetResult(calendar, status, itemtype, detail, count, items)
items.forEach(this.agendaListbox.addItem, this.agendaListbox);
};
/**
* Calendar and composite observer, used to keep agenda listbox up to date.
* @see calIObserver
* @see calICompositeObserver
*/
agendaListbox.calendarObserver = {
agendaListbox : agendaListbox
agendaListbox: agendaListbox
};
agendaListbox.calendarObserver.QueryInterface =
@ -774,6 +972,13 @@ function agenda_calAdd(aCalendar) {
agendaListbox.calendarObserver.onDefaultCalendarChanged = function(aCalendar) {
};
/**
* Updates the event considered "current". This goes through all "today" items
* and sets the "current" attribute on all list items that are currently
* occurring.
*
* @see scheduleNextCurrentEventUpdate
*/
function setCurrentEvent() {
if (agendaListbox.showsToday() && agendaListbox.today.open) {
@ -829,11 +1034,16 @@ function setCurrentEvent() {
var gEventTimer;
/** Creates a timer that will fire after the next event is current.
Pass in a function as
* aRefreshCallback that should be called at that time.
/**
* Creates a timer that will fire after the next event is current.
* Pass in a function as aRefreshCallback that should be called at that time.
*
* @param aRefreshCallback The function to call when the next event is
* current.
* @param aMsUntil The number of milliseconds until the next event
* is current.
*/
function scheduleNextCurrentEventUpdate(aRefreshCallback, aMsUntill) {
function scheduleNextCurrentEventUpdate(aRefreshCallback, aMsUntil) {
// Is an nsITimer/callback extreme overkill here? Yes, but it's necessary to
// workaround bug 291386. If we don't, we stand a decent chance of getting
@ -869,5 +1079,5 @@ function scheduleNextCurrentEventUpdate(aRefreshCallback, aMsUntill) {
} else {
gEventTimer.cancel();
}
gEventTimer.initWithCallback(udCallback, aMsUntill, gEventTimer.TYPE_ONE_SHOT);
gEventTimer.initWithCallback(udCallback, aMsUntil, gEventTimer.TYPE_ONE_SHOT);
}

Просмотреть файл

@ -35,7 +35,7 @@
* ***** END LICENSE BLOCK ***** */
/**
* Show the filepicker and create a new calendar with a local file using the ICS
* Shows the filepicker and creates a new calendar with a local file using the ICS
* provider.
*/
function openLocalCalendar() {

Просмотреть файл

@ -41,6 +41,12 @@
/**
* This function takes the recurrence info passed as argument and creates a
* literal string representing the repeat pattern in natural language.
*
* @param recurrenceInfo An item's recurrence info to parse.
* @param startDate The start date to base rules on.
* @param endDate The end date to base rules on.
* @param allDay If true, the pattern should assume an allday item.
* @return A human readable string describing the recurrence.
*/
function recurrenceRule2String(recurrenceInfo, startDate, endDate, allDay) {
@ -428,6 +434,13 @@ function recurrenceRule2String(recurrenceInfo, startDate, endDate, allDay) {
return null;
}
/**
* Split rules into negative and positive rules.
*
* @param recurrenceInfo An item's recurrence info to parse.
* @return An array with two elements: an array of positive
* rules and an array of negative rules.
*/
function splitRecurrenceRules(recurrenceInfo) {
var ritems = recurrenceInfo.getRecurrenceItems({});
var rules = [];
@ -442,6 +455,14 @@ function splitRecurrenceRules(recurrenceInfo) {
return [rules, exceptions];
}
/**
* Check if a recurrence rule's component is valid.
*
* @see calIRecurrenceRule
* @param aRule The recurrence rule to check.
* @param aArray An array of component names to check.
* @return Returns true if the rule is valid.
*/
function checkRecurrenceRule(aRule, aArray) {
for each (var comp in aArray) {
var ruleComp = aRule.getComponent(comp, {});
@ -452,6 +473,10 @@ function checkRecurrenceRule(aRule, aArray) {
return false;
}
/**
* Dispose of controlling operations of this event dialog. Uses
* window.arguments[0].job.dispose()
*/
function dispose() {
var args = window.arguments[0];
if (args.job && args.job.dispose) {
@ -459,6 +484,10 @@ function dispose() {
}
}
/**
* Opens the edit reminder dialog modally, setting the custom menuitem's
* 'reminder' property when done.
*/
function editReminder() {
var customReminder =
document.getElementById("reminder-custom-menuitem");
@ -479,6 +508,11 @@ function editReminder() {
args);
}
/**
* Update the reminder details from the selected alarm. This shows a string
* describing the reminder set, or nothing in case a preselected reminder was
* chosen.
*/
function updateReminderDetails() {
// find relevant elements in the document
var reminderPopup = document.getElementById("item-alarm");
@ -575,6 +609,11 @@ function updateReminderDetails() {
var gLastAlarmSelection = 0;
/**
* Load an item's reminders into the dialog
*
* @param item The item to load.
*/
function loadReminder(item) {
// select 'no reminder' by default
var reminderPopup = document.getElementById("item-alarm");
@ -673,6 +712,11 @@ function loadReminder(item) {
gLastAlarmSelection = reminderPopup.selectedIndex;
}
/**
* Save the selected reminder into the passed item.
*
* @param item The item save the reminder into.
*/
function saveReminder(item) {
var reminderPopup = document.getElementById("item-alarm");
if (reminderPopup.value == 'none') {
@ -712,6 +756,10 @@ function saveReminder(item) {
}
}
/**
* Common update functions for both event dialogs. Called when a reminder has
* been selected from the menulist.
*/
function commonUpdateReminder() {
// if a custom reminder has been selected, we show the appropriate
// dialog in order to allow the user to specify the details.
@ -804,6 +852,9 @@ function commonUpdateReminder() {
updateReminderDetails();
}
/**
* Updates the related link on the dialog
*/
function updateLink() {
var itemUrlString = (window.calendarItem || window.item).getProperty("URL") || "";
var linkCommand = document.getElementById("cmd_toggle_link");

Просмотреть файл

@ -39,6 +39,15 @@
var itemConversion = {
/**
* Converts an email message to a calendar item.
*
* XXX Currently, only the title is taken from the passed message. Aside
* from that, the currently visible message in the preview pane is used.
*
* @param aItem The target calIItemBase.
* @param aMessage The message to convert from
*/
calendarItemFromMessage: function iC_calendarItemFromMessage(aItem, aMessage) {
aItem.calendar = getSelectedCalendar();
aItem.title = aMessage.mime2DecodedSubject;
@ -89,6 +98,14 @@ var itemConversion = {
}
},
/**
* Copy base item properties from aItem to aTarget. This includes properties
* like title, location, description, priority, status, transparency,
* attendees, categories, calendar, recurrence and possibly more.
*
* @param aItem The item to copy from.
* @param aTarget the item to copy to.
*/
copyItemBase: function iC_copyItemBase(aItem, aTarget) {
const copyProps = ["SUMMARY", "LOCATION", "DESCRIPTION",
"URL", "CLASS", "PRIORITY", "STATUS"];
@ -120,6 +137,13 @@ var itemConversion = {
}
},
/**
* Creates a task from the passed event. This function copies the base item
* and a few event specific properties (dates, alarms, ...).
*
* @param aEvent The event to copy from.
* @return The resulting task.
*/
taskFromEvent: function iC_taskFromEvent(aEvent) {
var item = createTodo();
@ -143,6 +167,14 @@ var itemConversion = {
return item;
},
/**
* Creates an event from the passed task. This function copies the base item
* and a few task specific properties (dates, alarms, ...). If the task has
* no due date, the default event length is used.
*
* @param aTask The task to copy from.
* @return The resulting event.
*/
eventFromTask: function iC_eventFromTask(aTask) {
var item = createEvent();
@ -174,6 +206,10 @@ var itemConversion = {
}
};
/**
* A base class for drag and drop observers
* @class calDNDBaseObserver
*/
function calDNDBaseObserver() {
ASSERT(false, "Inheriting objects call calDNDBaseObserver!");
}
@ -193,6 +229,10 @@ calDNDBaseObserver.prototype = {
return flavourSet;
},
/**
* Action to take when dropping the event.
*/
onDrop: function calDNDDrop(aEvent, aTransferData, aDragSession) {
var transferable = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);
@ -396,6 +436,8 @@ calMailButtonDNDObserver.prototype = {
*
* Gets called in case we're dropping an array of items
* on the 'mail mode'-button.
*
* @param aItems An array of items to handle.
*/
onDropItems: function(aItems) {
if (aItems && aItems.length > 0) {
@ -432,6 +474,8 @@ calMailButtonDNDObserver.prototype = {
*
* Gets called in case we're dropping a message
* on the 'mail mode'-button.
*
* @param aMessage The message to handle.
*/
onDropMessage: function(aMessage) {
}
@ -456,6 +500,8 @@ 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 each (var item in aItems) {
@ -474,6 +520,8 @@ calCalendarButtonDNDObserver.prototype = {
* 'calendar mode'-button. In this case we create a new
* event from the mail. We open the default event dialog
* and just use the subject of the message as the event title.
*
* @param aMessage The message to handle.
*/
onDropMessage: function(aMessage) {
var newItem = createEvent();
@ -501,6 +549,8 @@ 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 each (var item in aItems) {
@ -517,6 +567,8 @@ calTaskButtonDNDObserver.prototype = {
*
* Gets called in case we're dropping a message
* on the 'task mode'-button.
*
* @param aMessage The message to handle.
*/
onDropMessage: function(aMessage) {
var todo = createTodo();
@ -525,6 +577,13 @@ calTaskButtonDNDObserver.prototype = {
}
};
/**
* Invoke a drag session for the passed item. The passed box will be used as a
* source.
*
* @param aItem The item to drag.
* @param aXULBox The XUL box to invoke the drag session from.
*/
function invokeEventDragSession(aItem, aXULBox) {
let transfer = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);

Просмотреть файл

@ -37,7 +37,11 @@
*
* ***** END LICENSE BLOCK ***** */
/**
* Get this window's currently selected calendar.
*
* @return The currently selected calendar.
*/
function getSelectedCalendar() {
var tree = document.getElementById("calendar-list-tree-widget");
if (tree) {
@ -47,6 +51,13 @@ function getSelectedCalendar() {
}
}
/**
* Deletes the passed calendar, prompting the user if he really wants to do
* this. If there is only one calendar left, no calendar is removed and the user
* is not prompted.
*
* @param aCalendar The calendar to delete.
*/
function promptDeleteCalendar(aCalendar) {
var calendars = getCalendarManager().getCalendars({});
if (calendars.length <= 1) {
@ -71,6 +82,9 @@ function promptDeleteCalendar(aCalendar) {
}
}
/**
* Ensure that the passed calendar is visible to the user in the current window.
*/
function ensureCalendarVisible(aCalendar) {
var composite = getCompositeCalendar();
if (!composite.getCalendar(aCalendar.uri)) {
@ -79,7 +93,7 @@ function ensureCalendarVisible(aCalendar) {
}
/**
* Calendar manager load/unload functions
* Called to initialize the calendar manager for a window.
*/
function loadCalendarManager() {
var calMgr = getCalendarManager();
@ -131,6 +145,9 @@ function loadCalendarManager() {
}
}
/**
* Called to clean up the calendar manager for a window.
*/
function unloadCalendarManager() {
calendarManagerObserver.unload();
var calMgr = getCalendarManager();
@ -148,6 +165,13 @@ function unloadCalendarManager() {
/**
* Color specific functions
*/
/**
* Update the calendar-view-bindings.css stylesheet to provide rules for
* category colors.
*
* XXX This doesn't really fit into the calendar manager and is here for
* historical reasons.
*/
var gCachedStyleSheet;
function calendarListInitCategoryColors() {
var calendars = getCalendarManager().getCalendars({});
@ -179,10 +203,15 @@ function calendarListInitCategoryColors() {
* preference. (For most users who upgrade and do not later add colors with a
* downgrade version, this should convert any illegal preferences once, so
* future runs have no illegal preferences.)
* @param categoryPrefBranch prefBranch for "calendar.category.color."
* @param coloredCategories array of preference name suffixes under the prefBranch.
* @return same array with each illegal name replaced with formatted name if
* it doesn't already exist, or simply removed from array if it does.
*
* @param categoryPrefBranch PrefBranch for "calendar.category.color."
* @param coloredCategories Array of preference name suffixes under the
* prefBranch.
* @return Same array with each illegal name replaced
* with formatted name if it doesn't already
* exist, or simply removed from array if it
* does.
*
*/
function calendarConvertObsoleteColorPrefs(categoryPrefBranch, coloredCategories) {
for (var i in coloredCategories) {
@ -202,6 +231,12 @@ function calendarConvertObsoleteColorPrefs(categoryPrefBranch, coloredCategories
return coloredCategories;
}
/**
* Update the cached stylesheet to provide rules for the calendar list's
* calendar colors.
*
* @param aCalendar The calendar to update rules for.
*/
function calendarListUpdateColor(aCalendar) {
var selectorPrefix = "treechildren::-moz-tree-cell";
var color = aCalendar.getProperty("color");
@ -245,6 +280,12 @@ var calendarListTreeView = {
* High-level calendar tree manipulation
*/
/**
* Find the array index of the passed calendar
*
* @param aCalendar The calendar to find an index for.
* @return The array index, or -1 if not found.
*/
findIndex: function cLTV_findIndex(aCalendar) {
for (var i = 0; i < this.mCalendarList.length; i++) {
if (this.mCalendarList[i].id == aCalendar.id) {
@ -254,6 +295,12 @@ var calendarListTreeView = {
return -1;
},
/**
* Find the array index of a calendar by its uri.
*
* @param aUri The uri to find an index for.
* @return The array index, or -1 if not found.
*/
findIndexByUri: function cLTV_findIndexByUri(aUri) {
for (var i = 0; i < this.mCalendarList.length; i++) {
if (this.mCalendarList[i].uri.equals(aUri)) {
@ -263,6 +310,11 @@ var calendarListTreeView = {
return -1;
},
/**
* Add a calendar to the calendar list
*
* @param aCalendar The calendar to add.
*/
addCalendar: function cLTV_addCalendar(aCalendar) {
var composite = getCompositeCalendar();
this.mCalendarList.push(aCalendar);
@ -275,6 +327,11 @@ var calendarListTreeView = {
}
},
/**
* Remove a calendar from the calendar list
*
* @param aCalendar The calendar to remove.
*/
removeCalendar: function cLTV_removeCalendar(aCalendar) {
var index = this.findIndex(aCalendar);
if (index < 0) {
@ -290,11 +347,24 @@ var calendarListTreeView = {
this.treebox.rowCountChanged(index, -1);
},
/**
* Update a calendar's tree row (to refresh the color and such)
*
* @param aCalendar The calendar to update.
*/
updateCalendar: function cLTV_updateCalendar(aCalendar) {
var index = this.findIndex(aCalendar);
this.treebox.invalidateRow(index);
},
/**
* Get the calendar from the given DOM event. This can be a Mouse event or a
* keyboard event.
*
* @param event The DOM event to check
* @param aCol An out-object for the column id.
* @param aRow An out-object for the row index.
*/
getCalendarFromEvent: function cLTV_getCalendarFromEvent(event,
aCol,
aRow) {
@ -318,13 +388,12 @@ var calendarListTreeView = {
return aRow && aRow.value > -1 && this.mCalendarList[aRow.value];
},
/**
* nsITreeView methods and properties
*/
get rowCount() {
return this.mCalendarList.length;
},
/**
* Get the calendar from a certain index.
*
* @param index The index to get the calendar for.
*/
getCalendar: function cLTV_getCalendar(index) {
if (index < 0) {
index = 0;
@ -334,6 +403,13 @@ var calendarListTreeView = {
return this.mCalendarList[index];
},
/**
* nsITreeView methods and properties
*/
get rowCount() {
return this.mCalendarList.length;
},
getCellProperties: function cLTV_getCellProperties(aRow, aCol, aProps) {
this.getRowProperties(aRow, aProps);
this.getColumnProperties(aCol, aProps);
@ -567,6 +643,12 @@ var calendarListTreeView = {
return (tooltipText != false);
},
/**
* A handler called to set up the context menu on the calendar list.
*
* @param event The DOM event that caused the context menu to open.
* @return Returns true if the context menu should be shown.
*/
setupContextMenu: function cLTV_setupContextMenu(event) {
var col = {};
var row = {};
@ -627,6 +709,10 @@ var calendarListTreeView = {
}
};
/**
* An observer of the composite calendar to keep the calendar list in sync.
* Implements calICompositeObserver and calIObserver.
*/
var calendarManagerCompositeObserver = {
QueryInterface: function cMCO_QueryInterface(aIID) {
if (!aIID.equals(Components.interfaces.calICompositeObserver) &&
@ -685,6 +771,10 @@ var calendarManagerCompositeObserver = {
aName) {}
}
/**
* An observer for the calendar manager xpcom component, to keep the calendar
* list in sync.
*/
var calendarManagerObserver = {
mDefaultCalendarItem: null,
@ -718,6 +808,9 @@ var calendarManagerObserver = {
document.commandDispatcher.updateCommands("calendar_commands");
},
/**
* Clean up function to remove observers when closing the window
*/
unload: function cMO_unload() {
var calendars = getCalendarManager().getCalendars({});
for each (var calendar in calendars) {
@ -725,6 +818,10 @@ var calendarManagerObserver = {
}
},
/**
* Disables all elements with the attribute
* 'disable-when-no-writable-calendars' set to 'true'.
*/
setupWritableCalendars: function cMO_setupWritableCalendars() {
var nodes = document.getElementsByAttribute("disable-when-no-writable-calendars", "true");
for (var i = 0; i < nodes.length; i++) {
@ -872,6 +969,9 @@ var calendarManagerObserver = {
}
};
/**
* Opens the subscriptions dialog modally.
*/
function openCalendarSubscriptionsDialog() {
// the dialog will reset this to auto when it is done loading
window.setCursor("wait");

Просмотреть файл

@ -42,7 +42,8 @@
var gCalendar;
/**
* To open the window, use an object as argument. The object needs a 'calendar'
* This function gets called when the calendar properties dialog gets opened. To
* open the window, use an object as argument. The object needs a 'calendar'
* attribute that passes the calendar in question.
*/
function onLoad() {
@ -93,7 +94,9 @@ function onLoad() {
}
/**
* Called when the dialog is accepted, to save settings
* Called when the dialog is accepted, to save settings.
*
* @return Returns true if the dialog should be closed.
*/
function onAcceptDialog() {
// Save calendar name

Просмотреть файл

@ -1,4 +1,3 @@
/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -39,9 +38,12 @@
*
* ***** END LICENSE BLOCK ***** */
/* dialog stuff */
function loadCalendarPublishDialog()
{
// TODO This file needs cleaning up, the code is quite stale.
/**
* Prepares the publish dialog from the window's arguments.
*/
function loadCalendarPublishDialog() {
var calendar = window.arguments[0];
window.calendar = calendar;
@ -57,9 +59,13 @@ function loadCalendarPublishDialog()
pathTextbox.focus();
}
function onOKCommand()
{
/**
* Publishes the calendar using the progress meter. The dialog should not be
* closed when this function returns, so false will always be returned.
*
* @return Returns false, since the dialog should not be closed.
*/
function onOKCommand() {
var progressMeter = document.getElementById("publish-progressmeter");
progressMeter.setAttribute("mode", "undetermined");
@ -78,8 +84,10 @@ function onOKCommand()
return false;
}
function checkURL()
{
/**
* Checks if the URL in the publish-remotePath-textbox is valid.
*/
function checkURL() {
var pathTextbox = document.getElementById("publish-remotePath-textbox");
var publishWindow = document.getElementById("calendar-publishwindow");
@ -89,15 +97,23 @@ function checkURL()
publishWindow.getButton("accept").setAttribute("disabled", "true");
}
function closeDialog()
{
/**
* Close the publish dialog.
*
* XXX This function may be broken
*/
function closeDialog() {
self.close();
}
function publishCalendar(calendar, remotePath)
{
/**
* Publish a calendar to a remote path. When this has been done, the accept
* button changes to a close button.
*
* @param calendar The calendar to publish.
* @param remotePath The remote url (as a string).
*/
function publishCalendar(calendar, remotePath) {
var icsURL = makeURL(remotePath);
var calManager = getCalendarManager();
@ -130,8 +146,14 @@ function publishCalendar(calendar, remotePath)
appendCalendars(newCalendar, [calendar], getListener);
}
function appendCalendars(to, froms, listener)
{
/**
* Appends one or more calendars to a target calendar.
*
* @param to The target calendar to write to.
* @param froms An array of source calendars.
* @param listener A calIOperationListener to call when complete.
*/
function appendCalendars(to, froms, listener) {
var getListener = {
onOperationComplete: function(aCalendar, aStatus, aOperationType, aId, aDetail)
{
@ -156,13 +178,8 @@ function appendCalendars(to, froms, listener)
}
};
for each(var from in froms) {
from.getItems(Components.interfaces.calICalendar.ITEM_FILTER_TYPE_ALL,
0, null, null, getListener);
}
}

Просмотреть файл

@ -39,6 +39,10 @@
Components.utils.import("resource://calendar/modules/calUtils.jsm");
Components.utils.import("resource://calendar/modules/calItipUtils.jsm");
/**
* Sets up the summary dialog, setting all needed fields on the dialog from the
* item received in the window arguments.
*/
function onLoad() {
var args = window.arguments[0];
var item = args.calendarEvent;
@ -172,6 +176,11 @@ function onLoad() {
opener.setCursor("auto");
}
/**
* Saves any changed information to the item.
*
* @return Returns true if the dialog
*/
function onAccept() {
dispose();
if (window.readOnly) {
@ -187,14 +196,19 @@ function onAccept() {
return true;
}
/**
* Called when closing the dialog and any changes should be thrown away.
*/
function onCancel() {
dispose();
return true;
}
/**
* Sets the dialog's invitation status dropdown to the value specified by the
* user's invitation status.
*/
function updateInvitationStatus() {
var item = window.item;
var calendar = item.calendar;
if (!window.readOnly) {
if (window.attendee) {
var invitationRow =
@ -202,11 +216,17 @@ function updateInvitationStatus() {
invitationRow.removeAttribute("hidden");
var statusElement =
document.getElementById("item-participation");
statusElement.value = attendee.participationStatus;
statusElement.value = window.attendee.participationStatus;
}
}
}
/**
* When the summary dialog is showing an invitation, this function updates the
* user's invitation status from the value chosen in the dialog.
*
* XXX rename me!
*/
function updateInvitation() {
var statusElement = document.getElementById("item-participation");
if (window.attendee) {
@ -214,6 +234,10 @@ function updateInvitation() {
}
}
/**
* Updates the dialog w.r.t recurrence, i.e shows a text describing the item's
* recurrence)
*/
function updateRepeatDetails() {
var args = window.arguments[0];
var item = args.calendarEvent;
@ -267,6 +291,10 @@ function updateRepeatDetails() {
}
}
/**
* Updates the attendee listbox, displaying all attendees invited to the
* window's item.
*/
function updateAttendees() {
var args = window.arguments[0];
var item = args.calendarEvent;
@ -310,10 +338,19 @@ function updateAttendees() {
}
}
/**
* Updates the reminder, called when a reminder has been selected in the
* menulist.
*/
function updateReminder() {
commonUpdateReminder();
}
/**
* Browse the item's attached URL.
*
* XXX This function is broken, should be fixed in bug 471967
*/
function browseDocument() {
var args = window.arguments[0];
var item = args.calendarEvent;
@ -321,6 +358,10 @@ function browseDocument() {
launchBrowser(url);
}
/**
* Extracts the item's organizer and opens a compose window to send the
* organizer an email.
*/
function sendMailToOrganizer() {
var args = window.arguments[0];
var item = args.calendarEvent;

Просмотреть файл

@ -44,9 +44,8 @@
* ***** END LICENSE BLOCK ***** */
/**
* Called when the calendar is loaded
* Called when the window is loaded to set up the unifinder-todo.
*/
function prepareCalendarToDoUnifinder() {
if (isSunbird()) {
document.getElementById("todo-label").removeAttribute("collapsed");
@ -55,9 +54,8 @@ function prepareCalendarToDoUnifinder() {
}
/**
* Called by event observers to update the display
* Called by event observers to update the task display
*/
function toDoUnifinderRefresh() {
// Set up hiding completed tasks for the unifinder-todo tree
var showCompleted = document.getElementById("show-completed-checkbox").checked;

Просмотреть файл

@ -52,6 +52,9 @@
*
* This is a hacked in interface to the unifinder. We will need to
* improve this to make it usable in general.
*
* NOTE: Including this file will cause a load handler to be added to the
* window.
*/
Components.utils.import("resource://calendar/modules/calUtils.jsm");
@ -66,10 +69,20 @@ var gCalendarEventTreeClicked = false;
var kDefaultTimezone;
var gUnifinderNeedsRefresh = true;
/**
* Checks if the unifinder is hidden
*
* @return Returns true if the unifinder is hidden.
*/
function isUnifinderHidden() {
return document.getElementById("bottom-events-box").hidden;
}
/**
* Returns the current filter applied to the unifinder.
*
* @return The string name of the applied filter.
*/
function getCurrentUnifinderFilter() {
return document.getElementById("event-filter-menulist").selectedItem.value;
}
@ -77,8 +90,10 @@ function getCurrentUnifinderFilter() {
/**
* Observer for the calendar event data source. This keeps the unifinder
* display up to date when the calendar event data is changed
*
* @see calIObserver
* @see calICompositeObserver
*/
var unifinderObserver = {
mInBatch: false,
@ -137,31 +152,6 @@ var unifinderObserver = {
}
},
// It is safe to call these for any event. The functions will determine
// whether or not anything actually needs to be done to the tree
addItemToTree: function uO_addItemToTree(aItem) {
var items;
var filter = unifinderTreeView.mFilter;
if (filter.startDate && filter.endDate) {
items = aItem.getOccurrencesBetween(filter.startDate, filter.endDate, {});
} else {
items = [aItem];
}
unifinderTreeView.addItems(items.filter(filter.isItemInFilters, filter));
},
removeItemFromTree: function uO_removeItemFromTree(aItem) {
var items;
var filter = unifinderTreeView.mFilter;
if (filter.startDate && filter.endDate && (aItem.parentItem == aItem)) {
items = aItem.getOccurrencesBetween(filter.startDate, filter.endDate, {});
} else {
items = [aItem];
}
// XXX: do we really still need this, we are always checking it in the refreshInternal
unifinderTreeView.removeItems(items.filter(filter.isItemInFilters, filter));
},
onError: function uO_onError(aCalendar, aErrNo, aMessage) {},
onPropertyChanged: function uO_onPropertyChanged(aCalendar, aName, aValue, aOldValue) {
@ -190,11 +180,50 @@ var unifinderObserver = {
}
},
onDefaultCalendarChanged: function uO_onDefaultCalendarChanged(aNewDefaultCalendar) {}
onDefaultCalendarChanged: function uO_onDefaultCalendarChanged(aNewDefaultCalendar) {},
/**
* Add an unifinder item to the tree. It is safe to call these for any
* event. The functions will determine whether or not anything actually
* needs to be done to the tree.
*
* @return aItem The item to add to the tree.
*/
addItemToTree: function uO_addItemToTree(aItem) {
var items;
var filter = unifinderTreeView.mFilter;
if (filter.startDate && filter.endDate) {
items = aItem.getOccurrencesBetween(filter.startDate, filter.endDate, {});
} else {
items = [aItem];
}
unifinderTreeView.addItems(items.filter(filter.isItemInFilters, filter));
},
/**
* Remove an item from the unifinder tree. It is safe to call these for any
* event. The functions will determine whether or not anything actually
* needs to be done to the tree.
*
* @return aItem The item to remove from the tree.
*/
removeItemFromTree: function uO_removeItemFromTree(aItem) {
var items;
var filter = unifinderTreeView.mFilter;
if (filter.startDate && filter.endDate && (aItem.parentItem == aItem)) {
items = aItem.getOccurrencesBetween(filter.startDate, filter.endDate, {});
} else {
items = [aItem];
}
// XXX: do we really still need this, we are always checking it in the refreshInternal
unifinderTreeView.removeItems(items.filter(filter.isItemInFilters, filter));
}
};
/**
* Called when the calendar is loaded
* Called when the window is loaded to prepare the unifinder. This function is
* used to add observers, event listeners, etc.
*/
function prepareCalendarUnifinder() {
// Only load once
@ -247,7 +276,8 @@ function prepareCalendarUnifinder() {
}
/**
* Called when the calendar is unloaded
* Called when the window is unloaded to clean up any observers and listeners
* added.
*/
function finishCalendarUnifinder() {
var ccalendar = getCompositeCalendar();
@ -272,7 +302,7 @@ function finishCalendarUnifinder() {
}
/**
* Event listeners for dayselect and itemselect events
* Event listener for the view deck's dayselect event.
*/
function unifinderDaySelect() {
if (getCurrentUnifinderFilter() == "current") {
@ -280,12 +310,18 @@ function unifinderDaySelect() {
}
}
/**
* Event listener for the view deck's itemselect event.
*/
function unifinderItemSelect(aEvent) {
unifinderTreeView.setSelectedItems(aEvent.detail);
}
/**
* Helper function to display event datetimes in the unifinder
* Helper function to display event datetimes in the unifinder.
*
* @param aDatetime A calIDateTime object to format.
* @return The passed date's formatted in the default timezone.
*/
function formatUnifinderEventDateTime(aDatetime) {
var dateFormatter = Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
@ -294,7 +330,9 @@ function formatUnifinderEventDateTime(aDatetime) {
}
/**
* Unifinder event handlers (click,select,etc)
* Handler function for double clicking the unifinder.
*
* @param event The DOM doubleclick event.
*/
function unifinderDoubleClick(event) {
// We only care about button 0 (left click) events
@ -312,6 +350,11 @@ function unifinderDoubleClick(event) {
}
}
/**
* Handler function for selection in the unifinder.
*
* @param event The DOM selection event.
*/
function unifinderSelect(event) {
var tree = unifinderTreeView.treeElement;
if (!tree.view.selection || tree.view.selection.getRangeCount() == 0) {
@ -351,6 +394,11 @@ function unifinderSelect(event) {
document.getElementById("unifinder-search-results-tree").focus();
}
/**
* Handler function for keypress in the unifinder.
*
* @param aEvent The DOM Key event.
*/
function unifinderKeyPress(aEvent) {
const kKE = Components.interfaces.nsIDOMKeyEvent;
switch (aEvent.keyCode) {
@ -383,10 +431,16 @@ var unifinderTreeView = {
mSelectedColumn: null,
sortDirection: null,
/**
* Returns the currently selected column in the unifinder (used for sorting).
*/
get selectedColumn uTV_getSelectedColumn() {
return this.mSelectedColumn;
},
/**
* Sets the currently selected column in the unifinder (used for sorting).
*/
set selectedColumn uTV_setSelectedColumn(aCol) {
var tree = document.getElementById("unifinder-search-results-tree");
var treecols = tree.getElementsByTagName("treecol");
@ -411,6 +465,12 @@ var unifinderTreeView = {
eventArray: [],
eventIndexMap: {},
/**
* Add an item to the unifinder tree.
*
* @param aItemArray An array of items to add.
* @param aDontSort If true, the items will only be appended.
*/
addItems: function uTV_addItems(aItemArray, aDontSort) {
this.eventArray = this.eventArray.concat(aItemArray);
if (this.tree) {
@ -425,6 +485,11 @@ var unifinderTreeView = {
}
},
/**
* Remove items from the unifinder tree.
*
* @param aItemArray An array of items to remove.
*/
removeItems: function uTV_removeItems(aItemArray) {
for each (var item in aItemArray) {
var row = this.getItemRow(item);
@ -438,6 +503,9 @@ var unifinderTreeView = {
this.calculateIndexMap();
},
/**
* Clear all items from the unifinder.
*/
clearItems: function uTV_clearItems() {
var oldCount = this.eventArray.length;
this.eventArray = [];
@ -447,6 +515,10 @@ var unifinderTreeView = {
this.calculateIndexMap();
},
/**
* Sets the items that should be in the unifinder. This removes all items
* that were previously in the unifinder.
*/
setItems: function uTV_setItems(aItemArray, aDontSort) {
var oldCount = this.eventArray.length;
this.eventArray = aItemArray.slice(0);
@ -461,6 +533,11 @@ var unifinderTreeView = {
}
},
/**
* Recalculate the index map that improves performance when accessing
* unifinder items. This is usually done automatically when adding/removing
* items.
*/
calculateIndexMap: function uTV_calculateIndexMap() {
this.eventIndexMap = {};
for (var i = 0 ; i < this.eventArray.length; i++) {
@ -472,8 +549,11 @@ var unifinderTreeView = {
}
},
/**
* Sort the items in the unifinder by the currently selected column.
*/
sortItems: function uTV_sortItems() {
if( this.selectedColumn) {
if (this.selectedColumn) {
var modifier = (this.sortDirection == "descending" ? -1 : 1);
var sortKey = unifinderTreeView.selectedColumn.getAttribute("itemproperty");
var sortType = cal.getSortTypeForSortKey(sortKey);
@ -487,6 +567,12 @@ var unifinderTreeView = {
this.calculateIndexMap();
},
/**
* Get the index of the row associated with the passed item.
*
* @param item The item to search for.
* @return The row index of the passed item.
*/
getItemRow: function uTV_getItemRow(item) {
if (this.eventIndexMap[item.hashId] === undefined) {
return -1;
@ -494,12 +580,21 @@ var unifinderTreeView = {
return this.eventIndexMap[item.hashId];
},
/**
* Get the item at the given row index.
*
* @param item The row index to get the item for.
* @return The item at the given row.
*/
getItemAt: function uTV_getItemAt(aRow) {
return this.eventArray[aRow];
},
/**
* Get the calendar item from the given event
* Get the calendar item from the given DOM event
*
* @param event The DOM mouse event to get the item for.
* @return The item under the mouse position.
*/
getItemFromEvent: function uTV_getItemFromEvent(event) {
var row = this.tree.getRowAt(event.clientX, event.clientY);
@ -510,6 +605,11 @@ var unifinderTreeView = {
return null;
},
/**
* Change the selection in the unifinder.
*
* @param aItemArray An array of items to select.
*/
setSelectedItems: function uTV_setSelectedItems(aItemArray) {
if (this.doingSelection || !this.tree) {
return;
@ -551,6 +651,10 @@ var unifinderTreeView = {
setTimeout(function() { unifinderTreeView.resetAllowSelection(); }, 1);
},
/**
* Due to a selection issue described in bug 168211 this method is needed to
* re-add the selection listeners selection listeners.
*/
resetAllowSelection: function uTV_resetAllowSelection() {
if (!this.tree) {
return;
@ -567,6 +671,7 @@ var unifinderTreeView = {
/**
* Tree View Implementation
* @see nsITreeView
*/
get rowCount uTV_getRowCount() {
return this.eventArray.length;
@ -727,6 +832,10 @@ var unifinderTreeView = {
outParameter: new Object() // used to obtain dates during sort
};
/**
* Refresh the unifinder tree by getting items from the composite calendar and
* applying the current filter.
*/
function refreshEventTree() {
if (isUnifinderHidden()) {
// If the unifinder is hidden, don't refresh the events to reduce needed
@ -780,11 +889,16 @@ function refreshEventTree() {
}
/**
* Get the dates for a certain filter. This function makes it easy to extend the
* unifinder. To add a new view, just overwrite this function with your own. Be
* sure to call this function afterwards though.
* EXTENSION_POINTS
* Filters the passed event array according to the currently applied filter.
* Afterwards, applies the items to the unifinder view.
*
* If you are implementing a new filter, you can overwrite this function and
* filter the items accordingly and afterwards call this function with the
* result.
*
* @param eventArray The array of items to be set in the unifinder.
*/
function refreshEventTreeInternal(eventArray) {
unifinderTreeView.setItems(eventArray.filter(unifinderTreeView
@ -799,10 +913,16 @@ function refreshEventTreeInternal(eventArray) {
unifinderTreeView.setSelectedItems();
}
/**
* Focuses the unifinder search field
*/
function focusSearch() {
document.getElementById("unifinder-search-field").focus();
}
/**
* Toggles the hidden state of the unifinder.
*/
function toggleUnifinder() {
// Toggle the elements
goToggleToolbar('bottom-events-box', 'calendar_show_unifinder_command');

Просмотреть файл

@ -50,6 +50,9 @@ var gUndoStack = [];
var gForce24Hours = false;
var gZoomFactor = 100;
/**
* Sets up the attendee dialog
*/
function onLoad() {
// first of all, attach all event handlers
window.addEventListener("resize", onResize, true);
@ -139,6 +142,12 @@ function onLoad() {
self.focus();
}
/**
* This function should be called when the accept button was pressed on the
* attendee dialog. Calls the accept function specified in the window arguments.
*
* @return Returns true, if the dialog should be closed.
*/
function onAccept() {
var attendees = document.getElementById("attendees-list");
window.arguments[0].onOk(
@ -149,14 +158,34 @@ function onAccept() {
return true;
}
/**
* This function should be called when the cancel button was pressed on the
* attendee dialog.
*
* @return Returns true, if the dialog should be closed.
*/
function onCancel() {
return true;
}
/**
* Event handler for setting the zoom factor
*
* @param aValue The zoom factor to set.
*
* XXX setZoomFactor should be called directly.
*/
function onZoomFactor(aValue) {
setZoomFactor(parseInt(aValue));
}
/**
* Loads the passed start and end dates, fills global variables that give
* information about the state of the dialog.
*
* @param aStartDate The date/time the grid should start at.
* @param aEndDate The date/time the grid should end at.
*/
function loadDateTime(aStartDate, aEndDate) {
gDuration = aEndDate.subtractDate(aStartDate);
var kDefaultTimezone = calendarDefaultTimezone();
@ -168,6 +197,9 @@ function loadDateTime(aStartDate, aEndDate) {
gEndDate.makeImmutable();
}
/**
* Sets up the time grid using the global start and end dates.
*/
function propagateDateTime() {
// Fill the controls
updateDateTime();
@ -209,14 +241,9 @@ function propagateDateTime() {
}
/**
* assumes that gStartDate and gEndDate have been correctly initialized,
* either by having called loadDateTime() or having read the information
* from the controls due to recent user input. gStartDate and gEndDate are
* assumed to always be in the default timezone while the actual timezones
* are expected at gStartTimezone and gEndTimezone. this function attempts
* to copy these state related informations to the dialog controls, which
* makes it read from the variables and write to the controls (i.e. it
* doesn't change the state).
* This function requires gStartDate and gEndDate and the respective timezone
* variables to be initialized. It updates the date/time information displayed in
* the dialog from the above noted variables.
*/
function updateDateTime() {
// Convert to default timezone if the timezone option
@ -276,14 +303,9 @@ function updateDateTime() {
}
/**
* assumes that gStartDate and gEndDate have been correctly initialized,
* either by having called loadDateTime() or having read the information
* from the controls due to recent user input. gStartDate and gEndDate are
* assumed to always be in the default timezone while the actual timezones
* are expected at gStartTimezone and gEndTimezone. this function attempts
* to copy these state related informations to the dialog controls, which
* makes it read from the variables and write to the controls (i.e. it
* doesn't change the state).
* This function requires gStartDate and gEndDate and the respective timezone
* variables to be initialized. It updates the timezone information displayed in
* the dialog from the above noted variables.
*/
function updateTimezone() {
gIgnoreUpdate = true;
@ -323,6 +345,9 @@ function updateTimezone() {
gIgnoreUpdate = false;
}
/**
* Updates gStartDate from the start time picker "event-starttime"
*/
function updateStartTime() {
if (gIgnoreUpdate) {
return;
@ -353,6 +378,9 @@ function updateStartTime() {
propagateDateTime();
}
/**
* Updates gEndDate from the end time picker "event-endtime"
*/
function updateEndTime() {
if (gIgnoreUpdate) {
return;
@ -416,6 +444,10 @@ function updateEndTime() {
}
}
/**
* Prompts the user to pick a new timezone for the starttime. The dialog is
* opened modally.
*/
function editStartTimezone() {
var tzStart = document.getElementById("timezone-starttime");
if (tzStart.hasAttribute("disabled")) {
@ -447,6 +479,10 @@ function editStartTimezone() {
args);
}
/**
* Prompts the user to pick a new timezone for the endtime. The dialog is
* opened modally.
*/
function editEndTimezone() {
var tzStart = document.getElementById("timezone-endtime");
if (tzStart.hasAttribute("disabled")) {
@ -474,6 +510,12 @@ function editEndTimezone() {
args);
}
/**
* Updates the dialog controls in case the window's event is an allday event, or
* was set to one in the attendee dialog.
*
* This for example disables the timepicker since its not needed.
*/
function updateAllDay() {
if (gIgnoreUpdate) {
return;
@ -509,6 +551,11 @@ function updateAllDay() {
}
}
/**
* Changes the global variables to adapt for the change of the allday checkbox.
*
* XXX Function names are all very similar here. This needs some consistancy!
*/
function changeAllDay() {
var allDayElement = document.getElementById("all-day");
var allDay = (allDayElement.getAttribute("checked") == "true");
@ -522,7 +569,7 @@ function changeAllDay() {
propagateDateTime();
// After propagating the modified times we enforce some constraints
// on the zoom-factor. in case this events is now said to be all-day,
// on the zoom-factor. In case this events is now said to be all-day,
// we automatically enforce a 25% zoom-factor and disable the control.
var zoom = document.getElementById("zoom-menulist");
if (allDay) {
@ -535,6 +582,9 @@ function changeAllDay() {
}
}
/**
* Handler function used when the window is resized.
*/
function onResize() {
// Don't do anything if we haven't been initialized.
if (!gStartDate || !gEndDate) {
@ -564,6 +614,11 @@ function onResize() {
}
}
/**
* Handler function to call when changing the calendar used in this dialog.
*
* @param calendar The calendar to change to.
*/
function onChangeCalendar(calendar) {
var args = window.arguments[0];
var organizer = args.organizer;
@ -591,6 +646,9 @@ function onChangeCalendar(calendar) {
freebusy.onChangeCalendar(calendar);
}
/**
* Updates the slot buttons.
*/
function updateButtons() {
var previousButton = document.getElementById("previous-slot");
if (gUndoStack.length > 0) {
@ -600,6 +658,9 @@ function updateButtons() {
}
}
/**
* Handler function called to advance to the next slot.
*/
function onNextSlot() {
// Store the current setting in the undo-stack.
var currentSlot = {};
@ -636,6 +697,9 @@ function onNextSlot() {
updateButtons();
}
/**
* Handler function called to advance to the previous slot.
*/
function onPreviousSlot() {
var previousSlot = gUndoStack.pop();
if (!previousSlot) {
@ -665,6 +729,9 @@ function onPreviousSlot() {
}
}
/**
* Handler function called to zoom out (minus button)
*/
function onMinus() {
var timebar = document.getElementById("timebar");
var ratio = timebar.scroll;
@ -677,6 +744,9 @@ function onMinus() {
scrollbar.setAttribute("curpos", ratio * maxpos);
}
/**
* Handler function called to zoom in (plus button)
*/
function onPlus() {
var timebar = document.getElementById("timebar");
var ratio = timebar.scroll;
@ -689,6 +759,10 @@ function onPlus() {
scrollbar.setAttribute("curpos", ratio * maxpos);
}
/**
* Scrolls the time grid to a position where the time of the item in question is
* visible.
*/
function scrollToCurrentTime() {
var timebar = document.getElementById("timebar");
var ratio = (gStartDate.hour - gStartHour) * timebar.step;
@ -704,6 +778,12 @@ function scrollToCurrentTime() {
}
/**
* Sets the zoom factor for the time grid
*
* @param aValue The zoom factor to set.
* @return aValue (for chaining)
*/
function setZoomFactor(aValue) {
if (gZoomFactor == aValue) {
return aValue;
@ -735,6 +815,12 @@ function setZoomFactor(aValue) {
return aValue;
}
/**
* Force the time grid to show 24 hours.
*
* @param aValue If true, the view will be forced to 24 hours.
* @return aValue (for chaining)
*/
function setForce24Hours(aValue) {
if (gForce24Hours == aValue) {
return aValue;
@ -768,6 +854,10 @@ function setForce24Hours(aValue) {
return aValue;
}
/**
* Initialize the time range, setting the start and end hours from the prefs, or
* to 24 hrs if gForce24Hours is set.
*/
function initTimeRange() {
if (gForce24Hours) {
gStartHour = 0;
@ -778,13 +868,26 @@ function initTimeRange() {
}
}
/**
* Handler function for the "modify" event, emitted from the attendees-list
* binding. event.details is an array of objects containing the user's email
* (calid) and a flag that tells if the user has entered text before the last
* onModify was called (dirty).
*
* @param event The DOM event that caused the modification.
*/
function onModify(event) {
onResize();
document.getElementById(
"freebusy-grid")
.onModify(event);
document.getElementById("freebusy-grid").onModify(event);
}
/**
* Handler function for the "rowchange" event, emitted from the attendees-list
* binding. event.details is the row that was changed to.
*
* @param event The DOM event caused by the row change.
*/
function onRowChange(event) {
var scrollbar = document.getElementById("vertical-scrollbar");
var attendees = document.getElementById("attendees-list");
@ -794,11 +897,21 @@ function onRowChange(event) {
event.details / attendees.mMaxAttendees * maxpos);
}
/**
* Handler function to take care of mouse scrolling on the window
*
* @param event The DOMMouseScroll event caused by scrolling.
*/
function onMouseScroll(event) {
// ignore mouse scrolling for now...
event.stopPropagation();
}
/**
* Hanlder function to take care of attribute changes on the window
*
* @param event The DOMAttrModified event caused by this change.
*/
function onAttrModified(event) {
if (event.attrName == "width") {
var selectionbar = document.getElementById("selection-bar");
@ -846,12 +959,25 @@ function onAttrModified(event) {
}
}
/**
* Handler function for initializing the selection bar, event usually emitted
* from the freebusy-timebar binding.
*
* @param event The "timebar" event with details and height property.
*/
function onTimebar(event) {
document.getElementById(
"selection-bar")
.init(event.details, event.height);
}
/**
* Handler function to update controls when the time has changed on the
* selection bar.
*
* @param event The "timechange" event with startDate and endDate
* properties.
*/
function onTimeChange(event) {
var start = event.startDate.getInTimezone(gStartTimezone);
var end = event.endDate.getInTimezone(gEndTimezone);

Просмотреть файл

@ -41,6 +41,10 @@ var gIsReadOnly = false;
var gStartTime = null;
var gEndTime = null;
/**
* Sets up the recurrence dialog from the window arguments. Takes care of filling
* the dialog controls with the recurrece information for this window.
*/
function onLoad() {
changeWidgetsOrder();
@ -95,6 +99,11 @@ function onLoad() {
self.focus();
}
/**
* Initialize the dialog controls according to the passed rule
*
* @param rule The recurrence rule to parse.
*/
function initializeControls(rule) {
function getOrdinalAndWeekdayOfRule(aByDayRuleComponent) {
return {
@ -218,6 +227,13 @@ function initializeControls(rule) {
}
}
/**
* Save the recurrence information selected in the dialog back to the given
* item.
*
* @param item The item to save back to.
* @return The saved recurrence info.
*/
function onSave(item) {
// Always return 'null' if this item is an occurrence.
if (!item || item.parentItem != item) {
@ -342,6 +358,11 @@ function onSave(item) {
return recurrenceInfo;
}
/**
* Handler function to be called when the accept button is pressed.
*
* @return Returns true if the window should be closed
*/
function onAccept() {
var args = window.arguments[0];
var item = args.calendarEvent;
@ -349,6 +370,15 @@ function onAccept() {
return true;
}
/**
* Handler function called when the calendar is changed (also for initial
* setup).
*
* XXX we don't change the calendar in this dialog, this function should be
* consolidated or renamed.
*
* @param calendar The calendar to use for setup.
*/
function onChangeCalendar(calendar) {
var args = window.arguments[0];
var item = args.calendarEvent;
@ -369,6 +399,17 @@ function onChangeCalendar(calendar) {
updateRecurrenceControls();
}
/**
* Disable or enable certain controls based on the given item:
* Uses the following attribute:
*
* - disable-on-occurrence
* - disable-on-readonly
*
* A task without a start time is also considered readonly.
*
* @param item The item to check.
*/
function disableOrEnable(item) {
if (item.parentItem != item) {
disableRecurrenceFields("disable-on-occurrence");
@ -381,6 +422,12 @@ function disableOrEnable(item) {
}
}
/**
* Disables all fields that have an attribute that matches the argument and is
* set to "true".
*
* @param aAttributeName The attribute to search for.
*/
function disableRecurrenceFields(aAttributeName) {
var disableElements = document.getElementsByAttribute(aAttributeName, "true");
for (var i = 0; i < disableElements.length; i++) {
@ -388,6 +435,12 @@ function disableRecurrenceFields(aAttributeName) {
}
}
/**
* Enables all fields that have an attribute that matches the argument and is
* set to "true".
*
* @param aAttributeName The attribute to search for.
*/
function enableRecurrenceFields(aAttributeName) {
var enableElements = document.getElementsByAttribute(aAttributeName, "true");
for (var i = 0; i < enableElements.length; i++) {
@ -395,6 +448,16 @@ function enableRecurrenceFields(aAttributeName) {
}
}
/**
* Split rules into negative and positive rules.
*
* XXX This function is duplicate from calendar-dialog-utils.js, which we may
* want to include in this dialog.
*
* @param recurrenceInfo An item's recurrence info to parse.
* @return An array with two elements: an array of positive
* rules and an array of negative rules.
*/
function splitRecurrenceRules(recurrenceInfo) {
var ritems = recurrenceInfo.getRecurrenceItems({});
var rules = [];
@ -409,12 +472,20 @@ function splitRecurrenceRules(recurrenceInfo) {
return [rules, exceptions];
}
/**
* Handler function to update the period-deck when an item from the period-list
* is selected. Also updates the controls on that deck.
*/
function updateRecurrenceDeck() {
document.getElementById("period-deck")
.selectedIndex = Number(getElementValue("period-list"));
updateRecurrenceControls();
}
/**
* Updates the controls regarding ranged controls (i.e repeat forever, repeat
* until, repeat n times...)
*/
function updateRecurrenceRange() {
var args = window.arguments[0];
var item = args.calendarEvent;
@ -460,6 +531,9 @@ function updateRecurrenceRange() {
}
}
/**
* Updates the recurrence preview calendars using the window's item.
*/
function updatePreview() {
var args = window.arguments[0];
var item = args.calendarEvent;
@ -468,8 +542,8 @@ 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
// 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();
var kDefaultTimezone = calendarDefaultTimezone();
@ -503,6 +577,9 @@ function updatePreview() {
preview.updatePreview(recInfo);
}
/**
* Update all recurrence controls on the dialog.
*/
function updateRecurrenceControls() {
updateRecurrencePattern();
updateRecurrenceRange();
@ -576,6 +653,9 @@ function updateRecurrencePattern() {
}
/**
* This function changes the order for certain elements using a locale string.
* This is needed for some locales that expect a different wording order.
*
* @param aPropKey The locale property key to get the order from
* @param aPropParams An array of ids to be passed to the locale property.
* These should be the ids of the elements to change
@ -615,7 +695,7 @@ function changeOrderForElements(aPropKey, aPropParams) {
}
/**
* Change widget order for Edit Recurrence window
* Change locale-specific widget order for Edit Recurrence window
*/
function changeWidgetsOrder() {
changeOrderForElements("monthlyOrder",

Просмотреть файл

@ -59,6 +59,13 @@ var gLastRepeatSelection = 0;
var gIgnoreUpdate = false;
var gShowTimeAs = null;
/**
* Checks if the given calendar supports notifying attendees. The item is needed
* since calendars may support notifications for only some types of items.
*
* @param calendar The calendar to check
* @param item The item to check support for.
*/
function canNotifyAttendees(calendar, item) {
try {
var cal = calendar.QueryInterface(Components.interfaces.calISchedulingSupport);
@ -68,7 +75,9 @@ function canNotifyAttendees(calendar, item) {
}
}
// update menu items that rely on focus
/**
* Update menu items that rely on focus
*/
function goUpdateGlobalEditMenuItems() {
goUpdateCommand('cmd_undo');
goUpdateCommand('cmd_redo');
@ -78,7 +87,9 @@ function goUpdateGlobalEditMenuItems() {
goUpdateCommand('cmd_selectAll');
}
// update menu items that rely on the current selection
/**
* Update menu items that rely on the current selection
*/
function goUpdateSelectEditMenuItems() {
goUpdateCommand('cmd_cut');
goUpdateCommand('cmd_copy');
@ -86,17 +97,25 @@ function goUpdateSelectEditMenuItems() {
goUpdateCommand('cmd_selectAll');
}
// update menu items that relate to undo/redo
/**
* Update menu items that relate to undo/redo
*/
function goUpdateUndoEditMenuItems() {
goUpdateCommand('cmd_undo');
goUpdateCommand('cmd_redo');
}
// update menu items that depend on clipboard contents
/**
* Update menu items that depend on clipboard contents
*/
function goUpdatePasteMenuItems() {
goUpdateCommand('cmd_paste');
}
/**
* Sets up the event dialog from the window arguments, also setting up all
* dialog controls from the window's item.
*/
function onLoad() {
// first of all retrieve the array of
// arguments this window has been called with.
@ -198,12 +217,25 @@ function onLoad() {
document.getElementById("item-title").select();
}
/**
* Handler function to be called when the accept button is pressed.
*
* @return Returns true if the window should be closed
*/
function onAccept() {
dispose();
onCommandSave(true);
return true;
}
/**
* Asks the user if the item should be saved and does so if requested. If the
* user cancels, the window should stay open.
*
* XXX Could possibly be consolidated into onCancel()
*
* @return Returns true if the window should be closed.
*/
function onCommandCancel() {
// find out if we should bring up the 'do you want to save?' question...
var newItem = saveItem();
@ -262,6 +294,10 @@ function onCommandCancel() {
}
}
/**
* Handler function to be called when the cancel button is pressed.
*
*/
function onCancel() {
var result = onCommandCancel();
if (result == true) {
@ -270,6 +306,11 @@ function onCancel() {
return result;
}
/**
* Sets up all dialog controls from the information of the passed item.
*
* @param item The item to parse information out of.
*/
function loadDialog(item) {
setElementValue("item-title", item.title);
setElementValue("item-location", item.getProperty("LOCATION"));
@ -381,6 +422,11 @@ function loadDialog(item) {
updateShowTimeAs();
}
/**
* Sets up all date related controls from the passed item
*
* @param item The item to parse information out of.
*/
function loadDateTime(item) {
var kDefaultTimezone = calendarDefaultTimezone();
if (isEvent(item)) {
@ -439,6 +485,13 @@ function loadDateTime(item) {
}
/**
* Handler function to be used when the start time or end time of the event have
* changed. If aKeepDuration is true then the end time will be modified so that
* the total duration of the item stays the same.
*
* @param aKeepDuration If true, the duration will be kept constant.
*/
function dateTimeControls2State(aKeepDuration) {
if (gIgnoreUpdate) {
return;
@ -527,6 +580,10 @@ function dateTimeControls2State(aKeepDuration) {
}
}
/**
* Updates the entry date checkboxes, used for example when choosing an alarm:
* the entry date needs to be checked in that case.
*/
function updateEntryDate() {
updateDateCheckboxes(
"todo-entrydate",
@ -541,6 +598,9 @@ function updateEntryDate() {
});
}
/**
* Updates the due date checkboxes.
*/
function updateDueDate() {
updateDateCheckboxes(
"todo-duedate",
@ -555,6 +615,15 @@ function updateDueDate() {
});
}
/**
* Common function used by updateEntryDate and updateDueDate to set up the
* checkboxes correctly.
*
* @param aDatePickerId The XUL id of the datepicker to update.
* @param aCheckboxId The XUL id of the corresponding checkbox.
* @param aDateTime An object implementing the isValid and setDateTime
* methods. XXX explain.
*/
function updateDateCheckboxes(aDatePickerId, aCheckboxId, aDateTime) {
if (gIgnoreUpdate) {
return;
@ -594,6 +663,12 @@ function updateDateCheckboxes(aDatePickerId, aCheckboxId, aDateTime) {
updateTimezone();
}
/**
* Update the dialog controls to display the item's recurrence information
* nicely.
*
* @param item The item to load.
*/
function loadRepeat(item) {
var recurrenceInfo = window.recurrenceInfo;
setElementValue("item-repeat", "none");
@ -703,11 +778,19 @@ function loadRepeat(item) {
}
}
/**
* Update reminder related elements on the dialog.
*/
function updateReminder() {
commonUpdateReminder();
updateAccept();
}
/**
* 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 = document.getElementById("item-calendar")
@ -793,6 +876,11 @@ function saveDialog(item) {
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) {
var kDefaultTimezone = calendarDefaultTimezone();
if (isEvent(item)) {
@ -822,6 +910,10 @@ function saveDateTime(item) {
}
}
/**
* Updates the dialog title based on item type and if the item is new or to be
* modified.
*/
function updateTitle() {
var title = "";
var isNew = window.calendarItem.isMutable;
@ -843,6 +935,17 @@ function updateTitle() {
document.title = title;
}
/**
* Updates the stylesheet to add rules to hide certain aspects (i.e task only
* elements when editing an event).
*
* TODO We can use general rules here, i.e
* dialog[itemType="task"] .event-only,
* dialog[itemType="event"] .task-only,
* dialog:not([product="lightning"]) .lightning-only {
* display: none;
* }
*/
function updateStyle() {
const kDialogStylesheet = "chrome://calendar/content/calendar-event-dialog.css";
@ -861,6 +964,13 @@ function updateStyle() {
}
}
/**
* Handler function for showing the options menu
*
* XXX This function could go away with more general CSS rules?
*
* @param menuPopup The menupopup node targetted by the event.
*/
function onPopupShowing(menuPopup) {
if (isToDo(window.calendarItem)) {
var nodes = menuPopup.childNodes;
@ -878,6 +988,11 @@ function onPopupShowing(menuPopup) {
}
}
/**
* Update the disabled status of the accept button. The button is enabled if all
* parts of the dialog have options selected that make sense.
* constraining factors like
*/
function updateAccept() {
var enableAccept = true;
@ -947,6 +1062,10 @@ function updateAccept() {
return enableAccept;
}
/**
* Handler function to update controls in consequence of the "all day" checkbox
* being clicked.
*/
function onUpdateAllDay() {
if (!isEvent(window.calendarItem)) {
return;
@ -959,15 +1078,15 @@ function onUpdateAllDay() {
updateAllDay();
}
// this function sets the enabled/disabled
// state of the following controls:
// - 'event-starttime'
// - 'event-endtime'
// - 'timezone-starttime'
// - 'timezone-endtime'
// the state depends on whether or not the
// event is configured as 'all-day' or not.
function updateAllDay() {
/**
* This function sets the enabled/disabled state of the following controls:
* - 'event-starttime'
* - 'event-endtime'
* - 'timezone-starttime'
* - 'timezone-endtime'
* the state depends on whether or not the event is configured as 'all-day' or not.
*/
function updateAllDay() {
if (gIgnoreUpdate) {
return;
}
@ -993,12 +1112,19 @@ function updateAllDay() {
updateAccept();
}
/**
* Use the window arguments to cause the opener to create a new event on the
* item's calendar
*/
function openNewEvent() {
var item = window.calendarItem;
var args = window.arguments[0];
args.onNewEvent(item.calendar);
}
/**
* Open a new Thunderbird compose window.
*/
function openNewMessage() {
var msgComposeService = Components.classes["@mozilla.org/messengercompose;1"]
.getService(Components.interfaces.nsIMsgComposeService);
@ -1011,6 +1137,9 @@ function openNewMessage() {
null);
}
/**
* Open a new addressbook window
*/
function openNewCardDialog() {
window.openDialog(
"chrome://messenger/content/addressbook/abNewCardDialog.xul",
@ -1018,8 +1147,12 @@ function openNewCardDialog() {
"chrome,resizable=no,titlebar,modal");
}
// automatically select pref calendar.allday.defaultTransparency if this
// event is said to be all-day.
/**
* 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) {
gShowTimeAs = (allDay ? getPrefSafe("calendar.allday.defaultTransparency", "TRANSPARENT") : "OPAQUE");
updateShowTimeAs();
@ -1226,11 +1359,20 @@ function updatePrivacy() {
}
}
/**
* Handler function to change the priority from the dialog elements
*
* @param target A XUL node with a value attribute which should be the new
* priority.
*/
function editPriority(target) {
gPriority = parseInt(target.getAttribute("value"));
updatePriority();
}
/**
* Update the dialog controls related related to priority.
*/
function updatePriority() {
// Set up capabilities
var hasPriority = capSupported("priority");
@ -1285,11 +1427,20 @@ function updatePriority() {
}
}
/**
* Handler function to change the status from the dialog elements
*
* @param target A XUL node with a value attribute which should be the new
* status.
*/
function editStatus(target) {
gStatus = target.getAttribute("value");
updateStatus();
}
/**
* Update the dialog controls related related to status.
*/
function updateStatus() {
[ "cmd_status_none",
"cmd_status_tentative",
@ -1304,11 +1455,20 @@ function updateStatus() {
);
}
/**
* Handler function to change the transparency from the dialog elements
*
* @param target A XUL node with a value attribute which should be the new
* transparency.
*/
function editShowTimeAs(target) {
gShowTimeAs = target.getAttribute("value");
updateShowTimeAs();
}
/**
* Update the dialog controls related related to transparency.
*/
function updateShowTimeAs() {
var showAsBusy = document.getElementById("cmd_showtimeas_busy");
var showAsFree = document.getElementById("cmd_showtimeas_free");
@ -1319,6 +1479,9 @@ function updateShowTimeAs() {
gShowTimeAs == "TRANSPARENT" ? "true" : "false");
}
/**
* Prompts the user to attach an url to this item.
*/
function attachURL() {
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
@ -1404,6 +1567,16 @@ function attachFile() {
}
}
/**
* Helper function to remember the last directory chosen when attaching files.
* XXX This function is currently unused, will be needed when we support
* attaching files.
*
* @param aFileUri (optional) If passed, the last directory will be set and
* returned. If null, the last chosen directory
* will be returned.
* @return The last directory that was set with this function.
*/
function lastDirectory(aFileUri) {
if (aFileUri) {
// Act similar to a setter, save the passed uri.
@ -1416,6 +1589,14 @@ function lastDirectory(aFileUri) {
return (lastDirectory.mValue !== undefined ? lastDirectory.mValue : null);
}
/**
* Turns an url into a string that can be used in UI.
* - For a file:// url, shows the filename.
* - For a http:// url, removes protocol and trailing slash
*
* @param aUri The uri to parse.
* @return A string that can be used in UI.
*/
function makePrettyName(aUri){
var name = aUri.spec;
if (aUri.schemeIs("file")) {
@ -1426,6 +1607,11 @@ function makePrettyName(aUri){
return name;
}
/**
* Adds the given attachment to dialog controls.
*
* @param attachment The calIAttachment object to add
*/
function addAttachment(attachment) {
if (!attachment ||
!attachment.uri ||
@ -1455,6 +1641,11 @@ function addAttachment(attachment) {
updateAttachment();
}
/**
* Removes the currently selected attachment from the dialog controls.
*
* XXX This could use a dialog maybe?
*/
function deleteAttachment() {
var documentLink = document.getElementById("attachment-link");
delete gAttachMap[documentLink.selectedItem.attachment.uri.spec];
@ -1462,6 +1653,9 @@ function deleteAttachment() {
updateAttachment();
}
/**
* Removes all attachments from the dialog controls.
*/
function deleteAllAttachments() {
var documentLink = document.getElementById("attachment-link");
var itemCount = documentLink.getRowCount();
@ -1491,6 +1685,10 @@ function deleteAllAttachments() {
updateAttachment();
}
/**
* Opens the selected attachment using the external protocol service.
* @see nsIExternalProtocolService
*/
function openAttachment() {
// Only one file has to be selected and we don't handle base64 files at all
var documentLink = document.getElementById("attachment-link");
@ -1503,6 +1701,11 @@ function openAttachment() {
}
}
/**
* Handler function to handle pressing keys in the attachment listbox.
*
* @param event The DOM event caused by the key press.
*/
function attachmentLinkKeyPress(event) {
const kKE = Components.interfaces.nsIDOMKeyEvent;
switch (event.keyCode) {
@ -1516,6 +1719,11 @@ function attachmentLinkKeyPress(event) {
}
}
/**
* Handler function to take care of clicking on an attachment
*
* @param event The DOM event caused by the clicking.
*/
function attachmentLinkClicked(event) {
event.currentTarget.focus();
@ -1530,6 +1738,9 @@ function attachmentLinkClicked(event) {
}
}
/**
* Update the dialog controls related related to the item's calendar.
*/
function updateCalendar() {
var item = window.calendarItem;
var calendar = document.getElementById("item-calendar")
@ -1629,6 +1840,10 @@ function updateCalendar() {
}
/**
* Opens the recurrence dialog modally to allow the user to edit the recurrence
* rules.
*/
function editRepeat() {
var args = new Object();
args.calendarEvent = window.calendarItem;
@ -1792,6 +2007,12 @@ function updateRepeat() {
updateAccept();
}
/**
* Updates the UI controls related to a task's completion status.
*
* @param status The item's completion status.
* @param passedInCompletedDate The item's completed date (as a JSDate).
*/
function updateToDoStatus(status, passedInCompletedDate) {
// RFC2445 doesn't support completedDates without the todo's status
// being "COMPLETED", however twiddling the status menulist shouldn't
@ -1859,6 +2080,11 @@ function updateToDoStatus(status, passedInCompletedDate) {
}
}
/**
* Saves all dialog controls back to the item.
*
* @return a copy of the original item with changes made.
*/
function saveItem() {
// we need to clone the item in order to apply the changes.
// it is important to not apply the changes to the original item
@ -1895,6 +2121,17 @@ function saveItem() {
return item;
}
/**
* Action to take when the user chooses to save. This can happen either by
* saving directly or the user selecting to save after being prompted when
* closing the dialog.
*
* This function also takes care of notifying this dialog's caller that the item
* is saved.
*
* @param aIsClosing If true, the save action originates from the
* save prompt just before the window is closing.
*/
function onCommandSave(aIsClosing) {
var originalItem = window.calendarItem;
var item = saveItem();
@ -1928,6 +2165,12 @@ function onCommandSave(aIsClosing) {
}
/**
* Handler function to toggle toolbar visibility.
*
* @param aToolbarId The id of the XUL toolbar node to toggle.
* @param aMenuitemId The corresponding menuitem in the view menu.
*/
function onCommandViewToolbar(aToolbarId, aMenuItemId) {
var toolbar = document.getElementById(aToolbarId);
var menuItem = document.getElementById(aMenuItemId);
@ -1952,8 +2195,9 @@ function onCommandViewToolbar(aToolbarId, aMenuItemId) {
* DialogToolboxCustomizeDone() is called after the customize toolbar dialog
* has been closed by the user. We need to restore the state of all buttons
* and commands of all customizable toolbars.
*
* @param aToolboxChanged If true, the toolbox has changed.
*/
function DialogToolboxCustomizeDone(aToolboxChanged) {
var menubar = document.getElementById("event-menubar");
@ -1972,6 +2216,10 @@ function DialogToolboxCustomizeDone(aToolboxChanged) {
updatePrivacy();
}
/**
* Handler function to start the customize toolbar dialog for the event dialog's
* toolbar.
*/
function onCommandCustomize() {
// install the callback that handles what needs to be
// done after a toolbar has been customized.
@ -2006,6 +2254,9 @@ function onCommandCustomize() {
}
}
/**
* Prompts the user to change the start timezone.
*/
function editStartTimezone() {
editTimezone(
"timezone-starttime",
@ -2025,6 +2276,9 @@ function editStartTimezone() {
});
}
/**
* Prompts the user to change the end timezone.
*/
function editEndTimezone() {
editTimezone(
"timezone-endtime",
@ -2044,6 +2298,14 @@ function editEndTimezone() {
});
}
/**
* Common function of edit(Start|End)Timezone() to prompt the user for a
* timezone change.
*
* @param aElementId The XUL element id of the timezone label.
* @param aDateTime The Date/Time of the time to change zone on.
* @param aCallback What to do when the user has chosen a zone.
*/
function editTimezone(aElementId,aDateTime,aCallback) {
if (document.getElementById(aElementId)
.hasAttribute("disabled")) {
@ -2064,28 +2326,30 @@ function editTimezone(aElementId,aDateTime,aCallback) {
args);
}
// this function initializes the following controls:
// - 'event-starttime'
// - 'event-endtime'
// - 'event-all-day'
// - 'todo-has-entrydate'
// - 'todo-entrydate'
// - 'todo-has-duedate'
// - 'todo-duedate'
// the date/time-objects are either displayed in their repective
// timezone or in the default timezone. this decision is based
// on whether or not 'options-timezone-menuitem' is checked.
// the necessary information is taken from the following variables:
// - 'gStartTime'
// - 'gEndTime'
// - 'window.calendarItem' (used to decide about event/task)
/**
* This function initializes the following controls:
* - 'event-starttime'
* - 'event-endtime'
* - 'event-all-day'
* - 'todo-has-entrydate'
* - 'todo-entrydate'
* - 'todo-has-duedate'
* - 'todo-duedate'
* The date/time-objects are either displayed in their respective
* timezone or in the default timezone. This decision is based
* on whether or not 'options-timezone-menuitem' is checked.
* the necessary information is taken from the following variables:
* - 'gStartTime'
* - 'gEndTime'
* - 'window.calendarItem' (used to decide about event/task)
*/
function updateDateTime() {
gIgnoreUpdate = true;
var item = window.calendarItem;
var menuItem = document.getElementById('options-timezone-menuitem');
// convert to default timezone if the timezone option
// 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 (menuItem.getAttribute('checked') == 'true') {
@ -2095,7 +2359,7 @@ function updateDateTime() {
setElementValue("event-all-day", startTime.isDate, "checked");
// in the case where the timezones are different but
// 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.
if (startTime && endTime) {
@ -2216,12 +2480,14 @@ function updateDateTime() {
gIgnoreUpdate = false;
}
// this function initializes the following controls:
// - 'timezone-starttime'
// - 'timezone-endtime'
// the timezone-links show the corrosponding names of the
// start/end times. if 'options-timezone-menuitem' is not checked
// the links will be collapsed.
/**
* This function initializes the following controls:
* - 'timezone-starttime'
* - 'timezone-endtime'
* the timezone-links show the corrosponding names of the
* start/end times. if 'options-timezone-menuitem' is not checked
* the links will be collapsed.
*/
function updateTimezone() {
var menuItem = document.getElementById('options-timezone-menuitem');
@ -2292,6 +2558,9 @@ function updateTimezone() {
}
}
/**
* This function updates dialog controls related to item attachments
*/
function updateAttachment() {
var hasAttachments = capSupported("attachments");
setElementValue("cmd_attach_url", !hasAttachments && "true", "disabled");
@ -2308,6 +2577,9 @@ function updateAttachment() {
}
}
/**
* Toggles the visibility of the related link (rfc2445 URL property)
*/
function toggleLink() {
var linkCommand = document.getElementById("cmd_toggle_link");
var row = document.getElementById("event-grid-link-row");
@ -2322,6 +2594,9 @@ function toggleLink() {
updateLink();
}
/**
* This function updates dialog controls related to attendees.
*/
function updateAttendees() {
var attendeeRow = document.getElementById("event-grid-attendee-row");
var attendeeRow2 = document.getElementById("event-grid-attendee-row-2");
@ -2365,6 +2640,10 @@ function updateAttendees() {
}
}
/**
* This function updates dialog controls related to recurrence, in this case the
* text describing the recurrence rule.
*/
function updateRepeatDetails() {
// Don't try to show the details text for
// anything but a custom recurrence rule.

Просмотреть файл

@ -37,6 +37,10 @@
Components.utils.import("resource://calendar/modules/calUtils.jsm");
/**
* Sets up the invitations dialog from the window arguments, retrieves the
* invitations from the invitations manager.
*/
function onLoad() {
var operationListener = {
onOperationComplete: function oL_onOperationComplete(aCalendar,
@ -84,11 +88,19 @@ function onLoad() {
opener.setCursor("auto");
}
/**
* Cleans up the invitations dialog, cancels pending requests.
*/
function onUnload() {
var args = window.arguments[0];
args.requestManager.cancelPendingRequests();
}
/**
* Handler function to be called when the accept button is pressed.
*
* @return Returns true if the window should be closed
*/
function onAccept() {
var args = window.arguments[0];
fillJobQueue(args.queue);
@ -96,6 +108,9 @@ function onAccept() {
return true;
}
/**
* Handler function to be called when the cancel button is pressed.
*/
function onCancel() {
var args = window.arguments[0];
if (args.finishedCallBack) {
@ -103,6 +118,12 @@ function onCancel() {
}
}
/**
* Fills the job queue from the invitations-listbox's items. The job queue
* contains objects for all items that have a modified participation status.
*
* @param queue The queue to fill.
*/
function fillJobQueue(queue) {
var richListBox = document.getElementById("invitations-listbox");
var rowCount = richListBox.getRowCount();

Просмотреть файл

@ -58,8 +58,7 @@ const MODE_EXCL = 0x80;
* @param aCalendar (optional) If specified, the items will be imported directly
* into the calendar
*/
function loadEventsFromFile(aCalendar)
{
function loadEventsFromFile(aCalendar) {
const nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"]
@ -142,6 +141,14 @@ function loadEventsFromFile(aCalendar)
}
}
/**
* Put items into a certain calendar, catching errors and showing them to the
* user.
*
* @param destCal The destination calendar.
* @param aItems An array of items to put into the calendar.
* @param aFilePath The original file path, for error messages.
*/
function putItemsIntoCal(destCal, aItems, aFilePath) {
// Set batch for the undo/redo transaction manager
startBatchTransaction();
@ -185,7 +192,7 @@ function putItemsIntoCal(destCal, aItems, aFilePath) {
}
}
for each (item in aItems) {
for each (let item in aItems) {
// XXX prompt when finding a duplicate.
try {
destCal.addItem(item, listener);
@ -213,9 +220,7 @@ function putItemsIntoCal(destCal, aItems, aFilePath) {
* be saved to file.
* @param aDefaultFileName (optional) Initial filename shown in SaveAs dialog.
*/
function saveEventsToFile(calendarEventArray, aDefaultFileName)
{
function saveEventsToFile(calendarEventArray, aDefaultFileName) {
if (!calendarEventArray)
return;
@ -302,8 +307,11 @@ function saveEventsToFile(calendarEventArray, aDefaultFileName)
}
}
/* Exports all the events and tasks in a calendar. If aCalendar is not specified,
/**
* Exports all the events and tasks in a calendar. If aCalendar is not specified,
* the user will be prompted with a list of calendars to choose which one to export.
*
* @param aCalendar (optional) A specific calendar to export
*/
function exportEntireCalendar(aCalendar) {
var itemArray = [];