diff options
Diffstat (limited to 'comm/calendar/base/content/calendar-task-tree-utils.js')
-rw-r--r-- | comm/calendar/base/content/calendar-task-tree-utils.js | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/comm/calendar/base/content/calendar-task-tree-utils.js b/comm/calendar/base/content/calendar-task-tree-utils.js new file mode 100644 index 0000000000..92dcb8513c --- /dev/null +++ b/comm/calendar/base/content/calendar-task-tree-utils.js @@ -0,0 +1,341 @@ +/* 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/. */ + +/* exported addCalendarNames, calendars, changeContextMenuForTask, + * contextChangeTaskCalendar, contextChangeTaskPriority, + * contextPostponeTask, modifyTaskFromContext, deleteToDoCommand, + * tasksToMail, tasksToEvents, toggleCompleted, + */ + +/* import-globals-from ../../../mail/base/content/globalOverlay.js */ +/* import-globals-from item-editing/calendar-item-editing.js */ +/* import-globals-from item-editing/calendar-item-panel.js */ +/* import-globals-from calendar-command-controller.js */ +/* import-globals-from calendar-dnd-listener.js */ +/* import-globals-from calendar-ui-utils.js */ +/* import-globals-from calendar-views-utils.js */ + +var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm"); + +/** + * Add registered calendars to the given menupopup. Removes all previous + * children. + * + * @param aEvent The popupshowing event of the opening menu + */ +function addCalendarNames(aEvent) { + let calendarMenuPopup = aEvent.target; + while (calendarMenuPopup.hasChildNodes()) { + calendarMenuPopup.lastChild.remove(); + } + let tasks = getSelectedTasks(); + let tasksSelected = tasks.length > 0; + if (tasksSelected) { + let selIndex = appendCalendarItems( + tasks[0], + calendarMenuPopup, + null, + "contextChangeTaskCalendar(event);" + ); + if (tasks.every(task => task.calendar == tasks[0].calendar) && selIndex > -1) { + calendarMenuPopup.children[selIndex].setAttribute("checked", "true"); + } + } +} + +/** + * For each child of an element (for example all menuitems in a menu), if it defines a command + * set an attribute on the command, otherwise set it on the child node itself. + * + * @param aAttribute {string} - The attribute to set. + * @param aValue {boolean|string} - The value to set. + * @param aElement {Element} - The parent node. + */ +function setAttributeOnChildrenOrTheirCommands(aAttribute, aValue, aElement) { + for (let child of aElement.children) { + const commandName = child.getAttribute("command"); + const command = commandName && document.getElementById(commandName); + + const domObject = command || child; + domObject.setAttribute(aAttribute, aValue); + } +} + +/** + * Change the opening context menu for the selected tasks. + * + * @param aEvent The popupshowing event of the opening menu. + */ +function changeContextMenuForTask(aEvent) { + if (aEvent.target.id !== "taskitem-context-menu") { + return; + } + + handleTaskContextMenuStateChange(aEvent); + + const treeNodeId = aEvent.target.triggerNode.closest(".calendar-task-tree").id; + const isTodaypane = treeNodeId == "unifinder-todo-tree"; + const isMainTaskTree = treeNodeId == "calendar-task-tree"; + + document.getElementById("task-context-menu-new").hidden = isTodaypane; + document.getElementById("task-context-menu-modify").hidden = isTodaypane; + document.getElementById("task-context-menu-new-todaypane").hidden = isMainTaskTree; + document.getElementById("task-context-menu-modify-todaypane").hidden = isMainTaskTree; + document.getElementById("task-context-menu-filter-todaypane").hidden = isMainTaskTree; + document.getElementById("task-context-menu-separator-filter").hidden = isMainTaskTree; + + let items = getSelectedTasks(); + let tasksSelected = items.length > 0; + + setAttributeOnChildrenOrTheirCommands("disabled", !tasksSelected, aEvent.target); + + if ( + calendarController.isCommandEnabled("calendar_new_todo_command") && + calendarController.isCommandEnabled("calendar_new_todo_todaypane_command") + ) { + document.getElementById("calendar_new_todo_command").removeAttribute("disabled"); + document.getElementById("calendar_new_todo_todaypane_command").removeAttribute("disabled"); + } else { + document.getElementById("calendar_new_todo_command").setAttribute("disabled", "true"); + document.getElementById("calendar_new_todo_todaypane_command").setAttribute("disabled", "true"); + } + + // make sure the "Paste" and "Cut" menu items are enabled + goUpdateCommand("cmd_paste"); + goUpdateCommand("cmd_cut"); + + // make sure the filter menu is enabled + document.getElementById("task-context-menu-filter-todaypane").removeAttribute("disabled"); + + setAttributeOnChildrenOrTheirCommands( + "disabled", + false, + document.getElementById("task-context-menu-filter-todaypane-popup") + ); + + changeMenuForTask(); + + let menu = document.getElementById("task-context-menu-attendance-menu"); + setupAttendanceMenu(menu, items); +} + +/** + * Notify the task tree that the context menu open state has changed. + * + * @param aEvent The popupshowing or popuphiding event of the menu. + */ +function handleTaskContextMenuStateChange(aEvent) { + if (aEvent.target.id !== "taskitem-context-menu") { + return; + } + + let tree = aEvent.target.triggerNode.closest(".calendar-task-tree"); + + if (tree) { + tree.updateFocus(); + } +} + +/** + * Change the opening menu for the selected tasks. + */ +function changeMenuForTask() { + // Make sure to update the status of some commands. + let commands = [ + "calendar_delete_todo_command", + "calendar_toggle_completed_command", + "calendar_general-progress_command", + "calendar_general-priority_command", + "calendar_general-postpone_command", + ]; + commands.forEach(goUpdateCommand); + + let tasks = getSelectedTasks(); + let tasksSelected = tasks.length > 0; + if (tasksSelected) { + let cmd = document.getElementById("calendar_toggle_completed_command"); + if (tasks.every(task => task.isCompleted == tasks[0].isCompleted)) { + cmd.checked = tasks[0].isCompleted; + } else { + cmd.checked = false; + } + } +} + +/** + * Handler function to change the progress of all selected tasks, or of + * the task loaded in the current tab. + * + * @param {short} aProgress - The new progress percentage + */ +function contextChangeTaskProgress(aProgress) { + if (gTabmail && gTabmail.currentTabInfo.mode.type == "calendarTask") { + editToDoStatus(aProgress); + } else { + startBatchTransaction(); + let tasks = getSelectedTasks(); + for (let task of tasks) { + let newTask = task.clone().QueryInterface(Ci.calITodo); + newTask.percentComplete = aProgress; + switch (aProgress) { + case 0: + newTask.isCompleted = false; + break; + case 100: + newTask.isCompleted = true; + break; + default: + newTask.status = "IN-PROCESS"; + newTask.completedDate = null; + break; + } + doTransaction("modify", newTask, newTask.calendar, task, null); + } + endBatchTransaction(); + } +} + +/** + * Handler function to change the calendar of the selected tasks. The targeted + * menuitem must have "calendar" property that implements calICalendar. + * + * @param aEvent The DOM event that triggered this command. + */ +function contextChangeTaskCalendar(aEvent) { + startBatchTransaction(); + let tasks = getSelectedTasks(); + for (let task of tasks) { + let newTask = task.clone(); + newTask.calendar = aEvent.target.calendar; + doTransaction("modify", newTask, newTask.calendar, task, null); + } + endBatchTransaction(); +} + +/** + * Handler function to change the priority of the selected tasks, or of + * the task loaded in the current tab. + * + * @param {short} aPriority - The priority to set on the task(s) + */ +function contextChangeTaskPriority(aPriority) { + let tabType = gTabmail && gTabmail.currentTabInfo.mode.type; + if (tabType == "calendarTask" || tabType == "calendarEvent") { + editConfigState({ priority: aPriority }); + } else { + startBatchTransaction(); + let tasks = getSelectedTasks(); + for (let task of tasks) { + let newTask = task.clone().QueryInterface(Ci.calITodo); + newTask.priority = aPriority; + doTransaction("modify", newTask, newTask.calendar, task, null); + } + endBatchTransaction(); + } +} + +/** + * Handler function to postpone the start and due dates of the selected + * tasks, or of the task loaded in the current tab. ISO 8601 format: + * "PT1H", "P1D", and "P1W" are 1 hour, 1 day, and 1 week. (We use this + * format intentionally instead of a calIDuration object because those + * objects cannot be serialized for message passing with iframes.) + * + * @param {string} aDuration - The duration to postpone in ISO 8601 format + */ +function contextPostponeTask(aDuration) { + let duration = cal.createDuration(aDuration); + if (!duration) { + cal.LOG("[calendar-task-tree] Postpone Task - Invalid duration " + aDuration); + return; + } + + if (gTabmail && gTabmail.currentTabInfo.mode.type == "calendarTask") { + postponeTask(aDuration); + } else { + startBatchTransaction(); + let tasks = getSelectedTasks(); + + tasks.forEach(task => { + if (task.entryDate || task.dueDate) { + let newTask = task.clone(); + cal.item.shiftOffset(newTask, duration); + doTransaction("modify", newTask, newTask.calendar, task, null); + } + }); + + endBatchTransaction(); + } +} + +/** + * Modifies the selected tasks with the event dialog + * + * @param initialDate (optional) The initial date for new task datepickers + */ +function modifyTaskFromContext(initialDate) { + let tasks = getSelectedTasks(); + for (let task of tasks) { + modifyEventWithDialog(task, true, initialDate); + } +} + +/** + * Delete the current selected item with focus from the task tree + * + * @param aDoNotConfirm If true, the user will not be asked to delete. + */ +function deleteToDoCommand(aDoNotConfirm) { + let tasks = getSelectedTasks(); + calendarViewController.deleteOccurrences(tasks, false, aDoNotConfirm); +} + +/** + * Gets the currently visible task tree + * + * @returns The XUL task tree element. + */ +function getTaskTree() { + if (gCurrentMode == "task") { + return document.getElementById("calendar-task-tree"); + } + return document.getElementById("unifinder-todo-tree"); +} + +/** + * Gets the tasks selected in the currently visible task tree. + */ +function getSelectedTasks() { + let taskTree = getTaskTree(); + return taskTree ? taskTree.selectedTasks : []; +} + +/** + * Convert selected tasks to emails. + */ +function tasksToMail() { + let tasks = getSelectedTasks(); + calendarMailButtonDNDObserver.onDropItems(tasks); +} + +/** + * Convert selected tasks to events. + */ +function tasksToEvents() { + let tasks = getSelectedTasks(); + calendarCalendarButtonDNDObserver.onDropItems(tasks); +} + +/** + * Toggle the completed state on selected tasks. + * + * @param aEvent The originating event, can be null. + */ +function toggleCompleted(aEvent) { + if (aEvent.target.getAttribute("checked") == "true") { + contextChangeTaskProgress(0); + } else { + contextChangeTaskProgress(100); + } +} |