diff options
Diffstat (limited to 'comm/calendar/base/content/calendar-command-controller.js')
-rw-r--r-- | comm/calendar/base/content/calendar-command-controller.js | 869 |
1 files changed, 869 insertions, 0 deletions
diff --git a/comm/calendar/base/content/calendar-command-controller.js b/comm/calendar/base/content/calendar-command-controller.js new file mode 100644 index 0000000000..605b2e9a58 --- /dev/null +++ b/comm/calendar/base/content/calendar-command-controller.js @@ -0,0 +1,869 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* globals goUpdateCommand, currentView, TodayPane, createEventWithDialog, + getSelectedCalendar, editSelectedEvents, viewSelectedEvents, + modifyTaskFromContext, deleteSelectedEvents, setupAttendanceMenu, + createTodoWithDialog, deleteToDoCommand, promptDeleteCalendar, + toImport, loadEventsFromFile, exportEntireCalendar, saveEventsToFile, + publishEntireCalendar, publishCalendarData, toggleUnifinder, toggleOrientation + toggleWorkdaysOnly, switchCalendarView, getTaskTree, selectAllEvents, + gCurrentMode, getSelectedTasks, canPaste, goSetMenuValue, canUndo, canRedo, + cutToClipboard, copyToClipboard, pasteFromClipboard, undo, redo, + PrintUtils */ + +var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm"); + +var CalendarDeleteCommandEnabled = false; +var CalendarNewEventsCommandEnabled = false; +var CalendarNewTasksCommandEnabled = false; + +/** + * Command controller to execute calendar specific commands + * + * @see nsICommandController + */ +var calendarController = { + commands: new Set([ + // Common commands + "calendar_new_event_command", + "calendar_new_event_context_command", + "calendar_new_event_todaypane_command", + "calendar_modify_event_command", + "calendar_view_event_command", + "calendar_delete_event_command", + + "calendar_modify_focused_item_command", + "calendar_delete_focused_item_command", + + "calendar_new_todo_command", + "calendar_new_todo_context_command", + "calendar_new_todo_todaypane_command", + "calendar_toggle_tasks_in_view_command", + "calendar_modify_todo_command", + "calendar_modify_todo_todaypane_command", + "calendar_delete_todo_command", + + "calendar_new_calendar_command", + "calendar_edit_calendar_command", + "calendar_delete_calendar_command", + + "calendar_import_command", + "calendar_export_command", + "calendar_export_selection_command", + + "calendar_publish_selected_calendar_command", + "calendar_publish_calendar_command", + "calendar_publish_selected_events_command", + + "calendar_view_next_command", + "calendar_view_prev_command", + + "calendar_toggle_orientation_command", + "calendar_toggle_workdays_only_command", + + "calendar_day-view_command", + "calendar_week-view_command", + "calendar_multiweek-view_command", + "calendar_month-view_command", + + "calendar_task_filter_command", + "calendar_reload_remote_calendars", + "calendar_show_unifinder_command", + "calendar_toggle_completed_command", + "calendar_percentComplete-0_command", + "calendar_percentComplete-25_command", + "calendar_percentComplete-50_command", + "calendar_percentComplete-75_command", + "calendar_percentComplete-100_command", + "calendar_priority-0_command", + "calendar_priority-9_command", + "calendar_priority-5_command", + "calendar_priority-1_command", + "calendar_general-priority_command", + "calendar_general-progress_command", + "calendar_general-postpone_command", + "calendar_postpone-1hour_command", + "calendar_postpone-1day_command", + "calendar_postpone-1week_command", + "calendar_task_category_command", + + "calendar_attendance_command", + + // for events/tasks in a tab + "cmd_save", + "cmd_accept", + + // Pseudo commands + "calendar_in_foreground", + "calendar_in_background", + "calendar_mode_calendar", + "calendar_mode_task", + + "cmd_selectAll", + ]), + + updateCommands() { + this.commands.forEach(goUpdateCommand); + }, + + supportsCommand(aCommand) { + if (this.commands.has(aCommand)) { + return true; + } + return false; + }, + + /* eslint-disable complexity */ + isCommandEnabled(aCommand) { + switch (aCommand) { + case "calendar_new_event_command": + case "calendar_new_event_context_command": + case "calendar_new_event_todaypane_command": + return CalendarNewEventsCommandEnabled; + case "calendar_modify_focused_item_command": + return this.item_selected && canEditSelectedItems(); + case "calendar_modify_event_command": + return this.item_selected && canEditSelectedItems(); + case "calendar_view_event_command": + return this.item_selected; + case "calendar_delete_focused_item_command": + return CalendarDeleteCommandEnabled && this.selected_items_writable; + case "calendar_delete_event_command": + return CalendarDeleteCommandEnabled && this.selected_items_writable; + case "calendar_new_todo_command": + case "calendar_new_todo_context_command": + case "calendar_new_todo_todaypane_command": + case "calendar_toggle_tasks_in_view_command": + return CalendarNewTasksCommandEnabled; + case "calendar_modify_todo_command": + case "calendar_modify_todo_todaypane_command": + return this.todo_items_selected; + // This code is temporarily commented out due to + // bug 469684 Unifinder-todo: raising of the context menu fires blur-event + // this.todo_tasktree_focused; + case "calendar_edit_calendar_command": + return this.isCalendarInForeground(); + case "calendar_task_filter_command": + return true; + case "calendar_delete_todo_command": + if (!CalendarDeleteCommandEnabled) { + return false; + } + // falls through otherwise + case "calendar_toggle_completed_command": + case "calendar_percentComplete-0_command": + case "calendar_percentComplete-25_command": + case "calendar_percentComplete-50_command": + case "calendar_percentComplete-75_command": + case "calendar_percentComplete-100_command": + case "calendar_priority-0_command": + case "calendar_priority-9_command": + case "calendar_priority-5_command": + case "calendar_priority-1_command": + case "calendar_task_category_command": + case "calendar_general-progress_command": + case "calendar_general-priority_command": + case "calendar_general-postpone_command": + case "calendar_postpone-1hour_command": + case "calendar_postpone-1day_command": + case "calendar_postpone-1week_command": + return ( + ((this.isCalendarInForeground() || this.todo_tasktree_focused) && + this.writable && + this.todo_items_selected && + this.todo_items_writable) || + document.getElementById("tabmail").currentTabInfo.mode.type == "calendarTask" + ); + case "calendar_delete_calendar_command": + return this.isCalendarInForeground() && !this.last_calendar; + case "calendar_import_command": + return this.writable; + case "calendar_export_selection_command": + return this.item_selected; + case "calendar_toggle_orientation_command": + return this.isInMode("calendar") && currentView().supportsRotation; + case "calendar_toggle_workdays_only_command": + return this.isInMode("calendar") && currentView().supportsWorkdaysOnly; + case "calendar_publish_selected_events_command": + return this.item_selected; + + case "calendar_reload_remote_calendars": + return this.has_enabled_reloadable_calendars && !this.offline; + case "calendar_attendance_command": { + let attendSel = false; + if (this.todo_tasktree_focused) { + attendSel = + this.writable && + this.todo_items_invitation && + this.todo_items_selected && + this.todo_items_writable; + } else { + attendSel = + this.item_selected && this.selected_events_invitation && this.selected_items_writable; + } + + // Small hack, we want to hide instead of disable. + document.getElementById("calendar_attendance_command").setAttribute("hidden", !attendSel); + return attendSel; + } + + // The following commands all just need the calendar in foreground, + // make sure you take care when changing things here. + case "calendar_view_next_command": + case "calendar_view_prev_command": + case "calendar_in_foreground": + return this.isCalendarInForeground(); + case "calendar_in_background": + return !this.isCalendarInForeground(); + + // The following commands need calendar mode, be careful when + // changing things. + case "calendar_day-view_command": + case "calendar_week-view_command": + case "calendar_multiweek-view_command": + case "calendar_month-view_command": + case "calendar_show_unifinder_command": + case "calendar_mode_calendar": + return this.isInMode("calendar"); + + case "calendar_mode_task": + return this.isInMode("task"); + + case "cmd_selectAll": + return this.todo_tasktree_focused || this.isInMode("calendar"); + + // for events/tasks in a tab + case "cmd_save": + // falls through + case "cmd_accept": { + let tabType = document.getElementById("tabmail").currentTabInfo.mode.type; + return tabType == "calendarTask" || tabType == "calendarEvent"; + } + + default: + if (this.commands.has(aCommand)) { + // All other commands we support should be enabled by default + return true; + } + } + return false; + }, + /* eslint-enable complexity */ + + doCommand(aCommand) { + switch (aCommand) { + // Common Commands + case "calendar_new_event_command": + createEventWithDialog( + getSelectedCalendar(), + cal.dtz.getDefaultStartDate(currentView().selectedDay) + ); + break; + case "calendar_new_event_context_command": { + let newStart = currentView().selectedDateTime; + if (!newStart) { + newStart = cal.dtz.getDefaultStartDate(currentView().selectedDay); + } + createEventWithDialog(getSelectedCalendar(), newStart, null, null, null, newStart.isDate); + break; + } + case "calendar_new_event_todaypane_command": + createEventWithDialog(getSelectedCalendar(), cal.dtz.getDefaultStartDate(TodayPane.start)); + break; + case "calendar_modify_event_command": + editSelectedEvents(); + break; + case "calendar_view_event_command": + viewSelectedEvents(); + break; + case "calendar_modify_focused_item_command": { + let focusedElement = document.commandDispatcher.focusedElement; + if (focusedElement == TodayPane.agenda) { + TodayPane.agenda.editSelectedItem(); + } else if (focusedElement && focusedElement.className == "calendar-task-tree") { + modifyTaskFromContext(); + } else if (this.isInMode("calendar")) { + editSelectedEvents(); + } + break; + } + case "calendar_delete_event_command": + deleteSelectedEvents(); + break; + case "calendar_delete_focused_item_command": { + let focusedElement = document.commandDispatcher.focusedElement; + if (focusedElement == TodayPane.agenda) { + TodayPane.agenda.deleteSelectedItem(false); + } else if (focusedElement && focusedElement.className == "calendar-task-tree") { + deleteToDoCommand(false); + } else if (this.isInMode("calendar")) { + deleteSelectedEvents(); + } + break; + } + case "calendar_new_todo_command": + createTodoWithDialog( + getSelectedCalendar(), + null, + null, + null, + cal.dtz.getDefaultStartDate(currentView().selectedDay) + ); + break; + case "calendar_new_todo_context_command": { + let initialDate = currentView().selectedDateTime; + if (!initialDate || initialDate.isDate) { + initialDate = cal.dtz.getDefaultStartDate(currentView().selectedDay); + } + createTodoWithDialog(getSelectedCalendar(), null, null, null, initialDate); + break; + } + case "calendar_new_todo_todaypane_command": + createTodoWithDialog( + getSelectedCalendar(), + null, + null, + null, + cal.dtz.getDefaultStartDate(TodayPane.start) + ); + break; + case "calendar_delete_todo_command": + deleteToDoCommand(); + break; + case "calendar_modify_todo_command": + modifyTaskFromContext(cal.dtz.getDefaultStartDate(currentView().selectedDay)); + break; + case "calendar_modify_todo_todaypane_command": + modifyTaskFromContext(cal.dtz.getDefaultStartDate(TodayPane.start)); + break; + + case "calendar_new_calendar_command": + cal.window.openCalendarWizard(window); + break; + case "calendar_edit_calendar_command": + cal.window.openCalendarProperties(window, { calendar: getSelectedCalendar() }); + break; + case "calendar_delete_calendar_command": + promptDeleteCalendar(getSelectedCalendar()); + break; + + case "calendar_import_command": + if (Services.prefs.getBoolPref("mail.import.in_new_tab")) { + toImport("calendar"); + } else { + loadEventsFromFile(); + } + break; + case "calendar_export_command": + exportEntireCalendar(); + break; + case "calendar_export_selection_command": + saveEventsToFile(currentView().getSelectedItems()); + break; + + case "calendar_publish_selected_calendar_command": + publishEntireCalendar(getSelectedCalendar()); + break; + case "calendar_publish_calendar_command": + publishEntireCalendar(); + break; + case "calendar_publish_selected_events_command": + publishCalendarData(); + break; + + case "calendar_reload_remote_calendars": + cal.view.getCompositeCalendar(window).refresh(); + break; + case "calendar_show_unifinder_command": + toggleUnifinder(); + break; + case "calendar_view_next_command": + currentView().moveView(1); + break; + case "calendar_view_prev_command": + currentView().moveView(-1); + break; + case "calendar_toggle_orientation_command": + toggleOrientation(); + break; + case "calendar_toggle_workdays_only_command": + toggleWorkdaysOnly(); + break; + + case "calendar_day-view_command": + switchCalendarView("day", true); + break; + case "calendar_week-view_command": + switchCalendarView("week", true); + break; + case "calendar_multiweek-view_command": + switchCalendarView("multiweek", true); + break; + case "calendar_month-view_command": + switchCalendarView("month", true); + break; + case "calendar_attendance_command": + // This command is actually handled inline, since it takes a value + break; + + case "cmd_selectAll": + if (this.todo_tasktree_focused) { + getTaskTree().selectAll(); + } else if (this.isInMode("calendar")) { + selectAllEvents(); + } + break; + } + }, + + onEvent(aEvent) {}, + + isCalendarInForeground() { + return gCurrentMode && gCurrentMode != "mail"; + }, + + isInMode(mode) { + switch (mode) { + case "mail": + return !this.isCalendarInForeground(); + case "calendar": + return gCurrentMode && gCurrentMode == "calendar"; + case "task": + return gCurrentMode && gCurrentMode == "task"; + } + return false; + }, + + onSelectionChanged(aEvent) { + let selectedItems = aEvent.detail; + + calendarUpdateDeleteCommand(selectedItems); + calendarController.item_selected = selectedItems && selectedItems.length > 0; + + let selLength = selectedItems === undefined ? 0 : selectedItems.length; + let selected_events_readonly = 0; + let selected_events_requires_network = 0; + let selected_events_invitation = 0; + + if (selLength > 0) { + for (let item of selectedItems) { + if (item.calendar.readOnly) { + selected_events_readonly++; + } + if ( + item.calendar.getProperty("requiresNetwork") && + !item.calendar.getProperty("cache.enabled") && + !item.calendar.getProperty("cache.always") + ) { + selected_events_requires_network++; + } + + if (cal.itip.isInvitation(item)) { + selected_events_invitation++; + } else if (item.organizer) { + // If we are the organizer and there are attendees, then + // this is likely also an invitation. + let calOrgId = item.calendar.getProperty("organizerId"); + if (item.organizer.id == calOrgId && item.getAttendees().length) { + selected_events_invitation++; + } + } + } + } + + calendarController.selected_events_readonly = selected_events_readonly == selLength; + + calendarController.selected_events_requires_network = + selected_events_requires_network == selLength; + calendarController.selected_events_invitation = selected_events_invitation == selLength; + + calendarController.updateCommands(); + calendarController2.updateCommands(); + document.commandDispatcher.updateCommands("mail-toolbar"); + }, + + /** + * Condition Helpers + */ + + // These attributes will be set up manually. + item_selected: false, + selected_events_readonly: false, + selected_events_requires_network: false, + selected_events_invitation: false, + + /** + * Returns a boolean indicating if its possible to write items to any + * calendar. + */ + get writable() { + return cal.manager.getCalendars().some(cal.acl.isCalendarWritable); + }, + + /** + * Returns a boolean indicating if the application is currently in offline + * mode. + */ + get offline() { + return Services.io.offline; + }, + + /** + * Returns a boolean indicating whether there is at least one enabled + * calendar that can be reloaded. Note: ICS calendars can have a network URL + * or a file URL, but both are reloadable. + */ + get has_enabled_reloadable_calendars() { + return cal.manager + .getCalendars() + .some( + calendar => + !calendar.getProperty("disabled") && + (calendar.type == "ics" || calendar.getProperty("requiresNetwork") !== false) + ); + }, + + /** + * Returns a boolean indicating that there is only one calendar left. + */ + get last_calendar() { + return cal.manager.calendarCount < 2; + }, + + /** + * Returns a boolean indicating that at least one of the items selected + * in the current view has a writable calendar. + */ + get selected_items_writable() { + return ( + this.writable && + this.item_selected && + !this.selected_events_readonly && + (!this.offline || !this.selected_events_requires_network) + ); + }, + + /** + * Returns a boolean indicating that tasks are selected. + */ + get todo_items_selected() { + let selectedTasks = getSelectedTasks(); + return selectedTasks.length > 0; + }, + + get todo_items_invitation() { + let selectedTasks = getSelectedTasks(); + let selected_tasks_invitation = 0; + + for (let item of selectedTasks) { + if (cal.itip.isInvitation(item)) { + selected_tasks_invitation++; + } else if (item.organizer) { + // If we are the organizer and there are attendees, then + // this is likely also an invitation. + let calOrgId = item.calendar.getProperty("organizerId"); + if (item.organizer.id == calOrgId && item.getAttendees().length) { + selected_tasks_invitation++; + } + } + } + + return selectedTasks.length == selected_tasks_invitation; + }, + + /** + * Returns a boolean indicating that at least one task in the selection is + * on a calendar that is writable. + */ + get todo_items_writable() { + let selectedTasks = getSelectedTasks(); + for (let task of selectedTasks) { + if (cal.acl.isCalendarWritable(task.calendar)) { + return true; + } + } + return false; + }, +}; + +/** + * XXX This is a temporary hack so we can release 1.0b2. This will soon be + * superseded by a new command controller architecture. + */ +var calendarController2 = { + commands: new Set([ + "cmd_cut", + "cmd_copy", + "cmd_paste", + "cmd_undo", + "cmd_redo", + "cmd_print", + "button_print", + "button_delete", + "cmd_delete", + "cmd_properties", + "cmd_goForward", + "cmd_goBack", + "cmd_fullZoomReduce", + "cmd_fullZoomEnlarge", + "cmd_fullZoomReset", + "cmd_showQuickFilterBar", + ]), + + // These functions can use the same from the calendar controller for now. + updateCommands: calendarController.updateCommands, + supportsCommand: calendarController.supportsCommand, + onEvent: calendarController.onEvent, + + isCommandEnabled(aCommand) { + switch (aCommand) { + // Thunderbird Commands + case "cmd_cut": + return calendarController.selected_items_writable; + case "cmd_copy": + return calendarController.item_selected; + case "cmd_paste": + return canPaste(); + case "cmd_undo": + goSetMenuValue(aCommand, "valueDefault"); + return canUndo(); + case "cmd_redo": + goSetMenuValue(aCommand, "valueDefault"); + return canRedo(); + case "button_delete": + case "cmd_delete": + return calendarController.isCommandEnabled("calendar_delete_focused_item_command"); + case "cmd_fullZoomReduce": + case "cmd_fullZoomEnlarge": + case "cmd_fullZoomReset": + return calendarController.isInMode("calendar") && currentView().supportsZoom; + case "cmd_properties": + return false; + case "cmd_showQuickFilterBar": + return calendarController.isInMode("task"); + default: + return true; + } + }, + + doCommand(aCommand) { + if (!this.isCommandEnabled(aCommand)) { + // doCommand is triggered for cmd_cut even if the command is disabled + // so we bail out here + return; + } + switch (aCommand) { + case "cmd_cut": + cutToClipboard(); + break; + case "cmd_copy": + copyToClipboard(); + break; + case "cmd_paste": + pasteFromClipboard(); + break; + case "cmd_undo": + undo(); + break; + case "cmd_redo": + redo(); + break; + case "button_print": + case "cmd_print": + printCalendar(); + break; + // Thunderbird commands + case "cmd_goForward": + currentView().moveView(1); + break; + case "cmd_goBack": + currentView().moveView(-1); + break; + case "cmd_fullZoomReduce": + currentView().zoomIn(); + break; + case "cmd_fullZoomEnlarge": + currentView().zoomOut(); + break; + case "cmd_fullZoomReset": + currentView().zoomReset(); + break; + case "cmd_showQuickFilterBar": + document.getElementById("task-text-filter-field").select(); + break; + + case "button_delete": + case "cmd_delete": + calendarController.doCommand("calendar_delete_focused_item_command"); + break; + } + }, +}; + +/** + * Inserts the command controller into the document. Make sure that it is + * inserted before the conflicting Thunderbird command controller. + */ +function injectCalendarCommandController() { + // This is the third-highest priority controller. It's preceded by + // DefaultController and tabmail.tabController, and followed by + // calendarController, then whatever Gecko adds. + top.controllers.insertControllerAt(2, calendarController); + document.commandDispatcher.updateCommands("calendar_commands"); +} + +/** + * Remove the calendar command controller from the document. + */ +function removeCalendarCommandController() { + top.controllers.removeController(calendarController); +} + +/** + * Handler function to set up the item context menu, depending on the given + * items. Changes the delete menuitem to fit the passed items. + * + * @param {DOMEvent} aEvent The DOM popupshowing event that is + * triggered by opening the context menu + * @param {Array.<calIItemBase>} aItems An array of items (usually the selected + * items) to adapt the context menu for + * @returns {boolean} True, to show the popup menu. + */ +function setupContextItemType(aEvent, aItems) { + function adaptModificationMenuItem(aMenuItemId, aItemType) { + let menuItem = document.getElementById(aMenuItemId); + if (menuItem) { + menuItem.setAttribute("label", cal.l10n.getCalString(`delete${aItemType}Label`)); + menuItem.setAttribute("accesskey", cal.l10n.getCalString(`delete${aItemType}Accesskey`)); + } + } + if (aItems.some(item => item.isEvent()) && aItems.some(item => item.isTodo())) { + aEvent.target.setAttribute("type", "mixed"); + adaptModificationMenuItem("calendar-item-context-menu-delete-menuitem", "Item"); + } else if (aItems.length && aItems[0].isEvent()) { + aEvent.target.setAttribute("type", "event"); + adaptModificationMenuItem("calendar-item-context-menu-delete-menuitem", "Event"); + } else if (aItems.length && aItems[0].isTodo()) { + aEvent.target.setAttribute("type", "todo"); + adaptModificationMenuItem("calendar-item-context-menu-delete-menuitem", "Task"); + } else { + aEvent.target.removeAttribute("type"); + adaptModificationMenuItem("calendar-item-context-menu-delete-menuitem", "Item"); + } + + let menu = document.getElementById("calendar-item-context-menu-attendance-menu"); + setupAttendanceMenu(menu, aItems); + return true; +} + +/** + * Tests whether the items currently selected can be edited in the event dialog. + * Invitations are not considered editable here. + */ +function canEditSelectedItems() { + let items = currentView().getSelectedItems(); + return items.every(item => { + let calendar = item.calendar; + return ( + cal.acl.isCalendarWritable(calendar) && + cal.acl.userCanModifyItem(item) && + calendar.supportsScheduling && + !calendar.getSchedulingSupport().isInvitation(item) + ); + }); +} + +/** + * Returns the selected items, based on which mode we are currently in and what task tree is focused. + */ +function getSelectedItems() { + if (calendarController.todo_tasktree_focused) { + return getSelectedTasks(); + } + + return currentView().getSelectedItems(); +} + +/** + * Deletes the selected items, based on which mode we are currently in and what task tree is focused + */ +function deleteSelectedItems() { + if (calendarController.todo_tasktree_focused) { + deleteToDoCommand(); + } else if (calendarController.isInMode("calendar")) { + deleteSelectedEvents(); + } +} + +/** + * Checks if any calendar allows new events and tasks to be added, otherwise + * disables the creation buttons. + */ +function calendarUpdateNewItemsCommand() { + // Re-calculate command status. + let calendars = cal.manager + .getCalendars() + .filter(cal.acl.isCalendarWritable) + .filter(cal.acl.userCanAddItemsToCalendar); + + CalendarNewEventsCommandEnabled = calendars.some(cal.item.isEventCalendar); + CalendarNewTasksCommandEnabled = calendars.some(cal.item.isTaskCalendar); + + [ + "calendar_new_event_command", + "calendar_new_event_context_command", + "calendar_new_event_todaypane_command", + "calendar_new_todo_command", + "calendar_new_todo_context_command", + "calendar_new_todo_todaypane_command", + "calendar_toggle_tasks_in_view_command", + ].forEach(goUpdateCommand); + + document.getElementById("sidePanelNewEvent").disabled = !CalendarNewEventsCommandEnabled; + document.getElementById("sidePanelNewTask").disabled = !CalendarNewTasksCommandEnabled; +} + +function calendarUpdateDeleteCommand(selectedItems) { + let oldValue = CalendarDeleteCommandEnabled; + CalendarDeleteCommandEnabled = selectedItems.length > 0; + + /* we must disable "delete" when at least one item cannot be deleted */ + for (let item of selectedItems) { + if (!cal.acl.userCanDeleteItemsFromCalendar(item.calendar)) { + CalendarDeleteCommandEnabled = false; + break; + } + } + + if (CalendarDeleteCommandEnabled != oldValue) { + [ + "calendar_delete_event_command", + "calendar_delete_todo_command", + "calendar_delete_focused_item_command", + "button_delete", + "cmd_delete", + ].forEach(goUpdateCommand); + } +} + +/** + * Loads the printing template into a hidden browser then starts the printing + * process for that browser. + */ +async function printCalendar() { + // Ensure the printing of this file will be detected by calPrintUtils.jsm. + cal.print.ensureInitialized(); + + await PrintUtils.loadPrintBrowser("chrome://calendar/content/printing-template.html"); + PrintUtils.startPrintWindow(PrintUtils.printBrowser.browsingContext, {}); +} +/** + * Toggle the visibility of the calendars list. + * + * @param {Event} event - The click DOMEvent. + */ +function toggleVisibilityCalendarsList(event) { + document.getElementById("calendar-list-inner-pane").togglePane(event); +} |