UNPKG

bardelman-dhtmlx-gantt-redux

Version:

An open source JavaScript Gantt chart that helps you illustrate a project schedule in a nice-looking chart.

589 lines (508 loc) 15 kB
<!DOCTYPE html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <title>Context menu to control tasks</title> <script src="https://cdn.dhtmlx.com/suite/8.3/suite.js?v=9.0.10"></script> <script src="../../codebase/dhtmlxgantt.js?v=9.0.10"></script> <link rel="stylesheet" href="../../codebase/dhtmlxgantt.css?v=9.0.10"> <link rel="stylesheet" href="https://cdn.dhtmlx.com/suite/8.3/suite.css?v=9.0.10"> <script src="../common/testdata.js?v=9.0.10"></script> <style> html, body { height: 100%; padding: 0px; margin: 0px; overflow: hidden; } .task_to_cut.gantt_row, .task_to_cut.gantt_row.odd, .task_to_cut.gantt_task_line { opacity: 0.5; } .task_to_copy.gantt_row, .task_to_copy.gantt_row.odd, .task_to_copy.gantt_task_line { border: 2px dotted LightSkyBlue; } </style> </head> <body> <div id="gantt_here" style='width:100%; height:100%'></div> <div id="context"></div> <script> let contextMenu = new dhx.ContextMenu(null, { css: "dhx_widget--bg_gray" }); let targetId, clickDate; gantt.attachEvent("onContextMenu", function (taskId, linkId, event) { itemsConfig = null; if (taskId) { const task = gantt.getTask(taskId); const isTaskBar = event.target.closest(".gantt_task_line"); const isParentTask = gantt.hasChild(task.id); const isSplitTask = task.render === "split"; const barHidden = task.hide_bar; let hasSplitParent = false; if (task.parent) { const parent = gantt.getTask(task.parent); hasSplitParent = parent.render === "split"; } itemsConfig = { isTaskBar, isParentTask, isSplitTask, barHidden, hasSplitParent }; } targetId = taskId; contextMenu.data.removeAll(); contextMenu.data.parse(generateMenuItems(itemsConfig)); contextMenu.showAt(event); const clickPosition = gantt.utils.dom.getRelativeEventPosition(event, gantt.$task_data).x; clickDate = gantt.dateFromPos(clickPosition) return false; }); contextMenu.events.on("click", function (id, e) { applyCommand(id, event); targetId = null; }); contextMenu.events.on("beforeHide", function (id, event) { return event.type === "click"; }); // Context menu commands function applyCommand(command, event) { let task; if (targetId) { task = gantt.getTask(targetId); } switch (command) { case "add_sibling_above": gantt.createTask({ id: gantt.uid(), text: "New task", start_date: task.start_date, duration: 1 }, task.parent, gantt.getTaskIndex(task.id)); break; case "add_sibling_below": gantt.createTask({ id: gantt.uid(), text: "New task", start_date: task.start_date, duration: 1 }, task.parent, gantt.getTaskIndex(task.id) + 1); break; case "add_subtask_top": gantt.createTask({ id: gantt.uid(), text: "New subtask", start_date: task.start_date, duration: 1 }, task.id, 0); break; case "add_subtask_bottom": gantt.createTask({ id: gantt.uid(), text: "New subtask", start_date: task.start_date, duration: 1 }, task.id); break; case "edit": gantt.showLightbox(task.id); break; case "delete": gantt.confirm({ text: "Delete task?", ok: "Yes", cancel: "No", callback: function (result) { if (result && gantt.isTaskExists(task.id)) { gantt.deleteTask(task.id); } } }); break; case "indent": const prevId = gantt.getPrevSibling(task.id); if (prevId) { const newParent = gantt.getTask(prevId); gantt.moveTask(task.id, gantt.getChildren(newParent.id).length, newParent.id); newParent.type = gantt.config.types.project; newParent.$open = true; gantt.updateTask(task.id); gantt.updateTask(newParent.id); return task.id; } break; case "outdent": const oldParent = task.parent; if (gantt.isTaskExists(oldParent) && oldParent != gantt.config.root_id) { var index = gantt.getTaskIndex(oldParent) + 1; gantt.moveTask(task.id, index, gantt.getParent(task.parent)); if (!gantt.hasChild(oldParent)) { gantt.getTask(oldParent).type = gantt.config.types.task; } gantt.updateTask(task.id); gantt.updateTask(oldParent); return task.id; } break; case "type_task": task.type = "task"; task.duration = task.duration || 1; task.end_date = gantt.calculateEndDate(task); gantt.updateTask(task.id); break; case "type_project": task.type = "project"; gantt.updateTask(task.id); break; case "type_milestone": task.type = "milestone"; gantt.updateTask(task.id); break; case "rollup": task.rollup = !task.rollup; gantt.updateTask(task.id); gantt.updateTask(task.parent); break; case "hide_bar": task.hide_bar = !task.hide_bar; gantt.updateTask(task.id); break; case "hide_row": hiddenTasks[task.id] = true; gantt.updateTask(task.id); break; case "show_hidden": hiddenTasks = {}; gantt.render(); break; case "complete": task.progress = 1; gantt.updateTask(task.id); break; case "cut": const copyIndex = tasksToCopy.indexOf(task.id) > -1; if (copyIndex) { tasksToCopy.splice(copyIndex, 1) } // exclude duplicates if (tasksToCut.indexOf(task.id) === -1) { tasksToCut.push(task.id); } gantt.refreshTask(task.id); break; case "copy": const cutIndex = tasksToCut.indexOf(task.id) > -1; if (cutIndex) { tasksToCut.splice(cutIndex, 1) } // exclude duplicates if (tasksToCopy.indexOf(task.id) === -1) { tasksToCopy.push(task.id); } gantt.refreshTask(task.id); break; case "paste_sibling": pasteTasks(task.parent, gantt.getTaskIndex(task.id) + 1); break; case "paste_child": pasteTasks(task.id); break; case "cancel_paste": tasksToCopy = []; tasksToCut = []; gantt.render(); break; case "split": gantt.batchUpdate(function () { if (gantt.hasChild(task.id)) { gantt.message("The task already has children, so, it won't be split to new sub tasks"); return; } const leftChild = gantt.copy(task); leftChild.id = gantt.uid(); leftChild.end_date = new Date(clickDate); leftChild.parent = task.id; leftChild.type = "task"; const rightChild = gantt.copy(task); rightChild.id = gantt.uid(); rightChild.start_date = new Date(clickDate) rightChild.parent = task.id; rightChild.type = "task"; task.render = 'split'; task.type = "project"; gantt.updateTask(task.id); gantt.close(task.id); gantt.addTask(leftChild); gantt.addTask(rightChild); }) break; case "unsplit": unsplit(task) break; case "unsplit_parent": const parent = gantt.getTask(task.parent); unsplit(parent) break; } function unsplit(task) { gantt.batchUpdate(function () { gantt.eachTask(function (child) { if (gantt.isTaskExists(child.id)) { gantt.deleteTask(child.id); } }, task.id) delete task.render; task.type = "task"; gantt.updateTask(task.id); }) } } // hide/filter tasks let hiddenTasks = {}; gantt.attachEvent("onBeforeTaskDisplay", function (id, task) { return !hiddenTasks[task.id] }); // copy/cut + paste implementation let tasksToCopy = []; let tasksToCut = []; function pasteTasks(parentId, index) { gantt.batchUpdate(function () { tasksToCopy.forEach(function (id) { const task = gantt.getTask(id); const clone = gantt.copy(task); clone.id = gantt.uid(); gantt.addTask(clone, parentId, index); }); tasksToCut.forEach(function (id) { gantt.moveTask(id, index, parentId); }); gantt.open(parentId); tasksToCopy = []; tasksToCut = []; }) } gantt.templates.grid_row_class = gantt.templates.task_class = function (start, end, task) { if (tasksToCopy.indexOf(task.id) > -1) { return "task_to_copy" } if (tasksToCut.indexOf(task.id) > -1) { return "task_to_cut" } return ""; }; function generateMenuItems(config) { const cancelCopyCut = { icon: "dxi dxi-close", type: "menuItem", id: "cancel_paste", value: "Cancel copy/cut operation", }; const showAllHidden = { icon: "dxi dxi-eye", type: "menuItem", id: "show_hidden", value: "Show all hidden tasks", }; if (config) { let hideBar = { icon: "dxi dxi-eye-off", type: "menuItem", id: "hide_bar", value: "Hide task bar", }; if (config.barHidden) { hideBar = { icon: "dxi dxi-eye", type: "menuItem", id: "hide_bar", value: "Show task bar", }; } const pasteSibling = { icon: "dxi dxi-chevron-down", type: "menuItem", id: "paste_sibling", value: "Paste as sibling", } const pasteChild = { icon: "dxi dxi-format-vertical-align-bottom", type: "menuItem", id: "paste_child", value: "Paste as child", } if (tasksToCopy.length + tasksToCut.length > 1){ pasteSibling.value += "s"; pasteChild.value += "ren"; } const menuItems = [ { type: "menuItem", id: "crud", icon: "dxi dxi-pencil", value: "Create/Update/Delete", items: [ { icon: "dxi dxi-chevron-up", type: "menuItem", id: "add_sibling_above", value: "Add sibling above", }, { icon: "dxi dxi-chevron-down", type: "menuItem", id: "add_sibling_below", value: "Add sibling below", }, { icon: "dxi dxi-format-vertical-align-top", type: "menuItem", id: "add_subtask_top", value: "Add subtask at the top", }, { icon: "dxi dxi-format-vertical-align-bottom", type: "menuItem", id: "add_subtask_bottom", value: "Add subtask at the bottom", }, { icon: "dxi dxi-pencil", type: "menuItem", id: "edit", value: "Edit task", }, { icon: "dxi dxi-delete-forever", type: "menuItem", id: "delete", value: "Delete Task", }, ] }, { type: "menuItem", id: "copy_paste", icon: "dxi dxi-file-outline", value: "Copy/Paste", items: [ { icon: "dxi dxi-file-excel", type: "menuItem", id: "cut", value: "Cut", }, { icon: "dxi dxi-file-import", type: "menuItem", id: "copy", value: "Copy", }, pasteSibling, pasteChild, cancelCopyCut, ] }, { type: "menuItem", icon: "dxi dxi-format-align-center", id: "change_level", value: "Change tree level", items: [ { icon: "dxi dxi-format-align-right", type: "menuItem", id: "indent", value: "Indent Task", }, { icon: "dxi dxi-format-align-left", type: "menuItem", id: "outdent", value: "Outdent task", }, ] }, { type: "menuItem", id: "change_type", value: "Change task type", icon: "dxi dxi-filter-variant", items: [ { icon: "dxi dxi-minus", type: "menuItem", id: "type_task", value: "Task type", }, { icon: "dxi dxi-filter-variant", type: "menuItem", id: "type_project", value: "Project type", }, { icon: "dxi dxi-format-color-fill", type: "menuItem", id: "type_milestone", value: "Milestone type", }, ] }, { type: "menuItem", id: "hide", icon: "dxi dxi dxi-eye", value: "Change visibility", items: [ { icon: "dxi dxi-format-vertical-align-top", type: "menuItem", id: "rollup", value: "Rollup", }, hideBar, { icon: "dxi dxi-eye-off", type: "menuItem", id: "hide_row", value: "Hide task row", }, showAllHidden, ] }, { icon: "dxi dxi-checkbox-marked-circle", type: "menuItem", id: "complete", value: "Mark as complete", }, ]; if (config.isSplitTask) { menuItems.push({ type: "menuItem", id: "unsplit", icon: "dxi dxi-table-row-remove", value: "Unsplit task", }) } if (config.hasSplitParent) { menuItems.push({ type: "menuItem", id: "unsplit_parent", icon: "dxi dxi-table-row-remove", value: "Unsplit parent", }) } if (config.isTaskBar && !config.isParentTask) { menuItems.push({ type: "menuItem", id: "split", icon: "dxi dxi-table-row", value: "Split task", }) } return menuItems; } else { const menuItems = []; if (tasksToCopy.length + tasksToCut.length > 1){ menuItems.push(cancelCopyCut); } if (Object.keys(hiddenTasks).length){ menuItems.push(showAllHidden); } return menuItems; } } gantt.config.open_split_tasks = true; gantt.config.round_dnd_dates = false; // Prevent task shrink after drag if their duration is 0 gantt.attachEvent("onTaskDrag", function(id, mode, task, original){ task.duration = task.duration || 1 }); gantt.init("gantt_here"); gantt.parse(demo_tasks); gantt.message({ text: "This example uses DHTMLX Suite's Context menu which can be used under GPLv2 license or has to be obtained separately. <br><br> You can do this or use a third-party context-menu widget instead.", expire: 1000 * 30 }); </script> </body>