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
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.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