Создание пользовательского элемента

Чтобы создать пользовательский элемент управления для лайтбокса, необходимо определить новый объект следующим образом:

gantt.form_blocks["my_editor"] = {
    render: function(sns) { // sns - объект конфигурации секции
        return "html код редактора здесь";
    },
    set_value: function(node, value, task, section) {
        // node - HTML элемент, связанный с кодом выше
        // value - значение из свойства map_to
        // task - объект задачи
        // section - объект конфигурации секции
        ... код для установки значения элемента ...
    },
    get_value: function(node, task, section) {
        // node - HTML элемент, связанный с кодом выше
        // task - объект задачи
        // section - объект конфигурации секции
        return "текущее значение из редактора";
    },
    focus: function(node) {
        // node - HTML элемент, связанный с кодом выше
        ... код для установки фокуса на элемент ...
    }
}

Важно избегать использования короткого синтаксиса закрытия тегов в HTML, возвращаемом функцией render. Это может привести к проблемам с разбором в браузере:

// Избегайте этого
render: function() {
    return "<div id='box'/>";
}
 
// Используйте это вместо
render: function() {
    return "<div id='box'></div>"; // рекомендуется
}

Related sample:  Custom control in the lightbox

Элементы управления лайтбоксом включают следующие типы:

  • render (sns): string - Создает строку, содержащую HTML для секции.
    • sns - (LightboxSection) - Детали конфигурации для секции.
  • set_value (node, value, task, section): any - Присваивает значение из объекта Task секции.
    • node - (HTMLElement) - HTML элемент, связанный с секцией.
    • value - (any) - Значение, определяемое свойством map_to.
    • task - (Task) - Объект задачи.
    • section - (LightboxSection) - Детали конфигурации для секции.
  • get_value (node, task, section): any - Извлекает значение из секции и сохраняет его в объект Task.
    • node - (HTMLElement) - HTML элемент, связанный с секцией.
    • task - (Task) - Объект задачи.
    • section - (LightboxSection) - Детали конфигурации для секции.
  • focus (node): void - Устанавливает фокус на секции.
    • node - (HTMLElement) - HTML элемент, связанный с секцией.

Пользовательский редактор с двумя полями ввода

Вот пример создания пользовательского редактора с двумя полями ввода:

gantt.form_blocks["my_editor"] = {
    render: function (sns) {
        return "<div class='dhx_cal_ltext' style='height:60px;'>"+
            "Текст&nbsp;<input class='editor_description' type='text'>"+
            "<br/>Держатели&nbsp;<input class='editor_holders' type='text'>"+
            "</div>";
    },
    set_value: function (node, value, task) {
        node.querySelector(".editor_description").value = value || "";
        node.querySelector(".editor_holders").value = task.users || "";
    },
    get_value: function (node, task) {
        task.users = node.querySelector(".editor_holders").value;
        return node.querySelector(".editor_description").value;
    },
    focus: function (node) {
        var a = node.querySelector(".editor_description");
        a.select();
        a.focus();
    }
};
gantt.config.lightbox.sections = [
    { name:"description", height:200, map_to:"text", type:"my_editor", focus:true},
    { name:"time", height:72, type:"duration", map_to:"auto"}
];

Related sample:  Custom control in the lightbox

Пользовательский редактор от стороннего разработчика

Вы можете добавить элемент управления multiselect для выбора нескольких значений. Например, элемент управления на основе jQuery Chosen plugin может использоваться для назначения нескольких ресурсов задаче. Это отличается от стандартного ресурсного элемента управления Gantt, так как не обрабатывает количество ресурсов. Это более простой вариант для некоторых случаев использования.

Custom resources control

Related sample:  3rd party multiselect control

Чтобы интегрировать элемент управления на основе jQuery Chosen в диаграмму Ганта:

  • Добавьте его исходные файлы на свою страницу:
<script
    src="https://code.jquery.com/jquery-3.3.1.min.js?v=5.2.4"
    integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
    crossorigin="anonymous"></script>
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.jquery.js?v=5.2.4"></script>
<link rel="stylesheet" type="text/css" 
    href="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.css?v=5.2.4">
  • Определите поведение элемента управления:
gantt.form_blocks["multiselect"] = {
 render: function (sns) {
  var height = (sns.height || "23") + "px";
  var html = "<div class='gantt_cal_ltext gantt_cal_chosen gantt_cal_multiselect'"+
     "style='height:"+ height + ";'><select data-placeholder='...'"+
        "class='chosen-select' multiple>";
  if (sns.options) {
   for (var i = 0; i < sns.options.length; i++) {
    if(sns.unassigned_value !== undefined && sns.options[i].key==sns.unassigned_value){
        continue;
    }
    html+="<option value='" +sns.options[i].key+ "'>"+sns.options[i].label+"</option>";
  }
}
  html += "</select></div>";
  return html;
},
 
set_value: function (node, value, ev, sns) {
    node.style.overflow = "visible";
    node.parentNode.style.overflow = "visible";
    node.style.display = "inline-block";
    var select = $(node.firstChild);
 
    if (value) {
        value = (value + "").split(",");
        select.val(value);
    }
    else {
        select.val([]);
    }
 
    select.chosen();
    if(sns.onchange){
        select.change(function(){
            sns.onchange.call(this);
        })
    }
    select.trigger('chosen:updated');
    select.trigger("change");
},
 
get_value: function (node, ev) {
    var value = $(node.firstChild).val();
    //value = value ? value.join(",") : null
    return value;
},
 
focus: function (node) {
    $(node.firstChild).focus();
 }
};
  • Используйте элемент управления в качестве секции лайтбокса, установив type:"multiselect":
gantt.config.lightbox.sections = [
    {name:"description",height:38,map_to:"text",type:"textarea",focus: true},
    {name:"owner",height:60, type:"multiselect", options:gantt.serverList("people"), 
        map_to:"owner_id", unassigned_value:5 },
    {name: "time", type: "duration", map_to: "auto"}
];

Свойство unassigned_value скрывает ресурсы, которые не должны быть доступны для выбора. Установите id ресурса в качестве значения этого свойства. В приведенном выше примере ресурс с id=5 не будет отображаться в качестве опции.

Пользовательский редактор от стороннего разработчика

Вы можете включить пользовательский datepicker в лайтбокс для установки длительности задачи путем выбора начальной и конечной дат.

jQuery Datepicker в лайтбоксе

Вот пример создания элемента управления Datepicker с использованием jQuery UI Datepicker.

Custom Datepicker control

Related sample:  3rd party Datepicker control

Чтобы интегрировать элемент управления jQuery Datepicker в диаграмму Ганта:

  • Добавьте файлы библиотеки jQuery на свою страницу:
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link  rel="stylesheet" type="text/css" 
    href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  • Определите поведение элемента управления:
(function () {
    function startDatepicker(node){
        return $(node).find("input[name='start']");
    }
    function endDateInput(node){
        return $(node).find("input[name='end']");
    }
 
    gantt.form_blocks["datepicker"] = {
        render: function (sns) { // sns - объект конфигурации секции
            return "<div class='gantt-lb-datepicker'>"+
                "<input type='text' name='start'>"+
                "<input type='text' name='end'>"+
                "</div>";;
        },
        set_value: function (node, value, task, section) {
            // node - HTML элемент, связанный с кодом выше
            // value - значение из свойства map_to
            // task - объект задачи
            // section - объект конфигурации секции
 
            startDatepicker(node).datepicker({
                dateFormat: "yy-mm-dd",
                onSelect: function (dateStr) {
                    var endValue = endDateInput(node).datepicker('getDate');
                    var startValue = startDatepicker(node).datepicker('getDate');
 
                    if(startValue && endValue){
                        if(endValue.valueOf() <= startValue.valueOf()){
                            endDateInput(node).datepicker("setDate", 
                                gantt.calculateEndDate({
                                    start_date: startValue, duration: 1, task:task
                                })
                            );
                        }
                    }
                }
            });
 
            startDatepicker(node).datepicker("setDate", task.start_date);
 
            endDateInput(node).datepicker({
                dateFormat: "yy-mm-dd",
                onSelect: function (dateStr) {
                    //  gantt.ext.inlineEditors.save()
                }
            });
            endDateInput(node).datepicker("setDate", task.end_date);
        },
        get_value: function (node, task, section) {
 
            if(task.start_date && task.end_date) {
                var start = startDatepicker(node).datepicker('getDate');
                var end =  endDateInput(node).datepicker('getDate');
 
                if(end.valueOf() <= start.valueOf()){
                    end = gantt.calculateEndDate({
                        start_date: start, duration: 1, task:task
                    });
                }
                task.start_date = start;
                task.end_date = end;                 
            }
 
            task.duration = gantt.calculateDuration(task);
        },
        focus: function (node) {
 
        }
    }
})();
  • Используйте элемент управления в качестве секции лайтбокса, установив type:"datepicker":
gantt.config.lightbox.sections = [
  { name: "description", height: 70, map_to: "text", type: "textarea", focus: true },
  { name: "time", height: 72, map_to: "auto", type: "datepicker" }
];

Bootstrap Datepicker в лайтбоксе

Вы можете интегрировать Bootstrap Datepicker в лайтбокс так же, как и jQuery Datepicker.

Bootstrap Datepicker control

Related sample:  Bootstrap Datepicker control

Чтобы включить элемент управления Bootstrap Datepicker в диаграмму Ганта:

  • Убедитесь, что добавили исходные файлы библиотеки Bootstrap на свою страницу.

  • Определите логику для элемента управления:

(function () {
    const startDatepicker = (node) => $(node).find("input[name='start']");
    const endDateInput = (node) => $(node).find("input[name='end']");
 
    gantt.form_blocks["datepicker"] = {
        render: (sns) => {
          const height = sns.height || 45;
            return "<div class='gantt-lb-datepicker' style='height:" + height + "px;'>"+
                        "<input type='text' name='start'> - "+
                        "<input type='text' name='end'>"+
                    "</div>";;
        },
        set_value: (node, value, task, section) => {
            const datepickerConfig = { 
                format: 'yyyy-mm-dd',
                autoclose: true,
                container: gantt.$container
            };
            startDatepicker(node).datepicker(datepickerConfig);
            startDatepicker(node).datepicker('setDate', 
                value ? value.start_date : task.start_date
            );
 
            endDateInput(node).datepicker(datepickerConfig);
            endDateInput(node).datepicker('setDate', 
                value ? value.end_date : task.end_date
            );
 
            startDatepicker(node).datepicker().on('changeDate', function(e) {
                const endValue = endDateInput(node).datepicker('getDate');
                const startValue = startDatepicker(node).datepicker('getDate');
 
                if (startValue && endValue) {
                    if (endValue.valueOf() <= startValue.valueOf()) {
                        endDateInput(node).datepicker('setDate', 
                            gantt.calculateEndDate({
                                start_date: startValue, duration: 1, task:task
                            })
                        );
                    }
                }
            });
        },
        get_value: (node, task, section) => {
            const start = startDatepicker(node).datepicker('getDate');
            let end =  endDateInput(node).datepicker('getDate');
 
            if (end.valueOf() <= start.valueOf()) {
                end = gantt.calculateEndDate({
                    start_date: start,
                    duration: 1,
                    task:task
                });
            }
            if (task.start_date && task.end_date) {
                task.start_date = start;
                task.end_date = end;                 
            }
 
            task.duration = gantt.calculateDuration(task);
 
            return {
                start_date: start,
                end_date: end,
                duration: task.duration
            };
        },
        focus: (node) => {
        }
    }
})();
  • Добавьте элемент управления в качестве секции лайтбокса, используя type:"datepicker":
gantt.config.lightbox.sections = [
  { name: "description", height: 70, map_to: "text", type: "textarea", focus: true },
  { name: "time", height: 45, map_to: "auto", type: "datepicker" }
];

Пользовательский контрол длительности от стороннего разработчика

Вы также можете добавить пользовательский контрол длительности в лайтбокс. Этот контрол позволяет установить начальную дату задачи и указать ее длительность в днях.

Custom Duration control

Related sample:  3rd party Duration control

Чтобы создать пользовательский контрол длительности с использованием jQuery:

  • Включите необходимые файлы библиотеки jQuery на свою страницу:
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link  rel="stylesheet" type="text/css" 
    href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  • Определите логику элемента управления:
(function () {
    function startDatepicker(node){
        return $(node).find("input[name='start']");
    }
    function durationInput(node){
        return $(node).find("input[name='duration']");
    }
    function endDateLabel(node){
        return $(node).find("span.gantt-lb-datepicker-label");
    }
 
    var formatter = gantt.ext.formatters.durationFormatter({
        enter: "day",
        store: "day",
        format: "auto"
    });
 
    gantt.form_blocks["datepicker_duration"] = {
        render: function (sns) { //sns - объект конфигурации секции
            return "<div class='gantt-lb-datepicker'>"+
                "<label>Начало:<input type='text' name='start'></label>"+
                "<label>Длительность: <input type='text' name='duration'></label>"+
                "<span class='gantt-lb-datepicker-label'></span>"
                "</div>";
        },
        set_value: function (node, value, task, section) {
            //node - HTML объект, связанный с определенным выше HTML
            //value - значение, определяемое свойством map_to
            //task - объект задачи
            //section- объект конфигурации секции
 
            startDatepicker(node).datepicker({
                dateFormat: "yy-mm-dd",
                onSelect: function (dateStr) {
                    var endValue = durationInput(node).datepicker('getDate');
                    var startValue = startDatepicker(node).datepicker('getDate');
 
                    if(startValue && endValue){
                        if(endValue.valueOf() <= startValue.valueOf()){
                            durationInput(node).datepicker("setDate",
                                gantt.calculateEndDate({
                                    start_date: startValue, duration: 1, task:task
                                })
                            );
                        }
                    }
                }
            });
 
            startDatepicker(node).datepicker("setDate", task.start_date);
 
            durationInput(node).val(formatter.format(task.duration));
            endDateLabel(node).text(
                "Конец: " + gantt.templates.task_date(task.end_date)
            );
        },
        get_value: function (node, task, section) {
 
            if(task.start_date && task.end_date) {
                var start = startDatepicker(node).datepicker('getDate');
                var end = task.end_date;
                var duration = formatter.parse(durationInput(node).val());
 
                if(duration && !isNaN(Number(duration))){
                    end = gantt.calculateEndDate({
                        start_date: start, duration: duration, task:task
                    });
                }
                task.start_date = start;
                task.duration = duration;
                task.end_date = end;
            }
 
            task.duration = gantt.calculateDuration(task);
            return {
                start_date: task.start_date,
                end_date: task.end_date,
                duration: task.duration
            }
        },
        focus: function (node) {
 
        }
    }
})();
  • Добавьте элемент управления в качестве секции лайтбокса, используя type:"datepicker_duration":
gantt.config.lightbox.sections = [
  { name: "description", height: 70, map_to: "text", type: "textarea", focus: true },
  { name: "time", height: 72, map_to: "auto", type: "datepicker_duration" }
];
К началу