dhtmlx-gantt
Version:
An open source JavaScript Gantt chart that helps you illustrate a project schedule in a nice-looking chart.
1,390 lines (1,384 loc) • 1.15 MB
JavaScript
(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.1.1 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 || trg.host;
}
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 _a;
const d = document.documentElement;
const box = getNodePosition(node);
const { clientX, clientY } = ((_a = ev.touches) == null ? void 0 : _a[0]) ?? ev;
return { x: clientX + d.scrollLeft - d.clientLeft - box.x + node.scrollLeft, y: 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 arrayFilter(arr, callback) {
var result = [];
if (arr.filter) {
return arr.filter(callback);
} else {
for (var i = 0; i < arr.length; i++) {
if (callback(arr[i], i)) {
result[result.length] = arr[i];
}
}
return result;
}
}
function throttle(callback, timeout) {
var wait = false;
return function() {
if (!wait) {
callback.apply(null, arguments);
wait = true;
setTimeout(function() {
wait = false;
}, timeout);
}
};
}
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 };
}
var plainObjectConstructor = {}.constructor.toString();
function isCustomType(object) {
var constructorString = object.constructor.toString();
return constructorString !== plainObjectConstructor;
}
function isExternalType(object) {
return object.$$typeof && object.$$typeof.toString().includes("react.");
}
function copy(object) {
var i, result;
if (object && typeof object == "object") {
switch (true) {
case isDate(object):
result = new Date(object);
break;
case isArray(object):
result = new Array(object.length);
for (i = 0; i < object.length; i++) {
result[i] = copy(object[i]);
}
break;
default:
if (isCustomType(object)) {
result = Object.create(object);
} else if (isExternalType(object)) {
result = object;
return result;
} else {
result = {};
}
for (i in object) {
if (Object.prototype.hasOwnProperty.apply(object, [i])) result[i] = copy(object[i]);
}
break;
}
}
return result || object;
}
function mixin(target, source, force) {
for (var f in source) if (target[f] === void 0 || force) target[f] = source[f];
return target;
}
function defined(obj) {
return typeof obj != "undefined";
}
var seed;
function uid() {
if (!seed) seed = (/* @__PURE__ */ new Date()).valueOf();
seed++;
return seed;
}
function bind(functor, object) {
if (functor.bind) return functor.bind(object);
else return function() {
return functor.apply(object, arguments);
};
}
function event(el, event2, handler, capture) {
if (el.addEventListener) el.addEventListener(event2, handler, capture === void 0 ? false : capture);
else if (el.attachEvent) el.attachEvent("on" + event2, handler);
}
function eventRemove(el, event2, handler, capture) {
if (el.removeEventListener) el.removeEventListener(event2, handler, capture === void 0 ? false : capture);
else if (el.detachEvent) el.detachEvent("on" + event2, handler);
}
const utils = Object.freeze(Object.defineProperty({ __proto__: null, bind, copy, defined, event, eventRemove, mixin, uid }, Symbol.toStringTag, { value: "Module" }));
function ScaleHelper(gantt2) {
var dateHelper = gantt2.date;
gantt2.$services;
return { getSum: function(sizes, from, to) {
if (to === void 0) to = sizes.length - 1;
if (from === void 0) from = 0;
var summ = 0;
for (var i = from; i <= to; i++) summ += sizes[i];
return summ;
}, setSumWidth: function(sum_width, scale, from, to) {
var parts = scale.width;
if (to === void 0) to = parts.length - 1;
if (from === void 0) from = 0;
var length = to - from + 1;
if (from > parts.length - 1 || length <= 0 || to > parts.length - 1) return;
var oldWidth = this.getSum(parts, from, to);
var diff = sum_width - oldWidth;
this.adjustSize(diff, parts, from, to);
this.adjustSize(-diff, parts, to + 1);
scale.full_width = this.getSum(parts);
}, splitSize: function(width, count) {
var arr = [];
for (var i = 0; i < count; i++) arr[i] = 0;
this.adjustSize(width, arr);
return arr;
}, adjustSize: function(width, parts, from, to) {
if (!from) from = 0;
if (to === void 0) to = parts.length - 1;
var length = to - from + 1;
var full = this.getSum(parts, from, to);
for (var i = from; i <= to; i++) {
var share = Math.floor(width * (full ? parts[i] / full : 1 / length));
full -= parts[i];
width -= share;
length--;
parts[i] += share;
}
parts[parts.length - 1] += width;
}, sortScales: function(scales) {
function cellSize(unit, step) {
var d = new Date(1970, 0, 1);
return dateHelper.add(d, step, unit) - d;
}
scales.sort(function(a, b) {
if (cellSize(a.unit, a.step) < cellSize(b.unit, b.step)) {
return 1;
} else if (cellSize(a.unit, a.step) > cellSize(b.unit, b.step)) {
return -1;
} else {
return 0;
}
});
for (var i = 0; i < scales.length; i++) {
scales[i].index = i;
}
}, _prepareScaleObject: function(scale) {
var format = scale.format;
if (!format) {
format = scale.template || scale.date || "%d %M";
}
if (typeof format === "string") {
format = gantt2.date.date_to_str(format);
}
return { unit: scale.unit || "day", step: scale.step || 1, format, css: scale.css, projection: scale.projection || null, column_width: scale.column_width || null };
}, primaryScale: function(config2) {
const scaleConfig = config2 || gantt2.config;
const primaryScale = scaleConfig.scales[0];
const result = { unit: primaryScale.unit, step: primaryScale.step, template: primaryScale.template, format: primaryScale.format, date: primaryScale.date, css: primaryScale.css || gantt2.templates.scale_cell_class, projection: primaryScale.projection || null, column_width: primaryScale.column_width || null };
return this._prepareScaleObject(result);
}, getAdditionalScales: function(config2) {
const scaleConfig = config2 || gantt2.config;
const scales = scaleConfig.scales.slice(1);
return scales.map((function(scale) {
return this._prepareScaleObject(scale);
}).bind(this));
}, prepareConfigs: function(scales, min_coll_width, container_width, scale_height, minDate, maxDate, rtl) {
var heights = this.splitSize(scale_height, scales.length);
var full_width = container_width;
var configs = [];
for (var i = scales.length - 1; i >= 0; i--) {
var main_scale = i == scales.length - 1;
var cfg = this.initScaleConfig(scales[i], minDate, maxDate);
if (main_scale) {
this.processIgnores(cfg);
}
if (main_scale && cfg.column_width) {
full_width = cfg.column_width * (cfg.display_count || cfg.count);
}
this.initColSizes(cfg, min_coll_width, full_width, heights[i]);
this.limitVisibleRange(cfg);
if (main_scale) {
full_width = cfg.full_width;
}
configs.unshift(cfg);
}
for (var i = 0; i < configs.length - 1; i++) {
this.alineScaleColumns(configs[configs.length - 1], configs[i]);
}
for (var i = 0; i < configs.length; i++) {
if (rtl) {
this.reverseScale(configs[i]);
}
this.setPosSettings(configs[i]);
}
return configs;
}, reverseScale: function(scale) {
scale.width = scale.width.reverse();
scale.trace_x = scale.trace_x.reverse();
var indexes = scale.trace_indexes;
scale.trace_indexes = {};
scale.trace_index_transition = {};
scale.rtl = true;
for (var i = 0; i < scale.trace_x.length; i++) {
scale.trace_indexes[scale.trace_x[i].valueOf()] = i;
scale.trace_index_transition[indexes[scale.trace_x[i].valueOf()]] = i;
}
return scale;
}, setPosSettings: function(config2) {
for (var i = 0, len = config2.trace_x.length; i < len; i++) {
config2.left.push((config2.width[i - 1] || 0) + (config2.left[i - 1] || 0));
}
}, _ignore_time_config: function(date2, scale) {
if (gantt2.config.skip_off_time) {
var skip = true;
var probe = date2;
for (var i = 0; i < scale.step; i++) {
if (i) {
probe = dateHelper.add(date2, i, scale.unit);
}
skip = skip && !this.isWorkTime(probe, scale.unit);
}
return skip;
}
return false;
}, processIgnores: function(config2) {
config2.ignore_x = {};
config2.display_count = config2.count;
}, initColSizes: function(config2, min_col_width, full_width, line_height) {
var cont_width = full_width;
config2.height = line_height;
var column_count = config2.display_count === void 0 ? config2.count : config2.display_count;
if (!column_count) column_count = 1;
const fixedMode = !isNaN(config2.column_width * 1) && config2.column_width * 1 > 0;
if (fixedMode) {
const baseCellWidth = config2.column_width * 1;
config2.col_width = baseCellWidth;
cont_width = baseCellWidth * column_count;
} else {
config2.col_width = Math.floor(cont_width / column_count);
if (min_col_width) {
if (config2.col_width < min_col_width) {
config2.col_width = min_col_width;
cont_width = config2.col_width * column_count;
}
}
}
config2.width = [];
var ignores = config2.ignore_x || {};
for (var i = 0; i < config2.trace_x.length; i++) {
if (ignores[config2.trace_x[i].valueOf()] || config2.display_count == config2.count) {
if (fixedMode) {
config2.width[i] = config2.col_width;
} else {
config2.width[i] = 0;
}
} else {
var width = 1;
if (config2.unit == "month") {
var days = Math.round((dateHelper.add(config2.trace_x[i], config2.step, config2.unit) - config2.trace_x[i]) / (1e3 * 60 * 60 * 24));
width = days;
}
config2.width[i] = width;
}
}
if (!fixedMode) {
this.adjustSize(cont_width - this.getSum(config2.width), config2.width);
}
config2.full_width = this.getSum(config2.width);
}, initScaleConfig: function(config2, min_date, max_date) {
var cfg = mixin({ count: 0, col_width: 0, full_width: 0, height: 0, width: [], left: [], trace_x: [], trace_indexes: {}, min_date: new Date(min_date), max_date: new Date(max_date) }, config2);
this.eachColumn(config2.unit, config2.step, min_date, max_date, function(date2) {
cfg.count++;
cfg.trace_x.push(new Date(date2));
cfg.trace_indexes[date2.valueOf()] = cfg.trace_x.length - 1;
});
cfg.trace_x_ascending = cfg.trace_x.slice();
return cfg;
}, iterateScales: function(lower_scale, upper_scale, from, to, callback) {
var upper_dates = upper_scale.trace_x;
var lower_dates = lower_scale.trace_x;
var prev = from || 0;
var end = to || lower_dates.length - 1;
var prevUpper = 0;
for (var up = 1; up < upper_dates.length; up++) {
var target_index = lower_scale.trace_indexes[+upper_dates[up]];
if (target_index !== void 0 && target_index <= end) {
if (callback) {
callback.apply(this, [prevUpper, up,