gantt-1.0.8/js/api.js

js/api.js
(function () {

  var apiUrl = "https://export.dhtmlx.com/gantt";

  var templates = [
    "leftside_text",
    "rightside_text",
    "task_text",
    "progress_text",
    "task_class"
  ];

  function xdr(url, pack, cb) {
    switch (true) {
      case gantt.env.isIE:
        gantt.env.isIE = false;
        gantt.ajax.post(url, pack, cb);
        gantt.env.isIE = true;
        break;

      case gantt.env.isNode:

        const http = require('http');

        let parts1 = url.split("://")[1];
        let parts2 = parts1.split("/")[0].split(":");
        let parts3 = parts1.split("/");

        let hostname = parts2[0];
        let port = parts2[1] || 80;
        let path = "/" + parts3.slice(1).join("/");

        const options = {
          hostname: hostname,
          port: port,
          path: path,
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Content-Length': JSON.stringify(pack).length
          }
        }

        const req = http.request(options, function (res) {
          let resData = []
          res.on('data', function (d) {
            resData.push(d)
          })
          res.on('end', function (d) {
            cb(Buffer.concat(resData))
          })
        })

        req.on('error', function (error) {
          console.error(error)
        })

        req.write(JSON.stringify(pack))
        req.end()
        break;

      default:
        gantt.ajax.post(url, pack, cb);
    }
  }

  function defaults(obj, std) {
    for (let key in std) {
      if (!obj[key]) {
        obj[key] = std[key];
      }
    }
    return obj;
  }

  function mark_columns(base) {
    let columns = base.config.columns;
    if (columns){
      for (let i = 0; i < columns.length; i++) {
        if (columns[i].template) {
          columns[i].$template = true;
        }
      }
    }
  }

  function add_export_methods(gantt) {
    let color_box = null;
    let color_hash = {};

    function get_styles(css) {
      if (!color_box) {
        let color_box = document.createElement("DIV");
        color_box.style.cssText = "position:absolute; display:none;";
        document.body.appendChild(color_box);
      }
      if (color_hash[css]) {
        return color_hash[css];
      }

      color_box.className = css;
      return (color_hash[css] = get_color(color_box, "color") + ";" + get_color(color_box, "backgroundColor"));
    }

    function getMinutesWorktimeSettings(parsedRanges) {
      let minutes = [];
      parsedRanges.forEach(function (range) {
        minutes.push(range.startMinute);
        minutes.push(range.endMinute);
      });
      return minutes;
    }

    //compatibility for new versions of gantt
    if (typeof gantt != 'undefined' && !gantt.ajax) {
      if (window.dhtmlxAjax) {
        gantt.ajax = window.dhtmlxAjax;
      } else if (window.dhx4) {
        gantt.ajax = window.dhx4.ajax;
      }
    }

    gantt._getWorktimeSettings = function () {

      let defaultWorkTimes = {
        hours: [0, 24],
        minutes: null,
        dates: {0: true, 1: true, 2: true, 3: true, 4: true, 5: true, 6: true}
      };

      let time;
      if (!gantt.config.work_time) {
        time = defaultWorkTimes;
      } else {
        let wTime = gantt._working_time_helper;
        if (wTime && wTime.get_calendar) {
          time = wTime.get_calendar();
        } else if (wTime) {
          time = {
            hours: wTime.hours,
            minutes: null,
            dates: wTime.dates
          };
        } else if (gantt.config.worktimes && gantt.config.worktimes.global) {
          let settings = gantt.config.worktimes.global;

          if (settings.parsed) {
            let minutes = getMinutesWorktimeSettings(settings.parsed.hours);
            time = {
              hours: null,
              minutes: minutes,
              dates: {}
            };
            for (let i in settings.parsed.dates) {
              if (Array.isArray(settings.parsed.dates[i])) {
                time.dates[i] = getMinutesWorktimeSettings(settings.parsed.dates[i]);
              } else {
                time.dates[i] = settings.parsed.dates[i];
              }
            }
          } else {
            time = {
              hours: settings.hours,
              minutes: null,
              dates: settings.dates
            };
          }

        } else {
          time = defaultWorkTimes;
        }
      }

      return time;
    };

    gantt.exportToPDF = function (config) {
      if (config && config.raw) {
        config = defaults(config, {
          name: "gantt.pdf", data: this._serialize_html()
        });
      } else {
        config = defaults((config || {}), {
          name: "gantt.pdf",
          data: this._serialize_all(),
          config: this.config
        });
        fix_columns(gantt, config.config.columns);
      }

      config.version = this.version;
      this._send_to_export(config, "pdf");
    };

    gantt.exportToPNG = function (config) {
      if (config && config.raw) {
        config = defaults(config, {
          name: "gantt.png", data: this._serialize_html()
        });
      } else {
        config = defaults((config || {}), {
          name: "gantt.png",
          data: this._serialize_all(),
          config: this.config
        });
        fix_columns(gantt, config.config.columns);
      }

      config.version = this.version;
      this._send_to_export(config, "png");
    };

    gantt.exportToICal = function (config) {
      config = defaults((config || {}), {
        name: "gantt.ical",
        data: this._serialize_plain().data,
        version: this.version
      });
      this._send_to_export(config, "ical");
    };

    function eachTaskTimed(start, end) {
      return function (code, parent, master) {
        parent = parent || this.config.root_id;
        master = master || this;

        let branch = this.getChildren(parent);
        if (branch) {
          for (let i = 0; i < branch.length; i++) {
            let item = this._pull[branch[i]];
            if ((!start || item.end_date > start) && (!end || item.start_date < end)) {
              code.call(master, item);
            }

            if (this.hasChild(item.id)) {
              this.eachTask(code, item.id, master);
            }
          }
        }
      };
    }

    gantt.exportToExcel = function (config) {
      config = config || {};

      let tasks, dates;
      let state, scroll;
      if (config.start || config.end) {
        state = this.getState();
        dates = [this.config.start_date, this.config.end_date];
        scroll = this.getScrollState();
        let convert = this.date.str_to_date(this.config.date_format);
        tasks = this.eachTask;

        if (config.start) {
          this.config.start_date = convert(config.start);
        }
        if (config.end) {
          this.config.end_date = convert(config.end);
        }

        this.render();
        this.eachTask = eachTaskTimed(this.config.start_date, this.config.end_date);
      }

      this._no_progress_colors = config.visual === "base-colors";

      let data = null;
      if (!gantt.env.isNode) {
        data = this._serialize_table(config).data;
      }

      config = defaults(config, {
        name: "gantt.xlsx",
        title: "Tasks",
        data: data,
        columns: this._serialize_columns({rawDates: true}),
        version: this.version
      });

      if (config.visual) {
        config.scales = this._serialize_scales(config);
      }

      this._send_to_export(config, "excel");

      if (config.start || config.end) {
        this.config.start_date = state.min_date;
        this.config.end_date = state.max_date;
        this.eachTask = tasks;

        this.render();
        this.scrollTo(scroll.x, scroll.y);

        this.config.start_date = dates[0];
        this.config.end_date = dates[1];
      }
    };

    gantt.exportToJSON = function (config) {
      config = defaults((config || {}), {
        name: "gantt.json",
        data: this._serialize_all(),
        config: this.config,
        columns: this._serialize_columns(),
        worktime: gantt._getWorktimeSettings(),
        version: this.version
      });
      this._send_to_export(config, "json");
    };

    function sendImportAjax(config) {
      let url = config.server || apiUrl;
      let store = config.store || 0;
      let formData = config.data;
      let callback = config.callback;

      formData.append("type", "excel-parse");
      formData.append("data", JSON.stringify({
        sheet: config.sheet || 0,
        server: url
      }));

      if (store) {
        formData.append("store", store);
      }

      let xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState === 4 && xhr.status === 0) {// network error
          if (callback) {
            callback(null);
          }
        }
      };

      xhr.onload = function () {
        let 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);
    }

    function nodejsImportExcel(config) {
      const http = require('http');
      let FormData = require('form-data');

      let url = config.server || apiUrl;

      let parts1 = url.split("://")[1];
      let parts2 = parts1.split("/")[0].split(":");
      let parts3 = parts1.split("/");

      let hostname = parts2[0];
      let port = parts2[1] || 80;
      let path = "/" + parts3.slice(1).join("/");

      const options = {
        hostname: hostname,
        port: port,
        path: path,
        method: 'POST',
        headers: {
          'X-Requested-With': 'XMLHttpRequest'
        }
      }

      let formData = new FormData();
      formData.append("file", config.data);
      formData.append("type", "excel-parse");
      formData.append("data", JSON.stringify({
        sheet: config.sheet || 0
      }));

      options.headers['Content-Type'] = formData.getHeaders()['content-type']

      const req = http.request(options, function (res) {
        let resData = '';
        res.on('data', function (d) {
          resData += d;
        })
        res.on('end', function (d) {
          config.callback(resData.toString())
        })
      })

      req.on('error', function (error) {
        console.error(error)
      })
      formData.pipe(req);
    }

    gantt.importFromExcel = function (config) {
      try {
        let formData = config.data;
        if (formData instanceof FormData) {

        } else if (formData instanceof File) {
          let data = new FormData();
          data.append("file", formData);
          config.data = data;
        }
      } catch (error) {
      }
      if (gantt.env.isNode) {
        nodejsImportExcel(config)
      } else {
        sendImportAjax(config);
      }
    };

    gantt._msp_config = function (config) {

      if (config.project) {
        for (let i in config.project) {
          if (!config._custom_data) {
            config._custom_data = {};
          }
          config._custom_data[i] = config.project[i](this.config);
        }
      }

      if (config.tasks) {
        for (let j = 0; j < config.data.length; j++) {
          let el = this.getTask(config.data[j].id);
          if (!el._custom_data) {
            el._custom_data = {};
          }
          for (let i in config.tasks) {
            el._custom_data[i] = config.tasks[i](el, this.config);
          }
        }
      }

      delete config.project;
      delete config.tasks;

      config.time = gantt._getWorktimeSettings();

      let p_dates = this.getSubtaskDates();
      let format = this.date.date_to_str("%d-%m-%Y %H:%i:%s");
      config.start_end = {
        start_date: format(p_dates.start_date),
        end_date: format(p_dates.end_date)
      };
    };

    gantt._msp_data = function () {
      let old_xml_format = this.templates.xml_format;
      let old_format_date = this.templates.format_date;
      this.templates.xml_format = this.date.date_to_str("%d-%m-%Y %H:%i:%s");
      this.templates.format_date = this.date.date_to_str("%d-%m-%Y %H:%i:%s");

      let data = this._serialize_all();

      this.templates.xml_format = old_xml_format;
      this.templates.format_date = old_format_date;
      return data;
    };

    gantt._ajax_to_export = function (data, type, callback) {
      delete data.callback;

      let url = data.server || apiUrl;
      let pack = "type=" + type + "&store=1&data=" + encodeURIComponent(JSON.stringify(data));

      let cb = function (loader) {
        let xdoc = loader.xmlDoc || loader;
        let fail = xdoc.status > 400;
        let info = null;

        if (!fail) {
          try {
            info = JSON.parse(xdoc.responseText);
          } catch (e) {
          }
        }
        callback(info);
      };

      xdr(url, pack, cb);
    };

    gantt._send_to_export = function (data, type) {
      let convert = this.date.date_to_str(this.config.date_format || this.config.xml_date);
      if (data.config) {
        data.config = this.copy(data.config);
        mark_columns(data, type);

        if (data.config.start_date && data.config.end_date) {
          if (data.config.start_date instanceof Date) {
            data.config.start_date = convert(data.config.start_date)
          }
          if (data.config.end_date instanceof Date) {
            data.config.end_date = convert(data.config.end_date)
          }
        }
      }

      if (gantt.env.isNode) {
        let url = data.server || apiUrl;
        let pack = {
          type: type,
          store: 0,
          data: JSON.stringify(data)
        }
        let callbackFunction = data.callback || function (response) {
          console.log(response)
        }

        return xdr(url, pack, callbackFunction)
      }

      if (data.callback) {
        return gantt._ajax_to_export(data, type, data.callback);
      }

      let form = this._create_hidden_form();
      form.firstChild.action = data.server || apiUrl;
      form.firstChild.childNodes[0].value = JSON.stringify(data);
      form.firstChild.childNodes[1].value = type;
      form.firstChild.submit();
    };

    gantt._create_hidden_form = function () {
      if (!this._hidden_export_form) {
        let t = this._hidden_export_form = document.createElement("div");
        t.style.display = "none";
        t.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(t);
      }
      return this._hidden_export_form;
    };

    //patch broken json serialization in gantt 2.1
    let original = gantt.json._copyObject;

    function copy_object_base(obj) {
      let copy = {};
      for (let key in obj) {
        if (key.charAt(0) === "$") {
          continue;
        }
        copy[key] = obj[key];
      }

      let formatDate = gantt.templates.xml_format || gantt.templates.format_date;

      copy.start_date = formatDate(copy.start_date);
      if (copy.end_date) {
        copy.end_date = formatDate(copy.end_date);
      }

      return copy;
    }

    function copy_object_plain(obj) {
      let text = gantt.templates.task_text(obj.start_date, obj.end_date, obj);

      let copy = copy_object_base(obj);
      copy.text = text || copy.text;

      return copy;
    }

    function get_color(node, style) {
      let value = node.currentStyle ? node.currentStyle[style] : getComputedStyle(node, null)[style];
      let rgb = value.replace(/\s/g, '').match(/^rgba?\((\d+),(\d+),(\d+)/i);
      return ((rgb && rgb.length === 4) ?
        ("0" + parseInt(rgb[1], 10).toString(16)).slice(-2) +
        ("0" + parseInt(rgb[2], 10).toString(16)).slice(-2) +
        ("0" + parseInt(rgb[3], 10).toString(16)).slice(-2) : value).replace("#", "");
    }

    // Excel interprets UTC time as local time in every timezone, send local time instead of actual UTC time.
    // https://github.com/SheetJS/js-xlsx/issues/126#issuecomment-60531614
    let toISOstring = gantt.date.date_to_str("%Y-%m-%dT%H:%i:%s.000Z");

    // excel serialization
    function copy_object_table(obj) {
      let copy = copy_object_columns(obj, copy_object_plain(obj));
      if (copy.start_date) {
        copy.start_date = toISOstring(obj.start_date);
      }
      if (copy.end_date) {
        copy.end_date = toISOstring(obj.end_date);
      }

      // private gantt._day_index_by_date was replaced by public gantt.columnIndexByDate in gantt 5.0
      let getDayIndex = gantt._day_index_by_date ? gantt._day_index_by_date : gantt.columnIndexByDate;

      copy.$start = getDayIndex.call(gantt, obj.start_date);
      copy.$end = getDayIndex.call(gantt, obj.end_date);
      copy.$level = obj.$level;
      copy.$type = obj.$rendered_type;

      let tmps = gantt.templates;
      copy.$text = tmps.task_text(obj.start, obj.end_date, obj);
      copy.$left = tmps.leftside_text ? tmps.leftside_text(obj.start, obj.end_date, obj) : "";
      copy.$right = tmps.rightside_text ? tmps.rightside_text(obj.start, obj.end_date, obj) : "";

      return copy;
    }

    function copy_object_colors(obj) {
      let copy = copy_object_table(obj);

      let node = gantt.getTaskNode(obj.id);
      if (node && node.firstChild) {
        let color = get_color((gantt._no_progress_colors ? node : node.firstChild), "backgroundColor");
        if (color === "363636") {
          color = get_color(node, "backgroundColor");
        }

        copy.$color = color;
      } else if (obj.color) {
        copy.$color = obj.color;
      }

      return copy;
    }

    function copy_object_columns(obj, copy) {
      for (let i = 0; i < gantt.config.columns.length; i++) {
        let ct = gantt.config.columns[i].template;
        if (ct) {
          let val = ct(obj);
          if (val instanceof Date) {
            val = gantt.templates.date_grid(val, obj);
          }
          copy["_" + i] = val;
        }
      }
      return copy;
    }

    function copy_object_all(obj) {
      let copy = copy_object_base(obj);

      //serialize all text templates
      for (let i = 0; i < templates.length; i++) {
        let template = gantt.templates[templates[i]];
        if (template) {
          copy["$" + i] = template(obj.start_date, obj.end_date, obj);
        }
      }

      copy_object_columns(obj, copy);
      copy.open = obj.$open;
      return copy;
    }

    function fix_columns(gantt, columns) {
      for (let i = 0; i < columns.length; i++) {
        columns[i].label = columns[i].label || gantt.locale.labels["column_" + columns[i].name];
        if (typeof columns[i].width === "string") {
          columns[i].width = columns[i].width * 1;
        }
      }
    }

    gantt._serialize_html = function () {
      let smartScales = gantt.config.smart_scales;
      let smartRendering = gantt.config.smart_rendering;
      if (smartScales || smartRendering) {
        gantt.config.smart_rendering = false;
        gantt.config.smart_scales = false;
        gantt.render();
      }

      let html = this.$container.parentNode.innerHTML;

      if (smartScales || smartRendering) {
        gantt.config.smart_scales = smartScales;
        gantt.config.smart_rendering = smartRendering;
        gantt.render();
      }

      return html;
    };

    gantt._serialize_all = function () {
      gantt.json._copyObject = copy_object_all;
      let data = export_serialize();
      gantt.json._copyObject = original;
      return data;
    };

    gantt._serialize_plain = function () {
      let oldXmlFormat = gantt.templates.xml_format;
      let oldFormatDate = gantt.templates.format_date;
      gantt.templates.xml_format = gantt.date.date_to_str("%Y%m%dT%H%i%s", true);
      gantt.templates.format_date = gantt.date.date_to_str("%Y%m%dT%H%i%s", true);
      gantt.json._copyObject = copy_object_plain;

      let data = export_serialize();

      gantt.templates.xml_format = oldXmlFormat;
      gantt.templates.format_date = oldFormatDate;
      gantt.json._copyObject = original;

      delete data.links;
      return data;
    };

    function get_raw() {
      // support Gantt < 5.0
      if (gantt._scale_helpers) {
        let scales = gantt._get_scales(),
          min_width = gantt.config.min_column_width,
          autosize_min_width = gantt._get_resize_options().x ? Math.max(gantt.config.autosize_min_width, 0) : config.$task.offsetWidth,
          height = config.config.scale_height - 1;
        return gantt._scale_helpers.prepareConfigs(scales, min_width, autosize_min_width, height);
      } else { // Gantt >= 5.0
        let timeline = gantt.$ui.getView("timeline");
        if (timeline) {
          let availWidth = timeline.$config.width;
          if (gantt.config.autosize === "x" || gantt.config.autosize === "xy") {
            availWidth = Math.max(gantt.config.autosize_min_width, 0);
          }
          let state = gantt.getState(),
            scales = timeline._getScales(),
            min_width = gantt.config.min_column_width,
            height = gantt.config.scale_height - 1,
            rtl = gantt.config.rtl;
          return timeline.$scaleHelper.prepareConfigs(scales, min_width, availWidth, height, state.min_date, state.max_date, rtl);
        }
      }
    }

    gantt._serialize_table = function (config) {
      gantt.json._copyObject = config.visual ? copy_object_colors : copy_object_table;
      let data = export_serialize();
      gantt.json._copyObject = original;

      delete data.links;

      if (config.cellColors) {
        let css = this.templates.timeline_cell_class || this.templates.task_cell_class;
        if (css) {
          let raw = get_raw();
          let steps = raw[0].trace_x;
          for (let i = 1; i < raw.length; i++) {
            if (raw[i].trace_x.length > steps.length) {
              steps = raw[i].trace_x;
            }
          }

          for (let i = 0; i < data.data.length; i++) {
            data.data[i].styles = [];
            let task = this.getTask(data.data[i].id);
            for (let j = 0; j < steps.length; j++) {
              let date = steps[j];
              let cell_css = css(task, date);
              if (cell_css) {
                data.data[i].styles.push({index: j, styles: get_styles(cell_css)});
              }            }
          }
        }
      }
      return data;
    };

    gantt._serialize_scales = function (config) {
      let scales = [];
      let raw = get_raw();

      let min = Infinity;
      let max = 0;
      for (let i = 0; i < raw.length; i++) {
        min = Math.min(min, raw[i].col_width);
      }

      for (let i = 0; i < raw.length; i++) {
        let start = 0;
        let end = 0;
        let row = [];

        scales.push(row);
        let step = raw[i];
        max = Math.max(max, step.trace_x.length);
        let template = step.format || step.template || (step.date ? gantt.date.date_to_str(step.date) : gantt.config.date_scale);

        for (let j = 0; j < step.trace_x.length; j++) {
          let date = step.trace_x[j];
          end = start + Math.round(step.width[j] / min);

          let scale_cell = {text: template(date), start: start, end: end};

          if (config.cellColors) {
            let css = step.css || this.templates.scale_cell_class;
            if (css) {
              let scale_css = css(date);
              if (scale_css) {
                scale_cell.styles = get_styles(scale_css);
              }
            }
          }

          row.push(scale_cell);
          start = end;
        }
      }

      return {width: max, height: scales.length, data: scales};
    };

    gantt._serialize_columns = function (config) {
      gantt.exportMode = true;

      let columns = [];
      let cols = gantt.config.columns;

      let ccount = 0;
      for (let i = 0; i < cols.length; i++) {
        if (cols[i].name === "add" || cols[i].name === "buttons") {
          continue;
        }

        columns[ccount] = {
          id: ((cols[i].template) ? ("_" + i) : cols[i].name),
          header: cols[i].label || gantt.locale.labels["column_" + cols[i].name],
          width: (cols[i].width ? Math.floor(cols[i].width / 4) : "")
        };

        if (cols[i].name === "duration") {
          columns[ccount].type = "number";
        }
        if (cols[i].name === "start_date" || cols[i].name === "end_date") {
          columns[ccount].type = "date";
          if (config && config.rawDates) {
            columns[ccount].id = cols[i].name;
          }
        }

        ccount++;
      }

      gantt.exportMode = false;
      return columns;
    };

    function export_serialize() {
      gantt.exportMode = true;

      let xmlFormat = gantt.templates.xml_format;
      let formatDate = gantt.templates.format_date;

      // use configuration date format for serialization so date could be parsed on the export
      // required when custom format date function is defined
      gantt.templates.xml_format =
        gantt.templates.format_date =
          gantt.date.date_to_str(gantt.config.date_format || gantt.config.xml_date);

      let data = gantt.serialize();

      gantt.templates.xml_format = xmlFormat;
      gantt.templates.format_date = formatDate;
      gantt.exportMode = false;
      return data;
    }
  }

  add_export_methods(gantt);
  try {
    if (window && window.Gantt && Gantt.plugin) {
      Gantt.plugin(add_export_methods);
    }
  } catch (error) {
  }

})();

(function () {
  var apiUrl = "https://export.dhtmlx.com/gantt";

  function set_level(data) {
    for (let i = 0; i < data.length; i++) {
      if (data[i].parent === 0) {
        data[i]._lvl = 1;
      }
      for (let j = i + 1; j < data.length; j++) {
        if (data[i].id === data[j].parent) {
          data[j]._lvl = data[i]._lvl + 1;
        }
      }
    }
  }

  function clear_level(data) {
    for (let i = 0; i < data.length; i++) {
      delete data[i]._lvl
    }
  }

  function clear_rec_links(data) {
    set_level(data.data);
    let tasks = {};
    for (let i = 0; i < data.data.length; i++) {
      tasks[data.data[i].id] = data.data[i];
    }

    let links = {};

    for (let i = 0; i < data.links.length; i++) {
      let link = data.links[i];
      if (gantt.isTaskExists(link.source) && gantt.isTaskExists(link.target) &&
        tasks[link.source] && tasks[link.target]) {
        links[link.id] = link;
      }
    }

    for (let i in links) {
      make_links_same_level(links[i], tasks);
    }

    const skippedLinks = {};
    for (let i in tasks) {
      clear_circ_dependencies(tasks[i], links, tasks, {}, skippedLinks, null);
    }

    for (let i in links) {
      clear_links_same_level(links, tasks);
    }

    for (let i = 0; i < data.links.length; i++) {
      if (!links[data.links[i].id]) {
        data.links.splice(i, 1);
        i--;
      }
    }

    clear_level(data.data);
  }

  function clear_circ_dependencies(task, links, tasks, usedTasks, skippedLinks, prevLink) {
    let sources = task.$_source;
    if (!sources) {
      return;
    }

    if (usedTasks[task.id]) {
      on_circ_dependency_find(prevLink, links, usedTasks, skippedLinks);
    }

    usedTasks[task.id] = true;

    let targets = {};

    for (let i = 0; i < sources.length; i++) {
      if (skippedLinks[sources[i]]) {
        continue;
      }
      let curLink = links[sources[i]];
      let targetTask = tasks[curLink._target];
      if (targets[targetTask.id]) { // two link from one task to another
        on_circ_dependency_find(curLink, links, usedTasks, skippedLinks);
      }
      targets[targetTask.id] = true;
      clear_circ_dependencies(targetTask, links, tasks, usedTasks, skippedLinks, curLink);
    }
    usedTasks[task.id] = false;
  }

  function on_circ_dependency_find(link, links, usedTasks, skippedLinks) {
    if (link) {
      if (gantt.callEvent("onExportCircularDependency", [link.id, link])) {
        delete links[link.id];
      }

      delete usedTasks[link._source];
      delete usedTasks[link._target];
      skippedLinks[link.id] = true;
    }
  }

  function make_links_same_level(link, tasks) {
    let task,
      targetLvl,
      linkT = {
        target: tasks[link.target],
        source: tasks[link.source]
      };

    if (linkT.target._lvl != linkT.source._lvl) {
      if (linkT.target._lvl < linkT.source._lvl) {
        task = "source";
        targetLvl = linkT.target._lvl
      } else {
        task = "target";
        targetLvl = linkT.source._lvl;
      }

      do {
        let parent = tasks[linkT[task].parent];
        if (!parent) {
          break;
        }
        linkT[task] = parent;
      } while (linkT[task]._lvl < targetLvl);

      let sourceParent = tasks[linkT.source.parent],
        targetParent = tasks[linkT.target.parent];

      while (sourceParent && targetParent && sourceParent.id != targetParent.id) {
        linkT.source = sourceParent;
        linkT.target = targetParent;
        sourceParent = tasks[linkT.source.parent];
        targetParent = tasks[linkT.target.parent];
      }
    }

    link._target = linkT.target.id;
    link._source = linkT.source.id;

    if (!linkT.target.$_target) {
      linkT.target.$_target = [];
    }
    linkT.target.$_target.push(link.id);

    if (!linkT.source.$_source) {
      linkT.source.$_source = [];
    }
    linkT.source.$_source.push(link.id);
  }

  function clear_links_same_level(links, tasks) {
    for (let link in links) {
      delete links[link]._target;
      delete links[link]._source;
    }

    for (let task in tasks) {
      delete tasks[task].$_source;
      delete tasks[task].$_target;
    }
  }

  function customProjectProperties(data, config) {
    if (config && config.project) {
      for (let i in config.project) {
        if (!gantt.config.$custom_data) {
          gantt.config.$custom_data = {};
        }
        gantt.config.$custom_data[i] = typeof config.project[i] === "function" ? config.project[i](gantt.config) : config.project[i];
      }
      delete config.project;
    }
  }

  function customTaskProperties(data, config) {
    if (config && config.tasks) {
      data.data.forEach(function (el) {
        for (let i in config.tasks) {
          if (!el.$custom_data) {
            el.$custom_data = {};
          }
          el.$custom_data[i] = typeof config.tasks[i] === "function" ? config.tasks[i](el, gantt.config) : config.tasks[i];
        }
      });
      delete config.tasks;
    }
  }

  function exportConfig(data, config) {
    let p_name = config.name || 'gantt.xml';
    delete config.name;

    gantt.config.custom = config;

    let time = gantt._getWorktimeSettings();

    let p_dates = gantt.getSubtaskDates();
    if (p_dates.start_date && p_dates.end_date) {
      let formatDate = gantt.templates.format_date || gantt.templates.xml_format;
      gantt.config.start_end = {
        start_date: formatDate(p_dates.start_date),
        end_date: formatDate(p_dates.end_date)
      };
    }

    let manual = config.auto_scheduling === undefined ? false : !!config.auto_scheduling;

    let res = {
      callback: config.callback || null,
      config: gantt.config,
      data: data,
      manual: manual,
      name: p_name,
      worktime: time
    };
    for (let i in config) {
      res[i] = config[i];
    }
    return res;
  }

  function add_export_methods(gantt) {
    gantt._ms_export = {};

    gantt.exportToMSProject = function (config) {
      config = config || {};
      config.skip_circular_links = config.skip_circular_links === undefined ? true : !!config.skip_circular_links;

      let oldXmlFormat = this.templates.xml_format;
      let oldFormatDate = this.templates.format_date;
      let oldXmlDate = this.config.xml_date;
      let oldDateFormat = this.config.date_format;

      let exportServiceDateFormat = "%d-%m-%Y %H:%i:%s";

      this.config.xml_date = exportServiceDateFormat;
      this.config.date_format = exportServiceDateFormat;
      this.templates.xml_format = this.date.date_to_str(exportServiceDateFormat);
      this.templates.format_date = this.date.date_to_str(exportServiceDateFormat);
      let data = this._serialize_all();

      customProjectProperties(data, config);

      customTaskProperties(data, config);

      if (config.skip_circular_links) {
        clear_rec_links(data);
      }

      config = exportConfig(data, config);

      this._send_to_export(config, config.type || "msproject");
      this.config.xml_date = oldXmlDate;
      this.config.date_format = oldDateFormat;
      this.templates.xml_format = oldXmlFormat;
      this.templates.format_date = oldFormatDate;

      this.config.$custom_data = null;
      this.config.custom = null;
    };

    gantt.exportToPrimaveraP6 = function (config) {
      config.type = "primaveraP6";
      return gantt.exportToMSProject(config);
    };

    function sendImportAjax(config) {
      let url = config.server || apiUrl;
      let store = config.store || 0;
      let formData = config.data;
      let callback = config.callback;

      let settings = {server: url};
      if (config.durationUnit) {
        settings.durationUnit = config.durationUnit
      }
      if (config.projectProperties) {
        settings.projectProperties = config.projectProperties;
      }
      if (config.taskProperties) {
        settings.taskProperties = config.taskProperties;
      }

      formData.append("type", config.type || "msproject-parse");
      formData.append("data", JSON.stringify(settings));

      if (store) {
        formData.append("store", store);
      }

      let xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState === 4 && xhr.status === 0) {// network error
          if (callback) {
            callback(null);
          }
        }
      };

      xhr.onload = function () {

        let 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);
    }

    function nodejsImportMSP(config) {
      const http = require('http');
      let FormData = require('form-data');

      let url = config.server || apiUrl;

      let parts1 = url.split("://")[1];
      let parts2 = parts1.split("/")[0].split(":");
      let parts3 = parts1.split("/");

      let hostname = parts2[0];
      let port = parts2[1] || 80;
      let path = "/" + parts3.slice(1).join("/");

      const options = {
        hostname: hostname,
        port: port,
        path: path,
        method: 'POST',
        headers: {
          'X-Requested-With': 'XMLHttpRequest'
        }
      }

      let settings = {};
      if (config.durationUnit) {
        settings.durationUnit = config.durationUnit
      }
      if (config.projectProperties) {
        settings.projectProperties = config.projectProperties;
      }
      if (config.taskProperties) {
        settings.taskProperties = config.taskProperties;
      }

      let formData = new FormData();
      formData.append("file", config.data);
      formData.append("type", config.type || "msproject-parse");
      formData.append("data", JSON.stringify(settings), options);

      options.headers['Content-Type'] = formData.getHeaders()['content-type']

      const req = http.request(options, function (res) {
        let resData = '';
        res.on('data', function (d) {
          resData += d;
        })
        res.on('end', function (d) {
          config.callback(resData.toString())
        })
      })

      req.on('error', function (error) {
        console.error(error)
      })
      formData.pipe(req);
    }

    gantt.importFromMSProject = function (config) {
      let formData = config.data;

      try {
        if (formData instanceof FormData) {

        } else if (formData instanceof File) {
          let data = new FormData();
          data.append("file", formData);
          config.data = data;
        }
      } catch (error) {
      }
      if (gantt.env.isNode) {
        nodejsImportMSP(config);
      } else {
        sendImportAjax(config);
      }
    };

    gantt.importFromPrimaveraP6 = function (config) {
      config.type = "primaveraP6-parse";
      return gantt.importFromMSProject(config);
    };
  }

  add_export_methods(gantt);
  try {
    if (window && window.Gantt && Gantt.plugin) {
      Gantt.plugin(add_export_methods);
    }
  } catch (error) {
  }

})();

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc