UNPKG

dhtmlx-gantt

Version:

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

1,359 lines (1,353 loc) 1.08 MB
(function(global2, factory) { typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, factory(global2.dhtmlxgantt = {})); })(this, function(exports2) { "use strict";/** @license dhtmlxGantt v.9.0.11 Standard This version of dhtmlxGantt is distributed under GPL 2.0 license and can be legally used in GPL projects. To use dhtmlxGantt in non-GPL projects (and get Pro version of the product), please obtain Individual, Commercial, Enterprise or Ultimate license on our site https://dhtmlx.com/docs/products/dhtmlxGantt/#licensing or contact us at info@dhtmlx.com (c) XB Software */ function getNodePosition(elem) { var top = 0, left = 0, right = 0, bottom = 0; if (elem.getBoundingClientRect) { var box = elem.getBoundingClientRect(); var body = document.body; var docElem = document.documentElement || document.body.parentNode || document.body; var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop; var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft; var clientTop = docElem.clientTop || body.clientTop || 0; var clientLeft = docElem.clientLeft || body.clientLeft || 0; top = box.top + scrollTop - clientTop; left = box.left + scrollLeft - clientLeft; right = document.body.offsetWidth - box.right; bottom = document.body.offsetHeight - box.bottom; } else { while (elem) { top = top + parseInt(elem.offsetTop, 10); left = left + parseInt(elem.offsetLeft, 10); elem = elem.offsetParent; } right = document.body.offsetWidth - elem.offsetWidth - left; bottom = document.body.offsetHeight - elem.offsetHeight - top; } return { y: Math.round(top), x: Math.round(left), width: elem.offsetWidth, height: elem.offsetHeight, right: Math.round(right), bottom: Math.round(bottom) }; } function isVisible(node) { var display = false, visibility = false; if (window.getComputedStyle) { var style = window.getComputedStyle(node, null); display = style["display"]; visibility = style["visibility"]; } else if (node.currentStyle) { display = node.currentStyle["display"]; visibility = node.currentStyle["visibility"]; } return display != "none" && visibility != "hidden"; } function hasNonNegativeTabIndex(node) { return !isNaN(node.getAttribute("tabindex")) && node.getAttribute("tabindex") * 1 >= 0; } function hasHref(node) { var canHaveHref = { a: true, area: true }; if (canHaveHref[node.nodeName.loLowerCase()]) { return !!node.getAttribute("href"); } return true; } function isEnabled(node) { var canDisable = { input: true, select: true, textarea: true, button: true, object: true }; if (canDisable[node.nodeName.toLowerCase()]) { return !node.hasAttribute("disabled"); } return true; } function getFocusableNodes(root) { var nodes = root.querySelectorAll(["a[href]", "area[href]", "input", "select", "textarea", "button", "iframe", "object", "embed", "[tabindex]", "[contenteditable]"].join(", ")); var nodesArray = Array.prototype.slice.call(nodes, 0); for (var i = 0; i < nodesArray.length; i++) { nodesArray[i].$position = i; } nodesArray.sort(function(a, b) { if (a.tabIndex === 0 && b.tabIndex !== 0) { return 1; } if (a.tabIndex !== 0 && b.tabIndex === 0) { return -1; } if (a.tabIndex === b.tabIndex) { return a.$position - b.$position; } if (a.tabIndex < b.tabIndex) { return -1; } return 1; }); for (var i = 0; i < nodesArray.length; i++) { var node = nodesArray[i]; var isValid = (hasNonNegativeTabIndex(node) || isEnabled(node) || hasHref(node)) && isVisible(node); if (!isValid) { nodesArray.splice(i, 1); i--; } } return nodesArray; } function getScrollSize() { var div = document.createElement("div"); div.style.cssText = "visibility:hidden;position:absolute;left:-1000px;width:100px;padding:0px;margin:0px;height:110px;min-height:100px;overflow-y:scroll;"; document.body.appendChild(div); var width = div.offsetWidth - div.clientWidth; document.body.removeChild(div); return Math.max(width, 15); } function getClassName(node) { if (!node) return ""; var className = node.className || ""; if (className.baseVal) className = className.baseVal; if (!className.indexOf) className = ""; return _trimString(className); } function addClassName(node, className) { if (className && node.className.indexOf(className) === -1) { node.className += " " + className; } } function removeClassName(node, name) { name = name.split(" "); for (var i = 0; i < name.length; i++) { var regEx = new RegExp("\\s?\\b" + name[i] + "\\b(?![-_.])", ""); node.className = node.className.replace(regEx, ""); } } function hasClass(element, className) { if ("classList" in element) { return element.classList.contains(className); } else { return new RegExp("\\b" + className + "\\b").test(element.className); } } function toNode(node) { if (typeof node === "string") { return document.getElementById(node) || document.querySelector(node) || document.body; } return node || document.body; } var _slave; function insertNode(node, newone) { if (!_slave) { _slave = document.createElement("div"); } _slave.innerHTML = newone; var child = _slave.firstChild; node.appendChild(child); return child; } function removeNode(node) { if (node && node.parentNode) { node.parentNode.removeChild(node); } } function getChildNodes(node, css) { var ch = node.childNodes; var len = ch.length; var out = []; for (var i = 0; i < len; i++) { var obj = ch[i]; if (obj.className && obj.className.indexOf(css) !== -1) { out.push(obj); } } return out; } function getTargetNode(e) { var trg; if (e.tagName) trg = e; else { e = e || window.event; trg = e.target || e.srcElement; if (trg.shadowRoot && e.composedPath) { trg = e.composedPath()[0]; } } return trg; } function locateAttribute(e, attribute) { if (!attribute) return; var trg = getTargetNode(e); while (trg) { if (trg.getAttribute) { var test = trg.getAttribute(attribute); if (test) return trg; } trg = trg.parentNode; } return null; } function _trimString(str) { var func = String.prototype.trim || function() { return this.replace(/^\s+|\s+$/g, ""); }; return func.apply(str); } function locateClassName(e, classname, strict) { var trg = getTargetNode(e); var css = ""; if (strict === void 0) strict = true; while (trg) { css = getClassName(trg); if (css) { var ind = css.indexOf(classname); if (ind >= 0) { if (!strict) return trg; var left = ind === 0 || !_trimString(css.charAt(ind - 1)); var right = ind + classname.length >= css.length || !_trimString(css.charAt(ind + classname.length)); if (left && right) return trg; } } trg = trg.parentNode; } return null; } function getRelativeEventPosition(ev, node) { var d = document.documentElement; var box = getNodePosition(node); return { x: ev.clientX + d.scrollLeft - d.clientLeft - box.x + node.scrollLeft, y: ev.clientY + d.scrollTop - d.clientTop - box.y + node.scrollTop }; } function getRelativeNodePosition(child, parent) { const childPos = getNodePosition(child); const parentPos = getNodePosition(parent); return { x: childPos.x - parentPos.x, y: childPos.y - parentPos.y }; } function isChildOf(child, parent) { if (!child || !parent) { return false; } while (child && child != parent) { child = child.parentNode; } return child === parent; } function closest(element, selector) { if (element.closest) { return element.closest(selector); } else if (element.matches || element.msMatchesSelector || element.webkitMatchesSelector) { var el = element; if (!document.documentElement.contains(el)) return null; do { var method = el.matches || el.msMatchesSelector || el.webkitMatchesSelector; if (method.call(el, selector)) return el; el = el.parentElement || el.parentNode; } while (el !== null && el.nodeType === 1); return null; } else { console.error("Your browser is not supported"); return null; } } function getClosestSizedElement(element) { while (element) { if (element.offsetWidth > 0 && element.offsetHeight > 0) { return element; } element = element.parentElement; } return null; } function isShadowDomSupported() { return document.head.createShadowRoot || document.head.attachShadow; } function getActiveElement() { var activeElement = document.activeElement; if (activeElement.shadowRoot) { activeElement = activeElement.shadowRoot.activeElement; } if (activeElement === document.body && document.getSelection) { activeElement = document.getSelection().focusNode || document.body; } return activeElement; } function getRootNode(element) { if (!element) { return document.body; } if (!isShadowDomSupported()) { return document.body; } while (element.parentNode && (element = element.parentNode)) { if (element instanceof ShadowRoot) { return element.host; } } return document.body; } function hasShadowParent(element) { return !!getRootNode(element); } const domHelpers = Object.freeze(Object.defineProperty({ __proto__: null, addClassName, closest, getActiveElement, getChildNodes, getClassName, getClosestSizedElement, getFocusableNodes, getNodePosition, getRelativeEventPosition, getRelativeNodePosition, getRootNode, getScrollSize, getTargetNode, hasClass, hasShadowParent, insertNode, isChildOf, isShadowDomSupported, locateAttribute, locateClassName, removeClassName, removeNode, toNode }, Symbol.toStringTag, { value: "Module" })); var globalScope; if (typeof window !== "undefined") { globalScope = window; } else { globalScope = global; } const scope = globalScope; let EventsManager$1 = class EventsManager { constructor(gantt2) { this._mouseDown = false; this._touchStarts = false; this._touchActive = false; this._longTapTimer = false; this._gantt = gantt2; this._domEvents = gantt2._createDomEventScope(); } attach(selectedRegion, useKey, ignore) { const gantt2 = this._gantt; const _target = selectedRegion.getViewPort(); this._originPosition = scope.getComputedStyle(_target).display; this._restoreOriginPosition = () => { _target.style.position = this._originPosition; }; if (this._originPosition === "static") { _target.style.position = "relative"; } const state = gantt2.$services.getService("state"); state.registerProvider("clickDrag", () => { const result = { autoscroll: false }; return result; }); let scheduledDndCoordinates = null; const startDragAndDrop = () => { if (!scheduledDndCoordinates) { return; } this._mouseDown = true; selectedRegion.setStart(gantt2.copy(scheduledDndCoordinates)); selectedRegion.setPosition(gantt2.copy(scheduledDndCoordinates)); selectedRegion.setEnd(gantt2.copy(scheduledDndCoordinates)); scheduledDndCoordinates = null; }; this._domEvents.attach(_target, "mousedown", (event2) => { startDrag(event2); }); const eventElement = getRootNode(gantt2.$root) || document.body; this._domEvents.attach(eventElement, "mouseup", (event2) => { stopDrag(event2); }); this._domEvents.attach(_target, "mousemove", (event2) => { dragMove(event2); }); this._domEvents.attach(_target, "touchstart", (event2) => { this._touchStarts = true; this._longTapTimer = setTimeout(() => { if (this._touchStarts) { startDrag(getTouchEvent(event2)); this._touchStarts = false; this._touchActive = true; } }, this._gantt.config.touch_drag); }); this._domEvents.attach(eventElement, "touchend", (event2) => { this._touchStarts = false; this._touchActive = false; clearTimeout(this._longTapTimer); stopDrag(getTouchEvent(event2)); }); this._domEvents.attach(_target, "touchmove", (event2) => { if (this._touchActive) { let filterTargets = getFilterTargets(); if (filterTargets && gantt2.utils.dom.closest(event2.target, filterTargets)) { return; } dragMove(getTouchEvent(event2)); event2.preventDefault(); } else { this._touchStarts = false; clearTimeout(this._longTapTimer); } }); function getTouchEvent(event2) { const touchEvent = event2.changedTouches && event2.changedTouches[0] || event2; return touchEvent; } const getFilterTargets = () => { let filterTargets = ".gantt_task_line, .gantt_task_link"; if (ignore !== void 0) { if (ignore instanceof Array) { filterTargets = ignore.join(", "); } else { filterTargets = ignore; } } return filterTargets; }; const startDrag = (event2) => { scheduledDndCoordinates = null; let filterTargets = getFilterTargets(); if (filterTargets) { if (gantt2.utils.dom.closest(event2.target, filterTargets)) { return; } } state.registerProvider("clickDrag", () => { const result = { autoscroll: this._mouseDown }; return result; }); if (useKey && event2[useKey] !== true) { return; } scheduledDndCoordinates = this._getCoordinates(event2, selectedRegion); }; const stopDrag = (event2) => { scheduledDndCoordinates = null; if (useKey && event2[useKey] !== true) { return; } if (this._mouseDown === true) { this._mouseDown = false; const coordinates = this._getCoordinates(event2, selectedRegion); selectedRegion.dragEnd(coordinates); } }; const dragMove = (event2) => { if (useKey && event2[useKey] !== true) { return; } const dragTimeline = this._gantt.ext.clickDrag; const dragTimelineUseKey = (this._gantt.config.drag_timeline || {}).useKey; if (dragTimeline && dragTimelineUseKey) { if (!useKey && event2[dragTimelineUseKey]) { return; } } let coordinates = null; if (!this._mouseDown && scheduledDndCoordinates) { coordinates = this._getCoordinates(event2, selectedRegion); if (Math.abs(scheduledDndCoordinates.relative.left - coordinates.relative.left) > 5) { startDragAndDrop(); } return; } if (this._mouseDown === true) { coordinates = this._getCoordinates(event2, selectedRegion); selectedRegion.setEnd(coordinates); selectedRegion.render(); } }; } detach() { const gantt2 = this._gantt; this._domEvents.detachAll(); if (this._restoreOriginPosition) { this._restoreOriginPosition(); } const state = gantt2.$services.getService("state"); state.unregisterProvider("clickDrag"); } destructor() { this.detach(); } _getCoordinates(event2, selectedRegion) { const viewPort = selectedRegion.getViewPort(); const viewPortBounds = viewPort.getBoundingClientRect(); const { clientX, clientY } = event2; const result = { absolute: { left: clientX, top: clientY }, relative: { left: clientX - viewPortBounds.left + viewPort.scrollLeft, top: clientY - viewPortBounds.top + viewPort.scrollTop } }; return result; } }; var EventHost = function() { this._silent_mode = false; this.listeners = {}; }; EventHost.prototype = { _silentStart: function() { this._silent_mode = true; }, _silentEnd: function() { this._silent_mode = false; } }; var createEventStorage = function(obj) { var handlers = {}; var index = 0; var eventStorage = function() { var combinedResult = true; for (var i in handlers) { var handlerResult = handlers[i].apply(obj, arguments); combinedResult = combinedResult && handlerResult; } return combinedResult; }; eventStorage.addEvent = function(handler, settings) { if (typeof handler == "function") { var handlerId; if (settings && settings.id) { handlerId = settings.id; } else { handlerId = index; index++; } if (settings && settings.once) { var originalHandler = handler; handler = function() { originalHandler(); eventStorage.removeEvent(handlerId); }; } handlers[handlerId] = handler; return handlerId; } return false; }; eventStorage.removeEvent = function(id) { delete handlers[id]; }; eventStorage.clear = function() { handlers = {}; }; return eventStorage; }; function makeEventable(obj) { var eventHost = new EventHost(); obj.attachEvent = function(eventName, handler, settings) { eventName = "ev_" + eventName.toLowerCase(); if (!eventHost.listeners[eventName]) { eventHost.listeners[eventName] = createEventStorage(this); } if (settings && settings.thisObject) { handler = handler.bind(settings.thisObject); } var innerId = eventHost.listeners[eventName].addEvent(handler, settings); var handlerId = eventName + ":" + innerId; if (settings && settings.id) { handlerId = settings.id; } return handlerId; }; obj.attachAll = function(callback) { this.attachEvent("listen_all", callback); }; obj.callEvent = function(name, eventArguments) { if (eventHost._silent_mode) return true; var handlerName = "ev_" + name.toLowerCase(); var listeners = eventHost.listeners; if (listeners["ev_listen_all"]) { listeners["ev_listen_all"].apply(this, [name].concat(eventArguments)); } if (listeners[handlerName]) return listeners[handlerName].apply(this, eventArguments); return true; }; obj.checkEvent = function(name) { var listeners = eventHost.listeners; return !!listeners["ev_" + name.toLowerCase()]; }; obj.detachEvent = function(id) { if (id) { var listeners = eventHost.listeners; for (var i in listeners) { listeners[i].removeEvent(id); } var list = id.split(":"); var listeners = eventHost.listeners; if (list.length === 2) { var eventName = list[0]; var eventId = list[1]; if (listeners[eventName]) { listeners[eventName].removeEvent(eventId); } } } }; obj.detachAllEvents = function() { for (var name in eventHost.listeners) { eventHost.listeners[name].clear(); } }; } var units = { second: 1, minute: 60, hour: 60 * 60, day: 60 * 60 * 24, week: 60 * 60 * 24 * 7, month: 60 * 60 * 24 * 30, quarter: 60 * 60 * 24 * 30 * 3, year: 60 * 60 * 24 * 365 }; function getSecondsInUnit(unit) { return units[unit] || units.hour; } function forEach(arr, callback) { if (arr.forEach) { arr.forEach(callback); } else { var workArray = arr.slice(); for (var i = 0; i < workArray.length; i++) { callback(workArray[i], i); } } } function arrayMap(arr, callback) { if (arr.map) { return arr.map(callback); } else { var workArray = arr.slice(); var resArray = []; for (var i = 0; i < workArray.length; i++) { resArray.push(callback(workArray[i], i)); } return resArray; } } function arrayFind(arr, callback) { if (arr.find) { return arr.find(callback); } else { for (var i = 0; i < arr.length; i++) { if (callback(arr[i], i)) { return arr[i]; } } } } function arrayIncludes(arr, item) { if (arr.includes) { return arr.includes(item); } else { for (var i = 0; i < arr.length; i++) { if (arr[i] === item) { return true; } } return false; } } function isArray(obj) { if (Array.isArray) { return Array.isArray(obj); } else { return obj && obj.length !== void 0 && obj.pop && obj.push; } } function isDate(obj) { if (obj && typeof obj === "object") { return !!(obj.getFullYear && obj.getMonth && obj.getDate); } else { return false; } } function isValidDate(obj) { return isDate(obj) && !isNaN(obj.getTime()); } function delay(callback, timeout) { var timer; var result = function() { result.$cancelTimeout(); result.$pending = true; var args = Array.prototype.slice.call(arguments); timer = setTimeout(function() { callback.apply(this, args); result.$pending = false; }, timeout); }; result.$pending = false; result.$cancelTimeout = function() { clearTimeout(timer); result.$pending = false; }; result.$execute = function() { var args = Array.prototype.slice.call(arguments); callback.apply(this, args); result.$cancelTimeout(); }; return result; } function isEventable(obj) { return obj.attachEvent && obj.detachEvent; } function replaceValidZeroId(id, rootId) { if (checkZeroId(id) && !checkZeroId(rootId)) { id = "0"; } return id; } function checkZeroId(id) { if (id === 0) { return true; } return false; } function findBinary(array, target) { var low = 0, high = array.length - 1, i, item, prev; while (low <= high) { i = Math.floor((low + high) / 2); item = +array[i]; prev = +array[i - 1]; if (item < target) { low = i + 1; continue; } if (item > target) { if (!(!isNaN(prev) && prev < target)) { high = i - 1; continue; } else { return i - 1; } } while (+array[i] == +array[i + 1]) i++; return i; } return array.length - 1; } class SelectedRegion { constructor(config2, gantt2, view) { this._el = document.createElement("div"); this.defaultRender = (start, end) => { if (!this._el) { this._el = document.createElement("div"); } const node = this._el; const top = Math.min(start.relative.top, end.relative.top); const bottom = Math.max(start.relative.top, end.relative.top); const left = Math.min(start.relative.left, end.relative.left); const right = Math.max(start.relative.left, end.relative.left); if (this._singleRow) { const pos = this._getTaskPositionByTop(this._startPoint.relative.top); node.style.height = pos.height + "px"; node.style.top = pos.top + "px"; } else { node.style.height = Math.abs(bottom - top) + "px"; node.style.top = top + "px"; } node.style.width = Math.abs(right - left) + "px"; node.style.left = left + "px"; return node; }; this._gantt = gantt2; this._view = view; this._viewPort = config2.viewPort; this._el.classList.add(config2.className); if (typeof config2.callback === "function") { this._callback = config2.callback; } this.render = () => { let node; if (config2.render) { node = config2.render(this._startPoint, this._endPoint); } else { node = this.defaultRender(this._startPoint, this._endPoint); } if (node !== this._el) { if (this._el && this._el.parentNode) { this._el.parentNode.removeChild(this._el); } this._el = node; } if (config2.className !== "") { this._el.classList.add(config2.className); } this.draw(); }; if (!isEventable(this._viewPort)) { makeEventable(this._viewPort); } this._singleRow = config2.singleRow; this._useRequestAnimationFrame = config2.useRequestAnimationFrame; } draw() { if (this._useRequestAnimationFrame) { return requestAnimationFrame(() => { this._viewPort.appendChild(this.getElement()); }); } else { this._viewPort.appendChild(this.getElement()); } } clear() { if (this._useRequestAnimationFrame) { return requestAnimationFrame(() => { if (!this._el.parentNode) { return; } this._viewPort.removeChild(this._el); }); } else { if (!this._el.parentNode) { return; } this._viewPort.removeChild(this._el); } } getElement() { return this._el; } getViewPort() { return this._viewPort; } setStart(startPoint) { const gantt2 = this._gantt; this._startPoint = startPoint; this._startDate = gantt2.dateFromPos(this._startPoint.relative.left); this._viewPort.callEvent("onBeforeDrag", [this._startPoint]); } setEnd(endPoint) { const gantt2 = this._gantt; this._endPoint = endPoint; if (this._singleRow) { const pos = this._getTaskPositionByTop(this._startPoint.relative.top); this._endPoint.relative.top = pos.top; } this._endDate = gantt2.dateFromPos(this._endPoint.relative.left); if (this._startPoint.relative.left > this._endPoint.relative.left) { this._positionPoint = { relative: { left: this._endPoint.relative.left, top: this._positionPoint.relative.top }, absolute: { left: this._endPoint.absolute.left, top: this._positionPoint.absolute.top } }; } if (this._startPoint.relative.top > this._endPoint.relative.top) { this._positionPoint = { relative: { left: this._positionPoint.relative.left, top: this._endPoint.relative.top }, absolute: { left: this._positionPoint.absolute.left, top: this._endPoint.absolute.top } }; } this._viewPort.callEvent("onDrag", [this._startPoint, this._endPoint]); } setPosition(positionPoint) { this._positionPoint = positionPoint; } dragEnd(endPoint) { const gantt2 = this._gantt; if (endPoint.relative.left < 0) { endPoint.relative.left = 0; } this._viewPort.callEvent("onBeforeDragEnd", [this._startPoint, endPoint]); this.setEnd(endPoint); this._endDate = this._endDate || gantt2.getState().max_date; if (this._startDate.valueOf() > this._endDate.valueOf()) { [this._startDate, this._endDate] = [this._endDate, this._startDate]; } this.clear(); const tasksByTime = gantt2.getTaskByTime(this._startDate, this._endDate); const tasksByIndex = this._getTasksByTop(this._startPoint.relative.top, this._endPoint.relative.top); this._viewPort.callEvent("onDragEnd", [this._startPoint, this._endPoint]); if (this._callback) { this._callback(this._startPoint, this._endPoint, this._startDate, this._endDate, tasksByTime, tasksByIndex); } } getInBounds() { return this._singleRow; } _getTasksByTop(start, end) { const gantt2 = this._gantt; let startValue = start; let endValue = end; if (start > end) { startValue = end; endValue = start; } const startIndex = this._getTaskPositionByTop(startValue).index; const endIndex = this._getTaskPositionByTop(endValue).index; const result = []; for (let i = startIndex; i <= endIndex; i++) { const task = gantt2.getTaskByIndex(i); if (task) { result.push(gantt2.getTaskByIndex(i)); } } return result; } _getTaskPositionByTop(top) { const gantt2 = this._gantt; const view = this._view; const index = view.getItemIndexByTopPosition(top); const task = gantt2.getTaskByIndex(index); if (task) { const height = view.getItemHeight(task.id); const itemTop = view.getItemTop(task.id); return { top: itemTop || 0, height: height || 0, index }; } else { const dataHeight = view.getTotalHeight(); return { top: top > dataHeight ? dataHeight : 0, height: gantt2.config.row_height, index: top > dataHeight ? gantt2.getTaskCount() : 0 }; } } } function click_drag(gantt2) { if (!gantt2.ext) { gantt2.ext = {}; } const defaultConfig = { className: "gantt_click_drag_rect", useRequestAnimationFrame: true, callback: void 0, singleRow: false }; function setClickDrag() { const config2 = { viewPort: gantt2.$task_data, ...defaultConfig }; if (gantt2.ext.clickDrag) { gantt2.ext.clickDrag.destructor(); } gantt2.ext.clickDrag = new EventsManager$1(gantt2); const clickDrag = gantt2.config.click_drag; config2.render = clickDrag.render || defaultConfig.render; config2.className = clickDrag.className || defaultConfig.className; config2.callback = clickDrag.callback || defaultConfig.callback; config2.viewPort = clickDrag.viewPort || gantt2.$task_data; config2.useRequestAnimationFrame = clickDrag.useRequestAnimationFrame === void 0 ? defaultConfig.useRequestAnimationFrame : clickDrag.useRequestAnimationFrame; config2.singleRow = clickDrag.singleRow === void 0 ? defaultConfig.singleRow : clickDrag.singleRow; const timeline = gantt2.$ui.getView("timeline"); const selectedRegion = new SelectedRegion(config2, gantt2, timeline); gantt2.ext.clickDrag.attach(selectedRegion, clickDrag.useKey, clickDrag.ignore); } gantt2.attachEvent("onGanttReady", () => { if (gantt2.config.click_drag) { setClickDrag(); } }); gantt2.attachEvent("onGanttLayoutReady", function() { if (gantt2.$container && gantt2.config.click_drag) { gantt2.attachEvent("onGanttRender", function() { setClickDrag(); }, { once: true }); } }); gantt2.attachEvent("onDestroy", () => { if (gantt2.ext.clickDrag) { gantt2.ext.clickDrag.destructor(); } }); } let _dragInProgress = false; class EventsManager { constructor(gantt2) { this._mouseDown = false; this._calculateDirectionVector = () => { const traceSteps = 10; if (this._trace.length >= traceSteps) { const dots = this._trace.slice(this._trace.length - traceSteps); const vectors = []; for (let i = 1; i < dots.length; i++) { vectors.push({ x: dots[i].x - dots[i - 1].x, y: dots[i].y - dots[i - 1].y }); } const resultVector = { x: 0, y: 0 }; vectors.forEach((vector) => { resultVector.x += vector.x; resultVector.y += vector.y; }); const magnitude = Math.sqrt(resultVector.x * resultVector.x + resultVector.y * resultVector.y); const angleDegrees = Math.atan2(Math.abs(resultVector.y), Math.abs(resultVector.x)) * 180 / Math.PI; return { magnitude, angleDegrees }; } return null; }; this._applyDndReadyStyles = () => { this._timeline.$task.classList.add("gantt_timeline_move_available"); }; this._clearDndReadyStyles = () => { this._timeline.$task.classList.remove("gantt_timeline_move_available"); }; this._getScrollPosition = (timeline) => { const gantt3 = this._gantt; return { x: gantt3.$ui.getView(timeline.$config.scrollX).getScrollState().position, y: gantt3.$ui.getView(timeline.$config.scrollY).getScrollState().position }; }; this._countNewScrollPosition = (coords) => { const vector = this._calculateDirectionVector(); let shiftX = this._startPoint.x - coords.x; let shiftY = this._startPoint.y - coords.y; if (vector) { if (vector.angleDegrees < 15) { shiftY = 0; } else if (vector.angleDegrees > 75) { shiftX = 0; } } const result = { x: this._scrollState.x + shiftX, y: this._scrollState.y + shiftY }; return result; }; this._setScrollPosition = (timeline, coords) => { const gantt3 = this._gantt; requestAnimationFrame(() => { gantt3.scrollLayoutCell(timeline.$id, coords.x, coords.y); }); }; this._stopDrag = (event2) => { const gantt3 = this._gantt; this._trace = []; gantt3.$root.classList.remove("gantt_noselect"); if (this._originalReadonly !== void 0 && this._mouseDown) { gantt3.config.readonly = this._originalReadonly; if (gantt3.config.drag_timeline && gantt3.config.drag_timeline.render) { gantt3.render(); } } if (this._originAutoscroll !== void 0) { gantt3.config.autoscroll = this._originAutoscroll; } if (gantt3.config.drag_timeline) { const { useKey } = gantt3.config.drag_timeline; if (useKey && event2[useKey] !== true) { return; } } this._mouseDown = false; _dragInProgress = false; }; this._startDrag = (event2) => { const gantt3 = this._gantt; this._originAutoscroll = gantt3.config.autoscroll; gantt3.config.autoscroll = false; _dragInProgress = true; gantt3.$root.classList.add("gantt_noselect"); this._originalReadonly = gantt3.config.readonly; gantt3.config.readonly = true; if (gantt3.config.drag_timeline && gantt3.config.drag_timeline.render) { gantt3.render(); } this._trace = []; this._mouseDown = true; const { x, y } = this._getScrollPosition(this._timeline); this._scrollState = { x, y }; this._startPoint = { x: event2.clientX, y: event2.clientY }; this._trace.push(this._startPoint); }; this._gantt = gantt2; this._domEvents = gantt2._createDomEventScope(); this._trace = []; } static create(gantt2) { return new EventsManager(gantt2); } static _isDragInProgress() { return _dragInProgress; } destructor() { this._domEvents.detachAll(); } attach(timeline) { this._timeline = timeline; const gantt2 = this._gantt; this._domEvents.attach(timeline.$task, "mousedown", (event2) => { if (!gantt2.config.drag_timeline) { return; } const { useKey, ignore, enabled } = gantt2.config.drag_timeline; if (enabled === false) { return; } let filterTargets = ".gantt_task_line, .gantt_task_link"; if (ignore !== void 0) { if (ignore instanceof Array) { filterTargets = ignore.join(", "); } else { filterTargets = ignore; } } if (filterTargets) { if (gantt2.utils.dom.closest(event2.target, filterTargets)) { return; } } if (useKey && event2[useKey] !== true) { return; } this._startDrag(event2); }); this._domEvents.attach(document, "keydown", (event2) => { if (!gantt2.config.drag_timeline) { return; } const { useKey } = gantt2.config.drag_timeline; if (useKey && event2[useKey] === true) { this._applyDndReadyStyles(); } }); this._domEvents.attach(document, "keyup", (event2) => { if (!gantt2.config.drag_timeline) { return; } const { useKey } = gantt2.config.drag_timeline; if (useKey && event2[useKey] === false) { this._clearDndReadyStyles(); this._stopDrag(event2); } }); this._domEvents.attach(document, "mouseup", (event2) => { this._stopDrag(event2); }); this._domEvents.attach(gantt2.$root, "mouseup", (event2) => { this._stopDrag(event2); }); this._domEvents.attach(document, "mouseleave", (event2) => { this._stopDrag(event2); }); this._domEvents.attach(gantt2.$root, "mouseleave", (event2) => { this._stopDrag(event2); }); this._domEvents.attach(gantt2.$root, "mousemove", (event2) => { if (!gantt2.config.drag_timeline) { return; } const { useKey } = gantt2.config.drag_timeline; if (useKey && event2[useKey] !== true) { return; } const clickDrag = this._gantt.ext.clickDrag; const clickDragUseKey = (this._gantt.config.click_drag || {}).useKey; if (clickDrag && clickDragUseKey) { if (!useKey && event2[clickDragUseKey]) { return; } } if (this._mouseDown === true) { this._trace.push({ x: event2.clientX, y: event2.clientY }); const scrollPosition = this._countNewScrollPosition({ x: event2.clientX, y: event2.clientY }); this._setScrollPosition(timeline, scrollPosition); this._scrollState = scrollPosition; this._startPoint = { x: event2.clientX, y: event2.clientY }; } }); } } function drag_timeline(gantt2) { if (!gantt2.ext) { gantt2.ext = {}; } gantt2.ext.dragTimeline = { create: () => EventsManager.create(gantt2), _isDragInProgress: () => EventsManager._isDragInProgress }; gantt2.config.drag_timeline = { enabled: true, render: false }; } function export_api(gantt2) { gantt2.ext = gantt2.ext || {}; gantt2.ext.export_api = gantt2.ext.export_api || { _apiUrl: "https://export.dhtmlx.com/gantt", _preparePDFConfigRaw(config2, type) { let previousDateRage = null; if (config2.start && config2.end) { previousDateRage = { start_date: gantt2.config.start_date, end_date: gantt2.config.end_date }; gantt2.config.start_date = gantt2.date.str_to_date(gantt2.config.date_format)(config2.start); gantt2.config.end_date = gantt2.date.str_to_date(gantt2.config.date_format)(config2.end); } config2 = gantt2.mixin(config2, { name: "gantt." + type, data: gantt2.ext.export_api._serializeHtml() }); if (previousDateRage) { gantt2.config.start_date = previousDateRage.start_date; gantt2.config.end_date = previousDateRage.end_date; } }, _prepareConfigPDF(config2, type) { config2 = gantt2.mixin(config2 || {}, { name: "gantt." + type, data: gantt2.ext.export_api._serializeAll(), config: gantt2.config }); gantt2.ext.export_api._fixColumns(config2.config.columns); return config2; }, _pdfExportRouter(config2, type) { if (config2 && config2.raw) { gantt2.ext.export_api._preparePDFConfigRaw(config2, type); } else { config2 = gantt2.ext.export_api._prepareConfigPDF(config2, type); } config2.version = gantt2.version; gantt2.ext.export_api._sendToExport(config2, type); }, exportToPDF(config2) { gantt2.ext.export_api._pdfExportRouter(config2, "pdf"); }, exportToPNG(config2) { gantt2.ext.export_api._pdfExportRouter(config2, "png"); }, exportToICal(config2) { config2 = gantt2.mixin(config2 || {}, { name: "gantt.ical", data: gantt2.ext.export_api._serializePlain().data, version: gantt2.version }); gantt2.ext.export_api._sendToExport(config2, "ical"); }, exportToExcel(config2) { config2 = config2 || {}; let tasks2; let dates; let state; let scroll; const smartRendering = gantt2.config.smart_rendering; if (config2.visual === "base-colors") { gantt2.config.smart_rendering = false; } if (config2.start || config2.end) { state = gantt2.getState(); dates = [gantt2.config.start_date, gantt2.config.end_date]; scroll = gantt2.getScrollState(); const convert = gantt2.date.str_to_date(gantt2.config.date_format); tasks2 = gantt2.eachTask; if (config2.start) { gantt2.config.start_date = convert(config2.start); } if (config2.end) { gantt2.config.end_date = convert(config2.end); } gantt2.render(); gantt2.config.smart_rendering = smartRendering; gantt2.eachTask = gantt2.ext.export_api._eachTaskTimed(gantt2.config.start_date, gantt2.config.end_date); } else if (config2.visual === "base-colors") { gantt2.render(); gantt2.config.smart_rendering = smartRendering; } gantt2._no_progress_colors = config2.visual === "base-colors"; config2 = gantt2.mixin(config2, { name: "gantt.xlsx", title: "Tasks", data: gantt2.ext.export_api._serializeTimeline(config2).data, columns: gantt2.ext.export_api._serializeGrid({ rawDates: true }), version: gantt2.version }); if (config2.visual) { config2.scales = gantt2.ext.export_api._serializeScales(config2); } gantt2.ext.export_api._sendToExport(config2, "excel"); if (config2.start || config2.end) { gantt2.config.start_date = state.min_date; gantt2.config.end_date = state.max_date; gantt2.eachTask = tasks2; gantt2.render(); gantt2.scrollTo(scroll.x, scroll.y); gantt2.config.start_date = dates[0]; gantt2.config.end_date = dates[1]; } }, exportToJSON(config2) { config2 = gantt2.mixin(config2 || {}, { name: "gantt.json", data: gantt2.ext.export_api._serializeAll(), config: gantt2.config, columns: gantt2.ext.export_api._serializeGrid(), worktime: gantt2.ext.export_api._getWorktimeSettings(), version: gantt2.version }); gantt2.ext.export_api._sendToExport(config2, "json"); }, importFromExcel(config2) { try { const formData = config2.data; if (formData instanceof File) { const data2 = new FormData(); data2.append("file", formData); config2.data = data2; } } catch (error) { } gantt2.ext.export_api._sendImportAjaxExcel(config2); }, importFromMSProject(config2) { const formData = config2.data; try { if (formData instanceof File) { const data2 = new FormData(); data2.append("file", formData); config2.data = data2; } } catch (error) { } gantt2.ext.export_api._sendImportAjaxMSP(config2); }, importFromPrimaveraP6(config2) { config2.type = "primaveraP6-parse"; return gantt2.importFromMSProject(config2); }, exportToMSProject(config2) { config2 = config2 || {}; config2.skip_circular_links = config2.skip_circular_links === void 0 ? true : !!config2.skip_circular_links; const oldXmlFormat = gantt2.templates.xml_format; const oldFormatDate = gantt2.templates.format_date; const oldXmlDate = gantt2.config.xml_date; const oldDateFormat = gantt2.config.date_format; const exportServiceDateFormat = "%d-%m-%Y %H:%i:%s"; gantt2.config.xml_date = exportServiceDateFormat; gantt2.config.date_format = exportServiceDateFormat; gantt2.templates.xml_format = gantt2.date.date_to_str(exportServiceDateFormat); gantt2.templates.format_date = gantt2.date.date_to_str(exportServiceDateFormat); const data2 = gantt2.ext.export_api._serializeAll(); gantt2.ext.export_api._customProjectProperties(data2, config2); gantt2.ext.export_api._customTaskProperties(data2, config2); if (config2.skip_circular_links) { gantt2.ext.export_api._clearRecLinks(data2); } config2 = gantt2.ext.export_api._exportConfig(data2, config2); gantt2.ext.export_api._sendToExport(config2, config2.type || "msproject"); gantt2.config.xml_date = oldXmlDate; gantt2.config.date_format = oldDateFormat; gantt2.templates.xml_format = oldXmlFormat; gantt2.templates.format_date = oldFormatDate; gantt2.config.$custom_data = null; gantt2.config.custom = null; }, exportToPrimaveraP6(config2) { config2 = config2 || {}; config2.type = "primaveraP6"; return gantt2.exportToMSProject(config2); }, _fixColumns(columns) { for (let i = 0; i < columns.length; i++) { columns[i].label = columns[i].label || gantt2.locale.labels["column_" + columns[i].name]; if (typeof columns[i].width === "string") { columns[i].width = columns[i].width * 1; } } }, _xdr(url, pack, cb) { gantt2.ajax.post(url, pack, cb); }, _markColumns(base2) { const columns = base2.config.columns; if (columns) { for (let i = 0; i < columns.length; i++) { if (columns[i].template) { columns[i].$template = true; } } } }, _sendImportAjaxExcel(config2) { const url = config2.server || gantt2.ext.export_api._apiUrl; const store = config2.store || 0; const formData = config2.data; const callback = config2.callback; formData.append("type", "excel-parse"); formData.append("data", JSON.stringify({ sheet: config2.sheet || 0 })); if (store) { formData.append("store", store); } const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(e) { if (xhr.readyState === 4 && xhr.status === 0) { if (callback) { callback(null); } } }; xhr.onload = function() { const fail = xhr.status > 400; let info = null; if (!fail) { try { info = JSON.parse(xhr.responseText); } catch (e) { } } if (callback) { callback(info); } }; xhr.open("POST", url, true); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.send(formData); }, _ajaxToExport(data2, type, callback) { delete data2.callback; const url = data2.server || gantt2.ext.export_api._apiUrl; const pack = "type=" + type + "&store=1&data=" + encodeURIComponent(JSON.stringify(data2)); const cb = function(loader) { const xdoc = loader.xmlDoc || loader; const fail = xdoc.status > 400; let info = null; if (!fail) { try { info = JSON.parse(xdoc.responseText); } catch (e) { } } callback(info); }; gantt2.ext.export_api._xdr(url, pack, cb); }, _serializableGanttConfig(config2) { const result = gantt2.mixin({}, config2); if (result.columns) { result.columns = result.columns.map(function(col) { const copy2 = gantt2.mixin({}, col); delete copy2.editor; return copy2; }); } delete result.editor_types; return result; }, _sendToExport(data2, type) { const convert = gantt2.date.date_to_str(gantt2.config.date_format || gantt2.config.xml_date); if (!data2.skin) { data2.skin = gantt2.skin; } if (data2.config) { data2.config = gantt2.copy(gantt2.ext.export_api._serializableGanttConfig(data2.config)); gantt2.ext.export_api._markColumns(data2, type); if (data2.config.start_date && data2.config.end_date) { if (data2.config.start_date instanceof Date) { data2.config.start_date = convert(data2.config.start_date); } if (data2.config.end_date instanceof Date) { data2.config.end_date = convert(data2.config.end_date); } } } if (data2.callback) { return gantt2.ext.export_api._ajaxToExport(data2, type, data2.callback); } const form = gantt2.ext.export_api._createHiddenForm(); form.firstChild.action = data2.server || gantt2.ext.export_api._apiUrl; form.firstChild.childNodes[0].value = JSON.stringify(data2); form.firstChild.childNodes[1].value = type; form.firstChild.submit(); }, _createHiddenForm() { if (!gantt2.ext.export_api._hidden_export_form) { const t2 = gantt2.ext.export_api._hidden_export_form = document.createElement("div"); t2.style.display = "none"; t2.innerHTML = "<form method='POST' target='_blank'><textarea name='data' style='width:0px; height:0px;' readonly='true'></textarea><input type='hidden' name='type' value=''></form>"; document.body.appendChild(t2); } return gantt2.ext.export_api._hidden_export_form; }, _copyObjectBase(obj) { const copy2 = { start_date: void 0, end_date: void 0, constraint_date: void 0, deadline: void 0 }; for (const key in obj) { if (key.charAt(0) === "$" || key === "baselines") { continue; } copy2[key] = obj[key]; } const formatDate = gantt2.templates.xml_format || gantt2.templates.format_date; copy2.start_date = formatDate(copy2.start_date); if (copy2.end_date) { co