summaryrefslogtreecommitdiffstats
path: root/comm/calendar/base/content/calendar-task-tree-utils.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/calendar/base/content/calendar-task-tree-utils.js')
-rw-r--r--comm/calendar/base/content/calendar-task-tree-utils.js341
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);
+ }
+}