{"version":3,"file":"static/js/index.9f245b26.js","sources":["webpack://core-admin_panel/./src/shared/components/Confirmation/NewConfirmation.module.scss?1e90","webpack://core-admin_panel/./src/shared/components/Spacer/spacer.module.scss?8720","webpack://core-admin_panel/./src/shared/components/TasksImport/components/styles.module.scss?9225","webpack://core-admin_panel/../sources/ext/auto_scheduling/constraint_types.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling_configs.js","webpack://core-admin_panel/../sources/core/relations/links_common.js","webpack://core-admin_panel/../sources/utils/helpers.js","webpack://core-admin_panel/../sources/core/worktime/dynamic_resource_calendars.js","webpack://core-admin_panel/../sources/core/ui/plugins/jquery_hooks.js","webpack://core-admin_panel/../sources/core/relations/graph_helper.js","webpack://core-admin_panel/../sources/core/relations/links_builder.js","webpack://core-admin_panel/../sources/core/ui/utils/dom_helpers.js","webpack://core-admin_panel/../sources/ext/auto_scheduling/task_plan.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling/constraints.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling/date_comparator.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling/alap_strategy.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling/asap_strategy.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling/planner.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling/connected_groups.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling/loops_finder.ts","webpack://core-admin_panel/../sources/utils/global.js","webpack://core-admin_panel/../sources/ext/click_drag/eventsManager.ts","webpack://core-admin_panel/../sources/utils/eventable.js","webpack://core-admin_panel/../sources/ext/click_drag/selectedRegion.ts","webpack://core-admin_panel/../sources/ext/drag_timeline/eventsManager.ts","webpack://core-admin_panel/../sources/ext/keyboard_navigation/modals.js","webpack://core-admin_panel/../sources/ext/quick_info/quickInfo.ts","webpack://core-admin_panel/../sources/utils/utils.js","webpack://core-admin_panel/../sources/core/ui/utils/dom_event_scope.js","webpack://core-admin_panel/../sources/ext/tooltip/tooltip.ts","webpack://core-admin_panel/../sources/ext/tooltip/tooltipManager.ts","webpack://core-admin_panel/../sources/ext/undo/monitor.ts","webpack://core-admin_panel/../sources/ext/undo/undo.ts","webpack://core-admin_panel/../sources/ext/extension_manager.ts","webpack://core-admin_panel/../sources/constants/index.js","webpack://core-admin_panel/../sources/core/common/config.ts","webpack://core-admin_panel/../sources/utils/env.js","webpack://core-admin_panel/../sources/core/common/serialize.ts","webpack://core-admin_panel/../sources/core/common/ajax.js","webpack://core-admin_panel/../sources/core/common/date_parsers/fast_version.ts","webpack://core-admin_panel/../sources/core/common/date_parsers/csp_compliant_version.ts","webpack://core-admin_panel/../sources/core/common/date.js","webpack://core-admin_panel/../node_modules/remote-client/dist/remote.es6.js","webpack://core-admin_panel/../sources/core/remote/remote_events.js","webpack://core-admin_panel/../sources/utils/timeout.js","webpack://core-admin_panel/../sources/core/common/state.js","webpack://core-admin_panel/../sources/utils/promise.js","webpack://core-admin_panel/../sources/core/facades/datastore_tasks.js","webpack://core-admin_panel/../sources/core/datastore/power_array.js","webpack://core-admin_panel/../sources/utils/placeholder_task.js","webpack://core-admin_panel/../sources/core/datastore/datastore.js","webpack://core-admin_panel/../sources/core/datastore/treedatastore.js","webpack://core-admin_panel/../sources/utils/is_headless.js","webpack://core-admin_panel/../sources/core/datastore/datastore_render.js","webpack://core-admin_panel/../sources/core/facades/datastore.js","webpack://core-admin_panel/../sources/core/datastore/select.js","webpack://core-admin_panel/../sources/core/facades/datastore_links.js","webpack://core-admin_panel/../sources/core/ui/timeline/scales.js","webpack://core-admin_panel/../sources/core/ui/timeline/scales_ignore.js","webpack://core-admin_panel/../sources/core/gantt_data_range.js","webpack://core-admin_panel/../sources/utils/task_tree_helpers.js","webpack://core-admin_panel/../sources/core/dataprocessor/data_processor_events.ts","webpack://core-admin_panel/../sources/core/dataprocessor/simple_storage.ts","webpack://core-admin_panel/../sources/core/dataprocessor/data_processor.ts","webpack://core-admin_panel/../sources/core/dataprocessor/extend_gantt.ts","webpack://core-admin_panel/../sources/core/dataprocessor/index.js","webpack://core-admin_panel/../sources/core/plugins/batch_update.js","webpack://core-admin_panel/../sources/core/plugins/wbs.js","webpack://core-admin_panel/../sources/core/plugins/resources.js","webpack://core-admin_panel/../sources/core/plugins/resource_assignments.js","webpack://core-admin_panel/../sources/core/plugins/new_task_placeholder.js","webpack://core-admin_panel/../sources/core/plugins/auto_task_types.js","webpack://core-admin_panel/../sources/core/common/duration_formatter.ts","webpack://core-admin_panel/../sources/core/common/link_formatter_simple.ts","webpack://core-admin_panel/../sources/core/common/link_formatter.ts","webpack://core-admin_panel/../sources/core/plugins/formatters.js","webpack://core-admin_panel/../sources/core/plugins/empty_state_screen.ts","webpack://core-admin_panel/../sources/core/ui/render/baseline_helper.js","webpack://core-admin_panel/../sources/core/plugins/baselines.js","webpack://core-admin_panel/../sources/core/ui/row_position_mixin.js","webpack://core-admin_panel/../sources/core/ui/row_position_fixed_height.js","webpack://core-admin_panel/../sources/core/ui/plugins/column_grid_dnd/scrollable_grid.ts","webpack://core-admin_panel/../sources/core/ui/plugins/column_grid_dnd/column_grid_dnd.ts","webpack://core-admin_panel/../sources/core/ui/mouse_event_container.js","webpack://core-admin_panel/../sources/core/ui/grid/grid.js","webpack://core-admin_panel/../sources/core/worktime/calendar_arguments_helper.js","webpack://core-admin_panel/../sources/core/ui/grid/grid_resize.js","webpack://core-admin_panel/../sources/core/ui/grid/task_grid_row_resize.js","webpack://core-admin_panel/../sources/core/worktime/strategy/work_calendar_merger.js","webpack://core-admin_panel/../sources/core/worktime/strategy/work_unit_cache/workunit_map_cache.ts","webpack://core-admin_panel/../sources/core/worktime/strategy/work_unit_cache/workunit_object_cache.ts","webpack://core-admin_panel/../sources/core/worktime/strategy/work_unit_cache/larger_units_helper.ts","webpack://core-admin_panel/../sources/core/worktime/strategy/work_unit_cache/date_duration_cache.ts","webpack://core-admin_panel/../sources/core/worktime/strategy/calendar_strategy.js","webpack://core-admin_panel/../sources/core/worktime/strategy/work_unit_cache/index.ts","webpack://core-admin_panel/../sources/core/worktime/legacy_resource_config.js","webpack://core-admin_panel/../sources/core/worktime/calendar_manager.js","webpack://core-admin_panel/../sources/core/worktime/strategy/no_work_time.js","webpack://core-admin_panel/../sources/core/worktime/time_calculator.js","webpack://core-admin_panel/../sources/core/ui/resize_listener.js","webpack://core-admin_panel/../sources/locale/locale_ar.ts","webpack://core-admin_panel/../sources/locale/locale_be.ts","webpack://core-admin_panel/../sources/locale/locale_ca.ts","webpack://core-admin_panel/../sources/locale/locale_cn.ts","webpack://core-admin_panel/../sources/locale/locale_cs.ts","webpack://core-admin_panel/../sources/locale/locale_da.ts","webpack://core-admin_panel/../sources/locale/locale_de.ts","webpack://core-admin_panel/../sources/locale/locale_el.ts","webpack://core-admin_panel/../sources/locale/locale_en.ts","webpack://core-admin_panel/../sources/locale/locale_es.ts","webpack://core-admin_panel/../sources/locale/locale_fa.ts","webpack://core-admin_panel/../sources/locale/locale_fi.ts","webpack://core-admin_panel/../sources/locale/locale_fr.ts","webpack://core-admin_panel/../sources/locale/locale_he.ts","webpack://core-admin_panel/../sources/locale/locale_hr.ts","webpack://core-admin_panel/../sources/locale/locale_hu.ts","webpack://core-admin_panel/../sources/locale/locale_id.ts","webpack://core-admin_panel/../sources/locale/locale_it.ts","webpack://core-admin_panel/../sources/locale/locale_jp.ts","webpack://core-admin_panel/../sources/locale/locale_kr.ts","webpack://core-admin_panel/../sources/locale/locale_manager.ts","webpack://core-admin_panel/../sources/locale/locale_nb.ts","webpack://core-admin_panel/../sources/locale/locale_nl.ts","webpack://core-admin_panel/../sources/locale/locale_no.ts","webpack://core-admin_panel/../sources/locale/locale_pl.ts","webpack://core-admin_panel/../sources/locale/locale_pt.ts","webpack://core-admin_panel/../sources/locale/locale_ro.ts","webpack://core-admin_panel/../sources/locale/locale_ru.ts","webpack://core-admin_panel/../sources/locale/locale_si.ts","webpack://core-admin_panel/../sources/locale/locale_sk.ts","webpack://core-admin_panel/../sources/locale/locale_sv.ts","webpack://core-admin_panel/../sources/locale/locale_tr.ts","webpack://core-admin_panel/../sources/locale/locale_ua.ts","webpack://core-admin_panel/../sources/factory/make_instance_common.js","webpack://core-admin_panel/../sources/core/ui/configurable.js","webpack://core-admin_panel/../sources/core/ui/ui_factory.js","webpack://core-admin_panel/../sources/core/ui/mouse.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/is_in_viewport.js","webpack://core-admin_panel/../sources/core/ui/render/is_legacy_smart_render.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/get_grid_row_rectangle.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/get_visible_bars_range.js","webpack://core-admin_panel/../sources/core/ui/render/render_factory.js","webpack://core-admin_panel/../sources/core/ui/render/layer_engine.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/get_bar_rectangle.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/factory/get_visible_link_range.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/get_link_rectangle.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/is_link_in_viewport.js","webpack://core-admin_panel/../sources/core/ui/gantt_layers.js","webpack://core-admin_panel/../sources/core/ui/layout/cell.js","webpack://core-admin_panel/../sources/utils/extends.js","webpack://core-admin_panel/../sources/core/ui/layout/layout.js","webpack://core-admin_panel/../sources/core/ui/layout/view_layout.js","webpack://core-admin_panel/../sources/core/ui/layout/view_cell.js","webpack://core-admin_panel/../sources/core/ui/layout/resizer_cell.js","webpack://core-admin_panel/../sources/core/ui/layout/scrollbar_cell.js","webpack://core-admin_panel/../sources/core/ui/timeline/tasks_canvas_render.js","webpack://core-admin_panel/../sources/core/ui/timeline/timeline.js","webpack://core-admin_panel/../sources/core/ui/resource_store_mixin.js","webpack://core-admin_panel/../sources/core/ui/timeline/timeline_layers.js","webpack://core-admin_panel/../sources/core/ui/grid/resource_grid.js","webpack://core-admin_panel/../sources/core/ui/timeline/resource_timeline.js","webpack://core-admin_panel/../sources/core/ui/timeline/resource_histogram.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/keyboard_mappings/default.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/keyboard_mappings/keyboard_navigation.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/editors/base.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/controller.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/editors/text.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/editors/number.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/editors/select.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/editors/date.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/editors/predecessor.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/editors/duration.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/is_bar_in_viewport.js","webpack://core-admin_panel/../sources/core/ui/render/task_bar_render.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/is_project_bar_in_viewport.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/is_split_task_in_viewport.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/get_bg_row_rectangle.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/get_visible_cells_range.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/is_column_visible.js","webpack://core-admin_panel/../sources/core/ui/render/prerender/task_bg_placeholder.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/is_grid_row_in_viewport.js","webpack://core-admin_panel/../sources/core/resource_timetable_builder.js","webpack://core-admin_panel/../sources/core/ui/render/viewport/are_dates_in_viewport.js","webpack://core-admin_panel/../sources/core/ui/render/task_constraints_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_deadline_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_baselines_render.js","webpack://core-admin_panel/../sources/core/ui/grid/tasks_grid_dnd.js","webpack://core-admin_panel/../sources/core/ui/grid/tasks_grid_dnd_marker_helpers/drop_target.js","webpack://core-admin_panel/../sources/core/ui/grid/tasks_grid_dnd_marker_helpers/locked_level.js","webpack://core-admin_panel/../sources/core/ui/grid/tasks_grid_dnd_marker_helpers/highlight.js","webpack://core-admin_panel/../sources/core/ui/grid/tasks_grid_dnd_marker.js","webpack://core-admin_panel/../sources/core/ui/grid/tasks_grid_dnd_marker_helpers/multi_level.js","webpack://core-admin_panel/../sources/core/ui/grid/main_grid_initializer.js","webpack://core-admin_panel/../sources/core/ui/timeline/tasks_dnd.js","webpack://core-admin_panel/../sources/core/ui/timeline/links_dnd.js","webpack://core-admin_panel/../sources/core/ui/timeline/main_timeline_initializer.js","webpack://core-admin_panel/../sources/core/ui/main_layout_initializer.js","webpack://core-admin_panel/../sources/core/ui/index.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/keyboard_mappings.js","webpack://core-admin_panel/../sources/core/ui/grid/editors/linked_properties.js","webpack://core-admin_panel/../sources/core/ui/render/task_grid_line_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_bg_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_bar_smart_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_project_smart_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_project_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_rollup_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_split_render.js","webpack://core-admin_panel/../sources/core/ui/render/link_render.js","webpack://core-admin_panel/../sources/core/ui/render/resource_matrix_render.js","webpack://core-admin_panel/../sources/core/ui/render/resource_histogram_render.js","webpack://core-admin_panel/../sources/core/ui/render/task_grid_row_resize_render.js","webpack://core-admin_panel/../sources/core/ui/skin.js","webpack://core-admin_panel/../sources/core/ui/plugins/autoscroll.js","webpack://core-admin_panel/../sources/core/ui/plugins/dhtmlx_hooks.js","webpack://core-admin_panel/../sources/core/ui/plugins/timeline_zoom.ts","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/base_control.js","webpack://core-admin_panel/../sources/core/ui/utils/html_helpers.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/select_control.js","webpack://core-admin_panel/../sources/core/common/duration_formatter_numeric.ts","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/parent_control.js","webpack://core-admin_panel/../sources/dhtmlxgantt.web.ts","webpack://core-admin_panel/../sources/factory/gantt_factory.ts","webpack://core-admin_panel/../sources/factory/make_instance_web.js","webpack://core-admin_panel/../sources/core/facades/worktime_calendars.js","webpack://core-admin_panel/../sources/core/common/services.js","webpack://core-admin_panel/../sources/core/worktime/work_time.js","webpack://core-admin_panel/../sources/core/common/dnd.js","webpack://core-admin_panel/../sources/core/common/templates.js","webpack://core-admin_panel/../sources/core/datastore/datastore_hooks.js","webpack://core-admin_panel/../sources/core/plugins/index.js","webpack://core-admin_panel/../sources/core/grid_column_api.gpl.js","webpack://core-admin_panel/../sources/core/grid_column_api.js","webpack://core-admin_panel/../sources/core/tasks.js","webpack://core-admin_panel/../sources/core/loading/parsing.js","webpack://core-admin_panel/../sources/core/data.js","webpack://core-admin_panel/../sources/core/data_task_types.js","webpack://core-admin_panel/../sources/core/cached_functions.js","webpack://core-admin_panel/../sources/core/gantt_core.js","webpack://core-admin_panel/../sources/core/common/assert.js","webpack://core-admin_panel/../sources/core/destructor.js","webpack://core-admin_panel/../sources/locale/index.ts","webpack://core-admin_panel/../sources/core/ui_core.js","webpack://core-admin_panel/../sources/core/ui/message.js","webpack://core-admin_panel/../sources/core/facades/layout.js","webpack://core-admin_panel/../sources/css/skins/skyblue.js","webpack://core-admin_panel/../sources/css/skins/dark.js","webpack://core-admin_panel/../sources/css/skins/meadow.js","webpack://core-admin_panel/../sources/css/skins/terrace.js","webpack://core-admin_panel/../sources/css/skins/broadway.js","webpack://core-admin_panel/../sources/css/skins/material.js","webpack://core-admin_panel/../sources/css/skins/contrast_black.js","webpack://core-admin_panel/../sources/css/skins/contrast_white.js","webpack://core-admin_panel/../sources/core/ui/plugins/index.js","webpack://core-admin_panel/../sources/core/ui/touch.js","webpack://core-admin_panel/../sources/core/ui/lightbox/index.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/template_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/textarea_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/time_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/checkbox_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/radio_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/duration_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/resources_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/constraint_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/typeselect_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/controls/baseline_control.js","webpack://core-admin_panel/../sources/core/ui/lightbox/lightbox_optional_time.js","webpack://core-admin_panel/../sources/core/ui/wai_aria.js","webpack://core-admin_panel/../sources/core/loading/ajax_loading.js","webpack://core-admin_panel/../sources/core/loading/dynamic_loading.js","webpack://core-admin_panel/../sources/ext/extensions_all.ts","webpack://core-admin_panel/../sources/ext/auto_scheduling.js","webpack://core-admin_panel/../sources/ext/auto_scheduling/ui_handlers.ts","webpack://core-admin_panel/../sources/ext/click_drag/index.ts","webpack://core-admin_panel/../sources/ext/critical_path.js","webpack://core-admin_panel/../sources/ext/critical_path/slack.js","webpack://core-admin_panel/../sources/ext/critical_path/critical_path.js","webpack://core-admin_panel/../sources/ext/drag_timeline/index.ts","webpack://core-admin_panel/../sources/ext/fullscreen/index.ts","webpack://core-admin_panel/../sources/ext/keyboard_navigation.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/common/keyboard_shortcuts.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/common/eventhandler.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/common/trap_modal_focus.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/elements/gantt_node.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/elements/nav_node.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/elements/header_cell.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/elements/task_row.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/elements/task_cell.js","webpack://core-admin_panel/../sources/ext/keyboard_navigation/core.js","webpack://core-admin_panel/../sources/ext/quick_info/index.ts","webpack://core-admin_panel/../sources/ext/tooltip/index.ts","webpack://core-admin_panel/../sources/ext/undo/index.ts","webpack://core-admin_panel/../sources/ext/grouping.js","webpack://core-admin_panel/../sources/ext/marker.js","webpack://core-admin_panel/../sources/ext/multiselect.js","webpack://core-admin_panel/../sources/ext/overlay.js","webpack://core-admin_panel/../sources/ext/export_api/index.ts","webpack://core-admin_panel/../sources/dhtmlxgantt.enterprise.ts","webpack://core-admin_panel/./src/services/TaskUpdateFifoQueue.ts","webpack://core-admin_panel/./src/shared/stores/GanttContextMenuStore.ts","webpack://core-admin_panel/./src/shared/utils/mapDependencyToGanttLink.ts","webpack://core-admin_panel/./src/shared/stores/GanttStore.ts","webpack://core-admin_panel/./src/shared/stores/TasksStore.ts","webpack://core-admin_panel/./src/IocContainer.ts","webpack://core-admin_panel/./src/api/axios.ts","webpack://core-admin_panel/./src/api/matrix.ts","webpack://core-admin_panel/./src/api/chat.ts","webpack://core-admin_panel/./src/api/company.ts","webpack://core-admin_panel/./src/api/feedback.ts","webpack://core-admin_panel/./src/api/import.ts","webpack://core-admin_panel/./src/api/oauth.ts","webpack://core-admin_panel/./src/api/projects.ts","webpack://core-admin_panel/./src/api/tasks.ts","webpack://core-admin_panel/./src/api/utils/calculateDynamicTimeout.ts","webpack://core-admin_panel/./src/api/utils/handlePollingErrors.ts","webpack://core-admin_panel/./src/api/worker.ts","webpack://core-admin_panel/./src/api/workers.ts","webpack://core-admin_panel/./src/assets/scripts/modernizr/modernizr-custom.js","webpack://core-admin_panel/./src/modules/Tasks/Views/GanttVisual/DocumentViewer/i18n.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Filters/utils/functions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/helpers.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/constants.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/functions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/gantt.ts","webpack://core-admin_panel/./src/services/Effect/api/createIssueEffect.ts","webpack://core-admin_panel/./src/services/Effect/api/createActivityIdsEffect.ts","webpack://core-admin_panel/./src/services/Effect/BatchLoader.ts","webpack://core-admin_panel/./src/services/Effect/ActivityIdsLoader.ts","webpack://core-admin_panel/./src/services/Effect/IssuesLoader.ts","webpack://core-admin_panel/./src/services/Effect/api/createProjecDepsEffect.ts","webpack://core-admin_panel/./src/services/Effect/ProjectLoader.ts","webpack://core-admin_panel/./src/services/Effect/api/createTasksEffect.ts","webpack://core-admin_panel/./src/services/Effect/TasksLoader.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/load.ts","webpack://core-admin_panel/./src/modules/Dashboard/meta.ts","webpack://core-admin_panel/./src/modules/Tasks/utils/functions.ts","webpack://core-admin_panel/./src/modules/Tasks/utils/utils.ts","webpack://core-admin_panel/./src/services/Effect/Polling.ts","webpack://core-admin_panel/./src/services/Effect/api/runPollingEffect.ts","webpack://core-admin_panel/./src/services/Effect/errors.ts","webpack://core-admin_panel/./src/services/Effect/helpers/index.ts","webpack://core-admin_panel/./src/services/Firebase/Firebase.ts","webpack://core-admin_panel/./src/services/TasksObserver/TasksObserver.ts","webpack://core-admin_panel/./src/services/TasksObserver/TasksObserverEvent.ts","webpack://core-admin_panel/./src/services/TasksObserver/const.ts","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/styles.ts","webpack://core-admin_panel/./src/shared/components/ProgressReport/utils/apiHelpers.ts","webpack://core-admin_panel/./src/shared/components/ProgressReport/utils/helpers.ts","webpack://core-admin_panel/./src/shared/components/ProgressReport/utils/uploadImagesToMatrix.ts","webpack://core-admin_panel/./src/shared/components/TasksImport/utils/constants.ts","webpack://core-admin_panel/./src/shared/components/Tooltip/tooltip.module.scss?578d","webpack://core-admin_panel/./src/shared/components/Tooltip/Tooltip.tsx","webpack://core-admin_panel/./src/shared/constants/common.ts","webpack://core-admin_panel/./src/shared/constants/completionUnits.ts","webpack://core-admin_panel/./src/shared/constants/env.ts","webpack://core-admin_panel/./src/shared/constants/firebase.ts","webpack://core-admin_panel/./src/shared/constants/gantt.ts","webpack://core-admin_panel/./src/shared/constants/mixpanelEvents.ts","webpack://core-admin_panel/./src/shared/constants/queryCache.ts","webpack://core-admin_panel/./src/shared/helpers/api.ts","webpack://core-admin_panel/./src/shared/helpers/axios.ts","webpack://core-admin_panel/./src/shared/helpers/common.ts","webpack://core-admin_panel/./src/shared/helpers/dates.ts","webpack://core-admin_panel/./src/shared/helpers/debounce.ts","webpack://core-admin_panel/./src/shared/helpers/ls.ts","webpack://core-admin_panel/./src/shared/helpers/project.ts","webpack://core-admin_panel/./src/shared/helpers/queryParams.ts","webpack://core-admin_panel/./src/shared/helpers/task.ts","webpack://core-admin_panel/./src/shared/helpers/tasks.ts","webpack://core-admin_panel/./src/shared/helpers/throttle.ts","webpack://core-admin_panel/./src/shared/helpers/worker.ts","webpack://core-admin_panel/./src/shared/hooks/analytics/useMixpanel.ts","webpack://core-admin_panel/./src/shared/hooks/core/useDebounce.ts","webpack://core-admin_panel/./src/shared/hooks/core/useEventListener.ts","webpack://core-admin_panel/./src/shared/hooks/core/useMount.ts","webpack://core-admin_panel/./src/shared/hooks/core/useOusideClick.ts","webpack://core-admin_panel/./src/shared/hooks/core/usePrevious.ts","webpack://core-admin_panel/./src/shared/hooks/core/useUnmount.ts","webpack://core-admin_panel/./src/shared/hooks/analytics/useZoomInfo.ts","webpack://core-admin_panel/./src/shared/hooks/useAnalyticsService.ts","webpack://core-admin_panel/./src/shared/hooks/useAppConstants.ts","webpack://core-admin_panel/./src/shared/hooks/useCompany.ts","webpack://core-admin_panel/./src/shared/hooks/useParsedQuery.ts","webpack://core-admin_panel/./src/shared/hooks/usePopupScrollHandler.ts","webpack://core-admin_panel/./src/shared/hooks/useProfile.ts","webpack://core-admin_panel/./src/shared/hooks/useProject.ts","webpack://core-admin_panel/./src/shared/mapping/task.ts","webpack://core-admin_panel/./src/shared/models/Gantt.ts","webpack://core-admin_panel/./src/shared/models/TaskDependency.ts","webpack://core-admin_panel/./src/shared/models/company.ts","webpack://core-admin_panel/./src/shared/models/feedback.ts","webpack://core-admin_panel/./src/shared/models/ioc.ts","webpack://core-admin_panel/./src/shared/models/project.ts","webpack://core-admin_panel/./src/shared/models/task/const.ts","webpack://core-admin_panel/./src/shared/models/task/task.ts","webpack://core-admin_panel/./src/shared/models/task/taskStatus.ts","webpack://core-admin_panel/./src/shared/stores/UIStore.ts","webpack://core-admin_panel/./src/shared/stores/utils/calculations.ts","webpack://core-admin_panel/./src/shared/stores/utils/transforms.ts","webpack://core-admin_panel/./src/shared/utils/UAParser.ts","webpack://core-admin_panel/./src/store/actions.ts","webpack://core-admin_panel/./src/store/company/actions.ts","webpack://core-admin_panel/./src/shared/constants/errors.ts","webpack://core-admin_panel/./src/store/ducks/auth/actions.ts","webpack://core-admin_panel/./src/store/ducks/auth/types.ts","webpack://core-admin_panel/./src/store/onboarding/index.ts","webpack://core-admin_panel/./src/api/subscription.ts","webpack://core-admin_panel/./src/store/profile/actions.ts","webpack://core-admin_panel/./src/store/profile/index.ts","webpack://core-admin_panel/./src/store/profile/utils.ts","webpack://core-admin_panel/./src/store/projects/actions.ts","webpack://core-admin_panel/./src/store/projects/index.ts","webpack://core-admin_panel/./src/store/tasks/actions.ts","webpack://core-admin_panel/./src/store/tasks/index.ts","webpack://core-admin_panel/./src/store/utils/serializeError.ts","webpack://core-admin_panel/./src/shared/utils/resizeObserver.ts","webpack://core-admin_panel/./src/modules/ApplyAuthCode/ApplyAuthCode.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/types.ts","webpack://core-admin_panel/./src/modules/Landing/components/MediaBlocks/MediaBlocks.tsx","webpack://core-admin_panel/./src/shared/helpers/reducerHelpers.ts","webpack://core-admin_panel/./src/modules/SignIn/index.tsx","webpack://core-admin_panel/./src/modules/Tasks/utils/constants.tsx","webpack://core-admin_panel/./src/shared/models/worker.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/GanttSplitDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/components/Baseline/Baseline.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkWatcher/BulkWatcher.tsx","webpack://core-admin_panel/./src/modules/Tasks/DailyRisk/TaskFlagClassifier.tsx","webpack://core-admin_panel/./src/shared/models/task/chat.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/utils/constants.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/SidebarPanel.tsx","webpack://core-admin_panel/./src/shared/hooks/useTaskCacheHlper/types.ts","webpack://core-admin_panel/./src/shared/components/MetaTags/index.tsx","webpack://core-admin_panel/./src/shared/components/OnboardingLayout/ZetOnboardingContainer/ZetOnboardingContainer.tsx","webpack://core-admin_panel/./src/shared/helpers/hooks/useCountDown.ts","webpack://core-admin_panel/./src/shared/hooks/core/useScrollToTopOnMount.ts","webpack://core-admin_panel/./src/shared/hooks/useLandingStyles.ts","webpack://core-admin_panel/./src/shared/hooks/useClassName.ts","webpack://core-admin_panel/./src/shared/layout/base/BaseLayoutStylesContainer.tsx","webpack://core-admin_panel/./src/services/ScrollToService.ts","webpack://core-admin_panel/./src/shared/components/DownloadAppLink/index.tsx","webpack://core-admin_panel/./src/shared/components/ExternalLink/index.tsx","webpack://core-admin_panel/./src/shared/components/LanguageSwitcher/constants.ts","webpack://core-admin_panel/./src/shared/components/LanguageSwitcher/LandingLngSwitcher.module.scss?a172","webpack://core-admin_panel/./src/shared/components/LanguageSwitcher/LandingLngSwitcher.tsx","webpack://core-admin_panel/./src/shared/components/Logo/Logo.tsx","webpack://core-admin_panel/./src/shared/hooks/useUserAgent.ts","webpack://core-admin_panel/./src/shared/layout/base/Header/Header.tsx","webpack://core-admin_panel/./src/shared/layout/base/Footer/Footer.tsx","webpack://core-admin_panel/./src/shared/layout/base/OnboardingLayout.tsx","webpack://core-admin_panel/./src/shared/hooks/useProjectSelector.ts","webpack://core-admin_panel/./src/modules/CollabLanding/CollabLanding.module.scss?e227","webpack://core-admin_panel/./src/modules/CollabLanding/CollabLanding.tsx","webpack://core-admin_panel/./src/shared/helpers/validationSchemas.ts","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlBooking/CtrlBooking.module.scss?e6f8","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlBooking/CtrlBooking.tsx","webpack://core-admin_panel/./src/shared/components/LanguageSwitcher/InternalLngSwitcher.tsx","webpack://core-admin_panel/./src/shared/constants/icons.ts","webpack://core-admin_panel/./src/shared/hooks/useIsCompanyAdmin.ts","webpack://core-admin_panel/./src/shared/hooks/useUnreadMessageCount.ts","webpack://core-admin_panel/./src/store/selectors/index.ts","webpack://core-admin_panel/./src/shared/layout/admin/NavMenu/NavMenuItem/NavMenuItem.module.scss","webpack://core-admin_panel/./src/shared/layout/admin/NavMenu/NavMenuItem/NavMenuItem.tsx","webpack://core-admin_panel/./src/shared/hooks/useAppIsReady.ts","webpack://core-admin_panel/./src/shared/layout/admin/NavMenu/NavMenu.tsx","webpack://core-admin_panel/./src/shared/components/Avatar/Avatar.tsx","webpack://core-admin_panel/./src/shared/layout/admin/UserMenu/UserMenu.tsx","webpack://core-admin_panel/./src/shared/layout/admin/WidgetMenu/index.tsx","webpack://core-admin_panel/./src/shared/layout/admin/WorkspaceSwitcher/workspaceSwitcher.module.scss?68fe","webpack://core-admin_panel/./src/shared/layout/admin/WorkspaceSwitcher/WorkspaceSwitcher.tsx","webpack://core-admin_panel/./src/shared/layout/admin/Header/Header.module.scss?aeec","webpack://core-admin_panel/./src/shared/layout/admin/Header/useHeaderControls.ts","webpack://core-admin_panel/./src/shared/layout/admin/Header/Header.tsx","webpack://core-admin_panel/./src/shared/layout/admin/Layout/Layout.tsx","webpack://core-admin_panel/./src/shared/layout/admin/Panel/Panel.module.scss?5575","webpack://core-admin_panel/./src/shared/layout/admin/Panel/Panel.tsx","webpack://core-admin_panel/./src/shared/layout/admin/ScreenGreed/ScreenGreed.tsx","webpack://core-admin_panel/./src/shared/layout/admin/SlidePanel/SlidePanel.module.scss","webpack://core-admin_panel/./src/shared/layout/admin/SlidePanel/SlidePanelBody/slidePanelBody.module.scss?d887","webpack://core-admin_panel/./src/shared/layout/admin/SlidePanel/SlidePanelBody/SlidePanelBody.tsx","webpack://core-admin_panel/./src/shared/layout/admin/SlidePanel/SlidePanel.tsx","webpack://core-admin_panel/./src/shared/layout/admin/SlidePanel/SlidePanelHeader/SlidePanelHeader.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/FormControl.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Geocoder/Geocoder.tsx","webpack://core-admin_panel/./src/shared/components/Slider/index.tsx","webpack://core-admin_panel/./src/shared/components/Cropper/NoAvatar.tsx","webpack://core-admin_panel/./src/shared/components/Cropper/Cropper.tsx","webpack://core-admin_panel/./src/shared/components/Cropper/useCropper.ts","webpack://core-admin_panel/./src/modules/CompanyProfile/CompanyForm/CompanyForm.tsx","webpack://core-admin_panel/./src/shared/components/SkeletonPreloader/index.module.scss","webpack://core-admin_panel/./src/shared/components/SkeletonPreloader/SkeletonPreloader.tsx","webpack://core-admin_panel/./src/modules/CompanyProfile/CompanyPreview/CompanyPreviewUpsell.module.scss?6ec8","webpack://core-admin_panel/./src/modules/CompanyProfile/CompanyPreview/CompanyPreview.tsx","webpack://core-admin_panel/./src/modules/CompanyProfile/CreateCompanyDesc/utils/getUniqueWorkerRoles.ts","webpack://core-admin_panel/./src/modules/CompanyProfile/CreateCompanyDesc/CreateCompanyDesc.tsx","webpack://core-admin_panel/./src/modules/CompanyProfile/CompanyProfile.tsx","webpack://core-admin_panel/./src/shared/components/LaptopSteps/LaptopSteps.module.scss?b132","webpack://core-admin_panel/./src/shared/components/LaptopSteps/LaptopSteps.tsx","webpack://core-admin_panel/./src/shared/components/MobileAuthStep/MobileAuthStep.module.scss?671e","webpack://core-admin_panel/./src/shared/components/MobileAuthStep/MobileAuthStep.tsx","webpack://core-admin_panel/./src/modules/ComputerStart/ComputerStart.tsx","webpack://core-admin_panel/./src/api/contact.ts","webpack://core-admin_panel/./src/shared/components/CoreForm/CountryCodeSelector/index.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/PhoneInput/PhoneInput.tsx","webpack://core-admin_panel/./src/modules/Contact/contentHelper.ts","webpack://core-admin_panel/./src/modules/Contact/ContactForm/ContactForm.tsx","webpack://core-admin_panel/./src/modules/Contact/HeroSection/index.tsx","webpack://core-admin_panel/./src/modules/Contact/Contact.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Trim.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/EmailInput/index.tsx","webpack://core-admin_panel/./src/modules/ForgotPassword/ForgotPassword.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/hooks/usePasswordVisibility.ts","webpack://core-admin_panel/./src/shared/components/CoreForm/PhoneControl/phoneControl.module.scss","webpack://core-admin_panel/./src/shared/components/CoreForm/PhoneControl/PhoneControl.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Radios/Radios.tsx","webpack://core-admin_panel/./src/shared/helpers/hooks/useRecaptcha.ts","webpack://core-admin_panel/./src/modules/InviteSignup/InviteSignupForm.tsx","webpack://core-admin_panel/./src/modules/SignUp/Alternative/GetStarted/DownloadAppContainer/CompanyInfo.tsx","webpack://core-admin_panel/./src/modules/InviteSignup/utils.ts","webpack://core-admin_panel/./src/modules/InviteSignup/InviteSignup.tsx","webpack://core-admin_panel/./src/shared/hooks/core/useEffectOnce.ts","webpack://core-admin_panel/./src/modules/Landing/components/Box/Box.module.scss?210f","webpack://core-admin_panel/./src/modules/Landing/components/Companies/Companies.module.scss?aed0","webpack://core-admin_panel/./src/modules/Landing/components/Companies/Companies.tsx","webpack://core-admin_panel/./src/modules/Landing/components/CtrlButton/CtrlButton.module.scss?a8ab","webpack://core-admin_panel/./src/modules/Landing/components/CtrlButton/CtrlButton.tsx","webpack://core-admin_panel/./src/modules/Landing/components/ContentSection/ContentSection.module.scss?3775","webpack://core-admin_panel/./src/modules/Landing/components/ContentSection/ContentSection.tsx","webpack://core-admin_panel/./src/modules/Landing/components/EasyToUse/EasyToUse.module.scss?600f","webpack://core-admin_panel/./src/modules/Landing/components/EasyToUse/SvgPoint.tsx","webpack://core-admin_panel/./src/modules/Landing/components/EasyToUse/EasyToUse.tsx","webpack://core-admin_panel/./src/modules/Landing/components/Icon/Icon.module.scss?4761","webpack://core-admin_panel/./src/modules/Landing/components/Icon/Icon.tsx","webpack://core-admin_panel/./src/modules/Landing/components/Social/Social.module.scss?9e04","webpack://core-admin_panel/./src/modules/Landing/components/Social/Social.tsx","webpack://core-admin_panel/./src/modules/Landing/components/CtrlForm/CtrlForm.module.scss?4dd6","webpack://core-admin_panel/./src/modules/Landing/components/CtrlForm/CtrlForm.tsx","webpack://core-admin_panel/./src/modules/Landing/components/CtrlTextfield/CtrlTextfield.module.scss?d880","webpack://core-admin_panel/./src/modules/Landing/components/CtrlTextfield/CtrlTextfield.tsx","webpack://core-admin_panel/./src/modules/Landing/components/Subscribe/Subscribe.module.scss?9d99","webpack://core-admin_panel/./src/modules/Landing/components/Subscribe/Subscribe.tsx","webpack://core-admin_panel/./src/modules/Landing/components/Footer/Footer.module.scss?4878","webpack://core-admin_panel/./src/modules/Landing/components/Footer/Footer.tsx","webpack://core-admin_panel/./src/modules/Landing/components/CtrlAppDetect/CtrlAppDetect.module.scss?b90b","webpack://core-admin_panel/./src/modules/Landing/components/CtrlAppDetect/CtrlAppDetect.tsx","webpack://core-admin_panel/./src/modules/Landing/components/Header/Header.module.scss?66ab","webpack://core-admin_panel/./src/modules/Landing/components/Header/Header.tsx","webpack://core-admin_panel/./src/modules/Landing/components/Hero/Hero.module.scss?b4e8","webpack://core-admin_panel/./src/modules/Landing/components/Hero/Hero.tsx","webpack://core-admin_panel/./src/modules/Landing/components/CtrlTab/CtrlTab.module.scss?701a","webpack://core-admin_panel/./src/modules/Landing/components/CtrlTab/CtrlTab.tsx","webpack://core-admin_panel/./src/modules/Landing/components/ContentSection/ContentTabs/ContentTabs.module.scss?e931","webpack://core-admin_panel/./src/modules/Landing/components/ContentSection/ContentTabs/ContentTabs.tsx","webpack://core-admin_panel/./src/modules/Landing/components/MediaBlocks/MediaBlocks.module.scss?3071","webpack://core-admin_panel/./src/modules/Landing/components/Reviews/Review/Review.module.scss?db70","webpack://core-admin_panel/./src/modules/Landing/components/Reviews/Review/Review.tsx","webpack://core-admin_panel/./src/modules/Landing/components/Slider/constants.ts","webpack://core-admin_panel/./src/modules/Landing/components/Slider/Slider.module.scss?8502","webpack://core-admin_panel/./src/modules/Landing/components/Slider/Slider.tsx","webpack://core-admin_panel/./src/modules/Landing/components/Reviews/Reviews.module.scss?c080","webpack://core-admin_panel/./src/modules/Landing/components/Reviews/Reviews.tsx","webpack://core-admin_panel/./src/modules/Landing/Landing.tsx","webpack://core-admin_panel/./src/shared/hooks/analytics/useFacebookTracking.ts","webpack://core-admin_panel/./src/shared/components/LaptopActions/LaptopActions.module.scss?5ebc","webpack://core-admin_panel/./src/shared/components/LaptopActions/LaptopAction.tsx","webpack://core-admin_panel/./src/shared/components/LaptopMedia/LaptopMedia.module.scss?6e82","webpack://core-admin_panel/./src/shared/components/LaptopMedia/LaptopMedia.tsx","webpack://core-admin_panel/./src/modules/MobileAccountComplete/MobileAccountComplete.tsx","webpack://core-admin_panel/./src/modules/OAuth/ProcoreOAuth.tsx","webpack://core-admin_panel/./src/modules/OAuth/index.tsx","webpack://core-admin_panel/./src/modules/Project/ProjectForm/validationSchema.tsx","webpack://core-admin_panel/./src/shared/components/ProgressBar/index.tsx","webpack://core-admin_panel/./src/api/export.ts","webpack://core-admin_panel/./src/api/utils/sleep.ts","webpack://core-admin_panel/./src/services/ExportToCSV.ts","webpack://core-admin_panel/./src/shared/components/DropPanel/index.tsx","webpack://core-admin_panel/./src/shared/hooks/useTasksUrlState.ts","webpack://core-admin_panel/./src/shared/components/CoreForm/CoreFormControl.tsx","webpack://core-admin_panel/./src/shared/components/TasksExport/TasksExportForm.tsx","webpack://core-admin_panel/./src/shared/components/TasksExport/TaskExportButton.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/TasksImportContext/TasksImportState.ts","webpack://core-admin_panel/./src/shared/components/TasksImport/TasksImportContext/TasksImportContext.ts","webpack://core-admin_panel/./src/shared/components/TasksImport/components/LegendCompare.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TaskImportPreviewTable.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TaskImportResult.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TasksImportMajorError.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Switcher/Switcher.tsx","webpack://core-admin_panel/./src/shared/components/FormikChangeWatcher/FormikChangeWatcher.tsx","webpack://core-admin_panel/./src/shared/hooks/useCompanyLocale.ts","webpack://core-admin_panel/./src/shared/hooks/usePreferDateFormat.ts","webpack://core-admin_panel/./src/shared/components/StatusElement/index.tsx","webpack://core-admin_panel/./src/shared/constants/statuses.ts","webpack://core-admin_panel/./src/shared/components/TaskStatusIcon/index.tsx","webpack://core-admin_panel/./src/shared/components/TaskStatus/TaskStatus.tsx","webpack://core-admin_panel/./src/shared/components/TaskCard/TaskCard.tsx","webpack://core-admin_panel/./src/shared/hooks/useBrowserLocale.ts","webpack://core-admin_panel/./src/shared/hooks/useQueryCache/QueryCacheHelper.ts","webpack://core-admin_panel/./src/shared/hooks/useQueryCache/useQueryCache.ts","webpack://core-admin_panel/./src/shared/components/TasksImport/utils/functions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/GanttColumnsDropdown/ProjectCustomColumnPopup/utils.ts","webpack://core-admin_panel/./src/shared/components/TasksImport/utils/types.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TasksImportMapping/schema.ts","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TasksImportMapping/CustomColumnMapping.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TasksImportMapping/customFieldImportHelpers.ts","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TasksImportMapping/TasksImportMapping.tsx","webpack://core-admin_panel/./src/shared/components/DragAndDrop/index.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TasksImportSource/TasksImportFileSelector.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/components/TasksImportSource/TasksImportSource.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/TasksImportContext/TasksImportProvider.tsx","webpack://core-admin_panel/./src/shared/components/TasksImport/TasksImportPopup.tsx","webpack://core-admin_panel/./src/modules/Project/components/ProjectPreview/ProjectPreview.module.scss?5b2c","webpack://core-admin_panel/./src/modules/Project/components/ProjectPreview/useCloneProject.ts","webpack://core-admin_panel/./src/modules/Project/components/ProjectPreview/useCloneProjectStatus.ts","webpack://core-admin_panel/./src/modules/Project/components/ProjectPreview/ProjectPreview.tsx","webpack://core-admin_panel/./src/api/timezone.ts","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/AsyncProjectSubcontractorSelect/index.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/SkeletonFieldPreloader.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/TimePicker/index.tsx","webpack://core-admin_panel/./src/shared/components/Permission/index.tsx","webpack://core-admin_panel/./src/modules/Project/ProjectForm/ProjectForm.tsx","webpack://core-admin_panel/./src/shared/hooks/useBrowserTimezone.ts","webpack://core-admin_panel/./src/modules/Project/Project.tsx","webpack://core-admin_panel/./src/shared/components/HelpModal/HelpModal.tsx","webpack://core-admin_panel/./src/shared/hooks/useEffectWithCompany.ts","webpack://core-admin_panel/./src/modules/Projects/components/ProjectItem/ProjectItem.tsx","webpack://core-admin_panel/./src/modules/Projects/components/ProjectsList/ProjectsList.module.scss?2041","webpack://core-admin_panel/./src/modules/Projects/components/ProjectsList/ProjectsList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/FilterDropdown/FilterDropdown.module.scss?1e77","webpack://core-admin_panel/./src/shared/components/CoreNewUI/SearchInput/SearchInput.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/SearchField/SearchField.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/Autocomplete/Autocomplete.module.scss?9a3f","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlBtnOption/CtrlBtnOption.module.scss?6778","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlBtnOption/CtrlBtnOption.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/Autocomplete/Autocomplete.tsx","webpack://core-admin_panel/./src/shared/hooks/useKey.ts","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlDrop/CtrlDrop.module.scss?39f3","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlDrop/CtrlDrop.tsx","webpack://core-admin_panel/./src/modules/Projects/components/ProjectsFilterAndSearch/helpers.ts","webpack://core-admin_panel/./src/modules/Projects/components/ProjectsFilterAndSearch/ProjectsFilterAndSearch.tsx","webpack://core-admin_panel/./src/modules/Projects/Projects.tsx","webpack://core-admin_panel/./src/modules/ResetPassword/resetPassword.module.scss?444a","webpack://core-admin_panel/./src/modules/ResetPassword/ResetPassword.tsx","webpack://core-admin_panel/./src/shared/hooks/useWorkflowStatuses.ts","webpack://core-admin_panel/./src/shared/hooks/UseTaskStatusOptions.ts","webpack://core-admin_panel/./src/modules/SharedTask/hooks/useSharedTaskStatusOptions.ts","webpack://core-admin_panel/./src/shared/hooks/core/useToggle.ts","webpack://core-admin_panel/./src/shared/components/TaskStatusHistory/index.ts","webpack://core-admin_panel/./src/shared/components/TaskStatusHistory/TaskStatusHistory.tsx","webpack://core-admin_panel/./src/modules/SharedTask/AppCard/AppCard.tsx","webpack://core-admin_panel/./src/modules/SharedTask/NotFound.tsx","webpack://core-admin_panel/./src/modules/SharedTask/Parts/AssigneesPart.tsx","webpack://core-admin_panel/./src/shared/components/CompletionAmountSlider/CompletionAmountSlider.module.scss?ce5f","webpack://core-admin_panel/./src/shared/components/CompletionAmountSlider/CompletionAmountSlider.tsx","webpack://core-admin_panel/./src/modules/SharedTask/Parts/AdditionalInfoPart/AdditionalInfoPart.tsx","webpack://core-admin_panel/./src/modules/SharedTask/Parts/TaskMainInfoPart/TaskMainInfoPart.tsx","webpack://core-admin_panel/./src/modules/SharedTask/Parts/DownloadAppPart.tsx","webpack://core-admin_panel/./src/modules/SharedTask/SharedTask.module.scss","webpack://core-admin_panel/./src/modules/SharedTask/TaskStatusSelect/TaskStatusSelect.tsx","webpack://core-admin_panel/./src/modules/SharedTask/SharedTask.tsx","webpack://core-admin_panel/./src/shared/components/MultiFactorDialog/MultiFactorDialog.tsx","webpack://core-admin_panel/./src/services/EventManager.ts","webpack://core-admin_panel/./src/store/onboarding/actions.ts","webpack://core-admin_panel/./src/modules/SignUp/Alternative/index.tsx","webpack://core-admin_panel/./src/modules/SignUp/index.tsx","webpack://core-admin_panel/./src/modules/SignUp/Alternative/GetStarted/GetStartedSignup.module.scss?d4b1","webpack://core-admin_panel/./src/modules/SignUp/Alternative/GetStarted/GetStartedSignup.tsx","webpack://core-admin_panel/./src/modules/SignUp/CongratsPopup/CongratsPopup.tsx","webpack://core-admin_panel/./src/shared/components/EmptyGridBubble/index.tsx","webpack://core-admin_panel/./src/shared/components/Toolbar/Toolbar.module.scss?c66b","webpack://core-admin_panel/./src/shared/components/Toolbar/Toolbar.tsx","webpack://core-admin_panel/./src/shared/components/ProjectLevelToolbar/ProjectLevelToolbar.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/FormControlInline/FieldInline/FieldInline.module.scss?643e","webpack://core-admin_panel/./src/shared/components/CoreNewUI/FormControlInline/FieldInline/FieldInline.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/FormControlInline/FormControlInline.module.scss?1a18","webpack://core-admin_panel/./src/shared/components/CoreNewUI/FormControlInline/FormControlInline.tsx","webpack://core-admin_panel/./src/shared/components/ProjectNameInlineEdit/ProjectNameInlineEdit.module.scss?7158","webpack://core-admin_panel/./src/shared/components/ProjectNameInlineEdit/ProjectNameInlineEdit.tsx","webpack://core-admin_panel/./src/shared/components/Table/Table.module.scss?1636","webpack://core-admin_panel/./src/shared/components/Table/components/Columns/TableColumns.tsx","webpack://core-admin_panel/./src/shared/components/Table/components/Columns/TableRow.tsx","webpack://core-admin_panel/./src/shared/components/Table/components/TableSortIndicator/TableSortIndicator.tsx","webpack://core-admin_panel/./src/shared/components/Table/Table.tsx","webpack://core-admin_panel/./src/shared/components/WorkspaceSwitcher/WorkspaceSwitcher.module.scss?4e78","webpack://core-admin_panel/./src/shared/components/WorkspaceSwitcher/WorkspaceSwitcher.tsx","webpack://core-admin_panel/./src/shared/hooks/useProjectWorkers.tsx","webpack://core-admin_panel/./src/shared/hooks/useResponsibleOrgColors.ts","webpack://core-admin_panel/./src/shared/hooks/useSaveLastSelectedProjectId.ts","webpack://core-admin_panel/./src/shared/hooks/useProjectIdValidation.ts","webpack://core-admin_panel/./src/shared/constants/localStorageKeys.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsContext/index.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/hooks/useGetSubcontractor.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/CtrlColor/CtrlColor.module.scss?ec7c","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/CtrlColor/CtrlColor.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/ColorsList/ColorsList.module.scss?b47f","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/ColorsList/ColorsList.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/components/CtrlColorPreview/CtrlColorPreview.module.scss?1e63","webpack://core-admin_panel/./src/modules/Subcontractors/components/CtrlColorPreview/CtrlColorPreview.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/utils/getSimilarNames.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/hooks/useSimilarSubcontractors.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/utils/detectNameCollisions.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/Subcontactor/SubcontractorForm/components/SubcontractorSimilar/SubcontractorSimilar.module.scss?264e","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/Subcontactor/SubcontractorForm/components/SubcontractorSimilar/SubcontractorSimilar.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/Subcontactor/SubcontractorForm/SubcontractorForm.module.scss?7810","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/Subcontactor/SubcontractorForm/SubcontractorForm.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/InfoMember/InfoMember.module.scss?3d3c","webpack://core-admin_panel/./src/shared/components/CoreNewUI/InfoMember/InfoMember.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/AsyncCompanyWorkerSelect/components.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/AsyncCompanyWorkerSelect/index.module.scss","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/AsyncCompanyWorkerSelect/AsyncCompanyWorkerSelect.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/Subcontactor/SubcontractorMember/SubcontractorMember.module.scss?d036","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/components/Subcontactor/SubcontractorMember/SubcontractorMember.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/SubcontractorTab.module.scss?72c3","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/components/SubcontractorTab/SubcontractorTab.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/constants/validation.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/hooks/mutations.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/hooks/useHandleSubcontractors.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/SubcontractorsPanel.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorsPanel/SubcontractorsPanel.module.scss?97eb","webpack://core-admin_panel/./src/modules/Subcontractors/hooks/useGetSubcontractors.ts","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorInfo/SubcontractorInfo.module.scss?bf96","webpack://core-admin_panel/./src/modules/Subcontractors/components/SubcontractorInfo/SubcontractorInfo.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/hooks/useSubcontractorsColumns.tsx","webpack://core-admin_panel/./src/modules/Subcontractors/Subcontractors.module.scss?cbf5","webpack://core-admin_panel/./src/modules/Subcontractors/utils/utils.ts","webpack://core-admin_panel/./src/modules/Subcontractors/Subcontractors.tsx","webpack://core-admin_panel/./src/modules/Tasks/hooks/useRemovePreviousProjectActivities.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/hooks/useUndo.ts","webpack://core-admin_panel/./src/store/projects/selectors.ts","webpack://core-admin_panel/./src/shared/hooks/useOptionsForSelect.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/FilterDropdown/useLocationsOptions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/FilterDropdown/useProjectSubcontractorOptions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/FilterDropdown/useTaskStatusOptions.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/FilterDropdown/useResponsibleOptions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/components/constants.ts","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/components/IssuesFilterDropdown.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/AsyncProjectWorkerSelect/components.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/AsyncProjectWorkerSelect/AsyncProjectWorkerSelect.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/components/utils.ts","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/TaskStatusSelect/TaskStatusSelect.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/IssuesBulkActions.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/components/bulkStatus.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/components/bulkResponsible.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/hooks/useBulkActions.ts","webpack://core-admin_panel/./src/shared/prediction/date-expander.ts","webpack://core-admin_panel/./src/shared/prediction/TaskGraph.ts","webpack://core-admin_panel/./src/shared/prediction/expander.ts","webpack://core-admin_panel/./src/shared/utils/normalizeI18Key.ts","webpack://core-admin_panel/./src/modules/Tasks/hooks/useTasksActions.ts","webpack://core-admin_panel/./src/services/TasksObserver/TasksObserverProvider.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/components/useDeleteOneSelectedIssue.ts","webpack://core-admin_panel/./src/shared/components/ProjectCollabPopup/helpers.ts","webpack://core-admin_panel/./src/shared/components/ProjectCollabPopup/ProjectCollabPopup.module.scss?fff9","webpack://core-admin_panel/./src/shared/components/ProjectCollabPopup/ProjectCollabPopup.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/CtrlDates/CtrlDates.module.scss?30ef","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/CtrlDates/CtrlDates.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/DatePicker/index.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlChip/CtrlChip.module.scss?ddc5","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlChip/CtrlChip.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlChipGroup/CtrlChipGroup.module.scss?f68b","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlChipGroup/CtrlChipGroup.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/DateDropdown/DateDropdown.module.scss?a419","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/DateDropdown/DateDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/hooks/useGanttZoom.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/utils/getOrg.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/ExportDropdown/ExportDropdown.module.scss?5909","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/ExportDropdown/util.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/ExportDropdown/ExportDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useRowsOpenState.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/utils.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Gantt/utils/baselineHandlers.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/date.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/ganttColumns.module.scss?8b05","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/useInlineSelectController.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/SelectEditor.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/CostImpactEditor.tsx","webpack://core-admin_panel/./src/shared/hooks/useCrews.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/CrewSelector.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/CustomFields/CustomFieldSelectEditor/CustomFieldSelectorEditor.module.scss","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/CustomFields/CustomFieldSelectEditor/CustomFieldSelectEditor.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/IssueTypeEditor.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/CreatableSelect/CreatableSelect.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/LocationEditor.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/ResponsibleEditor/index.module.scss","webpack://core-admin_panel/./src/shared/utils/inviteWorker.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MemberInvite/MemberInvite.module.scss?aaf2","webpack://core-admin_panel/./src/modules/Worker/mutations.ts","webpack://core-admin_panel/./src/modules/Worker/WorkerForm/validation.ts","webpack://core-admin_panel/./src/modules/Worker/WorkerForm/ShortWorkerForm.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/popups/InviteTaskResponsible.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/ResponsibleEditor/ResponsibleEditor.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/SeverityEditor.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/StatusEditor.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/SubcontractorEditor.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/AsyncTaskTypeSelect/index.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/TaskTypeEditor.tsx","webpack://core-admin_panel/./src/shared/hooks/useZones.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/ZoneSelector.tsx","webpack://core-admin_panel/./src/routerHistory.ts","webpack://core-admin_panel/./src/services/TaskChainUpdateQueue/TaskChainUpdateQueue.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/inlineEditors.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/config.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useGanttColumns.ts","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlCheckOption/CtrlCheckOption.module.scss?3b42","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlCheckOption/CtrlCheckOption.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/GanttColumnsDropdown/GanttColumnsDropdown.module.scss","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/GanttColumnsDropdown/ProjectCustomColumnPopup/ProjectCustomColumnPopup.module.scss?b652","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/GanttColumnsDropdown/ProjectCustomColumnPopup/ProjectCustomColumnPopup.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/GanttColumnsDropdown/GanttColumnsDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Toolbar/Toolbar.module.scss?edcc","webpack://core-admin_panel/./src/modules/Tasks/components/Toolbar/ToolbarMoreActions.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Toolbar/ToolbarSection.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Toolbar/Toolbar.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Toolbar/ToolbarItem.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/IssuesActionsBar.module.scss?10f5","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/IssuesActionsBar.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/IssuesActionsBar/useIssuesBulkActions.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/NoDataBubble.tsx","webpack://core-admin_panel/./src/modules/Tasks/utils/simpleLock.ts","webpack://core-admin_panel/./src/shared/components/ShareTask/index.tsx","webpack://core-admin_panel/./src/shared/hooks/useIsTablet.tsx","webpack://core-admin_panel/./src/store/tasks/selectors.ts","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/BaselineDropdown.module.scss","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/components/DateControl/DateControl.module.scss?ee4d","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/components/DateControl/DateControl.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/InfoWorker/InfoWorker.module.scss?ea6a","webpack://core-admin_panel/./src/shared/components/CoreNewUI/InfoWorker/InfoWorker.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/components/Snapshot/Snapshot.module.scss?5111","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/components/Snapshot/Snapshot.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/components/SnapshotsList/SnapshotsList.module.scss","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/components/SnapshotsList/SnapshotsList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/components/Baseline/Baseline.module.scss?86b0","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/BaselineDropdown/BaselineDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/ColorByButton/ColorTasksModeBtn.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlColorPicker/components/CtrlColor/CtrlColor.module.scss?6de8","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlColorPicker/components/CtrlColor/CtrlColor.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlColorPicker/CtrlColorPicker.module.scss?9f91","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlColorPicker/CtrlColorPicker.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/ColorDropdown/ColorDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/ColorDropdown/ColorDropdown.module.scss","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/DateDropdown/DailiesDateDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/DateDropdown/GanttVisualDateDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/TodayButton.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/FilterDropdown/WBSAutocomplete.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/DailiesActionBar/DailiesFilterDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/utils/generateTaskLayer.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/usePrint/constants.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/usePrint/functions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/TasksActionsBar.module.scss?3998","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/useTasksBulkOperations.ts","webpack://core-admin_panel/./src/shared/components/WorkerStatus/index.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/WorkerStatusSelect/index.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/StatusSelect.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkWatcher/BulkWatcher.module.scss?396e","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkWatcher/components.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkWatcher/utils.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/TasksBulkActions.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkResponsible/BulkResponsible.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkSubcontractor/BulkSubcontractor.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkLocation/BulkLocation.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkType/BulkType.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/bulkPopups/BulkStatus/BulkStatus.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlSwitcher/CtrlSwitcher.module.scss?4e60","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlSwitcher/CtrlSwitcher.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/TasksFilterDropdown.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/ActionsBar/components/FilterDropdown/useTaskTypeOptions.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/TasksActionsBar.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/TasksActionsBar/useTasksBulkActions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/usePrint/usePrint.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/InfoGallery/components/GalleryEmpty/GalleryEmpty.module.scss?e914","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/InfoGallery/components/GalleryEmpty/GalleryEmpty.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/ImageGallery/ImageGallery.module.scss?66cd","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/ImageGallery/ImageGallery.tsx","webpack://core-admin_panel/./src/shared/components/Pill/styles.module.scss?d0ac","webpack://core-admin_panel/./src/shared/components/Pill/Pill.tsx","webpack://core-admin_panel/./src/modules/Tasks/utils/updateSearchQuery.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/utils/handler.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesReportCard/DailyCardSeparator.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesReportCard/DailiesCardComments.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/utils/formatting.ts","webpack://core-admin_panel/./src/shared/components/Spacer/HSpacer.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/hooks/useFetchDailiesIssues.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesReportCard/ActivityIssues.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesReportCard/DailyCardHeader.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesReportCard/DailiesReportCard.tsx","webpack://core-admin_panel/./src/shared/helpers/reports.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesReportCard/DailiesCardReportContent.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesGeneralComments/DailiesGeneralComments.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/hooks/useDailiesGeneralComments.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/hooks/utils/groupGeneralComments.ts","webpack://core-admin_panel/./src/shared/components/ProgressReport/utils/validationSchema.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/utils/commentFormValidationSchema.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/utils/handlePostGeneralComments.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesCommentForm.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentCard/hooks/utils/groupFeedback.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/hooks/useDailiesReports.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/hooks/useFetchDailiesTasks.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/hooks/utils/mergeFeedback.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/hooks/useCurrentDateReports.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesReportHeader.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailiesReportIssues.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReportingPopup/ProgressReportPopupProvider.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailyTasksWithNoReports/DailyTasksWithNoReports.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/DailyTaskWithReport/DailyTaskWithReport.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Dailies/Dailies.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/IssueUpdatesPopup/IssueUpdatesPopup.module.scss?b6b8","webpack://core-admin_panel/./src/shared/components/CoreNewUI/IssueUpdatesPopup/IssueUpdatesPopup.tsx","webpack://core-admin_panel/./src/shared/components/TasksBulkAssignPopup/TasksBulkAssignPopup.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/TaskContextMenu/TaskContextMenu.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/Editors/DateEditor.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useDetectNewTask.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Filters/utils/dateRange.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useWeeksRange.ts","webpack://core-admin_panel/./src/modules/Tasks/hooks/useIssuesDictionary.tsx","webpack://core-admin_panel/./src/modules/Tasks/utils/asyncHelpers.ts","webpack://core-admin_panel/./src/shared/hooks/core/useEffectAfterMount.ts","webpack://core-admin_panel/./src/api/weather.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/components/ProjectCalendarConvertDay/ProjectCalendarConvertDay.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/GanttView.module.scss?df66","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useNavigateToMentions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useTaskMentionClickHandler.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/plugins/ganttPlugin.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/plugins/copyPaste.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/plugins/statusIcon.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/plugins/checkboxColumnPlugin.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/plugins/contextMenuPlugin.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/handlers.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/layers.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/GanttView.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useActiveTask.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/plugins/useGanttPlugins.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useGanttScrollPosition.ts","webpack://core-admin_panel/./src/shared/hooks/useGanttSubcontractorColors.tsx","webpack://core-admin_panel/./src/shared/hooks/useGanttWeatherReport.tsx","webpack://core-admin_panel/./src/shared/hooks/useGanttLabelCategories.tsx","webpack://core-admin_panel/./src/shared/hooks/useLabelCategories.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useHideContextOnGanttScroll.tsx","webpack://core-admin_panel/./src/modules/Tasks/utils/handleInitialStateParams.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useGanttScrollListener.ts","webpack://core-admin_panel/./src/shared/prediction/utils.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/dataProcessors.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/layout.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/zoomLevels.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/utils/helpers.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/utils/validationSchema.ts","webpack://core-admin_panel/./src/shared/components/Tabs/TabsContext.tsx","webpack://core-admin_panel/./src/shared/components/Tabs/Tabs.tsx","webpack://core-admin_panel/./src/shared/components/Tabs/Tab.tsx","webpack://core-admin_panel/./src/shared/components/Tabs/TabsContentContainer.tsx","webpack://core-admin_panel/./src/shared/components/Tabs/TabsHeader.module.scss?3d68","webpack://core-admin_panel/./src/shared/components/Tabs/TabsHeader.tsx","webpack://core-admin_panel/./src/shared/utils/prepareAssignees.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/PanelSection/PanelSection.module.scss?f99b","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/PanelSection/PanelSection.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/WbsSection/Wbs/Wbs.module.scss?ca35","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/WbsSection/Wbs/Wbs.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/WbsSection/WbsSection.tsx","webpack://core-admin_panel/./src/api/gantt.ts","webpack://core-admin_panel/./src/shared/hooks/useSubtaskCount.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/utils/constants.ts","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlCard/CtrlCard.module.scss?d833","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlCard/CtrlCard.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/CoreNativeDatePicker/CoreNativeDatePicker.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActionsList/ActionsForm/ActionsForm.module.scss?6f84","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActionsList/ActionsForm/ActionsForm.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActionsList/Action/Action.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActionsList/ActionsList.module.scss?c90b","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActionsList/utils.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActionsList/ActionsList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Collapse/Collpase.module.scss?a586","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Collapse/Collapse.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActivityForm/ActivityForm.module.scss?5acf","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CustomFieldSection/CustomFieldSection.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/utils/helpers.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/InfoGallery/InfoGallery.module.scss?e4e9","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/InfoGallery/InfoGallery.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/hooks/useLoadTaskChatHistory.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/InfoLinksList/InfoLinksList.module.scss?569f","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/InfoLinksList/InfoLinksList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActivityForm/constants.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/ActivityForm/ActivityForm.tsx","webpack://core-admin_panel/./src/shared/helpers/gantt.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/DependenciesList/DependenciesList.module.scss?4a72","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/TaskAsyncSelect/index.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/DependenciesList/DependencyForm/DependencyForm.module.scss?d825","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/DependenciesList/DependencyForm/DependencyForm.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/DependenciesList/Dependency/Dependency.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/DependenciesList/Dependency/Dependency.module.scss","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/DependenciesList/DependenciesList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/Comments.module.scss?a160","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/components/CommentsAction/CommentsAction.module.scss?cd8e","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/components/CommentsClear/CommentsClear.module.scss?b0b4","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/components/CommentsDate/CommentsDate.module.scss?c5d1","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/components/CommentsNew/CommentsNew.module.scss?ffda","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/Comments.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/components/CommentsAction/CommentsAction.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/components/CommentsClear/CommentsClear.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/components/CommentsDate/CommentsDate.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Comments/components/CommentsNew/CommentsNew.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/InfoHistory/InfoHistory.module.scss?2c08","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/InfoHistory/InfoHistory.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/HistoryList/HistoryList.module.scss?d980","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/HistoryList/HistoryList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/IssuesList/IssueForm.module.scss?b110","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/IssuesList/IssueForm.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/IssuesList/Issue.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/IssuesList/IssuesList.module.scss?c856","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/IssuesList/IssuesList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/PanelInfo/PanelInfo.module.scss?2e8e","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/PanelInfo/PanelInfo.tsx","webpack://core-admin_panel/./src/shared/components/TaskAssigneersFilter/index.module.scss?ef5c","webpack://core-admin_panel/./src/modules/Worker/queries.ts","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/AsyncCompanyOrgsSelect/index.tsx","webpack://core-admin_panel/./src/shared/constants/worker.ts","webpack://core-admin_panel/./src/shared/hooks/useLoadWorkerTrades.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/AssigneesTabContext.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MemberInvite/MemberInvite.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Member/Member.module.scss?22b4","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Member/Member.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Suggestions/Suggestions.module.scss?4e48","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Suggestions/Suggestions.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MembersAdd/MembersAdd.module.scss?d4fb","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MembersAdd/MembersAdd.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/utils/functions.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MembersList/components/SelectGroup.module.scss?a801","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MembersList/components/SelectGroup.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MembersList/MembersList.module.scss?7656","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MembersList/MembersList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/SearchWorkers.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/ResponsibleSection/ReassignmentResponsible.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MembersClear/MembersClear.module.scss?7b8c","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/MembersClear/MembersClear.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/ResponsibleSection/ResponsibleEmpty.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/Responsible/Responsible.module.scss?622a","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/ResponsibleSection/ResponsibleSelected.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/ResponsibleSection/ResponsibleSection.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/WatchersSection/AddNewWatchers.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/WatchersSection/SelectedWatchersList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/WatchersSection/WatchersEmpty.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/components/WatchersSection/WatchersSection.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/AssigneesTab/AssigneesTab.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/ChatTimeline/EmptyChatTimeline/ChatTimelinePlaceholder.module.scss?ad33","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/ChatTimeline/EmptyChatTimeline/ChatTimelinePlaceholder.tsx","webpack://core-admin_panel/./src/api/groups.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentCard/styles.module.scss?2076","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentCard/utils/index.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentCard/CommentCard.tsx","webpack://core-admin_panel/./src/shared/hooks/useGetGroup.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentCard/CommentList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentCard/hooks/useCommentsFeed.ts","webpack://core-admin_panel/./src/shared/hooks/useFetchFeedback.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentForm/styles.module.scss?50bd","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentForm/CommentForm.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTimeline/CommentsTimeline.tsx","webpack://core-admin_panel/./src/shared/hooks/useCalculatePosition.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/ChatTimeline/ChatTimeline.module.scss","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/ChatTimeline/index.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/components/CommentsTab/CommentsTab.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/utils/types.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/ActivityPanel/utils/getPreparedFormikValues.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/ActivityPanel/ActivityPanel.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/utils/hooks.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/hooks/useActivityMembers.ts","webpack://core-admin_panel/./src/shared/hooks/useTaskState.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/utils/methods.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/ActivityPanel/ActivityPanel.module.scss?2cbe","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/constants.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/ActivitiesList/ActivitiesList.module.scss?aaa8","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/ActivitiesList/ActivityListItem/ActivityListItem.module.scss?93d1","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/ActivitiesList/ActivityListItem/ActivityListItem.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/ActivitiesList/utils/mapActivitiesToSelectTaskOptions.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/ActivitiesList/ActivitiesList.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/IssuePanelForm/IssuePanelForm.module.scss?c5fd","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/components/IssuePanelForm/IssuePanelForm.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/IssuePanel.module.scss?f212","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/utils/getChangedFields.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/utils/getPreparedFormValues.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/utils/validationSchema.ts","webpack://core-admin_panel/./src/modules/Tasks/components/SidebarPanel/IssuePanel/IssuePanel.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Gantt/GanttDefaultView.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/GanttVisual/GanttVisual.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Issues/utils.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Issues/Issues.tsx","webpack://core-admin_panel/./src/modules/Tasks/Views/Lookahead/utils/handlers.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Lookahead/utils/config.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/Lookahead/GanttLookaheadView.tsx","webpack://core-admin_panel/./src/modules/Worker/hooks/useWorkerPath.ts","webpack://core-admin_panel/./src/shared/components/ErrorBoundary/ErrorBoundary.tsx","webpack://core-admin_panel/./src/shared/components/ErrorBoundary/ErrorBoundary.module.scss?5316","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/shared.module.scss?fa6c","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/ActualManpowerCounter/actualManpowerCounter.module.scss?1cd7","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/ActualManpowerCounter/index.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/ProgressSlider/progressSlider.module.scss?5419","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/ProgressSlider/index.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/DailyCard/dailyCard.module.scss?2c59","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/DailyCard/DailyCard.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/InlineFormElements/InlineFormElements.module.scss?107f","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/InlineFormElements/InlineInput.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/components/InlineFormElements/InlineSelect.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/hooks/useProgressReport.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/hooks/useScrollAfterLoading.ts","webpack://core-admin_panel/./src/shared/components/ProgressReport/progressReport.module.scss?844a","webpack://core-admin_panel/./src/shared/components/ProgressReport/ProgressReportCommentForm/components.module.scss?67d2","webpack://core-admin_panel/./src/shared/components/ProgressReport/ProgressReportCommentForm/ProgressReportCommentForm.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/ProgressReport.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/hooks/useHandleSubmitProgressReport.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReportingPopup/progressReportPopup.module.scss?b41f","webpack://core-admin_panel/./src/shared/components/ProgressReportingPopup/ProgressReportingPopup.tsx","webpack://core-admin_panel/./src/shared/components/TimelineBadge/TimelineBadge.module.scss","webpack://core-admin_panel/./src/shared/components/TimelineBadge/TimelineBadge.tsx","webpack://core-admin_panel/./src/shared/hooks/useQueryKeys.ts","webpack://core-admin_panel/./src/shared/hooks/useTaskCacheHlper/helpers.ts","webpack://core-admin_panel/./src/modules/Tasks/Views/View.tsx","webpack://core-admin_panel/./src/shared/hooks/useTaskCacheHlper/useTaskCacheHelper.ts","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useLoadRowNumbersAndLinks.ts","webpack://core-admin_panel/./src/services/TasksObserver/UseTasksObserver.tsx","webpack://core-admin_panel/./src/services/TasksObserver/utils.ts","webpack://core-admin_panel/./src/shared/components/TutorialPopup/tutorialPopup.module.scss?f0b2","webpack://core-admin_panel/./src/shared/components/TutorialPopup/TutorialPopup.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/popups/TasksTutorialPopup.tsx","webpack://core-admin_panel/./src/modules/Tasks/Tasks.tsx","webpack://core-admin_panel/./src/modules/Tasks/hooks/useTasksInterceptor.ts","webpack://core-admin_panel/./src/shared/helpers/statuses.ts","webpack://core-admin_panel/./src/modules/Worker/ProfileStatus/ProfileStatus.tsx","webpack://core-admin_panel/./src/modules/Worker/WorkerCard/WorkerCard.module.scss","webpack://core-admin_panel/./src/modules/Worker/WorkerCard/WorkerCard.tsx","webpack://core-admin_panel/./src/modules/Worker/WorkerForm/WorkerForm.tsx","webpack://core-admin_panel/./src/modules/Worker/WorkerProfile/WorkerProfile.tsx","webpack://core-admin_panel/./src/modules/Worker/WorkerTasks/WorkerTasks.module.scss?76bc","webpack://core-admin_panel/./src/modules/Worker/WorkerTasks/WorkerTasks.tsx","webpack://core-admin_panel/./src/modules/Worker/WorkerDetails.tsx","webpack://core-admin_panel/./src/modules/Worker/CompanyWorker.tsx","webpack://core-admin_panel/./src/modules/Worker/ProjectWorker.tsx","webpack://core-admin_panel/./src/modules/Worker/hooks/useProjectWorker.tsx","webpack://core-admin_panel/./src/modules/Worker/Worker.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlSwitch/CtrlSwitch.module.scss?83a4","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlSwitch/CtrlSwitch.tsx","webpack://core-admin_panel/./src/modules/Worker/Profile/components/ReAuthUserPopup/ReAuthUserPopup.tsx","webpack://core-admin_panel/./src/modules/Worker/Profile/components/TwoFactor/TwoFactorAuthSettings.module.scss?2107","webpack://core-admin_panel/./src/modules/Worker/Profile/components/TwoFactor/TwoFactorAuthSettings.tsx","webpack://core-admin_panel/./src/modules/Worker/Profile/validationSchema.ts","webpack://core-admin_panel/./src/modules/Worker/Profile/Profile.tsx","webpack://core-admin_panel/./src/shared/components/Table/components/Columns/Centered.tsx","webpack://core-admin_panel/./src/modules/Workers/Columns/TextArrayColumn.tsx","webpack://core-admin_panel/./src/modules/Workers/Columns/Name/NameColumn.module.scss?c395","webpack://core-admin_panel/./src/modules/Workers/Columns/Name/NameColumn.tsx","webpack://core-admin_panel/./src/modules/Workers/Columns/Orgs/OrgsColumn.module.scss?3db1","webpack://core-admin_panel/./src/modules/Workers/Columns/Orgs/OrgsColumn.tsx","webpack://core-admin_panel/./src/modules/Workers/Columns/Status/StatusColumn.module.scss?9f55","webpack://core-admin_panel/./src/modules/Workers/Columns/Status/StatusColumn.tsx","webpack://core-admin_panel/./src/modules/Workers/utils/constants.ts","webpack://core-admin_panel/./src/modules/Workers/FilterDropdown/FilterDropdown.tsx","webpack://core-admin_panel/./src/modules/Workers/Workers.module.scss","webpack://core-admin_panel/./src/modules/Workers/Workers.tsx","webpack://core-admin_panel/./src/shared/components/ProfileLoader/ProfileLoader.tsx","webpack://core-admin_panel/./src/shared/hooks/useHandleMentionRedirects.ts","webpack://core-admin_panel/./src/shared/components/ProtectedRoute/index.tsx","webpack://core-admin_panel/./src/shared/components/UnauthenticatedRoute/index.tsx","webpack://core-admin_panel/./src/shared/hooks/core/useMounted.ts","webpack://core-admin_panel/./src/MainRoutes.tsx","webpack://core-admin_panel/./src/shared/hooks/useCompanyDataLoader.ts","webpack://core-admin_panel/./src/shared/hooks/useSentryUserInfo.ts","webpack://core-admin_panel/./src/shared/helpers/mobx.ts","webpack://core-admin_panel/./src/shared/helpers/sentry.ts","webpack://core-admin_panel/./src/App.tsx","webpack://core-admin_panel/./src/react-i18next.config.js","webpack://core-admin_panel/./src/index.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Filters/FilterProvider.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Filters/utils/constants.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/hooks/useGanttLayoutSettings.tsx","webpack://core-admin_panel/./src/modules/Tasks/components/Gantt/utils/eventStore.tsx","webpack://core-admin_panel/./src/modules/Tasks/hooks/useViewMode.tsx","webpack://core-admin_panel/./src/shared/components/AuthUserProvider/AuthUserProvider.tsx","webpack://core-admin_panel/./src/shared/components/Button/index.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/Confirmation.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/ConfirmationCleanLayout.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/ConfirmationPopup.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/NewConfirmation.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/components/ActionButton.module.scss?96bb","webpack://core-admin_panel/./src/shared/components/Confirmation/components/ActionButton.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/components/Description.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/useConfirm/useConfirm.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/useConfirm/ConfirmationContext.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/useConfirm/ConfirmationWrapper.tsx","webpack://core-admin_panel/./src/shared/components/Confirmation/useConfirm/state.ts","webpack://core-admin_panel/./src/shared/components/Confirmation/useConfirm/ConformationProvider.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/DropdownIndicator/DropdownIndicator.tsx","webpack://core-admin_panel/./src/shared/components/CoreForm/Select/Select.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlButton/CtrlButton.module.scss?eee4","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlButton/CtrlButton.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlCheck/CtrlCheck.module.scss?8a9b","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlCheck/CtrlCheck.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlCheckGroup/CtrlCheckGroup.module.scss?b4ce","webpack://core-admin_panel/./src/shared/components/CoreNewUI/CtrlCheckGroup/CtrlCheckGroup.tsx","webpack://core-admin_panel/./src/shared/components/CoreNewUI/FormControl/FormControl.module.scss?7770","webpack://core-admin_panel/./src/shared/components/CoreNewUI/FormControl/FormControl.tsx","webpack://core-admin_panel/./src/shared/components/Icon/index.tsx","webpack://core-admin_panel/./src/shared/components/Loader/index.tsx","webpack://core-admin_panel/./src/shared/components/Popup/PopupContent.tsx","webpack://core-admin_panel/./src/shared/components/Popup/Popup.tsx","webpack://core-admin_panel/./src/shared/components/ProgressReport/hooks/useInitializeMatrixSession.tsx","webpack://core-admin_panel/./src/shared/components/Spacer/VSpacer.tsx","webpack://core-admin_panel/./src/shared/constants/routes.tsx","webpack://core-admin_panel/./src/shared/hooks/useCompanyWorkerRoles.tsx","webpack://core-admin_panel/./src/shared/hooks/useLocalStorage.tsx","webpack://core-admin_panel/./src/store/ducks/auth/reducers.tsx","webpack://core-admin_panel/./src/store/workers/actions.ts","webpack://core-admin_panel/./src/store/workers/index.ts","webpack://core-admin_panel/./src/store/index.tsx","webpack://core-admin_panel/./src/store/ducks/index.tsx"],"sourcesContent":["// extracted by css-extract-rspack-plugin\nexport default {\"confirmation\":\"confirmation-ee6BRq\",\"confirmation__item\":\"confirmation__item-tWpWcI\",\"confirmationItem\":\"confirmation__item-tWpWcI\",\"confirmation__header\":\"confirmation__header-YqJXdM\",\"confirmationHeader\":\"confirmation__header-YqJXdM\",\"confirmation__title\":\"confirmation__title-qgJ21P\",\"confirmationTitle\":\"confirmation__title-qgJ21P\",\"confirmation__footer\":\"confirmation__footer-Vgxl4m\",\"confirmationFooter\":\"confirmation__footer-Vgxl4m\",\"confirmation__footer--actions\":\"confirmation__footer--actions-V8G1Oe\",\"confirmationFooterActions\":\"confirmation__footer--actions-V8G1Oe\",\"confirmation__button\":\"confirmation__button-levnUT\",\"confirmationButton\":\"confirmation__button-levnUT\",\"confirmation__button--cancel\":\"confirmation__button--cancel-d3dvMk\",\"confirmationButtonCancel\":\"confirmation__button--cancel-d3dvMk\",\"confirmation__button-close\":\"confirmation__button-close-jLRfg4\",\"confirmationButtonClose\":\"confirmation__button-close-jLRfg4\"};","// extracted by css-extract-rspack-plugin\nexport default {\"h-spacer-1\":\"h-spacer-1-GOhK_c\",\"hSpacer1\":\"h-spacer-1-GOhK_c\",\"v-spacer-1\":\"v-spacer-1-VcszS4\",\"vSpacer1\":\"v-spacer-1-VcszS4\",\"h-spacer-2\":\"h-spacer-2-VgbaF9\",\"hSpacer2\":\"h-spacer-2-VgbaF9\",\"v-spacer-2\":\"v-spacer-2-w33pCB\",\"vSpacer2\":\"v-spacer-2-w33pCB\",\"h-spacer-3\":\"h-spacer-3-pzA7zf\",\"hSpacer3\":\"h-spacer-3-pzA7zf\",\"v-spacer-3\":\"v-spacer-3-rCNKSR\",\"vSpacer3\":\"v-spacer-3-rCNKSR\",\"h-spacer-4\":\"h-spacer-4-QufGnu\",\"hSpacer4\":\"h-spacer-4-QufGnu\",\"v-spacer-4\":\"v-spacer-4-jgD94C\",\"vSpacer4\":\"v-spacer-4-jgD94C\",\"h-spacer-5\":\"h-spacer-5-lEeG0k\",\"hSpacer5\":\"h-spacer-5-lEeG0k\",\"v-spacer-5\":\"v-spacer-5-KhgHVB\",\"vSpacer5\":\"v-spacer-5-KhgHVB\",\"h-spacer-6\":\"h-spacer-6-jQquTs\",\"hSpacer6\":\"h-spacer-6-jQquTs\",\"v-spacer-6\":\"v-spacer-6-zzEbBr\",\"vSpacer6\":\"v-spacer-6-zzEbBr\",\"h-spacer-7\":\"h-spacer-7-qUQBpT\",\"hSpacer7\":\"h-spacer-7-qUQBpT\",\"v-spacer-7\":\"v-spacer-7-l2B1JB\",\"vSpacer7\":\"v-spacer-7-l2B1JB\",\"h-spacer-8\":\"h-spacer-8-KmXtOX\",\"hSpacer8\":\"h-spacer-8-KmXtOX\",\"v-spacer-8\":\"v-spacer-8-NvhNbb\",\"vSpacer8\":\"v-spacer-8-NvhNbb\",\"h-spacer-9\":\"h-spacer-9-fZ0dN_\",\"hSpacer9\":\"h-spacer-9-fZ0dN_\",\"v-spacer-9\":\"v-spacer-9-YAU3kn\",\"vSpacer9\":\"v-spacer-9-YAU3kn\",\"h-spacer-10\":\"h-spacer-10-kP1XDX\",\"hSpacer10\":\"h-spacer-10-kP1XDX\",\"v-spacer-10\":\"v-spacer-10-yHLFt9\",\"vSpacer10\":\"v-spacer-10-yHLFt9\",\"h-spacer-11\":\"h-spacer-11-xYA0_V\",\"hSpacer11\":\"h-spacer-11-xYA0_V\",\"v-spacer-11\":\"v-spacer-11-lhh6R4\",\"vSpacer11\":\"v-spacer-11-lhh6R4\",\"h-spacer-12\":\"h-spacer-12-eWrrXM\",\"hSpacer12\":\"h-spacer-12-eWrrXM\",\"v-spacer-12\":\"v-spacer-12-tPfJp7\",\"vSpacer12\":\"v-spacer-12-tPfJp7\",\"h-spacer-13\":\"h-spacer-13-jEcYox\",\"hSpacer13\":\"h-spacer-13-jEcYox\",\"v-spacer-13\":\"v-spacer-13-Krew6M\",\"vSpacer13\":\"v-spacer-13-Krew6M\",\"h-spacer-14\":\"h-spacer-14-blObR7\",\"hSpacer14\":\"h-spacer-14-blObR7\",\"v-spacer-14\":\"v-spacer-14-n01TMi\",\"vSpacer14\":\"v-spacer-14-n01TMi\"};","// extracted by css-extract-rspack-plugin\nexport default {\"progressbar__container\":\"progressbar__container-qjs77C\",\"progressbarContainer\":\"progressbar__container-qjs77C\",\"custom-column-heading\":\"custom-column-heading-VpKGyr\",\"customColumnHeading\":\"custom-column-heading-VpKGyr\",\"custom-column-heading--cta\":\"custom-column-heading--cta-L41neN\",\"customColumnHeadingCta\":\"custom-column-heading--cta-L41neN\",\"custom-column-heading--cta-icon\":\"custom-column-heading--cta-icon-rJFf5L\",\"customColumnHeadingCtaIcon\":\"custom-column-heading--cta-icon-rJFf5L\",\"custom-column-heading--cta-icon--disabled\":\"custom-column-heading--cta-icon--disabled-Q32eVn\",\"customColumnHeadingCtaIconDisabled\":\"custom-column-heading--cta-icon--disabled-Q32eVn\",\"custom-column-item\":\"custom-column-item-hPHLcd\",\"customColumnItem\":\"custom-column-item-hPHLcd\",\"custom-column-label\":\"custom-column-label-Rd3zMi\",\"customColumnLabel\":\"custom-column-label-Rd3zMi\",\"custom-column-input\":\"custom-column-input-L5iQa9\",\"customColumnInput\":\"custom-column-input-L5iQa9\",\"custom-column-select-wrapper\":\"custom-column-select-wrapper-sN7OvY\",\"customColumnSelectWrapper\":\"custom-column-select-wrapper-sN7OvY\",\"custom-column-delete\":\"custom-column-delete-nlr8hi\",\"customColumnDelete\":\"custom-column-delete-nlr8hi\",\"custom-column-delete--is-submitting\":\"custom-column-delete--is-submitting-boGwXZ\",\"customColumnDeleteIsSubmitting\":\"custom-column-delete--is-submitting-boGwXZ\",\"tableHeader\":\"tableHeader-a9MRou\",\"tableBody\":\"tableBody-U3rWqr\",\"table__cell--default\":\"table__cell--default-sy49E8\",\"tableCellDefault\":\"table__cell--default-sy49E8\",\"footer\":\"footer-FiIgFA\",\"tableScrollContainer\":\"tableScrollContainer-wJIOEz\",\"aka-table__th-content--start\":\"aka-table__th-content--start-KhTTCF\",\"akaTableThContentStart\":\"aka-table__th-content--start-KhTTCF\"};","export enum ConstraintTypes {\n\t// As Soon As Possible (ASAP)\n\tASAP = \"asap\",\n\t// As Late As Possible (ALAP)\n\tALAP = \"alap\",\n\t// Start No Earlier Than (SNET)\n\tSNET = \"snet\",\n\t// Start No Later Than (SNLT)\n\tSNLT = \"snlt\",\n\t// Finish No Earlier Than (FNET)\n\tFNET = \"fnet\",\n\t// Finish No Later Than (FNLT)\n\tFNLT = \"fnlt\",\n\t// Must Start On (MSO)\n\tMSO = \"mso\",\n\t// Must Finish On (MFO)\n\tMFO = \"mfo\"\n}","export default function(gantt) {\n\tgantt.config.auto_scheduling_use_progress = false;\n\tgantt.config.auto_scheduling_project_constraint = false;\n\n};\n\n","export default function (gantt) {\n\t// helpers for building chain of dependencies, used for critical path calculation and for auto scheduling\n\n\tgantt._get_linked_task = function (link, getTarget) {\n\t\tvar task = null;\n\t\tvar taskId = getTarget ? link.target : link.source;\n\n\t\tif (gantt.isTaskExists(taskId)) {\n\t\t\ttask = gantt.getTask(taskId);\n\t\t}\n\n\t\treturn task;\n\t};\n\tgantt._get_link_target = function (link) {\n\t\treturn gantt._get_linked_task(link, true);\n\t};\n\n\tgantt._get_link_source = function (link) {\n\t\treturn gantt._get_linked_task(link, false);\n\t};\n\n\tvar caching = false;\n\tvar formattedLinksStash = {};\n\tvar inheritedSuccessorsStash = {};\n\tvar inheritedPredecessorsStash = {};\n\tvar getPredecessorsCache = {};\n\n\n\tgantt._isLinksCacheEnabled = function () {\n\t\treturn caching;\n\t};\n\tgantt._startLinksCache = function () {\n\t\tformattedLinksStash = {};\n\t\tinheritedSuccessorsStash = {};\n\t\tinheritedPredecessorsStash = {};\n\t\tgetPredecessorsCache = {};\n\t\tcaching = true;\n\t};\n\tgantt._endLinksCache = function () {\n\t\tformattedLinksStash = {};\n\t\tinheritedSuccessorsStash = {};\n\t\tinheritedPredecessorsStash = {};\n\t\tgetPredecessorsCache = {};\n\t\tcaching = false;\n\t};\n\n\tfunction isManuallyScheduledSummary(task){\n\t\treturn gantt.isSummaryTask(task) && task.auto_scheduling === false;\n\t}\n\n\tgantt._formatLink = function (link, sourceDates, targetDates) {\n\n\n\t\tif (caching && formattedLinksStash[link.id]) {\n\t\t\treturn formattedLinksStash[link.id];\n\t\t}\n\n\t\tvar relations = [];\n\t\tvar target = this._get_link_target(link);\n\t\tvar source = this._get_link_source(link);\n\n\t\tif (!(source && target)) {\n\t\t\treturn relations;\n\t\t}\n\n\t\tif ((gantt.isSummaryTask(target) && gantt.isChildOf(source.id, target.id)) || (gantt.isSummaryTask(source) && gantt.isChildOf(target.id, source.id))) {\n\t\t\treturn relations;\n\t\t}\n\n\t\tvar backwardsScheduling = gantt.config.schedule_from_end && gantt.config.project_end;\n\t\tvar respectTargetOffset = gantt.config.auto_scheduling_move_projects;\n\t\tif(!gantt.config.auto_scheduling_compatibility && gantt.config.auto_scheduling_strict){\n\t\t\trespectTargetOffset = false;\n\t\t}\n\n\n\n\t\t// there are three kinds of connections at this point\n\t\t// task -> task - regular link\n\t\t// task -> project - transform it into set of regular links (task -> [each subtask]), use offset beetween subtask and project dates as lag, in order not to change mutual positions of subtasks inside a project\n\t\t// project -> task - transform it into ([each subtask] -> task) links\n\t\t// project -> project - transform it into ([each subtask of p1] -> [each subtask of p2]) links\n\t\tsourceDates = sourceDates || (this.isSummaryTask(source) && !isManuallyScheduledSummary(source)) ? this.getSubtaskDates(source.id) : {\n\t\t\tstart_date: source.start_date,\n\t\t\tend_date: source.end_date\n\t\t};\n\n\t\tvar from = this._getImplicitLinks(link, source, function (c) {\n\t\t\tif(!respectTargetOffset || !backwardsScheduling){\n\t\t\t\treturn 0;\t\n\t\t\t}else{\n\t\t\t\tif (!c.$source.length && !(gantt.getState(\"tasksDnd\").drag_id == c.id)) {\n\t\t\t\t\t// drag_id - virtual lag shouldn't restrict task that is being moved inside project\n\t\t\t\t\treturn gantt.calculateDuration({\n\t\t\t\t\t\tstart_date: c.end_date,\n\t\t\t\t\t\tend_date: sourceDates.end_date,\n\t\t\t\t\t\ttask: source\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}, true);\n\n\t\tif (!targetDates){\n\t\t\ttargetDates = {\n\t\t\t\tstart_date: target.start_date,\n\t\t\t\tend_date: target.end_date\n\t\t\t};\n\t\t\tif (this.isSummaryTask(target) && !isManuallyScheduledSummary(target)){\n\t\t\t\ttargetDates = this.getSubtaskDates(target.id);\n\t\t\t\ttargetDates.start_date = targetDates.end_date;\n\t\t\t\t// GS-2427. When a successor starts earlier its predecessor, we should\n\t\t\t\t// obtain the dates of the predecessor\n\t\t\t\tthis.eachTask(function(child){\n\t\t\t\t\t// exclude projects as their dates are unreliable until the scheduling is done\n\t\t\t\t\tif (child.type === this.config.types.project){\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!child.$target.length && child.start_date < targetDates.start_date){\n\t\t\t\t\t\ttargetDates.start_date = child.start_date;\n\t\t\t\t\t}\n\t\t\t\t},target.id);\n\t\t\t}\n\t\t}\n\n\t\tvar to = this._getImplicitLinks(link, target, function (actualTarget) {\n\t\t\tif (!respectTargetOffset || backwardsScheduling) {\n\t\t\t\treturn 0;\n\t\t\t} else {\n\t\t\t\tif (!actualTarget.$target.length && !(gantt.getState(\"tasksDnd\").drag_id == actualTarget.id)) {// drag_id - virtual lag shouldn't restrict task that is being moved inside project\n\t\t\t\t\treturn gantt.calculateDuration({\n\t\t\t\t\t\tstart_date: targetDates.start_date,\n\t\t\t\t\t\tend_date: actualTarget.start_date,\n\t\t\t\t\t\ttask: target\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tfor (var i = 0, fromLength = from.length; i < fromLength; i++) {\n\t\t\tvar fromTask = from[i];\n\t\t\tfor (var j = 0, toLength = to.length; j < toLength; j++) {\n\t\t\t\tvar toTask = to[j];\n\n\t\t\t\tvar lag = fromTask.lag * 1 + toTask.lag * 1;\n\n\t\t\t\tvar subtaskLink = {\n\t\t\t\t\tid: link.id,\n\t\t\t\t\ttype: link.type,\n\t\t\t\t\tsource: fromTask.task,\n\t\t\t\t\ttarget: toTask.task,\n\t\t\t\t\tsubtaskLink: fromTask.subtaskLink,\n\t\t\t\t\tlag: (link.lag * 1 || 0) + lag\n\t\t\t\t};\n\n\t\t\t\tgantt._linkedTasks[subtaskLink.target] = gantt._linkedTasks[subtaskLink.target] || {};\n\t\t\t\tgantt._linkedTasks[subtaskLink.target][subtaskLink.source] = true;\n\n\t\t\t\trelations.push(gantt._convertToFinishToStartLink(toTask.task, subtaskLink, source, target, fromTask.taskParent, toTask.taskParent));\n\t\t\t}\n\t\t}\n\n\t\tif (caching)\n\t\t\tformattedLinksStash[link.id] = relations;\n\n\t\treturn relations;\n\t};\n\n\tgantt._isAutoSchedulable = function (task) {\n\t\tconst scheduleTask = task.auto_scheduling !== false && task.unscheduled !== true;\n\t\tif (!scheduleTask){\n\t\t\treturn false;\n\t\t}\n\t\t// GS-2420. Don't auto-schedule project when it has only unscheduled children\n\t\tif (this.isSummaryTask(task)){\n\t\t\tlet unscheduledChildren = true;\n\t\t\tthis.eachTask(function(child){\n\t\t\t\tif (unscheduledChildren){\n\t\t\t\t\tconst scheduleChild = gantt._isAutoSchedulable(child);\n\t\t\t\t\tif (scheduleChild){\n\t\t\t\t\t\tunscheduledChildren = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, task.id);\n\t\t\tif (unscheduledChildren){\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t};\n\n\tgantt._getImplicitLinks = function (link, parent, selectOffset, selectSourceLinks) {\n\t\tvar relations = [];\n\n\t\tif (this.isSummaryTask(parent) && !isManuallyScheduledSummary(parent)) {\n\n\t\t\t// if the summary task contains multiple chains of linked tasks - no need to consider every task of the chain,\n\t\t\t// it will be enough to check the first/last tasks of the chain\n\t\t\t// special conditions if there are unscheduled tasks in the chain, or negative lag values that put the end date of the successor task prior to its predecessors' date\n\t\t\tvar children = {};\n\t\t\tthis.eachTask(function (c) {\n\t\t\t\tif (!this.isSummaryTask(c) || isManuallyScheduledSummary(c)) {\n\t\t\t\t\tchildren[c.id] = c;\n\t\t\t\t}\n\t\t\t}, parent.id);\n\n\t\t\tvar skipChild;\n\n\t\t\tfor (var c in children) {\n\t\t\t\tvar task = children[c];\n\t\t\t\t// don't create subtask links with unscheduled tasks\n\t\t\t\tif (!gantt._isAutoSchedulable(task)){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tvar linksCollection = selectSourceLinks ? task.$source : task.$target;\n\n\t\t\t\tskipChild = false;\n\n\t\t\t\tfor (var l = 0; l < linksCollection.length; l++) {\n\t\t\t\t\t// GS-2014 and GS-2588. If the link type is SS or SF, we shouldn't change the skipChild variable\n\t\t\t\t\t// because the target task should be moved to an earlier date\n\t\t\t\t\tif (link.type == gantt.config.links.start_to_start || link.type == gantt.config.links.start_to_finish){\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tvar siblingLink = gantt.getLink(linksCollection[l]);\n\t\t\t\t\tvar siblingId = selectSourceLinks ? siblingLink.target : siblingLink.source;\n\t\t\t\t\tvar siblingTask = children[siblingId];\n\t\t\t\t\tif (siblingTask && gantt._isAutoSchedulable(task) && gantt._isAutoSchedulable(siblingTask)) {\n\t\t\t\t\t\tlet linkLag = 0;\n\t\t\t\t\t\tif (siblingLink.lag){\n\t\t\t\t\t\t\tlinkLag = Math.abs(siblingLink.lag);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// GS-2014 and GS-2588. If the link type is not FS, the actual lag will be different\n\t\t\t\t\t\tif (siblingLink.type != gantt.config.links.finish_to_start){\n\t\t\t\t\t\t\tlinkLag += gantt._convertToFinishToStartLink(null, {}, task, siblingTask).additionalLag;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst sameTarget = siblingLink.target == siblingTask.id;\n\t\t\t\t\t\tconst insignificantTargetLag = sameTarget && linkLag && linkLag <= siblingTask.duration;\n\n\t\t\t\t\t\tconst sameSource = siblingLink.target == task.id;\n\t\t\t\t\t\tconst insignificantSourceLag = sameSource && linkLag && linkLag <= task.duration;\n\n\t\t\t\t\t\tif (insignificantTargetLag || insignificantSourceLag) {\n\t\t\t\t\t\t\tskipChild = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!skipChild) {\n\t\t\t\t\t// GS-1689. If a task has links between other tasks within the project,\n\t\t\t\t\t// Gantt shouldn't try to keep the position within the project\n\t\t\t\t\tlet calculateLag = true;\n\t\t\t\t\tfor (const predecessorId in gantt._linkedTasks[task.id]){\n\t\t\t\t\t\tif (gantt.isChildOf(predecessorId, link.target)){\n\t\t\t\t\t\t\tcalculateLag = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tlet offsetLag = 0;\n\t\t\t\t\tif (calculateLag) {\n\t\t\t\t\t\toffsetLag = selectOffset(task);\n\t\t\t\t\t}\n\t\t\t\t\trelations.push({ task: task.id, taskParent: task.parent, lag: offsetLag, subtaskLink: true });\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\t\t\trelations.push({ task: parent.id, taskParent: parent.parent, lag: 0 });\n\t\t}\n\n\t\treturn relations;\n\t};\n\n\tgantt._getDirectDependencies = function (task, selectSuccessors) {\n\t\tgantt._linkedTasks = gantt._linkedTasks || {};\n\n\t\tvar links = [],\n\t\t\tsuccessors = [];\n\n\t\tvar linksIds = selectSuccessors ? task.$source : task.$target;\n\n\t\tfor (var i = 0; i < linksIds.length; i++) {\n\t\t\tvar link = this.getLink(linksIds[i]);\n\t\t\tif (this.isTaskExists(link.source) && this.isTaskExists(link.target)) {\n\t\t\t\tvar target = this.getTask(link.target);\n\t\t\t\tif (!this._isAutoSchedulable(target) || !this._isAutoSchedulable(task)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t} else if(gantt.config.auto_scheduling_use_progress) {\n\t\t\t\t\tif(target.progress == 1){\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tlinks.push(link);\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\tlinks.push(link);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (var i = 0; i < links.length; i++) {\n\t\t\tsuccessors = successors.concat(this._formatLink(links[i]));\n\t\t}\n\n\t\treturn successors;\n\t};\n\n\tgantt._getInheritedDependencies = function (task, selectSuccessors) {\n\n\t\t//var successors = [];\n\t\tvar stop = false;\n\t\tvar inheritedRelations = [];\n\t\tvar cacheCollection;\n\t\tif (this.isTaskExists(task.id)) {\n\t\t\tthis.eachParent(function (parent) {\n\t\t\t\tif (stop)\n\t\t\t\t\treturn;\n\n\t\t\t\tif (caching) {\n\t\t\t\t\tcacheCollection = selectSuccessors ? inheritedSuccessorsStash : inheritedPredecessorsStash;\n\t\t\t\t\tif (cacheCollection[parent.id]) {\n\t\t\t\t\t\tinheritedRelations = inheritedRelations.concat(cacheCollection[parent.id]);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar parentDependencies;\n\t\t\t\tif (this.isSummaryTask(parent)) {\n\t\t\t\t\tif (!this._isAutoSchedulable(parent)) {\n\t\t\t\t\t\tstop = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparentDependencies = this._getDirectDependencies(parent, selectSuccessors);\n\t\t\t\t\t\tif (caching) {\n\t\t\t\t\t\t\tcacheCollection[parent.id] = parentDependencies;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tinheritedRelations = inheritedRelations.concat(parentDependencies);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}, task.id, this);\n\t\t}\n\n\t\treturn inheritedRelations;\n\t};\n\n\n\tgantt._getDirectSuccessors = function (task) {\n\t\treturn this._getDirectDependencies(task, true);\n\t};\n\n\tgantt._getInheritedSuccessors = function (task) {\n\t\treturn this._getInheritedDependencies(task, true);\n\t};\n\n\tgantt._getDirectPredecessors = function (task) {\n\t\treturn this._getDirectDependencies(task, false);\n\t};\n\n\tgantt._getInheritedPredecessors = function (task) {\n\t\treturn this._getInheritedDependencies(task, false);\n\t};\n\n\tgantt._getSuccessors = function (task, skipInherited) {\n\t\tvar successors = this._getDirectSuccessors(task);\n\t\tif (skipInherited) {\n\t\t\treturn successors;\n\t\t} else {\n\t\t\treturn successors.concat(this._getInheritedSuccessors(task));\n\t\t}\n\t};\n\n\tgantt._getPredecessors = function (task, skipInherited) {\n\t\tvar key = String(task.id) + \"-\" + String(skipInherited);\n\t\tvar result;\n\n\t\tif (caching && getPredecessorsCache[key]) {\n\t\t\treturn getPredecessorsCache[key];\n\t\t}\n\n\t\tvar predecessors = this._getDirectPredecessors(task);\n\t\tif (skipInherited) {\n\t\t\tresult = predecessors;\n\t\t} else {\n\t\t\tresult = predecessors.concat(this._getInheritedPredecessors(task));\n\t\t}\n\t\tif (caching) {\n\t\t\tgetPredecessorsCache[key] = result;\n\t\t}\n\t\treturn result;\n\t};\n\n\n\tgantt._convertToFinishToStartLink = function (id, link, sourceTask, targetTask, sourceParent, targetParent) {\n\t\t// convert finish-to-finish, start-to-finish and start-to-start to finish-to-start link and provide some additional properties\n\t\tvar res = {\n\t\t\ttarget: id,\n\t\t\tlink: gantt.config.links.finish_to_start,\n\t\t\tid: link.id,\n\t\t\tlag: link.lag || 0,\n\t\t\tsourceLag: 0,\n\t\t\ttargetLag: 0,\n\t\t\ttrueLag: link.lag || 0,\n\t\t\tsource: link.source,\n\t\t\tpreferredStart: null,\n\t\t\tsourceParent: sourceParent,\n\t\t\ttargetParent: targetParent,\n\t\t\thashSum: null,\n\t\t\tsubtaskLink: link.subtaskLink\n\t\t};\n\t\t// GS-148: switch uses strict comparison, so we need to convert the values to the same type\n\t\tvar additionalLag = 0;\n\t\tswitch (String(link.type)) {\n\t\t\tcase String(gantt.config.links.start_to_start):\n\t\t\t\tadditionalLag = -sourceTask.duration;\n\t\t\t\tres.sourceLag = additionalLag;\n\t\t\t\tbreak;\n\t\t\tcase String(gantt.config.links.finish_to_finish):\n\t\t\t\tadditionalLag = -targetTask.duration;\n\t\t\t\tres.targetLag = additionalLag;\n\t\t\t\tbreak;\n\t\t\tcase String(gantt.config.links.start_to_finish):\n\t\t\t\tadditionalLag = -sourceTask.duration - targetTask.duration;\n\t\t\t\tres.sourceLag = -sourceTask.duration;\n\t\t\t\tres.targetLag = -targetTask.duration;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tadditionalLag = 0;\n\t\t}\n\n\t\tres.lag += additionalLag;\n\t\tres.hashSum = res.lag + \"_\" + res.link + \"_\" + res.source + \"_\" + res.target;\n\t\treturn res;\n\t};\n};","var units = {\n\t\"second\": 1,\n\t\"minute\": 60,\n\t\"hour\": 60 * 60,\n\t\"day\": 60 * 60 * 24,\n\t\"week\": 60 * 60 * 24 * 7,\n\t\"month\": 60 * 60 * 24 * 30,\n\t\"quarter\": 60 * 60 * 24 * 30 * 3,\n\t\"year\": 60 * 60 * 24 * 365\n};\nfunction getSecondsInUnit(unit){\n\treturn units[unit] || units.hour;\n}\n\nfunction forEach(arr, callback) {\n\tif (arr.forEach) {\n\t\tarr.forEach(callback);\n\t} else {\n\t\tvar workArray = arr.slice();\n\t\tfor (var i = 0; i < workArray.length; i++) {\n\t\t\tcallback(workArray[i], i);\n\t\t}\n\t}\n}\n\nfunction arrayMap(arr, callback) {\n\tif (arr.map) {\n\t\treturn arr.map(callback);\n\t} else {\n\t\tvar workArray = arr.slice();\n\t\tvar resArray = [];\n\n\t\tfor (var i = 0; i < workArray.length; i++) {\n\t\t\tresArray.push(callback(workArray[i], i));\n\t\t}\n\t\treturn resArray;\n\t}\n}\n\n\nfunction arrayFind(arr, callback) {\n\tif (arr.find) {\n\t\treturn arr.find(callback);\n\t} else {\n\t\tfor (var i = 0; i < arr.length; i++) {\n\t\t\tif (callback(arr[i], i)) {\n\t\t\t\treturn arr[i];\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction arrayIncludes(arr, item) {\n\tif(arr.includes){\n\t\treturn arr.includes(item);\n\t}else{\n\t\tfor (var i = 0; i < arr.length; i++) {\n\t\t\tif (arr[i] === item) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n}\n\n// iframe-safe array type check instead of using instanceof\nfunction isArray(obj){\n\tif(Array.isArray){\n\t\treturn Array.isArray(obj);\n\t}else{\n\t\t// close enough\n\t\treturn (obj && obj.length !== undefined && obj.pop && obj.push);\n\t}\n}\n\n// non-primitive string object, e.g. new String(\"abc\")\nfunction isStringObject(obj){\n\treturn obj && typeof obj === \"object\"\n\t\t&& Function.prototype.toString.call(obj.constructor) === \"function String() { [native code] }\";\n}\n\n// non-primitive number object, e.g. new Number(5)\nfunction isNumberObject(obj){\n\treturn obj && typeof obj === \"object\"\n\t\t&& Function.prototype.toString.call(obj.constructor) === \"function Number() { [native code] }\";\n}\n\n// non-primitive number object, e.g. new Boolean(true)\nfunction isBooleanObject(obj){\n\treturn obj && typeof obj === \"object\"\n\t\t&& Function.prototype.toString.call(obj.constructor) === \"function Boolean() { [native code] }\";\n}\n\nfunction isDate(obj) {\n\tif (obj && typeof obj === \"object\") {\n\t\treturn !!(obj.getFullYear && obj.getMonth && obj.getDate);\n\t} else {\n\t\treturn false;\n\t}\n}\n\nfunction isValidDate(obj){\n\treturn isDate(obj) && !isNaN(obj.getTime());\n}\n\nfunction arrayFilter(arr, callback) {\n\tvar result = [];\n\n\tif (arr.filter) {\n\t\treturn arr.filter(callback);\n\t} else {\n\t\tfor (var i = 0; i < arr.length; i++) {\n\t\t\tif (callback(arr[i], i)) {\n\t\t\t\tresult[result.length] = arr[i];\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\nfunction hashToArray(hash) {\n\tvar result = [];\n\n\tfor (var key in hash) {\n\t\tif (hash.hasOwnProperty(key)) {\n\t\t\tresult.push(hash[key]);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction arraySome(arr, callback) {\n\tif (arr.length === 0) return false;\n\n\tfor (var i = 0; i < arr.length; i++) {\n\t\tif (callback(arr[i], i, arr)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction arrayDifference(arr, callback) {\n\treturn arrayFilter(arr, function(item, i) {\n\t\treturn !callback(item, i);\n\t});\n}\n\nfunction throttle (callback, timeout) {\n\tvar wait = false;\n\n\treturn function () {\n\t\tif (!wait) {\n\t\t\tcallback.apply(null, arguments);\n\t\t\twait = true;\n\t\t\tsetTimeout(function () {\n\t\t\t\twait = false;\n\t\t\t}, timeout);\n\t\t}\n\t};\n}\n\nfunction delay (callback, timeout){\n\tvar timer;\n\n\tvar result = function() {\n\t\tresult.$cancelTimeout();\n\t\tresult.$pending = true;\n\t\tvar args = Array.prototype.slice.call(arguments);\n\t\ttimer = setTimeout(function(){\n\t\t\tcallback.apply(this, args);\n\t\t\tresult.$pending = false;\n\t\t}, timeout);\n\t};\n\n\tresult.$pending = false;\n\tresult.$cancelTimeout = function(){\n\t\tclearTimeout(timer);\n\t\tresult.$pending = false;\n\t};\n\tresult.$execute = function(){\n\t\tvar args = Array.prototype.slice.call(arguments);\n\t\tcallback.apply(this, args);\n\t\tresult.$cancelTimeout();\n\t};\n\n\treturn result;\n}\n\nfunction sortArrayOfHash(arr, field, desc) {\n\tvar compare = function(a, b) {\n\t\treturn a < b;\n\t};\n\n\tarr.sort(function(a, b) {\n\t\tif (a[field] === b[field]) return 0;\n\n\t\treturn desc ? compare(a[field], b[field]) : compare(b[field], a[field]);\n\t});\n}\n\nfunction objectKeys(obj) {\n\tif (Object.keys) {\n\t\treturn Object.keys(obj);\n\t}\n\tvar result = [];\n\tvar key;\n\tfor (key in obj) {\n\t\tif (Object.prototype.hasOwnProperty.call(obj, key)) {\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction isEventable(obj) {\n\treturn obj.attachEvent && obj.detachEvent;\n}\n\n//GS-1090: A task should be able to have the id = 0\nfunction replaceValidZeroId(id, rootId) {\n\tif (checkZeroId(id) && !checkZeroId(rootId)){\n\t\tid = \"0\";\n\t}\n\treturn id;\n}\n\nfunction checkZeroId(id) {\n\tif (id === 0){\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction findBinary(array, target) {\n\t// modified binary search, target value not exactly match array elements, looking for closest one\n\n\tvar low = 0, high = array.length - 1, i, item, prev;\n\twhile (low <= high) {\n\n\t\ti = Math.floor((low + high) / 2);\n\t\titem = +array[i];\n\t\tprev = +array[i - 1];\n\t\tif (item < target) {\n\t\t\tlow = i + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (item > target) {\n\t\t\tif (!(!isNaN(prev) && prev < target)) {\n\t\t\t\thigh = i - 1;\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\t// if target is between 'i' and 'i-1' return 'i - 1'\n\t\t\t\treturn i - 1;\n\t\t\t}\n\n\t\t}\n\t\twhile (+array[i] == +array[i + 1]) i++;\n\n\t\treturn i;\n\t}\n\treturn array.length - 1;\n}\n\nexport {\n\tgetSecondsInUnit,\n\tforEach,\n\tarrayMap,\n\tarrayIncludes,\n\tarrayFind,\n\tarrayFilter,\n\tarrayDifference,\n\tarraySome,\n\thashToArray,\n\tsortArrayOfHash,\n\tthrottle,\n\tisArray,\n\tisDate,\n\tisValidDate,\n\tisStringObject,\n\tisNumberObject,\n\tisBooleanObject,\n\tdelay,\n\tobjectKeys,\n\tisEventable,\n\treplaceValidZeroId,\n\tcheckZeroId,\n\tfindBinary\n};","export default function() {\n\tfunction getResourcesCalendarKey(resourceAssignments){\n\t\treturn resourceAssignments.map(function(res){\n\t\t\tif(res && res.resource_id){\n\t\t\t\treturn res.resource_id;\n\t\t\t} else {\n\t\t\t\treturn res;\n\t\t\t}\n\t\t}).sort().join(\"-\");\n\t}\n\n\tvar dynamicCalendars = {};\n\n\tfunction mergeResourceCalendars(resourceAssignments, manager){\n\t\treturn manager.mergeCalendars(resourceAssignments.map(function(assignment){\n\t\t\tvar resourceId = (assignment && assignment.resource_id) ? assignment.resource_id : assignment;\n\t\t\treturn manager.getResourceCalendar(resourceId);\n\t\t}));\n\t}\n\tfunction getCalendarIdFromMultipleResources(resourceAssignments, manager){\n\t\tvar key = getResourcesCalendarKey(resourceAssignments);\n\t\tif(!resourceAssignments.length){\n\t\t\treturn null;\n\t\t}else if(resourceAssignments.length === 1){\n\t\t\treturn manager.getResourceCalendar(key).id;\n\t\t}else if (dynamicCalendars[key]){\n\t\t\treturn dynamicCalendars[key].id;\n\t\t} else {\n\t\t\tvar tempCalendar = mergeResourceCalendars(resourceAssignments, manager);\n\n\t\t\tdynamicCalendars[key] = tempCalendar;\n\t\t\treturn manager.addCalendar(tempCalendar);\n\t\t}\n\t}\n\n\treturn {\n\t\tgetCalendarIdFromMultipleResources: getCalendarIdFromMultipleResources\n\t};\n};","if (window.jQuery){\n\n\t(function( $ ){\n\n\t\tvar methods = [];\n\t\t$.fn.dhx_gantt = function(config){\n\t\t\tconfig = config || {};\n\t\t\tif (typeof(config) === 'string') {\n\t\t\t\tif (methods[config] ) {\n\t\t\t\t\treturn methods[config].apply(this, []);\n\t\t\t\t}else {\n\t\t\t\t\t$.error('Method ' + config + ' does not exist on jQuery.dhx_gantt');\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar views = [];\n\t\t\t\tthis.each(function() {\n\t\t\t\t\tif (this && this.getAttribute){\n\t\t\t\t\t\tif (!this.gantt && !(window.gantt.$root == this)){\n\n\t\t\t\t\t\t\tvar newgantt = (window.gantt.$container && window.Gantt) ? window.Gantt.getGanttInstance():window.gantt;\n\t\t\t\t\t\t\tfor (var key in config)\n\t\t\t\t\t\t\t\tif (key!=\"data\")\n\t\t\t\t\t\t\t\t\tnewgantt.config[key] = config[key];\n\n\t\t\t\t\t\t\tnewgantt.init(this);\n\t\t\t\t\t\t\tif (config.data)\n\t\t\t\t\t\t\t\tnewgantt.parse(config.data);\n\n\t\t\t\t\t\t\tviews.push(newgantt);\n\t\t\t\t\t\t} else\n\t\t\t\t\t\t\tviews.push(typeof this.gantt == \"object\" ? this.gantt : window.gantt);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\n\t\t\t\tif (views.length === 1) return views[0];\n\t\t\t\treturn views;\n\t\t\t}\n\t\t};\n\n\t})(window.jQuery);\n\n}\n\n\nexport default null;","import * as helpers from \"../../utils/helpers\";\n\nexport default function(){\n\treturn {\n\t\tgetVertices: function(relations){\n\t\t\tvar ids = {};\n\t\t\tvar rel;\n\t\t\tfor(var i = 0, len = relations.length; i < len; i++){\n\t\t\t\trel = relations[i];\n\t\t\t\tids[rel.target] = rel.target;\n\t\t\t\tids[rel.source] = rel.source;\n\t\t\t}\n\n\t\t\tvar vertices = [];\n\t\t\tvar id;\n\t\t\tfor(var i in ids){\n\t\t\t\tid = ids[i];\n\t\t\t\tvertices.push(id);\n\t\t\t}\n\n\t\t\treturn vertices;\n\t\t},\n\t\ttopologicalSort: function(edges){\n\t\t\tvar vertices = this.getVertices(edges);\n\t\t\tvar hash = {};\n\n\t\t\tfor(var i = 0, len = vertices.length; i < len; i ++){\n\t\t\t\thash[vertices[i]] = {id: vertices[i], $source:[], $target:[], $incoming: 0};\n\t\t\t}\n\n\t\t\tfor(var i = 0, len = edges.length; i < len; i++){\n\t\t\t\tvar successor = hash[edges[i].target];\n\t\t\t\tsuccessor.$target.push(i);\n\t\t\t\tsuccessor.$incoming = successor.$target.length;\n\t\t\t\thash[edges[i].source].$source.push(i);\n\n\t\t\t}\n\n\t\t\t// topological sort, Kahn's algorithm\n\t\t\tvar S = vertices.filter(function(v){ return !hash[v].$incoming; });\n\n\t\t\tvar L = [];\n\n\t\t\twhile(S.length){\n\t\t\t\tvar n = S.pop();\n\n\t\t\t\tL.push(n);\n\n\t\t\t\tvar node = hash[n];\n\n\t\t\t\tfor(var i = 0; i < node.$source.length; i++){\n\t\t\t\t\tvar m = hash[edges[node.$source[i]].target];\n\t\t\t\t\tm.$incoming--;\n\t\t\t\t\tif(!m.$incoming){\n\t\t\t\t\t\tS.push(m.id);\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn L;\n\n\t\t},\n\t\tgroupAdjacentEdges: function(edges){\n\t\t\tvar res = {};\n\t\t\tvar edge;\n\t\t\tfor(var i = 0, len = edges.length; i < len; i++){\n\t\t\t\tedge = edges[i];\n\t\t\t\tif(!res[edge.source]){\n\t\t\t\t\tres[edge.source] = [];\n\t\t\t\t}\n\t\t\t\tres[edge.source].push(edge);\n\t\t\t}\n\t\t\treturn res;\n\t\t},\n\t\ttarjanStronglyConnectedComponents: function(vertices, edges){\n\t\t\t//https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm\n\t\t\t// iterative implementation\n\t\t\tvar verticesHash = {};\n\t\t\tvar stack = [];\n\t\t\tvar edgesFromTasks = this.groupAdjacentEdges(edges);\n\t\t\tvar recurse = false;\n\t\t\tvar connectedComponents = [];\n\n\t\t\tfor(var i = 0; i < vertices.length; i++){\n\t\t\t\tvar root = getVertex(vertices[i]);\n\t\t\t\tif(root.visited) continue;\n\t\t\t\tvar workStack = [root];\n\t\t\t\tvar index = 0;\n\t\t\t\twhile(workStack.length){\n\t\t\t\t\tvar v = workStack.pop();\n\n\t\t\t\t\tif(!v.visited){\n\t\t\t\t\t\tv.index = index;\n\t\t\t\t\t\tv.lowLink = index;\n\t\t\t\t\t\tindex++;\n\t\t\t\t\t\tstack.push(v);\n\t\t\t\t\t\tv.onStack = true;\n\t\t\t\t\t\tv.visited = true;\n\t\t\t\t\t}\n\t\t\t\t\trecurse = false;\n\t\t\t\t\tvar edges = edgesFromTasks[v.id] || [];\n\t\t\t\t\tfor(var e = 0; e < edges.length; e++){\n\t\t\t\t\t\tvar w = getVertex(edges[e].target);\n\t\t\t\t\t\tw.edge = edges[e];\n\t\t\t\t\t\tif(w.index === undefined){\n\t\t\t\t\t\t\tworkStack.push(v);\n\t\t\t\t\t\t\tworkStack.push(w);\n\t\t\t\t\t\t\trecurse = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}else if(w.onStack){\n\t\t\t\t\t\t\tv.lowLink = Math.min(v.lowLink, w.index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(recurse)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tif (v.index == v.lowLink){\n\t\t\t\t\t\tvar com = {tasks:[], links:[], linkKeys:[]};\n\t\t\t\t\t\twhile(true){\n\t\t\t\t\t\t\tw = stack.pop();\n\t\t\t\t\t\t\tw.onStack = false;\n\t\t\t\t\t\t\tcom.tasks.push(w.id);\n\t\t\t\t\t\t\tif(w.edge){\n\t\t\t\t\t\t\t\tcom.links.push(w.edge.id);\n\t\t\t\t\t\t\t\tcom.linkKeys.push(w.edge.hashSum);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(w == v){\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconnectedComponents.push(com);\n\t\t\t\t\t}\n\t\t\t\t\tif(workStack.length){\n\t\t\t\t\t\tw = v;\n\t\t\t\t\t\tv = workStack[workStack.length - 1];\n\t\t\t\t\t\tv.lowLink = Math.min(v.lowLink, w.lowLink);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn connectedComponents;\n\n\t\t\tfunction getVertex(id){\n\t\t\t\tif(!verticesHash[id]){\n\t\t\t\t\tverticesHash[id] = {id: id, onStack:false, index: undefined, lowLink: undefined, edge: undefined};\n\t\t\t\t}\n\n\t\t\t\treturn verticesHash[id];\n\t\t\t}\n\t\t},\n\n\t\tfindLoops: function(relations){\n\t\t\tvar cycles = [];\n\n\t\t\thelpers.forEach(relations, function(rel){\n\t\t\t\tif(rel.target == rel.source)\n\t\t\t\t\tcycles.push({ tasks: [rel.source], links: [rel.id]});\n\t\t\t});\n\n\t\t\tvar vertices = this.getVertices(relations);\n\n\t\t\tvar connectedComponents = this.tarjanStronglyConnectedComponents(vertices, relations);\n\t\t\thelpers.forEach(connectedComponents, function(component){\n\t\t\t\tif(component.tasks.length > 1){\n\t\t\t\t\tcycles.push(component);//{ tasks: [task ids], links: [links ids]}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn cycles;\n\t\t\t//{task:id, link:link.type, lag: link.lag || 0, source: link.source}\n\t\t}\n\t};\n};","export default function(gantt) {\n\treturn {\n\t\tgetVirtualRoot: function(){\n\t\t\treturn gantt.mixin(\n\t\t\t\tgantt.getSubtaskDates(),\n\t\t\t\t{\n\t\t\t\t\tid: gantt.config.root_id,\n\t\t\t\t\ttype: gantt.config.types.project,\n\t\t\t\t\t$source: [],\n\t\t\t\t\t$target: [],\n\t\t\t\t\t$virtual: true\n\t\t\t\t}\n\t\t\t);\n\t\t},\n\t\n\t\tgetLinkedTasks: function(id, includePredecessors){\n\t\t\tvar startIds = [id];\n\t\n\t\t\t//TODO: format links cache\n\t\t\tvar clearCache = false;\n\t\t\tif(!gantt._isLinksCacheEnabled()) {\n\t\t\t\tgantt._startLinksCache();\n\t\t\t\tclearCache = true;\n\t\t\t}\n\t\t\tvar relations = [];\n\t\t\tvar visited = {};\n\t\t\tvar result = {};\n\t\t\tfor(var i = 0; i < startIds.length; i++){\n\t\t\t\tthis._getLinkedTasks(startIds[i], visited, includePredecessors, result);\n\t\t\t}\n\t\n\t\t\tfor(var i in result){\n\t\t\t\trelations.push(result[i]);\n\t\t\t}\n\t\n\t\t\t//TODO: remove redundant edges before continue https://en.wikipedia.org/wiki/Transitive_reduction\n\t\t\tif(clearCache)\n\t\t\t\tgantt._endLinksCache();\n\t\t\treturn relations;\n\t\t},\n\t\n\t\t_collectRelations: function(rootObj, isChild, includePredecessors, visitedLinks){\n\t\t\tvar successors = gantt._getSuccessors(rootObj, isChild);\n\t\n\t\t\tvar predecessors = [];\n\t\t\tif (includePredecessors) {\n\t\t\t\tpredecessors = gantt._getPredecessors(rootObj, isChild);\n\t\t\t}\n\t\t\t\n\t\t\tvar linkKey;\n\t\t\tvar relations = [];\n\t\t\tfor(var i = 0; i < successors.length; i++){\n\t\t\t\tlinkKey = successors[i].hashSum;\n\t\t\t\tif(visitedLinks[linkKey]) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}else{\n\t\t\t\t\tvisitedLinks[linkKey] = true;\n\t\t\t\t\trelations.push(successors[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(var i = 0; i < predecessors.length; i++){\n\t\t\t\tlinkKey = predecessors[i].hashSum;\n\t\t\t\tif(visitedLinks[linkKey]) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}else{\n\t\t\t\t\tvisitedLinks[linkKey] = true;\n\t\t\t\t\trelations.push(predecessors[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn relations;\n\t\t},\n\t\t_getLinkedTasks: function(rootTask, visitedTasks, includePredecessors, output) {\n\t\t\tvar from = rootTask === undefined ? gantt.config.root_id : rootTask;\n\t\t\tvar visitedTasks = {};\n\t\t\tvar visitedLinks = {};\n\t\t\tvar rootObj;\n\t\n\t\t\tvar tasksStack = [{from: from, includePredecessors: includePredecessors, isChild:false}];\n\t\n\t\t\twhile(tasksStack.length){\n\t\t\t\tvar current = tasksStack.pop();\n\t\t\t\tvar isChild = current.isChild;\n\t\n\t\t\t\tfrom = current.from;\n\t\t\t\tif(visitedTasks[from]){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\trootObj = gantt.isTaskExists(from) ? gantt.getTask(from) : this.getVirtualRoot();\n\t\t\t\tvisitedTasks[from] = true;\n\t\t\t\t\n\t\t\t\tvar relations = this._collectRelations(rootObj, isChild, includePredecessors, visitedLinks);\n\t\n\t\t\t\tfor(var i=0; i < relations.length; i++){\n\t\t\t\t\tvar rel = relations[i];\n\n\t\t\t\t\tlet includeRelation = true;\n\t\t\t\t\tif(gantt.config.auto_scheduling_use_progress){\n\t\t\t\t\t\tconst target = gantt.getTask(rel.target);\n\t\t\t\t\t\tif(target.progress == 1){\n\t\t\t\t\t\t\tincludeRelation = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// don't process links for unscheduled tasks\n\t\t\t\t\tconst target = gantt.getTask(rel.target);\n\t\t\t\t\tconst source = gantt.getTask(rel.source);\n\t\t\t\t\tif (target.unscheduled || source.unscheduled){\n\t\t\t\t\t\tincludeRelation = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif(includeRelation){\n\t\t\t\t\t\toutput[rel.hashSum] = rel;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar isSameParent = rel.sourceParent == rel.targetParent;\n\t\t\t\t\tvar targetTask = rel.target;\n\t\t\t\t\tif(!visitedTasks[targetTask])\n\t\t\t\t\t\ttasksStack.push({from: rel.target, includePredecessors: true, isChild: isSameParent});\n\t\t\t\t}\n\t\n\t\t\t\tif(gantt.hasChild(rootObj.id)){\n\t\t\t\t\tvar children = gantt.getChildren(rootObj.id);\n\t\t\t\t\tfor(var i=0; i < children.length; i++){\n\t\t\t\t\t\tif(!visitedTasks[children[i]])\n\t\t\t\t\t\t\ttasksStack.push({from: children[i], includePredecessors: true, isChild: true});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn output;\n\t\t}\n\t};\n};","//returns position of html element on the page\nfunction getNodePosition(elem) {\n\tvar top=0, left=0, right=0, bottom=0;\n\tif (elem.getBoundingClientRect) { //HTML5 method\n\t\tvar box = elem.getBoundingClientRect();\n\t\tvar body = document.body;\n\t\tvar docElem = (document.documentElement ||\n\t\t\tdocument.body.parentNode ||\n\t\t\tdocument.body);\n\n\t\tvar scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;\n\t\tvar scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;\n\t\tvar clientTop = docElem.clientTop || body.clientTop || 0;\n\t\tvar clientLeft = docElem.clientLeft || body.clientLeft || 0;\n\t\ttop = box.top + scrollTop - clientTop;\n\t\tleft = box.left + scrollLeft - clientLeft;\n\n\t\tright = document.body.offsetWidth - box.right;\n\t\tbottom = document.body.offsetHeight - box.bottom;\n\t} else { //fallback to naive approach\n\t\twhile(elem) {\n\t\t\ttop = top + parseInt(elem.offsetTop,10);\n\t\t\tleft = left + parseInt(elem.offsetLeft,10);\n\t\t\telem = elem.offsetParent;\n\t\t}\n\n\t\tright = document.body.offsetWidth - elem.offsetWidth - left;\n\t\tbottom = document.body.offsetHeight - elem.offsetHeight - top;\n\t}\n\treturn { y: Math.round(top), x: Math.round(left), width:elem.offsetWidth, height:elem.offsetHeight, right: Math.round(right), bottom: Math.round(bottom) };\n}\n\nfunction isVisible(node){\n\tvar display = false,\n\t\tvisibility = false;\n\tif(window.getComputedStyle){\n\t\tvar style = window.getComputedStyle(node, null);\n\t\tdisplay = style[\"display\"];\n\t\tvisibility = style[\"visibility\"];\n\t}else if(node.currentStyle){\n\t\tdisplay = node.currentStyle[\"display\"];\n\t\tvisibility = node.currentStyle[\"visibility\"];\n\t}\n\treturn (display != \"none\" && visibility != \"hidden\");\n}\n\nfunction hasNonNegativeTabIndex(node){\n\treturn !isNaN(node.getAttribute(\"tabindex\")) && (node.getAttribute(\"tabindex\")*1 >= 0);\n}\n\nfunction hasHref(node){\n\tvar canHaveHref = {\"a\": true, \"area\": true};\n\tif(canHaveHref[node.nodeName.loLowerCase()]){\n\t\treturn !!node.getAttribute(\"href\");\n\t}\n\treturn true;\n}\n\nfunction isEnabled(node){\n\tvar canDisable = {\"input\":true, \"select\":true, \"textarea\":true, \"button\":true, \"object\":true};\n\tif(canDisable[node.nodeName.toLowerCase()]){\n\t\treturn !node.hasAttribute(\"disabled\");\n\t}\n\n\treturn true;\n}\n\nfunction getFocusableNodes(root){\n\tvar nodes = root.querySelectorAll([\n\t\t\"a[href]\",\n\t\t\"area[href]\",\n\t\t\"input\",\n\t\t\"select\",\n\t\t\"textarea\",\n\t\t\"button\",\n\t\t\"iframe\",\n\t\t\"object\",\n\t\t\"embed\",\n\t\t\"[tabindex]\",\n\t\t\"[contenteditable]\"\n\t].join(\", \"));\n\n\tvar nodesArray = Array.prototype.slice.call(nodes, 0);\n\t\n\tfor(var i = 0; i < nodesArray.length; i++){\n\t\tnodesArray[i].$position = i;\n\t\t// we remember original nodes order, \n\t\t// so when we sort them by tabindex we ensure order of nodes with same tabindex is preserved, \n\t\t// since some browsers do unstable sort\n\t}\n\t\n\t// use tabindex to sort focusable nodes\n\tnodesArray.sort(function(a, b) {\n\t\tif(a.tabIndex === 0 && b.tabIndex !== 0){\n\t\t\treturn 1;\n\t\t}\n\t\tif(a.tabIndex !== 0 && b.tabIndex === 0){\n\t\t\treturn -1;\n\t\t}\n\t\t\n\t\tif (a.tabIndex === b.tabIndex){\n\t\t\t// ensure we do stable sort\n\t\t\treturn a.$position - b.$position;\n\t\t}\n\t\tif (a.tabIndex < b.tabIndex) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn 1;\n\t});\n\t\n\tfor(var i = 0; i < nodesArray.length; i++){\n\t\tvar node = nodesArray[i];\n\t\tvar isValid = (hasNonNegativeTabIndex(node) || isEnabled(node) || hasHref(node)) && isVisible(node);\n\t\tif(!isValid){\n\t\t\tnodesArray.splice(i, 1);\n\t\t\ti--;\n\t\t}\n\t}\n\treturn nodesArray;\n}\n\nfunction getScrollSize(){\n\tvar div = document.createElement(\"div\");\n\tdiv.style.cssText=\"visibility:hidden;position:absolute;left:-1000px;width:100px;padding:0px;margin:0px;height:110px;min-height:100px;overflow-y:scroll;\";\n\n\tdocument.body.appendChild(div);\n\tvar width = div.offsetWidth-div.clientWidth;\n\tdocument.body.removeChild(div);\n\n\treturn Math.max(width, 15);\n}\n\nfunction getClassName(node){\n\tif(!node) return \"\";\n\n\tvar className = node.className || \"\";\n\tif(className.baseVal)//'className' exist but not a string - IE svg element in DOM\n\t\tclassName = className.baseVal;\n\n\tif(!className.indexOf)\n\t\tclassName = \"\";\n\n\treturn _trimString(className);\n}\n\nfunction addClassName(node, className){\n\tif (className && node.className.indexOf(className) === -1) {\n\t\tnode.className += \" \" + className;\n\t}\n}\n\nfunction removeClassName(node, name) {\n\tname = name.split(\" \");\n\tfor (var i = 0; i < name.length; i++) {\n\t\tvar regEx = new RegExp(\"\\\\s?\\\\b\" + name[i] + \"\\\\b(?![-_.])\", \"\");\n\t\tnode.className = node.className.replace(regEx, \"\");\n\t}\n}\n\nfunction hasClass(element, className){\n\tif ('classList' in element) {\n\t\treturn element.classList.contains(className);\n\t} else { \n\t\treturn new RegExp(\"\\\\b\" + className + \"\\\\b\").test(element.className);\n\t}\n}\n\nfunction toNode(node) {\n\tif (typeof node === \"string\") {\n\t\treturn (document.getElementById(node) || document.querySelector(node) || document.body);\n\t}\n\treturn node || document.body;\n}\n\nvar _slave;\nfunction insertNode(node, newone) {\n\tif(!_slave){\n\t\t_slave = document.createElement(\"div\");\n\t}\n\t_slave.innerHTML = newone;\n\tvar child = _slave.firstChild;\n\tnode.appendChild(child);\n\treturn child;\n}\n\nfunction removeNode(node) {\n\tif (node && node.parentNode) {\n\t\tnode.parentNode.removeChild(node);\n\t}\n}\n\nfunction getChildNodes(node, css) {\n\tvar ch = node.childNodes;\n\tvar len = ch.length;\n\tvar out = [];\n\tfor (var i = 0; i < len; i++) {\n\t\tvar obj = ch[i];\n\t\tif (obj.className && obj.className.indexOf(css) !== -1) {\n\t\t\tout.push(obj);\n\t\t}\n\t}\n\treturn out;\n}\n\nfunction getTargetNode(e) {\n\tvar trg;\n\tif (e.tagName)\n\t\ttrg = e;\n\telse {\n\t\te = e || window.event;\n\t\ttrg = e.target || e.srcElement;\n\t\tif (trg.shadowRoot && e.composedPath) {\n\t\t\ttrg = e.composedPath()[0];\n\t\t}\n\t}\n\treturn trg;\n}\n\nfunction locateAttribute(e, attribute) {\n\tif(!attribute) return;\n\n\tvar trg = getTargetNode(e);\n\n\twhile (trg){\n\t\tif (trg.getAttribute){\t//text nodes has not getAttribute\n\t\t\tvar test = trg.getAttribute(attribute);\n\t\t\tif (test) return trg;\n\t\t}\n\t\ttrg=trg.parentNode;\n\t}\n\treturn null;\n}\n\nfunction _trimString(str){\n\tvar func = String.prototype.trim || function(){ return this.replace(/^\\s+|\\s+$/g, \"\"); };\n\treturn func.apply(str);\n}\n\nfunction locateClassName(e, classname, strict){\n\tvar trg = getTargetNode(e);\n\tvar css = \"\";\n\n\tif(strict === undefined)\n\t\tstrict = true;\n\n\twhile (trg){\n\t\tcss = getClassName(trg);\n\t\tif(css){\n\t\t\tvar ind = css.indexOf(classname);\n\t\t\tif (ind >= 0){\n\t\t\t\tif (!strict)\n\t\t\t\t\treturn trg;\n\n\t\t\t\t//check that we have exact match\n\t\t\t\tvar left = (ind === 0) || (!_trimString(css.charAt(ind - 1)));\n\t\t\t\tvar right = ((ind + classname.length >= css.length)) || (!_trimString(css.charAt(ind + classname.length)));\n\n\t\t\t\tif (left && right)\n\t\t\t\t\treturn trg;\n\t\t\t}\n\t\t}\n\t\ttrg=trg.parentNode;\n\t}\n\treturn null;\n}\n\n/*\nevent position relatively to DOM element\n */\nfunction getRelativeEventPosition(ev, node){\n\tvar d = document.documentElement;\n\tvar box = getNodePosition(node);\n\n\treturn {\n\t\tx: ev.clientX + d.scrollLeft - d.clientLeft - box.x + node.scrollLeft,\n\t\ty: ev.clientY + d.scrollTop - d.clientTop - box.y + node.scrollTop\n\t};\n}\n\nfunction getRelativeNodePosition(child, parent){\n\tconst childPos = getNodePosition(child);\n\tconst parentPos = getNodePosition(parent);\n\treturn {\n\t\tx: childPos.x - parentPos.x,\n\t\ty: childPos.y - parentPos.y\n\t};\n}\n\nfunction isChildOf(child, parent){\n\tif(!child || !parent){\n\t\treturn false;\n\t}\n\n\twhile(child && child != parent) {\n\t\tchild = child.parentNode;\n\t}\n\n\treturn child === parent;\n}\n\nfunction closest(element, selector){\n\tif(element.closest){\n\t\treturn element.closest(selector);\n\t}else if(element.matches || element.msMatchesSelector || element.webkitMatchesSelector){\n\t\tvar el = element;\n\t\tif (!document.documentElement.contains(el)) return null;\n\t\tdo {\n\t\t\tvar method = el.matches || el.msMatchesSelector || el.webkitMatchesSelector;\n\n\t\t\tif (method.call(el, selector)) return el;\n\t\t\tel = el.parentElement || el.parentNode;\n\t\t} while (el !== null && el.nodeType === 1); \n\t\treturn null;\n\t}else{\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(\"Your browser is not supported\");\n\t\treturn null;\n\t}\n}\n\nfunction getClosestSizedElement(element) {\n\twhile (element) {\n\t\tif (element.offsetWidth > 0 && element.offsetHeight > 0) {\n\t\t\treturn element;\n\t\t}\n\t\telement = element.parentElement;\n\t}\n\treturn null;\n}\n\nfunction isShadowDomSupported() {\n\treturn document.head.createShadowRoot || document.head.attachShadow;\n}\n\n/**\n * Returns element that has the browser focus, or null if no element has focus.\n * Works with shadow DOM, so it's prefereed to use this function instead of document.activeElement directly.\n * @returns HTMLElement\n */\nfunction getActiveElement(){\n\tvar activeElement = document.activeElement;\n\tif (activeElement.shadowRoot) {\n\t\tactiveElement = activeElement.shadowRoot.activeElement;\n\t}\n\tif (activeElement === document.body && document.getSelection) {\n\t\tactiveElement = document.getSelection().focusNode || document.body;\n\t}\n\n\treturn activeElement;\n}\n\n/**\n * Returns document.body or the host node of the ShadowRoot, if the element is attached to ShadowDom\n * @param {HTMLElement} element \n * @returns HTMLElement\n */\nfunction getRootNode(element) {\n\tif (!element) {\n\t\treturn document.body;\n\t}\n\tif (!isShadowDomSupported()) {\n\t\treturn document.body;\n\t}\n\twhile (element.parentNode && (element = element.parentNode)) {\n\t\tif (element instanceof ShadowRoot) {\n\t\t\treturn element.host;\n\t\t}\n\t}\n\treturn document.body;\n}\n\nfunction hasShadowParent(element) {\n\treturn !!getRootNode(element);\n}\n\nexport {\n\tgetNodePosition,\n\tgetFocusableNodes,\n\tgetScrollSize,\n\tgetClassName,\n\taddClassName,\n\tremoveClassName,\n\tinsertNode,\n\tremoveNode,\n\tgetChildNodes,\n\ttoNode,\n\tlocateClassName,\n\tlocateAttribute,\n\tgetTargetNode,\n\tgetRelativeEventPosition,\n\tisChildOf,\n\thasClass,\n\tclosest,\n\tgetRootNode,\n\thasShadowParent,\n\tisShadowDomSupported,\n\tgetActiveElement,\n\tgetRelativeNodePosition,\n\tgetClosestSizedElement\n};","export class TaskPlan implements ITaskPlan {\n\tstatic Create(parent?: TaskPlan): TaskPlan {\n\t\tconst plan = new TaskPlan();\n\t\tif (parent) {\n\t\t\tfor (const i in plan) {\n\t\t\t\tif (parent[i] !== undefined) {\n\t\t\t\t\tplan[i] = parent[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn plan;\n\t}\n\n\tpublic link: string | number;\n\tpublic task: string | number;\n\t// tslint:disable-next-line variable-name\n\tpublic start_date: Date | null;\n\t// tslint:disable-next-line variable-name\n\tpublic end_date: Date | null;\n\n\tpublic latestStart: Date;\n\tpublic earliestStart: Date;\n\tpublic earliestEnd: Date;\n\tpublic latestEnd: Date;\n\n\tpublic latestSchedulingStart: Date;\n\tpublic earliestSchedulingStart: Date;\n\tpublic latestSchedulingEnd: Date;\n\tpublic earliestSchedulingEnd: Date;\n\n\tpublic kind: string;\n\tpublic conflict: boolean;\n\n\tconstructor() {\n\t\tthis.link = null;\n\t\tthis.task = null;\n\t\tthis.start_date = null;\n\t\tthis.end_date = null;\n\t\tthis.latestStart = null;\n\t\tthis.earliestStart = null;\n\t\tthis.earliestEnd = null;\n\t\tthis.latestEnd = null;\n\t\tthis.latestSchedulingStart = null;\n\t\tthis.earliestSchedulingStart = null;\n\t\tthis.latestSchedulingEnd = null;\n\t\tthis.earliestSchedulingEnd = null;\n\t\tthis.kind = \"asap\";\n\t\tthis.conflict = false;\n\t}\n}","import * as helpers from \"../../utils/helpers\";\nimport { ConstraintTypes } from \"./constraint_types\";\nimport { TaskPlan } from \"./task_plan\";\n\nexport class ConstraintsHelper {\n\tstatic Create(gantt: any): ConstraintsHelper {\n\t\treturn new ConstraintsHelper(gantt);\n\t}\n\n\tprivate _gantt: any;\n\tprivate constructor(gantt: any) {\n\t\tthis._gantt = gantt;\n\t}\n\n\tisAsapTask = (task: ITask): boolean => {\n\t\tconst constraintType = this.getConstraintType(task);\n\t\tif (this._gantt.config.schedule_from_end) {\n\t\t\tif (constraintType === ConstraintTypes.ASAP) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\tif (constraintType === ConstraintTypes.ALAP) {\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t};\n\n\tisAlapTask = (task: ITask): boolean => {\n\t\treturn !this.isAsapTask(task);\n\t};\n\n\tgetConstraintType = (task: ITask): ConstraintTypes => {\n\t\t// GS-1487. Don't add a constraint if auto-scheduling is cancelled\n\t\tif (!this._gantt._isAutoSchedulable(task)){\n\t\t\treturn;\n\t\t}\n\n\t\tconst constraint = this._getTaskConstraint(task);\n\n\t\t// in case of backward scheduling, tasks without explicit constraints are considered ALAP tasks\n\t\tif (constraint.constraint_type) {\n\t\t\treturn constraint.constraint_type;\n\t\t} else if (this._gantt.config.schedule_from_end) {\n\t\t\treturn ConstraintTypes.ALAP;\n\t\t} else {\n\t\t\treturn ConstraintTypes.ASAP;\n\t\t}\n\t};\n\n\t_getTaskConstraint = (task: ITask) => {\n\n\t\tlet constraint = this._getOwnConstraint(task);\n\n\t\t// GS-2231. Child task shouldn't inherit constraints in the group mode\n\t\tif(this._gantt.config.auto_scheduling_project_constraint && !this._gantt.getState().group_mode){\n\n\t\t\tlet defaultConstraintType = ConstraintTypes.ASAP;\n\t\t\tif(this._gantt.config.schedule_from_end){\n\t\t\t\tdefaultConstraintType = ConstraintTypes.ALAP;\n\t\t\t}\n\n\t\t\tif((constraint && constraint.constraint_type) === defaultConstraintType || !constraint){\n\t\t\t\tconstraint = this._getParentConstraint(task);\n\t\t\t}\n\t\t}\n\n\t\treturn constraint;\n\t};\n\n\t_getOwnConstraint = (task: ITask) => {\n\t\treturn {\n\t\t\tconstraint_type: task.constraint_type,\n\t\t\tconstraint_date: task.constraint_date\n\t\t};\n\t};\n\n\t_getParentConstraint = (task: ITask) => {\n\t\tlet defaultConstraintType = ConstraintTypes.ASAP;\n\t\tif(this._gantt.config.schedule_from_end){\n\t\t\tdefaultConstraintType = ConstraintTypes.ALAP;\n\t\t}\n\n\t\tlet constraint = {\n\t\t\tconstraint_type: defaultConstraintType,\n\t\t\tconstraint_date: null\n\t\t};\n\n\t\tthis._gantt.eachParent((parent) => {\n\t\t\tif(constraint.constraint_type !== defaultConstraintType){\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif(parent.constraint_type && parent.constraint_type !== defaultConstraintType){\n\t\t\t\tconstraint = {\n\t\t\t\t\tconstraint_type: parent.constraint_type,\n\t\t\t\t\tconstraint_date: parent.constraint_date\n\t\t\t\t};\n\t\t\t}\n\t\t}, task.id);\n\t\treturn constraint;\n\t};\n\n\thasConstraint = (task: ITask): boolean => {\n\t\treturn !!this.getConstraintType(task);\n\t};\n\n\tprocessConstraint = (task: ITask, plan: TaskPlan): TaskPlan => {\n\t\tconst constraint = this._getTaskConstraint(task);\n\n\t\tif (constraint) {\n\t\t\tif (\n\t\t\t\tconstraint.constraint_type === ConstraintTypes.ALAP ||\n\t\t\t\tconstraint.constraint_type === ConstraintTypes.ASAP\n\t\t\t) {\n\t\t\t\t// this kind of constraint is calculated after main scheduling\n\t\t\t} else if(helpers.isValidDate(constraint.constraint_date)) {\n\t\t\t\tconst constraintDate = constraint.constraint_date;\n\n\t\t\t\tconst newPlan = TaskPlan.Create(plan);\n\t\t\t\tnewPlan.task = task.id;\n\n\t\t\t\tswitch (constraint.constraint_type) {\n\t\t\t\t\tcase ConstraintTypes.SNET:\n\t\t\t\t\t\tnewPlan.earliestStart = new Date(constraintDate);\n\t\t\t\t\t\tnewPlan.earliestEnd = this._gantt.calculateEndDate({\n\t\t\t\t\t\t\tstart_date: newPlan.earliestStart,\n\t\t\t\t\t\t\tduration: task.duration,\n\t\t\t\t\t\t\ttask\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnewPlan.link = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ConstraintTypes.SNLT:\n\t\t\t\t\t\tnewPlan.latestStart = new Date(constraintDate);\n\t\t\t\t\t\tnewPlan.latestEnd = this._gantt.calculateEndDate({\n\t\t\t\t\t\t\tstart_date: newPlan.latestStart,\n\t\t\t\t\t\t\tduration: task.duration,\n\t\t\t\t\t\t\ttask\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnewPlan.link = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ConstraintTypes.FNET:\n\t\t\t\t\t\tnewPlan.earliestStart = this._gantt.calculateEndDate({\n\t\t\t\t\t\t\tstart_date: constraintDate,\n\t\t\t\t\t\t\tduration: -task.duration,\n\t\t\t\t\t\t\ttask\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnewPlan.earliestEnd = new Date(constraintDate);\n\t\t\t\t\t\tnewPlan.link = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ConstraintTypes.FNLT:\n\t\t\t\t\t\tnewPlan.latestStart = this._gantt.calculateEndDate({\n\t\t\t\t\t\t\tstart_date: constraintDate,\n\t\t\t\t\t\t\tduration: -task.duration,\n\t\t\t\t\t\t\ttask\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnewPlan.latestEnd = new Date(constraintDate);\n\t\t\t\t\t\tnewPlan.link = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ConstraintTypes.MSO:\n\t\t\t\t\t\tnewPlan.earliestStart = new Date(constraintDate);\n\t\t\t\t\t\tnewPlan.earliestEnd = this._gantt.calculateEndDate({\n\t\t\t\t\t\t\tstart_date: newPlan.earliestStart,\n\t\t\t\t\t\t\tduration: task.duration,\n\t\t\t\t\t\t\ttask\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnewPlan.latestStart = newPlan.earliestStart;\n\t\t\t\t\t\tnewPlan.latestEnd = newPlan.earliestEnd;\n\t\t\t\t\t\tnewPlan.link = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ConstraintTypes.MFO:\n\t\t\t\t\t\tnewPlan.earliestStart = this._gantt.calculateEndDate({\n\t\t\t\t\t\t\tstart_date: constraintDate,\n\t\t\t\t\t\t\tduration: -task.duration,\n\t\t\t\t\t\t\ttask\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnewPlan.earliestEnd = this._gantt.calculateEndDate({\n\t\t\t\t\t\t\tstart_date: newPlan.earliestStart,\n\t\t\t\t\t\t\tduration: task.duration,\n\t\t\t\t\t\t\ttask\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnewPlan.latestStart = newPlan.earliestStart;\n\t\t\t\t\t\tnewPlan.latestEnd = newPlan.earliestEnd;\n\t\t\t\t\t\tnewPlan.link = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\treturn newPlan;\n\t\t\t}\n\t\t}\n\n\t\treturn plan;\n\t};\n\n\tgetConstraints = (id: TaskID, relations: IInternalLink[]): ITask[] => {\n\t\tconst result = [];\n\t\tconst tasks = {};\n\n\t\tconst store = (task: any) => {\n\t\t\tif (tasks[task.id]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this.hasConstraint(task) && !this._gantt.isSummaryTask(task)) {\n\t\t\t\ttasks[task.id] = task;\n\t\t\t}\n\t\t};\n\n\t\tif (this._gantt.isTaskExists(id)) {\n\t\t\tconst task = this._gantt.getTask(id);\n\t\t\tstore(task);\n\t\t}\n\n\t\tthis._gantt.eachTask(task => store(task), id);\n\n\t\tlet current;\n\t\tif (relations) {\n\t\t\tfor (let i = 0; i < relations.length; i++) {\n\t\t\t\tconst rel = relations[i];\n\t\t\t\tif (!tasks[rel.target]) {\n\t\t\t\t\tcurrent = this._gantt.getTask(rel.target);\n\t\t\t\t\tstore(current);\n\t\t\t\t}\n\t\t\t\tif (!tasks[rel.source]) {\n\t\t\t\t\tcurrent = this._gantt.getTask(rel.source);\n\t\t\t\t\tstore(current);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const taskId in tasks) {\n\t\t\t// GS-745 do not auto-schedule placeholders\n\t\t\tif (tasks[taskId].type !== this._gantt.config.types.placeholder) {\n\t\t\t\tresult.push(tasks[taskId]);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t};\n}\n","export default class DateComparator {\n\tprotected _gantt: any;\n\n\tconstructor(gantt) {\n\t\tthis._gantt = gantt;\n\t}\n\n\tpublic isEqual(dateA: Date, dateB: Date, task: ITask): boolean {\n\t\treturn !this._gantt._hasDuration(dateA, dateB, task);\n\t}\n\n\tpublic isFirstSmaller(small: Date, big: Date, task: ITask): boolean {\n\t\tif (small.valueOf() < big.valueOf() && !this.isEqual(small, big, task)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic isSmallerOrDefault(smallDate: Date, bigDate: Date, task: ITask): boolean {\n\t\treturn !!(!smallDate || this.isFirstSmaller(smallDate, bigDate, task));\n\t}\n\n\tpublic isGreaterOrDefault(smallDate: Date, bigDate: Date, task: ITask): boolean {\n\t\treturn !!(!smallDate || this.isFirstSmaller(bigDate, smallDate, task));\n\t}\n}","import DateComparator from \"./date_comparator\";\nimport { TaskPlan } from \"./task_plan\";\n\nexport class AlapStrategy implements ISchedulingStrategy {\n\tstatic Create(gantt: any): AlapStrategy {\n\t\tconst instance = new AlapStrategy();\n\t\tinstance._gantt = gantt;\n\t\tinstance._comparator = new DateComparator(gantt);\n\t\treturn instance;\n\t}\n\n\tprotected _gantt: any;\n\tprotected _comparator: DateComparator;\n\n\tresolveRelationDate(taskId: TaskID, adjacentLinks: ITaskRelations, plansHash: IPlansHash): TaskPlan {\n\t\tlet maxEnd = null;\n\t\tlet linkId = null;\n\t\tlet maxStart = null;\n\t\tlet defaultStart = null;\n\t\tconst task = this._gantt.getTask(taskId);\n\t\tconst relations = adjacentLinks.successors;\n\t\tlet maxRelationDate = null;\n\t\tconst masterPlan = plansHash[taskId];\n\t\tfor (let i = 0; i < relations.length; i++) {\n\t\t\tconst relation = relations[i];\n\n\t\t\t// .preferredStart still exists only to emulate pre 6.1 auto scheduling behavior\n\t\t\t// will be removed in future versions\n\t\t\t// TODO: remove .preferredStart in v7.0\n\t\t\tdefaultStart = relation.preferredStart;\n\t\t\tconst constraintDate = this.getLatestEndDate(relation, plansHash, task);\n\t\t\tconst constraintStartDate = this._gantt.calculateEndDate({ start_date: constraintDate, duration: - task.duration, task });\n\n\t\t\tif (this._comparator.isGreaterOrDefault(maxRelationDate, constraintDate, task)) {\n\t\t\t\tmaxRelationDate = constraintDate;\n\t\t\t}\n\t\t\tif (this._comparator.isGreaterOrDefault(defaultStart, constraintStartDate, task) && this._comparator.isGreaterOrDefault(maxEnd, constraintDate, task)) {\n\t\t\t\tmaxEnd = constraintDate;\n\t\t\t\tmaxStart = constraintStartDate;\n\t\t\t\tlinkId = relation.id;\n\t\t\t}\n\t\t}\n\n\t\tif (!relations.length && this._gantt.config.project_end) {\n\t\t\tif (this._comparator.isGreaterOrDefault(this._gantt.config.project_end, task.end_date, task)) {\n\t\t\t\tmaxEnd = this._gantt.config.project_end;\n\t\t\t}\n\t\t\t// GS-1152. don't process tasks with cancelled auto-scheduling\n\t\t\tif (this._gantt.callEvent(\"onBeforeTaskAutoSchedule\", [task, task.end_date]) === false) {\n\t\t\t\tmaxEnd = task.end_date;\n\t\t\t}\n\t\t}\n\n\t\tif (maxEnd) {\n\t\t\t// GS-1556. Tasks with zero duration shouldn't violate the project_end date\n\t\t\tif (task.duration){\n\t\t\t\tmaxEnd = this._gantt.getClosestWorkTime({ date: maxEnd, dir: \"future\", task });\n\t\t\t\tmaxStart = this._gantt.calculateEndDate({ start_date: maxEnd, duration: - task.duration, task });\n\t\t\t} else {\n\t\t\t\tmaxStart = maxEnd = this._gantt.getClosestWorkTime({ date: maxEnd, dir: \"past\", task });\n\t\t\t}\n\t\t}\n\n\t\tconst currentPlan = TaskPlan.Create(masterPlan);\n\n\t\tcurrentPlan.link = linkId;\n\t\tcurrentPlan.task = taskId;\n\t\tcurrentPlan.end_date = maxEnd;\n\t\tcurrentPlan.start_date = maxStart;\n\t\tcurrentPlan.kind = \"alap\";\n\n\t\tif (maxRelationDate) {\n\t\t\tcurrentPlan.latestSchedulingStart = this._gantt.calculateEndDate({ start_date: maxRelationDate, duration: - task.duration, task });\n\t\t\tcurrentPlan.latestSchedulingEnd = maxRelationDate;\n\t\t}\n\n\t\treturn currentPlan;\n\n\t}\n\n\tprotected getSuccessorStartDate(id: TaskID, plansHash: IPlansHash): Date {\n\t\tconst plan = plansHash[id];\n\t\tconst task = this._gantt.getTask(id);\n\t\tlet res;\n\n\t\tif (!(plan && (plan.start_date || plan.end_date))) {\n\t\t\tres = task.start_date;\n\t\t} else if (plan.start_date) {\n\t\t\tres = plan.start_date;\n\t\t} else {\n\t\t\tres = this._gantt.calculateEndDate({ start_date: plan.end_date, duration: - task.duration, task });\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tprotected getLatestEndDate(relation: IInternalLink, plansHash: IPlansHash, task: ITask) {\n\t\tconst successorStart = this.getSuccessorStartDate(relation.target, plansHash);\n\t\tconst predecessor = task;\n\n\t\tlet predecessorEnd = this._gantt.getClosestWorkTime({ date: successorStart, dir: \"past\", task: predecessor });\n\n\t\tif (predecessorEnd && relation.lag && relation.lag * 1 === relation.lag * 1) {\n\t\t\tpredecessorEnd = this._gantt.calculateEndDate({ start_date: predecessorEnd, duration: -relation.lag * 1, task: predecessor });\n\t\t}\n\n\t\treturn predecessorEnd;\n\t}\n}","import DateComparator from \"./date_comparator\";\nimport { TaskPlan } from \"./task_plan\";\n\nexport class AsapStrategy implements ISchedulingStrategy {\n\tstatic Create(gantt: any): AsapStrategy {\n\t\tconst instance = new AsapStrategy();\n\t\tinstance._gantt = gantt;\n\t\tinstance._comparator = new DateComparator(gantt);\n\t\treturn instance;\n\t}\n\n\tprotected _gantt: any;\n\tprotected _comparator: DateComparator;\n\n\tresolveRelationDate(\n\t\ttaskId: TaskID,\n\t\tadjacentLinks: ITaskRelations,\n\t\tplansHash: IPlansHash\n\t): TaskPlan {\n\t\tlet minStart = null;\n\t\tlet linkId = null;\n\n\t\tlet defaultStart = null;\n\t\tconst task = this._gantt.getTask(taskId);\n\t\tconst relations = adjacentLinks.predecessors;\n\n\t\tconst autoScheduledDates = {};\n\t\tlet minRelationDate = null;\n\t\tfor (let i = 0; i < relations.length; i++) {\n\t\t\tconst relation = relations[i];\n\n\t\t\t// .preferredStart still exists only to emulate pre 6.1 auto scheduling behavior\n\t\t\t// will be removed in future versions\n\t\t\t// TODO: remove .preferredStart in v7.0\n\t\t\tdefaultStart = relation.preferredStart;\n\n\t\t\tconst constraintDate = this.getEarliestStartDate(\n\t\t\t\trelation,\n\t\t\t\tplansHash,\n\t\t\t\ttask\n\t\t\t);\n\n\t\t\tif (this._comparator.isSmallerOrDefault(minRelationDate, constraintDate, task)) {\n\t\t\t\tminRelationDate = constraintDate;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tthis._comparator.isSmallerOrDefault(defaultStart, constraintDate, task) &&\n\t\t\t\tthis._comparator.isSmallerOrDefault(minStart, constraintDate, task)\n\t\t\t) {\n\t\t\t\tminStart = constraintDate;\n\t\t\t\tlinkId = relation.id;\n\t\t\t}\n\t\t\tif (!task.duration){\n\t\t\t\tconst link = this._gantt.getLink(relation.id);\n\t\t\t\tif (autoScheduledDates[link.type] === undefined){\n\t\t\t\t\tautoScheduledDates[link.type] = +constraintDate;\n\t\t\t\t}\n\t\t\t\telse if (autoScheduledDates[link.type] < +constraintDate){\n\t\t\t\t\tautoScheduledDates[link.type] = +constraintDate;\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif (!relations.length && this._gantt.config.project_start) {\n\t\t\tif (this._comparator.isSmallerOrDefault(task.start_date, this._gantt.config.project_start, task) ||\n\t\t\t// GS-403 - auto_scheduling_strict = true to schedule independent asap tasks to the earliest date, auto_scheduling_strict=false to keep the old behavior\n\t\t\t(this._gantt.config.auto_scheduling_strict && this._comparator.isGreaterOrDefault(task.start_date, this._gantt.config.project_start, task)\n\t\t\t)\n\t\t\t) {\n\t\t\t\tminStart = this._gantt.config.project_start;\n\t\t\t}\n\t\t\t// GS-1152. don't process tasks with cancelled auto-scheduling\n\t\t\tif (this._gantt.callEvent(\"onBeforeTaskAutoSchedule\", [task, task.start_date]) === false) {\n\t\t\t\tminStart = task.start_date;\n\t\t\t}\n\t\t}\n\n\t\tlet maxEnd = null;\n\t\tif (minStart) {\n\t\t\tif (task.duration) {\n\t\t\t\tminStart = this._gantt.getClosestWorkTime({\n\t\t\t\t\tdate: minStart,\n\t\t\t\t\tdir: \"future\",\n\t\t\t\t\ttask\n\t\t\t\t});\n\t\t\t\tmaxEnd = this._gantt.calculateEndDate({\n\t\t\t\t\tstart_date: minStart,\n\t\t\t\t\tduration: task.duration,\n\t\t\t\t\ttask\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// GS-1340 and GS-2508. For FF links, the milestones should start before the weekends\n\t\t\t\t// When there are multiple links, other types have a higher priority over FF links\n\t\t\t\tlet milestoneWorktimeDirection = \"future\";\n\t\t\t\tconst linkProps = this._gantt.config.links;\n\t\t\t\tif (autoScheduledDates[linkProps.finish_to_finish] !== undefined){\n\t\t\t\t\tconst onlyFFLink = relations.length === 1;\n\t\t\t\t\tlet noRelevantLinks = true;\n\t\t\t\t\tfor (const linkType in autoScheduledDates){\n\t\t\t\t\t\tif (linkType != linkProps.finish_to_finish &&\n\t\t\t\t\t\t\tautoScheduledDates[linkProps.finish_to_finish] < autoScheduledDates[linkType]){\n\t\t\t\t\t\t\t\tnoRelevantLinks = false;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (onlyFFLink || noRelevantLinks){\n\t\t\t\t\t\tmilestoneWorktimeDirection = \"past\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tminStart = maxEnd = this._gantt.getClosestWorkTime({ date: minStart, dir: milestoneWorktimeDirection, task });\n\t\t\t}\n\n\t\t}\n\n\t\tconst masterPlan = plansHash[taskId];\n\t\tconst currentPlan = TaskPlan.Create(masterPlan);\n\n\t\tcurrentPlan.link = linkId;\n\t\tcurrentPlan.task = taskId;\n\t\tcurrentPlan.start_date = minStart;\n\t\tcurrentPlan.end_date = maxEnd;\n\t\tcurrentPlan.kind = \"asap\";\n\n\t\tif (minRelationDate) {\n\t\t\tcurrentPlan.earliestSchedulingStart = minRelationDate;\n\t\t\tcurrentPlan.earliestSchedulingEnd = this._gantt.calculateEndDate({\n\t\t\t\tstart_date: minRelationDate,\n\t\t\t\tduration: task.duration,\n\t\t\t\ttask\n\t\t\t});\n\t\t}\n\n\t\treturn currentPlan;\n\t}\n\n\tprotected getPredecessorEndDate(id: TaskID, plansHash: IPlansHash): Date {\n\t\tconst plan = plansHash[id];\n\t\tconst task = this._gantt.getTask(id);\n\t\tlet res;\n\n\t\tif (!(plan && (plan.start_date || plan.end_date))) {\n\t\t\tres = task.end_date;\n\t\t} else if (plan.end_date) {\n\t\t\tres = plan.end_date;\n\t\t} else {\n\t\t\tres = this._gantt.calculateEndDate({\n\t\t\t\tstart_date: plan.start_date,\n\t\t\t\tduration: task.duration,\n\t\t\t\ttask\n\t\t\t});\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tprotected getEarliestStartDate(relation: IInternalLink, plansHash: IPlansHash, task: ITask): Date {\n\t\tconst predecessorEnd = this.getPredecessorEndDate(\n\t\t\trelation.source,\n\t\t\tplansHash\n\t\t);\n\t\tconst successor = task;\n\t\tconst predecessor = this._gantt.getTask(relation.source);\n\t\tlet successorStart: Date;\n\n\t\tif (\n\t\t\t(predecessorEnd &&\n\t\t\trelation.lag &&\n\t\t\trelation.lag * 1 === relation.lag * 1)\n\t\t) {\n\t\t\t// GS-2330. If it is a subtask link and we move projects, we should use the project calendar\n\t\t\tlet taskCalendar = successor;\n\t\t\tif (this._gantt.config.auto_scheduling_move_projects && relation.subtaskLink && this._gantt.isTaskExists(relation.targetParent)){\n\t\t\t\ttaskCalendar = this._gantt.getTask(relation.targetParent);\n\t\t\t}\n\n\t\t\tsuccessorStart = this._gantt.getClosestWorkTime({\n\t\t\t\tdate: predecessorEnd,\n\t\t\t\tdir: \"future\",\n\t\t\t\ttask: predecessor\n\t\t\t});\n\n\t\t\tif(relation.sourceLag){\n\t\t\t\tsuccessorStart = this._gantt.calculateEndDate({\n\t\t\t\t\tstart_date: successorStart,\n\t\t\t\t\tduration: relation.sourceLag * 1,\n\t\t\t\t\ttask: predecessor\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif(relation.targetLag){\n\t\t\t\tsuccessorStart = this._gantt.calculateEndDate({\n\t\t\t\t\tstart_date: successorStart,\n\t\t\t\t\tduration: relation.targetLag * 1,\n\t\t\t\t\ttask: taskCalendar\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tsuccessorStart = this._gantt.calculateEndDate({\n\t\t\t\tstart_date: successorStart,\n\t\t\t\tduration: relation.trueLag * 1,\n\t\t\t\ttask: taskCalendar\n\t\t\t});\n\n\t\t} else {\n\t\t\tconst ffLink = this._gantt.getLink(relation.id).type === this._gantt.config.links.finish_to_finish;\n\n\t\t\tif (!successor.duration && ffLink) {\n\t\t\t\tsuccessorStart = this._gantt.getClosestWorkTime({\n\t\t\t\t\tdate: predecessorEnd,\n\t\t\t\t\tdir: \"past\",\n\t\t\t\t\ttask: successor\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tsuccessorStart = this._gantt.getClosestWorkTime({\n\t\t\t\t\tdate: predecessorEnd,\n\t\t\t\t\tdir: \"future\",\n\t\t\t\t\ttask: successor\n\t\t\t\t});\n\t\t\t}\n\n\t\t}\n\n\t\treturn successorStart;\n\t}\n}\n","import { AlapStrategy } from \"./alap_strategy\";\nimport { AsapStrategy } from \"./asap_strategy\";\nimport { ConstraintTypes } from \"./constraint_types\";\nimport { ConstraintsHelper } from \"./constraints\";\nimport { TaskPlan } from \"./task_plan\";\n\nexport class AutoSchedulingPlanner {\n\tprivate _gantt: any;\n\tprivate _constraintsHelper: ConstraintsHelper;\n\tprivate _graphHelper: any;\n\tprivate _asapStrategy: AsapStrategy;\n\tprivate _alapStrategy: AlapStrategy;\n\tprivate _secondIterationRequired?: boolean;\n\tprivate _secondIteration: boolean = false;\n\n\tconstructor(\n\t\tgantt: any,\n\t\tgraphHelper: any,\n\t\tconstraintsHelper: ConstraintsHelper\n\t) {\n\t\tthis._gantt = gantt;\n\t\tthis._constraintsHelper = constraintsHelper;\n\t\tthis._graphHelper = graphHelper;\n\t\tthis._asapStrategy = AsapStrategy.Create(gantt);\n\t\tthis._alapStrategy = AlapStrategy.Create(gantt);\n\t\tthis._secondIterationRequired = false;\n\t}\n\n\tgeneratePlan(relations: IInternalLink[], constraints: ITask[]): TaskPlan[] {\n\t\tconst graphHelper = this._graphHelper;\n\t\tconst gantt = this._gantt;\n\t\tconst constraintsHelper = this._constraintsHelper;\n\t\tconst alapStrategy = this._alapStrategy;\n\t\tconst asapStrategy = this._asapStrategy;\n\n\t\tconst {\n\t\t\torderedIds,\n\t\t\treversedIds,\n\t\t\trelationsMap,\n\t\t\tplansHash } = this.buildWorkCollections(relations, constraints, graphHelper);\n\n\t\tlet result: TaskPlan[];\n\n\t\tthis.processConstraints(orderedIds, plansHash, gantt, constraintsHelper);\n\n\t\tif (gantt.config.schedule_from_end) {\n\t\t\t// when scheduling from end - iterate tasks from end and schedule them as late as possible\n\t\t\t// after that - iterate tasks from start and schedule asap tasks\n\t\t\tresult = this.iterateTasks(reversedIds, orderedIds, constraintsHelper.isAlapTask, alapStrategy, asapStrategy, relationsMap, plansHash);\n\t\t} else {\n\t\t\t// when scheduling from end - iterate tasks from start and schedule them as soon as possible\n\t\t\t// after that - iterate tasks from end and schedule asap alap\n\t\t\tresult = this.iterateTasks(orderedIds, reversedIds, constraintsHelper.isAsapTask, asapStrategy, alapStrategy, relationsMap, plansHash);\n\t\t}\n\t\treturn result;\n\t}\n\n\tapplyProjectPlan(projectPlan: TaskPlan[]): ITask[] {\n\t\tconst gantt = this._gantt;\n\n\t\tlet plan: TaskPlan;\n\t\tlet task: ITask;\n\t\tlet link: ILink;\n\t\tlet reason: ITask;\n\n\t\tconst updateTasks = [];\n\t\tfor (let i = 0; i < projectPlan.length; i++) {\n\t\t\tlink = null;\n\t\t\treason = null;\n\t\t\tplan = projectPlan[i];\n\n\t\t\tif (!gantt.isTaskExists(plan.task)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttask = gantt.getTask(plan.task);\n\t\t\tif (plan.link) {\n\t\t\t\tlink = gantt.getLink(plan.link);\n\t\t\t\tif (plan.kind === \"asap\") {\n\t\t\t\t\treason = this._gantt.getTask(link.source);\n\t\t\t\t} else {\n\t\t\t\t\t// alap tasks are scheduled by their successors\n\t\t\t\t\treason = this._gantt.getTask(link.target);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet newDate = null;\n\t\t\tif (\n\t\t\t\tplan.start_date &&\n\t\t\t\ttask.start_date.valueOf() !== plan.start_date.valueOf()\n\t\t\t) {\n\t\t\t\tnewDate = plan.start_date;\n\t\t\t}\n\n\t\t\tif (!newDate) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttask.start_date = newDate;\n\t\t\ttask.end_date = gantt.calculateEndDate(task);\n\n\t\t\tupdateTasks.push(task.id);\n\t\t\tgantt.callEvent(\"onAfterTaskAutoSchedule\", [\n\t\t\t\ttask,\n\t\t\t\tnewDate,\n\t\t\t\tlink,\n\t\t\t\treason\n\t\t\t]);\n\t\t}\n\t\treturn updateTasks;\n\t}\n\n\tprotected iterateTasks(\n\t\tmainSequence: TaskID[],\n\t\tsecondarySequence: TaskID[],\n\t\tisMainSequence: (task: ITask) => boolean,\n\t\tmainSequenceStrategy: ISchedulingStrategy,\n\t\tsecondarySequenceStrategy: ISchedulingStrategy,\n\t\trelationsMap: ITaskLinksMap,\n\t\tplansHash: IPlansHash\n\n\t): TaskPlan[] {\n\t\tconst gantt = this._gantt;\n\t\tconst result: TaskPlan[] = [];\n\n\t\tfor (let i = 0; i < mainSequence.length; i++) {\n\t\t\tconst currentId = mainSequence[i];\n\t\t\tconst task = gantt.getTask(currentId);\n\t\t\tif (!gantt._isAutoSchedulable(task)){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst plan = mainSequenceStrategy.resolveRelationDate(\n\t\t\t\tcurrentId,\n\t\t\t\trelationsMap[currentId],\n\t\t\t\tplansHash\n\t\t\t);\n\t\t\tthis.limitPlanDates(task, plan);\n\t\t\tif (isMainSequence(task)) {\n\t\t\t\tthis.processResolvedDate(task, plan, result, plansHash);\n\t\t\t} else {\n\t\t\t\tplansHash[task.id] = plan;\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = 0; i < secondarySequence.length; i++) {\n\t\t\tconst currentId = secondarySequence[i];\n\t\t\tconst task = gantt.getTask(currentId);\n\t\t\tif (!gantt._isAutoSchedulable(task)){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isMainSequence(task)) {\n\t\t\t\tconst plan = secondarySequenceStrategy.resolveRelationDate(\n\t\t\t\t\tcurrentId,\n\t\t\t\t\trelationsMap[currentId],\n\t\t\t\t\tplansHash\n\t\t\t\t);\n\t\t\t\tthis.limitPlanDates(task, plan);\n\t\t\t\tthis.processResolvedDate(task, plan, result, plansHash);\n\t\t\t}\n\t\t}\n\n\t\tif (this._secondIterationRequired){\n\t\t\tif (this._secondIteration){\n\t\t\t\tthis._secondIteration = false;\n\t\t\t} else {\n\t\t\t\tthis._secondIteration = true;\n\n\t\t\t\t// if the duration of the project tasks changed, the lag value is updated\n\t\t\t\t// so, we need to auto-schedule tasks again with the updated dates\n\t\t\t\tif (this.summaryLagChanged(gantt, relationsMap, plansHash)){\n\t\t\t\t\treturn this.iterateTasks(\n\t\t\t\t\t\tmainSequence,\n\t\t\t\t\t\tsecondarySequence,\n\t\t\t\t\t\tisMainSequence,\n\t\t\t\t\t\tmainSequenceStrategy,\n\t\t\t\t\t\tsecondarySequenceStrategy,\n\t\t\t\t\t\trelationsMap,\n\t\t\t\t\t\tplansHash\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprotected summaryLagChanged(gantt, relationsMap, plansHash){\n\t\t// update projects and relations from plans\n\t\tconst projectUpdates = {};\n\t\tconst linksToUpdate = {};\n\n\t\t// get minimal and maximal dates for target and source projects\n\t\tfor (const taskId in relationsMap){\n\t\t\trelationsMap[taskId].predecessors.forEach((relation)=>{\n\t\t\t\tif (relation.subtaskLink){\n\t\t\t\t\tconst link = gantt.getLink(relation.id);\n\t\t\t\t\tthis.getProjectUpdates(gantt, plansHash, relation, link, \"source\", projectUpdates, linksToUpdate);\n\t\t\t\t\tthis.getProjectUpdates(gantt, plansHash, relation, link, \"target\", projectUpdates, linksToUpdate);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// update project tasks\n\t\tlet shouldReschedule = false;\n\n\t\tfor (const projectId in projectUpdates){\n\t\t\tconst updatedProject = projectUpdates[projectId];\n\t\t\tif (!updatedProject.min || !updatedProject.max){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst task = gantt.getTask(projectId);\n\t\t\t// we cannot rely on the `duration` parameter as it can have a different value for project tasks\n\t\t\t// during the initial scheduling\n\t\t\tconst initialDuration = gantt.calculateDuration({start_date: task.start_date, end_date: task.end_date, task});\n\t\t\t// we need to modify the dates and duration of the project tasks as\n\t\t\t// the _formatLink and the functions that follow rely on these parameters\n\t\t\t// it shouldn't impact logic as project tasks ignore the date parameters\n\t\t\tconst newDuration = gantt.calculateDuration({start_date: updatedProject.min, end_date: updatedProject.max, task});\n\t\t\tif (newDuration === initialDuration){\n\t\t\t\t// no need to reschedule\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttask.start_date = updatedProject.min;\n\t\t\ttask.end_date = updatedProject.max;\n\t\t\ttask.duration = newDuration;\n\t\t}\n\t\t\n\t\tfor (const linkId in linksToUpdate){\n\t\t\tconst link = linksToUpdate[linkId];\n\t\t\tlet sourceDates, targetDates;\n\n\t\t\tconst updatedSource = projectUpdates[link.source];\n\t\t\tconst updatedTarget = projectUpdates[link.target];\n\t\t\tif (updatedSource){\n\t\t\t\tsourceDates = {\n\t\t\t\t\tstart_date: updatedSource.start_date,\n\t\t\t\t\tend_date: updatedSource.end_date\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (updatedTarget){\n\t\t\t\tsourceDates = {\n\t\t\t\t\tstart_date: updatedTarget.start_date,\n\t\t\t\t\tend_date: updatedTarget.end_date\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// get updated formatted link with updated dates\n\t\t\tconst updatedRelations = gantt._formatLink(link, sourceDates, targetDates);\n\t\t\t// update relationsMap\n\t\t\tupdatedRelations.forEach(function(updatedRelation){\n\t\t\tfor (const taskId in relationsMap){\n\t\t\t\trelationsMap[taskId].predecessors.forEach(function(relation){\n\t\t\t\t\t\tconst idMatch = relation.id === updatedRelation.id;\n\t\t\t\t\t\tconst targetMatch = relation.target === updatedRelation.target;\n\t\t\t\t\t\tconst sourceMatch = relation.source === updatedRelation.source;\n\t\t\t\t\t\tif (idMatch && targetMatch && sourceMatch){\n\t\t\t\t\t\t\trelation.lag = updatedRelation.lag;\n\t\t\t\t\t\t\trelation.sourceLag = updatedRelation.sourceLag;\n\t\t\t\t\t\t\trelation.targetLag = updatedRelation.targetLag;\n\t\t\t\t\t\t\trelation.hashSum = updatedRelation.hashSum;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t\tshouldReschedule = true;\n\t\t}\n\t\treturn shouldReschedule;\n\t}\n\n\tprotected getProjectUpdates(gantt, plansHash, relation, link, relationProp, projectUpdates, linksToUpdate){\n\t\tconst task = gantt.getTask(link[relationProp]);\n\t\tif (task.type === gantt.config.types.project){\n\t\t\tprojectUpdates[link[relationProp]] = projectUpdates[link[relationProp]] || {id: link[relationProp], link};\n\t\t\tconst projectForUpdate = projectUpdates[link[relationProp]];\n\t\t\tlet childTask = plansHash[relation[relationProp]];\n\t\t\tif (childTask){\n\t\t\t\tif (relationProp == \"source\" && (!childTask.start_date || !childTask.end_date)){\n\t\t\t\t\tchildTask = gantt.getTask(childTask.task);\n\t\t\t\t}\n\n\t\t\t\tprojectForUpdate.min = projectForUpdate.min || childTask.start_date;\n\t\t\t\tif (projectForUpdate.min > childTask.start_date){\n\t\t\t\t\tprojectForUpdate.min = childTask.start_date;\n\t\t\t\t}\n\t\t\t\tprojectForUpdate.max = projectForUpdate.max || childTask.end_date;\n\t\t\t\tif (projectForUpdate.max < childTask.end_date){\n\t\t\t\t\tprojectForUpdate.max = childTask.end_date;\n\t\t\t\t}\n\t\t\t\tlinksToUpdate[link.id] = link;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected processResolvedDate(\n\t\ttask: ITask,\n\t\tplan: TaskPlan,\n\t\tresult: TaskPlan[],\n\t\tplansHash: any\n\t): void {\n\t\tif (plan.start_date && this._gantt.isLinkExists(plan.link)) {\n\t\t\tlet link = null;\n\t\t\tlet reason = null;\n\t\t\tif (plan.link) {\n\t\t\t\tlink = this._gantt.getLink(plan.link);\n\t\t\t\tif (plan.kind === \"asap\") {\n\t\t\t\t\treason = this._gantt.getTask(link.source);\n\t\t\t\t} else {\n\t\t\t\t\t// alap tasks are scheduled by their successors\n\t\t\t\t\treason = this._gantt.getTask(link.target);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\ttask.start_date.valueOf() !== plan.start_date.valueOf() &&\n\t\t\t\tthis._gantt.callEvent(\"onBeforeTaskAutoSchedule\", [\n\t\t\t\t\ttask,\n\t\t\t\t\tplan.start_date,\n\t\t\t\t\tlink,\n\t\t\t\t\treason\n\t\t\t\t]) === false\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tplansHash[task.id] = plan;\n\t\tif (plan.start_date) {\n\t\t\tresult.push(plan);\n\t\t}\n\t}\n\n\tprotected limitPlanDates(task: ITask, plan: TaskPlan): TaskPlan {\n\t\tconst effectiveStart = plan.start_date || task.start_date;\n\n\t\tif (plan.earliestStart) {\n\t\t\tif (effectiveStart < plan.earliestStart) {\n\t\t\t\tplan.start_date = plan.earliestStart;\n\t\t\t\tplan.end_date = plan.earliestEnd;\n\t\t\t}\n\t\t}\n\n\t\tif (plan.latestStart) {\n\t\t\tif (effectiveStart > plan.latestStart) {\n\t\t\t\tplan.start_date = plan.latestStart;\n\t\t\t\tplan.end_date = plan.latestEnd;\n\t\t\t}\n\t\t}\n\n\t\tif (plan.latestSchedulingStart && effectiveStart > plan.latestSchedulingStart) {\n\t\t\tplan.start_date = plan.latestSchedulingStart;\n\t\t\tplan.end_date = plan.latestSchedulingEnd;\n\t\t}\n\n\t\tif (plan.earliestSchedulingStart && effectiveStart < plan.earliestSchedulingStart) {\n\t\t\tplan.start_date = plan.earliestSchedulingStart;\n\t\t\tplan.end_date = plan.earliestSchedulingEnd;\n\t\t}\n\n\t\tif (plan.start_date) { // start/end dates are either both defined or both not\n\t\t\tif (plan.start_date > plan.latestSchedulingStart ||\n\t\t\t\tplan.start_date < plan.earliestSchedulingStart ||\n\t\t\t\tplan.start_date > plan.latestStart ||\n\t\t\t\tplan.start_date < plan.earliestStart ||\n\t\t\t\tplan.end_date > plan.latestSchedulingEnd ||\n\t\t\t\tplan.end_date < plan.earliestSchedulingEnd ||\n\t\t\t\tplan.end_date > plan.latestEnd ||\n\t\t\t\tplan.end_date < plan.earliestEnd) {\n\n\t\t\t\tplan.conflict = true;\n\t\t\t}\n\t\t}\n\t\treturn plan;\n\t}\n\n\tprotected buildWorkCollections(relations: IInternalLink[], constraints: ITask[], graphHelper: any) {\n\t\tconst gantt = this._gantt;\n\t\tconst orderedIds: TaskID[] = graphHelper.topologicalSort(relations);\n\t\tconst reversedIds: TaskID[] = orderedIds.slice().reverse();\n\t\tconst plansHash: IPlansHash = {};\n\n\t\tconst relationsMap: ITaskLinksMap = {};\n\t\tfor (let i = 0, len = orderedIds.length; i < len; i++) {\n\t\t\tconst id = orderedIds[i];\n\t\t\tconst task = gantt.getTask(id);\n\t\t\tif (!gantt._isAutoSchedulable(task)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trelationsMap[id] = {\n\t\t\t\tsuccessors: [],\n\t\t\t\tpredecessors: []\n\t\t\t};\n\n\t\t\tplansHash[id] = null;\n\t\t}\n\n\t\tfor (let i = 0, len = constraints.length; i < len; i++) {\n\t\t\tconst task = constraints[i];\n\n\t\t\tif (plansHash[task.id] === undefined) {\n\t\t\t\treversedIds.unshift(task.id);\n\t\t\t\torderedIds.unshift(task.id);\n\t\t\t\tplansHash[task.id] = null;\n\t\t\t\trelationsMap[task.id] = {\n\t\t\t\t\tsuccessors: [],\n\t\t\t\t\tpredecessors: []\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = 0, len = relations.length; i < len; i++) {\n\t\t\tconst rel = relations[i];\n\t\t\tif (relationsMap[rel.source]) {\n\t\t\t\trelationsMap[rel.source].successors.push(rel);\n\t\t\t}\n\n\t\t\tif (relationsMap[rel.target]) {\n\t\t\t\trelationsMap[rel.target].predecessors.push(rel);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\torderedIds,\n\t\t\treversedIds,\n\t\t\trelationsMap,\n\t\t\tplansHash\n\t\t};\n\t}\n\n\tprotected processConstraints(orderedIds: TaskID[], plansHash: IPlansHash, gantt: any, constraintsHelper: ConstraintsHelper) {\n\t\tfor (let i = 0; i < orderedIds.length; i++) {\n\t\t\tconst currentId = orderedIds[i];\n\t\t\tconst task = gantt.getTask(currentId);\n\n\t\t\tconst constraintType = constraintsHelper.getConstraintType(task);\n\t\t\tif (\n\t\t\t\tconstraintType &&\n\t\t\t\tconstraintType !== ConstraintTypes.ASAP &&\n\t\t\t\tconstraintType !== ConstraintTypes.ALAP\n\t\t\t) {\n\t\t\t\tconst plan = constraintsHelper.processConstraint(\n\t\t\t\t\ttask,\n\t\t\t\t\tTaskPlan.Create()\n\t\t\t\t);\n\t\t\t\tplansHash[task.id] = plan;\n\t\t\t}\n\t\t}\n\t}\n}\n","interface IFlagHash {\n\t[id: string]: boolean;\n}\n\nfunction findGroups(links: IInternalLink[]): IConnectedGroup[] {\n\tconst visited: IFlagHash = {};\n\tconst groups = [];\n\tlet source: TaskID;\n\tlet target: TaskID;\n\tlet root: TaskID;\n\t// main loop - find any unvisited vertex from the input array and\n\t// treat it as the source, then perform a breadth first search from\n\t// it. All vertices visited from this search belong to the same group\n\tfor (let i = 0; i < links.length; i++) {\n\t\tsource = links[i].source;\n\t\ttarget = links[i].target;\n\t\troot = null;\n\t\tif (!visited[source]) {\n\t\t\troot = source;\n\t\t} else if (!visited[target]) {\n\t\t\troot = target;\n\t\t}\n\t\tif (root) {\n\t\t\t// there is an unvisited vertex in this pair.\n\t\t\t// perform a breadth first search, and push the resulting\n\t\t\t// group onto the list of all groups\n\t\t\tconst length = links.length;\n\t\t\tgroups.push(breadthFirstSearch(root, links, visited));\n\t\t\tif (length !== links.length) {\n\t\t\t\ti = -1;\n\t\t\t}\n\t\t}\n\t}\n\treturn groups;\n}\n\n// Breadth First Search function\n// v is the source vertex\n// links is the input array, which contains all gantt relations\n// visited is a dictionary for keeping track of whether a node is visited\nfunction breadthFirstSearch(\n\tv: TaskID,\n\tlinks: IInternalLink[],\n\tvisited: IFlagHash\n): IConnectedGroupsDetailed {\n\tconst queue: TaskID[] = [v];\n\tconst groupTasks: TaskID[] = [];\n\tconst groupLinksInternal: { [hashSum: string]: IInternalLink } = {};\n\tconst groupLinksPublic: { [id: string]: boolean } = {};\n\n\tlet currentVertex: TaskID;\n\twhile (queue.length > 0) {\n\t\tcurrentVertex = queue.shift();\n\t\tif (!visited[currentVertex]) {\n\t\t\tvisited[currentVertex] = true;\n\t\t\tgroupTasks.push(currentVertex);\n\t\t\t// go through the input array to find vertices that are\n\t\t\t// directly adjacent to the current vertex, and put them\n\t\t\t// onto the queue\n\t\t\tfor (let i = 0; i < links.length; i++) {\n\t\t\t\tconst link = links[i];\n\t\t\t\t// tslint:disable-next-line triple-equals\n\t\t\t\tif ((link.source == currentVertex || link.sourceParent == currentVertex)) {\n\t\t\t\t\tif (!visited[link.target]) {\n\t\t\t\t\t\tqueue.push(link.target);\n\t\t\t\t\t\tgroupLinksPublic[link.id] = true;\n\t\t\t\t\t\tlinks.splice(i, 1);\n\t\t\t\t\t\ti--;\n\t\t\t\t\t}\n\t\t\t\t\tgroupLinksInternal[link.hashSum] = link;\n\n\t\t\t\t\t// tslint:disable-next-line triple-equals\n\t\t\t\t} else if ((link.target == currentVertex || link.targetParent == currentVertex)) {\n\t\t\t\t\tif (!visited[link.source]) {\n\t\t\t\t\t\tqueue.push(link.source);\n\t\t\t\t\t\tgroupLinksPublic[link.id] = true;\n\t\t\t\t\t\tlinks.splice(i, 1);\n\t\t\t\t\t\ti--;\n\t\t\t\t\t}\n\t\t\t\t\tgroupLinksInternal[link.hashSum] = link;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tconst linksArray: LinkID[] = [];\n\tlet linksObjects: IInternalLink[] = [];\n\tfor (const i in groupLinksPublic) {\n\t\tlinksArray.push(i);\n\t}\n\tfor (const i in groupLinksInternal) {\n\t\tlinksObjects.push(groupLinksInternal[i]);\n\t}\n\t// GS-1689. If we have several levels of projects, the code above might not add the links\n\t// so, we need to return the original `links` object\n\tif (!linksObjects.length){\n\t\tlinksObjects = links;\n\t}\n\t// return everything in the current \"group\"\n\treturn { tasks: groupTasks, links: linksArray, processedLinks: linksObjects };\n}\n\nexport class ConnectedGroupsHelper {\n\tprivate _linksBuilder: any;\n\tprivate _gantt: any;\n\tconstructor(gantt: any, linksBuilder: any) {\n\t\tthis._linksBuilder = linksBuilder;\n\t\tthis._gantt = gantt;\n\t}\n\n\tgetConnectedGroupRelations = (id: TaskID): IInternalLink[] => {\n\t\tconst links = this._linksBuilder.getLinkedTasks();\n\t\tconst group = breadthFirstSearch(id, links, {});\n\t\treturn group.processedLinks;\n\t};\n\n\tgetConnectedGroup = (id: TaskID): IConnectedGroup | IConnectedGroup[] => {\n\t\tconst links = this._linksBuilder.getLinkedTasks();\n\t\tif (id !== undefined) {\n\t\t\tif (this._gantt.getTask(id).type === this._gantt.config.types.project) {\n\t\t\t\treturn { tasks: [], links: [] };\n\t\t\t}\n\n\t\t\tconst group = breadthFirstSearch(id, links, {});\n\t\t\treturn {\n\t\t\t\ttasks: group.tasks,\n\t\t\t\tlinks: group.links\n\t\t\t};\n\t\t} else {\n\t\t\treturn findGroups(links).map(group => ({ tasks: group.tasks, links: group.links }));\n\t\t}\n\t};\n}\n","export class LoopsFinder {\n\tprivate _linksBuilder: any;\n\tprivate _graphHelper: any;\n\tprivate _gantt: any;\n\tconstructor(gantt: any, graphHelper: any, linksBuilder: any) {\n\t\tthis._linksBuilder = linksBuilder;\n\t\tthis._graphHelper = graphHelper;\n\t\tthis._gantt = gantt;\n\t}\n\tisCircularLink = (link: ILink): boolean => {\n\t\treturn !!this.getLoopContainingLink(link);\n\t};\n\n\tgetLoopContainingLink = (link: ILink): any => {\n\t\tconst graphHelper = this._graphHelper;\n\t\tconst linksBuilder = this._linksBuilder;\n\t\tconst gantt = this._gantt;\n\n\t\tlet allRelations = linksBuilder.getLinkedTasks();\n\t\tif (!gantt.isLinkExists(link.id)) {\n\t\t\tallRelations = allRelations.concat(gantt._formatLink(link));\n\t\t}\n\n\t\tconst cycles = graphHelper.findLoops(allRelations);\n\n\t\tconst found = false;\n\t\tfor (let i = 0; i < cycles.length && !found; i++) {\n\t\t\tconst links = cycles[i].links;\n\t\t\tfor (let j = 0; j < links.length; j++) {\n\t\t\t\t// tslint:disable-next-line triple-equals\n\t\t\t\tif (links[j] == link.id) {\n\t\t\t\t\treturn cycles[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t};\n\n\tfindCycles = () => {\n\t\tconst graphHelper = this._graphHelper;\n\t\tconst linksBuilder = this._linksBuilder;\n\n\t\tconst allRelations = linksBuilder.getLinkedTasks();\n\t\treturn graphHelper.findLoops(allRelations);\n\t};\n}\n","\n/* eslint-disable no-restricted-globals */\nvar globalScope;\nif(typeof window !== \"undefined\"){\n\tglobalScope = window;\n}else{\n\tglobalScope = global;\n}\n/* eslint-enable no-restricted-globals */\n\nexport default globalScope;","import * as domHelpers from \"../../core/ui/utils/dom_helpers\";\nimport global from \"../../utils/global\";\nimport { SelectedRegion } from \"./selectedRegion\";\n\nexport class EventsManager {\n\tprivate _mouseDown: boolean = false;\n\tprivate _domEvents: any;\n\tprivate _originPosition: string;\n\tprivate _gantt: any;\n\tprivate _restoreOriginPosition: () => void;\n\tconstructor(gantt: any) {\n\t\tthis._gantt = gantt;\n\t\tthis._domEvents = gantt._createDomEventScope();\n\t}\n\n\tattach(selectedRegion: SelectedRegion, useKey?: \"shiftKey\" | \"ctrlKey\" | \"altKey\", ignore?: any): void {\n\t\tconst gantt = this._gantt;\n\t\tconst _target = selectedRegion.getViewPort();\n\t\tthis._originPosition = global.getComputedStyle(_target).display;\n\t\tthis._restoreOriginPosition = () => {\n\t\t\t_target.style.position = this._originPosition;\n\t\t};\n\t\tif (this._originPosition === \"static\") {\n\t\t\t_target.style.position = \"relative\";\n\t\t}\n\t\tconst state = gantt.$services.getService(\"state\");\n\t\tstate.registerProvider(\"clickDrag\", () => {\n\t\t\tconst result = { autoscroll: false };\n\t\t\treturn result;\n\t\t});\n\n\n\t\tlet scheduledDndCoordinates = null;\n\t\tconst startDragAndDrop = () => {\n\t\t\tif (!scheduledDndCoordinates) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._mouseDown = true;\n\t\t\tselectedRegion.setStart(gantt.copy(scheduledDndCoordinates));\n\t\t\tselectedRegion.setPosition(gantt.copy(scheduledDndCoordinates));\n\t\t\tselectedRegion.setEnd(gantt.copy(scheduledDndCoordinates));\n\t\t\tscheduledDndCoordinates = null;\n\t\t};\n\n\t\tthis._domEvents.attach(_target, \"mousedown\", (event) => {\n\t\t\tscheduledDndCoordinates = null;\n\t\t\tlet filterTargets = \".gantt_task_line, .gantt_task_link\";\n\t\t\tif (ignore !== undefined) {\n\t\t\t\tif (ignore instanceof Array) {\n\t\t\t\t\tfilterTargets = ignore.join(\", \");\n\t\t\t\t} else {\n\t\t\t\t\tfilterTargets = ignore;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (filterTargets) {\n\t\t\t\tif (gantt.utils.dom.closest(event.target, filterTargets)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tstate.registerProvider(\"clickDrag\", () => {\n\t\t\t\tconst result = { autoscroll: this._mouseDown };\n\t\t\t\treturn result;\n\t\t\t});\n\n\t\t\tif (useKey && event[useKey] !== true) { return; }\n\t\t\tscheduledDndCoordinates = this._getCoordinates(event, selectedRegion);\n\t\t});\n\t\tconst eventElement = domHelpers.getRootNode(gantt.$root) || document.body;\n\t\tthis._domEvents.attach(eventElement, \"mouseup\", (event) => {\n\t\t\tscheduledDndCoordinates = null;\n\t\t\tif (useKey && event[useKey] !== true) { return; }\n\t\t\tif (this._mouseDown === true) {\n\t\t\t\tthis._mouseDown = false;\n\t\t\t\tconst coordinates = this._getCoordinates(event, selectedRegion);\n\t\t\t\tselectedRegion.dragEnd(coordinates);\n\t\t\t}\n\t\t});\n\t\tthis._domEvents.attach(_target, \"mousemove\", (event) => {\n\t\t\tif (useKey && event[useKey] !== true) { return; }\n\t\t\t// GS-854. If we don't have useKey for the click_drag extension,\n\t\t\t// check the drag_timeline to not simultaneously use both extensions\n\t\t\tconst dragTimeline = this._gantt.ext.clickDrag;\n\t\t\tconst dragTimelineUseKey = (this._gantt.config.drag_timeline || {}).useKey;\n\t\t\tif (dragTimeline && dragTimelineUseKey) {\n\t\t\t\tif (!useKey && event[dragTimelineUseKey]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet coordinates = null;\n\t\t\tif(!this._mouseDown && scheduledDndCoordinates){\n\t\t\t\tcoordinates = this._getCoordinates(event, selectedRegion);\n\t\t\t\tif(Math.abs(scheduledDndCoordinates.relative.left - coordinates.relative.left) > 5){\n\t\t\t\t\t// add small threshold not to start dnd on simple click\n\t\t\t\t\tstartDragAndDrop();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this._mouseDown === true) {\n\t\t\t\tcoordinates = this._getCoordinates(event, selectedRegion);\n\t\t\t\tselectedRegion.setEnd(coordinates);\n\t\t\t\tselectedRegion.render();\n\t\t\t}\n\t\t});\n\t}\n\n\tdetach(): void {\n\t\tconst gantt = this._gantt;\n\t\tthis._domEvents.detachAll();\n\t\tif(this._restoreOriginPosition){\n\t\t\tthis._restoreOriginPosition();\n\t\t}\n\n\t\tconst state = gantt.$services.getService(\"state\");\n\t\tstate.unregisterProvider(\"clickDrag\");\n\t}\n\n\tdestructor(): void {\n\t\tthis.detach();\n\t}\n\n\tprivate _getCoordinates(event: MouseEvent, selectedRegion: SelectedRegion) {\n\t\tconst viewPort = selectedRegion.getViewPort();\n\t\tconst viewPortBounds = viewPort.getBoundingClientRect();\n\t\tconst { clientX, clientY } = event;\n\t\tconst result = {\n\t\t\tabsolute: {\n\t\t\t\tleft: clientX,\n\t\t\t\ttop: clientY\n\t\t\t},\n\t\t\trelative: {\n\t\t\t\tleft: clientX - viewPortBounds.left + viewPort.scrollLeft,\n\t\t\t\ttop: clientY - viewPortBounds.top + viewPort.scrollTop\n\t\t\t}\n\t\t};\n\t\treturn result;\n\t}\n}","var EventHost = function(){\n\tthis._silent_mode = false;\n\tthis.listeners = {};\n};\n\nEventHost.prototype = {\n\t_silentStart: function() {\n\t\tthis._silent_mode = true;\n\t},\n\t_silentEnd: function() {\n\t\tthis._silent_mode = false;\n\t}\n};\n\nvar\tcreateEventStorage = function(obj) {\n\tvar handlers = {};\n\tvar index = 0;\n\tvar eventStorage = function(){\n\t\tvar combinedResult = true;\n\t\tfor(var i in handlers){\n\t\t\tvar handlerResult = handlers[i].apply(obj, arguments);\n\t\t\tcombinedResult=combinedResult && handlerResult;\n\t\t}\n\t\treturn combinedResult;\n\t};\n\teventStorage.addEvent=function(handler, settings){\n\t\tif (typeof (handler) == \"function\"){\n\t\t\tvar handlerId;\n\t\t\tif(settings && settings.id){\n\t\t\t\thandlerId = settings.id;\n\t\t\t}else{\n\t\t\t\thandlerId = index;\n\t\t\t\tindex++;\n\t\t\t}\n\n\t\t\tif(settings && settings.once){\n\t\t\t\tvar originalHandler = handler;\n\t\t\t\thandler = function(){\n\t\t\t\t\toriginalHandler();\n\t\t\t\t\teventStorage.removeEvent(handlerId);\n\t\t\t\t};\n\t\t\t}\n\n\t\t\thandlers[handlerId] = handler;\n\t\t\treturn handlerId;\n\t\t}\n\t\treturn false;\n\t};\n\teventStorage.removeEvent=function(id){\n\t\tdelete handlers[id];\n\t};\n\n\teventStorage.clear = function(){\n\t\thandlers = {};\n\t};\n\n\treturn eventStorage;\n};\n\nfunction makeEventable(obj){\n\n\tvar eventHost = new EventHost();\n\tobj.attachEvent=function(eventName, handler, settings){\n\t\teventName = 'ev_'+eventName.toLowerCase();\n\t\tif (!eventHost.listeners[eventName]){\n\t\t\teventHost.listeners[eventName] = createEventStorage(this);\n\t\t}\n\n\t\tif(settings && settings.thisObject){\n\t\t\thandler = handler.bind(settings.thisObject);\n\t\t}\n\n\t\tvar innerId = eventHost.listeners[eventName].addEvent(handler, settings);\n\n\t\tvar handlerId = (eventName+':'+innerId); //return ID (ev_eventname:1)\n\t\tif(settings && settings.id){\n\t\t\thandlerId = settings.id;\n\t\t}\n\t\treturn handlerId;\n\t};\n\n\tobj.attachAll = function(callback){\n\t\tthis.attachEvent('listen_all', callback);\n\t};\n\n\tobj.callEvent=function(name, eventArguments){\n\t\tif (eventHost._silent_mode) return true;\n\n\t\tvar handlerName = 'ev_'+name.toLowerCase();\n\n\t\tvar listeners = eventHost.listeners;\n\t\tif (listeners['ev_listen_all']){\n\t\t\tlisteners['ev_listen_all'].apply(this, [name].concat(eventArguments));\n\t\t}\n\n\t\tif (listeners[handlerName])\n\t\t\treturn listeners[handlerName].apply(this, eventArguments);\n\t\treturn true;\n\t};\n\n\tobj.checkEvent=function(name){\n\t\tvar listeners = eventHost.listeners;\n\t\treturn (!!listeners['ev_'+name.toLowerCase()]);\n\t};\n\n\tobj.detachEvent=function(id){\n\t\tif (id){\n\t\t\tvar listeners = eventHost.listeners;\n\t\t\tfor(var i in listeners){\n\t\t\t\tlisteners[i].removeEvent(id); //remove event\n\t\t\t}\n\n\t\t\tvar list = id.split(':');//get EventName and ID\n\t\t\tvar listeners = eventHost.listeners;\n\t\t\tif(list.length === 2){\n\t\t\t\tvar eventName = list[0];\n\t\t\t\tvar eventId = list[1];\n\t\t\t\tif(listeners[eventName]){\n\t\t\t\t\tlisteners[eventName].removeEvent(eventId); //remove event\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\tobj.detachAllEvents = function(){\n\t\tfor (var name in eventHost.listeners) {\n\t\t\teventHost.listeners[name].clear();\n\t\t}\n\t};\n\n}\n\nexport default makeEventable;","import eventable from \"../../utils/eventable\";\nimport { isEventable } from \"../../utils/helpers\";\n\nexport interface ISelectedRegionConfig {\n\tclassName?: string;\n\trender?: (startPoint: IPoint, endPoint: IPoint) => HTMLElement;\n\tviewPort?: HTMLElement;\n\tuseRequestAnimationFrame: boolean;\n\tcallback?: (startPoint: IPoint, endPoint: IPoint, startDate: Date, endDate: Date, tasksByDate: any[], tasksByIndex: any[]) => void;\n\tsingleRow: boolean;\n}\n\ninterface ICoordinates {\n\tleft: number;\n\ttop: number;\n}\n\nexport interface IPoint {\n\tabsolute: ICoordinates;\n\trelative: ICoordinates;\n}\n\nexport class SelectedRegion {\n\trender: () => void;\n\tprivate _viewPort: HTMLElement & eventable;\n\tprivate _el: HTMLElement = document.createElement(\"div\");\n\tprivate _callback: (startPoint: IPoint, endPoint: IPoint, startDate: Date, endDate: Date, tasksByDate: any[], tasksByIndex: any[]) => void;\n\tprivate _startPoint: IPoint;\n\tprivate _endPoint: IPoint;\n\tprivate _positionPoint: IPoint;\n\tprivate _useRequestAnimationFrame: boolean;\n\tprivate _startDate: Date;\n\tprivate _endDate: Date;\n\tprivate _singleRow: boolean;\n\tprivate _gantt: any;\n\tprivate _view: any;\n\n\tconstructor(config: ISelectedRegionConfig, gantt: any, view: any) {\n\t\tthis._gantt = gantt;\n\t\tthis._view = view;\n\t\tthis._viewPort = config.viewPort;\n\t\tthis._el.classList.add(config.className);\n\t\tif (typeof config.callback === \"function\") {\n\t\t\tthis._callback = config.callback;\n\t\t}\n\n\t\tthis.render = () => {\n\t\t\tlet node;\n\t\t\tif(config.render){\n\t\t\t\tnode = config.render(this._startPoint, this._endPoint);\n\t\t\t}else{\n\t\t\t\tnode = this.defaultRender(this._startPoint, this._endPoint);\n\t\t\t}\n\n\t\t\tif(node !== this._el){\n\t\t\t\tif(this._el && this._el.parentNode){\n\t\t\t\t\tthis._el.parentNode.removeChild(this._el);\n\t\t\t\t}\n\t\t\t\tthis._el = node;\n\t\t\t}\n\n\t\t\tif (config.className !== \"\") {\n\t\t\t\tthis._el.classList.add(config.className);\n\t\t\t}\n\t\t\tthis.draw();\n\t\t};\n\n\t\tif (!isEventable(this._viewPort)) {\n\t\t\teventable(this._viewPort);\n\t\t}\n\t\tthis._singleRow = config.singleRow;\n\t\tthis._useRequestAnimationFrame = config.useRequestAnimationFrame;\n\t}\n\n\tdefaultRender = (start: IPoint, end: IPoint) => {\n\t\tif(!this._el){\n\t\t\tthis._el = document.createElement(\"div\");\n\t\t}\n\t\tconst node = this._el;\n\t\t// const gantt = this._gantt;\n\n\t\tconst top = Math.min(start.relative.top, end.relative.top);\n\t\tconst bottom = Math.max(start.relative.top, end.relative.top);\n\t\tconst left = Math.min(start.relative.left, end.relative.left);\n\t\tconst right = Math.max(start.relative.left, end.relative.left);\n\n\t\tif (this._singleRow) {\n\t\t\tconst pos = this._getTaskPositionByTop(this._startPoint.relative.top);\n\t\t\tnode.style.height = pos.height + \"px\";\n\t\t\tnode.style.top = pos.top + \"px\";\n\t\t} else {\n\t\t\tnode.style.height = Math.abs(bottom - top) + \"px\";\n\t\t\tnode.style.top = top + \"px\";\n\t\t}\n\t\tnode.style.width = Math.abs(right - left) + \"px\";\n\t\tnode.style.left = left + \"px\";\n\t\treturn node;\n\t};\n\n\tdraw() {\n\t\tif (this._useRequestAnimationFrame) {\n\t\t\treturn requestAnimationFrame(() => {\n\t\t\t\tthis._viewPort.appendChild(this.getElement());\n\t\t\t});\n\t\t} else {\n\t\t\tthis._viewPort.appendChild(this.getElement());\n\t\t}\n\t}\n\n\tclear() {\n\t\tif (this._useRequestAnimationFrame) {\n\t\t\treturn requestAnimationFrame(() => {\n\t\t\t\tif (!this._el.parentNode) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._viewPort.removeChild(this._el);\n\t\t\t});\n\t\t} else {\n\t\t\tif (!this._el.parentNode) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._viewPort.removeChild(this._el);\n\t\t}\n\t}\n\n\tgetElement() {\n\t\treturn this._el;\n\t}\n\n\tgetViewPort() {\n\t\treturn this._viewPort;\n\t}\n\n\tsetStart(startPoint: IPoint) {\n\t\tconst gantt = this._gantt;\n\t\tthis._startPoint = startPoint;\n\t\tthis._startDate = gantt.dateFromPos(this._startPoint.relative.left);\n\t\tthis._viewPort.callEvent(\"onBeforeDrag\", [this._startPoint]);\n\t}\n\n\tsetEnd(endPoint: IPoint) {\n\t\tconst gantt = this._gantt;\n\t\tthis._endPoint = endPoint;\n\t\tif (this._singleRow) {\n\t\t\tconst pos = this._getTaskPositionByTop(this._startPoint.relative.top);\n\t\t\tthis._endPoint.relative.top = pos.top;\n\t\t}\n\t\tthis._endDate = gantt.dateFromPos(this._endPoint.relative.left);\n\t\tif (this._startPoint.relative.left > this._endPoint.relative.left) {\n\t\t\tthis._positionPoint = {\n\t\t\t\trelative: { left: this._endPoint.relative.left, top: this._positionPoint.relative.top },\n\t\t\t\tabsolute: { left: this._endPoint.absolute.left, top: this._positionPoint.absolute.top }\n\t\t\t};\n\t\t}\n\t\tif (this._startPoint.relative.top > this._endPoint.relative.top) {\n\t\t\tthis._positionPoint = {\n\t\t\t\trelative: { left: this._positionPoint.relative.left, top: this._endPoint.relative.top },\n\t\t\t\tabsolute: { left: this._positionPoint.absolute.left, top: this._endPoint.absolute.top }\n\t\t\t};\n\t\t}\n\n\n\t\tthis._viewPort.callEvent(\"onDrag\", [this._startPoint, this._endPoint]);\n\t}\n\n\tsetPosition(positionPoint: IPoint) {\n\t\tthis._positionPoint = positionPoint;\n\t}\n\n\tdragEnd(endPoint: IPoint) {\n\t\tconst gantt = this._gantt;\n\t\tif(endPoint.relative.left < 0){\n\t\t\tendPoint.relative.left = 0;\n\t\t}\n\t\tthis._viewPort.callEvent(\"onBeforeDragEnd\", [this._startPoint, endPoint]);\n\t\tthis.setEnd(endPoint);\n\t\t// GS-1422. The endDate can be null if we drag the mouse outside the Gantt container\n\t\tthis._endDate = this._endDate || gantt.getState().max_date;\n\n\t\tif (this._startDate.valueOf() > this._endDate.valueOf()) {\n\t\t\t[ this._startDate, this._endDate ] = [ this._endDate, this._startDate ];\n\t\t}\n\t\tthis.clear();\n\t\tconst tasksByTime = gantt.getTaskByTime(this._startDate, this._endDate);\n\t\tconst tasksByIndex = this._getTasksByTop(this._startPoint.relative.top, this._endPoint.relative.top);\n\n\t\tthis._viewPort.callEvent(\"onDragEnd\", [this._startPoint, this._endPoint]);\n\t\tif (this._callback) {\n\t\t\tthis._callback(this._startPoint, this._endPoint, this._startDate, this._endDate, tasksByTime, tasksByIndex);\n\t\t}\n\t}\n\n\tgetInBounds() {\n\t\treturn this._singleRow;\n\t}\n\n\tprivate _getTasksByTop(start: number, end:number) {\n\t\tconst gantt = this._gantt;\n\t\tlet startValue = start;\n\t\tlet endValue = end;\n\t\tif (start > end) {\n\t\t\tstartValue = end;\n\t\t\tendValue = start;\n\t\t}\n\t\tconst startIndex = this._getTaskPositionByTop(startValue).index;\n\t\tconst endIndex = this._getTaskPositionByTop(endValue).index;\n\t\tconst result = [];\n\t\tfor (let i = startIndex; i <= endIndex; i++) {\n\t\t\tconst task = gantt.getTaskByIndex(i);\n\t\t\tif (task) {\n\t\t\t\tresult.push(gantt.getTaskByIndex(i));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _getTaskPositionByTop(top: number){\n\t\tconst gantt = this._gantt;\n\t\tconst view = this._view;\n\t\tconst index = view.getItemIndexByTopPosition(top);\n\t\tconst task = gantt.getTaskByIndex(index);\n\t\tif(task){\n\t\t\tconst height = view.getItemHeight(task.id);\n\t\t\tconst itemTop = view.getItemTop(task.id);\n\t\t\treturn {\n\t\t\t\ttop: itemTop || 0,\n\t\t\t\theight: height || 0,\n\t\t\t\tindex\n\t\t\t};\n\t\t} else {\n\t\t\tconst dataHeight = view.getTotalHeight();\n\t\t\treturn {\n\t\t\t\ttop: top > dataHeight ? dataHeight : 0,\n\t\t\t\theight: gantt.config.row_height,\n\t\t\t\tindex: top > dataHeight ? gantt.getTaskCount() : 0\n\t\t\t};\n\t\t}\n\t}\n}","interface IPoint {\n\tx: number;\n\ty: number;\n}\n\nexport class EventsManager {\n\tstatic create(gantt: any) {\n\t\treturn new EventsManager(gantt);\n\t}\n\tprivate _mouseDown: boolean = false;\n\tprivate _startPoint: IPoint;\n\tprivate _scrollState: IPoint;\n\tprivate _originAutoscroll: boolean;\n\tprivate _domEvents: any;\n\tprivate _timeline: any;\n\tprivate _gantt: any;\n\tprivate _trace: IPoint[];\n\tprivate _originalReadonly: boolean;\n\n\tconstructor(gantt: any) {\n\t\tthis._gantt = gantt;\n\t\tthis._domEvents = gantt._createDomEventScope();\n\t\tthis._trace = [];\n\t}\n\n\tdestructor() {\n\t\tthis._domEvents.detachAll();\n\t}\n\n\tattach(timeline: any): void {\n\t\tthis._timeline = timeline;\n\t\tconst gantt = this._gantt;\n\t\tthis._domEvents.attach(timeline.$task, \"mousedown\", (event) => {\n\t\t\tif (!gantt.config.drag_timeline) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst { useKey,ignore, enabled } = gantt.config.drag_timeline;\n\t\t\tif(enabled === false) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet filterTargets = \".gantt_task_line, .gantt_task_link\";\n\t\t\tif(ignore !== undefined) {\n\t\t\t\tif(ignore instanceof Array){\n\t\t\t\t\tfilterTargets = ignore.join(\", \");\n\t\t\t\t} else {\n\t\t\t\t\tfilterTargets = ignore;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (filterTargets) {\n\t\t\t\tif (gantt.utils.dom.closest(event.target, filterTargets)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (useKey && event[useKey] !== true) { return; }\n\n\t\t\tthis._startDrag(event);\n\t\t});\n\n\t\tthis._domEvents.attach(document, \"keydown\", (event) => {\n\t\t\tif (!gantt.config.drag_timeline) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst { useKey } = gantt.config.drag_timeline;\n\t\t\tif (useKey && event[useKey] === true) {\n\t\t\t\tthis._applyDndReadyStyles();\n\t\t\t}\n\t\t});\n\t\tthis._domEvents.attach(document, \"keyup\", (event) => {\n\t\t\tif (!gantt.config.drag_timeline) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst { useKey } = gantt.config.drag_timeline;\n\t\t\tif (useKey && event[useKey] === false) {\n\t\t\t\tthis._clearDndReadyStyles();\n\t\t\t\tthis._stopDrag(event);\n\t\t\t}\n\t\t});\n\n\t\tthis._domEvents.attach(document, \"mouseup\", (event) => {\n\t\t\tthis._stopDrag(event);\n\t\t});\n\t\tthis._domEvents.attach(gantt.$root, \"mouseup\", (event) => {\n\t\t\tthis._stopDrag(event);\n\t\t});\n\t\tthis._domEvents.attach(document, \"mouseleave\", (event) => {\n\t\t\tthis._stopDrag(event);\n\t\t});\n\t\tthis._domEvents.attach(gantt.$root, \"mouseleave\", (event) => {\n\t\t\tthis._stopDrag(event);\n\t\t});\n\n\t\tthis._domEvents.attach(gantt.$root, \"mousemove\", (event) => {\n\t\t\tif (!gantt.config.drag_timeline) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst { useKey } = gantt.config.drag_timeline;\n\t\t\tif (useKey && event[useKey] !== true) { return; }\n\t\t\t// GS-854. If we don't have useKey for the drag_timeline extension,\n\t\t\t// check the click_drag to not simultaneously use both extensions\n\t\t\tconst clickDrag = this._gantt.ext.clickDrag;\n\t\t\tconst clickDragUseKey = (this._gantt.config.click_drag || {}).useKey;\n\t\t\tif (clickDrag && clickDragUseKey) {\n\t\t\t\tif (!useKey && event[clickDragUseKey]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._mouseDown === true) {\n\t\t\t\tthis._trace.push({ x: event.clientX, y: event.clientY });\n\t\t\t\tconst scrollPosition: IPoint = this._countNewScrollPosition({ x: event.clientX, y: event.clientY });\n\t\t\t\tthis._setScrollPosition(timeline, scrollPosition);\n\t\t\t\tthis._scrollState = scrollPosition;\n\t\t\t\tthis._startPoint = { x: event.clientX, y: event.clientY };\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate _calculateDirectionVector = () => {\n\t\tconst traceSteps = 10;\n\t\tif(this._trace.length >= traceSteps) {\n\t\t\tconst dots = this._trace.slice(this._trace.length - traceSteps);\n\n\t\t\tconst vectors = [];\n\t\t\tfor(let i = 1; i < dots.length; i++) {\n\t\t\t\tvectors.push({\n\t\t\t\t\tx: dots[i].x - dots[i - 1].x,\n\t\t\t\t\ty: dots[i].y - dots[i - 1].y\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst resultVector = {x:0, y:0};\n\n\t\t\tvectors.forEach((vector) => {\n\t\t\t\tresultVector.x += vector.x;\n\t\t\t\tresultVector.y += vector.y;\n\t\t\t});\n\n\t\t\tconst magnitude = Math.sqrt(resultVector.x*resultVector.x + resultVector.y*resultVector.y);\n\t\t\tconst angleDegrees = Math.atan2(Math.abs(resultVector.y), Math.abs(resultVector.x)) * 180 / Math.PI;\n\n\t\t\treturn {\n\t\t\t\tmagnitude,\n\t\t\t\tangleDegrees\n\t\t\t};\n\n\t\t}\n\t\treturn null;\n\t};\n\n\tprivate _applyDndReadyStyles = (): void => {\n\t\tthis._timeline.$task.classList.add(\"gantt_timeline_move_available\");\n\t};\n\n\tprivate _clearDndReadyStyles = (): void => {\n\t\tthis._timeline.$task.classList.remove(\"gantt_timeline_move_available\");\n\t};\n\n\tprivate _getScrollPosition = (timeline: any): IPoint => {\n\t\tconst gantt = this._gantt;\n\t\treturn {\n\t\t\tx: gantt.$ui.getView(timeline.$config.scrollX).getScrollState().position,\n\t\t\ty: gantt.$ui.getView(timeline.$config.scrollY).getScrollState().position\n\t\t};\n\t};\n\tprivate _countNewScrollPosition = (coords: IPoint): IPoint => {\n\t\tconst vector = this._calculateDirectionVector();\n\t\tlet shiftX = this._startPoint.x - coords.x;\n\t\tlet shiftY = this._startPoint.y - coords.y;\n\t\tif(vector){\n\t\t\tif(vector.angleDegrees < 15){\n\t\t\t\tshiftY = 0;\n\t\t\t} else if(vector.angleDegrees > 75){\n\t\t\t\tshiftX = 0;\n\t\t\t}\n\t\t}\n\n\t\tconst result = {\n\t\t\tx: this._scrollState.x + shiftX,\n\t\t\ty: this._scrollState.y + shiftY\n\t\t};\n\t\treturn result;\n\t};\n\tprivate _setScrollPosition = (timeline: any, coords: IPoint): void => {\n\t\tconst gantt = this._gantt;\n\t\trequestAnimationFrame(() => {\n\t\t\tgantt.scrollLayoutCell(timeline.$id, coords.x, coords.y);\n\t\t});\n\t};\n\tprivate _stopDrag = (event: Event): void => {\n\t\tconst gantt = this._gantt;\n\t\tthis._trace = [];\n\t\tgantt.$root.classList.remove(\"gantt_noselect\");\n\n\t\tif(this._originalReadonly !== undefined){\n\t\t\tgantt.config.readonly = this._originalReadonly;\n\t\t\tif(this._mouseDown && gantt.config.drag_timeline && gantt.config.drag_timeline.render){\n\t\t\t\tgantt.render();\n\t\t\t}\n\t\t}\n\n\t\tif(this._originAutoscroll !== undefined){\n\t\t\tgantt.config.autoscroll = this._originAutoscroll;\n\t\t}\n\n\t\tif(gantt.config.drag_timeline){\n\t\t\tconst { useKey } = gantt.config.drag_timeline;\n\t\t\tif (useKey && event[useKey] !== true) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tthis._mouseDown = false;\n\t};\n\n\tprivate _startDrag = (event: any) : void => {\n\t\tconst gantt = this._gantt;\n\t\tthis._originAutoscroll = gantt.config.autoscroll;\n\t\tgantt.config.autoscroll = false;\n\n\t\tgantt.$root.classList.add(\"gantt_noselect\");\n\t\tthis._originalReadonly = gantt.config.readonly;\n\t\tgantt.config.readonly = true;\n\n\t\tif(gantt.config.drag_timeline && gantt.config.drag_timeline.render){\n\t\t\tgantt.render();\n\t\t}\n\n\t\tthis._trace = [];\n\t\tthis._mouseDown = true;\n\t\tconst { x, y } = this._getScrollPosition(this._timeline);\n\t\tthis._scrollState = { x, y };\n\t\tthis._startPoint = { x: event.clientX, y: event.clientY };\n\t\tthis._trace.push(this._startPoint);\n\t};\n}","export default function(gantt) {\n\n\t(function () {\n\t\tvar modalsStack = [];\n\n\t\tfunction isModal() {\n\t\t\treturn !!modalsStack.length;\n\t\t}\n\n\t\tfunction afterPopup(box) {\n\t\t\tsetTimeout(function () {\n\t\t\t\tif (!isModal()){\n\t\t\t\t\tif(!gantt.$destroyed){\n\t\t\t\t\t\tgantt.focus();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 1);\n\t\t}\n\n\t\tfunction startModal(box) {\n\t\t\tgantt.eventRemove(box, \"keydown\", trapFocus);\n\t\t\tgantt.event(box, \"keydown\", trapFocus);\n\t\t\tmodalsStack.push(box);\n\t\t\t//gantt.$keyboardNavigation.dispatcher.disable();\n\t\t}\n\n\t\tfunction endModal() {\n\t\t\tvar box = modalsStack.pop();\n\t\t\tif (box) {\n\t\t\t\tgantt.eventRemove(box, \"keydown\", trapFocus);\n\t\t\t}\n\t\t\tafterPopup(box);\n\n\t\t}\n\n\n\t\tfunction isTopModal(box) {\n\t\t\treturn box == modalsStack[modalsStack.length - 1];\n\t\t}\n\n\t\tfunction trapFocus(event) {\n\t\t\tvar target = event.currentTarget;\n\t\t\tif (!isTopModal(target)) return;\n\n\t\t\tgantt.$keyboardNavigation.trapFocus(target, event);\n\t\t}\n\n\t\tfunction traceLightbox() {\n\t\t\tstartModal(gantt.getLightbox());\n\t\t}\n\n\t\tgantt.attachEvent(\"onLightbox\", traceLightbox);\n\t\tgantt.attachEvent(\"onAfterLightbox\", endModal);\n\t\tgantt.attachEvent(\"onLightboxChange\", function () {\n\t\t\tendModal();\n\t\t\ttraceLightbox();\n\t\t});\n\n\n\t\tgantt.attachEvent(\"onAfterQuickInfo\", function () {\n\t\t\tafterPopup();\n\t\t});\n\n\t\tgantt.attachEvent(\"onMessagePopup\", function (box) {\n\t\t\tsaveFocus();\n\t\t\tstartModal(box);\n\t\t});\n\t\tgantt.attachEvent(\"onAfterMessagePopup\", function () {\n\t\t\tendModal();\n\t\t\trestoreFocus();\n\t\t});\n\n\t\tvar focusElement = null;\n\n\t\tfunction saveFocus() {\n\t\t\tfocusElement = gantt.utils.dom.getActiveElement();\n\t\t}\n\n\t\tfunction restoreFocus() {\n\t\t\tsetTimeout(function () {\n\t\t\t\tif (focusElement) {\n\t\t\t\t\tfocusElement.focus();\n\t\t\t\t\tfocusElement = null;\n\t\t\t\t}\n\t\t\t}, 1);\n\t\t}\n\n\t\tgantt.$keyboardNavigation.isModal = isModal;\n\n\n\t})();\n\n};","\ninterface IQuickInfoContainer{\n\tparent: HTMLElement;\n\txViewport: HTMLElement;\n\tyViewport: HTMLElement;\n}\n\nexport class QuickInfo {\n\tprivate _quickInfoTask: TaskID;\n\tprivate _quickInfoBoxId: number | string;\n\tprivate _quickInfoBox: HTMLElement;\n\tprivate _quickInfoReadonly: boolean | null;\n\tprivate _container: HTMLElement;\n\tprivate _gantt: any;\n\n\tconstructor(gantt: any) {\n\t\tthis._gantt = gantt;\n\t}\n\n\t// show at coordinates:\n\t// show(x: number, y: number)\n\t// show for a task:\n\t// show(id: TaskID)\n\tshow : {\n\t\t(x: number, y: number) : void;\n\t\t(id: TaskID) : void;\n\t} = (id: TaskID | number, y? : number) : void => {\n\t\tif (y === undefined) {\n\t\t\tthis._showForTask(id);\n\t\t} else {\n\t\t\tthis._showAtCoordinates(id as number, y);\n\t\t}\n\t};\n\n\thide = (forced?: boolean) : any => {\n\t\tconst gantt = this._gantt;\n\t\tconst qi = this._quickInfoBox;\n\t\tthis._quickInfoBoxId = 0;\n\t\tconst taskId = this._quickInfoTask;\n\t\tthis._quickInfoTask = null;\n\n\t\tif (qi && qi.parentNode){\n\n\t\t\tif (gantt.config.quick_info_detached) {\n\t\t\t\tgantt.callEvent(\"onAfterQuickInfo\", [taskId]);\n\t\t\t\treturn qi.parentNode.removeChild(qi);\n\t\t\t}\n\n\t\t\tqi.className += \" gantt_qi_hidden\";\n\t\t\tif (qi.style.right === \"auto\"){\n\t\t\t\tqi.style.left = \"-350px\";\n\t\t\t} else {\n\t\t\t\tqi.style.right = \"-350px\";\n\t\t\t}\n\n\t\t\tif (forced) {\n\t\t\t\tqi.style.left = qi.style.right = \"\";\n\t\t\t\tqi.parentNode.removeChild(qi);\n\t\t\t}\n\t\t\tgantt.callEvent(\"onAfterQuickInfo\", [taskId]);\n\t\t}\n\t};\n\n\tgetNode = (): HTMLElement => {\n\t\tif(this._quickInfoBox) {\n\t\t\treturn this._quickInfoBox;\n\t\t}\n\t\treturn null;\n\t};\n\n\tsetContainer = (container: string|HTMLElement): void => {\n\t\tif(container){\n\t\t\tthis._container = typeof container === \"string\" ? document.getElementById(container) : container;\n\t\t}\n\t};\n\n\tsetContent = (content?: IQuickInfoContent) => {\n\t\tconst gantt = this._gantt;\n\n\t\tconst defaultContent = {\n\t\t\ttaskId: null,\n\t\t\theader: {\n\t\t\t\ttitle: \"\",\n\t\t\t\tdate: \"\"\n\t\t\t},\n\t\t\tcontent: \"\",\n\t\t\tbuttons: gantt.config.quickinfo_buttons\n\t\t};\n\n\t\tif(!content){\n\t\t\tcontent = defaultContent;\n\t\t}\n\n\t\tif(!content.taskId){\n\t\t\tcontent.taskId = defaultContent.taskId;\n\t\t}\n\n\t\tif(!content.header){\n\t\t\tcontent.header = defaultContent.header;\n\t\t}\n\n\t\tif(!content.header.title){\n\t\t\tcontent.header.title = defaultContent.header.title;\n\t\t}\n\t\tif(!content.header.date){\n\t\t\tcontent.header.date = defaultContent.header.date;\n\t\t}\n\t\tif(!content.content){\n\t\t\tcontent.content = defaultContent.content;\n\t\t}\n\t\tif(!content.buttons){\n\t\t\tcontent.buttons = defaultContent.buttons;\n\t\t}\n\n\n\t\tlet qi = this.getNode();\n\t\tif(!qi){\n\t\t\tqi = this._createQuickInfoElement();\n\t\t}\n\n\t\tif(content.taskId){\n\t\t\tthis._quickInfoBoxId = content.taskId;\n\t\t}\n\n\t\tconst titleBox = qi.querySelector(\".gantt_cal_qi_title\") as HTMLElement;\n\t\tconst titleContent = titleBox.querySelector(\".gantt_cal_qi_tcontent\");\n\t\tconst titleDate = titleBox.querySelector(\".gantt_cal_qi_tdate\");\n\t\tconst main = qi.querySelector(\".gantt_cal_qi_content\");\n\t\tconst controls = qi.querySelector(\".gantt_cal_qi_controls\") as HTMLElement;\n\n\t\tgantt._waiAria.quickInfoHeader(qi, [content.header.title, content.header.date].join(\" \"));\n\n\t\ttitleContent.innerHTML = content.header.title;\n\t\ttitleDate.innerHTML = content.header.date;\n\n\t\tif(!content.header.title && !content.header.date){\n\t\t\ttitleBox.style.display = \"none\";\n\t\t}else{\n\t\t\ttitleBox.style.display = \"\";\n\t\t}\n\t\tmain.innerHTML = content.content;\n\n\t\tconst buttons = content.buttons;\n\t\tif(!buttons.length){\n\t\t\tcontrols.style.display = \"none\";\n\t\t}else{\n\t\t\tcontrols.style.display = \"\";\n\t\t}\n\t\tlet html = \"\";\n\t\tfor (let i = 0; i < buttons.length; i++){\n\n\t\t\tconst ariaAttr = gantt._waiAria.quickInfoButtonAttrString(gantt.locale.labels[buttons[i]]);\n\n\t\t\thtml += `
\n
\n
${gantt.locale.labels[buttons[i]]}
\n
`;\n\t\t}\n\t\tcontrols.innerHTML = html;\n\n\t\tgantt.eventRemove(qi, \"click\", this._qiButtonClickHandler);\n\t\tgantt.eventRemove(qi, \"keypress\", this._qiKeyPressHandler);\n\n\t\tgantt.event(qi, \"click\", this._qiButtonClickHandler);\n\t\tgantt.event(qi, \"keypress\", this._qiKeyPressHandler);\n\t};\n\n\tprivate _qiButtonClickHandler = (ev) => {\n\t\tthis._qi_button_click(ev.target);\n\t};\n\n\tprivate _qiKeyPressHandler = (e) => {\n\n\t\tconst code = e.which;\n\t\tif (code === 13 || code === 32){\n\t\t\tsetTimeout(() => {\n\t\t\t\tthis._qi_button_click(e.target);\n\t\t\t},1);\n\t\t}\n\t};\n\n\tprivate _showAtCoordinates(x: number, y: number) : void {\n\t\tthis.hide(true);\n\t\tthis._quickInfoBoxId = 0;\n\t\tthis._quickInfoTask = null;\n\t\tif(!this._quickInfoBox){\n\t\t\tthis._createQuickInfoElement();\n\t\t\tthis.setContent();\n\t\t}\n\n\t\tthis._appendAtCoordinates(x, y);\n\t\tthis._gantt.callEvent(\"onQuickInfo\", [null]);\n\t}\n\n\tprivate _showForTask(id: TaskID) : void {\n\t\tconst gantt = this._gantt;\n\t\tif ((\n\t\t\tid === this._quickInfoBoxId &&\n\t\t\tgantt.utils.dom.isChildOf(this._quickInfoBox, document.body)\n\t\t) || !gantt.config.show_quick_info) {\n\t\t\t// not show if the quick info is already displayed for this task, or if it shouldn't be displayed\n\t\t\treturn;\n\t\t}\n\t\tthis.hide(true);\n\t\tconst offset = 6; // offset TASK <> QI-BOX in 'px'\n\t\tconst container = this._getContainer();\n\t\tconst pos = this._get_event_counter_part(id, offset, container.xViewport, container.yViewport);\n\n\t\tif (pos){\n\t\t\tthis._quickInfoBox = this._init_quick_info(id);\n\t\t\tthis._quickInfoTask = id;\n\t\t\tthis._quickInfoBox.className = this._prepare_quick_info_classname(id);\n\n\t\t\tthis._fill_quick_data(id);\n\t\t\tthis._show_quick_info(pos, offset);\n\t\t\tgantt.callEvent(\"onQuickInfo\", [id]);\n\t\t}\n\t}\n\n\tprivate _get_event_counter_part(id: TaskID, offset: number, xViewport: HTMLElement, yViewport: HTMLElement) : any {\n\t\tconst gantt = this._gantt;\n\t\tlet domEv = gantt.getTaskNode(id);\n\t\tif (!domEv) {\n\t\t\tdomEv = gantt.getTaskRowNode(id);\n\t\t\tif (!domEv) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tlet left = 0;\n\t\tconst top = offset + domEv.offsetTop + domEv.offsetHeight;\n\n\t\tlet node = domEv;\n\n\t\tif (gantt.utils.dom.isChildOf(node, xViewport)) {\n\t\t\twhile (node && node !== xViewport){\n\t\t\t\tleft += node.offsetLeft;\n\t\t\t\tnode = node.offsetParent;\n\t\t\t}\n\t\t}\n\n\t\tconst scroll = gantt.getScrollState();\n\n\t\tif(node){\n\t\t\tconst dx = (left + domEv.offsetWidth/2) - scroll.x > (xViewport.offsetWidth/2) ? 1 : 0;\n\t\t\tconst dy = (top + domEv.offsetHeight/2) - scroll.y > (yViewport.offsetHeight/2) ? 1 : 0;\n\n\t\t\treturn { left, top, dx, dy, width:domEv.offsetWidth, height:domEv.offsetHeight };\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate _createQuickInfoElement() : HTMLElement {\n\t\tconst gantt = this._gantt;\n\t\tconst qi = document.createElement(\"div\");\n\t\tqi.className += \"gantt_cal_quick_info\";\n\t\tgantt._waiAria.quickInfoAttr(qi);\n\n\t\t// title\n\t\tconst ariaAttr = gantt._waiAria.quickInfoHeaderAttrString();\n\t\tvar html = `\n\t\t
\n\t\t\t\n\t\t
\n\t\t
\n\t\t\t\t\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t\t
`;\n\n\t\t//buttons\n\t\thtml += \"
\";\n\n\t\thtml += \"
\";\n\n\t\tqi.innerHTML = html;\n\n\n\t\tif (gantt.config.quick_info_detached) {\n\t\t\tconst container = this._getContainer();\n\t\t\tgantt.event(container.parent, \"scroll\", () => { this.hide(); });\n\t\t}\n\n\t\tthis._quickInfoBox = qi;\n\t\treturn qi;\n\t}\n\n\tprivate _init_quick_info(id: TaskID) : HTMLElement {\n\t\tconst gantt = this._gantt;\n\t\tconst task = gantt.getTask(id);\n\t\t\n\n\t\tif(typeof this._quickInfoReadonly === \"boolean\"){\n\t\t\tif(gantt.isReadonly(task) !== this._quickInfoReadonly){\n\t\t\t\tthis.hide(true);\n\t\t\t\tthis._quickInfoBox = null;\n\t\t\t}\n\t\t}\n\n\t\tthis._quickInfoReadonly = gantt.isReadonly(task);\n\n\t\tif (!this._quickInfoBox){\n\t\t\tthis._quickInfoBox = this._createQuickInfoElement();\n\t\t}\n\n\t\treturn this._quickInfoBox;\n\t}\n\n\tprivate _prepare_quick_info_classname(id: TaskID) : string {\n\t\tconst gantt = this._gantt;\n\t\tconst task = gantt.getTask(id);\n\t\tconst taskType = gantt.getTaskType(task);\n\n\t\tlet css = `gantt_cal_quick_info gantt_${taskType}`;\n\t\tconst template = gantt.templates.quick_info_class(task.start_date, task.end_date, task);\n\n\t\tif(template){\n\t\t\tcss += \" \" + template;\n\t\t}\n\t\treturn css;\n\t}\n\n\tprivate _fill_quick_data(id: TaskID) : void {\n\t\tconst gantt = this._gantt;\n\t\tconst ev = gantt.getTask(id);\n\n\t\tthis._quickInfoBoxId = id;\n\n\t\tlet allowedButtons = [];\n\t\tif (this._quickInfoReadonly){\n\t\t\tconst buttons = gantt.config.quickinfo_buttons;\n\t\t\tconst isEditor = {icon_delete: true, icon_edit: true};\n\t\t\tfor (let i = 0; i < buttons.length; i++){\n\t\t\t\tif(this._quickInfoReadonly && isEditor[buttons[i]]){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tallowedButtons.push(buttons[i]);\n\t\t\t}\n\t\t} else {\n\t\t\tallowedButtons = gantt.config.quickinfo_buttons;\n\t\t}\n\n\t\tthis.setContent({\n\t\t\theader: {\n\t\t\t\ttitle: gantt.templates.quick_info_title(ev.start_date, ev.end_date, ev),\n\t\t\t\tdate: gantt.templates.quick_info_date(ev.start_date, ev.end_date, ev)\n\t\t\t},\n\t\t\tcontent: gantt.templates.quick_info_content(ev.start_date, ev.end_date, ev),\n\t\t\tbuttons: allowedButtons\n\t\t});\n\t}\n\n\tprivate _appendAtCoordinates(x: number, y: number): void {\n\t\tconst qi = this._quickInfoBox;\n\t\tconst container = this._getContainer();\n\t\tif (!qi.parentNode ||\n\t\t\tqi.parentNode.nodeName.toLowerCase() === \"#document-fragment\"){ // IE8\n\t\t\tcontainer.parent.appendChild(qi);\n\t\t}\n\n\t\tqi.style.left = x + \"px\";\n\t\tqi.style.top = y + \"px\";\n\t}\n\n\tprivate _show_quick_info(pos: any, offset: number) : void {\n\t\tconst gantt = this._gantt;\n\t\tconst qi = this._quickInfoBox;\n\t\tif (gantt.config.quick_info_detached) {\n\t\t\tconst container = this._getContainer();\n\t\t\tif (!qi.parentNode ||\n\t\t\t\tqi.parentNode.nodeName.toLowerCase() === \"#document-fragment\"){ // IE8\n\t\t\t\tcontainer.parent.appendChild(qi);\n\t\t\t}\n\t\t\tconst width = qi.offsetWidth;\n\t\t\tconst popupHeight = qi.offsetHeight;\n\n\t\t\tconst scrolls = gantt.getScrollState();\n\t\t\tconst xViewport = container.xViewport;\n\t\t\tconst yViewport = container.yViewport;\n\t\t\tconst screenWidth = xViewport.offsetWidth + scrolls.x - width;\n\n\t\t\tconst relativePopupTop = pos.top - scrolls.y;\n\t\t\tconst relativePopupBottom = relativePopupTop + popupHeight;\n\n\t\t\tlet top = pos.top;\n\t\t\tif(relativePopupBottom > yViewport.offsetHeight / 2){\n\t\t\t\ttop = pos.top - (popupHeight + pos.height + 2*offset);\n\t\t\t\tif(top < scrolls.y && relativePopupBottom <= yViewport.offsetHeight){\n\t\t\t\t\ttop = pos.top;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (top < scrolls.y) {\n\t\t\t\ttop = scrolls.y;\n\t\t\t}\n\n\t\t\tconst x = Math.min(Math.max(scrolls.x, pos.left - pos.dx*(width - pos.width)), screenWidth);\n\t\t\tconst y = top;\n\n\t\t\tthis._appendAtCoordinates(x, y);\n\t\t} else {\n\t\t\tqi.style.top = 20 + \"px\";\n\t\t\tif (pos.dx === 1){\n\t\t\t\tqi.style.right = \"auto\";\n\t\t\t\tqi.style.left = \"-300px\";\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tqi.style.left = \"10px\";\n\t\t\t\t},1);\n\t\t\t} else {\n\t\t\t\tqi.style.left = \"auto\";\n\t\t\t\tqi.style.right = \"-300px\";\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tqi.style.right = \"10px\";\n\t\t\t\t},1);\n\t\t\t}\n\t\t\tqi.className += \" gantt_qi_\"+(pos.dx === 1 ? \"left\" : \"right\");\n\t\t\tgantt.$root.appendChild(qi);\n\t\t}\n\t}\n\n\tprivate _qi_button_click(node: any) : void {\n\t\tconst gantt = this._gantt;\n\t\tconst box = this._quickInfoBox;\n\t\tif (!node || node === box){\n\t\t\treturn;\n\t\t}\n\t\tif(node.closest(\".gantt_cal_qi_close_btn\")){\n\t\t\tthis.hide();\n\t\t\treturn;\n\t\t}\n\n\t\tconst mask = node.className;\n\t\tif (mask.indexOf(\"_icon\") !== -1){\n\t\t\tconst id = this._quickInfoBoxId;\n\t\t\tgantt.$click.buttons[mask.split(\" \")[1].replace(\"icon_\",\"\")](id);\n\t\t} else {\n\t\t\tthis._qi_button_click(node.parentNode);\n\t\t}\n\t}\n\n\tprivate _getContainer(): IQuickInfoContainer{\n\t\tconst gantt = this._gantt;\n\t\tlet container = this._container ? this._container : gantt.$task_data;\n\t\tif (container && container.offsetHeight && container.offsetWidth) {\n\t\t\treturn {\n\t\t\t\tparent: container,\n\t\t\t\txViewport: gantt.$task,\n\t\t\t\tyViewport: gantt.$task_data\n\t\t\t};\n\t\t}\n\t\tcontainer = this._container ? this._container : gantt.$grid_data;\n\t\tif (container && container.offsetHeight && container.offsetWidth) {\n\t\t\treturn {\n\t\t\t\tparent: container,\n\t\t\t\txViewport: gantt.$grid,\n\t\t\t\tyViewport: gantt.$grid_data\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tparent: this._container ? this._container : gantt.$layout,\n\t\t\txViewport: gantt.$layout,\n\t\t\tyViewport: gantt.$layout\n\t\t};\n\t}\n}\n","import * as helpers from \"./helpers\";\n\nvar plainObjectConstructor = ({}).constructor.toString();\nfunction isCustomType(object){\n\tvar constructorString = object.constructor.toString();\n\n\treturn constructorString !== plainObjectConstructor;\n}\n\nfunction copy(object) {\n\tvar i, result; // iterator, types array, result\n\n\tif (object && typeof object == \"object\") {\n\n\t\tswitch (true){\n\t\t\tcase (helpers.isDate(object)):\n\t\t\t\tresult = new Date(object);\n\t\t\t\tbreak;\n\t\t\tcase (helpers.isArray(object)):\n\t\t\t\tresult = new Array(object.length);\n\t\t\t\tfor(i = 0; i < object.length; i++){\n\t\t\t\t\tresult[i] = copy(object[i]);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t/*\t\tcase (helpers.isStringObject(object)):\n\t\t\t\tresult = new String(object);\n\t\t\t\tbreak;\n\t\t\tcase (helpers.isNumberObject(object)):\n\t\t\t\tresult = new Number(object);\n\t\t\t\tbreak;\n\t\t\tcase (helpers.isBooleanObject(object)):\n\t\t\t\tresult = new Boolean(object);\n\t\t\t\tbreak;*/\n\t\t\tdefault:\n\t\t\t\tif(isCustomType(object)){\n\t\t\t\t\tresult = Object.create(object);\n\t\t\t\t}else{\n\t\t\t\t\tresult = {};\n\t\t\t\t}\n\n\t\t\t\tfor (i in object) {\n\t\t\t\t\tif (Object.prototype.hasOwnProperty.apply(object, [i]))\n\t\t\t\t\t\tresult[i] = copy(object[i]);\n\t\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn result || object;\n}\n\nfunction mixin (target, source, force){\n\tfor (var f in source)\n\t\tif (((target[f] === undefined) || force)) target[f]=source[f];\n\treturn target;\n}\n\nfunction defined(obj) {\n\treturn typeof(obj) != \"undefined\";\n}\n\nvar seed;\nfunction uid() {\n\tif (!seed)\n\t\tseed = (new Date()).valueOf();\n\n\tseed++;\n\treturn seed;\n}\n\n//creates function with specified \"this\" pointer\nfunction bind(functor, object){\n\tif(functor.bind)\n\t\treturn functor.bind(object);\n\telse\n\t\treturn function(){ return functor.apply(object,arguments); };\n}\n\nfunction event(el, event, handler, capture){\n\tif (el.addEventListener)\n\t\tel.addEventListener(event, handler, capture === undefined ? false : capture);\n\n\telse if (el.attachEvent)\n\t\tel.attachEvent(\"on\"+event, handler);\n}\n\nfunction eventRemove(el, event, handler, capture){\n\tif (el.removeEventListener)\n\t\tel.removeEventListener(event, handler, capture === undefined ? false : capture);\n\n\telse if (el.detachEvent)\n\t\tel.detachEvent(\"on\"+event, handler);\n}\n\nexport {\n\tcopy,\n\tdefined,\n\tmixin,\n\tuid,\n\tbind,\n\tevent,\n\teventRemove\n};","import * as utils from \"../../../utils/utils\";\n\nfunction createScope(addEvent, removeEvent) {\n\taddEvent = addEvent || utils.event;\n\tremoveEvent = removeEvent || utils.eventRemove;\n\n\tvar handlers = [];\n\n\tvar eventScope = {\n\t\tattach: function(el, event, callback, capture){\n\t\t\thandlers.push({element: el, event:event, callback: callback, capture: capture});\n\t\t\taddEvent(el, event, callback, capture);\n\t\t},\n\t\tdetach: function(el, event, callback, capture){\n\t\t\tremoveEvent(el, event, callback, capture);\n\t\t\tfor(var i = 0; i < handlers.length; i++){\n\t\t\t\tvar handler = handlers[i];\n\t\t\t\tif (handler.element === el && handler.event === event && handler.callback === callback && handler.capture === capture) {\n\t\t\t\t\thandlers.splice(i, 1);\n\t\t\t\t\ti--;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tdetachAll: function () {\n\t\t\tvar staticArray = handlers.slice();\n\t\t\t// original handlers array can be spliced on every iteration\n\t\t\tfor (var i = 0; i < staticArray.length; i++){\n\t\t\t\tvar handler = staticArray[i];\n\t\t\t\teventScope.detach(handler.element, handler.event, handler.callback, handler.capture);\n\t\t\t\teventScope.detach(handler.element, handler.event, handler.callback, undefined);\n\t\t\t\teventScope.detach(handler.element, handler.event, handler.callback, false);\n\t\t\t\teventScope.detach(handler.element, handler.event, handler.callback, true);\n\t\t\t}\n\t\t\thandlers.splice(0, handlers.length);\n\t\t},\n\t\textend: function(){\n\t\t\treturn createScope(this.event, this.eventRemove);\n\t\t}\n\t};\n\n\treturn eventScope;\n}\n\nexport default createScope;","import * as domHelpers from \"../../core/ui/utils/dom_helpers\";\n\n/* eslint-disable no-restricted-globals */\n\ninterface IViewPosition{\n\ttop: number;\n\tleft: number;\n}\n\ninterface IViewBox extends IViewPosition{\n\twidth: number;\n\theight: number;\n\tbottom: number;\n\tright: number;\n}\n\nexport class Tooltip {\n\tprivate _root: HTMLElement;\n\tprivate _tooltipNode: HTMLElement;\n\tprivate _gantt: any;\n\n\tconstructor(gantt: any){\n\t\tthis._gantt = gantt;\n\t}\n\n\tgetNode() : HTMLElement {\n\t\tconst gantt = this._gantt;\n\t\tif (!this._tooltipNode){\n\t\t\tthis._tooltipNode = document.createElement(\"div\");\n\t\t\tthis._tooltipNode.className = \"gantt_tooltip\";\n\t\t\tgantt._waiAria.tooltipAttr(this._tooltipNode);\n\t\t}\n\t\treturn this._tooltipNode;\n\t}\n\n\tsetViewport(node: HTMLElement):Tooltip{\n\t\tthis._root = node;\n\t\treturn this;\n\t}\n\n\tshow(left: number, top: number): Tooltip;\n\tshow(event: MouseEvent): Tooltip;\n\tshow(left: number | MouseEvent, top?: number): Tooltip {\n\t\tconst gantt = this._gantt;\n\t\tconst container = document.body;\n\t\tconst node = this.getNode();\n\n\t\tif(!domHelpers.isChildOf(node, container)){\n\t\t\tthis.hide();\n\t\t\t// GS-2463. Don't put the node beyond the body coordinates\n\t\t\t// as it may trigger the resize event\n\t\t\tnode.style.top = node.style.top || \"0px\";\n\t\t\tnode.style.left = node.style.left || \"0px\";\n\t\t\tcontainer.appendChild(node);\n\t\t}\n\n\t\tif (this._isLikeMouseEvent(left)) {\n\t\t\tconst position = this._calculateTooltipPosition(left as MouseEvent);\n\t\t\ttop = position.top;\n\t\t\tleft = position.left;\n\t\t}\n\n\t\tnode.style.top = top + \"px\";\n\t\tnode.style.left = left + \"px\";\n\n\t\tgantt._waiAria.tooltipVisibleAttr(node);\n\t\treturn this;\n\t}\n\thide() : Tooltip{\n\t\tconst gantt = this._gantt;\n\t\tconst node = this.getNode();\n\t\tif(node && node.parentNode){\n\t\t\tnode.parentNode.removeChild(node);\n\t\t}\n\t\tgantt._waiAria.tooltipHiddenAttr(node);\n\t\treturn this;\n\t}\n\n\tsetContent(html: string) : Tooltip{\n\t\tconst node = this.getNode();\n\t\tnode.innerHTML = html;\n\t\treturn this;\n\t}\n\n\t// it is for salesforce, because it proxies event to it own events\n\tprivate _isLikeMouseEvent(event: any): boolean {\n\t\tif (!event || typeof event !== \"object\") {\n\t\t\treturn false;\n\t\t}\n\t\treturn \"clientX\" in event && \"clientY\" in event;\n\t}\n\n\tprivate _getViewPort() : HTMLElement {\n\t\treturn this._root || document.body;\n\t}\n\n\n\tprivate _calculateTooltipPosition(event: MouseEvent): IViewPosition{\n\t\tconst gantt = this._gantt;\n\t\t// top/left coordinates inside the viewport by mouse position\n\t\tconst viewport = this._getViewPortSize();\n\t\tconst tooltipNode = this.getNode();\n\t\tconst tooltip: IViewBox = {\n\t\t\ttop:0,\n\t\t\tleft: 0,\n\t\t\twidth: tooltipNode.offsetWidth,\n\t\t\theight: tooltipNode.offsetHeight,\n\t\t\tbottom: 0,\n\t\t\tright: 0\n\t\t};\n\n\t\tconst offsetX = gantt.config.tooltip_offset_x;\n\t\tconst offsetY = gantt.config.tooltip_offset_y;\n\n\t\tconst container = document.body;\n\t\tconst mouse = domHelpers.getRelativeEventPosition(event, container);\n\t\tconst containerPos = domHelpers.getNodePosition(container);\n\t\tmouse.y += containerPos.y; // to fix margin collapsing\n\n\t\ttooltip.top = mouse.y;\n\t\ttooltip.left = mouse.x;\n\t\ttooltip.top += offsetY;\n\t\ttooltip.left += offsetX;\n\t\ttooltip.bottom = tooltip.top + tooltip.height;\n\t\ttooltip.right = tooltip.left + tooltip.width;\n\n\t\tconst scrollTop = window.scrollY + container.scrollTop; // to fix margin collapsing\n\t\t// edge cases when the tooltip element can be partially hidden by edges of the viewport\n\t\tif(tooltip.top < viewport.top - scrollTop){\n\t\t\ttooltip.top = viewport.top;\n\t\t\ttooltip.bottom = tooltip.top + tooltip.height;\n\t\t}else if(tooltip.bottom > viewport.bottom){\n\t\t\ttooltip.bottom = viewport.bottom;\n\t\t\ttooltip.top = tooltip.bottom - tooltip.height;\n\t\t}\n\n\t\tif(tooltip.left < viewport.left){\n\t\t\ttooltip.left = viewport.left;\n\t\t\ttooltip.right = viewport.left + tooltip.width;\n\t\t}else if(tooltip.right > viewport.right){\n\t\t\ttooltip.right = viewport.right;\n\t\t\ttooltip.left = tooltip.right - tooltip.width;\n\t\t}\n\n\t\tif(mouse.x >= tooltip.left && mouse.x <= tooltip.right) {\n\t\t\ttooltip.left = mouse.x - tooltip.width - offsetX;\n\t\t\ttooltip.right = tooltip.left + tooltip.width;\n\t\t}\n\n\t\tif(mouse.y >= tooltip.top && mouse.y <= tooltip.bottom) {\n\t\t\ttooltip.top = mouse.y - tooltip.height - offsetY;\n\t\t\ttooltip.bottom = tooltip.top + tooltip.height;\n\t\t}\n\n\t\treturn tooltip;\n\t}\n\n\tprivate _getViewPortSize() : IViewBox {\n\t\tconst gantt = this._gantt;\n\t\tconst container = this._getViewPort();\n\t\tlet viewport = container;\n\t\tlet scrollTop = window.scrollY + document.body.scrollTop;\n\t\tlet scrollLeft = window.scrollX + document.body.scrollLeft;\n\t\tlet pos;\n\t\t// support for the initial tooltip mode where the tooltip element was attached to the data area of gantt\n\t\tif(container === gantt.$task_data){\n\t\t\tviewport = gantt.$task;\n\t\t\tscrollTop = 0;\n\t\t\tscrollLeft = 0;\n\t\t\tpos = domHelpers.getNodePosition(gantt.$task);\n\t\t}else{\n\t\t\tpos = domHelpers.getNodePosition(viewport);\n\t\t}\n\t\treturn {\n\t\t\tleft:pos.x + scrollLeft,\n\t\t\ttop: pos.y + scrollTop,\n\t\t\twidth: pos.width,\n\t\t\theight: pos.height,\n\t\t\tbottom: pos.y + pos.height + scrollTop,\n\t\t\tright: pos.x + pos.width + scrollLeft\n\t\t};\n\t}\n}\n","import domEventsScope from \"../../core/ui/utils/dom_event_scope\";\nimport * as domHelpers from \"../../core/ui/utils/dom_helpers\";\nimport * as helpers from \"../../utils/helpers\";\nimport { Tooltip } from \"./tooltip\";\n\ninterface ITrackerTarget {\n\tselector: string;\n\tonmouseenter: (event: MouseEvent, node: HTMLElement) => void;\n\tonmousemove: (event: MouseEvent, node: HTMLElement) => void;\n\tonmouseleave: (event: MouseEvent, node: HTMLElement) => void;\n\tglobal: boolean;\n}\n\ninterface ITooltipConfig {\n\tselector: string;\n\thtml: (event: MouseEvent, node: HTMLElement) => string;\n\tglobal: boolean;\n}\n\nexport class TooltipManager{\n\ttooltip: Tooltip;\n\tprotected _domEvents: any;\n\tprivate _listeners: object = {};\n\tprivate _gantt: any;\n\tprivate delayShow: any;\n\tprivate delayHide: any;\n\n\tconstructor(gantt: any) {\n\t\tthis.tooltip = new Tooltip(gantt);\n\t\tthis._gantt = gantt;\n\t\tthis._domEvents = domEventsScope();\n\t\tthis._initDelayedFunctions();\n\t}\n\n\tdestructor(): void{\n\t\tthis.tooltip.hide();\n\t\tthis._domEvents.detachAll();\n\t}\n\thideTooltip(): void{\n\t\tthis.delayHide();\n\t}\n\tattach(config: ITrackerTarget): void {\n\t\tlet root = document.body;\n\t\tconst gantt = this._gantt;\n\t\tif(!config.global){\n\t\t\troot = gantt.$root;\n\t\t}\n\n\t\tlet watchableTarget = null;\n\t\tconst handler = (event) => {\n\t\t\tconst eventTarget = domHelpers.getTargetNode(event);\n\t\t\tconst targetNode = domHelpers.closest(eventTarget, config.selector);\n\t\t\tif(domHelpers.isChildOf(eventTarget, this.tooltip.getNode())){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst doOnMouseEnter = () => {\n\t\t\t\twatchableTarget = targetNode;\n\t\t\t\tconfig.onmouseenter(event, targetNode);\n\t\t\t};\n\n\t\t\tif(watchableTarget){\n\t\t\t\tif(targetNode && targetNode === watchableTarget){\n\t\t\t\t\tconfig.onmousemove(event, targetNode);\n\t\t\t\t}else{\n\t\t\t\t\tconfig.onmouseleave(event, watchableTarget);\n\t\t\t\t\twatchableTarget = null;\n\n\t\t\t\t\tif(targetNode && targetNode !== watchableTarget){\n\t\t\t\t\t\tdoOnMouseEnter();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tif(targetNode){\n\t\t\t\t\tdoOnMouseEnter();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.detach(config.selector);\n\t\tthis._domEvents.attach(root, \"mousemove\", handler);\n\t\tthis._listeners[config.selector] = {\n\t\t\tnode: root,\n\t\t\thandler\n\t\t};\n\t}\n\n\tdetach(selector: string): void {\n\t\tconst listener = this._listeners[selector];\n\t\tif(listener){\n\t\t\tthis._domEvents.detach(listener.node, \"mousemove\", listener.handler);\n\t\t}\n\t}\n\n\ttooltipFor(config: ITooltipConfig): void {\n\t\tconst cloneDomEvent = (event: MouseEvent) => {\n\t\t\tlet clone = event;\n\t\t\t// making events survive timeout in ie\n\t\t\t// tslint:disable-next-line no-string-literal\n\t\t\tif(document[\"createEventObject\"] && !document.createEvent){\n\t\t\t\t// tslint:disable-next-line no-string-literal\n\t\t\t\tclone = document[\"createEventObject\"](event);\n\t\t\t}\n\t\t\treturn clone;\n\t\t};\n\t\tthis._initDelayedFunctions();\n\t\tthis.attach({\n\t\t\tselector: config.selector,\n\t\t\tglobal: config.global,\n\t\t\tonmouseenter:(event: MouseEvent, node: HTMLElement) => {\n\t\t\t\tconst html = config.html(event, node);\n\t\t\t\tif(html){\n\t\t\t\t\tthis.delayShow(cloneDomEvent(event), html);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonmousemove:(event: MouseEvent, node: HTMLElement) => {\n\t\t\t\tconst html = config.html(event, node);\n\t\t\t\tif(html){\n\t\t\t\t\tthis.delayShow(cloneDomEvent(event), html);\n\t\t\t\t}else{\n\t\t\t\t\tthis.delayShow.$cancelTimeout();\n\t\t\t\t\tthis.delayHide();\n\t\t\t\t}\n\t\t\t},\n\t\t\tonmouseleave:() => {\n\t\t\t\tthis.delayShow.$cancelTimeout();\n\t\t\t\tthis.delayHide();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate _initDelayedFunctions(){\n\t\tconst gantt = this._gantt;\n\t\t// reset delayed functions in order to apply current values of tooltip_timeout\n\t\tif(this.delayShow){\n\t\t\tthis.delayShow.$cancelTimeout();\n\t\t}\n\t\tif(this.delayHide){\n\t\t\tthis.delayHide.$cancelTimeout();\n\t\t}\n\t\tthis.tooltip.hide();\n\n\t\tthis.delayShow = helpers.delay((event: MouseEvent, html: string) => {\n\t\t\tif(gantt.callEvent(\"onBeforeTooltip\", [event]) === false) {\n\t\t\t\tthis.tooltip.hide();\n\t\t\t} else {\n\t\t\t\tthis.tooltip.setContent(html);\n\t\t\t\tthis.tooltip.show(event);\n\t\t\t}\n\t\t}, gantt.config.tooltip_timeout || 1);\n\n\t\tthis.delayHide = helpers.delay(() => {\n\t\t\tthis.delayShow.$cancelTimeout();\n\t\t\tthis.tooltip.hide();\n\t\t}, gantt.config.tooltip_hide_timeout || 1);\n\t}\n\n}","import { IInlineEditState, IMonitor, IUndo, IUndoCommand, TActionType, TEntityType, TUndoValue } from \"./types\";\n\nconst noTrack = {\n\tonBeforeUndo: \"onAfterUndo\",\n\tonBeforeRedo: \"onAfterRedo\"\n};\n\nconst batchActions = [\n\t\"onTaskDragStart\",\n\t\"onAfterTaskUpdate\",\n\t\"onAfterParentExpand\",\n\t\"onAfterTaskDelete\",\n\t\"onBeforeBatchUpdate\"\n];\n\nexport class Monitor implements IMonitor {\n\tprivate _batchAction = null;\n\tprivate _batchMode = false;\n\tprivate _ignore = false;\n\tprivate _ignoreMoveEvents = false;\n\tprivate _initialTasks = {};\n\tprivate _initialLinks = {};\n\tprivate _nestedTasks = {};\n\tprivate _nestedLinks = {};\n\tprivate _timeout;\n\tprivate _gantt: any;\n\tprivate _undo: IUndo;\n\n\tconstructor(undo: IUndo, gantt: any) {\n\t\tthis._undo = undo;\n\t\tthis._gantt = gantt;\n\t\tthis._attachEvents();\n\t}\n\n\tstore(id: TaskID | LinkID, type: TEntityType, overwrite: boolean = false) {\n\t\tif (type === this._gantt.config.undo_types.task) {\n\t\t\treturn this._storeTask(id, overwrite);\n\t\t}\n\t\tif (type === this._gantt.config.undo_types.link) {\n\t\t\treturn this._storeLink(id, overwrite);\n\t\t}\n\t\treturn false;\n\t}\n\tisMoveEventsIgnored() {\n\t\treturn this._ignoreMoveEvents;\n\t}\n\ttoggleIgnoreMoveEvents(newValue?: boolean) {\n\t\tthis._ignoreMoveEvents = newValue || false;\n\t}\n\tstartIgnore() {\n\t\tthis._ignore = true;\n\t}\n\tstopIgnore() {\n\t\tthis._ignore = false;\n\t}\n\tstartBatchAction() {\n\t\t// try catching updates made from event handlers using timeout\n\t\tif (!this._timeout){\n\t\t\tthis._timeout = setTimeout(() => {\n\t\t\t\tthis.stopBatchAction();\n\t\t\t\tthis._timeout = null;\n\t\t\t}, 10);\n\t\t}\n\n\n\t\tif (this._ignore || this._batchMode) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._batchMode = true;\n\t\tthis._batchAction = this._undo.action.create();\n\t}\n\tstopBatchAction() {\n\t\tif (this._ignore) {\n\t\t\treturn;\n\t\t}\n\t\tconst undo = this._undo;\n\t\tif (this._batchAction) {\n\t\t\tundo.logAction(this._batchAction);\n\t\t}\n\t\tthis._batchMode = false;\n\t\tthis._batchAction = null;\n\t}\n\tonTaskAdded(task: ITask) {\n\t\tif (!this._ignore) {\n\t\t\tthis._storeTaskCommand(task, this._undo.command.type.add);\n\t\t}\n\t}\n\tonTaskUpdated(task: ITask) {\n\t\tif (!this._ignore) {\n\t\t\tthis._storeTaskCommand(task, this._undo.command.type.update);\n\t\t}\n\t}\n\tonTaskMoved(task: ITask) {\n\t\tif (!this._ignore) {\n\t\t\t(task as any).$local_index = this._gantt.getTaskIndex(task.id);\n\t\t\tconst oldValue = this.getInitialTask(task.id);\n\t\t\tif((task as any).$local_index === oldValue.$local_index &&\n\t\t\t\tthis._gantt.getParent(task) === this._gantt.getParent(oldValue)){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\tthis._storeEntityCommand(\n\t\t\t\ttask,\n\t\t\t\tthis.getInitialTask(task.id),\n\t\t\t\tthis._undo.command.type.move,\n\t\t\t\tthis._undo.command.entity.task\n\t\t\t);\n\t\t}\n\t}\n\tonTaskDeleted(task: ITask) {\n\t\tif (!this._ignore) {\n\t\t\tthis._storeTaskCommand(task, this._undo.command.type.remove);\n\t\t\tif (this._nestedTasks[task.id]) {\n\t\t\t\tconst children = this._nestedTasks[task.id];\n\t\t\t\tfor (let i = 0; i < children.length; i++) {\n\t\t\t\t\tthis._storeTaskCommand(children[i], this._undo.command.type.remove);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._nestedLinks[task.id]) {\n\t\t\t\tconst childrenLinks = this._nestedLinks[task.id];\n\t\t\t\tfor (let i = 0; i < childrenLinks.length; i++) {\n\t\t\t\t\tthis._storeLinkCommand(childrenLinks[i], this._undo.command.type.remove);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tonLinkAdded(link: ILink) {\n\t\tif (!this._ignore) {\n\t\t\tthis._storeLinkCommand(link, this._undo.command.type.add);\n\t\t}\n\t}\n\tonLinkUpdated(link: ILink) {\n\t\tif (!this._ignore) {\n\t\t\tthis._storeLinkCommand(link, this._undo.command.type.update);\n\t\t}\n\t}\n\tonLinkDeleted(link: ILink) {\n\t\tif (!this._ignore) {\n\t\t\tthis._storeLinkCommand(link, this._undo.command.type.remove);\n\t\t}\n\t}\n\tsetNestedTasks(id: TaskID, taskIds: TaskID[]) {\n\t\tconst gantt = this._gantt;\n\t\tlet task = null;\n\t\tconst tasks = [];\n\t\tlet\tlinkIds = this._getLinks(gantt.getTask(id));\n\n\t\tfor (let i = 0; i < taskIds.length; i++) {\n\t\t\ttask = this.setInitialTask(taskIds[i]);\n\t\t\tlinkIds = linkIds.concat(this._getLinks(task));\n\t\t\ttasks.push(task);\n\t\t}\n\n\t\tconst uniqueLinks = {};\n\t\tfor (let i = 0; i < linkIds.length; i++) {\n\t\t\tuniqueLinks[linkIds[i]] = true;\n\t\t}\n\t\tconst links = [];\n\t\tfor (const i in uniqueLinks) {\n\t\t\tlinks.push(this.setInitialLink(i));\n\t\t}\n\t\tthis._nestedTasks[id] = tasks;\n\t\tthis._nestedLinks[id] = links;\n\t}\n\tsetInitialTask(id: TaskID, overwrite?: boolean) {\n\t\tconst gantt = this._gantt;\n\t\tif (overwrite || (!this._initialTasks[id] || !this._batchMode)) {\n\t\t\tconst task = gantt.copy(gantt.getTask(id));\n\t\t\ttask.$index = gantt.getGlobalTaskIndex(id);\n\t\t\ttask.$local_index = gantt.getTaskIndex(id);\n\t\t\tthis.setInitialTaskObject(id, task);\n\t\t}\n\t\treturn this._initialTasks[id];\n\t}\n\tgetInitialTask(id: TaskID) {\n\t\treturn this._initialTasks[id];\n\t}\n\tclearInitialTasks() {\n\t\tthis._initialTasks = {};\n\t}\n\tsetInitialTaskObject(id: TaskID, object: ITask) {\n\t\tthis._initialTasks[id] = object;\n\t}\n\tsetInitialLink(id: LinkID, overwrite?: boolean) {\n\t\tif (!this._initialLinks[id] || !this._batchMode) {\n\t\t\tthis._initialLinks[id] = this._gantt.copy(this._gantt.getLink(id));\n\t\t}\n\t\treturn this._initialLinks[id];\n\t}\n\tgetInitialLink(id: LinkID) {\n\t\treturn this._initialLinks[id];\n\t}\n\tclearInitialLinks() {\n\t\tthis._initialLinks = {};\n\t}\n\tprivate _attachEvents() {\n\t\tlet deleteCacheCooldown = null;\n\t\tconst gantt = this._gantt;\n\n\t\tconst saveInitialAll = () => {\n\t\t\tif (!deleteCacheCooldown) {\n\t\t\t\tdeleteCacheCooldown = setTimeout(() => {\n\t\t\t\t\tdeleteCacheCooldown = null;\n\t\t\t\t});\n\n\t\t\t\tthis.clearInitialTasks();\n\t\t\t\tgantt.eachTask((task: ITask) => {\n\t\t\t\t\tthis.setInitialTask(task.id);\n\t\t\t\t});\n\n\t\t\t\tthis.clearInitialLinks();\n\t\t\t\tgantt.getLinks().forEach((link: ILink) => {\n\t\t\t\t\tthis.setInitialLink(link.id);\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\tconst getMoveObjectByTaskId = (id: TaskID) => {\n\t\t\treturn gantt.copy(gantt.getTask(id));\n\t\t};\n\n\t\tfor (const i in noTrack) {\n\t\t\tgantt.attachEvent(i, () => {\n\t\t\t\tthis.startIgnore();\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tgantt.attachEvent(noTrack[i], () => {\n\t\t\t\tthis.stopIgnore();\n\t\t\t\treturn true;\n\t\t\t});\n\t\t}\n\n\t\tfor (let i = 0; i < batchActions.length; i++) {\n\t\t\tgantt.attachEvent(batchActions[i], () => {\n\t\t\t\tthis.startBatchAction();\n\t\t\t\treturn true;\n\t\t\t});\n\t\t}\n\n\t\tgantt.attachEvent(\"onParse\", () => {\n\t\t\tthis._undo.clearUndoStack();\n\t\t\tthis._undo.clearRedoStack();\n\t\t\tsaveInitialAll();\n\t\t});\n\t\tgantt.attachEvent(\"onAfterTaskAdd\", (id: TaskID, task: ITask) => {\n\t\t\tthis.setInitialTask(id, true);\n\t\t\tthis.onTaskAdded(task);\n\t\t});\n\t\tgantt.attachEvent(\"onAfterTaskUpdate\", (id: TaskID, task: ITask) => {\n\t\t\tthis.onTaskUpdated(task);\n\t\t});\n\t\tgantt.attachEvent(\"onAfterParentExpand\", (id: TaskID, task: ITask) => {\n\t\t\tthis.onTaskUpdated(task);\n\t\t});\n\t\tgantt.attachEvent(\"onAfterTaskDelete\", (id: TaskID, task: ITask) => {\n\t\t\tthis.onTaskDeleted(task);\n\t\t});\n\t\tgantt.attachEvent(\"onAfterLinkAdd\", (id: LinkID, link: ILink) => {\n\t\t\tthis.setInitialLink(id, true);\n\t\t\tthis.onLinkAdded(link);\n\t\t});\n\t\tgantt.attachEvent(\"onAfterLinkUpdate\", (id: LinkID, link: ILink) => {\n\t\t\tthis.onLinkUpdated(link);\n\t\t});\n\t\tgantt.attachEvent(\"onAfterLinkDelete\", (id: LinkID, link: ILink) => {\n\t\t\tthis.onLinkDeleted(link);\n\t\t});\n\t\tgantt.attachEvent(\"onRowDragEnd\", (id: TaskID, target: TaskID) => {\n\t\t\tthis.onTaskMoved(getMoveObjectByTaskId(id));\n\t\t\tthis.toggleIgnoreMoveEvents();\n\t\t\treturn true;\n\t\t});\n\t\tgantt.attachEvent(\"onBeforeTaskDelete\", (id: TaskID) => {\n\t\t\tthis.store(id, gantt.config.undo_types.task);\n\t\t\tconst nested = [];\n\n\t\t\t// remember task indexes in case their being deleted in a loop, so they could be restored in the correct order\n\t\t\tsaveInitialAll();\n\n\t\t\tgantt.eachTask((task: ITask) => {\n\t\t\t\tnested.push(task.id);\n\t\t\t}, id);\n\t\t\tthis.setNestedTasks(id, nested);\n\t\t\treturn true;\n\t\t});\n\t\tconst datastore = gantt.getDatastore(\"task\");\n\n\t\tdatastore.attachEvent(\"onBeforeItemMove\", (id: TaskID, parent: TaskID, tindex: number) => {\n\t\t\tif (!this.isMoveEventsIgnored()) {\n\t\t\t\tsaveInitialAll();\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tdatastore.attachEvent(\"onAfterItemMove\", (id: TaskID, parent: TaskID, tindex: number) => {\n\t\t\tif (!this.isMoveEventsIgnored()) {\n\t\t\t\tthis.onTaskMoved(getMoveObjectByTaskId(id));\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tgantt.attachEvent(\"onRowDragStart\", (id: TaskID, target: TaskID, e: Event) => {\n\t\t\tthis.toggleIgnoreMoveEvents(true);\n\t\t\tsaveInitialAll();\n\t\t\treturn true;\n\t\t});\n\n\t\tlet dragId = null;\n\t\tlet projectDrag = false;\n\t\tgantt.attachEvent(\"onBeforeTaskDrag\", (taskId: TaskID) => {\n\t\t\tdragId = gantt.getState().drag_id;\n\t\t\tif (dragId === taskId){\n\t\t\t\tconst task = gantt.getTask(taskId);\n\t\t\t\tif (gantt.isSummaryTask(task) && gantt.config.drag_project){\n\t\t\t\t\tprojectDrag = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// GS-99. Store the initial task dates before multiple drag\n\t\t\tif (gantt.plugins().multiselect){\n\t\t\t\tconst selectedIds = gantt.getSelectedTasks();\n\t\t\t\tif (selectedIds.length > 1){\n\t\t\t\t\tselectedIds.forEach((id)=>{\n\t\t\t\t\t\tthis.store(id, gantt.config.undo_types.task, true);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this.store(taskId, gantt.config.undo_types.task);\n\t\t});\n\n\t\tgantt.attachEvent(\"onAfterTaskDrag\", (taskId: TaskID) => {\n\t\t\t// if we drag multiple tasks and other tasks move to another date after that,\n\t\t\t// auto-scheduling/correct work time should occur in anoher command.\n\t\t\t// otherwise, when we undo the changes, the task constraint is not restored correctly\n\t\t\tconst multipleDrag = projectDrag || (gantt.plugins().multiselect && gantt.getSelectedTasks().length > 1);\n\t\t\tif (multipleDrag && dragId === taskId){\n\t\t\t\tprojectDrag = false;\n\t\t\t\tdragId = null;\n\t\t\t\tthis.stopBatchAction();\n\t\t\t}\n\t\t\t// GS-99. When dragging multiple tasks, we need to store the initial tasks\n\t\t\tthis.store(taskId, gantt.config.undo_types.task, true);\n\t\t});\n\n\t\tgantt.attachEvent(\"onLightbox\", (taskId: TaskID) => this.store(taskId, gantt.config.undo_types.task));\n\n\t\tgantt.attachEvent(\"onBeforeTaskAutoSchedule\", (task: ITask) => {\n\t\t\tthis.store(task.id, gantt.config.undo_types.task, true);\n\t\t\treturn true;\n\t\t});\n\n\t\tif (gantt.ext.inlineEditors) {\n\t\t\t// remove the onGanttLayoutReady wrapper when GS-1288 is merged\n\t\t\tlet onBeforeEditStartId = null;\n\t\t\tlet onEditStart = null;\n\t\t\tgantt.attachEvent(\"onGanttLayoutReady\", () => {\n\t\t\t\tif (onBeforeEditStartId) {\n\t\t\t\t\tgantt.ext.inlineEditors.detachEvent(onBeforeEditStartId);\n\t\t\t\t}\n\t\t\t\tif (onEditStart) {\n\t\t\t\t\tgantt.ext.inlineEditors.detachEvent(onEditStart);\n\t\t\t\t}\n\n\t\t\t\tonEditStart = gantt.ext.inlineEditors.attachEvent(\"onEditStart\", (state: IInlineEditState) => {\n\t\t\t\t\tthis.store(state.id, gantt.config.undo_types.task);\n\t\t\t\t});\n\n\t\t\t\t// GS-99. If another inline editor is opened and we open a new inline editor,\n\t\t\t\t// we shouldn't use the batchAction\n\t\t\t\tonBeforeEditStartId = gantt.ext.inlineEditors.attachEvent(\"onBeforeEditStart\", (state: IInlineEditState) => {\n\t\t\t\t\tthis.stopBatchAction();\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _storeCommand(command: IUndoCommand) {\n\t\tconst undo = this._undo;\n\t\tundo.updateConfigs();\n\n\t\tif (!undo.undoEnabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._batchMode) {\n\t\t\tthis._batchAction.commands.push(command);\n\t\t} else {\n\t\t\tconst action = undo.action.create([command]);\n\t\t\tundo.logAction(action);\n\t\t}\n\t}\n\tprivate _storeEntityCommand(obj: TUndoValue, old: TUndoValue, actionType: TActionType, entityType: TEntityType) {\n\t\tconst undo = this._undo;\n\t\tconst command = undo.command.create(obj, old, actionType, entityType);\n\t\tthis._storeCommand(command);\n\t}\n\tprivate _storeTaskCommand(obj: ITask, type: TActionType) {\n\t\tif(this._gantt.isTaskExists(obj.id)){\n\t\t\t(obj as any).$local_index = this._gantt.getTaskIndex(obj.id);\n\t\t}\n\n\t\tthis._storeEntityCommand(obj, this.getInitialTask(obj.id), type, this._undo.command.entity.task);\n\t}\n\tprivate _storeLinkCommand(obj: ILink, type: TActionType) {\n\t\tthis._storeEntityCommand(obj, this.getInitialLink(obj.id), type, this._undo.command.entity.link);\n\t}\n\tprivate _getLinks(task: ITask) {\n\t\treturn task.$source.concat(task.$target);\n\t}\n\tprivate _storeTask(taskId: TaskID, overwrite: boolean = false) {\n\t\tconst gantt = this._gantt;\n\t\tthis.setInitialTask(taskId, overwrite);\n\t\tgantt.eachTask((child: ITask) => {\n\t\t\tthis.setInitialTask(child.id);\n\t\t}, taskId);\n\t\treturn true;\n\t}\n\tprivate _storeLink(linkId: LinkID, overwrite: boolean = false) {\n\t\tthis.setInitialLink(linkId, overwrite);\n\t\treturn true;\n\t}\n}","import { IUndo, IUndoCommand, IUndoCommands, IUndoPropAction, IUndoPropCommand, TActionType, TEntityType, TUndoStack, TUndoValue } from \"./types\";\n\nconst MAX_UNDO_STEPS = 100;\n\nexport class Undo implements IUndo {\n\n\tmaxSteps = MAX_UNDO_STEPS;\n\tundoEnabled = true;\n\tredoEnabled = true;\n\taction: IUndoPropAction = {\n\t\tcreate: (commands?: IUndoCommand[]): IUndoCommands => {\n\t\t\treturn { commands: (commands ? commands.slice() : []) };\n\t\t},\n\t\tinvert: (action: IUndoCommands): IUndoCommands => {\n\t\t\tconst gantt = this._gantt;\n\t\t\tconst revert = gantt.copy(action);\n\t\t\tconst commands = this.command;\n\t\t\tfor (let i = 0; i < action.commands.length; i++) {\n\t\t\t\tconst command = revert.commands[i] = commands.invert(revert.commands[i]);\n\t\t\t\tif (command.type === commands.type.update || command.type === commands.type.move) {\n\t\t\t\t\t[command.value, command.oldValue] = [command.oldValue, command.value];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn revert as IUndoCommands;\n\t\t}\n\t};\n\tcommand: IUndoPropCommand = {\n\t\t// entities that require different processing for undoing-redoing changes (gantt.config.undo_types)\n\t\tentity: null,\n\n\t\t// types of traced actions (gantt.config.undo_actions)\n\t\ttype: null,\n\n\t\tcreate: (value: TUndoValue, oldValue: TUndoValue, type: TActionType, entity: TEntityType): IUndoCommand => {\n\t\t\tconst gantt = this._gantt;\n\t\t\treturn {\n\t\t\t\tentity,\n\t\t\t\ttype,\n\t\t\t\tvalue: gantt.copy(value),\n\t\t\t\toldValue: gantt.copy(oldValue || value)\n\t\t\t};\n\t\t},\n\t\tinvert: (command: IUndoCommand): IUndoCommand => {\n\t\t\tconst gantt = this._gantt;\n\t\t\tconst revert = gantt.copy(command);\n\t\t\trevert.type = this.command.inverseCommands(command.type);\n\t\t\treturn revert;\n\t\t},\n\t\tinverseCommands: (command: TActionType): TActionType => {\n\t\t\tconst gantt = this._gantt;\n\t\t\tconst types = this.command.type;\n\t\t\tswitch (command) {\n\t\t\t\tcase types.update:\n\t\t\t\t\treturn types.update;\n\t\t\t\tcase types.remove:\n\t\t\t\t\treturn types.add;\n\t\t\t\tcase types.add:\n\t\t\t\t\treturn types.remove;\n\t\t\t\tcase types.move:\n\t\t\t\t\treturn types.move;\n\t\t\t\tdefault:\n\t\t\t\t\tgantt.assert(false, \"Invalid command \"+ command);\n\t\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t};\n\n\tprivate _undoStack = [];\n\tprivate _redoStack = [];\n\tprivate _gantt: any;\n\n\tconstructor(gantt: any){\n\t\tthis._gantt = gantt;\n\t}\n\tgetUndoStack() {\n\t\treturn this._undoStack;\n\t}\n\tsetUndoStack(stack: []) {\n\t\tthis._undoStack = stack;\n\t}\n\n\tgetRedoStack() {\n\t\treturn this._redoStack;\n\t}\n\tsetRedoStack(stack: []) {\n\t\tthis._redoStack = stack;\n\t}\n\n\tclearUndoStack() {\n\t\tthis._undoStack = [];\n\t}\n\n\tclearRedoStack() {\n\t\tthis._redoStack = [];\n\t}\n\n\tupdateConfigs() {\n\t\tconst gantt = this._gantt;\n\t\tthis.maxSteps = gantt.config.undo_steps || MAX_UNDO_STEPS;\n\t\tthis.command.entity = gantt.config.undo_types;\n\t\tthis.command.type = gantt.config.undo_actions;\n\t\tthis.undoEnabled = !!gantt.config.undo;\n\t\tthis.redoEnabled = !!gantt.config.redo; // GS-873, Redo should work even when the `gantt.config.undo` is disabled.\n\t}\n\n\tundo() {\n\t\tconst gantt = this._gantt;\n\t\tthis.updateConfigs();\n\t\tif (!this.undoEnabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst action = this._pop(this._undoStack);\n\t\tif (action) {\n\t\t\tthis._reorderCommands(action);\n\t\t}\n\t\tif (gantt.callEvent(\"onBeforeUndo\", [action]) !== false) {\n\t\t\tif (action) {\n\t\t\t\tthis._applyAction(this.action.invert(action));\n\t\t\t\tthis._push(this._redoStack, gantt.copy(action));\n\t\t\t\tgantt.callEvent(\"onAfterUndo\", [action]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tgantt.callEvent(\"onAfterUndo\", [null]);\n\t}\n\n\tredo() {\n\t\tconst gantt = this._gantt;\n\t\tthis.updateConfigs();\n\t\tif (!this.redoEnabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst action = this._pop(this._redoStack);\n\t\tif (action) {\n\t\t\tthis._reorderCommands(action);\n\t\t}\n\n\t\tif (gantt.callEvent(\"onBeforeRedo\", [action]) !== false) {\n\t\t\tif (action) {\n\t\t\t\tthis._applyAction(action);\n\t\t\t\tthis._push(this._undoStack, gantt.copy(action));\n\t\t\t\tgantt.callEvent(\"onAfterRedo\", [action]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tgantt.callEvent(\"onAfterRedo\", [null]);\n\t}\n\n\t// storeUndo:\n\tlogAction(action: IUndoCommands) {\n\t\tthis._push(this._undoStack, action);\n\t\tthis._redoStack = [];\n\t}\n\n\tprivate _push(stack: TUndoStack, action: IUndoCommands): IUndoCommands {\n\t\tconst gantt = this._gantt;\n\t\tif (!action.commands.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst event = stack === this._undoStack ? \"onBeforeUndoStack\" : \"onBeforeRedoStack\";\n\t\tif (gantt.callEvent(event, [action]) === false){\n\t\t\treturn;\n\t\t}\n\t\t// commands can be removed from event handler\n\t\tif (!action.commands.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tstack.push(action);\n\t\twhile (stack.length > this.maxSteps) {\n\t\t\tstack.shift();\n\t\t}\n\t\treturn action;\n\t}\n\n\tprivate _pop(stack: TUndoStack): IUndoCommands {\n\t\treturn stack.pop();\n\t}\n\n\tprivate _reorderCommands(action) {\n\t\t// firstly process tasks and only then links\n\t\t// in order to ensure links are added not earlier than their tasks\n\t\t// firstly to 'move' actions and only then updates\n\t\tconst weights = { any: 0, link:1, task:2 };\n\t\tconst actionWeights = { move: 1, any:0 };\n\t\taction.commands.sort(function(a, b) {\n\t\t\tif (a.entity === \"task\" && b.entity === \"task\") {\n\t\t\t\tif (a.type !== b.type) {\n\t\t\t\t\treturn (actionWeights[b.type] || 0) - (actionWeights[a.type] || 0);\n\t\t\t\t} else if (a.type === \"move\" && a.oldValue && b.oldValue && b.oldValue.parent === a.oldValue.parent) {\n\t\t\t\t\treturn a.oldValue.$index - b.oldValue.$index;\n\t\t\t\t} else {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst weightA = weights[a.entity] || weights.any;\n\t\t\t\tconst weightB = weights[b.entity] || weights.any;\n\t\t\t\treturn weightB - weightA;\n\t\t\t}\n\n\t\t});\n\t}\n\n\tprivate _applyAction(action: IUndoCommands) {\n\t\tlet command = null;\n\t\tconst entities = this.command.entity;\n\t\tconst actions = this.command.type;\n\t\tconst gantt = this._gantt;\n\t\tconst methods = {};\n\t\tmethods[entities.task] = {\n\t\t\tadd: \"addTask\",\n\t\t\tget: \"getTask\",\n\t\t\tupdate: \"updateTask\",\n\t\t\tremove: \"deleteTask\",\n\t\t\tmove: \"moveTask\",\n\t\t\tisExists: \"isTaskExists\"\n\t\t};\n\t\tmethods[entities.link] = {\n\t\t\tadd: \"addLink\",\n\t\t\tget: \"getLink\",\n\t\t\tupdate: \"updateLink\",\n\t\t\tremove: \"deleteLink\",\n\t\t\tisExists: \"isLinkExists\"\n\t\t};\n\n\t\tgantt.batchUpdate(function() {\n\t\t\t// it is logical to undo actions from the last one to the first one\n\t\t\t// but we have to do it from the first one because the order\n\t\t\t// of tasks ($index and $local_index) depends on the existing tasks\n\t\t\tfor (let i = 0; i < action.commands.length; i++) {\n\t\t\t\tcommand = action.commands[i];\n\t\t\t\tconst method = methods[command.entity][command.type];\n\t\t\t\tconst getMethod = methods[command.entity].get;\n\t\t\t\tconst check = methods[command.entity].isExists;\n\n\t\t\t\tif (command.type === actions.add) {\n\t\t\t\t\tgantt[method](command.oldValue, command.oldValue.parent, command.oldValue.$local_index);\n\t\t\t\t} else if (command.type === actions.remove) {\n\t\t\t\t\tif (gantt[check](command.value.id)) {\n\t\t\t\t\t\tgantt[method](command.value.id);\n\t\t\t\t\t}\n\t\t\t\t} else if (command.type === actions.update) {\n\t\t\t\t\tconst item = gantt[getMethod](command.value.id);\n\t\t\t\t\tfor(const prop in command.value){\n\t\t\t\t\t\tconst internalProperty = prop.startsWith(\"$\") || prop.startsWith(\"_\");\n\t\t\t\t\t\tconst whitelist = [\"$open\"];\n\t\t\t\t\t\tlet copyProperty = !internalProperty;\n\t\t\t\t\t\tif (whitelist.indexOf(prop) > -1){\n\t\t\t\t\t\t\tcopyProperty = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(copyProperty){\n\t\t\t\t\t\t\titem[prop] = command.value[prop];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tgantt[method](command.value.id);\n\t\t\t\t} else if (command.type === actions.move) {\n\t\t\t\t\tgantt[method](command.value.id, command.value.$local_index, command.value.parent);\n\t\t\t\t\t// GS-680: We should send the changes to the server after we undo vertical reorder\n\t\t\t\t\tgantt.callEvent(\"onRowDragEnd\", [command.value.id]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n}","export default class ExtensionsManager{\n\tprivate _extensions:{[key:string]: GanttPlugin };\n\n\tconstructor(config: {[key:string]: GanttPlugin }){\n\t\tthis._extensions = {};\n\t\tfor(const i in config){\n\t\t\tthis._extensions[i] = config[i];\n\t\t}\n\t}\n\n\taddExtension = (name: string, ext: GanttPlugin) => {\n\t\tthis._extensions[name] = ext;\n\t};\n\n\tgetExtension = (name: string): GanttPlugin => {\n\t\treturn this._extensions[name];\n\t};\n}","export default {\n\tKEY_CODES: {\n\t\tUP: 38,\n\t\tDOWN: 40,\n\t\tLEFT: 37,\n\t\tRIGHT: 39,\n\t\tSPACE: 32,\n\t\tENTER: 13,\n\t\tDELETE: 46,\n\t\tESC: 27,\n\t\tTAB: 9\n\t}\n};","type DurationUnits = \"minute\" | \"hour\" | \"day\" | \"week\" | \"month\" | \"year\";\ntype Align = \"left\" | \"center\" | \"right\";\ntype SectionType = \"textarea\"\n\t\t\t\t\t| \"time\"\n\t\t\t\t\t| \"duration\"\n\t\t\t\t\t| \"select\"\n\t\t\t\t\t| \"typeselect\"\n\t\t\t\t\t| \"parent\"\n\t\t\t\t\t| \"template\"\n\t\t\t\t\t| \"checkbox\"\n\t\t\t\t\t| \"radio\"\n\t\t\t\t\t| \"resources\"\n\t\t\t\t\t| \"constraint\";\n\ntype LightboxSection = Array;\n\ntype LayoutView = \"grid\"\n\t| \"timeline\"\n\t| \"resizer\"\n\t| \"scrollbar\"\n\t| \"resourceGrid\"\n\t| \"resourceTimeline\";\n\ninterface IColumnItem {\n\tname: string;\n\tlabel?: string;\n\ttree?: boolean;\n\talign?: Align;\n\thide?: boolean;\n\tmax_width?: number;\n\tmin_width?: number;\n\tresize?: boolean;\n\ttemplate?: (obj: any) => string;\n\twidth?: number | \"*\";\n}\n\nexport type TModifierKeys = \"metaKey\" | \"ctrlKey\" | \"altKey\" | \"shiftKey\" | false | undefined;\n\nexport interface IScale {\n\tcss?: () => string;\n\tdate?: string;\n\tstep: number;\n\ttemplate?: (date: Date) => string;\n\tunit: DurationUnits;\n}\n\ninterface ILightboxSection {\n\tname: string;\n\tmap_to: string;\n\ttype: SectionType;\n\theight?: number;\n\tfocus?: boolean;\n}\n\ninterface ILightboxTimeAndDurationSection extends ILightboxSection {\n\treadonly: boolean;\n\tyear_range: number[] | number;\n\tsingle_date: boolean;\n\ttime_format: string;\n}\n\ninterface ILightboxInputControl extends ILightboxSection {\n\tdefault_value?: any;\n\toptions?: Array<{key: string, label: string}>;\n}\n\ninterface ILightboxSelectControl extends ILightboxInputControl {\n\tonchange: () => boolean | undefined;\n}\n\ninterface ILightboxParentControl extends ILightboxSection {\n\tallow_root: boolean;\n\troot_label: string;\n\tsort?: (a: any, b: any) => -1 | 0 | 1;\n\tfilter?: (task: string | number | object) => boolean;\n\ttemplate?: (start: Date, end: Date, ev: object) => string;\n}\n\ninterface ILightboxTypeselectControl extends ILightboxSection {\n\tfilter?: (typeName: string) => boolean;\n}\n\n\ninterface ILayoutScrollbar {\n\tview: \"scrollbar\";\n\tscroll?: \"x\" | \"y\";\n\tid: string;\n\theight?: number;\n\twidth?: number;\n}\n\ninterface ILayoutView {\n\tview: LayoutView;\n\tid?: string;\n\tscrollX?: string;\n\tscrollY?: string;\n\tconfig?: object;\n}\n\ninterface ILayoutGrid extends ILayoutView {\n\tview: \"grid\";\n\tbind?: string;\n}\n\ninterface ILayoutTimeline extends ILayoutView {\n\tview: \"timeline\";\n\tbindLinks?: string;\n\tlayers?: any[];\n}\n\ninterface ILayoutResizer {\n\tview?: undefined;\n\tresizer: boolean;\n\twidth: number;\n}\n\ninterface ILayoutResourceGrid extends ILayoutView {\n\tview: \"resourceGrid\";\n\twidth: number;\n\tgroup: \"string\";\n}\n\ninterface ILayoutResourceTimeline extends ILayoutView {\n\tview: \"resourceTimeline\";\n\twidth: number;\n\tgroup: \"string\";\n}\n\ninterface ILayoutHtml {\n\thtml: string;\n\tcss: string;\n\twidth: number;\n}\n\ntype LayoutRow = ILayoutGrid\n\t| ILayoutTimeline\n\t| ILayoutResizer\n\t| ILayoutResourceGrid\n\t| ILayoutResourceTimeline\n\t| ILayoutHtml\n\t| ILayoutScrollbar\n\t| { cols: LayoutCol[] };\n\ntype LayoutCol = ILayoutGrid\n\t| ILayoutTimeline\n\t| ILayoutResizer\n\t| ILayoutResourceGrid\n\t| ILayoutResourceTimeline\n\t| ILayoutHtml\n\t| ILayoutScrollbar\n\t| { rows: LayoutRow[] };\n\ninterface ILayout {\n\tcss: string;\n\trows?: LayoutRow[];\n\tcols?: LayoutCol[];\n}\n\ntype TCsp = boolean | \"auto\";\n\ninterface IResourceConfig {\n\tdataprocessor_assignments?: boolean;\n\tdataprocessor_resources?: boolean;\n\teditable_resource_diagram?: boolean;\n\tresource_store?: {\n\t\ttype?: \"treeDataStore\"|\"dataStore\"|string;\n\t\tfetchTasks?: boolean;\n\t\tinitItem?: (item: any) => any;\n\t};\n\tlightbox_resources?: (resources: any[]) => any[];\n\n}\n\ninterface IGanttConfig {\n\tlayout: ILayout;\n\tlinks: {\n\t\tfinish_to_start: \"0\";\n\t\tstart_to_start: \"1\";\n\t\tfinish_to_finish: \"2\";\n\t\tstart_to_finish: \"3\";\n\t};\n\ttypes: {\n\t\ttask: string;\n\t\tproject: string;\n\t\tmilestone: string;\n\t};\n\tauto_types: boolean;\n\tduration_unit: DurationUnits;\n\twork_time: boolean;\n\tcorrect_work_time: boolean;\n\tdeadlines: boolean;\n\tskip_off_time: boolean;\n\tcascade_delete: boolean;\n\tautosize: boolean | string;\n\tautoscroll: boolean;\n\tshow_links: boolean;\n\tshow_task_cells: boolean;\n\tautosize_min_width: number;\n\tautoscroll_speed: number;\n\tdeepcopy_on_parse: boolean;\n\tstatic_background: boolean;\n\tstatic_background_cells: boolean;\n\tbranch_loading: boolean;\n\tbranch_loading_property: string;\n\tshow_loading: boolean;\n\tshow_chart: boolean;\n\tshow_grid: boolean;\n\tmin_duration: number;\n\tdate_format: string; // use instead xml_date\n\txml_date?: string; // deprecated\n\tstart_on_monday: boolean;\n\tserver_utc: boolean;\n\tshow_progress: boolean;\n\tfit_tasks: boolean;\n\tselect_task: boolean;\n\tscroll_on_click: boolean;\n\tsmart_rendering: boolean;\n\tpreserve_scroll: boolean;\n\treadonly: boolean;\n\tcontainer_resize_timeout: number;\n\n\t/*grid */\n\tdate_grid: string;\n\n\tdrag_links: boolean;\n\tdrag_progress: boolean;\n\tdrag_resize: boolean;\n\tdrag_project: boolean;\n\tdrag_move: boolean;\n\tdrag_mode: {\n\t\tresize: \"resize\",\n\t\tprogress: \"progress\",\n\t\tmove: \"move\",\n\t\tignore: \"ignore\"\n\t};\n\tround_dnd_dates: boolean;\n\tlink_wrapper_width: number;\n\troot_id: string | number;\n\n\tlink_arrow_size:number;\n\n\tautofit: boolean;\n\tcolumns: IColumnItem[];\n\n\t/* scale*/\n\t/* it will be deprecated */\n\tdate_scale?: string;\n\tstep?: number;\n\tscale_unit?: DurationUnits;\n\tsubscales?: IScale[];\n\t/* it will be deprecated end */\n\n\tscales: IScale[];\n\n\tscale_offset_minimal: boolean;\n\n\tinherit_scale_class: boolean;\n\n\n\ttime_step: number;\n\tduration_step: number;\n\n\n\ttask_date: string;\n\ttime_picker: string;\n\ttask_attribute: string;\n\tlink_attribute: string;\n\tlayer_attribute: string;\n\tbuttons_left: string[];\n\t_migrate_buttons: {\n\t\tdhx_save_btn: \"gantt_save_btn\",\n\t\tdhx_cancel_btn: \"gantt_cancel_btn\",\n\t\tdhx_delete_btn: \"gantt_delete_btn\"\n\t};\n\n\tbuttons_right: string[];\n\n\n\tlightbox: {\n\t\tsections?: LightboxSection,\n\t\tproject_sections?: LightboxSection,\n\t\tmilestone_sections?: LightboxSection\n\t};\n\tdrag_lightbox: boolean;\n\tsort: boolean;\n\tdetails_on_create: boolean;\n\tdetails_on_dblclick: boolean;\n\tinitial_scroll: boolean;\n\ttask_scroll_offset: number;\n\n\torder_branch: boolean;\n\torder_branch_free: boolean;\n\n\t// task_height is deprecated, use 'bar_height` instead\n\ttask_height: number | \"full\" | undefined;\n\tbar_height: number | \"full\";\n\tmin_column_width: number;\n\tbar_height_padding: number,\n\trow_height: number,\n\n\t// min width for grid column (when resizing)\n\tmin_grid_column_width: number;\n\t// name of the attribute with column index for resize element\n\tgrid_resizer_column_attribute: string;\n\t// name of the attribute with column index for resize element\n\t// grid_resizer_attribute: string; // usage of this parameter is not found\n\n\t// grid width can be increased after the column has been resized\n\tkeep_grid_width: boolean;\n\n\t// grid width can be adjusted\n\tgrid_resize: boolean;\n\tgrid_elastic_columns: boolean;\n\tshow_tasks_outside_timescale: boolean;\n\tshow_unscheduled: boolean;\n\treadonly_property: string;\n\teditable_property: string;\n\tcalendar_property: string;\n\tresource_calendars: object;\n\tdynamic_resource_calendars: boolean;\n\tinherit_calendar: boolean;\n\ttype_renderers: object;\n\n\tresize_rows: boolean;\n\t// name of the attribute with row index for resize element\n\ttask_grid_row_resizer_attribute: string;\n\t// min height for row (when resizing)\n\tmin_task_grid_row_height: number;\n\n\topen_tree_initially: boolean;\n\toptimize_render: boolean;\n\tprevent_default_scroll: boolean;\n\tshow_errors: boolean;\n\twai_aria_attributes: boolean;\n\tsmart_scales: boolean;\n\trtl: boolean;\n\tplaceholder_task: boolean | object;\n\thorizontal_scroll_key: TModifierKeys;\n\tdrag_timeline: {\n\t\tuseKey: TModifierKeys;\n\t\tignore: string;\n\t\trender?: boolean;\n\t};\n\tdrag_multiple: boolean;\n\tcsp: TCsp;\n\n\tresources?: IResourceConfig;\n}\n\nexport default () => {\n\tconst result: IGanttConfig = {\n\t\tlayout: {\n\t\t\tcss: \"gantt_container\",\n\t\t\trows: [\n\t\t\t\t{\n\t\t\t\t\tcols: [\n\t\t\t\t\t\t{view: \"grid\", scrollX: \"scrollHor\", scrollY: \"scrollVer\"},\n\t\t\t\t\t\t{resizer: true, width: 1},\n\t\t\t\t\t\t{view: \"timeline\", scrollX: \"scrollHor\", scrollY: \"scrollVer\"},\n\t\t\t\t\t\t{view: \"scrollbar\", id: \"scrollVer\"}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{view: \"scrollbar\", id: \"scrollHor\", height: 20}\n\t\t\t]\n\t\t},\n\t\tlinks: {\n\t\t\tfinish_to_start: \"0\",\n\t\t\tstart_to_start: \"1\",\n\t\t\tfinish_to_finish: \"2\",\n\t\t\tstart_to_finish: \"3\"\n\t\t},\n\t\ttypes: {\n\t\t\ttask: \"task\",\n\t\t\tproject: \"project\",\n\t\t\tmilestone: \"milestone\"\n\t\t},\n\t\tauto_types: false,\n\t\tduration_unit: \"day\",\n\t\twork_time: false,\n\t\tcorrect_work_time: false,\n\t\tskip_off_time: false,\n\n\t\tcascade_delete: true,\n\n\t\tautosize: false,\n\t\tautosize_min_width: 0,\n\t\tautoscroll: true,\n\t\tautoscroll_speed: 30,\n\t\tdeepcopy_on_parse: false,\n\t\tshow_links: true,\n\t\tshow_task_cells: true,\n\t\t// replace backgroung of the task area with a canvas img\n\t\tstatic_background: false,\n\t\tstatic_background_cells: true,\n\t\tbranch_loading: false,\n\t\tbranch_loading_property: \"$has_child\",\n\t\tshow_loading: false,\n\t\tshow_chart: true,\n\t\tshow_grid: true,\n\t\tmin_duration: 60 * 60 * 1000,\n\t\tdate_format: \"%d-%m-%Y %H:%i\", // use instead xml_date\n\t\txml_date: undefined, // \"%d-%m-%Y %H:%i\", // deprecated\n\t\tstart_on_monday: true,\n\t\tserver_utc: false,\n\t\tshow_progress: true,\n\t\tfit_tasks: false,\n\t\tselect_task: true,\n\t\tscroll_on_click: true,\n\t\tsmart_rendering: true,\n\t\tpreserve_scroll: true,\n\t\treadonly: false,\n\t\tcontainer_resize_timeout: 20,\n\t\tdeadlines: true,\n\n\t\t/*grid */\n\t\tdate_grid: \"%Y-%m-%d\",\n\n\t\tdrag_links: true,\n\t\tdrag_progress: true,\n\t\tdrag_resize: true,\n\t\tdrag_project: false,\n\t\tdrag_move: true,\n\t\tdrag_mode: {\n\t\t\tresize: \"resize\",\n\t\t\tprogress: \"progress\",\n\t\t\tmove: \"move\",\n\t\t\tignore: \"ignore\"\n\t\t},\n\t\tround_dnd_dates: true,\n\t\tlink_wrapper_width: 20,\n\t\tlink_arrow_size:12,\n\t\troot_id: 0,\n\n\t\tautofit: false, // grid column automatic fit grid_width config\n\t\tcolumns: [\n\t\t\t{name: \"text\", tree: true, width: \"*\", resize: true},\n\t\t\t{name: \"start_date\", align: \"center\", resize: true},\n\t\t\t{name: \"duration\", align: \"center\"},\n\t\t\t{name: \"add\", width: 44}\n\t\t],\n\n\t\t/*scale*/\n\n\t\tscale_offset_minimal: true,\n\t\tinherit_scale_class: false,\n\n\t\tscales: [\n\t\t\t{\n\t\t\t\tunit: \"day\",\n\t\t\t\tstep: 1,\n\t\t\t\tdate: \"%d %M\"\n\t\t\t}\n\t\t],\n// \t\tdate_scale: \"%d %M\",\n\n\t\ttime_step: 60,\n\t\tduration_step: 1,\n\t\ttask_date: \"%d %F %Y\",\n\t\ttime_picker: \"%H:%i\",\n\t\ttask_attribute: \"data-task-id\",\n\t\tlink_attribute: \"data-link-id\",\n\t\tlayer_attribute: \"data-layer\",\n\t\tbuttons_left: [\n\t\t\t\"gantt_save_btn\",\n\t\t\t\"gantt_cancel_btn\"\n\t\t],\n\t\t_migrate_buttons: {\n\t\t\tdhx_save_btn: \"gantt_save_btn\",\n\t\t\tdhx_cancel_btn: \"gantt_cancel_btn\",\n\t\t\tdhx_delete_btn: \"gantt_delete_btn\"\n\t\t},\n\t\tbuttons_right: [\n\t\t\t\"gantt_delete_btn\"\n\t\t],\n\t\tlightbox: {\n\t\t\tsections: [\n\t\t\t\t{name: \"description\", height: 70, map_to: \"text\", type: \"textarea\", focus: true},\n\t\t\t\t{name: \"time\", type: \"duration\", map_to: \"auto\"}\n\t\t\t],\n\t\t\tproject_sections: [\n\t\t\t\t{name: \"description\", height: 70, map_to: \"text\", type: \"textarea\", focus: true},\n\t\t\t\t{name: \"type\", type: \"typeselect\", map_to: \"type\"},\n\t\t\t\t{name: \"time\", type: \"duration\", readonly: true, map_to: \"auto\"}\n\t\t\t],\n\t\t\tmilestone_sections: [\n\t\t\t\t{name: \"description\", height: 70, map_to: \"text\", type: \"textarea\", focus: true},\n\t\t\t\t{name: \"type\", type: \"typeselect\", map_to: \"type\"},\n\t\t\t\t{name: \"time\", type: \"duration\", single_date: true, map_to: \"auto\"}\n\t\t\t]\n\t\t},\n\t\tdrag_lightbox: true,\n\t\tsort: false,\n\t\tdetails_on_create: true,\n\t\tdetails_on_dblclick: true,\n\t\tinitial_scroll: true,\n\t\ttask_scroll_offset: 100,\n\n\t\torder_branch: false,\n\t\torder_branch_free: false,\n\n\t\t// task height is deprecated, use 'bar_height' instead\n\t\ttask_height: undefined,// number px of 'full' for row height\n\t\tbar_height: \"full\",\n\t\tbar_height_padding:9,\n\t\tmin_column_width: 70,\n\n\t\t// min width for grid column (when resizing)\n\t\tmin_grid_column_width: 70,\n\t\t// name of the attribute with column index for resize element\n\t\tgrid_resizer_column_attribute: \"data-column-index\",\n\t\t// name of the attribute with column index for resize element\n\t\t// grid_resizer_attribute: \"grid_resizer\", // - usage of this parameter is not found in code\n\n\t\t// grid width can be increased after the column has been resized\n\t\tkeep_grid_width: false,\n\n\t\t// grid width can be adjusted\n\t\tgrid_resize: false,\n\t\tgrid_elastic_columns: false,\n\t\tshow_tasks_outside_timescale: false,\n\t\tshow_unscheduled: true,\n\n\t\tresize_rows: false,\n\t\t// name of the attribute with row index for resize element\n\t\ttask_grid_row_resizer_attribute: \"data-row-index\",\n\t\t// min height for row (when resizing)\n\t\tmin_task_grid_row_height: 30,\n\t\trow_height: 36,\n\n\t\t//\n\t\treadonly_property: \"readonly\",\n\t\teditable_property: \"editable\",\n\t\tcalendar_property: \"calendar_id\",\n\t\tresource_calendars: {},\n\t\tdynamic_resource_calendars: false,\n\t\tinherit_calendar: false,\n\t\ttype_renderers: {},\n\n\t\topen_tree_initially: false,\n\t\toptimize_render: true,\n\t\tprevent_default_scroll: false,\n\t\tshow_errors: true,\n\t\twai_aria_attributes: true,\n\t\tsmart_scales: true,\n\t\trtl:false,\n\t\tplaceholder_task: false,\n\t\thorizontal_scroll_key: \"shiftKey\",\n\t\tdrag_timeline: {\n\t\t\tuseKey: undefined,\n\t\t\tignore: \".gantt_task_line, .gantt_task_link\",\n\t\t\trender: false\n\t\t},\n\t\tdrag_multiple: true,\n\t\tcsp: \"auto\"\n\t};\n\treturn result;\n};\n","/* eslint-disable no-restricted-globals */\nvar isWindowAwailable = typeof window !== \"undefined\";\n\n/* eslint-enable no-restricted-globals */\n\nexport default {\n\tisIE: isWindowAwailable && (navigator.userAgent.indexOf(\"MSIE\") >= 0 || navigator.userAgent.indexOf(\"Trident\") >= 0),\n\tisIE6: isWindowAwailable && (!XMLHttpRequest && navigator.userAgent.indexOf(\"MSIE\") >= 0),\n\tisIE7: isWindowAwailable && (navigator.userAgent.indexOf(\"MSIE 7.0\") >= 0 && navigator.userAgent.indexOf(\"Trident\") < 0),\n\tisIE8: isWindowAwailable && (navigator.userAgent.indexOf(\"MSIE 8.0\") >= 0 && navigator.userAgent.indexOf(\"Trident\") >= 0),\n\tisOpera: isWindowAwailable && (navigator.userAgent.indexOf(\"Opera\") >= 0),\n\tisChrome: isWindowAwailable && (navigator.userAgent.indexOf(\"Chrome\") >= 0),\n\tisKHTML: isWindowAwailable && (navigator.userAgent.indexOf(\"Safari\") >= 0 || navigator.userAgent.indexOf(\"Konqueror\") >= 0),\n\tisFF: isWindowAwailable && (navigator.userAgent.indexOf(\"Firefox\") >= 0),\n\tisIPad: isWindowAwailable && (navigator.userAgent.search(/iPad/gi) >= 0),\n\tisEdge: isWindowAwailable && (navigator.userAgent.indexOf(\"Edge\")!=-1),\n\tisNode: (!isWindowAwailable || typeof navigator == \"undefined\" || (typeof PRODUCTION !== \"undefined\" && PRODUCTION === \"test\"))\n};\n","export default function serialize(data: object | string) {\n\tif (typeof data === \"string\" || typeof data === \"number\") {\n\t\treturn data;\n\t}\n\n\tlet result = \"\";\n\n\tfor (const key in data) {\n\t\tlet serialized = \"\";\n\t\tif (data.hasOwnProperty(key)) {\n\t\t\tif (typeof data[key] === \"string\") {\n\t\t\t\tserialized = encodeURIComponent(data[key]);\n\t\t\t} else if (typeof data[key] === \"number\") {\n\t\t\t\tserialized = String(data[key]);\n\t\t\t} else {\n\t\t\t\tserialized = encodeURIComponent(JSON.stringify(data[key]));\n\t\t\t}\n\t\t\tserialized = key + \"=\" + serialized;\n\n\t\t\tif (result.length) {\n\t\t\t\tserialized = \"&\" + serialized;\n\t\t\t}\n\t\t\tresult += serialized;\n\t\t}\n\t}\n\treturn result;\n}\n","import env from \"../../utils/env\";\nimport global from \"../../utils/global\";\nimport serialize from \"./serialize\";\n\nfunction createConfig(method, args) {\n\tvar result = {\n\t\tmethod: method\n\t};\n\n\tif (args.length === 0) {\n\t\tthrow new Error(\"Arguments list of query is wrong.\");\n\t}\n\tif (args.length === 1) {\n\t\tif (typeof args[0] === \"string\") {\n\t\t\tresult.url = args[0];\n\t\t\tresult.async = true;\n\t\t} else {\n\t\t\tresult.url = args[0].url;\n\t\t\tresult.async = (args[0].async || true);\n\t\t\tresult.callback = args[0].callback;\n\t\t\tresult.headers = args[0].headers;\n\t\t}\n\t\tif (method === \"POST\" || \"PUT\") {\n\t\t\tif (args[0].data) {\n\t\t\t\tif (typeof args[0].data !== \"string\") {\n\t\t\t\t\tresult.data = serialize(args[0].data);\n\t\t\t\t} else {\n\t\t\t\t\tresult.data = args[0].data;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult.data = \"\";\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tresult.url = args[0];\n\tswitch(method) {\n\t\tcase \"GET\":\n\t\tcase \"DELETE\":\n\t\t\tresult.callback = args[1];\n\t\t\tresult.headers = args[2];\n\t\tbreak;\n\t\tcase \"POST\":\n\t\tcase \"PUT\":\n\t\t\tif (args[1]) {\n\t\t\t\tif (typeof args[1] !== \"string\") {\n\t\t\t\t\tresult.data = serialize(args[1]);\n\t\t\t\t} else {\n\t\t\t\t\tresult.data = args[1];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult.data = \"\";\n\t\t\t}\n\t\t\tresult.callback = args[2];\n\t\t\tresult.headers = args[3];\n\t\tbreak;\n\t}\n\treturn result;\n}\n\nexport default function(gantt) {\n\treturn {\n\n\t\t// if false - dhxr param will added to prevent caching on client side (default),\n\t\t// if true - do not add extra params\n\t\tcache: true,\n\n\t\t// default method for load/loadStruct, post/get allowed\n\t\t// get - since 4.1.1, this should fix 412 error for macos safari\n\t\tmethod: \"get\",\n\n\t\tparse: function(data) {\n\t\t\tif (typeof data !== \"string\") return data;\n\n\t\t\tvar obj;\n\t\t\tdata = data.replace(/^[\\s]+/,\"\");\n\t\t\tif (typeof DOMParser !== \"undefined\" && !env.isIE) { // ff,ie9\n\t\t\t\tobj = (new DOMParser()).parseFromString(data, \"text/xml\");\n\t\t\t} else if (typeof global.ActiveXObject !== \"undefined\") {\n\t\t\t\tobj = new global.ActiveXObject(\"Microsoft.XMLDOM\");\n\t\t\t\tobj.async = \"false\";\n\t\t\t\tobj.loadXML(data);\n\t\t\t}\n\t\t\treturn obj;\n\t\t},\n\t\txmltop: function(tagname, xhr, obj) {\n\t\t\tif (typeof xhr.status == \"undefined\" || xhr.status < 400) {\n\t\t\t\tvar xml = (!xhr.responseXML) ? this.parse(xhr.responseText || xhr) : (xhr.responseXML || xhr);\n\t\t\t\tif (xml && xml.documentElement !== null && !xml.getElementsByTagName(\"parsererror\").length) {\n\t\t\t\t\treturn xml.getElementsByTagName(tagname)[0];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (obj !== -1) gantt.callEvent(\"onLoadXMLError\",[\"Incorrect XML\", arguments[1], obj]);\n\t\t\treturn document.createElement(\"DIV\");\n\t\t},\n\t\txpath: function(xpathExp, docObj) {\n\t\t\tif (!docObj.nodeName) docObj = docObj.responseXML || docObj;\n\t\t\tif (env.isIE) {\n\t\t\t\treturn docObj.selectNodes(xpathExp)||[];\n\t\t\t} else {\n\t\t\t\tvar rows = [];\n\t\t\t\tvar first;\n\t\t\t\tvar col = (docObj.ownerDocument||docObj).evaluate(xpathExp, docObj, null, XPathResult.ANY_TYPE, null);\n\n\t\t\t\twhile (true){\n\t\t\t\t\tfirst = col.iterateNext();\n\t\t\t\t\tif(first){\n\t\t\t\t\t\trows.push(first);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn rows;\n\t\t\t}\n\t\t},\n\t\tquery: function(config) {\n\t\t\treturn this._call(\n\t\t\t\t(config.method || \"GET\"),\n\t\t\t\tconfig.url,\n\t\t\t\tconfig.data || \"\",\n\t\t\t\t(config.async || true),\n\t\t\t\tconfig.callback,\n\t\t\t\tconfig.headers\n\t\t\t);\n\t\t},\n\t\tget: function(url, onLoad, headers) {\n\t\t\tvar config = createConfig(\"GET\", arguments);\n\t\t\treturn this.query(config);\n\t\t},\n\t\tgetSync: function(url, headers) {\n\t\t\tvar config = createConfig(\"GET\", arguments);\n\t\t\tconfig.async = false;\n\t\t\treturn this.query(config);\n\t\t},\n\t\tput: function(url, postData, onLoad, headers) {\n\t\t\tvar config = createConfig(\"PUT\", arguments);\n\t\t\treturn this.query(config);\n\t\t},\n\t\tdel: function(url, onLoad, headers) {\n\t\t\t/**\n\t\t\t * https://tools.ietf.org/html/rfc7231#section-4.3.5\n\t\t\t * A payload within a DELETE request message has no defined semantics;\n\t\t\t * sending a payload body on a DELETE request might cause some existing\n\t\t\t * implementations to reject the request.\n\t\t\t */\n\t\t\tvar config = createConfig(\"DELETE\", arguments);\n\t\t\treturn this.query(config);\n\t\t},\n\t\tpost: function(url, postData, onLoad, headers) {\n\t\t\tif (arguments.length == 1) {\n\t\t\t\tpostData = \"\";\n\t\t\t} else if (arguments.length == 2 && typeof(postData) == \"function\") {\n\t\t\t\tonLoad = postData;\n\t\t\t\tpostData = \"\";\n\t\t\t}\n\t\t\tvar config = createConfig(\"POST\", arguments);\n\t\t\treturn this.query(config);\n\t\t},\n\t\tpostSync: function(url, postData, headers) {\n\t\t\tpostData = (postData === null ? \"\" : String(postData));\n\n\t\t\tvar config = createConfig(\"POST\", arguments);\n\t\t\tconfig.async = false;\n\t\t\treturn this.query(config);\n\t\t},\n\t\t_call: function(method, url, postData, async, onLoad, headers) {\n\t\t\treturn new gantt.Promise(function(resolve, reject) {\n\t\t\t\tvar t = (typeof XMLHttpRequest !== undefined ? new XMLHttpRequest() : new global.ActiveXObject(\"Microsoft.XMLHTTP\"));\n\t\t\t\tvar isQt = (navigator.userAgent.match(/AppleWebKit/) !== null && navigator.userAgent.match(/Qt/) !== null && navigator.userAgent.match(/Safari/) !== null);\n\n\t\t\t\tif (!!async) {\n\t\t\t\t\tt.onreadystatechange = function() {\n\t\t\t\t\t\tif ((t.readyState == 4) || (isQt && t.readyState == 3)) { // what for long response and status 404?\n\t\t\t\t\t\t\tif (t.status != 200 || t.responseText === \"\")\n\t\t\t\t\t\t\t\tif (!gantt.callEvent(\"onAjaxError\", [t])) return;\n\n\t\t\t\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t\t\t\tif (typeof(onLoad) == \"function\") {\n\t\t\t\t\t\t\t\t\tonLoad.apply(global, [{xmlDoc:t, filePath:url}]); // dhtmlx-compat, response.xmlDoc.responseXML/responseText\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresolve(t);\n\t\t\t\t\t\t\t\tif (typeof(onLoad) == \"function\") {\n\t\t\t\t\t\t\t\t\tonLoad = null;\n\t\t\t\t\t\t\t\t\tt = null;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar noCache = !this || !this.cache;\n\t\t\t\tif (method == \"GET\" && noCache) {\n\t\t\t\t\turl += (url.indexOf(\"?\")>=0?\"&\":\"?\")+\"dhxr\"+new Date().getTime()+\"=1\";\n\t\t\t\t}\n\n\t\t\t\tt.open(method, url, async);\n\n\t\t\t\tif (headers){\n\t\t\t\t\tfor (var key in headers)\n\t\t\t\t\t\tt.setRequestHeader(key, headers[key]);\n\t\t\t\t} else if (method.toUpperCase() == \"POST\" || method == \"PUT\" || method == \"DELETE\") {\n\t\t\t\t\tt.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n\t\t\t\t} else if (method == \"GET\") {\n\t\t\t\t\tpostData = null;\n\t\t\t\t}\n\n\t\t\t\tt.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n\n\t\t\t\tt.send(postData);\n\n\t\t\t\tif (!async) return {xmlDoc:t, filePath:url}; // dhtmlx-compat, response.xmlDoc.responseXML/responseText\n\t\t\t});\n\t\t},\n\t\turlSeparator: function(str){\n\t\t\tif (str.indexOf(\"?\") != -1)\n\t\t\t\treturn \"&\";\n\t\t\telse\n\t\t\t\treturn \"?\";\n\t\t}\n\t};\n};\n","const dateToStr = (format: string, utc: boolean, gantt) => {\n\tformat = format.replace(/%[a-zA-Z]/g, (a) => {\n\t\tswitch (a) {\n\t\t\tcase \"%d\":\n\t\t\t\treturn `\"+to_fixed(date.get${utc?\"UTC\":\"\"}Date())+\"`;\n\t\t\tcase \"%m\":\n\t\t\t\treturn `\"+to_fixed((date.get${utc?\"UTC\":\"\"}Month()+1))+\"`;\n\t\t\tcase \"%j\":\n\t\t\t\treturn `\"+date.get${utc?\"UTC\":\"\"}Date()+\"`;\n\t\t\tcase \"%n\":\n\t\t\t\treturn `\"+(date.get${utc?\"UTC\":\"\"}Month()+1)+\"`;\n\t\t\tcase \"%y\":\n\t\t\t\treturn `\"+to_fixed(date.get${utc?\"UTC\":\"\"}FullYear()%100)+\"`;\n\t\t\tcase \"%Y\":\n\t\t\t\treturn `\"+date.get${utc?\"UTC\":\"\"}FullYear()+\"`;\n\t\t\tcase \"%D\":\n\t\t\t\treturn `\"+locale.date.day_short[date.get${utc?\"UTC\":\"\"}Day()]+\"`;\n\t\t\tcase \"%l\":\n\t\t\t\treturn `\"+locale.date.day_full[date.get${utc?\"UTC\":\"\"}Day()]+\"`;\n\t\t\tcase \"%M\":\n\t\t\t\treturn `\"+locale.date.month_short[date.get${utc?\"UTC\":\"\"}Month()]+\"`;\n\t\t\tcase \"%F\":\n\t\t\t\treturn `\"+locale.date.month_full[date.get${utc?\"UTC\":\"\"}Month()]+\"`;\n\t\t\tcase \"%h\":\n\t\t\t\treturn `\"+to_fixed((date.get${utc?\"UTC\":\"\"}Hours()+11)%12+1)+\"`;\n\t\t\tcase \"%g\":\n\t\t\t\treturn `\"+((date.get${utc?\"UTC\":\"\"}Hours()+11)%12+1)+\"`;\n\t\t\tcase \"%G\":\n\t\t\t\treturn `\"+date.get${utc?\"UTC\":\"\"}Hours()+\"`;\n\t\t\tcase \"%H\":\n\t\t\t\treturn `\"+to_fixed(date.get${utc?\"UTC\":\"\"}Hours())+\"`;\n\t\t\tcase \"%i\":\n\t\t\t\treturn `\"+to_fixed(date.get${utc?\"UTC\":\"\"}Minutes())+\"`;\n\t\t\tcase \"%a\":\n\t\t\t\treturn `\"+(date.get${utc?\"UTC\":\"\"}Hours()>11?\"pm\":\"am\")+\"`;\n\t\t\tcase \"%A\":\n\t\t\t\treturn `\"+(date.get${utc?\"UTC\":\"\"}Hours()>11?\"PM\":\"AM\")+\"`;\n\t\t\tcase \"%s\":\n\t\t\t\treturn `\"+to_fixed(date.get${utc?\"UTC\":\"\"}Seconds())+\"`;\n\t\t\tcase \"%W\":\n\t\t\t\treturn `\"+to_fixed(getISOWeek(date))+\"`;\n\t\t\tcase \"%w\":\n\t\t\t\treturn `\"+to_fixed(getWeek(date))+\"`;\n\t\t\tdefault:\n\t\t\t\treturn a;\n\t\t}\n\t});\n\n\t// tslint:disable-next-line: function-constructor\n\tconst dateToStrFn = new Function(\"date\", \"to_fixed\", \"locale\", \"getISOWeek\", \"getWeek\", `return \"${format}\";`);\n\n\treturn (date: Date) => {\n\t\treturn dateToStrFn(date, gantt.date.to_fixed, gantt.locale, gantt.date.getISOWeek, gantt.date.getWeek);\n\t};\n};\n\n\nconst strToDate = (format: string, utc: boolean, gantt:any) => {\n\tlet splt = \"var temp=date.match(/[a-zA-Z]+|[0-9]+/g);\";\n\tconst mask = format.match(/%[a-zA-Z]/g);\n\tfor (let i = 0; i < mask.length; i++) {\n\t\tswitch (mask[i]) {\n\t\t\tcase \"%j\":\n\t\t\tcase \"%d\":\n\t\t\t\tsplt += `set[2]=temp[${i}]||1;`;\n\t\t\t\tbreak;\n\t\t\tcase \"%n\":\n\t\t\tcase \"%m\":\n\t\t\t\tsplt += `set[1]=(temp[${i}]||1)-1;`;\n\t\t\t\tbreak;\n\t\t\tcase \"%y\":\n\t\t\t\tsplt += `set[0]=temp[${i}]*1+(temp[${i}]>50?1900:2000);`;\n\t\t\t\tbreak;\n\t\t\tcase \"%g\":\n\t\t\tcase \"%G\":\n\t\t\tcase \"%h\":\n\t\t\tcase \"%H\":\n\t\t\t\tsplt += `set[3]=temp[${i}]||0;`;\n\t\t\t\tbreak;\n\t\t\tcase \"%i\":\n\t\t\t\tsplt += `set[4]=temp[${i}]||0;`;\n\t\t\t\tbreak;\n\t\t\tcase \"%Y\":\n\t\t\t\tsplt += `set[0]=temp[${i}]||0;`;\n\t\t\t\tbreak;\n\t\t\tcase \"%a\":\n\t\t\tcase \"%A\":\n\t\t\t\tsplt += `set[3]=set[3]%12+((temp[${i}]||'').toLowerCase()=='am'?0:12);`;\n\t\t\t\tbreak;\n\t\t\tcase \"%s\":\n\t\t\t\tsplt += `set[5]=temp[${i}]||0;`;\n\t\t\t\tbreak;\n\t\t\tcase \"%M\":\n\t\t\t\tsplt += `set[1]=locale.date.month_short_hash[temp[${i}]]||0;`;\n\t\t\t\tbreak;\n\t\t\tcase \"%F\":\n\t\t\t\tsplt += `set[1]=locale.date.month_full_hash[temp[${i}]]||0;`;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tlet code = \"set[0],set[1],set[2],set[3],set[4],set[5]\";\n\tif (utc) { code = ` Date.UTC(${code})`; }\n\t// tslint:disable-next-line: function-constructor\n\tconst strToDateFn = new Function(\"date\", \"locale\", `var set=[0,0,1,0,0,0]; ${splt} return new Date(${code});`);\n\n\treturn (dateString) => {\n\t\treturn strToDateFn(dateString, gantt.locale);\n\t};\n};\n\nconst fastVersion = {\n\tdate_to_str: dateToStr,\n\tstr_to_date: strToDate\n};\n\nexport default fastVersion;","const dateToStr = (format: string, utc: boolean, gantt) => {\n\treturn (date) => {\n\t\treturn format.replace(/%[a-zA-Z]/g, (a) => {\n\t\t\tswitch (a) {\n\t\t\t\tcase \"%d\": return utc ? gantt.date.to_fixed(date.getUTCDate()) : gantt.date.to_fixed(date.getDate());\n\t\t\t\tcase \"%m\": return utc ? gantt.date.to_fixed((date.getUTCMonth() + 1)) : gantt.date.to_fixed((date.getMonth() + 1));\n\t\t\t\tcase \"%j\": return utc ? date.getUTCDate() : date.getDate();\n\t\t\t\tcase \"%n\": return utc ? (date.getUTCMonth() + 1) : (date.getMonth() + 1);\n\t\t\t\tcase \"%y\": return utc ? gantt.date.to_fixed(date.getUTCFullYear() % 100) : gantt.date.to_fixed(date.getFullYear() % 100);\n\t\t\t\tcase \"%Y\": return utc ? date.getUTCFullYear() : date.getFullYear();\n\t\t\t\tcase \"%D\": return utc ? gantt.locale.date.day_short[date.getUTCDay()] : gantt.locale.date.day_short[date.getDay()];\n\t\t\t\tcase \"%l\": return utc ? gantt.locale.date.day_full[date.getUTCDay()] : gantt.locale.date.day_full[date.getDay()];\n\t\t\t\tcase \"%M\": return utc ? gantt.locale.date.month_short[date.getUTCMonth()] : gantt.locale.date.month_short[date.getMonth()];\n\t\t\t\tcase \"%F\": return utc ? gantt.locale.date.month_full[date.getUTCMonth()] : gantt.locale.date.month_full[date.getMonth()];\n\t\t\t\tcase \"%h\": return utc ? gantt.date.to_fixed((date.getUTCHours() + 11) % 12 + 1) : gantt.date.to_fixed((date.getHours() + 11) % 12 + 1);\n\t\t\t\tcase \"%g\": return utc ? ((date.getUTCHours() + 11) % 12 + 1) : ((date.getHours() + 11) % 12 + 1);\n\t\t\t\tcase \"%G\": return utc ? date.getUTCHours() : date.getHours();\n\t\t\t\tcase \"%H\": return utc ? gantt.date.to_fixed(date.getUTCHours()) : gantt.date.to_fixed(date.getHours());\n\t\t\t\tcase \"%i\": return utc ? gantt.date.to_fixed(date.getUTCMinutes()) : gantt.date.to_fixed(date.getMinutes());\n\t\t\t\tcase \"%a\": return utc ? (date.getUTCHours() > 11 ? \"pm\" : \"am\") : (date.getHours() > 11 ? \"pm\" : \"am\");\n\t\t\t\tcase \"%A\": return utc ? (date.getUTCHours() > 11 ? \"PM\" : \"AM\") : (date.getHours() > 11 ? \"PM\" : \"AM\");\n\t\t\t\tcase \"%s\": return utc ? gantt.date.to_fixed(date.getUTCSeconds()) : gantt.date.to_fixed(date.getSeconds());\n\t\t\t\tcase \"%W\": return utc ? gantt.date.to_fixed(gantt.date.getUTCISOWeek(date)) : gantt.date.to_fixed(gantt.date.getISOWeek(date));\n\t\t\t\tdefault: return a;\n\t\t\t}\n\t\t});\n\t};\n};\nconst strToDate = (format: string, utc: boolean, gantt:any) => {\n\treturn (date: string) => {\n\t\tconst set: Array = [0, 0, 1, 0, 0, 0];\n\t\tconst temp = date.match(/[a-zA-Z]+|[0-9]+/g);\n\t\tconst mask = format.match(/%[a-zA-Z]/g);\n\n\t\tfor (let i = 0; i < mask.length; i++) {\n\t\t\tswitch (mask[i]) {\n\t\t\t\tcase \"%j\":\n\t\t\t\tcase \"%d\":\n\t\t\t\t\tset[2] = temp[i] as unknown as number || 1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%n\":\n\t\t\t\tcase \"%m\":\n\t\t\t\t\tset[1] = (temp[i] as unknown as number || 1) - 1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%y\":\n\t\t\t\t\tset[0] = temp[i] as unknown as number * 1 + ((temp[i] as unknown as number) > 50 ? 1900 : 2000);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%g\":\n\t\t\t\tcase \"%G\":\n\t\t\t\tcase \"%h\":\n\t\t\t\tcase \"%H\":\n\t\t\t\t\tset[3] = temp[i] as unknown as number || 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%i\":\n\t\t\t\t\tset[4] = temp[i] as unknown as number || 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%Y\":\n\t\t\t\t\tset[0] = temp[i] as unknown as number || 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%a\":\n\t\t\t\tcase \"%A\":\n\t\t\t\t\tset[3] = set[3] as number % 12 + ((temp[i] || \"\").toLowerCase() === \"am\" ? 0 : 12);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%s\":\n\t\t\t\t\tset[5] = temp[i] || 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%M\":\n\t\t\t\t\tset[1] = gantt.locale.date.month_short_hash[temp[i]] || 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%F\":\n\t\t\t\t\tset[1] = gantt.locale.date.month_full_hash[temp[i]] || 0;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (utc) {\n\t\t\treturn new Date(Date.UTC(\n\t\t\t\tset[0] as number,\n\t\t\t\tset[1] as number,\n\t\t\t\tset[2] as number,\n\t\t\t\tset[3] as number,\n\t\t\t\tset[4] as number,\n\t\t\t\tset[5] as number\n\t\t\t));\n\t\t}\n\t\treturn new Date(\n\t\t\tset[0] as number,\n\t\t\tset[1] as number,\n\t\t\tset[2] as number,\n\t\t\tset[3] as number,\n\t\t\tset[4] as number,\n\t\t\tset[5] as number\n\t\t);\n\t};\n\n};\n\n\nconst cspVersion = {\n\tdate_to_str: dateToStr,\n\tstr_to_date: strToDate\n};\n\nexport default cspVersion;","/*\n %d - the day as a number with a leading zero ( 01 to 31 );\n %j - the day as a number without a leading zero ( 1 to 31 );\n %D - the day as an abbreviation ( Sun to Sat );\n %l - the day as a full name ( Sunday to Saturday );\n %W - the ISO-8601 week number of the year. Weeks start on Monday; 1)\n %m - the month as a number without a leading zero ( 1 to 12 );\n %n - the month as a number with a leading zero ( 01 to 12);\n %M - the month as an abbreviation ( Jan to Dec );\n %F - the month as a full name ( January to December );\n %y - the year as a two-digit number ( 00 to 99 );\n %Y - the year as a four-digit number ( 1900–9999 );\n %h - the hour based on the 12-hour clock ( 00 to 11 );\n %H - the hour based on the 24-hour clock ( 00 to 23 );\n %i - the minute as a number with a leading zero ( 00 to 59 );\n %s - the second as a number without a leading zero ( 00 to 59 ); 2)\n %a - displays am (for times from midnight until noon) and pm (for times from noon until midnight);\n %A - displays AM (for times from midnight until noon) and PM (for times from noon until midnight).\n*/\n\nimport fastVersion from \"./date_parsers/fast_version\";\nimport cspCompliantVersion from \"./date_parsers/csp_compliant_version\";\n\nexport default function(gantt) {\n\tvar canUseCsp = null;\n\tfunction cspAutoCheck() {\n\t\ttry {\n\t\t\tnew Function(\"canUseCsp = false;\");\n\t\t} catch(e) {\n\t\t\tcanUseCsp = true;\n\t\t}\n\t}\n\tfunction useCsp() {\n\t\tvar result = false;\n\t\tif (gantt.config.csp === \"auto\") {\n\t\t\tif(canUseCsp === null) {\n\t\t\t\tcspAutoCheck();\n\t\t\t}\n\t\t\tresult = canUseCsp;\n\t\t} else {\n\t\t\tresult = gantt.config.csp;\n\t\t}\n\t\treturn result;\n\t}\n\n\tvar dateHelper = {\n\t\tinit: function () {\n\t\t\tvar locale = gantt.locale;\n\n\t\t\tvar s = locale.date.month_short;\n\t\t\tvar t = locale.date.month_short_hash = {};\n\t\t\tfor (var i = 0; i < s.length; i++)\n\t\t\t\tt[s[i]] = i;\n\n\t\t\tvar s = locale.date.month_full;\n\t\t\tvar t = locale.date.month_full_hash = {};\n\t\t\tfor (var i = 0; i < s.length; i++)\n\t\t\t\tt[s[i]] = i;\n\t\t},\n\t\tdate_part: function (date) {\n\t\t\tvar old = new Date(date);\n\t\t\tdate.setHours(0);\n\t\t\tthis.hour_start(date);\n\t\t\tif (date.getHours() && //shift to yesterday on dst\n\t\t\t\t(date.getDate() < old.getDate() || date.getMonth() < old.getMonth() || date.getFullYear() < old.getFullYear()))\n\t\t\t\tdate.setTime(date.getTime() + 60 * 60 * 1000 * (24 - date.getHours()));\n\t\t\treturn date;\n\t\t},\n\t\ttime_part: function (date) {\n\t\t\treturn (date.valueOf() / 1000 - date.getTimezoneOffset() * 60) % 86400;\n\t\t},\n\t\tweek_start: function (date) {\n\t\t\tvar shift = date.getDay();\n\t\t\tif (gantt.config.start_on_monday) {\n\t\t\t\tif (shift === 0) shift = 6;\n\t\t\t\telse shift--;\n\t\t\t}\n\t\t\treturn this.date_part(this.add(date, -1 * shift, \"day\"));\n\t\t},\n\t\tmonth_start: function (date) {\n\t\t\tdate.setDate(1);\n\t\t\treturn this.date_part(date);\n\t\t},\n\t\tquarter_start: function (date) {\n\t\t\tthis.month_start(date);\n\t\t\tvar m = date.getMonth(),\n\t\t\t\tres_month;\n\n\t\t\tif (m >= 9) {\n\t\t\t\tres_month = 9;\n\t\t\t} else if (m >= 6) {\n\t\t\t\tres_month = 6;\n\t\t\t} else if (m >= 3) {\n\t\t\t\tres_month = 3;\n\t\t\t} else {\n\t\t\t\tres_month = 0;\n\t\t\t}\n\n\t\t\tdate.setMonth(res_month);\n\t\t\treturn date;\n\t\t},\n\t\tyear_start: function (date) {\n\t\t\tdate.setMonth(0);\n\t\t\treturn this.month_start(date);\n\t\t},\n\t\tday_start: function (date) {\n\t\t\treturn this.date_part(date);\n\t\t},\n\t\thour_start: function (date) {\n\t\t\tif (date.getMinutes())\n\t\t\t\tdate.setMinutes(0);\n\t\t\tthis.minute_start(date);\n\n\t\t\treturn date;\n\t\t},\n\t\tminute_start: function (date) {\n\t\t\tif (date.getSeconds())\n\t\t\t\tdate.setSeconds(0);\n\t\t\tif (date.getMilliseconds())\n\t\t\t\tdate.setMilliseconds(0);\n\t\t\treturn date;\n\t\t},\n\t\t_add_days: function (modifiedDate, inc, originalDate) {\n\n\t\t\tmodifiedDate.setDate(modifiedDate.getDate() + inc);\n\t\t\tvar incCondition = inc >= 0;\n\t\t\tvar getHoursCondition = !originalDate.getHours() && modifiedDate.getHours(); //shift to yesterday on dst\n\t\t\tvar getDateCondition = (modifiedDate.getDate() <= originalDate.getDate() || modifiedDate.getMonth() < originalDate.getMonth() || modifiedDate.getFullYear() < originalDate.getFullYear());\n\t\t\tif (incCondition && getHoursCondition && getDateCondition){\n\t\t\t\tmodifiedDate.setTime(modifiedDate.getTime() + 60 * 60 * 1000 * (24 - modifiedDate.getHours()));\n\t\t\t}\n\t\t\tvar worktimeCalculation = inc > 1;\n\t\t\tif (worktimeCalculation && getHoursCondition){\n\t\t\t\t// try to shift the modified Date to 00:00\n\t\t\t\tmodifiedDate.setHours(0);\n\t\t\t}\n\t\t\treturn modifiedDate;\n\t\t},\n\n\t\tadd: function (date, inc, mode) {\n\t\t\t/*jsl:ignore*/\n\t\t\tvar ndate = new Date(date.valueOf());\n\t\t\tswitch (mode) {\n\t\t\t\tcase \"day\":\n\t\t\t\t\tndate = this._add_days(ndate, inc, date);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"week\":\n\t\t\t\t\tndate = this._add_days(ndate, inc * 7, date);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"month\":\n\t\t\t\t\tndate.setMonth(ndate.getMonth() + inc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"year\":\n\t\t\t\t\tndate.setYear(ndate.getFullYear() + inc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"hour\":\n\t\t\t\t\t/*\n\t\t\t\t\t\tadding hours/minutes via setHour(getHour() + inc) gives weird result when\n\t\t\t\t\t\tadding one hour to the time before switch to a Daylight Saving time\n\n\t\t\t\t\t\texample: //Sun Mar 30 2014 01:00:00 GMT+0100 (W. Europe Standard Time)\n\t\t\t\t\t\tnew Date(2014, 02, 30, 1).setHours(2)\n\t\t\t\t\t\t>>Sun Mar 30 2014 01:00:00 GMT+0100 (W. Europe Standard Time)\n\n\t\t\t\t\t\tsetTime seems working as expected\n\t\t\t\t\t */\n\t\t\t\t\tndate.setTime(ndate.getTime() + inc * 60 * 60 * 1000);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"minute\":\n\n\t\t\t\t\tndate.setTime(ndate.getTime() + inc * 60 * 1000);\n\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn this[\"add_\" + mode](date, inc, mode);\n\t\t\t}\n\t\t\treturn ndate;\n\t\t\t/*jsl:end*/\n\t\t},\n\t\tadd_quarter: function (date, inc) {\n\t\t\treturn this.add(date, inc * 3, \"month\");\n\t\t},\n\n\t\tto_fixed: function (num) {\n\t\t\tif (num < 10) return \"0\" + num;\n\t\t\treturn num;\n\t\t},\n\t\tcopy: function (date) {\n\t\t\treturn new Date(date.valueOf());\n\t\t},\n\t\tdate_to_str: function (format, utc) {\n\t\t\tvar result = fastVersion;\n\t\t\tif (useCsp()) {\n\t\t\t\tresult = cspCompliantVersion;\n\t\t\t}\n\t\t\treturn result.date_to_str(format, utc, gantt);\n\t\t},\n\t\tstr_to_date: function (format, utc) {\n\t\t\tvar result = fastVersion;\n\t\t\tif (useCsp()) {\n\t\t\t\tresult = cspCompliantVersion;\n\t\t\t}\n\t\t\treturn result.str_to_date(format, utc, gantt);\n\t\t},\n\t\tgetISOWeek: function (ndate) {\n\t\t\treturn gantt.date._getWeekNumber(ndate, true);\n\t\t},\n\t\t_getWeekNumber: function(ndate, isoWeek){\n\t\t\tif (!ndate) return false;\n\t\t\tvar nday = ndate.getDay();\n\t\t\tif(isoWeek){\n\t\t\t\tif (nday === 0) {\n\t\t\t\t\tnday = 7;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar first_thursday = new Date(ndate.valueOf());\n\t\t\tfirst_thursday.setDate(ndate.getDate() + (4 - nday));\n\t\t\tvar year_number = first_thursday.getFullYear(); // year of the first Thursday\n\t\t\tvar ordinal_date = Math.round((first_thursday.getTime() - new Date(year_number, 0, 1).getTime()) / 86400000); //ordinal date of the first Thursday - 1 (so not really ordinal date)\n\t\t\tvar week_number = 1 + Math.floor(ordinal_date / 7);\n\t\t\treturn week_number;\n\t\t},\n\n\t\tgetWeek: function(ndate){\n\t\t\treturn gantt.date._getWeekNumber(ndate, gantt.config.start_on_monday);\n\t\t},\n\t\tgetUTCISOWeek: function (ndate) {\n\t\t\treturn gantt.date.getISOWeek(ndate);\n\t\t},\n\t\tconvert_to_utc: function (date) {\n\t\t\treturn new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());\n\t\t},\n\t\tparseDate: function (date, format) {\n\t\t\t// raw date may be of type string, number (timestamp) or something else\n\t\t\t// do not check for instanceof Date explicitly, since we may swap native date with different date implementation at some point\n\t\t\tif (date && !date.getFullYear) {\n\t\t\t\tif (typeof(format) !== \"function\") {\n\t\t\t\t\tif (typeof(format) === \"string\") {\n\t\t\t\t\t\tif (format === \"parse_date\" || format === \"xml_date\") {\n\t\t\t\t\t\t\tformat = gantt.defined(gantt.templates.xml_date) ? gantt.templates.xml_date : gantt.templates.parse_date;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tformat = gantt.defined(gantt.templates[format]) ? gantt.templates[format] : gantt.date.str_to_date(format);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tformat = gantt.defined(gantt.templates.xml_date) ? gantt.templates.xml_date : gantt.templates.parse_date;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (date) {\n\t\t\t\t\tdate = format(date);\n\t\t\t\t} else {\n\t\t\t\t\tdate = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn date;\n\t\t}\n\t};\n\treturn dateHelper;\n};","class t{constructor(t){const{url:e,token:s}=t;this._url=e,this._token=s,this._mode=1,this._seed=1,this._queue=[],this.data={},this.api={},this._events={}}headers(){return{Accept:\"application/json\",\"Content-Type\":\"application/json\",\"Remote-Token\":this._token}}fetch(t,e){const s={credentials:\"include\",headers:this.headers()};return e&&(s.method=\"POST\",s.body=e),fetch(t,s).then(t=>t.json())}load(t){return t&&(this._url=t),this.fetch(this._url).then(t=>this.parse(t))}parse(t){const{key:e,websocket:s}=t;e&&(this._token=t.key);for(const e in t.data)this.data[e]=t.data[e];for(const e in t.api){const s=this.api[e]={},i=t.api[e];for(const t in i)s[t]=this._wrapper(e+\".\"+t)}return s&&this.connect(),this}connect(){const t=this._socket;t&&(this._socket=null,t.onclose=function(){},t.close()),this._mode=2,this._socket=function(t,e,s,i){let n=e;\"/\"===n[0]&&(n=document.location.protocol+\"//\"+document.location.host+e);n=n.replace(/^http(s|):/,\"ws$1:\");const o=-1!=n.indexOf(\"?\")?\"&\":\"?\";n=`${n}${o}token=${s}&ws=1`;const r=new WebSocket(n);return r.onclose=()=>setTimeout(()=>t.connect(),2e3),r.onmessage=e=>{const s=JSON.parse(e.data);switch(s.action){case\"result\":t.result(s.body,[]);break;case\"event\":t.fire(s.body.name,s.body.value);break;case\"start\":i();break;default:t.onError(s.data)}},r}(this,this._url,this._token,()=>(this._mode=3,this._send(),this._resubscribe(),this))}_wrapper(t){return function(){const e=[].slice.call(arguments);let s=null;const i=new Promise((i,n)=>{s={data:{id:this._uid(),name:t,args:e},status:1,resolve:i,reject:n},this._queue.push(s)});return this.onCall(s,i),3===this._mode?this._send(s):setTimeout(()=>this._send(),1),i}.bind(this)}_uid(){return(this._seed++).toString()}_send(t){if(2==this._mode)return void setTimeout(()=>this._send(),100);const e=t?[t]:this._queue.filter(t=>1===t.status);if(!e.length)return;const s=e.map(t=>(t.status=2,t.data));3!==this._mode?this.fetch(this._url,JSON.stringify(s)).catch(t=>this.onError(t)).then(t=>this.result(t,s)):this._socket.send(JSON.stringify({action:\"call\",body:s}))}result(t,e){const s={};if(t)for(let e=0;e=0;t--){const e=this._queue[t],i=s[e.data.id];i&&(this.onResponse(e,i),i.error?e.reject(i.error):e.resolve(i.data),this._queue.splice(t,1))}}on(t,e){const s=this._uid();let i=this._events[t];const n=!!i;return n||(i=this._events[t]=[]),i.push({id:s,handler:e}),n||3!=this._mode||this._socket.send(JSON.stringify({action:\"subscribe\",name:t})),{name:t,id:s}}_resubscribe(){if(3==this._mode)for(const t in this._events)this._socket.send(JSON.stringify({action:\"subscribe\",name:t}))}detach(t){if(!t){if(3==this._mode)for(const t in this._events)this._socket.send(JSON.stringify({action:\"unsubscribe\",key:t}));return void(this._events={})}const{id:e,name:s}=t,i=this._events[s];if(i){const t=i.filter(t=>t.id!=e);t.length?this._events[s]=t:(delete this._events[s],3==this._mode&&this._socket.send(JSON.stringify({action:\"unsubscribe\",name:s})))}}fire(t,e){const s=this._events[t];if(s)for(let t=0;t res.json());\n };\n\n this._ready = remote.load().then((back) => (this._remote = back));\n\n function ready() {\n return this._ready;\n }\n \n function on(name, handler) {\n this.ready().then((back) => {\n if (typeof name === \"string\") back.on(name, handler);\n else {\n for (const key in name) {\n back.on(key, name[key]);\n }\n }\n });\n }\n\n this.ready = ready;\n this.on = on;\n };\n\n","function checkTimeout(host, updPerSecond){\n\tif (!updPerSecond)\n\t\treturn true;\n\t\n\tif (host._on_timeout)\n\t\treturn false;\n\t\n\tvar timeout = Math.ceil(1000/updPerSecond);\n\tif (timeout < 2) return true;\n\n\tsetTimeout(function(){\n\t\tdelete host._on_timeout;\n\t}, timeout);\n\n\thost._on_timeout = true;\n\treturn true;\n}\n\nexport default checkTimeout;","import * as utils from \"../../utils/utils\";\n\nvar StateService = (function(){\n\tvar stateProviders = {};\n\n\tfunction getState(name){\n\t\tvar provider = stateProviders[name];\n\t\tif(provider){\n\t\t\treturn stateProviders[name].method();\n\t\t}else{\n\t\t\tvar res = {};\n\t\t\tfor(var i in stateProviders){\n\t\t\t\tif(!stateProviders[i].internal)\n\t\t\t\t\tutils.mixin(res, stateProviders[i].method(), true);\n\t\t\t}\n\t\t\treturn res;\n\t\t}\n\t}\n\n\tfunction registerProvider(name, provider, internal){\n\t\tstateProviders[name] = { method: provider, internal: internal};\n\t}\n\n\tfunction unregisterProvider(name){\n\t\tdelete stateProviders[name];\n\t}\n\n\treturn {\n\t\tgetState: getState,\n\t\tregisterProvider: registerProvider,\n\t\tunregisterProvider: unregisterProvider\n\t};\n});\n\nexport default StateService;\n\n","// eslint-disable-next-line no-restricted-globals\nexport default Promise;","import * as utils from \"../../utils/utils\";\nimport {replaceValidZeroId} from \"../../utils/helpers\";\n\nvar createTasksDatastoreFacade = function(){\n\treturn {\n\tgetTask: function (id) {\n\t\tid = replaceValidZeroId(id, this.config.root_id);\n\t\tthis.assert(id, \"Invalid argument for gantt.getTask\");\n\t\tvar task = this.$data.tasksStore.getItem(id);\n\t\tthis.assert(task, \"Task not found id=\" + id);\n\t\treturn task;\n\t},\n\tgetTaskByTime: function (from, to) {\n\t\tvar p = this.$data.tasksStore.getItems();\n\n\t\tvar res = [];\n\n\t\tif (!(from || to)) {\n\t\t\tres = p;\n\t\t} else {\n\t\t\tfrom = +from || -Infinity;\n\t\t\tto = +to || Infinity;\n\t\t\tfor (var t = 0; t < p.length; t++){\n\t\t\t\tvar task = p[t];\n\t\t\t\tif (+task.start_date < to && +task.end_date > from)\n\t\t\t\t\tres.push(task);\n\t\t\t}\n\t\t}\n\t\treturn res;\n\t},\n\tisTaskExists: function (id) {\n\t\tif(!this.$data || !this.$data.tasksStore){\n\t\t\treturn false;\n\t\t}\n\t\treturn this.$data.tasksStore.exists(id);\n\t},\n\tupdateTask: function (id, item) {\n\t\tif (!utils.defined(item)) item = this.getTask(id);\n\t\tthis.$data.tasksStore.updateItem(id, item);\n\t\tif(this.isTaskExists(id))\n\t\t\tthis.refreshTask(id);\n\t},\n\taddTask: function (item, parent, index) {\n\t\tif (!utils.defined(item.id))\n\t\t\titem.id = utils.uid();\n\n\t\t//GS-761: assert unique ID\n\t\tif (this.isTaskExists(item.id)){\n\t\t\tvar task = this.getTask(item.id);\n\t\t\tif (task.$index != item.$index) {\n\t\t\t\t// Someone may try to mistakenly add a task with the same ID, and most likely\n\t\t\t\t// use the string format for the dates. Gantt shouldn't break in this scenario\n\t\t\t\tif (item.start_date && typeof item.start_date === \"string\"){\n\t\t\t\t\titem.start_date = this.date.parseDate(item.start_date, \"parse_date\");\n\t\t\t\t}\n\t\t\t\tif (item.end_date && typeof item.end_date === \"string\"){\n\t\t\t\t\titem.end_date = this.date.parseDate(item.end_date, \"parse_date\");\n\t\t\t\t}\n\n\t\t\t\treturn this.$data.tasksStore.updateItem(item.id, item);\n\t\t\t}\n\t\t}\n\n\n\t\tif (!utils.defined(parent)) parent = this.getParent(item) || 0;\n\t\tif (!this.isTaskExists(parent)) parent = this.config.root_id;\n\t\tthis.setParent(item, parent);\n\n\t\t// GS-1583. Save the $open state to the Undo Stack\n\t\tif (this.getState().lightbox && this.isTaskExists(parent)) {\n\t\t\tvar parentObj = this.getTask(parent);\n\t\t\tthis.callEvent(\"onAfterParentExpand\", [parent, parentObj]);\n\t\t}\n\t\treturn this.$data.tasksStore.addItem(item, index, parent);\n\t},\n\tdeleteTask: function (id) {\n\t\tid = replaceValidZeroId(id, this.config.root_id);\n\t\treturn this.$data.tasksStore.removeItem(id);\n\t},\n\tgetTaskCount: function () {\n\t\treturn this.$data.tasksStore.count();\n\t},\n\tgetVisibleTaskCount: function () {\n\t\treturn this.$data.tasksStore.countVisible();\n\t},\n\tgetTaskIndex: function (id) {\n\t\treturn this.$data.tasksStore.getBranchIndex(id);\n\t},\n\tgetGlobalTaskIndex: function (id) {\n\t\tid = replaceValidZeroId(id, this.config.root_id);\n\t\tthis.assert(id, \"Invalid argument\");\n\t\treturn this.$data.tasksStore.getIndexById(id);\n\t},\n\teachTask: function (code, parent, master) {\n\t\treturn this.$data.tasksStore.eachItem(utils.bind(code, master||this), parent);\n\t},\n\teachParent: function (callback, startTask, master) {\n\t\treturn this.$data.tasksStore.eachParent(utils.bind(callback, master || this), startTask);\n\t},\n\tchangeTaskId: function (oldid, newid) {\n\t\tthis.$data.tasksStore.changeId(oldid, newid);\n\t\tvar task = this.$data.tasksStore.getItem(newid);\n\n\t\tvar links = [];\n\n\t\tif (task.$source) {\n\t\t\tlinks = links.concat(task.$source);\n\t\t}\n\t\tif (task.$target) {\n\t\t\tlinks = links.concat(task.$target);\n\t\t}\n\n\t\tfor (var i = 0; i < links.length; i++) {\n\t\t\tvar link = this.getLink(links[i]);\n\t\t\tif (link.source == oldid) {\n\t\t\t\tlink.source = newid;\n\t\t\t}\n\t\t\tif (link.target == oldid) {\n\t\t\t\tlink.target = newid;\n\t\t\t}\n\t\t}\n\t},\n\tcalculateTaskLevel: function (item) {\n\t\treturn this.$data.tasksStore.calculateItemLevel(item);\n\t},\n\tgetNext: function (id) {\n\t\treturn this.$data.tasksStore.getNext(id);\n\t},\n\tgetPrev: function (id) {\n\t\treturn this.$data.tasksStore.getPrev(id);\n\t},\n\tgetParent: function (id) {\n\t\treturn this.$data.tasksStore.getParent(id);\n\t},\n\tsetParent: function (task, new_pid, silent) {\n\t\treturn this.$data.tasksStore.setParent(task, new_pid, silent);\n\t},\n\tgetSiblings: function (id) {\n\t\treturn this.$data.tasksStore.getSiblings(id).slice();\n\t},\n\tgetNextSibling: function (id) {\n\t\treturn this.$data.tasksStore.getNextSibling(id);\n\t},\n\tgetPrevSibling: function (id) {\n\t\treturn this.$data.tasksStore.getPrevSibling(id);\n\t},\n\tgetTaskByIndex: function(index){\n\t\tvar id = this.$data.tasksStore.getIdByIndex(index);\n\t\tif(this.isTaskExists(id)){\n\t\t\treturn this.getTask(id);\n\t\t}else{\n\t\t\treturn null;\n\t\t}\n\t},\n\tgetChildren: function (id) {\n\t\tif(!this.hasChild(id)){\n\t\t\treturn [];\n\t\t}else{\n\t\t\treturn this.$data.tasksStore.getChildren(id).slice();\n\t\t}\n\t},\n\thasChild: function (id) {\n\t\treturn this.$data.tasksStore.hasChild(id);\n\t},\n\topen: function (id) {\n\t\tthis.$data.tasksStore.open(id);\n\t},\n\tclose: function (id) {\n\t\tthis.$data.tasksStore.close(id);\n\t},\n\tmoveTask: function (sid, tindex, parent) {\n\t\tparent = replaceValidZeroId(parent, this.config.root_id);\n\t\treturn this.$data.tasksStore.move.apply(this.$data.tasksStore, arguments);\n\t},\n\tsort: function(field, desc, parent, silent) {\n\t\tvar render = !silent;//4th argument to cancel redraw after sorting\n\n\t\tthis.$data.tasksStore.sort(field, desc, parent);\n\t\tthis.callEvent(\"onAfterSort\", [field, desc, parent]);\n\n\t\tif (render) {\n\t\t\tthis.render();\n\t\t}\n\t}\n};\n};\n\nexport default createTasksDatastoreFacade;\n\n\n","import * as utils from \"../../utils/utils\";\n\nvar $powerArray = {\n\t$create: function(array){\n\t\treturn utils.mixin(array || [], this);\n\t},\n\t//remove element at specified position\n\t$removeAt:function(pos,len){\n\t\tif (pos>=0) this.splice(pos,(len||1));\n\t},\n\t//find element in collection and remove it\n\t$remove:function(value){\n\t\tthis.$removeAt(this.$find(value));\n\t},\n\t//add element to collection at specific position\n\t$insertAt:function(data,pos){\n\t\tif (!pos && pos!==0) \t//add to the end by default\n\t\t\tthis.push(data);\n\t\telse {\n\t\t\tvar b = this.splice(pos,(this.length-pos));\n\t\t\tthis[pos] = data;\n\t\t\tthis.push.apply(this,b); //reconstruct array without loosing this pointer\n\t\t}\n\t},\n\t//return index of element, -1 if it doesn't exists\n\t$find:function(data){\n\t\tfor (var i=0; i data_size){\n\t\t\t\t//dhx.log(\"Warning\",\"DataStore:add\",\"Index of out of bounds\");\n\t\t\t\tindex = Math.min(order.length,index);\n\t\t\t}\n\t\t}\n\n\n\t\t//gantt.assert(!this.exists(id), \"Not unique ID\");\n\n\t\tthis.pull[item.id]=item;\n\t\tif (!this.isSilent()){\n\t\t\tthis._updateOrder(function(){\n\t\t\t\tif(this.$find(item.id) === -1)\n\t\t\t\t\tthis.$insertAt(item.id,index);\n\t\t\t});\n\t\t}\n\t\tthis.filter();\n\t\t//order.$insertAt(item.id,index);\n\t},\n\n\n\tisVisible: function(id){\n\t\treturn this.visibleOrder.$find(id) > -1;\n\t},\n\tgetVisibleItems: function(){\n\t\treturn this.getIndexRange();\n\t},\n\n\taddItem: function(item, index){\n\t\tif (!utils.defined(item.id))\n\t\t\titem.id = utils.uid();\n\n\t\tif(this.$initItem){\n\t\t\titem = this.$initItem(item);\n\t\t}\n\n\t\tif (!this.isSilent()){\n\t\t\tif (this.callEvent(\"onBeforeAdd\", [item.id, item]) === false) return false;\n\t\t}\n\n\n\t\tthis._addItemInner(item, index);\n\n\t\tif (!this.isSilent()){\n\t\t\tthis.callEvent(\"onAfterAdd\",[item.id, item]);\n\t\t\t//repaint signal\n\t\t\tthis.callEvent(\"onStoreUpdated\",[item.id,item,\"add\"]);\n\t\t}\n\t\treturn item.id;\n\t},\n\n\t_changeIdInner: function(oldId, newId){\n\t\tif(this.pull[oldId])\n\t\t\tthis.pull[newId] = this.pull[oldId];\n\n\t\tvar visibleOrder = this._searchVisibleOrder[oldId];\n\t\tthis.pull[newId].id = newId;\n\t\tthis._updateOrder(function(){\n\t\t\tthis[this.$find(oldId)] = newId;\n\t\t});\n\t\tthis._searchVisibleOrder[newId] = visibleOrder;\n\t\tdelete this._searchVisibleOrder[oldId];\n\n\t\t//this.visibleOrder[this.visibleOrder.$find(oldId)]=newId;\n\t\tdelete this.pull[oldId];\n\t},\n\tchangeId: function(oldId, newId){\n\t\tthis._changeIdInner(oldId, newId);\n\n\t\tthis.callEvent(\"onIdChange\", [oldId, newId]);\n\n\t},\n\texists: function(id){\n\t\treturn !!(this.pull[id]);\n\t},\n\n\t_moveInner: function(sindex, tindex){\n\t\tvar id = this.getIdByIndex(sindex);\n\n\t\tthis._updateOrder(function(){\n\t\t\tthis.$removeAt(sindex);\n\t\t\tthis.$insertAt(id,Math.min(this.length, tindex));\n\t\t});\n\t\t//this.visibleOrder.$removeAt(sindex);\t//remove at old position\n\t\t//if (sindex=0 && tindex>=0, \"DataStore::move\",\"Incorrect indexes\");\n\n\t\tvar id = this.getIdByIndex(sindex);\n\t\tvar obj = this.getItem(id);\n\t\tthis._moveInner(sindex, tindex);\n\n\t\tif (!this.isSilent()) {\n\t\t\t//repaint signal\n\t\t\tthis.callEvent(\"onStoreUpdated\", [obj.id, obj, \"move\"]);\n\t\t}\n\t},\n\tclearAll: function(){\n\t\tif(this.$destroyed){\n\t\t\treturn;\n\t\t}\n\t\t// GS-956 We need to unselect the resource as its ID is cached\n\t\tthis.silent(function(){\n\t\t\tthis.unselect();\n\t\t});\n\t\tthis.pull = {};\n\t\tthis.visibleOrder = powerArray.$create();\n\t\tthis.fullOrder = powerArray.$create();\n\t\tif (this.isSilent()) return;\n\t\tthis.callEvent(\"onClearAll\",[]);\n\t\tthis.refresh();\n\t},\n\n\tsilent:function(code, master){\n\t\tvar alreadySilent = false;\n\t\tif(this.isSilent()) {\n\t\t\talreadySilent = true;\n\t\t}\n\t\tthis._skip_refresh = true;\n\t\tcode.call(master||this);\n\t\t\n\t\tif (!alreadySilent) {\n\t\t\tthis._skip_refresh = false;\n\t\t}\n\t},\n\tisSilent: function(){\n\t\treturn !!this._skip_refresh;\n\t},\n\n\tarraysEqual: function (arr1, arr2) {\n\t\tif(arr1.length !== arr2.length)\n\t\t\treturn false;\n\t\tfor(var i = 0; i < arr1.length; i++) {\n\t\t\tif(arr1[i] !== arr2[i])\n\t\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t},\n\n\trefresh: function(id, quick){\n\t\tif (this.isSilent()) return;\n\n\t\tvar item;\n\t\tif(id){\n\t\t\titem = this.getItem(id);\n\t\t}\n\n\t\tvar args;\n\t\tif (id){\n\t\t\targs = [id, item, \"paint\"];\n\t\t}else{\n\t\t\targs = [null,null,null];\n\t\t}\n\n\t\tif(this.callEvent(\"onBeforeStoreUpdate\", args) === false){\n\t\t\treturn;\n\t\t}\n\n\t\tvar skipFilter = this._quick_refresh && !this._mark_recompute;\n\t\tthis._mark_recompute = false;\n\t\tif(id){\n\t\t\t// if item changes visible order (e.g. expand-collapse branch) - do a complete repaint\n\t\t\tif(!quick && !skipFilter){\n\t\t\t\tvar oldOrder = this.visibleOrder;\n\t\t\t\tthis.filter();\n\t\t\t\tif(!this.arraysEqual(oldOrder, this.visibleOrder)){\n\t\t\t\t\tid = undefined;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}else if(!skipFilter){\n\t\t\tthis.filter();\n\t\t}\n\n\t\tif (id){\n\t\t\targs = [id, item, \"paint\"];\n\t\t}else{\n\t\t\targs = [null,null,null];\n\t\t}\n\n\t\tthis.callEvent(\"onStoreUpdated\",args);\n\t},\n\n\tcount: function(){\n\t\treturn this.fullOrder.length;\n\t},\n\tcountVisible: function(){\n\t\treturn this.visibleOrder.length;\n\t},\n\n\tsort: function(sort){},\n\n\tserialize: function(){},\n\n\teachItem: function(code){\n\t\tfor (var i=0; i= item.$level){\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\twhile (item && this.exists(pid)) {\n\t\t\t\titem = this.getItem(pid);\n\n\t\t\t\tif (item && item.id == parentId)\n\t\t\t\t\treturn true;\n\t\t\t\tpid = this.getParent(item);\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\n\t\tgetSiblings: function(id){\n\t\t\tif(!this.exists(id)){\n\t\t\t\treturn powerArray.$create();\n\t\t\t}\n\t\t\tvar parent = this.getParent(id);\n\t\t\treturn this.getChildren(parent);\n\n\t\t},\n\t\tgetNextSibling: function(id){\n\t\t\tvar siblings = this.getSiblings(id);\n\t\t\tfor(var i= 0, len = siblings.length; i < len; i++){\n\t\t\t\tif(siblings[i] == id){\n\t\t\t\t\tvar nextSibling = siblings[i+1];\n\t\t\t\t\tif (nextSibling === 0 && i > 0){\n\t\t\t\t\t\tnextSibling = \"0\";\n\t\t\t\t\t}\n\t\t\t\t\treturn nextSibling || null;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tgetPrevSibling: function(id){\n\t\t\tvar siblings = this.getSiblings(id);\n\t\t\tfor(var i= 0, len = siblings.length; i < len; i++){\n\t\t\t\tif(siblings[i] == id){\n\t\t\t\t\tvar previousSibling = siblings[i-1];\n\t\t\t\t\tif (previousSibling === 0 && i > 0){\n\t\t\t\t\t\tpreviousSibling = \"0\";\n\t\t\t\t\t}\n\t\t\t\t\treturn previousSibling || null;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tgetParent: function(id){\n\t\t\tvar item = null;\n\t\t\tif(id.id !== undefined){\n\t\t\t\titem = id;\n\t\t\t}else{\n\t\t\t\titem = this.getItem(id);\n\t\t\t}\n\n\t\t\tvar parent;\n\t\t\tif(item){\n\t\t\t\tparent = item[this.$parentProperty];\n\t\t\t}else{\n\t\t\t\tparent = this.$getRootId();\n\t\t\t}\n\t\t\treturn parent;\n\n\t\t},\n\n\t\tclearAll: function(){\n\t\t\tthis._branches = {};\n\t\t\tDataStore.prototype.clearAll.call(this);\n\t\t},\n\n\t\tcalculateItemLevel: function(item){\n\t\t\tvar level = 0;\n\t\t\tthis.eachParent(function(){\n\t\t\t\tlevel++;\n\t\t\t}, item);\n\t\t\treturn level;\n\t\t},\n\n\t\t_setParentInner: function(item, new_pid, silent){\n\t\t\tif(!silent){\n\t\t\t\tif(item.hasOwnProperty(\"$rendered_parent\")){\n\t\t\t\t\tthis._move_branch(item, item.$rendered_parent, new_pid);\n\t\t\t\t}else{\n\t\t\t\t\tthis._move_branch(item, item[this.$parentProperty], new_pid);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tsetParent: function(item, new_pid, silent){\n\t\t\tthis._setParentInner(item, new_pid, silent);\n\n\t\t\titem[this.$parentProperty] = new_pid;\n\t\t},\n\n\t\t_eachItemCached: function(code, cache){\n\t\t\tfor(var i = 0, len = cache.length; i < len; i++){\n\t\t\t\tcode.call(this, cache[i]);\n\t\t\t}\n\t\t},\n\t\t_eachItemIterate: function(code, startId, cache){\n\t\t\tvar itemsStack = this.getChildren(startId);\n\t\t\tif(itemsStack.length){\n\t\t\t\titemsStack = itemsStack.slice().reverse();\n\t\t\t}\n\t\t\twhile(itemsStack.length){\n\t\t\t\tvar itemId = itemsStack.pop();\n\t\t\t\tvar item = this.getItem(itemId);\n\t\t\t\tcode.call(this, item);\n\t\t\t\tif(cache){\n\t\t\t\t\tcache.push(item);\n\t\t\t\t}\n\n\t\t\t\tif(this.hasChild(item.id)){\n\t\t\t\t\tvar children = this.getChildren(item.id);\n\t\t\t\t\tvar len = children.length;\n\t\t\t\t\tfor(var i = len - 1; i >= 0; i--){\n\t\t\t\t\t\titemsStack.push(children[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t},\n\n\t\teachItem: function(code, parent){\n\t\t\tvar rootId = this.$getRootId();\n\t\t\tif (!utils.defined(parent)) {\n\t\t\t\tparent = rootId;\n\t\t\t}\n\t\t\tvar startId = replaceValidZeroId(parent, rootId) || rootId;\n\n\t\t\tvar useCache = false;\n\t\t\tvar buildCache = false;\n\t\t\tvar cache = null;\n\t\t\tif(startId === rootId){\n\t\t\t\tif(this._eachItemMainRangeCache){\n\t\t\t\t\tuseCache = true;\n\t\t\t\t\tcache = this._eachItemMainRangeCache;\n\t\t\t\t}else{\n\t\t\t\t\tbuildCache = true;\n\t\t\t\t\tcache = this._eachItemMainRangeCache = [];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(useCache){\n\t\t\t\tthis._eachItemCached(code, cache);\n\t\t\t}else{\n\t\t\t\tthis._eachItemIterate(code, startId, buildCache ? cache : null);\n\t\t\t}\n\t\t},\n\t\teachParent: function(code, startItem) {\n\t\t\tvar parentsHash = {};\n\t\t\tvar item = startItem;\n\t\t\tvar parent = this.getParent(item);\n\n\t\t\twhile (this.exists(parent)) {\n\t\t\t\tif (parentsHash[parent]) {\n\t\t\t\t\tthrow new Error(\"Invalid tasks tree. Cyclic reference has been detected on task \" + parent);\n\t\t\t\t}\n\t\t\t\tparentsHash[parent] = true;\n\t\t\t\titem = this.getItem(parent);\n\t\t\t\tcode.call(this, item);\n\t\t\t\tparent = this.getParent(item);\n\t\t\t}\n\t\t},\n\t\t_add_branch: function(item, index, parent){\n\t\t\tvar pid = parent === undefined ? this.getParent(item) : parent;\n\t\t\tif (!this.hasChild(pid))\n\t\t\t\tthis._branches[pid] = powerArray.$create();\n\t\t\tvar branch = this.getChildren(pid);\n\t\t\tvar added_already = branch.indexOf(item.id + \"\") > -1 || branch.indexOf(+item.id) > -1;\n\t\t\tif(!added_already){\n\t\t\t\tif(index*1 == index){\n\n\t\t\t\t\tbranch.splice(index, 0, item.id);\n\t\t\t\t}else{\n\t\t\t\t\tbranch.push(item.id);\n\t\t\t\t}\n\n\t\t\t\titem.$rendered_parent = pid;\n\t\t\t}\n\t\t},\n\t\t_move_branch: function(item, old_parent, new_parent){\n\t\t\tthis._eachItemMainRangeCache = null;\n\t\t\t//this.setParent(item, new_parent);\n\t\t\t//this._sync_parent(task);\n\t\t\tthis._replace_branch_child(old_parent, item.id);\n\t\t\tif(this.exists(new_parent) || new_parent == this.$getRootId()){\n\n\t\t\t\tthis._add_branch(item, undefined, new_parent);\n\t\t\t}else{\n\t\t\t\tdelete this._branches[item.id];\n\t\t\t}\n\t\t\titem.$level = this.calculateItemLevel(item);\n\t\t\tthis.eachItem(function(child){\n\t\t\t\tchild.$level = this.calculateItemLevel(child);\n\t\t\t}, item.id);\n\t\t},\n\n\t\t_replace_branch_child: function(node, old_id, new_id){\n\t\t\tvar branch = this.getChildren(node);\n\t\t\tif (branch && node !== undefined){\n\t\t\t\tvar newbranch = powerArray.$create();\n\n\t\t\t\tlet index = branch.indexOf(old_id + \"\");\n\t\t\t\tif (index == -1 && !isNaN(+old_id)){\n\t\t\t\t\tindex = branch.indexOf(+old_id);\n\t\t\t\t} \n\n\t\t\t\tif (index > -1){\n\t\t\t\t\tif (new_id){\n\t\t\t\t\t\tbranch.splice(index, 1, new_id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbranch.splice(index, 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnewbranch = branch;\n\n\t\t\t\tthis._branches[node] = newbranch;\n\t\t\t}\n\n\t\t},\n\n\t\tsort: function(field, desc, parent){\n\t\t\tif (!this.exists(parent)) {\n\t\t\t\tparent = this.$getRootId();\n\t\t\t}\n\n\t\t\tif (!field) field = \"order\";\n\t\t\tvar criteria = (typeof(field) == \"string\") ? (function(a, b) {\n\t\t\t\tif (a[field] == b[field] ||\n\t\t\t\t\t(helpers.isDate(a[field]) && helpers.isDate(b[field]) && a[field].valueOf() == b[field].valueOf()))\n\t\t\t\t{\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\tvar result = a[field] > b[field];\n\t\t\t\treturn result ? 1 : -1;\n\t\t\t}) : field;\n\n\t\t\tif (desc) {\n\t\t\t\tvar original_criteria = criteria;\n\t\t\t\tcriteria = function (a, b) {\n\t\t\t\t\treturn original_criteria(b, a);\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tvar els = this.getChildren(parent);\n\n\t\t\tif (els){\n\t\t\t\tvar temp = [];\n\t\t\t\tfor (var i = els.length - 1; i >= 0; i--)\n\t\t\t\t\ttemp[i] = this.getItem(els[i]);\n\n\t\t\t\ttemp.sort(criteria);\n\n\t\t\t\tfor (var i = 0; i < temp.length; i++) {\n\t\t\t\t\tels[i] = temp[i].id;\n\t\t\t\t\tthis.sort(field, desc, els[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tfilter: function(rule){\n\t\t\tfor(let i in this.pull){\n\t\t\t\tconst renderedParent = this.pull[i].$rendered_parent;\n\t\t\t\tconst actualParent = this.getParent(this.pull[i]);\n\t\t\t\tif(renderedParent !== actualParent){\n\t\t\t\t\tthis._move_branch(this.pull[i], renderedParent, actualParent);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn DataStore.prototype.filter.apply(this, arguments);\n\t\t},\n\n\t\topen: function(id){\n\t\t\tif(this.exists(id)){\n\t\t\t\tthis.getItem(id).$open = true;\n\t\t\t\t// GS-2170. Do not recalculate the indexes and dates as they will be recalculated later\n\t\t\t\tthis._skipTaskRecalculation = true;\n\t\t\t\tthis.callEvent(\"onItemOpen\", [id]);\n\t\t\t}\n\t\t},\n\n\t\tclose: function(id){\n\t\t\tif(this.exists(id)){\n\t\t\t\tthis.getItem(id).$open = false;\n\t\t\t\t// GS-2170. Do not recalculate the indexes and dates as they will be recalculated later\n\t\t\t\tthis._skipTaskRecalculation = true;\n\t\t\t\tthis.callEvent(\"onItemClose\", [id]);\n\t\t\t}\n\t\t},\n\n\t\tdestructor: function(){\n\t\t\tDataStore.prototype.destructor.call(this);\n\t\t\tthis._branches = null;\n\t\t\tthis._indexRangeCache = {};\n\t\t\tthis._eachItemMainRangeCache = null;\n\t\t}\n\t},\n\tDataStore.prototype\n);\n\nexport default TreeDataStore;","import env from \"./env\";\n\nexport default function(gantt){\n\treturn env.isNode || !gantt.$root;\n};","import isHeadless from \"../../utils/is_headless\";\n\nconst storeRenderCreator = function(name, gantt){\n\n\tconst store = gantt.getDatastore(name);\n\n\tconst itemRepainter = {\n\t\trenderItem: function(id, renderer){\n\n\t\t\tconst renders = renderer.getLayers();\n\n\t\t\tconst item = store.getItem(id);\n\t\t\tif(item && store.isVisible(id)) {\n\t\t\t\tfor (let i = 0; i < renders.length; i++)\n\t\t\t\t\trenders[i].render_item(item);\n\t\t\t}\n\t\t},\n\t\trenderItems: function(renderer){\n\t\t\tconst renderers = renderer.getLayers();\n\t\t\tfor (let i = 0; i < renderers.length; i++) {\n\t\t\t\trenderers[i].clear();\n\t\t\t}\n\n\t\t\tlet allData = null;\n\n\t\t\tconst loadedRanges = {};\n\t\t\tfor (let i = 0; i < renderers.length; i++) {\n\t\t\t\tconst layer = renderers[i];\n\t\t\t\tlet layerData;\n\t\t\t\tif(layer.get_visible_range){\n\n\t\t\t\t\tvar range = layer.get_visible_range(store);\n\t\t\t\t\tif(range.start !== undefined && range.end !== undefined){\n\t\t\t\t\t\tvar key = range.start + \" - \" + range.end;\n\t\t\t\t\t\tif(loadedRanges[key]){\n\t\t\t\t\t\t\tlayerData = loadedRanges[key];\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tlayerData = store.getIndexRange(range.start, range.end);\n\t\t\t\t\t\t\tloadedRanges[key] = layerData;\n\t\t\t\t\t\t}\n\t\t\t\t\t}else if(range.ids !== undefined){\n\t\t\t\t\t\tlayerData = range.ids.map(function(id){\n\t\t\t\t\t\t\treturn store.getItem(id);\n\t\t\t\t\t\t});\n\t\t\t\t\t}else{\n\t\t\t\t\t\tthrow new Error(\"Invalid range returned from 'getVisibleRange' of the layer\");\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\tif(!allData){\n\t\t\t\t\t\tallData = store.getVisibleItems();\n\t\t\t\t\t}\n\t\t\t\t\tlayerData = allData;\n\t\t\t\t}\n\n\t\t\t\tif (layer.prepare_data) {\n\t\t\t\t\t// GS-1605. Highlight timeline cells below tasks and in an empty chart\n\t\t\t\t\tlayer.prepare_data(layerData);\n\t\t\t\t}\n\n\t\t\t\trenderers[i].render_items(layerData);\n\t\t\t}\n\t\t},\n\t\tupdateItems: function(layer) {\n\t\t\tif(layer.update_items){\n\t\t\t\tlet data = [];\n\t\t\t\tif(layer.get_visible_range){\n\n\t\t\t\t\tvar range = layer.get_visible_range(store);\n\t\t\t\t\tif(range.start !== undefined && range.end !== undefined){\n\t\t\t\t\t\tdata = store.getIndexRange(range.start, range.end);\n\t\t\t\t\t}\n\t\t\t\t\tif(range.ids !== undefined){\n\t\t\t\t\t\tlet extraDataArr = range.ids.map(function(id){\n\t\t\t\t\t\t\treturn store.getItem(id);\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// GS-2502: range.ids might not exist in other datastores\n\t\t\t\t\t\tif(extraDataArr.length > 0){\n\t\t\t\t\t\t\textraDataArr = extraDataArr.filter(element => element !== undefined);\n\t\t\t\t\t\t\tdata = data.concat(extraDataArr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif((range.start == undefined || range.end == undefined) && range.ids == undefined) {\n\t\t\t\t\t\tthrow new Error(\"Invalid range returned from 'getVisibleRange' of the layer\");\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\tdata = store.getVisibleItems();\n\t\t\t\t}\n\n\t\t\t\tif (layer.prepare_data) {\n\t\t\t\t\t// GS-1605. Highlight timeline cells below tasks and in an empty chart\n\t\t\t\t\tlayer.prepare_data(data, layer);\n\t\t\t\t}\n\t\t\t\tlayer.update_items(data);\n\t\t\t}\n\t\t}\n\t};\n\n\tstore.attachEvent(\"onStoreUpdated\", function(id, item, action){\n\t\tif(isHeadless(gantt)){\n\t\t\treturn true;\n\t\t}\n\n\t\tconst renderer = gantt.$services.getService(\"layers\").getDataRender(name);\n\t\tif(renderer){\n\t\t\trenderer.onUpdateRequest = function(layer){\n\t\t\t\titemRepainter.updateItems(layer);\n\t\t\t};\n\t\t}\n\t});\n\n\tfunction skipRepaint(gantt){\n\t\tconst state = gantt.$services.getService(\"state\");\n\t\tif(state.getState(\"batchUpdate\").batch_update){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tstore.attachEvent(\"onStoreUpdated\", function(id, item, action){\n\t\tif(skipRepaint(gantt)){\n\t\t\treturn;\n\t\t}\n\t\tif(!id || action == \"move\" || action == \"delete\"){\n\t\t\tstore.callEvent(\"onBeforeRefreshAll\", []);\n\t\t\tstore.callEvent(\"onAfterRefreshAll\", []);\n\t\t}else{\n\t\t\tstore.callEvent(\"onBeforeRefreshItem\", [item.id]);\n\t\t\tstore.callEvent(\"onAfterRefreshItem\", [item.id]);\n\t\t}\n\t});\n\n\tstore.attachEvent(\"onAfterRefreshAll\", function(){\n\t\tif(isHeadless(gantt)){\n\t\t\treturn true;\n\t\t}\n\n\t\tconst renderer = gantt.$services.getService(\"layers\").getDataRender(name);\n\t\tif(renderer && !skipRepaint(gantt)){\n\t\t\titemRepainter.renderItems(renderer);\n\t\t}\n\t});\n\tstore.attachEvent(\"onAfterRefreshItem\", function(id){\n\t\tif(isHeadless(gantt)){\n\t\t\treturn true;\n\t\t}\n\n\t\tconst renderer = gantt.$services.getService(\"layers\").getDataRender(name);\n\t\tif(renderer){\n\t\t\titemRepainter.renderItem(id, renderer);\n\t\t}\n\t});\n\n\t// TODO: probably can be done more in a more efficient way\n\tstore.attachEvent(\"onItemOpen\", function(){\n\t\tif(isHeadless(gantt)){\n\t\t\treturn true;\n\t\t}\n\n\t\tgantt.render();\n\t});\n\n\tstore.attachEvent(\"onItemClose\", function(){\n\t\tif(isHeadless(gantt)){\n\t\t\treturn true;\n\t\t}\n\n\t\tgantt.render();\n\t});\n\n\tfunction refreshId(renders, oldId, newId, item) {\n\t\tfor (let i = 0; i < renders.length; i++) {\n\t\t\trenders[i].change_id(oldId, newId);\n\t\t}\n\t}\n\n\tstore.attachEvent(\"onIdChange\", function(oldId, newId){\n\t\tif(isHeadless(gantt)){\n\t\t\treturn true;\n\t\t}\n\n\t\t// in case of linked datastores (tasks <-> links), id change should recalculate something in linked datastore before any repaint\n\t\t// use onBeforeIdChange for this hook.\n\t\t// TODO: use something more reasonable instead\n\t\tstore.callEvent(\"onBeforeIdChange\", [oldId, newId]);\n\n\t\tif(skipRepaint(gantt)){\n\t\t\treturn;\n\t\t}\n\t\tif(!store.isSilent()){\n\t\t\tconst renderer = gantt.$services.getService(\"layers\").getDataRender(name);\n\t\t\tif(renderer){ // missing check for renderer GS-1814\n\t\t\t\trefreshId(renderer.getLayers(), oldId, newId, store.getItem(newId));\n\t\t\t\titemRepainter.renderItem(newId, renderer);\n\t\t\t}else{\n\t\t\t\t// GS-1814 repaint ui to apply new id when the datastore don't have own renderer\n\t\t\t\tgantt.render();\n\t\t\t}\n\t\t}\n\t});\n\n};\n\nexport default {\n\tbindDataStore: storeRenderCreator\n};","import * as utils from \"../../utils/utils\";\nimport createTasksFacade from \"./datastore_tasks\";\nimport createLinksFacade from \"./datastore_links\";\nimport DataStore from \"../datastore/datastore\";\nimport TreeDataStore from \"../datastore/treedatastore\";\nimport createDatastoreSelect from \"../datastore/select\";\nimport datastoreRender from \"../datastore/datastore_render\";\nimport isHeadless from \"../../utils/is_headless\";\nimport {replaceValidZeroId} from \"../../utils/helpers\";\n\nfunction getDatastores(){\n\tvar storeNames = this.$services.getService(\"datastores\");\n\tvar res = [];\n\tfor(var i = 0; i < storeNames.length; i++){\n\t\tvar store = this.getDatastore(storeNames[i]);\n\t\tif(!store.$destroyed){\n\t\t\tres.push(store);\n\t\t}\n\t}\n\treturn res;\n}\n\nvar createDatastoreFacade = function(){\n\treturn {\n\tcreateDatastore: function(config){\n\n\t\tvar $StoreType = (config.type || \"\").toLowerCase() == \"treedatastore\" ? TreeDataStore : DataStore;\n\n\t\tif (config) {\n\t\t\tvar self = this;\n\t\t\tconfig.openInitially = function(){ return self.config.open_tree_initially; };\n\t\t\tconfig.copyOnParse = function(){ return self.config.deepcopy_on_parse; };\n\t\t}\n\n\t\tvar store = new $StoreType(config);\n\t\tthis.mixin(store, createDatastoreSelect(store));\n\n\t\tif (config.name) {\n\t\t\tvar servicePrefix = \"datastore:\";\n\t\t\tvar storeAccessName = servicePrefix + config.name;\n\n\t\t\tstore.attachEvent(\"onDestroy\", function(){\n\t\t\t\tthis.$services.dropService(storeAccessName);\n\t\t\t\tvar storeList = this.$services.getService(\"datastores\");\n\t\t\t\tfor(var i = 0; i < storeList.length; i++){\n\t\t\t\t\tif(storeList[i] === config.name){\n\t\t\t\t\t\tstoreList.splice(i, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}.bind(this));\n\n\t\t\tthis.$services.dropService(storeAccessName);\n\t\t\tthis.$services.setService(storeAccessName, function() { return store; } );\n\n\t\t\tvar storeList = this.$services.getService(\"datastores\");\n\t\t\tif (!storeList) {\n\t\t\t\tstoreList = [];\n\t\t\t\tthis.$services.setService(\"datastores\", function() { return storeList; });\n\t\t\t\tstoreList.push(config.name);\n\t\t\t} else if (storeList.indexOf(config.name) < 0) {\n\t\t\t\tstoreList.push(config.name);\n\t\t\t}\n\n\t\t\tdatastoreRender.bindDataStore(config.name, this);\n\n\t\t}\n\n\t\treturn store;\n\t},\n\tgetDatastore: function(name){\n\t\treturn this.$services.getService(\"datastore:\" + name);\n\t},\n\t_getDatastores: getDatastores,\n\n\trefreshData: function () {\n\t\tvar scrollState;\n\t\tif(!isHeadless(this)){\n\t\t\tscrollState = this.getScrollState();\n\t\t}\n\n\t\tthis.callEvent(\"onBeforeDataRender\", []);\n\n\t\tvar stores = getDatastores.call(this);\n\t\tfor(var i = 0; i < stores.length; i++){\n\t\t\tstores[i].refresh();\n\t\t}\n\n\t\tif(this.config.preserve_scroll && !isHeadless(this) && (scrollState.x || scrollState.y)){\n\t\t\tthis.scrollTo(scrollState.x, scrollState.y);\n\t\t}\n\t\tthis.callEvent(\"onDataRender\", []);\n\n\t},\n\n\tisChildOf: function(childId, parentId){\n\t\treturn this.$data.tasksStore.isChildOf(childId, parentId);\n\t},\n\n\trefreshTask: function (taskId, refresh_links) {\n\t\tvar task = this.getTask(taskId);\n\t\tvar self = this;\n\t\tfunction refreshLinks(){\n\t\t\tif (refresh_links !== undefined && !refresh_links)\n\t\t\t\treturn;\n\t\t\tfor (var i = 0; i < task.$source.length; i++) {\n\t\t\t\tself.refreshLink(task.$source[i]);\n\t\t\t}\n\t\t\tfor (var i = 0; i < task.$target.length; i++) {\n\t\t\t\tself.refreshLink(task.$target[i]);\n\t\t\t}\n\t\t}\n\n\t\tif (task && this.isTaskVisible(taskId)) {\n\t\t\tthis.$data.tasksStore.refresh(taskId, !!this.getState(\"tasksDnd\").drag_id || refresh_links === false);// do quick refresh during drag and drop\n\t\t\trefreshLinks();\n\t\t}else if(this.isTaskExists(taskId) && this.isTaskExists(this.getParent(taskId)) && !this._bulk_dnd){\n\t\t\tthis.refreshTask(this.getParent(taskId));\n\n\t\t\tvar hasSplitParent = false;\n\t\t\tthis.eachParent(function(parent){\n\t\t\t\tif(hasSplitParent || this.isSplitTask(parent)){\n\t\t\t\t\thasSplitParent = true;\n\t\t\t\t}\n\t\t\t}, taskId);\n\t\t\tif(hasSplitParent){\n\t\t\t\trefreshLinks();\n\t\t\t}\n\t\t}\n\n\t},\n\trefreshLink: function (linkId) {\n\t\tthis.$data.linksStore.refresh(linkId, !!this.getState(\"tasksDnd\").drag_id);// do quick refresh during drag and drop\n\t},\n\n\tsilent: function(code){\n\t\tvar gantt = this;\n\t\tgantt.$data.tasksStore.silent(function(){\n\t\t\tgantt.$data.linksStore.silent(function(){\n\t\t\t\tcode();\n\t\t\t});\n\t\t});\n\t},\n\n\tclearAll: function () {\n\t\tvar stores = getDatastores.call(this);\n\t\t\n\t\t// clear all stores without invoking clearAll event\n\t\t// in order to prevent calling handlers when only some stores are cleared\n\t\tfor(var i = 0; i < stores.length; i++){\n\t\t\tstores[i].silent(function(){\n\t\t\t\tstores[i].clearAll();\t\n\t\t\t});\n\t\t}\n\t\t// run clearAll again to invoke events\n\t\tfor(var i = 0; i < stores.length; i++){\n\t\t\tstores[i].clearAll();\t\n\t\t}\n\n\t\tthis._update_flags();\n\t\tthis.userdata = {};\n\t\tthis.callEvent(\"onClear\", []);\n\t\tthis.render();\n\t},\n\t_clear_data: function () {\n\t\tthis.$data.tasksStore.clearAll();\n\t\tthis.$data.linksStore.clearAll();\n\t\tthis._update_flags();\n\t\tthis.userdata = {};\n\t},\n\n\tselectTask: function(id){\n\t\tvar store = this.$data.tasksStore;\n\t\tif(!this.config.select_task)\n\t\t\treturn false;\n\t\tid = replaceValidZeroId(id, this.config.root_id);\n\t\tif (id){\n\t\t\tlet oldSelectId = this.getSelectedId();\n\t\t\t// Don't repaint the resource panel as the data didn't change\n\t\t\tstore._skipResourceRepaint = true;\n\t\t\tstore.select(id);\n\t\t\tstore._skipResourceRepaint = false;\n\t\t\t// GS-730. Split task is not included in the tree, \n\t\t\t// so the datastore renderer will think that the task is not visible\n\t\t\tif (oldSelectId && store.pull[oldSelectId].$split_subtask && oldSelectId != id) {\n\t\t\t\tthis.refreshTask(oldSelectId);\n\t\t\t}\n\t\t\tif (store.pull[id].$split_subtask && oldSelectId != id) {// GS-1850. Do not repaint split task after double click\n\t\t\t\tthis.refreshTask(id);\n\t\t\t}\n\t\t}\n\t\treturn store.getSelectedId();\n\t},\n\tunselectTask: function(id){\n\t\tvar store = this.$data.tasksStore;\n\t\tstore.unselect(id);\n\t\t// GS-730. Split task is not included in the tree, \n\t\t// so the datastore renderer will think that the task is not visible\n\t\tif (id && store.pull[id].$split_subtask) {\n\t\t\tthis.refreshTask(id);\n\t\t}\n\t},\n\tisSelectedTask: function(id){\n\t\treturn this.$data.tasksStore.isSelected(id);\n\t},\n\tgetSelectedId: function() {\n\t\treturn this.$data.tasksStore.getSelectedId();\n\t}\n};\n};\n\nfunction createFacade(){\n\tvar res = utils.mixin({}, createDatastoreFacade());\n\tutils.mixin(res, createTasksFacade());\n\tutils.mixin(res, createLinksFacade());\n\treturn res;\n}\n\n\n\n\nexport default {create: createFacade};","function createDataStoreSelectMixin(store){\n\tvar selectedId = null;\n\n\tvar deleteItem = store._removeItemInner;\n\t\n\tfunction unselect(id){\n\t\tselectedId = null;\n\t\tthis.callEvent(\"onAfterUnselect\", [id]);\n\t}\n\n\tstore._removeItemInner = function(id){\n\t\tif(selectedId == id){\n\t\t\tunselect.call(this, id);\n\t\t}\n\n\t\tif(selectedId && this.eachItem){\n\t\t\tthis.eachItem(function(subItem){\n\t\t\t\tif(subItem.id == selectedId){\n\t\t\t\t\tunselect.call(this, subItem.id);\n\t\t\t\t}\n\t\t\t}, id);\n\t\t}\n\n\t\treturn deleteItem.apply(this, arguments);\n\t};\n\n\tstore.attachEvent(\"onIdChange\", function(oldId, newId) {\n\t\tif (store.getSelectedId() == oldId) {\n\t\t\tstore.silent(function () {\n\t\t\t\tstore.unselect(oldId);\n\t\t\t\tstore.select(newId);\n\t\t\t});\n\t\t}\n\t});\n\n\treturn {\n\t\tselect: function(id){\n\t\t\tif (id){\n\n\t\t\t\tif(selectedId == id)\n\t\t\t\t\treturn selectedId;\n\n\t\t\t\tif(!this._skip_refresh) {\n\t\t\t\t\tif (!this.callEvent(\"onBeforeSelect\", [id])) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.unselect();\n\n\t\t\t\tselectedId = id;\n\n\t\t\t\tif(!this._skip_refresh) {\n\t\t\t\t\tthis.refresh(id);\n\t\t\t\t\tthis.callEvent(\"onAfterSelect\", [id]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn selectedId;\n\t\t},\n\t\tgetSelectedId: function(){\n\t\t\treturn selectedId;\n\t\t},\n\t\tisSelected: function(id){\n\t\t\treturn id == selectedId;\n\t\t},\n\t\tunselect: function(id){\n\t\t\tvar id = id || selectedId;\n\t\t\tif(!id)\n\t\t\t\treturn;\n\t\t\tselectedId = null;\n\t\t\tif(!this._skip_refresh){\n\t\t\t\tthis.refresh(id);\n\t\t\t\tunselect.call(this, id);\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport default createDataStoreSelectMixin;","import * as utils from \"../../utils/utils\";\n\n\nvar createLinksStoreFacade = function(){\n\treturn {\n\tgetLinkCount: function () {\n\t\treturn this.$data.linksStore.count();\n\t},\n\n\tgetLink : function (id) {\n\t\treturn this.$data.linksStore.getItem(id);\n\t},\n\n\tgetLinks : function () {\n\t\treturn this.$data.linksStore.getItems();\n\t},\n\n\tisLinkExists : function (id) {\n\t\treturn this.$data.linksStore.exists(id);\n\t},\n\n\taddLink : function (link) {\n\t\tconst newLink = this.$data.linksStore.addItem(link);\n\t\t// GS-1222. Update fullOrder otherwise the link won't appear after render\n\t\tif (this.$data.linksStore.isSilent()){\n\t\t\tthis.$data.linksStore.fullOrder.push(newLink);\n\t\t}\n\t\treturn newLink;\n\t},\n\n\tupdateLink : function (id, data) {\n\t\tif (!utils.defined(data))\n\t\t\tdata = this.getLink(id);\n\t\tthis.$data.linksStore.updateItem(id, data);\n\t},\n\n\tdeleteLink : function (id) {\n\t\treturn this.$data.linksStore.removeItem(id);\n\t},\n\n\tchangeLinkId : function (oldid, newid) {\n\t\treturn this.$data.linksStore.changeId(oldid, newid);\n\t}\n};\n};\n\nexport default createLinksStoreFacade;","import * as utils from \"../../../utils/utils\";\n\nfunction ScaleHelper(gantt){\n\tvar dateHelper = gantt.date;\n\tvar services = gantt.$services;\n\n\treturn {\n\t\tgetSum: function (sizes, from, to) {\n\t\t\tif (to === undefined)\n\t\t\t\tto = sizes.length - 1;\n\t\t\tif (from === undefined)\n\t\t\t\tfrom = 0;\n\n\t\t\tvar summ = 0;\n\t\t\tfor (var i = from; i <= to; i++)\n\t\t\t\tsumm += sizes[i];\n\n\t\t\treturn summ;\n\t\t},\n\t\tsetSumWidth: function (sum_width, scale, from, to) {\n\t\t\tvar parts = scale.width;\n\n\t\t\tif (to === undefined)\n\t\t\t\tto = parts.length - 1;\n\t\t\tif (from === undefined)\n\t\t\t\tfrom = 0;\n\t\t\tvar length = to - from + 1;\n\n\t\t\tif (from > parts.length - 1 || length <= 0 || to > parts.length - 1)\n\t\t\t\treturn;\n\n\t\t\tvar oldWidth = this.getSum(parts, from, to);\n\n\t\t\tvar diff = sum_width - oldWidth;\n\n\t\t\tthis.adjustSize(diff, parts, from, to);\n\t\t\tthis.adjustSize(-diff, parts, to + 1);\n\n\t\t\tscale.full_width = this.getSum(parts);\n\t\t},\n\t\tsplitSize: function (width, count) {\n\t\t\tvar arr = [];\n\t\t\tfor (var i = 0; i < count; i++) arr[i] = 0;\n\n\t\t\tthis.adjustSize(width, arr);\n\t\t\treturn arr;\n\n\t\t},\n\t\tadjustSize: function (width, parts, from, to) {\n\t\t\tif (!from)\n\t\t\t\tfrom = 0;\n\t\t\tif (to === undefined)\n\t\t\t\tto = parts.length - 1;\n\n\t\t\tvar length = to - from + 1;\n\n\t\t\tvar full = this.getSum(parts, from, to);\n\n\t\t\tfor (var i = from; i <= to; i++) {\n\t\t\t\tvar share = Math.floor(width * (full ? (parts[i] / full) : (1 / length)));\n\n\t\t\t\tfull -= parts[i];\n\t\t\t\twidth -= share;\n\t\t\t\tlength--;\n\n\t\t\t\tparts[i] += share;\n\t\t\t}\n\t\t\tparts[parts.length - 1] += width;\n\t\t},\n\t\tsortScales: function (scales) {\n\t\t\tfunction cellSize(unit, step) {\n\t\t\t\tvar d = new Date(1970, 0, 1);\n\t\t\t\treturn dateHelper.add(d, step, unit) - d;\n\t\t\t}\n\n\t\t\tscales.sort(function (a, b) {\n\t\t\t\tif (cellSize(a.unit, a.step) < cellSize(b.unit, b.step)) {\n\t\t\t\t\treturn 1;\n\t\t\t\t} else if (cellSize(a.unit, a.step) > cellSize(b.unit, b.step)) {\n\t\t\t\t\treturn -1;\n\t\t\t\t} else {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tfor (var i = 0; i < scales.length; i++) {\n\t\t\t\tscales[i].index = i;\n\t\t\t}\n\t\t},\n\t\t_isLegacyMode: function(config){\n\t\t\tvar scaleConfig = config || gantt.config;\n\t\t\treturn scaleConfig.scale_unit || scaleConfig.date_scale || scaleConfig.subscales;\n\t\t},\n\t\t_prepareScaleObject: function(scale){\n\t\t\tvar format = scale.format;\n\t\t\tif(!format){\n\t\t\t\tformat = scale.template || scale.date || \"%d %M\";\n\t\t\t}\n\n\t\t\tif(typeof format === \"string\"){\n\t\t\t\tformat = gantt.date.date_to_str(format);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tunit: scale.unit || \"day\",\n\t\t\t\tstep: scale.step || 1,\n\t\t\t\tformat: format,\n\t\t\t\tcss: scale.css\n\t\t\t};\n\t\t},\n\t\tprimaryScale: function(config) {\n\t\t\tvar templates = services.getService(\"templateLoader\");\n\t\t\tvar legacyMode = this._isLegacyMode(config);\n\n\t\t\tvar scaleConfig = config || gantt.config;\n\n\t\t\tvar result;\n\t\t\tif(legacyMode){\n\t\t\t\ttemplates.initTemplate(\"date_scale\", undefined, undefined, scaleConfig, gantt.config.templates);\n\t\t\t\tresult = {\n\t\t\t\t\tunit: gantt.config.scale_unit,\n\t\t\t\t\tstep: gantt.config.step,\n\t\t\t\t\ttemplate: gantt.templates.date_scale,\n\t\t\t\t\tdate: gantt.config.date_scale,\n\t\t\t\t\tcss: gantt.templates.scale_cell_class\n\t\t\t\t};\n\t\t\t}else{\n\t\t\t\tvar primaryScale = scaleConfig.scales[0];\n\t\t\t\tresult = {\n\t\t\t\t\tunit: primaryScale.unit,\n\t\t\t\t\tstep: primaryScale.step,\n\t\t\t\t\ttemplate: primaryScale.template,\n\t\t\t\t\tformat: primaryScale.format,\n\t\t\t\t\tdate: primaryScale.date,\n\t\t\t\t\tcss: primaryScale.css || gantt.templates.scale_cell_class\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn this._prepareScaleObject(result);\n\t\t},\n\t\tgetSubScales: function(config) {\n\t\t\tvar legacyMode = this._isLegacyMode(config);\n\t\t\tvar scaleConfig = config || gantt.config;\n\t\t\tvar scales;\n\t\t\tif(legacyMode){\n\t\t\t\tlet docLink = \"https://docs.dhtmlx.com/gantt/migrating.html#:~:text=%3D%20false%3B-,Time%20scale%20settings,-Configuration%20of%20time\";\n\t\t\t\tif (gantt.env.isFF){\n\t\t\t\t\tdocLink = \"https://docs.dhtmlx.com/gantt/migrating.html#6162\";\n\t\t\t\t}\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`You are using the obsolete scale configuration.\nIt will stop working in the future versions.\nPlease migrate the configuration to the newer version:\n${docLink}`);\n\t\t\t\tscales = scaleConfig.subscales || [];\n\t\t\t}else{\n\t\t\t\tscales = scaleConfig.scales.slice(1);\n\t\t\t}\n\t\t\t\n\t\t\treturn scales.map(function(scale){\n\t\t\t\treturn this._prepareScaleObject(scale);\n\t\t\t}.bind(this));\n\t\t},\n\n\t\tprepareConfigs: function (scales, min_coll_width, container_width, scale_height, minDate, maxDate, rtl) {\n\t\t\tvar heights = this.splitSize(scale_height, scales.length);\n\t\t\tvar full_width = container_width;\n\n\t\t\tvar configs = [];\n\t\t\tfor (var i = scales.length - 1; i >= 0; i--) {\n\t\t\t\tvar main_scale = (i == scales.length - 1);\n\t\t\t\tvar cfg = this.initScaleConfig(scales[i], minDate, maxDate);\n\t\t\t\tif (main_scale) {\n\t\t\t\t\tthis.processIgnores(cfg);\n\t\t\t\t}\n\n\t\t\t\tthis.initColSizes(cfg, min_coll_width, full_width, heights[i]);\n\t\t\t\tthis.limitVisibleRange(cfg);\n\n\t\t\t\tif (main_scale) {\n\t\t\t\t\tfull_width = cfg.full_width;\n\t\t\t\t}\n\n\t\t\t\tconfigs.unshift(cfg);\n\t\t\t}\n\n\n\t\t\tfor (var i = 0; i < configs.length - 1; i++) {\n\t\t\t\tthis.alineScaleColumns(configs[configs.length - 1], configs[i]);\n\t\t\t}\n\t\t\tfor (var i = 0; i < configs.length; i++) {\n\n\t\t\t\tif(rtl){\n\t\t\t\t\tthis.reverseScale(configs[i]);\n\t\t\t\t}\n\t\t\t\tthis.setPosSettings(configs[i]);\n\t\t\t}\n\t\t\treturn configs;\n\n\t\t},\n\n\t\treverseScale: function(scale){\n\t\t\tscale.width = scale.width.reverse();\n\t\t\tscale.trace_x = scale.trace_x.reverse();\n\n\t\t\tvar indexes = scale.trace_indexes;\n\t\t\tscale.trace_indexes = {};\n\t\t\tscale.trace_index_transition = {};\n\t\t\tscale.rtl = true;\n\t\t\tfor(var i = 0; i < scale.trace_x.length; i++){\n\t\t\t\tscale.trace_indexes[scale.trace_x[i].valueOf()] = i;\n\t\t\t\tscale.trace_index_transition[indexes[scale.trace_x[i].valueOf()]] = i;\n\t\t\t}\n\t\t\treturn scale;\n\t\t},\n\n\t\tsetPosSettings: function (config) {\n\t\t\tfor (var i = 0, len = config.trace_x.length; i < len; i++) {\n\t\t\t\tconfig.left.push((config.width[i - 1] || 0) + (config.left[i - 1] || 0));\n\t\t\t}\n\t\t},\n\n\t\t_ignore_time_config: function (date, scale) {\n\n\t\t\tif (gantt.config.skip_off_time) {\n\t\t\t\tvar skip = true;\n\t\t\t\tvar probe = date;\n\n\t\t\t\t// check dates in case custom scale unit, e.g. {unit: \"month\", step: 3}\n\t\t\t\tfor (var i = 0; i < scale.step; i++) {\n\t\t\t\t\tif (i) {\n\t\t\t\t\t\tprobe = dateHelper.add(date, i, scale.unit);\n\t\t\t\t\t}\n\n\t\t\t\t\tskip = skip && !this.isWorkTime(probe, scale.unit);\n\t\t\t\t}\n\n\t\t\t\treturn skip;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\t//defined in an extension\n\t\tprocessIgnores: function (config) {\n\t\t\tconfig.ignore_x = {};\n\t\t\tconfig.display_count = config.count;\n\t\t},\n\t\tinitColSizes: function (config, min_col_width, full_width, line_height) {\n\t\t\tvar cont_width = full_width;\n\n\t\t\tconfig.height = line_height;\n\n\t\t\tvar column_count = config.display_count === undefined ? config.count : config.display_count;\n\n\t\t\tif (!column_count)\n\t\t\t\tcolumn_count = 1;\n\n\t\t\tconfig.col_width = Math.floor(cont_width / column_count);\n\n\t\t\tif (min_col_width) {\n\t\t\t\tif (config.col_width < min_col_width) {\n\t\t\t\t\tconfig.col_width = min_col_width;\n\t\t\t\t\tcont_width = config.col_width * column_count;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconfig.width = [];\n\t\t\tvar ignores = config.ignore_x || {};\n\t\t\tfor (var i = 0; i < config.trace_x.length; i++) {\n\t\t\t\tif (ignores[config.trace_x[i].valueOf()] || (config.display_count == config.count)) {\n\t\t\t\t\tconfig.width[i] = 0;\n\t\t\t\t} else {\n\t\t\t\t\t// width of month columns should be proportional month duration\n\t\t\t\t\tvar width = 1;\n\t\t\t\t\tif (config.unit == \"month\") {\n\t\t\t\t\t\tvar days = Math.round((dateHelper.add(config.trace_x[i], config.step, config.unit) - config.trace_x[i]) / (1000 * 60 * 60 * 24));\n\t\t\t\t\t\twidth = days;\n\t\t\t\t\t}\n\t\t\t\t\tconfig.width[i] = width;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.adjustSize(cont_width - this.getSum(config.width)/* 1 width per column from the code above */, config.width);\n\t\t\tconfig.full_width = this.getSum(config.width);\n\t\t},\n\t\tinitScaleConfig: function (config, min_date, max_date) {\n\t\t\tvar cfg = utils.mixin({\n\t\t\t\tcount: 0,\n\t\t\t\tcol_width: 0,\n\t\t\t\tfull_width: 0,\n\t\t\t\theight: 0,\n\t\t\t\twidth: [],\n\t\t\t\tleft: [],\n\t\t\t\ttrace_x: [],\n\t\t\t\ttrace_indexes: {},\n\t\t\t\tmin_date: new Date(min_date),\n\t\t\t\tmax_date: new Date(max_date)\n\t\t\t}, config);\n\n\t\t\tthis.eachColumn(config.unit, config.step, min_date, max_date, function (date) {\n\t\t\t\tcfg.count++;\n\t\t\t\tcfg.trace_x.push(new Date(date));\n\t\t\t\tcfg.trace_indexes[date.valueOf()] = cfg.trace_x.length - 1;\n\t\t\t});\n\n\t\t\tcfg.trace_x_ascending = cfg.trace_x.slice();\n\t\t\treturn cfg;\n\t\t},\n\t\titerateScales: function (lower_scale, upper_scale, from, to, callback) {\n\t\t\tvar upper_dates = upper_scale.trace_x;\n\t\t\tvar lower_dates = lower_scale.trace_x;\n\n\t\t\tvar prev = from || 0;\n\t\t\tvar end = to || (lower_dates.length - 1);\n\t\t\tvar prevUpper = 0;\n\n\n\t\t\tfor (var up = 1; up < upper_dates.length; up++) {\n\t\t\t\tvar target_index = (lower_scale.trace_indexes[+upper_dates[up]]);\n\t\t\t\tif (target_index !== undefined && target_index <= end) {\n\t\t\t\t\tif (callback) {\n\t\t\t\t\t\tcallback.apply(this, [prevUpper, up, prev, target_index]);\n\t\t\t\t\t}\n\t\t\t\t\tprev = target_index;\n\t\t\t\t\tprevUpper = up;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\talineScaleColumns: function (lower_scale, upper_scale, from, to) {\n\t\t\tthis.iterateScales(lower_scale, upper_scale, from, to, function (upper_start, upper_end, lower_start, lower_end) {\n\t\t\t\tvar targetWidth = this.getSum(lower_scale.width, lower_start, lower_end - 1);\n\t\t\t\tvar actualWidth = this.getSum(upper_scale.width, upper_start, upper_end - 1);\n\t\t\t\tif (actualWidth != targetWidth) {\n\t\t\t\t\tthis.setSumWidth(targetWidth, upper_scale, upper_start, upper_end - 1);\n\t\t\t\t}\n\n\t\t\t});\n\t\t},\n\n\t\teachColumn: function (unit, step, min_date, max_date, callback) {\n\t\t\tvar start = new Date(min_date),\n\t\t\t\tend = new Date(max_date);\n\t\t\tif (dateHelper[unit + \"_start\"]) {\n\t\t\t\tstart = dateHelper[unit + \"_start\"](start);\n\t\t\t}\n\n\t\t\tvar curr = new Date(start);\n\t\t\tif (+curr >= +end) {\n\t\t\t\tend = dateHelper.add(curr, step, unit);\n\t\t\t}\n\t\t\twhile (+curr < +end) {\n\t\t\t\tcallback.call(this, new Date(curr));\n\t\t\t\tvar tzOffset = curr.getTimezoneOffset();\n\t\t\t\tcurr = dateHelper.add(curr, step, unit);\n\t\t\t\tcurr = gantt._correct_dst_change(curr, tzOffset, step, unit);\n\t\t\t\tif (dateHelper[unit + '_start'])\n\t\t\t\t\tcurr = dateHelper[unit + \"_start\"](curr);\n\t\t\t}\n\t\t},\n\t\tlimitVisibleRange: function (cfg) {\n\t\t\tvar dates = cfg.trace_x;\n\n\t\t\tvar left = 0, right = cfg.width.length - 1;\n\t\t\tvar diff = 0;\n\t\t\tif (+dates[0] < +cfg.min_date && left != right) {\n\t\t\t\tvar width = Math.floor(cfg.width[0] * ((dates[1] - cfg.min_date) / (dates[1] - dates[0])));\n\t\t\t\tdiff += cfg.width[0] - width;\n\t\t\t\tcfg.width[0] = width;\n\n\t\t\t\tdates[0] = new Date(cfg.min_date);\n\t\t\t}\n\n\t\t\tvar last = dates.length - 1;\n\t\t\tvar lastDate = dates[last];\n\t\t\tvar outDate = dateHelper.add(lastDate, cfg.step, cfg.unit);\n\t\t\tif (+outDate > +cfg.max_date && last > 0) {\n\t\t\t\tvar width = cfg.width[last] - Math.floor(cfg.width[last] * ((outDate - cfg.max_date) / (outDate - lastDate)));\n\t\t\t\tdiff += cfg.width[last] - width;\n\t\t\t\tcfg.width[last] = width;\n\t\t\t}\n\n\t\t\tif (diff) {\n\t\t\t\tvar full = this.getSum(cfg.width);\n\t\t\t\tvar shared = 0;\n\t\t\t\tfor (var i = 0; i < cfg.width.length; i++) {\n\t\t\t\t\tvar share = Math.floor(diff * (cfg.width[i] / full));\n\t\t\t\t\tcfg.width[i] += share;\n\t\t\t\t\tshared += share;\n\t\t\t\t}\n\t\t\t\tthis.adjustSize(diff - shared, cfg.width);\n\t\t\t}\n\n\t\t}\n\t};\n}\n\nexport default ScaleHelper;\n","\nimport ScaleHelper from \"./scales\";\n\nfunction ScaleIgnoreHelper(gantt){\n\tvar helper = new ScaleHelper(gantt);\n\n\thelper.processIgnores = function (config) {\n\t\tvar display_count = config.count;\n\t\tconfig.ignore_x = {};\n\t\tif (gantt.ignore_time || gantt.config.skip_off_time) {\n\t\t\tvar ignore = gantt.ignore_time || function () {\n\t\t\t\treturn false;\n\t\t\t};\n\t\t\tdisplay_count = 0;\n\n\t\t\tfor (var i = 0; i < config.trace_x.length; i++) {\n\n\t\t\t\tif (ignore.call(gantt, config.trace_x[i]) || this._ignore_time_config.call(gantt, config.trace_x[i], config)) {\n\t\t\t\t\tconfig.ignore_x[config.trace_x[i].valueOf()] = true;\n\t\t\t\t\tconfig.ignored_colls = true;\n\t\t\t\t} else {\n\t\t\t\t\tdisplay_count++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tconfig.display_count = display_count;\n\t};\n\n\treturn helper;\n}\n\nexport default ScaleIgnoreHelper;","import ScaleHelper from \"./ui/timeline/scales_ignore\";\nimport PrimaryScaleHelper from \"./ui/timeline/scales\";\n\nfunction resolveConfigRange(unit, gantt){\n\tvar range = {\n\t\tstart_date:null,\n\t\tend_date:null\n\t};\n\n\tif (gantt.config.start_date && gantt.config.end_date) {\n\t\trange.start_date = gantt.date[unit + \"_start\"](new Date(gantt.config.start_date));\n\n\t\tvar end = new Date(gantt.config.end_date);\n\t\tvar start_interval = gantt.date[unit + \"_start\"](new Date(end));\n\t\tif (+end != +start_interval) {\n\t\t\tend = gantt.date.add(start_interval, 1, unit);\n\t\t} else {\n\t\t\tend = start_interval;\n\t\t}\n\n\t\trange.end_date = end;\n\t}\n\treturn range;\n}\n\nfunction _scale_range_unit(gantt) {\n\tvar primaryScale = (new PrimaryScaleHelper(gantt)).primaryScale();\n\tvar unit = primaryScale.unit;\n\tvar step = primaryScale.step;\n\tif (gantt.config.scale_offset_minimal) {\n\n\t\tvar helper = new ScaleHelper(gantt);\n\t\tvar scales = [helper.primaryScale()].concat(helper.getSubScales());\n\n\t\thelper.sortScales(scales);\n\t\tunit = scales[scales.length - 1].unit;\n\t\tstep = scales[scales.length - 1].step || 1;\n\t}\n\treturn { unit:unit, step:step };\n}\n\nfunction _init_tasks_range(gantt) {\n\tvar cfg = _scale_range_unit(gantt);\n\tvar unit = cfg.unit,\n\t\tstep = cfg.step;\n\tvar range = resolveConfigRange(unit, gantt);\n\n\t// GS-1544: Show correct date range if we have tasks or only projects\n\tif(!(range.start_date && range.end_date)){\n\t\tvar onlyProjectTasks = true;\n\t\tvar tasks = gantt.getTaskByTime();\n\t\tfor (var i = 0; i < tasks.length; i++) {\n\t\t\tvar task = tasks[i];\n\t\t\tif (task.type !== gantt.config.types.project){\n\t\t\t\tonlyProjectTasks = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (tasks.length && onlyProjectTasks){\n\t\t\tvar start_date = tasks[0].start_date;\n\t\t\tvar end_date = gantt.date.add(start_date, 1, gantt.config.duration_unit);\n\t\t\trange = {\n\t\t\t\tstart_date: new Date(start_date),\n\t\t\t\tend_date: new Date(end_date)\n\t\t\t};\n\t\t} else{\n\t\t\trange = gantt.getSubtaskDates();\n\t\t}\n\n\t\tif(!range.start_date || !range.end_date){\n\t\t\trange = {\n\t\t\t\tstart_date: new Date(),\n\t\t\t\tend_date: new Date()\n\t\t\t};\n\t\t}\n\t\t// extend the displayed date range including the constraints, deadlines and baselines\n\t\tgantt.eachTask(function(task){\n\t\t\tif (gantt.config.deadlines !== false && task.deadline){\n\t\t\t\textendRangeForDates(range, task.deadline, task.deadline);\n\t\t\t}\n\t\t\tif (task.constraint_date && task.constraint_type){\n\t\t\t\tif (gantt.config.constraint_types && task.constraint_type !== gantt.config.constraint_types.ASAP && task.constraint_type !== gantt.config.constraint_types.ALAP){\n\t\t\t\t\textendRangeForDates(range, task.constraint_date, task.constraint_date);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (gantt.config.baselines !== false && task.baselines){\n\t\t\t\ttask.baselines.forEach(function(baseline){\n\t\t\t\t\textendRangeForDates(range, baseline.start_date, baseline.end_date);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\trange.start_date = gantt.date[unit + \"_start\"](range.start_date);\n\t\trange.start_date = gantt.calculateEndDate({\n\t\t\tstart_date: gantt.date[unit + \"_start\"](range.start_date),\n\t\t\tduration: -1,\n\t\t\tunit: unit,\n\t\t\tstep:step\n\t\t});//one free column before first task\n\n\t\trange.end_date = gantt.date[unit + \"_start\"](range.end_date);\n\t\trange.end_date = gantt.calculateEndDate({start_date: range.end_date, duration: 2, unit: unit, step:step});//one free column after last task\n\t}\n\n\tgantt._min_date = range.start_date;\n\tgantt._max_date = range.end_date;\n}\n\nfunction extendRangeForDates(range, start_date, end_date){\n\tif (start_date < range.start_date){\n\t\trange.start_date = new Date(start_date);\n\t}\n\tif (end_date > range.end_date){\n\t\trange.end_date = new Date(end_date);\n\t}\n}\n\nfunction _adjust_scales(gantt) {\n\tif (gantt.config.fit_tasks) {\n\t\tvar old_min = +gantt._min_date,\n\t\t\told_max = +gantt._max_date;\n\t\t//this._init_tasks_range();\n\t\tif (+gantt._min_date != old_min || +gantt._max_date != old_max) {\n\t\t\tgantt.render();\n\n\t\t\tgantt.callEvent(\"onScaleAdjusted\", []);\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nexport default function updateTasksRange(gantt){\n\t_init_tasks_range(gantt);\n\t_adjust_scales(gantt);\n};\n","function copyLinkIdsArray(gantt, linkIds, targetHash){\n\tfor(var i = 0; i < linkIds.length; i++) {\n\t\tif(gantt.isLinkExists(linkIds[i])){\n\t\t\ttargetHash[linkIds[i]] = gantt.getLink(linkIds[i]);\n\t\t}\n\t}\n}\n\nfunction copyLinkIds(gantt, task, targetHash){\n\tcopyLinkIdsArray(gantt, task.$source, targetHash);\n\tcopyLinkIdsArray(gantt, task.$target, targetHash);\n}\n\nfunction getSubtreeLinks(gantt, rootId){\n\tvar res = {};\n\n\tif(gantt.isTaskExists(rootId)){\n\t\tcopyLinkIds(gantt, gantt.getTask(rootId), res);\n\t}\n\n\tgantt.eachTask(function(child){\n\t\tcopyLinkIds(gantt, child, res);\n\t}, rootId);\n\n\treturn res;\n}\n\nfunction getSubtreeTasks(gantt, rootId){\n\tvar res = {};\n\n\tgantt.eachTask(function(child){\n\t\tres[child.id] = child;\n\t}, rootId);\n\n\treturn res;\n}\n\nexport default {\n\tgetSubtreeLinks: getSubtreeLinks,\n\tgetSubtreeTasks: getSubtreeTasks\n};","import * as helpers from \"../../utils/helpers\";\nimport treeHelper from \"../../utils/task_tree_helpers\";\n\n\nexport default class DataProcessorEvents {\n\tprotected _dataProcessorHandlers: any[];\n\tprotected $gantt: any;\n\tprotected $dp: any;\n\n\tconstructor(gantt: any, dp: any) {\n\t\tthis.$gantt = gantt;\n\t\tthis.$dp = dp;\n\t\tthis._dataProcessorHandlers = [];\n\t}\n\n\tattach() {\n\t\tconst dp = this.$dp;\n\t\tconst gantt = this.$gantt;\n\t\tconst cascadeDelete = {};\n\n\t\tconst clientSideDelete = (id) => {\n\t\t\treturn this.clientSideDelete(id, dp, gantt);\n\t\t};\n\n\t\tfunction getTaskLinks(task) {\n\t\t\tlet _links = [];\n\n\t\t\tif (task.$source) {\n\t\t\t\t_links = _links.concat(task.$source);\n\t\t\t}\n\t\t\tif (task.$target) {\n\t\t\t\t_links = _links.concat(task.$target);\n\t\t\t}\n\n\t\t\treturn _links;\n\t\t}\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onAfterTaskAdd\", function(id, item) { // tslint:disable-line\n\t\t\tif (gantt.isTaskExists(id)) {\n\t\t\t\tdp.setGanttMode(\"tasks\");\n\t\t\t\tdp.setUpdated(id, true, \"inserted\");\n\t\t\t}\n\t\t}));\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onAfterTaskUpdate\", function(id, item) { // tslint:disable-line\n\t\t\tif (gantt.isTaskExists(id)) {\n\t\t\t\tdp.setGanttMode(\"tasks\");\n\t\t\t\tdp.setUpdated(id, true);\n\n\t\t\t\t// gantt can be destroyed/reinitialized after dp.setUpdated\n\t\t\t\tif(gantt._sendTaskOrder){\n\t\t\t\t\tgantt._sendTaskOrder(id, item);\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onBeforeTaskDelete\", function(id, item) { // tslint:disable-line\n\t\t\tif (gantt.config.cascade_delete) {\n\t\t\t\tcascadeDelete[id] = {\n\t\t\t\t\ttasks: treeHelper.getSubtreeTasks(gantt, id),\n\t\t\t\t\tlinks: treeHelper.getSubtreeLinks(gantt, id)\n\t\t\t\t};\n\t\t\t}\n\t\t\t// GS-631. Keep the deleted item in Gantt until we receive the successful response from the server\n\t\t\tif (dp.deleteAfterConfirmation) {\n\t\t\t\tdp.setGanttMode(\"tasks\");\n\t\t\t\tdp.setUpdated(id, true, \"deleted\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}));\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onAfterTaskDelete\", function(id, item) { // tslint:disable-line\n\t\t\tdp.setGanttMode(\"tasks\");\n\n\t\t\t// not send delete request if item is not inserted into the db - just remove it from the client\n\t\t\tconst needDbDelete = !clientSideDelete(id);\n\t\t\tconst needCascadeDelete = gantt.config.cascade_delete && cascadeDelete[id];\n\t\t\tif (!needDbDelete && !needCascadeDelete) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (needCascadeDelete) {\n\t\t\t\tconst dpMode = dp.updateMode;\n\t\t\t\tdp.setUpdateMode(\"off\");\n\n\t\t\t\tconst cascade = cascadeDelete[id];\n\t\t\t\tfor (const i in cascade.tasks) {\n\t\t\t\t\tif (!clientSideDelete(i)) {\n\t\t\t\t\t\tdp.storeItem(cascade.tasks[i]);\n\t\t\t\t\t\tdp.setUpdated(i, true, \"deleted\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdp.setGanttMode(\"links\");\n\t\t\t\tfor (const i in cascade.links) {\n\t\t\t\t\tif (!clientSideDelete(i)) {\n\t\t\t\t\t\tdp.storeItem(cascade.links[i]);\n\t\t\t\t\t\tdp.setUpdated(i, true, \"deleted\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcascadeDelete[id] = null;\n\n\t\t\t\tif (dpMode !== \"off\") {\n\t\t\t\t\tdp.sendAllData();\n\t\t\t\t}\n\t\t\t\tdp.setGanttMode(\"tasks\");\n\t\t\t\tdp.setUpdateMode(dpMode);\n\t\t\t}\n\n\t\t\tif (needDbDelete){\n\t\t\t\tdp.storeItem(item);\n\t\t\t\tif (!dp.deleteAfterConfirmation){\n\t\t\t\t\tdp.setUpdated(id, true, \"deleted\");\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tif (dp.updateMode !== \"off\" && !dp._tSend) {\n\t\t\t\tdp.sendAllData();\n\t\t\t}\n\t\t}));\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onAfterLinkUpdate\", function(id, item) { // tslint:disable-line\n\t\t\tif (gantt.isLinkExists(id)) {\n\t\t\t\tdp.setGanttMode(\"links\");\n\t\t\t\tdp.setUpdated(id, true);\n\t\t\t}\n\t\t}));\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onAfterLinkAdd\", function(id, item) { // tslint:disable-line\n\t\t\tif (gantt.isLinkExists(id)) {\n\t\t\t\tdp.setGanttMode(\"links\");\n\t\t\t\tdp.setUpdated(id, true,\"inserted\");\n\t\t\t}\n\t\t}));\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onAfterLinkDelete\", function(id, item) { // tslint:disable-line\n\t\t\tdp.setGanttMode(\"links\");\n\n\t\t\tconst needDbDelete = !clientSideDelete(id);\n\t\t\tif (!needDbDelete) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdp.storeItem(item);\n\t\t\tdp.setUpdated(id, true,\"deleted\");\n\t\t}));\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onRowDragEnd\", function(id, target) { // tslint:disable-line\n\t\t\tgantt._sendTaskOrder(id, gantt.getTask(id));\n\t\t}));\n\n\t\tlet tasks = null;\n\t\tlet links = null;\n\n\t\tthis._dataProcessorHandlers.push(gantt.attachEvent(\"onTaskIdChange\", function(oldId, newId) { // tslint:disable-line\n\t\t\tif (!dp._waitMode) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst children = gantt.getChildren(newId);\n\t\t\tif (children.length) {\n\t\t\t\ttasks = tasks || {};\n\n\t\t\t\tfor (let i = 0; i < children.length; i++) {\n\t\t\t\t\tconst ch = this.getTask(children[i]);\n\t\t\t\t\ttasks[ch.id] = ch;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst item = this.getTask(newId);\n\t\t\tconst itemLinks = getTaskLinks(item);\n\n\t\t\tif (itemLinks.length) {\n\t\t\t\tlinks = links || {};\n\n\t\t\t\tfor (let i = 0; i < itemLinks.length; i++) {\n\t\t\t\t\tconst link = this.getLink(itemLinks[i]);\n\t\t\t\t\tlinks[link.id] = link;\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\t\tdp.attachEvent(\"onAfterUpdateFinish\", function() {\n\t\t\tif (tasks || links) {\n\t\t\t\tgantt.batchUpdate(function() {\n\t\t\t\t\tfor (const id in tasks) {\n\t\t\t\t\t\tgantt.updateTask(tasks[id].id);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const id in links) {\n\t\t\t\t\t\tgantt.updateLink(links[id].id);\n\t\t\t\t\t}\n\t\t\t\t\ttasks = null;\n\t\t\t\t\tlinks = null;\n\t\t\t\t});\n\t\t\t\tif (tasks) {\n\t\t\t\t\tgantt._dp.setGanttMode(\"tasks\");\n\t\t\t\t} else {\n\t\t\t\t\tgantt._dp.setGanttMode(\"links\");\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tdp.attachEvent(\"onBeforeDataSending\", function() {\n\t\t\tif (this._tMode === \"CUSTOM\") {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tlet url = this._serverProcessor;\n\t\t\tif (this._tMode === \"REST-JSON\" || this._tMode === \"REST\") {\n\t\t\t\tconst mode = this._ganttMode;\n\n\t\t\t\turl = url.substring(0, url.indexOf(\"?\") > -1 ? url.indexOf(\"?\") : url.length);\n\t\t\t\t// editing=true&\n\t\t\t\tthis.serverProcessor = url + (url.slice(-1) === \"/\" ? \"\" : \"/\") + mode;\n\t\t\t} else {\n\t\t\t\tconst pluralizedMode = this._ganttMode + \"s\";\n\t\t\t\tthis.serverProcessor = url + gantt.ajax.urlSeparator(url) + \"gantt_mode=\" + pluralizedMode;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t});\n\n\t\tdp.attachEvent(\"insertCallback\", function insertCallback(upd, id, parent, mode) { // tslint:disable-line\n\t\t\tconst data = upd.data || gantt.xml._xmlNodeToJSON(upd.firstChild);\n\t\t\tconst methods = {\n\t\t\t\tadd: gantt.addTask,\n\t\t\t\tisExist: gantt.isTaskExists\n\t\t\t};\n\t\t\tif (mode === \"links\") {\n\t\t\t\tmethods.add = gantt.addLink;\n\t\t\t\tmethods.isExist = gantt.isLinkExists;\n\t\t\t}\n\t\t\tif (methods.isExist.call(gantt, id)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdata.id = id;\n\t\t\tmethods.add.call(gantt, data);\n\t\t});\n\n\t\tdp.attachEvent(\"updateCallback\", function updateCallback(upd, id) {\n\t\t\tconst data = upd.data || gantt.xml._xmlNodeToJSON(upd.firstChild);\n\t\t\tif (!gantt.isTaskExists(id)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst objData = gantt.getTask(id);\n\t\t\tfor (const key in data) {\n\t\t\t\tlet property = data[key];\n\t\t\t\tswitch (key) {\n\t\t\t\t\tcase \"id\":\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase \"start_date\":\n\t\t\t\t\tcase \"end_date\":\n\t\t\t\t\t\tproperty = gantt.defined(gantt.templates.xml_date) ? gantt.templates.xml_date(property) : gantt.templates.parse_date(property);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"duration\":\n\t\t\t\t\t\tobjData.end_date = gantt.calculateEndDate({start_date: objData.start_date, duration: property, task:objData});\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tobjData[key] = property;\n\t\t\t}\n\t\t\tgantt.updateTask(id);\n\t\t\tgantt.refreshData();\n\t\t});\n\t\tdp.attachEvent(\"deleteCallback\", function deleteCallback(upd, id, parent, mode) { // tslint:disable-line\n\t\t\tconst methods = {\n\t\t\t\tdelete: gantt.deleteTask,\n\t\t\t\tisExist: gantt.isTaskExists\n\t\t\t};\n\t\t\tif (mode === \"links\") {\n\t\t\t\tmethods.delete = gantt.deleteLink;\n\t\t\t\tmethods.isExist = gantt.isLinkExists;\n\t\t\t} else if(mode === \"assignment\") {\n\t\t\t\tmethods.delete = function(val) {\n\t\t\t\t\tgantt.$data.assignmentsStore.remove(val);\n\t\t\t\t};\n\t\t\t\tmethods.isExist = function(val){\n\t\t\t\t\treturn gantt.$data.assignmentsStore.exists(val);\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (methods.isExist.call(gantt, id)) {\n\t\t\t\tmethods.delete.call(gantt, id);\n\t\t\t}\n\t\t});\n\n\t\tthis.handleResourceCRUD(dp, gantt);\n\t\tthis.handleResourceAssignmentCRUD(dp, gantt);\n\t\tthis.handleBaselineCRUD(dp, gantt);\n\t}\n\n\tclientSideDelete(id, dp, gantt){\n\t\tconst updated = dp.updatedRows.slice();\n\t\tlet clientOnly = false;\n\n\t\tif(gantt.getUserData(id, \"!nativeeditor_status\", dp._ganttMode) === \"true_deleted\"){\n\t\t\tclientOnly = true;\n\t\t\tdp.setUpdated(id,false);\n\t\t}\n\n\t\tfor (let i = 0; i < updated.length && !dp._in_progress[id]; i++) {\n\t\t\tif (updated[i] === id) {\n\t\t\t\tif (gantt.getUserData(id, \"!nativeeditor_status\", dp._ganttMode) === \"inserted\") {\n\t\t\t\t\tclientOnly = true;\n\t\t\t\t}\n\t\t\t\tdp.setUpdated(id,false);\n\t\t\t}\n\t\t}\n\t\treturn clientOnly;\n\t}\n\n\thandleResourceAssignmentCRUD(dp, gantt){\n\t\tif(!gantt.config.resources || gantt.config.resources.dataprocessor_assignments !== true){\n\t\t\treturn;\n\t\t}\n\n\t\tconst assignmentsStore = gantt.getDatastore(gantt.config.resource_assignment_store);\n\t\tconst insertedTasks = {};\n\t\tconst pendingAssignments = {};\n\n\t\tgantt.attachEvent(\"onBeforeTaskAdd\", function(id, task){\n\t\t\tinsertedTasks[id] = true;\n\t\t\treturn true;\n\t\t});\n\n\t\tfunction putAssignmentToQueue(item){\n\t\t\tpendingAssignments[item.id] = item;\n\t\t\tinsertedTasks[item.task_id] = true;\n\t\t}\n\n\t\tfunction insertResourceAssignment(assignment){\n\t\t\tconst id = assignment.id;\n\t\t\tif (assignmentsStore.exists(id)) {\n\t\t\t\tdp.setGanttMode(\"assignment\");\n\t\t\t\tdp.setUpdated(id, true,\"inserted\");\n\t\t\t}\n\t\t\tdelete pendingAssignments[id];\n\t\t}\n\n\t\tgantt.attachEvent(\"onTaskIdChange\", function(id, newId){\n\t\t\tdelete insertedTasks[id];\n\t\t});\n\n\t\tassignmentsStore.attachEvent(\"onAfterAdd\", (id, item) => {\n\t\t\tif(insertedTasks[item.task_id]){\n\t\t\t\t// inserting assignment of new task\n\t\t\t\t// task is not saved yet, need to wait till it gets permanent id and save assigmnents after that\n\t\t\t\tputAssignmentToQueue(item);\n\t\t\t}else{\n\t\t\t\tinsertResourceAssignment(item);\n\t\t\t}\n\t\t});\n\n\t\tassignmentsStore.attachEvent(\"onAfterUpdate\", (id, item) => {\n\t\t\tif (assignmentsStore.exists(id)) {\n\t\t\t\tif(pendingAssignments[id]){\n\t\t\t\t\tinsertResourceAssignment(item);\n\t\t\t\t}else{\n\t\t\t\t\tdp.setGanttMode(\"assignment\");\n\t\t\t\t\tdp.setUpdated(id, true);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tassignmentsStore.attachEvent(\"onAfterDelete\", (id, item) => {\n\t\t\tdp.setGanttMode(\"assignment\");\n\n\t\t\tconst needDbDelete = !this.clientSideDelete(id, dp, gantt);\n\t\t\tif (!needDbDelete) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdp.storeItem(item);\n\t\t\tdp.setUpdated(id, true,\"deleted\");\n\t\t});\n\n\t}\n\n\thandleResourceCRUD(dp, gantt){\n\t\tif(!gantt.config.resources || gantt.config.resources.dataprocessor_resources !== true){\n\t\t\treturn;\n\t\t}\n\n\t\tconst resourcesStore = gantt.getDatastore(gantt.config.resource_store);\n\n\t\tfunction insertResource(resource){\n\t\t\tconst id = resource.id;\n\t\t\tif (resourcesStore.exists(id)) {\n\t\t\t\tdp.setGanttMode(\"resource\");\n\t\t\t\tdp.setUpdated(id, true,\"inserted\");\n\t\t\t}\n\t\t}\n\n\t\tresourcesStore.attachEvent(\"onAfterAdd\", (id, item) => {\n\t\t\tinsertResource(item);\n\t\t});\n\n\t\tresourcesStore.attachEvent(\"onAfterUpdate\", (id, item) => {\n\t\t\tif (resourcesStore.exists(id)) {\n\t\t\t\tdp.setGanttMode(\"resource\");\n\t\t\t\tdp.setUpdated(id, true);\n\t\t\t}\n\t\t});\n\n\t\tresourcesStore.attachEvent(\"onAfterDelete\", (id, item) => {\n\t\t\tdp.setGanttMode(\"resource\");\n\n\t\t\tconst needDbDelete = !this.clientSideDelete(id, dp, gantt);\n\t\t\tif (!needDbDelete) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdp.storeItem(item);\n\t\t\tdp.setUpdated(id, true,\"deleted\");\n\t\t});\n\n\t}\n\n\thandleBaselineCRUD(dp, gantt){\n\t\tif(!gantt.config.baselines || gantt.config.baselines.dataprocessor_baselines !== true){\n\t\t\treturn;\n\t\t}\n\n\t\tconst baselineStore = gantt.getDatastore(gantt.config.baselines.datastore);\n\n\t\tfunction insertResource(resource){\n\t\t\tconst id = resource.id;\n\t\t\tif (baselineStore.exists(id)) {\n\t\t\t\tdp.setGanttMode(\"baseline\");\n\t\t\t\tdp.setUpdated(id, true,\"inserted\");\n\t\t\t}\n\t\t}\n\n\t\tbaselineStore.attachEvent(\"onAfterAdd\", (id, item) => {\n\t\t\tinsertResource(item);\n\t\t});\n\n\t\tbaselineStore.attachEvent(\"onAfterUpdate\", (id, item) => {\n\t\t\tif (baselineStore.exists(id)) {\n\t\t\t\tdp.setGanttMode(\"baseline\");\n\t\t\t\tdp.setUpdated(id, true);\n\t\t\t}\n\t\t});\n\n\t\tbaselineStore.attachEvent(\"onAfterDelete\", (id, item) => {\n\t\t\tdp.setGanttMode(\"baseline\");\n\n\t\t\tconst needDbDelete = !this.clientSideDelete(id, dp, gantt);\n\t\t\tif (!needDbDelete) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdp.storeItem(item);\n\t\t\tdp.setUpdated(id, true,\"deleted\");\n\t\t});\n\t}\n\n\tdetach() {\n\t\thelpers.forEach(this._dataProcessorHandlers, (e) => {\n\t\t\tthis.$gantt.detachEvent(e);\n\t\t});\n\t\tthis._dataProcessorHandlers = [];\n\t}\n}\n","import * as utils from \"../../utils/utils\";\n\nexport default class SimpleStorage {\n\tpublic static create = () : SimpleStorage => {\n\t\treturn new SimpleStorage();\n\t};\n\n\tprotected _storage: { [id: string]: any; };\n\n\tprotected constructor() {\n\t\tthis._storage = {};\n\t}\n\n\tpublic clear = (): void => {\n\t\tthis._storage = {};\n\t};\n\n\tpublic storeItem = (item: any): void => {\n\t\tthis._storage[item.id] = utils.copy(item);\n\t};\n\n\tpublic getStoredItem = (id: string): any => {\n\t\treturn this._storage[id] || null;\n\t};\n}","import eventable from \"../../utils/eventable\";\nimport * as helpers from \"../../utils/helpers\";\nimport * as utils from \"../../utils/utils\";\nimport DataProcessorEvents from \"./data_processor_events\";\nimport extendGantt from \"./extend_gantt\";\nimport SimpleStorage from \"./simple_storage\";\nimport global from \"../../utils/global\";\n\nexport interface DataProcessor { // tslint:disable-line\n\t$gantt: any;\n\tdetachAllEvents: any;\n\tattachEvent: any;\n\tcallEvent: any;\n\n\tserverProcessor: string;\n\taction_param: string;\n\tupdatedRows: any[];\n\tautoUpdate: boolean;\n\tupdateMode: string;\n\tmessages: any[];\n\tstyles: object;\n\tdnd: any;\n\tdeleteAfterConfirmation?: any;\n}\n\nexport function createDataProcessor(config: any) {\n\tlet router;\n\tlet tMode;\n\tlet headers;\n\tif (config instanceof Function) {\n\t\trouter = config;\n\t} else if (config.hasOwnProperty(\"router\")) {\n\t\trouter = config.router;\n\t} else if (config.hasOwnProperty(\"assignment\") || config.hasOwnProperty(\"baseline\") || config.hasOwnProperty(\"link\") || config.hasOwnProperty(\"task\")) {\n\t\trouter = config;\n\t} else if(config.hasOwnProperty(\"headers\")){\n\t\t// GS-2312 for custom headers\n\t\theaders = config.headers;\n\t}\n\tif (router) {\n\t\ttMode = \"CUSTOM\";\n\t} else {\n\t\ttMode = config.mode || \"REST-JSON\";\n\t}\n\tconst gantt = this; // tslint:disable-line\n\tconst dp = new DataProcessor(config.url);\n\n\n\tdp.init(gantt);\n\tdp.setTransactionMode({\n\t\tmode: tMode,\n\t\trouter,\n\t\theaders\n\t}, config.batchUpdate);\n\tif(config.deleteAfterConfirmation){\n\t\tdp.deleteAfterConfirmation = config.deleteAfterConfirmation;\n\t}\n\treturn dp;\n}\n\nexport class DataProcessor {\n\tpublic modes: object;\n\tpublic serverProcessor: string;\n\tpublic action_param: string; // tslint:disable-line\n\tpublic updatedRows: any[];\n\tpublic autoUpdate: boolean;\n\tpublic updateMode: string;\n\tpublic messages: any[];\n\tpublic styles: object;\n\tpublic dnd: any;\n\n\tprotected _tMode: string;\n\tprotected _headers: any;\n\tprotected _payload: any;\n\tprotected _postDelim: string;\n\tprotected _waitMode: number;\n\tprotected _in_progress: object; // tslint:disable-line\n\tprotected _invalid: object;\n\tprotected _storage: SimpleStorage;\n\tprotected _tSend: boolean;\n\tprotected _serializeAsJson: boolean;\n\tprotected _router: any;\n\tprotected _utf: boolean;\n\tprotected _methods: any[];\n\tprotected _user: any;\n\tprotected _uActions: object;\n\tprotected _needUpdate: boolean;\n\tprotected _ganttMode: \"task\"|\"link\";\n\tprotected _routerParametersFormat: \"parameters\"|\"object\";\n\n\tprotected _silent_mode: any; // tslint:disable-line\n\tprotected _updateBusy: any;\n\tprotected _serverProcessor: any;\n\tprotected _initialized: boolean;\n\n\tconstructor(serverProcessorURL?) {\n\t\tthis.serverProcessor = serverProcessorURL;\n\t\tthis.action_param = \"!nativeeditor_status\";\n\n\t\tthis.updatedRows = []; // ids of updated rows\n\n\t\tthis.autoUpdate = true;\n\t\tthis.updateMode = \"cell\";\n\t\tthis._headers = null;\n\t\tthis._payload = null;\n\t\tthis._postDelim = \"_\";\n\t\tthis._routerParametersFormat = \"parameters\";\n\n\t\tthis._waitMode = 0;\n\t\tthis._in_progress = {}; // ?\n\t\tthis._storage = SimpleStorage.create();\n\t\tthis._invalid = {};\n\t\tthis.messages = [];\n\n\t\tthis.styles = {\n\t\t\tupdated: \"font-weight:bold;\",\n\t\t\tinserted: \"font-weight:bold;\",\n\t\t\tdeleted: \"text-decoration : line-through;\",\n\t\t\tinvalid: \"background-color:FFE0E0;\",\n\t\t\tinvalid_cell: \"border-bottom:2px solid red;\",\n\t\t\terror: \"color:red;\",\n\t\t\tclear: \"font-weight:normal;text-decoration:none;\"\n\t\t};\n\t\tthis.enableUTFencoding(true);\n\t\teventable(this);\n\t}\n\n\tsetTransactionMode(mode:any, total?:any) {\n\t\tif (typeof mode === \"object\") {\n\t\t\tthis._tMode = mode.mode || this._tMode;\n\n\t\t\tif (utils.defined(mode.headers)) {\n\t\t\t\tthis._headers = mode.headers;\n\t\t\t}\n\n\t\t\tif (utils.defined(mode.payload)) {\n\t\t\t\tthis._payload = mode.payload;\n\t\t\t}\n\t\t\tthis._tSend = !!total;\n\t\t} else {\n\t\t\tthis._tMode = mode;\n\t\t\tthis._tSend = total;\n\t\t}\n\n\t\tif (this._tMode === \"REST\") {\n\t\t\tthis._tSend = false;\n\t\t}\n\n\t\tif (this._tMode === \"JSON\" || this._tMode === \"REST-JSON\") {\n\t\t\tthis._tSend = false;\n\t\t\tthis._serializeAsJson = true;\n\t\t\tthis._headers = this._headers || {};\n\t\t\tthis._headers[\"Content-Type\"] = \"application/json\";\n\t\t}else{\n\t\t\tif(this._headers && !this._headers[\"Content-Type\"]){\n\t\t\t\tthis._headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n\t\t\t}\n\t\t}\n\n\t\tif (this._tMode === \"CUSTOM\") {\n\t\t\tthis._tSend = false;\n\t\t\tthis._router = mode.router;\n\t\t}\n\t}\n\n\tescape(data:any) {\n\t\tif (this._utf) {\n\t\t\treturn encodeURIComponent(data);\n\t\t} else {\n\t\t\treturn escape(data);\n\t\t}\n\t}\n\n\t/**\n\t * @desc: allows to set escaping mode\n\t * @param: true - utf based escaping, simple - use current page encoding\n\t * @type: public\n\t */\n\tenableUTFencoding(mode:boolean) {\n\t\tthis._utf = !!mode;\n\t}\n\n\t/**\n\t * @desc: get state of updating\n\t * @returns: true - all in sync with server, false - some items not updated yet.\n\t * @type: public\n\t */\n\tgetSyncState() {\n\t\treturn !this.updatedRows.length;\n\t}\n\n\t/**\n\t * @desc: set if rows should be send to server automatically\n\t * @param: mode - \"row\" - based on row selection changed, \"cell\" - based on cell editing finished, \"off\" - manual data sending\n\t * @type: public\n\t */\n\tsetUpdateMode(mode: string, dnd: any) {\n\t\tthis.autoUpdate = (mode === \"cell\");\n\t\tthis.updateMode = mode;\n\t\tthis.dnd = dnd;\n\t}\n\n\tignore(code: any, master: any) {\n\t\tthis._silent_mode = true;\n\t\tcode.call(master || global);\n\t\tthis._silent_mode = false;\n\t}\n\n\t/**\n\t * @desc: mark row as updated/normal. check mandatory fields, initiate autoupdate (if turned on)\n\t * @param: rowId - id of row to set update-status for\n\t * @param: state - true for \"updated\", false for \"not updated\"\n\t * @param: mode - update mode name\n\t * @type: public\n\t */\n\tsetUpdated(rowId:number|string, state: boolean, mode?: string) {\n\t\tif (this._silent_mode) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst ind = this.findRow(rowId);\n\n\t\tmode = mode || \"updated\";\n\t\tconst existing = this.$gantt.getUserData(rowId, this.action_param, this._ganttMode);\n\t\tif (existing && mode === \"updated\") {\n\t\t\tmode = existing;\n\t\t}\n\t\tif (state) {\n\t\t\tthis.set_invalid(rowId, false); // clear previous error flag\n\t\t\tthis.updatedRows[ind] = rowId;\n\t\t\tthis.$gantt.setUserData(rowId, this.action_param, mode, this._ganttMode);\n\t\t\tif (this._in_progress[rowId]) {\n\t\t\t\tthis._in_progress[rowId] = \"wait\";\n\t\t\t}\n\t\t} else {\n\t\t\tif (!this.is_invalid(rowId)) {\n\t\t\t\tthis.updatedRows.splice(ind, 1);\n\t\t\t\tthis.$gantt.setUserData(rowId, this.action_param, \"\", this._ganttMode);\n\t\t\t}\n\t\t}\n\n\t\tthis.markRow(rowId, state, mode);\n\t\tif (state && this.autoUpdate) {\n\t\t\tthis.sendData(rowId);\n\t\t}\n\t}\n\n\tmarkRow(id: number | string, state: boolean, mode: string) {\n\t\tlet str = \"\";\n\t\tconst invalid = this.is_invalid(id);\n\t\tif (invalid) {\n\t\t\tstr = this.styles[invalid];\n\t\t\tstate = true;\n\t\t}\n\t\tif (this.callEvent(\"onRowMark\", [id, state, mode, invalid])) {\n\t\t\t// default logic\n\t\t\tstr = this.styles[state ? mode : \"clear\"] + \" \" + str;\n\n\t\t\tthis.$gantt[this._methods[0]](id, str);\n\n\t\t\tif (invalid && invalid.details) {\n\t\t\t\tstr += this.styles[invalid + \"_cell\"];\n\t\t\t\tfor (let i = 0; i < invalid.details.length; i++) {\n\t\t\t\t\tif (invalid.details[i]) {\n\t\t\t\t\t\tthis.$gantt[this._methods[1]](id, i, str);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tgetActionByState(state: string):string {\n\t\tif (state === \"inserted\") {\n\t\t\treturn \"create\";\n\t\t}\n\n\t\tif (state === \"updated\") {\n\t\t\treturn \"update\";\n\t\t}\n\n\t\tif (state === \"deleted\") {\n\t\t\treturn \"delete\";\n\t\t}\n\n\t\t// reorder\n\t\treturn \"update\";\n\t}\n\n\tgetState(id: number | string) {\n\t\treturn this.$gantt.getUserData(id, this.action_param, this._ganttMode);\n\t}\n\n\tis_invalid(id: number | string) {\n\t\treturn this._invalid[id];\n\t}\n\n\tset_invalid(id: number | string, mode: any, details?) {\n\t\tif (details) {\n\t\t\tmode = {\n\t\t\t\tvalue: mode,\n\t\t\t\tdetails,\n\t\t\t\ttoString: function() { // tslint:disable-line\n\t\t\t\t\treturn this.value.toString();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\tthis._invalid[id] = mode;\n\t}\n\n\t/**\n\t * @desc: check mandatory fields and verify values of cells, initiate update (if specified). Can be redefined in order to provide custom validation\n\t * @param: rowId - id of row to set update-status for\n\t * @type: public\n\t */\n\t// tslint:disable-next-line\n\tcheckBeforeUpdate(rowId: number | string) {\n\t\treturn true;\n\t}\n\n\t/**\n\t * @desc: send row(s) values to server\n\t * @param: rowId - id of row which data to send. If not specified, then all \"updated\" rows will be send\n\t * @type: public\n\t */\n\tsendData(rowId?: any) {\n\t\tif (this.$gantt.editStop) {\n\t\t\tthis.$gantt.editStop();\n\t\t}\n\n\t\tif (typeof rowId === \"undefined\" || this._tSend) {\n\n\t\t\tconst pendingUpdateModes = [];\n\t\t\tif(this.modes){\n\t\t\t\tconst knownModes = [\"task\", \"link\", \"assignment\", \"baseline\"];\n\t\t\t\tknownModes.forEach((mode) => {\n\t\t\t\t\tif(this.modes[mode] && this.modes[mode].updatedRows.length){\n\t\t\t\t\t\tpendingUpdateModes.push(mode);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (pendingUpdateModes.length){\n\t\t\t\tfor(let i = 0; i < pendingUpdateModes.length; i++){\n\t\t\t\t\tthis.setGanttMode(pendingUpdateModes[i]);\n\t\t\t\t\tthis.sendAllData();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\treturn this.sendAllData();\n\t\t\t}\n\t\t}\n\t\tif (this._in_progress[rowId]) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.messages = [];\n\t\tif (!this.checkBeforeUpdate(rowId) && this.callEvent(\"onValidationError\", [rowId, this.messages])) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._beforeSendData(this._getRowData(rowId), rowId);\n\t}\n\n\tserialize(data: any, id: any) {\n\t\tif (this._serializeAsJson) {\n\t\t\treturn this._serializeAsJSON(data);\n\t\t}\n\n\t\tif (typeof data === \"string\") {\n\t\t\treturn data;\n\t\t}\n\t\tif (typeof id !== \"undefined\") {\n\t\t\treturn this.serialize_one(data, \"\");\n\t\t} else {\n\t\t\tconst stack = [];\n\t\t\tconst keys = [];\n\t\t\tfor (const key in data) {\n\t\t\t\tif (data.hasOwnProperty(key)) {\n\t\t\t\t\tstack.push(this.serialize_one(data[key], key + this._postDelim));\n\t\t\t\t\tkeys.push(key);\n\t\t\t\t}\n\t\t\t}\n\t\t\tstack.push(\"ids=\" + this.escape(keys.join(\",\")));\n\t\t\tif (this.$gantt.security_key) {\n\t\t\t\tstack.push(\"dhx_security=\" + this.$gantt.security_key);\n\t\t\t}\n\t\t\treturn stack.join(\"&\");\n\t\t}\n\t}\n\n\tserialize_one(data: any, pref: string) {\n\t\tif (typeof data === \"string\") {\n\t\t\treturn data;\n\t\t}\n\t\tconst stack = [];\n\t\tlet serialized = \"\";\n\t\tfor (const key in data)\n\t\t\tif (data.hasOwnProperty(key)) {\n\t\t\t\tif ((key === \"id\" ||\n\t\t\t\t\tkey == this.action_param) && // tslint:disable-line\n\t\t\t\t\tthis._tMode === \"REST\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (typeof data[key] === \"string\" || typeof data[key] === \"number\") {\n\t\t\t\t\tserialized = String(data[key]);\n\t\t\t\t} else {\n\t\t\t\t\tserialized = JSON.stringify(data[key]);\n\t\t\t\t}\n\t\t\t\tstack.push(this.escape((pref || \"\") + key) + \"=\" + this.escape(serialized));\n\t\t\t}\n\t\treturn stack.join(\"&\");\n\t}\n\n\tsendAllData() {\n\t\tif (!this.updatedRows.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.messages = [];\n\t\tlet valid: any = true;\n\n\t\tthis._forEachUpdatedRow(function(rowId) {\n\t\t\tvalid = valid && this.checkBeforeUpdate(rowId);\n\t\t});\n\n\t\tif (!valid && !this.callEvent(\"onValidationError\", [\"\", this.messages])) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._tSend) {\n\t\t\tthis._sendData(this._getAllData());\n\t\t} else {\n\t\t\t// this.updatedRows can be spliced from onBeforeUpdate via dp.setUpdated false\n\t\t\t// use an iterator instead of for(var i = 0; i < this.updatedRows; i++) then\n\t\t\tthis._forEachUpdatedRow(function(rowId) {\n\t\t\t\tif (!this._in_progress[rowId]) {\n\t\t\t\t\tif (this.is_invalid(rowId)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis._beforeSendData(this._getRowData(rowId), rowId);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tfindRow(pattern: any) {\n\t\tlet i = 0;\n\t\tfor (i = 0; i < this.updatedRows.length; i++) {\n\t\t\tif (pattern == this.updatedRows[i]) { // tslint:disable-line\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn i;\n\t}\n\n\t/**\n\t * @desc: define custom actions\n\t * @param: name - name of action, same as value of action attribute\n\t * @param: handler - custom function, which receives a XMl response content for action\n\t * @type: private\n\t */\n\tdefineAction(name: string, handler: any) {\n\t\tif (!this._uActions) {\n\t\t\tthis._uActions = {};\n\t\t}\n\t\tthis._uActions[name] = handler;\n\t}\n\n\t/**\n\t * @desc: used in combination with setOnBeforeUpdateHandler to create custom client-server transport system\n\t * @param: sid - id of item before update\n\t * @param: tid - id of item after up0ate\n\t * @param: action - action name\n\t * @type: public\n\t * @topic: 0\n\t */\n\tafterUpdateCallback(sid: number | string, tid: number | string, action: string, btag: any, ganttMode: string) {\n\t\tif(!this.$gantt){\n\t\t\t// destructor has been called before the callback\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setGanttMode(ganttMode);\n\n\t\tconst marker = sid;\n\t\tconst correct = (action !== \"error\" && action !== \"invalid\");\n\t\tif (!correct) {\n\t\t\tthis.set_invalid(sid, action);\n\t\t}\n\t\tif ((this._uActions) && (this._uActions[action]) && (!this._uActions[action](btag))) {\n\t\t\treturn (delete this._in_progress[marker]);\n\t\t}\n\n\t\tif (this._in_progress[marker] !== \"wait\") {\n\t\t\tthis.setUpdated(sid, false);\n\t\t}\n\n\t\tconst originalSid = sid;\n\n\t\tswitch (action) {\n\t\t\tcase \"inserted\":\n\t\t\tcase \"insert\":\n\t\t\t\tif (tid != sid) { // tslint:disable-line\n\t\t\t\t\tthis.setUpdated(sid, false);\n\t\t\t\t\tthis.$gantt[this._methods[2]](sid, tid);\n\t\t\t\t\tsid = tid;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"delete\":\n\t\t\tcase \"deleted\":\n\t\t\t\tif(!this.deleteAfterConfirmation || this._ganttMode !== \"task\"){\n\t\t\t\t\tthis.$gantt.setUserData(sid, this.action_param, \"true_deleted\", this._ganttMode);\n\t\t\t\t\tthis.$gantt[this._methods[3]](sid);\n\t\t\t\t\tdelete this._in_progress[marker];\n\t\t\t\t\treturn this.callEvent(\"onAfterUpdate\", [sid, action, tid, btag]);\n\t\t\t\t}else{\n\t\t\t\t\tif (this._ganttMode === \"task\" && this.$gantt.isTaskExists(sid)) {\n\t\t\t\t\t\tthis.$gantt.setUserData(sid, this.action_param, \"true_deleted\", this._ganttMode);\n\t\t\t\t\t\tconst task = this.$gantt.getTask(sid);\n\t\t\t\t\t\tthis.$gantt.silent(() => {\n\t\t\t\t\t\t\tthis.$gantt.deleteTask(sid);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.$gantt.callEvent(\"onAfterTaskDelete\", [sid, task]);\n\t\t\t\t\t\tthis.$gantt.render();\n\t\t\t\t\t\tdelete this._in_progress[marker];\n\t\t\t\t\t}\n\t\t\t\t\treturn this.callEvent(\"onAfterUpdate\", [sid, action, tid, btag]);\n\t\t\t\t}\n\n\t\t}\n\n\t\tif (this._in_progress[marker] !== \"wait\") {\n\t\t\tif (correct) {\n\t\t\t\tthis.$gantt.setUserData(sid, this.action_param, \"\", this._ganttMode);\n\t\t\t}\n\t\t\tdelete this._in_progress[marker];\n\t\t} else {\n\t\t\tdelete this._in_progress[marker];\n\t\t\tthis.setUpdated(tid, true, this.$gantt.getUserData(sid, this.action_param, this._ganttMode));\n\t\t}\n\n\t\tthis.callEvent(\"onAfterUpdate\", [originalSid, action, tid, btag]);\n\t}\n\n\t/**\n\t * @desc: response from server\n\t * @param: xml - XMLLoader object with response XML\n\t * @type: private\n\t */\n\tafterUpdate(that: any, xml: any, id?:any) {\n\t\tlet _xml;\n\t\tif (arguments.length === 3) {\n\t\t\t_xml = arguments[1];\n\t\t} else {\n\t\t\t// old dataprocessor\n\t\t\t_xml = arguments[4];\n\t\t}\n\t\tlet mode = this.getGanttMode();\n\t\tconst reqUrl = _xml.filePath || _xml.url;\n\n\t\tif (this._tMode !== \"REST\" && this._tMode !== \"REST-JSON\") {\n\t\t\tif (reqUrl.indexOf(\"gantt_mode=links\") !== -1) {\n\t\t\t\tmode = \"link\";\n\t\t\t} else if (reqUrl.indexOf(\"gantt_mode=assignments\") !== -1) {\n\t\t\t\tmode = \"assignment\";\n\t\t\t} else if (reqUrl.indexOf(\"gantt_mode=baselines\") !== -1) {\n\t\t\t\tmode = \"baseline\";\n\t\t\t} else {\n\t\t\t\tmode = \"task\";\n\t\t\t}\n\t\t} else {\n\t\t\tif (reqUrl.indexOf(\"/link\") >= 0) {\n\t\t\t\tmode = \"link\";\n\t\t\t} else if(reqUrl.indexOf(\"/assignment\") >= 0){\n\t\t\t\tmode = \"assignment\";\n\t\t\t} else if(reqUrl.indexOf(\"/baseline\") >= 0){\n\t\t\t\tmode = \"baseline\";\n\t\t\t} else {\n\t\t\t\tmode = \"task\";\n\t\t\t}\n\t\t}\n\t\tthis.setGanttMode(mode);\n\n\t\tconst ajax = this.$gantt.ajax;\n\t\t// try to use json first\n\t\tlet tag;\n\n\t\ttry {\n\t\t\ttag = JSON.parse(xml.xmlDoc.responseText);\n\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\t} catch (e) {\n\n\t\t\t// empty response also can be processed by json handler\n\t\t\tif (!xml.xmlDoc.responseText.length) {\n\t\t\t\ttag = {};\n\t\t\t}\n\t\t}\n\n\t\tconst processCallback = (itemId: any) => {\n\t\t\tconst action = tag.action || this.getState(itemId) || \"updated\";\n\t\t\tconst sid = tag.sid || itemId[0];\n\t\t\tconst tid = tag.tid || itemId[0];\n\t\t\tthat.afterUpdateCallback(sid, tid, action, tag, mode);\n\t\t};\n\t\tif (tag) {\n\t\t\t// GS-753. When multiple tasks are updated, unhighlight all of them\n\t\t\tif (Array.isArray(id) && id.length > 1) {\n\t\t\t\tid.forEach((taskId) => processCallback(taskId));\n\t\t\t} else {\n\t\t\t\tprocessCallback(id);\n\t\t\t}\n\t\t\tthat.finalizeUpdate();\n\t\t\tthis.setGanttMode(mode);\n\t\t\treturn;\n\t\t}\n\n\t\t// xml response\n\t\tconst top = ajax.xmltop(\"data\", xml.xmlDoc); // fix incorrect content type in IE\n\t\tif (!top) {\n\t\t\treturn this.cleanUpdate(id);\n\t\t}\n\t\tconst atag = ajax.xpath(\"//data/action\", top);\n\t\tif (!atag.length) {\n\t\t\treturn this.cleanUpdate(id);\n\t\t}\n\n\t\tfor (let i = 0; i < atag.length; i++) {\n\t\t\tconst btag = atag[i];\n\t\t\tconst action = btag.getAttribute(\"type\");\n\t\t\tconst sid = btag.getAttribute(\"sid\");\n\t\t\tconst tid = btag.getAttribute(\"tid\");\n\n\t\t\tthat.afterUpdateCallback(sid, tid, action, btag, mode);\n\t\t}\n\t\tthat.finalizeUpdate();\n\t}\n\n\tcleanUpdate(id: any[]) {\n\t\tif (id) {\n\t\t\tfor (let i = 0; i < id.length; i++) {\n\t\t\t\tdelete this._in_progress[id[i]];\n\t\t\t}\n\t\t}\n\t}\n\n\tfinalizeUpdate() {\n\t\tif (this._waitMode) {\n\t\t\tthis._waitMode--;\n\t\t}\n\n\t\tthis.callEvent(\"onAfterUpdateFinish\", []);\n\t\tif (!this.updatedRows.length) {\n\t\t\tthis.callEvent(\"onFullSync\", []);\n\t\t}\n\t}\n\n\t/**\n\t * @desc: initializes data-processor\n\t * @param: gantt - dhtmlxGantt object to attach this data-processor to\n\t * @type: public\n\t */\n\tinit(gantt: any) {\n\t\tif (this._initialized) {\n\t\t\treturn;\n\t\t}\n\t\tthis.$gantt = gantt;\n\t\tif (this.$gantt._dp_init) {\n\t\t\tthis.$gantt._dp_init(this);\n\t\t}\n\n\t\tthis._setDefaultTransactionMode();\n\n\t\tthis.styles = {\n\t\t\tupdated:\"gantt_updated\",\n\t\t\torder:\"gantt_updated\",\n\t\t\tinserted:\"gantt_inserted\",\n\t\t\tdeleted:\"gantt_deleted\",\n\t\t\tdelete_confirmation:\"gantt_deleted\",\n\t\t\tinvalid:\"gantt_invalid\",\n\t\t\terror:\"gantt_error\",\n\t\t\tclear:\"\"\n\t\t};\n\n\t\tthis._methods=[\"_row_style\",\"setCellTextStyle\",\"_change_id\",\"_delete_task\"];\n\t\textendGantt(this.$gantt, this);\n\t\tconst dataProcessorEvents = new DataProcessorEvents(this.$gantt, this);\n\t\tdataProcessorEvents.attach();\n\t\tthis.attachEvent(\"onDestroy\", function() {\n\t\t\tdelete this.setGanttMode;\n\t\t\tdelete this._getRowData;\n\n\t\t\tdelete this.$gantt._dp;\n\t\t\tdelete this.$gantt._change_id;\n\t\t\tdelete this.$gantt._row_style;\n\t\t\tdelete this.$gantt._delete_task;\n\t\t\tdelete this.$gantt._sendTaskOrder;\n\t\t\tdelete this.$gantt;\n\n\t\t\tdataProcessorEvents.detach();\n\t\t});\n\t\tthis.$gantt.callEvent(\"onDataProcessorReady\", [this]);\n\t\tthis._initialized = true;\n\t}\n\n\tsetOnAfterUpdate(handler) {\n\t\tthis.attachEvent(\"onAfterUpdate\", handler);\n\t}\n\n\tsetOnBeforeUpdateHandler(handler) {\n\t\tthis.attachEvent(\"onBeforeDataSending\", handler);\n\t}\n\n\t/* starts autoupdate mode\n\t\t@param interval time interval for sending update requests\n\t*/\n\tsetAutoUpdate(interval, user) {\n\t\tinterval = interval || 2000;\n\n\t\tthis._user = user || (new Date()).valueOf();\n\t\tthis._needUpdate = false;\n\n\t\tthis._updateBusy = false;\n\n\t\tthis.attachEvent(\"onAfterUpdate\", this.afterAutoUpdate); // arguments sid, action, tid, xml_node;\n\n\t\tthis.attachEvent(\"onFullSync\", this.fullSync);\n\n\t\tsetInterval(() => {\n\t\t\tthis.loadUpdate();\n\t\t}, interval);\n\t}\n\n\t/* process updating request response\n\t\tif status == collision version is deprecated\n\t\tset flag for autoupdating immediately\n\t*/\n\tafterAutoUpdate(sid, action, tid, xml_node) { // tslint:disable-line\n\t\tif (action === \"collision\") {\n\t\t\tthis._needUpdate = true;\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/* callback function for onFillSync event\n\t\tcall update function if it's need\n\t*/\n\tfullSync() {\n\t\tif (this._needUpdate) {\n\t\t\tthis._needUpdate = false;\n\t\t\tthis.loadUpdate();\n\t\t}\n\t\treturn true;\n\t}\n\n\t/* sends query to the server and call callback function\n\t*/\n\tgetUpdates(url, callback) {\n\t\tconst ajax = this.$gantt.ajax;\n\t\tif (this._updateBusy) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\tthis._updateBusy = true;\n\t\t}\n\n\t\tajax.get(url, callback);\n\n\t}\n\n\t/* loads updates and processes them\n\t*/\n\tloadUpdate() {\n\t\tconst ajax = this.$gantt.ajax;\n\t\tconst version = this.$gantt.getUserData(0, \"version\", this._ganttMode);\n\t\tlet url = this.serverProcessor + ajax.urlSeparator(this.serverProcessor) + [\"dhx_user=\" + this._user, \"dhx_version=\" + version].join(\"&\");\n\t\turl = url.replace(\"editing=true&\", \"\");\n\t\tthis.getUpdates(url, (xml) => {\n\t\t\tconst vers = ajax.xpath(\"//userdata\", xml);\n\t\t\tthis.$gantt.setUserData(0, \"version\", this._getXmlNodeValue(vers[0]), this._ganttMode);\n\n\t\t\tconst updates = ajax.xpath(\"//update\", xml);\n\t\t\tif (updates.length) {\n\t\t\t\tthis._silent_mode = true;\n\n\t\t\t\tfor (let i = 0; i < updates.length; i++) {\n\t\t\t\t\tconst status = updates[i].getAttribute(\"status\");\n\t\t\t\t\tconst id = updates[i].getAttribute(\"id\");\n\t\t\t\t\tconst parent = updates[i].getAttribute(\"parent\");\n\t\t\t\t\tswitch (status) {\n\t\t\t\t\t\tcase \"inserted\":\n\t\t\t\t\t\t\tthis.callEvent(\"insertCallback\", [updates[i], id, parent]);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"updated\":\n\t\t\t\t\t\t\tthis.callEvent(\"updateCallback\", [updates[i], id, parent]);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"deleted\":\n\t\t\t\t\t\t\tthis.callEvent(\"deleteCallback\", [updates[i], id, parent]);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis._silent_mode = false;\n\t\t\t}\n\n\t\t\tthis._updateBusy = false;\n\t\t});\n\t}\n\n\tdestructor() {\n\t\tthis.callEvent(\"onDestroy\", []);\n\t\tthis.detachAllEvents();\n\n\t\tthis.updatedRows = [];\n\t\tthis._in_progress = {}; // ?\n\t\tthis._invalid = {};\n\t\tthis._storage.clear();\n\t\tthis._storage = null;\n\t\tthis._headers = null;\n\t\tthis._payload = null;\n\t\tdelete this._initialized;\n\t}\n\n\tsetGanttMode(mode) {\n\t\tif (mode === \"tasks\") {\n\t\t\tmode = \"task\";\n\t\t} else if (mode === \"links\") {\n\t\t\tmode = \"link\";\n\t\t}\n\n\t\tconst modes = this.modes || {};\n\t\tconst ganttMode = this.getGanttMode();\n\t\tif (ganttMode) {\n\t\t\tmodes[ganttMode] = {\n\t\t\t\t_in_progress : this._in_progress,\n\t\t\t\t_invalid: this._invalid,\n\t\t\t\t_storage: this._storage,\n\t\t\t\tupdatedRows : this.updatedRows\n\t\t\t};\n\t\t}\n\n\t\tlet newState = modes[mode];\n\t\tif (!newState) {\n\t\t\tnewState = modes[mode] = {\n\t\t\t\t_in_progress : {},\n\t\t\t\t_invalid : {},\n\t\t\t\t_storage : SimpleStorage.create(),\n\t\t\t\tupdatedRows : []\n\t\t\t};\n\t\t}\n\t\tthis._in_progress = newState._in_progress;\n\t\tthis._invalid = newState._invalid;\n\t\tthis._storage = newState._storage;\n\t\tthis.updatedRows = newState.updatedRows;\n\t\tthis.modes = modes;\n\t\tthis._ganttMode = mode;\n\t}\n\tgetGanttMode():string {\n\t\treturn this._ganttMode;\n\t}\n\n\tstoreItem(item) {\n\t\tthis._storage.storeItem(item);\n\t}\n\n\turl(url: string) {\n\t\tthis.serverProcessor = this._serverProcessor = url;\n\t}\n\n\tprotected _beforeSendData(data: any, rowId: any) {\n\t\tif (!this.callEvent(\"onBeforeUpdate\", [rowId, this.getState(rowId), data])) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._sendData(data, rowId);\n\t}\n\n\tprotected _serializeAsJSON(data: any) {\n\t\tif (typeof data === \"string\") {\n\t\t\treturn data;\n\t\t}\n\n\t\tconst copy = utils.copy(data);\n\t\tif (this._tMode === \"REST-JSON\") {\n\t\t\tdelete copy.id;\n\t\t\tdelete copy[this.action_param];\n\t\t}\n\n\t\treturn JSON.stringify(copy);\n\t}\n\n\tprotected _applyPayload(url: string) {\n\t\tconst ajax = this.$gantt.ajax;\n\t\tif (this._payload) {\n\t\t\tfor (const key in this._payload) {\n\t\t\t\turl = url + ajax.urlSeparator(url) + this.escape(key) + \"=\" + this.escape(this._payload[key]);\n\t\t\t}\n\t\t}\n\t\treturn url;\n\t}\n\n\t// GET/POST/JSON modes of the dataProcessor didn't send the whole data items in 'delete' requests\n\t// clear extra info from the data in order not to change the request format\n\tprotected _cleanupArgumentsBeforeSend(dataToSend: any) {\n\t\tlet processedData;\n\t\tif(dataToSend[this.action_param] === undefined){// hash of updated items, and not an individual item\n\t\t\tprocessedData = {};\n\t\t\tfor(const i in dataToSend) {\n\t\t\t\tprocessedData[i] = this._cleanupArgumentsBeforeSend(dataToSend[i]);\n\t\t\t}\n\t\t} else {\n\t\t\tprocessedData = this._cleanupItemBeforeSend(dataToSend);\n\t\t}\n\t\treturn processedData;\n\t}\n\tprotected _cleanupItemBeforeSend(updatedItem: any) {\n\t\tlet output = null;\n\t\tif(updatedItem){\n\t\t\tif(updatedItem[this.action_param] === \"deleted\"){\n\t\t\t\toutput = {};\n\t\t\t\toutput.id = updatedItem.id;\n\t\t\t\toutput[this.action_param] = updatedItem[this.action_param];\n\t\t\t}else{\n\t\t\t\toutput = updatedItem;\n\t\t\t}\n\t\t}\n\n\t\treturn output;\n\t}\n\n\tprotected _sendData(dataToSend: any, rowId?: any) {\n\t\tif (!dataToSend) {\n\t\t\treturn; // nothing to send\n\t\t}\n\t\tif (!this.callEvent(\"onBeforeDataSending\", rowId ? [rowId, this.getState(rowId), dataToSend] : [null, null, dataToSend])) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (rowId) {\n\t\t\tthis._in_progress[rowId] = (new Date()).valueOf();\n\t\t}\n\n\t\tconst ajax = this.$gantt.ajax;\n\n\t\tif (this._tMode === \"CUSTOM\") {\n\t\t\tconst taskState = this.getState(rowId);\n\t\t\tconst taskAction = this.getActionByState(taskState);\n\t\t\tconst ganttMode = this.getGanttMode();\n\t\t\tconst _onResolvedCreateUpdate = (tag) => {\n\t\t\t\tlet action = taskState || \"updated\";\n\t\t\t\tlet sid = rowId;\n\t\t\t\tlet tid = rowId;\n\n\t\t\t\tif (tag) {\n\t\t\t\t\taction = tag.action || taskState;\n\t\t\t\t\tsid = tag.sid || sid;\n\t\t\t\t\ttid = tag.id || tag.tid || tid;\n\t\t\t\t}\n\t\t\t\tthis.afterUpdateCallback(sid, tid, action, tag, ganttMode);\n\t\t\t};\n\n\t\t\tlet actionPromise;\n\t\t\tif (this._router instanceof Function) {\n\t\t\t\tif(this._routerParametersFormat === \"object\"){\n\t\t\t\t\tconst obj = {\n\t\t\t\t\t\tentity: ganttMode,\n\t\t\t\t\t\taction: taskAction,\n\t\t\t\t\t\tdata: dataToSend,\n\t\t\t\t\t\tid: rowId\n\t\t\t\t\t};\n\t\t\t\t\tactionPromise = this._router(obj);\n\t\t\t\t} else {\n\t\t\t\t\tactionPromise = this._router(ganttMode, taskAction, dataToSend, rowId);\n\t\t\t\t}\n\t\t\t} else if (this._router[ganttMode] instanceof Function) {\n\t\t\t\tactionPromise = this._router[ganttMode](taskAction, dataToSend, rowId);\n\t\t\t} else {\n\n\t\t\t\tconst errorMsgStart = \"Incorrect configuration of gantt.createDataProcessor\";\n\t\t\t\tconst errorMsgEnd = `\nYou need to either add missing properties to the dataProcessor router object or to use a router function.\nSee https://docs.dhtmlx.com/gantt/desktop__server_side.html#customrouting and https://docs.dhtmlx.com/gantt/api__gantt_createdataprocessor.html for details.`;\n\n\t\t\t\tif(!this._router[ganttMode]){\n\t\t\t\t\tthrow new Error(`${errorMsgStart}: router for the **${ganttMode}** entity is not defined. ${errorMsgEnd}`);\n\t\t\t\t}\n\t\t\t\tswitch (taskState) {\n\t\t\t\t\tcase \"inserted\":\n\t\t\t\t\t\tif(!this._router[ganttMode].create){\n\t\t\t\t\t\t\tthrow new Error(`${errorMsgStart}: **create** action for the **${ganttMode}** entity is not defined. ${errorMsgEnd}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tactionPromise = this._router[ganttMode].create(dataToSend);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"deleted\":\n\t\t\t\t\t\tif(!this._router[ganttMode].delete){\n\t\t\t\t\t\t\tthrow new Error(`${errorMsgStart}: **delete** action for the **${ganttMode}** entity is not defined. ${errorMsgEnd}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tactionPromise = this._router[ganttMode].delete(rowId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif(!this._router[ganttMode].update){\n\t\t\t\t\t\t\tthrow new Error(`${errorMsgStart}: **update**\" action for the **${ganttMode}** entity is not defined. ${errorMsgEnd}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tactionPromise = this._router[ganttMode].update(dataToSend, rowId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(actionPromise){\n\t\t\t\t// neither promise nor {tid: newId} response object\n\t\t\t\tif(!actionPromise.then &&\n\t\t\t\t\t(actionPromise.id === undefined && actionPromise.tid === undefined && actionPromise.action === undefined)){\n\t\t\t\t\tthrow new Error(\"Incorrect router return value. A Promise or a response object is expected\");\n\t\t\t\t}\n\n\t\t\t\tif(actionPromise.then){\n\t\t\t\t\tactionPromise.then(_onResolvedCreateUpdate).catch((error) => {\n\t\t\t\t\t\tif(error && error.action){\n\t\t\t\t\t\t\t_onResolvedCreateUpdate(error);\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t_onResolvedCreateUpdate({ action: \"error\", value: error});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}else{\n\t\t\t\t\t// custom method may return a response object in case of sync action\n\t\t\t\t\t_onResolvedCreateUpdate(actionPromise);\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\t_onResolvedCreateUpdate(null);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tlet queryParams: any;\n\t\tqueryParams = {\n\t\t\tcallback: (xml) => {\n\t\t\t\tconst ids = [];\n\n\t\t\t\tif (rowId) {\n\t\t\t\t\tids.push(rowId);\n\t\t\t\t} else if (dataToSend) {\n\t\t\t\t\tfor (const key in dataToSend) {\n\t\t\t\t\t\tids.push(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn this.afterUpdate(this, xml, ids);\n\t\t\t},\n\t\t\theaders: this._headers\n\t\t};\n\n\t\tconst dhxVersion = \"dhx_version=\" + this.$gantt.getUserData(0, \"version\", this._ganttMode);\n\t\tconst urlParams = this.serverProcessor + (this._user ? (ajax.urlSeparator(this.serverProcessor) + [\"dhx_user=\" + this._user, dhxVersion].join(\"&\")) : \"\");\n\t\tlet url: any = this._applyPayload(urlParams);\n\t\tlet data;\n\n\t\tswitch (this._tMode) {\n\t\t\tcase \"GET\":\n\t\t\t\tdata = this._cleanupArgumentsBeforeSend(dataToSend);\n\t\t\t\tqueryParams.url = url + ajax.urlSeparator(url) + this.serialize(data, rowId);\n\t\t\t\tqueryParams.method = \"GET\";\n\t\t\t\tbreak;\n\t\t\tcase \"POST\":\n\t\t\t\tdata = this._cleanupArgumentsBeforeSend(dataToSend);\n\t\t\t\tqueryParams.url = url;\n\t\t\t\tqueryParams.method = \"POST\";\n\t\t\t\tqueryParams.data = this.serialize(data, rowId);\n\t\t\t\tbreak;\n\t\t\tcase \"JSON\":\n\t\t\t\tdata = {};\n\t\t\t\tconst preprocessedData = this._cleanupItemBeforeSend(dataToSend);\n\t\t\t\tfor (const key in preprocessedData) {\n\t\t\t\t\tif (key === this.action_param || key === \"id\" || key === \"gr_id\") {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tdata[key] = preprocessedData[key];\n\t\t\t\t}\n\n\t\t\t\tqueryParams.url = url;\n\t\t\t\tqueryParams.method = \"POST\";\n\t\t\t\tqueryParams.data = JSON.stringify({\n\t\t\t\t\tid: rowId,\n\t\t\t\t\taction: dataToSend[this.action_param],\n\t\t\t\t\tdata\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"REST\":\n\t\t\tcase \"REST-JSON\":\n\t\t\t\turl = urlParams.replace(/(&|\\?)editing=true/, \"\");\n\t\t\t\tdata = \"\";\n\n\t\t\t\tswitch (this.getState(rowId)) {\n\t\t\t\t\tcase \"inserted\":\n\t\t\t\t\t\tqueryParams.method = \"POST\";\n\t\t\t\t\t\tqueryParams.data = this.serialize(dataToSend, rowId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"deleted\":\n\t\t\t\t\t\tqueryParams.method = \"DELETE\";\n\t\t\t\t\t\turl = url + (url.slice(-1) === \"/\" ? \"\" : \"/\") + rowId;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tqueryParams.method = \"PUT\";\n\t\t\t\t\t\tqueryParams.data = this.serialize(dataToSend, rowId);\n\t\t\t\t\t\turl = url + (url.slice(-1) === \"/\" ? \"\" : \"/\") + rowId;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tqueryParams.url = this._applyPayload(url);\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis._waitMode++;\n\t\treturn ajax.query(queryParams);\n\t}\n\n\tprotected _forEachUpdatedRow(code: any) {\n\t\tconst updatedRows = this.updatedRows.slice();\n\t\tfor (let i = 0; i < updatedRows.length; i++) {\n\t\t\tconst rowId = updatedRows[i];\n\t\t\tif (this.$gantt.getUserData(rowId, this.action_param, this._ganttMode)) {\n\t\t\t\tcode.call(this, rowId);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected _setDefaultTransactionMode() {\n\t\tif (this.serverProcessor) {\n\t\t\tthis.setTransactionMode(\"POST\", true);\n\t\t\tthis.serverProcessor += (this.serverProcessor.indexOf(\"?\") !== -1 ? \"&\" : \"?\") + \"editing=true\";\n\t\t\tthis._serverProcessor = this.serverProcessor;\n\t\t}\n\t}\n\n\t/* returns xml node value\n\t\t@param node\n\t\t\txml node\n\t*/\n\tprotected _getXmlNodeValue(node) {\n\t\tif (node.firstChild) {\n\t\t\treturn node.firstChild.nodeValue;\n\t\t}\n\t\treturn \"\";\n\t}\n\n\tprotected _getAllData() {\n\t\tconst out = {};\n\t\tlet hasOne = false;\n\n\t\tthis._forEachUpdatedRow(function(id) {\n\t\t\tif (this._in_progress[id] || this.is_invalid(id)){\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst row = this._getRowData(id);\n\t\t\tif (!this.callEvent(\"onBeforeUpdate\", [id, this.getState(id), row])) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tout[id] = row;\n\t\t\thasOne = true;\n\t\t\tthis._in_progress[id] = (new Date()).valueOf();\n\t\t});\n\n\t\treturn hasOne ? out : null;\n\t}\n\n\tprotected _prepareDate(value: Date) : string {\n\t\treturn this.$gantt.defined(this.$gantt.templates.xml_format) ? this.$gantt.templates.xml_format(value) : this.$gantt.templates.format_date(value);\n\t}\n\n\tprotected _prepareArray(value: any[], traversedObjects: object[]) : any[] {\n\t\ttraversedObjects.push(value);\n\n\t\treturn value.map((item) => {\n\t\t\tif(helpers.isDate(item)){\n\t\t\t\treturn this._prepareDate(item);\n\t\t\t} else if (Array.isArray(item) && !helpers.arrayIncludes(traversedObjects, item)){\n\t\t\t\treturn this._prepareArray(item, traversedObjects);\n\t\t\t} else if (item && typeof item === \"object\" && !helpers.arrayIncludes(traversedObjects, item)) {\n\t\t\t\treturn this._prepareObject(item, traversedObjects);\n\t\t\t} else {\n\t\t\t\treturn item;\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected _prepareObject(rawItem: any, traversedObjects: object[]) : any {\n\t\tconst processedItem = {};\n\t\ttraversedObjects.push(rawItem);\n\n\t\tfor (const key in rawItem) {\n\t\t\tif (key.substr(0, 1) === \"$\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst value = rawItem[key];\n\t\t\tif (helpers.isDate(value)) {\n\t\t\t\tprocessedItem[key] = this._prepareDate(value);\n\t\t\t} else if(value === null) {\n\t\t\t\tprocessedItem[key] = \"\";\n\t\t\t} else if (Array.isArray(value) && !helpers.arrayIncludes(traversedObjects, value)){\n\t\t\t\tprocessedItem[key] = this._prepareArray(value, traversedObjects);\n\t\t\t} else if (value && typeof value === \"object\" && !helpers.arrayIncludes(traversedObjects, value)) {\n\t\t\t\tprocessedItem[key] = this._prepareObject(value, traversedObjects);\n\t\t\t} else {\n\t\t\t\tprocessedItem[key] = value;\n\t\t\t}\n\t\t}\n\t\treturn processedItem;\n\t}\n\n\tprotected _prepareDataItem(rawItem: any): any {\n\t\tconst processedItem = this._prepareObject(rawItem, []);\n\n\t\tprocessedItem[this.action_param] = this.$gantt.getUserData(rawItem.id, this.action_param, this._ganttMode);\n\t\treturn processedItem;\n\t}\n\n\tprotected getStoredItem(id){\n\t\treturn this._storage.getStoredItem(id);\n\t}\n\n\tprotected _getRowData(id) {\n\t\tlet dataItem;\n\t\tconst gantt = this.$gantt;\n\t\tif (this.getGanttMode() === \"task\") {\n\t\t\tif(gantt.isTaskExists(id)){\n\t\t\t\tdataItem =this.$gantt.getTask(id);\n\t\t\t}\n\t\t} else if (this.getGanttMode() === \"assignment\") {\n\t\t\tif(this.$gantt.$data.assignmentsStore.exists(id)){\n\t\t\t\tdataItem =this.$gantt.$data.assignmentsStore.getItem(id);\n\t\t\t}\n\t\t} else if (this.getGanttMode() === \"baseline\") {\n\t\t\tif(this.$gantt.$data.baselineStore.exists(id)){\n\t\t\t\tdataItem =this.$gantt.$data.baselineStore.getItem(id);\n\t\t\t}\n\t\t} else {\n\t\t\tif(gantt.isLinkExists(id)){\n\t\t\t\tdataItem =this.$gantt.getLink(id);\n\t\t\t}\n\t\t}\n\n\t\tif (!dataItem) {\n\t\t\tdataItem = this.getStoredItem(id);\n\t\t}\n\n\t\tif (!dataItem) {\n\t\t\tdataItem = { id };\n\t\t}\n\n\t\treturn this._prepareDataItem(dataItem);\n\t}\n}","\nexport default function extendGantt(gantt: any, dp: any) {\n\tgantt.getUserData = function(id, name, store) {\n\t\tif (!this.userdata) {\n\t\t\tthis.userdata = {};\n\t\t}\n\t\tthis.userdata[store] = this.userdata[store] || {};\n\t\tif (this.userdata[store][id] && this.userdata[store][id][name]) {\n\t\t\treturn this.userdata[store][id][name];\n\t\t}\n\t\treturn \"\";\n\t};\n\tgantt.setUserData = function(id, name, value, store) {\n\t\tif (!this.userdata) {\n\t\t\tthis.userdata = {};\n\t\t}\n\t\tthis.userdata[store] = this.userdata[store] || {};\n\t\tthis.userdata[store][id] = this.userdata[store][id] || {};\n\t\tthis.userdata[store][id][name] = value;\n\t};\n\n\tgantt._change_id = function(oldId, newId) {\n\t\tswitch (this._dp._ganttMode) {\n\t\t\tcase \"task\":\n\t\t\t\tthis.changeTaskId(oldId, newId);\n\t\t\t\tbreak;\n\t\t\tcase \"link\":\n\t\t\t\tthis.changeLinkId(oldId, newId);\n\t\t\t\tbreak;\n\t\t\tcase \"assignment\":\n\t\t\t\tthis.$data.assignmentsStore.changeId(oldId, newId);\n\t\t\t\tbreak;\n\t\t\tcase \"resource\":\n\t\t\t\tthis.$data.resourcesStore.changeId(oldId, newId);\n\t\t\t\tbreak;\n\t\t\tcase \"baseline\":\n\t\t\t\tthis.$data.baselineStore.changeId(oldId, newId);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Invalid mode of the dataProcessor after database id is received: ${this._dp._ganttMode}, new id: ${newId}`);\n\t\t}\n\t};\n\n\tgantt._row_style = function(rowId, classname){\n\t\tif (this._dp._ganttMode !== \"task\") {\n\t\t\treturn;\n\t\t}\n\t\tif (!gantt.isTaskExists(rowId)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst task = gantt.getTask(rowId);\n\t\ttask.$dataprocessor_class = classname;\n\t\tgantt.refreshTask(rowId);\n\t};\n\n\t// fake method for dataprocessor\n\tgantt._delete_task = function(rowId, node) {}; // tslint:disable-line\n\n\tgantt._sendTaskOrder = function(id, item){\n\t\tif (item.$drop_target) {\n\t\t\tthis._dp.setGanttMode(\"task\");\n\t\t\tthis.getTask(id).target = item.$drop_target;\n\t\t\tthis._dp.setUpdated(id, true,\"order\");\n\t\t\tdelete this.getTask(id).$drop_target;\n\t\t}\n\t};\n\n\tgantt.setDp = function() {\n\t\tthis._dp = dp;\n\t};\n\n\tgantt.setDp();\n}","import * as DataProcessor from \"./data_processor\";\nexport default {\n\tDEPRECATED_api: function(server) {\n\t\treturn new (DataProcessor.DataProcessor)(server);\n\t},\n\tcreateDataProcessor: DataProcessor.createDataProcessor\n};","import global from \"../../utils/global\";\n\nfunction createMethod(gantt){\n\tvar methods = {};\n\tvar isActive = false;\n\tfunction disableMethod(methodName, dummyMethod){\n\t\tdummyMethod = typeof dummyMethod == \"function\" ? dummyMethod : function(){};\n\n\t\tif(!methods[methodName]){\n\t\t\tmethods[methodName] = this[methodName];\n\t\t\tthis[methodName] = dummyMethod;\n\t\t}\n\t}\n\tfunction restoreMethod(methodName){\n\t\tif(methods[methodName]){\n\t\t\tthis[methodName] = methods[methodName];\n\t\t\tmethods[methodName] = null;\n\t\t}\n\t}\n\tfunction disableMethods(methodsHash){\n\t\tfor(var i in methodsHash){\n\t\t\tdisableMethod.call(this, i, methodsHash[i]);\n\t\t}\n\t}\n\tfunction restoreMethods(){\n\t\tfor(var i in methods){\n\t\t\trestoreMethod.call(this, i);\n\t\t}\n\t}\n\n\tfunction batchUpdatePayload(callback){\n\t\ttry{\n\t\t\tcallback();\n\t\t}catch(e){\n\t\t\tglobal.console.error(e);\n\t\t}\n\t}\n\n\tvar state = gantt.$services.getService(\"state\");\n\tstate.registerProvider(\"batchUpdate\", function(){\n\t\treturn {\n\t\t\tbatch_update: isActive\n\t\t};\n\t}, false);\n\n\treturn function batchUpdate(callback, noRedraw) {\n\t\tif(isActive){\n\t\t\t// batch mode is already active\n\t\t\tbatchUpdatePayload(callback);\n\t\t\treturn;\n\t\t}\n\n\t\tvar call_dp = (this._dp && this._dp.updateMode != \"off\");\n\t\tvar dp_mode;\n\t\tif (call_dp){\n\t\t\tdp_mode = this._dp.updateMode;\n\t\t\tthis._dp.setUpdateMode(\"off\");\n\t\t}\n\n\t\t// temporary disable some methods while updating multiple tasks\n\t\tvar resetProjects = {};\n\t\tvar methods = {\n\t\t\t\"render\":true,\n\t\t\t\"refreshData\":true,\n\t\t\t\"refreshTask\":true,\n\t\t\t\"refreshLink\":true,\n\t\t\t\"resetProjectDates\":function(task){\n\t\t\t\tresetProjects[task.id] = task;\n\t\t\t}\n\t\t};\n\n\t\tdisableMethods.call(this, methods);\n\n\t\tisActive = true;\n\t\tthis.callEvent(\"onBeforeBatchUpdate\", []);\n\n\t\tbatchUpdatePayload(callback);\n\n\t\tthis.callEvent(\"onAfterBatchUpdate\", []);\n\n\t\trestoreMethods.call(this);\n\n\t\t// do required updates after changes applied\n\t\tfor(var i in resetProjects){\n\t\t\tthis.resetProjectDates(resetProjects[i]);\n\t\t}\n\n\t\tisActive = false;\n\n\t\tif(!noRedraw){\n\t\t\tthis.render();\n\t\t}\n\n\t\tif (call_dp) {\n\t\t\tthis._dp.setUpdateMode(dp_mode);\n\t\t\tthis._dp.setGanttMode(\"task\");\n\t\t\tthis._dp.sendData();\n\t\t\tthis._dp.setGanttMode(\"link\");\n\t\t\tthis._dp.sendData();\n\t\t}\n\t};\n\n\n\n}\n\nexport default function(gantt){\n\tgantt.batchUpdate = createMethod(gantt);\n};","var createWbs = (function(gantt){\n\treturn {\n\t_needRecalc: true,\n\treset: function(){\n\t\tthis._needRecalc = true;\n\t},\n\t_isRecalcNeeded: function(){\n\t\treturn (!this._isGroupSort() && this._needRecalc);\n\t},\n\t_isGroupSort: function() {\n\t\treturn !!(gantt.getState().group_mode);\n\t},\n\t_getWBSCode: function(task) {\n\t\tif(!task) return \"\";\n\n\t\tif(this._isRecalcNeeded()){\n\t\t\tthis._calcWBS();\n\t\t}\n\n\t\tif(task.$virtual) return \"\";\n\t\tif(this._isGroupSort()) return task.$wbs || \"\";\n\n\t\tif(!task.$wbs) {\n\t\t\tthis.reset();\n\t\t\tthis._calcWBS();\n\t\t}\n\t\treturn task.$wbs;\n\t},\n\t_setWBSCode: function(task, value) {\n\t\ttask.$wbs = value;\n\t},\n\tgetWBSCode: function(task) {\n\t\treturn this._getWBSCode(task);\n\t},\n\tgetByWBSCode: function(code){\n\t\tvar parts = code.split(\".\");\n\t\tvar currentNode = gantt.config.root_id;\n\t\tfor(var i = 0; i < parts.length; i++){\n\t\t\tvar children = gantt.getChildren(currentNode);\n\t\t\tvar index = parts[i]*1 - 1;\n\t\t\tif(gantt.isTaskExists(children[index])){\n\t\t\t\tcurrentNode = children[index];\n\t\t\t}else{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tif(gantt.isTaskExists(currentNode)){\n\t\t\treturn gantt.getTask(currentNode);\n\t\t}else{\n\t\t\treturn null;\n\t\t}\n\t},\n\t_calcWBS: function() {\n\t\tif(!this._isRecalcNeeded()) return;\n\n\t\tvar _isFirst = true;\n\t\tgantt.eachTask(function(ch) {\n\t\t\tif(_isFirst) {\n\t\t\t\t_isFirst = false;\n\t\t\t\tthis._setWBSCode(ch, \"1\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar _prevSibling = gantt.getPrevSibling(ch.id);\n\t\t\tif (_prevSibling !== null) {\n\t\t\t\tvar _wbs = gantt.getTask(_prevSibling).$wbs;\n\t\t\t\tif(_wbs) {\n\t\t\t\t\t_wbs = _wbs.split(\".\");\n\t\t\t\t\t_wbs[_wbs.length-1]++;\n\t\t\t\t\tthis._setWBSCode(ch, _wbs.join(\".\"));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar _parent = gantt.getParent(ch.id);\n\t\t\t\tthis._setWBSCode(ch, gantt.getTask(_parent).$wbs + \".1\");\n\t\t\t}\n\t\t}, gantt.config.root_id, this);\n\n\t\tthis._needRecalc = false;\n\t}\n};\n});\n\nexport default function(gantt){\n\tvar wbs = createWbs(gantt);\n\tgantt.getWBSCode = function getWBSCode(task) {\n\t\treturn wbs.getWBSCode(task);\n\t};\n\n\tgantt.getTaskByWBSCode = function(code) {\n\t\treturn wbs.getByWBSCode(code);\n\t};\n\n\tfunction resetCache(){\n\t\twbs.reset();\n\t\treturn true;\n\t}\n\n\tgantt.attachEvent(\"onAfterTaskMove\", resetCache);\n\tgantt.attachEvent(\"onBeforeParse\", resetCache);\n\tgantt.attachEvent(\"onAfterTaskDelete\", resetCache);\n\tgantt.attachEvent(\"onAfterTaskAdd\", resetCache);\n\tgantt.attachEvent(\"onAfterSort\", resetCache);\n\n};\n","import * as helpers from \"../../utils/helpers\";\n\nfunction createResourceMethods(gantt){\n\n\tvar resourceTaskCache = {};\n\tvar singleResourceCacheBuilt = false;\n\n\tgantt.$data.tasksStore.attachEvent(\"onStoreUpdated\", function(){\n\t\tresourceTaskCache = {};\n\t\tsingleResourceCacheBuilt = false;\n\t});\n\tgantt.attachEvent(\"onBeforeGanttRender\", function(){\n\t\tresourceTaskCache = {};\n\t});\n\n\tfunction getTaskBy(propertyName, propertyValue, typeFilter) {\n\t\tif (typeof propertyName == \"function\") {\n\t\t\treturn filterResourceTasks(propertyName);\n\t\t} else {\n\t\t\tif (helpers.isArray(propertyValue)) {\n\t\t\t\treturn getResourceTasks(propertyName, propertyValue, typeFilter);\n\t\t\t} else {\n\t\t\t\treturn getResourceTasks(propertyName, [propertyValue], typeFilter);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction filterResourceTasks(filter) {\n\t\tvar res = [];\n\t\tgantt.eachTask(function (task) {\n\t\t\tif (filter(task)) {\n\t\t\t\tres.push(task);\n\t\t\t}\n\t\t});\n\t\treturn res;\n\t}\n\n\tvar falsyValuePrefix = String(Math.random());\n\tfunction resourceHashFunction(value){\n\t\tif (value === null){\n\t\t\treturn falsyValuePrefix + String(value);\n\t\t}\n\t\treturn String(value);\n\t}\n\n\tfunction getCacheKey(resourceIds, property, typeFilter) {\n\t\tif (Array.isArray(resourceIds)) {\n\t\t\treturn resourceIds.map(function (value) {\n\t\t\t\treturn resourceHashFunction(value);\n\t\t\t}).join(\"_\") + `_${property}_${typeFilter}`;\n\t\t} else {\n\t\t\treturn resourceHashFunction(resourceIds) + `_${property}_${typeFilter}`;\n\t\t}\n\t}\n\n\tfunction getResourceTasks(property, resourceIds, typeFilter) {\n\t\tvar res;\n\t\tvar cacheKey = getCacheKey(resourceIds, property, JSON.stringify(typeFilter));\n\t\tvar matchingResources = {};\n\t\thelpers.forEach(resourceIds, function(resourceId) {\n\t\t\tmatchingResources[resourceHashFunction(resourceId)] = true;\n\t\t});\n\n\t\tif (!resourceTaskCache[cacheKey]) {\n\t\t\tres = resourceTaskCache[cacheKey] = [];\n\t\t\tgantt.eachTask(function (task) {\n\t\t\t\tif (typeFilter) {\n\t\t\t\t\tif (!typeFilter[gantt.getTaskType(task)]) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} else if (task.type == gantt.config.types.project) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (property in task) {\n\t\t\t\t\tvar resourceValue;\n\t\t\t\t\tif (!helpers.isArray(task[property])) {\n\t\t\t\t\t\tresourceValue = [task[property]];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresourceValue = task[property];\n\t\t\t\t\t}\n\n\t\t\t\t\thelpers.forEach(resourceValue, function(value) {\n\t\t\t\t\t\tvar resourceValue = (value && value.resource_id) ? value.resource_id : value;\n\n\t\t\t\t\t\tif (matchingResources[resourceHashFunction(resourceValue)]) {\n\t\t\t\t\t\t\tres.push(task);\n\t\t\t\t\t\t}else if(!singleResourceCacheBuilt){\n\n\t\t\t\t\t\t\tvar key = getCacheKey(value, property);\n\t\t\t\t\t\t\tif(!resourceTaskCache[key]){\n\t\t\t\t\t\t\t\tresourceTaskCache[key] = [];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresourceTaskCache[key].push(task);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tsingleResourceCacheBuilt = true;\n\t\t} else {\n\t\t\tres = resourceTaskCache[cacheKey];\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tfunction selectAssignments(resourceId, taskId, result){\n\t\tvar property = gantt.config.resource_property;\n\t\tvar owners = [];\n\t\tif (gantt.getDatastore(\"task\").exists(taskId)) {\n\t\t\tvar task = gantt.getTask(taskId);\n\t\t\towners = task[property] || [];\n\t\t}\n\n\t\tif (!Array.isArray(owners)) {\n\t\t\towners = [owners];\n\t\t}\n\t\tfor (var i = 0; i < owners.length; i++) {\n\t\t\tif (owners[i].resource_id == resourceId) {\n\t\t\t\tresult.push({task_id: task.id, resource_id:owners[i].resource_id, value:owners[i].value});\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction getResourceAssignments(resourceId, taskId){\n\t\t// resource assignment as an independent module:\n\t\t// {taskId:, resourceId, value}\n\t\t// TODO: probably should add a separate datastore for these\n\t\tvar assignments = [];\n\t\tvar property = gantt.config.resource_property;\n\t\tif(taskId !== undefined){\n\t\t\tselectAssignments(resourceId, taskId, assignments);\n\t\t}else{\n\t\t\tvar tasks = gantt.getTaskBy(property, resourceId);\n\t\t\ttasks.forEach(function(task){\n\t\t\t\tselectAssignments(resourceId, task.id, assignments);\n\t\t\t});\n\t\t}\n\t\treturn assignments;\n\t}\n\n\treturn {\n\t\tgetTaskBy: getTaskBy,\n\t\tgetResourceAssignments: getResourceAssignments\n\t};\n}\n\nfunction createHelper(gantt){\n\tconst resourcePlugin = {\n\t\trenderEditableLabel: function(start_date, end_date, resource, tasks, assignments){\n\t\t\tconst editable = gantt.config.readonly ? \"\" : \"contenteditable\";\n\t\t\tif(start_date < resource.end_date && end_date > resource.start_date){\n\t\t\t\tfor(let i = 0; i < assignments.length; i++){\n\t\t\t\t\tconst a = assignments[i];\n\t\t\t\t\t\treturn \"
\" + a.value + \"
\";\n\t\t\t\t}\n\t\t\t\treturn \"
-
\";\n\t\t\t}\n\t\t\treturn \"\";\n\t\t},\n\t\trenderSummaryLabel: function(start_date, end_date, resource, tasks, assignments){\n\t\t\tlet sum = assignments.reduce(function(total, assignment){ \n\t\t\t\treturn total + Number(assignment.value);\n\t\t\t}, 0);\n\n\t\t\tif(sum % 1){\n\t\t\t\tsum = Math.round(sum * 10)/10;\n\t\t\t}\n\n\t\t\tif(sum){\n\t\t\t\treturn \"
\" + sum + \"
\";\n\t\t\t}\n\t\t\treturn \"\";\n\t\t},\n\t\teditableResourceCellTemplate: function(start_date, end_date, resource, tasks, assignments){\n\t\t\tif(resource.$role === \"task\"){\n\t\t\t\treturn resourcePlugin.renderEditableLabel(start_date, end_date, resource, tasks, assignments);\n\t\t\t}else{\n\t\t\t\treturn resourcePlugin.renderSummaryLabel(start_date, end_date, resource, tasks, assignments);\n\t\t\t}\n\n\t\t},\n\t\t\n\t\teditableResourceCellClass: function(start_date, end_date, resource, tasks, assignments){\n\t\t\tconst css = [];\n\t\t\tcss.push(\"resource_marker\");\n\n\t\t\tif(resource.$role === \"task\"){\n\t\t\t\tcss.push(\"task_cell\");\n\t\t\t}else{\n\t\t\t\tcss.push(\"resource_cell\");\n\t\t\t}\n\n\t\t\tconst sum = assignments.reduce(function(total, assignment){ \n\t\t\t\treturn total + Number(assignment.value);\n\t\t\t}, 0);\n\n\t\t\tlet capacity = Number(resource.capacity);\n\t\t\tif(isNaN(capacity)){\n\t\t\t\tcapacity = 8;\n\t\t\t}\n\t\t\tif (sum <= capacity) {\n\t\t\t\tcss.push(\"workday_ok\");\n\t\t\t} else {\n\t\t\t\tcss.push(\"workday_over\");\n\t\t\t}\n\t\t\treturn css.join(\" \");\n\t\t},\n\t\tgetSummaryResourceAssignments: function getResourceAssignments(resourceId) {\n\t\t\tlet assignments;\n\t\t\tconst store = gantt.getDatastore(gantt.config.resource_store);\n\t\t\tconst resource = store.getItem(resourceId);\n\n\t\t\tif(resource.$role === \"task\"){\n\t\t\t\tassignments = gantt.getResourceAssignments(resource.$resource_id, resource.$task_id);\n\t\t\t}else{\n\t\t\t\tassignments = gantt.getResourceAssignments(resourceId);\n\t\t\t\tif(store.eachItem){\n\t\t\t\t\tstore.eachItem(function(childResource){\n\t\t\t\t\t\tif(childResource.$role !== \"task\"){\n\t\t\t\t\t\t\tassignments = assignments.concat(gantt.getResourceAssignments(childResource.id));\n\t\t\t\t\t\t}\n\t\t\t\t\t}, resourceId);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn assignments;\n\t\t},\n\t\t\n\t\tinitEditableDiagram: function(){\n\t\t\tgantt.config.resource_render_empty_cells = true;\n\t\t\t\n\t\t\t\n\t\t\t(function(){\n\t\t\t\t/// salesforce locker workaround\n\t\t\t\t// SF removes 'contenteditable' attribute from cells\n\t\t\t\t// restore it on render\n\t\t\t\tlet timeoutId = null;\n\t\t\t\tfunction makeEditable() {\n\t\t\t\t\tif (timeoutId) {\n\t\t\t\t\t\tcancelAnimationFrame(timeoutId);\n\t\t\t\t\t}\n\t\t\t\t\ttimeoutId = requestAnimationFrame(function () {\n\t\t\t\t\t\tif (gantt.$container){\n\t\t\t\t\t\t\tvar cells = Array.prototype.slice.call(gantt.$container.querySelectorAll(\".resourceTimeline_cell [data-assignment-cell]\"));\n\t\t\t\t\t\t\tcells.forEach(function (cell) {\n\t\t\t\t\t\t\t\tcell.contentEditable = true;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tgantt.attachEvent(\"onGanttReady\", function(){\n\t\t\t\t\tgantt.getDatastore(gantt.config.resource_assignment_store).attachEvent(\"onStoreUpdated\", makeEditable);\n\t\t\t\t\tgantt.getDatastore(gantt.config.resource_store).attachEvent(\"onStoreUpdated\", makeEditable);\n\t\t\t\t}, {once: true});\n\t\t\t\tgantt.attachEvent(\"onGanttLayoutReady\", function(){\n\t\t\t\t\tconst ganttViews = gantt.$layout.getCellsByType(\"viewCell\");\n\t\t\t\t\tganttViews.forEach(function(view){\n\t\t\t\t\t\tif(view.$config && view.$config.view === \"resourceTimeline\" && view.$content){\n\t\t\t\t\t\t\tview.$content.attachEvent(\"onScroll\", makeEditable);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t})();\n\n\n\t\t\tgantt.attachEvent(\"onGanttReady\", function(){\n\t\t\t\tlet assignmentEditInProcess = false;\n\t\t\t\tgantt.event(gantt.$container, \"keypress\", function(e){\n\t\t\t\t\tvar target = e.target.closest(\".resourceTimeline_cell [data-assignment-cell]\");\n\t\t\t\t\tif(target){\n\t\t\t\t\t\tif (e.keyCode === 13 || e.keyCode === 27) {\n\t\t\t\t\t\t\ttarget.blur();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tgantt.event(gantt.$container, \"focusout\", function(e){\n\t\t\t\t\tif (assignmentEditInProcess){\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tassignmentEditInProcess = true;\n\t\t\t\t\tsetTimeout(function(){\n\t\t\t\t\t\tassignmentEditInProcess = false;\n\t\t\t\t\t}, 300);\n\t\t\t\t\tvar target = e.target.closest(\".resourceTimeline_cell [data-assignment-cell]\");\n\t\t\t\t\tif(target){\n\t\t\t\t\t\tvar strValue = (target.innerText || \"\").trim();\n\t\t\t\t\t\tif(strValue == \"-\"){\n\t\t\t\t\t\t\tstrValue = \"0\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar value = Number(strValue);\n\t\t\t\t\t\tvar rowId = target.getAttribute(\"data-row-id\");\n\t\t\t\t\t\tvar assignmentId = target.getAttribute(\"data-assignment-id\");\n\t\t\t\t\t\tvar taskId = target.getAttribute(\"data-task\");\n\t\t\t\t\t\tvar resourceId = target.getAttribute(\"data-resource-id\");\n\t\t\t\t\t\tvar startDate = gantt.templates.parse_date(target.getAttribute(\"data-start-date\"));\n\t\t\t\t\t\tvar endDate = gantt.templates.parse_date(target.getAttribute(\"data-end-date\"));\n\n\t\t\t\t\t\tvar assignmentStore = gantt.getDatastore(gantt.config.resource_assignment_store);\n\t\t\t\t\t\tif(isNaN(value)){\n\t\t\t\t\t\t\tgantt.getDatastore(gantt.config.resource_store).refresh(rowId);\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tvar task = gantt.getTask(taskId);\n\t\t\t\t\t\t\t// GS-2141. Track the changes by the Undo extension\n\t\t\t\t\t\t\tif (gantt.plugins().undo){\n\t\t\t\t\t\t\t\tgantt.ext.undo.saveState(taskId, \"task\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(assignmentId){\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tvar assignment = assignmentStore.getItem(assignmentId);\n\t\t\t\t\t\t\t\tif(value === assignment.value){\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(assignment.start_date.valueOf() === startDate.valueOf() && assignment.end_date.valueOf() === endDate.valueOf()){\n\t\t\t\t\t\t\t\t\tassignment.value = value;\n\t\t\t\t\t\t\t\t\tif(!value){\n\t\t\t\t\t\t\t\t\t\tassignmentStore.removeItem(assignment.id);\n\t\t\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\t\t\tassignmentStore.updateItem(assignment.id);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tif(assignment.end_date.valueOf() > endDate.valueOf()){\n\t\t\t\t\t\t\t\t\t\tvar nextChunk = gantt.copy(assignment);\n\t\t\t\t\t\t\t\t\t\tnextChunk.id = gantt.uid();\n\t\t\t\t\t\t\t\t\t\tnextChunk.start_date = endDate;\n\t\t\t\t\t\t\t\t\t\tnextChunk.duration = gantt.calculateDuration({\n\t\t\t\t\t\t\t\t\t\t\tstart_date: nextChunk.start_date,\n\t\t\t\t\t\t\t\t\t\t\tend_date: nextChunk.end_date,\n\t\t\t\t\t\t\t\t\t\t\ttask: task\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\tnextChunk.delay = gantt.calculateDuration({\n\t\t\t\t\t\t\t\t\t\t\tstart_date: task.start_date,\n\t\t\t\t\t\t\t\t\t\t\tend_date: nextChunk.start_date,\n\t\t\t\t\t\t\t\t\t\t\ttask: task\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\tnextChunk.mode = assignment.mode || \"default\";\n\t\t\t\t\t\t\t\t\t\tif(nextChunk.duration !== 0){\n\t\t\t\t\t\t\t\t\t\t\tassignmentStore.addItem(nextChunk);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif(assignment.start_date.valueOf() < startDate.valueOf()){\n\t\t\t\t\t\t\t\t\t\tassignment.end_date = startDate;\n\t\t\t\t\t\t\t\t\t\tassignment.duration = gantt.calculateDuration({\n\t\t\t\t\t\t\t\t\t\t\tstart_date: assignment.start_date,\n\t\t\t\t\t\t\t\t\t\t\tend_date: assignment.end_date,\n\t\t\t\t\t\t\t\t\t\t\ttask: task\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\tassignment.mode = \"fixedDuration\";\n\n\t\t\t\t\t\t\t\t\t\tif(assignment.duration === 0){\n\t\t\t\t\t\t\t\t\t\t\tassignmentStore.removeItem(assignment.id);\n\t\t\t\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\t\t\t\tassignmentStore.updateItem(assignment.id);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\t\t\tassignmentStore.removeItem(assignment.id);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif(value){\n\t\t\t\t\t\t\t\t\t\tassignmentStore.addItem({\n\t\t\t\t\t\t\t\t\t\t\ttask_id: assignment.task_id,\n\t\t\t\t\t\t\t\t\t\t\tresource_id: assignment.resource_id,\n\t\t\t\t\t\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\t\t\t\t\t\tstart_date: startDate,\n\t\t\t\t\t\t\t\t\t\t\tend_date: endDate,\n\t\t\t\t\t\t\t\t\t\t\tduration: gantt.calculateDuration({\n\t\t\t\t\t\t\t\t\t\t\t\tstart_date: startDate,\n\t\t\t\t\t\t\t\t\t\t\t\tend_date: endDate,\n\t\t\t\t\t\t\t\t\t\t\t\ttask: task\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\tdelay: gantt.calculateDuration({\n\t\t\t\t\t\t\t\t\t\t\t\tstart_date: task.start_date,\n\t\t\t\t\t\t\t\t\t\t\t\tend_date: startDate,\n\t\t\t\t\t\t\t\t\t\t\t\ttask: task\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\tmode: \"fixedDuration\"\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tgantt.updateTaskAssignments(task.id);\n\t\t\t\t\t\t\t\tgantt.updateTask(task.id);\n\t\t\t\t\t\t\t}else if(value){\n\t\t\t\t\t\t\t\tvar assignment = {\n\t\t\t\t\t\t\t\t\ttask_id: taskId,\n\t\t\t\t\t\t\t\t\tresource_id: resourceId,\n\t\t\t\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\t\t\t\tstart_date: startDate,\n\t\t\t\t\t\t\t\t\tend_date: endDate,\n\t\t\t\t\t\t\t\t\tduration: gantt.calculateDuration({\n\t\t\t\t\t\t\t\t\t\tstart_date: startDate,\n\t\t\t\t\t\t\t\t\t\tend_date: endDate,\n\t\t\t\t\t\t\t\t\t\ttask: task\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\tdelay: gantt.calculateDuration({\n\t\t\t\t\t\t\t\t\t\tstart_date: task.start_date,\n\t\t\t\t\t\t\t\t\t\tend_date: startDate,\n\t\t\t\t\t\t\t\t\t\ttask: task\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\tmode: \"fixedDuration\"\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tassignmentStore.addItem(assignment);\n\t\t\t\t\t\t\t\tgantt.updateTaskAssignments(task.id);\n\t\t\t\t\t\t\t\tgantt.updateTask(task.id);\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}, {once: true});\n\t\t}\n\t};\n\treturn resourcePlugin;\n}\n\nexport default function(gantt){\n\tvar methods = createResourceMethods(gantt);\n\t\n\tgantt.ext.resources = createHelper(gantt);\n\n\tgantt.config.resources = {\n\t\tdataprocessor_assignments: false,\n\t\tdataprocessor_resources: false,\n\t\teditable_resource_diagram: false,\n\t\tresource_store: {\n\t\t\ttype: \"treeDataStore\",\n\t\t\tfetchTasks: false,\n\t\t\tinitItem: function(item) {\n\t\t\t\titem.parent = item.parent || gantt.config.root_id;\n\t\t\t\titem[gantt.config.resource_property] = item.parent;\n\t\t\t\titem.open = true;\n\t\t\t\treturn item;\n\t\t\t}\n\t\t},\n\t\tlightbox_resources: function selectResourceControlOptions(resources){\n\t\t\tconst lightboxOptions = [];\n\t\t\tconst store = gantt.getDatastore(gantt.config.resource_store);\n\t\t\tresources.forEach(function(res) {\n\t\t\t\tif (!store.hasChild(res.id)) {\n\t\t\t\t\tconst copy = gantt.copy(res);\n\t\t\t\t\tcopy.key = res.id;\n\t\t\t\t\tcopy.label = res.text;\n\t\t\t\t\tlightboxOptions.push(copy);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn lightboxOptions;\n\t\t}\n\t};\n\n\tgantt.attachEvent(\"onBeforeGanttReady\", function(){\n\t\tif(gantt.getDatastore(gantt.config.resource_store)){\n\t\t\treturn;\n\t\t}\n\n\t\tconst resourceStoreConfig = gantt.config.resources ? gantt.config.resources.resource_store : undefined;\n\t\tlet fetchTasks = resourceStoreConfig ? resourceStoreConfig.fetchTasks : undefined;\n\t\tif(gantt.config.resources && gantt.config.resources.editable_resource_diagram){\n\t\t\tfetchTasks = true;\n\t\t}\n\n\t\tlet initItems = function(item) {\n\t\t\titem.parent = item.parent || gantt.config.root_id;\n\t\t\titem[gantt.config.resource_property] = item.parent;\n\t\t\titem.open = true;\n\t\t\treturn item;\n\t\t};\n\n\t\tif(resourceStoreConfig && resourceStoreConfig.initItem){\n\t\t\tinitItems = resourceStoreConfig.initItem;\n\t\t}\n\n\t\tconst storeType = resourceStoreConfig && resourceStoreConfig.type ? resourceStoreConfig.type : \"treeDatastore\";\n\n\t\tgantt.$resourcesStore = gantt.createDatastore({\n\t\t\tname: gantt.config.resource_store,\n\t\t\ttype: storeType,\n\t\t\tfetchTasks: fetchTasks !== undefined ? fetchTasks : false,\n\t\t\tinitItem: initItems\n\t\t});\n\n\t\tgantt.$data.resourcesStore = gantt.$resourcesStore;\n\n\t\tgantt.$resourcesStore.attachEvent(\"onParse\", function() {\n\t\t\tfunction selectResourceControlOptions(resources){\n\t\t\t\tconst lightboxOptions = [];\n\t\t\t\tresources.forEach(function(res) {\n\t\t\t\t\tif (!gantt.$resourcesStore.hasChild(res.id)) {\n\t\t\t\t\t\tvar copy = gantt.copy(res);\n\t\t\t\t\t\tcopy.key = res.id;\n\t\t\t\t\t\tcopy.label = res.text;\n\t\t\t\t\t\tlightboxOptions.push(copy);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn lightboxOptions;\n\t\t\t}\n\n\t\t\tlet lightboxOptionsFnc = selectResourceControlOptions;\n\t\t\tif(gantt.config.resources && gantt.config.resources.lightbox_resources){\n\t\t\t\tlightboxOptionsFnc = gantt.config.resources.lightbox_resources;\n\t\t\t}\n\n\t\t\tconst options = lightboxOptionsFnc(gantt.$resourcesStore.getItems());\n\n\t\t\tgantt.updateCollection(\"resourceOptions\", options);\n\t\t});\n\t});\n\n\tgantt.getTaskBy = methods.getTaskBy;\n\tgantt.getResourceAssignments = methods.getResourceAssignments;\n\tgantt.config.resource_property = \"owner_id\";\n\tgantt.config.resource_store = \"resource\";\n\tgantt.config.resource_render_empty_cells = false;\n\n\t/**\n\t * these are placeholder functions that should be redefined by the user\n\t*/\n\tgantt.templates.histogram_cell_class = function(start_date, end_date, resource, tasks, assignments) {};\n\tgantt.templates.histogram_cell_label = function(start_date, end_date, resource, tasks, assignments) {\n\t\treturn tasks.length + \"/3\";\n\t};\n\tgantt.templates.histogram_cell_allocated = function(start_date, end_date, resource, tasks, assignments) {\n\t\treturn tasks.length / 3;\n\t};\n\tgantt.templates.histogram_cell_capacity = function(start_date, end_date, resource, tasks, assignments) {\n\t\treturn 0;\n\t};\n\n\n\tconst defaultResourceCellClass = function(start, end, resource, tasks, assignments) {\n\t\tvar css = \"\";\n\t\tif (tasks.length <= 1) {\n\t\t\tcss = \"gantt_resource_marker_ok\";\n\t\t} else {\n\t\t\tcss = \"gantt_resource_marker_overtime\";\n\t\t}\n\t\treturn css;\n\t};\n\n\tconst defaultResourceCellTemplate = function(start, end, resource, tasks, assignments) {\n\t\treturn tasks.length * 8;\n\t};\n\n\tgantt.templates.resource_cell_value = defaultResourceCellTemplate;\n\tgantt.templates.resource_cell_class = defaultResourceCellClass;\n\n\t//editable_resource_diagram\n\tgantt.attachEvent(\"onBeforeGanttReady\", function(){\n\t\tif(gantt.config.resources && gantt.config.resources.editable_resource_diagram){\n\n\t\t\tgantt.config.resource_render_empty_cells = true;\n\t\t\tif(gantt.templates.resource_cell_value === defaultResourceCellTemplate){\n\t\t\t\tgantt.templates.resource_cell_value = gantt.ext.resources.editableResourceCellTemplate;\n\t\t\t}\n\t\t\tif(gantt.templates.resource_cell_class === defaultResourceCellClass){\n\t\t\t\tgantt.templates.resource_cell_class = gantt.ext.resources.editableResourceCellClass;\n\t\t\t}\n\t\t\t\n\t\t\tgantt.ext.resources.initEditableDiagram(gantt);\n\t\t}\n\t});\n};\n\n\n","export default function (gantt) {\n\tvar resourceAssignmentsProperty = \"$resourceAssignments\";\n\tgantt.config.resource_assignment_store = \"resourceAssignments\";\n\tgantt.config.process_resource_assignments = true;\n\n\tvar resourceAssignmentFormats = {\n\t\tauto: \"auto\",\n\t\tsingleValue: \"singleValue\",\n\t\tvalueArray: \"valueArray\",\n\t\tresourceValueArray: \"resourceValueArray\",\n\t\tassignmentsArray: \"assignmentsArray\"\n\t};\n\tvar resourceAssignmentFormat = resourceAssignmentFormats.auto;//\"primitiveSingle\";//\"primitive\";//\"object\"|\"assignment\"\n\n\tvar assignmentModes = {\n\t\tfixedDates: \"fixedDates\",\n\t\tfixedDuration: \"fixedDuration\",\n\t\tdefault: \"default\"\n\t};\n\n\n\tfunction initAssignmentFields(item, task){\n\t\tif (item.start_date) {\n\t\t\titem.start_date = gantt.date.parseDate(item.start_date, \"parse_date\");\n\t\t} else {\n\t\t\titem.start_date = null;\n\t\t}\n\n\t\tif (item.end_date) {\n\t\t\titem.end_date = gantt.date.parseDate(item.end_date, \"parse_date\");\n\t\t} else {\n\t\t\titem.end_date = null;\n\t\t}\n\n\t\tvar delay = Number(item.delay);\n\t\tvar initDelay = false;\n\t\tif (!isNaN(delay)) {\n\t\t\titem.delay = delay;\n\t\t} else {\n\t\t\titem.delay = 0;\n\t\t\tinitDelay = true;\n\t\t}\n\n\t\tif (!gantt.defined(item.value)) {\n\t\t\titem.value = null;\n\t\t}\n\n\t\tif (!item.task_id || !item.resource_id) {\n\t\t\treturn false;\n\t\t}\n\n\t\titem.mode = item.mode || assignmentModes.default;\n\n\t\tif(item.mode === assignmentModes.fixedDuration){\n\t\t\tif(isNaN(Number(item.duration))){\n\t\t\t\ttask = task || gantt.getTask(item.task_id);\n\t\t\t\titem.duration = gantt.calculateDuration({\n\t\t\t\t\tstart_date: item.start_date,\n\t\t\t\t\tend_date: item.end_date,\n\t\t\t\t\tid: task\n\t\t\t\t});\n\t\t\t}\n\t\t\tif(initDelay){\n\t\t\t\ttask = task || gantt.getTask(item.task_id);\n\t\t\t\titem.delay = gantt.calculateDuration({\n\t\t\t\t\tstart_date: task.start_date,\n\t\t\t\t\tend_date: item.start_date,\n\t\t\t\t\tid: task\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (item.mode !== assignmentModes.fixedDates && (task || gantt.isTaskExists(item.task_id))) {\n\t\t\ttask = task || gantt.getTask(item.task_id);\n\t\t\tvar timing = _assignmentTimeFromTask(item, task);\n\t\t\titem.start_date = timing.start_date;\n\t\t\titem.end_date = timing.end_date;\n\t\t\titem.duration = timing.duration;\n\t\t}\n\t}\n\t// gantt init\n\tvar resourceAssignmentsStore = gantt.createDatastore({\n\t\tname: gantt.config.resource_assignment_store,\n\t\tinitItem: function (item) {\n\t\t\tif (!item.id) {\n\t\t\t\titem.id = gantt.uid();\n\t\t\t}\n\n\t\t\tinitAssignmentFields(item);\n\n\t\t\treturn item;\n\t\t}\n\t});\n\t\n\tgantt.$data.assignmentsStore = resourceAssignmentsStore;\n\n\tfunction _assignmentTimeFromTask(assignment, task) {\n\n\t\tif (assignment.mode === assignmentModes.fixedDates) {\n\t\t\treturn {\n\t\t\t\tstart_date: assignment.start_date,\n\t\t\t\tend_date: assignment.end_date,\n\t\t\t\tduration: assignment.duration\n\t\t\t};\n\t\t} else {\n\t\t\tvar start = assignment.delay ? gantt.calculateEndDate({\n\t\t\t\tstart_date: task.start_date,\n\t\t\t\tduration: assignment.delay,\n\t\t\t\ttask: task\n\t\t\t}) : new Date(task.start_date);\n\n\t\t\tvar end;\n\t\t\tvar duration;\n\t\t\tif (assignment.mode === assignmentModes.fixedDuration) {\n\t\t\t\tend = gantt.calculateEndDate({\n\t\t\t\t\tstart_date: start,\n\t\t\t\t\tduration: assignment.duration,\n\t\t\t\t\ttask: task\n\t\t\t\t});\n\t\t\t\tduration = assignment.duration;\n\t\t\t} else {\n\t\t\t\tend = new Date(task.end_date);\n\t\t\t\tduration = task.duration - assignment.delay;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tstart_date: start,\n\t\t\tend_date: end,\n\t\t\tduration: duration\n\t\t};\n\t}\n\n\t// data loading\n\n\tfunction _makeAssignmentsFromTask(task) {\n\t\tconst property = gantt.config.resource_property;\n\t\tlet assignments = task[property];\n\t\tconst resourceAssignments = [];\n\t\tlet detectFormat = resourceAssignmentFormat === resourceAssignmentFormats.auto;\n\n\t\tif (gantt.defined(assignments) && assignments) {\n\t\t\tif (!Array.isArray(assignments)) {\n\t\t\t\tassignments = [assignments];\n\t\t\t\tif (detectFormat) {\n\t\t\t\t\tresourceAssignmentFormat = resourceAssignmentFormats.singleValue;\n\t\t\t\t\tdetectFormat = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst usedIds = {};\n\t\t\tassignments.forEach(function (res) {\n\t\t\t\tif (!res.resource_id) { // when resource is a string/number\n\t\t\t\t\tres = { resource_id: res };\n\t\t\t\t\tif (detectFormat) {\n\t\t\t\t\t\tresourceAssignmentFormat = resourceAssignmentFormats.valueArray;\n\t\t\t\t\t\tdetectFormat = false;\n\t\t\t\t\t}\n\t\t\t\t\t//\tisSimpleArray = true;\n\t\t\t\t}\n\n\t\t\t\tif (detectFormat) {\n\t\t\t\t\tif (res.id && res.resource_id) {\n\t\t\t\t\t\tresourceAssignmentFormat = resourceAssignmentFormats.assignmentsArray;\n\t\t\t\t\t\tdetectFormat = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresourceAssignmentFormat = resourceAssignmentFormats.resourceValueArray;\n\t\t\t\t\t\tdetectFormat = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet defaultMode = assignmentModes.default;\n\t\t\t\tif(!res.mode){\n\t\t\t\t\tif((res.start_date && res.end_date) || (res.start_date && res.duration)){\n\t\t\t\t\t\tdefaultMode = assignmentModes.fixedDuration;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet id;\n\t\t\t\tif(!res.id && res.$id && !usedIds[res.$id]){\n\t\t\t\t\tid = res.$id;\n\t\t\t\t} else if(res.id && !usedIds[res.id]){\n\t\t\t\t\tid = res.id;\n\t\t\t\t} else{\n\t\t\t\t\tid = gantt.uid();\n\t\t\t\t}\n\t\t\t\tusedIds[id] = true;\n\n\t\t\t\tconst assignment = {\n\t\t\t\t\tid: id,\n\t\t\t\t\tstart_date: res.start_date,\n\t\t\t\t\tduration: res.duration,\n\t\t\t\t\tend_date: res.end_date,\n\t\t\t\t\tdelay: res.delay,\n\t\t\t\t\ttask_id: task.id,\n\t\t\t\t\tresource_id: res.resource_id,\n\t\t\t\t\tvalue: res.value,\n\t\t\t\t\tmode: res.mode || defaultMode\n\t\t\t\t};\n\t\t\t\t// GS-2490: to add custom properties to assignment\n\t\t\t\t// need to exclude $id which incfluences on render \n\t\t\t\tObject.keys(res).forEach(key => {\n\t\t\t\t\tif(key != \"$id\") {\n\t\t\t\t\t\tassignment[key] = res[key];\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif(!(assignment.start_date && assignment.start_date.getMonth \n\t\t\t\t\t&& assignment.end_date && assignment.end_date.getMonth && typeof assignment.duration === \"number\")){\n\t\t\t\t\tinitAssignmentFields(assignment, task);\n\t\t\t\t}\n\n\t\t\t\tresourceAssignments.push(assignment);\n\t\t\t});\n\t\t}\n\t\treturn resourceAssignments;\n\t}\n\n\tfunction _updateTaskBack(taskId) {\n\t\t// GS-1493. In some cases, the resource assignment store has the tasks that no longer exist\n\t\tif (!gantt.isTaskExists(taskId)){\n\t\t\treturn;\n\t\t}\n\n\t\tvar task = gantt.getTask(taskId);\n\t\tvar assignments = gantt.getTaskAssignments(task.id);\n\t\t_assignAssignments(task, assignments);\n\t}\n\n\tfunction _assignAssignments(task, assignments){\n\t\tassignments.sort(function(a, b){\n\t\t\tif(a.start_date && b.start_date && a.start_date.valueOf() != b.start_date.valueOf()){\n\t\t\t\treturn a.start_date - b.start_date;\n\t\t\t}else{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t});\n\t\tif (resourceAssignmentFormat == resourceAssignmentFormats.assignmentsArray) {\n\t\t\ttask[gantt.config.resource_property] = assignments;\n\t\t} else if (resourceAssignmentFormat == resourceAssignmentFormats.resourceValueArray) {\n\t\t\ttask[gantt.config.resource_property] = assignments.map(function (a) {\n\t\t\t\treturn {\n\t\t\t\t\t$id: a.id,\n\t\t\t\t\tstart_date: a.start_date,\n\t\t\t\t\tduration: a.duration,\n\t\t\t\t\tend_date: a.end_date,\n\t\t\t\t\tdelay: a.delay,\n\t\t\t\t\tresource_id: a.resource_id,\n\t\t\t\t\tvalue: a.value,\n\t\t\t\t\tmode: a.mode\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\n\t\ttask[resourceAssignmentsProperty] = assignments;\n\t}\n\n\tfunction _loadAssignmentsFromTask(task) {\n\t\tvar assignments = _makeAssignmentsFromTask(task);\n\t\tvar taskAssignments = [];\n\t\tassignments.forEach(function (a) {\n\t\t\ta.id = a.id || gantt.uid();\n\t\t\t//var newId = resourceAssignmentsStore.addItem(a);\n\t\t\ttaskAssignments.push(a);\n\t\t});\n\n\t\treturn assignments;\n\t}\n\n\tfunction diffAssignments(taskValues, assignmentsStoreValues) {\n\t\tvar result = {\n\t\t\tinBoth: [],\n\t\t\tinTaskNotInStore: [],\n\t\t\tinStoreNotInTask: []\n\t\t};\n\n\t\tif (resourceAssignmentFormat == resourceAssignmentFormats.singleValue) {\n\t\t\tvar taskOwner = taskValues[0];\n\t\t\tvar ownerId = taskOwner ? taskOwner.resource_id : null;\n\t\t\tvar foundOwnerAssignment = false;\n\t\t\tassignmentsStoreValues.forEach(function (a) {\n\t\t\t\tif (a.resource_id != ownerId) {\n\t\t\t\t\tresult.inStoreNotInTask.push(a);\n\t\t\t\t} else if (a.resource_id == ownerId) {\n\t\t\t\t\tresult.inBoth.push({ store: a, task: taskOwner });\n\t\t\t\t\tfoundOwnerAssignment = true;\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (!foundOwnerAssignment && taskOwner) {\n\t\t\t\tresult.inTaskNotInStore.push(taskOwner);\n\t\t\t}\n\n\n\t\t} else if (resourceAssignmentFormat == resourceAssignmentFormats.valueArray){\n\n\t\t\tvar taskSearch = {};\n\t\t\tvar storeSearch = {};\n\t\t\tvar processedIds = {};\n\t\t\ttaskValues.forEach(function (a) {\n\t\t\t\ttaskSearch[a.resource_id] = a;\n\t\t\t});\n\t\t\tassignmentsStoreValues.forEach(function (a) {\n\t\t\t\tstoreSearch[a.resource_id] = a;\n\t\t\t});\n\t\t\ttaskValues.concat(assignmentsStoreValues).forEach(function (a) {\n\t\t\t\tif (processedIds[a.resource_id]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tprocessedIds[a.resource_id] = true;\n\t\t\t\tvar inTask = taskSearch[a.resource_id];\n\t\t\t\tvar inStore = storeSearch[a.resource_id];\n\n\t\t\t\tif (inTask && inStore) {\n\t\t\t\t\tresult.inBoth.push({ store: inStore, task: inTask });\n\t\t\t\t} else if (inTask && !inStore) {\n\t\t\t\t\tresult.inTaskNotInStore.push(inTask);\n\t\t\t\t} else if (!inTask && inStore) {\n\t\t\t\t\tresult.inStoreNotInTask.push(inStore);\n\t\t\t\t}\n\t\t\t});\n\t\t} else if ((resourceAssignmentFormat == resourceAssignmentFormats.assignmentsArray)\n\t\t\t|| (resourceAssignmentFormat == resourceAssignmentFormats.resourceValueArray)) {\n\t\t\tvar taskSearch = {};\n\t\t\tvar storeSearch = {};\n\t\t\tvar processedIds = {};\n\t\t\ttaskValues.forEach(function (a) {\n\t\t\t\ttaskSearch[a.id || a.$id] = a;\n\t\t\t});\n\t\t\tassignmentsStoreValues.forEach(function (a) {\n\t\t\t\tstoreSearch[a.id] = a;\n\t\t\t});\n\t\t\ttaskValues.concat(assignmentsStoreValues).forEach(function (a) {\n\t\t\t\tvar id = a.id || a.$id;\n\t\t\t\tif (processedIds[id]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprocessedIds[id] = true;\n\t\t\t\tvar inTask = taskSearch[id];\n\t\t\t\tvar inStore = storeSearch[id];\n\n\t\t\t\tif (inTask && inStore) {\n\t\t\t\t\tresult.inBoth.push({ store: inStore, task: inTask });\n\t\t\t\t} else if (inTask && !inStore) {\n\t\t\t\t\tresult.inTaskNotInStore.push(inTask);\n\t\t\t\t} else if (!inTask && inStore) {\n\t\t\t\t\tresult.inStoreNotInTask.push(inStore);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\tfunction assignmentHasChanged(source, target) {\n\t\tvar ignoreFields = {\n\t\t\tid: true\n\t\t};\n\n\t\tfor (var i in source) {\n\t\t\tif (!ignoreFields[i]) {\n\t\t\t\tif (String(source[i]) !== String(target[i])) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\tfunction updateAssignment(source, target) {\n\t\tvar ignoreFields = {\n\t\t\tid: true\n\t\t};\n\n\t\tfor (var i in source) {\n\t\t\tif (!ignoreFields[i]) {\n\t\t\t\ttarget[i] = source[i];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction _syncAssignments(task, storeAssignments){\n\t\tvar tasksAssignments = _makeAssignmentsFromTask(task);\n\n\t\tvar diff = diffAssignments(tasksAssignments, storeAssignments);\n\t\tdiff.inStoreNotInTask.forEach(function (a) {\n\t\t\tresourceAssignmentsStore.removeItem(a.id);\n\t\t});\n\t\tdiff.inTaskNotInStore.forEach(function (a) {\n\t\t\tresourceAssignmentsStore.addItem(a);\n\t\t});\n\n\t\tdiff.inBoth.forEach(function (a) {\n\t\t\tif (assignmentHasChanged(a.task, a.store)) {\n\t\t\t\tupdateAssignment(a.task, a.store);\n\t\t\t\tresourceAssignmentsStore.updateItem(a.store.id);\n\t\t\t} else {\n\t\t\t\tif (a.task.start_date && a.task.end_date && a.task.mode !== assignmentModes.fixedDates) {\n\t\t\t\t\tvar timing = _assignmentTimeFromTask(a.store, task);\n\t\t\t\t\tif (a.store.start_date.valueOf() != timing.start_date.valueOf() || a.store.end_date.valueOf() != timing.end_date.valueOf()) {\n\t\t\t\t\t\ta.store.start_date = timing.start_date;\n\t\t\t\t\t\ta.store.end_date = timing.end_date;\n\t\t\t\t\t\ta.store.duration = timing.duration;\n\t\t\t\t\t\tresourceAssignmentsStore.updateItem(a.store.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t_updateTaskBack(task.id);\n\t}\n\n\tfunction _syncOnTaskUpdate(task) {\n\t\tvar storeAssignments = task[resourceAssignmentsProperty] || resourceAssignmentsStore.find(function (a) {\n\t\t\treturn a.task_id == task.id;\n\t\t});\n\n\t\t_syncAssignments(task, storeAssignments);\n\t}\n\n\tfunction _syncOnTaskDelete(ids) {\n\t\tvar idsSearch = {};\n\t\tids.forEach(function (id) {\n\t\t\tidsSearch[id] = true;\n\t\t});\n\t\tvar taskResources = resourceAssignmentsStore.find(function (a) {\n\t\t\treturn idsSearch[a.task_id];\n\t\t});\n\t\ttaskResources.forEach(function (a) {\n\t\t\tresourceAssignmentsStore.removeItem(a.id);\n\t\t});\n\t}\n\n\tgantt.attachEvent(\"onGanttReady\", function(){\n\n\t\tif (gantt.config.process_resource_assignments) {\n\t\t\tgantt.attachEvent(\"onParse\", function () {\n\t\t\t\tgantt.silent(function () {\n\t\t\t\t\tresourceAssignmentsStore.clearAll();\n\t\t\t\t\tvar totalAssignments = [];\n\t\t\t\t\tgantt.eachTask(function (task) {\n\t\t\t\t\t\tif (task.type === gantt.config.types.project) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar assignments = _loadAssignmentsFromTask(task);\n\t\t\t\t\t\t_assignAssignments(task, assignments);\n\n\t\t\t\t\t\tassignments.forEach(function (a) {\n\t\t\t\t\t\t\ttotalAssignments.push(a);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\tresourceAssignmentsStore.parse(totalAssignments);\n\t\t\t\t});\n\n\t\t\t});\n\n\t\t\tvar batchUpdate = false;\n\t\t\tvar needUpdate = false;\n\t\t\tvar needUpdateFor = {};\n\t\t\tvar undoBatchCancel = false;\n\t\t\tgantt.attachEvent(\"onBeforeBatchUpdate\", function(){\n\t\t\t\tbatchUpdate = true;\n\t\t\t});\n\t\t\tgantt.attachEvent(\"onAfterBatchUpdate\", function(){\n\t\t\t\t\n\t\t\t\tif(needUpdate){\n\t\t\t\t\tvar assignmentsHash = {};\n\t\t\t\t\tfor(var i in needUpdateFor){\n\t\t\t\t\t\tassignmentsHash[i] = gantt.getTaskAssignments(needUpdateFor[i].id);\n\t\t\t\t\t}\n\t\t\t\t\tfor(var i in needUpdateFor){\n\t\t\t\t\t\t_syncAssignments(needUpdateFor[i], assignmentsHash[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tneedUpdate = false;\n\t\t\t\tbatchUpdate = false;\n\t\t\t\tneedUpdateFor = {};\n\t\t\t});\n\n\t\t\tgantt.attachEvent(\"onTaskCreated\", function (item) {\n\t\t\t\tvar assignments = _loadAssignmentsFromTask(item);\n\t\t\t\tresourceAssignmentsStore.parse(assignments);\n\t\t\t\t_assignAssignments(item, assignments);\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tgantt.attachEvent(\"onAfterTaskUpdate\", function (id, item) {\n\t\t\t\tif(batchUpdate){\n\t\t\t\t\tneedUpdate = true;\n\t\t\t\t\tneedUpdateFor[id] = item;\n\t\t\t\t}else if (!item.unscheduled){\n\t\t\t\t\t_syncOnTaskUpdate(item);\n\t\t\t\t}\n\t\t\t});\n\t\t\tgantt.attachEvent(\"onAfterTaskAdd\", function (id, item) {\n\t\t\t\tif(batchUpdate){\n\t\t\t\t\tneedUpdate = true;\n\t\t\t\t\tneedUpdateFor[id] = item;\n\t\t\t\t}else{\n\t\t\t\t\t_syncOnTaskUpdate(item);\n\t\t\t\t}\n\t\t\t});\n\n\t\t/*\tgantt.attachEvent(\"onRowDragMove\", function (id) {\n\t\t\t\t_syncOnTaskUpdate(gantt.getTask(id));\n\t\t\t});*/\n\t\t\tgantt.attachEvent(\"onRowDragEnd\", function (id) {\n\t\t\t\t_syncOnTaskUpdate(gantt.getTask(id));\n\t\t\t});\n\t\t\tgantt.$data.tasksStore.attachEvent(\"onAfterDeleteConfirmed\", function (id, item) {\n\t\t\t\tvar deleteIds = [id];\n\t\t\t\tgantt.eachTask(function (task) {\n\t\t\t\t\tdeleteIds.push(task.id);\n\t\t\t\t}, id);\n\t\t\t\t_syncOnTaskDelete(deleteIds);\n\t\t\t});\n\t\t\tgantt.$data.tasksStore.attachEvent(\"onClearAll\", function () {\n\t\t\t\tresourceAssignmentsCache = null;\n\t\t\t\tresourceTaskAssignmentsCache = null;\n\t\t\t\ttaskAssignmentsCache = null;\n\t\t\t\tresourceAssignmentsStore.clearAll();\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tgantt.attachEvent(\"onTaskIdChange\", function (id, new_id) {\n\t\t\t\tvar taskResources = resourceAssignmentsStore.find(function (a) {\n\t\t\t\t\treturn a.task_id == id;\n\t\t\t\t});\n\t\t\t\ttaskResources.forEach(function (a) {\n\t\t\t\t\ta.task_id = new_id;\n\t\t\t\t\tresourceAssignmentsStore.updateItem(a.id);\n\t\t\t\t});\n\t\t\t\t_updateTaskBack(new_id);\n\t\t\t\t//any custom logic here\n\t\t\t});\n\t\t\t// GS-2144. When we Undo something, the cache should be reset\n\t\t\t// during the `onStoreUpdated` event to properly update the assignments\n\t\t\tgantt.attachEvent(\"onBeforeUndo\", function (action) {\n\t\t\t\tundoBatchCancel = true;\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tgantt.attachEvent(\"onAfterUndo\", function (action) {\n\t\t\t\tundoBatchCancel = true;\n\t\t\t});\n\n\n\t\t\tvar resourceAssignmentsCache = null;\n\t\t\tvar resourceTaskAssignmentsCache = null;\n\t\t\tvar taskAssignmentsCache = null;\n\n\t\t\tresourceAssignmentsStore.attachEvent(\"onStoreUpdated\", function resetCache(){\n\t\t\t\tif(batchUpdate && !undoBatchCancel){\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tresourceAssignmentsCache = null;\n\t\t\t\tresourceTaskAssignmentsCache = null;\n\t\t\t\ttaskAssignmentsCache = null;\n\t\t\t\treturn true;\n\t\t\t});\n\n\t\t\tgantt.getResourceAssignments = function (resourceId, taskId) {\n\t\t\t\tvar searchTaskId = gantt.defined(taskId) && taskId !== null;\n\n\t\t\t\tif(resourceAssignmentsCache === null){\n\t\t\t\t\tresourceAssignmentsCache = {};\n\t\t\t\t\tresourceTaskAssignmentsCache = {};\n\n\t\t\t\t\tresourceAssignmentsStore.eachItem(function (a) {\n\t\t\t\t\t\tif(!resourceAssignmentsCache[a.resource_id]){\n\t\t\t\t\t\t\tresourceAssignmentsCache[a.resource_id] = [];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresourceAssignmentsCache[a.resource_id].push(a);\n\n\t\t\t\t\t\tvar resourceTaskCacheKey = a.resource_id + \"-\" + a.task_id;\n\t\t\t\t\t\tif(!resourceTaskAssignmentsCache[resourceTaskCacheKey]){\n\t\t\t\t\t\t\tresourceTaskAssignmentsCache[resourceTaskCacheKey] = [];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresourceTaskAssignmentsCache[resourceTaskCacheKey].push(a);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\n\t\t\t\tif(searchTaskId){\n\t\t\t\t\treturn (resourceTaskAssignmentsCache[resourceId + \"-\" + taskId] || []).slice();\n\t\t\t\t}else{\n\t\t\t\t\treturn (resourceAssignmentsCache[resourceId] || []).slice();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t\n\t\t\tgantt.getTaskAssignments = function (taskId) {\n\t\t\t\tif(taskAssignmentsCache === null){\n\t\t\t\t\tvar result = [];\n\t\t\t\t\ttaskAssignmentsCache = {};\n\t\t\t\t\tresourceAssignmentsStore.eachItem(function (a) {\n\t\t\t\t\t\tif(!taskAssignmentsCache[a.task_id]){\n\t\t\t\t\t\t\ttaskAssignmentsCache[a.task_id] = [];\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttaskAssignmentsCache[a.task_id].push(a);\n\t\t\t\t\t\tif (a.task_id == taskId) {\n\t\t\t\t\t\t\tresult.push(a);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn (taskAssignmentsCache[taskId] || []).slice();\n\t\t\t};\n\t\t\t\n\t\t\tgantt.getTaskResources = function (taskId) {\n\t\t\t\tconst store = gantt.getDatastore(\"resource\");\n\t\t\t\tconst assignments = gantt.getTaskAssignments(taskId);\n\t\n\t\t\t\tconst uniqueResources = {};\n\t\t\t\tassignments.forEach(function(a){\n\t\t\t\t\tif(!uniqueResources[a.resource_id]){\n\t\t\t\t\t\tuniqueResources[a.resource_id] = a.resource_id;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tconst resources = [];\n\t\t\t\tfor(const i in uniqueResources){\n\t\t\t\t\tconst res = store.getItem(uniqueResources[i]);\n\t\t\t\t\tif(res){\n\t\t\t\t\t\tresources.push(res);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn resources;\n\t\t\t};\n\n\t\t\tgantt.updateTaskAssignments = _updateTaskBack;\n\t\t}\n\t}, {once: true});\n};","export default function addPlaceholder(gantt){\n\tfunction isEnabled(){\n\t\treturn gantt.config.placeholder_task;\n\t}\n\n\tfunction callIfEnabled(callback){\n\t\treturn function(){\n\t\t\tif(!isEnabled()){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn callback.apply(this, arguments);\n\t\t};\n\t}\n\n\tfunction silenceDataProcessor(dataProcessor){\n\t\tif(dataProcessor && !dataProcessor._silencedPlaceholder){\n\t\t\tdataProcessor._silencedPlaceholder = true;\n\t\t\tdataProcessor.attachEvent(\"onBeforeUpdate\", callIfEnabled(function(id, state, data){\n\t\t\t\tif(data.type == gantt.config.types.placeholder){\n\t\t\t\t\tdataProcessor.setUpdated(id, false);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}));\n\t\t}\n\t}\n\n\tfunction insertPlaceholder(){\n\t\tvar placeholders = gantt.getTaskBy(\"type\", gantt.config.types.placeholder);\n\t\tif(!placeholders.length || !gantt.isTaskExists(placeholders[0].id)){\n\t\t\tvar placeholder = {\n\t\t\t\tunscheduled: true,\n\t\t\t\ttype: gantt.config.types.placeholder,\n\t\t\t\tduration:0,\n\t\t\t\ttext: gantt.locale.labels.new_task\n\t\t\t};\n\t\t\tif(gantt.callEvent(\"onTaskCreated\", [placeholder]) === false){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tgantt.addTask(placeholder);\n\t\t\t\n\t\t}\n\t}\n\n\tfunction afterEdit(id){\n\t\tvar item = gantt.getTask(id);\n\t\tif(item.type == gantt.config.types.placeholder) {\n\t\t\tif(item.start_date && item.end_date && item.unscheduled){\n\t\t\t\titem.unscheduled = false;\n\t\t\t}\n\n\t\t\tgantt.batchUpdate(function(){\n\t\t\t\tvar newTask = gantt.copy(item);\n\t\t\t\tgantt.silent(function(){\n\t\t\t\t\tgantt.deleteTask(item.id);\n\t\t\t\t});\n\n\t\t\t\tdelete newTask[\"!nativeeditor_status\"];\n\t\t\t\tnewTask.type = gantt.config.types.task;\n\t\t\t\tnewTask.id = gantt.uid();\n\t\t\t\tgantt.addTask(newTask);\n\n\t\t\t\t//insertPlaceholder();\n\t\t\t});\n\n\t\t}\n\t}\n\n\tgantt.config.types.placeholder = \"placeholder\";\n\tgantt.attachEvent(\"onDataProcessorReady\", callIfEnabled(silenceDataProcessor));\n\n\tvar ready = false;\n\tgantt.attachEvent(\"onGanttReady\", function(){\n\t\tif(ready){\n\t\t\treturn;\n\t\t}\n\t\tready = true;\n\t\tgantt.attachEvent(\"onAfterTaskUpdate\", callIfEnabled(afterEdit));\n\t\tgantt.attachEvent(\"onAfterTaskAdd\", callIfEnabled(function(id, task){\n\t\t\tif(task.type != gantt.config.types.placeholder){\n\t\t\t\tvar placeholders = gantt.getTaskBy(\"type\", gantt.config.types.placeholder);\n\t\t\t\tplaceholders.forEach(function(p){\n\t\t\t\t\tgantt.silent(function(){\n\t\t\t\t\t\tif(gantt.isTaskExists(p.id))\n\t\t\t\t\t\t\tgantt.deleteTask(p.id);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\tinsertPlaceholder();\n\t\t\t}\n\t\t}));\n\t\tgantt.attachEvent(\"onParse\", callIfEnabled(insertPlaceholder));\n\t});\n\n\tfunction isPlaceholderTask(taskId){\n\t\tif(gantt.config.types.placeholder && gantt.isTaskExists(taskId)){\n\t\t\tvar task = gantt.getTask(taskId);\n\t\t\tif(task.type == gantt.config.types.placeholder){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\tfunction isPlaceholderLink(link){\n\t\tif(isPlaceholderTask(link.source) || isPlaceholderTask(link.target)){\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\tgantt.attachEvent(\"onLinkValidation\", function(link){\n\t\tif(isPlaceholderLink(link)){\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t});\n\tgantt.attachEvent(\"onBeforeLinkAdd\", function(id,link){\n\t\tif(isPlaceholderLink(link)){\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t});\n\n\tgantt.attachEvent(\"onBeforeUndoStack\", function(action){\n\t\tfor(var i = 0; i < action.commands.length; i++){\n\t\t\tvar command = action.commands[i];\n\t\t\tif(command.entity === \"task\" && command.value.type === gantt.config.types.placeholder){\n\t\t\t\taction.commands.splice(i,1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t});\n\n};","export default function(gantt) {\n\tfunction isEnabled() {\n\t\treturn gantt.config.auto_types && // if enabled\n\t\t\t(gantt.getTaskType(gantt.config.types.project) == gantt.config.types.project);// and supported\n\t}\n\n\tfunction callIfEnabled(callback) {\n\t\treturn function() {\n\t\t\tif (!isEnabled()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn callback.apply(this, arguments);\n\t\t};\n\t}\n\n\tfunction checkTaskType(id, changedTypes) {\n\t\tvar task = gantt.getTask(id);\n\t\tvar targetType = getTaskTypeToUpdate(task);\n\t\tif (targetType !== false && gantt.getTaskType(task) !== targetType) {\n\t\t\tchangedTypes.$needsUpdate = true;\n\t\t\tchangedTypes[task.id] = {task: task, type: targetType};\n\t\t}\n\t}\n\n\tfunction getUpdatedTypes(id, changedTypes) {\n\t\tchangedTypes = changedTypes || {};\n\t\t\n\t\tcheckTaskType(id, changedTypes);\n\t\tgantt.eachParent(function(parent) {\n\t\t\tcheckTaskType(parent.id, changedTypes);\n\t\t}, id);\n\n\t\treturn changedTypes;\n\t}\n\n\tfunction applyChanges(changedTypes) {\n\t\tfor (var i in changedTypes) {\n\t\t\tif(changedTypes[i] && changedTypes[i].task){\n\t\t\t\tvar task = changedTypes[i].task;\n\t\t\t\ttask.type = changedTypes[i].type;\n\t\t\t\tgantt.updateTask(task.id);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction updateParentTypes(startId) {\n\t\tif (gantt.getState().group_mode) {\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tvar changedTypes = getUpdatedTypes(startId);\n\t\tif (changedTypes.$needsUpdate) {\n\t\t\tgantt.batchUpdate(function() {\n\t\t\t\tapplyChanges(changedTypes);\n\t\t\t});\n\t\t}\n\t}\n\n\tvar delTaskParent;\n\n\tfunction updateTaskType(task, targetType) {\n\t\tif(!gantt.getState().group_mode){\n\t\t\ttask.type = targetType;\n\t\t\tgantt.updateTask(task.id);\n\t\t}\n\t}\n\n\tfunction getTaskTypeToUpdate(task) {\n\t\tvar allTypes = gantt.config.types;\n\t\tvar hasChildren = gantt.hasChild(task.id);\n\t\tvar taskType = gantt.getTaskType(task.type);\n\n\t\tif (hasChildren && taskType === allTypes.task) {\n\t\t\treturn allTypes.project;\n\t\t}\n\n\t\tif (!hasChildren && taskType === allTypes.project) {\n\t\t\treturn allTypes.task;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tvar isParsingDone = true;\n\n\tgantt.attachEvent(\"onParse\", callIfEnabled(function() {\n\t\tisParsingDone = false;\n\t\tif(gantt.getState().group_mode){\n\t\t\treturn;\n\t\t}\n\n\t\tgantt.batchUpdate(function() {\n\t\t\tgantt.eachTask(function(task) {\n\t\t\t\tvar targetType = getTaskTypeToUpdate(task);\n\t\t\t\tif (targetType !== false) {\n\t\t\t\t\tupdateTaskType(task, targetType);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tisParsingDone = true;\n\t}));\n\n\tgantt.attachEvent(\"onAfterTaskAdd\", callIfEnabled(function(id) {\n\t\tif (isParsingDone) {\n\t\t\tupdateParentTypes(id);\n\t\t}\n\t}));\n\n\tgantt.attachEvent(\"onAfterTaskUpdate\", callIfEnabled(function(id) {\n\t\tif (isParsingDone) {\n\t\t\tupdateParentTypes(id);\n\t\t}\n\t}));\n\n\tfunction updateAfterRemoveChild(id){\n\t\tif (id != gantt.config.root_id && gantt.isTaskExists(id)) {\n\t\t\tupdateParentTypes(id);\n\t\t}\n\t}\n\n\tgantt.attachEvent(\"onBeforeTaskDelete\", callIfEnabled(function(id, task) {\n\t\tdelTaskParent = gantt.getParent(id);\n\t\treturn true;\n\t}));\n\n\tgantt.attachEvent(\"onAfterTaskDelete\", callIfEnabled(function(id, task) {\n\t\tupdateAfterRemoveChild(delTaskParent);\n\t}));\n\n\n\tvar originalRowDndParent;\n\n\tgantt.attachEvent(\"onRowDragStart\", callIfEnabled(function(id, target, e) {\n\t\toriginalRowDndParent = gantt.getParent(id);\n\t\treturn true;\n\t}));\n\n\tgantt.attachEvent(\"onRowDragEnd\", callIfEnabled(function(id, target) {\n\t\tupdateAfterRemoveChild(originalRowDndParent);\n\t\tupdateParentTypes(id);\n\t}));\n\n\tvar originalMoveTaskParent;\n\n\tgantt.attachEvent(\"onBeforeTaskMove\", callIfEnabled(function(sid, parent, tindex) {\n\t\toriginalMoveTaskParent = gantt.getParent(sid);\n\t\treturn true;\n\t}));\n\n\tgantt.attachEvent(\"onAfterTaskMove\", callIfEnabled(function(id, parent, tindex) {\n\t\tif (document.querySelector(\".gantt_drag_marker\")) {\n\t\t\t// vertical dnd in progress\n\t\t\treturn;\n\t\t}\n\t\tupdateAfterRemoveChild(originalMoveTaskParent);\n\t\tupdateParentTypes(id);\n\t}));\n};","interface IFormatterTransfer {\n\ttoMinutes: (value: number) => number;\n\tfromMinutes: (value: number) => number;\n}\n\nexport default class DurationFormatter implements IDurationFormatter {\n\tstatic create = (settings: IDurationFormatterConfig = null): IDurationFormatter => {\n\t\treturn new DurationFormatter(settings);\n\t};\n\tprotected transferUnits: { [unit: string]: IFormatterTransfer };\n\tprotected _config: IDurationFormatterConfig;\n\tconstructor(settings: IDurationFormatterConfig = null) {\n\n\t\tthis._config = this._defaultSettings(settings);\n\t\tthis.transferUnits = {\n\t\t\tminute: {\n\t\t\t\ttoMinutes: (value: number) => {\n\t\t\t\t\treturn value;\n\t\t\t\t},\n\t\t\t\tfromMinutes: (value: number) => {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t},\n\t\t\thour: {\n\t\t\t\ttoMinutes: (value: number) => {\n\t\t\t\t\treturn value * this._config.minutesPerHour;\n\t\t\t\t},\n\t\t\t\tfromMinutes: (value: number) => {\n\t\t\t\t\treturn value / this._config.minutesPerHour;\n\t\t\t\t}\n\t\t\t},\n\t\t\tday: {\n\t\t\t\ttoMinutes: (value: number) => {\n\t\t\t\t\treturn value * this._config.minutesPerHour * this._config.hoursPerDay;\n\t\t\t\t},\n\t\t\t\tfromMinutes: (value: number) => {\n\t\t\t\t\treturn value / (this._config.minutesPerHour * this._config.hoursPerDay);\n\t\t\t\t}\n\t\t\t},\n\t\t\tweek: {\n\t\t\t\ttoMinutes: (value: number) => {\n\t\t\t\t\treturn value * this._config.minutesPerHour * this._config.hoursPerWeek;\n\t\t\t\t},\n\t\t\t\tfromMinutes: (value: number) => {\n\t\t\t\t\treturn value / (this._config.minutesPerHour * this._config.hoursPerWeek);\n\t\t\t\t}\n\t\t\t},\n\t\t\tmonth: {\n\t\t\t\ttoMinutes: (value: number) => {\n\t\t\t\t\treturn value * this._config.minutesPerHour * this._config.hoursPerDay * this._config.daysPerMonth;\n\t\t\t\t},\n\t\t\t\tfromMinutes: (value: number) => {\n\t\t\t\t\treturn value / (this._config.minutesPerHour * this._config.hoursPerDay * this._config.daysPerMonth);\n\t\t\t\t}\n\t\t\t},\n\t\t\tyear: {\n\t\t\t\ttoMinutes: (value: number) => {\n\t\t\t\t\treturn value * this._config.minutesPerHour * this._config.hoursPerDay * this._config.daysPerYear;\n\t\t\t\t},\n\t\t\t\tfromMinutes: (value: number) => {\n\t\t\t\t\treturn value / (this._config.minutesPerHour * this._config.hoursPerDay * this._config.daysPerYear);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tcanParse = (value: string) : boolean => {\n\t\tlet units = \"\";\n\t\t// create all possible unit names\n\t\tconst labels = this._config.labels;\n\t\tfor(const labelName in labels){\n\t\t\tconst label = labels[labelName];\n\t\t\tunits += `${label.full}|${label.plural}|${label.short}|`;\n\t\t}\n\t\tconst reg = new RegExp(`^([+\\-]? *[0-9\\.]{1,}\\\\s*(${units})\\\\s*)*$`); // model looks like: 4h 20 minute\n\t\treturn reg.test((value||\"\").trim());\n\t};\n\n\tformat = (value:number) : string => {\n\n\t\tconst durationUnit = this._config.store;\n\t\tconst formatUnits = this._config.format;\n\t\tconst useShortLabels = this._config.short;\n\n\t\tlet totalMinutes = this.transferUnits[durationUnit]\n\t\t\t.toMinutes(value);\n\n\t\tlet units = formatUnits;\n\t\tif(units && units === \"auto\") {\n\t\t\tunits = this._selectFormatForValue(totalMinutes);\n\t\t}\n\t\tif(!units) {\n\t\t\tunits = \"day\";\n\t\t}\n\n\t\tif(formatUnits === \"auto\" && !value){\n\t\t\treturn \"\";\n\t\t}\n\t\tunits = Array.isArray(units) ? units : [units];\n\t\tlet result = \"\";\n\t\tconst last = units.length - 1;\n\t\tfor(let i = 0; i < units.length; i++){\n\t\t\tconst unit = units[i];\n\t\t\tconst countedValue = this._getValueFromMinutes(totalMinutes, unit, i === last);\n\t\t\ttotalMinutes -= this._getValueInMinutes(countedValue, unit);\n\n\t\t\tresult += `${this._getLabelForConvert(countedValue, unit, useShortLabels)}${i === last ? \"\" : \" \"}`;\n\t\t}\n\t\treturn result;\n\t};\n\n\tparse = (value: string) : number => {\n\t\tif(this.canParse(value)){\n\t\t\tvalue = (value||\"\").trim();\n\t\t\tlet part = \"\";\n\t\t\tlet isPartReady = false;\n\t\t\tlet needToParse = false;\n\t\t\tlet result = 0;\n\t\t\tconst last = value.length - 1;\n\t\t\tconst isNumber = /^[+\\-0-9\\. ]$/; // numbers and .;\n\n\t\t\tfor(let i = 0; i < value.length; i++){\n\t\t\t\tconst symbol = value[i];\n\t\t\t\tif(isNumber.test(symbol)){\n\t\t\t\t\t// found the next number. can parse the part of value\n\t\t\t\t\tneedToParse = isPartReady;\n\t\t\t\t} else {\n\t\t\t\t\t// the number is over. letters in turn. find the next number to get whole unit name\n\t\t\t\t\tisPartReady = true;\n\t\t\t\t}\n\n\t\t\t\t// parse the part of number or the resulting part, if the last element\n\t\t\t\tif(needToParse || last === i){\n\t\t\t\t\t// add the last symbol to the part if the last element\n\t\t\t\t\tif(!needToParse) {\n\t\t\t\t\t\tpart += symbol;\n\t\t\t\t\t}\n\n\t\t\t\t\t// parse the part to minutes\n\t\t\t\t\tresult += this._getNumericValue(part);\n\t\t\t\t\tisPartReady = needToParse = false;\n\t\t\t\t\tpart = \"\";\n\t\t\t\t}\n\t\t\t\tpart += symbol;\n\t\t\t}\n\t\t\tif(result){\n\t\t\t\tconst durationUnit = this._config.store;\n\t\t\t\treturn Math.round(this.transferUnits[durationUnit]\n\t\t\t\t\t.fromMinutes(Math.ceil(result)));\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t};\n\n\tprotected _defaultSettings(settings: IDurationFormatterConfig = null){\n\t\tconst preparedSettings: IDurationFormatterConfig = {\n\t\t\tenter: \"day\",\n\t\t\tstore: \"hour\",\n\t\t\tformat: \"auto\",\n\t\t\tshort: false,\n\t\t\tminutesPerHour: 60,\n\t\t\thoursPerDay: 8,\n\t\t\thoursPerWeek: 40,\n\t\t\tdaysPerMonth: 30,\n\t\t\tdaysPerYear: 365,\n\t\t\tlabels: {\n\t\t\t\tminute: {\n\t\t\t\t\tfull: \"minute\",\n\t\t\t\t\tplural: \"minutes\",\n\t\t\t\t\tshort: \"min\"\n\t\t\t\t},\n\t\t\t\thour: {\n\t\t\t\t\tfull: \"hour\",\n\t\t\t\t\tplural: \"hours\",\n\t\t\t\t\tshort: \"h\"\n\t\t\t\t},\n\t\t\t\tday: {\n\t\t\t\t\tfull: \"day\",\n\t\t\t\t\tplural: \"days\",\n\t\t\t\t\tshort: \"d\"\n\t\t\t\t},\n\t\t\t\tweek: {\n\t\t\t\t\tfull: \"week\",\n\t\t\t\t\tplural: \"weeks\",\n\t\t\t\t\tshort: \"wk\"\n\t\t\t\t},\n\t\t\t\tmonth: {\n\t\t\t\t\tfull: \"month\",\n\t\t\t\t\tplural: \"months\",\n\t\t\t\t\tshort: \"mon\"\n\t\t\t\t},\n\t\t\t\tyear: {\n\t\t\t\t\tfull: \"year\",\n\t\t\t\t\tplural: \"years\",\n\t\t\t\t\tshort: \"y\"\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tif(settings){\n\t\t\tfor(const i in settings){\n\t\t\t\tif(settings[i] !== undefined && i !== \"labels\") {\n\t\t\t\t\tpreparedSettings[i] = settings[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(settings.labels){\n\t\t\t\tfor(const i in settings.labels) {\n\t\t\t\t\tpreparedSettings.labels[i] = settings.labels[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn preparedSettings;\n\n\t}\n\n\tprotected _selectFormatForValue(value: number): string {\n\t\tconst units = [\"year\",\"month\",\"day\",\"hour\",\"minute\"];\n\t\tconst values = [];\n\t\tfor(let i = 0; i < units.length; i++) {\n\t\t\tvalues[i] = Math.abs(this.transferUnits[units[i]].fromMinutes(value));\n\t\t}\n\n\t\tfor(let i = 0; i < values.length; i++) {\n\t\t\tconst valueInUnit = values[i];\n\t\t\tif(valueInUnit < 1 && i < values.length - 1){\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\treturn units[i];\n\t\t\t}\n\t\t}\n\n\t\treturn \"day\";\n\t}\n\n\tprotected _getNumericValue(value: string) : number {\n\t\tconst numericValue = parseFloat(value.replace(/ /g, \"\")) || 0;\n\t\tconst lettersValue = value.match(/\\p{L}/gu) ? value.match(/\\p{L}/gu).join(\"\") : \"\";\n\t\tconst unitName = this._getUnitName(lettersValue); // leave only letters\n\n\t\tif(!numericValue || !unitName){\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn this._getValueInMinutes(numericValue, unitName);\n\t}\n\n\tprotected _getValueInMinutes = (value: number, unit: string) => {\n\t\tif(this.transferUnits[unit] && this.transferUnits[unit].toMinutes){\n\t\t\treturn this.transferUnits[unit].toMinutes(value);\n\t\t}\n\t\treturn 0;\n\t};\n\n\tprotected _getLabelForConvert = (value: number, unit: string, short: boolean) : string => {\n\t\tconst labels = this._config.labels;\n\t\tconst label = labels[unit];\n\t\tif(short){\n\t\t\treturn `${value}${label.short}`;\n\t\t}\n\n\t\treturn `${value} ${value !== 1 ? label.plural : label.full}`;\n\t};\n\n\tprotected _getValueFromMinutes = (value: number, unit: string, last: boolean) : number => {\n\t\tif(this.transferUnits[unit] && this.transferUnits[unit].fromMinutes){\n\t\t\tconst result = this.transferUnits[unit].fromMinutes(value);\n\n\t\t\tif(last){\n\t\t\t\treturn parseFloat(result.toFixed(2));\n\t\t\t}\n\t\t\treturn parseInt(result.toString(), 10);\n\t\t}\n\t\treturn null;\n\t};\n\n\tprotected _isUnitName = (unit: any, value: string) : boolean => {\n\t\tvalue = value.toLowerCase();\n\t\treturn unit.full.toLowerCase() === value\n\t\t\t|| unit.plural.toLowerCase() === value\n\t\t\t|| unit.short.toLowerCase() === value;\n\t};\n\n\tprotected _getUnitName = (value: string) : string => {\n\t\tconst labels = this._config.labels;\n\t\tlet labelName: string;\n\t\tlet isUnit = false;\n\t\tfor(labelName in labels){\n\t\t\tif(this._isUnitName(labels[labelName], value)){\n\t\t\t\tisUnit = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif(isUnit){\n\t\t\treturn labelName;\n\t\t}\n\t\treturn this._config.enter;\n\t};\n}","export default class LinkFormatterSimple implements ILinkFormatter {\n\tstatic create = (settings: ILinkFormatterConfig = null, gantt: any): LinkFormatterSimple => {\n\t\treturn new LinkFormatterSimple(gantt);\n\t};\n\tprotected _linkReg: RegExp;\n\tprotected _gantt: any;\n\n\tconstructor(gantt: any) {\n\t\tthis._linkReg = /^[0-9\\.]+/;\n\t\tthis._gantt = gantt;\n\t}\n\n\tformat = (link: ILink) : string => {\n\t\tconst wbs = this._getWBSCode(link.source);\n\t\treturn wbs;\n\t};\n\n\tcanParse = (value: string) : boolean => {\n\t\treturn this._linkReg.test(value);\n\t};\n\tparse = (value: string) : ILink => {\n\t\tif(!this.canParse(value)){\n\t\t\treturn null;\n\t\t}\n\n\t\tconst linkPart = this._linkReg.exec(value)[0].trim();\n\n\t\tconst source = this._findSource(linkPart) || null;\n\n\t\treturn {\n\t\t\tid: undefined,\n\t\t\tsource,\n\t\t\ttarget: null,\n\t\t\ttype: this._gantt.config.links.finish_to_start,\n\t\t\tlag: 0\n\t\t};\n\t};\n\n\tprotected _getWBSCode = (source: number | string) => {\n\t\tconst pred = this._gantt.getTask(source);\n\t\treturn this._gantt.getWBSCode(pred);\n\t};\n\n\tprotected _findSource = (value: string) => {\n\t\tconst reqTemplate = new RegExp(\"^[0-9\\.]+\", \"i\");\n\t\tif(reqTemplate.exec(value)){\n\t\t\tconst wbs = reqTemplate.exec(value)[0];\n\t\t\tconst task = this._gantt.getTaskByWBSCode(wbs);\n\t\t\tif(task){\n\t\t\t\treturn task.id;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t};\n}","import LinkFormatterSimple from \"./link_formatter_simple\";\n\nexport default class LinkFormatter extends LinkFormatterSimple implements ILinkFormatter {\n\tstatic create = (settings: ILinkFormatterConfig = null, gantt: any): LinkFormatter => {\n\t\treturn new LinkFormatter(settings, gantt);\n\t};\n\tprotected _config: ILinkFormatterConfig;\n\n\tconstructor(settings: ILinkFormatterConfig, gantt: any) {\n\t\tsuper(gantt);\n\t\tthis._config = this._defaultSettings(settings);\n\t\tthis._linkReg = /^[0-9\\.]+[a-zA-Z]*/;\n\t}\n\n\tformat = (link: ILink) : string => {\n\t\tconst formattedType = this._getFormattedLinkType(this._getLinkTypeName(link.type));\n\t\tconst wbs = this._getWBSCode(link.source);\n\t\tconst lag = this._getLagString(link.lag);\n\n\t\tif(link.type === this._gantt.config.links.finish_to_start && !link.lag){\n\t\t\treturn wbs;\n\t\t}else{\n\t\t\treturn `${wbs}${formattedType}${lag}`;\n\t\t}\n\t};\n\n\tparse = (value: string) : ILink => {\n\t\tif(!this.canParse(value)){\n\t\t\treturn null;\n\t\t}\n\n\t\tconst linkPart = this._linkReg.exec(value)[0].trim();\n\t\tconst lagPart = value.replace(linkPart, \"\").trim();\n\n\t\tconst typeFormat = this._findTypeFormat(linkPart);\n\t\tconst typeNumber = this._getLinkTypeNumber(typeFormat);\n\t\tconst source = this._findSource(linkPart) || null;\n\t\tconst lag = this._parseLag(lagPart);\n\n\t\treturn {\n\t\t\tid: undefined,\n\t\t\tsource,\n\t\t\ttarget: null,\n\t\t\ttype: typeNumber,\n\t\t\tlag\n\t\t};\n\t};\n\n\tprotected _defaultSettings(settings: ILinkFormatterConfig = null) : ILinkFormatterConfig{\n\t\tconst preparedSettings: ILinkFormatterConfig = {\n\t\t\tdurationFormatter: this._gantt.ext.formatters.durationFormatter(),\n\t\t\tlabels: {\n\t\t\t\tfinish_to_finish: \"FF\",\n\t\t\t\tfinish_to_start: \"FS\",\n\t\t\t\tstart_to_start: \"SS\",\n\t\t\t\tstart_to_finish: \"SF\"\n\t\t\t}\n\t\t};\n\n\t\tif(settings && settings.durationFormatter){\n\t\t\tpreparedSettings.durationFormatter = settings.durationFormatter;\n\t\t}\n\n\t\tif(settings && settings.labels){\n\t\t\tfor(const i in settings.labels){\n\t\t\t\tpreparedSettings.labels[i] = settings.labels[i];\n\t\t\t}\n\t\t}\n\t\treturn preparedSettings;\n\t}\n\n\tprotected _getLinkTypeName = (value: string) => {\n\t\tlet linkName = \"\";\n\t\tfor(linkName in this._config.labels){\n\t\t\tif(this._gantt.config.links[linkName].toLowerCase() === value.toLowerCase()){\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn linkName;\n\t};\n\n\tprotected _getLinkTypeNumber = (value: string) => {\n\t\tlet linkName = \"\";\n\t\tfor(linkName in this._gantt.config.links){\n\t\t\tif(linkName.toLowerCase() === value.toLowerCase()){\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn this._gantt.config.links[linkName];\n\t};\n\n\tprotected _getFormattedLinkType = (name: string) => {\n\t\treturn this._config.labels[name] || \"\";\n\t};\n\n\tprotected _getLagString = (lag: number) => {\n\t\tif(!lag){\n\t\t\treturn \"\";\n\t\t}\n\n\t\tconst formatted = this._config.durationFormatter.format(lag);\n\t\tif(lag < 0) {\n\t\t\treturn formatted;// -3 days\n\t\t}else{\n\t\t\treturn `+${formatted}`;// + 3 days\n\t\t}\n\t};\n\n\tprotected _findTypeFormat = (value: string) => {\n\t\tconst format = value.replace(/[^a-zA-Z]/gi, \"\"); // leave only letters\n\t\tlet name = \"finish_to_start\";\n\t\tfor(const i in this._config.labels){\n\t\t\tif(this._config.labels[i].toLowerCase() === format.toLowerCase()){\n\t\t\t\tname = i;\n\t\t\t}\n\t\t}\n\t\treturn name;\n\t};\n\n\tprotected _parseLag = (value: string) => {\n\t\tif(!value){\n\t\t\treturn 0;\n\t\t}\n\t\treturn this._config.durationFormatter.parse(value);\n\t};\n}","\nimport DurationFormatter from \"../common/duration_formatter\";\nimport LinkFormatter from \"../common/link_formatter\";\n\nexport default function(gantt){\n\tgantt.ext.formatters = {\n\t\tdurationFormatter: function(settings){\n\t\t\tif(!settings){\n\t\t\t\tsettings = {};\n\t\t\t}\n\t\t\tif(!settings.store){\n\t\t\t\tsettings.store = gantt.config.duration_unit;\n\t\t\t}\n\t\t\tif(!settings.enter){\n\t\t\t\tsettings.enter = gantt.config.duration_unit;\n\t\t\t}\n\t\t\treturn DurationFormatter.create(settings, gantt);\n\t\t},\n\t\tlinkFormatter: function(settings){\n\t\t\treturn LinkFormatter.create(settings, gantt);\n\t\t}\n\t};\n};","export default function(gantt: any){\n\n\tgantt.ext = gantt.ext || {};\n\tgantt.config.show_empty_state = false;\n\n\tgantt.ext.emptyStateElement = gantt.ext.emptyStateElement || {\n\t\tisEnabled() {\n\t\t\treturn gantt.config.show_empty_state === true;\n\t\t},\n\t\tisGanttEmpty(){\n\t\t\treturn !gantt.getTaskByTime().length;\n\t\t},\n\t\trenderContent(container){\n\t\t\tconst placeholderTextElement = `
\n \n
${gantt.locale.labels.empty_state_text_description}
\n
`;\n\t\t\tconst placeholderImageElement = \"
\";\n\n\t\t\tconst placeholderContainer = `
${placeholderImageElement}${placeholderTextElement}
`;\n\t\t\tcontainer.innerHTML = placeholderContainer;\n\t\t},\n\n\t\tclickEvents: [],\n\t\tattachAddTaskEvent(){\n\t\t\tconst id = gantt.attachEvent(\"onEmptyClick\", function(e){\n\t\t\t\tconst domHelpers = gantt.utils.dom;\n\t\t\t\tconst gridPlaceholder = domHelpers.closest(e.target, \"[data-empty-state-create-task]\");\n\t\t\t\tif (gridPlaceholder){\n\t\t\t\t\tgantt.createTask({\n\t\t\t\t\t\tid: gantt.uid(),\n\t\t\t\t\t\ttext: \"New Task\"\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.clickEvents.push(id);\n\t\t},\n\t\tdetachAddTaskEvents(){\n\t\t\tthis.clickEvents.forEach(function(event){\n\t\t\t\tgantt.detachEvent(event);\n\t\t\t});\n\t\t\tthis.clickEvents = [];\n\t\t},\n\n\t\tgetContainer(){\n\t\t\tif (gantt.$container) {\n\t\t\t\tconst domHelpers = gantt.utils.dom;\n\t\t\t\tif (gantt.$container.contains(gantt.$grid_data)) {\n\t\t\t\t\treturn domHelpers.closest(gantt.$grid_data, \".gantt_layout_content\");\n\t\t\t\t}\n\t\t\t\tif (gantt.$container.contains(gantt.$task_data)){\n\t\t\t\t\treturn domHelpers.closest(gantt.$task_data, \".gantt_layout_content\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\tgetNode(){\n\t\t\tconst container = this.getContainer();\n\t\t\tif (!container){\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst emptyStateElementNode = container.querySelector(\".gantt_empty_state_wrapper\");\n\t\t\treturn emptyStateElementNode;\n\t\t},\n\n\t\tshow(){\n\t\t\tconst container = this.getContainer();\n\t\t\tif (!container && this.isGanttEmpty()){\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst wrapper = document.createElement(\"div\");\n\t\t\twrapper.className = \"gantt_empty_state_wrapper\";\n\t\t\twrapper.style.marginTop = (gantt.config.scale_height - container.offsetHeight) + \"px\";\n\t\t\tconst oldNodes = gantt.$container.querySelectorAll(\".gantt_empty_state_wrapper\");\n\t\t\t// for IE11\n\t\t\tArray.prototype.forEach.call(oldNodes, function(node){\n\t\t\t\tnode.parentNode.removeChild(node);\n\t\t\t});\n\n\t\t\tthis.detachAddTaskEvents();\n\t\t\tthis.attachAddTaskEvent();\n\n\t\t\tcontainer.appendChild(wrapper);\n\t\t\tthis.renderContent(wrapper);\n\t\t},\n\t\thide(){\n\t\t\tconst emptyStateElementNode = this.getNode();\n\t\t\tif (emptyStateElementNode){\n\t\t\t\temptyStateElementNode.parentNode.removeChild(emptyStateElementNode);\n\t\t\t} else{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t},\n\t\tinit(){ }\n\t};\n\n\tgantt.attachEvent(\"onDataRender\", function() {\n\t\tconst emptyStateElement = gantt.ext.emptyStateElement;\n\t\tif (emptyStateElement.isEnabled() && emptyStateElement.isGanttEmpty()) {\n\t\t\temptyStateElement.show();\n\t\t} else {\n\t\t\temptyStateElement.hide();\n\t\t}\n\t});\n\n\n\n\n}\n","export const hasBaselinesBelow = function (gantt, task) {\n const baselines = task.baselines && task.baselines.length;\n const baselinesOnDifferentRow = gantt.config.baselines.render_mode == \"separateRow\" || gantt.config.baselines.render_mode == \"individualRow\";\n if (baselines && baselinesOnDifferentRow) {\n return true;\n }\n};\n\nexport const childrenHaveBaselines = function (gantt, taskId) {\n let hasBaselines = false;\n gantt.eachTask(function (child) {\n if (hasBaselines) {\n return;\n }\n hasBaselines = hasBaselinesBelow(gantt, child);\n }, taskId);\n return hasBaselines;\n};\n\nexport const isSplitChild = function (gantt, id) {\n let splitChild = false;\n gantt.eachParent(function (parent) {\n if (isSplitParent(parent)) {\n splitChild = true;\n }\n }, id);\n return splitChild;\n};\n\nexport const isSplitParent = function (task) {\n return task.render && task.render == \"split\" && !task.$open;\n};\n\nexport const getMaxParentHeight = function (gantt, view, task, heightLimit) {\n let maxHeight = heightLimit || view.$task_data.scrollHeight;\n let shrinkHeight = false;\n let splitChild = false;\n\n gantt.eachParent(function (parent) {\n if (isSplitParent(parent)) {\n splitChild = true;\n const parentSizes = view.getItemPosition(parent);\n const parentHeight = parentSizes.rowHeight;\n if (parentHeight < maxHeight) {\n maxHeight = parentHeight;\n shrinkHeight = true;\n }\n }\n }, task.id);\n\n return { maxHeight, shrinkHeight, splitChild };\n};\n\nexport const getMilestoneHeight = function (height) {\n return Math.sqrt(2 * height * height);\n};\n\nexport const getInvertedMilestoneHeight = function (height) {\n return Math.round(height / Math.sqrt(2));\n};\n\nexport const getAdjustedPosition = function (gantt, timeline, sizes, heightLimit, task, childBaselines) {\n const baselines = hasBaselinesBelow(gantt, task);\n\n const splitParams = getMaxParentHeight(gantt, timeline, task);\n let maxHeight = splitParams.maxHeight;\n\n let height = sizes.height;\n let largerHeight = height > heightLimit;\n let noNeedToShrink = sizes.rowHeight >= heightLimit && !splitParams.splitChild && !baselines;\n if (largerHeight || noNeedToShrink) {\n height = heightLimit;\n }\n\n if (maxHeight < height) {\n height = maxHeight;\n }\n\n let marginTop = Math.floor((sizes.rowHeight - height) / 2);\n\n if (splitParams.splitChild) {\n marginTop = Math.floor((maxHeight - height) / 2);\n }\n if (childBaselines || baselines) {\n let heightDiff = Math.min(sizes.height, maxHeight) - height;\n\n let additionalMargin = 2;\n let exceedBarHeight = baselines && task.bar_height >= task.row_height;\n let exceedParentHeight = splitParams.splitChild && sizes.height >= maxHeight;\n if (exceedBarHeight || exceedParentHeight){\n additionalMargin = 0;\n }\n\n marginTop = Math.floor(heightDiff / 2) + additionalMargin;\n const bottom = height + marginTop;\n if (bottom > sizes.rowHeight || bottom > maxHeight) {\n // marginTop = 0;\n }\n }\n\n return { height, marginTop };\n};\n\nexport default {\n hasBaselinesBelow,\n childrenHaveBaselines,\n isSplitChild,\n isSplitParent,\n getMaxParentHeight,\n getMilestoneHeight,\n getInvertedMilestoneHeight,\n getAdjustedPosition\n};\n","import { hasBaselinesBelow, isSplitParent } from \"../ui/render/baseline_helper\";\n\nexport default function (gantt) {\n gantt.config.baselines = {\n datastore: \"baselines\",\n render_mode: false,\n dataprocessor_baselines: false,\n row_height: 16,\n bar_height: 8\n };\n\n function initBaselineFields(item, task) {\n // don't add baseline if it doesn't belong to any task\n // or if doesn't have the dates\n if (!item.task_id || (!item.start_date && !item.end_date)) {\n return false;\n }\n\n if (item.start_date) {\n item.start_date = gantt.date.parseDate(item.start_date, \"parse_date\");\n } else {\n item.start_date = null;\n }\n\n if (item.end_date) {\n item.end_date = gantt.date.parseDate(item.end_date, \"parse_date\");\n } else {\n item.end_date = null;\n }\n\n // set min baseline duration\n item.duration = item.duration || 1;\n\n // GS-2636. Calculate the 3rd date parameter basing on existing date parameters\n if (item.start_date && !item.end_date){\n item.end_date = gantt.calculateEndDate(item.start_date, item.duration);\n } else if (item.end_date && !item.start_date){\n item.start_date = gantt.calculateEndDate(item.end_date, -item.duration);\n } \n }\n // gantt init\n const baselineStore = gantt.createDatastore({\n name: gantt.config.baselines.datastore,\n initItem: function (item) {\n if (!item.id) {\n item.id = gantt.uid();\n }\n\n initBaselineFields(item);\n\n return item;\n }\n });\n\n gantt.$data.baselineStore = baselineStore;\n\n function _syncBaselines(task) {\n let shouldRepaint = false;\n const iteratedBaselines = {};\n\n const taskBaselines = task.baselines || [];\n const exisingBaselines = gantt.getTaskBaselines(task.id);\n\n if (taskBaselines.length != exisingBaselines.length) {\n shouldRepaint = true;\n }\n\n taskBaselines.forEach(function (baseline) {\n iteratedBaselines[baseline.id] = true;\n const exisingBaseline = baselineStore.getItem(baseline.id);\n if (exisingBaseline) {\n const start = +exisingBaseline.start_date !== +baseline.start_date;\n const end = +exisingBaseline.end_date !== +baseline.end_date;\n if (start || end) {\n baselineStore.updateItem(baseline.id, baseline);\n }\n } else {\n baselineStore.addItem(baseline);\n }\n });\n\n exisingBaselines.forEach(function (baseline) {\n if (!iteratedBaselines[baseline.id]) {\n baselineStore.removeItem(baseline.id);\n }\n });\n\n if (shouldRepaint) {\n if (isSplitParent(task)){\n // here we adjust the parent height, then adjust it with the total child height\n _adjustSplitParentHeight (task);\n } else {\n gantt.adjustTaskHeightForBaselines(task);\n }\n gantt.render();\n }\n }\n\n function _deleteOrphanBaselines() {\n baselineStore.eachItem(function (baseline) {\n if (!gantt.isTaskExists(baseline.task_id)) {\n baselineStore.removeItem(baseline.id);\n }\n });\n }\n\n function _adjustSplitParentHeight (task){\n let maxParentHeight = 0;\n\n gantt.adjustTaskHeightForBaselines(task);\n\n gantt.eachTask(function(child){\n let childHeight = child.row_height || gantt.config.row_height;\n\n maxParentHeight = maxParentHeight || childHeight;\n if (childHeight > maxParentHeight){\n maxParentHeight = childHeight;\n }\n }, task.id);\n\n if (task.row_height < maxParentHeight){\n task.row_height = maxParentHeight;\n }\n }\n\n gantt.adjustTaskHeightForBaselines = function (task) {\n let height, baselineSize, betweenBaselines;\n let margins = 2;\n let baselineAmount = task.baselines && task.baselines.length || 0;\n const subrowHeight = gantt.config.baselines.row_height;\n //const baselineBarHeight = task?.baselines.bar_height\n\n switch (gantt.config.baselines.render_mode) {\n case \"taskRow\":\n task.row_height = task.bar_height + 4;\n break;\n\n case \"separateRow\":\n height = gantt.getLayoutView(\"timeline\").getBarHeight(task.id);\n if (baselineAmount) {\n task.bar_height = task.bar_height || height;\n\n if (task.bar_height > height){\n height = task.bar_height;\n }\n\n task.row_height = height + subrowHeight;\n } else if (task.bar_height) {\n task.row_height = task.bar_height + 4;\n }\n\n _increaseSplitParentHeight(task);\n break;\n\n case \"individualRow\":\n height = gantt.getLayoutView(\"timeline\").getBarHeight(task.id);\n\n if (baselineAmount) {\n task.bar_height = task.bar_height || height;\n\n if (task.bar_height > height){\n height = task.bar_height;\n }\n\n baselineSize = subrowHeight * baselineAmount;\n // betweenBaselines = 3 * (baselineAmount + 1);\n\n task.row_height = height + baselineSize + margins;\n } else if (task.bar_height){\n task.row_height = task.bar_height + 4;\n }\n\n _increaseSplitParentHeight(task);\n }\n };\n\n function _increaseSplitParentHeight(task) {\n gantt.eachParent(function (parent) {\n if (isSplitParent(parent)) {\n const parentHeight = parent.row_height || gantt.getLayoutView(\"timeline\").getBarHeight(parent.id);\n let maxHeight = task.row_height;\n\n // iterate only direct children\n const subtasks = gantt.getChildren(parent.id);\n subtasks.forEach(function (subtaskId) {\n const subtask = gantt.getTask(subtaskId);\n if (subtask.id == task.id) {\n return;\n }\n const subtaskHeight = subtask.row_height || gantt.getLayoutView(\"timeline\").getBarHeight(subtask.id);\n maxHeight = maxHeight || subtaskHeight;\n if (subtaskHeight > maxHeight) {\n maxHeight = subtaskHeight;\n }\n });\n\n parent.row_height = maxHeight;\n parent.bar_height = parent.bar_height || parentHeight;\n }\n }, task.id);\n }\n\n gantt.attachEvent(\n \"onGanttReady\",\n function () {\n\n if(gantt.config.baselines === false){\n return;\n }\n\n gantt.attachEvent(\"onParse\", function () {\n baselineStore.eachItem(function (baseline) {\n const taskId = baseline.task_id;\n if (gantt.isTaskExists(taskId)) {\n const task = gantt.getTask(taskId);\n\n task.baselines = task.baselines || [];\n\n let newBaseline = true;\n for (let i = 0; i < task.baselines.length; i++) {\n let existingBaseline = task.baselines[i];\n if (existingBaseline.id == baseline.id){\n newBaseline = false;\n gantt.mixin(existingBaseline, baseline, true);\n break;\n }\n }\n if (newBaseline){\n task.baselines.push(baseline);\n }\n\n if (isSplitParent(task)){\n _adjustSplitParentHeight (task);\n } else {\n gantt.adjustTaskHeightForBaselines(task);\n }\n }\n });\n });\n\n gantt.attachEvent(\"onBeforeTaskUpdate\", function (id, task) {\n _syncBaselines(task);\n return true;\n });\n\n gantt.attachEvent(\"onAfterUndo\", function(action){\n const baselinesRenderedBelow = gantt.config.baselines.render_mode == \"separateRow\" || gantt.config.baselines.render_mode == \"individualRow\";\n if (baselinesRenderedBelow && action){\n let repaint = false;\n action.commands.forEach(function(command){\n if (command.entity == \"task\"){\n const taskId = command.value.id;\n if (gantt.isTaskExists(taskId)){\n const task = gantt.getTask(taskId);\n if (task.parent && gantt.isTaskExists(task.parent)){\n const parent = gantt.getTask(task.parent);\n if (isSplitParent(parent)){\n _adjustSplitParentHeight (parent);\n repaint = true;\n }\n }\n } \n }\n });\n if (repaint){\n gantt.render();\n }\n }\n });\n\n gantt.attachEvent(\"onAfterTaskDelete\", function (id, task) {\n if (hasBaselinesBelow){\n if (task.parent && gantt.isTaskExists(task.parent)){\n const parent = gantt.getTask(task.parent);\n if (isSplitParent(parent)){\n _adjustSplitParentHeight (parent);\n }\n }\n }\n _deleteOrphanBaselines();\n });\n\n gantt.getTaskBaselines = function (taskId) {\n const baselines = [];\n baselineStore.eachItem(function (baseline) {\n if (baseline.task_id == taskId) {\n baselines.push(baseline);\n }\n });\n return baselines;\n };\n gantt.$data.baselineStore.attachEvent(\"onClearAll\", function () {\n gantt.eachTask(function(task){\n if (task.baselines){\n delete task.baselines;\n }\n });\n // The data should not be repainted as otherwise it causes issues when we have resource \n // assignments and group tasks. It should be fixed when we add a repaint stack\n // gantt.refreshData();\n return true;\n });\n\n gantt.$data.tasksStore.attachEvent(\"onClearAll\", function () {\n baselineStore.clearAll();\n return true;\n });\n gantt.attachEvent(\"onTaskIdChange\", function (id, new_id) {\n const baselines = baselineStore.find(function (a) {\n return a.task_id == id;\n });\n baselines.forEach(function (a) {\n a.task_id = new_id;\n baselineStore.updateItem(a.id);\n });\n });\n },\n { once: true }\n );\n};\n","import quickPositionHelperFactory from \"./row_position_fixed_height\";\n\nfunction createMixin(view){\n\tvar getItemTopCache = {};\n\tvar getRowTopCache = {};\n\tvar getItemHeightCache = null;\n\tvar totalHeightCache = -1;\n\tvar getItemHeightCacheState = null;\n\n\tvar quickPosition = quickPositionHelperFactory(view);\n\n\treturn {\n\t\t_resetTopPositionHeight: function(){\n\t\t\tgetItemTopCache = {};\n\t\t\tgetRowTopCache = {};\n\t\t\tquickPosition.resetCache();\n\t\t},\n\t\t_resetHeight: function(){\n\t\t\tvar store = this.$config.rowStore;\n\t\t\tvar newState = this.getCacheStateTotalHeight(store);\n\t\t\tif(!getItemHeightCacheState){\n\t\t\t\tgetItemHeightCacheState = newState;\n\t\t\t}else if(this.shouldClearHeightCache(getItemHeightCacheState, newState)){\n\t\t\t\tgetItemHeightCacheState = newState;\n\t\t\t\tgetItemHeightCache = null;\n\t\t\t}\n\n\t\t\ttotalHeightCache = -1;\n\t\t\tquickPosition.resetCache();\n\t\t},\n\n\t\t/**\n\t\t * Get top coordinate by row index (order)\n\t\t * @param {number} index\n\t\t */\n\t\tgetRowTop: function(index){\n\t\t\tif(quickPosition.canUseSimpleCalculation()){\n\t\t\t\treturn quickPosition.getRowTop(index);\n\t\t\t}\n\n\t\t\tvar store = this.$config.rowStore;\n\t\t\tif(!store){\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif(getRowTopCache[index] !== undefined){\n\t\t\t\treturn getRowTopCache[index];\n\t\t\t}else {\n\t\t\t\tvar all = store.getIndexRange();\n\t\t\t\tvar top = 0;\n\t\t\t\tvar result = 0;\n\t\t\t\tfor(var i = 0; i < all.length; i++){\n\t\t\t\t\tgetRowTopCache[i] = top;\n\t\t\t\t\ttop += this.getItemHeight(all[i].id);\n\t\t\t\t\tif(i < index){\n\t\t\t\t\t\tresult = top;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Get top coordinate by item id\n\t\t * @param {*} task_id\n\t\t */\n\t\tgetItemTop: function (taskId) {\n\t\t\tif(this.$config.rowStore){\n\t\t\t\tif(getItemTopCache[taskId] !== undefined){\n\t\t\t\t\treturn getItemTopCache[taskId];\n\t\t\t\t}\n\t\t\t\tvar store = this.$config.rowStore;\n\t\t\t\tif(!store) return 0;\n\n\t\t\t\tvar itemIndex = store.getIndexById(taskId);\n\n\t\t\t\tif (itemIndex === -1 && store.getParent && store.exists(taskId)) {\n\t\t\t\t\tvar parentId = store.getParent(taskId);\n\t\t\t\t\tif (store.exists(parentId)) {\n\t\t\t\t\t\t// if task is not found in list - maybe it's parent is a split task and we should use parents index instead\n\t\t\t\t\t\tvar parent = store.getItem(parentId);\n\t\t\t\t\t\tif (this.$gantt.isSplitTask(parent)) {\n\t\t\t\t\t\t\treturn this.getItemTop(parentId);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tgetItemTopCache[taskId] = this.getRowTop(itemIndex);\n\t\t\t\treturn getItemTopCache[taskId];\n\t\t\t}else{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Get height of the item by item id\n\t\t * @param {*} itemId\n\t\t */\n\t\tgetItemHeight: function (itemId) {\n\t\t\tif(quickPosition.canUseSimpleCalculation()){\n\t\t\t\treturn quickPosition.getItemHeight(itemId);\n\t\t\t}\n\n\t\t\tif(!getItemHeightCache && this.$config.rowStore){\n\t\t\t\tthis._fillHeightCache(this.$config.rowStore);\n\t\t\t}\n\n\t\t\tif(getItemHeightCache[itemId] !== undefined){\n\t\t\t\treturn getItemHeightCache[itemId];\n\t\t\t}\n\n\t\t\tvar defaultHeight = this.$getConfig().row_height;\n\n\t\t\tif(this.$config.rowStore){\n\t\t\t\tvar store = this.$config.rowStore;\n\t\t\t\tif(!store) return defaultHeight;\n\n\t\t\t\tvar item = store.getItem(itemId);\n\n\t\t\t\treturn getItemHeightCache[itemId] = item && item.row_height || defaultHeight;\n\t\t\t}else{\n\t\t\t\treturn defaultHeight;\n\t\t\t}\n\t\t},\n\n\t\t_fillHeightCache: function(store){\n\t\t\tif(!store){\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tgetItemHeightCache = {};\n\t\t\tvar defaultHeight = this.$getConfig().row_height;\n\t\t\tstore.eachItem(function(item){\n\t\t\t\treturn getItemHeightCache[item.id] = item && item.row_height || defaultHeight;\n\t\t\t});\n\t\t},\n\n\t\tgetCacheStateTotalHeight: function(store){\n\n\t\t\tvar globalHeight = this.$getConfig().row_height;\n\t\t\tvar itemHeightCache = {};\n\t\t\tvar items = [];\n\t\t\tvar sumHeight = 0;\n\t\t\tif(store){\n\t\t\t\tstore.eachItem(function(item){\n\t\t\t\t\titems.push(item);\n\t\t\t\t\titemHeightCache[item.id] = item.row_height;\n\t\t\t\t\tsumHeight += item.row_height || globalHeight;\n\t\t\t\t});\n\t\t\t}\n\n\n\t\t\treturn {\n\t\t\t\tglobalHeight: globalHeight,\n\t\t\t\titems: items,\n\t\t\t\tcount: items.length,\n\t\t\t\tsumHeight: sumHeight\n\t\t\t};\n\t\t},\n\t\tshouldClearHeightCache: function(oldState, newState){\n\n\t\t\tif(oldState.count != newState.count){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif(oldState.globalHeight != newState.globalHeight){\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif(oldState.sumHeight != newState.sumHeight){\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tfor(var i in oldState.items){\n\t\t\t\tvar newValue = newState.items[i];\n\t\t\t\tif(newValue !== undefined && newValue != oldState.items[i]){\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\t\t/**\n\t\t * Get total height of items\n\t\t */\n\t\tgetTotalHeight: function () {\n\t\t\tif(quickPosition.canUseSimpleCalculation()){\n\t\t\t\treturn quickPosition.getTotalHeight();\n\t\t\t}\n\n\t\t\tif(totalHeightCache != -1){\n\t\t\t\treturn totalHeightCache;\n\t\t\t}\n\n\t\t\tif(this.$config.rowStore){\n\t\t\t\tvar store = this.$config.rowStore;\n\t\t\t\tthis._fillHeightCache(store);\n\t\t\t\tvar getHeight = this.getItemHeight.bind(this);\n\t\t\t\tvar visibleItems = store.getVisibleItems();\n\t\t\t\tvar totalHeight = 0;\n\n\t\t\t\tvisibleItems.forEach(function(item){\n\t\t\t\t\ttotalHeight += getHeight(item.id);\n\t\t\t\t});\n\n\t\t\t\ttotalHeightCache = totalHeight;\n\t\t\t\treturn totalHeight;\n\t\t\t}else{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Get item by top position\n\t\t * @param {*} top\n\t\t */\n\t\tgetItemIndexByTopPosition: function (top) {\n\t\t\tif(this.$config.rowStore){\n\t\t\t\tif(quickPosition.canUseSimpleCalculation()){\n\t\t\t\t\treturn quickPosition.getItemIndexByTopPosition(top);\n\t\t\t\t}\n\n\t\t\t\tvar store = this.$config.rowStore;\n\t\t\t\tfor(var i = 0; i < store.countVisible(); i++){\n\t\t\t\t\tvar current = this.getRowTop(i);\n\t\t\t\t\tvar next = this.getRowTop(i+1);\n\t\t\t\t\tif(!next){\n\t\t\t\t\t\tvar taskId = store.getIdByIndex(i);\n\t\t\t\t\t\tnext = current + this.getItemHeight(taskId);\n\t\t\t\t\t}\n\t\t\t\t\tif(top >= current && top < next){\n\t\t\t\t\t\treturn i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// GS-1723: If we iterated all tasks and didn't find the position, the target is below all other tasks\n\t\t\t\treturn store.countVisible() + 2;\n\t\t\t}else{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport default createMixin;","function createHelper(view){\n\tvar cachedRowHeight = -1;\n\tvar canUseSimpleCalc = -1;\n\treturn {\n\t\tresetCache: function(){\n\t\t\tcachedRowHeight = -1;\n\t\t\tcanUseSimpleCalc = -1;\n\t\t},\n\t\t_getRowHeight: function(){\n\t\t\tif(cachedRowHeight === -1){\n\t\t\t\tcachedRowHeight = view.$getConfig().row_height;\n\t\t\t}\n\t\t\treturn cachedRowHeight;\n\t\t},\n\t\t_refreshState: function(){\n\t\t\tthis.resetCache();\n\t\t\tcanUseSimpleCalc = true;\n\t\t\tvar store = view.$config.rowStore;\n\t\t\tif(!store){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar globalRowHeight = this._getRowHeight();\n\t\t\tfor (var i=0; i {\n\t\t\t\tconst gridBoundingRect = this.$grid.$grid.getBoundingClientRect();\n\t\t\t\tconst maxLeft = gridBoundingRect.right;\n\t\t\t\tconst minLeft = gridBoundingRect.left;\n\t\t\t\tconst currentX = this.getCurrentX(e.clientX);\n\n\t\t\t\tif (currentX >= maxLeft - SENSITIVITY) {\n\t\t\t\t\tthis.autoscrollRight();\n\t\t\t\t\tthis.autoscrollStart();\n\t\t\t\t}\n\t\t\t\tif (currentX <= minLeft + SENSITIVITY) {\n\t\t\t\t\tthis.autoscrollLeft();\n\t\t\t\t\tthis.autoscrollStart();\n\t\t\t\t}\n\t\t\t\tif (currentX < maxLeft - SENSITIVITY && currentX > minLeft + SENSITIVITY) {\n\t\t\t\t\tthis.autoscrollStop();\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tthis._dnd.attachEvent(\"onDragEnd\", () => {\n\t\t\t\tthis.autoscrollStop();\n\t\t\t});\n\t\t}\n\t}\n\tautoscrollStart() {\n\t\tif (this._scrollOrder === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst scrollStep = SCROLLSTEP * this._scrollOrder;\n\t\tconst scrollState = this._scrollView.getScrollState();\n\t\tthis._scrollView.scrollTo(scrollState.position + scrollStep);\n\t\tsetTimeout(() => { this.autoscrollStart(); }, TIMEOUT);\n\t}\n\tautoscrollRight() {\n\t\tthis._scrollOrder = 1;\n\t}\n\tautoscrollLeft() {\n\t\tthis._scrollOrder = -1;\n\t}\n\tautoscrollStop() {\n\t\tthis._scrollOrder = 0;\n\t}\n\tgetCorrection() {\n\t\tif (!this.isScrollable()) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn this._scrollView.getScrollState().position;\n\t}\n\tisScrollable() {\n\t\treturn !!this.$grid.$config.scrollable;\n\t}\n}","import * as domHelpers from \"../../utils/dom_helpers\";\nimport ScrollableGrid from \"./scrollable_grid\";\n\nconst COLUMN_ID_ATTR_NAME = \"data-column-id\";\n\nexport class ColumnsGridDnd {\n\tprivate $gantt;\n\tprivate $grid;\n\tprivate _dragX;\n\tprivate _dnd;\n\tprivate _originAutoscroll;\n\tprivate _scrollableGrid: ScrollableGrid;\n\tprivate _draggedCell;\n\tprivate _targetMarker = null;\n\tprivate _gridConfig;\n\tconstructor(gantt, grid) {\n\t\tthis.$gantt = gantt;\n\t\tthis.$grid = grid;\n\t}\n\tinit() {\n\t\tconst DND = this.$gantt.$services.getService(\"dnd\");\n\t\tthis._dnd = new DND(this.$grid.$grid_scale, { updates_per_second: 60 });\n\t\tthis._scrollableGrid = new ScrollableGrid({\n\t\t\tgantt: this.$gantt,\n\t\t\tgrid: this.$grid,\n\t\t\tdnd: this._dnd,\n\t\t\tgetCurrentX: this.calculateCurrentPosition\n\t\t});\n\t\tthis.attachEvents();\n\t}\n\tattachEvents() {\n\t\tthis._dnd.attachEvent(\"onBeforeDragStart\", (obj, e) => {\n\t\t\tthis._draggedCell = this.$gantt.utils.dom.closest(e.target, \".gantt_grid_head_cell\");\n\t\t\tif(!this._draggedCell){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst columns = this.$grid.$getConfig().columns;\n\t\t\tconst columnName = this._draggedCell.getAttribute(COLUMN_ID_ATTR_NAME);\n\t\t\tlet draggedColumn;\n\t\t\tlet draggedIndex;\n\t\t\tcolumns.map(function(column, index){\n\t\t\t\tif(column.name === columnName){\n\t\t\t\t\tdraggedColumn = column;\n\t\t\t\t\tdraggedIndex = index;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (this.$grid.callEvent(\"onBeforeColumnDragStart\", [{ draggedColumn, draggedIndex}]) === false) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!this._draggedCell || !draggedColumn) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._gridConfig = this.$grid.$getConfig();\n\t\t\tthis._originAutoscroll = this.$gantt.config.autoscroll;\n\t\t\tthis.$gantt.config.autoscroll = false;\n\t\t\treturn true;\n\t\t});\n\n\t\tthis._dnd.attachEvent(\"onAfterDragStart\", (obj, e) => {\n\t\t\tif (!this._draggedCell) {\n\t\t\t\treturn; // GS-1333: don't try to reorder a column when we resize it\n\t\t\t}\n\t\t\tthis._dnd.config.column = this._draggedCell.getAttribute(COLUMN_ID_ATTR_NAME);\n\t\t\tthis._dnd.config.marker.innerHTML = this._draggedCell.outerHTML;\n\t\t\tthis._dnd.config.marker.classList.add(\"gantt_column_drag_marker\");\n\t\t\tthis._dnd.config.marker.style.height = this._gridConfig.scale_height + \"px\";\n\t\t\tthis._dnd.config.marker.style.lineHeight = this._gridConfig.scale_height + \"px\";\n\t\t\tthis._draggedCell.classList.add(\"gantt_grid_head_cell_dragged\");\n\t\t});\n\n\t\tthis._dnd.attachEvent(\"onDragMove\", (obj, e) => {\n\t\t\tif(!this._draggedCell){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._dragX = e.clientX;\n\t\t\tconst x = this.calculateCurrentPosition(e.clientX);\n\t\t\tconst columnIndexes = this.findColumnsIndexes();\n\t\t\tconst targetIndex = columnIndexes.targetIndex;\n\t\t\tconst draggedIndex = columnIndexes.draggedIndex;\n\t\t\tconst columns = this.$grid.$getConfig().columns;\n\n\t\t\tconst draggedColumn = columns[draggedIndex];\n\t\t\tconst targetColumn = columns[targetIndex];\n\t\t\tif (this.$grid.callEvent(\"onColumnDragMove\", [{ draggedColumn, targetColumn, draggedIndex, targetIndex }]) === false) {\n\t\t\t\tthis.cleanTargetMarker();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis.setMarkerPosition(x);\n\t\t\tthis.drawTargetMarker(columnIndexes);\n\t\t\treturn true;\n\t\t});\n\n\t\tthis._dnd.attachEvent(\"onDragEnd\", () => {\n\t\t\tif (!this._draggedCell) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.$gantt.config.autoscroll = this._originAutoscroll;\n\t\t\tthis._draggedCell.classList.remove(\"gantt_grid_head_cell_dragged\");\n\t\t\tthis.cleanTargetMarker();\n\t\t\tthis.reorderColumns();\n\t\t});\n\n\t}\n\treorderColumns() {\n\t\tconst { targetIndex, draggedIndex } = this.findColumnsIndexes();\n\n\t\tconst columns = this.$grid.$getConfig().columns;\n\t\tconst draggedColumn = columns[draggedIndex];\n\t\tconst targetColumn = columns[targetIndex];\n\n\t\tif (this.$grid.callEvent(\"onBeforeColumnReorder\", [{ draggedColumn, targetColumn, draggedIndex, targetIndex }]) === false) {\n\t\t\treturn;\n\t\t}\n\t\tif (targetIndex === draggedIndex) {\n\t\t\treturn;\n\t\t}\n\t\tcolumns.splice(draggedIndex, 1);\n\t\tcolumns.splice(targetIndex, 0, draggedColumn);\n\t\tthis.$gantt.render();\n\t\tthis.$grid.callEvent(\"onAfterColumnReorder\", [{ draggedColumn, targetColumn, draggedIndex, targetIndex }]);\n\t}\n\tfindColumnsIndexes() {\n\t\tconst draggedId = this._dnd.config.column;\n\t\tconst columns = this.$grid.$getConfig().columns;\n\t\tlet targetIndex: number;\n\t\tlet draggedIndex: number;\n\t\tlet xBefore: number;\n\t\tlet xAfter: number;\n\t\tconst currentColumn = { startX: 0, endX: 0 };\n\n\t\tlet start = 0;\n\t\tlet end = columns.length - 1;\n\t\tlet compare = (a, b) => a <= b;\n\t\tlet next = (index) => ++index;\n\t\tif (this.$gantt.config.rtl) {\n\t\t\tstart = columns.length - 1;\n\t\t\tend = 0;\n\t\t\tcompare = (a, b) => a >= b;\n\t\t\tnext = (index) => --index;\n\t\t}\n\n\t\tlet columnRelativePos: number;\n\n\t\tconst relativeX = this._dragX - this.$grid.$grid.getBoundingClientRect().left + this._scrollableGrid.getCorrection();\n\t\tfor (let i = start; compare(i, end); i = next(i)) {\n\t\t\tif (targetIndex !== undefined && draggedIndex !== undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(!columns[i].hide) {\n\t\t\t\tcurrentColumn.startX = currentColumn.endX;\n\t\t\t\tcurrentColumn.endX += columns[i].width;\n\n\t\t\t\t// if drop on a column or drop after the last column\n\t\t\t\tif (relativeX >= currentColumn.startX && (relativeX <= currentColumn.endX || !compare(next(i), end))) {\n\t\t\t\t\ttargetIndex = i;\n\t\t\t\t\txBefore = currentColumn.startX;\n\t\t\t\t\txAfter = currentColumn.endX;\n\t\t\t\t\tcolumnRelativePos = (relativeX - currentColumn.startX) / (currentColumn.endX - currentColumn.startX);\n\t\t\t\t}\n\t\t\t\tif (draggedId === columns[i].name) {\n\t\t\t\t\tdraggedIndex = i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\ttargetIndex,\n\t\t\tdraggedIndex,\n\t\t\txBefore,\n\t\t\txAfter,\n\t\t\tcolumnRelativePos\n\t\t};\n\t}\n\tsetMarkerPosition(x: number, y: number = 10) {\n\t\tconst { marker } = this._dnd.config;\n\t\tconst gridOffset = this._dnd._obj.getBoundingClientRect();\n\t\tmarker.style.top = `${gridOffset.y + y}px`;\n\t\tmarker.style.left = `${x}px`;\n\t}\n\tcalculateCurrentPosition = (eventX: number) => {\n\t\tconst gridBoundingRect = this.$grid.$grid.getBoundingClientRect();\n\t\tconst maxLeft = gridBoundingRect.right;\n\t\tconst minLeft = gridBoundingRect.left;\n\t\tlet x = eventX;\n\t\tif (x > maxLeft) {\n\t\t\tx = maxLeft;\n\t\t}\n\t\tif (x < minLeft) {\n\t\t\tx = minLeft;\n\t\t}\n\t\treturn x;\n\t};\n\tdrawTargetMarker({ targetIndex, draggedIndex, xBefore, xAfter, columnRelativePos }) {\n\t\tif (!this._targetMarker) {\n\t\t\tthis._targetMarker = document.createElement(\"div\");\n\t\t\tdomHelpers.addClassName(this._targetMarker, \"gantt_grid_target_marker\");\n\t\t\tthis._targetMarker.style.display = \"none\";\n\t\t\tthis._targetMarker.style.height = `${this._gridConfig.scale_height}px`;\n\t\t}\n\n\t\t// marker can be detached after gantt.render\n\t\tif(!this._targetMarker.parentNode){\n\t\t\tthis.$grid.$grid_scale.appendChild(this._targetMarker);\n\t\t}\n\n\t\tlet nextPosition: number;\n\t\tif (targetIndex > draggedIndex) {\n\t\t\tnextPosition = xAfter;\n\t\t} else if (targetIndex < draggedIndex) {\n\t\t\tnextPosition = xBefore;\n\t\t} else {\n\t\t\tif(columnRelativePos > 0.5){\n\t\t\t\tnextPosition = xAfter;\n\t\t\t}else{\n\t\t\t\tnextPosition = xBefore;\n\t\t\t}\n\t\t}\n\n\t\tthis._targetMarker.style.left = `${nextPosition}px`;\n\t\tthis._targetMarker.style.display = \"block\";\n\t}\n\tcleanTargetMarker() {\n\t\tif (this._targetMarker && this._targetMarker.parentNode) {\n\t\t\tthis.$grid.$grid_scale.removeChild(this._targetMarker);\n\t\t}\n\t\tthis._targetMarker = null;\n\t}\n}","function create(gantt){\n\tvar events = [];\n\n\treturn {\n\t\tdelegate:function(event, className, handler, root) {\n\t\t\tevents.push([event, className, handler, root]);\n\n\t\t\tvar helper = gantt.$services.getService(\"mouseEvents\");\n\t\t\thelper.delegate(event, className, handler, root);\n\t\t},\n\t\tdestructor: function(){\n\t\t\tvar mouseEvents = gantt.$services.getService(\"mouseEvents\");\n\t\t\tfor(var i = 0; i < events.length; i++){\n\t\t\t\tvar h = events[i];\n\t\t\t\tmouseEvents.detach(h[0], h[1], h[2], h[3]);\n\t\t\t}\n\t\t\tevents = [];\n\t\t}\n\t};\n}\n\nexport default create;","import * as domHelpers from \"../utils/dom_helpers\";\nimport * as utils from \"../../../utils/utils\";\nimport eventable from \"../../../utils/eventable\";\nimport gridResize from \"./grid_resize\";\nimport topPositionMixin from \"../row_position_mixin\";\nimport rowResize from \"./task_grid_row_resize\";\n\nimport ColumnDnd from \"../plugins/column_grid_dnd\";\n\nimport mouseEventContainer from \"../mouse_event_container\";\n\nvar Grid = function (parent, config, factory, gantt) {\n\tthis.$config = utils.mixin({}, config || {});\n\tthis.$gantt = gantt;\n\tthis.$parent = parent;\n\teventable(this);\n\tthis.$state = {};\n\tutils.mixin(this, topPositionMixin(this));\n};\n\n\nGrid.prototype = {\n\tinit: function(container) {\n\t\tvar gantt = this.$gantt;\n\t\tvar gridAriaAttr = gantt._waiAria.gridAttrString();\n\t\tvar gridDataAriaAttr = gantt._waiAria.gridDataAttrString();\n\t\tvar _ganttConfig = this.$getConfig();\n\t\tvar reorderColumns = _ganttConfig.reorder_grid_columns || false;\n\t\tif (this.$config.reorder_grid_columns !== undefined) {\n\t\t\treorderColumns = this.$config.reorder_grid_columns;\n\t\t}\n\n\n\t\tcontainer.innerHTML = \"
\";\n\t\tthis.$grid = container.childNodes[0];\n\n\t\tthis.$grid.innerHTML = \"
\";\n\n\t\tthis.$grid_scale = this.$grid.childNodes[0];\n\t\tthis.$grid_data = this.$grid.childNodes[1];\n\n\t\tvar attr = _ganttConfig[this.$config.bind + \"_attribute\"];\n\t\tif (!attr && this.$config.bind) {\n\t\t\tattr = \"data-\" + this.$config.bind + \"-id\";\n\t\t}\n\t\tthis.$config.item_attribute = attr || null;\n\n\t\tif (!this.$config.layers) {\n\t\t\tvar layers = this._createLayerConfig();\n\t\t\tthis.$config.layers = layers;\n\t\t}\n\n\t\tvar resizer = gridResize(gantt, this);\n\t\tresizer.init();\n\t\tthis._renderHeaderResizers = resizer.doOnRender;\n\t\tthis._mouseDelegates = mouseEventContainer(gantt);\n\n\t\tvar resizerrow = rowResize(gantt, this);\n\t\tresizerrow.init();\n\n\t\tthis._addLayers(this.$gantt);\n\t\tthis._initEvents();\n\n\t\tif (reorderColumns) {\n\t\t\tthis._columnDND = new ColumnDnd(gantt, this);\n\t\t\tthis._columnDND.init();\n\t\t}\n\n\t\tthis.callEvent(\"onReady\", []);\n\t\t//this.refresh();\n\t},\n\n\t_validateColumnWidth: function (column, property) {\n\t\t// user can set {name:\"text\", width:\"200\",...} for some reason,\n\t\t// check and convert it to number when possible\n\t\tvar value = column[property];\n\t\tif (value && value != \"*\") {\n\t\t\tvar gantt = this.$gantt;\n\t\t\tvar numericWidth = value * 1;\n\t\t\tif (isNaN(numericWidth)) {\n\t\t\t\tgantt.assert(false, \"Wrong \" + property + \" value of column \" + column.name);\n\t\t\t} else {\n\t\t\t\tcolumn[property] = numericWidth;\n\t\t\t}\n\t\t}\n\t},\n\n\tsetSize: function (width, height) {\n\t\tthis.$config.width = this.$state.width = width;\n\t\tthis.$config.height = this.$state.height = height;\n\n\t\t// TODO: maybe inherit and override in a subclass instead of extending here\n\n\t\tvar columns = this.getGridColumns(),\n\t\t\tinnerWidth = 0;\n\n\t\tvar config = this.$getConfig();\n\t\tvar elasticColumns = config.grid_elastic_columns;\n\n\t\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\t\tthis._validateColumnWidth(columns[i], \"min_width\");\n\t\t\tthis._validateColumnWidth(columns[i], \"max_width\");\n\t\t\tthis._validateColumnWidth(columns[i], \"width\");\n\n\t\t\tinnerWidth += columns[i].width * 1;\n\t\t}\n\n\t\tvar outerWidth;\n\t\tif (isNaN(innerWidth) || !this.$config.scrollable) {\n\t\t\touterWidth = this._setColumnsWidth(width + 1);\n\t\t\tinnerWidth = outerWidth;\n\t\t}\n\n\t\tif(this.$config.scrollable && elasticColumns && !isNaN(innerWidth)){\n\t\t\t// GS-1352: Allow resizing the grid columns, then the grid width is increased\n\t\t\t// or keep the grid width, but don't allow column resize to affect the grid width\n\t\t\tlet columnProperty = \"width\";\n\t\t\tif (elasticColumns == \"min_width\"){\n\t\t\t\tcolumnProperty = \"min_width\";\n\t\t\t}\n\t\t\tlet newColumnWidth = 0;\n\t\t\tcolumns.forEach(function(col){\n\t\t\t\tnewColumnWidth += col[columnProperty] || config.min_grid_column_width;\n\t\t\t});\n\t\t\t//newColumnWidth--; // the total column width shouldn't match the outerWidth // GS-2190 reducing width seems to be not needed\n\t\t\tvar columnsWidth = Math.max(newColumnWidth, width);\n\t\t\tinnerWidth = this._setColumnsWidth(columnsWidth);\n\t\t\touterWidth = width;\n\t\t}\n\n\t\tif (this.$config.scrollable) {\n\t\t\tthis.$grid_scale.style.width = innerWidth + \"px\";\n\t\t\tthis.$grid_data.style.width = innerWidth + \"px\";\n\t\t} else {\n\t\t\tthis.$grid_scale.style.width = \"inherit\";\n\t\t\tthis.$grid_data.style.width = \"inherit\";\n\t\t}\n\t\tthis.$config.width -= 1;\n\n\t\tvar config = this.$getConfig();\n\t\tif (outerWidth !== width) {\n\t\t\tif(outerWidth !== undefined){\n\t\t\t\tconfig.grid_width = outerWidth;\n\t\t\t\tthis.$config.width = outerWidth - 1;\n\t\t\t}else{\n\t\t\t\tif(!isNaN(innerWidth)){\n\t\t\t\t\tthis._setColumnsWidth(innerWidth);\n\t\t\t\t\tconfig.grid_width = innerWidth;\n\t\t\t\t\tthis.$config.width = innerWidth - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvar dataHeight = Math.max(this.$state.height - config.scale_height, 0);\n\t\tthis.$grid_data.style.height = dataHeight + \"px\";\n\t\tthis.refresh();\n\t},\n\tgetSize: function () {\n\n\t\tvar config = this.$getConfig();\n\n\t\tvar store = this.$config.rowStore;\n\n\t\tvar contentHeight = store ? this.getTotalHeight() : 0,\n\t\t\tcontentWidth = this._getGridWidth();\n\n\t\tvar size = {\n\t\t\tx: this.$state.width,\n\t\t\ty: this.$state.height,\n\t\t\tcontentX: this.isVisible() ? contentWidth : 0,\n\t\t\tcontentY: this.isVisible() ? (config.scale_height + contentHeight) : 0,\n\t\t\tscrollHeight: this.isVisible() ? contentHeight : 0,\n\t\t\tscrollWidth: this.isVisible() ? contentWidth : 0\n\t\t};\n\n\t\treturn size;\n\t},\n\n\t_bindStore: function () {\n\t\tif (this.$config.bind){\n\t\t\tvar rowStore = this.$gantt.getDatastore(this.$config.bind);\n\t\t\tthis.$config.rowStore = rowStore;\n\t\t\tif(rowStore && !rowStore._gridCacheAttached){\n\t\t\t\tvar self = this;\n\t\t\t\trowStore._gridCacheAttached = rowStore.attachEvent(\"onBeforeFilter\", function(){\n\t\t\t\t\tself._resetTopPositionHeight();\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t},\n\t_unbindStore: function(){\n\t\tif (this.$config.bind){\n\t\t\tvar rowStore = this.$gantt.getDatastore(this.$config.bind);\n\t\t\tif(rowStore && rowStore._gridCacheAttached){\n\t\t\t\trowStore.detachEvent(rowStore._gridCacheAttached);\n\t\t\t\trowStore._gridCacheAttached = false;\n\t\t\t}\n\t\t}\n\t},\n\n\trefresh: function () {\n\t\tthis._bindStore();\n\n\t\tthis._resetTopPositionHeight();\n\t\tthis._resetHeight();\n\t\tthis._initSmartRenderingPlaceholder();\n\n\t\tthis._calculateGridWidth();\n\t\tthis._renderGridHeader();\n\t},\n\n\tgetViewPort: function(){\n\t\tvar scrollLeft = this.$config.scrollLeft || 0;\n\t\tvar scrollTop = this.$config.scrollTop || 0;\n\t\tvar height = this.$config.height || 0;\n\t\tvar width = this.$config.width || 0;\n\t\treturn {\n\t\t\ty: scrollTop,\n\t\t\ty_end: scrollTop + height,\n\t\t\tx: scrollLeft,\n\t\t\tx_end: scrollLeft + width,\n\t\t\theight: height,\n\t\t\twidth: width\n\t\t};\n\t},\n\n\tscrollTo: function (left, top) {\n\t\tif (!this.isVisible())\n\t\t\treturn;\n\n\t\tvar scrolled = false;\n\n\t\tthis.$config.scrollTop = this.$config.scrollTop || 0;\n\t\tthis.$config.scrollLeft = this.$config.scrollLeft || 0;\n\n\t\tif (left * 1 == left) {\n\t\t\tthis.$config.scrollLeft = this.$state.scrollLeft = this.$grid.scrollLeft = left;\n\t\t\tscrolled = true;\n\t\t}\n\n\t\t// var config = this.$getConfig();\n\t\tif (top * 1 == top) {\n\t\t\tthis.$config.scrollTop = this.$state.scrollTop = this.$grid_data.scrollTop = top;\n\t\t\tscrolled = true;\n\t\t}\n\n\t\tif(scrolled){\n\t\t\tthis.callEvent(\"onScroll\", [this.$config.scrollLeft, this.$config.scrollTop]);\n\t\t}\n\t},\n\n\tgetColumnIndex: function (name, excludeHidden) {\n\t\tvar columns = this.$getConfig().columns;\n\t\tvar hiddenIndexShift = 0;\n\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\t// GS-1257. If the cell is hidden, the target column index should be correct\n\t\t\tif (excludeHidden && columns[i].hide){\n\t\t\t\thiddenIndexShift++;\n\t\t\t}\n\t\t\tif (columns[i].name == name) {\n\t\t\t\treturn i - hiddenIndexShift;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t},\n\n\tgetColumn: function (name) {\n\t\tvar index = this.getColumnIndex(name);\n\t\tif (index === null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.$getConfig().columns[index];\n\t},\n\n\tgetGridColumns: function () {\n\t\tvar config = this.$getConfig();\n\t\treturn config.columns.slice();\n\t},\n\tisVisible: function () {\n\t\tif (this.$parent && this.$parent.$config) {\n\t\t\treturn !this.$parent.$config.hidden;\n\t\t} else {\n\t\t\treturn this.$grid.offsetWidth;\n\t\t}\n\t},\n\n\t// getItemHeight: function () {\n\t// \tvar config = this.$getConfig();\n\t// \treturn config.row_height;\n\t// },\n\n\t_createLayerConfig: function () {\n\t\tvar gantt = this.$gantt;\n\t\tvar self = this;\n\t\tvar layers = [\n\t\t\t{\n\t\t\t\trenderer: gantt.$ui.layers.gridLine(),\n\t\t\t\tcontainer: this.$grid_data,\n\t\t\t\tfilter: [function () {\n\t\t\t\t\treturn self.isVisible();\n\t\t\t\t}]\n\t\t\t},\n\t\t\t{\n\t\t\t\trenderer: gantt.$ui.layers.gridTaskRowResizer(),\n\t\t\t\tcontainer: this.$grid_data,\n\t\t\t\tappend: true,\n\t\t\t\tfilter: [function () {\n\t\t\t\t\treturn gantt.config.resize_rows;\n\t\t\t\t}]\n\t\t\t}\n\t\t];\n\t\treturn layers;\n\t},\n\n\t_addLayers: function (gantt) {\n\t\tif (!this.$config.bind)\n\t\t\treturn;\n\n\t\tthis._taskLayers = [];\n\n\t\tvar self = this;\n\n\t\tvar layers = this.$gantt.$services.getService(\"layers\");\n\t\tvar taskRenderer = layers.getDataRender(this.$config.bind);\n\n\t\tif (!taskRenderer) {\n\t\t\ttaskRenderer = layers.createDataRender({\n\t\t\t\tname: this.$config.bind,\n\t\t\t\tdefaultContainer: function () { return self.$grid_data; }\n\t\t\t});\n\t\t}\n\n\t\tvar taskLayers = this.$config.layers;\n\t\tfor (var i = 0; taskLayers && i < taskLayers.length; i++) {\n\t\t\tvar layer = taskLayers[i];\n\t\t\tlayer.view = this;\n\n\t\t\tvar bar_layer = taskRenderer.addLayer(layer);\n\t\t\tthis._taskLayers.push(bar_layer);\n\t\t}\n\n\t\tthis._bindStore();\n\n\t\tthis._initSmartRenderingPlaceholder();\n\t},\n\n\t_refreshPlaceholderOnStoreUpdate: function (id) {\n\t\tvar config = this.$getConfig(),\n\t\t\tstore = this.$config.rowStore;\n\n\t\tif (!store || id !== null || !this.isVisible() || !config.smart_rendering) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar contentHeight;\n\t\tif (this.$config.scrollY) {\n\t\t\tvar scroll = this.$gantt.$ui.getView(this.$config.scrollY);\n\t\t\tif (scroll)\n\t\t\t\tcontentHeight = scroll.getScrollState().scrollSize;\n\t\t}\n\n\t\tif (!contentHeight) {\n\t\t\tcontentHeight = store ? this.getTotalHeight() : 0;\n\t\t}\n\n\t\tif (contentHeight) {\n\t\t\tif (this.$rowsPlaceholder && this.$rowsPlaceholder.parentNode) {\n\t\t\t\tthis.$rowsPlaceholder.parentNode.removeChild(this.$rowsPlaceholder);\n\t\t\t}\n\n\t\t\tvar placeholder = this.$rowsPlaceholder = document.createElement(\"div\");\n\t\t\tplaceholder.style.visibility = \"hidden\";\n\t\t\tplaceholder.style.height = contentHeight + \"px\";\n\t\t\tplaceholder.style.width = \"1px\";\n\t\t\tthis.$grid_data.appendChild(placeholder);\n\t\t}\n\t},\n\n\t_initSmartRenderingPlaceholder: function () {\n\t\tvar store = this.$config.rowStore;\n\t\tif (!store) {\n\t\t\treturn;\n\t\t} else {\n\t\t\tthis._initSmartRenderingPlaceholder = function () { };\n\t\t}\n\t\tthis._staticBgHandler = store.attachEvent(\"onStoreUpdated\", utils.bind(this._refreshPlaceholderOnStoreUpdate, this));\n\t},\n\n\t_initEvents: function () {\n\t\tvar gantt = this.$gantt;\n\t\tthis._mouseDelegates.delegate(\"click\", \"gantt_close\", gantt.bind(function (e, id, trg) {\n\t\t\tvar store = this.$config.rowStore;\n\t\t\tif (!store) return true;\n\n\t\t\tvar target = domHelpers.locateAttribute(e, this.$config.item_attribute);\n\t\t\tif (target) {\n\t\t\t\tstore.close(target.getAttribute(this.$config.item_attribute));\n\n\t\t\t}\n\t\t\treturn false;\n\t\t}, this), this.$grid);\n\n\t\tthis._mouseDelegates.delegate(\"click\", \"gantt_open\", gantt.bind(function (e, id, trg) {\n\t\t\tvar store = this.$config.rowStore;\n\t\t\tif (!store) return true;\n\n\t\t\tvar target = domHelpers.locateAttribute(e, this.$config.item_attribute);\n\t\t\tif (target) {\n\t\t\t\tstore.open(target.getAttribute(this.$config.item_attribute));\n\n\t\t\t}\n\t\t\treturn false;\n\t\t}, this), this.$grid);\n\t},\n\n\t_clearLayers: function (gantt) {\n\t\tvar layers = this.$gantt.$services.getService(\"layers\");\n\t\tvar taskRenderer = layers.getDataRender(this.$config.bind);\n\n\t\tif (this._taskLayers) {\n\t\t\tfor (var i = 0; i < this._taskLayers.length; i++) {\n\t\t\t\ttaskRenderer.removeLayer(this._taskLayers[i]);\n\t\t\t}\n\t\t}\n\n\t\tthis._taskLayers = [];\n\t},\n\n\t_getColumnWidth: function (column, config, width) {\n\t\tvar min_width = column.min_width || config.min_grid_column_width;\n\t\tvar new_width = Math.max(width, min_width || 10);\n\t\tif (column.max_width)\n\t\t\tnew_width = Math.min(new_width, column.max_width);\n\t\treturn new_width;\n\t},\n\t// set min width only if width < than config.min_grid_column_width\n\t_checkGridColumnMinWidthLimits: function (columns, config) {\n\t\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\t\tvar width = columns[i].width * 1;\n\t\t\tif (!columns[i].min_width && width < config.min_grid_column_width){\n\t\t\t\tcolumns[i].min_width = width;\n\t\t\t}\n\t\t}\n\t},\n\t// return min and max possible grid width according to restricts\n\t_getGridWidthLimits: function () {\n\t\tvar config = this.$getConfig(),\n\t\t\tcolumns = this.getGridColumns(),\n\t\t\tmin_limit = 0,\n\t\t\tmax_limit = 0;\n\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tmin_limit += columns[i].min_width ? columns[i].min_width : config.min_grid_column_width;\n\t\t\tif (max_limit !== undefined) {\n\t\t\t\tmax_limit = columns[i].max_width ? (max_limit + columns[i].max_width) : undefined;\n\t\t\t}\n\t\t}\n\t\tthis._checkGridColumnMinWidthLimits(columns, config); // FIX ME: should it be before calculating limits?\n\t\treturn [min_limit, max_limit];\n\t},\n\t// resize columns to get total newWidth, starting from columns[start_index]\n\t_setColumnsWidth: function (newWidth, start_index) {\n\t\tvar config = this.$getConfig();\n\t\tvar columns = this.getGridColumns(),\n\t\t\tcolumns_width = 0,\n\t\t\tfinal_width = newWidth;\n\n\t\tstart_index = !window.isNaN(start_index) ? start_index : -1;\n\n\t\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\t\tcolumns_width += columns[i].width * 1;\n\t\t}\n\n\t\tif (window.isNaN(columns_width)) {\n\t\t\tthis._calculateGridWidth();\n\t\t\tcolumns_width = 0;\n\t\t\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\t\t\tcolumns_width += columns[i].width * 1;\n\t\t\t}\n\t\t}\n\n\t\tvar extra_width = final_width - columns_width;\n\n\t\tvar start_width = 0;\n\t\tfor (var i = 0; i < start_index + 1; i++) {\n\t\t\tstart_width += columns[i].width;\n\t\t}\n\n\t\tcolumns_width -= start_width;\n\n\t\tfor (var i = start_index + 1; i < columns.length; i++) {\n\n\t\t\tvar col = columns[i];\n\t\t\tvar share = Math.round(extra_width * (col.width / columns_width));\n\n\t\t\t// columns have 2 additional restrict fields - min_width & max_width that are set by user\n\t\t\tif (extra_width < 0) {\n\t\t\t\tif (col.min_width && col.width + share < col.min_width)\n\t\t\t\t\tshare = col.min_width - col.width;\n\t\t\t\telse if (!col.min_width && config.min_grid_column_width && col.width + share < config.min_grid_column_width)\n\t\t\t\t\tshare = config.min_grid_column_width - col.width;\n\t\t\t} else if (col.max_width && col.width + share > col.max_width)\n\t\t\t\tshare = col.max_width - col.width;\n\n\t\t\tcolumns_width -= col.width;\n\t\t\tcol.width += share;\n\t\t\textra_width -= share;\n\n\t\t}\n\n\t\tvar iterator = extra_width > 0 ? 1 : -1;\n\t\twhile ((extra_width > 0 && iterator === 1) || (extra_width < 0 && iterator === -1)) {\n\t\t\tvar curExtra = extra_width;\n\t\t\tfor (i = start_index + 1; i < columns.length; i++) {\n\t\t\t\tvar new_width = columns[i].width + iterator;\n\n\t\t\t\tif (new_width == this._getColumnWidth(columns[i], config, new_width)) {\n\t\t\t\t\textra_width -= iterator;\n\t\t\t\t\tcolumns[i].width = new_width;\n\t\t\t\t}\n\n\t\t\t\tif (!extra_width)\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif (curExtra == extra_width)\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// if impossible to resize the right-side columns, resize the start column\n\t\tif (extra_width && start_index > -1) {\n\t\t\tvar new_width = columns[start_index].width + extra_width;\n\t\t\tif (new_width == this._getColumnWidth(columns[start_index], config, new_width))\n\t\t\t\tcolumns[start_index].width = new_width;\n\t\t}\n\n\t\t//if (this.callEvent(\"onGridResizeEnd\", [config.grid_width, final_width]) === false)\n\t\t//\treturn;\n\n\t\treturn this._getColsTotalWidth();\n\t},\n\n\t_getColsTotalWidth: function () {\n\t\tvar columns = this.getGridColumns();\n\t\tvar cols_width = 0;\n\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tvar v = parseFloat(columns[i].width);\n\t\t\tif (window.isNaN(v)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcols_width += v;\n\t\t}\n\t\treturn cols_width;\n\t},\n\t_calculateGridWidth: function () {\n\t\tvar config = this.$getConfig();\n\t\tvar columns = this.getGridColumns();\n\t\tvar cols_width = 0;\n\t\tvar unknown = [];\n\t\tvar width = [];\n\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tvar v = parseFloat(columns[i].width);\n\t\t\tif (window.isNaN(v)) {\n\t\t\t\tv = config.min_grid_column_width || 10;\n\t\t\t\tunknown.push(i);\n\t\t\t}\n\t\t\twidth[i] = v;\n\t\t\tcols_width += v;\n\t\t}\n\t\tvar gridWidth = this._getGridWidth() + 1;\n\t\tif (config.autofit || unknown.length) {\n\t\t\tvar diff = gridWidth - cols_width;\n\t\t\t// TODO: logic may be improved for proportional changing of width\n\n\t\t\t// autofit adjusts columns widths to the outer grid width\n\t\t\t// it doesn't makes sense if grid has inner scroll with elastic columns\n\t\t\tif (config.autofit && !config.grid_elastic_columns) {\n\t\t\t\t// delta must be added for all columns\n\t\t\t\tfor (var i = 0; i < width.length; i++) {\n\t\t\t\t\tvar delta = Math.round(diff / (width.length - i));\n\t\t\t\t\twidth[i] += delta;\n\t\t\t\t\tvar new_width = this._getColumnWidth(columns[i], config, width[i]);\n\n\t\t\t\t\tif (new_width != width[i]) {\n\t\t\t\t\t\tdelta = new_width - width[i];\n\t\t\t\t\t\twidth[i] = new_width;\n\t\t\t\t\t}\n\t\t\t\t\tdiff -= delta;\n\t\t\t\t}\n\t\t\t} else if (unknown.length) {\n\t\t\t\t// there are several columns with undefined width\n\t\t\t\tfor (var i = 0; i < unknown.length; i++) {\n\t\t\t\t\tvar delta = Math.round(diff / (unknown.length - i)); // no float values, just integer\n\t\t\t\t\tvar index = unknown[i];\n\t\t\t\t\twidth[index] += delta;\n\t\t\t\t\tvar new_width = this._getColumnWidth(columns[index], config, width[index]);\n\t\t\t\t\tif (new_width != width[index]) {\n\t\t\t\t\t\tdelta = new_width - width[index];\n\t\t\t\t\t\twidth[index] = new_width;\n\t\t\t\t\t}\n\t\t\t\t\tdiff -= delta;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < width.length; i++) {\n\t\t\t\tcolumns[i].width = width[i];\n\t\t\t}\n\t\t} else {\n\t\t\tvar changed = (gridWidth != cols_width);\n\t\t\tthis.$config.width = cols_width - 1;\n\t\t\tconfig.grid_width = cols_width;\n\t\t\tif (changed) {\n\t\t\t\tthis.$parent._setContentSize(this.$config.width, null);\n\t\t\t}\n\t\t}\n\n\t},\n\n\t_renderGridHeader: function () {\n\t\tvar gantt = this.$gantt;\n\t\tvar config = this.$getConfig();\n\t\tvar locale = this.$gantt.locale;\n\t\tvar templates = this.$gantt.templates;\n\n\t\tvar columns = this.getGridColumns();\n\t\tif (config.rtl) {\n\t\t\tcolumns = columns.reverse();\n\t\t}\n\t\tvar cells = [];\n\t\tvar width = 0,\n\t\t\tlabels = locale.labels;\n\n\t\tvar lineHeigth = config.scale_height - 1;\n\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tvar last = i == columns.length - 1;\n\t\t\tvar col = columns[i];\n\n\t\t\t// ensure columns have non-empty names\n\t\t\tif (!col.name) {\n\t\t\t\tcol.name = gantt.uid() + \"\";\n\t\t\t}\n\n\t\t\tvar colWidth = col.width * 1;\n\n\t\t\tvar gridWidth = this._getGridWidth();\n\t\t\tif (last && gridWidth > width + colWidth)\n\t\t\t\tcol.width = colWidth = gridWidth - width;\n\t\t\twidth += colWidth;\n\t\t\tvar sort = (gantt._sort && col.name == gantt._sort.name) ? (`
`) : \"\";\n\t\t\tvar cssClass = [\"gantt_grid_head_cell\",\n\t\t\t\t(\"gantt_grid_head_\" + col.name),\n\t\t\t\t(last ? \"gantt_last_cell\" : \"\"),\n\t\t\t\ttemplates.grid_header_class(col.name, col)].join(\" \");\n\n\t\t\tvar style = \"width:\" + (colWidth - (last ? 1 : 0)) + \"px;\";\n\t\t\tvar label = (col.label || labels[\"column_\" + col.name] || labels[col.name]);\n\t\t\tlabel = label || \"\";\n\n\t\t\tvar ariaAttrs = gantt._waiAria.gridScaleCellAttrString(col, label);\n\n\t\t\tvar cell = \"
\" + label + sort + \"
\";\n\t\t\tcells.push(cell);\n\t\t}\n\t\tthis.$grid_scale.style.height = (config.scale_height) + \"px\";\n\t\tthis.$grid_scale.style.lineHeight = lineHeigth + \"px\";\n\t\t//this.$grid_scale.style.width = \"inherit\";\n\t\tthis.$grid_scale.innerHTML = cells.join(\"\");\n\n\t\tif (this._renderHeaderResizers) {\n\t\t\tthis._renderHeaderResizers();\n\t\t}\n\t},\n\n\t_getGridWidth: function () {\n\t\t// TODO: refactor/remove/comment some of _getGridWidth/this.$config.width/this.$state.width, it's not clear what they do\n\t\treturn this.$config.width;\n\t},\n\n\tdestructor: function () {\n\t\tthis._clearLayers(this.$gantt);\n\t\tif (this._mouseDelegates) {\n\t\t\tthis._mouseDelegates.destructor();\n\t\t\tthis._mouseDelegates = null;\n\t\t}\n\t\tthis._unbindStore();\n\t\tthis.$grid = null;\n\t\tthis.$grid_scale = null;\n\t\tthis.$grid_data = null;\n\t\tthis.$gantt = null;\n\t\tif (this.$config.rowStore) {\n\t\t\tthis.$config.rowStore.detachEvent(this._staticBgHandler);\n\t\t\tthis.$config.rowStore = null;\n\t\t}\n\n\t\tthis.callEvent(\"onDestroy\", []);\n\t\tthis.detachAllEvents();\n\t}\n};\n\nexport default Grid;\n","import * as utils from \"../../utils/utils\";\nimport * as helpers from \"../../utils/helpers\";\n\n\nfunction IsWorkTimeArgument(date, unit, task, id, calendar){\n\tthis.date = date;\n\tthis.unit = unit;\n\tthis.task = task;\n\tthis.id = id;\n\tthis.calendar = calendar;\n\treturn this;\n}\n\nfunction ClosestWorkTimeArgument(date, dir, unit, task, id, calendar){\n\tthis.date = date;\n\tthis.dir = dir;\n\tthis.unit = unit;\n\tthis.task = task;\n\tthis.id = id;\n\tthis.calendar = calendar;\n\treturn this;\n}\n\nfunction CalculateEndDateArgument(start_date, duration, unit, step, task, id, calendar){\n\tthis.start_date = start_date;\n\tthis.duration = duration;\n\tthis.unit = unit;\n\tthis.step = step;\n\tthis.task = task;\n\tthis.id = id;\n\tthis.calendar = calendar;\n\treturn this;\n}\n\nfunction GetDurationArgument(start, end, task, calendar) {\n\tthis.start_date = start;\n\tthis.end_date = end;\n\tthis.task = task;\n\tthis.calendar = calendar;\n\tthis.unit = null;\n\tthis.step = null;\n\treturn this;\n}\n\nvar calendarArgumentsHelper = function(gantt){\n\treturn {\n\t\tgetWorkHoursArguments: function () {\n\t\t\tvar config = arguments[0];\n\t\t\tif (helpers.isDate(config)) {\n\t\t\t\tconfig = {\n\t\t\t\t\tdate: config\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tconfig = utils.mixin({}, config);\n\t\t\t}\n\n\t\t\tif(!helpers.isValidDate(config.date)){\n\t\t\t\tgantt.assert(false, \"Invalid date argument for getWorkHours method\");\n\t\t\t\tthrow new Error(\"Invalid date argument for getWorkHours method\");\n\t\t\t}\n\n\t\t\treturn config;\n\t\t},\n\t\tsetWorkTimeArguments: function () {\n\t\t\treturn arguments[0];\n\t\t},\n\t\tunsetWorkTimeArguments: function () {\n\t\t\treturn arguments[0];\n\t\t},\n\t\tisWorkTimeArguments: function () {\n\t\t\tvar config = arguments[0];\n\t\t\tif(config instanceof IsWorkTimeArgument){\n\t\t\t\treturn config;\n\t\t\t}\n\n\t\t\tvar processedConfig;\n\t\t\tif (!config.date) {\n\t\t\t\t//IsWorkTimeArgument(date, unit, task, id, calendar)\n\t\t\t\tprocessedConfig = new IsWorkTimeArgument(arguments[0], arguments[1], arguments[2], null, arguments[3]);\n\t\t\t} else {\n\t\t\t\tprocessedConfig = new IsWorkTimeArgument(config.date, config.unit, config.task, null, config.calendar);\n\t\t\t}\n\n\t\t\tprocessedConfig.unit = processedConfig.unit || gantt.config.duration_unit;\n\n\t\t\tif(!helpers.isValidDate(processedConfig.date)){\n\t\t\t\tgantt.assert(false, \"Invalid date argument for isWorkTime method\");\n\t\t\t\tthrow new Error(\"Invalid date argument for isWorkTime method\");\n\t\t\t}\n\n\t\t\treturn processedConfig;\n\t\t},\n\t\tgetClosestWorkTimeArguments: function (arg) {\n\t\t\tvar config = arguments[0];\n\t\t\tif (config instanceof ClosestWorkTimeArgument)\n\t\t\t\treturn config;\n\n\t\t\tvar processedConfig;\n\t\t\tif (helpers.isDate(config)) {\n\t\t\t\tprocessedConfig = new ClosestWorkTimeArgument(config);\n\n\t\t\t} else {\n\t\t\t\tprocessedConfig = new ClosestWorkTimeArgument(\n\t\t\t\t\tconfig.date,\n\t\t\t\t\tconfig.dir,\n\t\t\t\t\tconfig.unit,\n\t\t\t\t\tconfig.task,\n\t\t\t\t\tnull,//config.id,\n\t\t\t\t\tconfig.calendar\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif(config.id){\n\t\t\t\tprocessedConfig.task = config;\n\t\t\t}\n\t\t\tprocessedConfig.dir = config.dir || 'any';\n\t\t\tprocessedConfig.unit = config.unit || gantt.config.duration_unit;\n\n\t\t\tif(!helpers.isValidDate(processedConfig.date)){\n\t\t\t\tgantt.assert(false, \"Invalid date argument for getClosestWorkTime method\");\n\t\t\t\tthrow new Error(\"Invalid date argument for getClosestWorkTime method\");\n\t\t\t}\n\t\t\treturn processedConfig;\n\t\t},\n\n\t\t_getStartEndConfig: function (param) {\n\t\t\tvar argumentType = GetDurationArgument;\n\t\t\tvar config;\n\t\t\tif (param instanceof argumentType)\n\t\t\t\treturn param;\n\n\t\t\tif (helpers.isDate(param)) {\n\t\t\t\tconfig = new argumentType(arguments[0], arguments[1], arguments[2], arguments[3]);\n\t\t\t} else {\n\t\t\t\tconfig = new argumentType(param.start_date, param.end_date, param.task);\n\t\t\t\tif (param.id !== null && param.id !== undefined) {\n\t\t\t\t\tconfig.task = param;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconfig.unit = config.unit || gantt.config.duration_unit;\n\t\t\tconfig.step = config.step || gantt.config.duration_step;\n\t\t\tconfig.start_date = config.start_date || config.start || config.date;\n\n\t\t\tif(!helpers.isValidDate(config.start_date)){\n\t\t\t\tgantt.assert(false, \"Invalid start_date argument for getDuration method\");\n\t\t\t\tthrow new Error(\"Invalid start_date argument for getDuration method\");\n\t\t\t}\n\n\t\t\tif(!helpers.isValidDate(config.end_date)){\n\t\t\t\tgantt.assert(false, \"Invalid end_date argument for getDuration method\");\n\t\t\t\tthrow new Error(\"Invalid end_date argument for getDuration method\");\n\t\t\t}\n\n\t\t\treturn config;\n\t\t},\n\n\t\tgetDurationArguments: function (start, end, unit, step) {\n\t\t\treturn this._getStartEndConfig.apply(this, arguments);\n\t\t},\n\n\t\thasDurationArguments: function (start, end, unit, step) {\n\t\t\treturn this._getStartEndConfig.apply(this, arguments);\n\t\t},\n\n\t\tcalculateEndDateArguments: function (start, duration, unit, step) {\n\t\t\tvar config = arguments[0];\n\t\t\tif (config instanceof CalculateEndDateArgument)\n\t\t\t\treturn config;\n\n\t\t\tvar processedConfig;\n\t\t\t//CalculateEndDateArgument(start_date, duration, unit, step, task, id, calendar)\n\t\t\tif (helpers.isDate(config)) {\n\t\t\t\tprocessedConfig = new CalculateEndDateArgument(\n\t\t\t\t\targuments[0],\n\t\t\t\t\targuments[1],\n\t\t\t\t\targuments[2],\n\t\t\t\t\tundefined,\n\t\t\t\t\targuments[3],\n\t\t\t\t\tundefined,\n\t\t\t\t\targuments[4]\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\tprocessedConfig = new CalculateEndDateArgument(\n\t\t\t\t\tconfig.start_date,\n\t\t\t\t\tconfig.duration,\n\t\t\t\t\tconfig.unit,\n\t\t\t\t\tconfig.step,\n\t\t\t\t\tconfig.task,\n\t\t\t\t\tnull,//config.id,\n\t\t\t\t\tconfig.calendar\n\t\t\t\t);\n\t\t\t}\n\t\t\tif(config.id !== null && config.id !== undefined){\n\t\t\t\tprocessedConfig.task = config;\n\n\t\t\t\t// received a task object as an argument\n\t\t\t\t// ignore 'unit' and 'step' properties in this case, since it's likely a part of data model of a task\n\t\t\t\tprocessedConfig.unit = null;\n\t\t\t\tprocessedConfig.step = null;\n\t\t\t}\n\n\t\t\tprocessedConfig.unit = processedConfig.unit || gantt.config.duration_unit;\n\t\t\tprocessedConfig.step = processedConfig.step || gantt.config.duration_step;\n\n\t\t\tif(!helpers.isValidDate(processedConfig.start_date)){\n\t\t\t\tgantt.assert(false, \"Invalid start_date argument for calculateEndDate method\");\n\t\t\t\tthrow new Error(\"Invalid start_date argument for calculateEndDate method\");\n\t\t\t}\n\n\t\t\treturn processedConfig;\n\t\t}\n\t};\n};\n\n\nexport default calendarArgumentsHelper;","import * as domHelpers from \"../utils/dom_helpers\";\n\nfunction createResizer(gantt, grid){\n// renders resize elements in the grid header\n\tvar _render_grid_header_resize = function () {\n\t\tvar columns = grid.getGridColumns(),\n\t\t\tconfig = grid.$getConfig(),\n\t\t\twidth = 0,\n\t\t\ttotalWidth = grid.$config.width,\n\t\t\tlineHeigth = config.scale_height;\n\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tvar col = columns[i];\n\n\t\t\tvar pos;\n\t\t\twidth += col.width;\n\t\t\tif(config.rtl){\n\t\t\t\tpos = totalWidth - width;\n\t\t\t}else{\n\t\t\t\tpos = width;\n\t\t\t}\n\n\t\t\t// GS-205. don't add resizer for the last column\n\t\t\tif (col.resize && i != columns.length - 1) {\n\t\t\t\tvar resize_el = document.createElement(\"div\");\n\t\t\t\tresize_el.className = \"gantt_grid_column_resize_wrap\";\n\t\t\t\tresize_el.style.top = \"0px\";\n\t\t\t\tresize_el.style.height = lineHeigth + \"px\";\n\t\t\t\tresize_el.innerHTML = \"
\";\n\t\t\t\tresize_el.setAttribute(config.grid_resizer_column_attribute, i);\n\t\t\t\tresize_el.setAttribute(\"column_index\", i); // hardcoded for backward compatibility\n\n\t\t\t\tgantt._waiAria.gridSeparatorAttr(resize_el);\n\n\t\t\t\tgrid.$grid_scale.appendChild(resize_el);\n\n\t\t\t\tresize_el.style.left = Math.max(0, pos) + \"px\";\n\t\t\t}\n\t\t}\n\t};\n\n\tvar _grid_resize = {\n\t\tcolumn_before_start: gantt.bind(function (dnd, obj, e) {\n\t\t\tvar config = grid.$getConfig();\n\n\t\t\tvar el = domHelpers.locateAttribute(e, config.grid_resizer_column_attribute);\n\t\t\tif (!el) return false;\n\n\t\t\tif (!domHelpers.closest(el,\".gantt_grid_column_resize_wrap\")) {\n\t\t\t\t// column resize should work only when we use the resizer\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tvar column_index = this.locate(e, config.grid_resizer_column_attribute),\n\t\t\t\tcolumn = grid.getGridColumns()[column_index];\n\n\t\t\tif (grid.callEvent(\"onColumnResizeStart\", [column_index, column]) === false)\n\t\t\t\treturn false;\n\t\t}, gantt),\n\n\t\tcolumn_after_start: gantt.bind(function (dnd, obj, e) {\n\t\t\tvar config = grid.$getConfig();\n\n\t\t\tvar column_index = this.locate(e, config.grid_resizer_column_attribute);\n\t\t\tdnd.config.marker.innerHTML = \"\";\n\t\t\tdnd.config.marker.className += \" gantt_grid_resize_area\";\n\t\t\tdnd.config.marker.style.height = grid.$grid.offsetHeight + \"px\";\n\t\t\tdnd.config.marker.style.top = \"0px\";\n\t\t\tdnd.config.drag_index = column_index;\n\n\t\t}, gantt),\n\n\t\tcolumn_drag_move: gantt.bind(function (dnd, obj, e) {\n\t\t\tvar config = grid.$getConfig();\n\n\t\t\tvar dd = dnd.config,\n\t\t\t\tcolumns = grid.getGridColumns();\n\t\t\tvar index = parseInt(dd.drag_index, 10);\n\t\t\tvar target_column = columns[index];\n\t\t\tvar\tpos = domHelpers.getNodePosition(grid.$grid_scale),\n\t\t\t\tpointerPosition = parseInt(dd.marker.style.left, 10),\n\t\t\t\tminPointerPosition = target_column.min_width ? target_column.min_width : config.min_grid_column_width,\n\t\t\t\tmaxPointerPosition = grid.$grid_data.offsetWidth,// - config.min_grid_column_width * (columns.length - dd.drag_index - 2),// 1 for current column + 1 for last column\n\t\t\t\tmarkerStartPosition = 0,\n\t\t\t\tmarker_width = 0;\n\n\t\t\t\n\t\t/*\tif(config.rtl){\n\t\t\t\tindex = columns.length - 1 - index;\n\t\t\t\tcolumns = columns.reverse();\n\t\t\t}*/\n\n\t\t\tif(!config.rtl){\n\t\t\t\tpointerPosition -= pos.x - 1;\n\t\t\t}else{\n\t\t\t\tpointerPosition = (pos.x + pos.width - 1) - pointerPosition;\n\t\t\t}\n\n\t\t\t//pointerPosition -= pos.x - 1;\n\t\t\tfor (var i = 0; i < index; i++) {\n\t\t\t\tminPointerPosition += columns[i].width;\n\t\t\t\tmarkerStartPosition += columns[i].width;\n\t\t\t}\n\n\t\t\tif (pointerPosition < minPointerPosition) {\n\t\t\t\tpointerPosition = minPointerPosition;\n\t\t\t}\n\n\t\t\tif (config.keep_grid_width) {\n\t\t\t\tvar limit_max = 0;\n\t\t\t\tfor (var i=index+1; i maxPointerPosition) {\n\t\t\t\t\tpointerPosition = maxPointerPosition;\n\t\t\t\t}\n\t\t\t} else if (!grid.$config.scrollable) {\n\t\t\t\tvar targetWidth = pointerPosition;\n\t\t\t\tvar maxWidth = gantt.$container.offsetWidth;\n\n\t\t\t\tvar rightColumnsWidth = 0;\n\t\t\t\t// 25 is a scrollbar width. due to GS-1314 fix, the grid should always be visible\n\t\t\t\t// because of that, the internal grid width can be larger than the visible grid width\n\t\t\t\tif (grid.$grid_data.offsetWidth <= (maxWidth - 25)){\n\t\t\t\t\tfor (var i=index+1; i= 0; i--) {\n\t\t\t\t\t\trightColumnsWidth += columns[i].width;\n\t\t\t\t\t}\n\t\t\t\t\trightColumnsWidth = maxWidth - rightColumnsWidth;\n\t\t\t\t}\n\n\t\t\t\t// in case if something went wrong in the previous part\n\t\t\t\tif (rightColumnsWidth > maxWidth){\n\t\t\t\t\trightColumnsWidth -= maxWidth;\n\t\t\t\t}\n\n\t\t\t\t// prevent grid from occupying the whole layout cell, which would disable the timeline\n\t\t\t\tvar parentLayout = grid.$parent.$parent;\n\t\t\t\tif(parentLayout && parentLayout.$config.mode == \"y\"){\n\t\t\t\t\tvar parentWidth = parentLayout.$lastSize.x;\n\t\t\t\t\tmaxWidth = Math.min(maxWidth, parentWidth - (parentLayout.$cells.length - 1));\n\t\t\t\t}\n\t\n\t\t\t\tif(targetWidth + rightColumnsWidth > maxWidth){\n\t\t\t\t\tpointerPosition = maxWidth - rightColumnsWidth;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tdd.left = pointerPosition - 1;// -1 for border\n\n\t\t\tmarker_width = Math.abs(pointerPosition - markerStartPosition);\n\n\t\t\t// column.max_width - maximum width of the column, user defined\n\t\t\tif (target_column.max_width && marker_width > target_column.max_width)\n\t\t\t\tmarker_width = target_column.max_width;\n\n\t\t\tif(config.rtl){\n\t\t\t\tmarkerStartPosition = (pos.width - markerStartPosition) + 2 - marker_width;\n\t\t\t}\n\t\t\tdd.marker.style.top = pos.y + \"px\";\n\t\t\tdd.marker.style.left = pos.x - 1 + markerStartPosition + \"px\";\n\t\t\tdd.marker.style.width = marker_width + \"px\";\n\n\t\t\tgrid.callEvent(\"onColumnResize\", [index, columns[index], marker_width - 1]);\n\t\t\treturn true;\n\t\t}, gantt),\n\n\t\tcolumn_drag_end: gantt.bind(function (dnd, obj, e) {\n\t\t\tvar config = grid.$getConfig();\n\t\t\tvar columns = grid.getGridColumns(),\n\t\t\t\tcolumns_width = 0,\n\t\t\t\tindex = parseInt(dnd.config.drag_index, 10),\n\t\t\t\ttarget_column = columns[index];\n\n\t\t\t// var colIndex = index;\n\t\t\t/*if(config.rtl){\n\t\t\t\tcolIndex = columns.length - 1 - target_index;\n\t\t\t\tcolumns = columns.reverse();\n\t\t\t}*/\n\n\t\t\tfor (var i = 0; i < index; i++) {\n\t\t\t\tcolumns_width += columns[i].width;\n\t\t\t}\n\n\t\t\tvar final_width = (target_column.min_width && (dnd.config.left - columns_width) < target_column.min_width) ?\n\t\t\t\ttarget_column.min_width : (dnd.config.left - columns_width);\n\n\t\t\tif (target_column.max_width && target_column.max_width < final_width) // TODO: probably can be omitted\n\t\t\t\tfinal_width = target_column.max_width;\n\n\t\t\tif (grid.callEvent(\"onColumnResizeEnd\", [index, target_column, final_width]) === false)\n\t\t\t\treturn;\n\n\t\t\tif (target_column.width == final_width)\n\t\t\t\treturn;\n\n\t\t\ttarget_column.width = final_width;\n\n\t\t\tif (config.keep_grid_width) {\n\t\t\t\tcolumns_width = config.grid_width;\n\t\t\t} else {\n\t\t\t\t// in other case we set a new grid width and call gantt render\n\t\t\t\tfor (var i = index, l = columns.length; i < l; i++) {\n\t\t\t\t\tcolumns_width += columns[i].width;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tgrid.callEvent(\"onColumnResizeComplete\", [columns, grid._setColumnsWidth(columns_width, index)]);\n\n\t\t\tif(!grid.$config.scrollable){\n\t\t\t\tgantt.$layout._syncCellSizes(grid.$config.group, {value: config.grid_width, isGravity: false});\n\t\t\t}\n\t\t\t//grid.callEvent(\"onColumnResizeComplete\", [columns, columns_width]);\n\n\t\t\tthis.render();\n\t\t}, gantt)\n\t};\n\n// calls the initialization of the D'n'D events for resize elements\n\tvar _init_resize = function () {\n\t\tvar DnD = gantt.$services.getService(\"dnd\");\n\n\t\tvar config = grid.$getConfig();\n\n\t\tvar dnd = new DnD(grid.$grid_scale, {updates_per_second: 60});\n\t\tif (gantt.defined(config.dnd_sensitivity))\n\t\t\tdnd.config.sensitivity = config.dnd_sensitivity;\n\n\t\tdnd.attachEvent(\"onBeforeDragStart\", function (obj, e) {\n\t\t\treturn _grid_resize.column_before_start(dnd, obj, e);\n\t\t});\n\t\tdnd.attachEvent(\"onAfterDragStart\", function (obj, e) {\n\t\t\treturn _grid_resize.column_after_start(dnd, obj, e);\n\t\t});\n\t\tdnd.attachEvent(\"onDragMove\", function (obj, e) {\n\t\t\treturn _grid_resize.column_drag_move(dnd, obj, e);\n\t\t});\n\t\tdnd.attachEvent(\"onDragEnd\", function (obj, e) {\n\t\t\treturn _grid_resize.column_drag_end(dnd, obj, e);\n\t\t});\n\n\t};\n\n\treturn {\n\t\tinit: _init_resize,\n\t\tdoOnRender: _render_grid_header_resize\n\t};\n}\n\nexport default createResizer;\n","import * as domHelpers from \"../utils/dom_helpers\";\n\nfunction createRowResizer(gantt, grid){\n\n\tvar _task_grid_row_resize = {\n\t\trow_before_start: gantt.bind(function (dnd, obj, e) {\n\t\t\tvar config = grid.$getConfig();\n\t\t\tvar store = grid.$config.rowStore;\n\n\t\t\tvar el = domHelpers.locateAttribute(e, config.task_grid_row_resizer_attribute);\n\t\t\tif (!el) return false;\n\n\t\t\tvar row_id = this.locate(e, config.task_grid_row_resizer_attribute),\n\t\t\t\trow = store.getItem(row_id);\n\n\t\t\tif (grid.callEvent(\"onBeforeRowResize\", [row]) === false)\n\t\t\t\treturn false;\n\t\t}, gantt),\n\n\t\trow_after_start: gantt.bind(function (dnd, obj, e) {\n\t\t\tvar config = grid.$getConfig();\n\n\t\t\tvar row_id = this.locate(e, config.task_grid_row_resizer_attribute);\n\t\t\tdnd.config.marker.innerHTML = \"\";\n\n\t\t\tdnd.config.marker.className += \" gantt_row_grid_resize_area\";\n\t\t\tdnd.config.marker.style.width = grid.$grid.offsetWidth + \"px\";\n\t\t\tdnd.config.drag_id = row_id;\n\n\t\t}, gantt),\n\n\t\trow_drag_move: gantt.bind(function (dnd, obj, e) {\n\t\t\tvar store = grid.$config.rowStore;\n\t\t\tvar config = grid.$getConfig();\n\t\t\tvar dd = dnd.config;\n\t\t\tvar id = dd.drag_id,\n\t\t\t\titemHeight = grid.getItemHeight(id),\n\t\t\t\titemTop = grid.getItemTop(id) - obj.scrollTop;\n\t\t\tvar pos = domHelpers.getNodePosition(grid.$grid_data),\n\t\t\t\tpointerPosition = parseInt(dd.marker.style.top, 10),\n\t\t\t\tmarkerStartPosition = itemTop + pos.y,\n\t\t\t\tmarker_height = 0,\n\t\t\t\tminPointerPosition = config.min_task_grid_row_height;\n\n\t\t\tmarker_height = pointerPosition - markerStartPosition;\n\t\t\tif(marker_height < minPointerPosition){\n\t\t\t\tmarker_height = minPointerPosition;\n\t\t\t}\n\n\t\t\tdd.marker.style.left = pos.x + \"px\";\n\t\t\tdd.marker.style.top = markerStartPosition - 1 + \"px\";\n\t\t\tdd.marker.style.height = Math.abs(marker_height) + 1 + \"px\";\n\n\t\t\tdd.marker_height = marker_height;\n\t\t\t\n\t\t\tgrid.callEvent(\"onRowResize\", [id, store.getItem(id), marker_height + itemHeight]);\n\t\t\treturn true;\n\t\t}, gantt),\n\n\t\trow_drag_end: gantt.bind(function (dnd, obj, e) {\n\t\t\tvar store = grid.$config.rowStore;\n\t\t\tvar dd = dnd.config;\n\t\t\tvar id = dd.drag_id,\n\t\t\t\titem = store.getItem(id),\n\t\t\t\toldItemHeight = grid.getItemHeight(id);\n\n\t\t\tvar finalHeight = dd.marker_height;\n\n\t\t\tif (grid.callEvent(\"onBeforeRowResizeEnd\", [id, item, finalHeight]) === false)\n\t\t\t\treturn;\n\n\t\t\tif (item.row_height == finalHeight)\n\t\t\t\treturn;\n\n\t\t\titem.row_height = finalHeight;\n\t\t\tgantt.updateTask(id);\n\n\t\t\tgrid.callEvent(\"onAfterRowResize\", [id, item, oldItemHeight, finalHeight]);\n\n\t\t\tthis.render();\n\t\t}, gantt)\n\t};\n\n\t// calls the initialization of the D'n'D events for resize elements\n\tvar _init_resize = function () {\n\n\t\tvar DnD = gantt.$services.getService(\"dnd\");\n\n\t\tvar config = grid.$getConfig();\n\n\t\tvar dnd = new DnD(grid.$grid_data, {updates_per_second: 60});\n\t\tif (gantt.defined(config.dnd_sensitivity))\n\t\t\tdnd.config.sensitivity = config.dnd_sensitivity;\n\n\t\tdnd.attachEvent(\"onBeforeDragStart\", function (obj, e) {\n\t\t\treturn _task_grid_row_resize.row_before_start(dnd, obj, e);\n\t\t});\n\t\tdnd.attachEvent(\"onAfterDragStart\", function (obj, e) {\n\t\t\treturn _task_grid_row_resize.row_after_start(dnd, obj, e);\n\t\t});\n\t\tdnd.attachEvent(\"onDragMove\", function (obj, e) {\n\t\t\treturn _task_grid_row_resize.row_drag_move(dnd, obj, e);\n\t\t});\n\t\tdnd.attachEvent(\"onDragEnd\", function (obj, e) {\n\t\t\treturn _task_grid_row_resize.row_drag_end(dnd, obj, e);\n\t\t});\n\n\t};\n\n\treturn {\n\t\tinit: _init_resize\n\t};\n}\n\nexport default createRowResizer;","import * as utils from \"../../../utils/utils\";\nfunction WorkTimeCalendarMerger(){\n}\n\nWorkTimeCalendarMerger.prototype = {\n\n\n\t/**\n\t * convert hours array items into objects, e.g. [8, 12, 17, 18] -> [{start: 8, end: 12}, {start:17, end:18}]\n\t * @param {Array} hoursArray\n\t */\n\t_getIntervals: function(hoursArray){\n\t\tvar result = [];\n\t\tfor(var i = 0; i < hoursArray.length; i += 2){\n\n\t\t\tresult.push({\n\t\t\t\tstart: hoursArray[i],\n\t\t\t\tend: hoursArray[i+1]\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t},\n\n\t/**\n\t * Convert ranges config into hours array\n\t * [{start: 8, end: 12}, {start:17, end:18}] --> [8, 12, 17, 18]\n\t * @param {*} intervalsArray\n\t */\n\t_toHoursArray: function(intervalsArray){\n\t\tvar result = [];\n\n\t\tfunction toFixed(value){\n\t\t\tvar str = String(value);\n\t\t\tif(str.length < 2){\n\t\t\t\tstr = \"0\" + str;\n\t\t\t}\n\t\t\treturn str;\n\t\t}\n\t\tfunction formatHHMM(secondsValue){\n\t\t\tvar hours = Math.floor(secondsValue / (60*60));\n\t\t\tvar minutePart = secondsValue - hours * 60 * 60;\n\n\t\t\tvar minutes = Math.floor(minutePart / (60));\n\t\t\treturn hours + \":\" + toFixed(minutes);\n\t\t}\n\t\tfor(var i = 0; i < intervalsArray.length; i++){\n\t\t\tresult.push(\n\t\t\t\tformatHHMM(intervalsArray[i].start) +\n\t\t\t\t\"-\" +\n\t\t\t\tformatHHMM(intervalsArray[i].end)\n\t\t\t);\n\t\t}\n\t\treturn result;\n\t},\n\n\t/**\n\t * Build intersection of hour intervals. e.g.\n\t * first: [{start: 8, end: 12}, {start:13, end:18}]\n\t * second: [{start: 10, end: 15}]\n\t * result: [{start: 10, end: 12}, {start: 13, end: 15}]\n\t * @param {Array} first\n\t * @param {Array} second\n\t */\n\t_intersectHourRanges: function(first, second){\n\t\tvar result = [];\n\n\t\tvar baseArray = first.length > second.length ? first : second;\n\t\tvar overridesArray = first === baseArray ? second: first;\n\t\tbaseArray = baseArray.slice();\n\t\toverridesArray = overridesArray.slice();\n\n\t\tvar result = [];\n\t\tfor(var i = 0; i < baseArray.length; i++){\n\t\t\tvar base = baseArray[i];\n\n\t\t\tfor(var j = 0; j < overridesArray.length; j++){\n\t\t\t\tvar current = overridesArray[j];\n\t\t\t\tif(current.start < base.end && current.end > base.start){\n\t\t\t\t\tresult.push({\n\t\t\t\t\t\tstart: Math.max(base.start, current.start),\n\t\t\t\t\t\tend: Math.min(base.end, current.end)\n\t\t\t\t\t});\n\t\t\t\t\tif(base.end > current.end){\n\t\t\t\t\t\toverridesArray.splice(j, 1);\n\t\t\t\t\t\tj--;\n\t\t\t\t\t\ti--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t},\n\n\t/**\n\t * Reduce the number of ranges in config when possible,\n\t * joins ranges that can be merged\n\t * parts: [{start: 8, end: 12}, {start:12, end:13}, {start: 15, end: 17}]\n\t * result: [{start: 8, end: 13}, {start: 15, end: 17}]\n\t * @param {Array} parts\n\t */\n\t_mergeAdjacentIntervals: function(parts){\n\t\tvar result = parts.slice();\n\t\tresult.sort(function(a, b){\n\t\t\treturn a.start - b.start;\n\t\t});\n\t\tvar base = result[0];\n\t\tfor(var i = 1; i < result.length; i++){\n\t\t\tvar current = result[i];\n\t\t\tif(current.start <= base.end){\n\t\t\t\tif(current.end > base.end){\n\t\t\t\t\tbase.end = current.end;\n\t\t\t\t}\n\t\t\t\tresult.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}else{\n\t\t\t\tbase = current;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t},\n\n\t_mergeHoursConfig: function(firstHours, secondHours){\n\t\t//var firstIntervals = this._getIntervals(firstHours);\n\t\t//var secondIntervals = this._getIntervals(secondHours);\n\n\t\treturn this._mergeAdjacentIntervals(\n\t\t\tthis._intersectHourRanges(firstHours, secondHours)\n\t\t);\n\t},\n\n\tmerge: function(first, second){\n\t\tvar firstConfig = utils.copy(first.getConfig().parsed);\n\n\t\tvar secondConfig = utils.copy(second.getConfig().parsed);\n\n\t\tvar mergedSettings = {\n\t\t\thours: this._toHoursArray(this._mergeHoursConfig(firstConfig.hours, secondConfig.hours)),\n\t\t\tdates: {},\n\t\t\tcustomWeeks: {}\n\t\t};\n\n\t\tconst processCalendar = (config1, config2) => {\n\t\t\tfor (let i in config1.dates) {\n\t\t\t\tconst date1 = config1.dates[i];\n\t\n\t\t\t\t// dates contain day-of-week rules [0-7] and rules for specific dates (js date timestamps) - set false date rules initially\n\t\t\t\tif (+i > 1000) {\n\t\t\t\t\tmergedSettings.dates[i] = false;\n\t\t\t\t}\n\t\t\t\t// Check if the key exists in the fisrt calendar object\n\t\t\t\tfor (const key in config2.dates) {\n\t\t\t\t\tconst date2 = config2.dates[key];\n\t\n\t\t\t\t\t// Logical AND for week days\n\t\t\t\t\tif (key == i) {\n\t\t\t\t\t\tmergedSettings.dates[i] = !!(date1 && date2);\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Handle case where dates are arrays\n\t\t\t\t\tif (Array.isArray(date1)) {\n\t\t\t\t\t\tconst hours2 = Array.isArray(date2) ? date2 : config2.hours;\n\t\t\t\t\t\tmergedSettings.dates[i] = this._toHoursArray(this._mergeHoursConfig(date1, hours2));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Check both calendars\n\t\tprocessCalendar(firstConfig, secondConfig);\n\t\tprocessCalendar(secondConfig, firstConfig);\n\n\t\t// transfer and overwrite custom week calendars\n\t\tif(firstConfig.customWeeks){\n\t\t\tfor(var i in firstConfig.customWeeks){\n\t\t\t\tmergedSettings.customWeeks[i] = firstConfig.customWeeks[i];\n\t\t\t}\n\t\t}\n\t\tif(secondConfig.customWeeks){\n\t\t\tfor(var i in secondConfig.customWeeks){\n\t\t\t\tmergedSettings.customWeeks[i] = secondConfig.customWeeks[i];\n\t\t\t}\n\t\t}\n\n\t\treturn mergedSettings;\n\n\t}\n\n};\n\nexport default WorkTimeCalendarMerger;","\n\nimport { IWorkUnitCache } from \"./workunit_cache_interface\";\n\nexport class WorkUnitsMapCache implements IWorkUnitCache {\n\tprivate _cache: Map>>;\n\tconstructor() {\n\t\tthis.clear();\n\t}\n\n\tgetItem(unit: string, timestamp: string, value: Date): number|boolean {\n\t\tif (this._cache.has(unit)) {\n\t\t\tconst unitCache = this._cache.get(unit);\n\n\t\t\tconst subCache = unitCache[value.getFullYear()];\n\t\t\tif (subCache && subCache.has(timestamp)) {\n\t\t\t\treturn subCache.get(timestamp);\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t}\n\tsetItem(unit: string, timestamp: string, value: boolean, rawValue: Date): void {\n\t\tif (!unit || !timestamp) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst cache = this._cache;\n\t\tconst year = rawValue.getFullYear();\n\n\t\tlet unitCache;\n\t\tif (!cache.has(unit)) {\n\t\t\tunitCache = [];\n\t\t\tcache.set(unit, unitCache);\n\t\t} else {\n\t\t\tunitCache = cache.get(unit);\n\t\t}\n\n\t\tlet yearCache = unitCache[year];\n\t\tif(!yearCache){\n\t\t\tyearCache = unitCache[year] = new Map();\n\t\t}\n\n\n\t\tyearCache.set(timestamp, value);\n\t}\n\tclear(): void{\n\t\tthis._cache = new Map>>();\n\t}\n}","import { IWorkUnitCache } from \"./workunit_cache_interface\";\n\nexport class WorkUnitsObjectCache implements IWorkUnitCache {\n\tprivate _cache: any;\n\tconstructor() {\n\t\tthis.clear();\n\t}\n\n\tgetItem(unit: string, timestamp: string, value: Date): number|boolean {\n\t\tconst cache = this._cache;\n\t\tif (cache && cache[unit]) {\n\t\t\tconst units = cache[unit];\n\t\t\tif(units === undefined){\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tconst subCache = units[value.getFullYear()];\n\t\t\tif (subCache && subCache[timestamp] !== undefined) {\n\t\t\t\treturn subCache[timestamp];\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t}\n\tsetItem(unit: string, timestamp: string, value: boolean, rawValue: Date): void {\n\t\tif (!unit || !timestamp) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst cache = this._cache;\n\n\t\tif (!cache) {\n\t\t\treturn;\n\t\t}\n\t\tif (!cache[unit]) {\n\t\t\tcache[unit] = [];\n\t\t}\n\t\tconst unitCache = cache[unit];\n\n\t\tconst year = rawValue.getFullYear();\n\t\tlet yearCache = unitCache[year];\n\t\tif(!yearCache){\n\t\t\tyearCache = unitCache[year] = {};\n\t\t}\n\t\tyearCache[timestamp] = value;\n\t}\n\tclear(): void{\n\t\tthis._cache = {};\n\t}\n}","\n\nexport class LargerUnitsCache {\n\tprivate _weekCache: Map;\n\tprivate _monthCache: Map;\n\tprivate _calendar: any;\n\tconstructor(calendar) {\n\t\tthis.clear();\n\t\tthis._calendar = calendar;\n\t}\n\n\tgetMinutesPerWeek = (weekStart: Date) => {\n\t\tconst key = weekStart.valueOf();\n\n\t\tif(this._weekCache.has(key)){\n\t\t\treturn this._weekCache.get(key);\n\t\t}\n\n\t\tconst calendar = this._calendar;\n\t\tconst gantt = this._calendar.$gantt;\n\n\t\tlet minutesPerWeek = 0;\n\t\tlet start = gantt.date.week_start(new Date(weekStart));\n\t\tfor(let i = 0; i < 7; i++){\n\t\t\tminutesPerWeek += calendar.getHoursPerDay(start) * 60;\n\t\t\tstart = gantt.date.add(start, 1, \"day\");\n\t\t}\n\n\t\tthis._weekCache.set(key, minutesPerWeek);\n\t\treturn minutesPerWeek;\n\t};\n\n\tgetMinutesPerMonth = (monthStart: Date) => {\n\t\tconst key = monthStart.valueOf();\n\n\t\tif(this._monthCache.has(key)){\n\t\t\treturn this._monthCache.get(key);\n\t\t}\n\n\t\tconst calendar = this._calendar;\n\t\tconst gantt = this._calendar.$gantt;\n\n\t\tlet minutesPerMonth = 0;\n\t\tlet start = gantt.date.week_start(new Date(monthStart));\n\t\tconst nextMonth = gantt.date.add(start, 1, \"month\").valueOf();\n\t\twhile(start.valueOf() < nextMonth){\n\t\t\tminutesPerMonth += calendar.getHoursPerDay(start) * 60;\n\t\t\tstart = gantt.date.add(start, 1, \"day\");\n\t\t}\n\n\t\tthis._monthCache.set(key, minutesPerMonth);\n\t\treturn minutesPerMonth;\n\t};\n\n\tclear = (): void => {\n\t\tthis._weekCache = new Map();\n\t\tthis._monthCache = new Map();\n\t};\n}","export class DateDurationCache {\n\tprivate _cache: any;\n\tconstructor() {\n\t\tthis.clear();\n\t}\n\n\t_getCacheObject(startDate: Date, unit: string, step:number){\n\t\tconst cache = this._cache;\n\t\tif (!cache[unit]) {\n\t\t\tcache[unit] = [];\n\t\t}\n\t\tlet unitCache = cache[unit];\n\t\tif(!unitCache) {\n\t\t\tunitCache = cache[unit] = {};\n\t\t}\n\n\t\tlet stepCache = unitCache[step];\n\t\tif(!stepCache) {\n\t\t\tstepCache = unitCache[step] = {};\n\t\t}\n\n\t\tconst year = startDate.getFullYear();\n\t\tlet yearCache = stepCache[year];\n\t\tif(!yearCache){\n\t\t\tyearCache = stepCache[year] = {durations: {}, endDates: {}};\n\t\t}\n\n\t\treturn yearCache;\n\t}\n\t_endDateCacheKey(startDate: number, duration: number){\n\t\treturn String(startDate) + \"-\" + String(duration);\n\t}\n\t_durationCacheKey(startDate: number, endDate: number){\n\t\treturn String(startDate) + \"-\" + String(endDate);\n\t}\n\tgetEndDate(startDate: Date, duration: number, unit: string, step: number, compute: () => Date): number|null{\n\t\tconst cache = this._getCacheObject(startDate, unit, step);\n\n\t\tconst startDateTimestamp = startDate.valueOf();\n\t\tconst key = this._endDateCacheKey(startDateTimestamp, duration);\n\t\tlet endDate;\n\t\tif(cache.endDates[key] === undefined){\n\t\t\tconst result = compute();\n\t\t\tconst resultTimestamp = result.valueOf();\n\t\t\tcache.endDates[key] = resultTimestamp;\n\t\t\tcache.durations[this._durationCacheKey(startDateTimestamp, resultTimestamp)] = duration;\n\t\t\tendDate = result;\n\t\t}else{\n\t\t\tendDate = new Date(cache.endDates[key]);\n\t\t}\n\n\t\treturn endDate;\n\t}\n\n\tgetDuration(startDate: Date, endDate: Date, unit: string, step: number, compute: () => number): number|null{\n\t\tconst cache = this._getCacheObject(startDate, unit, step);\n\n\t\tconst startDateTimestamp = startDate.valueOf();\n\t\tconst endDateTimestamp = endDate.valueOf();\n\t\tconst key = this._durationCacheKey(startDateTimestamp, endDateTimestamp);\n\t\tlet duration;\n\t\tif(cache.durations[key] === undefined){\n\t\t\tconst result = compute();\n\t\t\tcache.durations[key] = result.valueOf();\n\n\t\t\t// can't populate end date due to logic of end date calculation, current unit tests capture it\n\t\t\t// cache.endDates[this._endDateCacheKey(startDateTimestamp, result)] = endDateTimestamp;\n\t\t\tduration = result;\n\t\t}else{\n\t\t\tduration = cache.durations[key];\n\t\t}\n\n\t\treturn duration;\n\t}\n\n\tclear(): void{\n\t\tthis._cache = {};\n\t}\n}","import {createCacheObject} from \"./work_unit_cache\";\nimport {LargerUnitsCache} from \"./work_unit_cache\";\nimport * as utils from \"../../../utils/utils\";\nimport {DateDurationCache} from \"./work_unit_cache/date_duration_cache\";\n\nfunction CalendarWorkTimeStrategy(gantt, argumentsHelper) {\n\tthis.argumentsHelper = argumentsHelper;\n\tthis.$gantt = gantt;\n\tthis._workingUnitsCache = createCacheObject();\n\tthis._largeUnitsCache = new LargerUnitsCache(this);\n\tthis._dateDurationCache = new DateDurationCache();\n\tthis._worktime = null;\n\tthis._cached_timestamps = {};\n\tthis._cached_timestamps_count = 0;\n}\n\nCalendarWorkTimeStrategy.prototype = {\n\tunits: [\n\t\t\"year\",\n\t\t\"month\",\n\t\t\"week\",\n\t\t\"day\",\n\t\t\"hour\",\n\t\t\"minute\"\n\t],\n\t_clearCaches: function(){\n\t\tthis._workingUnitsCache.clear();\n\t\tthis._largeUnitsCache.clear();\n\t\tthis._dateDurationCache.clear();\n\t},\n\t// cache previously calculated worktime\n\t_getUnitOrder: function (unit) {\n\t\tfor (var i = 0, len = this.units.length; i < len; i++) {\n\t\t\tif (this.units[i] == unit)\n\t\t\t\treturn i;\n\t\t}\n\t},\n\t_resetTimestampCache: function(){\n\t\tthis._cached_timestamps = {};\n\t\tthis._cached_timestamps_count = 0;\n\t},\n\t_timestamp: function (settings) {\n\t\t// minor optimization, store calculated timestamps to reduce computations\n\t\t// reset cache when number of keys exceeds large number where key lookup may became more expensive than the recalculation\n\t\tif(this._cached_timestamps_count > 1000000){\n\t\t\tthis._resetTimestampCache();\n\t\t}\n\n\t\tvar timestamp = null;\n\t\tif ((settings.day || settings.day === 0)) {\n\t\t\ttimestamp = settings.day;\n\t\t} else if (settings.date) {\n\t\t\tvar value = String(settings.date.valueOf());\n\t\t\tif(this._cached_timestamps[value]){\n\t\t\t\ttimestamp = this._cached_timestamps[value];\n\t\t\t}else{\n\t\t\t\t// store worktime datestamp in utc so it could be recognized in different timezones (e.g. opened locally and sent to the export service in different timezone)\n\t\t\t\ttimestamp = Date.UTC(settings.date.getFullYear(), settings.date.getMonth(), settings.date.getDate());\n\t\t\t\tthis._cached_timestamps[value] = timestamp;\n\t\t\t\tthis._cached_timestamps_count++;\n\t\t\t}\n\n\t\t}\n\t\treturn timestamp;\n\t},\n\t_checkIfWorkingUnit: function (date, unit) {\n\t\t// GS-596: If unit is larger than day or has a custom logic\n\t\tif (!this[\"_is_work_\" + unit]) {\n\t\t\tconst from = this.$gantt.date[`${unit}_start`](new Date(date));\n\t\t\tconst to = this.$gantt.date.add(from, 1, unit);\n\t\t\treturn this.hasDuration(from, to);\n\t\t}\n\t\treturn this[\"_is_work_\" + unit](date);\n\t},\n\t//checkings for particular time units\n\t//methods for month-year-week can be defined, otherwise always return 'true'\n\t_is_work_day: function (date) {\n\t\tvar val = this._getWorkHours(date);\n\n\t\tif (Array.isArray(val)) {\n\t\t\treturn val.length > 0;\n\t\t}\n\t\treturn false;\n\t},\n\t_is_work_hour: function (date) {\n\t\tvar hours = this._getWorkHours(date); // [{start: 8*60*60, end: 12*60*60}, {start: 13*60*60, end: 17*60*60}]\n\t\tvar value = date.getHours();\n\t\tfor (var i = 0; i < hours.length; i++) {\n\t\t\tif(value >= hours[i].startHour && value < hours[i].endHour){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t},\n\n\t_getTimeOfDayStamp: function(date, dayEnd) {\n\t\tvar hours = date.getHours();\n\t\tif(!date.getHours() && !date.getMinutes() && dayEnd){\n\t\t\thours = 24;\n\t\t}\n\t\treturn hours * 60 * 60 + date.getMinutes() * 60;\n\t},\n\n\t_is_work_minute: function(date){\n\t\tvar hours = this._getWorkHours(date); // [{start: 8*60*60, end: 12*60*60}, {start: 13*60*60, end: 17*60*60}]\n\t\tvar checkTime = this._getTimeOfDayStamp(date);\n\t\tfor (var i = 0; i < hours.length; i++) {\n\t\t\tif(checkTime >= hours[i].start && checkTime < hours[i].end){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t},\n\n\t_nextDate: function (start, unit, step) {\n\t\treturn this.$gantt.date.add(start, step, unit);\n\t},\n\t_getWorkUnitsBetweenGeneric: function (from, to, unit, step) {\n\t\tvar dateHelper = this.$gantt.date;\n\t\tvar start = new Date(from),\n\t\t\tend = new Date(to);\n\t\tstep = step || 1;\n\t\tvar units = 0;\n\n\n\t\tvar next = null;\n\t\tvar stepStart,\n\t\t\tstepEnd;\n\n\t\t// calculating decimal durations, i.e. 2016-09-20 00:05:00 - 2016-09-20 01:00:00 ~ 0.95 instead of 1\n\t\t// and also 2016-09-20 00:00:00 - 2016-09-20 00:05:00 ~ 0.05 instead of 1\n\t\t// durations must be rounded later\n\t\tvar checkFirst = false;\n\t\tstepStart = dateHelper[unit + \"_start\"](new Date(start));\n\t\tif (stepStart.valueOf() != start.valueOf()) {\n\t\t\tcheckFirst = true;\n\t\t}\n\t\tvar checkLast = false;\n\t\tstepEnd = dateHelper[unit + \"_start\"](new Date(to));\n\t\tif (stepEnd.valueOf() != to.valueOf()) {\n\t\t\tcheckLast = true;\n\t\t}\n\n\t\tvar isLastStep = false;\n\t\twhile (start.valueOf() < end.valueOf()) {\n\t\t\tnext = this._nextDate(start, unit, step);\n\t\t\tisLastStep = (next.valueOf() > end.valueOf());\n\n\t\t\tif (this._isWorkTime(start, unit)) {\n\t\t\t\tif (checkFirst || (checkLast && isLastStep)) {\n\t\t\t\t\tstepStart = dateHelper[unit + \"_start\"](new Date(start));\n\t\t\t\t\tstepEnd = dateHelper.add(stepStart, step, unit);\n\t\t\t\t}\n\n\t\t\t\tif (checkFirst) {\n\t\t\t\t\tcheckFirst = false;\n\t\t\t\t\tnext = this._nextDate(stepStart, unit, step);\n\t\t\t\t\tunits += ((stepEnd.valueOf() - start.valueOf()) / (stepEnd.valueOf() - stepStart.valueOf()));\n\t\t\t\t} else if (checkLast && isLastStep) {\n\t\t\t\t\tcheckLast = false;\n\t\t\t\t\tunits += ((end.valueOf() - start.valueOf()) / (stepEnd.valueOf() - stepStart.valueOf()));\n\n\t\t\t\t} else {\n\t\t\t\t\tunits++;\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tvar unitOrder = this._getUnitOrder(unit);\n\t\t\t\tvar biggerTimeUnit = this.units[unitOrder - 1];\n\t\t\t\tif(biggerTimeUnit && !this._isWorkTime(start, biggerTimeUnit)){\n\t\t\t\t\tnext = this._getClosestWorkTimeFuture(start, biggerTimeUnit);\n\t\t\t\t}\n\t\t\t}\n\t\t\tstart = next;\n\t\t}\n\t\treturn units;\n\t},\n\n\t_getMinutesPerHour: function (date) {\n\t\tvar hourStart = this._getTimeOfDayStamp(date);\n\t\tvar hourEnd = this._getTimeOfDayStamp(this._nextDate(date, \"hour\", 1));\n\t\tif (hourEnd === 0){\n\t\t\thourEnd = 24 * 60 * 60;\n\t\t}\n\t\tvar worktimes = this._getWorkHours(date);\n\n\t\tfor(var i = 0; i < worktimes.length; i++){\n\t\t\tvar interval = worktimes[i];\n\t\t\tif(hourStart >= interval.start && hourEnd <= interval.end){\n\t\t\t\treturn 60;// hour inside a working interval, all hour is a work hour\n\t\t\t}else if(hourStart < interval.end && hourEnd > interval.start){\n\t\t\t\t// hour is partially work time\n\t\t\t\tvar duration = Math.min(hourEnd, interval.end) - Math.max(hourStart, interval.start);\n\t\t\t\treturn duration / 60;\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t},\n\n\t_getMinutesPerDay: function (date) {\n\t\tvar hours = this._getWorkHours(date);\n\t\tvar res = 0;\n\t\thours.forEach(function(interval){\n\t\t\tres+= interval.durationMinutes;\n\t\t});\n\t\treturn res;\n\t},\n\tgetHoursPerDay: function (date) {\n\t\tvar hours = this._getWorkHours(date);\n\t\tvar res = 0;\n\t\thours.forEach(function(interval){\n\t\t\tres+= interval.durationHours;\n\t\t});\n\t\treturn res;\n\t},\n\t_getWorkUnitsForRange: function (from, to, unit, step) {\n\t\tvar total = 0;\n\t\tvar start = new Date(from),\n\t\t\tend = new Date(to);\n\n\t\tvar getUnitsPerDay;\n\t\tif (unit == \"minute\") {\n\t\t\tgetUnitsPerDay = utils.bind(this._getMinutesPerDay, this);\n\t\t} else {\n\t\t\tgetUnitsPerDay = utils.bind(this.getHoursPerDay, this);\n\t\t}\n\n\t\twhile (start.valueOf() < end.valueOf()) {\n\t\t\tif(end - start > 1000*60*60*24*32 && start.getDate() === 0) {\n\t\t\t\tvar units = this._largeUnitsCache.getMinutesPerMonth(start);\n\t\t\t\tif(unit == \"hour\"){\n\t\t\t\t\tunits = units / 60;\n\t\t\t\t}\n\t\t\t\ttotal += units;\n\t\t\t\tstart = this.$gantt.date.add(start, 1, \"month\");\n\t\t\t\tcontinue;\n\t\t\t}else if(end - start > 1000*60*60*24*16) {\n\t\t\t\tvar weekStart = this.$gantt.date.week_start(new Date(start));\n\t\t\t\tif(start.valueOf() === weekStart.valueOf()){\n\t\t\t\t\tvar units = this._largeUnitsCache.getMinutesPerWeek(start);\n\t\t\t\t\tif(unit == \"hour\"){\n\t\t\t\t\t\tunits = units / 60;\n\t\t\t\t\t}\n\t\t\t\t\ttotal += units;\n\t\t\t\t\tstart = this.$gantt.date.add(start, 7, \"day\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t//\tif (this._isWorkTime(start, \"day\")) {\n\t\t\ttotal += getUnitsPerDay(start);\n\t\t//\t}\n\t\t\tstart = this._nextDate(start, \"day\", 1);\n\t\t}\n\n\t\treturn total / step;\n\t},\n\n\n\t_getMinutesBetweenSingleDay: function(from, to){\n\t\tvar range = this._getIntervalTimestamp(from, to);\n\t\tvar worktimes = this._getWorkHours(from);\n\t\tvar result = 0;\n\n\t\tfor(var i = 0; i < worktimes.length; i++){\n\t\t\tvar interval = worktimes[i];\n\t\t\tif(range.end >= interval.start && range.start <= interval.end){\n\t\t\t\tvar minuteFrom = Math.max(interval.start, range.start);\n\t\t\t\tvar minuteTo = Math.min(interval.end, range.end);\n\n\t\t\t\tresult += (minuteTo - minuteFrom) / 60;\n\t\t\t\trange.start = minuteTo;\n\t\t\t}\n\t\t}\n\n\t\treturn Math.floor(result);\n\t},\n\n\t_getMinutesBetween: function(from, to, unit, step){\n\t\tvar start = new Date(from),\n\t\t\tend = new Date(to);\n\t\tstep = step || 1;\n\n\t\tvar firstDayStart = new Date(start);\n\t\tvar firstDayEnd = this.$gantt.date.add(this.$gantt.date.day_start(new Date(start)), 1, \"day\");\n\n\t\tif (end.valueOf() <= firstDayEnd.valueOf()) {\n\t\t\treturn this._getMinutesBetweenSingleDay(from, to);\n\t\t} else {\n\n\t\t\tvar lastDayStart = this.$gantt.date.day_start(new Date(end));\n\t\t\tvar lastDayEnd = end;\n\n\t\t\tvar startPart = this._getMinutesBetweenSingleDay(firstDayStart, firstDayEnd);\n\t\t\tvar endPart = this._getMinutesBetweenSingleDay(lastDayStart, lastDayEnd);\n\n\t\t\tvar rangePart = this._getWorkUnitsForRange(firstDayEnd, lastDayStart, unit, step);\n\t\t\tvar total = startPart + rangePart + endPart;\n\n\t\t\treturn total;\n\t\t}\n\t},\n\t// optimized method for calculating work units duration of large time spans\n\t// implemented for hours and minutes units, bigger time units don't benefit from the optimization so much\n\t_getHoursBetween: function (from, to, unit, step) {\n\t\tvar start = new Date(from),\n\t\t\tend = new Date(to);\n\t\tstep = step || 1;\n\n\t\tvar firstDayStart = new Date(start);\n\t\tvar firstDayEnd = this.$gantt.date.add(this.$gantt.date.day_start(new Date(start)), 1, \"day\");\n\n\t\tif (end.valueOf() <= firstDayEnd.valueOf()) {\n\t\t\treturn Math.round(this._getMinutesBetweenSingleDay(from, to) / 60);\n\t\t} else {\n\n\t\t\tvar lastDayStart = this.$gantt.date.day_start(new Date(end));\n\t\t\tvar lastDayEnd = end;\n\n\t\t\tvar startPart = this._getMinutesBetweenSingleDay(firstDayStart, firstDayEnd, unit, step) / 60;\n\t\t\tvar endPart = this._getMinutesBetweenSingleDay(lastDayStart, lastDayEnd, unit, step) / 60;\n\n\t\t\tvar rangePart = this._getWorkUnitsForRange(firstDayEnd, lastDayStart, unit, step);\n\t\t\tvar total = startPart + rangePart + endPart;\n\n\t\t\treturn Math.round(total);\n\t\t}\n\t},\n\n\tgetConfig: function () {\n\t\treturn this._worktime;\n\t},\n\t_setConfig: function (settings) {\n\t\tthis._worktime = settings;\n\t\tthis._parseSettings();\n\t\tthis._clearCaches();\n\t},\n\t_parseSettings: function() {\n\t\tvar settings = this.getConfig();\n\t\tsettings.parsed = {\n\t\t\tdates: {},\n\t\t\thours: null,\n\t\t\thaveCustomWeeks: false,\n\t\t\tcustomWeeks: {},\n\t\t\tcustomWeeksRangeStart: null,\n\t\t\tcustomWeeksRangeEnd: null,\n\t\t\tcustomWeeksBoundaries: []\n\t\t};\n\n\t\tsettings.parsed.hours = this._parseHours(settings.hours);\n\t\tfor(var i in settings.dates){\n\t\t\tsettings.parsed.dates[i] = this._parseHours(settings.dates[i]);\n\t\t}\n\n\t\tif(settings.customWeeks) {\n\t\t\tvar minCustomRangeStart = null;\n\t\t\tvar maxCustomRangeEnd = null;\n\t\t\tfor(var i in settings.customWeeks){\n\t\t\t\tvar customTime = settings.customWeeks[i];\n\n\t\t\t\tif(customTime.from && customTime.to){\n\t\t\t\t\tvar rangeStart = customTime.from;\n\t\t\t\t\tvar rangeEnd = customTime.to;\n\t\t\t\t\tif(!minCustomRangeStart || minCustomRangeStart > rangeStart.valueOf()){\n\t\t\t\t\t\tminCustomRangeStart = rangeStart.valueOf();\n\t\t\t\t\t}\n\t\t\t\t\tif(!maxCustomRangeEnd || maxCustomRangeEnd < rangeEnd.valueOf()){\n\t\t\t\t\t\tmaxCustomRangeEnd = rangeEnd.valueOf();\n\t\t\t\t\t}\n\n\t\t\t\t\tsettings.parsed.customWeeksBoundaries.push({\n\t\t\t\t\t\tfrom: rangeStart.valueOf(),\n\t\t\t\t\t\tfromReadable: new Date(rangeStart),\n\t\t\t\t\t\tto: rangeEnd.valueOf(),\n\t\t\t\t\t\ttoReadable: new Date(rangeEnd),\n\t\t\t\t\t\tname: i\n\t\t\t\t\t});\n\n\t\t\t\t\tsettings.parsed.haveCustomWeeks = true;\n\t\t\t\t\tvar currentWeek = settings.parsed.customWeeks[i] = {\n\t\t\t\t\t\tfrom: customTime.from,\n\t\t\t\t\t\tto: customTime.to,\n\t\t\t\t\t\thours: this._parseHours(customTime.hours),\n\t\t\t\t\t\tdates: {}\n\t\t\t\t\t};\n\n\t\t\t\t\tfor(var d in customTime.dates){\n\t\t\t\t\t\tcurrentWeek.dates[d] = this._parseHours(customTime.dates[d]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsettings.parsed.customWeeksRangeStart = minCustomRangeStart;\n\t\t\tsettings.parsed.customWeeksRangeEnd = maxCustomRangeEnd;\n\n\t\t}\n\t},\n\n\t_tryChangeCalendarSettings: function (payload) {\n\t\tvar backup = JSON.stringify(this.getConfig());\n\t\tpayload();\n\t\tif (!this.hasWorkTime()) {\n\t\t//\tthis.$gantt.assert(false, \"Invalid calendar settings, no worktime available\");\n\t\t\tthis._setConfig(JSON.parse(backup));\n\t\t\tthis._clearCaches();\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\n\t},\n\n\t_arraysEqual: function(a, b){\n\t\tif (a === b) return true;\n\t\tif (!a || !b) return false;\n\t\tif (a.length != b.length) return false;\n\n\t\tfor (var i = 0; i < a.length; ++i) {\n\t\t\tif (a[i] !== b[i]) return false;\n\t\t}\n\t\treturn true;\n\t},\n\n\n\t_compareSettings: function (mySettings, thatSettings) {\n\t\tif (!this._arraysEqual(mySettings.hours, thatSettings.hours)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar myDays = Object.keys(mySettings.dates);\n\t\tvar otherDates = Object.keys(thatSettings.dates);\n\t\tmyDays.sort();\n\t\totherDates.sort();\n\n\t\tif (!this._arraysEqual(myDays, otherDates)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor(var i = 0; i < myDays.length; i++){\n\t\t\tvar timestamp = myDays[i];\n\t\t\tvar myHours = mySettings.dates[timestamp];\n\t\t\tvar otherHours = mySettings.dates[timestamp];\n\n\t\t\t// day settings not equal\n\t\t\tif(myHours !== otherHours &&\n\t\t\t\t// but still can be two arrays with the equivalent hour settings\n\t\t\t\t!(Array.isArray(myHours) && Array.isArray(otherHours) && this._arraysEqual(myHours, otherHours))\n\t\t\t\t){\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t},\n\n\tequals: function (calendar) {\n\t\tif(!(calendar instanceof CalendarWorkTimeStrategy)){\n\t\t\treturn false;\n\t\t}\n\n\t\tvar mySettings = this.getConfig();\n\t\tvar thatSettings = calendar.getConfig();\n\n\t\tif(!this._compareSettings(mySettings, thatSettings)){\n\t\t\treturn false;\n\t\t}\n\n\t\tif(mySettings.parsed.haveCustomWeeks && thatSettings.parsed.haveCustomWeeks){\n\t\t\tif(mySettings.parsed.customWeeksBoundaries.length != thatSettings.parsed.customWeeksBoundaries.length){\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor(var i in mySettings.parsed.customWeeks){\n\t\t\t\tvar myWeek = mySettings.parsed.customWeeks[i];\n\t\t\t\tvar thatWeek = thatSettings.parsed.customWeeks[i];\n\t\t\t\tif(!thatWeek){\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif(!this._compareSettings(myWeek, thatWeek)){\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}else if(mySettings.parse.haveCustomWeeks !== thatSettings.parsed.haveCustomWeeks){\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t},\n\n\tgetWorkHours: function () {\n\t\tvar config = this.argumentsHelper.getWorkHoursArguments.apply(this.argumentsHelper, arguments);\n\t\treturn this._getWorkHours(config.date, false);\n\t},\n\t_getWorkHours: function (date, parsed) {\n\t\tvar calendar = this.getConfig();\n\t\tif(parsed !== false){\n\t\t\tcalendar = calendar.parsed;\n\t\t}\n\n\t\tif(!date){\n\t\t\treturn calendar.hours;\n\t\t}\n\n\t\tvar dateValue = this._timestamp({date: date});\n\n\t\tif(calendar.haveCustomWeeks){\n\t\t\tif(calendar.customWeeksRangeStart <= dateValue && calendar.customWeeksRangeEnd > dateValue){\n\t\t\t\tfor(var i = 0; i < calendar.customWeeksBoundaries.length; i++){\n\t\t\t\t\tif(calendar.customWeeksBoundaries[i].from <= dateValue && calendar.customWeeksBoundaries[i].to > dateValue){\n\t\t\t\t\t\tcalendar = calendar.customWeeks[calendar.customWeeksBoundaries[i].name];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvar hours = true;\n\n\t\tif (calendar.dates[dateValue] !== undefined) {\n\t\t\thours = calendar.dates[dateValue];//custom day\n\t\t} else if (calendar.dates[date.getDay()] !== undefined) {\n\t\t\thours = calendar.dates[date.getDay()];//week day\n\t\t}\n\t\tif (hours === true) {\n\t\t\treturn calendar.hours;\n\t\t} else if (hours) {\n\t\t\treturn hours;\n\t\t}\n\t\treturn [];\n\t},\n\n\t_getIntervalTimestamp: function(from, to){\n\t\tvar res = {\n\t\t\tstart: 0,\n\t\t\tend: 0\n\t\t};\n\n\t\tres.start = from.getHours() * 60 * 60 + from.getMinutes() * 60 + from.getSeconds();\n\t\tvar endHours = to.getHours();\n\t\tif(!endHours && !to.getMinutes() && !to.getSeconds() && from.valueOf() < to.valueOf()){\n\t\t\tendHours = 24;\n\t\t}\n\t\tres.end = endHours * 60 * 60 + to.getMinutes() * 60 + to.getSeconds();\n\t\treturn res;\n\t},\n\n\t_parseHours: function(hours) {\n\t\tif(Array.isArray(hours)){\n\n\t\t\tvar timestampRanges = [];// worktime as seconds range\n\t\t\thours.forEach(function(hour){\n\t\t\t\tif(typeof hour === \"number\"){\n\t\t\t\t\ttimestampRanges.push(hour*60*60);\n\t\t\t\t}else if(typeof hour === \"string\") {\n\t\t\t\t\t// \"12-13\", or \"12:00-13:00\", or \"12:00:00-13:00:00\"\n\t\t\t\t\thour.split(\"-\").map(function(time){\n\t\t\t\t\t\treturn time.trim();\n\t\t\t\t\t}).forEach(function(part){\n\t\t\t\t\t\tvar parsed = part.split(\":\").map(function(time){\n\t\t\t\t\t\t\treturn time.trim();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tvar value = parseInt(parsed[0]*60*60);\n\t\t\t\t\t\tif(parsed[1]){\n\t\t\t\t\t\t\tvalue += parseInt(parsed[1]*60);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(parsed[2]){\n\t\t\t\t\t\t\tvalue += parseInt(parsed[2]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttimestampRanges.push(value);\n\t\t\t\t\t});\n\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar timerangeConfig = [];\n\t\t\tfor (var i = 0; i < timestampRanges.length; i += 2) {\n\t\t\t\tvar start = timestampRanges[i];\n\t\t\t\tvar end = timestampRanges[i + 1];\n\t\t\t\tvar duration = end - start;\n\n\t\t\t\ttimerangeConfig.push({\n\t\t\t\t\tstart: start,\n\t\t\t\t\tend: end,\n\t\t\t\t\tstartHour: Math.floor(start / (60*60)),\n\t\t\t\t\tstartMinute: Math.floor(start / (60)),\n\t\t\t\t\tendHour: Math.ceil(end / (60*60)),\n\t\t\t\t\tendMinute: Math.ceil(end / (60)),\n\t\t\t\t\tdurationSeconds: duration,\n\t\t\t\t\tdurationMinutes: duration/60,\n\t\t\t\t\tdurationHours: duration/(60 * 60)\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn timerangeConfig;\n\t\t} else {\n\t\t\treturn hours;\n\t\t}\n\t},\n\n\tsetWorkTime: function (settings) {\n\t\treturn this._tryChangeCalendarSettings(utils.bind(function () {\n\t\t\tvar hours = settings.hours !== undefined ? settings.hours : true;\n\t\t\tvar timestamp = this._timestamp(settings);\n\t\t\tvar calendarConfig = this.getConfig();\n\t\t\tif (timestamp !== null) {\n\t\t\t\tcalendarConfig.dates[timestamp] = hours;\n\t\t\t} else if(!settings.customWeeks) {\n\t\t\t\tcalendarConfig.hours = hours;\n\t\t\t}\n\n\t\t\tif(settings.customWeeks){\n\t\t\t\tif(!calendarConfig.customWeeks){\n\t\t\t\t\tcalendarConfig.customWeeks = {};\n\t\t\t\t}\n\t\t\t\t// GS-1867. allow setWorkTime to exclude dates in the customWeeks range\n\t\t\t\tif (typeof settings.customWeeks == \"string\"){\n\t\t\t\t\tif (timestamp !== null) {\n\t\t\t\t\t\tcalendarConfig.customWeeks[settings.customWeeks].dates[timestamp] = hours;\n\t\t\t\t\t} else if(!settings.customWeeks) {\n\t\t\t\t\t\tcalendarConfig.customWeeks[settings.customWeeks].hours = hours;\n\t\t\t\t\t}\t\t\n\t\t\t\t} else if (typeof settings.customWeeks === \"object\"\n\t\t\t\t&& Function.prototype.toString.call(settings.customWeeks.constructor) === \"function Object() { [native code] }\"){\n\t\t\t\t\tfor(var i in settings.customWeeks){\n\t\t\t\t\t\tcalendarConfig.customWeeks[i] = settings.customWeeks[i];\n\t\t\t\t\t}\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._parseSettings();\n\t\t\tthis._clearCaches();\n\t\t}, this));\n\t},\n\n\tunsetWorkTime: function (settings) {\n\t\treturn this._tryChangeCalendarSettings(utils.bind(function () {\n\t\t\tif (!settings) {\n\t\t\t\tthis.reset_calendar();\n\t\t\t} else {\n\n\t\t\t\tvar timestamp = this._timestamp(settings);\n\n\t\t\t\tif (timestamp !== null) {\n\t\t\t\t\tdelete this.getConfig().dates[timestamp];\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Load updated settings and clear work units cache\n\t\t\tthis._parseSettings();\n\t\t\tthis._clearCaches();\n\t\t}, this));\n\t},\n\n\t_isWorkTime: function (date, unit) {\n\t\t// Check if this item has in the cache\n\n\t\tvar useCache = true;//unit === \"day\"; // use cache only for days. In case of hours/minutes cache size grows too large and the overhead exceeds the gains\n\t\tvar isWorkUnit = -1;\n\t\tvar dateKey = null;\n\n\t\tif(useCache){\n\t\t\t// use string keys\n\t\t\tdateKey = String(date.valueOf());\n\t\t\tisWorkUnit = this._workingUnitsCache.getItem(unit, dateKey, date);\n\t\t}\n\n\t\tif (isWorkUnit == -1) {\n\t\t\t// calculate if not cached\n\t\t\tisWorkUnit = this._checkIfWorkingUnit(date, unit);\n\t\t\tif(useCache){\n\t\t\t\tthis._workingUnitsCache.setItem(unit, dateKey, isWorkUnit, date);\n\t\t\t}\n\t\t}\n\n\t\treturn isWorkUnit;\n\t},\n\n\tisWorkTime: function () {\n\t\tvar config = this.argumentsHelper.isWorkTimeArguments.apply( this.argumentsHelper, arguments);\n\t\treturn this._isWorkTime(config.date, config.unit);\n\t},\n\n\tcalculateDuration: function () {\n\t\tvar config = this.argumentsHelper.getDurationArguments.apply( this.argumentsHelper, arguments);\n\n\t\tif (!config.unit) {\n\t\t\treturn false;\n\t\t}\n\t\t//return this._calculateDuration(config.start_date, config.end_date, config.unit, config.step);\n\n\t\tvar self = this;\n\t\treturn this._dateDurationCache.getDuration(config.start_date, config.end_date, config.unit, config.step, function(){ \n\t\t\treturn self._calculateDuration(config.start_date, config.end_date, config.unit, config.step);\n\t\t});\n\t},\n\n\t_calculateDuration: function (from, to, unit, step) {\n\t\tvar res = 0;\n\n\t\tvar sign = 1;\n\t\tif(from.valueOf() > to.valueOf()){\n\t\t\tvar tmp = to;\n\t\t\tto = from;\n\t\t\tfrom = tmp;\n\t\t\tsign = -1;\n\t\t}\n\n\t\tif (unit == \"hour\" && step == 1) {\n\t\t\tres = this._getHoursBetween(from, to, unit, step);\n\t\t} else if(unit == \"minute\" && step == 1){\n\t\t\t// quick calculation for minutes with 1 minute step\n\t\t\tres = this._getMinutesBetween(from, to, unit, step);\n\t\t} else {\n\t\t\tres = this._getWorkUnitsBetweenGeneric(from, to, unit, step);\n\t\t}\n\n\t\t// getWorkUnits.. returns decimal durations\n\t\treturn sign * Math.round(res);\n\t},\n\thasDuration: function () {\n\t\tvar config = this.argumentsHelper.getDurationArguments.apply( this.argumentsHelper, arguments);\n\n\t\tvar from = config.start_date,\n\t\t\tto = config.end_date,\n\t\t\tunit = config.unit,\n\t\t\tstep = config.step;\n\n\t\tif (!unit) {\n\t\t\treturn false;\n\t\t}\n\t\tvar start = new Date(from),\n\t\t\tend = new Date(to);\n\t\tstep = step || 1;\n\n\t\twhile (start.valueOf() < end.valueOf()) {\n\t\t\tif (this._isWorkTime(start, unit))\n\t\t\t\treturn true;\n\t\t\tstart = this._nextDate(start, unit, step);\n\t\t}\n\t\treturn false;\n\t},\n\n\tcalculateEndDate: function () {\n\t\tvar config = this.argumentsHelper.calculateEndDateArguments.apply( this.argumentsHelper, arguments);\n\n\t\tvar from = config.start_date,\n\t\t\tduration = config.duration,\n\t\t\tunit = config.unit,\n\t\t\tstep = config.step;\n\n\t\tif (!unit)\n\t\t\treturn false;\n\n\t\tvar mult = (config.duration >= 0) ? 1 : -1;\n\t\tduration = Math.abs(duration * 1);\n\t//\tvar endDate = this._calculateEndDate(from, duration, unit, step * mult);\n\t//\treturn endDate;\n\t\tvar self = this;\n\t\treturn this._dateDurationCache.getEndDate(from, duration, unit, step * mult, function(){ \n\t\t\treturn self._calculateEndDate(from, duration, unit, step * mult);\n\t\t} );\n\t},\n\n\t_calculateEndDate: function (from, duration, unit, step) {\n\t\tif (!unit)\n\t\t\treturn false;\n\n\t\tif (step == 1 && unit == \"minute\") {\n\t\t\treturn this._calculateMinuteEndDate(from, duration, step);\n\t\t} else if(step == -1 && unit == \"minute\") {\n\t\t\treturn this._subtractMinuteDate(from, duration, step);\n\t\t} else if (step == 1 && unit == \"hour\") {\n\t\t\treturn this._calculateHourEndDate(from, duration, step);\n\t\t} else {\n\t\t\tvar interval = this._addInterval(from, duration, unit, step, null);\n\t\t\treturn interval.end;\n\t\t}\n\t},\n\n\t_addInterval: function (start, duration, unit, step, stopAction) {\n\t\tvar added = 0;\n\t\tvar current = start;\n\t\tvar dstShift = false;\n\n\t\twhile (added < duration && !(stopAction && stopAction(current))) {\n\t\t\tvar next = this._nextDate(current, unit, step);\n\n\t\t\t// GS-1501. Correct hours after DST change\n\t\t\tif (unit == \"day\"){\n\t\t\t\tdstShift = dstShift || !current.getHours() && next.getHours();\n\n\t\t\t\tif (dstShift){\n\t\t\t\t\tnext.setHours(0);\n\t\t\t\t\tif (next.getHours()){\n\t\t\t\t\t// the day when the timezone is changed, try to correct hours next time\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdstShift = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar dateValue = new Date(next.valueOf() + 1);\n\t\t\tif (step > 0) {\n\t\t\t\tdateValue = new Date(next.valueOf() - 1);\n\t\t\t}\n\t\t\tvar workTimeCheck = this._isWorkTime(dateValue, unit);\n\n\t\t\tif (workTimeCheck && !dstShift) {\n\t\t\t\tadded++;\n\t\t\t}\n\t\t\tcurrent = next;\n\t\t}\n\t\treturn {\n\t\t\tend: current,\n\t\t\tstart: start,\n\t\t\tadded: added\n\t\t};\n\t},\n\n\t_addHoursUntilDayEnd: function(from, duration) {\n\t\tvar dayEnd = this.$gantt.date.add(this.$gantt.date.day_start(new Date(from)), 1, \"day\");\n\t\tvar added = 0;\n\t\tvar left = duration;\n\n\t\tvar range = this._getIntervalTimestamp(from, dayEnd);\n\t\tvar worktimes = this._getWorkHours(from);\n\t\tfor(var i = 0; i < worktimes.length && added < duration; i++){\n\t\t\tvar interval = worktimes[i];\n\t\t\tif(range.end >= interval.start && range.start <= interval.end){\n\t\t\t\tvar minuteFrom = Math.max(interval.start, range.start);\n\t\t\t\tvar minuteTo = Math.min(interval.end, range.end);\n\t\t\t\tvar rangeHours = (minuteTo - minuteFrom) / (60 * 60);\n\t\t\t\tif(rangeHours > left){\n\t\t\t\t\trangeHours = left;\n\t\t\t\t\tminuteTo = minuteFrom + (left * 60 * 60);\n\t\t\t\t}\n\n\t\t\t\tvar addHours = Math.round((minuteTo - minuteFrom) / (60 * 60));\n\t\t\t\tadded += addHours;\n\t\t\t\tleft -= addHours;\n\t\t\t\trange.start = minuteTo;\n\t\t\t}\n\t\t}\n\n\t\tvar intervalEnd = dayEnd;\n\t\tif(added === duration){\n\t\t\tintervalEnd = new Date(from.getFullYear(), from.getMonth(), from.getDate(), 0, 0, range.start);\n\t\t}\n\t\treturn {\n\t\t\tadded: added,\n\t\t\tend: intervalEnd\n\t\t};\n\t},\n\n\t_calculateHourEndDate: function (from, duration, step) {\n\t\tvar start = new Date(from),\n\t\tadded = 0;\n\t\tstep = step || 1;\n\t\tduration = Math.abs(duration * 1);\n\n\t\tvar interval = this._addHoursUntilDayEnd(start, duration);\n\t\tadded = interval.added;\n\t\tstart = interval.end;\n\n\t\tvar durationLeft = duration - added;\n\n\t\tif (durationLeft) {\n\t\t\tvar current = start;\n\t\t\twhile (added < duration) {\n\t\t\t\tvar next = this._nextDate(current, \"day\", step);\n\t\t\t\t// reset to day start in case DST switch happens in the process\n\t\t\t\tnext.setHours(0);\n\t\t\t\tnext.setMinutes(0);\n\t\t\t\tnext.setSeconds(0);\n\n\t\t\t\tvar hoursPerDay = 0;\n\t\t\t\tif(step > 0){\n\t\t\t\t\thoursPerDay = this.getHoursPerDay(new Date(next.valueOf() - 1));\n\t\t\t\t}else{\n\t\t\t\t\thoursPerDay = this.getHoursPerDay(new Date(next.valueOf() + 1));\n\t\t\t\t}\n\n\t\t\t\tif (added + hoursPerDay >= duration) {\n\t\t\t\t\tbreak;\n\t\t\t\t} else {\n\t\t\t\t\tadded += hoursPerDay;\n\t\t\t\t}\n\n\t\t\t\tcurrent = next;\n\t\t\t}\n\t\t\tstart = current;\n\t\t}\n\n\t\tif (added < duration) {\n\t\t\tvar durationLeft = duration - added;\n\t\t\tinterval = this._addHoursUntilDayEnd(start, durationLeft);\n\t\t\tstart = interval.end;\n\t\t}\n\n\t\treturn start;\n\t},\n\n\t_addMinutesUntilHourEnd: function(from, duration){\n\t\tif(from.getMinutes() === 0) {\n\t\t\t// already at hour end\n\t\t\treturn {\n\t\t\t\tadded: 0,\n\t\t\t\tend: new Date(from)\n\t\t\t};\n\t\t}\n\t\tvar hourEnd = this.$gantt.date.add(this.$gantt.date.hour_start(new Date(from)), 1, \"hour\");\n\t\tvar added = 0;\n\t\tvar left = duration;\n\n\t\tvar range = this._getIntervalTimestamp(from, hourEnd);\n\t\tvar worktimes = this._getWorkHours(from);\n\t\tfor(var i = 0; i < worktimes.length && added < duration; i++){\n\t\t\tvar interval = worktimes[i];\n\t\t\tif(range.end >= interval.start && range.start <= interval.end){\n\t\t\t\tvar minuteFrom = Math.max(interval.start, range.start);\n\t\t\t\tvar minuteTo = Math.min(interval.end, range.end);\n\t\t\t\tvar rangeMinutes = (minuteTo - minuteFrom) / 60;\n\t\t\t\tif(rangeMinutes > left){\n\t\t\t\t\trangeMinutes = left;\n\t\t\t\t\tminuteTo = minuteFrom + (left * 60);\n\t\t\t\t}\n\n\t\t\t\t// TODO: verify testcase https://dhtmlxsupport.teamwork.com/desk/tickets/9625700/messages\n\t\t\t\t/*if (rangeMinutes === 0) {\n\t\t\t\t\trangeMinutes = left;\n\t\t\t\t\tminuteTo = minuteFrom + (left * 60);\n\t\t\t\t}*/\n\n\t\t\t\tvar addMinutes = Math.round((minuteTo - minuteFrom) / 60);\n\t\t\t\tleft -= addMinutes;\n\t\t\t\tadded += addMinutes;\n\t\t\t\trange.start = minuteTo;\n\t\t\t}\n\t\t}\n\n\t\tvar intervalEnd = hourEnd;\n\t\tif(added === duration){\n\t\t\tintervalEnd = new Date(from.getFullYear(), from.getMonth(), from.getDate(), 0, 0, range.start);\n\t\t}\n\t\treturn {\n\t\t\tadded: added,\n\t\t\tend: intervalEnd\n\t\t};\n\t},\n\n\t_subtractMinutesUntilHourStart: function(from, duration){\n\t\tvar hourStart = this.$gantt.date.hour_start(new Date(from));\n\t\tvar added = 0;\n\t\tvar left = duration;\n\n\t\tvar hourStartTimestamp = hourStart.getHours() * 60 * 60 + hourStart.getMinutes() * 60 + hourStart.getSeconds();\n\t\tvar initialDateTimestamp = from.getHours() * 60 * 60 + from.getMinutes() * 60 + from.getSeconds();\n\n\t\tvar worktimes = this._getWorkHours(from);\n\t\tfor(var i = worktimes.length - 1; i >= 0 && added < duration; i--){\n\t\t\tvar interval = worktimes[i];\n\t\t\tif(initialDateTimestamp > interval.start && hourStartTimestamp <= interval.end){\n\t\t\t\tvar minuteFrom = Math.min(initialDateTimestamp, interval.end);\n\t\t\t\tvar minuteTo = Math.max(hourStartTimestamp, interval.start);\n\n\t\t\t//\tvar minuteFrom = Math.max(interval.start, currentHour.start);\n\t\t\t//\tvar minuteTo = Math.min(interval.end, currentHour.end);\n\t\t\t\tvar rangeMinutes = (minuteFrom - minuteTo) / 60;\n\t\t\t\tif(rangeMinutes > left){\n\t\t\t\t\trangeMinutes = left;\n\t\t\t\t\tminuteTo = minuteFrom - (left * 60);\n\t\t\t\t}\n\n\t\t\t\t// TODO: verify testcase https://dhtmlxsupport.teamwork.com/desk/tickets/9625700/messages\n\t\t\t\t/*if (rangeMinutes === 0) {\n\t\t\t\t\trangeMinutes = left;\n\t\t\t\t\tminuteTo = minuteFrom - (left * 60);\n\t\t\t\t}*/\n\n\t\t\t\tvar addMinutes = Math.abs(Math.round((minuteFrom - minuteTo) / 60));\n\t\t\t\tleft -= addMinutes;\n\t\t\t\tadded += addMinutes;\n\t\t\t\tinitialDateTimestamp = minuteTo;\n\t\t\t}\n\t\t}\n\n\t\tvar intervalEnd = hourStart;\n\t\tif(added === duration){\n\t\t\tintervalEnd = new Date(from.getFullYear(), from.getMonth(), from.getDate(), 0, 0, initialDateTimestamp);\n\t\t}\n\t\treturn {\n\t\t\tadded: added,\n\t\t\tend: intervalEnd\n\t\t};\n\t},\n\n\t_subtractMinuteDate: function (from, duration, step) {\n\t\tvar start = new Date(from),\n\t\t\tadded = 0;\n\t\tstep = step || -1;\n\t\tduration = Math.abs(duration * 1);\n\t\tduration = Math.round(duration);\n\n\t\tconst minutePrecision = this._isMinutePrecision(start);\n\n\t\tlet addedInterval = this._subtractMinutesUntilHourStart(start, duration);\n\t\tadded += addedInterval.added;\n\n\t\tstart = addedInterval.end;\n\n\t\tvar calculatedDay = 0;\n\t\tvar daySchedule = [];\n\t\tvar minutesInDay = 0;\n\n\t\twhile (added < duration) {\n\t\t\tvar dayStart = this.$gantt.date.day_start(new Date(start));\n\n\t\t\tvar iterateFromDayEnd = false;\n\t\t\tif(start.valueOf() === dayStart.valueOf()){\n\t\t\t\tdayStart = this.$gantt.date.add(dayStart, -1, \"day\");\n\t\t\t\titerateFromDayEnd = true;\n\t\t\t}\n\t\t\t//var dayStartTimestamp = this.$gantt.date.day_start(new Date(start)).valueOf();\n\t\t\tvar dayEnd = new Date(dayStart.getFullYear(), dayStart.getMonth(), dayStart.getDate(), 23, 59,59,999).valueOf();\n\n\t\t\tif(dayEnd !== calculatedDay){\n\t\t\t\tdaySchedule = this._getWorkHours(dayStart);\n\t\t\t\tminutesInDay = this._getMinutesPerDay(dayStart);\n\t\t\t\tcalculatedDay = dayEnd;\n\t\t\t}\n\n\t\t\tvar left = duration - added;\n\t\t\tvar timestamp = this._getTimeOfDayStamp(start, iterateFromDayEnd);\n\n\t\t\tif(!daySchedule.length || !minutesInDay){\n\t\t\t\tstart = this.$gantt.date.add(start, -1, \"day\");\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(daySchedule[daySchedule.length - 1].end <= timestamp){\n\t\t\t\tif(left > minutesInDay){\n\t\t\t\t\tadded += minutesInDay;\n\t\t\t\t\tstart = this.$gantt.date.add(start, -1, \"day\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar isWorkHour = false;\n\t\t\tvar workInterval = null;\n\t\t\tvar prevInterval = null;\n\t\t\tfor(var i = daySchedule.length - 1; i >= 0; i--){\n\t\t\t\tif(daySchedule[i].start < timestamp - 1 && daySchedule[i].end >= timestamp - 1){\n\t\t\t\t\tisWorkHour = true;\n\t\t\t\t\tworkInterval = daySchedule[i];\n\t\t\t\t\tprevInterval = daySchedule[i-1];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(isWorkHour){\n\n\t\t\t\t// we're at the end of worktime interval and subtracting more than the duration of the interval\n\t\t\t\t// -> subtract the duration of the interval and move to the start of the interval (we're moving from end)\n\t\t\t\tif(timestamp === workInterval.end && left >= workInterval.durationMinutes){\n\t\t\t\t\tadded += workInterval.durationMinutes;\n\t\t\t\t\tstart = this.$gantt.date.add(start, -workInterval.durationMinutes, \"minute\");\n\t\t\t\t} // worktime is set in whole hours (no intervals like 9:15-10:00)\n\t\t\t\t// the amount we need to subtract lies inside the interval\n\t\t\t\telse if(!minutePrecision && left <= (timestamp/60 - workInterval.startMinute)){\n\t\t\t\t\tadded += left;\n\t\t\t\t\tstart = this.$gantt.date.add(start, -left, \"minute\");\n\t\t\t\t}else if (minutePrecision){\n\t\t\t\t\t// GS-2129. If the working time is set in minutes, we accumulate the working time in minutes from right to left\n\t\t\t\t\t\n\t\t\t\t\t// duration we need to subtract lies completely inside the work interval\n\t\t\t\t\tif(left <= (timestamp/60 - workInterval.startMinute)){\n\t\t\t\t\t\tadded += left;\n\t\t\t\t\t\tstart = this.$gantt.date.add(start, -left, \"minute\");\n\t\t\t\t\t}else {\n\t\t\t\t\t\t// we need to go trough multiple work intervals to subtract needed time\n\t\t\t\t\t\tadded += (timestamp/60 - workInterval.startMinute);\n\t\t\t\t\t\tif(prevInterval){\n\t\t\t\t\t\t\tstart = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 0, 0, prevInterval.end);\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tstart = this.$gantt.date.day_start(start);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\n\t\t\t\t}else{\n\t\t\t\t\tvar minutesInHour = this._getMinutesPerHour(start);\n\t\t\t\t\tif(minutesInHour <= left){\n\t\t\t\t\t\tadded += minutesInHour;\n\t\t\t\t\t\tstart = this._nextDate(start, \"hour\", step);\n\t\t\t\t\t}else{\n\t\t\t\t\t\taddedInterval = this._subtractMinutesUntilHourStart(start, left);\n\t\t\t\t\t\tadded += addedInterval.added;\n\t\t\t\t\t\tstart = addedInterval.end;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tif(start.getHours() === 0 && start.getMinutes() === 0 && start.getSeconds() === 0){\n\t\t\t\t\tvar prev = this._getClosestWorkTimePast(start, \"hour\");\n\t\t\t\t\tif(prev.valueOf() === start.valueOf()){\n\t\t\t\t\t\tvar prev = this.$gantt.date.add(start, -1, \"day\");\n\t\t\t\t\t\tvar times = this._getWorkHours(prev);\n\t\t\t\t\t\tif(times.length){\n\t\t\t\t\t\t\tvar lastInterval = times[times.length - 1];\n\t\t\t\t\t\t\tprev.setSeconds(lastInterval.durationSeconds);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tstart = prev;\n\n\t\t\t\t} else{\n\t\t\t\t\tstart = this._getClosestWorkTimePast(new Date(start - 1), \"hour\");\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\tif (added < duration) {\n\t\t\tvar durationLeft = duration - added;\n\t\t\taddedInterval = this._subtractMinutesUntilHourStart(start, durationLeft);\n\t\t\tadded += addedInterval.added;\n\t\t\tstart = addedInterval.end;\n\t\t}\n\n\t\treturn start;\n\t},\n\t_calculateMinuteEndDate: function (from, duration, step) {\n\t\tvar start = new Date(from),\n\t\t\tadded = 0;\n\t\tstep = step || 1;\n\t\tduration = Math.abs(duration * 1);\n\t\tduration = Math.round(duration);\n\n\t\tvar addedInterval = this._addMinutesUntilHourEnd(start, duration);\n\t\tadded += addedInterval.added;\n\n\t\tstart = addedInterval.end;\n\n\t\tvar calculatedDay = 0;\n\t\tvar daySchedule = [];\n\t\tvar minutesInDay = 0;\n\n\t\tvar minutePrecision = this._isMinutePrecision(start);\n\n\t\twhile (added < duration) {\n\t\t\tvar dayStart = this.$gantt.date.day_start(new Date(start)).valueOf();\n\t\t\tif(dayStart !== calculatedDay){\n\t\t\t\tdaySchedule = this._getWorkHours(start);\n\t\t\t\tminutesInDay = this._getMinutesPerDay(start);\n\t\t\t\tcalculatedDay = dayStart;\n\n\t\t\t}\n\n\t\t\tvar left = duration - added;\n\t\t\tvar timestamp = this._getTimeOfDayStamp(start);\n\n\t\t\tif(!daySchedule.length || !minutesInDay){\n\t\t\t\tstart = this.$gantt.date.add(this.$gantt.date.day_start(start), 1, \"day\");\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(daySchedule[0].start >= timestamp){\n\t\t\t\tif(left >= minutesInDay){\n\t\t\t\t\tadded += minutesInDay;\n\t\t\t\t\tif (left == minutesInDay) {\n\t\t\t\t\t\tstart = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 0, 0, daySchedule[daySchedule.length - 1].end);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tstart = this.$gantt.date.add(start, 1, \"day\");\n\t\t\t\t\t\tstart = this.$gantt.date.day_start(start);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar isWorkHour = false;\n\t\t\tvar workInterval = null;\n\t\t\tfor(var i = 0; i < daySchedule.length; i++){\n\t\t\t\tif(daySchedule[i].start <= timestamp && daySchedule[i].end > timestamp){\n\t\t\t\t\tisWorkHour = true;\n\t\t\t\t\tworkInterval = daySchedule[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(isWorkHour){\n\n\t\t\t\tif(timestamp === workInterval.start && left >= workInterval.durationMinutes){\n\t\t\t\t\tadded += workInterval.durationMinutes;\n\t\t\t\t\tstart = this.$gantt.date.add(start, workInterval.durationMinutes, \"minute\");\n\t\t\t\t}else if(left <= (workInterval.endMinute - timestamp/60)){\n\t\t\t\t\tadded += left;\n\t\t\t\t\tstart = this.$gantt.date.add(start, left, \"minute\");\n\t\t\t\t}else{\n\t\t\t\t\tvar minutesInHour = this._getMinutesPerHour(start);\n\t\t\t\t\tif(minutesInHour <= left){\n\t\t\t\t\t\tadded += minutesInHour;\n\t\t\t\t\t\t// when the working time settings are set in minutes move to the next minutes\n\t\t\t\t\t\tif (minutePrecision) {\n\t\t\t\t\t\t\tstart = this.$gantt.date.add(start, minutesInHour, \"minute\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstart = this._nextDate(start, \"hour\", step);\n\t\t\t\t\t\t}\n\t\t\t\t\t}else{\n\t\t\t\t\t\taddedInterval = this._addMinutesUntilHourEnd(start, left);\n\t\t\t\t\t\tadded += addedInterval.added;\n\t\t\t\t\t\tstart = addedInterval.end;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tstart = this._getClosestWorkTimeFuture(start, \"hour\");\n\t\t\t}\n\t\t}\n\n\t\tif (added < duration) {\n\t\t\tvar durationLeft = duration - added;\n\t\t\taddedInterval = this._addMinutesUntilHourEnd(start, durationLeft);\n\t\t\tadded += addedInterval.added;\n\t\t\tstart = addedInterval.end;\n\t\t}\n\n\t\treturn start;\n\t},\n\n\tgetClosestWorkTime: function () {\n\t\tvar settings = this.argumentsHelper.getClosestWorkTimeArguments.apply( this.argumentsHelper, arguments);\n\t\treturn this._getClosestWorkTime(settings.date, settings.unit, settings.dir);\n\t},\n\n\t_getClosestWorkTime: function (inputDate, unit, direction) {\n\t\tvar result = new Date(inputDate);\n\n\t\tif (this._isWorkTime(result, unit)) {\n\t\t\treturn result;\n\t\t}\n\n\t\tresult = this.$gantt.date[unit + '_start'](result);\n\n\t\tif (direction == 'any' || !direction) {\n\t\t\tvar closestFuture = this._getClosestWorkTimeFuture(result, unit);\n\t\t\tvar closestPast = this._getClosestWorkTimePast(result, unit);\n\t\t\tif (Math.abs(closestFuture - inputDate) <= Math.abs(inputDate - closestPast)) {\n\t\t\t\tresult = closestFuture;\n\t\t\t} else {\n\t\t\t\tresult = closestPast;\n\t\t\t}\n\t\t} else if (direction == \"past\") {\n\t\t\tresult = this._getClosestWorkTimePast(result, unit);\n\t\t} else {\n\t\t\tresult = this._getClosestWorkTimeFuture(result, unit);\n\t\t}\n\t\treturn result;\n\t},\n\n\t_getClosestWorkTimeFuture: function (date, unit) {\n\t\treturn this._getClosestWorkTimeGeneric(date, unit, 1);\n\t},\n\n\t_getClosestWorkTimePast: function (date, unit) {\n\t\tvar result = this._getClosestWorkTimeGeneric(date, unit, -1);\n\t\t// should return the end of the closest work interval\n\t\treturn this.$gantt.date.add(result, 1, unit);\n\t},\n\n\t_findClosestTimeInDay: function(date, direction, worktimes) {\n\t\tvar start = new Date(date);\n\t\tvar resultDate = null;\n\t\tvar fromDayEnd = false;\n\t\tif(!this._getWorkHours(start).length){\n\t\t\tstart = this._getClosestWorkTime(start, \"day\", direction < 0 ? \"past\" : \"future\");\n\t\t\tif(direction < 0){\n\t\t\t\tstart = new Date(start.valueOf() - 1);\n\t\t\t\tfromDayEnd = true;\n\t\t\t}\n\t\t\tworktimes = this._getWorkHours(start);\n\t\t}\n\n\t\tvar value = this._getTimeOfDayStamp(start);\n\t\tif(fromDayEnd){\n\t\t\tvalue = this._getTimeOfDayStamp(new Date(start.valueOf() + 1), fromDayEnd);\n\t\t}\n\t\tif(direction > 0){\n\t\t\tfor(var i = 0; i < worktimes.length; i++){\n\t\t\t\tif(worktimes[i].start >= value){\n\t\t\t\t\tresultDate = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 0, 0, worktimes[i].start);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}else{\n\t\t\tfor(var i = worktimes.length - 1; i >= 0; i--){\n\t\t\t\tif(worktimes[i].end <= value){\n\t\t\t\t\tresultDate = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 0, 0, worktimes[i].end);\n\t\t\t\t\tbreak;\n\t\t\t\t}else if(worktimes[i].end > value && worktimes[i].start <= value) {\n\t\t\t\t\tresultDate = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 0, 0, value);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn resultDate;\n\t},\n\t_getClosestWorkMinute: function(date, unit, direction) {\n\t\tvar start = new Date(date);\n\t\tvar worktimes = this._getWorkHours(start);\n\t\tvar resultDate = this._findClosestTimeInDay(start, direction, worktimes);\n\t\tif(!resultDate){\n\t\t\tstart = this.calculateEndDate(start, direction, \"day\");\n\t\t\tif(direction > 0){\n\t\t\t\tstart = this.$gantt.date.day_start(start);\n\t\t\t}else{\n\t\t\t\tstart = this.$gantt.date.day_start(start);\n\t\t\t\tstart = this.$gantt.date.add(start, 1, \"day\");\n\t\t\t\tstart = new Date(start.valueOf() - 1);\n\t\t\t}\n\t\t\tworktimes = this._getWorkHours(start);\n\t\t\tresultDate = this._findClosestTimeInDay(start, direction, worktimes);\n\t\t}\n\t\tif(direction < 0){\n\t\t\t// getClosestWorkTimePast adds one time unit to the result date after this\n\t\t\tresultDate = this.$gantt.date.add(resultDate, -1, unit);\n\t\t}\n\t\treturn resultDate;\n\t},\n\n\t_getClosestWorkTimeGeneric: function (date, unit, increment) {\n\t\tif(unit === \"hour\" || unit === \"minute\"){\n\t\t\treturn this._getClosestWorkMinute(date, unit, increment);\n\t\t}\n\n\t\tvar unitOrder = this._getUnitOrder(unit),\n\t\t\tbiggerTimeUnit = this.units[unitOrder - 1];\n\n\t\tvar result = date;\n\n\t\t// be extra sure we won't fall into infinite loop, 3k seems big enough\n\t\tvar maximumLoop = 3000,\n\t\t\tcount = 0;\n\n\t\twhile (!this._isWorkTime(result, unit)) {\n\t\t\tif (biggerTimeUnit && !this._isWorkTime(result, biggerTimeUnit)) {\n\t\t\t\t// if we look for closest work hour and detect a week-end - first find the closest work day,\n\t\t\t\t// and continue iterations after that\n\t\t\t\tif (increment > 0) {\n\t\t\t\t\tresult = this._getClosestWorkTimeFuture(result, biggerTimeUnit);\n\t\t\t\t} else {\n\t\t\t\t\tresult = this._getClosestWorkTimePast(result, biggerTimeUnit);\n\t\t\t\t}\n\n\t\t\t\tif (this._isWorkTime(result, unit)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcount++;\n\t\t\tif (count > maximumLoop) {\n\t\t\t\tthis.$gantt.assert(false, \"Invalid working time check\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tvar tzOffset = result.getTimezoneOffset();\n\t\t\tresult = this.$gantt.date.add(result, increment, unit);\n\n\t\t\tresult = this.$gantt._correct_dst_change(result, tzOffset, increment, unit);\n\t\t\tif (this.$gantt.date[unit + '_start']) {\n\t\t\t\tresult = this.$gantt.date[unit + '_start'](result);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t},\n\n\t/**\n\t * Check whether this calendar has working time. Calendar has working time only if there are regular working days of week\n\t *\n\t */\n\thasWorkTime: function () {\n\t\tvar worktime = this.getConfig();\n\t\tvar dates = worktime.dates;\n\n\t\tvar daysOfWeek = [0, 1, 2, 3, 4, 5, 6];\n\t\tvar exceptions = [];\n\t\tfor(var i in worktime.dates){\n\t\t\tif(Number(i) > 6){\n\t\t\t\texceptions.push(Number(i));\n\t\t\t}\n\t\t}\n\n\t\tvar hasRegularHours = this._checkWorkHours(worktime.hours);\n\n\t\tvar result = false;\n\t\tdaysOfWeek.forEach((function(day){\n\t\t\tif(result){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar dayConfig = dates[day];\n\t\t\tif(dayConfig === true){\n\t\t\t\t// workday uses global hours\n\t\t\t\tresult = hasRegularHours;\n\t\t\t}else if(Array.isArray(dayConfig)){\n\t\t\t\t// workday uses custom hours\n\t\t\t\tresult = this._checkWorkHours(dayConfig);\n\t\t\t}\n\t\t}).bind(this));\n\n\t\treturn result;\n\n\t},\n\n\t_checkWorkHours: function(hoursArray) {\n\t\tif (hoursArray.length === 0) {\n\t\t\treturn false;\n\t\t}\n\t\tvar result = false;\n\t\tfor (var i = 0; i < hoursArray.length; i += 2) {\n\t\t\tif (hoursArray[i] !== hoursArray[i + 1]) {\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t},\n\n\t_isMinutePrecision: function (date) {\n\t\tlet minutePrecision = false;\n\t\tthis._getWorkHours(date).forEach(function(interval){\n\t\t\tif (interval.startMinute % 60 || interval.endMinute % 60){\n\t\t\t\tminutePrecision = true;\n\t\t\t}\n\t\t});\n\t\treturn minutePrecision;\n\t}\n};\n\nexport default CalendarWorkTimeStrategy;","import { IWorkUnitCache } from \"./workunit_cache_interface\";\nimport { WorkUnitsMapCache } from \"./workunit_map_cache\";\nimport { WorkUnitsObjectCache } from \"./workunit_object_cache\";\nexport { LargerUnitsCache } from \"./larger_units_helper\";\n\nexport function createCacheObject(): IWorkUnitCache {\n\n\t// worktime hash is on the hot path,\n\t// Map seems to work faster than plain array, use it whenever possible\n\tif (typeof Map !== \"undefined\") {\n\t\treturn new WorkUnitsMapCache();\n\t} else {\n\t\treturn new WorkUnitsObjectCache();\n\t}\n}\n","export default {\n\tisLegacyResourceCalendarFormat: function(resourceCalendarsProperty){\n\t\t// modern format:\n\t\t//gantt.config.resource_calendars = {\n\t\t//\tresourceId: calendarId,\n\t\t//\tresourceId: calendarId,\n\t\t//\tresourceId: calendarId\n\t\t//\t};\n\t\t\n\t\t// legacy format:\n\t\t// gantt.config.resource_calendars = {\n\t\t//\t\"resourceProperty\": {\n\t\t//\t\tresourceId: calendarId,\n\t\t//\t\tresourceId: calendarId,\n\t\t//\t\tresourceId: calendarId\n\t\t//\t\t}\n\t\t//\t};\n\n\t\tif(!resourceCalendarsProperty){\n\t\t\treturn false;\n\t\t}\n\t\tfor(var i in resourceCalendarsProperty){\n\t\t\tif(resourceCalendarsProperty[i] && typeof resourceCalendarsProperty[i] === \"object\"){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t},\n\tgetResourceProperty: function(config){\n\t\tvar resourceCalendarsConfig = config.resource_calendars;\n\t\tvar propertyName = config.resource_property;\n\t\tif(this.isLegacyResourceCalendarFormat(resourceCalendarsConfig)){\n\t\t\tfor(var i in config){\n\t\t\t\tpropertyName = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn propertyName;\n\t},\n\tgetCalendarIdFromLegacyConfig: function(task, config){\n\t\tif (config) {\n\t\t\tfor (var field in config) {\n\t\t\t\tvar resource = config[field];\n\t\t\t\tif (task[field]) {\n\t\t\t\t\tvar calendarId = resource[task[field]];\n\t\t\t\t\tif (calendarId) {\n\t\t\t\t\t\treturn calendarId;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n};","import * as utils from \"../../utils/utils\";\nimport createArgumentsHelper from \"./calendar_arguments_helper\";\nimport CalendarMergeHelper from \"./strategy/work_calendar_merger\";\nimport CalendarWorkTimeStrategy from \"./strategy/calendar_strategy\";\nimport legacyResourceCalendarConfig from \"./legacy_resource_config\";\nimport dynamicResourceCalendarsFactory from \"./dynamic_resource_calendars\";\n\nconst dynamicResourceCalendars = dynamicResourceCalendarsFactory();\n\nfunction CalendarManager (gantt){\n\tthis.$gantt = gantt;\n\tthis._calendars = {};\n\tthis._legacyConfig = undefined;\n\tthis.$gantt.attachEvent(\"onGanttReady\", function(){\n\t\tif(this.$gantt.config.resource_calendars){\n\t\t\tthis._isLegacyConfig = legacyResourceCalendarConfig.isLegacyResourceCalendarFormat(this.$gantt.config.resource_calendars);\n\t\t}\n\t}.bind(this));\n\n\tthis.$gantt.attachEvent(\"onBeforeGanttReady\", function(){\n\t\tthis.createDefaultCalendars();\n\t}.bind(this));\n\tthis.$gantt.attachEvent(\"onBeforeGanttRender\", function(){\n\t\tthis.createDefaultCalendars();\n\t}.bind(this));\n}\n\nCalendarManager.prototype = {\n\t_calendars: {},\n\t_convertWorkTimeSettings: function (settings) {\n\t\tvar days = settings.days;\n\t\tif (days && !settings.dates) {\n\t\t\tsettings.dates = settings.dates || {};\n\t\t\tfor (var i = 0; i < days.length; i++) {\n\t\t\t\tsettings.dates[i] = days[i];\n\t\t\t\tif (!(days[i] instanceof Array)) {\n\t\t\t\t\tsettings.dates[i] = !!days[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdelete settings.days;\n\t\treturn settings;\n\t},\n\tmergeCalendars: function(){\n\t\tvar calendars = [];\n\t\tvar args = arguments;\n\t\tif(Array.isArray(args[0])){\n\t\t\tcalendars = args[0].slice();\n\t\t}else{\n\t\t\tfor(var i = 0; i < arguments.length; i++){\n\t\t\t\tcalendars.push(arguments[i]);\n\t\t\t}\n\t\t}\n\n\t\tvar mergeHelper = new CalendarMergeHelper();\n\n\t\tvar result;\n\t\tcalendars.forEach(function(calendar){\n\t\t\tif(!result){\n\t\t\t\tresult = calendar;\n\t\t\t} else{\n\t\t\t\tresult = this._createCalendarFromConfig(mergeHelper.merge(result, calendar));\n\t\t\t}\n\n\t\t}.bind(this));\n\t\treturn this.createCalendar(result);\n\t},\n\n\t_createCalendarFromConfig: function(config){\n\t\tvar apiCore = new CalendarWorkTimeStrategy(this.$gantt, createArgumentsHelper(this.$gantt));\n\t\tapiCore.id = String(utils.uid());\n\n\t\tvar preparedConfig = this._convertWorkTimeSettings(config);\n\t\tif(preparedConfig.customWeeks){\n\t\t\tfor(var i in preparedConfig.customWeeks){\n\t\t\t\tpreparedConfig.customWeeks[i] = this._convertWorkTimeSettings(preparedConfig.customWeeks[i]);\n\t\t\t}\n\t\t}\n\t\tapiCore._setConfig(preparedConfig);\n\n\t\treturn apiCore;\n\t},\n\n\tcreateCalendar: function (parentCalendar) {\n\t\tvar settings;\n\n\t\tif (!parentCalendar) {\n\t\t\tparentCalendar = {};\n\t\t}\n\n\t\tif (parentCalendar.getConfig){\n\t\t\tsettings = utils.copy(parentCalendar.getConfig());\n\t\t} else if (parentCalendar.worktime) {\n\t\t\tsettings = utils.copy(parentCalendar.worktime);\n\t\t} else {\n\t\t\tsettings = utils.copy(parentCalendar);\n\t\t}\n\n\t\tvar defaults = utils.copy(this.defaults.fulltime.worktime);\n\t\tutils.mixin(settings, defaults);\n\n\t\treturn this._createCalendarFromConfig(settings);\n\t},\n\n\tgetCalendar: function (id) {\n\t\tid = id || \"global\";\n\t\tvar calendar = this._calendars[id];\n\t\tif(!calendar){\n\t\t\tthis.createDefaultCalendars();\n\t\t\tcalendar = this._calendars[id];\n\t\t}\n\n\t\treturn calendar;\n\t},\n\n\tgetCalendars: function () {\n\t\tvar res = [];\n\t\tfor (var i in this._calendars) {\n\t\t\tres.push(this.getCalendar(i));\n\t\t}\n\t\treturn res;\n\t},\n\n\t_getOwnCalendar: function(task){\n\t\tvar config = this.$gantt.config;\n\t\tif (task[config.calendar_property]) {\n\t\t\treturn this.getCalendar(task[config.calendar_property]);\n\t\t}\n\n\t\tif (config.resource_calendars) {\n\t\t\tvar calendar;\n\t\t\tvar calendarId;\n\t\t\tvar resourceProperty;\n\t\t\tif(this._legacyConfig === false){\n\t\t\t\tresourceProperty = config.resource_property;\n\t\t\t}else{\n\t\t\t\tresourceProperty = legacyResourceCalendarConfig.getResourceProperty(config);\n\t\t\t}\n\t\t\tif(Array.isArray(task[resourceProperty])){\n\t\t\t\t// if multiple resources are attached to the task - merge their calendars\n\t\t\t\tif(config.dynamic_resource_calendars){\n\t\t\t\t\tcalendarId = dynamicResourceCalendars.getCalendarIdFromMultipleResources(task[resourceProperty], this);\n\t\t\t\t} else {\n\t\t\t\t\tcalendar = this.getResourceCalendar(task[resourceProperty]);\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tif(this._legacyConfig === undefined){\n\t\t\t\t\tthis._legacyConfig = legacyResourceCalendarConfig.isLegacyResourceCalendarFormat(config.resource_calendars);\n\t\t\t\t}\n\n\t\t\t\tif(this._legacyConfig){\n\t\t\t\t\tvar calendarId = legacyResourceCalendarConfig.getCalendarIdFromLegacyConfig(task, config.resource_calendars);\n\t\t\t\t}else if(resourceProperty && task[resourceProperty] && config.resource_calendars[task[resourceProperty]]){\n\t\t\t\t\tvar calendar = this.getResourceCalendar(task[resourceProperty]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(calendarId){\n\t\t\t\tcalendar = this.getCalendar(calendarId);\n\t\t\t}\n\n\t\t\tif(calendar){\n\t\t\t\treturn calendar;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t},\n\n\t/**\n\t * Returns calendar assigned to the specified resource.\n\t * Returns the global calendar if no custom calendar is associated with the resource.\n\t * @param {(string|number|Object)} resource - resource object or resource id\n\t * @returns {object} Calendar object\n\t */\n\tgetResourceCalendar: function(resource) {\n\t\tif (resource === null || resource === undefined) {\n\t\t\treturn this.getCalendar();\n\t\t}\n\n\t\tvar resourceId = null;\n\t\t// if task id is provided\n\t\tif((typeof resource === \"number\" || typeof resource === \"string\")){\n\t\t\tresourceId = resource;\n\t\t}else{\n\t\t\tresourceId = resource.id || resource.key;\n\t\t}\n\n\t\tvar config = this.$gantt.config;\n\t\tvar calendarsConfig = config.resource_calendars;\n\t\tvar calendarId = null;\n\n\t\t// GS-1714: if resource is specified through array\n\t\tif (Array.isArray(resource)){\n\t\t\tif (resource.length === 1){\n\t\t\t\tif (typeof resource[0] === 'object'){\n\t\t\t\t\tresourceId = resource[0].resource_id; // if resource: [\"resource_id: \"6\", value: \"4\", ...\"]\n\t\t\t\t} else {\n\t\t\t\t\tresourceId = resource[0]; // if resource: [1]\n\t\t\t\t}\n\t\t\t} \n\t\t}\n\t\t\n\t\tif (calendarsConfig) {\n\t\t\tif(this._legacyConfig === undefined){\n\t\t\t\tthis._legacyConfig = legacyResourceCalendarConfig.isLegacyResourceCalendarFormat(config.resource_calendars);\n\t\t\t}\n\n\t\t\tif(this._legacyConfig){\n\t\t\t\tfor(var field in calendarsConfig){\n\t\t\t\t\tif(calendarsConfig[field][resourceId]){\n\t\t\t\t\t\tcalendarId = calendarsConfig[field][resourceId];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tvar calendarId = calendarsConfig[resourceId];\n\t\t\t}\n\n\t\t\tif(calendarId){\n\t\t\t\treturn this.getCalendar(calendarId);\n\t\t\t}\n\n\t\t}\n\t\treturn this.getCalendar();\n\t},\n\n\t/**\n\t * Returns the calendar assigned to a task.\n\t * - Returns a calendar assigned via task[gantt.config.calendar_property] if specified.\n\t * - Returns a calendar assigned to the task resource if specified.\n\t * - Returns the global calendar otherwise.\n\t * @param {(string|number|Object)} task - task object or task id\n\t * @returns {object} Calendar object\n\t */\n\tgetTaskCalendar: function (task) {\n\t\tvar gantt = this.$gantt;\n\t\tvar taskObject;\n\t\tif (task === null || task === undefined) {\n\t\t\treturn this.getCalendar();\n\t\t}\n\n\t\t// if task id is provided\n\t\tif((typeof task === \"number\" || typeof task === \"string\") && gantt.isTaskExists(task)){\n\t\t\ttaskObject = gantt.getTask(task);\n\t\t}else{\n\t\t\ttaskObject = task;\n\t\t}\n\n\t\tif(!taskObject){\n\t\t\treturn this.getCalendar();\n\t\t}\n\n\t\tvar calendar = this._getOwnCalendar(taskObject);\n\t\tvar groupMode = !!gantt.getState().group_mode;\n\n\t\tif (!calendar && gantt.config.inherit_calendar && gantt.isTaskExists(taskObject.parent)){\n\t\t\t// GS-1579 group mode overrides tree hierarchy, iterate using `.parent` property, instead of using eachParent iterator\n\t\t\tvar currentTask = taskObject;\n\t\t\twhile(gantt.isTaskExists(currentTask.parent)){\n\t\t\t\tcurrentTask = gantt.getTask(currentTask.parent);\n\t\t\t\tif(gantt.isSummaryTask(currentTask)){\n\t\t\t\t\tcalendar = this._getOwnCalendar(currentTask);\n\t\t\t\t\tif(calendar){\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(groupMode && !calendar){\n\t\t\t\t// if group mode and inherit_calendars is enabled - preserve previously applied parent calendar\n\t\t\t\t// we may need it when groupBy parses grouped data, old parent may be not loaded yet\n\t\t\t\tif(task.$effective_calendar){\n\t\t\t\t\tcalendar = this.getCalendar(task.$effective_calendar);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn calendar || this.getCalendar();\n\t},\n\n\taddCalendar: function(calendar) { // puts new calendar to Global Storage - gantt.calendarManager._calendars {}\n\t\tif (!(this.isCalendar(calendar))) {\n\t\t\tvar id = calendar.id;\n\t\t\tcalendar = this.createCalendar(calendar);\n\t\t\tcalendar.id = id;\n\t\t}\n\n\t\t// validate/check if empty calendar\n\t\tif (!calendar._tryChangeCalendarSettings(function () {\n\t\t\t})) {\n\n\t\t\tthis.$gantt.callEvent(\"onCalendarError\", [{message: \"Invalid calendar settings, no worktime available\"}, calendar]);\n\t\t\treturn null;\n\t\t} else {\n\t\t\tvar config = this.$gantt.config;\n\n\t\t\tcalendar.id = calendar.id || utils.uid();\n\t\t\tthis._calendars[calendar.id] = calendar;\n\t\t\tif (!config.worktimes)\n\t\t\t\tconfig.worktimes = {};\n\t\t\tconfig.worktimes[calendar.id] = calendar.getConfig();\n\t\t\treturn calendar.id;\n\t\t}\n\t},\n\n\tdeleteCalendar: function (calendar) {\n\t\tvar config = this.$gantt.config;\n\t\tif (!calendar) return false;\n\t\tif (this._calendars[calendar]) {\n\t\t\tdelete this._calendars[calendar];\n\t\t\tif (config.worktimes && config.worktimes[calendar])\n\t\t\t\tdelete config.worktimes[calendar];\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t},\n\n\trestoreConfigCalendars: function (configs) {\n\t\tfor (var i in configs) {\n\t\t\tif (this._calendars[i])\n\t\t\t\tcontinue;\n\n\t\t\tvar settings = configs[i];\n\t\t\tvar calendar = this.createCalendar(settings);\n\t\t\tcalendar.id = i;\n\t\t\tthis.addCalendar(calendar);\n\t\t}\n\t},\n\n\tdefaults: {\n\t\tglobal: {\n\t\t\tid: \"global\",\n\t\t\tworktime: {\n\t\t\t\thours: [8, 12, 13, 17],\n\t\t\t\tdays: [0, 1, 1, 1, 1, 1, 0]\n\t\t\t}\n\t\t},\n\t\tfulltime: {\n\t\t\tid: \"fulltime\",\n\t\t\tworktime: {\n\t\t\t\thours: [0, 24],\n\t\t\t\tdays: [1, 1, 1, 1, 1, 1, 1]\n\t\t\t}\n\t\t}\n\t},\n\n\tcreateDefaultCalendars: function () {\n\t\tvar config = this.$gantt.config;\n\t\tthis.restoreConfigCalendars(this.defaults);\n\t\tthis.restoreConfigCalendars(config.worktimes);\n\t},\n\n\tisCalendar: function(possibleCalendar) {\n\t\t// because we don't have any way to check without dependency to CalendarWorkTimeStrategy\n\t\tvar props = [\n\t\t\tpossibleCalendar.isWorkTime,\n\t\t\tpossibleCalendar.setWorkTime,\n\t\t\tpossibleCalendar.getWorkHours,\n\t\t\tpossibleCalendar.unsetWorkTime,\n\t\t\tpossibleCalendar.getClosestWorkTime,\n\t\t\tpossibleCalendar.calculateDuration,\n\t\t\tpossibleCalendar.hasDuration,\n\t\t\tpossibleCalendar.calculateEndDate\n\t\t];\n\t\treturn props.every(function(entry) {\n\t\t\treturn entry instanceof Function;\n\t\t});\n\t}\n};\n\nexport default CalendarManager;","function CalendarDisabledTimeStrategy(gantt, argumentsHelper){\n\tthis.argumentsHelper = argumentsHelper;\n\tthis.$gantt = gantt;\n}\n\nCalendarDisabledTimeStrategy.prototype = {\n\tgetWorkHours: function () {\n\t\treturn [0, 24];\n\t},\n\tsetWorkTime: function () {\n\t\treturn true;\n\t},\n\tunsetWorkTime: function () {\n\t\treturn true;\n\t},\n\tisWorkTime: function () {\n\t\treturn true;\n\t},\n\tgetClosestWorkTime: function (config) {\n\t\tvar config = this.argumentsHelper.getClosestWorkTimeArguments.apply(this.argumentsHelper, arguments);\n\t\treturn config.date;\n\t},\n\n\tcalculateDuration: function () {\n\t\tvar config = this.argumentsHelper.getDurationArguments.apply(this.argumentsHelper, arguments);\n\t\tvar from = config.start_date,\n\t\t\tto = config.end_date,\n\t\t\tunit = config.unit,\n\t\t\tstep = config.step;\n\n\t\treturn this._calculateDuration(from, to, unit, step);\n\t},\n\t_calculateDuration: function (start, end, unit, step) {\n\t\tvar dateHelper = this.$gantt.date;\n\t\tvar fixedUnits = {\n\t\t\t\"week\": 1000 * 60 * 60 * 24 * 7,\n\t\t\t\"day\": 1000 * 60 * 60 * 24,\n\t\t\t\"hour\": 1000 * 60 * 60,\n\t\t\t\"minute\": 1000 * 60\n\t\t};\n\n\t\tvar res = 0;\n\t\tif (fixedUnits[unit]) {\n\t\t\tres = Math.round((end - start) / (step * fixedUnits[unit]));\n\t\t} else {\n\t\t\tvar from = new Date(start),\n\t\t\t\tto = new Date(end);\n\t\t\twhile (from.valueOf() < to.valueOf()) {\n\t\t\t\tres += 1;\n\t\t\t\tfrom = dateHelper.add(from, step, unit);\n\t\t\t}\n\n\t\t\tif (from.valueOf() != end.valueOf()) {\n\t\t\t\tres += (to - from) / (dateHelper.add(from, step, unit) - from);\n\t\t\t}\n\t\t}\n\n\t\treturn Math.round(res);\n\t},\n\n\thasDuration: function () {\n\t\tvar config = this.argumentsHelper.getDurationArguments.apply(this.argumentsHelper, arguments);\n\t\tvar from = config.start_date,\n\t\t\tto = config.end_date,\n\t\t\tunit = config.unit;\n\n\t\tif (!unit) {\n\t\t\treturn false;\n\t\t}\n\t\tfrom = new Date(from);\n\t\tto = new Date(to);\n\n\t\treturn (from.valueOf() < to.valueOf());\n\t},\n\n\thasWorkTime: function() {\n\t\treturn true;\n\t},\n\n\tequals: function(calendar) {\n\t\tif(!(calendar instanceof CalendarDisabledTimeStrategy)){\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\tcalculateEndDate: function () {\n\t\tvar config = this.argumentsHelper.calculateEndDateArguments.apply(this.argumentsHelper, arguments);\n\n\t\tvar start = config.start_date,\n\t\t\tduration = config.duration,\n\t\t\tunit = config.unit,\n\t\t\tstep = config.step;\n\n\t\treturn this.$gantt.date.add(start, step * duration, unit);\n\t}\n};\n\nexport default CalendarDisabledTimeStrategy;","import createArgumentsHelper from \"./calendar_arguments_helper\";\nimport NoWorkTimeCalendar from \"./strategy/no_work_time\";\n\nfunction TimeCalculator(calendarManager){\n\n\tthis.$gantt = calendarManager.$gantt;\n\tthis.argumentsHelper = createArgumentsHelper(this.$gantt);\n\tthis.calendarManager = calendarManager;\n\tthis.$disabledCalendar = new NoWorkTimeCalendar(this.$gantt, this.argumentsHelper);\n}\n\nTimeCalculator.prototype = {\n\t_getCalendar: function (config) {\n\t\tvar calendar;\n\t\tif (!this.$gantt.config.work_time) {\n\t\t\tcalendar = this.$disabledCalendar;\n\t\t} else {\n\t\t\tvar manager = this.calendarManager;\n\t\t\tif (config.task) {\n\t\t\t\tcalendar = manager.getTaskCalendar(config.task);\n\t\t\t} else if (config.id) {\n\t\t\t\tcalendar = manager.getTaskCalendar(config);\n\t\t\t} else if (config.calendar) {\n\t\t\t\tcalendar = config.calendar;\n\t\t\t}\n\t\t\tif (!calendar) {\n\t\t\t\tcalendar = manager.getTaskCalendar();\n\t\t\t}\n\t\t}\n\t\treturn calendar;\n\t},\n\n\tgetWorkHours: function (config) {\n\t\tconfig = this.argumentsHelper.getWorkHoursArguments.apply(this.argumentsHelper, arguments);\n\n\t\tvar calendar = this._getCalendar(config);\n\n\t\treturn calendar.getWorkHours(config.date);\n\t},\n\n\tsetWorkTime: function (config, calendar) {\n\t\tconfig = this.argumentsHelper.setWorkTimeArguments.apply(this.argumentsHelper, arguments);\n\n\t\tif (!calendar)\n\t\t\tcalendar = this.calendarManager.getCalendar(); // Global\n\t\treturn calendar.setWorkTime(config);\n\t},\n\n\tunsetWorkTime: function (config, calendar) {\n\t\tconfig = this.argumentsHelper.unsetWorkTimeArguments.apply(this.argumentsHelper, arguments);\n\n\t\tif (!calendar)\n\t\t\tcalendar = this.calendarManager.getCalendar(); // Global\n\t\treturn calendar.unsetWorkTime(config);\n\t},\n\tisWorkTime: function (date, unit, task, calendar) {\n\t\tvar config = this.argumentsHelper.isWorkTimeArguments.apply(this.argumentsHelper, arguments);\n\n\t\tcalendar = this._getCalendar(config);\n\t\treturn calendar.isWorkTime(config);\n\t},\n\tgetClosestWorkTime: function (config) {\n\t\tconfig = this.argumentsHelper.getClosestWorkTimeArguments.apply(this.argumentsHelper, arguments);\n\n\t\tvar calendar = this._getCalendar(config);\n\n\t\treturn calendar.getClosestWorkTime(config);\n\t},\n\n\tcalculateDuration: function () { // start_date_date, end_date, task\n\t\tvar config = this.argumentsHelper.getDurationArguments.apply(this.argumentsHelper, arguments);\n\n\n\t\tvar calendar = this._getCalendar(config);\n\t\treturn calendar.calculateDuration(config);\n\t},\n\thasDuration: function () {\n\t\tvar config = this.argumentsHelper.hasDurationArguments.apply(this.argumentsHelper, arguments);\n\n\t\tvar calendar = this._getCalendar(config);\n\n\t\treturn calendar.hasDuration(config);\n\t},\n\tcalculateEndDate: function (config) { // start_date, duration, unit, task\n\t\tvar config = this.argumentsHelper.calculateEndDateArguments.apply(this.argumentsHelper, arguments);\n\n\t\tvar calendar = this._getCalendar(config);\n\t\treturn calendar.calculateEndDate(config);\n\t}\n};\n\nexport default TimeCalculator;\n\n","function addResizeListener(gantt){\n\tvar containerStyles = window.getComputedStyle(gantt.$root);\n\tif(containerStyles.getPropertyValue(\"position\") == \"static\"){\n\t\tgantt.$root.style.position = \"relative\";\n\t}\n\n\tvar resizeWatcher = document.createElement('iframe');\n\tresizeWatcher.className = \"gantt_container_resize_watcher\";\n\tresizeWatcher.tabIndex = -1;\n\tif(gantt.config.wai_aria_attributes){\n\t\tresizeWatcher.setAttribute(\"role\", \"none\");\n\t\tresizeWatcher.setAttribute(\"aria-hidden\", true);\n\t}\n\n\tvar salesforce_environment = !!window[\"Sfdc\"] || !!window[\"$A\"] || window[\"Aura\"];\n\tif (salesforce_environment){\n\t\tgantt.config.container_resize_method = \"timeout\";\n\t}\n\n\t// in some environments (namely, in SalesForce) iframe.contentWindow is not available\n\tgantt.$root.appendChild(resizeWatcher);\n\tif (resizeWatcher.contentWindow) {\n\t\tlistenWindowResize(gantt, resizeWatcher.contentWindow);\n\t} else {\n\t\t// if so - ditch the iframe and fallback to listening the main window resize\n\t\tgantt.$root.removeChild(resizeWatcher);\n\t\tlistenWindowResize(gantt, window);\n\t}\n}\n\nfunction listenWindowResize(gantt, window){\n\tvar resizeTimeout = gantt.config.container_resize_timeout || 20;\n\tvar resizeDelay;\n\tlet previousSize = getContainerSize(gantt);\n\n\tif (gantt.config.container_resize_method == \"timeout\"){\n\t\tlowlevelResizeWatcher();\n\t}\n\telse {\n\t\ttry {\n\t\t\tgantt.event(window, \"resize\", function () {\n\t\t\t\tif (gantt.$scrollbarRepaint) {\n\t\t\t\t\tgantt.$scrollbarRepaint = null;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// GS-2140. Don't repaint Gantt if it has the same sizes\n\t\t\t\t\tlet currentSize = getContainerSize(gantt);\n\t\t\t\t\tif (previousSize.x == currentSize.x && previousSize.y == currentSize.y){\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tpreviousSize = currentSize;\n\t\t\t\t\trepaintGantt();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tcatch (e) {\n\t\t\tlowlevelResizeWatcher();\n\t\t}\n\t}\n\n\tfunction repaintGantt(){\n\t\tclearTimeout(resizeDelay);\n\t\tresizeDelay = setTimeout(function(){\n\t\t\tif(!gantt.$destroyed){\n\t\t\t\tgantt.render();\n\t\t\t}\n\t\t}, resizeTimeout);\n\t}\n\n\tvar previousHeight = gantt.$root.offsetHeight;\n\tvar previousWidth = gantt.$root.offsetWidth;\t\n\n\tfunction lowlevelResizeWatcher(){\n\t\tif (gantt.$root.offsetHeight != previousHeight ||\n\t\t\t\tgantt.$root.offsetWidth != previousWidth){\n\t\t\t\trepaintGantt();\n\t\t}\n\n\t\tpreviousHeight = gantt.$root.offsetHeight;\n\t\tpreviousWidth = gantt.$root.offsetWidth;\n\n\t\tsetTimeout(lowlevelResizeWatcher, resizeTimeout);\n\t}\n}\n\nfunction getContainerSize(gantt){\n\treturn {\n\t\tx: gantt.$root.offsetWidth,\n\t\ty: gantt.$root.offsetHeight\n\t};\n}\n\nexport default addResizeListener;","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"كانون الثاني\", \"شباط\", \"آذار\", \"نيسان\", \"أيار\", \"حزيران\", \"تموز\", \"آب\", \"أيلول\", \"تشرين الأول\", \"تشرين الثاني\", \"كانون الأول\"],\n\t\tmonth_short: [\"يناير\", \"فبراير\", \"مارس\", \"أبريل\", \"مايو\", \"يونيو\", \"يوليو\", \"أغسطس\", \"سبتمبر\", \"أكتوبر\", \"نوفمبر\", \"ديسمبر\"],\n\t\tday_full: [\"الأحد\", \"الأثنين\", \"ألثلاثاء\", \"الأربعاء\", \"ألحميس\", \"ألجمعة\", \"السبت\"],\n\t\tday_short: [\"احد\", \"اثنين\", \"ثلاثاء\", \"اربعاء\", \"خميس\", \"جمعة\", \"سبت\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"مهمة جديد\",\n\t\ticon_save: \"اخزن\",\n\t\ticon_cancel: \"الغاء\",\n\t\ticon_details: \"تفاصيل\",\n\t\ticon_edit: \"تحرير\",\n\t\ticon_delete: \"حذف\",\n\t\tconfirm_closing: \"التغييرات سوف تضيع, هل انت متأكد؟\", // Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"الحدث سيتم حذفها نهائيا ، هل أنت متأكد؟\",\n\t\tsection_description: \"الوصف\",\n\t\tsection_time: \"الفترة الزمنية\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"الغاء\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Студзень\", \"Люты\", \"Сакавік\", \"Красавік\", \"Maй\", \"Чэрвень\", \"Ліпень\", \"Жнівень\", \"Верасень\", \"Кастрычнік\", \"Лістапад\", \"Снежань\"],\n\t\tmonth_short: [\"Студз\", \"Лют\", \"Сак\", \"Крас\", \"Maй\", \"Чэр\", \"Ліп\", \"Жнів\", \"Вер\", \"Каст\", \"Ліст\", \"Снеж\"],\n\t\tday_full: [\"Нядзеля\", \"Панядзелак\", \"Аўторак\", \"Серада\", \"Чацвер\", \"Пятніца\", \"Субота\"],\n\t\tday_short: [\"Нд\", \"Пн\", \"Аўт\", \"Ср\", \"Чцв\", \"Пт\", \"Сб\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Новае заданне\",\n\t\ticon_save: \"Захаваць\",\n\t\ticon_cancel: \"Адмяніць\",\n\t\ticon_details: \"Дэталі\",\n\t\ticon_edit: \"Змяніць\",\n\t\ticon_delete: \"Выдаліць\",\n\t\tconfirm_closing: \"\", // Унесеныя змены будуць страчаны, працягнуць?\n\t\tconfirm_deleting: \"Падзея будзе выдалена незваротна, працягнуць?\",\n\t\tsection_description: \"Апісанне\",\n\t\tsection_time: \"Перыяд часу\",\n\t\tsection_type: \"Тып\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"ІСР\",\n\t\tcolumn_text: \"Задача\",\n\t\tcolumn_start_date: \"Пачатак\",\n\t\tcolumn_duration: \"Працяг\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Сувязь\",\n\t\tconfirm_link_deleting: \"будзе выдалена\",\n\t\tlink_start: \"(пачатак)\",\n\t\tlink_end: \"(канец)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Хвiлiна\",\n\t\thours: \"Гадзiна\",\n\t\tdays: \"Дзень\",\n\t\tweeks: \"Тыдзень\",\n\t\tmonths: \"Месяц\",\n\t\tyears: \"Год\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Адмяніць\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n @Traducido por Vicente Adria Bohigues - vicenteadria@hotmail.com\n */\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Gener\", \"Febrer\", \"Març\", \"Abril\", \"Maig\", \"Juny\", \"Juliol\", \"Agost\", \"Setembre\", \"Octubre\", \"Novembre\", \"Desembre\"],\n\t\tmonth_short: [\"Gen\", \"Feb\", \"Mar\", \"Abr\", \"Mai\", \"Jun\", \"Jul\", \"Ago\", \"Set\", \"Oct\", \"Nov\", \"Des\"],\n\t\tday_full: [\"Diumenge\", \"Dilluns\", \"Dimarts\", \"Dimecres\", \"Dijous\", \"Divendres\", \"Dissabte\"],\n\t\tday_short: [\"Dg\", \"Dl\", \"Dm\", \"Dc\", \"Dj\", \"Dv\", \"Ds\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nova tasca\",\n\t\ticon_save: \"Guardar\",\n\t\ticon_cancel: \"Cancel·lar\",\n\t\ticon_details: \"Detalls\",\n\t\ticon_edit: \"Editar\",\n\t\ticon_delete: \"Esborrar\",\n\t\tconfirm_closing: \"\", // \"Els seus canvis es perdràn, continuar ?\"\n\t\tconfirm_deleting: \"L'esdeveniment s'esborrarà definitivament, continuar ?\",\n\t\tsection_description: \"Descripció\",\n\t\tsection_time: \"Periode de temps\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Cancel·lar\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\nTranslation by FreezeSoul\n\nUpdate 26/10/2015:\nTranslation of new labels by zwh8800\n https://github.com/DHTMLX/gantt/pull/7\n\n*/\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"一月\", \"二月\", \"三月\", \"四月\", \"五月\", \"六月\", \"七月\", \"八月\", \"九月\", \"十月\", \"十一月\", \"十二月\"],\n\t\tmonth_short: [\"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\"],\n\t\tday_full: [\"星期日\", \"星期一\", \"星期二\", \"星期三\", \"星期四\", \"星期五\", \"星期六\"],\n\t\tday_short: [\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"新任務\",\n\t\ticon_save: \"保存\",\n\t\ticon_cancel: \"关闭\",\n\t\ticon_details: \"详细\",\n\t\ticon_edit: \"编辑\",\n\t\ticon_delete: \"删除\",\n\t\tconfirm_closing: \"请确认是否撤销修改!\", // Your changes will be lost, are your sure?\n\t\tconfirm_deleting: \"是否删除日程?\",\n\t\tsection_description: \"描述\",\n\t\tsection_time: \"时间范围\",\n\t\tsection_type: \"类型\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"工作分解结构\",\n\t\tcolumn_text: \"任务名\",\n\t\tcolumn_start_date: \"开始时间\",\n\t\tcolumn_duration: \"持续时间\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\n\t\tlink: \"关联\",\n\t\tconfirm_link_deleting: \"将被删除\",\n\t\tlink_start: \" (开始)\",\n\t\tlink_end: \" (结束)\",\n\n\t\ttype_task: \"任务\",\n\t\ttype_project: \"项目\",\n\t\ttype_milestone: \"里程碑\",\n\n\t\tminutes: \"分钟\",\n\t\thours: \"小时\",\n\t\tdays: \"天\",\n\t\tweeks: \"周\",\n\t\tmonths: \"月\",\n\t\tyears: \"年\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"关闭\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Leden\", \"Únor\", \"Březen\", \"Duben\", \"Květen\", \"Červen\", \"Červenec\", \"Srpen\", \"Září\", \"Říjen\", \"Listopad\", \"Prosinec\"],\n\t\tmonth_short: [\"Led\", \"Ún\", \"Bře\", \"Dub\", \"Kvě\", \"Čer\", \"Čec\", \"Srp\", \"Září\", \"Říj\", \"List\", \"Pro\"],\n\t\tday_full: [\"Neděle\", \"Pondělí\", \"Úterý\", \"Středa\", \"Čtvrtek\", \"Pátek\", \"Sobota\"],\n\t\tday_short: [\"Ne\", \"Po\", \"Út\", \"St\", \"Čt\", \"Pá\", \"So\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nová práce\",\n\t\ticon_save: \"Uložit\",\n\t\ticon_cancel: \"Zpět\",\n\t\ticon_details: \"Detail\",\n\t\ticon_edit: \"Edituj\",\n\t\ticon_delete: \"Smazat\",\n\t\tconfirm_closing: \"\", // Vaše změny budou ztraceny, opravdu ?\n\t\tconfirm_deleting: \"Událost bude trvale smazána, opravdu?\",\n\t\tsection_description: \"Poznámky\",\n\t\tsection_time: \"Doba platnosti\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Zpět\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Januar\", \"Februar\", \"Marts\", \"April\", \"Maj\", \"Juni\", \"Juli\", \"August\", \"September\", \"Oktober\", \"November\", \"December\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Maj\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dec\"],\n\t\tday_full: [\"Søndag\", \"Mandag\", \"Tirsdag\", \"Onsdag\", \"Torsdag\", \"Fredag\", \"Lørdag\"],\n\t\tday_short: [\"Søn\", \"Man\", \"Tir\", \"Ons\", \"Tor\", \"Fre\", \"Lør\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Ny opgave\",\n\t\ticon_save: \"Gem\",\n\t\ticon_cancel: \"Fortryd\",\n\t\ticon_details: \"Detaljer\",\n\t\ticon_edit: \"Tilret\",\n\t\ticon_delete: \"Slet\",\n\t\tconfirm_closing: \"Dine rettelser vil gå tabt.. Er dy sikker?\", // Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"Bigivenheden vil blive slettet permanent. Er du sikker?\",\n\t\tsection_description: \"Beskrivelse\",\n\t\tsection_time: \"Tidsperiode\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Fortryd\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\" Januar\", \" Februar\", \" März \", \" April\", \" Mai\", \" Juni\", \" Juli\", \" August\", \" September \", \" Oktober\", \" November \", \" Dezember\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mär\", \"Apr\", \"Mai\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dez\"],\n\t\tday_full: [\"Sonntag\", \"Montag\", \"Dienstag\", \" Mittwoch\", \" Donnerstag\", \"Freitag\", \"Samstag\"],\n\t\tday_short: [\"So\", \"Mo\", \"Di\", \"Mi\", \"Do\", \"Fr\", \"Sa\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Neue Aufgabe\",\n\t\ticon_save: \"Speichern\",\n\t\ticon_cancel: \"Abbrechen\",\n\t\ticon_details: \"Details\",\n\t\ticon_edit: \"Ändern\",\n\t\ticon_delete: \"Löschen\",\n\t\tconfirm_closing: \"\", // \"Ihre Veränderungen werden verloren sein, wollen Sie ergänzen? \"\n\t\tconfirm_deleting: \"Der Eintrag wird gelöscht\",\n\t\tsection_description: \"Beschreibung\",\n\t\tsection_time: \"Zeitspanne\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"PSP\",\n\t\tcolumn_text: \"Task-Namen\",\n\t\tcolumn_start_date: \"Startzeit\",\n\t\tcolumn_duration: \"Dauer\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"werden gelöscht\",\n\t\tlink_start: \"(starten)\",\n\t\tlink_end: \"(ende)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minuten\",\n\t\thours: \"Stunden\",\n\t\tdays: \"Tage\",\n\t\tweeks: \"Wochen\",\n\t\tmonths: \"Monate\",\n\t\tyears: \"Jahre\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Abbrechen\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Regel\",\n\t\tconstraint_type: \"Regel\",\n\t\tconstraint_date: \"Regel - Datum\",\n\t\tasap: \"So bald wie möglich\",\n\t\talap: \"So spät wie möglich\",\n\t\tsnet: \"Beginn nicht vor\",\n\t\tsnlt: \"Beginn nicht später als\",\n\t\tfnet: \"Fertigstellung nicht vor\",\n\t\tfnlt: \"Fertigstellung nicht später als\",\n\t\tmso: \"Muss beginnen am\",\n\t\tmfo: \"Muss fertig sein am\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Ιανουάριος\", \"Φεβρουάριος\", \"Μάρτιος\", \"Απρίλιος\", \"Μάϊος\", \"Ιούνιος\", \"Ιούλιος\", \"Αύγουστος\", \"Σεπτέμβριος\", \"Οκτώβριος\", \"Νοέμβριος\", \"Δεκέμβριος\"],\n\t\tmonth_short: [\"ΙΑΝ\", \"ΦΕΒ\", \"ΜΑΡ\", \"ΑΠΡ\", \"ΜΑΙ\", \"ΙΟΥΝ\", \"ΙΟΥΛ\", \"ΑΥΓ\", \"ΣΕΠ\", \"ΟΚΤ\", \"ΝΟΕ\", \"ΔΕΚ\"],\n\t\tday_full: [\"Κυριακή\", \"Δευτέρα\", \"Τρίτη\", \"Τετάρτη\", \"Πέμπτη\", \"Παρασκευή\", \"Κυριακή\"],\n\t\tday_short: [\"ΚΥ\", \"ΔΕ\", \"ΤΡ\", \"ΤΕ\", \"ΠΕ\", \"ΠΑ\", \"ΣΑ\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Νέα εργασία\",\n\t\ticon_save: \"Αποθήκευση\",\n\t\ticon_cancel: \"Άκυρο\",\n\t\ticon_details: \"Λεπτομέρειες\",\n\t\ticon_edit: \"Επεξεργασία\",\n\t\ticon_delete: \"Διαγραφή\",\n\t\tconfirm_closing: \"\", // Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"Το έργο θα διαγραφεί οριστικά. Θέλετε να συνεχίσετε;\",\n\t\tsection_description: \"Περιγραφή\",\n\t\tsection_time: \"Χρονική περίοδος\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Άκυρο\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"],\n\t\tday_full: [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"],\n\t\tday_short: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"New task\",\n\t\ticon_save: \"Save\",\n\t\ticon_cancel: \"Cancel\",\n\t\ticon_details: \"Details\",\n\t\ticon_edit: \"Edit\",\n\t\ticon_delete: \"Delete\",\n\t\tconfirm_closing: \"\",// Your changes will be lost, are you sure?\n\t\tconfirm_deleting: \"Task will be deleted permanently, are you sure?\",\n\t\tsection_description: \"Description\",\n\t\tsection_time: \"Time period\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\n\t\t/* grid columns */\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Cancel\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;","/*\n @Autor Manuel Fernandez Panzuela - www.mfernandez.es\n\n Update 30/10/2015:\n Translation of new labels by Jorge Macias\n https://disqus.com/by/disqus_bTuZk1voC7/\n */\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Enero\", \"Febrero\", \"Marzo\", \"Abril\", \"Mayo\", \"Junio\", \"Julio\", \"Agosto\", \"Septiembre\", \"Octubre\", \"Noviembre\", \"Diciembre\"],\n\t\tmonth_short: [\"Ene\", \"Feb\", \"Mar\", \"Abr\", \"May\", \"Jun\", \"Jul\", \"Ago\", \"Sep\", \"Oct\", \"Nov\", \"Dic\"],\n\t\tday_full: [\"Domingo\", \"Lunes\", \"Martes\", \"Miércoles\", \"Jueves\", \"Viernes\", \"Sábado\"],\n\t\tday_short: [\"Dom\", \"Lun\", \"Mar\", \"Mié\", \"Jue\", \"Vie\", \"Sáb\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nueva tarea\",\n\t\ticon_save: \"Guardar\",\n\t\ticon_cancel: \"Cancelar\",\n\t\ticon_details: \"Detalles\",\n\t\ticon_edit: \"Editar\",\n\t\ticon_delete: \"Eliminar\",\n\t\tconfirm_closing: \"\", // \"Sus cambios se perderán, continuar ?\"\n\t\tconfirm_deleting: \"El evento se borrará definitivamente, ¿continuar?\",\n\t\tsection_description: \"Descripción\",\n\t\tsection_time: \"Período\",\n\t\tsection_type: \"Tipo\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"EDT\",\n\t\tcolumn_text: \"Tarea\",\n\t\tcolumn_start_date: \"Inicio\",\n\t\tcolumn_duration: \"Duración\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Enlace\",\n\t\tconfirm_link_deleting: \"será borrada\",\n\t\tlink_start: \" (inicio)\",\n\t\tlink_end: \" (fin)\",\n\n\t\ttype_task: \"Tarea\",\n\t\ttype_project: \"Proyecto\",\n\t\ttype_milestone: \"Hito\",\n\n\n\t\tminutes: \"Minutos\",\n\t\thours: \"Horas\",\n\t\tdays: \"Días\",\n\t\tweeks: \"Semanas\",\n\t\tmonths: \"Meses\",\n\t\tyears: \"Años\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Cancelar\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n dhtmlxGantt Persian (Farsi, fa_IR) locale by Mohammad Shokri http://slashsbin.com/\n */\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\n\t\t\t\"ژانویه\",\n\t\t\t\"فوریه\",\n\t\t\t\"مارس\",\n\t\t\t\"آوریل\",\n\t\t\t\"مه\",\n\t\t\t\"ژوئن\",\n\t\t\t\"ژوئیه\",\n\t\t\t\"اوت\",\n\t\t\t\"سپتامبر\",\n\t\t\t\"اکتبر\",\n\t\t\t\"نوامبر\",\n\t\t\t\"دسامبر\"\n\t\t],\n\t\tmonth_short: [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\"],\n\t\tday_full: [\n\t\t\t\"يکشنبه\",\n\t\t\t\"دوشنبه\",\n\t\t\t\"سه‌شنبه\",\n\t\t\t\"چهارشنبه\",\n\t\t\t\"پنجشنبه\",\n\t\t\t\"جمعه\",\n\t\t\t\"شنبه\"\n\t\t],\n\t\tday_short: [\n\t\t\t\"ی\",\n\t\t\t\"د\",\n\t\t\t\"س\",\n\t\t\t\"چ\",\n\t\t\t\"پ\",\n\t\t\t\"ج\",\n\t\t\t\"ش\"\n\t\t]\n\t},\n\tlabels: {\n\t\tnew_task: \"وظیفه جدید\",\n\t\ticon_save: \"ذخیره\",\n\t\ticon_cancel: \"لغو\",\n\t\ticon_details: \"جزییات\",\n\t\ticon_edit: \"ویرایش\",\n\t\ticon_delete: \"حذف\",\n\t\tconfirm_closing: \"تغییرات شما ازدست خواهد رفت، آیا مطمئن هستید؟\",\n\t\tconfirm_deleting: \"این مورد برای همیشه حذف خواهد شد، آیا مطمئن هستید؟\",\n\t\tsection_description: \"توضیحات\",\n\t\tsection_time: \"مدت زمان\",\n\t\tsection_type: \"نوع\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"عنوان\",\n\t\tcolumn_start_date: \"زمان شروع\",\n\t\tcolumn_duration: \"مدت\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"ارتباط\",\n\t\tconfirm_link_deleting: \"حذف خواهد شد\",\n\t\tlink_start: \" (آغاز)\",\n\t\tlink_end: \" (پایان)\",\n\n\t\ttype_task: \"وظیفه\",\n\t\ttype_project: \"پروژه\",\n\t\ttype_milestone: \"نگارش\",\n\n\t\tminutes: \"دقایق\",\n\t\thours: \"ساعات\",\n\t\tdays: \"روزها\",\n\t\tweeks: \"هفته\",\n\t\tmonths: \"ماه‌ها\",\n\t\tyears: \"سال‌ها\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"تایید\",\n\t\tmessage_cancel: \"لغو\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Tammikuu\", \"Helmikuu\", \"Maaliskuu\", \"Huhtikuu\", \"Toukokuu\", \"Kesäkuu\", \"Heinäkuu\", \"Elokuu\", \"Syyskuu\", \"Lokakuu\", \"Marraskuu\", \"Joulukuu\"],\n\t\tmonth_short: [\"Tam\", \"Hel\", \"Maa\", \"Huh\", \"Tou\", \"Kes\", \"Hei\", \"Elo\", \"Syy\", \"Lok\", \"Mar\", \"Jou\"],\n\t\tday_full: [\"Sunnuntai\", \"Maanantai\", \"Tiistai\", \"Keskiviikko\", \"Torstai\", \"Perjantai\", \"Lauantai\"],\n\t\tday_short: [\"Su\", \"Ma\", \"Ti\", \"Ke\", \"To\", \"Pe\", \"La\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Uusi tehtävä\",\n\t\ticon_save: \"Tallenna\",\n\t\ticon_cancel: \"Peru\",\n\t\ticon_details: \"Tiedot\",\n\t\ticon_edit: \"Muokkaa\",\n\t\ticon_delete: \"Poista\",\n\t\tconfirm_closing: \"\", // Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"Haluatko varmasti poistaa tapahtuman?\",\n\t\tsection_description: \"Kuvaus\",\n\t\tsection_time: \"Aikajakso\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Peru\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Janvier\", \"Février\", \"Mars\", \"Avril\", \"Mai\", \"Juin\", \"Juillet\", \"Août\", \"Septembre\", \"Octobre\", \"Novembre\", \"Décembre\"],\n\t\tmonth_short: [\"Jan\", \"Fév\", \"Mar\", \"Avr\", \"Mai\", \"Juin\", \"Juil\", \"Aoû\", \"Sep\", \"Oct\", \"Nov\", \"Déc\"],\n\t\tday_full: [\"Dimanche\", \"Lundi\", \"Mardi\", \"Mercredi\", \"Jeudi\", \"Vendredi\", \"Samedi\"],\n\t\tday_short: [\"Dim\", \"Lun\", \"Mar\", \"Mer\", \"Jeu\", \"Ven\", \"Sam\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nouvelle tâche\",\n\t\ticon_save: \"Enregistrer\",\n\t\ticon_cancel: \"Annuler\",\n\t\ticon_details: \"Détails\",\n\t\ticon_edit: \"Modifier\",\n\t\ticon_delete: \"Effacer\",\n\t\tconfirm_closing: \"\",// Vos modifications seront perdus, êtes-vous sûr ?\n\t\tconfirm_deleting: \"L'événement sera effacé sans appel, êtes-vous sûr ?\",\n\n\t\tsection_description: \"Description\",\n\t\tsection_time: \"Période\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"OTP\",\n\t\tcolumn_text: \"Nom de la tâche\",\n\t\tcolumn_start_date: \"Date initiale\",\n\t\tcolumn_duration: \"Durée\",\n\t\tcolumn_add: \"\",\n\n\n\t\t/* link confirmation */\n\t\tlink: \"Le lien\",\n\t\tconfirm_link_deleting: \"sera supprimé\",\n\t\tlink_start: \"(début)\",\n\t\tlink_end: \"(fin)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Heures\",\n\t\tdays: \"Jours\",\n\t\tweeks: \"Semaines\",\n\t\tmonths: \"Mois\",\n\t\tyears: \"Années\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Annuler\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"ינואר\", \"פברואר\", \"מרץ\", \"אפריל\", \"מאי\", \"יוני\", \"יולי\", \"אוגוסט\", \"ספטמבר\", \"אוקטובר\", \"נובמבר\", \"דצמבר\"],\n\t\tmonth_short: [\"ינו\", \"פבר\", \"מרץ\", \"אפר\", \"מאי\", \"יונ\", \"יול\", \"אוג\", \"ספט\", \"אוק\", \"נוב\", \"דצמ\"],\n\t\tday_full: [\"ראשון\", \"שני\", \"שלישי\", \"רביעי\", \"חמישי\", \"שישי\", \"שבת\"],\n\t\tday_short: [\"א\", \"ב\", \"ג\", \"ד\", \"ה\", \"ו\", \"ש\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"משימה חדש\",\n\t\ticon_save: \"שמור\",\n\t\ticon_cancel: \"בטל\",\n\t\ticon_details: \"פרטים\",\n\t\ticon_edit: \"ערוך\",\n\t\ticon_delete: \"מחק\",\n\t\tconfirm_closing: \"\", // Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"ארוע ימחק סופית.להמשיך?\",\n\t\tsection_description: \"הסבר\",\n\t\tsection_time: \"תקופה\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"בטל\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n Translation by Davor\n http://docs.dhtmlx.com/gantt/desktop__localization.html#comment-2569116291\n */\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Siječanj\", \"Veljača\", \"Ožujak\", \"Travanj\", \"Svibanj\", \"Lipanj\", \"Srpanj\", \"Kolovoz\", \"Rujan\", \"Listopad\", \"Studeni\", \"Prosinac\"],\n\t\tmonth_short: [\"Sij\", \"Velj\", \"Ožu\", \"Tra\", \"Svi\", \"Lip\", \"Srp\", \"Kol\", \"Ruj\", \"Lis\", \"Stu\", \"Pro\"],\n\t\tday_full: [\"Nedjelja\", \"Ponedjeljak\", \"Utorak\", \"Srijeda\", \"Četvrtak\", \"Petak\", \"Subota\"],\n\t\tday_short: [\"Ned\", \"Pon\", \"Uto\", \"Sri\", \"Čet\", \"Pet\", \"Sub\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Novi Zadatak\",\n\t\ticon_save: \"Spremi\",\n\t\ticon_cancel: \"Odustani\",\n\t\ticon_details: \"Detalji\",\n\t\ticon_edit: \"Izmjeni\",\n\t\ticon_delete: \"Obriši\",\n\t\tconfirm_closing: \"\",\n\t\tconfirm_deleting: \"Zadatak će biti trajno izbrisan, jeste li sigurni?\",\n\t\tsection_description: \"Opis\",\n\t\tsection_time: \"Vremenski Period\",\n\t\tsection_type: \"Tip\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\n\t\t/* grid columns */\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Naziv Zadatka\",\n\t\tcolumn_start_date: \"Početno Vrijeme\",\n\t\tcolumn_duration: \"Trajanje\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Poveznica\",\n\t\tconfirm_link_deleting: \"će biti izbrisan\",\n\t\tlink_start: \" (početak)\",\n\t\tlink_end: \" (kraj)\",\n\n\t\ttype_task: \"Zadatak\",\n\t\ttype_project: \"Projekt\",\n\t\ttype_milestone: \"Milestone\",\n\n\t\tminutes: \"Minute\",\n\t\thours: \"Sati\",\n\t\tdays: \"Dani\",\n\t\tweeks: \"Tjedni\",\n\t\tmonths: \"Mjeseci\",\n\t\tyears: \"Godine\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Odustani\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Január\", \"Február\", \"Március\", \"Április\", \"Május\", \"Június\", \"Július\", \"Augusztus\", \"Szeptember\", \"Október\", \"November\", \"December\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Már\", \"Ápr\", \"Máj\", \"Jún\", \"Júl\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dec\"],\n\t\tday_full: [\"Vasárnap\", \"Hétfõ\", \"Kedd\", \"Szerda\", \"Csütörtök\", \"Péntek\", \"szombat\"],\n\t\tday_short: [\"Va\", \"Hé\", \"Ke\", \"Sze\", \"Csü\", \"Pé\", \"Szo\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Új feladat\",\n\t\ticon_save: \"Mentés\",\n\t\ticon_cancel: \"Mégse\",\n\t\ticon_details: \"Részletek\",\n\t\ticon_edit: \"Szerkesztés\",\n\t\ticon_delete: \"Törlés\",\n\t\tconfirm_closing: \"\", // A változások elvesznek, biztosan folytatja? \"\n\t\tconfirm_deleting: \"Az esemény törölve lesz, biztosan folytatja?\",\n\t\tsection_description: \"Leírás\",\n\t\tsection_time: \"Idõszak\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Mégse\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Januari\", \"Februari\", \"Maret\", \"April\", \"Mei\", \"Juni\", \"Juli\", \"Agustus\", \"September\", \"Oktober\", \"November\", \"Desember\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Mei\", \"Jun\", \"Jul\", \"Ags\", \"Sep\", \"Okt\", \"Nov\", \"Des\"],\n\t\tday_full: [\"Minggu\", \"Senin\", \"Selasa\", \"Rabu\", \"Kamis\", \"Jumat\", \"Sabtu\"],\n\t\tday_short: [\"Ming\", \"Sen\", \"Sel\", \"Rab\", \"Kam\", \"Jum\", \"Sab\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Tugas baru\",\n\t\ticon_save: \"Simpan\",\n\t\ticon_cancel: \"Batal\",\n\t\ticon_details: \"Detail\",\n\t\ticon_edit: \"Edit\",\n\t\ticon_delete: \"Hapus\",\n\t\tconfirm_closing: \"\", /* Perubahan tidak akan disimpan ? */\n\t\tconfirm_deleting: \"Acara akan dihapus\",\n\t\tsection_description: \"Keterangan\",\n\t\tsection_time: \"Periode\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Batal\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n Update 29/12/2015:\n New labels translation by ARCANGELI CLAUDIO\n\n */\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Gennaio\", \"Febbraio\", \"Marzo\", \"Aprile\", \"Maggio\", \"Giugno\", \"Luglio\", \"Agosto\", \"Settembre\", \"Ottobre\", \"Novembre\", \"Dicembre\"],\n\t\tmonth_short: [\"Gen\", \"Feb\", \"Mar\", \"Apr\", \"Mag\", \"Giu\", \"Lug\", \"Ago\", \"Set\", \"Ott\", \"Nov\", \"Dic\"],\n\t\tday_full: [\"Domenica\", \"Lunedì\", \"Martedì\", \"Mercoledì\", \"Giovedì\", \"Venerdì\", \"Sabato\"],\n\t\tday_short: [\"Dom\", \"Lun\", \"Mar\", \"Mer\", \"Gio\", \"Ven\", \"Sab\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nuovo compito\",\n\t\ticon_save: \"Salva\",\n\t\ticon_cancel: \"Chiudi\",\n\t\ticon_details: \"Dettagli\",\n\t\ticon_edit: \"Modifica\",\n\t\ticon_delete: \"Elimina\",\n\t\tconfirm_closing: \"\",// \"Sei sicuro di confermare la chiusura?\",\n\t\tconfirm_deleting: \"Sei sicuro di confermare l'eliminazione?\",\n\t\tsection_description: \"Descrizione\",\n\t\tsection_time: \"Periodo di tempo\",\n\t\tsection_type: \"Tipo\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Nome Attività\",\n\t\tcolumn_start_date: \"Inizio\",\n\t\tcolumn_duration: \"Durata\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"sarà eliminato\",\n\t\tlink_start: \" (inizio)\",\n\t\tlink_end: \" (fine)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minuti\",\n\t\thours: \"Ore\",\n\t\tdays: \"Giorni\",\n\t\tweeks: \"Settimane\",\n\t\tmonths: \"Mesi\",\n\t\tyears: \"Anni\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Chiudi\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n Translation by Genexus Japan Inc.\n */\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\"],\n\t\tmonth_short: [\"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\"],\n\t\tday_full: [\"日曜日\", \"月曜日\", \"火曜日\", \"水曜日\", \"木曜日\", \"金曜日\", \"土曜日\"],\n\t\tday_short: [\"日\", \"月\", \"火\", \"水\", \"木\", \"金\", \"土\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"新しい仕事\",\n\t\ticon_save: \"保存\",\n\t\ticon_cancel: \"キャンセル\",\n\t\ticon_details: \"詳細\",\n\t\ticon_edit: \"編集\",\n\t\ticon_delete: \"削除\",\n\t\tconfirm_closing: \"\", // 変更が取り消されます、宜しいですか?\n\t\tconfirm_deleting: \"イベント完全に削除されます、宜しいですか?\",\n\t\tsection_description: \"デスクリプション\",\n\t\tsection_time: \"期間\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"キャンセル\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n\tTranslated by cjkim@dbvalley.com\n*/\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"1월\", \"2월\", \"3월\", \"4월\", \"5월\", \"6월\", \"7월\", \"8월\", \"9월\", \"10월\", \"11월\", \"12월\"],\n\t\tmonth_short: [\"1월\", \"2월\", \"3월\", \"4월\", \"5월\", \"6월\", \"7월\", \"8월\", \"9월\", \"10월\", \"11월\", \"12월\"],\n\t\tday_full: [\"일요일\", \"월요일\", \"화요일\", \"수요일\", \"목요일\", \"금요일\", \"토요일\"],\n\t\tday_short: [\"일\", \"월\", \"화\", \"수\", \"목\", \"금\", \"토\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"이름없는 작업\",\n\t\ticon_save: \"저장\",\n\t\ticon_cancel: \"취소\",\n\t\ticon_details: \"세부 사항\",\n\t\ticon_edit: \"수정\",\n\t\ticon_delete: \"삭제\",\n\t\tconfirm_closing: \"\",\n\t\tconfirm_deleting: \"작업을 삭제하시겠습니까?\",\n\t\tsection_description: \"설명\",\n\t\tsection_time: \"기간\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"작업명\",\n\t\tcolumn_start_date: \"시작일\",\n\t\tcolumn_duration: \"기간\",\n\t\tcolumn_add: \"\",\n\t\tlink: \"전제\",\n\t\tconfirm_link_deleting: \"삭제 하시겠습니까?\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\t\ttype_task: \"작업\",\n\t\ttype_project: \"프로젝트\",\n\t\ttype_milestone: \"마일스톤\",\n\t\tminutes: \"분\",\n\t\thours: \"시간\",\n\t\tdays: \"일\",\n\t\tweeks: \"주\",\n\t\tmonths: \"달\",\n\t\tyears: \"년\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"취소\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","export default class LocaleManager{\n\tprivate _locales:{[key:string]: IGanttLocale };\n\n\tconstructor(config: {[key:string]: IGanttLocale }){\n\t\tthis._locales = {};\n\t\tfor(const i in config){\n\t\t\tthis._locales[i] = config[i];\n\t\t}\n\t}\n\n\taddLocale = (name: string, locale: IGanttLocale) => {\n\t\tthis._locales[name] = locale;\n\t};\n\n\tgetLocale = (name: string): IGanttLocale => {\n\t\treturn this._locales[name];\n\t};\n}","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Januar\", \"Februar\", \"Mars\", \"April\", \"Mai\", \"Juni\", \"Juli\", \"August\", \"September\", \"Oktober\", \"November\", \"Desember\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Mai\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Des\"],\n\t\tday_full: [\"Søndag\", \"Mandag\", \"Tirsdag\", \"Onsdag\", \"Torsdag\", \"Fredag\", \"Lørdag\"],\n\t\tday_short: [\"Søn\", \"Mon\", \"Tir\", \"Ons\", \"Tor\", \"Fre\", \"Lør\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Ny oppgave\",\n\t\ticon_save: \"Lagre\",\n\t\ticon_cancel: \"Avbryt\",\n\t\ticon_details: \"Detaljer\",\n\t\ticon_edit: \"Rediger\",\n\t\ticon_delete: \"Slett\",\n\t\tconfirm_closing: \"\", // Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"Hendelsen vil bli slettet permanent. Er du sikker?\",\n\t\tsection_description: \"Beskrivelse\",\n\t\tsection_time: \"Tidsperiode\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Avbryt\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Januari\", \"Februari\", \"Maart\", \"April\", \"Mei\", \"Juni\", \"Juli\", \"Augustus\", \"September\", \"Oktober\", \"November\", \"December\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"mrt\", \"Apr\", \"Mei\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dec\"],\n\t\tday_full: [\"Zondag\", \"Maandag\", \"Dinsdag\", \"Woensdag\", \"Donderdag\", \"Vrijdag\", \"Zaterdag\"],\n\t\tday_short: [\"Zo\", \"Ma\", \"Di\", \"Wo\", \"Do\", \"Vr\", \"Za\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nieuwe taak\",\n\t\ticon_save: \"Opslaan\",\n\t\ticon_cancel: \"Annuleren\",\n\t\ticon_details: \"Details\",\n\t\ticon_edit: \"Bewerken\",\n\t\ticon_delete: \"Verwijderen\",\n\t\tconfirm_closing: \"\", // Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"Item zal permanent worden verwijderd, doorgaan?\",\n\t\tsection_description: \"Beschrijving\",\n\t\tsection_time: \"Tijd periode\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Taak omschrijving\",\n\t\tcolumn_start_date: \"Startdatum\",\n\t\tcolumn_duration: \"Duur\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Koppeling\",\n\t\tconfirm_link_deleting: \"zal worden verwijderd\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (eind)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"minuten\",\n\t\thours: \"uren\",\n\t\tdays: \"dagen\",\n\t\tweeks: \"weken\",\n\t\tmonths: \"maanden\",\n\t\tyears: \"jaren\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Annuleren\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Januar\", \"Februar\", \"Mars\", \"April\", \"Mai\", \"Juni\", \"Juli\", \"August\", \"September\", \"Oktober\", \"November\", \"Desember\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Mai\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Des\"],\n\t\tday_full: [\"Søndag\", \"Mandag\", \"Tirsdag\", \"Onsdag\", \"Torsdag\", \"Fredag\", \"Lørdag\"],\n\t\tday_short: [\"Søn\", \"Man\", \"Tir\", \"Ons\", \"Tor\", \"Fre\", \"Lør\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Ny oppgave\",\n\t\ticon_save: \"Lagre\",\n\t\ticon_cancel: \"Avbryt\",\n\t\ticon_details: \"Detaljer\",\n\t\ticon_edit: \"Endre\",\n\t\ticon_delete: \"Slett\",\n\t\tconfirm_closing: \"Endringer blir ikke lagret, er du sikker?\", // Endringer blir ikke lagret, er du sikker?\n\t\tconfirm_deleting: \"Oppføringen vil bli slettet, er du sikker?\",\n\t\tsection_description: \"Beskrivelse\",\n\t\tsection_time: \"Tidsperiode\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Avbryt\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Styczeń\", \"Luty\", \"Marzec\", \"Kwiecień\", \"Maj\", \"Czerwiec\", \"Lipiec\", \"Sierpień\", \"Wrzesień\", \"Październik\", \"Listopad\", \"Grudzień\"],\n\t\tmonth_short: [\"Sty\", \"Lut\", \"Mar\", \"Kwi\", \"Maj\", \"Cze\", \"Lip\", \"Sie\", \"Wrz\", \"Paź\", \"Lis\", \"Gru\"],\n\t\tday_full: [\"Niedziela\", \"Poniedziałek\", \"Wtorek\", \"Środa\", \"Czwartek\", \"Piątek\", \"Sobota\"],\n\t\tday_short: [\"Nie\", \"Pon\", \"Wto\", \"Śro\", \"Czw\", \"Pią\", \"Sob\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nowe zadanie\",\n\t\ticon_save: \"Zapisz\",\n\t\ticon_cancel: \"Anuluj\",\n\t\ticon_details: \"Szczegóły\",\n\t\ticon_edit: \"Edytuj\",\n\t\ticon_delete: \"Usuń\",\n\t\tconfirm_closing: \"\", // Zmiany zostaną usunięte, jesteś pewien?\n\t\tconfirm_deleting: \"Zdarzenie zostanie usunięte na zawsze, kontynuować?\",\n\t\tsection_description: \"Opis\",\n\t\tsection_time: \"Okres czasu\",\n\t\tsection_type: \"Typ\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Nazwa zadania\",\n\t\tcolumn_start_date: \"Początek\",\n\t\tcolumn_duration: \"Czas trwania\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"zostanie usunięty\",\n\t\tlink_start: \" (początek)\",\n\t\tlink_end: \" (koniec)\",\n\n\t\ttype_task: \"Zadanie\",\n\t\ttype_project: \"Projekt\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minuty\",\n\t\thours: \"Godziny\",\n\t\tdays: \"Dni\",\n\t\tweeks: \"Tydzień\",\n\t\tmonths: \"Miesiące\",\n\t\tyears: \"Lata\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Anuluj\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n\n TRANSLATION BY MATTHEUS PIROVANI RORIZ GONЗALVES\n\n mattheusroriz@hotmail.com / mattheus.pirovani@gmail.com /\n\n www.atrixian.com.br\n\n\n Updated by Jorge Albernaz Martins\n\n jorgefox@hotmail.com\n\n www.redfox.inf.br\n\n JorgeFox\n\n*/\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Janeiro\", \"Fevereiro\", \"Março\", \"Abril\", \"Maio\", \"Junho\", \"Julho\", \"Agosto\", \"Setembro\", \"Outubro\", \"Novembro\", \"Dezembro\"],\n\t\tmonth_short: [\"Jan\", \"Fev\", \"Mar\", \"Abr\", \"Mai\", \"Jun\", \"Jul\", \"Ago\", \"Set\", \"Out\", \"Nov\", \"Dez\"],\n\t\tday_full: [\"Domingo\", \"Segunda\", \"Terça\", \"Quarta\", \"Quinta\", \"Sexta\", \"Sábado\"],\n\t\tday_short: [\"Dom\", \"Seg\", \"Ter\", \"Qua\", \"Qui\", \"Sex\", \"Sab\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nova tarefa\",\n\t\ticon_save: \"Salvar\",\n\t\ticon_cancel: \"Cancelar\",\n\t\ticon_details: \"Detalhes\",\n\t\ticon_edit: \"Editar\",\n\t\ticon_delete: \"Excluir\",\n\t\tconfirm_closing: \"\",// Suas alterações serão perdidas, confirme?\n\t\tconfirm_deleting: \"As tarefas serão excluidas permanentemente, confirme?\",\n\t\tsection_description: \"Descrição\",\n\t\tsection_time: \"Período\",\n\t\tsection_type: \"Tipo\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"EAP\",\n\t\tcolumn_text: \"Nome tarefa\",\n\t\tcolumn_start_date: \"Data início\",\n\t\tcolumn_duration: \"Duração\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"Será excluído!\",\n\t\tlink_start: \" (início)\",\n\t\tlink_end: \" (fim)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Projeto\",\n\t\ttype_milestone: \"Marco\",\n\n\n\t\tminutes: \"Minutos\",\n\t\thours: \"Horas\",\n\t\tdays: \"Dias\",\n\t\tweeks: \"Semanas\",\n\t\tmonths: \"Meses\",\n\t\tyears: \"Anos\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Cancelar\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Restrição\",\n\t\tconstraint_type: \"Tipo Restrição\",\n\t\tconstraint_date: \"Data restrição\",\n\t\tasap: \"Mais breve possível\",\n\t\talap: \"Mais tarde possível\",\n\t\tsnet: \"Não começar antes de\",\n\t\tsnlt: \"Não começar depois de\",\n\t\tfnet: \"Não terminar antes de\",\n\t\tfnlt: \"Não terminar depois de\",\n\t\tmso: \"Precisa começar em\",\n\t\tmfo: \"Precisa terminar em\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"Tipo de filtros\",\n\t\tresources_filter_label: \"Ocultar vazios\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n\tTraducere de Ovidiu Lixandru: http://www.madball.ro\n */\n\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Ianuarie\", \"Februarie\", \"Martie\", \"Aprilie\", \"Mai\", \"Iunie\", \"Iulie\", \"August\", \"Septembrie\", \"Octombrie\", \"November\", \"December\"],\n\t\tmonth_short: [\"Ian\", \"Feb\", \"Mar\", \"Apr\", \"Mai\", \"Iun\", \"Iul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"],\n\t\tday_full: [\"Duminica\", \"Luni\", \"Marti\", \"Miercuri\", \"Joi\", \"Vineri\", \"Sambata\"],\n\t\tday_short: [\"Du\", \"Lu\", \"Ma\", \"Mi\", \"Jo\", \"Vi\", \"Sa\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Sarcina noua\",\n\t\ticon_save: \"Salveaza\",\n\t\ticon_cancel: \"Anuleaza\",\n\t\ticon_details: \"Detalii\",\n\t\ticon_edit: \"Editeaza\",\n\t\ticon_delete: \"Sterge\",\n\t\tconfirm_closing: \"Schimbarile nu vor fi salvate, esti sigur?\",// Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"Evenimentul va fi sters permanent, esti sigur?\",\n\t\tsection_description: \"Descriere\",\n\t\tsection_time: \"Interval\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Anuleaza\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Январь\", \"Февраль\", \"Март\", \"Апрель\", \"Maй\", \"Июнь\", \"Июль\", \"Август\", \"Сентябрь\", \"Oктябрь\", \"Ноябрь\", \"Декабрь\"],\n\t\tmonth_short: [\"Янв\", \"Фев\", \"Maр\", \"Aпр\", \"Maй\", \"Июн\", \"Июл\", \"Aвг\", \"Сен\", \"Окт\", \"Ноя\", \"Дек\"],\n\t\tday_full: [\"Воскресенье\", \"Понедельник\", \"Вторник\", \"Среда\", \"Четверг\", \"Пятница\", \"Суббота\"],\n\t\tday_short: [\"Вс\", \"Пн\", \"Вт\", \"Ср\", \"Чт\", \"Пт\", \"Сб\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Новое задание\",\n\t\ticon_save: \"Сохранить\",\n\t\ticon_cancel: \"Отменить\",\n\t\ticon_details: \"Детали\",\n\t\ticon_edit: \"Изменить\",\n\t\ticon_delete: \"Удалить\",\n\t\tconfirm_closing: \"\", // Ваши изменения будут потеряны, продолжить?\n\t\tconfirm_deleting: \"Событие будет удалено безвозвратно, продолжить?\",\n\t\tsection_description: \"Описание\",\n\t\tsection_time: \"Период времени\",\n\t\tsection_type: \"Тип\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"ИСР\",\n\t\tcolumn_text: \"Задача\",\n\t\tcolumn_start_date: \"Начало\",\n\t\tcolumn_duration: \"Длительность\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Связь\",\n\t\tconfirm_link_deleting: \"будет удалена\",\n\t\tlink_start: \" (начало)\",\n\t\tlink_end: \" (конец)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Минута\",\n\t\thours: \"Час\",\n\t\tdays: \"День\",\n\t\tweeks: \"Неделя\",\n\t\tmonths: \"Месяц\",\n\t\tyears: \"Год\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Отменить\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"начните вводить слово для фильтрации\",\n\t\tresources_filter_label: \"спрятать не установленные\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Januar\", \"Februar\", \"Marec\", \"April\", \"Maj\", \"Junij\", \"Julij\", \"Avgust\", \"September\", \"Oktober\", \"November\", \"December\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Maj\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dec\"],\n\t\tday_full: [\"Nedelja\", \"Ponedeljek\", \"Torek\", \"Sreda\", \"Četrtek\", \"Petek\", \"Sobota\"],\n\t\tday_short: [\"Ned\", \"Pon\", \"Tor\", \"Sre\", \"Čet\", \"Pet\", \"Sob\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nova naloga\",\n\t\ticon_save: \"Shrani\",\n\t\ticon_cancel: \"Prekliči\",\n\t\ticon_details: \"Podrobnosti\",\n\t\ticon_edit: \"Uredi\",\n\t\ticon_delete: \"Izbriši\",\n\t\tconfirm_closing: \"\", // Spremembe ne bodo shranjene. Želite nadaljevati ?\n\t\tconfirm_deleting: \"Dogodek bo izbrisan. Želite nadaljevati?\",\n\t\tsection_description: \"Opis\",\n\t\tsection_time: \"Časovni okvir\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Prekliči\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Január\", \"Február\", \"Marec\", \"Apríl\", \"Máj\", \"Jún\", \"Júl\", \"August\", \"September\", \"Október\", \"November\", \"December\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Máj\", \"Jún\", \"Júl\", \"Aug\", \"Sept\", \"Okt\", \"Nov\", \"Dec\"],\n\t\tday_full: [\"Nedeľa\", \"Pondelok\", \"Utorok\", \"Streda\", \"Štvrtok\", \"Piatok\", \"Sobota\"],\n\t\tday_short: [\"Ne\", \"Po\", \"Ut\", \"St\", \"Št\", \"Pi\", \"So\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Nová úloha\",\n\t\ticon_save: \"Uložiť\",\n\t\ticon_cancel: \"Späť\",\n\t\ticon_details: \"Detail\",\n\t\ticon_edit: \"Edituj\",\n\t\ticon_delete: \"Zmazať\",\n\t\tconfirm_closing: \"Vaše zmeny nebudú uložené. Skutočne?\", // Vaše změny budou ztraceny, opravdu ?\n\t\tconfirm_deleting: \"Udalosť bude natrvalo vymazaná. Skutočne?\",\n\t\tsection_description: \"Poznámky\",\n\t\tsection_time: \"Doba platnosti\",\n\t\tsection_type: \"Type\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Späť\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n\tTranslation by Peter Eriksson\n */\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Januari\", \"Februari\", \"Mars\", \"April\", \"Maj\", \"Juni\", \"Juli\", \"Augusti\", \"September\", \"Oktober\", \"November\", \"December\"],\n\t\tmonth_short: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"Maj\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dec\"],\n\t\tday_full: [\"Söndag\", \"Måndag\", \"Tisdag\", \"Onsdag\", \"Torsdag\", \"Fredag\", \"Lördag\"],\n\t\tday_short: [\"Sön\", \"Mån\", \"Tis\", \"Ons\", \"Tor\", \"Fre\", \"Lör\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Ny uppgift\",\n\t\ticon_save: \"Spara\",\n\t\ticon_cancel: \"Avbryt\",\n\t\ticon_details: \"Detajer\",\n\t\ticon_edit: \"Ändra\",\n\t\ticon_delete: \"Ta bort\",\n\t\tconfirm_closing: \"\",\n\t\tconfirm_deleting: \"Är du säker på att du vill ta bort händelsen permanent?\",\n\t\tsection_description: \"Beskrivning\",\n\t\tsection_time: \"Tid\",\n\t\tsection_type: \"Typ\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Uppgiftsnamn\",\n\t\tcolumn_start_date: \"Starttid\",\n\t\tcolumn_duration: \"Varaktighet\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\n\t\tlink: \"Länk\",\n\t\tconfirm_link_deleting: \"kommer tas bort\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (slut)\",\n\t\ttype_task: \"Uppgift\",\n\t\ttype_project: \"Projekt\",\n\t\ttype_milestone: \"Milstolpe\",\n\n\t\tminutes: \"Minuter\",\n\t\thours: \"Timmar\",\n\t\tdays: \"Dagar\",\n\t\tweeks: \"Veckor\",\n\t\tmonths: \"Månader\",\n\t\tyears: \"År\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Avbryt\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","/*\n * updated by @levkar at https://github.com/DHTMLX/gantt/pull/10\n */\nconst locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Ocak\", \"Şubat\", \"Mart\", \"Nisan\", \"Mayıs\", \"Haziran\", \"Temmuz\", \"Ağustos\", \"Eylül\", \"Ekim\", \"Kasım\", \"Aralık\"],\n\t\tmonth_short: [\"Oca\", \"Şub\", \"Mar\", \"Nis\", \"May\", \"Haz\", \"Tem\", \"Ağu\", \"Eyl\", \"Eki\", \"Kas\", \"Ara\"],\n\t\tday_full: [\"Pazar\", \"Pazartesi\", \"Salı\", \"Çarşamba\", \"Perşembe\", \"Cuma\", \"Cumartesi\"],\n\t\tday_short: [\"Paz\", \"Pzt\", \"Sal\", \"Çar\", \"Per\", \"Cum\", \"Cmt\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Yeni görev\",\n\t\ticon_save: \"Kaydet\",\n\t\ticon_cancel: \"İptal\",\n\t\ticon_details: \"Detaylar\",\n\t\ticon_edit: \"Düzenle\",\n\t\ticon_delete: \"Sil\",\n\t\tconfirm_closing: \"\", // Your changes will be lost, are your sure ?\n\t\tconfirm_deleting: \"Görev silinecek, emin misiniz?\",\n\t\tsection_description: \"Açıklama\",\n\t\tsection_time: \"Zaman Aralığı\",\n\t\tsection_type: \"Tip\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Görev Adı\",\n\t\tcolumn_start_date: \"Başlangıç\",\n\t\tcolumn_duration: \"Süre\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Bağlantı\",\n\t\tconfirm_link_deleting: \"silinecek\",\n\t\tlink_start: \" (başlangıç)\",\n\t\tlink_end: \" (bitiş)\",\n\n\t\ttype_task: \"Görev\",\n\t\ttype_project: \"Proje\",\n\t\ttype_milestone: \"Kilometretaşı\",\n\n\n\t\tminutes: \"Dakika\",\n\t\thours: \"Saat\",\n\t\tdays: \"Gün\",\n\t\tweeks: \"Hafta\",\n\t\tmonths: \"Ay\",\n\t\tyears: \"Yıl\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Ýptal\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","const locale: IGanttLocale = {\n\tdate: {\n\t\tmonth_full: [\"Січень\", \"Лютий\", \"Березень\", \"Квітень\", \"Травень\", \"Червень\", \"Липень\", \"Серпень\", \"Вересень\", \"Жовтень\", \"Листопад\", \"Грудень\"],\n\t\tmonth_short: [\"Січ\", \"Лют\", \"Бер\", \"Кві\", \"Тра\", \"Чер\", \"Лип\", \"Сер\", \"Вер\", \"Жов\", \"Лис\", \"Гру\"],\n\t\tday_full: [\"Неділя\", \"Понеділок\", \"Вівторок\", \"Середа\", \"Четвер\", \"П'ятниця\", \"Субота\"],\n\t\tday_short: [\"Нед\", \"Пон\", \"Вів\", \"Сер\", \"Чет\", \"Птн\", \"Суб\"]\n\t},\n\tlabels: {\n\t\tnew_task: \"Нове завдання\",\n\t\ticon_save: \"Зберегти\",\n\t\ticon_cancel: \"Відміна\",\n\t\ticon_details: \"Деталі\",\n\t\ticon_edit: \"Редагувати\",\n\t\ticon_delete: \"Вилучити\",\n\t\tconfirm_closing: \"\", // Ваші зміни втратяться. Ви впевнені ?\n\t\tconfirm_deleting: \"Подія вилучиться назавжди. Ви впевнені?\",\n\t\tsection_description: \"Опис\",\n\t\tsection_time: \"Часовий проміжок\",\n\t\tsection_type: \"Тип\",\n\t\tsection_deadline: \"Deadline\",\n\t\tsection_baselines: \"Baselines\",\n\t\t/* grid columns */\n\n\t\tcolumn_wbs: \"WBS\",\n\t\tcolumn_text: \"Task name\",\n\t\tcolumn_start_date: \"Start time\",\n\t\tcolumn_duration: \"Duration\",\n\t\tcolumn_add: \"\",\n\n\t\t/* link confirmation */\n\t\tlink: \"Link\",\n\t\tconfirm_link_deleting: \"will be deleted\",\n\t\tlink_start: \" (start)\",\n\t\tlink_end: \" (end)\",\n\n\t\ttype_task: \"Task\",\n\t\ttype_project: \"Project\",\n\t\ttype_milestone: \"Milestone\",\n\n\n\t\tminutes: \"Minutes\",\n\t\thours: \"Hours\",\n\t\tdays: \"Days\",\n\t\tweeks: \"Week\",\n\t\tmonths: \"Months\",\n\t\tyears: \"Years\",\n\n\t\t/* message popup */\n\t\tmessage_ok: \"OK\",\n\t\tmessage_cancel: \"Відміна\",\n\n\t\t/* constraints */\n\t\tsection_constraint: \"Constraint\",\n\t\tconstraint_type: \"Constraint type\",\n\t\tconstraint_date: \"Constraint date\",\n\t\tasap: \"As Soon As Possible\",\n\t\talap: \"As Late As Possible\",\n\t\tsnet: \"Start No Earlier Than\",\n\t\tsnlt: \"Start No Later Than\",\n\t\tfnet: \"Finish No Earlier Than\",\n\t\tfnlt: \"Finish No Later Than\",\n\t\tmso: \"Must Start On\",\n\t\tmfo: \"Must Finish On\",\n\n\t\t/* resource control */\n\t\tresources_filter_placeholder: \"type to filter\",\n\t\tresources_filter_label: \"hide empty\",\n\n\t\t/* empty state screen */\n\t\tempty_state_text_link: \"Click here\",\n\t\tempty_state_text_description: \"to create your first task\",\n\n\t\t/* baselines control */\n\t\tbaselines_section_placeholder: \"Start adding a new baseline\",\n\t\tbaselines_add_button: \"Add Baseline\",\n\t\tbaselines_remove_button: \"Remove\",\n\t\tbaselines_remove_all_button: \"Remove All\",\n\n\t\t/* deadline control */\n\t\tdeadline_enable_button: \"Set\",\n\t\tdeadline_disable_button: \"Remove\"\n\t}\n};\n\nexport default locale;\n","import * as utils from \"../utils/utils\";\nimport constants from \"../constants\";\nimport ExtensionManager from \"../ext/extension_manager\";\n\nimport services from \"../core/common/services\";\nimport config from \"../core/common/config\";\nimport ajax from \"../core/common/ajax\";\nimport date from \"../core/common/date\";\nimport {remoteEvents} from \"../core/remote/remote_events\";\n\nimport DnD from \"../core/common/dnd\";\nimport templates from \"../core/common/templates\";\nimport eventable from \"../utils/eventable\";\n\nimport StateService from \"../core/common/state\";\n\nimport Promise from \"../utils/promise\";\nimport env from \"../utils/env\";\nimport datastoreHooks from \"../core/datastore/datastore_hooks\";\nimport DataProcessor from \"../core/dataprocessor\";\n\nimport plugins from \"../core/plugins\";\n\nimport grid_column_api from \"../core/grid_column_api\";\nimport tasks from \"../core/tasks\";\nimport parsing from \"../core/loading/parsing\";\nimport work_time from \"../core/worktime/work_time\";\nimport data from \"../core/data\";\n\nimport void_script_second from \"../publish_helpers/void_script_second\";\n\nimport data_task_types from \"../core/data_task_types\";\nimport cached_functions from \"../core/cached_functions\";\n\nimport gantt_core from \"../core/gantt_core\";\nimport destructor from \"../core/destructor\";\nimport void_script_third from \"../publish_helpers/void_script_third\";\n\nimport i18nFactory from \"../locale\";\n\nfunction DHXGantt(){\n\tthis.constants = constants;\n\tthis.version = VERSION;\n\tthis.license = LICENSE;\n\tthis.templates = {};\n\tthis.ext = {};\n\tthis.keys = {\n\t\tedit_save: this.constants.KEY_CODES.ENTER,\n\t\tedit_cancel: this.constants.KEY_CODES.ESC\n\t};\n}\n\nexport default function(supportedExtensions) {\n\t// use a named constructor to make gantt instance discoverable in heap snapshots\n\tvar gantt = new DHXGantt();\n\n\tvar extensionManager = new ExtensionManager(supportedExtensions);\n\tvar activePlugins = {};\n\tgantt.plugins = function(config){\n\t\tfor(var i in config){\n\t\t\tif(config[i] && !activePlugins[i]){\n\t\t\t\tvar plugin = extensionManager.getExtension(i);\n\t\t\t\tif(plugin){\n\t\t\t\t\tplugin(gantt);\n\t\t\t\t\tactivePlugins[i] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn activePlugins;\n\t};\n\n\tgantt.$services = services();\n\tgantt.config = config();\n\tgantt.ajax = ajax(gantt);\n\tgantt.date = date(gantt);\n\tgantt.RemoteEvents = remoteEvents;\n\n\tvar dnd = DnD(gantt);\n\tgantt.$services.setService(\"dnd\", function(){return dnd;});\n\n\tvar templatesLoader = templates(gantt);\n\tgantt.$services.setService(\"templateLoader\", function () {\n\t\treturn templatesLoader;\n\t});\n\n\teventable(gantt);\n\n\t\n\tvar stateService = new StateService();\n\n\tstateService.registerProvider(\"global\", function () {\n\t\tvar res = {\n\t\t\tmin_date: gantt._min_date,\n\t\t\tmax_date: gantt._max_date,\n\t\t\tselected_task: null\n\t\t};\n\n\t\t// do not throw error if getState called from non-initialized gantt\n\t\tif(gantt.$data && gantt.$data.tasksStore){\n\t\t\tres.selected_task = gantt.$data.tasksStore.getSelectedId();\n\t\t}\n\t\treturn res;\n\t});\n\tgantt.getState = stateService.getState;\n\tgantt.$services.setService(\"state\", function () {\n\t\treturn stateService;\n\t});\n\n\tutils.mixin(gantt, utils);\n\n\tgantt.Promise = Promise;\n\tgantt.env = env;\n\n\tdatastoreHooks(gantt);\n\n\tgantt.dataProcessor = DataProcessor.DEPRECATED_api;\n\tgantt.createDataProcessor = DataProcessor.createDataProcessor;\n\n\tplugins(gantt);\n\n\tgrid_column_api(gantt);\n\ttasks(gantt);\n\tparsing(gantt);\n\twork_time(gantt);\n\tdata(gantt);\n\n\tvoid_script_second(gantt);\n\n\tdata_task_types(gantt);\n\tcached_functions(gantt);\n\n\tgantt_core(gantt);\n\tdestructor(gantt);\n\tvoid_script_third(gantt);\n\n\tvar i18n = i18nFactory();\n\tgantt.i18n = {\n\t\taddLocale: i18n.addLocale,\n\t\tsetLocale: function(locale){\n\t\t\tif(typeof locale === \"string\"){\n\t\t\t\tvar localeObject = i18n.getLocale(locale);\n\t\t\t\tif(!localeObject){\n\t\t\t\t\tlocaleObject = i18n.getLocale(\"en\");\n\t\t\t\t}\n\n\t\t\t\tgantt.locale = localeObject;\n\t\t\t}else if(locale){\n\t\t\t\tif(!gantt.locale){\n\t\t\t\t\tgantt.locale = locale;\n\t\t\t\t}else{\n\t\t\t\t\tfor(var i in locale){\n\t\t\t\t\t\tif(locale[i] && typeof locale[i] === \"object\"){\n\t\t\t\t\t\t\tif(!gantt.locale[i]){\n\t\t\t\t\t\t\t\tgantt.locale[i] = {};\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tgantt.mixin(gantt.locale[i], locale[i], true);\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tgantt.locale[i] = locale[i];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tgetLocale: i18n.getLocale\n\t};\n\tgantt.i18n.setLocale(\"en\");\n\treturn gantt;\n};","import * as utils from \"../../utils/utils\";\n\nfunction extendSettings (store, parentSettings){\n\tvar own = this.$config[store];\n\n\tif(own){\n\t\tif(!own.$extendedConfig){\n\t\t\town.$extendedConfig = true;\n\t\t\tObject.setPrototypeOf(own, parentSettings);\n\t\t}\n\t\treturn own;\n\t}else{\n\t\treturn parentSettings;\n\t}\n}\n\nvar configurable = function(parentView){\n\tvar parentConfig,\n\t\tparentTemplates;\n\n\treturn {\n\t\t$getConfig: function(){\n\t\t\tif(!parentConfig){\n\t\t\t\tparentConfig = parentView ? parentView.$getConfig() : this.$gantt.config;\n\t\t\t}\n\t\t\tif(!this.$config.config){\n\t\t\t\treturn parentConfig;\n\t\t\t}else{\n\t\t\t\treturn extendSettings.call(this, \"config\", parentConfig);\n\t\t\t}\n\t\t},\n\t\t$getTemplates: function(){\n\t\t\tif(!parentTemplates){\n\t\t\t\tparentTemplates = parentView ? parentView.$getTemplates() : this.$gantt.templates;\n\t\t\t}\n\t\t\tif(!this.$config.templates){\n\t\t\t\treturn parentTemplates;\n\t\t\t}else{\n\t\t\t\treturn extendSettings.call(this, \"templates\", parentTemplates);\n\t\t\t}\n\t\t}\n\t};\n};\n\nexport default function(obj, parent){\n\tutils.mixin(obj, configurable(parent));\n};","import * as utils from \"../../utils/utils\";\nimport configurable from \"./configurable\";\n\nvar uiFactory = function createFactory(gantt){\n\tvar views = {};\n\n\tfunction ui(cell, parentView) {\n\t\tvar content;\n\t\tvar view = \"cell\";\n\t\tif (cell.view){\n\t\t\tview = \"viewcell\";\n\t\t}else if (cell.resizer) {\n\t\t\tview = \"resizer\";\n\t\t}\n\t\telse if (cell.rows || cell.cols) {\n\t\t\tview = \"layout\";\n\t\t}\n\t\telse if (cell.views) {\n\t\t\tview = \"multiview\";\n\t\t}\n\n\t\tcontent = createView.call(this, view, null, cell, parentView);\n\t\treturn content;\n\t}\n\t\n\tvar createdViews = {};\n\n\tfunction createView(name, parent, config, parentView) {\n\t\tvar creator = views[name];\n\n\t\tif(!creator || !creator.create)\n\t\t\treturn false;\n\n\t\tif(name == \"resizer\" && !config.mode){\n\t\t\tif(parentView.$config.cols){\n\t\t\t\tconfig.mode = \"x\";\n\t\t\t}else{\n\t\t\t\tconfig.mode = \"y\";\n\t\t\t}\n\t\t}\n\n\t\tif(name == \"viewcell\" && config.view == \"scrollbar\" && !config.scroll){\n\t\t\tif(parentView.$config.cols){\n\t\t\t\tconfig.scroll = \"y\";\n\t\t\t}else{\n\t\t\t\tconfig.scroll = \"x\";\n\t\t\t}\n\t\t}\n\n\t\tvar config = utils.copy(config);\n\n\t\tif(!config.id && !createdViews[config.view]){\n\t\t\tconfig.id = config.view;\n\t\t}\n\n\t\tif(config.id && !config.css){\n\t\t\tconfig.css = config.id+\"_cell\";\n\t\t}\n\n\t\tvar view = new creator.create(parent, config, this, gantt);\n\n\t\tif(creator.configure){\n\t\t\tcreator.configure(view);\n\t\t}\n\n\t\tconfigurable(view, parentView);\n\t\tif(!view.$id){\n\t\t\tview.$id = config.id || gantt.uid();\n\t\t}\n\n\t\tif(!view.$parent && typeof parent == \"object\"){\n\t\t\tview.$parent = parent;\n\t\t}\n\t\tif(!view.$config){\n\t\t\tview.$config = config;\n\t\t}\n\n\t\tif(createdViews[view.$id]){\n\t\t\tview.$id = gantt.uid();\n\t\t}\n\n\t\tcreatedViews[view.$id] = view;\n\n\t\treturn view;\n\t}\n\n\tfunction reset(){\n\t\tcreatedViews = {};\n\t}\n\n\tfunction register(name, viewConstructor, configure){\n\t\tviews[name] = {create: viewConstructor, configure: configure};\n\t}\n\n\tfunction getView(id){\n\t\treturn createdViews[id];\n\t}\n\n\tvar factory = {\n\t\tinitUI:ui,\n\t\treset: reset,\n\t\tregisterView: register,\n\t\tcreateView: createView,\n\t\tgetView: getView\n\t};\n\n\treturn factory;\n};\n\nexport default {\n\tcreateFactory: uiFactory\n};\n\n","import * as domHelpers from \"./utils/dom_helpers\";\n\nvar createMouseHandler = (function(domHelpers) {\n\treturn function (gantt) {\n\t\tvar eventHandlers = {\n\t\t\t\"click\": {},\n\t\t\t\"doubleclick\": {},\n\t\t\t\"contextMenu\": {}\n\t\t};\n\n\t\tfunction addEventTarget(event, className, handler, root) {\n\t\t\tif(!eventHandlers[event][className]){\n\t\t\t\teventHandlers[event][className] = [];\n\t\t\t}\n\n\t\t\teventHandlers[event][className].push({\n\t\t\t\thandler: handler,\n\t\t\t\troot: root\n\t\t\t});\n\t\t}\n\n\t\tfunction callHandler(eventName, className, root, args) {\n\t\t\tvar handlers = eventHandlers[eventName][className];\n\t\t\tif(handlers){\n\t\t\t\tfor(var i = 0; i < handlers.length; i++){\n\t\t\t\t\tif(!(root || handlers[i].root) || handlers[i].root === root){\n\t\t\t\t\t\thandlers[i].handler.apply(this, args);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction onClick(e) {\n\t\t\te = e || window.event;\n\t\t\tvar id = gantt.locate(e);\n\n\t\t\tvar handlers = findEventHandlers(e, eventHandlers.click);\n\t\t\tvar res = true;\n\t\t\tif (id !== null) {\n\t\t\t\tres = !gantt.checkEvent(\"onTaskClick\") || gantt.callEvent(\"onTaskClick\", [id, e]);\n\t\t\t} else {\n\t\t\t\tgantt.callEvent(\"onEmptyClick\", [e]);\n\t\t\t}\n\n\t\t\tif (res) {\n\t\t\t\tvar default_action = callEventHandlers(handlers, e, id);\n\t\t\t\tif (!default_action)\n\t\t\t\t\treturn;\n\n\t\t\t\t// GS-1025: if we don't do that, the dropdown or date select will be closed for unselected tasks\n\t\t\t\t// GS-1078: or for the built-in select inline editor\n\t\t\t\tswitch(e.target.nodeName) {\n\t\t\t\t\tcase \"SELECT\":\n\t\t\t\t\tcase 'INPUT':\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t//allow task selection when the multiselect plugin is not enabled\n\t\t\t\tif (id && gantt.getTask(id) && !gantt._multiselect && gantt.config.select_task) {\n\t\t\t\t\tgantt.selectTask(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction onContextMenu(e) {\n\t\t\te = e || window.event;\n\t\t\tvar src = e.target || e.srcElement,\n\t\t\t\ttaskId = gantt.locate(src),\n\t\t\t\tlinkId = gantt.locate(src, gantt.config.link_attribute);\n\n\t\t\tvar res = !gantt.checkEvent(\"onContextMenu\") || gantt.callEvent(\"onContextMenu\", [taskId, linkId, e]);\n\t\t\tif (!res) {\n\t\t\t\tif (e.preventDefault)\n\t\t\t\t\te.preventDefault();\n\t\t\t\telse\n\t\t\t\t\te.returnValue = false;\n\t\t\t}\n\t\t\treturn res;\n\t\t}\n\n\t\tfunction findEventHandlers(e, hash){\n\t\t\tvar trg = e.target || e.srcElement;\n\t\t\tvar handlers = [];\n\t\t\twhile (trg) {\n\t\t\t\tvar css = domHelpers.getClassName(trg);\n\t\t\t\tif (css) {\n\t\t\t\t\tcss = css.split(\" \");\n\t\t\t\t\tfor (var i = 0; i < css.length; i++) {\n\t\t\t\t\t\tif (!css[i]) continue;\n\t\t\t\t\t\tif (hash[css[i]]) {\n\t\t\t\t\t\t\tvar delegateHandlers = hash[css[i]];\n\n\t\t\t\t\t\t\tfor(var h = 0; h < delegateHandlers.length; h++){\n\t\t\t\t\t\t\t\tif(delegateHandlers[h].root){\n\t\t\t\t\t\t\t\t\tif(!domHelpers.isChildOf(trg, delegateHandlers[h].root)){\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\thandlers.push(delegateHandlers[h].handler);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttrg = trg.parentNode;\n\t\t\t}\n\t\t\treturn handlers;\n\t\t}\n\n\t\tfunction callEventHandlers(handlers, e, id){\n\t\t\tvar res = true;\n\n\t\t\tfor(var i = 0; i < handlers.length; i++){\n\t\t\t\tvar handlerResult = handlers[i].call(gantt, e, id, e.target || e.srcElement);\n\t\t\t\tres = res && !(typeof handlerResult != \"undefined\" && handlerResult !== true);\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\n\n\t\tfunction onDoubleClick(e) {\n\t\t\te = e || window.event;\n\t\t\tvar id = gantt.locate(e);\n\n\t\t\tvar handlers = findEventHandlers(e, eventHandlers.doubleclick);\n\t\t\t// when doubleclick fired not on task, id === null\n\t\t\tvar res = !gantt.checkEvent(\"onTaskDblClick\") || id === null || gantt.callEvent(\"onTaskDblClick\", [id, e]);\n\t\t\tif (res) {\n\t\t\t\tvar default_action = callEventHandlers(handlers, e, id);\n\t\t\t\tif (!default_action)\n\t\t\t\t\treturn;\n\n\t\t\t\tif (id !== null && gantt.getTask(id)) {\n\t\t\t\t\tif (res && gantt.config.details_on_dblclick && !gantt.isReadonly(id)) {\n\t\t\t\t\t\tgantt.showLightbox(id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction onMouseMove(e) {\n\t\t\tif (gantt.checkEvent(\"onMouseMove\")) {\n\t\t\t\tvar id = gantt.locate(e);\n\t\t\t\tgantt._last_move_event = e;\n\t\t\t\tgantt.callEvent(\"onMouseMove\", [id, e]);\n\t\t\t}\n\t\t}\n\n\t\tfunction detach(eventName, className, handler, root) {\n\t\t\tif (eventHandlers[eventName] && eventHandlers[eventName][className]) {\n\t\t\t\tvar handlers = eventHandlers[eventName];\n\t\t\t\tvar elementHandlers = handlers[className];\n\t\t\t\tfor(var i = 0; i < elementHandlers.length; i++){\n\t\t\t\t\tif(elementHandlers[i].root == root){\n\t\t\t\t\t\telementHandlers.splice(i, 1);\n\t\t\t\t\t\ti--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(!elementHandlers.length){\n\t\t\t\t\tdelete handlers[className];\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\tvar domEvents = gantt._createDomEventScope();\n\n\t\tfunction reset(node){\n\n\t\t\tdomEvents.detachAll();\n\n\t\t\tif(node){\n\t\t\t\tdomEvents.attach(node, \"click\", onClick);\n\t\t\t\tdomEvents.attach(node, \"dblclick\", onDoubleClick);\n\t\t\t\tdomEvents.attach(node, \"mousemove\", onMouseMove);\n\t\t\t\tdomEvents.attach(node, \"contextmenu\", onContextMenu);\n\t\t\t}\n\t\t}\n\n\n\n\t\treturn {\n\t\t\treset: reset,\n\t\t\tglobal: function(event, classname, handler){\n\t\t\t\taddEventTarget(event, classname, handler, null);\n\t\t\t},\n\t\t\tdelegate: addEventTarget,\n\t\t\tdetach: detach,\n\t\t\tcallHandler: callHandler,\n\t\t\tonDoubleClick: onDoubleClick,\n\t\t\tonMouseMove: onMouseMove,\n\t\t\tonContextMenu: onContextMenu,\n\t\t\tonClick: onClick,\n\t\t\tdestructor: function(){\n\t\t\t\treset();\n\t\t\t\teventHandlers = null;\n\t\t\t\tdomEvents = null;\n\t\t\t}\n\n\t\t};\n\t};\n\n})(domHelpers);\n\n\nexport default {\n\tinit:createMouseHandler\n};","export default function(viewport, box, gantt){\n\tif(!box){\n\t\treturn false;\n\t}\n\n\tif(box.left > viewport.x_end || box.left + box.width < viewport.x){\n\t\treturn false;\n\t}\n\n\tif(box.top > viewport.y_end || box.top + box.height < viewport.y){\n\t\treturn false;\n\t}\n\t\n\treturn true;\n};","export default function(gantt){\n\treturn gantt.config.smart_rendering && gantt._smart_render;\n};","export default function(item, view, config){\n\treturn {\n\t\ttop: view.getItemTop(item.id),\n\t\theight: view.getItemHeight(item.id),\n\t\tleft: 0,\n\t\tright: Infinity\n\t};\n};","export default function getVisibleTasksRange(gantt, view, config, datastore, viewport){\n\tvar buffer = 1;\n\tvar start = view.getItemIndexByTopPosition(viewport.y) || 0;\n\tvar end = view.getItemIndexByTopPosition(viewport.y_end) || datastore.count();\n\tvar indexStart = Math.max(0, start - buffer);\n\tvar indexEnd = Math.min(datastore.count(), end + buffer);\n\t// GS-2481 and GS-1715, need to take into account selected task when using keyboard shortcuts and when the inline editor is opened \n\tconst extraTasksIds= [];\n\tif (gantt.config.keyboard_navigation && gantt.getSelectedId()) {\n\t\textraTasksIds.push(gantt.getSelectedId());\n\t}\n\tif (gantt.$ui.getView(\"grid\") && gantt.ext.inlineEditors && gantt.ext.inlineEditors.getState().id) {\n\t\tlet inlineEditorId = gantt.ext.inlineEditors.getState().id;\n\t\tif (datastore.exists(inlineEditorId)){\n\t\t\textraTasksIds.push(inlineEditorId);\n\t\t}\n\t}\n\treturn {\n\t\tstart: indexStart,\n\t\tend: indexEnd,\n\t\tids: extraTasksIds \n\t};\n};","import genericViewPortChecker from \"./viewport/is_in_viewport\";\nimport isLegacyRender from \"./is_legacy_smart_render\";\nimport basicGetRectangle from \"./viewport/get_grid_row_rectangle\";\nimport basicGetRange from \"./viewport/get_visible_bars_range\";\nvar rendererFactory = function(gantt){\n\n\t//hash of dom elements is needed to redraw single bar/link\n\tvar task_area_pulls = {},\n\t\ttask_area_renderers = {};\n\n\tfunction getView(layer){\n\t\tvar view = null;\n\t\tif (typeof layer.view === \"string\") {\n\t\t\tview = gantt.$ui.getView(layer.view);\n\t\t} else if (layer.view) {\n\t\t\tview = layer.view;\n\t\t}\n\t\treturn view;\n\t}\n\n\tfunction getRenderer(id, layer, node) {\n\t\t\n\t\tif (task_area_renderers[id])\n\t\t\treturn task_area_renderers[id];\n\n\t\tif (!layer.renderer)\n\t\t\tgantt.assert(false, \"Invalid renderer call\");\n\n\t\tvar renderMethod = null;\n\t\tvar updateMethod = null;\n\t\tvar getRectangle = null;\n\t\tvar renderCallbackMethod = null;\n\t\tvar specializedViewPortChecker = null;\n\n\t\tif(typeof layer.renderer === \"function\"){\n\t\t\trenderMethod = layer.renderer;\n\t\t\tgetRectangle = basicGetRectangle;\n\t\t}else{\n\t\t\trenderMethod = layer.renderer.render;\n\t\t\tupdateMethod = layer.renderer.update;\n\t\t\trenderCallbackMethod = layer.renderer.onrender;\n\t\t\t\n\t\t\tif(layer.renderer.isInViewPort){\n\t\t\t\tspecializedViewPortChecker = layer.renderer.isInViewPort;\n\t\t\t}else{\n\t\t\t\tgetRectangle = layer.renderer.getRectangle;\n\t\t\t}\n\n\t\t\tif (!getRectangle && getRectangle !== null) {\n\t\t\t\tgetRectangle = basicGetRectangle;\n\t\t\t}\n\t\t}\n\n\t\tvar filter = layer.filter;\n\n\t\tif (node)\n\t\t\tnode.setAttribute(gantt.config.layer_attribute, true);\n\n\t\ttask_area_renderers[id] = {\n\t\t\trender_item: function (item, container, viewPort, layerView, viewConfig) {\n\t\t\t\tcontainer = container || node;\n\t\t\t\tif (filter) {\n\t\t\t\t\tif (!filter(item)) {\n\t\t\t\t\t\tthis.remove_item(item.id);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar view = layerView || getView(layer);\n\t\t\t\tvar config = viewConfig || (view ? view.$getConfig() : null);\n\t\t\t\tvar rendererViewPort = viewPort;\n\t\t\t\tif(!rendererViewPort && config && config.smart_rendering){\n\t\t\t\t\trendererViewPort = view.getViewPort();\n\t\t\t\t}\n\n\t\t\t\tvar dom = null;\n\t\t\t\tif(!isLegacyRender(gantt) && (getRectangle || specializedViewPortChecker) && rendererViewPort){\n\t\t\t\t\tvar isVisible = false;\n\t\t\t\t\tif(specializedViewPortChecker){\n\t\t\t\t\t\tisVisible = specializedViewPortChecker(item, rendererViewPort, view, config, gantt);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tisVisible = genericViewPortChecker(rendererViewPort, getRectangle(item, view, config, gantt), gantt);\n\t\t\t\t\t}\n\t\t\t\t\tif(isVisible){\n\t\t\t\t\t\tdom = renderMethod.call(gantt, item, view, config, rendererViewPort);\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\tdom = renderMethod.call(gantt, item, view, config, rendererViewPort);\n\t\t\t\t}\n\t\t\t\tthis.append(item, dom, container);\n\n\t\t\t\tvar useBuffer = container.nodeType == 11;//DocumentFragment\n\t\t\t\tif(renderCallbackMethod && !useBuffer && dom) {\n\t\t\t\t\trenderCallbackMethod.call(gantt, item, dom, view);\n\t\t\t\t} \n\t\t\t},\n\n\t\t\tclear: function (container) {\n\n\t\t\t\tthis.rendered = task_area_pulls[id] = {};\n\t\t\t\tif(!layer.append)\n\t\t\t\t\tthis.clear_container(container);\n\t\t\t},\n\t\t\tclear_container: function (container) {\n\t\t\t\tcontainer = container || node;\n\t\t\t\tif (container){\n\t\t\t\t\tcontainer.innerHTML = \"\";\n\t\t\t\t}\n\t\t\t},\n\t\t\tget_visible_range: function(datastore){\n\t\t\t\tvar view = getView(layer);\n\t\t\t\tvar viewport;\n\t\t\t\tvar viewConfig = view ? view.$getConfig() : null;\n\t\t\t\tif(viewConfig && viewConfig.smart_rendering){\n\t\t\t\t\tviewport = view.getViewPort();\n\t\t\t\t}\n\n\t\t\t\tvar range;\n\t\t\t\tif(view && viewport){\n\t\t\t\t\tif(typeof layer.renderer === \"function\"){\n\t\t\t\t\t\trange = basicGetRange(gantt, view, viewConfig, datastore, viewport);\n\t\t\t\t\t}else if(layer.renderer && layer.renderer.getVisibleRange){\n\t\t\t\t\t\trange = layer.renderer.getVisibleRange(gantt, view, viewConfig, datastore, viewport);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(!range){\n\t\t\t\t\trange = {\n\t\t\t\t\t\tstart: 0,\n\t\t\t\t\t\tend: datastore.count()\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn range;\n\t\t\t},\n\t\t\tprepare_data: function(items){\n\t\t\t\tif(layer.renderer && layer.renderer.prepareData){\n\t\t\t\t\treturn layer.renderer.prepareData(items, gantt, layer);\n\t\t\t\t}\n\t\t\t},\n\t\t\trender_items: function (items, container) {\n\t\t\t\tcontainer = container || node;\n\n\t\t\t\tvar buffer = document.createDocumentFragment();\n\t\t\t\tthis.clear(container);\n\n\t\t\t\tvar viewPort = null;\n\t\t\t\tvar view = getView(layer);\n\t\t\t\tvar viewConfig = view ? view.$getConfig() : null;\n\t\t\t\tif(viewConfig && viewConfig.smart_rendering){\n\t\t\t\t\tviewPort = view.getViewPort();\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0, vis = items.length; i < vis; i++) {\n\t\t\t\t\tthis.render_item(items[i], buffer, viewPort, view, viewConfig);\n\t\t\t\t}\n\n\t\t\t\tcontainer.appendChild(buffer, container);\n\n\t\t\t\tvar itemsSearch = {};\n\t\t\t\titems.forEach(function(item){\n\t\t\t\t\titemsSearch[item.id] = item;\n\t\t\t\t});\n\t\t\t\tvar renderedItems = {};\n\t\t\t\tif (renderCallbackMethod) {\n\t\t\t\t\tvar newElements = {};\n\t\t\t\t\tfor(var i in this.rendered) {\n\t\t\t\t\t\tif(!renderedItems[i]){\n\t\t\t\t\t\t\tnewElements[i] = this.rendered[i];\n\t\t\t\t\t\t\trenderCallbackMethod.call(gantt, itemsSearch[i], this.rendered[i], view);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t},\n\t\t\tupdate_items: function (items, container) {\n\t\t\t\tvar view = getView(layer);\n\t\t\t\tvar viewConfig = view ? view.$getConfig() : null;\n\t\t\t\tif(!view || !view.$getConfig().smart_rendering || isLegacyRender(gantt)){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif(!this.rendered){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif(!(getRectangle || specializedViewPortChecker)){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontainer = container || node;\n\n\t\t\t\tvar buffer = document.createDocumentFragment();\n\n\t\t\t\tvar viewPort = null;\n\t\t\t\tif(view){\n\t\t\t\t\tviewPort = view.getViewPort();\n\t\t\t\t}\n\n\t\t\t\tvar itemsSearch = {};\n\t\t\t\titems.forEach(function(item){\n\t\t\t\t\titemsSearch[item.id] = item;\n\t\t\t\t});\n\t\t\t\tvar renderedItems = {};\n\n\t\t\t\tvar nodesToRemove = {};\n\t\t\t\tfor(var i in this.rendered){\n\t\t\t\t\tnodesToRemove[i] = true;\n\t\t\t\t\trenderedItems[i] = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar renderCalledFor = {};\n\t\t\t\tfor (var i = 0, vis = items.length; i < vis; i++) {\n\t\t\t\t\tvar item = items[i];\n\t\t\t\t\tvar itemNode = this.rendered[item.id];\n\t\t\t\t\tnodesToRemove[item.id] = false;\n\t\t\t\t\tif (itemNode && itemNode.parentNode) {\n\t\t\t\t\t\tvar isVisible = false;\n\t\t\t\t\t\tif(specializedViewPortChecker){\n\t\t\t\t\t\t\tisVisible = specializedViewPortChecker(item, viewPort, view, viewConfig, gantt);\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tisVisible = genericViewPortChecker(viewPort, getRectangle(item, view, viewConfig, gantt), gantt);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!isVisible) {\n\t\t\t\t\t\t\tnodesToRemove[item.id] = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif(updateMethod){\n\t\t\t\t\t\t\t\tupdateMethod.call(gantt, item, itemNode, view, viewConfig, viewPort);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.restore(item, buffer);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\trenderCalledFor[items[i].id] = true;\n\t\t\t\t\t\tthis.render_item(items[i], buffer, viewPort, view, viewConfig);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor(var i in nodesToRemove){\n\t\t\t\t\tif(nodesToRemove[i]){\n\t\t\t\t\t\tthis.hide(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(buffer.childNodes.length){\n\t\t\t\t\tcontainer.appendChild(buffer, container);\n\t\t\t\t}\n\n\t\t\t\tif (renderCallbackMethod) {\n\t\t\t\t\tvar newElements = {};\n\t\t\t\t\tfor(var i in this.rendered) {\n\t\t\t\t\t\tif(!renderedItems[i] || renderCalledFor[i]){\n\t\t\t\t\t\t\tnewElements[i] = this.rendered[i];\n\t\t\t\t\t\t\trenderCallbackMethod.call(gantt, itemsSearch[i], this.rendered[i], view);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t},\n\t\t\tappend: function (item, node, container) {\n\t\t\t\tif(!this.rendered){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!node) {\n\t\t\t\t\tif (this.rendered[item.id]) {\n\t\t\t\t\t\tthis.remove_item(item.id);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (this.rendered[item.id] && this.rendered[item.id].parentNode) {\n\t\t\t\t\tthis.replace_item(item.id, node);\n\t\t\t\t} else {\n\t\t\t\t\tcontainer.appendChild(node);\n\t\t\t\t}\n\t\t\t\tthis.rendered[item.id] = node;\n\t\t\t},\n\t\t\treplace_item: function (item_id, newNode) {\n\t\t\t\tvar item = this.rendered[item_id];\n\t\t\t\tif (item && item.parentNode) {\n\t\t\t\t\titem.parentNode.replaceChild(newNode, item);\n\n\t\t\t\t}\n\t\t\t\tthis.rendered[item_id] = newNode;\n\t\t\t},\n\t\t\tremove_item: function (item_id) {\n\t\t\t\tthis.hide(item_id);\n\t\t\t\tdelete this.rendered[item_id];\n\t\t\t},\n\t\t\thide: function (item_id) {\n\t\t\t\tvar item = this.rendered[item_id];\n\t\t\t\tif (item && item.parentNode) {\n\t\t\t\t\titem.parentNode.removeChild(item);\n\t\t\t\t}\n\t\t\t},\n\t\t\trestore: function (item, container) {\n\t\t\t\tvar dom = this.rendered[item.id];\n\t\t\t\tif (dom) {\n\t\t\t\t\tif (!dom.parentNode) {\n\t\t\t\t\t\tthis.append(item, dom, container || node);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.render_item(item, container || node);\n\t\t\t\t}\n\t\t\t},\n\t\t\tchange_id: function (oldid, newid) {\n\t\t\t\tthis.rendered[newid] = this.rendered[oldid];\n\t\t\t\tdelete this.rendered[oldid];\n\t\t\t},\n\t\t\trendered: task_area_pulls[id],\n\t\t\tnode: node,\n\t\t\tdestructor: function () {\n\t\t\t\tthis.clear();\n\t\t\t\tdelete task_area_renderers[id];\n\t\t\t\tdelete task_area_pulls[id];\n\t\t\t}\n\t\t};\n\n\t\treturn task_area_renderers[id];\n\t}\n\n\n\tfunction clearRenderers() {\n\t\tfor (var i in task_area_renderers) {\n\t\t\tgetRenderer(i).destructor();\n\t\t}\n\t}\n\n\treturn {\n\t\tgetRenderer: getRenderer,\n\t\tclearRenderers: clearRenderers\n\t};\n\n};\n\nexport default rendererFactory;","import renderFactoryProvider from \"./render_factory\";\nimport * as utils from \"../../../utils/utils\";\nimport * as domHelpers from \"../utils/dom_helpers\";\nimport isLegacyRender from \"./is_legacy_smart_render\";\n\nvar layerFactory = function(gantt){\n\n\tvar renderFactory = renderFactoryProvider(gantt);\n\treturn {\n\tcreateGroup: function (getContainer, relativeRoot, defaultFilters, initLayer) {\n\n\t\tvar renderGroup = {\n\t\t\ttempCollection: [],\n\t\t\trenderers: {},\n\t\t\tcontainer: getContainer,\n\t\t\tfilters: [],\n\t\t\tgetLayers: function () {\n\t\t\t\tthis._add();// add pending layers\n\n\t\t\t\tvar res = [];\n\t\t\t\tfor (var i in this.renderers) {\n\t\t\t\t\tres.push(this.renderers[i]);\n\t\t\t\t}\n\t\t\t\treturn res;\n\t\t\t},\n\t\t\tgetLayer: function (id) {\n\t\t\t\treturn this.renderers[id];\n\t\t\t},\n\t\t\t_add: function (layer) {\n\t\t\t\tif (layer) {\n\t\t\t\t\tlayer.id = layer.id || utils.uid();\n\t\t\t\t\tthis.tempCollection.push(layer);\n\t\t\t\t}\n\n\t\t\t\tvar container = this.container();\n\n\t\t\t\tvar pending = this.tempCollection;\n\t\t\t\tfor (var i = 0; i < pending.length; i++) {\n\t\t\t\t\tlayer = pending[i];\n\n\t\t\t\t\tif (!this.container() && !(layer && layer.container && domHelpers.isChildOf(layer.container, document.body))) continue;\n\n\t\t\t\t\tvar node = layer.container,\n\t\t\t\t\t\tid = layer.id,\n\t\t\t\t\t\ttopmost = layer.topmost;\n\t\t\t\t\tif (!node.parentNode) {\n\t\t\t\t\t\t//insert on top or below the tasks\n\t\t\t\t\t\tif (topmost) {\n\t\t\t\t\t\t\tcontainer.appendChild(node);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar rel = relativeRoot ? relativeRoot() : container.firstChild;\n\t\t\t\t\t\t\t// GS-1274: if we don't add the second check, Gantt stops working if\n\t\t\t\t\t\t\t// we add the task layer without the timeline and switch to a layout with the timeline\n\t\t\t\t\t\t\tif (rel && rel.parentNode == container)\n\t\t\t\t\t\t\t\tcontainer.insertBefore(node, rel);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tcontainer.appendChild(node);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.renderers[id] = renderFactory.getRenderer(\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tlayer,\n\t\t\t\t\t\tnode\n\t\t\t\t\t);\n\n\t\t\t\t\tif (initLayer) {\n\t\t\t\t\t\tinitLayer(layer, gantt);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.tempCollection.splice(i, 1);\n\t\t\t\t\ti--;\n\t\t\t\t}\n\t\t\t},\n\t\t\taddLayer: function (config) {\n\t\t\t\tif(config){\n\t\t\t\t\tif(typeof config == \"function\"){\n\t\t\t\t\t\tconfig = {renderer: config};\n\t\t\t\t\t}\n\n\t\t\t\t\tif(config.filter === undefined){\n\t\t\t\t\t\tconfig.filter = mergeFilters(defaultFilters || []);\n\t\t\t\t\t}else if(config.filter instanceof Array){\n\t\t\t\t\t\tconfig.filter.push(defaultFilters);\n\t\t\t\t\t\tconfig.filter = mergeFilters(config.filter);\n\t\t\t\t\t}\n\n\t\t\t\t\tif(!config.container){\n\t\t\t\t\t\tconfig.container = document.createElement(\"div\");\n\t\t\t\t\t}\n\t\t\t\t\tvar self = this;\n\t\t\t\t\tconfig.requestUpdate = function(){\n\t\t\t\t\t\tif(gantt.config.smart_rendering && !isLegacyRender(gantt)){\n\t\t\t\t\t\t\tif(self.renderers[config.id]){\n\t\t\t\t\t\t\t\tself.onUpdateRequest(self.renderers[config.id]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tthis._add(config);\n\t\t\t\treturn (config ? config.id : undefined);\n\t\t\t},\n\t\t\tonUpdateRequest: function(layer){\n\n\t\t\t},\n\n\t\t\teachLayer: function(code){\n\t\t\t\tfor (var i in this.renderers) {\n\t\t\t\t\tcode(this.renderers[i]);\n\t\t\t\t}\n\t\t\t},\n\t\t\tremoveLayer: function (id) {\n\t\t\t\tif(!this.renderers[id])\n\t\t\t\t\treturn;\n\t\t\t\tthis.renderers[id].destructor();\n\t\t\t\tdelete this.renderers[id];\n\t\t\t},\n\t\t\tclear: function () {\n\t\t\t\tfor (var i in this.renderers) {\n\t\t\t\t\tthis.renderers[i].destructor();\n\t\t\t\t}\n\t\t\t\tthis.renderers = {};\n\t\t\t}//,\n\t\t\t//prepareConfig: prepareConfig\n\t\t};\n\n\t\tgantt.attachEvent(\"onDestroy\", function(){\n\t\t\trenderGroup.clear();\n\t\t\trenderGroup = null;\n\t\t});\n\n\t\treturn renderGroup;\n\t}\n};};\n\n\nfunction mergeFilters(filter_methods){\n\tif(!(filter_methods instanceof Array)){\n\t\tfilter_methods = Array.prototype.slice.call(arguments, 0);\n\t}\n\n\treturn function(obj){\n\t\tvar res = true;\n\t\tfor(var i = 0, len = filter_methods.length; i < len; i++){\n\t\t\tvar filter_method = filter_methods[i];\n\t\t\tif(filter_method){\n\t\t\t\tres = res && (filter_method(obj.id, obj) !== false);\n\t\t\t}\n\t\t}\n\n\t\treturn res;\n\t};\n}\n\n\nexport default layerFactory;\n","export default function(item, view, config){\n\tif(!item.start_date || !item.end_date){\n\t\treturn null;\n\t}\n\tvar padding = 200;\n\tvar startCoord = view.posFromDate(item.start_date);\n\tvar endCoord = view.posFromDate(item.end_date);\n\tvar left = Math.min(startCoord, endCoord) - padding;\n\tvar right = Math.max(startCoord, endCoord) + padding;\n\treturn {\n\t\ttop: view.getItemTop(item.id),\n\t\theight: view.getItemHeight(item.id),\n\t\tleft: left,\n\t\twidth: right - left\n\t};\n};","import getLinkRectangle from \"../get_link_rectangle\";\n\nexport default function(){\n\tvar coordinates = [];\n\tvar calculated = false;\n\n\tfunction clearCache(){\n\t\tcoordinates = [];\n\t\tcalculated = false;\n\t}\n\n\tfunction buildCache(datastore, view, gantt){\n\t\tvar config = view.$getConfig();\n\t\tvar visibleItems = datastore.getVisibleItems();\n\t\t//datastore.eachItem(function(link){\n\t\tvisibleItems.forEach(function(link){\n\t\t\tvar rec = getLinkRectangle(link, view, config, gantt);\n\t\t\tif(!rec){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcoordinates.push({id: link.id, rec: rec});\n\t\t});\n\n\t\tcoordinates.sort(function(a, b){\n\t\t\tif(a.rec.right < b.rec.right){\n\t\t\t\treturn -1;\n\t\t\t}else {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t});\n\n\t\tcalculated = true;\n\t}\n\n\tvar initialized = false;\n\tfunction init(datastore){\n\t\tif(initialized){\n\t\t\treturn;\n\t\t}\n\t\tinitialized = true;\n\t\tdatastore.attachEvent(\"onPreFilter\", clearCache);\n\t\tdatastore.attachEvent(\"onStoreUpdated\", clearCache);\n\t\tdatastore.attachEvent(\"onClearAll\", clearCache);\n\t\tdatastore.attachEvent(\"onBeforeStoreUpdate\", clearCache);\n\t}\n\n\treturn function getVisibleLinksRange(gantt, view, config, datastore, viewport){\n\t\tinit(datastore);\n\t\tif(!calculated){\n\t\t\tbuildCache(datastore, view, gantt);\n\t\t}\n\n\t\tvar visibleBoxes = [];\n\t\tfor(var i = 0; i < coordinates.length; i++){\n\t\t\tvar item = coordinates[i];\n\t\t\tvar box = item.rec;\n\t\t\tif(box.right < viewport.x){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(box.left < viewport.x_end && box.right > viewport.x && box.top < viewport.y_end && box.bottom > viewport.y){\n\t\t\t\tvisibleBoxes.push(item.id);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn {\n\t\t\tids: visibleBoxes\n\t\t};\n\t};\n};","\n\nimport barRectangle from \"./get_bar_rectangle\";\n\nexport default function getLinkBox(item, view, config, gantt){\n\tif(!gantt.isTaskExists(item.source)){\n\t\treturn null;\n\t}\n\n\tif(!gantt.isTaskExists(item.target)){\n\t\treturn null;\n\t}\n\tvar sourceBox = barRectangle(gantt.getTask(item.source), view, gantt);\n\tvar targetBox = barRectangle(gantt.getTask(item.target), view, gantt);\n\n\tif(!sourceBox || !targetBox){\n\t\treturn null;\n\t}\n\n\tvar padding = 100;\n\tvar left = Math.min(sourceBox.left, targetBox.left) - padding;\n\tvar right = Math.max(sourceBox.left + sourceBox.width, targetBox.left + targetBox.width) + padding;\n\tvar top = Math.min(sourceBox.top, targetBox.top) - padding;\n\tvar bottom = Math.max(sourceBox.top + sourceBox.height, targetBox.top + targetBox.height) + padding;\n\n\treturn {\n\t\ttop: top,\n\t\theight: bottom - top,\n\t\tbottom,\n\t\tleft: left,\n\t\twidth: right - left,\n\t\tright\n\t};\n};\n","\n// optimized checker for links smart rendering\n\n// first check the vertical position since it's easier to calculate\n\nexport default function isLinkInViewPort(item, viewport, view, config, gantt){\n\tvar source = view.$gantt.getTask(item.source);\n\tvar target = view.$gantt.getTask(item.target);\n\t// check vertical visibility first since it's a lighter check\n\tvar sourceTop = view.getItemTop(source.id);\n\tvar sourceHeight = view.getItemHeight(source.id);\n\n\tvar targetTop = view.getItemTop(target.id);\n\tvar targetHeight = view.getItemHeight(target.id);\n\n\tif(viewport.y > sourceTop + sourceHeight &&\n\t\tviewport.y > targetTop + targetHeight){\n\t\treturn false;\n\t}\n\n\tif(viewport.y_end < targetTop &&\n\t\tviewport.y_end < sourceTop){\n\t\treturn false;\n\t}\n\n\tvar padding = 100;\n\tvar sourceLeft = view.posFromDate(source.start_date);\n\tvar sourceRight = view.posFromDate(source.end_date);\n\tvar targetLeft = view.posFromDate(target.start_date);\n\tvar targetRight = view.posFromDate(target.end_date);\n\n\tif(sourceLeft > sourceRight){\n\t\t// rtl\n\t\tvar tmp = sourceRight;\n\t\tsourceRight = sourceLeft;\n\t\tsourceLeft = tmp;\n\t}\n\tif(targetLeft > targetRight){\n\t\t// rtl\n\t\tvar tmp = targetRight;\n\t\ttargetRight = targetLeft;\n\t\ttargetLeft = tmp;\n\t}\n\tsourceLeft += -padding; // add buffer for custom elements\n\tsourceRight += padding;\n\ttargetLeft += -padding; // add buffer for custom elements\n\ttargetRight += padding;\n\n\tif(viewport.x > sourceRight &&\n\t\tviewport.x > targetRight){\n\t\treturn false;\n\t}\n\n\tif(viewport.x_end < sourceLeft &&\n\t\tviewport.x_end < targetLeft){\n\t\treturn false;\n\t}\n\treturn true;\n};\n","import createLayerFactory from \"./render/layer_engine\";\n\nimport getVisibleTaskRange from \"./render/viewport/get_visible_bars_range\";\nimport getVisibleLinksRangeFactory from \"./render/viewport/factory/get_visible_link_range\";\n\nimport isLinkInViewport from \"./render/viewport/is_link_in_viewport\";\n\nfunction initLayer(layer, gantt){\n\tif(!layer.view){\n\t\treturn;\n\t}\n\n\tvar view = layer.view;\n\tif(typeof view === \"string\"){\n\t\tview = gantt.$ui.getView(view);\n\t}\n\n\tif(view && view.attachEvent){\n\t\tview.attachEvent(\"onScroll\", function(){\n\t\t\tvar state = gantt.$services.getService(\"state\");\n\t\t\t// don't repaint if we're inside batchUpdate, a complete repaint will be called afterwards\n\t\t\tif(!state.getState(\"batchUpdate\").batch_update && !view.$config.$skipSmartRenderOnScroll){\n\t\t\t\tif(layer.requestUpdate){\n\t\t\t\t\tlayer.requestUpdate();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n}\n\nvar createLayerEngine = function(gantt){\n\tvar factory = createLayerFactory(gantt);\n\treturn {\n\t\tgetDataRender: function(name){\n\t\t\treturn gantt.$services.getService(\"layer:\" + name) || null;\n\t\t},\n\t\tcreateDataRender: function(config){\n\t\t\tvar name = config.name,\n\t\t\t\tdefaultContainer = config.defaultContainer,\n\t\t\t\tpreviusSiblingContainer = config.defaultContainerSibling;\n\n\t\t\tvar layers = factory.createGroup(\n\t\t\t\tdefaultContainer,\n\t\t\t\tpreviusSiblingContainer,\n\t\t\t\tfunction(itemId, item){\n\t\t\t\t\tif(layers.filters){\n\t\t\t\t\t\tfor(var i = 0; i < layers.filters.length; i++){\n\t\t\t\t\t\t\tif(layers.filters[i](itemId, item) === false){\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}else{\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tinitLayer\n\t\t\t);\n\n\t\t\tgantt.$services.setService(\"layer:\" + name, function(){\n\t\t\t\treturn layers;\n\t\t\t});\n\n\t\t\tgantt.attachEvent(\"onGanttReady\", function () {\n\t\t\t\tlayers.addLayer();// init layers on start\n\t\t\t});\n\n\t\t\treturn layers;\n\t\t},\n\t\tinit: function(){\n\t\t\tvar taskLayers = this.createDataRender({\n\t\t\t\tname: \"task\",\n\t\t\t\tdefaultContainer: function(){\n\t\t\t\t\tif(gantt.$task_data){\n\t\t\t\t\t\treturn gantt.$task_data;\n\t\t\t\t\t}else if(gantt.$ui.getView(\"timeline\")){\n\t\t\t\t\t\treturn gantt.$ui.getView(\"timeline\").$task_data;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tdefaultContainerSibling: function(){\n\t\t\t\t\tif(gantt.$task_links){\n\t\t\t\t\t\treturn gantt.$task_links;\n\t\t\t\t\t}else if(gantt.$ui.getView(\"timeline\")){\n\t\t\t\t\t\treturn gantt.$ui.getView(\"timeline\").$task_links;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tfilter: function(item){\n\n\t\t\t\t}\n\t\t\t}, gantt);\n\n\t\t\tvar linkLayers = this.createDataRender({\n\t\t\t\tname: \"link\",\n\t\t\t\tdefaultContainer: function(){\n\t\t\t\t\tif(gantt.$task_data){\n\t\t\t\t\t\treturn gantt.$task_data;\n\t\t\t\t\t}else if(gantt.$ui.getView(\"timeline\")){\n\t\t\t\t\t\treturn gantt.$ui.getView(\"timeline\").$task_data;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, gantt);\n\n\t\t\treturn {\n\t\t\t\taddTaskLayer: function(config){\n\t\t\t\t\tconst rangeFunction = getVisibleTaskRange;\n\t\t\t\t\tif(typeof config === \"function\"){\n\t\t\t\t\t\tconfig = {\n\t\t\t\t\t\t\trenderer: {\n\t\t\t\t\t\t\t\trender: config,\n\t\t\t\t\t\t\t\tgetVisibleRange: rangeFunction\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}else{\n\t\t\t\t\t\tif(config.renderer && !config.renderer.getVisibleRange){\n\t\t\t\t\t\t\tconfig.renderer.getVisibleRange = rangeFunction;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconfig.view = \"timeline\";\n\n\t\t\t\t\treturn taskLayers.addLayer(config);\n\t\t\t\t},\n\n\t\t\t\t_getTaskLayers: function(){\n\t\t\t\t\treturn taskLayers.getLayers();\n\t\t\t\t},\n\t\t\t\tremoveTaskLayer: function(id){\n\t\t\t\t\ttaskLayers.removeLayer(id);\n\t\t\t\t},\n\n\t\t\t\t_clearTaskLayers: function(){\n\t\t\t\t\ttaskLayers.clear();\n\t\t\t\t},\n\t\t\t\taddLinkLayer: function(config){\n\t\t\t\t\tconst rangeFunction = getVisibleLinksRangeFactory();\n\t\t\t\t\tif(typeof config === \"function\"){\n\t\t\t\t\t\tconfig = {\n\t\t\t\t\t\t\trenderer: {\n\t\t\t\t\t\t\t\trender: config,\n\t\t\t\t\t\t\t\tgetVisibleRange: rangeFunction\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}else{\n\t\t\t\t\t\tif(config.renderer && !config.renderer.getVisibleRange){\n\t\t\t\t\t\t\tconfig.renderer.getVisibleRange = rangeFunction;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconfig.view = \"timeline\";\n\t\t\t\t\tif(config && config.renderer){\n\t\t\t\t\t\tif(!config.renderer.getRectangle && !config.renderer.isInViewPort){\n\t\t\t\t\t\t\tconfig.renderer.isInViewPort = isLinkInViewport;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn linkLayers.addLayer(config);\n\t\t\t\t},\n\n\t\t\t\t_getLinkLayers: function(){\n\t\t\t\t\treturn linkLayers.getLayers();\n\t\t\t\t},\n\t\t\t\tremoveLinkLayer: function(id){\n\t\t\t\t\tlinkLayers.removeLayer(id);\n\t\t\t\t},\n\n\t\t\t\t_clearLinkLayers: function(){\n\t\t\t\t\tlinkLayers.clear();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t};\n};\n\nexport default createLayerEngine;","import * as utils from \"../../../utils/utils\";\nimport eventable from \"../../../utils/eventable\";\nimport * as domHelpers from \"../utils/dom_helpers\";\n\nvar Cell = (function () {\n\t\"use strict\";\n\n\tfunction Cell(parent, config, factory, gantt) {\n\t\tif (parent) {\n\t\t\tthis.$container = domHelpers.toNode(parent);\n\t\t\tthis.$parent = parent;\n\t\t}\n\t\t// save config\n\t\tthis.$config = utils.mixin(config, {\n\t\t\theaderHeight: 33\n\t\t});\n\t\tthis.$gantt = gantt;\n\t\tthis.$domEvents = gantt._createDomEventScope();\n\t\t// set id\n\t\tthis.$id = config.id || \"c\" + utils.uid();\n\n\t\tthis.$name = \"cell\";\n\t\tthis.$factory = factory;\n\n\t\teventable(this);\n\n\t}\n\n\tCell.prototype.destructor = function () {\n\t\tthis.$parent = this.$container = this.$view = null;\n\t\tvar mouse = this.$gantt.$services.getService(\"mouseEvents\");\n\t\tmouse.detach(\"click\", \"gantt_header_arrow\", this._headerClickHandler);\n\t\tthis.$domEvents.detachAll();\n\t\tthis.callEvent(\"onDestroy\", []);\n\t\tthis.detachAllEvents();\n\t};\n\tCell.prototype.cell = function (id) {\n\t\treturn null;\n\t};\n\n\tCell.prototype.scrollTo = function(left, top){\n\n\t\t//GS-333 Add a way to scroll the HTML views:\n\t\tvar cell = this.$view;\n\t\tif (this.$config.html) cell = this.$view.firstChild;\n\n\t\tif (left*1 == left){\n\t\t\tcell.scrollLeft = left;\n\t\t}\n\t\tif(top*1 == top){\n\t\t\tcell.scrollTop = top;\n\t\t}\n\t};\n\n\tCell.prototype.clear = function(){\n\t\tthis.getNode().innerHTML = \"\";\n\t\tthis.getNode().className = \"gantt_layout_content\";\n\t\tthis.getNode().style.padding = \"0\";\n\t};\n\n\tCell.prototype.resize = function (final) {\n\t\tif (this.$parent) {\n\t\t\treturn this.$parent.resize(final);\n\t\t}\n\n\t\tif(final === false){\n\t\t\tthis.$preResize = true;\n\t\t}\n\n\t\tvar topCont = this.$container;\n\t\tvar x = topCont.offsetWidth;\n\t\tvar y = topCont.offsetHeight;\n\t\tvar topSize = this.getSize();\n\t\tif (topCont === document.body) {\n\t\t\tx = document.body.offsetWidth;\n\t\t\ty = document.body.offsetHeight;\n\t\t}\n\t\tif (x < topSize.minWidth) {\n\t\t\tx = topSize.minWidth;\n\t\t}\n\t\tif (x > topSize.maxWidth) {\n\t\t\tx = topSize.maxWidth;\n\t\t}\n\t\tif (y < topSize.minHeight) {\n\t\t\ty = topSize.minHeight;\n\t\t}\n\t\tif (y > topSize.maxHeight) {\n\t\t\ty = topSize.maxHeight;\n\t\t}\n\t\tthis.setSize(x, y);\n\n\t\tif(!this.$preResize){\n\t\t//\tself.callEvent(\"onResize\", [x, y]);\n\t\t}\n\t\tthis.$preResize = false;\n\t};\n\n\tCell.prototype.hide = function () {\n\t\tthis._hide(true);\n\t\tthis.resize();\n\t};\n\tCell.prototype.show = function (force) {\n\t\tthis._hide(false);\n\t\tif (force && this.$parent) {\n\t\t\tthis.$parent.show();\n\t\t}\n\t\tthis.resize();\n\t};\n\tCell.prototype._hide = function (mode) {\n\t\tif (mode === true && this.$view.parentNode) {\n\t\t\tthis.$view.parentNode.removeChild(this.$view);\n\t\t}\n\t\telse if (mode === false && !this.$view.parentNode) {\n\t\t\tvar index = this.$parent.cellIndex(this.$id);\n\t\t\tthis.$parent.moveView(this, index);\n\t\t}\n\t\tthis.$config.hidden = mode;\n\t};\n\tCell.prototype.$toHTML = function (content, css) {\n\t\tif (content === void 0) { content = \"\"; }\n\t\tcss = [(css || \"\"), (this.$config.css || \"\")].join(\" \");\n\t\tvar obj = this.$config;\n\t\tvar header = \"\";\n\t\tif (obj.raw) {\n\t\t\tcontent = typeof obj.raw === \"string\" ? obj.raw : \"\";\n\t\t}\n\t\telse {\n\t\t\tif (!content) {\n\t\t\t\tcontent = \"
\" + (obj.html || \"\") + \"
\";\n\t\t\t}\n\t\t\tif (obj.header) {\n\t\t\t\tvar collapseIcon = obj.canCollapse ? \"
\" : \"\";\n\t\t\t\theader = \"
\" + collapseIcon + \"
\" + obj.header + \"
\";\n\t\t\t}\n\t\t}\n\t\treturn \"
\" + header + content + \"
\";\n\t};\n\tCell.prototype.$fill = function (node, parent) {\n\t\tthis.$view = node;\n\t\tthis.$parent = parent;\n\t\tthis.init();\n\t};\n\tCell.prototype.getNode = function () {\n\t\treturn (this.$view.querySelector(\"gantt_layout_cell\") || this.$view);\n\t};\n\tCell.prototype.init = function () {\n\t\t// [NOT-GOOD] code is executed for each component, while it still has only one handler, it is no good\n\n\t\tvar self = this;\n\n\t\tthis._headerClickHandler = function(e){\n\t\t\tvar cellId = domHelpers.locateAttribute(e, \"data-cell-id\");\n\t\t\tif(cellId == self.$id){\n\t\t\t\tself.toggle();\n\t\t\t}\n\t\t};\n\n\t\tvar mouse = this.$gantt.$services.getService(\"mouseEvents\");\n\t\tmouse.delegate(\"click\", \"gantt_header_arrow\", this._headerClickHandler);\n\n\t\tthis.callEvent(\"onReady\", []);\n\t};\n\tCell.prototype.toggle = function () {\n\t\tthis.$config.collapsed = !this.$config.collapsed;\n\t\tthis.resize();\n\t};\n\tCell.prototype.getSize = function () {\n\t\tvar size = {\n\t\t\theight: this.$config.height || 0,\n\t\t\twidth: this.$config.width || 0,\n\t\t\tgravity: this.$config.gravity || 1,\n\t\t\tminHeight: this.$config.minHeight || 0,\n\t\t\tminWidth: this.$config.minWidth || 0,\n\t\t\tmaxHeight: this.$config.maxHeight || 100000000000,\n\t\t\tmaxWidth: this.$config.maxWidth || 100000000000\n\t\t};\n\t\tif (this.$config.collapsed) {\n\t\t\tvar mode = this.$config.mode === \"x\";\n\t\t\tsize[mode ? \"width\" : \"height\"] = size[mode ? \"maxWidth\" : \"maxHeight\"] = this.$config.headerHeight;\n\t\t}\n\t\treturn size;\n\t};\n\n\tCell.prototype.getContentSize = function(){\n\n\t\tvar width = this.$lastSize.contentX;\n\t\tif(width !== width*1){\n\t\t\twidth = this.$lastSize.width;\n\t\t}\n\n\t\tvar height = this.$lastSize.contentY;\n\t\tif(height !== height*1){\n\t\t\theight = this.$lastSize.height;\n\t\t}\n\n\t\treturn {\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t};\n\t};\n\n\tCell.prototype._getBorderSizes = function(){\n\t\tvar borders = {\n\t\t\ttop: 0,\n\t\t\tright: 0,\n\t\t\tbottom: 0,\n\t\t\tleft: 0,\n\t\t\thorizontal: 0,\n\t\t\tvertical: 0\n\t\t};\n\t\tif(this._currentBorders){\n\t\t\tif(this._currentBorders[this._borders.left]){\n\t\t\t\tborders.left = 1;\n\t\t\t\tborders.horizontal++;\n\t\t\t}\n\n\t\t\tif(this._currentBorders[this._borders.right]){\n\t\t\t\tborders.right = 1;\n\t\t\t\tborders.horizontal++;\n\t\t\t}\n\n\t\t\tif(this._currentBorders[this._borders.top]){\n\t\t\t\tborders.top = 1;\n\t\t\t\tborders.vertical++;\n\t\t\t}\n\n\t\t\tif(this._currentBorders[this._borders.bottom]){\n\t\t\t\tborders.bottom = 1;\n\t\t\t\tborders.vertical++;\n\t\t\t}\n\t\t}\n\n\t\treturn borders;\n\n\t};\n\n\tCell.prototype.setSize = function (x, y) {\n\t\tthis.$view.style.width = x + \"px\";\n\t\tthis.$view.style.height = y + \"px\";\n\n\t\tvar borders = this._getBorderSizes();\n\t\tvar contentY = y - borders.vertical;\n\t\tvar contentX = x - borders.horizontal;\n\n\t\tthis.$lastSize = { x: x, y: y, contentX: contentX, contentY: contentY };\n\t\tif (this.$config.header) {\n\t\t\tthis._sizeHeader();\n\t\t}else{\n\t\t\tthis._sizeContent();\n\t\t}\n\t};\n\n\tCell.prototype._borders = {\n\t\t\"left\":\"gantt_layout_cell_border_left\",\n\t\t\"right\":\"gantt_layout_cell_border_right\",\n\t\t\"top\":\"gantt_layout_cell_border_top\",\n\t\t\"bottom\":\"gantt_layout_cell_border_bottom\"\n\t};\n\n\tCell.prototype._setBorders = function(css, view){\n\t\tif(!view) {\n\t\t\tview = this;\n\t\t}\n\t\tvar node = view.$view;\n\n\t\tfor( var i in this._borders){\n\t\t\tdomHelpers.removeClassName(node, this._borders[i]);\n\t\t}\n\n\t\tif(typeof css == \"string\"){\n\t\t\tcss = [css];\n\t\t}\n\n\t\tvar cssHash = {};\n\n\t\tfor(var i = 0; i < css.length; i++){\n\t\t\tdomHelpers.addClassName(node, css[i]);\n\t\t\tcssHash[css[i]] = true;\n\t\t}\n\n\t\tview._currentBorders = cssHash;\n\t};\n\n\n\tCell.prototype._sizeContent = function(){\n\t\tvar content = this.$view.childNodes[0];\n\t\tif(content && content.className == \"gantt_layout_content\"){\n\t\t\tcontent.style.height = this.$lastSize.contentY + \"px\";\n\t\t}\n\t};\n\n\tCell.prototype._sizeHeader = function () {\n\t\tvar size = this.$lastSize;\n\t\tsize.contentY -= this.$config.headerHeight;\n\t\tvar header = this.$view.childNodes[0];\n\t\tvar content = this.$view.childNodes[1];\n\t\tvar xLayout = this.$config.mode === \"x\";\n\t\tif (this.$config.collapsed) {\n\t\t\tcontent.style.display = \"none\";\n\t\t\tif (xLayout) {\n\t\t\t\theader.className = \"gantt_layout_header collapsed_x\";\n\t\t\t\theader.style.width = size.y + \"px\";\n\t\t\t\tvar d = Math.floor(size.y / 2 - size.x / 2);\n\t\t\t\theader.style.transform = \"rotate(90deg) translate(\" + d + \"px, \" + d + \"px)\";\n\t\t\t\tcontent.style.display = \"none\";\n\t\t\t}\n\t\t\telse {\n\t\t\t\theader.className = \"gantt_layout_header collapsed_y\";\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (xLayout) {\n\t\t\t\theader.className = \"gantt_layout_header\";\n\t\t\t}\n\t\t\telse {\n\t\t\t\theader.className = \"gantt_layout_header vertical\";\n\t\t\t}\n\t\t\theader.style.width = 'auto';\n\t\t\theader.style.transform = '';\n\t\t\tcontent.style.display = \"\";\n\t\t\tcontent.style.height = size.contentY + \"px\";\n\t\t}\n\t\theader.style.height = this.$config.headerHeight + \"px\";\n\t};\n\treturn Cell;\n}());\n\nexport default Cell;\n","export default function (d, b) {\n\tfor (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];\n\tfunction __() { this.constructor = d; }\n\td.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n};","import __extends from \"../../../utils/extends\";\nimport * as domHelpers from \"../utils/dom_helpers\";\nimport Cell from \"./cell\";\n\nvar Layout = (function (_super) {\n\t\"use strict\";\n\n\t__extends(Layout, _super);\n\tfunction Layout(parent, config, factory) {\n\t\tvar _this = _super.apply(this, arguments) || this;\n\n\t\tif(parent)\n\t\t\t_this.$root = true;\n\n\t\t_this._parseConfig(config);\n\t\t_this.$name = \"layout\";\n\t\treturn _this;\n\t}\n\n\tLayout.prototype.destructor = function () {\n\t\tif (this.$container && this.$view) {\n\t\t\tdomHelpers.removeNode(this.$view);\n\t\t}\n\n\t\tfor (var i = 0; i < this.$cells.length; i++) {\n\t\t\tvar child = this.$cells[i];\n\t\t\tchild.destructor();\n\t\t}\n\t\tthis.$cells = [];\n\n\t\t_super.prototype.destructor.call(this);\n\t};\n\n\tLayout.prototype._resizeScrollbars = function(autosize, scrollbars){\n\t\tvar scrollChanged = false;\n\t\tvar visibleScrollbars = [],\n\t\t\thiddenScrollbars = [];\n\n\t\tconst scrollbarsToHide = [];\n\n\t\tfunction showScrollbar(scrollbar){\n\t\t\tscrollbar.$parent.show();\n\t\t\tscrollChanged = true;\n\t\t\tvisibleScrollbars.push(scrollbar);\n\t\t}\n\t\tfunction hideScrollbar(scrollbar){\n\t\t\tscrollbar.$parent.hide();\n\t\t\tscrollChanged = true;\n\t\t\thiddenScrollbars.push(scrollbar);\n\t\t}\n\n\t\tvar scrollbar;\n\t\tfor(var i = 0; i < scrollbars.length; i++){\n\t\t\tscrollbar = scrollbars[i];\n\n\t\t\tif(autosize[scrollbar.$config.scroll]) {\n\t\t\t\thideScrollbar(scrollbar);\n\t\t\t}else if(scrollbar.shouldHide()){\n\t\t\t\t//hideScrollbar(scrollbar);\n\t\t\t\tscrollbarsToHide.push(scrollbar);\n\t\t\t}else if(scrollbar.shouldShow()){\n\t\t\t\tshowScrollbar(scrollbar);\n\t\t\t}else{\n\t\t\t\tif(scrollbar.isVisible()){\n\t\t\t\t\tvisibleScrollbars.push(scrollbar);\n\t\t\t\t}else{\n\t\t\t\t\thiddenScrollbars.push(scrollbar);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvar visibleGroups = {};\n\t\tfor(var i = 0; i < visibleScrollbars.length; i++){\n\t\t\tif(visibleScrollbars[i].$config.group){\n\t\t\t\tvisibleGroups[visibleScrollbars[i].$config.group] = true;\n\t\t\t}\n\t\t}\n\n\t\t// GS-2220\n\t\tscrollbarsToHide.forEach(function(scrollbar){\n\t\t\tif(!(scrollbar.$config.group && visibleGroups[scrollbar.$config.group])){\n\t\t\t\thideScrollbar(scrollbar);\n\t\t\t}\n\t\t});\n\n\t\tfor(var i = 0; i < hiddenScrollbars.length; i++){\n\t\t\tscrollbar = hiddenScrollbars[i];\n\n\t\t\tif(scrollbar.$config.group && visibleGroups[scrollbar.$config.group]){\n\t\t\t\tshowScrollbar(scrollbar);\n\t\t\t\t// GS-707 If the scrollbar was hidden then showed, the container resize shouldn't happen because of that\n\t\t\t\tfor(var j = 0; j < visibleScrollbars.length; j++){\n\t\t\t\t\tif(visibleScrollbars[j] == scrollbar){\n\t\t\t\t\t\tthis.$gantt.$scrollbarRepaint = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn scrollChanged;\n\t};\n\n\tLayout.prototype._syncCellSizes = function(groupName, newSize){\n\t\tif(!groupName)\n\t\t\treturn;\n\n\t\tvar groups = {};\n\n\t\tthis._eachChild(function(cell){\n\t\t\tif(cell.$config.group && cell.$name != \"scrollbar\" && cell.$name != \"resizer\"){\n\t\t\t\tif(!groups[cell.$config.group]){\n\t\t\t\t\tgroups[cell.$config.group] = [];\n\t\t\t\t}\n\t\t\t\tgroups[cell.$config.group].push(cell);\n\t\t\t}\n\t\t});\n\n\t\tif(groups[groupName]){\n\t\t\tthis._syncGroupSize(groups[groupName], newSize);\n\t\t}\n\t\treturn groups[groupName];\n\t};\n\n\tLayout.prototype._syncGroupSize = function(cells, newSize){\n\t\tif(!cells.length) return;\n\n\t\tvar property = cells[0].$parent._xLayout ? \"width\" : \"height\";\n\t\tvar direction = cells[0].$parent.getNextSibling(cells[0].$id) ? 1 : -1;\n\n\t\tvar newSizeValue = newSize.value;\n\t\tvar isGravity = newSize.isGravity;\n\t\tfor(var i = 0; i < cells.length; i++){\n\t\t\tvar ownSize = cells[i].getSize();\n\n\t\t\tvar resizeSibling = direction > 0 ? cells[i].$parent.getNextSibling(cells[i].$id) : cells[i].$parent.getPrevSibling(cells[i].$id);\n\t\t\tif(resizeSibling.$name == \"resizer\"){\n\t\t\t\tresizeSibling = direction > 0 ? resizeSibling.$parent.getNextSibling(resizeSibling.$id) : resizeSibling.$parent.getPrevSibling(resizeSibling.$id);\n\t\t\t}\n\t\t\tvar siblingSize = resizeSibling.getSize();\n\n\t\t\tif(!isGravity) {\n\t\t\t\tif(resizeSibling[property]){\n\t\t\t\t\tvar totalGravity = ownSize.gravity + siblingSize.gravity;\n\t\t\t\t\tvar totalSize = ownSize[property] + siblingSize[property];\n\t\t\t\t\tvar k = totalGravity / totalSize;\n\t\t\t\t\tcells[i].$config.gravity = k * newSizeValue;\n\n\t\t\t\t\tresizeSibling.$config[property] = totalSize - newSizeValue;\n\t\t\t\t\tresizeSibling.$config.gravity = totalGravity - k * newSizeValue;\n\t\t\t\t}else{\n\t\t\t\t\tcells[i].$config[property] = newSizeValue;\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tcells[i].$config.gravity = newSizeValue;\n\t\t\t}\n\n\t\t\tvar mainGrid = this.$gantt.$ui.getView(\"grid\");\n\t\t\tif(mainGrid && cells[i].$content === mainGrid && !mainGrid.$config.scrollable && !isGravity){\n\t\t\t\tthis.$gantt.config.grid_width = newSizeValue;\n\t\t\t}\n\t\t}\n\t};\n\n\tLayout.prototype.resize = function(startStage){\n\t\tvar mainCall = false;\n\t\tif(this.$root && !this._resizeInProgress){\n\t\t\tthis.callEvent(\"onBeforeResize\", []);\n\t\t\tmainCall = true;\n\t\t\tthis._resizeInProgress = true;\n\t\t}\n\n\t\t_super.prototype.resize.call(this, true);\n\t\t_super.prototype.resize.call(this, false);\n\n\t\tif(mainCall){\n\n\t\t\tvar contentViews = [];\n\t\t\tcontentViews = contentViews.concat(this.getCellsByType(\"viewCell\"));\n\t\t\tcontentViews = contentViews.concat(this.getCellsByType(\"viewLayout\"));\n\t\t\tcontentViews = contentViews.concat(this.getCellsByType(\"hostCell\"));\n\n\t\t\tvar scrollbars = this.getCellsByType(\"scroller\");\n\n\t\t\tfor(var i = 0; i < contentViews.length; i++){\n\t\t\t\tif(!contentViews[i].$config.hidden)\n\t\t\t\t\tcontentViews[i].setContentSize();\n\t\t\t}\n\n\t\t\tvar autosize = this._getAutosizeMode(this.$config.autosize);\n\n\t/* // possible to rollback set content size when autisize is disabled, not sure if need to\n\t\t\tcontentViews.forEach(function(view){\n\t\t\t\tconst parent = view.$parent;\n\t\t\t\tif(!autosize.x){\n\t\t\t\t\tif(parent.$config.$originalWidthStored){\n\t\t\t\t\t\tparent.$config.$originalWidthStored = false;\n\t\t\t\t\t\tparent.$config.width = parent.$config.$originalWidth;\n\t\t\t\t\t\tparent.$config.$originalWidth = undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif(!autosize.y){\n\t\t\t\t\tif(parent.$config.$originalHeightStored){\n\t\t\t\t\t\tparent.$config.$originalHeightStored = false;\n\t\t\t\t\t\tparent.$config.height = parent.$config.$originalHeight;\n\t\t\t\t\t\tparent.$config.$originalHeight = undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});*/\n\t\t\t\n\t\t\tvar scrollChanged = this._resizeScrollbars(autosize, scrollbars);\n\n\t\t\tif(this.$config.autosize){\n\t\t\t\tthis.autosize(this.$config.autosize);\n\t\t\t\tcontentViews.forEach(function(view){\n\t\t\t\t\tconst parent = view.$parent;\n\t\t\t\t\tconst sizes = parent.getContentSize(autosize);\n\t\t\t\t\tif(autosize.x){\n\t\t\t\t\t\tif(!parent.$config.$originalWidthStored){\n\t\t\t\t\t\t\tparent.$config.$originalWidthStored = true;\n\t\t\t\t\t\t\tparent.$config.$originalWidth = parent.$config.width;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tparent.$config.width = sizes.width;\n\t\t\t\t\t}\n\t\t\t\t\tif(autosize.y){\n\t\t\t\t\t\tif(!parent.$config.$originalHeightStored){\n\t\t\t\t\t\t\tparent.$config.$originalHeightStored = true;\n\t\t\t\t\t\t\tparent.$config.$originalHeight = parent.$config.height;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tparent.$config.height = sizes.height;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tscrollChanged = true;\n\t\t\t}\n\n\t\t\tif(scrollChanged){\n\t\t\t\tthis.resize();\n\t\t\t\tfor(var i = 0; i < contentViews.length; i++){\n\t\t\t\t\tif(!contentViews[i].$config.hidden)\n\t\t\t\t\t\tcontentViews[i].setContentSize();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.callEvent(\"onResize\", []);\n\t\t}\n\t\tif(mainCall){\n\t\t\tthis._resizeInProgress = false;\n\t\t}\n\t};\n\n\tLayout.prototype._eachChild = function(code, cell){\n\t\tcell = cell || this;\n\t\tcode(cell);\n\t\tif(cell.$cells){\n\t\t\tfor(var i = 0; i < cell.$cells.length; i++){\n\t\t\t\tthis._eachChild(code, cell.$cells[i]);\n\t\t\t}\n\t\t}\n\t};\n\n\tLayout.prototype.isChild = function(view){\n\t\tvar res = false;\n\t\tthis._eachChild(function(child){\n\t\t\tif(child === view || child.$content === view){\n\t\t\t\tres = true;\n\t\t\t}\n\t\t});\n\t\treturn res;\n\t};\n\n\tLayout.prototype.getCellsByType = function(type){\n\t\tvar res = [];\n\t\tif(type === this.$name){\n\t\t\tres.push(this);\n\t\t}\n\n\t\tif(this.$content && this.$content.$name == type){\n\t\t\tres.push(this.$content);\n\t\t}\n\n\t\tif(this.$cells){\n\t\t\tfor(var i = 0; i < this.$cells.length; i++){\n\t\t\t\tvar children = Layout.prototype.getCellsByType.call(this.$cells[i], type);\n\t\t\t\tif(children.length){\n\t\t\t\t\tres.push.apply(res, children);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn res;\n\t};\n\n\tLayout.prototype.getNextSibling = function(cellId){\n\t\tvar index = this.cellIndex(cellId);\n\t\tif(index >= 0 && this.$cells[index + 1]){\n\t\t\treturn this.$cells[index + 1];\n\t\t}else{\n\t\t\treturn null;\n\t\t}\n\t};\n\n\tLayout.prototype.getPrevSibling = function(cellId){\n\t\tvar index = this.cellIndex(cellId);\n\t\tif(index >= 0 && this.$cells[index - 1]){\n\t\t\treturn this.$cells[index - 1];\n\t\t}else{\n\t\t\treturn null;\n\t\t}\n\t};\n\n\n\tLayout.prototype.cell = function (id) {\n\t\tfor (var i = 0; i < this.$cells.length; i++) {\n\t\t\tvar child = this.$cells[i];\n\t\t\tif (child.$id === id) {\n\t\t\t\treturn child;\n\t\t\t}\n\t\t\tvar sub = child.cell(id);\n\t\t\tif (sub) {\n\t\t\t\treturn sub;\n\t\t\t}\n\t\t}\n\t};\n\tLayout.prototype.cellIndex = function (id) {\n\t\tfor (var i = 0; i < this.$cells.length; i++) {\n\t\t\tif (this.$cells[i].$id === id) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t};\n\tLayout.prototype.moveView = function (view, ind) {\n\t\tif (this.$cells[ind] !== view) {\n\t\t\treturn window.alert(\"Not implemented\");\n\t\t}\n\t\telse {\n\t\t\tind += this.$config.header ? 1 : 0;\n\t\t\tvar node = this.$view;\n\t\t\tif (ind >= node.childNodes.length) {\n\t\t\t\tnode.appendChild(view.$view);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnode.insertBefore(view.$view, node.childNodes[ind]);\n\t\t\t}\n\t\t}\n\t};\n\tLayout.prototype._parseConfig = function (config) {\n\t\tthis.$cells = [];\n\t\tthis._xLayout = !config.rows;\n\t\tvar cells = config.rows || config.cols || config.views;\n\t\tfor (var i = 0; i < cells.length; i++) {\n\t\t\tvar cell = cells[i];\n\t\t\tcell.mode = this._xLayout ? \"x\" : \"y\";\n\t\t\tvar $content = this.$factory.initUI(cell, this);\n\t\t\tif(!$content){\n\t\t\t\tcells.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}else{\n\t\t\t\t$content.$parent = this;\n\t\t\t\tthis.$cells.push($content);\n\t\t\t}\n\t\t}\n\t};\n\tLayout.prototype.getCells = function () {\n\t\treturn this.$cells;\n\t};\n\tLayout.prototype.render = function () {\n\t\tvar view = domHelpers.insertNode(this.$container, this.$toHTML());\n\t\tthis.$fill(view, null);\n\t\tthis.callEvent(\"onReady\", []);\n\t\tthis.resize();\n\n\t\t// do simple repaint after the first call\n\t\tthis.render = this.resize;\n\t};\n\tLayout.prototype.$fill = function (node, parent) {\n\t\tthis.$view = node;\n\t\tthis.$parent = parent;\n\t\tvar cells = domHelpers.getChildNodes(node, \"gantt_layout_cell\");\n\t\tfor (var i = cells.length - 1; i >= 0; i--) {\n\t\t\tvar sub = this.$cells[i];\n\t\t\tsub.$fill(cells[i], this);\n\t\t\t// initially hidden cell\n\t\t\tif (sub.$config.hidden) {\n\t\t\t\tsub.$view.parentNode.removeChild(sub.$view);\n\t\t\t}\n\t\t}\n\t};\n\tLayout.prototype.$toHTML = function () {\n\t\tvar mode = this._xLayout ? \"x\" : \"y\";\n\t\tvar html = [];\n\t\tfor (var i = 0; i < this.$cells.length; i++) {\n\t\t\thtml.push(this.$cells[i].$toHTML());\n\t\t}\n\t\treturn _super.prototype.$toHTML.call(this, html.join(\"\"), (this.$root ? \"gantt_layout_root \" : \"\") + \"gantt_layout gantt_layout_\" + mode);\n\t};\n\n\tLayout.prototype.getContentSize = function(mode){\n\t\tvar contentWidth = 0,\n\t\t\tcontentHeight = 0;\n\n\t\tvar cellSize, cell, borders;\n\t\tfor (var i = 0; i < this.$cells.length; i++) {\n\t\t\tcell = this.$cells[i];\n\t\t\tif(cell.$config.hidden)\n\t\t\t\tcontinue;\n\n\t\t\tcellSize = cell.getContentSize(mode);\n\n\t\t\tif(cell.$config.view === \"scrollbar\" && mode[cell.$config.scroll]){\n\t\t\t\tcellSize.height = 0;\n\t\t\t\tcellSize.width = 0;\n\t\t\t}\n\n\t\t\tif(cell.$config.resizer){\n\t\t\t\tif(this._xLayout){\n\t\t\t\t\tcellSize.height = 0;\n\t\t\t\t}else{\n\t\t\t\t\tcellSize.width = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tborders = cell._getBorderSizes();\n\n\t\t\tif(this._xLayout){\n\t\t\t\tcontentWidth += (cellSize.width + borders.horizontal);\n\t\t\t\tcontentHeight = Math.max(contentHeight, (cellSize.height + borders.vertical));\n\t\t\t}else{\n\t\t\t\tcontentWidth = Math.max(contentWidth, cellSize.width + borders.horizontal);\n\t\t\t\tcontentHeight += cellSize.height + borders.vertical;\n\t\t\t}\n\t\t}\n\n\t\tborders = this._getBorderSizes();\n\t\tcontentWidth += borders.horizontal;\n\t\tcontentHeight += borders.vertical;\n\n\t\t// GS-149 & GS-150: By default this code only increases the container sizes, because of that, the cell sizes\n\t\t// are also increased. Keep this code here in the case if something goes wrong\n\t\t/*\n\t\tif(this.$root){\n\t\t\tcontentWidth += 1;\n\t\t\tcontentHeight += 1;\n\t\t}\n\t\t*/\n\t\treturn {\n\t\t\twidth: contentWidth,\n\t\t\theight: contentHeight\n\t\t};\n\t};\n\n\tLayout.prototype._cleanElSize = function(value){\n\t\treturn ((value || \"\").toString().replace(\"px\", \"\") * 1 || 0);\n\t};\n\tLayout.prototype._getBoxStyles = function(div){\n\t\tvar computed = null;\n\t\tif(window.getComputedStyle){\n\t\t\tcomputed = window.getComputedStyle(div, null);\n\t\t}else{\n\t\t\t//IE with elem.currentStyle does not calculate sizes from %, so will use the default approach\n\t\t\tcomputed = {\n\t\t\t\t\"width\":div.clientWidth,\n\t\t\t\t\"height\":div.clientHeight\n\t\t\t};\n\t\t}\n\t\tvar properties = [\n\t\t\t\"width\",\n\t\t\t\"height\",\n\n\t\t\t\"paddingTop\",\n\t\t\t\"paddingBottom\",\n\t\t\t\"paddingLeft\",\n\t\t\t\"paddingRight\",\n\n\t\t\t\"borderLeftWidth\",\n\t\t\t\"borderRightWidth\",\n\t\t\t\"borderTopWidth\",\n\t\t\t\"borderBottomWidth\"\n\t\t];\n\t\tvar styles = {\n\t\t\tboxSizing:(computed.boxSizing == \"border-box\")\n\t\t};\n\n\t\tif(computed.MozBoxSizing){\n\t\t\tstyles.boxSizing = (computed.MozBoxSizing == \"border-box\");\n\t\t}\n\t\tfor(var i =0; i < properties.length; i++){\n\t\t\tstyles[properties[i]] = computed[properties[i]] ? this._cleanElSize(computed[properties[i]]) : 0;\n\t\t}\n\n\n\t\tvar box = {\n\t\t\thorPaddings : (styles.paddingLeft + styles.paddingRight + styles.borderLeftWidth + styles.borderRightWidth),\n\t\t\tvertPaddings : (styles.paddingTop + styles.paddingBottom + styles.borderTopWidth + styles.borderBottomWidth),\n\t\t\tborderBox: styles.boxSizing,\n\t\t\tinnerWidth : styles.width,\n\t\t\tinnerHeight : styles.height,\n\t\t\touterWidth : styles.width,\n\t\t\touterHeight : styles.height\n\t\t};\n\n\n\t\tif(box.borderBox){\n\t\t\tbox.innerWidth -= box.horPaddings;\n\t\t\tbox.innerHeight -= box.vertPaddings;\n\t\t}else{\n\t\t\tbox.outerWidth += box.horPaddings;\n\t\t\tbox.outerHeight += box.vertPaddings;\n\t\t}\n\n\t\treturn box;\n\t};\n\n\tLayout.prototype._getAutosizeMode = function(config){\n\t\tvar res = {x:false, y:false};\n\t\tif(config === \"xy\"){\n\t\t\tres.x = res.y = true;\n\t\t}else if(config === \"y\" || config === true){\n\t\t\tres.y = true;\n\t\t}else if(config === \"x\"){\n\t\t\tres.x = true;\n\t\t}\n\t\treturn res;\n\t};\n\n\tLayout.prototype.autosize = function(mode) {\n\t\tvar res = this._getAutosizeMode(mode);\n\t\tvar boxSizes = this._getBoxStyles(this.$container);\n\t\tvar contentSizes = this.getContentSize(mode);\n\n\t\tvar node = this.$container;\n\t\tif(res.x){\n\t\t\tif(boxSizes.borderBox){\n\t\t\t\tcontentSizes.width += boxSizes.horPaddings;\n\t\t\t}\n\t\t\tnode.style.width = contentSizes.width + \"px\";\n\t\t}\n\t\tif(res.y){\n\t\t\tif(boxSizes.borderBox){\n\t\t\t\tcontentSizes.height += boxSizes.vertPaddings;\n\t\t\t}\n\t\t\tnode.style.height = contentSizes.height + \"px\";\n\t\t}\n\t};\n\n\tLayout.prototype.getSize = function () {\n\t\tthis._sizes = [];\n\t\tvar width = 0;\n\t\tvar minWidth = 0;\n\t\tvar maxWidth = 100000000000;\n\t\tvar height = 0;\n\t\tvar maxHeight = 100000000000;\n\t\tvar minHeight = 0;\n\n\t\tfor (var i = 0; i < this.$cells.length; i++) {\n\n\t\t\tvar size = this._sizes[i] = this.$cells[i].getSize();\n\t\t\tif (this.$cells[i].$config.hidden) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (this._xLayout) {\n\t\t\t\tif (!size.width && size.minWidth) {\n\t\t\t\t\twidth += size.minWidth;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twidth += size.width;\n\t\t\t\t}\n\t\t\t\tmaxWidth += size.maxWidth;\n\t\t\t\tminWidth += size.minWidth;\n\t\t\t\theight = Math.max(height, size.height);\n\t\t\t\tmaxHeight = Math.min(maxHeight, size.maxHeight); // min of maxHeight\n\t\t\t\tminHeight = Math.max(minHeight, size.minHeight); // max of minHeight\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!size.height && size.minHeight) {\n\t\t\t\t\theight += size.minHeight;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\theight += size.height;\n\t\t\t\t}\n\t\t\t\tmaxHeight += size.maxHeight;\n\t\t\t\tminHeight += size.minHeight;\n\t\t\t\twidth = Math.max(width, size.width);\n\t\t\t\tmaxWidth = Math.min(maxWidth, size.maxWidth); // min of maxWidth\n\t\t\t\tminWidth = Math.max(minWidth, size.minWidth); // max of minWidth\n\t\t\t}\n\t\t}\n\t\tvar self = _super.prototype.getSize.call(this);\n\t\t// maxWidth\n\t\tif (self.maxWidth >= 100000) {\n\t\t\tself.maxWidth = maxWidth;\n\t\t}\n\t\t// maxHeight\n\t\tif (self.maxHeight >= 100000) {\n\t\t\tself.maxHeight = maxHeight;\n\t\t}\n\t\t// minWidth\n\t\tself.minWidth = self.minWidth !== self.minWidth ? 0 : self.minWidth;// || self.width || Math.max(minWidth, width);\n\t\t// minHeight\n\t\tself.minHeight = self.minHeight !== self.minHeight ? 0 : self.minHeight;//self.minHeight || self.height || Math.max(minHeight, height);\n\t\t// sizes with paddings and margins\n\t\tif (this._xLayout) {\n\t\t\tself.minWidth += this.$config.margin * (this.$cells.length) || 0;\n\t\t\tself.minWidth += this.$config.padding * 2 || 0;\n\t\t\tself.minHeight += (this.$config.padding * 2) || 0;\n\t\t}\n\t\telse {\n\t\t\tself.minHeight += this.$config.margin * (this.$cells.length) || 0;\n\t\t\tself.minHeight += (this.$config.padding * 2) || 0;\n\t\t}\n\t\t\n\t\treturn self;\n\t};\n\t// calc total gravity and free space\n\tLayout.prototype._calcFreeSpace = function (s, cell, xLayout) {\n\t\tvar min = xLayout ? cell.minWidth : cell.minHeight;\n\t\tvar max = xLayout ? cell.maxWidth : cell.maxWidth;\n\t\tvar side = s;\n\t\tif (!side) {\n\t\t\tside = Math.floor(this._free / this._gravity * cell.gravity);\n\t\t\tif (side > max) {\n\t\t\t\tside = max;\n\t\t\t\tthis._free -= side;\n\t\t\t\tthis._gravity -= cell.gravity;\n\t\t\t}\n\t\t\tif (side < min) {\n\t\t\t\tside = min;\n\t\t\t\tthis._free -= side;\n\t\t\t\tthis._gravity -= cell.gravity;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (side > max) {\n\t\t\t\tside = max;\n\t\t\t}\n\t\t\tif (side < min) {\n\t\t\t\tside = min;\n\t\t\t}\n\t\t\tthis._free -= side;\n\t\t}\n\t\treturn side;\n\t};\n\tLayout.prototype._calcSize = function (s, size, xLayout) {\n\t\tvar side = s;\n\t\tvar min = xLayout ? size.minWidth : size.minHeight;\n\t\tvar max = xLayout ? size.maxWidth : size.maxHeight;\n\t\tif (!side) {\n\t\t\tside = Math.floor(this._free / this._gravity * size.gravity);\n\t\t}\n\t\tif (side > max) {\n\t\t\tside = max;\n\t\t}\n\t\tif (side < min) {\n\t\t\tside = min;\n\t\t}\n\t\treturn side;\n\t};\n\n\tLayout.prototype._configureBorders = function(){\n\t\tif(this.$root){\n\t\t\tthis._setBorders([\n\t\t\t\tthis._borders.left,\n\t\t\t\tthis._borders.top,\n\t\t\t\tthis._borders.right,\n\t\t\t\tthis._borders.bottom\n\t\t\t],\n\t\t\tthis);\n\t\t}\n\n\t\tvar borderClass = this._xLayout ? this._borders.right : this._borders.bottom;\n\n\t\tvar cells = this.$cells;\n\n\t\tvar lastVisibleIndex = cells.length - 1;\n\t\tfor(var i = lastVisibleIndex; i >= 0; i--){\n\t\t\tif (!cells[i].$config.hidden) {\n\t\t\t\tlastVisibleIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tfor (var i = 0; i < cells.length; i++) {\n\t\t\tif (cells[i].$config.hidden) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvar lastCell = i >= lastVisibleIndex;\n\t\t\tvar borderColorClass = \"\";\n\t\t\tif(!lastCell && cells[i + 1]){\n\t\t\t\tif(cells[i + 1].$config.view == \"scrollbar\"){\n\t\t\t\t\tif(this._xLayout){\n\t\t\t\t\t\tlastCell = true;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tborderColorClass = \"gantt_layout_cell_border_transparent\";\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tthis._setBorders(lastCell ? [] : [borderClass, borderColorClass], cells[i]);\n\t\t}\n\t};\n\n\tLayout.prototype._updateCellVisibility = function(){\n\t\tvar oldVisibleCells = this._visibleCells || {};\n\t\tvar firstCall = !this._visibleCells;\n\t\tvar visibleCells = {};\n\t\tvar cell = null;\n\t\tvar parentVisibility = [];\n\t\tfor (var i = 0; i < this._sizes.length; i++) {\n\t\t\tcell = this.$cells[i];\n\t\t\tif (cell.$config.hide_empty){\n\t\t\t\tparentVisibility.push(cell);\n\t\t\t}\n\n\t\t\tif (!firstCall && cell.$config.hidden && oldVisibleCells[cell.$id]) {\n\t\t\t\tcell._hide(true);\n\t\t\t}else if(!cell.$config.hidden && !oldVisibleCells[cell.$id]){\n\t\t\t\tcell._hide(false);\n\t\t\t}\n\n\t\t\tif(!cell.$config.hidden){\n\t\t\t\tvisibleCells[cell.$id] = true;\n\t\t\t}\n\t\t}\n\t\tthis._visibleCells = visibleCells;\n\n\t\t// GS-27. A way to hide the whole cell if all its children are hidden\n\t\tfor (var i = 0; i < parentVisibility.length; i++) {\n\t\t\tvar cell = parentVisibility[i];\n\t\t\tvar children = cell.$cells;\n\t\t\tvar hideCell = true;\n\t\t\tchildren.forEach(function(child){\n\t\t\t\tif (!child.$config.hidden && !child.$config.resizer){\n\t\t\t\t\thideCell = false;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tcell.$config.hidden = hideCell;\n\t\t}\n\t};\n\n\tLayout.prototype.setSize = function (x, y) {\n\t\tthis._configureBorders();\n\t\t_super.prototype.setSize.call(this, x, y);\n\t\ty = this.$lastSize.contentY;\n\t\tx = this.$lastSize.contentX;\n\n\t\tvar padding = (this.$config.padding || 0);\n\t\tthis.$view.style.padding = padding + \"px\";\n\t\tthis._gravity = 0;\n\t\tthis._free = this._xLayout ? x : y;\n\t\tthis._free -= padding * 2;\n\t\t// calc all gravity\n\n\t\tvar cell,\n\t\t\tsize;\n\n\t\tthis._updateCellVisibility();\n\n\t\tfor (var i = 0; i < this._sizes.length; i++) {\n\t\t\tcell = this.$cells[i];\n\n\t\t\tif (cell.$config.hidden) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvar margin = (this.$config.margin || 0);\n\t\t\tif(cell.$name == \"resizer\" && !margin){\n\t\t\t\tmargin = -1;\n\t\t\t}\n\n\t\t\t// set margins to child cell\n\t\t\tvar cellView = cell.$view;\n\n\t\t\tvar marginSide = this._xLayout ? \"marginRight\" : \"marginBottom\";\n\t\t\tif (i !== this.$cells.length - 1) {\n\t\t\t\tcellView.style[marginSide] = margin + \"px\";\n\t\t\t\tthis._free -= margin; // calc free space without margin\n\t\t\t}\n\t\t\tsize = this._sizes[i];\n\t\t\tif (this._xLayout) {\n\t\t\t\tif (!size.width) {\n\t\t\t\t\tthis._gravity += size.gravity;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!size.height) {\n\t\t\t\t\tthis._gravity += size.gravity;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (var i = 0; i < this._sizes.length; i++) {\n\t\t\tcell = this.$cells[i];\n\n\t\t\tif (cell.$config.hidden) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsize = this._sizes[i];\n\t\t\tvar width = size.width;\n\t\t\tvar height = size.height;\n\t\t\tif (this._xLayout) {\n\t\t\t\tthis._calcFreeSpace(width, size, true);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis._calcFreeSpace(height, size, false);\n\t\t\t}\n\t\t}\n\t\tfor (var i = 0; i < this.$cells.length; i++) {\n\t\t\tcell = this.$cells[i];\n\n\t\t\tif (cell.$config.hidden) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsize = this._sizes[i];\n\t\t\tvar dx = void 0;\n\t\t\tvar dy = void 0;\n\t\t\tif (this._xLayout) {\n\t\t\t\tdx = this._calcSize(size.width, size, true);\n\t\t\t\tdy = y - padding * 2; // layout height without paddings\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdx = x - padding * 2; // layout width without paddings\n\t\t\t\tdy = this._calcSize(size.height, size, false);\n\t\t\t}\n\n\t\t\tcell.setSize(dx, dy);\n\t\t}\n\n\t};\n\n\treturn Layout;\n}(Cell));\n\nexport default Layout;","import __extends from \"../../../utils/extends\";\nimport Layout from \"./layout\";\nimport Cell from \"./cell\";\n\nvar ViewLayout = (function (_super) {\n\t\"use strict\";\n\n\t__extends(ViewLayout, _super);\n\tfunction ViewLayout(parent, config, factory) {\n\t\tvar _this = _super.apply(this, arguments) || this;\n\t\tfor (var i = 0; i < _this.$cells.length; i++) {\n\t\t\t_this.$cells[i].$config.hidden = (i !== 0);\n\t\t}\n\t\t_this.$cell = _this.$cells[0];\n\t\t_this.$name = \"viewLayout\";\n\n\t\treturn _this;\n\t}\n\tViewLayout.prototype.cell = function (id) {\n\t\tvar cell = _super.prototype.cell.call(this, id);\n\t\tif (!cell.$view) {\n\t\t\tthis.$fill(null, this);\n\t\t}\n\t\treturn cell;\n\t};\n\tViewLayout.prototype.moveView = function (view) {\n\t\tvar body = this.$view;\n\t\tif (this.$cell) {\n\t\t\tthis.$cell.$config.hidden = true;\n\t\t\tbody.removeChild(this.$cell.$view);\n\t\t}\n\t\tthis.$cell = view;\n\t\tbody.appendChild(view.$view);\n\t};\n\tViewLayout.prototype.setSize = function (x, y) {\n\t\tCell.prototype.setSize.call(this, x, y);\n\t};\n\n\tViewLayout.prototype.setContentSize = function(){\n\t\tvar size = this.$lastSize;\n\t\tthis.$cell.setSize(size.contentX, size.contentY);\n\t};\n\n\tViewLayout.prototype.getSize = function () {\n\t\tvar sizes = _super.prototype.getSize.call(this);\n\t\tif (this.$cell) {\n\t\t\tvar cellSize = this.$cell.getSize();\n\t\t\tif (this.$config.byMaxSize) {\n\t\t\t\tfor (var i = 0; i < this.$cells.length; i++) {\n\t\t\t\t\tvar otherCell = this.$cells[i].getSize();\n\t\t\t\t\tfor (var cell in cellSize) {\n\t\t\t\t\t\tcellSize[cell] = Math.max(cellSize[cell], otherCell[cell]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (var size in sizes) {\n\t\t\t\tsizes[size] = sizes[size] || cellSize[size];\n\t\t\t}\n\t\t\tsizes.gravity = Math.max(sizes.gravity, cellSize.gravity);\n\t\t}\n\t\treturn sizes;\n\t};\n\treturn ViewLayout;\n}(Layout));\n\nexport default ViewLayout;","import __extends from \"../../../utils/extends\";\nimport * as utils from \"../../../utils/utils\";\nimport Cell from \"./cell\";\n\nvar ViewCell = (function (_super) {\n\t\"use strict\";\n\n\t__extends(ViewCell, _super);\n\tfunction ViewCell(parent, config, factory) {\n\n\t\tvar _this = _super.apply(this, arguments) || this;\n\n\t\tif(config.view){\n\t\t\tif(config.id){\n\t\t\t\t// pass id to the nested view\n\t\t\t\tthis.$id = utils.uid();\n\t\t\t}\n\t\t\tvar childConfig = utils.copy(config);\n\t\t\tdelete childConfig.config;\n\t\t\tdelete childConfig.templates;\n\n\t\t\tthis.$content = this.$factory.createView(config.view, this, childConfig, this);\n\t\t\tif(!this.$content)\n\t\t\t\treturn false;\n\t\t}\n\n\t\t_this.$name = \"viewCell\";\n\t\treturn _this;\n\t}\n\n\tViewCell.prototype.destructor = function(){\n\t\tthis.clear();\n\t\t_super.prototype.destructor.call(this);\n\t};\n\n\tViewCell.prototype.clear = function(){\n\n\t\tthis.$initialized = false;\n\n\t\t// call destructor\n\t\tif (this.$content){\n\t\t\tvar method = this.$content.unload || this.$content.destructor;\n\t\t\tif (method){\n\t\t\t\tmethod.call(this.$content);\n\t\t\t}\n\t\t}\n\n\t\t_super.prototype.clear.call(this);\n\n\t};\n\n\tViewCell.prototype.scrollTo = function(left, top){\n\n\t\tif(this.$content && this.$content.scrollTo){\n\t\t\tthis.$content.scrollTo(left, top);\n\t\t}else{\n\t\t\t_super.prototype.scrollTo.call(this, left, top);\n\t\t}\n\t};\n\n\tViewCell.prototype._setContentSize = function(x, y){\n\t\tvar borders = this._getBorderSizes();\n\t\tif(typeof x === \"number\"){\n\t\t\tvar outerX = x + borders.horizontal;\n\t\t\tthis.$config.width = outerX;\n\t\t}\n\t\tif(typeof y === \"number\"){\n\t\t\tvar outerY = y + borders.vertical;\n\t\t\tthis.$config.height = outerY;\n\t\t}\n\t};\n\n\tViewCell.prototype.setSize = function(x, y){\n\t\t_super.prototype.setSize.call(this, x, y);\n\n\t\tif(!this.$preResize && this.$content) {\n\t\t\tif (!this.$initialized) {\n\t\t\t\tthis.$initialized = true;\n\t\t\t\tvar header = this.$view.childNodes[0];\n\t\t\t\tvar content = this.$view.childNodes[1];\n\t\t\t\tif(!content) content = header;\n\n\t\t\t\t/*if(this.$content.$config){\n\t\t\t\t\tthis.$content.$config.width = this.$lastSize.contentX;\n\t\t\t\t\tthis.$content.$config.height = this.$lastSize.contentY;\n\t\t\t\t}*/\n\t\t\t\tthis.$content.init(content);\n\t\t\t}\n\t\t}\n\t};\n\n\tViewCell.prototype.setContentSize = function(){\n\t\tif(!this.$preResize && this.$content) {\n\t\t\tif (this.$initialized) {\n\t\t\t\tthis.$content.setSize(this.$lastSize.contentX, this.$lastSize.contentY);\n\t\t\t}\n\t\t}\n\t};\n\n\n\tViewCell.prototype.getContentSize = function(){\n\t\tvar size = _super.prototype.getContentSize.call(this);\n\n\t\tif(this.$content && this.$initialized){\n\t\t\tvar childSize = this.$content.getSize();\n\t\t\tsize.width = childSize.contentX === undefined ? childSize.width : childSize.contentX;\n\t\t\tsize.height = childSize.contentY === undefined ? childSize.height : childSize.contentY;\n\t\t}\n\n\t\tvar borders = this._getBorderSizes();\n\t\tsize.width += borders.horizontal;\n\t\tsize.height += borders.vertical;\n\n\t\treturn size;\n\t};\n\n\treturn ViewCell;\n}(Cell));\n\nexport default ViewCell;","import __extends from \"../../../utils/extends\";\nimport * as domHelpers from \"../utils/dom_helpers\";\nimport * as utils from \"../../../utils/utils\";\nimport Cell from \"./cell\";\n\nvar ResizerCell = (function (_super) {\n\t\"use strict\";\n\n\t__extends(ResizerCell, _super);\n\tfunction ResizerCell(parent, config, factory) {\n\t\tvar _this = _super.apply(this, arguments) || this;\n\n\t\tvar startBackSize, startFrontSize;\n\n\t\tfunction getPageCoordinates(e){\n\t\t\tvar x = e.pageX;\n\t\t\tvar y = e.pageY;\n\n\t\t\tif (e.touches){\n\t\t\t\tx = e.touches[0].pageX;\n\t\t\t\ty = e.touches[0].pageY;\n\t\t\t}\n\n\t\t\treturn {x:x,y:y};\n\t\t}\n\n\t\t_this._moveHandler = function (e) {\n\t\t\t_this._moveResizer(_this._resizer, getPageCoordinates(e).x, getPageCoordinates(e).y);\n\t\t};\n\t\t_this._upHandler = function (e) {\n\t\t\tvar newSizes = _this._getNewSizes();\n\t\t\tif(_this.callEvent(\"onResizeEnd\", [startBackSize, startFrontSize, newSizes ? newSizes.back : 0, newSizes ? newSizes.front : 0]) !== false){\n\t\t\t\t_this._setSizes();\n\t\t\t}\n\n\t\t\t_this._setBackground(false);\n\t\t\t_this._clearResizer();\n\t\t\t_this._clearListeneres();\n\n\t\t\tif (e.touches) _this.$gantt._prevent_touch_scroll = false;\n\t\t};\n\n\t\t_this._clearListeneres = function(){\n\t\t\tthis.$domEvents.detach(document, \"mouseup\", _this._upHandler);\n\t\t\tthis.$domEvents.detach(document, \"mousemove\", _this._moveHandler);\n\t\t\tthis.$domEvents.detach(document, \"mousemove\", _this._startOnMove);\n\t\t\tthis.$domEvents.detach(document, \"mouseup\", _this._cancelDND);\n\n\t\t\tthis.$domEvents.detach(document, \"touchend\", _this._upHandler);\n\t\t\tthis.$domEvents.detach(document, \"touchmove\", _this._startOnMove);\n\t\t\tthis.$domEvents.detach(document, \"touchstart\", _this._downHandler);\n\t\t};\n\n\t\t_this._callStartDNDEvent = function(){\n\t\t\tif (this._xMode) {\n\t\t\t\tstartBackSize = this._behind.$config.width || this._behind.$view.offsetWidth;\n\t\t\t\tstartFrontSize = this._front.$config.width || this._front.$view.offsetWidth;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstartBackSize = this._behind.$config.height || this._behind.$view.offsetHeight;\n\t\t\t\tstartFrontSize = this._front.$config.height || this._front.$view.offsetHeight;\n\t\t\t}\n\n\t\t\tif(_this.callEvent(\"onResizeStart\", [startBackSize, startFrontSize]) === false){\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\t_this._startDND = function(e){\n\t\t\tvar res = this._callStartDNDEvent();\n\t\t\tif(res === false){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar stop = false;\n\t\t\tthis._eachGroupItem(function(resizer){\n\t\t\t\tresizer._getSiblings();\n\t\t\t\tif(resizer._callStartDNDEvent() === false){\n\t\t\t\t\tstop = true;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif(stop){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_this._moveHandler(e);\n\n\t\t\t_this.$domEvents.attach(document, \"mousemove\", _this._moveHandler);\n\t\t\t_this.$domEvents.attach(document, \"mouseup\", _this._upHandler);\n\t\t};\n\n\t\t_this._cancelDND = function(){\n\t\t\t_this._setBackground(false);\n\t\t\t_this._clearResizer();\n\t\t\t_this._clearListeneres();\n\t\t};\n\n\t\t_this._startOnMove = function(e){\n\t\t\t// don't scroll the timeline on touch devices\n\t\t\tif (e.touches){\n\t\t\t\t_this.$gantt._touch_drag = true;\n\t\t\t\t// GS-45. Don't scroll the timeline while dragging something on touch devices (e.g. resizer)\n\t\t\t\t_this.$gantt._prevent_touch_scroll = true;\n\t\t\t}\n\n\t\t\tif(_this._isPosChanged(e)){\n\t\t\t\t_this._clearListeneres();\n\t\t\t\t_this._startDND(e);\n\t\t\t}\n\t\t};\n\n\t\t_this._downHandler = function (e) {\n\t\t\t_this._getSiblings();\n\n\t\t\tif (_this._behind.$config.collapsed || _this._front.$config.collapsed) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_this._setBackground(true);\n\t\t\t_this._resizer = _this._setResizer();\n\n\t\t\t_this._positions = {\n\t\t\t\tx: getPageCoordinates(e).x,\n\t\t\t\ty: getPageCoordinates(e).y,\n\t\t\t\ttimestamp: Date.now()\n\t\t\t};\n\n\t\t\t_this.$domEvents.attach(document, \"mousemove\", _this._startOnMove);\n\t\t\t_this.$domEvents.attach(document, \"mouseup\", _this._cancelDND);\n\t\t};\n\t\t_this.$name = \"resizer\";\n\t\treturn _this;\n\t}\n\tResizerCell.prototype.init = function () {\n\t\tvar _this = this;\n\t\t_super.prototype.init.call(this);\n\t\tthis._xMode = this.$config.mode === \"x\";\n\t\tif (this._xMode && !this.$config.width) {\n\t\t\tthis.$config.width = this.$config.minWidth = 1;\n\t\t}\n\t\telse if (!this._xMode && !this.$config.height) {\n\t\t\tthis.$config.height = this.$config.minHeight = 1;\n\t\t}\n\n\t\tthis.$config.margin = -1;\n\n\t\tthis.$domEvents.attach(this.$view, \"mousedown\", _this._downHandler);\n\n\t\tthis.$domEvents.attach(this.$view, \"touchstart\", _this._downHandler);\n\t\tthis.$domEvents.attach(this.$view, \"touchmove\", _this._startOnMove);\n\t\tthis.$domEvents.attach(this.$view, \"touchend\", _this._upHandler);\n\t};\n\tResizerCell.prototype.$toHTML = function () {\n\t\tvar mode = this.$config.mode;\n\t\tvar css = this.$config.css || \"\";\n\t\treturn \"
\";\n\t};\n\n\tResizerCell.prototype._clearResizer = function(){\n\t\tif(this._resizer){\n\t\t\tif(this._resizer.parentNode){\n\t\t\t\tthis._resizer.parentNode.removeChild(this._resizer);\n\t\t\t}\n\t\t\tthis._resizer = null;\n\t\t}\n\t};\n\n\tResizerCell.prototype._isPosChanged = function(e){\n\t\tif(!this._positions){\n\t\t\treturn false;\n\t\t}\n\n\t\tif(Math.abs(this._positions.x - e.pageX) > 3 || Math.abs(this._positions.y - e.pageY) > 3){\n\t\t\treturn true;\n\t\t}\n\n\t\tif(Date.now() - this._positions.timestamp > 300){\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t};\n\n\tResizerCell.prototype._getSiblings = function () {\n\t\tvar cells = this.$parent.getCells();\n\n\t\tif(this.$config.prev){\n\t\t\tthis._behind = this.$factory.getView(this.$config.prev);\n\t\t\tif(!(this._behind instanceof Cell)){\n\t\t\t\tthis._behind = this._behind.$parent;\n\t\t\t}\n\t\t}\n\t\tif(this.$config.next){\n\t\t\tthis._front = this.$factory.getView(this.$config.next);\n\t\t\tif(!(this._front instanceof Cell)){\n\t\t\t\tthis._front = this._behind.$parent;\n\t\t\t}\n\t\t}\n\n\t\tfor (var i = 0; i < cells.length; i++) {\n\t\t\tif (this === cells[i]) {\n\t\t\t\tif(!this._behind)\n\t\t\t\t\tthis._behind = cells[i - 1];\n\t\t\t\tif(!this._front)\n\t\t\t\t\tthis._front = cells[i + 1];\n\t\t\t}\n\t\t}\n\t};\n\tResizerCell.prototype._setBackground = function (state) {\n\t\tvar classes = \"gantt_resizing\";\n\t\tif (!state) {\n\t\t\tdomHelpers.removeClassName(this._behind.$view, classes);\n\t\t\tdomHelpers.removeClassName(this._front.$view, classes);\n\t\t\tdocument.body.classList.remove(\"gantt_noselect\");\n\t\t\treturn;\n\t\t}\n\t\tdomHelpers.addClassName(this._behind.$view, classes, true);\n\t\tdomHelpers.addClassName(this._front.$view, classes, true);\n\t\tdocument.body.classList.add(\"gantt_noselect\");\n\t};\n\tResizerCell.prototype._setResizer = function () {\n\t\tvar resizer = document.createElement(\"div\");\n\t\tresizer.className = \"gantt_resizer_stick\";\n\t\tthis.$view.appendChild(resizer);\n\t\tthis.$view.style.overflow = \"visible\";\n\t\tresizer.style.height = this.$view.style.height;\n\t\treturn resizer;\n\t};\n\n\tResizerCell.prototype._getDirection = function(x, y){\n\t\tvar shift;\n\t\tif (this._xMode) {\n\t\t\tshift = x - this._positions.x;\n\t\t}else{\n\t\t\tshift = y - this._positions.y;\n\t\t}\n\t\treturn shift ? shift < 0 ? -1 : 1 : 0;\n\t};\n\n\tResizerCell.prototype._getResizePosition = function(x, y){\n\t\tvar size;\n\t\tvar behindSide;\n\t\tvar behindMin;\n\t\tvar frontSide;\n\t\tvar frontMin;\n\t\tif (this._xMode) {\n\t\t\tsize = x - this._positions.x;\n\t\t\tbehindSide = this._behind.$config.width || this._behind.$view.offsetWidth;\n\t\t\tfrontSide = this._front.$config.width || this._front.$view.offsetWidth;\n\t\t\tbehindMin = this._behind.$config.minWidth;\n\t\t\tfrontMin = this._front.$config.minWidth;\n\t\t}\n\t\telse {\n\t\t\tsize = y - this._positions.y;\n\t\t\tbehindSide = this._behind.$config.height || this._behind.$view.offsetHeight;\n\t\t\tfrontSide = this._front.$config.height || this._front.$view.offsetHeight;\n\t\t\tbehindMin = this._front.$config.minHeight;\n\t\t\tfrontMin = this._front.$config.minHeight;\n\t\t}\n\t\tvar direction = this._getDirection(x, y);\n\t\tvar newBehindSide,\n\t\t\tnewFrontSide;\n\n\t\tif (direction === -1) {\n\t\t\tnewFrontSide = frontSide - size;\n\t\t\tnewBehindSide = behindSide - Math.abs(size);\n\n\t\t\tif (frontSide - size > this._front.$config.maxWidth) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (Math.abs(size) >= behindSide) {\n\t\t\t\tsize = -Math.abs(behindSide - 2);\n\t\t\t}\n\t\t\t// if min width\n\t\t\tif (behindSide - Math.abs(size) <= behindMin) {\n\t\t\t\t//this._resizer.style.background = \"red\";\n\t\t\t\tsize = -Math.abs(behindSide - behindMin);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tnewFrontSide = frontSide - Math.abs(size);\n\t\t\tnewBehindSide = behindSide + size;\n\n\t\t\tif (behindSide + size > this._behind.$config.maxWidth) {\n\t\t\t\tsize = this._behind.$config.maxWidth - behindSide;\n\t\t\t\t// return;\n\t\t\t}\n\t\t\tif (Math.abs(size) >= frontSide) {\n\t\t\t\tsize = frontSide - 2;\n\t\t\t}\n\t\t\t// if min width\n\t\t\tif (frontSide - Math.abs(size) <= frontMin) {\n\t\t\t\tsize = Math.abs(frontSide - frontMin);\n\t\t\t}\n\t\t}\n\n\t\tif (direction === -1) {\n\t\t\tnewFrontSide = frontSide - size;\n\t\t\tnewBehindSide = behindSide - Math.abs(size);\n\t\t} else {\n\t\t\tnewFrontSide = frontSide - Math.abs(size);\n\t\t\tnewBehindSide = behindSide + size;\n\t\t}\n\n\t\treturn {\n\t\t\tsize: size,\n\t\t\tnewFrontSide: newFrontSide,\n\t\t\tnewBehindSide: newBehindSide\n\t\t};\n\t};\n\n\tResizerCell.prototype._getGroupName = function(){\n\t\tthis._getSiblings();\n\t\treturn this._front.$config.group || this._behind.$config.group;\n\t};\n\n\tResizerCell.prototype._eachGroupItem = function(callback, master){\n\t\tvar layout = this.$factory.getView(\"main\");\n\n\t\tvar group = this._getGroupName();\n\n\t\tvar resizers = layout.getCellsByType(\"resizer\");\n\t\tfor(var i = 0; i < resizers.length; i++) {\n\t\t\tif (resizers[i]._getGroupName() == group && resizers[i] != this) {\n\t\t\t\tcallback.call(master || this, resizers[i]);\n\t\t\t}\n\t\t}\n\t};\n\n\tResizerCell.prototype._getGroupResizePosition = function(x, y){\n\t\tvar sizes = this._getResizePosition(x, y);\n\n\t\tif(!this._getGroupName()){\n\t\t\treturn sizes;\n\t\t}\n\n\t\tvar positions = [sizes];\n\n\t\tthis._eachGroupItem(function(resizer){\n\t\t\tresizer._getSiblings();\n\t\t\tvar pos = utils.copy(this._positions);\n\t\t\tif(this._xMode){\n\t\t\t\tpos.x += (resizer._behind.$config.width - this._behind.$config.width);\n\t\t\t}else{\n\t\t\t\tpos.y += (resizer._behind.$config.height - this._behind.$config.height);\n\t\t\t}\n\t\t\tresizer._positions = pos;\n\t\t\tpositions.push(resizer._getResizePosition(x, y));\n\t\t});\n\n\t\tvar minMax;\n\t\tfor(var i =0; i < positions.length; i++){\n\t\t\tif(!positions[i]) return;\n\t\t\tif(minMax === undefined){\n\t\t\t\tminMax = positions[i];\n\t\t\t}else if(positions[i].newBehindSide > minMax.newBehindSide){\n\t\t\t\tminMax = positions[i];\n\t\t\t}\n\t\t}\n\n\t/*\tif(minMax != sizes){\n\t\t\tminMax.size = minMax.size;\n\t\t}*/\n\n\t\treturn minMax;\n\t};\n\n\tResizerCell.prototype._moveResizer = function (av, x, y) {\n\t\tif (x === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar sizes = this._getGroupResizePosition(x, y);\n\t\tif(!sizes)\n\t\t\treturn;\n\n\t\tif (Math.abs(sizes.size) === 1) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._xMode) {\n\t\t\tav.style.left = sizes.size + 'px';\n\t\t\tthis._positions.nextX = sizes.size || 0;\n\t\t}\n\t\telse {\n\t\t\tav.style.top = sizes.size + 'px';\n\t\t\tthis._positions.nextY = sizes.size || 0;\n\t\t}\n\n\t\tthis.callEvent(\"onResize\", [sizes.newBehindSide, sizes.newFrontSide]);\n\t};\n\tResizerCell.prototype._setGravity = function (cell) {\n\t\tvar size = this._xMode ? \"offsetWidth\" : \"offsetHeight\";\n\t\tvar position = this._xMode ? this._positions.nextX : this._positions.nextY;\n\t\tvar frontSize = this._front.$view[size];\n\t\tvar behindSize = this._behind.$view[size];\n\t\tvar frontG = this._front.getSize().gravity;\n\t\tvar behindG = this._behind.getSize().gravity;\n\t\tvar newFrontG = (frontSize - position) / frontSize * frontG;\n\t\tvar newBehindG = (behindSize + position) / behindSize * behindG;\n\t\tif (cell !== \"front\") {\n\t\t\tthis._front.$config.gravity = newFrontG;\n\t\t}\n\t\tif (cell !== \"behind\") {\n\t\t\tthis._behind.$config.gravity = newBehindG;\n\t\t}\n\t};\n\n/*\tResizerCell.prototype.setSize = function(){\n\t\t_super.apply(this, arguments)\n\t};*/\n\n\tResizerCell.prototype._getNewSizes = function(){\n\t\tvar behindSize, frontSize, position;\n\n\t\tif(this._xMode){\n\t\t\tbehindSize = this._behind.$config.width;\n\t\t\tfrontSize = this._front.$config.width;\n\t\t\tposition = this._positions.nextX;\n\t\t}else{\n\t\t\tbehindSize = this._behind.$config.height;\n\t\t\tfrontSize = this._front.$config.height;\n\t\t\tposition = this._positions.nextY;\n\t\t}\n\n\t\tif(!frontSize && !behindSize){\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\tfront: frontSize ? ((frontSize - position) || 1) : 0,\n\t\t\tback: behindSize ? ((behindSize + position) || 1) : 0\n\t\t};\n\t};\n\n\tResizerCell.prototype._assignNewSizes = function(newSizes){\n\t\tthis._getSiblings();\n\t\tvar side = this._xMode ? 'width' : 'height';\n\n\t\t// if only gravity cells\n\t\tif (!newSizes) {\n\t\t\tthis._setGravity();\n\t\t}\n\t\telse {\n\t\t\tif (!newSizes.front) {\n\t\t\t\tthis._setGravity(\"behind\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis._front.$config[side] = newSizes.front;\n\t\t\t}\n\t\t\tif (!newSizes.back) {\n\t\t\t\tthis._setGravity(\"front\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis._behind.$config[side] = newSizes.back;\n\t\t\t}\n\t\t}\n\n\t};\n\n\tResizerCell.prototype._setSizes = function () {\n\t\tif (this._resizer) {\n\t\t\tthis.$view.removeChild(this._resizer);\n\t\t}\n\t\tvar newSizes = this._getNewSizes();\n\n\t\tif (this._positions.nextX || this._positions.nextY) {\n\t\t\tthis._assignNewSizes(newSizes);\n\n\t\t\tvar side = this._xMode ? 'width' : 'height';\n\t\t\tvar resizeValue;\n\t\t\tif(!newSizes || !newSizes.front){\n\t\t\t\tif(this._front.$config.group){\n\t\t\t\t\tresizeValue = {\n\t\t\t\t\t\tvalue: this._front.$config.gravity,\n\t\t\t\t\t\tisGravity: true\n\t\t\t\t\t};\n\t\t\t\t\tthis.$gantt.$layout._syncCellSizes(this._front.$config.group, resizeValue);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!newSizes || !newSizes.back){\n\t\t\t\tif(this._behind.$config.group){\n\t\t\t\t\tresizeValue = {\n\t\t\t\t\t\tvalue: this._behind.$config.gravity,\n\t\t\t\t\t\tisGravity: true\n\t\t\t\t\t};\n\t\t\t\t\tthis.$gantt.$layout._syncCellSizes(this._behind.$config.group, resizeValue);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(newSizes){\n\t\t\t\tif(newSizes.front){\n\t\t\t\t\tif(this._front.$config.group){\n\t\t\t\t\t\tresizeValue = {\n\t\t\t\t\t\t\tvalue: this._front.$config[side],\n\t\t\t\t\t\t\tisGravity: false\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis.$gantt.$layout._syncCellSizes(this._front.$config.group, resizeValue);\n\t\t\t\t\t}\n\t\t\t\t} else if(newSizes.back){\n\t\t\t\t\tif(this._behind.$config.group){\n\t\t\t\t\t\tresizeValue = {\n\t\t\t\t\t\t\tvalue: this._behind.$config[side],\n\t\t\t\t\t\t\tisGravity: false\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis.$gantt.$layout._syncCellSizes(this._behind.$config.group, resizeValue);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(this._getGroupName()){\n\t\t\t\tthis.$factory.getView(\"main\").resize();\n\t\t\t}else{\n\t\t\t\tthis.$parent.resize();\n\t\t\t}\n\n\t\t}\n\t};\n\treturn ResizerCell;\n}(Cell));\n\nexport default ResizerCell;","import __extends from \"../../../utils/extends\";\nimport * as domHelpers from \"../utils/dom_helpers\";\nimport * as utils from \"../../../utils/utils\";\nimport env from \"../../../utils/env\";\nimport Cell from \"./cell\";\n\nvar ScrollbarCell = (function (_super) {\n\t\"use strict\";\n\n\tvar SCROLL_MODIFIER_KEYS = [\"altKey\", \"shiftKey\", \"metaKey\"]; // it's no way to disable ctrl+wheel\n\t__extends(ScrollbarCell, _super);\n\tfunction ScrollbarCell(parent, config, factory, gantt) {\n\n\t\tvar _this = _super.apply(this, arguments) || this;\n\t\tthis.$config = utils.mixin(config, {scroll: \"x\"});\n\t\t_this._scrollHorizontalHandler = utils.bind(_this._scrollHorizontalHandler, _this);\n\t\t_this._scrollVerticalHandler = utils.bind(_this._scrollVerticalHandler, _this);\n\t\t_this._outerScrollVerticalHandler = utils.bind(_this._outerScrollVerticalHandler, _this);\n\t\t_this._outerScrollHorizontalHandler = utils.bind(_this._outerScrollHorizontalHandler, _this);\n\t\t_this._mouseWheelHandler = utils.bind(_this._mouseWheelHandler, _this);\n\n\t\tthis.$config.hidden = true;\n\t\tvar size = gantt.config.scroll_size;\n\n\t\tif(gantt.env.isIE){\n\t\t\t// full element height/width must be bigger than just a browser scrollbar,\n\t\t\t// otherwise the scrollbar element won't be scrolled on click\n\t\t\tsize += 1;\n\t\t}\n\n\t\tif(this._isHorizontal()){\n\t\t\t_this.$config.height = size;\n\t\t\t_this.$parent.$config.height = size;\n\t\t}else{\n\t\t\t_this.$config.width = size;\n\t\t\t_this.$parent.$config.width = size;\n\t\t}\n\n\t\tthis.$config.scrollPosition = 0;\n\n\t\t_this.$name = \"scroller\";\n\t\treturn _this;\n\t}\n\n\tScrollbarCell.prototype.init = function(container){\n\t\tcontainer.innerHTML = this.$toHTML();\n\t\tthis.$view = container.firstChild;\n\n\t\tif(!this.$view){\n\t\t\tthis.init();\n\t\t}\n\t\tif(this._isVertical()){\n\t\t\tthis._initVertical();\n\t\t}else{\n\t\t\tthis._initHorizontal();\n\t\t}\n\t\tthis._initMouseWheel();\n\t\tthis._initLinkedViews();\n\t};\n\n\tScrollbarCell.prototype.$toHTML = function () {\n\t\tvar className = this._isHorizontal() ? \"gantt_hor_scroll\" : \"gantt_ver_scroll\";\n\t\treturn \"
\";\n\t};\n\n\tScrollbarCell.prototype._getRootParent = function(){\n\t\tvar parent = this.$parent;\n\t\twhile(parent && parent.$parent){\n\t\t\tparent = parent.$parent;\n\t\t}\n\t\tif(parent){\n\t\t\treturn parent;\n\t\t}\n\t};\n\n\n\tfunction eachCell(root, res){\n\t\tres.push(root);\n\t\tif(root.$cells){\n\t\t\tfor(var i = 0; i < root.$cells.length; i++){\n\t\t\t\teachCell(root.$cells[i], res);\n\t\t\t}\n\t\t}\n\t}\n\tScrollbarCell.prototype._eachView = function(){\n\t\tvar res = [];\n\t\teachCell(this._getRootParent(), res);\n\t\treturn res;\n\t};\n\n\tScrollbarCell.prototype._getLinkedViews = function(){\n\t\tvar views = this._eachView();\n\t\tvar res = [];\n\t\tfor(var i = 0; i < views.length; i++){\n\t\t\tif(views[i].$config && ((this._isVertical() && views[i].$config.scrollY == this.$id) || (this._isHorizontal() && views[i].$config.scrollX == this.$id)) ){\n\t\t\t\tres.push(views[i]);\n\t\t\t}\n\t\t}\n\t\treturn res;\n\t};\n\n\n\tScrollbarCell.prototype._initHorizontal = function(){\n\t\tthis.$scroll_hor = this.$view;\n\t\tthis.$domEvents.attach(this.$view, \"scroll\", this._scrollHorizontalHandler);\n\n\t};\n\n\tScrollbarCell.prototype._initLinkedViews = function(){\n\t\tvar views = this._getLinkedViews();\n\t\tvar css = this._isVertical() ?\"gantt_layout_outer_scroll gantt_layout_outer_scroll_vertical\" : \"gantt_layout_outer_scroll gantt_layout_outer_scroll_horizontal\";\n\t\tfor(var i = 0; i < views.length; i++){\n\t\t\t//views[i].$config.css = [views[i].$config.css || \"\", css].join(\" \");\n\t\t\tdomHelpers.addClassName(views[i].$view || views[i].getNode(), css);\n\t\t}\n\t};\n\n\tScrollbarCell.prototype._initVertical = function(){\n\t\tthis.$scroll_ver = this.$view;\n\t\tthis.$domEvents.attach(this.$view, \"scroll\", this._scrollVerticalHandler);\n\t};\n\n\tScrollbarCell.prototype._updateLinkedViews = function(){\n\t};\n\n\tScrollbarCell.prototype._initMouseWheel = function(){\n\t\tvar ff = env.isFF;\n\t\tif (ff)\n\t\t\tthis.$domEvents.attach(this._getRootParent().$view, \"wheel\", this._mouseWheelHandler, {passive: false});\n\t\telse\n\t\t\tthis.$domEvents.attach(this._getRootParent().$view, \"mousewheel\", this._mouseWheelHandler, {passive: false});\n\t};\n\n\n\n\n\tScrollbarCell.prototype.scrollHorizontally = function(left){\n\t\tif(this._scrolling) return;\n\t\tthis._scrolling = true;\n\n\t\tthis.$scroll_hor.scrollLeft = left;\n\t\tthis.$config.codeScrollLeft = left;\n\t\tleft = this.$scroll_hor.scrollLeft;\n\n\t\tvar views = this._getLinkedViews();\n\t\tfor(var i = 0; i < views.length; i++){\n\t\t\tif(views[i].scrollTo){\n\t\t\t\tviews[i].scrollTo(left, undefined);\n\t\t\t}\n\t\t}\n\t\tvar oldSize = this.$config.scrollPosition;\n\t\tthis.$config.scrollPosition = left;\n\t\tthis.callEvent(\"onScroll\", [oldSize, left, this.$config.scroll]);\n\t\tthis._scrolling = false;\n\t};\n\tScrollbarCell.prototype.scrollVertically = function(top){\n\t\tif(this._scrolling) return;\n\t\tthis._scrolling = true;\n\n\t\tthis.$scroll_ver.scrollTop = top;\n\t\ttop = this.$scroll_ver.scrollTop;\n\n\t\tvar views = this._getLinkedViews();\n\n\t\tfor(var i = 0; i < views.length; i++){\n\t\t\tif(views[i].scrollTo){\n\t\t\t\tviews[i].scrollTo(undefined, top);\n\t\t\t}\n\t\t}\n\t\tvar oldSize = this.$config.scrollPosition;\n\t\tthis.$config.scrollPosition = top;\n\t\tthis.callEvent(\"onScroll\", [oldSize, top, this.$config.scroll]);\n\t\tthis._scrolling = false;\n\t};\n\n\tScrollbarCell.prototype._isVertical = function(){\n\t\treturn this.$config.scroll == \"y\";\n\t};\n\tScrollbarCell.prototype._isHorizontal = function(){\n\t\treturn this.$config.scroll == \"x\";\n\t};\n\tScrollbarCell.prototype._scrollHorizontalHandler = function (e) {\n\t\tif(this._isVertical() || this._scrolling){\n\t\t\treturn;\n\t\t}\n\n\t\t//in safari we can catch previous onscroll after setting new value from mouse-wheel event\n\t\t//set delay to prevent value drifiting\n\t\tif ((new Date()) - ( this._wheel_time || 0 ) < 100) return true;\n\t\t//if (this.$gantt._touch_scroll_active) return;\n\t\tvar left = this.$scroll_hor.scrollLeft;\n\n\t\tthis.scrollHorizontally(left);\n\n\t\tthis._oldLeft = this.$scroll_hor.scrollLeft;\n\t};\n\tScrollbarCell.prototype._outerScrollHorizontalHandler = function(e){\n\t\tif(this._isVertical()){\n\t\t\treturn;\n\t\t}\n\t};\n\n\tScrollbarCell.prototype.show = function(){\n\t\tthis.$parent.show();\n\t};\n\tScrollbarCell.prototype.hide = function(){\n\t\tthis.$parent.hide();\n\t};\n\n\tScrollbarCell.prototype._getScrollSize = function(){\n\t\tvar scrollSize = 0;\n\t\tvar outerSize = 0;\n\t\tvar isHorizontal = this._isHorizontal();\n\n\t\tvar linked = this._getLinkedViews();\n\t\tvar view;\n\t\tvar scrollProperty = isHorizontal ? \"scrollWidth\" : \"scrollHeight\",\n\t\t\tinnerSizeProperty = isHorizontal ? \"contentX\" : \"contentY\";\n\t\tvar outerProperty = isHorizontal ? \"x\" : \"y\";\n\t\tvar offset = this._getScrollOffset();\n\n\t\tfor(var i = 0; i < linked.length; i++){\n\t\t\tview = linked[i];\n\t\t\tif(!(view && view.$content && view.$content.getSize && !view.$config.hidden)) continue;\n\n\t\t\tvar sizes = view.$content.getSize();\n\t\t\tvar cellScrollSize;\n\t\t\tif(sizes.hasOwnProperty(scrollProperty)){\n\t\t\t\tcellScrollSize = sizes[scrollProperty];\n\t\t\t}else{\n\t\t\t\tcellScrollSize = sizes[innerSizeProperty];\n\t\t\t}\n\n\t\t\tif(offset){\n\t\t\t\t// precalculated vertical/horizontal offsets of scrollbar to emulate 4.x look\n\t\t\t\tif(sizes[innerSizeProperty] > sizes[outerProperty] && sizes[innerSizeProperty] > scrollSize && (cellScrollSize > (sizes[outerProperty] - offset + 2))){\n\t\t\t\t\tscrollSize = cellScrollSize + (isHorizontal ? 0 : 2);\n\t\t\t\t\touterSize = sizes[outerProperty];\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tvar nonScrollableSize = Math.max(sizes[innerSizeProperty] - cellScrollSize, 0);\n\t\t\t\tvar scrollableViewPortSize = Math.max(sizes[outerProperty] - nonScrollableSize, 0);\n\t\t\t\tcellScrollSize = cellScrollSize + nonScrollableSize;\n\n\t\t\t\tif(cellScrollSize > scrollableViewPortSize && (cellScrollSize > scrollSize) ){\n\t\t\t\t\t//|| (cellScrollSize === scrollSize && sizes[outerProperty] < outerSize) // same scroll width but smaller scrollable view port\n\n\t\t\t\t\tscrollSize = cellScrollSize;\n\t\t\t\t\touterSize = sizes[outerProperty];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\touterScroll: outerSize,\n\t\t\tinnerScroll: scrollSize\n\t\t};\n\t};\n\n\tScrollbarCell.prototype.scroll = function(position){\n\t\tif(this._isHorizontal()){\n\t\t\tthis.scrollHorizontally(position);\n\t\t}else{\n\t\t\tthis.scrollVertically(position);\n\t\t}\n\t};\n\n\tScrollbarCell.prototype.getScrollState = function(){\n\t\treturn {\n\t\t\tvisible: this.isVisible(),\n\t\t\tdirection: this.$config.scroll,\n\t\t\tsize: this.$config.outerSize,\n\t\t\tscrollSize: this.$config.scrollSize || 0,\n\t\t\tposition: this.$config.scrollPosition || 0\n\t\t};\n\t};\n\n\tScrollbarCell.prototype.setSize = function(width, height){\n\t\t_super.prototype.setSize.apply(this, arguments);\n\n\t\tvar scrollSizes = this._getScrollSize();\n\n\t\tvar ownSize = (this._isVertical() ? height : width) - this._getScrollOffset() + (this._isHorizontal() ? 1 : 0);\n\n\t\tif(scrollSizes.innerScroll && ownSize > scrollSizes.outerScroll){\n\t\t\tscrollSizes.innerScroll += (ownSize - scrollSizes.outerScroll);\n\t\t}\n\t\tthis.$config.scrollSize = scrollSizes.innerScroll;\n\n\t\tthis.$config.width = width;\n\t\tthis.$config.height = height;\n\t\tthis._setScrollSize(scrollSizes.innerScroll);\n\t};\n\n\tScrollbarCell.prototype.isVisible = function(){\n\t\treturn !!(this.$parent && this.$parent.$view.parentNode);\n\t};\n\n\tScrollbarCell.prototype.shouldShow = function(){\n\t\tvar scrollSizes = this._getScrollSize();\n\t\tif(!scrollSizes.innerScroll && (this.$parent && this.$parent.$view.parentNode)){\n\t\t\treturn false;\n\t\t}else if(scrollSizes.innerScroll && !(this.$parent && this.$parent.$view.parentNode)){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tScrollbarCell.prototype.shouldHide = function(){\n\t\tvar scrollSizes = this._getScrollSize();\n\t\tif(!scrollSizes.innerScroll && (this.$parent && this.$parent.$view.parentNode)){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t};\n\n\n\tScrollbarCell.prototype.toggleVisibility = function(){\n\t\tif(this.shouldHide()){\n\t\t\tthis.hide();\n\t\t}else if(this.shouldShow()){\n\t\t\tthis.show();\n\t\t}\n\t};\n\n\tScrollbarCell.prototype._getScaleOffset = function(view){\n\t\tvar offset = 0;\n\t\tif(view && (view.$config.view == \"timeline\" || view.$config.view == \"grid\")){\n\t\t\toffset = view.$content.$getConfig().scale_height;\n\t\t}\n\t\treturn offset;\n\t};\n\n\tScrollbarCell.prototype._getScrollOffset = function(){\n\t\tvar offset = 0;\n\t\tif(this._isVertical()){\n\t\t\tvar parentLayout = this.$parent.$parent;\n\t\t\toffset = Math.max(\n\t\t\t\tthis._getScaleOffset(parentLayout.getPrevSibling(this.$parent.$id)),\n\t\t\t\tthis._getScaleOffset(parentLayout.getNextSibling(this.$parent.$id))\n\t\t\t\t);\n\t\t}else{\n\t\t\tvar linked = this._getLinkedViews();\n\n\t\t\tfor (var i = 0; i < linked.length; i++) {\n\t\t\t\tvar view = linked[i],\n\t\t\t\t\tvparent = view.$parent;\n\t\t\t\tvar cells = vparent.$cells;\n\n\t\t\t\tvar last = cells[cells.length - 1];\n\n\t\t\t\tif (last && last.$config.view == \"scrollbar\" && last.$config.hidden === false) {\n\t\t\t\t\toffset = last.$config.width;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\treturn offset || 0;\n\t};\n\n\tScrollbarCell.prototype._setScrollSize = function(size){\n\t\tvar property = this._isHorizontal() ? \"width\" : \"height\";\n\t\tvar scrollbar = this._isHorizontal() ? this.$scroll_hor : this.$scroll_ver;\n\n\t\tvar offset = this._getScrollOffset();\n\n\t\tvar node = scrollbar.firstChild;\n\n\t\tif(offset){\n\t\t\tif(this._isVertical()){\n\n\t\t\t\tthis.$config.outerSize = (this.$config.height - offset + 3);\n\t\t\t\tscrollbar.style.height = this.$config.outerSize + \"px\";\n\t\t\t\tscrollbar.style.top = (offset-1) + \"px\";\n\t\t\t\tdomHelpers.addClassName(scrollbar, this.$parent._borders.top);\n\t\t\t\tdomHelpers.addClassName(scrollbar.parentNode, \"gantt_task_vscroll\");\n\t\t\t}else{\n\t\t\t\tthis.$config.outerSize = (this.$config.width - offset + 1);\n\t\t\t\tscrollbar.style.width = this.$config.outerSize + \"px\";\n\t\t\t\t//domHelpers.addClassName(scrollbar, this.$parent._borders.right);\n\t\t\t}\n\t\t}else{\n\t\t\tscrollbar.style.top = \"auto\";\n\t\t\tdomHelpers.removeClassName(scrollbar, this.$parent._borders.top);\n\t\t\tdomHelpers.removeClassName(scrollbar.parentNode, \"gantt_task_vscroll\");\n\t\t\tthis.$config.outerSize = this.$config.height;\n\t\t}\n\n\t\tnode.style[property] = size + \"px\";\n\t};\n\n\tScrollbarCell.prototype._scrollVerticalHandler = function (e) {\n\t\tif(this._scrollHorizontalHandler() || this._scrolling){\n\t\t\treturn;\n\t\t}\n\n\t\t//if (this.$gantt._touch_scroll_active) return;\n\t\tvar top = this.$scroll_ver.scrollTop;\n\t\tvar prev = this._oldTop;\n\t\tif(top == prev) return;\n\n\t\tthis.scrollVertically(top);\n\n\t\tthis._oldTop = this.$scroll_ver.scrollTop;\n\n\t};\n\tScrollbarCell.prototype._outerScrollVerticalHandler = function(e){\n\t\tif(this._scrollHorizontalHandler()){\n\t\t\treturn;\n\t\t}\n\t};\n\n\tScrollbarCell.prototype._checkWheelTarget = function(targetNode){\n\t\tvar connectedViews = this._getLinkedViews().concat(this);\n\n\t\tfor(var i = 0; i < connectedViews.length; i++){\n\t\t\tvar node = connectedViews[i].$view;\n\t\t\tif(domHelpers.isChildOf(targetNode, node)){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t};\n\n\tScrollbarCell.prototype._mouseWheelHandler = function(e){\n\t\tvar target = e.target || e.srcElement;\n\n\t\tif(!this._checkWheelTarget(target))\n\t\t\treturn;\n\n\t\tthis._wheel_time = new Date();\n\n\t\tvar res = {};\n\n\t\tvar wheelSpeed = {x: 1, y: 1};\n\t\tvar wheelSpeedConfig = this.$gantt.config.wheel_scroll_sensitivity;\n\n\t\tif (typeof wheelSpeedConfig == \"number\" && !!wheelSpeedConfig) {\n\t\t\twheelSpeed = {x: wheelSpeedConfig, y: wheelSpeedConfig};\n\t\t}\n\t\telse if (({}).toString.apply(wheelSpeedConfig) == \"[object Object]\") {\n\t\t\twheelSpeed = {x: wheelSpeedConfig.x, y: wheelSpeedConfig.y};\n\t\t}\n\n\t\tvar ff = env.isFF;\n\t\tvar deltaX = ff ? (e.deltaX) : e.wheelDeltaX;\n\t\tvar deltaY = ff ? (e.deltaY) : e.wheelDelta;\n\n\t\tvar multiplier = -20;\n\t\tif (ff) {\n\t\t\tif (e.deltaMode !== 0) {\n\t\t\t\tmultiplier = -40;\n\t\t\t} else {\n\t\t\t\tmultiplier = -10;\n\t\t\t}\n\t\t}\n\n\t\tvar wx = ff ? (deltaX * multiplier * wheelSpeed.x) : deltaX * 2 * wheelSpeed.x;\n\t\tvar wy = ff ? (deltaY * multiplier * wheelSpeed.y) : deltaY * wheelSpeed.y;\n\n\t\tvar horizontalScrollModifier = this.$gantt.config.horizontal_scroll_key;\n\n\t\tif (horizontalScrollModifier !== false) {\n\t\t\tif (SCROLL_MODIFIER_KEYS.indexOf(horizontalScrollModifier) >= 0) {\n\t\t\t\tif(e[horizontalScrollModifier] && !(e.deltaX || e.wheelDeltaX)){\n\t\t\t\t\t// shift+mousewheel for horizontal scroll\n\t\t\t\t\twx = wy*2;\n\t\t\t\t\twy = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\tif (wx && Math.abs(wx) > Math.abs(wy)){\n\t\t\tif(this._isVertical()){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif(res.x) return true;//no horisontal scroll, must not block scrolling\n\t\t\tif(!this.$scroll_hor || !this.$scroll_hor.offsetWidth) return true;\n\n\t\t\tvar dir = wx/-40;\n\t\t\tvar oldLeft = this._oldLeft;\n\t\t\tvar left = oldLeft+dir*30;\n\t\t\tthis.scrollHorizontally(left);\n\t\t\tthis.$scroll_hor.scrollLeft = left;\n\t\t\t// not block scroll if position hasn't changed\n\t\t\tif(oldLeft == this.$scroll_hor.scrollLeft){\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis._oldLeft = this.$scroll_hor.scrollLeft;\n\t\t} else {\n\t\t\tif(this._isHorizontal()){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif(res.y) return true;//no vertical scroll, must not block scrolling\n\t\t\tif(!this.$scroll_ver || !this.$scroll_ver.offsetHeight) return true;\n\n\t\t\tvar dir = wy/-40;\n\t\t\tif (typeof wy == \"undefined\")\n\t\t\t\tdir = e.detail;\n\n\t\t\tvar oldTop = this._oldTop;\n\t\t\tvar top = this.$scroll_ver.scrollTop+dir*30;\n\n\t\t\t//if(!this.$gantt.config.prevent_default_scroll &&\n\t\t\t//\t(this.$gantt._cached_scroll_pos && ((this.$gantt._cached_scroll_pos.y == top) || (this.$gantt._cached_scroll_pos.y <= 0 && top <= 0)))) return true;\n\n\n\t\t\tthis.scrollVertically(top);\n\t\t\tthis.$scroll_ver.scrollTop = top;\n\n\t\t\t// not block scroll if position hasn't changed\n\t\t\tif(oldTop == this.$scroll_ver.scrollTop){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tthis._oldTop = this.$scroll_ver.scrollTop;\n\t\t}\n\n\t\tif (e.preventDefault)\n\t\t\te.preventDefault();\n\t\te.cancelBubble=true;\n\t\treturn false;\n\t};\n\n\treturn ScrollbarCell;\n})(Cell);\n\nexport default ScrollbarCell;","import * as utils from \"../../../utils/utils\";\nimport env from \"../../../utils/env\";\n\nvar createStaticBgHelper = function(utils, env){\n\n\tvar canvasBgCache = {};\n\tvar staticBgStyleId = \"gantt-static-bg-styles-\" + utils.uid();\n\n\tfunction renderBgCanvas(targetNode, config, scale, totalHeight, itemHeight) {\n\t\tif (!config.static_background && !config.timeline_placeholder) return;\n\n\t\tvar canvas = document.createElement(\"canvas\");\n\t\tif (!canvas.getContext) return; // if canvas is not supported (for IE8)\n\n\t\t// clear previous bg data\n\t\ttargetNode.innerHTML = \"\";\n\n\t\tvar styleParams = getCellStyles(targetNode);\n\t\tvar png = createBackgroundTiles(styleParams, config, scale, itemHeight);\n\t\tvar bgDivs = createBgDivs(png, config, scale, totalHeight);\n\n\t\tvar fragment = document.createDocumentFragment();\n\n\t\tbgDivs.forEach(function (div) {\n\t\t\tfragment.appendChild(div);\n\t\t});\n\n\t\ttargetNode.appendChild(fragment);\n\t}\n\n\tfunction getColumnWidths(scale) {\n\t\tvar widths = scale.width;\n\t\tvar differentWidths = {};\n\t\tfor (var i = 0; i < widths.length; i++) {\n\t\t\tif (widths[i] * 1)\n\t\t\t\tdifferentWidths[widths[i]] = true;\n\t\t}\n\t\treturn differentWidths;\n\t}\n\n\tfunction parseRgb(rgbCss) {\n\t\tvar result = /^rgba?\\(([\\d]{1,3}), *([\\d]{1,3}), *([\\d]{1,3}) *(,( *[\\d.]+ *))?\\)$/i.exec(rgbCss);\n\t\treturn result ? {\n\t\t\tr: result[1] * 1,\n\t\t\tg: result[2] * 1,\n\t\t\tb: result[3] * 1,\n\t\t\ta: (result[5] * 255) || 255\n\t\t} : null;\n\t}\n\n\tfunction getUrlFromCache(key) {\n\t\treturn canvasBgCache[key] || null;\n\t}\n\n\tfunction getHashKey(width, height, cellStyles) {\n\t\treturn (width + '' + height + cellStyles.bottomBorderColor + cellStyles.rightBorderColor).replace(/[^\\w\\d]/g, '');\n\t}\n\n\tfunction getStyleElement() {\n\t\tvar style = document.getElementById(staticBgStyleId);\n\n\t\tif (!style) {\n\t\t\tstyle = document.createElement(\"style\");\n\t\t\tstyle.id = staticBgStyleId;\n\t\t\tdocument.body.appendChild(style);\n\t\t}\n\t\treturn style;\n\t}\n\n\tfunction cleanup() {\n\t\tvar style = document.getElementById(staticBgStyleId);\n\t\tif (style && style.parentNode) {\n\t\t\tstyle.parentNode.removeChild(style);\n\t\t}\n\t}\n\n\tfunction cacheUrl(key, url) {\n\t\tcanvasBgCache[key] = url;\n\t}\n\n\tfunction generateBgUrl(width, height, cellStyles) {\n\t\t// use relatively big bg image about 500*500px in order to reduce misalignments due browser zoom\n\t\tvar cols = Math.floor(500 / width) || 1;\n\t\tvar rows = Math.floor(500 / height) || 1;\n\n\t\tvar canvas = document.createElement(\"canvas\");\n\t\tcanvas.height = height * rows;\n\t\tcanvas.width = width * cols;\n\n\t\tvar context = canvas.getContext(\"2d\");\n\n\t\tdrawGrid(height, width, rows, cols, context, cellStyles);\n\n\t\treturn canvas.toDataURL();\n\n\t\tfunction drawGrid(rowHeight, colWidth, rows, cols, context, styles) {\n\t\t\t// paint pixels manually instead of using lineTo in order to prevent canvas aliasing\n\t\t\tvar image = context.createImageData(colWidth * cols, rowHeight * rows);\n\t\t\timage.imageSmoothingEnabled = false;\n\n\t\t\tvar verticalLineWidth = styles.rightBorderWidth * 1;\n\t\t\tvar verticalLineColor = parseRgb(styles.rightBorderColor);\n\n\t\t\tvar x = 0,\n\t\t\t\ty = 0,\n\t\t\t\tw = 0;\n\n\t\t\tfor (var col = 1; col <= cols; col++) {\n\t\t\t\tx = col * colWidth - 1;\n\t\t\t\tfor (w = 0; w < verticalLineWidth; w++) {\n\t\t\t\t\tfor (y = 0; y < rowHeight * rows; y++) {\n\t\t\t\t\t\tdrawDot(x - w, y, verticalLineColor, image);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar horizontalLineWidth = styles.bottomBorderWidth * 1;\n\t\t\tvar horizontalLineColor = parseRgb(styles.bottomBorderColor);\n\n\t\t\ty = 0;\n\t\t\tfor (var row = 1; row <= rows; row++) {\n\t\t\t\ty = row * rowHeight - 1;\n\t\t\t\tfor (w = 0; w < horizontalLineWidth; w++) {\n\t\t\t\t\tfor (x = 0; x < colWidth * cols; x++) {\n\t\t\t\t\t\tdrawDot(x, y - w, horizontalLineColor, image);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontext.putImageData(image, 0, 0);\n\t\t}\n\n\t\tfunction drawDot(x, y, color, matrix) {\n\t\t\tvar rowLength = width * cols;\n\n\t\t\tvar index = (y * rowLength + x) * 4;\n\n\t\t\tmatrix.data[index] = color.r;\n\t\t\tmatrix.data[index + 1] = color.g;\n\t\t\tmatrix.data[index + 2] = color.b;\n\t\t\tmatrix.data[index + 3] = color.a;\n\t\t}\n\t}\n\n\tfunction getCssClass(key) {\n\t\treturn \"gantt-static-bg-\" + key;\n\t}\n\n\tfunction createBackgroundTiles(cellStyles, config, scale, itemHeight) {\n\t\tvar data = {};\n\t\tvar widths = getColumnWidths(scale),\n\t\t\theight = itemHeight;\n\n\t\tvar styleHTML = \"\";\n\t\tfor (var i in widths) {\n\n\t\t\tvar width = i * 1;\n\t\t\tvar key = getHashKey(width, height, cellStyles);\n\t\t\tvar cachedUrl = getUrlFromCache(key);\n\n\t\t\tif (!cachedUrl) {\n\t\t\t\tvar bgImage = generateBgUrl(width, height, cellStyles);\n\t\t\t\tcacheUrl(key, bgImage);\n\t\t\t\tstyleHTML += \".\" + getCssClass(key) + \"{ background-image: url('\" + bgImage + \"');}\";\n\t\t\t}\n\n\t\t\tdata[i] = getCssClass(key);\n\t\t}\n\n\t\tif (styleHTML) {\n\t\t\tvar style = getStyleElement();\n\t\t\tstyle.innerHTML += styleHTML;\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tfunction createBgDivs(bgTiles, config, scale, dataHeight) {\n\t\tvar divs = [];\n\t\tvar tile,\n\t\t\tprevWidth = 0,\n\t\t\tprevCell;\n\n\t\tvar widths = scale.width.filter(function (i) {\n\t\t\treturn !!i;\n\t\t});\n\n\t\tvar leftPos = 0;\n\n\t\t//TODO: fixme\n\t\t// bg image misalignments on horizontal scroll on very large time scales, especially in IE/Edge browsers\n\t\t// limiting max tile width seems to solve the issue, but can increase rendering time\n\t\tvar maxTileSize = 100000;\n\t\tif (env.isIE) {\n\t\t\t// special case for IE11 on win7x and probably 8x\n\t\t\tvar appVersion = navigator.appVersion || \"\";\n\t\t\tif (appVersion.indexOf(\"Windows NT 6.2\") != -1 ||\n\t\t\t\tappVersion.indexOf(\"Windows NT 6.1\") != -1 ||\n\t\t\t\tappVersion.indexOf(\"Windows NT 6.0\") != -1) {\n\n\t\t\t\tmaxTileSize = 20000;\n\t\t\t}\n\t\t}\n\n\t\tfor (var i = 0; i < widths.length; i++) {\n\t\t\t//var currentWidth = cells[i].clientWidth;\n\t\t\tvar cell = widths[i];\n\n\t\t\tif ((cell != prevCell && prevCell !== undefined) || (i == widths.length - 1) || (prevWidth > maxTileSize)) {\n\n\t\t\t\tvar totalHeight = dataHeight,\n\t\t\t\t\tcurrentTop = 0,\n\t\t\t\t\trowHeight = Math.floor(maxTileSize / config.row_height) * config.row_height;\n\n\t\t\t\tvar tileWidth = prevWidth;\n\n\t\t\t\twhile (totalHeight > 0) {\n\t\t\t\t\tvar currentHeight = Math.min(totalHeight, rowHeight);\n\t\t\t\t\ttotalHeight -= rowHeight;\n\n\t\t\t\t\ttile = document.createElement(\"div\");\n\n\t\t\t\t\ttile.style.height = currentHeight + \"px\";\n\t\t\t\t\ttile.style.position = \"absolute\";\n\t\t\t\t\ttile.style.top = currentTop + \"px\";\n\t\t\t\t\ttile.style.left = leftPos + \"px\";\n\t\t\t\t\ttile.style.pointerEvents = \"none\";\n\n\t\t\t\t\ttile.style.whiteSpace = \"no-wrap\";\n\t\t\t\t\ttile.className = bgTiles[prevCell || cell];\n\n\t\t\t\t\t// if last - short by 1 px (bug fix)\n\t\t\t\t\tif (i == widths.length - 1) {\n\t\t\t\t\t\ttileWidth = cell + tileWidth - 1;\n\t\t\t\t\t}\n\t\t\t\t\ttile.style.width = tileWidth + \"px\";\n\n\t\t\t\t\tdivs.push(tile);\n\t\t\t\t\tcurrentTop += currentHeight;\n\t\t\t\t}\n\t\t\t\tprevWidth = 0;\n\t\t\t\tleftPos += tileWidth;\n\n\t\t\t\t//cell = 0;\n\t\t\t}\n\t\t\tif (cell) {\n\t\t\t\tprevWidth += cell;\n\t\t\t\tprevCell = cell;\n\t\t\t}\n\n\t\t}\n\n\t\treturn divs;\n\t}\n\n\n\tfunction createProbeElement(){\n\t\tvar cell = document.createElement(\"div\");\n\t\tcell.className = \"gantt_task_cell\";\n\t\tvar row = document.createElement(\"div\");\n\t\trow.className = \"gantt_task_row\";\n\t\trow.appendChild(cell);\n\t\treturn row;\n\t}\n\tfunction getCellStyles(targetNode) {\n\t\t// creating temp DOM structure for resolving style parameters. Will be removed after calculating.\n\t\t// Add two rows and read styles from the first one. \n\t\t// Some skins (e.g. material) define special styles for the last row, so we add a couple and read styles from one which is not the :last-child;\n\t\tvar firstRow = createProbeElement();\n\t\tvar secondRow = createProbeElement();\n\n\t\ttargetNode.appendChild(firstRow);\n\t\ttargetNode.appendChild(secondRow);\n\n\t\tvar firstRowCell = firstRow.firstChild;\n\n\t\tvar rowStyles = getComputedStyle(firstRow),\n\t\t\tcellStyles = getComputedStyle(firstRowCell);\n\n\t\tvar params = {\n\t\t\tbottomBorderWidth: rowStyles.getPropertyValue(\"border-bottom-width\").replace(\"px\", \"\"),\n\t\t\trightBorderWidth: cellStyles.getPropertyValue(\"border-right-width\").replace(\"px\", \"\"),\n\t\t\tbottomBorderColor: rowStyles.getPropertyValue(\"border-bottom-color\"),\n\t\t\trightBorderColor: cellStyles.getPropertyValue(\"border-right-color\")\n\t\t};\n\n\t\ttargetNode.removeChild(firstRow);\n\t\ttargetNode.removeChild(secondRow);\n\n\t\treturn params;\n\t}\n\n\treturn {\n\t\trender: renderBgCanvas,\n\t\tdestroy: cleanup\n\t};\n};\n\nexport default {\n\tcreate: function(){\n\t\treturn createStaticBgHelper(utils, env);\n\t}\n};\n\n","import ScaleHelper from \"./scales_ignore\";\nimport eventable from \"../../../utils/eventable\";\nimport * as utils from \"../../../utils/utils\";\nimport * as helpers from \"../../../utils/helpers\";\nimport topPositionMixin from \"../row_position_mixin\";\nimport canvasRender from \"./tasks_canvas_render\";\nimport createLayerConfig from \"./timeline_layers\";\n\nvar Timeline = function(parent, config, factory, gantt){\n\tthis.$config = utils.mixin({}, config || {});\n\tthis.$scaleHelper = new ScaleHelper(gantt);\n\tthis.$gantt = gantt;\n\tthis._posFromDateCache = {};\n\tthis._timelineDragScroll = null;\n\tutils.mixin(this, topPositionMixin(this));\n\teventable(this);\n};\n\nTimeline.prototype = {\n\tinit: function(container) {\n\t\tcontainer.innerHTML += \"
\";\n\t\tthis.$task = container.childNodes[0];\n\n\t\tthis.$task.innerHTML = \"
\";\n\t\tthis.$task_scale = this.$task.childNodes[0];\n\n\t\tthis.$task_data = this.$task.childNodes[1];\n\t\tconst taskBg = \"
\";\n\t\tconst links = \"\";\n\t\tconst taskBars = \"
\";\n\n\t\tconst taskConstraints = \"
\";\n\t\tconst taskDeadlines = \"
\";\n\t\tconst taskBaselines = \"
\";\n\n\t\tthis.$task_data.innerHTML = taskBg + taskBaselines + links + taskBars + taskConstraints + taskDeadlines;\n\n\t\tthis.$task_bg = this.$task_data.childNodes[0];\n\t\tthis.$task_baselines = this.$task_data.childNodes[1];\n\t\tthis.$task_links = this.$task_data.childNodes[2];\n\t\tthis.$task_bars = this.$task_data.childNodes[3];\n\t\tthis.$task_constraints = this.$task_data.childNodes[4];\n\t\tthis.$task_deadlines = this.$task_data.childNodes[5];\n\n\t\tthis._tasks = {\n\t\t\tcol_width: 0,\n\t\t\twidth: [], // width of each column\n\t\t\tfull_width: 0, // width of all columns\n\t\t\ttrace_x: [],\n\t\t\trendered: {}\n\t\t};\n\n\t\tvar config = this.$getConfig();\n\t\tvar attr = config[this.$config.bind + \"_attribute\"];\n\t\tvar linksAttr = config[this.$config.bindLinks + \"_attribute\"];\n\t\tif(!attr && this.$config.bind){\n\t\t\tattr = \"data-\" + this.$config.bind + \"-id\";\n\t\t}\n\t\tif(!linksAttr && this.$config.bindLinks){\n\t\t\tlinksAttr = \"data-\" + this.$config.bindLinks + \"-id\";\n\t\t}\n\t\tthis.$config.item_attribute = attr || null;\n\t\tthis.$config.link_attribute = linksAttr || null;\n\n\t\tvar layers = this._createLayerConfig();\n\t\tif(!this.$config.layers){\n\t\t\tthis.$config.layers = layers.tasks;\n\t\t}\n\t\tif(!this.$config.linkLayers){\n\t\t\tthis.$config.linkLayers = layers.links;\n\t\t}\n\n\t\tthis._attachLayers(this.$gantt);\n\n\t\tthis.callEvent(\"onReady\", []);\n\t\t//this.refresh();\n\t\tif (this.$gantt.ext.dragTimeline) {\n\t\t\tthis._timelineDragScroll = this.$gantt.ext.dragTimeline.create();\n\t\t\tthis._timelineDragScroll.attach(this);\n\t\t}\n\t},\n\n\tsetSize: function(width, height){\n\t\tvar config = this.$getConfig();\n\n\t\tif(width*1 === width){\n\t\t\tthis.$config.width = width;\n\t\t}\n\t\tif(height*1 === height){\n\n\t\t\tthis.$config.height = height;\n\t\t\tvar dataHeight = Math.max(this.$config.height - config.scale_height);\n\t\t\tthis.$task_data.style.height = dataHeight + 'px';\n\t\t}\n\n\t\tthis.refresh();\n\t\tthis.$task_bg.style.backgroundImage = \"\";\n\n\t\tif(config.smart_rendering && this.$config.rowStore){\n\t\t\tthis.$task_bg.style.height = this.getTotalHeight() +\"px\";\n\t\t}else{\n\t\t\tthis.$task_bg.style.height = \"\";\n\t\t}\n\n\t\tvar scale = this._tasks;\n\t\t//timeline area layers\n\t\tvar data_els = this.$task_data.childNodes;\n\t\tfor(var i= 0, len = data_els.length; i < len; i++){\n\t\t\tvar el = data_els[i];\n\t\t\tif(el.hasAttribute(\"data-layer\") && el.style)\n\t\t\t\tel.style.width = scale.full_width + \"px\";\n\t\t}\n\t},\n\n\tisVisible: function(){\n\t\tif(this.$parent && this.$parent.$config){\n\t\t\treturn !this.$parent.$config.hidden;\n\t\t}else{\n\t\t\treturn this.$task.offsetWidth;\n\t\t}\n\t},\n\n\tgetSize: function(){\n\t\tvar config = this.$getConfig();\n\t\tvar store = this.$config.rowStore;\n\n\t\tvar contentHeight = store ? this.getTotalHeight() : 0,\n\t\t\tcontentWidth = this.isVisible() ? this._tasks.full_width : 0;\n\n\t\treturn {\n\t\t\tx: this.isVisible() ? this.$config.width : 0,\n\t\t\ty: this.isVisible() ? this.$config.height : 0,\n\t\t\tcontentX: this.isVisible() ? contentWidth : 0,\n\t\t\tcontentY: this.isVisible() ? (config.scale_height + contentHeight) : 0,\n\t\t\tscrollHeight: this.isVisible() ? contentHeight : 0,\n\t\t\tscrollWidth: this.isVisible() ? contentWidth : 0\n\t\t};\n\t},\n\n\tscrollTo: function(left, top){\n\t\tif(!this.isVisible())\n\t\t\treturn;\n\n\t\tvar scrolled = false;\n\n\t\tthis.$config.scrollTop = this.$config.scrollTop || 0;\n\t\tthis.$config.scrollLeft = this.$config.scrollLeft || 0;\n\t\tif(top*1 === top){\n\t\t\tthis.$config.scrollTop = top;\n\t\t\tthis.$task_data.scrollTop = this.$config.scrollTop;\n\t\t\tscrolled = true;\n\t\t}\n\t\tif (left*1 === left){\n\t\t\tthis.$task.scrollLeft = left;\n\t\t\tthis.$config.scrollLeft = this.$task.scrollLeft;\n\t\t\tthis._refreshScales();\n\t\t\tscrolled = true;\n\t\t}\n\n\t\tif(scrolled){\n\t\t\tthis.callEvent(\"onScroll\", [this.$config.scrollLeft, this.$config.scrollTop]);\n\t\t}\n\t},\n\n\t_refreshScales: function _refreshScales() {\n\t\tif(!this.isVisible())\n\t\t\treturn;\n\n\t\tvar config = this.$getConfig();\n\t\tif (!config.smart_scales) return;\n\n\t\tvar viewPort = this.getViewPort();\n\n\t\tvar scales = this._scales;\n\t\tthis.$task_scale.innerHTML = this._getScaleChunkHtml(scales, viewPort.x, viewPort.x_end);\n\t},\n\n\tgetViewPort: function(){\n\t\tvar scrollLeft = this.$config.scrollLeft || 0;\n\t\tvar scrollTop = this.$config.scrollTop || 0;\n\t\tvar height = this.$config.height || 0;\n\t\tvar width = this.$config.width || 0;\n\t\treturn {\n\t\t\ty: scrollTop,\n\t\t\ty_end: scrollTop + height,\n\t\t\tx: scrollLeft,\n\t\t\tx_end: scrollLeft + width,\n\t\t\theight: height,\n\t\t\twidth: width\n\t\t};\n\t},\n\n\t_createLayerConfig: createLayerConfig,\n\n\t_attachLayers: function(gantt){\n\t\tthis._taskLayers = [];\n\t\tthis._linkLayers = [];\n\n\t\tvar self = this;\n\n\t\tvar layers = this.$gantt.$services.getService(\"layers\");\n\n\t\tif(this.$config.bind){\n\n\t\t\tthis._bindStore();\n\t\t\tvar taskRenderer = layers.getDataRender(this.$config.bind);\n\n\t\t\tif(!taskRenderer){\n\t\t\t\ttaskRenderer = layers.createDataRender({\n\t\t\t\t\tname: this.$config.bind,\n\t\t\t\t\tdefaultContainer: function(){ return self.$task_data;}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttaskRenderer.container = function(){ return self.$task_data;};\n\n\t\t\tvar taskLayers = this.$config.layers;\n\t\t\tfor(var i = 0; taskLayers && i < taskLayers.length; i++){\n\t\t\t\tvar layer = taskLayers[i];\n\n\t\t\t\tif(typeof layer == \"string\"){\n\t\t\t\t\tlayer = this.$gantt.$ui.layers[layer]();\n\t\t\t\t}\n\n\t\t\t\tif(typeof layer == \"function\" || (layer && layer.render && layer.update)){\n\t\t\t\t\tlayer = {renderer: layer};\n\t\t\t\t}\n\n\t\t\t\tlayer.view = this;\n\n\t\t\t\tvar bar_layer = taskRenderer.addLayer(layer);\n\t\t\t\tthis._taskLayers.push(bar_layer);\n\t\t\t\tif(layer.expose){\n\t\t\t\t\tthis._taskRenderer = taskRenderer.getLayer(bar_layer);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._initStaticBackgroundRender();\n\t\t}\n\n\t\tif(this.$config.bindLinks){\n\t\t\tself.$config.linkStore = self.$gantt.getDatastore(self.$config.bindLinks);\n\n\t\t\tvar linkRenderer = layers.getDataRender(this.$config.bindLinks);\n\n\t\t\tif(!linkRenderer){\n\t\t\t\tlinkRenderer = layers.createDataRender({\n\t\t\t\t\tname: this.$config.bindLinks,\n\t\t\t\t\tdefaultContainer: function(){ return self.$task_data;}\n\t\t\t\t});\n\t\t\t}\n\t\t\tvar linkLayers = this.$config.linkLayers;\n\t\t\tfor(var i = 0; linkLayers && i < linkLayers.length; i++){\n\n\t\t\t\tif(typeof layer == \"string\"){\n\t\t\t\t\tlayer = this.$gantt.$ui.layers[layer]();\n\t\t\t\t}\n\n\t\t\t\tvar layer = linkLayers[i];\n\t\t\t\tlayer.view = this;\n\t\t\t//\tlayer.getViewPort = getViewPort;\n\t\t\t//\tsubscribeSmartRender(layer);\n\t\t\t\tvar linkLayer = linkRenderer.addLayer(layer);\n\t\t\t\tthis._taskLayers.push(linkLayer);\n\t\t\t\tif(linkLayers[i].expose){\n\t\t\t\t\tthis._linkRenderer = linkRenderer.getLayer(linkLayer);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_initStaticBackgroundRender: function(){\n\t\tvar self = this;\n\t\tvar staticRender = canvasRender.create();\n\t\tvar store = self.$config.rowStore;\n\t\tif(!store) return;\n\n\t\tthis._staticBgHandler = store.attachEvent(\"onStoreUpdated\", function(id, item, mode){\n\t\t\tif(id !== null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif(!self.isVisible())\n\t\t\t\treturn;\n\t\t\tvar config = self.$getConfig();\n\t\t\tif(config.static_background || config.timeline_placeholder) {\n\t\t\t\tvar store = self.$gantt.getDatastore(self.$config.bind);\n\t\t\t\tvar staticBgContainer = self.$task_bg_static;\n\t\t\t\tif(!staticBgContainer){\n\t\t\t\t\tstaticBgContainer = document.createElement(\"div\");\n\t\t\t\t\tstaticBgContainer.className = \"gantt_task_bg\";\n\t\t\t\t\tself.$task_bg_static = staticBgContainer;\n\t\t\t\t\tif(self.$task_bg.nextSibling){\n\t\t\t\t\t\tself.$task_data.insertBefore(staticBgContainer, self.$task_bg.nextSibling);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tself.$task_data.appendChild(staticBgContainer);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (store) {\n\t\t\t\t\tvar staticBackgroundHeight = self.getTotalHeight();\n\t\t\t\t\tif (config.timeline_placeholder){\n\t\t\t\t\t\tstaticBackgroundHeight = config.timeline_placeholder.height || self.$task_data.offsetHeight || 99999;\n\t\t\t\t\t}\n\t\t\t\t\tstaticRender.render(staticBgContainer, config, self.getScale(), staticBackgroundHeight, self.getItemHeight(item ? item.id : null));\n\t\t\t\t}\n\t\t\t}else if(config.static_background){\n\t\t\t\tif(self.$task_bg_static && self.$task_bg_static.parentNode){\n\t\t\t\t\tself.$task_bg_static.parentNode.removeChild(self.$task_bg_static);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.attachEvent(\"onDestroy\", function () {\n\t\t\tstaticRender.destroy();\n\t\t});\n\t\tthis._initStaticBackgroundRender = function(){};//init once\n\t},\n\n\t_clearLayers: function(gantt){\n\t\tvar layers = this.$gantt.$services.getService(\"layers\");\n\t\tvar taskRenderer = layers.getDataRender(this.$config.bind);\n\t\tvar linkRenderer = layers.getDataRender(this.$config.bindLinks);\n\n\t\tif (this._taskLayers) {\n\t\t\tfor(var i = 0; i < this._taskLayers.length; i++){\n\t\t\t\ttaskRenderer.removeLayer(this._taskLayers[i]);\n\t\t\t}\n\t\t}\n\t\tif (this._linkLayers) {\n\t\t\tfor(var i = 0; i < this._linkLayers.length; i++){\n\t\t\t\tlinkRenderer.removeLayer(this._linkLayers[i]);\n\t\t\t}\n\t\t}\n\n\t\tthis._linkLayers = [];\n\t\tthis._taskLayers = [];\n\t},\n\n\t_render_tasks_scales: function _render_tasks_scales() {\n\t\tvar config = this.$getConfig();\n\n\t\tvar scales_html = \"\",\n\t\t\touter_width = 0,\n\t\t\tscale_height = 0;\n\n\t\tvar state = this.$gantt.getState();\n\n\t\tif (this.isVisible()) {\n\t\t\tvar helpers = this.$scaleHelper;\n\t\t\tvar scales = this._getScales();\n\t\t\tscale_height = config.scale_height;\n\n\t\t\tvar availWidth = this.$config.width;\n\t\t\tif(config.autosize == \"x\" || config.autosize == \"xy\"){\n\t\t\t\tavailWidth = Math.max(config.autosize_min_width, 0);\n\t\t\t}\n\n\t\t\tvar cfgs = helpers.prepareConfigs(scales, config.min_column_width, availWidth, scale_height - 1, state.min_date, state.max_date, config.rtl);\n\t\t\tvar cfg = this._tasks = cfgs[cfgs.length - 1];\n\t\t\tthis._scales = cfgs;\n\t\t\tthis._posFromDateCache = {};\n\n\t\t\tscales_html = this._getScaleChunkHtml(cfgs, 0, this.$config.width);\n\n\t\t\touter_width = cfg.full_width + \"px\";//cfg.full_width + (this._scroll_sizes().y ? scrollSizes.scroll_size : 0) + \"px\";\n\t\t\tscale_height += \"px\";\n\t\t}\n\n\t\tthis.$task_scale.style.height = scale_height;\n\n\t\tthis.$task_data.style.width =\n\t\t\tthis.$task_scale.style.width = outer_width;\n\n\t\tthis.$task_scale.innerHTML = scales_html;\n\n\t},\n\n\t_getScaleChunkHtml: function _get_scale_chunk_html (scales, fromPos, toPos) {\n\t\tvar templates = this.$gantt.templates;\n\t\tvar html = [];\n\n\t\tvar css = templates.scale_row_class;\n\t\tfor (var i = 0; i < scales.length; i++) {\n\t\t\tvar cssClass = \"gantt_scale_line\";\n\t\t\tvar tplClass = css(scales[i]);\n\t\t\tif (tplClass) {\n\t\t\t\tcssClass += \" \" + tplClass;\n\t\t\t}\n\n\t\t\thtml.push(\"
\" + this._prepareScaleHtml(scales[i], fromPos, toPos, i) + \"
\");\n\t\t}\n\n\t\treturn html.join(\"\");\n\t},\n\t_prepareScaleHtml: function _prepare_scale_html(config, fromPos, toPos, index) {\n\t\tvar globalConfig = this.$getConfig();\n\t\tvar globalTemplates = this.$gantt.templates;\n\n\t\tvar cells = [];\n\t\tvar date = null, css = null;\n\n\t\tvar content = config.format || config.template || config.date;\n\n\t\tif(typeof content === \"string\"){\n\t\t\tcontent = this.$gantt.date.date_to_str(content);\n\t\t}\n\n\t\tvar startIndex = 0,\n\t\t\tendIndex = config.count;\n\n\t\tif (globalConfig.smart_scales && (!isNaN(fromPos) && !isNaN(toPos))) {\n\t\t\tstartIndex = helpers.findBinary(config.left, fromPos);\n\t\t\tendIndex = helpers.findBinary(config.left, toPos) + 1;\n\t\t}\n\n\t\tcss = config.css || function () {\n\t\t\t};\n\t\tif (!config.css && globalConfig.inherit_scale_class) {\n\t\t\tcss = globalTemplates.scale_cell_class;\n\t\t}\n\n\t\tfor (var i = startIndex; i < endIndex; i++) {\n\t\t\tif (!config.trace_x[i]) break;\n\n\t\t\tdate = new Date(config.trace_x[i]);\n\t\t\tvar value = content.call(this, date),\n\t\t\t\twidth = config.width[i],\n\t\t\t\theight = config.height,\n\t\t\t\tleft = config.left[i],\n\t\t\t\tstyle = \"\",\n\t\t\t\ttemplate = \"\",\n\t\t\t\tcssclass = \"\";\n\n\t\t\tif (width) {\n\t\t\t\tvar position = globalConfig.smart_scales ? (\"position:absolute;left:\" + left + \"px\") : \"\";\n\n\t\t\t\tstyle = \"width:\" + (width) + \"px;\" + position;\n\t\t\t\t// GS-1188: Display the scale value in the viewport for long cells\n\t\t\t\tconst viewPort = this.getViewPort();\n\t\t\t\tconst floatConfig = (globalConfig.scales[index] || {}).sticky; // for old scale settings\n\n\t\t\t\tlet labelPosition = '';\n\t\t\t\tconst approxLabelWidth = 70;\n\t\t\t\t// if sticky config is not specified - sticky labels are enabled for long cells only\n\t\t\t\tif ((floatConfig !== false && width > approxLabelWidth) || floatConfig === true) {\n\t\t\t\t\t\n\t\t\t\t\tif (left < viewPort.x && left + width/2 - approxLabelWidth/2 < viewPort.x){\n\t\t\t\t\t\tlabelPosition = ` style='position:absolute;left: ${viewPort.x - left + 10}px;' `;\n\t\t\t\t\t} else if(left + width/2 + approxLabelWidth/2 > viewPort.x_end && width > approxLabelWidth){\n\t\t\t\t\t\tlet labelPos = viewPort.x_end - left - 10;\n\t\t\t\t\t\tlet translateValue = \"-100%\";\n\t\t\t\t\t\tif(labelPos < approxLabelWidth) {\n\t\t\t\t\t\t\tlabelPos = approxLabelWidth;\n\t\t\t\t\t\t\ttranslateValue = `-${labelPos}px`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlabelPosition = ` style='position:absolute;left: ${labelPos}px;transform: translate(${translateValue},0);' `;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcssclass = \"gantt_scale_cell\" + (i == config.count - 1 ? \" gantt_last_cell\" : \"\");\n\n\t\t\t\ttemplate = css.call(this, date);\n\t\t\t\tif (template) cssclass += \" \" + template;\n\n\t\t\t\tvar ariaAttr = this.$gantt._waiAria.getTimelineCellAttr(value);\n\t\t\t\tvar cell = `
${value}
`;\n\t\t\t\tcells.push(cell);\n\t\t\t} else {\n\t\t\t\t//do not render ignored cells\n\t\t\t}\n\n\t\t}\n\t\treturn cells.join(\"\");\n\t},\n\tdateFromPos: function dateFromPos(x) {\n\t\tvar scale = this._tasks;\n\t\tif (x < 0 || x > scale.full_width || !scale.full_width) {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar ind = helpers.findBinary(this._tasks.left, x);\n\t\tvar summ = this._tasks.left[ind];\n\n\t\tvar col_width = scale.width[ind] || scale.col_width;\n\t\tvar part = 0;\n\t\tif (col_width) {\n\t\t\tpart = (x - summ) / col_width;\n\t\t\tif(scale.rtl){\n\t\t\t\tpart = 1 - part;\n\t\t\t}\n\n\t\t}\n\n\t\tvar unit = 0;\n\t\tif (part) {\n\t\t\tunit = this._getColumnDuration(scale, scale.trace_x[ind]);\n\t\t}\n\n\t\tvar date = new Date(scale.trace_x[ind].valueOf() + Math.round(part * unit));\n\t\treturn date;\n\t},\n\tposFromDate: function posFromDate(date) {\n\t\tif (!this.isVisible())\n\t\t\treturn 0;\n\n\t\tif(!date){\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar dateValue = String(date.valueOf());\n\n\t\tif(this._posFromDateCache[dateValue] !== undefined){\n\t\t\treturn this._posFromDateCache[dateValue];\n\t\t}\n\t\tvar ind = this.columnIndexByDate(date);\n\t\tthis.$gantt.assert(ind >= 0, \"Invalid day index\");\n\n\t\tvar wholeCells = Math.floor(ind);\n\t\tvar partCell = ind % 1;\n\n\t\tvar pos = this._tasks.left[Math.min(wholeCells, this._tasks.width.length - 1)];\n\t\tif (wholeCells == this._tasks.width.length)\n\t\t\tpos += this._tasks.width[this._tasks.width.length - 1];\n\t\t//for(var i=1; i <= wholeCells; i++)\n\t\t//\tpos += gantt._tasks.width[i-1];\n\n\t\tif (partCell) {\n\t\t\tif (wholeCells < this._tasks.width.length) {\n\t\t\t\tpos += this._tasks.width[wholeCells] * (partCell % 1);\n\t\t\t} else {\n\t\t\t\tpos += 1;\n\t\t\t}\n\n\t\t}\n\n\t\tvar roundPos = Math.round(pos);\n\t\tthis._posFromDateCache[dateValue] = roundPos;\n\t\treturn Math.round(roundPos);\n\t},\n\n\t_getNextVisibleColumn: function (startIndex, columns, ignores) {\n\t\t// iterate columns to the right\n\t\tvar date = +columns[startIndex];\n\t\tvar visibleDateIndex = startIndex;\n\t\twhile (ignores[date]) {\n\t\t\tvisibleDateIndex++;\n\t\t\tdate = +columns[visibleDateIndex];\n\t\t}\n\n\t\treturn visibleDateIndex;\n\t},\n\t_getPrevVisibleColumn: function (startIndex, columns, ignores) {\n\t\t// iterate columns to the left\n\t\tvar date = +columns[startIndex];\n\t\tvar visibleDateIndex = startIndex;\n\t\twhile (ignores[date]) {\n\t\t\tvisibleDateIndex--;\n\t\t\tdate = +columns[visibleDateIndex];\n\t\t}\n\t\treturn visibleDateIndex;\n\t},\n\t_getClosestVisibleColumn: function (startIndex, columns, ignores) {\n\t\tvar visibleDateIndex = this._getNextVisibleColumn(startIndex, columns, ignores);\n\t\tif (!columns[visibleDateIndex]) {\n\t\t\tvisibleDateIndex = this._getPrevVisibleColumn(startIndex, columns, ignores);\n\t\t}\n\t\treturn visibleDateIndex;\n\t},\n\tcolumnIndexByDate: function columnIndexByDate(date) {\n\t\tvar pos = new Date(date).valueOf();\n\t\tvar days = this._tasks.trace_x_ascending,\n\t\t\tignores = this._tasks.ignore_x;\n\n\t\tvar state = this.$gantt.getState();\n\n\t\tif (pos <= state.min_date) {\n\t\t\tif(this._tasks.rtl){\n\t\t\t\treturn days.length;\n\t\t\t}else{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t}\n\n\t\tif (pos >= state.max_date) {\n\t\t\tif(this._tasks.rtl){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn days.length;\n\t\t\t}\n\t\t}\n\n\t\tvar dateIndex = helpers.findBinary(days, pos);\n\n\t\tvar visibleIndex = this._getClosestVisibleColumn(dateIndex, days, ignores);\n\t\tvar visibleDate = days[visibleIndex];\n\t\tvar transition = this._tasks.trace_index_transition;\n\n\t\tif(!visibleDate){\n\t\t\tif(transition){\n\t\t\t\treturn transition[0];\n\t\t\t}else{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tvar part = ((date - days[visibleIndex]) / this._getColumnDuration(this._tasks, days[visibleIndex]));\n\t\tif(transition){\n\t\t\treturn transition[visibleIndex] + (1 - part);\n\t\t}else{\n\t\t\treturn visibleIndex + part;\n\t\t}\n\t},\n\tgetItemPosition:function (task, start_date, end_date) {\n\t\tvar xLeft, xRight, width;\n\n\t\tlet displayStart = start_date || task.start_date || task.$auto_start_date;\n\t\tlet displayEnd = end_date || task.end_date || task.$auto_end_date;\n\t\tif(this._tasks.rtl){\n\t\t\txRight = this.posFromDate(displayStart);\n\t\t\txLeft = this.posFromDate(displayEnd);\n\t\t}else{\n\t\t\txLeft = this.posFromDate(displayStart);\n\t\t\txRight = this.posFromDate(displayEnd);\n\t\t}\n\t\twidth = Math.max((xRight - xLeft), 0);\n\n\t\tvar y = this.getItemTop(task.id);\n\n\t\tvar height = this.getBarHeight(task.id);\n\t\tvar rowHeight = this.getItemHeight(task.id);\n\t\treturn {\n\t\t\tleft: xLeft,\n\t\t\ttop: y,\n\t\t\theight: height,\n\t\t\twidth: width,\n\t\t\trowHeight: rowHeight\n\t\t};\n\t},\n\n\tgetBarHeight: function(taskId, isMilestoneRender){\n\t\tvar config = this.$getConfig();\n\n\t\tvar task = this.$config.rowStore.getItem(taskId);\n\t\t// height of the bar item\n\t\tvar height = task.task_height || task.bar_height || config.bar_height || config.task_height;\n\t\tvar rowHeight = this.getItemHeight(taskId);\n\n\t\tif (height == \"full\") {\n\t\t\tvar offset = config.bar_height_padding || 3;\n\t\t\theight = rowHeight - offset;\n\t\t}\n\t\t//item height cannot be bigger than row height\n\t\theight = Math.min(height, rowHeight);\n\t\tif (isMilestoneRender) { // to get correct height for addapting Milestone to the row\n\t\t\theight = Math.round(height / Math.sqrt(2));\n\t\t}\n\t\treturn Math.max(height, 0);\n\t},\n\n\tgetScale: function(){\n\t\treturn this._tasks;\n\t},\n\n\t_getScales: function _get_scales() {\n\t\tvar config = this.$getConfig();\n\t\tvar helpers = this.$scaleHelper;\n\t\tvar scales = [helpers.primaryScale(config)].concat(helpers.getSubScales(config));\n\n\t\thelpers.sortScales(scales);\n\t\treturn scales;\n\t},\n\n\t_getColumnDuration: function _get_coll_duration(scale, date) {\n\t\treturn this.$gantt.date.add(date, scale.step, scale.unit) - date;\n\t},\n\t_bindStore: function () {\n\t\tif (this.$config.bind){\n\t\t\tvar rowStore = this.$gantt.getDatastore(this.$config.bind);\n\t\t\tthis.$config.rowStore = rowStore;\n\t\t\tif(rowStore && !rowStore._timelineCacheAttached){\n\t\t\t\tvar self = this;\n\t\t\t\trowStore._timelineCacheAttached = rowStore.attachEvent(\"onBeforeFilter\", function(){\n\t\t\t\t\tself._resetTopPositionHeight();\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t},\n\t_unbindStore: function(){\n\t\tif (this.$config.bind){\n\t\t\tvar rowStore = this.$gantt.getDatastore(this.$config.bind);\n\t\t\tif(rowStore && rowStore._timelineCacheAttached){\n\t\t\t\trowStore.detachEvent(rowStore._timelineCacheAttached);\n\t\t\t\trowStore._timelineCacheAttached = false;\n\t\t\t}\n\t\t}\n\t},\n\trefresh: function(){\n\t\tthis._bindStore();\n\n\t\tif(this.$config.bindLinks) {\n\t\t\tthis.$config.linkStore = this.$gantt.getDatastore(this.$config.bindLinks);\n\t\t}\n\n\t\tthis._resetTopPositionHeight();\n\t\tthis._resetHeight();\n\t\tthis._initStaticBackgroundRender();\n\t\tthis._render_tasks_scales();\n\t},\n\n\tdestructor: function(){\n\t\tvar gantt = this.$gantt;\n\t\tthis._clearLayers(gantt);\n\t\tthis._unbindStore();\n\t\tthis.$task = null;\n\t\tthis.$task_scale = null;\n\t\tthis.$task_data = null;\n\t\tthis.$task_bg = null;\n\t\tthis.$task_links = null;\n\t\tthis.$task_bars = null;\n\n\t\tthis.$gantt = null;\n\n\t\tif(this.$config.rowStore){\n\t\t\tthis.$config.rowStore.detachEvent(this._staticBgHandler);\n\t\t\tthis.$config.rowStore = null;\n\t\t}\n\t\tif(this.$config.linkStore){\n\t\t\tthis.$config.linkStore = null;\n\t\t}\n\n\t\tif(this._timelineDragScroll) {\n\t\t\tthis._timelineDragScroll.destructor();\n\t\t\tthis._timelineDragScroll = null;\n\t\t}\n\n\t\tthis.callEvent(\"onDestroy\", []);\n\t\tthis.detachAllEvents();\n\n\t}\n};\n\nexport default Timeline;","import * as helpers from \"../../utils/helpers\";\n\nfunction clearTaskStoreHandler(self) {\n\tif (self._delayRender) {\n\t\tself._delayRender.$cancelTimeout();\n\t}\n\n\tif (!self.$gantt) {\n\t\treturn;\n\t}\n\n\tvar tasks = self.$gantt.$data.tasksStore;\n\tvar ownStore = self.$config.rowStore;\n\n\tvar handlerIdProperty = \"_attached_\" + ownStore.$config.name;\n\tif (self[handlerIdProperty]) {\n\t\ttasks.detachEvent(self[handlerIdProperty]);\n\t\tself[handlerIdProperty] = null;\n\t}\n\n\tif (ownStore.$attachedResourceViewHandler) {\n\t\townStore.detachEvent(ownStore.$attachedResourceViewHandler);\n\t\townStore.$attachedResourceViewHandler = null;\n\n\t\ttasks.detachEvent(ownStore.$attachedTaskStoreHandler);\n\t\townStore.$attachedTaskStoreHandler = null;\n\t}\n}\n\nfunction createMixin(_super){\n\n\tvar initGrid = _super.prototype.init,\n\t\tdestroyGrid = _super.prototype.destructor;\n\n\treturn {\n\t\tinit: function() {\n\t\t\tinitGrid.apply(this, arguments);\n\t\t\tthis._linkToTaskStore();\n\t\t},\n\n\t\tdestructor: function() {\n\t\t\tclearTaskStoreHandler(this);\n\t\t\tdestroyGrid.apply(this, arguments);\n\t\t},\n\n\t\tpreviousDragId: null,\n\t\trelevantResources: null,\n\n\t\t_linkToTaskStore: function () {\n\t\t\tif (this.$config.rowStore && this.$gantt.$data.tasksStore) {\n\t\t\t\tvar tasks = this.$gantt.$data.tasksStore;\n\t\t\t\tvar ownStore = this.$config.rowStore;\n\t\t\t\tclearTaskStoreHandler(this);\n\n\t\t\t\tvar self = this;\n\t\t\t\tvar delayRender = helpers.delay(function() {\n\t\t\t\t\tif (self.$gantt.getState().lightbox) {\n\t\t\t\t\t\tdelayRender();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst linkedStore = self.$config.rowStore;\n\n\t\t\t\t\t\t// Repaint only relevant resources for task drag\n\t\t\t\t\t\tconst repaintStack = self._getRelevantResources();\n\t\t\t\t\t\tif (repaintStack){\n\t\t\t\t\t\t\tif (repaintStack == \"nothing_to_repaint\"){\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlinkedStore._quick_refresh = true;\n\t\t\t\t\t\t\tself.relevantResources.forEach(function(id){\n\t\t\t\t\t\t\t\tlinkedStore.refresh(id);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tlinkedStore._quick_refresh = false;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// because rowstore could be changed during timeout\n\t\t\t\t\t\t\tlinkedStore.refresh();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, 300);\n\t\t\t\tthis._delayRender = delayRender;\n\t\t\t\tvar handlerIdProperty = \"_attached_\" + ownStore.$config.name;\n\n\t\t\t\tif (!self[handlerIdProperty]) {\n\t\t\t\t\tself[handlerIdProperty] = tasks.attachEvent(\"onStoreUpdated\", function(){\n\t\t\t\t\t\tif(!delayRender.$pending && !this._skipResourceRepaint){\n\t\t\t\t\t\t\t// don't repaint if we update progress\n\t\t\t\t\t\t\tconst state = self.$gantt.getState();\n\t\t\t\t\t\t\tif (state.drag_mode == \"progress\"){\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t} else if (state.drag_mode && state.drag_id){\n\t\t\t\t\t\t\t\t// we need it here because if you started dragging a task and quickly stopped the drag_id is removed \n\t\t\t\t\t\t\t\t// from the state before we record it, so we cannot repaint only the relevant resources\n\t\t\t\t\t\t\t\tself.previousDragId = state.drag_id;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdelayRender();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis.$gantt.attachEvent(\"onDestroy\", function() {\n\t\t\t\t\t// detach events to don't call delayed tasks\n\t\t\t\t\tclearTaskStoreHandler(self);\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (!ownStore.$attachedResourceViewHandler) {\n\t\t\t\t\townStore.$attachedResourceViewHandler = ownStore.attachEvent(\"onBeforeFilter\", function() {\n\t\t\t\t\t\tif (self.$gantt.getState().lightbox) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (delayRender.$pending) {\n\t\t\t\t\t\t\tdelayRender.$cancelTimeout();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tself._updateNestedTasks();\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t});\n\n\t\t\t\t\townStore.$attachedTaskStoreHandler = tasks.attachEvent(\"onAfterDelete\", function(){\n\t\t\t\t\t\townStore._mark_recompute = true;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_getRelevantResources: function (){\n\t\t\t// GS-2199. process_resource_assignments is disabled,\n\t\t\t// so we cannot get only the relevant assignment resources\n\t\t\tif (!this.$gantt.getTaskAssignments){\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst state = this.$gantt.getState();\n\t\t\tconst linkedStore = this.$config.rowStore;\n\n\t\t\tlet resourceIds = [];\n\t\t\tif (state.drag_mode && state.drag_id){\n\t\t\t\tif (this.previousDragId == state.drag_id){ // we continue dragging the task\n\t\t\t\t\tif (this.relevantResources) {\n\t\t\t\t\t\treturn this.relevantResources;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresourceIds = this._getIdsFromAssignments(this.previousDragId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse { // we started the task drag\n\t\t\t\t\tthis.previousDragId = state.drag_id;\n\t\t\t\t\tresourceIds = this._getIdsFromAssignments(this.previousDragId);\n\t\t\t\t}\n\t\t\t} else if (this.previousDragId){ // finished task drag, but the resources are still the same\n\t\t\t\tresourceIds = this._getIdsFromAssignments(this.previousDragId);\n\t\t\t\tthis.previousDragId = null;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (!resourceIds.length){\n\t\t\t\treturn this.relevantResources = \"nothing_to_repaint\";\n\t\t\t}\n\t\t\t\n\t\t\tresourceIds.forEach(function(resourceId){\n\t\t\t\tlinkedStore.eachParent(function(parent){\n\t\t\t\t\tresourceIds.push(parent.id);\n\t\t\t\t}, resourceId);\n\t\t\t});\n\n\t\t\treturn this.relevantResources = [...new Set(resourceIds)];\n\t\t},\n\n\t\t_getIdsFromAssignments: function(id){\n\t\t\tconst gantt = this.$gantt;\n\t\t\tconst resourceIds = [];\n\n\t\t\tconst task = gantt.getTask(id);\n\t\t\tlet assignments = gantt.getTaskAssignments(id);\n\t\t\tassignments.forEach(function(assignment){\n\t\t\t\tresourceIds.push(assignment.resource_id);\n\t\t\t});\n\n\t\t\t// get child assignments when dragging project task\n\t\t\tif (gantt.isSummaryTask(task) && gantt.config.drag_project) {\n\t\t\t\tgantt.eachTask(function(child){\n\t\t\t\t\tconst childAssignments = gantt.getTaskAssignments(child.id);\n\t\t\t\t\tchildAssignments.forEach(function(assignment){\n\t\t\t\t\t\tresourceIds.push(assignment.resource_id);\n\t\t\t\t\t});\n\t\t\t\t}, id);\n\t\t\t}\n\n\t\t\t// get assignments of other selected tasks\n\t\t\tif (gantt.config.drag_multiple && gantt.getSelectedTasks){\n\t\t\t\tconst selectedIds = gantt.getSelectedTasks();\n\t\t\t\tselectedIds.forEach(function(selectedId){\n\t\t\t\t\tconst selectedAssignments = gantt.getTaskAssignments(selectedId);\n\t\t\t\t\tselectedAssignments.forEach(function(assignment){\n\t\t\t\t\t\tresourceIds.push(assignment.resource_id);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn resourceIds;\n\t\t},\n\n\t\t_updateNestedTasks: function(){\n\t\t\tvar gantt = this.$gantt;\n\t\t\tvar resourceStore = gantt.getDatastore(gantt.config.resource_store);\n\t\t\tif (!resourceStore.$config.fetchTasks) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresourceStore.silent(function(){\n\t\t\t\tvar toAddArray = [];\n\t\t\t\tvar toAdd = {};\n\t\t\t\tvar toDelete = {};\n\n\t\t\t\tresourceStore.eachItem(function(resource){\n\t\t\t\t\tif (resource.$role == \"task\") {\n\t\t\t\t\t\ttoDelete[resource.id] = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar assignments = gantt.getResourceAssignments(resource.id);\n\t\t\t\t\tvar addedTasks = {};\n\n\t\t\t\t\t// GS-1505. We need to sort assignments before updating tasks. \n\t\t\t\t\t// Iterating them without that will affect the order of featched tasks in the resource store\n\t\t\t\t\tassignments.sort(function (a, b) {\n\t\t\t\t\t\tconst resourceData = resourceStore.pull;\n\t\t\t\t\t\tconst resource1 = resourceData[`${a.task_id}_${a.resource_id}`];\n\t\t\t\t\t\tconst resource2 = resourceData[`${b.task_id}_${b.resource_id}`];\n\t\t\t\t\t\tif (resource1 && resource2) {\n\t\t\t\t\t\t\treturn resource1.$local_index - resource2.$local_index;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tassignments.forEach(function(a) {\n\t\t\t\t\t\tif(addedTasks[a.task_id] || !gantt.isTaskExists(a.task_id)){\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddedTasks[a.task_id] = true;\n\n\t\t\t\t\t\tvar task = gantt.getTask(a.task_id);\n\t\t\t\t\t\t//var copy = gantt.copy(task);\n\t\t\t\t\t\tvar copy = Object.create(task);\n\t\t\t\t\t\tcopy.id = task.id + '_' + resource.id;\n\n\t\t\t\t\t\tcopy.$task_id = task.id;\n\t\t\t\t\t\tcopy.$resource_id = resource.id;\n\t\t\t\t\t\tcopy[resourceStore.$parentProperty] = resource.id;\n\t\t\t\t\t\tcopy.$role = \"task\";\n\t\t\t\t\t\ttoAddArray.push(copy);\n\t\t\t\t\t\ttoAdd[copy.id] = true;\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\tfor (var id in toDelete) {\n\t\t\t\t\tif (!toAdd[id]) {\n\t\t\t\t\t\tresourceStore.removeItem(id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(toAddArray.length){\n\t\t\t\t\tresourceStore.parse(toAddArray);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t};\n}\n\nexport default createMixin;","\nexport default function(){\n\tvar self = this;\n\tvar taskFilter = function(){\n\t\treturn self.isVisible();\n\t};\n\n\tvar barVisible = function(id, task){\n\t\treturn !task.hide_bar;\n\t};\n\n\tconst gantt = this.$gantt;\n\n\tconst isTimedProject = function(id, task){\n\t\treturn task.type === gantt.config.types.project && task.auto_scheduling === false;\n\t};\n\tconst isNotTimedProject = function(id, task){\n\t\treturn !isTimedProject(id, task);\n\t};\n\n\tvar taskLayers = [\n\t\t{\n\t\t\texpose: true,\n\t\t\trenderer: this.$gantt.$ui.layers.taskBar(),\n\t\t\tcontainer: this.$task_bars,\n\t\t\tfilter: [taskFilter, barVisible, isNotTimedProject]\n\t\t},\n\t\t{\n\t\t\trenderer: this.$gantt.$ui.layers.timedProjectBar(),\n\t\t\tfilter: [taskFilter, isTimedProject],\n\t\t\tcontainer: this.$task_bars,\n\t\t\tappend: true\n\t\t},\n\t\t{\n\t\t\trenderer: this.$gantt.$ui.layers.taskSplitBar(),\n\t\t\tfilter: [taskFilter],\n\t\t\tcontainer: this.$task_bars,\n\t\t\tappend: true\n\t\t},\n\t\t{\n\t\t\trenderer: this.$gantt.$ui.layers.taskRollupBar(),\n\t\t\tfilter: [taskFilter],\n\t\t\tcontainer: this.$task_bars,\n\t\t\tappend: true\n\t\t},\n\t\t{\n\t\t\trenderer: this.$gantt.$ui.layers.taskConstraints(),\n\t\t\tfilter: [taskFilter],\n\t\t\tcontainer: this.$task_constraints,\n\t\t\tappend: false\n\t\t}\n\t];\n\n\tif(gantt.config.deadlines !== false){\n\t\ttaskLayers.push({\n\t\t\trenderer: this.$gantt.$ui.layers.taskDeadline(),\n\t\t\tfilter: [taskFilter],\n\t\t\tcontainer: this.$task_deadlines,\n\t\t\tappend: false\n\t\t});\n\t}\n\n\tif(gantt.config.baselines !== false){\n\t\ttaskLayers.push({\n\t\t\trenderer: this.$gantt.$ui.layers.taskBaselines(),\n\t\t\tfilter: [taskFilter],\n\t\t\tcontainer: this.$task_baselines,\n\t\t\tappend: false\n\t\t});\n\t}\n\n\ttaskLayers.push({\n\t\trenderer: this.$gantt.$ui.layers.taskBg(),\n\t\tcontainer: this.$task_bg,\n\t\tfilter: [\n\t\t\t//function(){\n\t\t\t//\treturn !self.$getConfig().static_background;\n\t\t\t//},\n\t\t\ttaskFilter\n\t\t]\n\t});\n\n\tvar linkLayers = [\n\t\t{\n\t\t\texpose: true,\n\t\t\trenderer: this.$gantt.$ui.layers.link(),\n\t\t\tcontainer: this.$task_links,\n\t\t\tfilter: [taskFilter]\n\t\t}\n\t];\n\n\treturn {\n\t\ttasks: taskLayers,\n\t\tlinks: linkLayers\n\t};\n\n};","import * as domHelpers from \"../utils/dom_helpers\";\nimport * as utils from \"../../../utils/utils\";\nimport resourceStoreMixin from \"../resource_store_mixin\";\nimport Grid from \"./grid\";\nimport __extends from \"../../../utils/extends\";\n\nvar ResourceGrid = (function (_super) {\n\n\tfunction ResourceGrid(parent, config, factory, gantt) {\n\t\treturn _super.apply(this, arguments) || this;\n\t}\n\n\t__extends(ResourceGrid, _super);\n\n\tutils.mixin(ResourceGrid.prototype, {\n\t\tinit: function(){\n\t\t\tif(this.$config.bind === undefined){\n\t\t\t\tthis.$config.bind = this.$getConfig().resource_store;\n\t\t\t}\n\t\t\t_super.prototype.init.apply(this, arguments);\n\t\t},\n\n\t\t_initEvents: function(){\n\t\t\tvar gantt = this.$gantt;\n\t\t\t_super.prototype._initEvents.apply(this, arguments);\n\t\t\tthis._mouseDelegates.delegate(\"click\", \"gantt_row\", gantt.bind(function (e, id, trg) {\n\t\t\t\tvar store = this.$config.rowStore;\n\t\t\t\tif(!store) return true;\n\n\t\t\t\tvar target = domHelpers.locateAttribute(e, this.$config.item_attribute);\n\t\t\t\tif(target){\n\t\t\t\t\tstore.select(target.getAttribute(this.$config.item_attribute));\n\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}, this), this.$grid);\n\n\t\t}\n\n\t}, true);\n\n\tutils.mixin(ResourceGrid.prototype, resourceStoreMixin(ResourceGrid), true);\n\n\treturn ResourceGrid;\n})(Grid);\n\nexport default ResourceGrid;","import * as utils from \"../../../utils/utils\";\nimport Timeline from \"./timeline\";\nimport resourceStoreMixin from \"../resource_store_mixin\";\nimport __extends from \"../../../utils/extends\";\n\nvar ResourceTimeline = (function (_super) {\n\n\tfunction ResourceTimeline(parent, config, factory, gantt) {\n\t\tvar self = _super.apply(this, arguments) || this;\n\t\tself.$config.bindLinks = null;\n\t\treturn self;\n\t}\n\n\t__extends(ResourceTimeline, _super);\n\n\tutils.mixin(ResourceTimeline.prototype, {\n\t\tinit: function(){\n\t\t\t\n\t\t\tif(this.$config.bind === undefined){\n\t\t\t\tthis.$config.bind = this.$getConfig().resource_store;\n\t\t\t}\n\t\t\t_super.prototype.init.apply(this, arguments);\n\t\t},\n\t\t_createLayerConfig: function() {\n\t\t\tvar self = this;\n\t\t\tvar taskFilter = function() {\n\t\t\t\treturn self.isVisible();\n\t\t\t};\n\n\t\t\tvar taskLayers = [\n\t\t\t\t{\n\t\t\t\t\trenderer: this.$gantt.$ui.layers.resourceRow(),\n\t\t\t\t\tcontainer: this.$task_bars,\n\t\t\t\t\tfilter: [taskFilter]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\trenderer: this.$gantt.$ui.layers.taskBg(),\n\t\t\t\t\tcontainer: this.$task_bg,\n\t\t\t\t\tfilter: [taskFilter]\n\t\t\t\t}\n\t\t\t];\n\n\t\t\tvar linkLayers = [];\n\n\t\t\treturn {\n\t\t\t\ttasks: taskLayers,\n\t\t\t\tlinks: linkLayers\n\t\t\t};\n\t\t}\n\n\t}, true);\n\n\tutils.mixin(ResourceTimeline.prototype, resourceStoreMixin(ResourceTimeline), true);\n\n\treturn ResourceTimeline;\n})(Timeline);\n\n\nexport default ResourceTimeline;\n\n\n","import * as utils from \"../../../utils/utils\";\nimport ResourceTimeline from \"./resource_timeline\";\nimport resourceStoreMixin from \"../resource_store_mixin\";\nimport __extends from \"../../../utils/extends\";\n\nvar ResourceHistogram = (function (_super) {\n\n\tfunction ResourceHistogram(parent, config, factory, gantt) {\n\t\tvar self = _super.apply(this, arguments) || this;\n\t\tself.$config.bindLinks = null;\n\t\treturn self;\n\t}\n\n\t__extends(ResourceHistogram, _super);\n\n\tutils.mixin(ResourceHistogram.prototype, {\n\t\t_createLayerConfig: function(){\n\t\t\tvar self = this;\n\t\t\tvar taskFilter = function(){\n\t\t\t\treturn self.isVisible();\n\t\t\t};\n\n\t\t\tvar taskLayers = [\n\t\t\t\t{\n\t\t\t\t\trenderer: this.$gantt.$ui.layers.resourceHistogram(),\n\t\t\t\t\tcontainer: this.$task_bars,\n\t\t\t\t\tfilter: [taskFilter]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\trenderer: this.$gantt.$ui.layers.taskBg(),\n\t\t\t\t\tcontainer: this.$task_bg,\n\t\t\t\t\tfilter: [taskFilter]\n\t\t\t\t}\n\t\t\t];\n\n\t\t\tvar linkLayers = [];\n\n\t\t\treturn {\n\t\t\t\ttasks: taskLayers,\n\t\t\t\tlinks: linkLayers\n\t\t\t};\n\t\t}\n\n\t}, true);\n\n\tutils.mixin(ResourceHistogram.prototype, resourceStoreMixin(_super), true);\n\n\treturn ResourceHistogram;\n})(ResourceTimeline);\n\n\nexport default ResourceHistogram;\n\n\n","export default {\n\tinit: function (controller, grid) {\n\t\tvar gantt = grid.$gantt;\n\n\t\tgantt.attachEvent(\"onTaskClick\", function (id, e) {\n\t\t\tif (gantt._is_icon_open_click(e))\n\t\t\t\treturn true;\n\t\t\tvar state = controller.getState();\n\t\t\tvar cell = controller.locateCell(e.target);\n\n\t\t\tif (cell && controller.getEditorConfig(cell.columnName)) {\n\t\t\t\tif (controller.isVisible() && state.id == cell.id && state.columnName == cell.columnName) {\n\t\t\t\t\t// do nothing if editor is already active in this cell\n\t\t\t\t} else {\n\t\t\t\t\tcontroller.startEdit(cell.id, cell.columnName);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tgantt.attachEvent(\"onEmptyClick\", function () {\n\t\t\tif (controller.isVisible() && controller.isChanged()) {\n\t\t\t\tcontroller.save();\n\t\t\t} else {\n\t\t\t\tcontroller.hide();\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tgantt.attachEvent(\"onTaskDblClick\", function (id, e) {\n\t\t\tvar state = controller.getState();\n\t\t\tvar cell = controller.locateCell(e.target);\n\t\t\tif (cell && controller.isVisible() && cell.columnName == state.columnName) {\n\t\t\t\t//GS-933 probably, we don't need to hide the inline editor because the lightbox cannot be opened if you double-click on an inline editor\n\t\t\t\t//remove this code later if people don't complain\n\t\t\t\t//controller.hide();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t},\n\n\tonShow: function (controller, placeholder, grid) {\n\t\tvar gantt = grid.$gantt;\n\t\t\n\n\t\tif(gantt.ext && gantt.ext.keyboardNavigation){\n\t\t\tvar keyNav = gantt.ext.keyboardNavigation;\n\t\t\tkeyNav.attachEvent(\"onKeyDown\", function(command, e){\n\t\t\t\tvar keyboard = gantt.constants.KEY_CODES;\n\t\t\t\tvar keyCode = e.keyCode;\n\t\t\t\tvar preventKeyNav = false;\n\n\t\t\t\tswitch (keyCode){\n\t\t\t\t\tcase keyboard.SPACE:\n\t\t\t\t\t\tif(controller.isVisible()){\n\t\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (preventKeyNav){\n\t\t\t\t\treturn false;\n\t\t\t\t} else{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\t\n\t\tplaceholder.onkeydown = function (e) {\n\t\t\te = e || window.event;\n\n\t\t\tvar keyboard = gantt.constants.KEY_CODES;\n\t\t\tif (e.defaultPrevented || (e.shiftKey && e.keyCode != keyboard.TAB)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar shouldPrevent = true;\n\t\t\tswitch (e.keyCode) {\n\t\t\t\tcase gantt.keys.edit_save:\n\t\t\t\t\tcontroller.save();\n\t\t\t\t\tbreak;\n\t\t\t\tcase gantt.keys.edit_cancel:\n\t\t\t\t\tcontroller.hide();\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyboard.UP:\n\t\t\t\tcase keyboard.DOWN:\n\t\t\t\t\tif (controller.isVisible()) {\n\t\t\t\t\t\tcontroller.hide();\n\t\t\t\t\t\tshouldPrevent = false;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyboard.TAB:\n\t\t\t\t\tif (e.shiftKey) {\n\t\t\t\t\t\tcontroller.editPrevCell(true);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontroller.editNextCell(true);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tshouldPrevent = false;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (shouldPrevent) {\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t};\n\t},\n\tonHide: function () {\n\n\t},\n\n\tdestroy: function () {\n\n\t}\n};\n\n","export default {\n\tinit: function(controller, grid){\n\t\tvar self = controller;\n\t\tvar gantt = grid.$gantt;\n\n\t\tvar onBlurDelay = null;\n\t\tvar keyNav = gantt.ext.keyboardNavigation;\n\t\tkeyNav.attachEvent(\"onBeforeFocus\", function (node) {\n\t\t\tvar activeCell = controller.locateCell(node);\n\t\t\tclearTimeout(onBlurDelay);\n\t\t\tif (activeCell) {\n\t\t\t\tvar columnName = activeCell.columnName;\n\t\t\t\tvar id = activeCell.id;\n\n\t\t\t\tvar editorState = self.getState();\n\t\t\t\tif(self.isVisible()){\n\t\t\t\t\tif(editorState.id == id && editorState.columnName === columnName) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tkeyNav.attachEvent(\"onFocus\", function (node) {\n\t\t\tvar activeCell = controller.locateCell(node);\n\t\t\tvar state = controller.getState();\n\t\t\tclearTimeout(onBlurDelay);\n\t\t\tif (activeCell && !(activeCell.id == state.id && activeCell.columnName == state.columnName)) {\n\t\t\t\tif(self.isVisible()){\n\t\t\t\t\tself.save();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tcontroller.attachEvent(\"onHide\", function(){\n\t\t\tclearTimeout(onBlurDelay);\n\t\t});\n\n\t\tkeyNav.attachEvent(\"onBlur\", function () {\n\t\t\tonBlurDelay = setTimeout(function(){\n\t\t\t\tself.save();\n\t\t\t});\n\n\t\t\treturn true;\n\t\t});\n\n\t\tgantt.attachEvent(\"onTaskDblClick\", function(id,e){\n\t\t\t// block lightbox on double click inside editor\n\t\t\tvar state = controller.getState();\n\t\t\tvar cell = controller.locateCell(e.target);\n\t\t\tif(cell && controller.isVisible() && cell.columnName == state.columnName){\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tgantt.attachEvent(\"onTaskClick\", function (id, e) {\n\t\t\tif(gantt._is_icon_open_click(e))\n\t\t\t\treturn true;\n\n\t\t\tvar state = controller.getState();\n\t\t\tvar cell = controller.locateCell(e.target);\n\n\t\t\tif (cell && controller.getEditorConfig(cell.columnName)) {\n\t\t\t\tif(controller.isVisible() && state.id == cell.id && state.columnName == cell.columnName){\n\t\t\t\t\t// do nothing if editor is already active in this cell\n\t\t\t\t}else{\n\t\t\t\t\tcontroller.startEdit(cell.id, cell.columnName);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t\tgantt.attachEvent(\"onEmptyClick\", function () {\n\t\t\tself.save();\n\t\t\treturn true;\n\t\t});\n\n\t\tkeyNav.attachEvent(\"onKeyDown\", function(command, e){\n\t\t\tvar activeCell = controller.locateCell(e.target);\n\t\t\tvar hasEditor = activeCell ? controller.getEditorConfig(activeCell.columnName) : false;\n\n\t\t\tvar state = controller.getState();\n\t\t\tvar keyboard = gantt.constants.KEY_CODES;\n\t\t\tvar keyCode = e.keyCode;\n\t\t\tvar preventKeyNav = false;\n\n\t\t\tswitch (keyCode){\n\t\t\t\tcase keyboard.ENTER:\n\t\t\t\t\tif(controller.isVisible()){\n\t\t\t\t\t\tcontroller.save();\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t}else if(hasEditor && !(e.ctrlKey || e.metaKey || e.shiftKey)){\n\t\t\t\t\t\tself.startEdit(activeCell.id, activeCell.columnName);\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyboard.ESC:\n\t\t\t\t\tif(controller.isVisible()){\n\t\t\t\t\t\tcontroller.hide();\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyboard.UP:\n\t\t\t\tcase keyboard.DOWN:\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyboard.LEFT:\n\t\t\t\tcase keyboard.RIGHT:\n\t\t\t\t\tif((hasEditor && controller.isVisible()) || state.editorType === \"date\"){\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyboard.SPACE:\n\t\t\t\t\tif(controller.isVisible()){\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif(hasEditor && !controller.isVisible()){\n\t\t\t\t\t\tself.startEdit(activeCell.id, activeCell.columnName);\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyboard.DELETE:\n\t\t\t\t\tif(hasEditor && !controller.isVisible()){\n\t\t\t\t\t\tself.startEdit(activeCell.id, activeCell.columnName);\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t} else if(hasEditor && controller.isVisible()){\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyboard.TAB:\n\t\t\t\t\tif(controller.isVisible()){\n\n\t\t\t\t\t\tif(e.shiftKey){\n\t\t\t\t\t\t\tcontroller.editPrevCell(true);\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tcontroller.editNextCell(true);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar newState = controller.getState();\n\t\t\t\t\t\tif(newState.id){\n\t\t\t\t\t\t\tkeyNav.focus({type:\"taskCell\", id: newState.id, column:newState.columnName});\n\t\t\t\t\t\t}\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tif(controller.isVisible())\n\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\telse{\n\n\t\t\t\t\t\t// start editing on character key\n\t\t\t\t\t\tif((keyCode >= 48 && keyCode <= 57) || // [0-9]\n\t\t\t\t\t\t\t(keyCode > 95 && keyCode < 112) || // numpad\n\t\t\t\t\t\t\t(keyCode >= 64 && keyCode <= 91) || // [a-z]\n\t\t\t\t\t\t\t(keyCode > 185 && keyCode < 193) || //;=-,etc\n\t\t\t\t\t\t\t(keyCode > 218 && keyCode < 223)\n\t\t\t\t\t\t){\n\t\t\t\t\t\t\tvar modifiers = command.modifiers;\n\n\t\t\t\t\t\t\tvar anyModifier = modifiers.alt || modifiers.ctrl || modifiers.meta || modifiers.shift;\n\t\t\t\t\t\t\tif(modifiers.alt){\n\t\t\t\t\t\t\t\t// don't start editing on alt+key\n\t\t\t\t\t\t\t}else if (anyModifier && keyNav.getCommandHandler(command, \"taskCell\")){\n\t\t\t\t\t\t\t\t// don't start editing if command already have a keyboard shortcut\n\t\t\t\t\t\t\t}else if(hasEditor && !controller.isVisible()){\n\t\t\t\t\t\t\t\tself.startEdit(activeCell.id, activeCell.columnName);\n\t\t\t\t\t\t\t\tpreventKeyNav = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (preventKeyNav){\n\t\t\t\treturn false;\n\t\t\t} else{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t});\n\t},\n\tonShow: function(controller, placeholder, grid){},\n\tonHide: function(controller, placeholder, grid){\n\t\tconst gantt = grid.$gantt;\n\t\tif (gantt){\n\t\t\tgantt.focus();\n\t\t}\n\n\t},\n\tdestroy: function(){}\n};\n\n","export default function (gantt) {\n\n\tvar BaseEditor = function () {\n\t};\n\n\tBaseEditor.prototype = {\n\t\tshow: function (id, column, config, placeholder) {\n\t\t},\n\t\thide: function () {\n\t\t},\n\t\tset_value: function (value, id, column, node) {\n\t\t\tthis.get_input(node).value = value;\n\t\t},\n\t\tget_value: function (id, column, node) {\n\t\t\treturn this.get_input(node).value || \"\";\n\t\t},\n\t\tis_changed: function (value, id, column, node) {\n\t\t\tvar currentValue = this.get_value(id, column, node);\n\t\t\tif (currentValue && value && currentValue.valueOf && value.valueOf) {\n\t\t\t\treturn currentValue.valueOf() != value.valueOf();\n\t\t\t} else {\n\t\t\t\treturn currentValue != value;\n\t\t\t}\n\t\t},\n\t\tis_valid: function (value, id, column, node) {\n\t\t\treturn true;\n\t\t},\n\n\t\tsave: function (id, column, node) {\n\n\t\t},\n\t\tget_input: function (node) {\n\t\t\treturn node.querySelector(\"input\");\n\t\t},\n\t\tfocus: function (node) {\n\t\t\tvar input = this.get_input(node);\n\t\t\tif (!input) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (input.focus) {\n\t\t\t\tinput.focus();\n\t\t\t}\n\n\t\t\tif (input.select) {\n\t\t\t\tinput.select();\n\t\t\t}\n\t\t}\n\t};\n\treturn BaseEditor;\n};","import getKeyboardMapping from \"./keyboard_mappings\";\nimport textEditorFactory from \"./editors/text\";\nimport numberEditorFactory from \"./editors/number\";\nimport selectEditorFactory from \"./editors/select\";\nimport dateEditorFactory from \"./editors/date\";\nimport predecessorEditorFactory from \"./editors/predecessor\";\nimport durationEditorFactory from \"./editors/duration\";\nimport * as utils from \"../../../../utils/utils\";\nimport * as domHelpers from \"../../utils/dom_helpers\";\nimport eventable from \"../../../../utils/eventable\";\nimport linkedPropertiesProcessor from \"./linked_properties\";\n\nfunction initConfigs(gantt){\n\tgantt.config.editor_types = {\n\t\ttext: new (textEditorFactory(gantt))(),\n\t\tnumber: new (numberEditorFactory(gantt))(),\n\t\tselect: new (selectEditorFactory(gantt))(),\n\t\tdate: new (dateEditorFactory(gantt))(),\n\t\tpredecessor: new (predecessorEditorFactory(gantt))(),\n\t\tduration: new (durationEditorFactory(gantt))()\n\t};\n}\n\nfunction create(gantt){\n\tvar keyboardMapping = getKeyboardMapping(gantt);\n\n\tvar eventBus = {};\n\teventable(eventBus);\n\n\tfunction createGridEditors(grid) {\n\n\t\tfunction _getGridCellFromNode(node){\n\t\t\tif(!domHelpers.isChildOf(node, grid.$grid)){\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar row = domHelpers.locateAttribute(node, grid.$config.item_attribute);\n\t\t\tvar cell = domHelpers.locateAttribute(node, \"data-column-name\");\n\t\t\tif(row && cell){\n\t\t\t\tvar columnName = cell.getAttribute(\"data-column-name\");\n\t\t\t\tvar id = row.getAttribute(grid.$config.item_attribute);\n\t\t\t\treturn {\n\t\t\t\t\tid: id,\n\t\t\t\t\tcolumnName: columnName\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn null;\n\n\t\t}\n\n\t\tfunction _getEditorPosition(itemId, columnName) {\n\t\t\tvar config = grid.$getConfig();\n\t\t\tvar top = grid.getItemTop(itemId);\n\t\t\tvar height = grid.getItemHeight(itemId);\n\t\t\tvar cols = grid.getGridColumns();\n\t\t\tvar left = 0,\n\t\t\t\tright = 0,\n\t\t\t\twidth = 0;\n\n\t\t\tfor (var i = 0; i < cols.length; i++) {\n\t\t\t\tif (cols[i].name == columnName) {\n\t\t\t\t\twidth = cols[i].width;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (config.rtl) {\n\t\t\t\t\tright += cols[i].width;\n\t\t\t\t}\telse {\n\t\t\t\t\tleft += cols[i].width;\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tif (config.rtl) {\n\t\t\t\treturn {\n\t\t\t\t\ttop: top,\n\t\t\t\t\tright: right,\n\t\t\t\t\theight: height,\n\t\t\t\t\twidth: width\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\treturn {\n\t\t\t\t\ttop: top,\n\t\t\t\t\tleft: left,\n\t\t\t\t\theight: height,\n\t\t\t\t\twidth: width\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t\tfunction findVisibleIndex(grid, columnName) {\n\t\t\tvar columns = grid.getGridColumns();\n\t\t\tfor (var i = 0; i < columns.length; i++){\n\t\t\t\tif(columns[i].name == columnName){\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\tfunction _createPlaceholder(itemId, columnName) {\n\t\t\tvar config = grid.$getConfig();\n\t\t\tvar pos = _getEditorPosition(itemId, columnName);\n\t\t\tvar el = document.createElement(\"div\");\n\t\t\tel.className = \"gantt_grid_editor_placeholder\";\n\t\t\tel.setAttribute(grid.$config.item_attribute, itemId);\n\t\t\tel.setAttribute(grid.$config.bind + \"_id\", itemId);// for backward compatibility\n\n\t\t\tel.setAttribute(\"data-column-name\", columnName);\n\n\t\t\tvar visibleIndex = findVisibleIndex(grid, columnName);\n\t\t\tel.setAttribute(\"data-column-index\", visibleIndex);\n\n\t\t\tgantt._waiAria.inlineEditorAttr(el);\n\n\t\t\tif (config.rtl) {\n\t\t\t\tel.style.cssText = [\n\t\t\t\t\t\"top:\" + pos.top + \"px\",\n\t\t\t\t\t\"right:\" + pos.right + \"px\",\n\t\t\t\t\t\"width:\" + pos.width + \"px\",\n\t\t\t\t\t\"height:\" + pos.height + \"px\"\n\t\t\t\t].join(\";\");\n\t\t\t} else {\n\t\t\t\tel.style.cssText = [\n\t\t\t\t\t\"top:\" + pos.top + \"px\",\n\t\t\t\t\t\"left:\" + pos.left + \"px\",\n\t\t\t\t\t\"width:\" + pos.width + \"px\",\n\t\t\t\t\t\"height:\" + pos.height + \"px\"\n\t\t\t\t].join(\";\");\n\t\t\t}\n\n\t\t\treturn el;\n\t\t}\n\n\t\tvar updateTaskDateProperties = linkedPropertiesProcessor(gantt);\n\n\t\tvar handlers = [];\n\t\tvar ganttHandlers = [];\n\t\tvar store = null;\n\t\tvar controller = {\n\t\t\t_itemId: null,\n\t\t\t_columnName: null,\n\t\t\t_editor: null,\n\t\t\t_editorType: null,\n\t\t\t_placeholder: null,\n\n\t\t\tlocateCell: _getGridCellFromNode,\n\t\t\tgetEditorConfig: function (columnName) {\n\t\t\t\tvar column = grid.getColumn(columnName);\n\t\t\t\treturn column.editor;\n\t\t\t},\n\n\t\t\tinit: function () {\n\t\t\t\tvar mapping = keyboardMapping.getMapping();\n\t\t\t\tif(mapping.init){\n\t\t\t\t\tmapping.init(this, grid);\n\t\t\t\t}\n\n\t\t\t\tstore = grid.$gantt.getDatastore(grid.$config.bind);\n\n\t\t\t\tvar self = this;\n\n\t\t\t\thandlers.push(store.attachEvent(\"onIdChange\", function(oldId, newId){\n\t\t\t\t\tif(self._itemId == oldId){\n\t\t\t\t\t\tself._itemId = newId;\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t\thandlers.push(store.attachEvent(\"onStoreUpdated\", function(){\n\t\t\t\t\tif(grid.$gantt.getState(\"batchUpdate\").batch_update){\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif(self.isVisible() && !store.isVisible(self._itemId)){\n\t\t\t\t\t\tself.hide();\n\t\t\t\t\t}\n\t\t\t\t}));\n\n\t\t\t\tganttHandlers.push(gantt.attachEvent(\"onDataRender\", function(){\n\t\t\t\t\tif(self._editor && self._placeholder && !domHelpers.isChildOf(self._placeholder, gantt.$root)){\n\t\t\t\t\t\tgrid.$grid_data.appendChild(self._placeholder);\n\t\t\t\t\t}\n\t\t\t\t}));\n\n\t\t\t\tthis.init = function(){};\n\t\t\t},\n\n\t\t\tgetState: function(){\n\t\t\t\treturn {\n\t\t\t\t\teditor: this._editor,\n\t\t\t\t\teditorType: this._editorType,\n\t\t\t\t\tplaceholder: this._placeholder,\n\t\t\t\t\tid: this._itemId,\n\t\t\t\t\tcolumnName: this._columnName\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tstartEdit: function(itemId, columnName) {\n\t\t\t\tif (this.isVisible()) {\n\t\t\t\t\tthis.save();\n\t\t\t\t}\n\n\t\t\t\tif(!store.exists(itemId)){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar editorState = {id: itemId, columnName: columnName};\n\t\t\t\tif (gantt.isReadonly(store.getItem(itemId))) {\n\t\t\t\t\tthis.callEvent(\"onEditPrevent\", [editorState]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (this.callEvent(\"onBeforeEditStart\", [editorState]) === false) {\n\t\t\t\t\tthis.callEvent(\"onEditPrevent\", [editorState]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.show(editorState.id, editorState.columnName);\n\t\t\t\tthis.setValue();\n\n\t\t\t\tthis.callEvent(\"onEditStart\", [editorState]);\n\t\t\t},\n\t\t\tisVisible: function(){\n\t\t\t\treturn !!(this._editor && domHelpers.isChildOf(this._placeholder, gantt.$root));\n\t\t\t},\n\t\t\tshow: function (itemId, columnName) {\n\t\t\t\tif (this.isVisible()) {\n\t\t\t\t\tthis.save();\n\t\t\t\t}\n\t\t\t\tvar editorState = {id: itemId, columnName: columnName};\n\n\t\t\t\tvar column = grid.getColumn(editorState.columnName);\n\t\t\t\tvar editorConfig = this.getEditorConfig(column.name);\n\t\t\t\tif(!editorConfig)\n\t\t\t\t\treturn;\n\n\t\t\t\tvar editor = grid.$getConfig().editor_types[editorConfig.type];\n\n\t\t\t\tvar placeholder = _createPlaceholder(editorState.id, editorState.columnName);\n\t\t\t\tgrid.$grid_data.appendChild(placeholder);\n\t\t\t\teditor.show(editorState.id, column, editorConfig, placeholder);\n\t\t\t\tthis._editor = editor;\n\t\t\t\tthis._placeholder = placeholder;\n\t\t\t\tthis._itemId = editorState.id;\n\t\t\t\tthis._columnName = editorState.columnName;\n\t\t\t\tthis._editorType = editorConfig.type;\n\n\t\t\t\tvar mapping = keyboardMapping.getMapping();\n\t\t\t\tif(mapping.onShow){\n\t\t\t\t\tmapping.onShow(this, placeholder, grid);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tsetValue: function () {\n\t\t\t\tvar state = this.getState();\n\t\t\t\tvar itemId = state.id,\n\t\t\t\t\tcolumnName = state.columnName;\n\n\t\t\t\tvar column = grid.getColumn(columnName);\n\t\t\t\tvar item = store.getItem(itemId);\n\t\t\t\tvar editorConfig = this.getEditorConfig(columnName);\n\n\t\t\t\tif(!editorConfig)\n\t\t\t\t\treturn;\n\n\t\t\t\tvar value = item[editorConfig.map_to];\n\t\t\t\tif(editorConfig.map_to == \"auto\"){\n\t\t\t\t\tvalue = store.getItem(itemId);\n\t\t\t\t}\n\n\t\t\t\tthis._editor.set_value(value, itemId, column, this._placeholder);\n\t\t\t\tthis.focus();\n\t\t\t},\n\n\t\t\tfocus: function(){\n\t\t\t\tthis._editor.focus(this._placeholder);\n\t\t\t},\n\n\t\t\tgetValue: function () {\n\t\t\t\tvar column = grid.getColumn(this._columnName);\n\t\t\t\treturn this._editor.get_value(this._itemId, column, this._placeholder);\n\t\t\t},\n\n\t\t\t_getItemValue: function() {\n\t\t\t\tvar editorConfig = this.getEditorConfig(this._columnName);\n\n\t\t\t\tif(!editorConfig)\n\t\t\t\t\treturn;\n\n\t\t\t\tvar item = gantt.getTask(this._itemId);\n\t\t\t\tvar value = item[editorConfig.map_to];\n\t\t\t\tif(editorConfig.map_to == \"auto\"){\n\t\t\t\t\tvalue = store.getItem(this._itemId);\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t},\n\n\t\t\tisChanged: function(){\n\n\t\t\t\tvar column = grid.getColumn(this._columnName);\n\n\t\t\t\tvar value = this._getItemValue();\n\n\t\t\t\treturn this._editor.is_changed(value, this._itemId, column, this._placeholder);\n\t\t\t},\n\n\t\t\thide: function () {\n\t\t\t\tif(!this._itemId)\n\t\t\t\t\treturn;\n\n\t\t\t\tvar itemId = this._itemId,\n\t\t\t\t\tcolumnName = this._columnName;\n\n\t\t\t\tvar mapping = keyboardMapping.getMapping();\n\t\t\t\tif(mapping.onHide){\n\t\t\t\t\tmapping.onHide(this, this._placeholder, grid);\n\t\t\t\t}\n\n\t\t\t\tthis._itemId = null;\n\t\t\t\tthis._columnName = null;\n\t\t\t\tthis._editorType = null;\n\t\t\t\tif (!this._placeholder) return;\n\n\t\t\t\tif (this._editor && this._editor.hide) {\n\t\t\t\t\tthis._editor.hide(this._placeholder);\n\t\t\t\t}\n\t\t\t\tthis._editor = null;\n\t\t\t\tif (this._placeholder.parentNode) {\n\t\t\t\t\tthis._placeholder.parentNode.removeChild(this._placeholder);\n\t\t\t\t}\n\t\t\t\tthis._placeholder = null;\n\n\t\t\t\tthis.callEvent(\"onEditEnd\", [{id: itemId, columnName: columnName}]);\n\t\t\t},\n\t\t\tsave: function () {\n\t\t\t\tif(!(this.isVisible() && store.exists(this._itemId) && this.isChanged())) {\n\t\t\t\t\tthis.hide();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar itemId = this._itemId,\n\t\t\t\t\tcolumnName = this._columnName;\n\n\t\t\t\tif(!store.exists(itemId)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar item = store.getItem(itemId);\n\t\t\t\tvar editorConfig = this.getEditorConfig(columnName);\n\t\t\t\tvar editorState = {\n\t\t\t\t\tid: itemId,\n\t\t\t\t\tcolumnName: columnName,\n\t\t\t\t\tnewValue: this.getValue(),\n\t\t\t\t\toldValue: this._getItemValue()\n\t\t\t\t};\n\t\t\t\tif (this.callEvent(\"onBeforeSave\", [editorState]) !== false) {\n\t\t\t\t\tif (!this._editor.is_valid || this._editor.is_valid(editorState.newValue, editorState.id, grid.getColumn(columnName), this._placeholder)) {\n\n\t\t\t\t\t\tvar mapTo = editorConfig.map_to;\n\t\t\t\t\t\tvar value = editorState.newValue;\n\t\t\t\t\t\tif (mapTo != \"auto\") {\n\t\t\t\t\t\t\titem[mapTo] = value;\n\t\t\t\t\t\t\tupdateTaskDateProperties(item, mapTo, gantt.config.inline_editors_date_processing);\n\n\t\t\t\t\t\t\tstore.updateItem(itemId);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._editor.save(itemId, grid.getColumn(columnName), this._placeholder);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.callEvent(\"onSave\", [editorState]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.hide();\n\t\t\t},\n\n\t\t\t_findEditableCell: function findEditableCell(start, direction){\n\t\t\t\tvar nextIndex = start;\n\t\t\t\tvar columns = grid.getGridColumns();\n\t\t\t\tvar nextColumn = columns[nextIndex];\n\n\t\t\t\tvar columnName = nextColumn ? nextColumn.name : null;\n\t\t\t\tif(columnName){\n\t\t\t\t\twhile(columnName && !this.getEditorConfig(columnName)){\n\t\t\t\t\t\tcolumnName = this._findEditableCell(start + direction, direction);\n\t\t\t\t\t}\n\t\t\t\t\treturn columnName;\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t},\n\n\t\t\tgetNextCell: function moveCell(dir){\n\t\t\t\t// GS-1257. true means to exclude hidden columns\n\t\t\t\treturn this._findEditableCell(grid.getColumnIndex(this._columnName, true) + dir, dir);\n\t\t\t},\n\n\t\t\tgetFirstCell: function getFirstCell(){\n\t\t\t\treturn this._findEditableCell(0, 1);\n\t\t\t},\n\n\t\t\tgetLastCell: function getLastCell(){\n\t\t\t\treturn this._findEditableCell(grid.getGridColumns().length - 1, -1);\n\t\t\t},\n\n\t\t\teditNextCell: function nextCell(canChangeRow){\n\t\t\t\tvar cell = this.getNextCell(1);\n\t\t\t\tif(cell){\n\t\t\t\t\tvar nextColumn = this.getNextCell(1);\n\t\t\t\t\tif(nextColumn && this.getEditorConfig(nextColumn)){\n\t\t\t\t\t\tthis.startEdit(this._itemId, nextColumn);\n\t\t\t\t\t}\n\t\t\t\t}else if(canChangeRow && this.moveRow(1)){\n\t\t\t\t\tvar task = this.moveRow(1);\n\t\t\t\t\tcell = this.getFirstCell();\n\t\t\t\t\tif(cell && this.getEditorConfig(cell)){\n\t\t\t\t\t\tthis.startEdit(task, cell);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\teditPrevCell: function prevCell(canChangeRow){\n\t\t\t\tvar cell = this.getNextCell(-1);\n\t\t\t\tif(cell){\n\t\t\t\t\tvar nextColumn = this.getNextCell(-1);\n\t\t\t\t\tif(nextColumn && this.getEditorConfig(nextColumn)){\n\t\t\t\t\t\tthis.startEdit(this._itemId, nextColumn);\n\t\t\t\t\t}\n\t\t\t\t}else if(canChangeRow && this.moveRow(-1)){\n\t\t\t\t\tvar task = this.moveRow(-1);\n\t\t\t\t\tcell = this.getLastCell();\n\t\t\t\t\tif(cell && this.getEditorConfig(cell)){\n\t\t\t\t\t\tthis.startEdit(task, cell);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tmoveRow: function moveRow(dir) {\n\t\t\t\tvar moveTask = dir > 0 ? gantt.getNext : gantt.getPrev;\n\t\t\t\tmoveTask = gantt.bind(moveTask, gantt);\n\n\t\t\t\tvar nextItem = moveTask(this._itemId);\n\t\t\t\t// skip readonly rows\n\t\t\t\twhile (gantt.isTaskExists(nextItem) && gantt.isReadonly(gantt.getTask(nextItem))) {\n\t\t\t\t\tnextItem = moveTask(nextItem);\n\t\t\t\t}\n\t\t\t\treturn nextItem;\n\t\t\t},\n\n\t\t\teditNextRow: function nextRow(skipReadonly){\n\t\t\t\tvar id = this.getState().id;\n\t\t\t\tif (!gantt.isTaskExists(id)) return;\n\n\t\t\t\tvar next = null;\n\t\t\t\tif (skipReadonly){\n\t\t\t\t\tnext = this.moveRow(1);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tnext = gantt.getNext(id);\n\t\t\t\t}\n\n\t\t\t\tif (gantt.isTaskExists(next)){\n\t\t\t\t\tthis.startEdit(next, this._columnName);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\teditPrevRow: function prevRow(skipReadonly){\n\t\t\t\tvar id = this.getState().id;\n\t\t\t\tif (!gantt.isTaskExists(id)) return;\n\n\t\t\t\tvar prev = null;\n\t\t\t\tif (skipReadonly){\n\t\t\t\t\tprev = this.moveRow(-1);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tprev = gantt.getPrev(id);\n\t\t\t\t}\n\n\t\t\t\tif (gantt.isTaskExists(prev)){\n\t\t\t\t\tthis.startEdit(prev, this._columnName);\n\t\t\t\t}\n\t\t\t},\n\t\t\tdetachStore: function(){\n\t\t\t\thandlers.forEach(function(handlerId){\n\t\t\t\t\tstore.detachEvent(handlerId);\n\t\t\t\t});\n\n\t\t\t\tganttHandlers.forEach(function(handlerId){\n\t\t\t\t\tgantt.detachEvent(handlerId);\n\t\t\t\t});\n\t\t\t\thandlers = [];\n\t\t\t\tganttHandlers = [];\n\n\t\t\t\tstore = null;\n\t\t\t\tthis.hide();\n\t\t\t},\n\t\t\tdestructor: function(){\n\t\t\t\tthis.detachStore();\n\t\t\t\tthis.detachAllEvents();\n\t\t\t}\n\t\t};\n\n\t\tutils.mixin(controller, keyboardMapping);\n\t\tutils.mixin(controller, eventBus);\n\n\t\treturn controller;\n\t}\n\n\n\tvar inlineEditController = {\n\t\tinit: initConfigs,\n\t\tcreateEditors: createGridEditors\n\t};\n\n\tutils.mixin(inlineEditController, keyboardMapping);\n\tutils.mixin(inlineEditController, eventBus);\n\n\treturn inlineEditController;\n}\n\n\n\n\nexport default create;","import BaseFactory from \"./base\";\nimport * as utils from \"../../../../../utils/utils\";\nimport __extends from \"../../../../../utils/extends\";\n\n\nexport default function(gantt) {\n\n\tvar BaseEditor = BaseFactory(gantt);\n\n\tfunction TextEditor() {\n\t\tvar self = BaseEditor.apply(this, arguments) || this;\n\t\treturn self;\n\t}\n\n\t__extends(TextEditor, BaseEditor);\n\n\tutils.mixin(TextEditor.prototype, {\n\t\tshow: function (id, column, config, placeholder) {\n\t\t\tvar html = `
`;\n\t\t\tplaceholder.innerHTML = html;\n\t\t}\n\t}, true);\n\n\treturn TextEditor;\n};","import BaseFactory from \"./base\";\nimport * as utils from \"../../../../../utils/utils\";\nimport __extends from \"../../../../../utils/extends\";\n\n\nexport default function(gantt) {\n\n\tvar BaseEditor = BaseFactory(gantt);\n\n\tfunction NumberEditor() {\n\t\tvar self = BaseEditor.apply(this, arguments) || this;\n\t\treturn self;\n\t}\n\n\t__extends(NumberEditor, BaseEditor);\n\n\tutils.mixin(NumberEditor.prototype, {\n\t\tshow: function (id, column, config, placeholder) {\n\t\t\tvar min = config.min || 0,\n\t\t\t\tmax = config.max || 100;\n\n\t\t\tvar html = `
`;\n\t\t\tplaceholder.innerHTML = html;\n\n\t\t\t// GS-1914. Do not allow entering alues beyond min and max via keyboard\n\t\t\tplaceholder.oninput = function (e) {\n\t\t\t\tif (+e.target.value < min) {\n\t\t\t\t\te.target.value = min;\n\t\t\t\t}\n\t\t\t\tif (+e.target.value > max) {\n\t\t\t\t\te.target.value = max;\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\tget_value: function (id, column, node) {\n\t\t\treturn this.get_input(node).value || \"\";\n\t\t},\n\t\tis_valid: function (value, id, column, node) {\n\t\t\treturn !isNaN(parseInt(value, 10));\n\t\t}\n\t}, true);\n\n\treturn NumberEditor;\n};","import BaseFactory from \"./base\";\nimport * as utils from \"../../../../../utils/utils\";\nimport __extends from \"../../../../../utils/extends\";\n\n\nexport default function(gantt) {\n\n\tvar BaseEditor = BaseFactory(gantt);\n\n\tfunction SelectEditor() {\n\t\tvar self = BaseEditor.apply(this, arguments) || this;\n\t\treturn self;\n\t}\n\n\t__extends(SelectEditor, BaseEditor);\n\n\tutils.mixin(SelectEditor.prototype, {\n\t\tshow: function (id, column, config, placeholder) {\n\t\t\tvar html = `
\";\n\t\t\tplaceholder.innerHTML = html;\n\t\t},\n\t\tget_input: function (node) {\n\t\t\treturn node.querySelector(\"select\");\n\t\t}\n\t}, true);\n\n\treturn SelectEditor;\n};","import * as utils from \"../../../../../utils/utils\";\nimport __extends from \"../../../../../utils/extends\";\nimport BaseFactory from \"./base\";\n\nexport default function (gantt) {\n\tvar BaseEditor = BaseFactory(gantt);\n\t\n\t\n\n\tvar html5DateFormat = \"%Y-%m-%d\";\n\n\tvar dateToStr = null;\n\tvar strToDate = null;\n\n\tfunction init() {\n\t\tif (!dateToStr) {\n\t\t\tdateToStr = gantt.date.date_to_str(html5DateFormat);\n\t\t}\n\t\tif (!strToDate) {\n\t\t\tstrToDate = gantt.date.str_to_date(html5DateFormat);\n\t\t}\n\t}\n\n\tfunction DateEditor() {\n\t\tvar self = BaseEditor.apply(this, arguments) || this;\n\n\t\treturn self;\n\t}\n\n\t__extends(DateEditor, BaseEditor);\n\n\tutils.mixin(DateEditor.prototype, {\n\t\tshow: function (id, column, config, placeholder) {\n\t\t\tinit();\n\t\t\tvar minValue = null;\n\t\t\tvar maxValue = null;\n\n\t\t\tif(typeof config.min === \"function\"){\n\t\t\t\tminValue = config.min(id, column);\n\t\t\t}else{\n\t\t\t\tminValue = config.min;\n\t\t\t}\n\n\t\t\tif(typeof config.max === \"function\"){\n\t\t\t\tmaxValue = config.max(id, column);\n\t\t\t}else{\n\t\t\t\tmaxValue = config.max;\n\t\t\t}\n\n\t\t\tvar minAttr = minValue ? \" min='\" + dateToStr(minValue)+\"' \" : \"\";\n\t\t\tvar maxAttr = maxValue ? \" max='\" + dateToStr(maxValue)+\"' \" : \"\";\n\t\t\tvar html = `
`;\n\t\t\tplaceholder.innerHTML = html;\n\n\t\t\t// GS-1914. Do not allow entering alues beyond min and max via keyboard\n\t\t\tplaceholder.oninput = function (e) {\n\t\t\t\tif (+gantt.date.str_to_date(\"%Y-%m-%d\")(e.target.value) < +minValue) {\n\t\t\t\t\te.target.value = gantt.date.date_to_str(\"%Y-%m-%d\")(minValue);\n\t\t\t\t}\n\t\t\t\tif (+gantt.date.str_to_date(\"%Y-%m-%d\")(e.target.value) > +maxValue) {\n\t\t\t\t\te.target.value = gantt.date.date_to_str(\"%Y-%m-%d\")(maxValue);\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\tset_value: function (value, id, column, node) {\n\t\t\tif (value && value.getFullYear) {\n\t\t\t\tthis.get_input(node).value = dateToStr(value);\n\t\t\t} else {\n\t\t\t\tthis.get_input(node).value = value;\n\t\t\t}\n\t\t},\n\t\tis_valid: function (value, id, column, node) {\n\t\t\tif (!value || isNaN(value.getTime()))\n\t\t\t\treturn false;\n\t\t\treturn true;\n\t\t},\n\t\tget_value: function (id, column, node) {\n\t\t\tvar parsed;\n\t\t\ttry {\n\t\t\t\tparsed = strToDate(this.get_input(node).value || \"\");\n\t\t\t} catch (e) {\n\t\t\t\tparsed = null;// return null will cancel changes\n\t\t\t}\n\n\t\t\treturn parsed;\n\t\t}\n\t}, true);\n\n\treturn DateEditor;\n};\n","import BaseFactory from \"./base\";\nimport * as utils from \"../../../../../utils/utils\";\nimport __extends from \"../../../../../utils/extends\";\n\n\nexport default function(gantt) {\n\n\tvar BaseEditor = BaseFactory(gantt);\n\n\tfunction PredecessorEditor() {\n\t\tvar self = BaseEditor.apply(this, arguments) || this;\n\t\treturn self;\n\t}\n\n\t__extends(PredecessorEditor, BaseEditor);\n\n\tfunction getFormatter(config) {\n\t\treturn config.formatter || gantt.ext.formatters.linkFormatter();\n\t}\n\n\tfunction parseInputString(value, config) {\n\t\tvar predecessors = (value || \"\").split(config.delimiter || \",\");\n\t\tfor (var i = 0; i < predecessors.length; i++) {\n\t\t\tvar val = predecessors[i].trim();\n\t\t\tif (val) {\n\t\t\t\tpredecessors[i] = val;\n\t\t\t} else {\n\t\t\t\tpredecessors.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t\tpredecessors.sort();\n\t\treturn predecessors;\n\t}\n\n\tfunction formatPredecessors(task, config, gantt) {\n\t\tvar links = task.$target;\n\t\tvar labels = [];\n\t\tfor (var i = 0; i < links.length; i++) {\n\t\t\tvar link = gantt.getLink(links[i]);\n\t\t\tlabels.push(getFormatter(config).format(link));\n\t\t}\n\t\treturn labels.join((config.delimiter || \",\") + \" \");\n\t}\n\n\tfunction getSelectedLinks(taskId, predecessorCodes, config) {\n\t\tvar links = [];\n\t\t// select only unique codes GS-1439\n\t\t[...new Set(predecessorCodes)].forEach(function (code) {\n\t\t\tvar link = getFormatter(config).parse(code);\n\t\t\tif(link){\n\t\t\t\tlink.target = taskId;\n\t\t\t\t// GS-1290 A way to preserve the link. Otherwise validation will return false\n\t\t\t\t// because the existing link ID is not passed there\n\t\t\t\tlink.id = \"predecessor_generated\";\n\t\t\t\tif (gantt.isLinkAllowed(link)) {\n\t\t\t\t\tlink.id = undefined;\n\t\t\t\t\tlinks.push(link);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn links;\n\t}\n\n\tfunction formatLinkKey(link){\n\t\treturn link.source + \"_\" + link.target + \"_\" + link.type + \"_\" + (link.lag||0);\n\t}\n\n\tfunction getLinksDiff(task, predecessorCodes, config) {\n\t\tvar selectedLinks = getSelectedLinks(task.id, predecessorCodes, config);\n\t\tvar existingLinksSearch = {};\n\t\ttask.$target.forEach(function (linkId) {\n\t\t\tvar link = gantt.getLink(linkId);\n\t\t\texistingLinksSearch[formatLinkKey(link)] = link.id;\n\t\t});\n\n\t\tvar linksToAdd = [];\n\t\tselectedLinks.forEach(function (link) {\n\t\t\tvar linkKey = formatLinkKey(link);\n\t\t\tif (!existingLinksSearch[linkKey]) {\n\t\t\t\tlinksToAdd.push(link);\n\t\t\t} else {\n\t\t\t\tdelete existingLinksSearch[linkKey];\n\t\t\t}\n\t\t});\n\n\t\tvar linksToDelete = [];\n\t\tfor (var i in existingLinksSearch) {\n\t\t\tlinksToDelete.push(existingLinksSearch[i]);\n\t\t}\n\n\t\treturn {\n\t\t\tadd: linksToAdd,\n\t\t\tremove: linksToDelete\n\t\t};\n\t}\n\n\tutils.mixin(PredecessorEditor.prototype, {\n\t\tshow: function (id, column, config, placeholder) {\n\t\t\tvar html = `
`;\n\t\t\tplaceholder.innerHTML = html;\n\t\t},\n\t\thide: function () {\n\t\t},\n\t\tset_value: function (value, id, column, node) {\n\t\t\tthis.get_input(node).value = formatPredecessors(value, column.editor, gantt);\n\t\t},\n\t\tget_value: function (id, column, node) {\n\t\t\treturn parseInputString((this.get_input(node).value || \"\"), column.editor);\n\t\t},\n\t\tsave: function (id, column, node) {\n\t\t\tvar task = gantt.getTask(id);\n\n\t\t\tvar linksDiff = getLinksDiff(task, this.get_value(id, column, node), column.editor);\n\n\t\t\tif (linksDiff.add.length || linksDiff.remove.length) {\n\t\t\t\tgantt.batchUpdate(function () {\n\t\t\t\t\tlinksDiff.add.forEach(function (link) {\n\t\t\t\t\t\tgantt.addLink(link);\n\t\t\t\t\t});\n\t\t\t\t\tlinksDiff.remove.forEach(function (linkId) {\n\t\t\t\t\t\tgantt.deleteLink(linkId);\n\t\t\t\t\t});\n\n\t\t\t\t\tif (gantt.autoSchedule)\n\t\t\t\t\t\tgantt.autoSchedule();\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tis_changed: function (value, id, column, node) {\n\t\t\tvar inputPredecessors = this.get_value(id, column, node);\n\t\t\tvar taskPredecessors = parseInputString(formatPredecessors(value, column.editor, gantt), column.editor);\n\n\t\t\treturn inputPredecessors.join() !== taskPredecessors.join();\n\t\t}\n\t}, true);\n\n\treturn PredecessorEditor;\n};","import BaseFactory from \"./base\";\nimport * as utils from \"../../../../../utils/utils\";\nimport __extends from \"../../../../../utils/extends\";\n\n\nexport default function(gantt) {\n\n\tvar BaseEditor = BaseFactory(gantt);\n\n\tfunction TextEditor() {\n\t\tvar self = BaseEditor.apply(this, arguments) || this;\n\t\treturn self;\n\t}\n\n\t__extends(TextEditor, BaseEditor);\n\n\tfunction getFormatter(config) {\n\t\treturn config.formatter || gantt.ext.formatters.durationFormatter();\n\t}\n\tutils.mixin(TextEditor.prototype, {\n\t\tshow: function (id, column, config, placeholder) {\n\t\t\tvar html = `
`;\n\t\t\tplaceholder.innerHTML = html;\n\t\t},\n\t\tset_value: function (value, id, column, node) {\n\t\t\tthis.get_input(node).value = getFormatter(column.editor).format(value);\n\t\t},\n\t\tget_value: function (id, column, node) {\n\t\t\treturn getFormatter(column.editor).parse(this.get_input(node).value || \"\");\n\t\t}\n\t}, true);\n\n\treturn TextEditor;\n};","// optimized checker for task bars smart rendering\n\n// first check the vertical position since it's easier to calculate\nexport default function isBarInViewport(item, viewport, view, config, gantt){\n\tif(!item.start_date || !item.end_date){\n\t\treturn null;\n\t}\n\n\tvar top = view.getItemTop(item.id);\n\tvar height = view.getItemHeight(item.id);\n\n\tif(top > viewport.y_end || top + height < viewport.y){\n\t\treturn false;\n\t}\n\n\tvar padding = 200;\n\tvar startCoord = view.posFromDate(item.start_date);\n\tvar endCoord = view.posFromDate(item.end_date);\n\tvar left = Math.min(startCoord, endCoord) - padding;\n\tvar right = Math.max(startCoord, endCoord) + padding;\n\n\tif(left > viewport.x_end || right < viewport.x){\n\t\treturn false;\n\t}\n\n\treturn true;\n};","function createTaskRenderer(gantt) {\n\n\tfunction _render_task_element(task, view, config) {\n\t\tvar config = view.$getConfig();\n\t\tvar painters = config.type_renderers;\n\t\tvar renderer = painters[gantt.getTaskType(task.type)],\n\t\t\tdefaultRenderer = _task_default_render;\n\n\t\tif (!renderer) {\n\t\t\treturn defaultRenderer.call(gantt, task, view, config);\n\t\t}else{\n\t\t\treturn renderer.call(gantt, task, function(task){ return defaultRenderer.call(gantt, task, view, config);}, view);\n\t\t}\n\t}\n\n\tfunction _task_default_render(task, view, config) {\n\t\tif (gantt._isAllowedUnscheduledTask(task))\n\t\t\treturn;\n\n\t\tif (!gantt._isTaskInTimelineLimits(task)) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar pos = view.getItemPosition(task);\n\n\t\tvar cfg = config,\n\t\t\ttemplates = view.$getTemplates();\n\n\t\tvar taskType = gantt.getTaskType(task.type);\n\t\tvar height = view.getBarHeight(task.id, taskType == cfg.types.milestone);\n\n\t\tvar controlsMargin = 0;\n\t\tif (taskType == cfg.types.milestone) {\n\t\t\tcontrolsMargin = (height - pos.height)/2;\n\t\t}\n\n\t\tvar padd = Math.floor((view.getItemHeight(task.id) - height) / 2);\n\t\tconst hasBaselines = gantt.config.baselines !== false && task.baselines && task.baselines.length;\n\t\tconst baselinesOnDifferentRow = gantt.config.baselines !== false && (gantt.config.baselines.render_mode == \"separateRow\" || gantt.config.baselines.render_mode == \"individualRow\");\n\t\tif (hasBaselines && baselinesOnDifferentRow){\n\t\t\tif (task.bar_height !== \"full\" && task.bar_height < task.row_height){\n\t\t\t\tif (taskType === cfg.types.milestone){\n\t\t\t\t\tlet milestoneHeight = view.getBarHeight(task.id, true);\n\t\t\t\t\tlet milestoneWidth = Math.sqrt(2 * milestoneHeight * milestoneHeight);\n\t\t\t\t\tpadd = Math.floor((milestoneWidth - height) / 2) + 2;\n\t\t\t\t} else {\n\t\t\t\t\tpadd = 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t//\tif(task.type == cfg.types.milestone){\n\t//\t\tpadd -= 1;\n\t//\t}\n\t//\tif (taskType == cfg.types.milestone && cfg.link_line_width > 1) {\n\t//\t\t//little adjust milestone position, so horisontal corners would match link arrow when thickness of link line is more than 1px\n\t//\t\tpadd += 1;\n\t//\t}\n\n\t\tif (taskType == cfg.types.milestone) {\n\t\t\tpos.left -= Math.round(height / 2);\n\t\t\tpos.width = height;\n\t\t}\n\n\t\tvar div = document.createElement(\"div\");\n\n\t\tvar width = Math.round(pos.width);\n\n\t\tif(view.$config.item_attribute) {\n\t\t\tdiv.setAttribute(view.$config.item_attribute, task.id);\n\t\t\tdiv.setAttribute(view.$config.bind + \"_id\", task.id); // 'task_id'/'resource_id' for backward compatibility\n\t\t}\n\n\t\tif (cfg.show_progress && taskType != cfg.types.milestone) {\n\t\t\t_render_task_progress(task, div, width, cfg, templates);\n\t\t}\n\n\t\t//use separate div to display content above progress bar\n\t\tvar content = _render_task_content(task, width, templates);\n\n\t\tdiv.appendChild(content);\n\n\t\tvar css = _combine_item_class(\"gantt_task_line\",\n\t\t\ttemplates.task_class(task.start_date, task.end_date, task),\n\t\t\ttask.id,\n\t\t\tview);\n\t\tif (task.color || task.progressColor || task.textColor) {\n\t\t\tcss += \" gantt_task_inline_color\";\n\t\t}\n\t\tif (pos.width < 20){\n\t\t\tcss += \" gantt_thin_task\";\n\t\t}\n\t\tdiv.className = css;\n\n\t\tvar styles = [\n\t\t\t\"left:\" + pos.left + \"px\",\n\t\t\t\"top:\" + (padd + pos.top) + 'px',\n\t\t\t\"height:\" + (height) + 'px',\n\t\t\t\"line-height:\" + (Math.max(height < 30 ? height - 2 : height, 0)) + 'px',\n\t\t\t\"width:\" + width + 'px'\n\t\t];\n\n\t\tdiv.style.cssText = styles.join(\";\");\n\t\tif (task.color) {\n\t\t\tdiv.style.setProperty(\"--dhx-gantt-task-background\", task.color);\n\t\t}\n\t\tif (task.textColor) {\n\t\t\tdiv.style.setProperty(\"--dhx-gantt-task-color\", task.textColor);\n\t\t}\n\n\t\tif (task.progressColor) {\n\t\t\tdiv.style.setProperty(\"--dhx-gantt-task-progress-color\", task.progressColor);\n\t\t}\n\n\t\t\n\t\tvar side = _render_leftside_content(task, cfg, templates, controlsMargin);\n\t\tif (side) div.appendChild(side);\n\n\t\tside = _render_rightside_content(task, cfg, templates, controlsMargin);\n\t\tif (side) div.appendChild(side);\n\n\t\tgantt._waiAria.setTaskBarAttr(task, div);\n\n\t\tvar state = gantt.getState();\n\n\t\tif (!gantt.isReadonly(task)) {\n\t\t\tif (cfg.drag_resize && !gantt.isSummaryTask(task) && taskType != cfg.types.milestone) {\n\t\t\t\t_render_pair(div, \"gantt_task_drag\", task, function (css) {\n\t\t\t\t\tvar el = document.createElement(\"div\");\n\t\t\t\t\tel.className = css;\n\t\t\t\t\treturn el;\n\t\t\t\t}, cfg);\n\t\t\t}\n\t\t\tif (cfg.drag_links && cfg.show_links) {\n\t\t\t\t_render_pair(div, \"gantt_link_control\", task, function (css) {\n\t\t\t\t\tvar outer = document.createElement(\"div\");\n\t\t\t\t\touter.className = css;\n\t\t\t\t\touter.style.cssText = [\n\t\t\t\t\t\t\"height:\" + height + 'px',\n\t\t\t\t\t\t\"line-height:\" + height + 'px'\n\t\t\t\t\t].join(\";\");\n\t\t\t\t\tvar inner = document.createElement(\"div\");\n\t\t\t\t\tinner.className = \"gantt_link_point\";\n\n\t\t\t\t\tvar showLinkPoints = false;\n\t\t\t\t\tif(state.link_source_id && cfg.touch){\n\t\t\t\t\t\tshowLinkPoints = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tinner.style.display = showLinkPoints ? \"block\" : \"\";\n\t\t\t\t\touter.appendChild(inner);\n\t\t\t\t\treturn outer;\n\t\t\t\t}, cfg, controlsMargin);\n\t\t\t}\n\t\t}\n\t\treturn div;\n\t}\n\n\tfunction _render_side_content(task, template, cssClass, marginStyle) {\n\t\tif (!template) return null;\n\n\t\tvar text = template(task.start_date, task.end_date, task);\n\t\tif (!text) return null;\n\t\tvar content = document.createElement(\"div\");\n\t\tcontent.className = \"gantt_side_content \" + cssClass;\n\t\tcontent.innerHTML = text;\n\t\tif(marginStyle){\n\t\t\tcontent.style[marginStyle.type] = Math.abs(marginStyle.value) + \"px\";\n\t\t}\n\t\treturn content;\n\t}\n\n\tfunction _render_leftside_content(task, cfg, templates, margin) {\n\t\tvar css = \"gantt_left \" + _get_link_crossing_css(!cfg.rtl ? true : false, task, cfg);\n\t\tvar marginStyle = null;\n\t\tif(margin){\n\t\t\tmarginStyle = { type: \"marginRight\", value: margin };\n\t\t}\n\t\treturn _render_side_content(task, templates.leftside_text, css, marginStyle);\n\t}\n\n\tfunction _render_rightside_content(task, cfg, templates, margin) {\n\t\tvar css = \"gantt_right \" + _get_link_crossing_css(!cfg.rtl ? false : true, task, cfg);\n\t\tvar marginStyle = null;\n\t\tif(margin){\n\t\t\tmarginStyle = { type: \"marginLeft\", value: margin };\n\t\t}\n\t\treturn _render_side_content(task, templates.rightside_text, css, marginStyle);\n\t}\n\n\tfunction _get_link_crossing_css(left, task) {\n\t\tvar cond = _get_conditions(left);\n\n\t\tfor (var i in cond) {\n\t\t\tvar links = task[i];\n\t\t\tfor (var ln = 0; ln < links.length; ln++) {\n\t\t\t\tvar link = gantt.getLink(links[ln]);\n\n\t\t\t\tfor (var tp = 0; tp < cond[i].length; tp++) {\n\t\t\t\t\tif (link.type == cond[i][tp]) {\n\t\t\t\t\t\treturn \"gantt_link_crossing\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn \"\";\n\t}\n\n\n\tfunction _render_task_content(task, width, templates) {\n\t\tvar content = document.createElement(\"div\");\n\t\tif (gantt.getTaskType(task.type) != gantt.config.types.milestone){\n\t\t\tcontent.innerHTML = templates.task_text(task.start_date, task.end_date, task);\n\t\t} else if(gantt.getTaskType(task.type) == gantt.config.types.milestone && width) {\n\t\t\tcontent.style.height = content.style.width = width + \"px\";\n\t\t}\n\t\tcontent.className = \"gantt_task_content\";\n\t\t//content.style.width = width + 'px';\n\t\treturn content;\n\t}\n\n\tfunction _render_task_progress(task, element, maxWidth, cfg, templates) {\n\t\tvar done = task.progress * 1 || 0;\n\n\t\tmaxWidth = Math.max(maxWidth - 2, 0);//2px for borders\n\t\tvar pr = document.createElement(\"div\");\n\t\tvar width = Math.round(maxWidth * done);\n\n\t\twidth = Math.min(maxWidth, width);\n\n\t\tpr.style.width = width + 'px';\n\t\tpr.className = \"gantt_task_progress\";\n\t\tpr.innerHTML = templates.progress_text(task.start_date, task.end_date, task);\n\n\t\tif(cfg.rtl){\n\t\t\tpr.style.position = \"absolute\";\n\t\t\tpr.style.right = \"0px\";\n\t\t}\n\n\t\tvar wrapper = document.createElement(\"div\");\n\t\twrapper.className = \"gantt_task_progress_wrapper\";\n\t\twrapper.appendChild(pr);\n\t\telement.appendChild(wrapper);\n\n\t\tif (gantt.config.drag_progress && !gantt.isReadonly(task)) {\n\t\t\tvar drag = document.createElement(\"div\");\n\n\t\t\tvar markerPos = width;\n\t\t\tif(cfg.rtl){\n\t\t\t\tmarkerPos = maxWidth - width;\n\t\t\t}\n\n\t\t\tdrag.style.left = markerPos + 'px';\n\t\t\tdrag.className = \"gantt_task_progress_drag\";\n\t\t\tdrag.innerHTML = `\n\n`;\n\t\t\tpr.appendChild(drag);\n\t\t\telement.appendChild(drag);\n\t\t}\n\t}\n\n\tfunction _get_conditions(leftside) {\n\t\tif (leftside) {\n\t\t\treturn {\n\t\t\t\t$source: [\n\t\t\t\t\tgantt.config.links.start_to_start\n\t\t\t\t],\n\t\t\t\t$target: [\n\t\t\t\t\tgantt.config.links.start_to_start,\n\t\t\t\t\tgantt.config.links.finish_to_start\n\t\t\t\t]\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\t$source: [\n\t\t\t\t\tgantt.config.links.finish_to_start,\n\t\t\t\t\tgantt.config.links.finish_to_finish\n\t\t\t\t],\n\t\t\t\t$target: [\n\t\t\t\t\tgantt.config.links.finish_to_finish\n\t\t\t\t]\n\t\t\t};\n\t\t}\n\t}\n\n\tfunction _combine_item_class(basic, template, itemId, view) {\n\t\tvar cfg = view.$getConfig();\n\t\tvar css = [basic];\n\t\tif (template)\n\t\t\tcss.push(template);\n\n\t\tvar state = gantt.getState();\n\n\t\tvar task = gantt.getTask(itemId);\n\n\t\tif (gantt.getTaskType(task.type) == cfg.types.milestone) {\n\t\t\tcss.push(\"gantt_milestone\");\n\t\t}else if (gantt.getTaskType(task.type) == cfg.types.project) {\n\t\t\tcss.push(\"gantt_project\");\n\t\t}\n\n\t\tcss.push(\"gantt_bar_\" + gantt.getTaskType(task.type));\n\n\n\t\tif (gantt.isSummaryTask(task))\n\t\t\tcss.push(\"gantt_dependent_task\");\n\n\t\tif (gantt.isSplitTask(task) && ((cfg.open_split_tasks && !task.$open) || !cfg.open_split_tasks)) {\n\t\t\tcss.push(\"gantt_split_parent\");\n\t\t}\n\n\t\tif (cfg.select_task && gantt.isSelectedTask(itemId)) {\n\t\t\tcss.push(\"gantt_selected\");\n\t\t}\n\n\t\tif (itemId == state.drag_id) {\n\t\t\tcss.push(\"gantt_drag_\" + state.drag_mode);\n\t\t\tif (state.touch_drag) {\n\t\t\t\tcss.push(\"gantt_touch_\" + state.drag_mode);\n\t\t\t}\n\t\t}\n\n\t\tif (state.link_source_id == itemId){\n\t\t\tcss.push(\"gantt_link_source\");\n\t\t\tif(state.link_from_start) {\n\t\t\t\tcss.push(\"gantt_link_from_start\");\n\t\t\t}else{\n\t\t\t\tcss.push(\"gantt_link_from_end\");\n\t\t\t}\n\t\t}\n\n\t\tif (state.link_target_id == itemId)\n\t\t\tcss.push(\"gantt_link_target\");\n\n\n\t\tif (cfg.highlight_critical_path && gantt.isCriticalTask) {\n\t\t\tif (gantt.isCriticalTask(task))\n\t\t\t\tcss.push(\"gantt_critical_task\");\n\t\t}\n\n\t\tif (state.link_landing_area &&\n\t\t\t(state.link_target_id && state.link_source_id) &&\n\t\t\t(state.link_target_id != state.link_source_id) &&\n\t\t\t(state.link_target_id == itemId || state.link_source_id == itemId)) {\n\n\t\t\tvar from_id = state.link_source_id;\n\t\t\tvar from_start = state.link_from_start;\n\t\t\tvar to_start = state.link_to_start;\n\n\t\t\tvar allowDrag = gantt.isLinkAllowed(from_id, itemId, from_start, to_start);\n\n\t\t\tvar dragClass = \"\";\n\t\t\tif (allowDrag) {\n\t\t\t\tif (to_start)\n\t\t\t\t\tdragClass = \"link_start_allow\";\n\t\t\t\telse\n\t\t\t\t\tdragClass = \"link_finish_allow\";\n\t\t\t} else {\n\t\t\t\tif (to_start)\n\t\t\t\t\tdragClass = \"link_start_deny\";\n\t\t\t\telse\n\t\t\t\t\tdragClass = \"link_finish_deny\";\n\t\t\t}\n\t\t\tcss.push(dragClass);\n\t\t}\n\t\treturn css.join(\" \");\n\t}\n\n\tfunction _render_pair(parent, css, task, content, config, margin) {\n\t\tvar state = gantt.getState();\n\t\tvar className, element;\n\t\tif (+task.start_date >= +state.min_date) {\n\t\t\tclassName = [css, config.rtl ? \"task_right\" : \"task_left\", \"task_start_date\"];\n\t\t\telement = content(className.join(\" \"));\n\t\t\telement.setAttribute(\"data-bind-property\", \"start_date\");\n\t\t\tif(margin){\n\t\t\t\telement.style.marginLeft = margin + \"px\";\n\t\t\t}\n\t\t\tparent.appendChild(element);\n\t\t}\n\n\t\tif (+task.end_date <= +state.max_date){\n\t\t\tclassName = [css, config.rtl ? \"task_left\" : \"task_right\", \"task_end_date\"];\n\t\t\telement = content(className.join(\" \"));\n\t\t\telement.setAttribute(\"data-bind-property\", \"end_date\");\n\t\t\tif(margin){\n\t\t\t\telement.style.marginRight = margin + \"px\";\n\t\t\t}\n\t\t\tparent.appendChild(element);\n\t\t}\n\n\t}\n\n\treturn _render_task_element;\n}\n\nexport default createTaskRenderer;","// optimized checker for task bars smart rendering\n\n// first check the vertical position since it's easier to calculate\nexport default function isBarInViewport(item, viewport, view, config, gantt){\n\tif(!((item.start_date && item.end_date) || (item.$auto_start_date && item.$auto_end_date))){\n\t\treturn null;\n\t}\n\n\tvar top = view.getItemTop(item.id);\n\tvar height = view.getItemHeight(item.id);\n\n\tif(top > viewport.y_end || top + height < viewport.y){\n\t\treturn false;\n\t}\n\n\tvar padding = 200;\n\n\tconst coords = [];\n\tif(item.start_date){\n\t\tcoords.push(view.posFromDate(item.start_date));\n\t}\n\tif(item.end_date){\n\t\tcoords.push(view.posFromDate(item.end_date));\n\t}\n\tif(item.$auto_start_date){\n\t\tcoords.push(view.posFromDate(item.$auto_start_date));\n\t}\n\tif(item.$auto_end_date){\n\t\tcoords.push(view.posFromDate(item.$auto_end_date));\n\t}\n\t\n\tvar left = Math.min(...coords) - padding;\n\tvar right = Math.max(...coords) + padding;\n\n\tif(left > viewport.x_end || right < viewport.x){\n\t\treturn false;\n\t}\n\n\treturn true;\n};","import isBarInViewport from \"./is_bar_in_viewport\";\nexport default function isSplitTaskInViewport(item, viewport, view, config, gantt){\n\tif (!gantt.isSplitTask(item)) {\n\t\treturn false;\n\t}\n\n\tvar range = gantt.getSubtaskDates(item.id);\n\n\treturn isBarInViewport({\n\t\tid: item.id,\n\t\tstart_date: range.start_date,\n\t\tend_date: range.end_date,\n\t\tparent: item.parent\n\t}, viewport, view, gantt);\n};","export default function(item, view, config){\n\treturn {\n\t\ttop: view.getItemTop(item.id),\n\t\theight: view.getItemHeight(item.id),\n\t\tleft: 0,\n\t\tright: Infinity\n\t};\n};","export default function getVisibleCellsRange(scale, viewport){\n\tvar firstCellIndex = 0;\n\tvar lastCellIndex = scale.left.length - 1;\n\tif(viewport){\n\t\tfor(var i = 0; i < scale.left.length; i++){\n\t\t\tvar left = scale.left[i];\n\t\t\tif(left < viewport.x){\n\t\t\t\tfirstCellIndex = i;\n\t\t\t}\n\t\t\tif(left > viewport.x_end){\n\t\t\t\tlastCellIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tstart: firstCellIndex,\n\t\tend: lastCellIndex\n\t};\n};","import isLegacyRender from \"../is_legacy_smart_render\";\n\nexport default function isColumnVisible(columnIndex, scale, viewPort, gantt){\n\tvar width = scale.width[columnIndex];\n\tif(width <= 0){\n\t\treturn false;\n\t}\n\tif(!gantt.config.smart_rendering || isLegacyRender(gantt)){\n\t\treturn true;\n\t}\n\tvar cellLeftCoord = scale.left[columnIndex] - width;\n\tvar cellRightCoord = scale.left[columnIndex] + width;\n\treturn (cellLeftCoord <= viewPort.x_end && cellRightCoord >= viewPort.x);//do not render skipped columns\n};","export default function (items, gantt){\n\tvar placeholderConfig = gantt.config.timeline_placeholder;\n\titems = items || [];\n\tif (placeholderConfig && items.filter(e => e.id === 'timeline_placeholder_task').length === 0){\n\t\tvar state = gantt.getState();\n\t\tvar lastTaskId = null;\n\t\tvar start_date = state.min_date;\n\t\tvar end_date = state.max_date;\n\t\tif (items.length){\n\t\t\tlastTaskId = items[items.length -1].id;\n\t\t}\n\t\tvar placeholderTask = {\n\t\t\tstart_date: start_date, \n\t\t\tend_date: end_date, \n\t\t\trow_height: placeholderConfig.height || 0,\n\t\t\tid: \"timeline_placeholder_task\", \n\t\t\tunscheduled: true,\n\t\t\tlastTaskId: lastTaskId, \n\t\t\tcalendar_id: placeholderConfig.calendar || \"global\",\n\t\t\t$source:[], \n\t\t\t$target: []\n\t\t};\n\t\titems.push(placeholderTask);\n\t}\n};","export default function(item, viewport, view, config, gantt){\n // GS-2481 and GS-1715, don't remove selected task when using keyboard shortcuts and when the inline editor is opened\n if(gantt.$ui.getView(\"grid\") && ((gantt.config.keyboard_navigation && gantt.getSelectedId()) || (gantt.ext.inlineEditors && gantt.ext.inlineEditors.getState().id))) {\n\t\treturn true;\n\t}\n var top = view.getItemTop(item.id);\n\tvar height = view.getItemHeight(item.id);\n\n\tif(top > viewport.y_end || top + height < viewport.y){\n\t\treturn false;\n\t}\n\n\treturn true;\n};","import * as helpers from \"../utils/helpers\";\n\nexport default function createResourceTimelineBuilder(gantt){\n\n\tlet resourceTaskCache = {};\n\n\tgantt.$data.tasksStore.attachEvent(\"onStoreUpdated\", function(){\n\t\tresourceTaskCache = {};\n\t});\n\n\tfunction getResourceLoad(resource, resourceProperty, scale, timeline){\n\t\tconst cacheKey = resource.id + \"_\" + resourceProperty + \"_\" + scale.unit + \"_\" + scale.step;\n\t\tlet res;\n\t\tif (!resourceTaskCache[cacheKey]) {\n\t\t\tres = resourceTaskCache[cacheKey] = calculateResourceLoad(resource, resourceProperty, scale, timeline);\n\n\t\t} else {\n\t\t\tres = resourceTaskCache[cacheKey];\n\t\t}\n\t\treturn res;\n\t}\n\n\tfunction calculateResourceLoadFromAssignments(items, scale, assignmentsPassed){\n\t\tconst scaleUnit = scale.unit;\n\t\tconst scaleStep = scale.step;\n\t\tconst timegrid = {};\n\n\t\tconst precalculatedTimes = {};\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst item = items[i];\n\t\t\tlet task = item;\n\t\t\tif(assignmentsPassed){\n\t\t\t\ttask = gantt.getTask(item.task_id);\n\t\t\t}\n\t\t\tif (task.unscheduled){\n\t\t\t\tcontinue; // do not process assignments for unscheduled tasks\n\t\t\t}\n\t\t\tlet minDate = (item.start_date || task.start_date);\n\t\t\tlet maxDate = (item.end_date || task.end_date);\n\t\t\tif(assignmentsPassed){\n\t\t\t\tif(item.start_date){\n\t\t\t\t\tminDate = new Date(Math.max(item.start_date.valueOf(), task.start_date.valueOf()));\n\t\t\t\t}\n\t\t\t\tif(item.end_date){\n\t\t\t\t\tmaxDate = new Date(Math.min(item.end_date.valueOf(), task.end_date.valueOf()));\n\t\t\t\t}\n\t\t\t\t// GS-2063: handle case with fixedDates mode\n\t\t\t\tif(item.mode && item.mode == \"fixedDates\"){\n\t\t\t\t\tminDate = item.start_date;\n\t\t\t\t\tmaxDate = item.end_date;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet firstColumn = helpers.findBinary(scale.trace_x, minDate.valueOf());\n\t\t\tlet minScaleDate = new Date(scale.trace_x[firstColumn] || gantt.date[scaleUnit + \"_start\"](new Date(minDate)));\n\t\t\t// GS-2307: need to take into account that task could start before the min scale date\n\t\t\t// so the task would be added to timegrid\n\t\t\tlet currDate = new Date(Math.min(minDate.valueOf(), minScaleDate.valueOf())); \n\n\t\t\tlet calendar = gantt.config.work_time ? gantt.getTaskCalendar(task) : gantt;\n\t\t\tprecalculatedTimes[calendar.id] = {};\n\t\t\twhile (currDate < maxDate) {\n\t\t\t\tconst cachedTimes = precalculatedTimes[calendar.id];\n\n\t\t\t\tlet date = currDate;\n\t\t\t\tconst timestamp = date.valueOf();\n\n\t\t\t\tcurrDate = gantt.date.add(currDate, scaleStep, scaleUnit);\n\n\t\t\t\tif(cachedTimes[timestamp] === false){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!timegrid[timestamp]){\n\t\t\t\t\ttimegrid[timestamp] = {tasks: [], assignments: []};\n\t\t\t\t}\n\n\t\t\t\ttimegrid[timestamp].tasks.push(task);\n\t\t\t\tif(assignmentsPassed){\n\t\t\t\t\ttimegrid[timestamp].assignments.push(item);\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\treturn timegrid;\n\t}\n\n\tfunction calculateResourceLoad(resource, resourceProperty, scale, timeline) {\n\n\t\tlet items;\n\t\tlet assignmentsPassed = false;\n\t\tlet timegrid = {};\n\n\t\tif(gantt.config.process_resource_assignments && resourceProperty === gantt.config.resource_property){\n\t\t\tif(resource.$role == \"task\"){\n\t\t\t\titems = gantt.getResourceAssignments(resource.$resource_id, resource.$task_id);\n\t\t\t}else{\n\t\t\t\titems = gantt.getResourceAssignments(resource.id);\n\t\t\t}\n\n\t\t\tassignmentsPassed = true;\n\t\t}else if(resource.$role == \"task\"){\n\t\t\titems = [];\n\t\t}else{\n\t\t\titems = gantt.getTaskBy(resourceProperty, resource.id);\n\t\t}\n\n\t\ttimegrid = calculateResourceLoadFromAssignments(items, scale, assignmentsPassed);\n\t\tconst scaleUnit = scale.unit;\n\t\tconst scaleStep = scale.step;\n\n\t\tconst timetable = [];\n\t\tlet start, end, tasks, assignments, cell;\n\t\tconst config = timeline.$getConfig();\n\n\t\tfor(let i = 0; i < scale.trace_x.length; i++){\n\t\t\tstart = new Date(scale.trace_x[i]);\n\t\t\tend = gantt.date.add(start, scaleStep, scaleUnit);\n\t\t\tcell = timegrid[start.valueOf()] || {};\n\t\t\ttasks = cell.tasks || [];\n\t\t\tassignments = cell.assignments || [];\n\t\t\tif(tasks.length || config.resource_render_empty_cells){\n\t\t\t\ttimetable.push({\n\t\t\t\t\tstart_date: start,\n\t\t\t\t\tend_date: end,\n\t\t\t\t\ttasks: tasks,\n\t\t\t\t\tassignments: assignments\n\t\t\t\t});\n\t\t\t}else{\n\t\t\t\ttimetable.push(null);\n\t\t\t}\n\t\t}\n\n\t\treturn timetable;\n\t}\n\n\n\n\treturn getResourceLoad;\n};","import isBarInViewport from \"./is_bar_in_viewport\";\nexport default function areDatesInViewPort(task, viewport, view, config, gantt, dateProperties ){\n\tconst bar = {\n\t\tid: task.id,\n\t\tparent: task.id\n\t};\n\n\tfunction checkTaskProperties(task){\n\t\tconst hasAllDates = task[dateProperties.start_date] && task[dateProperties.end_date];\n\t\tif (!hasAllDates) {\n\t\t\treturn false;\n\t\t}\n\t\n\t\tfor (let i = 0; i < dateProperties.length; i++) {\n\t\t\tif (!task[dateProperties[i]]){\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tconst taskProperties = checkTaskProperties(task);\n\tlet childProperties = false;\n\n\tif (taskProperties){\n\t\tbar.start_date = task[dateProperties.start_date];\n\t\tbar.end_date = task[dateProperties.end_date];\t\n\t}\n\n\tif (task.render == \"split\"){\n\t\tgantt.eachTask(function(child){\n\t\t\tif (checkTaskProperties(child)){\n\t\t\t\tchildProperties = true;\n\t\t\t\tbar.start_date = bar.start_date || child[dateProperties.start_date];\n\t\t\t\tbar.end_date = bar.end_date || child[dateProperties.end_date];\n\n\t\t\t\tif (bar.start_date < child[dateProperties.start_date]){\n\t\t\t\t\tbar.start_date = child[dateProperties.start_date];\n\t\t\t\t}\n\t\t\t\tif (bar.end_date > child[dateProperties.end_date]){\n\t\t\t\t\tbar.end_date = child[dateProperties.end_date];\t\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tif (taskProperties || childProperties){\n\t\treturn isBarInViewport(bar, viewport, view, gantt);\n\t} else {\n\t\treturn false;\n\t}\n};","import getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport areDatesInViewPort from \"./viewport/are_dates_in_viewport\";\nimport { childrenHaveBaselines, getAdjustedPosition, isSplitParent } from \"./baseline_helper\";\n\nfunction isConstraintInViewPort (item, viewport, view, config, gantt){\n if (gantt.config.auto_scheduling && gantt.config.auto_scheduling.show_constraints !== false){\n const dateProperties = {\n start_date: \"constraint_date\",\n end_date: \"constraint_date\",\n additional_properties: [\"constraint_type\"]\n };\n return areDatesInViewPort(item, viewport, view, config, gantt, dateProperties);\n } else {\n // don't process constraints when they shouldn't be displayed\n return false;\n }\n}\n\nfunction createTaskRenderer(gantt) {\n // we need that for the use case when the constraints have different names\n const constraintNames = {};\n for (let prop in gantt.config.constraint_types) {\n constraintNames[gantt.config.constraint_types[prop]] = prop;\n }\n\n function getConstraintName(task) {\n const constraintValue = gantt.getConstraintType(task);\n const commonName = constraintNames[constraintValue].toLowerCase();\n return commonName;\n }\n\n function generateConstraintNode(task, timeline, childBaselines){\n const constraintType = getConstraintName(task);\n if (constraintType == \"asap\" || constraintType == \"alap\"){\n return false;\n }\n const el = document.createElement(\"div\");\n const sizes = gantt.getTaskPosition(task, task.constraint_date, task.constraint_date);\n\n const heightLimit = 30;\n let { height, marginTop } = getAdjustedPosition(gantt, timeline, sizes, heightLimit, task, childBaselines);\n\n let width = height;\n\n let marginLeft = 0;\n switch (constraintType) {\n case \"snet\":\n case \"fnet\":\n case \"mso\":\n if (gantt.config.rtl){\n marginLeft = 1;\n }\n else {\n marginLeft = -width - 1;\n }\n\n break;\n case \"snlt\":\n case \"fnlt\":\n case \"mfo\":\n if (gantt.config.rtl){\n marginLeft = -width - 1;\n }\n else {\n marginLeft = 1;\n }\n break;\n\n }\n\n if (task.type === gantt.config.types.milestone){\n marginTop -= 1;\n }\n\n el.style.height = height + \"px\";\n el.style.width = width + \"px\";\n\n el.style.left = sizes.left + \"px\";\n el.style.top = sizes.top + \"px\";\n \n el.style.marginLeft = marginLeft + \"px\";\n el.style.marginTop = marginTop + \"px\";\n\n el.className = \"gantt_constraint_marker gantt_constraint_marker_\" + constraintType;\n \n switch (constraintType) {\n case \"snet\":\n case \"snlt\":\n case \"fnet\":\n case \"fnlt\":\n el.innerHTML = `\n\n\n\n\n\n`;\n break;\n case \"mfo\":\n case \"mso\":\n el.innerHTML = `\n\n\n\n\n\n`;\n break;\n }\n \n \n el.setAttribute(\"data-task-id\", task.id);\n\n return el;\n }\n\n function renderConstraints(task, timeline, config, viewPort) {\n if(gantt.config.auto_scheduling_compatibility){\n return;\n }\n if (gantt.config.auto_scheduling && gantt.config.auto_scheduling.show_constraints !== false){\n const constraintNodes = document.createElement(\"div\");\n constraintNodes.className = \"gantt_constraint_nodes\";\n constraintNodes.setAttribute(\"data-task-row-id\", task.id);\n \n if (task.constraint_date && task.constraint_type) {\n const taskConstraint = generateConstraintNode(task, timeline);\n if (taskConstraint){\n constraintNodes.appendChild(taskConstraint); \n }\n }\n\n if (isSplitParent(task)){\n const childBaselines = childrenHaveBaselines(gantt, task.id);\n gantt.eachTask(function(child){\n if (child.constraint_date && child.constraint_type) {\n const childConstraint = generateConstraintNode(child, timeline, childBaselines);\n if (childConstraint){\n constraintNodes.appendChild(childConstraint);\n }\n }\n }, task.id);\n }\n \n if (constraintNodes.childNodes.length){\n return constraintNodes;\n }\n \n }\n }\n return {\n render: renderConstraints,\n isInViewPort: isConstraintInViewPort,\n getVisibleRange: getVisibleRange\n };\n}\n\nexport default createTaskRenderer;\n","import getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport areDatesInViewPort from \"./viewport/are_dates_in_viewport\";\nimport { childrenHaveBaselines, getAdjustedPosition, isSplitParent } from \"./baseline_helper\";\n\nfunction isDeadlineInViewPort (item, viewport, view, config, gantt){\n\tconst dateProperties = {\n\t\tstart_date: \"deadline\",\n\t\tend_date: \"deadline\"\n\t};\n\treturn areDatesInViewPort(item, viewport, view, config, gantt, dateProperties);\n}\n\nfunction createTaskRenderer(gantt) {\n\n function generateDeadlineNode(task, timeline, childBaselines){\n const el = document.createElement(\"div\");\n\n const sizes = gantt.getTaskPosition(task, task.deadline, task.deadline);\n\n const heightLimit = 20;\n const { height, marginTop } = getAdjustedPosition(gantt, timeline, sizes, heightLimit, task, childBaselines);\n \n let width = height;\n\n if (gantt.config.rtl){\n sizes.left += width;\n }\n\n el.style.left = sizes.left - width + \"px\";\n el.style.top = sizes.top + \"px\";\n el.style.marginTop = marginTop + \"px\";\n\n el.style.width = width + \"px\";\n el.style.height = height + \"px\";\n\n el.style.fontSize = height + \"px\";\n\n el.className = \"gantt_task_deadline\";\n el.setAttribute(\"data-task-id\", task.id);\n\n return el;\n }\n\n function renderDeadline(task, timeline, config, viewPort) {\n const deadlineNodes = document.createElement(\"div\");\n deadlineNodes.className = \"gantt_deadline_nodes\";\n deadlineNodes.setAttribute(\"data-task-row-id\", task.id);\n\n if (task.deadline) {\n const taskDeadline = generateDeadlineNode(task, timeline);\n deadlineNodes.appendChild(taskDeadline);\n }\n if (isSplitParent(task)){\n const childBaselines = childrenHaveBaselines(gantt, task.id);\n gantt.eachTask(function(child){\n if (child.deadline){\n const childDeadline = generateDeadlineNode(child, timeline, childBaselines);\n deadlineNodes.appendChild(childDeadline);\n }\n }, task.id);\n }\n\n if (deadlineNodes.childNodes.length){\n return deadlineNodes;\n }\n }\n return {\n render: renderDeadline,\n isInViewPort: isDeadlineInViewPort,\n getVisibleRange: getVisibleRange\n };\n}\n\nexport default createTaskRenderer;\n","import getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport areDatesInViewPort from \"./viewport/are_dates_in_viewport\";\nimport { getMaxParentHeight, getMilestoneHeight, getInvertedMilestoneHeight, isSplitParent } from \"./baseline_helper\";\n\nfunction isBaselineInViewPort (task, viewport, view, config, gantt){\n let inViewport = false;\n const dateProperties = {\n start_date: \"start_date\",\n end_date: \"end_date\"\n };\n if (task.type == gantt.config.types.milestone){\n dateProperties.end_date = dateProperties.start_date;\n }\n\n if (task.baselines){\n inViewport = iterateBaselines(task, viewport, view, config, gantt, dateProperties);\n }\n if (isSplitParent(task)){\n gantt.eachTask(function(child){\n if (inViewport){\n return;\n }\n if (child.baselines && child.baselines.length) {\n if (child.type == gantt.config.types.milestone){\n dateProperties.end_date = dateProperties.start_date;\n } \n if (iterateBaselines(child, viewport, view, config, gantt, dateProperties)){\n inViewport = true;\n }\n }\n }, task.id);\n }\n\n return inViewport;\n}\n\nfunction iterateBaselines(task, viewport, view, config, gantt, dateProperties){\n for (var i = 0; i < task.baselines.length; i++) {\n const baseline = {\n id: task.id,\n parent: task.parent,\n start_date: task.baselines[i].start_date,\n end_date: task.baselines[i].end_date\n };\n if (areDatesInViewPort(baseline, viewport, view, config, gantt, dateProperties)){\n return true;\n }\n }\n}\n\nfunction createBaselineRenderer(gantt) {\n\n function generateBaselineNode(task, baseline, index, timeline, splitChild){\n const el = document.createElement(\"div\");\n let baselineEnd = baseline.end_date;\n let milestoneTask = task.type === gantt.config.types.milestone;\n if (milestoneTask){\n baselineEnd = baseline.start_date;\n }\n const sizes = gantt.getTaskPosition(task, baseline.start_date, baselineEnd);\n\n let milestoneMarginTop = 0;\n let milestoneWidth;\n if (milestoneTask){\n let milestoneHeight = timeline.getBarHeight(task.id, true);\n milestoneWidth = getMilestoneHeight(milestoneHeight);\n milestoneMarginTop = Math.floor((milestoneWidth - milestoneHeight) / 4);\n }\n\n let parentHeight = getMaxParentHeight(gantt, timeline, task, sizes.rowHeight);\n let maxHeight = parentHeight.maxHeight;\n\n\n let top = sizes.top + 1 + milestoneMarginTop;\n let height = timeline.getBarHeight(task.id, task.type);\n const baselineSubrowHeight = gantt.config.baselines.row_height;\n const baselineBarHeight = gantt.config.baselines.bar_height;\n\n // between task and first baseline\n let siblingBaselinesSize;\n let marginTop;\n\n switch (gantt.config.baselines.render_mode) {\n case \"separateRow\":\n top += sizes.height + (baselineSubrowHeight - baselineBarHeight) / 2;\n height = baselineBarHeight;\n break;\n\n case \"individualRow\":\n // betweenBaselines = 3 * (index + 1);\n siblingBaselinesSize = (baselineSubrowHeight) * index;\n top += sizes.height + siblingBaselinesSize + (baselineSubrowHeight - baselineBarHeight) / 2;\n \n height = baselineBarHeight;\n break;\n \n case \"taskRow\":\n default:\n // TODO: simplify positioning\n marginTop = 1;\n if (splitChild){\n maxHeight = getMaxParentHeight(gantt, timeline, task).maxHeight;\n if (milestoneMarginTop){\n if (maxHeight >= milestoneWidth){\n marginTop = (maxHeight - height) / 2 - 1 - milestoneMarginTop;\n } else {\n height = getInvertedMilestoneHeight(maxHeight);\n top = sizes.top;\n marginTop = Math.abs(height - maxHeight) / 2;\n milestoneMarginTop = 0; // for maxBottom\n }\n } else {\n if (maxHeight > height){\n marginTop = (maxHeight - height) / 2 - 1;\n } \n marginTop -= milestoneMarginTop; \n }\n if(!task.bar_height){\n marginTop -= 1;\n }else{\n // marginTop += 1;\n }\n } else {\n if (task.bar_height && sizes.rowHeight >= task.bar_height){\n marginTop = (sizes.rowHeight - task.bar_height) / 2 - 1;\n }\n marginTop += milestoneMarginTop;\n\n if(!task.bar_height){\n marginTop += 2;\n }\n if (milestoneTask){\n marginTop += 1;\n }\n \n }\n break;\n }\n\n let maxBottom = sizes.top + maxHeight + 1 - milestoneMarginTop;\n\n\n // don't exceed maximal task row height\n if (top + height > maxBottom){\n height -= top + height - maxBottom;\n if (height <= 0) {\n return false;\n }\n }\n\n\n el.style.left = sizes.left + \"px\";\n el.style.width = sizes.width + \"px\";\n el.style.top = top + \"px\";\n el.style.height = Math.floor(height) + \"px\";\n if(marginTop){\n el.style.marginTop = marginTop + \"px\";\n }\n el.className = `gantt_task_baseline gantt_task_baseline_${index} ${baseline.className || \"\"}`;\n\n if (milestoneTask){\n el.className += \"gantt_milestone_baseline\";\n el.style.width = el.style.height = height + \"px\";\n el.style.marginLeft = Math.floor(-height / 2) + \"px\";\n } else {\n el.innerHTML = gantt.templates.baseline_text(task, baseline, index);\n }\n\n\n el.setAttribute(\"data-task-id\", task.id);\n el.setAttribute(\"data-baseline-id\", baseline.id);\n\n return el;\n }\n\n function renderBaseline(task, timeline, config, viewPort) {\n if (!gantt.config.baselines.render_mode){\n return;\n }\n\n const baselineNodes = document.createElement(\"div\");\n baselineNodes.className = \"gantt_baseline_nodes\";\n baselineNodes.setAttribute(\"data-task-row-id\", task.id);\n\n if (task.baselines && task.baselines.length) {\n task.baselines.forEach(function(baseline, index){\n const taskBaseline = generateBaselineNode(task, baseline, index, timeline);\n if (taskBaseline){\n baselineNodes.appendChild(taskBaseline); \n }\n });\n }\n if (isSplitParent(task)){\n gantt.eachTask(function(child){\n if (child.baselines && child.baselines.length) {\n child.baselines.forEach(function(baseline, index){\n const childBaseline = generateBaselineNode(child, baseline, index, timeline, true);\n if (childBaseline){\n baselineNodes.appendChild(childBaseline); \n }\n });\n }\n }, task.id);\n }\n\n if (baselineNodes.childNodes.length){\n return baselineNodes;\n }\n }\n return {\n render: renderBaseline,\n isInViewPort: isBaselineInViewPort,\n getVisibleRange: getVisibleRange\n };\n}\n\nexport default createBaselineRenderer;\n","import * as domHelpers from \"../utils/dom_helpers\";\nimport isPlaceholderTask from \"../../../utils/placeholder_task\";\n\nfunction _init_dnd(gantt, grid) {\n\tvar DnD = gantt.$services.getService(\"dnd\");\n\n\tif(!grid.$config.bind || !gantt.getDatastore(grid.$config.bind)){\n\t\treturn;\n\t}\n\n\tfunction locate(e){\n\t\treturn domHelpers.locateAttribute(e, grid.$config.item_attribute);\n\t}\n\n\tfunction getStore(){\n\t\treturn gantt.getDatastore(grid.$config.bind);\n\t}\n\n\tfunction checkPlaceholderTask(id){\n\t\treturn isPlaceholderTask(id, gantt, getStore());\n\t}\n\n\tvar dnd = new DnD(grid.$grid_data, {updates_per_second: 60});\n\tif (gantt.defined(grid.$getConfig().dnd_sensitivity))\n\t\tdnd.config.sensitivity = grid.$getConfig().dnd_sensitivity;\n\n\tdnd.attachEvent(\"onBeforeDragStart\", gantt.bind(function (obj, e) {\n\t\tvar el = locate(e);\n\t\tif (!el) return false;\n\t\tif (gantt.hideQuickInfo) gantt.hideQuickInfo();\n\n\t\tif (domHelpers.closest(e.target, \".gantt_grid_editor_placeholder\")){\n\t\t\treturn false;\n\t\t}\n\n\t\tvar id = el.getAttribute(grid.$config.item_attribute);\n\t\tif (checkPlaceholderTask(id)) return false;\n\n\t\tvar datastore = getStore();\n\n\t\tvar task = datastore.getItem(id);\n\n\t\tif (gantt.isReadonly(task))\n\t\t\treturn false;\n\n\t\tdnd.config.initial_open_state = task.$open;\n\t\tif (!gantt.callEvent(\"onRowDragStart\", [id, e.target || e.srcElement, e])) {\n\t\t\treturn false;\n\t\t}\n\n\t}, gantt));\n\n\tdnd.attachEvent(\"onAfterDragStart\", gantt.bind(function (obj, e) {\n\t\tvar el = locate(e);\n\t\tdnd.config.marker.innerHTML = el.outerHTML;\n\t\tvar element = dnd.config.marker.firstChild;\n\t\tif(element){\n\t\t\telement.style.position = \"static\";\n\t\t}\n\n\t\tdnd.config.id = el.getAttribute(grid.$config.item_attribute);\n\n\t\tvar store = getStore();\n\n\t\tvar task = store.getItem(dnd.config.id);\n\t\tdnd.config.index = store.getBranchIndex(dnd.config.id);\n\t\tdnd.config.parent = task.parent;\n\t\ttask.$open = false;\n\t\ttask.$transparent = true;\n\t\tthis.refreshData();\n\t}, gantt));\n\n\tdnd.lastTaskOfLevel = function (level) {\n\t\tvar last_item = null;\n\t\tvar store = getStore();\n\t\tvar tasks = store.getItems();\n\t\tfor (var i = 0, len = tasks.length; i < len; i++) {\n\t\t\tif (tasks[i].$level == level) {\n\t\t\t\tlast_item = tasks[i];\n\t\t\t}\n\t\t}\n\t\treturn last_item ? last_item.id : null;\n\t};\n\tdnd._getGridPos = gantt.bind(function (e) {\n\t\tvar pos = domHelpers.getNodePosition(grid.$grid_data);\n\t\t// row offset\n\t\tvar x = pos.x + grid.$grid.scrollLeft;\n\t\tvar y = e.pos.y - 10;\n\n\t\tvar rowHeight = grid.getItemHeight(dnd.config.id);\n\t\t// prevent moving row out of grid_data container\n\t\tif (y < pos.y) y = pos.y;\n\t\tvar gridHeight = grid.getTotalHeight();\n\t\tif (y > pos.y + gridHeight - rowHeight) y = pos.y + gridHeight - rowHeight;\n\t\tconst maxBottom = pos.y + pos.height;\n\t\tif (y > maxBottom - rowHeight) {\n\t\t\ty = maxBottom - rowHeight;\n\t\t}\n\n\t\tpos.x = x;\n\t\tpos.y = y;\n\t\treturn pos;\n\t}, gantt);\n\tdnd._getTargetY = gantt.bind(function (e) {\n\t\tvar pos = domHelpers.getNodePosition(grid.$grid_data);\n\t\tvar scrollPos = grid.$state.scrollTop || 0;\n\t\tvar maxBottom = gantt.$grid_data.getBoundingClientRect().height + scrollPos;\n\n\t\tvar y = e.pageY - pos.y + scrollPos;\n\t\tif (y > maxBottom) {\n\t\t\ty = maxBottom;\n\t\t} else if (y < scrollPos) {\n\t\t\ty = scrollPos;\n\t\t}\n\t\treturn y;\n\t}, gantt);\n\tdnd._getTaskByY = gantt.bind(function (y, dropIndex) {\n\n\t\tvar store = getStore();\n\n\t\ty = y || 0;\n\n\t\tvar index = grid.getItemIndexByTopPosition(y);\n\t\tindex = dropIndex < index ? index - 1 : index;\n\n\t\tif (index > store.countVisible() - 1)\n\t\t\treturn null;\n\n\t\treturn store.getIdByIndex(index);\n\t}, gantt);\n\tdnd.attachEvent(\"onDragMove\", gantt.bind(function (obj, e) {\n\t\tvar gridDataSizes = gantt.$grid_data.getBoundingClientRect();\n\t\tvar maxBottom = gridDataSizes.height + gridDataSizes.y + (grid.$state.scrollTop || 0) + window.scrollY;\n\t\tvar dd = dnd.config;\n\t\tvar pos = dnd._getGridPos(e);\n\n\t\tgantt._waiAria.reorderMarkerAttr(dd.marker);\n\n\t\tvar config = grid.$getConfig(),\n\t\t\tstore = getStore();\n\n\t\t// setting position of row\n\t\tif (pos.y < maxBottom) {\n\t\t\tdd.marker.style.top = pos.y + \"px\";\n\t\t} else {\n\t\t\tdd.marker.style.top = maxBottom + \"px\";\n\t\t}\n\t\tdd.marker.style.left = pos.x + 10 + \"px\";\n\t\tconst containerSize = domHelpers.getNodePosition(gantt.$root);\n\t\tif (pos.width > containerSize.width){\n\t\t\tdd.marker.style.width = containerSize.width - 10 - 2 + \"px\";\n\t\t\tdd.marker.style.overflow = \"hidden\";\t\n\t\t}\n\n\t\t// highlight row when mouseover\n\t\tvar item = store.getItem(dnd.config.id);\n\t\tvar targetY = dnd._getTargetY(e);\n\t\tvar el = dnd._getTaskByY(targetY, store.getIndexById(item.id));\n\n\t\tif (!store.exists(el)) {\n\t\t\tel = dnd.lastTaskOfLevel(config.order_branch_free ? item.$level : 0);\n\t\t\tif (el == dnd.config.id) {\n\t\t\t\tel = null;\n\t\t\t}\n\t\t}\n\n\t\tfunction allowedLevel(next, item) {\n\t\t\treturn (!(store.isChildOf(over.id, item.id)) && (next.$level == item.$level || config.order_branch_free));\n\t\t}\n\n\t\tif (store.exists(el)) {\n\t\t\tvar over = store.getItem(el);\n\n\t\t\tvar itemTop = grid.getItemTop(over.id);\n\t\t\tvar itemHeight = grid.getItemHeight(over.id);\n\t\t\tif (itemTop + itemHeight / 2 < targetY) {\n\t\t\t\t//hovering over bottom part of item, check can be drop to bottom\n\t\t\t\tvar index = store.getIndexById(over.id);\n\t\t\t\tvar nextId = store.getNext(over.id);//adds +1 when hovering over placeholder\n\t\t\t\tvar next = store.getItem(nextId);\n\t\t\t\tif (checkPlaceholderTask(nextId)){\n\t\t\t\t\tvar prevId = store.getPrev(next.id);\n\t\t\t\t\tnext = store.getItem(prevId);\n\t\t\t\t}\n\t\t\t\tif (next) {\n\t\t\t\t\tif (next.id != item.id) {\n\t\t\t\t\t\tover = next; //there is a valid target\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (config.order_branch_free) {\n\t\t\t\t\t\t\tif (!(store.isChildOf(item.id, over.id) && store.getChildren(over.id).length == 1))\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tstore.move(item.id, store.getBranchIndex(over.id) + 1, store.getParent(over.id));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t//we at end of the list, check and drop at the end of list\n\t\t\t\t\tnextId = store.getIdByIndex(index);\n\t\t\t\t\tnext = store.getItem(nextId);\n\n\t\t\t\t\tif (checkPlaceholderTask(nextId)){\n\t\t\t\t\t\tvar prevId = store.getPrev(next.id);\n\t\t\t\t\t\tnext = store.getItem(prevId);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (allowedLevel(next, item) && next.id != item.id) {\n\t\t\t\t\t\tstore.move(item.id, -1, store.getParent(next.id));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (config.order_branch_free) {\n\t\t\t\tif (over.id != item.id && allowedLevel(over, item) && !checkPlaceholderTask(over.id)) {\n\t\t\t\t\tif (!store.hasChild(over.id)) {\n\t\t\t\t\t\tover.$open = true;\n\t\t\t\t\t\tstore.move(item.id, -1, over.id);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (store.getIndexById(over.id) || itemHeight / 3 < targetY) return;\n\t\t\t\t}\n\t\t\t}\n\t\t\t//if item is on different level, check the one before it\n\t\t\tvar index = store.getIndexById(over.id),\n\t\t\t\tprevId = store.getIdByIndex(index - 1);\n\n\t\t\tvar prev = store.getItem(prevId);\n\n\t\t\tvar shift = 1;\n\t\t\twhile ((!prev || prev.id == over.id) && index - shift >= 0) {\n\n\t\t\t\tprevId = store.getIdByIndex(index - shift);\n\t\t\t\tprev = store.getItem(prevId);\n\t\t\t\tshift++;\n\t\t\t}\n\n\t\t\tif (item.id == over.id || checkPlaceholderTask(over.id)) return;\n\t\t\t//replacing item under cursor\n\t\t\tif (allowedLevel(over, item) && item.id != over.id) {\n\t\t\t\tstore.move(item.id, 0, 0, over.id);\n\n\t\t\t} else if (over.$level == item.$level - 1 && !store.getChildren(over.id).length) {\n\t\t\t\tstore.move(item.id, 0, over.id);\n\n\t\t\t} else if (prev && (allowedLevel(prev, item)) && (item.id != prev.id)) {\n\t\t\t\tstore.move(item.id, -1, store.getParent(prev.id));\n\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}, gantt));\n\n\tdnd.attachEvent(\"onDragEnd\", gantt.bind(function () {\n\t\tvar store = getStore();\n\t\tvar task = store.getItem(dnd.config.id);\n\t\ttask.$transparent = false;\n\t\ttask.$open = dnd.config.initial_open_state;\n\n\t\tif (this.callEvent(\"onBeforeRowDragEnd\", [dnd.config.id, dnd.config.parent, dnd.config.index]) === false) {\n\t\t\tstore.move(dnd.config.id, dnd.config.index, dnd.config.parent);\n\t\t\ttask.$drop_target = null;\n\t\t} else {\n\t\t\tthis.callEvent(\"onRowDragEnd\", [dnd.config.id, task.$drop_target]);\n\t\t}\n\t\tgantt.render();\n\t\tthis.refreshData();\n\t}, gantt));\n}\n\nexport default {\n\tinit: _init_dnd\n};","/**\n * The state object for order branch drag and drop\n */\n\nimport * as utils from \"../../../../utils/utils\";\n\nexport default {\n\tcreateDropTargetObject: function createDropTargetObject(parent) {\n\t\tvar res = {\n\t\t\ttargetParent: null,\n\t\t\ttargetIndex: 0,\n\t\t\ttargetId: null,\n\t\t\tchild: false,\n\t\t\tnextSibling: false,\n\t\t\tprevSibling: false\n\t\t};\n\n\t\tif (parent) {\n\t\t\tutils.mixin(res, parent, true);\n\t\t}\n\t\treturn res;\n\t},\n\tnextSiblingTarget: function nextSiblingTarget(dndTaskId, targetTaskId, store) {\n\t\tvar result = this.createDropTargetObject();\n\t\tresult.targetId = targetTaskId;\n\t\tresult.nextSibling = true;\n\t\tresult.targetParent = store.getParent(result.targetId);\n\t\tresult.targetIndex = store.getBranchIndex(result.targetId);\n\t\tif(store.getParent(dndTaskId) != result.targetParent || result.targetIndex < store.getBranchIndex(dndTaskId)){\n\t\t\tresult.targetIndex += 1;\n\t\t}\n\t\treturn result;\n\t},\n\tprevSiblingTarget: function prevSiblingTarget(dndTaskId, targetTaskId, store) {\n\t\tvar result = this.createDropTargetObject();\n\t\tresult.targetId = targetTaskId;\n\t\tresult.prevSibling = true;\n\t\tresult.targetParent = store.getParent(result.targetId);\n\t\tresult.targetIndex = store.getBranchIndex(result.targetId);\n\t\tif(store.getParent(dndTaskId) == result.targetParent && result.targetIndex > store.getBranchIndex(dndTaskId)){\n\t\t\tresult.targetIndex -= 1;\n\t\t}\n\t\treturn result;\n\t},\n\tfirstChildTarget: function firstChildTarget(dndTaskId, targetTaskId, store) {\n\t\tvar result = this.createDropTargetObject();\n\t\tresult.targetId = targetTaskId;\n\t\tresult.targetParent = result.targetId;\n\t\tresult.targetIndex = 0;\n\t\tresult.child = true;\n\t\treturn result;\n\t},\n\tlastChildTarget: function lastChildTarget(dndTaskId, targetTaskId, store) {\n\t\tvar children = store.getChildren(targetTaskId);\n\t\tvar result = this.createDropTargetObject();\n\t\tresult.targetId = children[children.length - 1];\n\t\tresult.targetParent = targetTaskId;\n\t\tresult.targetIndex = children.length;\n\t\tresult.nextSibling = true;\n\t\treturn result;\n\t}\n};","/**\n * resolve dnd position of the task when gantt.config.order_branch_free = false\n */\n\nimport dropTarget from \"./drop_target\";\n\nfunction getLast(store){\n\tvar current = store.getNext();\n\twhile(store.exists(current)){\n\n\t\tvar next = store.getNext(current);\n\t\tif(!store.exists(next)){\n\t\t\treturn current;\n\t\t}else{\n\t\t\tcurrent = next;\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction findClosesTarget(dndTaskId, taskId, allowedLevel, store, up){\n\tvar prev = taskId;\n\twhile(store.exists(prev)){\n\t\tvar targetLevel = store.calculateItemLevel(store.getItem(prev));\n\t\tif((targetLevel === allowedLevel || targetLevel === (allowedLevel - 1)) && store.getBranchIndex(prev) > -1){\n\t\t\tbreak;\n\t\t}else {\n\t\t\tprev = up ? store.getPrev(prev) : store.getNext(prev);\n\t\t}\n\t}\n\n\tif(store.exists(prev)){\n\t\tif(store.calculateItemLevel(store.getItem(prev)) === allowedLevel){\n\t\t\treturn up ? dropTarget.nextSiblingTarget(dndTaskId, prev, store) : dropTarget.prevSiblingTarget(dndTaskId, prev, store);\n\t\t}else{\n\t\t\treturn dropTarget.firstChildTarget(dndTaskId, prev, store);\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction findTargetAbove(dndTaskId, taskId, allowedLevel, store){\n\treturn findClosesTarget(dndTaskId, taskId, allowedLevel, store, true);\n}\nfunction findTargetBelow(dndTaskId, taskId, allowedLevel, store){\n\treturn findClosesTarget(dndTaskId, taskId, allowedLevel, store, false);\n}\n\nexport default function getSameLevelDropPosition(dndTaskId, targetTaskId, relTargetPos, eventTop, store, level){\n\tvar result;\n\tif(targetTaskId !== store.$getRootId()){\n\t\tvar targetTask = store.getItem(targetTaskId);\n\t\tvar targetLevel = store.calculateItemLevel(targetTask);\n\t\tif(targetLevel === level){\n\t\t\tvar prevSibling = store.getPrevSibling(targetTaskId);\n\t\t\tif(relTargetPos < 0.5 && !prevSibling){\n\t\t\t\tresult = dropTarget.prevSiblingTarget(dndTaskId, targetTaskId, store);\n\t\t\t}else{\n\t\t\t\tif(relTargetPos < 0.5){\n\t\t\t\t\ttargetTaskId = prevSibling;\n\t\t\t\t}\n\t\t\t\tresult = dropTarget.nextSiblingTarget(dndTaskId, targetTaskId, store);\n\t\t\t}\n\t\t}else if(targetLevel > level){\n\t\t\tstore.eachParent(function(parent){\n\t\t\t\tif(store.calculateItemLevel(parent) === level){\n\t\t\t\t\ttargetTaskId = parent.id;\n\t\t\t\t}\n\t\t\t}, targetTask); \n\t\t\tresult = findTargetAbove(dndTaskId, targetTaskId, level, store);\n\t\t}else{\n\t\t\tvar targetAbove = findTargetAbove(dndTaskId, targetTaskId, level, store);\n\t\t\tvar targetBelow = findTargetBelow(dndTaskId, targetTaskId, level, store);\n\t\t\tresult = (relTargetPos < 0.5) ? targetAbove : targetBelow;\n\t\t}\n\t}else{\n\t\tvar rootId = store.$getRootId();\n\t\tvar rootLevel = store.getChildren(rootId);\n\t\tresult = dropTarget.createDropTargetObject();\n\t\tif(rootLevel.length && eventTop >= 0){\n\t\t\tresult = findTargetAbove(dndTaskId, getLast(store), level, store);\n\t\t}else{\n\t\t\tresult = findTargetBelow(dndTaskId, rootId, level, store);\n\t\t}\n\t}\n\n\treturn result;\n};\n","import * as domHelpers from \"../../utils/dom_helpers\";\n\n/**\n * methods for highlighting current drag and drop position\n */\n\nfunction highlightPosition(target, root, grid){\n\tvar markerPos = getTaskMarkerPosition(target, grid);\n\t// setting position of row\n\troot.marker.style.left = markerPos.x + 9 + \"px\";\n\troot.marker.style.width = markerPos.width + \"px\";\n\troot.marker.style.overflow = \"hidden\";\n\tvar markerLine = root.markerLine;\n\tif(!markerLine){\n\t\tmarkerLine = document.createElement(\"div\");\n\t\tmarkerLine.className = \"gantt_drag_marker gantt_grid_dnd_marker\";\n\t\tmarkerLine.innerHTML = \"
\";\n\t\tmarkerLine.style.pointerEvents = \"none\";\n\t}\n\n\tif(target.child){\n\t\thighlightFolder(target, markerLine, grid);\n\t}else{\n\t\thighlightRow(target, markerLine, grid);\n\t}\n\n\tif(!root.markerLine){\n\t\tdocument.body.appendChild(markerLine);\n\t\troot.markerLine = markerLine;\n\t}\n}\n\nfunction removeLineHighlight(root){\n\tif(root.markerLine && root.markerLine.parentNode){\n\t\troot.markerLine.parentNode.removeChild(root.markerLine);\n\t}\n\troot.markerLine = null;\n}\n\nfunction highlightRow(target, markerLine, grid){\n\tvar linePos = getLineMarkerPosition(target, grid);\n\tvar maxBottom = grid.$grid_data.getBoundingClientRect().bottom + window.scrollY;\n\n\tmarkerLine.innerHTML = \"
\";\n\tmarkerLine.style.left = linePos.x + \"px\";\n\tmarkerLine.style.height = \"4px\";\n\n\tvar markerLineTop = linePos.y - 2;\n\tmarkerLine.style.top = markerLineTop + \"px\";\n\tmarkerLine.style.width = linePos.width + \"px\";\n\n\tif (markerLineTop > maxBottom) {\n\t\tmarkerLine.style.top = maxBottom + 'px';\n\t}\n\n\treturn markerLine;\n}\nfunction highlightFolder(target, markerFolder, grid){\n\tvar id = target.targetParent;\n\tvar pos = gridToPageCoordinates({x: 0, y: grid.getItemTop(id)}, grid);\n\tvar maxBottom = grid.$grid_data.getBoundingClientRect().bottom + window.scrollY;\n\n\tlet folderHighlightWidth = setWidthWithinContainer(grid.$gantt, grid.$grid_data.offsetWidth);\t\n\n\tmarkerFolder.innerHTML = \"
\";\n\tmarkerFolder.style.width = folderHighlightWidth + \"px\";\n\tmarkerFolder.style.top = pos.y + \"px\";\n\tmarkerFolder.style.left = pos.x + \"px\";\n\tmarkerFolder.style.height = grid.getItemHeight(id) + \"px\";\n\tif (pos.y > maxBottom) {\n\t\tmarkerFolder.style.top = maxBottom + 'px';\n\t}\n\n\treturn markerFolder;\n}\n\nfunction getLineMarkerPosition(target, grid){\n\tvar store = grid.$config.rowStore;\n\tvar pos = {x:0, y:0};\n\tvar indentNode = grid.$grid_data.querySelector(\".gantt_tree_indent\");\n\tvar indent = 15;\n\tvar level = 0;\n\tif(indentNode){\n\t\tindent = indentNode.offsetWidth;\n\t}\n\tvar iconWidth = 40;\n\tif(target.targetId !== store.$getRootId()){\n\t\tvar itemTop = grid.getItemTop(target.targetId);\n\t\tvar itemHeight = grid.getItemHeight(target.targetId);\n\t\tlevel = store.exists(target.targetId) ? store.calculateItemLevel(store.getItem(target.targetId)) : 0;\n\n\t\tif(target.prevSibling){\n\t\t\tpos.y = itemTop;\n\t\t}else if(target.nextSibling){\n\t\t\tvar childCount = 0;\n\t\t\tstore.eachItem(function(child){\n\t\t\t\tif(store.getIndexById(child.id) !== -1)\n\t\t\t\t\tchildCount++;\n\t\t\t}, target.targetId);\n\n\t\t\tpos.y = itemTop + itemHeight + childCount*itemHeight;\n\t\t}else {\n\t\t\tpos.y = itemTop + itemHeight;\n\t\t\tlevel += 1;\n\t\t}\n\t}\n\tpos.x = iconWidth + level * indent;\n\tpos.width = setWidthWithinContainer(grid.$gantt, Math.max(grid.$grid_data.offsetWidth - pos.x, 0), pos.x);\n\treturn gridToPageCoordinates(pos, grid);\n}\n\nfunction gridToPageCoordinates(pos, grid){\n\tvar gridPos = domHelpers.getNodePosition(grid.$grid_data);\n\tpos.x += gridPos.x + grid.$grid.scrollLeft;\n\tpos.y += gridPos.y - grid.$grid_data.scrollTop;\n\treturn pos;\n}\n\nfunction getTaskMarkerPosition(e, grid) {\n\tvar pos = domHelpers.getNodePosition(grid.$grid_data);\n\tvar ePos = domHelpers.getRelativeEventPosition(e, grid.$grid_data);\n\t// row offset\n\tvar x = pos.x + grid.$grid.scrollLeft;\n\tvar y = ePos.y - 10;\n\n\tvar rowHeight = grid.getItemHeight(e.targetId);\n\t// prevent moving row out of grid_data container\n\tif (y < pos.y) y = pos.y;\n\tvar gridHeight = grid.getTotalHeight();\n\tif (y > pos.y + gridHeight - rowHeight) y = pos.y + gridHeight - rowHeight;\n\n\tpos.x = x;\n\tpos.y = y;\n\tpos.width = setWidthWithinContainer(grid.$gantt, pos.width, 9);\n\treturn pos;\n}\n\nfunction setWidthWithinContainer(gantt, width, offset = 0){\n\tconst containerSize = domHelpers.getNodePosition(gantt.$root);\n\tif (width > containerSize.width){\n\t\twidth = containerSize.width - offset - 2;\n\t}\n\treturn width;\n}\n\nexport default {\n\tremoveLineHighlight: removeLineHighlight,\n\thighlightPosition: highlightPosition\n};\n","import * as domHelpers from \"../utils/dom_helpers\";\nimport dropTarget from \"./tasks_grid_dnd_marker_helpers/drop_target\";\nimport getLockedLevelTarget from \"./tasks_grid_dnd_marker_helpers/locked_level\";\nimport getMultiLevelTarget from \"./tasks_grid_dnd_marker_helpers/multi_level\";\nimport higlighter from \"./tasks_grid_dnd_marker_helpers/highlight\";\nimport isPlaceholderTask from \"../../../utils/placeholder_task\";\n\nfunction _init_dnd(gantt, grid) {\n\tvar DnD = gantt.$services.getService(\"dnd\");\n\n\tif(!grid.$config.bind || !gantt.getDatastore(grid.$config.bind)){\n\t\treturn;\n\t}\n\n\tfunction locate(e){\n\t\treturn domHelpers.locateAttribute(e, grid.$config.item_attribute);\n\t}\n\n\tfunction getStore(){\n\t\treturn gantt.getDatastore(grid.$config.bind);\n\t}\n\n\tfunction checkPlaceholderTask(id){\n\t\treturn isPlaceholderTask(id, gantt, getStore());\n\t}\n\n\tvar dnd = new DnD(grid.$grid_data, {updates_per_second: 60});\n\tif (gantt.defined(grid.$getConfig().dnd_sensitivity))\n\t\tdnd.config.sensitivity = grid.$getConfig().dnd_sensitivity;\n\n\tdnd.attachEvent(\"onBeforeDragStart\", gantt.bind(function (obj, e) {\n\t\tvar el = locate(e);\n\t\tif (!el) return false;\n\t\tif (gantt.hideQuickInfo) gantt.hideQuickInfo();\n\t\tif (domHelpers.closest(e.target, \".gantt_grid_editor_placeholder\")){\n\t\t\treturn false;\n\t\t}\n\n\t\tvar id = el.getAttribute(grid.$config.item_attribute);\n\t\tvar datastore = grid.$config.rowStore;\n\t\tvar task = datastore.getItem(id);\n\n\t\tif (gantt.isReadonly(task) || checkPlaceholderTask(id))\n\t\t\treturn false;\n\n\t\tdnd.config.initial_open_state = task.$open;\n\t\tif (!gantt.callEvent(\"onRowDragStart\", [id, e.target || e.srcElement, e])) {\n\t\t\treturn false;\n\t\t}\n\n\t}, gantt));\n\n\tdnd.attachEvent(\"onAfterDragStart\", gantt.bind(function (obj, e) {\n\t\tvar el = locate(e);\n\n\t\tdnd.config.marker.innerHTML = el.outerHTML;\n\t\tvar element = dnd.config.marker.firstChild;\n\t\tif(element){\n\t\t\tdnd.config.marker.style.opacity = 0.4;\n\t\t\telement.style.position = \"static\";\n\t\t\telement.style.pointerEvents = \"none\";\n\t\t}\n\n\t\tdnd.config.id = el.getAttribute(grid.$config.item_attribute);\n\n\t\tvar store = grid.$config.rowStore;\n\n\t\tvar task = store.getItem(dnd.config.id);\n\t\tdnd.config.level = store.calculateItemLevel(task);\n\t\tdnd.config.drop_target = dropTarget.createDropTargetObject({\n\t\t\ttargetParent: store.getParent(task.id),\n\t\t\ttargetIndex: store.getBranchIndex(task.id),\n\t\t\ttargetId: task.id,\n\t\t\tnextSibling: true\n\t\t});\n\n\t\ttask.$open = false;\n\t\ttask.$transparent = true;\n\t\tthis.refreshData();\n\t}, gantt));\n\n\tfunction getTargetTaskId(e){\n\t\tvar y = domHelpers.getRelativeEventPosition(e, grid.$grid_data).y;\n\t\tvar store = grid.$config.rowStore;\n\n\t\tif (!document.doctype){\n\t\t\ty += window.scrollY;\n\t\t}\n\t\ty = y || 0;\n\n\t\t// limits for the marker according to the layout layer\n\t\tvar scrollPos = grid.$state.scrollTop || 0;\n\t\tvar maxBottom = gantt.$grid_data.getBoundingClientRect().height + scrollPos + window.scrollY;\n\t\tvar minTop = scrollPos;\n\n\t\tvar firstVisibleTaskIndex = grid.getItemIndexByTopPosition(grid.$state.scrollTop);\n\t\tif (!store.exists(firstVisibleTaskIndex)){\n\t\t\tfirstVisibleTaskIndex = store.countVisible() - 1;\n\t\t}\n\t\tif (firstVisibleTaskIndex < 0) {\n\t\t\treturn store.$getRootId();\n\t\t}\n\n\t\tvar firstVisibleTaskId = store.getIdByIndex(firstVisibleTaskIndex);\n\n\t\tvar firstVisibleTaskPos = grid.$state.scrollTop / grid.getItemHeight(firstVisibleTaskId);\n\t\tvar hiddenTaskPart = firstVisibleTaskPos - Math.floor(firstVisibleTaskPos);\n\t\tif (hiddenTaskPart > 0.1 && hiddenTaskPart < 0.9) {\n\t\t\tmaxBottom = maxBottom - grid.getItemHeight(firstVisibleTaskId) * hiddenTaskPart;\n\t\t\tminTop = minTop + grid.getItemHeight(firstVisibleTaskId) * (1 - hiddenTaskPart);\n\t\t}\n\n\t\t// GS-715. The placeholder task row shouldn't be draggable below the Gantt container\n\t\tconst gridPosition = domHelpers.getNodePosition(grid.$grid_data);\n\t\tconst gridBottom = gridPosition.y + gridPosition.height;\n\t\tconst placeholderRowHeight = dnd.config.marker.offsetHeight;\n\t\tif (y + placeholderRowHeight + window.scrollY >= maxBottom){\n\t\t\tdnd.config.marker.style.top = gridBottom - placeholderRowHeight\t+ \"px\";\n\t\t}\n\n\t\tif (y >= maxBottom) {\n\t\t\ty = maxBottom;\n\t\t} else if (y <= minTop) {\n\t\t\ty = minTop;\n\t\t\tdnd.config.marker.style.top = gridPosition.y + \"px\";\n\t\t}\n\n\t\tvar index = grid.getItemIndexByTopPosition(y);\n\n\t\tif (index > store.countVisible() - 1 || index < 0) {\n\t\t\treturn store.$getRootId();\n\t\t}\n\n\t\tvar targetId = store.getIdByIndex(index);\n\t\tif (checkPlaceholderTask(targetId)) {\n\t\t\treturn store.getPrevSibling(targetId);\n\t\t}\n\n\t\treturn store.getIdByIndex(index);\n\t}\n\n\tfunction getDropPosition(e){\n\t\tvar targetTaskId = getTargetTaskId(e);\n\t\tvar relTargetPos = null;\n\t\tvar store = grid.$config.rowStore;\n\t\tvar config = grid.$getConfig();\n\t\tvar lockLevel = !config.order_branch_free;\n\n\t\tvar eventTop = domHelpers.getRelativeEventPosition(e, grid.$grid_data).y;\n\t\tif (!document.doctype){\n\t\t\teventTop += window.scrollY;\n\t\t}\n\n\t\tif(targetTaskId !== store.$getRootId()) {\n\t\t\tvar rowTop = grid.getItemTop(targetTaskId);\n\t\t\tvar rowHeight = grid.getItemHeight(targetTaskId);\n\t\t\trelTargetPos = (eventTop - rowTop) / rowHeight;\n\t\t}\n\n\t\tvar result;\n\t\tif(!lockLevel){\n\t\t\tresult = getMultiLevelTarget(dnd.config.id, targetTaskId, relTargetPos, eventTop, store);\n\t\t}else{\n\t\t\tresult = getLockedLevelTarget(dnd.config.id, targetTaskId, relTargetPos, eventTop, store, dnd.config.level);\n\t\t\tif(result && result.targetParent && checkPlaceholderTask(result.targetParent)){\n\t\t\t\ttargetTaskId = store.getPrevSibling(result.targetParent);\n\t\t\t\tresult = getLockedLevelTarget(dnd.config.id, targetTaskId, relTargetPos, eventTop, store, dnd.config.level);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tdnd.attachEvent(\"onDragMove\", gantt.bind(function (obj, e) {\n\t\tvar target = getDropPosition(e);\n\n\t\tif(!target ||\n\t\t\tgantt.callEvent(\"onBeforeRowDragMove\", [dnd.config.id, target.targetParent, target.targetIndex]) === false){\n\t\t\t\ttarget = dropTarget.createDropTargetObject(dnd.config.drop_target);\n\t\t\t}\n\n\t\thiglighter.highlightPosition(target, dnd.config, grid);\n\t\tdnd.config.drop_target = target;\n\t\tgantt._waiAria.reorderMarkerAttr(dnd.config.marker);\n\n\t\tthis.callEvent(\"onRowDragMove\", [dnd.config.id, target.targetParent, target.targetIndex]);\n\t\treturn true;\n\t}, gantt));\n\n\tdnd.attachEvent(\"onDragEnd\", gantt.bind(function () {\n\t\tvar store = grid.$config.rowStore;\n\t\tvar task = store.getItem(dnd.config.id);\n\n\t\thiglighter.removeLineHighlight(dnd.config);\n\n\t\ttask.$transparent = false;\n\t\ttask.$open = dnd.config.initial_open_state;\n\t\tvar target = dnd.config.drop_target;\n\n\t\tif (this.callEvent(\"onBeforeRowDragEnd\", [dnd.config.id, target.targetParent, target.targetIndex]) === false) {\n\t\t\ttask.$drop_target = null;\n\t\t} else {\n\t\t\tstore.move(dnd.config.id, target.targetIndex, target.targetParent);\n\t\t\tgantt.render();\n\t\t\tthis.callEvent(\"onRowDragEnd\", [dnd.config.id, target.targetParent, target.targetIndex]);\n\t\t}\n\t\tstore.refresh(task.id);\n\t}, gantt));\n}\n\nexport default {\n\tinit: _init_dnd\n};","/**\n * resolve dnd position of the task when gantt.config.order_branch_free = true\n */\n\nimport dropTarget from \"./drop_target\";\n\nexport default function getMultiLevelDropPosition(dndTaskId, targetTaskId, relTargetPos, eventTop, store){\n\tvar result;\n\n\tif(targetTaskId !== store.$getRootId()){\n\t\tif(relTargetPos < 0.25){\n\t\t\tresult = dropTarget.prevSiblingTarget(dndTaskId, targetTaskId, store);\n\t\t}else if(relTargetPos > 0.60 && !(store.hasChild(targetTaskId) && store.getItem(targetTaskId).$open)){\n\t\t\tresult = dropTarget.nextSiblingTarget(dndTaskId, targetTaskId, store);\n\t\t}else {\n\t\t\tresult = dropTarget.firstChildTarget(dndTaskId, targetTaskId, store);\n\t\t}\n\t}else{\n\t\tvar rootId = store.$getRootId();\n\t\tif(store.hasChild(rootId) && eventTop >= 0){\n\t\t\tresult = dropTarget.lastChildTarget(dndTaskId, rootId, store);\n\t\t}else{\n\t\t\tresult = dropTarget.firstChildTarget(dndTaskId, rootId, store);\n\t\t}\n\t}\n\n\treturn result;\n};","import * as utils from \"../../../utils/utils\";\nimport rowDnd from \"./tasks_grid_dnd\";\nimport rowDndMarker from \"./tasks_grid_dnd_marker\";\nimport mouseEventContainer from \"../mouse_event_container\";\n\nvar initializer = (function(){\n\treturn function(gantt){\n\t\treturn {\n\t\t\tonCreated: function (grid) {\n\t\t\t\tgrid.$config = utils.mixin(grid.$config, {\n\t\t\t\t\tbind: \"task\"\n\t\t\t\t});\n\t\t\t\tif(grid.$config.id == \"grid\") {\n\t\t\t\t\tthis.extendGantt(grid);\n\t\t\t\t\tgantt.ext.inlineEditors = gantt.ext._inlineEditors.createEditors(grid);\n\t\t\t\t\tgantt.ext.inlineEditors.init();\n\t\t\t\t}\n\n\t\t\t\tthis._mouseDelegates = mouseEventContainer(gantt);\n\t\t\t},\n\t\t\tonInitialized: function (grid) {\n\t\t\t\tvar config = grid.$getConfig();\n\t\t\t\tif (config.order_branch) {\n\t\t\t\t\tif(config.order_branch == \"marker\"){\n\t\t\t\t\t\trowDndMarker.init(grid.$gantt, grid);\n\t\t\t\t\t}else{\n\t\t\t\t\t\trowDnd.init(grid.$gantt, grid);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.initEvents(grid, gantt);\n\t\t\t\tif(grid.$config.id == \"grid\") {\n\t\t\t\t\tthis.extendDom(grid);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonDestroyed: function (grid) {\n\t\t\t\tif(grid.$config.id == \"grid\") {\n\t\t\t\t\t// GS-1288. We need to only detach the store and its events without detaching the\n\t\t\t\t\t// inline editor's events. Otherwise, we won't be able to access them\n\t\t\t\t\tgantt.ext.inlineEditors.detachStore();\n\t\t\t\t}\n\t\t\t\tthis.clearEvents(grid, gantt);\n\t\t\t},\n\n\t\t\tinitEvents: function (grid, gantt) {\n\t\t\t\tthis._mouseDelegates.delegate(\"click\", \"gantt_row\", gantt.bind(function (e, id, trg) {\n\t\t\t\t\tvar config = grid.$getConfig();\n\t\t\t\t\tif (id !== null) {\n\t\t\t\t\t\tvar task = this.getTask(id);\n\t\t\t\t\t\tif (config.scroll_on_click && !gantt._is_icon_open_click(e))\n\t\t\t\t\t\t\tthis.showDate(task.start_date);\n\t\t\t\t\t\tgantt.callEvent(\"onTaskRowClick\", [id, trg]);\n\t\t\t\t\t}\n\t\t\t\t}, gantt), grid.$grid);\n\n\t\t\t\tthis._mouseDelegates.delegate(\"click\", \"gantt_grid_head_cell\", gantt.bind(function (e, id, trg) {\n\t\t\t\t\tvar column = trg.getAttribute(\"data-column-id\");\n\n\t\t\t\t\tif (!gantt.callEvent(\"onGridHeaderClick\", [column, e]))\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tvar config = grid.$getConfig();\n\n\t\t\t\t\tif (column == \"add\") {\n\t\t\t\t\t\tvar mouseEvents = gantt.$services.getService(\"mouseEvents\");\n\t\t\t\t\t\tmouseEvents.callHandler(\"click\", \"gantt_add\", grid.$grid, [e, config.root_id]);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (config.sort && column) { // GS-929: if there is no column name, we cannot sort the column\n\t\t\t\t\t\tvar sorting_method = column,\n\t\t\t\t\t\t\tconf;\n\n\t\t\t\t\t\tfor (var i = 0; i < config.columns.length; i++) {\n\t\t\t\t\t\t\tif (config.columns[i].name == column) {\n\t\t\t\t\t\t\t\tconf = config.columns[i];\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (conf && conf.sort !== undefined && conf.sort !== true) {\n\t\t\t\t\t\t\tsorting_method = conf.sort;\n\n\t\t\t\t\t\t\tif (!sorting_method) { // column sort property 'false', no sorting\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar sort = (this._sort && this._sort.direction && this._sort.name == column) ? this._sort.direction : \"desc\";\n\t\t\t\t\t\t// invert sort direction\n\t\t\t\t\t\tsort = (sort == \"desc\") ? \"asc\" : \"desc\";\n\t\t\t\t\t\tthis._sort = {\n\t\t\t\t\t\t\tname: column,\n\t\t\t\t\t\t\tdirection: sort\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis.sort(sorting_method, sort == \"desc\");\n\t\t\t\t\t}\n\t\t\t\t}, gantt), grid.$grid);\n\n\t\t\t\tthis._mouseDelegates.delegate(\"click\", \"gantt_add\", gantt.bind(function (e, id, trg) {\n\t\t\t\t\tvar config = grid.$getConfig();\n\t\t\t\t\tif (config.readonly) return;\n\n\t\t\t\t\tvar item = {};\n\t\t\t\t\tthis.createTask(item, id ? id : gantt.config.root_id);\n\n\t\t\t\t\treturn false;\n\t\t\t\t}, gantt), grid.$grid);\n\n\t\t\t},\n\n\t\t\tclearEvents: function(grid, gantt){\n\t\t\t\tthis._mouseDelegates.destructor();\n\t\t\t\tthis._mouseDelegates = null;\n\t\t\t},\n\n\t\t\textendDom: function(grid){\n\t\t\t\tgantt.$grid = grid.$grid;\n\t\t\t\tgantt.$grid_scale = grid.$grid_scale;\n\t\t\t\tgantt.$grid_data = grid.$grid_data;\n\t\t\t},\n\t\t\textendGantt: function(grid){\n\t\t\t\tgantt.getGridColumns = gantt.bind(grid.getGridColumns, grid);\n\n\t\t\t\tgrid.attachEvent(\"onColumnResizeStart\", function(){\n\t\t\t\t\treturn gantt.callEvent(\"onColumnResizeStart\", arguments);\n\t\t\t\t});\n\t\t\t\tgrid.attachEvent(\"onColumnResize\", function(){\n\t\t\t\t\treturn gantt.callEvent(\"onColumnResize\", arguments);\n\t\t\t\t});\n\t\t\t\tgrid.attachEvent(\"onColumnResizeEnd\", function(){\n\t\t\t\t\treturn gantt.callEvent(\"onColumnResizeEnd\", arguments);\n\t\t\t\t});\n\n\t\t\t\tgrid.attachEvent(\"onColumnResizeComplete\", function(columns, totalWidth){\n\t\t\t\t\tgantt.config.grid_width = totalWidth;\n\t\t\t\t});\n\n\t\t\t\tgrid.attachEvent(\"onBeforeRowResize\", function(){\n\t\t\t\t\treturn gantt.callEvent(\"onBeforeRowResize\", arguments);\n\t\t\t\t});\n\t\t\t\tgrid.attachEvent(\"onRowResize\", function(){\n\t\t\t\t\treturn gantt.callEvent(\"onRowResize\", arguments);\n\t\t\t\t});\n\t\t\t\tgrid.attachEvent(\"onBeforeRowResizeEnd\", function(){\n\t\t\t\t\treturn gantt.callEvent(\"onBeforeRowResizeEnd\", arguments);\n\t\t\t\t});\n\t\t\t\tgrid.attachEvent(\"onAfterRowResize\", function(){\n\t\t\t\t\treturn gantt.callEvent(\"onAfterRowResize\", arguments);\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t};\n})();\n\nexport default initializer;","import * as domHelpers from \"../utils/dom_helpers\";\nimport * as utils from \"../../../utils/utils\";\nimport timeout from \"../../../utils/timeout\";\nimport * as helpers from \"../../../utils/helpers\";\n\nfunction createTaskDND(timeline, gantt) {\n\tvar services = gantt.$services;\n\treturn {\n\t\tdrag: null,\n\t\tdragMultiple: {},\n\t\t_events: {\n\t\t\tbefore_start: {},\n\t\t\tbefore_finish: {},\n\t\t\tafter_finish: {}\n\t\t},\n\t\t_handlers: {},\n\t\tinit: function() {\n\t\t\tthis._domEvents = gantt._createDomEventScope();\n\t\t\tthis.clear_drag_state();\n\t\t\tvar drag = gantt.config.drag_mode;\n\t\t\tthis.set_actions();\n\n\t\t\tvar stateService = services.getService(\"state\");\n\t\t\tstateService.registerProvider(\"tasksDnd\", utils.bind(function() {\n\t\t\t\treturn {\n\t\t\t\t\tdrag_id : this.drag ? this.drag.id : undefined,\n\t\t\t\t\tdrag_mode : this.drag ? this.drag.mode : undefined,\n\t\t\t\t\tdrag_from_start : this.drag ? this.drag.left : undefined\n\t\t\t\t};\n\t\t\t}, this));\n\n\t\t\tvar evs = {\n\t\t\t\t\"before_start\": \"onBeforeTaskDrag\",\n\t\t\t\t\"before_finish\": \"onBeforeTaskChanged\",\n\t\t\t\t\"after_finish\": \"onAfterTaskDrag\"\n\t\t\t};\n\t\t\t//for now, all drag operations will trigger the same events\n\t\t\tfor (var stage in this._events) {\n\t\t\t\tfor (var mode in drag) {\n\t\t\t\t\tthis._events[stage][mode] = evs[stage];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._handlers[drag.move] = this._move;\n\t\t\tthis._handlers[drag.resize] = this._resize;\n\t\t\tthis._handlers[drag.progress] = this._resize_progress;\n\t\t},\n\t\tset_actions: function() {\n\t\t\tvar data = timeline.$task_data;\n\t\t\tthis._domEvents.attach(data, \"mousemove\", gantt.bind(function(e) {\n\t\t\t\tthis.on_mouse_move(e);\n\t\t\t}, this));\n\t\t\tthis._domEvents.attach(data, \"mousedown\", gantt.bind(function(e) {\n\t\t\t\tthis.on_mouse_down(e);\n\t\t\t}, this));\n\t\t\tthis._domEvents.attach(document.body, \"mouseup\", gantt.bind(function(e) {\n\t\t\t\tthis.on_mouse_up(e);\n\t\t\t}, this));\n\t\t},\n\n\t\tclear_drag_state: function() {\n\t\t\tthis.drag = {\n\t\t\t\tid: null,\n\t\t\t\tmode: null,\n\t\t\t\tpos: null,\n\t\t\t\tstart_x: null,\n\t\t\t\tstart_y: null,\n\t\t\t\tobj: null,\n\t\t\t\tleft: null\n\t\t\t};\n\t\t\tthis.dragMultiple = {};\n\t\t},\n\t\t_resize: function(task, shift, drag) {\n\t\t\tvar cfg = timeline.$getConfig();\n\t\t\tvar coords_x = this._drag_task_coords(task, drag);\n\t\t\tif (drag.left) {\n\t\t\t\ttask.start_date = gantt.dateFromPos(coords_x.start + shift);\n\t\t\t\tif (!task.start_date) {\n\t\t\t\t\ttask.start_date = new Date(gantt.getState().min_date);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttask.end_date = gantt.dateFromPos(coords_x.end + shift);\n\t\t\t\tif (!task.end_date) {\n\t\t\t\t\ttask.end_date = new Date(gantt.getState().max_date);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar minDurationInUnits = this._calculateMinDuration(cfg.min_duration, cfg.duration_unit);\n\t\t\tif (task.end_date - task.start_date < cfg.min_duration) {\n\t\t\t\tif (drag.left)\n\t\t\t\t\ttask.start_date = gantt.calculateEndDate(task.end_date, -minDurationInUnits, cfg.duration_unit, task);\n\t\t\t\telse\n\t\t\t\t\ttask.end_date = gantt.calculateEndDate(task.start_date, minDurationInUnits, cfg.duration_unit, task);\n\t\t\t}\n\t\t\tgantt._init_task_timing(task);\n\t\t},\n\t\t_calculateMinDuration: function(duration, unit) {\n\t\t\tvar inMs = {\n\t\t\t\t\"minute\": 60000,\n\t\t\t\t\"hour\": 3600000,\n\t\t\t\t\"day\": 86400000,\n\t\t\t\t\"week\": 604800000,\n\t\t\t\t\"month\": 2419200000,\n\t\t\t\t\"year\": 31356000000\n\t\t\t};\n\t\t\treturn Math.ceil(duration / inMs[unit]);\n\t\t},\n\t\t_resize_progress: function(task, shift, drag) {\n\t\t\tvar coords_x = this._drag_task_coords(task, drag);\n\n\t\t\tvar config = timeline.$getConfig();\n\t\t\tvar diffValue = !config.rtl ? (drag.pos.x - coords_x.start) : (coords_x.start - drag.pos.x);\n\n\t\t\tvar diff = Math.max(0, diffValue);\n\t\t\ttask.progress = Math.min(1, diff / Math.abs(coords_x.end - coords_x.start));\n\t\t},\n\t\t_find_max_shift: function(dragItems, shift) {\n\t\t\tvar correctShift;\n\t\t\tfor (var i in dragItems) {\n\t\t\t\tvar drag = dragItems[i];\n\t\t\t\tvar task = gantt.getTask(drag.id);\n\n\t\t\t\tvar coords_x = this._drag_task_coords(task, drag);\n\t\t\t\tvar minX = gantt.posFromDate(new Date(gantt.getState().min_date));\n\t\t\t\tvar maxX = gantt.posFromDate(new Date(gantt.getState().max_date));\n\n\t\t\t\tif (coords_x.end + shift > maxX) {\n\t\t\t\t\tvar maxShift = maxX - coords_x.end;\n\t\t\t\t\tif (maxShift < correctShift || correctShift === undefined) {\n\t\t\t\t\t\tcorrectShift = maxShift;\n\t\t\t\t\t}\n\t\t\t\t} else if (coords_x.start + shift < minX) {\n\t\t\t\t\tvar minShift = minX - coords_x.start;\n\t\t\t\t\tif (minShift > correctShift || correctShift === undefined) {\n\t\t\t\t\t\tcorrectShift = minShift;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn correctShift;\n\t\t},\n\t\t_move: function(task, shift, drag, multipleDragShift) {\n\t\t\tvar coords_x = this._drag_task_coords(task, drag);\n\t\t\tvar new_start = null,\n\t\t\tnew_end = null;\n\t\t\t// GS-454: If we drag multiple tasks, rely on the dates instead of timeline coordinates\n\t\t\tif (multipleDragShift){\n\t\t\t\tnew_start = new Date(+drag.obj.start_date + multipleDragShift),\n\t\t\t\tnew_end = new Date(+drag.obj.end_date + multipleDragShift);\n\t\t\t} else {\n\t\t\t\tnew_start = gantt.dateFromPos(coords_x.start + shift),\n\t\t\t\tnew_end = gantt.dateFromPos(coords_x.end + shift);\n\t\t\t}\n\t\t\tif (!new_start) {\n\t\t\t\ttask.start_date = new Date(gantt.getState().min_date);\n\t\t\t\ttask.end_date = gantt.dateFromPos(gantt.posFromDate(task.start_date) + (coords_x.end - coords_x.start));\n\t\t\t} else if (!new_end) {\n\t\t\t\ttask.end_date = new Date(gantt.getState().max_date);\n\t\t\t\ttask.start_date = gantt.dateFromPos(gantt.posFromDate(task.end_date) - (coords_x.end - coords_x.start));\n\t\t\t} else {\n\t\t\t\ttask.start_date = new_start;\n\t\t\t\ttask.end_date = new_end;\n\t\t\t}\n\t\t},\n\t\t_drag_task_coords: function(t, drag) {\n\t\t\tvar start = drag.obj_s_x = drag.obj_s_x || gantt.posFromDate(t.start_date);\n\t\t\tvar end = drag.obj_e_x = drag.obj_e_x || gantt.posFromDate(t.end_date);\n\t\t\treturn {\n\t\t\t\tstart: start,\n\t\t\t\tend: end\n\t\t\t};\n\t\t},\n\t\t_mouse_position_change: function(oldPos, newPos) {\n\t\t\tvar dx = oldPos.x - newPos.x,\n\t\t\t\tdy = oldPos.y - newPos.y;\n\t\t\treturn Math.sqrt(dx * dx + dy * dy);\n\t\t},\n\t\t_is_number: function(n) {\n\t\t\treturn !isNaN(parseFloat(n)) && isFinite(n);\n\t\t},\n\n\t\ton_mouse_move: function(e) {\n\t\t\tif (this.drag.start_drag) {\n\t\t\t\tvar pos = domHelpers.getRelativeEventPosition(e, gantt.$task_data);\n\n\t\t\t\tvar sX = this.drag.start_drag.start_x,\n\t\t\t\t\tsY = this.drag.start_drag.start_y;\n\n\t\t\t\tif ((Date.now() - this.drag.timestamp > 50) ||\n\t\t\t\t\t(this._is_number(sX) && this._is_number(sY) && this._mouse_position_change({\n\t\t\t\t\t\tx: sX,\n\t\t\t\t\t\ty: sY\n\t\t\t\t\t}, pos) > 20)) {\n\t\t\t\t\tthis._start_dnd(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar drag = this.drag;\n\n\t\t\tif (drag.mode) {\n\t\t\t\tif (!timeout(this, 40))//limit update frequency\n\t\t\t\t\treturn;\n\n\t\t\t\tthis._update_on_move(e);\n\n\t\t\t}\n\t\t},\n\n\t\t_update_item_on_move: function(shift, id, mode, drag, e, multipleDragShift) {\n\t\t\tvar task = gantt.getTask(id);\n\t\t\tvar original = gantt.mixin({}, task);\n\t\t\tvar copy = gantt.mixin({}, task);\n\t\t\tthis._handlers[mode].apply(this, [copy, shift, drag, multipleDragShift]);\n\t\t\tgantt.mixin(task, copy, true);\n\t\t\t//gantt._update_parents(drag.id, true);\n\t\t\tgantt.callEvent(\"onTaskDrag\", [task.id, mode, copy, original, e]);\n\t\t\tgantt.mixin(task, copy, true);\n\t\t\tgantt.refreshTask(id);\n\t\t},\n\n\t\t_update_on_move: function(e) {\n\t\t\tvar drag = this.drag;\n\t\t\tvar config = timeline.$getConfig();\n\t\t\tif (drag.mode) {\n\t\t\t\tvar pos = domHelpers.getRelativeEventPosition(e, timeline.$task_data);\n\t\t\t\tif (drag.pos && drag.pos.x == pos.x)\n\t\t\t\t\treturn;\n\n\t\t\t\tdrag.pos = pos;\n\n\t\t\t\tvar curr_date = gantt.dateFromPos(pos.x);\n\t\t\t\tif (!curr_date || isNaN(curr_date.getTime()))\n\t\t\t\t\treturn;\n\n\n\t\t\t\tvar shift = pos.x - drag.start_x;\n\t\t\t\tvar task = gantt.getTask(drag.id);\n\t\t\t\tif (this._handlers[drag.mode]) {\n\t\t\t\t\tif (drag.mode === config.drag_mode.move) {\n\t\t\t\t\t\tvar dragHash = {};\n\n\t\t\t\t\t\tif (this._isMultiselect()) {\n\t\t\t\t\t\t\tvar selectedTasksIds = gantt.getSelectedTasks();\n\t\t\t\t\t\t\tif (selectedTasksIds.indexOf(drag.id) >= 0) {\n\t\t\t\t\t\t\t\tdragHash = this.dragMultiple;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar dragProject = false;\n\t\t\t\t\t\tif (gantt.isSummaryTask(task) && gantt.config.drag_project) {\n\t\t\t\t\t\t\tvar initialDrag = {};\n\t\t\t\t\t\t\tinitialDrag[drag.id] = utils.copy(drag);\n\t\t\t\t\t\t\tdragProject = true;\n\t\t\t\t\t\t\tdragHash = utils.mixin(initialDrag, this.dragMultiple);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar maxShift = this._find_max_shift(dragHash, shift);\n\t\t\t\t\t\tif (maxShift !== undefined) {\n\t\t\t\t\t\t\tshift = maxShift;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis._update_item_on_move(shift, drag.id, drag.mode, drag, e);\n\n\t\t\t\t\t\tfor (var i in dragHash) {\n\t\t\t\t\t\t\tvar childDrag = dragHash[i];\n\t\t\t\t\t\t\tif(dragProject && childDrag.id != drag.id){\n\t\t\t\t\t\t\t\tgantt._bulk_dnd = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// GS-454: Calculate the date shift in milliseconds instead of pixels\n\t\t\t\t\t\t\tif (maxShift === undefined && (dragProject || Object.keys(dragHash).length > 1)) {\n\t\t\t\t\t\t\t\tvar shiftDate = gantt.dateFromPos(drag.start_x);\n\t\t\t\t\t\t\t\tvar multipleDragShift = curr_date - shiftDate;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis._update_item_on_move(shift, childDrag.id, childDrag.mode, childDrag, e, multipleDragShift);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgantt._bulk_dnd = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// for resize and progress\n\t\t\t\t\t\tthis._update_item_on_move(shift, drag.id, drag.mode, drag, e);\n\t\t\t\t\t}\n\t\t\t\t\tgantt._update_parents(drag.id);\n\t\t\t\t}\n\n\t\t\t}\n\t\t},\n\n\t\ton_mouse_down: function(e, src) {\n\t\t\t// on Mac we do not get onmouseup event when clicking right mouse button leaving us in dnd state\n\t\t\t// let's ignore right mouse button then\n\t\t\tif (e.button == 2 && e.button !== undefined)\n\t\t\t\treturn;\n\n\t\t\tvar config = timeline.$getConfig();\n\t\t\tvar id = gantt.locate(e);\n\t\t\tvar task = null;\n\t\t\tif (gantt.isTaskExists(id)) {\n\t\t\t\ttask = gantt.getTask(id);\n\t\t\t}\n\n\t\t\tif (gantt.isReadonly(task) || this.drag.mode) return;\n\n\t\t\tthis.clear_drag_state();\n\n\t\t\tsrc = src || (e.target || e.srcElement);\n\n\t\t\tvar className = domHelpers.getClassName(src);\n\t\t\tvar drag = this._get_drag_mode(className, src);\n\n\t\t\tif (!className || !drag) {\n\t\t\t\tif (src.parentNode)\n\t\t\t\t\treturn this.on_mouse_down(e, src.parentNode);\n\t\t\t\telse\n\t\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!drag) {\n\t\t\t\tif (gantt.checkEvent(\"onMouseDown\") && gantt.callEvent(\"onMouseDown\", [className.split(\" \")[0]])) {\n\t\t\t\t\tif (src.parentNode)\n\t\t\t\t\t\treturn this.on_mouse_down(e, src.parentNode);\n\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (drag.mode && drag.mode != config.drag_mode.ignore && config[\"drag_\" + drag.mode]) {\n\t\t\t\t\tid = gantt.locate(src);\n\t\t\t\t\ttask = gantt.copy(gantt.getTask(id) || {});\n\n\t\t\t\t\tif (gantt.isReadonly(task)) {\n\t\t\t\t\t\tthis.clear_drag_state();\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ((gantt.isSummaryTask(task) && !(task.auto_scheduling === false) && !config.drag_project) && drag.mode != config.drag_mode.progress) {//only progress drag is allowed for tasks with flexible duration\n\t\t\t\t\t\tthis.clear_drag_state();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tdrag.id = id;\n\t\t\t\t\tvar pos = domHelpers.getRelativeEventPosition(e, gantt.$task_data);\n\n\t\t\t\t\tdrag.start_x = pos.x;\n\t\t\t\t\tdrag.start_y = pos.y;\n\t\t\t\t\tdrag.obj = task;\n\t\t\t\t\tthis.drag.start_drag = drag;\n\t\t\t\t\tthis.drag.timestamp = Date.now();\n\n\t\t\t\t} else\n\t\t\t\t\tthis.clear_drag_state();\n\t\t\t}\n\t\t},\n\t\t_fix_dnd_scale_time: function(task, drag) {\n\t\t\tvar config = timeline.$getConfig();\n\t\t\tvar unit = gantt.getScale().unit,\n\t\t\t\tstep = gantt.getScale().step;\n\t\t\tif (!config.round_dnd_dates) {\n\t\t\t\tunit = 'minute';\n\t\t\t\tstep = config.time_step;\n\t\t\t}\n\n\t\t\tfunction fixStart(task) {\n\t\t\t\tif (!gantt.config.correct_work_time)\n\t\t\t\t\treturn;\n\t\t\t\tvar config = timeline.$getConfig();\n\t\t\t\tif (!gantt.isWorkTime(task.start_date, undefined, task))\n\t\t\t\t\ttask.start_date = gantt.calculateEndDate({\n\t\t\t\t\t\tstart_date: task.start_date,\n\t\t\t\t\t\tduration: -1,\n\t\t\t\t\t\tunit: config.duration_unit,\n\t\t\t\t\t\ttask: task\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\tfunction fixEnd(task) {\n\t\t\t\tif (!gantt.config.correct_work_time)\n\t\t\t\t\treturn;\n\t\t\t\tvar config = timeline.$getConfig();\n\t\t\t\tif (!gantt.isWorkTime(new Date(task.end_date - 1), undefined, task))\n\t\t\t\t\ttask.end_date = gantt.calculateEndDate({\n\t\t\t\t\t\tstart_date: task.end_date,\n\t\t\t\t\t\tduration: 1,\n\t\t\t\t\t\tunit: config.duration_unit,\n\t\t\t\t\t\ttask: task\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (drag.mode == config.drag_mode.resize) {\n\t\t\t\tif (drag.left) {\n\t\t\t\t\ttask.start_date = gantt.roundDate({date: task.start_date, unit: unit, step: step});\n\t\t\t\t\tfixStart(task);\n\t\t\t\t} else {\n\t\t\t\t\ttask.end_date = gantt.roundDate({date: task.end_date, unit: unit, step: step});\n\t\t\t\t\tfixEnd(task);\n\t\t\t\t}\n\t\t\t} else if (drag.mode == config.drag_mode.move) {\n\t\t\t\ttask.start_date = gantt.roundDate({date: task.start_date, unit: unit, step: step});\n\t\t\t\tfixStart(task);\n\t\t\t\ttask.end_date = gantt.calculateEndDate(task);\n\t\t\t}\n\t\t},\n\t\t_fix_working_times: function(task, drag) {\n\t\t\tvar config = timeline.$getConfig();\n\t\t\tvar drag = drag || {mode: config.drag_mode.move};\n\n\t\t\tif (drag.mode == config.drag_mode.resize) {\n\t\t\t\tif (drag.left) {\n\t\t\t\t\ttask.start_date = gantt.getClosestWorkTime({date: task.start_date, dir: 'future', task: task});\n\t\t\t\t} else {\n\t\t\t\t\ttask.end_date = gantt.getClosestWorkTime({date: task.end_date, dir: 'past', task: task});\n\t\t\t\t}\n\t\t\t} else if (drag.mode == config.drag_mode.move) {\n\t\t\t\tgantt.correctTaskWorkTime(task);\n\t\t\t}\n\t\t},\n\n\t\t_finalize_mouse_up: function(taskId, config, drag, e) {\n\t\t\tvar task = gantt.getTask(taskId);\n\n\t\t\tif (config.work_time && config.correct_work_time) {\n\t\t\t\tthis._fix_working_times(task, drag);\n\t\t\t}\n\n\t\t\tthis._fix_dnd_scale_time(task, drag);\n\n\t\t\tif (!this._fireEvent(\"before_finish\", drag.mode, [taskId, drag.mode, gantt.copy(drag.obj), e])) {\n\t\t\t\t//drag.obj._dhx_changed = false;\n\t\t\t\tthis.clear_drag_state();\n\t\t\t\tif (taskId == drag.id) {\n\t\t\t\t\tdrag.obj._dhx_changed = false;\n\t\t\t\t\tgantt.mixin(task, drag.obj, true);\n\t\t\t\t}\n\n\n\t\t\t\tgantt.refreshTask(task.id);\n\t\t\t} else {\n\t\t\t\tvar drag_id = taskId;\n\n\t\t\t\tgantt._init_task_timing(task);\n\n\t\t\t\tthis.clear_drag_state();\n\t\t\t\tgantt.updateTask(task.id);\n\t\t\t\tthis._fireEvent(\"after_finish\", drag.mode, [drag_id, drag.mode, e]);\n\t\t\t}\n\n\t\t},\n\n\t\ton_mouse_up: function(e) {\n\n\t\t\tvar drag = this.drag;\n\t\t\tif (drag.mode && drag.id) {\n\t\t\t\tvar config = timeline.$getConfig();\n\t\t\t\t//drop\n\t\t\t\tvar task = gantt.getTask(drag.id);\n\t\t\t\tvar dragMultiple = this.dragMultiple;\n\n\t\t\t\tvar finalizingBulkMove = false;\n\t\t\t\tvar moveCount = 0;\n\t\t\t\tif (drag.mode === config.drag_mode.move) {\n\t\t\t\t\tif ((gantt.isSummaryTask(task) && config.drag_project) || (this._isMultiselect())) {\n\t\t\t\t\t\tfinalizingBulkMove = true;\n\t\t\t\t\t\tmoveCount = Object.keys(dragMultiple).length;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar doFinalize = function doFinalize(){\n\t\t\t\t\tif(finalizingBulkMove){\n\t\t\t\t\t\tfor (var i in dragMultiple) {\n\t\t\t\t\t\t\t// GS-1057: Don't call drag events for the dragged task as they will be called later\n\t\t\t\t\t\t\tif (dragMultiple[i].id != drag.id){\n\t\t\t\t\t\t\t\tthis._finalize_mouse_up(dragMultiple[i].id, config, dragMultiple[i], e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._finalize_mouse_up(drag.id, config, drag, e);\n\n\t\t\t\t};\n\n\t\t\t\tif(finalizingBulkMove && moveCount > 10){// 10 - arbitrary threshold for bulk dnd at which we start doing complete repaint to refresh\n\t\t\t\t\tgantt.batchUpdate(function(){\n\t\t\t\t\t\tdoFinalize.call(this);\n\t\t\t\t\t}.bind(this));\n\t\t\t\t}else{\n\t\t\t\t\tdoFinalize.call(this);\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tthis.clear_drag_state();\n\t\t},\n\t\t_get_drag_mode: function(className, el) {\n\t\t\tvar config = timeline.$getConfig();\n\t\t\tvar modes = config.drag_mode;\n\t\t\tvar classes = (className || \"\").split(\" \");\n\t\t\tvar classname = classes[0];\n\t\t\tvar drag = {mode: null, left: null};\n\t\t\tswitch (classname) {\n\t\t\t\tcase \"gantt_task_line\":\n\t\t\t\tcase \"gantt_task_content\":\n\t\t\t\t\tdrag.mode = modes.move;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"gantt_task_drag\":\n\t\t\t\t\tdrag.mode = modes.resize;\n\n\t\t\t\t\tvar dragProperty = el.getAttribute(\"data-bind-property\");\n\n\t\t\t\t\tif (dragProperty == \"start_date\") {\n\t\t\t\t\t\tdrag.left = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdrag.left = false;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"gantt_task_progress_drag\":\n\t\t\t\t\tdrag.mode = modes.progress;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"gantt_link_control\":\n\t\t\t\tcase \"gantt_link_point\":\n\t\t\t\t\tdrag.mode = modes.ignore;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdrag = null;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn drag;\n\n\t\t},\n\n\t\t_start_dnd: function(e) {\n\t\t\tvar drag = this.drag = this.drag.start_drag;\n\t\t\tdelete drag.start_drag;\n\n\t\t\tvar cfg = timeline.$getConfig();\n\t\t\tvar id = drag.id;\n\n\t\t\tif (!cfg[\"drag_\" + drag.mode] || !gantt.callEvent(\"onBeforeDrag\", [id, drag.mode, e]) || !this._fireEvent(\"before_start\", drag.mode, [id, drag.mode, e])) {\n\t\t\t\tthis.clear_drag_state();\n\t\t\t} else {\n\t\t\t\tdelete drag.start_drag;\n\t\t\t\tvar task = gantt.getTask(id);\n\t\t\t\tif (gantt.isReadonly(task)){\n\t\t\t\t\tthis.clear_drag_state();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (this._isMultiselect()) {\n\t\t\t\t\t// for don't move selected tasks when drag unselected task\n\t\t\t\t\tvar selectedTasksIds = gantt.getSelectedTasks();\n\t\t\t\t\tif (selectedTasksIds.indexOf(drag.id) >= 0) {\n\t\t\t\t\t\thelpers.forEach(selectedTasksIds, gantt.bind(function(taskId) {\n\t\t\t\t\t\t\tvar selectedTask = gantt.getTask(taskId);\n\t\t\t\t\t\t\tif (gantt.isSummaryTask(selectedTask) && gantt.config.drag_project && drag.mode == cfg.drag_mode.move) {\n\t\t\t\t\t\t\t\tthis._addSubtasksToDragMultiple(selectedTask.id);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.dragMultiple[taskId] = gantt.mixin({\n\t\t\t\t\t\t\t\tid: selectedTask.id,\n\t\t\t\t\t\t\t\tobj: gantt.copy(selectedTask)\n\t\t\t\t\t\t\t}, this.drag);\n\t\t\t\t\t\t}, this));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// for move unselected summary\n\t\t\t\tif (gantt.isSummaryTask(task) && gantt.config.drag_project && drag.mode == cfg.drag_mode.move) {\n\t\t\t\t\tthis._addSubtasksToDragMultiple(task.id);\n\t\t\t\t}\n\t\t\t\tgantt.callEvent(\"onTaskDragStart\", []);\n\t\t\t}\n\n\t\t},\n\t\t_fireEvent: function(stage, mode, params) {\n\t\t\tgantt.assert(this._events[stage], \"Invalid stage:{\" + stage + \"}\");\n\n\t\t\tvar trigger = this._events[stage][mode];\n\n\t\t\tgantt.assert(trigger, \"Unknown after drop mode:{\" + mode + \"}\");\n\t\t\tgantt.assert(params, \"Invalid event arguments\");\n\n\n\t\t\tif (!gantt.checkEvent(trigger))\n\t\t\t\treturn true;\n\n\t\t\treturn gantt.callEvent(trigger, params);\n\t\t},\n\n\t\tround_task_dates: function(task) {\n\t\t\tvar drag_state = this.drag;\n\t\t\tvar config = timeline.$getConfig();\n\t\t\tif (!drag_state) {\n\t\t\t\tdrag_state = {mode: config.drag_mode.move};\n\t\t\t}\n\t\t\tthis._fix_dnd_scale_time(task, drag_state);\n\t\t},\n\t\tdestructor: function() {\n\t\t\tthis._domEvents.detachAll();\n\t\t},\n\t\t_isMultiselect: function() {\n\t\t\treturn gantt.config.drag_multiple && !!(gantt.getSelectedTasks && gantt.getSelectedTasks().length > 0);\n\t\t},\n\t\t_addSubtasksToDragMultiple: function(summaryId) {\n\t\t\tgantt.eachTask(function(child) {\n\t\t\t\tthis.dragMultiple[child.id] = gantt.mixin({\n\t\t\t\t\tid: child.id,\n\t\t\t\t\tobj: gantt.copy(child)\n\t\t\t\t}, this.drag);\n\t\t\t}, summaryId, this);\n\t\t}\n\t};\n}\n\nfunction initTaskDND() {\n\tvar _tasks_dnd;\n\treturn {\n\t\textend: function(timeline) {\n\t\t\ttimeline.roundTaskDates = function(task) {\n\t\t\t\t_tasks_dnd.round_task_dates(task);\n\t\t\t};\n\n\t\t},\n\t\tinit: function(timeline, gantt) {\n\t\t\t_tasks_dnd = createTaskDND(timeline, gantt);\n\t\t\t// TODO: entry point for touch handlers, move touch to timeline\n\t\t\ttimeline._tasks_dnd = _tasks_dnd;\n\t\t\treturn _tasks_dnd.init(gantt);\n\t\t},\n\t\tdestructor: function() {\n\t\t\tif (_tasks_dnd) {\n\t\t\t\t_tasks_dnd.destructor();\n\t\t\t\t_tasks_dnd = null;\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport default {\n\tcreateTaskDND: initTaskDND\n};","import * as domHelpers from \"../utils/dom_helpers\";\n\nvar initLinksDND = function(timeline, gantt) {\n\tvar _link_landing,\n\t\t_link_target_task,\n\t\t_link_target_task_start,\n\t\t_link_source_task,\n\t\t_link_source_task_start,\n\t\tmarkerDefaultOffset = 10,\n\t\tscrollDefaultSize = 18;\n\n\tfunction getDndState(){\n\t\treturn {\n\t\t\tlink_source_id : _link_source_task,\n\t\t\tlink_target_id : _link_target_task,\n\t\t\tlink_from_start : _link_source_task_start,\n\t\t\tlink_to_start : _link_target_task_start,\n\t\t\tlink_landing_area : _link_landing\n\t\t};\n\t}\n\n\tvar services = gantt.$services;\n\n\tvar state = services.getService(\"state\");\n\tvar DnD = services.getService(\"dnd\");\n\n\tstate.registerProvider(\"linksDnD\", getDndState);\n\n\tvar start_marker = \"task_start_date\",\n\t\tend_marker = \"task_end_date\",\n\t\tlink_edge_marker = \"gantt_link_point\",\n\t\tlink_landing_hover_area = \"gantt_link_control\";\n\n\tvar dnd = new DnD(timeline.$task_bars, {\n\t\tsensitivity : 0,\n\t\tupdates_per_second : 60,\n\t\tmousemoveContainer: gantt.$root,\n\t\tselector: \".\" + link_edge_marker,\n\t\tpreventDefault: true\n\t});\n\n\tdnd.attachEvent(\"onBeforeDragStart\", gantt.bind(function(obj,e) {\n\t\tvar target = (e.target||e.srcElement);\n\t\tresetDndState();\n\t\tif(gantt.getState(\"tasksDnd\").drag_id)\n\t\t\treturn false;\n\n\t\tif(domHelpers.locateClassName(target, link_edge_marker)){\n\t\t\tif(domHelpers.locateClassName(target, start_marker))\n\t\t\t\t_link_source_task_start = true;\n\n\t\t\tvar sid = gantt.locate(e);\n\t\t\t_link_source_task = sid;\n\n\t\t\tvar t = gantt.getTask(sid);\n\t\t\tif(gantt.isReadonly(t)){\n\t\t\t\tresetDndState();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._dir_start = {\n\t\t\t\tx: dnd.config.original_element_sizes.x + dnd.config.original_element_sizes.width/2,\n\t\t\t\ty: dnd.config.original_element_sizes.y + dnd.config.original_element_sizes.height/2\n\t\t\t};\n\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\n\t}, this));\n\n\tdnd.attachEvent(\"onAfterDragStart\", gantt.bind(function(obj,e) {\n\t\tif(gantt.config.touch) {\n\t\t\tgantt.refreshData();\n\t\t}\n\t\tupdateMarkedHtml(dnd.config.marker);\n\t}, this));\n\n\tfunction getVieportSize(){\n\t\tvar root = gantt.$root;\n\t\treturn { right: root.offsetWidth, bottom: root.offsetHeight };\n\t}\n\tfunction getMarkerSize (marker){\n\t\tvar width = 0, height = 0;\n\t\tif(marker){\n\t\t\twidth = marker.offsetWidth || 0;\n\t\t\theight = marker.offsetHeight || 0;\n\t\t}\n\t\treturn { width: width, height: height };\n\t}\n\n\tfunction getPosition(e, marker){\n\t\tvar oldPos = dnd.getPosition(e);\n\n\t\tvar markerSize = getMarkerSize(marker);\n\t\tvar viewportSize = getVieportSize();\n\n\t\tvar offsetX = gantt.config.tooltip_offset_x || markerDefaultOffset;\n\t\tvar offsetY = gantt.config.tooltip_offset_y || markerDefaultOffset;\n\n\t\tvar scrollSize = gantt.config.scroll_size || scrollDefaultSize;\n\n\t\t// GS-1315: Add offset if there are elements above Gantt\n\t\tvar ganttOffsetY = gantt.$container.getBoundingClientRect().y + window.scrollY;\n\n\t\tvar position = {\n\t\t\ty: oldPos.y + offsetY,\n\t\t\tx: oldPos.x + offsetX,\n\t\t\tbottom: oldPos.y + markerSize.height + offsetY + scrollSize,\n\t\t\tright: oldPos.x + markerSize.width + offsetX + scrollSize\n\t\t};\n\n\t\tif(position.bottom > viewportSize.bottom + ganttOffsetY){\n\t\t\tposition.y = viewportSize.bottom + ganttOffsetY - markerSize.height - offsetY;\n\t\t}\n\n\t\tif(position.right > viewportSize.right){\n\t\t\tposition.x = viewportSize.right - markerSize.width - offsetX;\n\t\t}\n\t\treturn position;\n\t}\n\n\tdnd.attachEvent(\"onDragMove\", gantt.bind(function(obj,e) {\n\t\tvar dd = dnd.config;\n\t\tvar pos = getPosition(e, dd.marker);\n\t\tadvanceMarker(dd.marker, pos);\n\t\tvar landing = !!domHelpers.locateClassName(e, link_landing_hover_area);\n\n\t\tvar prevTarget = _link_target_task;\n\t\tvar prevLanding = _link_landing;\n\t\tvar prevToStart = _link_target_task_start;\n\n\t\tvar targ = gantt.locate(e),\n\t\t\tto_start = true;\n\n\t\t// can drag and drop link to another gantt on the page, such links are not supported\n\t\tvar eventTarget = domHelpers.getTargetNode(e);\n\n\t\tvar sameGantt = domHelpers.isChildOf(eventTarget, gantt.$root);\n\t\tif(!sameGantt){\n\t\t\tlanding = false;\n\t\t\ttarg = null;\n\t\t}\n\n\t\tif(landing){\n\t\t\t//refreshTask\n\t\t\tto_start = !domHelpers.locateClassName(e, end_marker);\n\t\t\tlanding = !!targ;\n\t\t}\n\n\t\t_link_target_task = targ;\n\t\t_link_landing = landing;\n\t\t_link_target_task_start = to_start;\n\n\t\tif(landing){\n\n\t\t\tvar node = domHelpers.locateClassName(e, link_landing_hover_area);\n\t\t\n\t\t\tconst point = node.querySelector(`.${link_edge_marker}`);\n\t\t\tif(point){\n\t\t\t\tconst absCoords = domHelpers.getRelativeNodePosition(point, timeline.$task_bg);\n\t\t\t\tthis._dir_end = {\n\t\t\t\t\tx: absCoords.x + point.offsetWidth/2,\n\t\t\t\t\ty: absCoords.y + point.offsetHeight/2\n\t\t\t\t};\n\t\t\t}\n\n\t\t}else{\n\t\t\tthis._dir_end = domHelpers.getRelativeEventPosition(e, timeline.$task_data);\n\t\t\tif(gantt.env.isEdge){ // to fix margin collapsing\n\t\t\t\tthis._dir_end.y += window.scrollY;\n\t\t\t}\n\t\t}\n\n\t\tvar targetChanged = !(prevLanding == landing && prevTarget == targ && prevToStart == to_start);\n\t\tif(targetChanged){\n\t\t\tif(prevTarget)\n\t\t\t\tgantt.refreshTask(prevTarget, false);\n\t\t\tif(targ)\n\t\t\t\tgantt.refreshTask(targ, false);\n\t\t}\n\n\t\tif(targetChanged){\n\t\t\tupdateMarkedHtml(dd.marker);\n\t\t}\n\n\t\tshowDirectingLine(this._dir_start.x, this._dir_start.y, this._dir_end.x, this._dir_end.y);\n\n\t\treturn true;\n\t}, this));\n\n\n\tdnd.attachEvent(\"onDragEnd\", gantt.bind(function() {\n\t\tvar drag = getDndState();\n\n\t\tif(drag.link_source_id && drag.link_target_id && drag.link_source_id != drag.link_target_id){\n\t\t\tvar type = gantt._get_link_type(drag.link_from_start, drag.link_to_start);\n\n\t\t\tvar link = {source : drag.link_source_id, target: drag.link_target_id, type:type};\n\t\t\tif(link.type && gantt.isLinkAllowed(link)) {\n\t\t\t\tif(gantt.callEvent(\"onLinkCreated\", [link])){\n\t\t\t\t\tgantt.addLink(link);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tresetDndState();\n\n\t\tif(gantt.config.touch) {\n\t\t\tgantt.refreshData();\n\t\t}\n\t\telse {\n\t\t\tif (drag.link_source_id)\n\t\t\t\tgantt.refreshTask(drag.link_source_id, false);\n\t\t\tif (drag.link_target_id)\n\t\t\t\tgantt.refreshTask(drag.link_target_id, false);\n\t\t}\n\t\tremoveDirectionLine();\n\t}, this));\n\n\tfunction updateMarkedHtml(marker){\n\t\tvar link = getDndState();\n\n\t\tvar css = [\"gantt_link_tooltip\"];\n\t\tif(link.link_source_id && link.link_target_id){\n\t\t\tif(gantt.isLinkAllowed(link.link_source_id, link.link_target_id, link.link_from_start, link.link_to_start)){\n\t\t\t\tcss.push(\"gantt_allowed_link\");\n\t\t\t}else{\n\t\t\t\tcss.push(\"gantt_invalid_link\");\n\t\t\t}\n\t\t}\n\n\t\tvar className = gantt.templates.drag_link_class(link.link_source_id, link.link_from_start, link.link_target_id, link.link_to_start);\n\t\tif(className)\n\t\t\tcss.push(className);\n\n\t\tvar html = \"
\" +\n\t\t\tgantt.templates.drag_link(link.link_source_id, link.link_from_start, link.link_target_id, link.link_to_start) +\n\t\t\t\"
\";\n\t\tmarker.innerHTML = html;\n\t}\n\n\tfunction advanceMarker(marker, pos){\n\t\tmarker.style.left = pos.x + \"px\";\n\t\tmarker.style.top = pos.y + \"px\";\n\t}\n\n\tfunction resetDndState(){\n\t\t_link_source_task =\n\t\t\t_link_source_task_start =\n\t\t\t\t_link_target_task = null;\n\t\t_link_target_task_start = true;\n\t}\n\tfunction showDirectingLine(s_x, s_y, e_x, e_y){\n\t\tvar div = getDirectionLine();\n\n\t\tvar link = getDndState();\n\n\t\tvar css = [\"gantt_link_direction\"];\n\t\tif(gantt.templates.link_direction_class){\n\t\t\tcss.push(gantt.templates.link_direction_class(link.link_source_id, link.link_from_start, link.link_target_id, link.link_to_start));\n\t\t}\n\n\t\tvar dist =Math.sqrt( (Math.pow(e_x - s_x, 2)) + (Math.pow(e_y - s_y, 2)) );\n\t\tdist = Math.max(0, dist - 3);\n\t\tif(!dist)\n\t\t\treturn;\n\n\t\tdiv.className = css.join(\" \");\n\t\tvar tan = (e_y - s_y)/(e_x - s_x),\n\t\t\tangle = Math.atan(tan);\n\n\t\tif(coordinateCircleQuarter(s_x, e_x, s_y, e_y) == 2){\n\t\t\tangle += Math.PI;\n\t\t}else if(coordinateCircleQuarter(s_x, e_x, s_y, e_y) == 3){\n\t\t\tangle -= Math.PI;\n\t\t}\n\n\n\n\t\tvar sin = Math.sin(angle),\n\t\t\tcos = Math.cos(angle),\n\t\t\ttop = Math.round(s_y),\n\t\t\tleft = Math.round(s_x);\n\n\n\t\tvar style = [\n\t\t\t\"-webkit-transform: rotate(\"+angle+\"rad)\",\n\t\t\t\"-moz-transform: rotate(\"+angle+\"rad)\",\n\t\t\t\"-ms-transform: rotate(\"+angle+\"rad)\",\n\t\t\t\"-o-transform: rotate(\"+angle+\"rad)\",\n\t\t\t\"transform: rotate(\"+angle+\"rad)\",\n\t\t\t\"width:\" + Math.round(dist) + \"px\"\n\t\t];\n\n\t\tif(window.navigator.userAgent.indexOf(\"MSIE 8.0\") != -1){\n\t\t\t//ms-filter breaks styles in ie9, so add it only for 8th\n\t\t\tstyle.push(\"-ms-filter: \\\"\" + ieTransform(sin, cos) + \"\\\"\");\n\n\t\t\tvar shiftLeft = Math.abs(Math.round(s_x - e_x)),\n\t\t\t\tshiftTop = Math.abs(Math.round(e_y - s_y));\n\t\t\t//fix rotation axis\n\t\t\tswitch(coordinateCircleQuarter(s_x, e_x, s_y, e_y)){\n\t\t\t\tcase 1:\n\t\t\t\t\ttop -= shiftTop;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tleft -= shiftLeft;\n\t\t\t\t\ttop -= shiftTop;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tleft -= shiftLeft;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t}\n\n\t\tstyle.push(\"top:\" + top + \"px\");\n\t\tstyle.push(\"left:\" + left + \"px\");\n\n\t\tdiv.style.cssText = style.join(\";\");\n\t}\n\n\tfunction ieTransform(sin, cos){\n\t\treturn \"progid:DXImageTransform.Microsoft.Matrix(\"+\n\t\t\t\"M11 = \"+cos+\",\"+\n\t\t\t\"M12 = -\"+sin+\",\"+\n\t\t\t\"M21 = \"+sin+\",\"+\n\t\t\t\"M22 = \"+cos+\",\"+\n\t\t\t\"SizingMethod = 'auto expand'\"+\n\t\t\")\";\n\t}\n\tfunction coordinateCircleQuarter(sX, eX, sY, eY){\n\t\tif(eX >= sX){\n\t\t\tif(eY <= sY){\n\t\t\t\treturn 1;\n\t\t\t}else{\n\t\t\t\treturn 4;\n\t\t\t}\n\t\t}else{\n\t\t\tif(eY <= sY){\n\t\t\t\treturn 2;\n\t\t\t}else{\n\t\t\t\treturn 3;\n\t\t\t}\n\t\t}\n\n\t}\n\tfunction getDirectionLine(){\n\t\tif(!dnd._direction || !dnd._direction.parentNode){\n\t\t\tdnd._direction = document.createElement(\"div\");\n\t\t\ttimeline.$task_links.appendChild(dnd._direction);\n\t\t}\n\t\treturn dnd._direction;\n\t}\n\tfunction removeDirectionLine(){\n\t\tif(dnd._direction){\n\t\t\tif (dnd._direction.parentNode)\t//the event line can be detached because of data refresh\n\t\t\t\tdnd._direction.parentNode.removeChild(dnd._direction);\n\n\t\t\tdnd._direction = null;\n\t\t}\n\t}\n\tgantt.attachEvent(\"onGanttRender\", gantt.bind(function() {\n\t\tif(dnd._direction){\n\t\t\tshowDirectingLine(this._dir_start.x, this._dir_start.y, this._dir_end.x, this._dir_end.y);\n\t\t}\n\t}, this));\n};\n\nexport default {\n\tcreateLinkDND: function(){\n\t\treturn {\n\t\t\tinit: initLinksDND\n\t\t};\n\t}\n};","import * as utils from \"../../../utils/utils\";\nimport taskDnD from \"./tasks_dnd\";\nimport linkDnD from \"./links_dnd\";\nimport * as domHelpers from \"../utils/dom_helpers\";\nimport MouseDelegates from \"../mouse_event_container\";\n\nvar initializer = (function(){\n\treturn function(gantt){\n\t\tvar services = gantt.$services;\n\t\treturn {\n\t\t\tonCreated: function (timeline) {\n\t\t\t\tvar config = timeline.$config;\n\t\t\t\tconfig.bind = utils.defined(config.bind) ? config.bind : \"task\";\n\t\t\t\tconfig.bindLinks = utils.defined(config.bindLinks) ? config.bindLinks : \"link\";\n\n\t\t\t\ttimeline._linksDnD = linkDnD.createLinkDND();\n\t\t\t\ttimeline._tasksDnD = taskDnD.createTaskDND();\n\t\t\t\ttimeline._tasksDnD.extend(timeline);\n\n\t\t\t\tthis._mouseDelegates = MouseDelegates(gantt);\n\t\t\t},\n\t\t\tonInitialized: function (timeline) {\n\t\t\t\tthis._attachDomEvents(gantt);\n\n\t\t\t\tthis._attachStateProvider(gantt, timeline);\n\n\t\t\t\ttimeline._tasksDnD.init(timeline, gantt);\n\t\t\t\ttimeline._linksDnD.init(timeline, gantt);\n\n\t\t\t\tif(timeline.$config.id == \"timeline\"){\n\t\t\t\t\tthis.extendDom(timeline);\n\t\t\t\t}\n\n\t\t\t},\n\t\t\tonDestroyed: function (timeline) {\n\t\t\t\tthis._clearDomEvents(gantt);\n\t\t\t\tthis._clearStateProvider(gantt);\n\t\t\t\tif (timeline._tasksDnD) {\n\t\t\t\t\ttimeline._tasksDnD.destructor();\n\t\t\t\t}\n\t\t\t},\n\t\t\textendDom: function(timeline){\n\t\t\t\tgantt.$task = timeline.$task;\n\t\t\t\tgantt.$task_scale = timeline.$task_scale;\n\t\t\t\tgantt.$task_data = timeline.$task_data;\n\t\t\t\tgantt.$task_bg = timeline.$task_bg;\n\t\t\t\tgantt.$task_links = timeline.$task_links;\n\t\t\t\tgantt.$task_bars = timeline.$task_bars;\n\t\t\t},\n\n\t\t\t_clearDomEvents: function(){\n\t\t\t\tthis._mouseDelegates.destructor();\n\t\t\t\tthis._mouseDelegates = null;\n\t\t\t},\n\n\t\t\t_attachDomEvents: function(gantt){\n\t\t\t\tfunction _delete_link_handler(id, e) {\n\t\t\t\t\tif (id && this.callEvent(\"onLinkDblClick\", [id, e])) {\n\n\t\t\t\t\t\tvar link = this.getLink(id);\n\t\t\t\t\t\tif (this.isReadonly(link)) return;\n\n\t\t\t\t\t\tvar title = \"\";\n\t\t\t\t\t\tvar question = this.locale.labels.link + \" \" + this.templates.link_description(this.getLink(id)) + \" \" + this.locale.labels.confirm_link_deleting;\n\n\t\t\t\t\t\twindow.setTimeout(function () {\n\t\t\t\t\t\t\tgantt._simple_confirm(question, title, function () {\n\t\t\t\t\t\t\t\tgantt.deleteLink(id);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}, (this.config.touch ? 300 : 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis._mouseDelegates.delegate(\"click\", \"gantt_task_link\", gantt.bind(function (e, trg) {\n\t\t\t\t\tvar id = this.locate(e, this.config.link_attribute);\n\t\t\t\t\tif (id) {\n\t\t\t\t\t\tthis.callEvent(\"onLinkClick\", [id, e]);\n\t\t\t\t\t}\n\t\t\t\t}, gantt), this.$task);\n\n\t\t\t\tthis._mouseDelegates.delegate(\"click\", \"gantt_scale_cell\", gantt.bind(function (e, trg) {\n\t\t\t\t\tvar pos = domHelpers.getRelativeEventPosition(e, gantt.$task_data);\n\t\t\t\t\tvar date = gantt.dateFromPos(pos.x);\n\t\t\t\t\tvar coll = Math.floor(gantt.columnIndexByDate(date));\n\n\t\t\t\t\tvar coll_date = gantt.getScale().trace_x[coll];\n\n\t\t\t\t\tgantt.callEvent(\"onScaleClick\", [e, coll_date]);\n\t\t\t\t}, gantt), this.$task);\n\n\t\t\t\tthis._mouseDelegates.delegate(\"doubleclick\", \"gantt_task_link\", gantt.bind(function (e, id, trg) {\n\t\t\t\t\tvar id = this.locate(e, gantt.config.link_attribute);\n\t\t\t\t\t_delete_link_handler.call(this, id, e);\n\t\t\t\t}, gantt), this.$task);\n\n\t\t\t\tthis._mouseDelegates.delegate(\"doubleclick\", \"gantt_link_point\", gantt.bind(function (e, id, trg) {\n\t\t\t\t\tvar id = this.locate(e),\n\t\t\t\t\t\ttask = this.getTask(id);\n\n\t\t\t\t\tvar link = null;\n\t\t\t\t\tif (trg.parentNode && domHelpers.getClassName(trg.parentNode)) {\n\t\t\t\t\t\tif (domHelpers.getClassName(trg.parentNode).indexOf(\"_left\") > -1) {\n\t\t\t\t\t\t\tlink = task.$target[0];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlink = task.$source[0];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (link)\n\t\t\t\t\t\t_delete_link_handler.call(this, link, e);\n\t\t\t\t\treturn false;\n\t\t\t\t}, gantt), this.$task);\n\t\t\t},\n\n\t\t\t_attachStateProvider: function(gantt, timeline){\n\t\t\t\tvar self = timeline;\n\t\t\t\tvar state = services.getService(\"state\");\n\t\t\t\tstate.registerProvider(\"tasksTimeline\", function(){\n\t\t\t\t\treturn {\n\t\t\t\t\t\tscale_unit: self._tasks ? self._tasks.unit : undefined,\n\t\t\t\t\t\tscale_step: self._tasks ? self._tasks.step : undefined\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t},\n\n\t\t\t_clearStateProvider: function(){\n\t\t\t\tvar state = services.getService(\"state\");\n\t\t\t\tstate.unregisterProvider(\"tasksTimeline\");\n\t\t\t}\n\t\t};\n\t};\n\n})();\n\nexport default initializer;","import * as domHelpers from \"./utils/dom_helpers\";\n\nvar initializer = (function() {\n\treturn function (gantt) {\n\t\treturn {\n\n\t\t\tgetVerticalScrollbar: function(){\n\t\t\t\treturn gantt.$ui.getView(\"scrollVer\");\n\t\t\t},\n\t\t\tgetHorizontalScrollbar: function(){\n\t\t\t\treturn gantt.$ui.getView(\"scrollHor\");\n\t\t\t},\n\n\t\t\t_legacyGridResizerClass: function(layout){\n\t\t\t\tvar resizers = layout.getCellsByType(\"resizer\");\n\t\t\t\tfor(var i = 0; i < resizers.length; i++){\n\t\t\t\t\tvar r = resizers[i];\n\t\t\t\t\tvar gridResizer = false;\n\n\t\t\t\t\tvar prev = r.$parent.getPrevSibling(r.$id);\n\t\t\t\t\tif(prev && prev.$config && prev.$config.id === \"grid\"){\n\t\t\t\t\t\tgridResizer= true;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tvar next = r.$parent.getNextSibling(r.$id);\n\t\t\t\t\t\tif(next && next.$config && next.$config.id === \"grid\"){\n\t\t\t\t\t\t\tgridResizer= true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif(gridResizer){\n\t\t\t\t\t\tr.$config.css = (r.$config.css ? r.$config.css + \" \" : \"\") + \"gantt_grid_resize_wrap\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tonCreated: function(layout) {\n\t\t\t\tvar first = true;\n\n\t\t\t\tthis._legacyGridResizerClass(layout);\n\n\t\t\t\tlayout.attachEvent(\"onBeforeResize\", function() {\n\t\t\t\t\tvar mainTimeline = gantt.$ui.getView(\"timeline\");\n\t\t\t\t\tif (mainTimeline)\n\t\t\t\t\t\tmainTimeline.$config.hidden = mainTimeline.$parent.$config.hidden = !gantt.config.show_chart;\n\n\t\t\t\t\tvar mainGrid = gantt.$ui.getView(\"grid\");\n\n\t\t\t\t\tif(!mainGrid)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tvar colsWidth = mainGrid._getColsTotalWidth();\n\t\t\t\t\tvar hideGrid = !gantt.config.show_grid || !gantt.config.grid_width || colsWidth === 0;\n\t\t\t\t\tif (first && !hideGrid && colsWidth !== false){\n\t\t\t\t\t\t\tgantt.config.grid_width = colsWidth;\n\t\t\t\t\t}\n\t\t\t\t\tmainGrid.$config.hidden = mainGrid.$parent.$config.hidden = hideGrid;\n\n\t\t\t\t\tif (!mainGrid.$config.hidden) {\n\t\t\t\t\t\t/* restrict grid width due to min_width, max_width, min_grid_column_width */\n\t\t\t\t\t\tvar grid_limits = mainGrid._getGridWidthLimits();\n\t\t\t\t\t\tif (grid_limits[0] && gantt.config.grid_width < grid_limits[0])\n\t\t\t\t\t\t\tgantt.config.grid_width = grid_limits[0];\n\t\t\t\t\t\tif (grid_limits[1] && gantt.config.grid_width > grid_limits[1])\n\t\t\t\t\t\t\tgantt.config.grid_width = grid_limits[1];\n\t\t\t\t\t\tif (mainTimeline && gantt.config.show_chart){\n\n\t\t\t\t\t\t\tmainGrid.$config.width = gantt.config.grid_width - 1;\n\n\t\t\t\t\t\t\t// GS-1314: Don't let the non-scrollable grid to be larger than the container with the correct width\n\t\t\t\t\t\t\tif (!mainGrid.$config.scrollable && mainGrid.$config.scrollY && gantt.$root.offsetWidth){\n\t\t\t\t\t\t\t\tvar ganttContainerWidth = mainGrid.$gantt.$layout.$container.offsetWidth;\n\t\t\t\t\t\t\t\tvar verticalScrollbar = gantt.$ui.getView(mainGrid.$config.scrollY);\n\t\t\t\t\t\t\t\tvar verticalScrollbarWidth = verticalScrollbar.$config.width;\n\n\t\t\t\t\t\t\t\t// GS-2488: to prevent grid from occupying the whole gantt container(timeline will be disabled) \n\t\t\t\t\t\t\t\t// need to leave min width for timeline\n\t\t\t\t\t\t\t\tvar gridOverflow = ganttContainerWidth - (mainGrid.$config.width + verticalScrollbarWidth) - 4;\n\t\t\t\t\t\t\t\tif (gridOverflow < 0){\n\t\t\t\t\t\t\t\t\tmainGrid.$config.width += gridOverflow;\n\t\t\t\t\t\t\t\t\tgantt.config.grid_width += gridOverflow;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!first) {\n\t\t\t\t\t\t\t\tif (mainTimeline && !domHelpers.isChildOf(mainTimeline.$task, layout.$view)) {\n\t\t\t\t\t\t\t\t\t// timeline is being displayed after being not visible, reset grid with from full screen\n\t\t\t\t\t\t\t\t\tif (!mainGrid.$config.original_grid_width) {\n\t\t\t\t\t\t\t\t\t\tvar skinSettings = gantt.skins[gantt.skin];\n\t\t\t\t\t\t\t\t\t\tif(skinSettings && skinSettings.config && skinSettings.config.grid_width){\n\t\t\t\t\t\t\t\t\t\t\tmainGrid.$config.original_grid_width = skinSettings.config.grid_width;\n\t\t\t\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\t\t\t\tmainGrid.$config.original_grid_width = 0;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tgantt.config.grid_width = mainGrid.$config.original_grid_width;\n\t\t\t\t\t\t\t\t\tmainGrid.$parent.$config.width = gantt.config.grid_width;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tmainGrid.$parent._setContentSize(mainGrid.$config.width, null);\n\t\t\t\t\t\t\t\t\tgantt.$layout._syncCellSizes(mainGrid.$parent.$config.group, {value: gantt.config.grid_width, isGravity: false});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tmainGrid.$parent.$config.width = gantt.config.grid_width;\n\t\t\t\t\t\t\t\tif (mainGrid.$parent.$config.group) {\n\t\t\t\t\t\t\t\t\tgantt.$layout._syncCellSizes(mainGrid.$parent.$config.group, {value: mainGrid.$parent.$config.width, isGravity: false});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (mainTimeline && domHelpers.isChildOf(mainTimeline.$task, layout.$view)) {\n\t\t\t\t\t\t\t\t// hiding timeline, remember grid with to restore it when timeline is displayed again\n\t\t\t\t\t\t\t\tmainGrid.$config.original_grid_width = gantt.config.grid_width;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!first) {\n\t\t\t\t\t\t\t\tmainGrid.$parent.$config.width = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfirst = false;\n\t\t\t\t});\n\t\t\t\tthis._initScrollStateEvents(layout);\n\t\t\t},\n\n\t\t\t_initScrollStateEvents: function(layout) {\n\t\t\t\tgantt._getVerticalScrollbar = this.getVerticalScrollbar;\n\t\t\t\tgantt._getHorizontalScrollbar = this.getHorizontalScrollbar;\n\n\t\t\t\tvar vertical = this.getVerticalScrollbar();\n\t\t\t\tvar horizontal = this.getHorizontalScrollbar();\n\t\t\t\tif (vertical) {\n\t\t\t\t\tvertical.attachEvent(\"onScroll\", function(oldPos, newPos, dir){\n\t\t\t\t\t\tvar scrollState = gantt.getScrollState();\n\t\t\t\t\t\tgantt.callEvent(\"onGanttScroll\", [scrollState.x, oldPos, scrollState.x, newPos]);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (horizontal) {\n\t\t\t\t\thorizontal.attachEvent(\"onScroll\", function(oldPos, newPos, dir){\n\t\t\t\t\t\tvar scrollState = gantt.getScrollState();\n\t\t\t\t\t\tgantt.callEvent(\"onGanttScroll\", [oldPos, scrollState.y, newPos, scrollState.y]);\n\n\t\t\t\t\t\t// if the grid doesn't fit the width, scroll the row container\n\t\t\t\t\t\tvar grid = gantt.$ui.getView(\"grid\");\n\t\t\t\t\t\tif (grid && grid.$grid_data && !grid.$config.scrollable){\n\t\t\t\t\t\t\tgrid.$grid_data.style.left = grid.$grid.scrollLeft + \"px\";\n\t\t\t\t\t\t\tgrid.$grid_data.scrollLeft = grid.$grid.scrollLeft;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tlayout.attachEvent(\"onResize\", function(){\n\t\t\t\t\tif (vertical && !gantt.$scroll_ver){\n\t\t\t\t\t\tgantt.$scroll_ver = vertical.$scroll_ver;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (horizontal && !gantt.$scroll_hor){\n\t\t\t\t\t\tgantt.$scroll_hor = horizontal.$scroll_hor;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\n\t\t\t_findGridResizer: function(layout, grid){\n\t\t\t\tvar resizers = layout.getCellsByType(\"resizer\");\n\n\t\t\t\tvar gridFirst = true;\n\t\t\t\tvar gridResizer;\n\t\t\t\tfor(var i = 0; i < resizers.length; i++){\n\t\t\t\t\tvar res = resizers[i];\n\t\t\t\t\tres._getSiblings();\n\t\t\t\t\tvar prev = res._behind;\n\t\t\t\t\tvar next = res._front;\n\t\t\t\t\tif(prev && prev.$content === grid || (prev.isChild && prev.isChild(grid))){\n\t\t\t\t\t\tgridResizer = res;\n\t\t\t\t\t\tgridFirst = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else if(next && next.$content === grid || (next.isChild && next.isChild(grid))){\n\t\t\t\t\t\tgridResizer = res;\n\t\t\t\t\t\tgridFirst = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tresizer: gridResizer,\n\t\t\t\t\tgridFirst: gridFirst\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tonInitialized: function (layout) {\n\t\t\t\tvar grid = gantt.$ui.getView(\"grid\");\n\n\t\t\t\tvar resizeInfo = this._findGridResizer(layout, grid);\n\n\t\t\t\t// expose grid resize events\n\t\t\t\tif(resizeInfo.resizer){\n\t\t\t\t\tvar gridFirst = resizeInfo.gridFirst,\n\t\t\t\t\t\tnext = resizeInfo.resizer;\n\t\t\t\t\t\t\n\t\t\t\t\tif(next.$config.mode !== \"x\"){\n\t\t\t\t\t\treturn;// track only horizontal resize\n\t\t\t\t\t}\n\n\t\t\t\t\tvar initialWidth;\n\t\t\t\t\tnext.attachEvent(\"onResizeStart\", function(prevCellWidth, nextCellWidth){\n\n\t\t\t\t\t\tvar grid = gantt.$ui.getView(\"grid\");\n\t\t\t\t\t\tvar viewCell = grid ? grid.$parent : null;\n\t\t\t\t\t\tif(viewCell){\n\t\t\t\t\t\t\tvar limits = grid._getGridWidthLimits();\n\n\t\t\t\t\t\t\t// min grid width is defined by min widths of its columns, unless grid has horizontal scroll\n\t\t\t\t\t\t\tif(!grid.$config.scrollable)\n\t\t\t\t\t\t\t\tviewCell.$config.minWidth = limits[0];\n\n\t\t\t\t\t\t\tviewCell.$config.maxWidth = limits[1];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinitialWidth = gridFirst ? prevCellWidth : nextCellWidth;\n\t\t\t\t\t\treturn gantt.callEvent(\"onGridResizeStart\", [initialWidth]);\n\t\t\t\t\t});\n\t\t\t\t\tnext.attachEvent(\"onResize\", function(newBehindSize, newFrontSize){\n\t\t\t\t\t\tvar newSize = gridFirst ? newBehindSize : newFrontSize;\n\t\t\t\t\t\treturn gantt.callEvent(\"onGridResize\", [initialWidth, newSize]);\n\t\t\t\t\t});\n\t\t\t\t\tnext.attachEvent(\"onResizeEnd\", function(oldBackSize, oldFrontSize, newBackSize, newFrontSize){\n\n\t\t\t\t\t\tvar oldSize = gridFirst ? oldBackSize : oldFrontSize;\n\t\t\t\t\t\tvar newSize = gridFirst ? newBackSize : newFrontSize;\n\t\t\t\t\t\tvar grid = gantt.$ui.getView(\"grid\");\n\t\t\t\t\t\tvar viewCell = grid ? grid.$parent : null;\n\t\t\t\t\t\tif(viewCell){\n\t\t\t\t\t\t\tviewCell.$config.minWidth = undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar res = gantt.callEvent(\"onGridResizeEnd\", [oldSize, newSize]);\n\t\t\t\t\t\tif(res && newSize !== 0){// new size may be numeric zero when cell size is defined by 'gravity', actual size will be calculated by layout later\n\t\t\t\t\t\t\tgantt.config.grid_width = newSize;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn res;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t},\n\t\t\tonDestroyed: function (timeline) {\n\n\t\t\t}\n\t\t};\n\n\t};\n})();\n\nexport default initializer;","import uiFactory from \"./ui_factory\";\nimport mouseEvents from \"./mouse\";\nimport createLayers from \"./gantt_layers\";\nimport Cell from \"./layout/cell\";\nimport Layout from \"./layout/layout\";\nimport ViewLayout from \"./layout/view_layout\";\nimport ViewCell from \"./layout/view_cell\";\nimport Resizer from \"./layout/resizer_cell\";\nimport Scrollbar from \"./layout/scrollbar_cell\";\nimport Timeline from \"./timeline/timeline\";\nimport Grid from \"./grid/grid\";\nimport ResourceGrid from \"./grid/resource_grid\";\nimport ResourceTimeline from \"./timeline/resource_timeline\";\nimport ResourceHistogram from \"./timeline/resource_histogram\";\n\n\nimport gridEditorsFactory from \"./grid/editors/controller\";\n\nimport renderTaskBar from \"./render/task_bar_smart_render\";\nimport renderTimedProjectBar from \"./render/task_project_smart_render\";\nimport renderSplitTaskBar from \"./render/task_split_render\";\nimport renderRollupTaskBar from \"./render/task_rollup_render\";\nimport renderTaskBg from \"./render/task_bg_render\";\nimport renderLink from \"./render/link_render\";\nimport gridRenderer from \"./render/task_grid_line_render\";\nimport resourceMatrixRenderer from \"./render/resource_matrix_render\";\nimport resourceHistogramRenderer from \"./render/resource_histogram_render\";\nimport gridTaskRowResizerRenderer from \"./render/task_grid_row_resize_render\";\nimport renderConstraints from \"./render/task_constraints_render\";\nimport renderDeadline from \"./render/task_deadline_render\";\nimport renderBaselines from \"./render/task_baselines_render\";\nimport mainGridInitializer from \"./grid/main_grid_initializer\";\nimport mainTimelineInitializer from \"./timeline/main_timeline_initializer\";\nimport mainLayoutInitializer from \"./main_layout_initializer\";\n\nfunction initUI(gantt){\n\tfunction attachInitializer(view, initializer){\n\t\tvar ext = initializer(gantt);\n\t\tif(ext.onCreated)\n\t\t\text.onCreated(view);\n\t\tview.attachEvent(\"onReady\", function(){\n\t\t\tif(ext.onInitialized)\n\t\t\t\text.onInitialized(view);\n\t\t});\n\t\tview.attachEvent(\"onDestroy\", function(){\n\t\t\tif(ext.onDestroyed)\n\t\t\t\text.onDestroyed(view);\n\t\t});\n\t}\n\n\tvar factory = uiFactory.createFactory(gantt);\n\tfactory.registerView(\"cell\", Cell);\n\tfactory.registerView(\"resizer\", Resizer);\n\tfactory.registerView(\"scrollbar\", Scrollbar);\n\tfactory.registerView(\"layout\", Layout, function(view){\n\t\tvar id = view.$config ? view.$config.id : null;\n\t\tif(id === \"main\"){\n\t\t\tattachInitializer(view, mainLayoutInitializer);\n\t\t}\n\t});\n\tfactory.registerView(\"viewcell\", ViewCell);\n\tfactory.registerView(\"multiview\", ViewLayout);\n\tfactory.registerView(\"timeline\", Timeline, function(view){\n\t\tvar id = view.$config ? view.$config.id : null;\n\t\tif(id === \"timeline\" || view.$config.bind == \"task\"){\n\t\t\tattachInitializer(view, mainTimelineInitializer);\n\t\t}\n\t});\n\tfactory.registerView(\"grid\", Grid, function(view){\n\t\tvar id = view.$config ? view.$config.id : null;\n\t\tif(id === \"grid\" || view.$config.bind == \"task\"){\n\t\t\tattachInitializer(view, mainGridInitializer);\n\t\t}\n\t});\n\n\tfactory.registerView(\"resourceGrid\", ResourceGrid);\n\tfactory.registerView(\"resourceTimeline\", ResourceTimeline);\n\tfactory.registerView(\"resourceHistogram\", ResourceHistogram);\n\n\tvar layersEngine = createLayers(gantt);\n\n\tvar inlineEditors = gridEditorsFactory(gantt);\n\n\tgantt.ext.inlineEditors = inlineEditors;\n\tgantt.ext._inlineEditors = inlineEditors;\n\tinlineEditors.init(gantt);\n\n\treturn {\n\t\tfactory:factory,\n\t\tmouseEvents: mouseEvents.init(gantt),\n\t\tlayersApi: layersEngine.init(),\n\t\trender:{\n\t\t\tgridLine: function(){\n\t\t\t\treturn gridRenderer(gantt);\n\t\t\t},\n\t\t\ttaskBg: function(){\n\t\t\t\treturn renderTaskBg(gantt);\n\t\t\t},\n\t\t\ttaskBar: function(){\n\t\t\t\treturn renderTaskBar(gantt);\n\t\t\t},\n\t\t\ttimedProjectBar: function(){\n\t\t\t\treturn renderTimedProjectBar(gantt);\n\t\t\t},\n\t\t\ttaskRollupBar: function() {\n\t\t\t\treturn renderRollupTaskBar(gantt);\n\t\t\t},\n\t\t\ttaskSplitBar: function(){\n\t\t\t\treturn renderSplitTaskBar(gantt);\n\t\t\t},\n\t\t\ttaskConstraints: function(){\n\t\t\t\treturn renderConstraints(gantt);\n\t\t\t},\n\t\t\ttaskDeadline: function(){\n\t\t\t\treturn renderDeadline(gantt);\n\t\t\t},\n\t\t\ttaskBaselines: function(){\n\t\t\t\treturn renderBaselines(gantt);\n\t\t\t},\n\t\t\tlink: function(){\n\t\t\t\treturn renderLink(gantt);\n\t\t\t},\n\t\t\tresourceRow: function(){\n\t\t\t\treturn resourceMatrixRenderer(gantt);\n\t\t\t},\n\t\t\tresourceHistogram: function(){\n\t\t\t\treturn resourceHistogramRenderer(gantt);\n\t\t\t},\n\t\t\tgridTaskRowResizer: function(){\n\t\t\t\treturn gridTaskRowResizerRenderer(gantt);\n\t\t\t}\n\t\t},\n\t\tlayersService: {\n\t\t\tgetDataRender: function(name){\n\t\t\t\treturn layersEngine.getDataRender(name, gantt);\n\t\t\t},\n\t\t\tcreateDataRender: function(config){\n\t\t\t\treturn layersEngine.createDataRender(config, gantt);\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport default {\n\tinit: initUI\n};","import defaultMapping from \"./keyboard_mappings/default\";\nimport keyNavMappings from \"./keyboard_mappings/keyboard_navigation\";\n\nexport default function(gantt){\n\n\tvar mapping = null;\n\n\treturn {\n\t\tsetMapping: function(map){\n\t\t\tmapping = map;\n\t\t},\n\t\tgetMapping: function(){\n\n\t\t\tif(mapping){\n\t\t\t\treturn mapping;\n\t\t\t}else if(gantt.config.keyboard_navigation_cells && gantt.ext.keyboardNavigation){\n\t\t\t\treturn keyNavMappings;\n\t\t\t}else{\n\t\t\t\treturn defaultMapping;\n\t\t\t}\n\t\t}\n\t};\n};\n","export default function (gantt) {\n\treturn function processTaskDateProperties(item, mapTo, mode) {\n\t\tif (mode == \"keepDates\") {\n\t\t\tkeepDatesOnEdit(item, mapTo);\n\t\t} else if (mode == \"keepDuration\") {\n\t\t\tkeepDurationOnEdit(item, mapTo);\n\t\t} else {\n\t\t\tdefaultActionOnEdit(item, mapTo);\n\t\t}\n\t};\n\n\t// resize task\n\t// resize task when start/end/duration changes\n\tfunction keepDatesOnEdit(item, mapTo) {\n\t\tif (mapTo == \"duration\") {\n\t\t\titem.end_date = gantt.calculateEndDate(item);\n\t\t} else if (mapTo == \"end_date\" || mapTo == \"start_date\") {\n\t\t\titem.duration = gantt.calculateDuration(item);\n\t\t}\n\t}\n\n\t// move task(before 6.2)\n\t// move task when start/end dates changes\n\t// resize task when duration changes\n\tfunction keepDurationOnEdit(item, mapTo) {\n\t\tif (mapTo == \"end_date\") {\n\t\t\titem.start_date = decreaseStartDate(item);\n\t\t} else if (mapTo == \"start_date\" || mapTo == \"duration\") {\n\t\t\titem.end_date = gantt.calculateEndDate(item);\n\t\t}\n\t}\n\n\t// default behavior\n\t// move task when start date changes\n\t// resize task when end date/duration changes\n\tfunction defaultActionOnEdit(item, mapTo) {\n\t\tif (gantt.config.schedule_from_end){\n\t\t\tif (mapTo == \"end_date\" || mapTo == \"duration\") {\n\t\t\t\titem.start_date = decreaseStartDate(item);\n\t\t\t} else if (mapTo == \"start_date\") {\n\t\t\t\titem.duration = gantt.calculateDuration(item);\n\t\t\t}\n\t\t} else {\n\t\t\tif (mapTo == \"start_date\" || mapTo == \"duration\") {\n\t\t\t\titem.end_date = gantt.calculateEndDate(item);\n\t\t\t} else if (mapTo == \"end_date\") {\n\t\t\t\titem.duration = gantt.calculateDuration(item);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction decreaseStartDate(item){\n\t\treturn gantt.calculateEndDate({\n\t\t\tstart_date: item.end_date,\n\t\t\tduration: -item.duration,\n\t\t\ttask: item\n\t\t});\n\t}\n};","import * as helpers from \"../../../utils/helpers\";\nimport getRowRectangle from \"./viewport/get_grid_row_rectangle\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport isInViewPort from \"./viewport/is_grid_row_in_viewport\";\n\nfunction createGridLineRender(gantt){\n\n\tfunction _render_grid_item(item, view, config, viewport) {\n\t\tvar columns = view.getGridColumns();\n\t\tvar templates = view.$getTemplates();\n\n\t\tvar store = view.$config.rowStore;\n\n\t\tvar cells = [];\n\t\tvar has_child;\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tvar last = i == columns.length - 1;\n\t\t\tvar col = columns[i];\n\t\t\tvar cell;\n\n\t\t\tvar value;\n\t\t\tvar textValue;\n\t\t\tif (col.name == \"add\") {\n\t\t\t\tvar aria = gantt._waiAria.gridAddButtonAttrString(col);\n\n\t\t\t\tvalue = \"
\";\n\t\t\t\ttextValue = \"\";\n\t\t\t} else {\n\t\t\t\tif (col.template)\n\t\t\t\t\tvalue = col.template(item);\n\t\t\t\telse\n\t\t\t\t\tvalue = item[col.name];\n\n\t\t\t\tif (helpers.isDate(value)){\n\t\t\t\t\tvalue = templates.date_grid(value, item, col.name);\n\t\t\t\t}\n\n\t\t\t\tif (value === null || value === undefined) {\n\t\t\t\t\tvalue = \"\";\n\t\t\t\t}\n\n\t\t\t\ttextValue = value;\n\t\t\t\tvalue = \"
\" + value + \"
\";\n\t\t\t}\n\t\t\tvar css = \"gantt_cell\" + (last ? \" gantt_last_cell\" : \"\");\n\n\t\t\tvar tree = [];\n\t\t\tif (col.tree) {\n\t\t\t\tcss += \" gantt_cell_tree\";\n\t\t\t\tfor (var j = 0; j < item.$level; j++)\n\t\t\t\t\ttree.push(templates.grid_indent(item));\n\n\t\t\t\thas_child = store.hasChild(item.id) && !(gantt.isSplitTask(item) && !gantt.config.open_split_tasks);\n\t\t\t\tif (has_child) {\n\t\t\t\t\ttree.push(templates.grid_open(item));\n\t\t\t\t\ttree.push(templates.grid_folder(item));\n\t\t\t\t} else {\n\t\t\t\t\ttree.push(templates.grid_blank(item));\n\t\t\t\t\ttree.push(templates.grid_file(item));\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar style = \"width:\" + (col.width - (last ? 1 : 0)) + \"px;\";\n\t\t\tif (this.defined(col.align)){\n\t\t\t\tvar flexAlign = {\n\t\t\t\t\tright: \"flex-end\",\n\t\t\t\t\tleft: \"flex-start\",\n\t\t\t\t\tcenter: \"center\"\n\t\t\t\t};\n\t\t\t\tvar justifyContent = flexAlign[col.align];\n\n\t\t\t\tstyle += \"text-align:\" + col.align + \";justify-content:\" + justifyContent + \";\";\n\t\t\t}\n\n\t\t\tvar aria = gantt._waiAria.gridCellAttrString(col, textValue, item);\n\n\t\t\ttree.push(value);\n\t\t\tcell = \"
\" + tree.join(\"\") + \"
\";\n\t\t\tcells.push(cell);\n\t\t}\n\t\t// GS-291. The odd class should be assigned correctly\n\t\tcss = \"\";\n\t\tconst storeName = store.$config.name;\n\t\tswitch (storeName) {\n\t\t\tcase \"task\":\n\t\t\t\tcss = gantt.getGlobalTaskIndex(item.id) % 2 === 0 ? \"\" : \" odd\";\n\t\t\t\tbreak;\n\t\t\tcase \"resource\":\n\t\t\t\tcss = store.visibleOrder.indexOf(item.id) % 2 === 0 ? \"\" : \" odd\";\n\t\t\t\tbreak;\n\t\t}\n\n\t\tcss += (item.$transparent) ? \" gantt_transparent\" : \"\";\n\n\t\tcss += (item.$dataprocessor_class ? \" \" + item.$dataprocessor_class : \"\");\n\n\t\tif (templates.grid_row_class) {\n\t\t\tvar css_template = templates.grid_row_class.call(gantt, item.start_date, item.end_date, item);\n\t\t\tif (css_template)\n\t\t\t\tcss += \" \" + css_template;\n\t\t}\n\n\t\tif(store.isSelected(item.id)) {\n\t\t\tcss += \" gantt_selected\";\n\t\t}\n\n\t\tvar el = document.createElement(\"div\");\n\t\tel.className = \"gantt_row\" + css + \" gantt_row_\" + gantt.getTaskType(item.type);\n\t\tvar height = view.getItemHeight(item.id);\n\t\tel.style.height = height + \"px\";\n\t\tel.style.lineHeight = height + \"px\";\n\n\t\tif(config.smart_rendering){\n\t\t\tel.style.position = \"absolute\";\n\t\t\tel.style.left = \"0px\";\n\t\t\tel.style.top = view.getItemTop(item.id) + \"px\";\n\t\t}\n\n\t\tif(view.$config.item_attribute){\n\t\t\tel.setAttribute(view.$config.item_attribute, item.id);\n\t\t\tel.setAttribute(view.$config.bind + \"_id\", item.id); // 'task_id'/'resource_id' for backward compatibility\n\t\t}\n\n\t\tgantt._waiAria.taskRowAttr(item, el);\n\n\t\tel.innerHTML = cells.join(\"\");\n\t\treturn el;\n\t}\n\n\tfunction onrender(item, rowNode, view){\n\t\tvar columns = view.getGridColumns();\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tvar column = columns[i];\n\t\t\tif (column.onrender){\n\n\t\t\t\t// find cell node for current column\n\t\t\t\tvar cellNode = rowNode.querySelector(\"[data-column-name=\" + column.name + \"]\");\n\t\t\t\tif (cellNode) {\n\t\t\t\t\tvar content = column.onrender(item, cellNode);\n\t\t\t\t\tif (content && typeof content === \"string\") {\n\t\t\t\t\t\tcellNode.innerHTML = content;\n\t\t\t\t\t} else if (content && typeof content === \"object\") {\n\t\t\t\t\t\t// render object to node using additional functionality\n\t\t\t\t\t\tif (gantt.config.external_render){\n\t\t\t\t\t\t\tvar adapter = gantt.config.external_render;\n\t\t\t\t\t\t\tif (adapter.isElement(content)){\n\t\t\t\t\t\t\t\tadapter.renderElement(content, cellNode);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\trender: _render_grid_item,\n\t\tupdate: null,\n\t\tgetRectangle: getRowRectangle,\n\t\tisInViewPort: isInViewPort,\n\t\tgetVisibleRange: getVisibleRange,\n\t\tonrender: onrender\n\t};\n}\n\nexport default createGridLineRender;","import getRowRectangle from \"./viewport/get_bg_row_rectangle\";\nimport isLegacyRender from \"./is_legacy_smart_render\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport getVisibleCellsRange from \"./viewport/get_visible_cells_range\";\nimport isColumnVisible from \"./viewport/is_column_visible\";\nimport bgPlaceholder from \"./prerender/task_bg_placeholder\";\n\nfunction createTaskBgRender(gantt){\n\tvar renderedCells = {};\n\tvar visibleCells = {};\n\n\tfunction isRendered(item, columnIndex){\n\t\tif(renderedCells[item.id][columnIndex] && renderedCells[item.id][columnIndex].parentNode){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfunction detachRenderedCell(itemId, columnIndex){\n\t\tif(renderedCells[itemId] && renderedCells[itemId][columnIndex] &&\n\t\t\trenderedCells[itemId][columnIndex].parentNode\n\t\t\t){\n\t\t\t\trenderedCells[itemId][columnIndex].parentNode.removeChild(renderedCells[itemId][columnIndex]);\n\t\t\t}\n\t}\n\n\tfunction getCellClassTemplate(view){\n\t\tvar templates = view.$getTemplates();\n\t\tvar cssTemplate;\n\t\tif (typeof templates.task_cell_class !== \"undefined\") {\n\t\t\tcssTemplate = templates.task_cell_class;\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tvar log = console.warn || console.log;\n\t\t\tlog('gantt.templates.task_cell_class template is deprecated and will be removed soon. Please use gantt.templates.timeline_cell_class instead.');\n\t\t} else {\n\t\t\tcssTemplate = templates.timeline_cell_class;\n\t\t}\n\t\treturn cssTemplate;\n\t}\n\tfunction getCellContentTemplate(view){\n\t\tvar templates = view.$getTemplates();\n\t\tvar contentTemplate = templates.timeline_cell_content;\n\t\treturn contentTemplate;\n\t}\n\n\tfunction renderCells(item, node, view, config, viewPort){\n\t\tvar cfg = view.getScale();\n\t\tvar count = cfg.count;\n\t\tvar cssTemplate = getCellClassTemplate(view);\n\t\tvar contentTemplate = getCellContentTemplate(view);\n\n\t\tif (config.show_task_cells) {\n\t\t\tif(!renderedCells[item.id]){\n\t\t\t\trenderedCells[item.id] = {};\n\t\t\t}\n\t\t\tif(!visibleCells[item.id]){\n\t\t\t\tvisibleCells[item.id] = {};\n\t\t\t}\n\n\t\t\tvar range = getVisibleCellsRange(cfg, viewPort);\n\n\t\t\tfor(var i in visibleCells[item.id]){\n\t\t\t\tvar index = visibleCells[item.id][i];\n\n\t\t\t\tif(Number(index) < range.start || Number(index) > range.end){\n\t\t\t\t\tdetachRenderedCell(item.id, index);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvisibleCells[item.id] = {};\n\t\t\t// TODO: do not iterate all cell, only ones in the viewport and once that are already rendered\n\t\t\tfor (var columnIndex = range.start; columnIndex <= range.end; columnIndex++) {\n\t\t\t\tvar cell = renderOneCell(cfg, columnIndex, item, viewPort, count, cssTemplate, contentTemplate, config);\n\t\t\t\tif(!cell && isRendered(item, columnIndex)){\n\t\t\t\t\tdetachRenderedCell(item.id, columnIndex);\n\t\t\t\t}else if (cell && !cell.parentNode){\n\t\t\t\t\tnode.appendChild(cell);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction renderOneCell(scale, columnIndex, item, viewPort, count, cssTemplate, contentTemplate, config){\n\t\tvar width = scale.width[columnIndex],\n\t\t\tcssclass = \"\";\n\n\t\tif (isColumnVisible(columnIndex, scale, viewPort, gantt)) {//do not render skipped columns\n\n\t\t\tvar cssTemplateContent = cssTemplate(item, scale.trace_x[columnIndex]);\n\t\t\tvar htmlTemplateContent = \"\";\n\t\t\tif (contentTemplate) {// for backward compatibility, contentTemplate was added in 7.2.0+, will be undefined if someone used copy of old config/template object\n\t\t\t\thtmlTemplateContent = contentTemplate(item, scale.trace_x[columnIndex]);\n\t\t\t}\n\n\t\t\tif(config.static_background){\n\t\t\t\t// if cell render in static background is not allowed, or if it's a blank cell\n\t\t\t\tvar customCell = !!(cssTemplateContent || htmlTemplateContent);\n\t\t\t\tif(!(config.static_background_cells && customCell)){\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(renderedCells[item.id][columnIndex]){\n\t\t\t\tvisibleCells[item.id][columnIndex] = columnIndex;\n\t\t\t\treturn renderedCells[item.id][columnIndex];\n\t\t\t}\n\t\t\tvar cell = document.createElement(\"div\");\n\t\t\tcell.style.width = (width) + \"px\";\n\n\t\t\tcssclass = \"gantt_task_cell\" + (columnIndex == count - 1 ? \" gantt_last_cell\" : \"\");\n\t\t\tif (cssTemplateContent) {\n\t\t\t\tcssclass += \" \" + cssTemplateContent;\n\t\t\t}\n\t\t\tcell.className = cssclass;\n\n\t\t\tif (htmlTemplateContent) {\n\t\t\t\tcell.innerHTML = htmlTemplateContent;\n\t\t\t}\n\n\t\t\tcell.style.position = \"absolute\";\n\t\t\tcell.style.left = scale.left[columnIndex] + \"px\";\n\t\t\trenderedCells[item.id][columnIndex] = cell;\n\t\t\tvisibleCells[item.id][columnIndex] = columnIndex;\n\n\t\t\treturn cell;\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction _render_bg_line(item, view, config, viewPort) {\n\t\tvar templates = view.$getTemplates();\n\t\tvar cfg = view.getScale();\n\t\tvar count = cfg.count;\n\n\t\tif(config.static_background && !config.static_background_cells){\n\t\t\treturn null;\n\t\t}\n\n\t\tvar row = document.createElement(\"div\");\n\n\t\tvar cellCssTemplate = getCellClassTemplate(view);\n\t\tvar cellHtmlTemplate = getCellContentTemplate(view);\n\n\t\tvar range;\n\n\t\tif(!viewPort || !config.smart_rendering || isLegacyRender(gantt)){\n\t\t\trange = {\n\t\t\t\tstart: 0,\n\t\t\t\tend: count - 1\n\t\t\t};\n\t\t} else {\n\t\t\trange = getVisibleCellsRange(cfg, viewPort.x);\n\t\t}\n\t\tif (config.show_task_cells) {\n\t\t\trenderedCells[item.id] = {};\n\t\t\tvisibleCells[item.id] = {};\n\t\t\tfor (var columnIndex = range.start; columnIndex <= range.end; columnIndex++) {\n\t\t\t\tvar cell = renderOneCell(cfg, columnIndex, item, viewPort, count, cellCssTemplate, cellHtmlTemplate, config);\n\t\t\t\tif(cell){\n\t\t\t\t\trow.appendChild(cell);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// GS-291. The odd class should be assigned correctly\n\t\tconst store = view.$config.rowStore;\n\t\tconst odd = store.getIndexById(item.id) % 2 !== 0;\n\n\t\tvar cssTemplate = templates.task_row_class(item.start_date, item.end_date, item);\n\t\tvar css = \"gantt_task_row\" + (odd ? \" odd\" : \"\") + (cssTemplate ? ' ' + cssTemplate : '');\n\n\t\tif(store.isSelected(item.id)) {\n\t\t\tcss += \" gantt_selected\";\n\t\t}\n\n\t\trow.className = css;\n\n\t\tif (config.smart_rendering) {\n\t\t\trow.style.position = \"absolute\";\n\t\t\trow.style.top = view.getItemTop(item.id) + \"px\";\n\t\t\trow.style.width = \"100%\";\n\t\t}else{\n\t\t\trow.style.position = \"relative\";\n\t\t}\n\t\trow.style.height = (view.getItemHeight(item.id)) + \"px\";\n\n\t\tif (item.id == \"timeline_placeholder_task\"){\n\t\t\tvar placeholderTop = 0;\n\t\t\tif (item.lastTaskId){\n\t\t\t\tvar lastTaskTop = view.getItemTop(item.lastTaskId);\n\t\t\t\tvar lastTaskHeight = view.getItemHeight(item.lastTaskId);\n\t\t\t\tplaceholderTop = lastTaskTop + lastTaskHeight;\t\n\t\t\t}\n\n\t\t\tvar maxHeight = item.row_height || view.$task_data.offsetHeight;\n\n\t\t\tvar placeholderHeight = maxHeight - placeholderTop;\n\t\t\t// So that it won't exceed the placeholder timeline height\n\t\t\tif (placeholderHeight < 0){\n\t\t\t\tplaceholderHeight = 0;\n\t\t\t}\n\n\t\t\tif (config.smart_rendering) {\n\t\t\t\trow.style.top = placeholderTop + \"px\";\t\n\t\t\t}\n\t\t\trow.style.height = placeholderHeight + \"px\";\n\t\t}\n\n\n\t\tif(view.$config.item_attribute){\n\t\t\trow.setAttribute(view.$config.item_attribute, item.id);\n\t\t\trow.setAttribute(view.$config.bind + \"_id\", item.id); // 'task_id'/'resource_id' for backward compatibility\n\t\t}\n\n\t\treturn row;\n\t}\n\n\treturn {\n\t\trender: _render_bg_line,\n\t\tupdate: renderCells,\n\t\tgetRectangle: getRowRectangle,\n\t\tgetVisibleRange: getVisibleRange,\n\t\tprepareData: bgPlaceholder\n\t};\n}\n\nexport default createTaskBgRender;\n","import isInViewPort from \"./viewport/is_bar_in_viewport\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport createBaseBarRender from \"./task_bar_render\";\n\nexport default function createTaskRenderer(gantt){\n\tvar defaultRender = createBaseBarRender(gantt);\n\treturn {\n\t\trender: defaultRender,\n\t\tupdate: null,\n\t\t//getRectangle: getBarRectangle\n\t\tisInViewPort: isInViewPort,\n\t\tgetVisibleRange: getVisibleRange\n\t};\n};","import isInViewPort from \"./viewport/is_project_bar_in_viewport\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport createBaseBarRender from \"./task_project_render\";\n\nexport default function createTaskRenderer(gantt){\n\tvar defaultRender = createBaseBarRender(gantt);\n\treturn {\n\t\trender: defaultRender,\n\t\tupdate: null,\n\t\t//getRectangle: getBarRectangle\n\t\tisInViewPort: isInViewPort,\n\t\tgetVisibleRange: getVisibleRange\n\t};\n};","function createTaskRenderer(gantt) {\n\n\tfunction _render_task_element(task, view, config) {\n\t\n\t\tvar config = view.$getConfig();\n\t\tvar painters = config.type_renderers;\n\t\tvar renderer = painters[gantt.getTaskType(task.type)],\n\t\t\tdefaultRenderer = _task_default_render;\n\n\t\tif (!renderer) {\n\t\t\treturn defaultRenderer.call(gantt, task, view, config);\n\t\t}else{\n\t\t\treturn renderer.call(gantt, task, function(task){ return defaultRenderer.call(gantt, task, view, config);}, view);\n\t\t}\n\t}\n\n\tfunction _task_default_render(task, view, config) {\n\t\tif (gantt._isAllowedUnscheduledTask(task))\n\t\t\treturn;\n\n\t\tif (!gantt._isTaskInTimelineLimits(task)) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar pos = view.getItemPosition(task);\n\n\t\tvar cfg = config,\n\t\t\ttemplates = view.$getTemplates();\n\n\t\tvar taskType = gantt.getTaskType(task.type);\n\t\tvar height = view.getBarHeight(task.id, taskType == cfg.types.milestone);\n\n\t\tvar controlsMargin = 0;\n\t\tif (taskType == cfg.types.milestone) {\n\t\t\tcontrolsMargin = (height - pos.height)/2;\n\t\t}\n\n\t\tvar padd = Math.floor((view.getItemHeight(task.id) - height) / 2);\n\n\t\tconst hasBaselines = gantt.config.baselines !== false && task.baselines && task.baselines.length;\n\t\tconst baselinesOnDifferentRow = gantt.config.baselines !== false && (gantt.config.baselines.render_mode == \"separateRow\" || gantt.config.baselines.render_mode == \"individualRow\");\n\t\tif (hasBaselines && baselinesOnDifferentRow){\n\t\t\tif (task.bar_height !== \"full\" && task.bar_height < task.row_height){\n\t\t\t\tif (taskType === cfg.types.milestone){\n\t\t\t\t\tlet milestoneHeight = view.getBarHeight(task.id, true);\n\t\t\t\t\tlet milestoneWidth = Math.sqrt(2 * milestoneHeight * milestoneHeight);\n\t\t\t\t\tpadd = Math.floor((milestoneWidth - height) / 2) + 2;\n\t\t\t\t} else {\n\t\t\t\t\tpadd = 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvar div = document.createElement(\"div\");\n\n\t\tvar width = Math.round(pos.width);\n\n\t\tif(view.$config.item_attribute) {\n\t\t\tdiv.setAttribute(view.$config.item_attribute, task.id);\n\t\t\tdiv.setAttribute(view.$config.bind + \"_id\", task.id); // 'task_id'/'resource_id' for backward compatibility\n\t\t}\n\n\t\t// generate outline bracket with planned dates\n\n\t\tconst planned = document.createElement(\"div\");\n\t\t\n\t\tplanned.classList.add(\"gantt_task_line_planned\", \"gantt_task_line\" , \"gantt_project\");\n\t\tconst plannedCoords = view.getItemPosition(task, task.start_date, task.end_date);\n\t\tconst barHeight = 5;\n\t\tplanned.style.cssText = [\n\t\t\t\"position:absolute\",\n\t\t\t\"left:\" + plannedCoords.left + \"px\",\n\t\t\t\"top:\" + (padd/2 + 1) + 'px',\n\t\t\t\"height:\" + barHeight + 'px',\n\t\t\t\"width:\" + plannedCoords.width + 'px'\n\t\t].join(\";\");\n\t\tplanned.style.setProperty('--dhx-gantt-scheduled-summary-bracket-size', \"10px\");\n\n\t\tdiv.appendChild(planned);\n\t\t// generate element with actual dates & progress\n\n\t\tconst actual = document.createElement(\"div\");\n\t\tconst actualCoords = view.getItemPosition(task, task.$auto_start_date || task.start_date, task.$auto_end_date || task.end_date);\n\t\tactual.classList.add(\"gantt_task_line_actual\", \"gantt_task_line\" , \"gantt_project\");\n\t\tactual.style.cssText = [\n\t\t\t\"position:absolute\",\n\t\t\t\"left:\" + actualCoords.left + \"px\",\n\t\t\t\"top:\" + (barHeight*2 + 6) + 'px',\n\t\t\t\"height:\" + (barHeight + 3) + 'px',\n\t\t\t\"width:\" + actualCoords.width + 'px'\n\t\t].join(\";\");\n\n\t\tdiv.appendChild(actual);\n\n\t\tif (cfg.show_progress && taskType != cfg.types.milestone) {\n\t\t\t_render_task_progress(task, actual, width, cfg, templates);\n\t\t}\n\n\t\t//use separate div to display content above progress bar\n\t\t// var content = _render_task_content(task, width, templates);\n\n\t\t// actual.appendChild(content);\n\n\t\tvar css = _combine_item_class(\"gantt_task_line\",\n\t\t\ttemplates.task_class(task.$auto_start_date || task.start_date, task.$auto_end_date || task.end_date, task),\n\t\t\ttask.id,\n\t\t\tview);\n\t\tif (task.color || task.progressColor || task.textColor) {\n\t\t\tcss += \" gantt_task_inline_color\";\n\t\t}\n\t\tif (pos.width < 20){\n\t\t\tcss += \" gantt_thin_task\";\n\t\t}\n\n\n\t\tif(task.start_date > task.$auto_start_date || task.end_date < task.$auto_end_date){\n\t\t\tcss += \" gantt_project_scheduling_conflict\";\n\t\t}\n\n\t\tdiv.className = css;\n\n\t\tdiv.style.top = (padd + pos.top) + 'px';\n\t\tdiv.style.height = (taskType == cfg.types.milestone ? pos.height : height) + 'px';\n\t\tif (task.color) {\n\t\t\tdiv.style.setProperty(\"--dhx-gantt-task-background\", task.color);\n\t\t}\n\t\tif (task.textColor) {\n\t\t\tdiv.style.setProperty(\"--dhx-gantt-task-color\", task.textColor);\n\t\t}\n\n\t\tif (task.progressColor) {\n\t\t\tdiv.style.setProperty(\"--dhx-gantt-task-progress-color\", task.progressColor);\n\t\t}\n\n\n\t\tvar side = _render_leftside_content(task, cfg, templates, controlsMargin);\n\t\tif (side) planned.appendChild(side);\n\n\t\tside = _render_rightside_content(task, cfg, templates, controlsMargin);\n\t\tif (side) planned.appendChild(side);\n\n\t\tgantt._waiAria.setTaskBarAttr(task, div);\n\n\t\tvar state = gantt.getState();\n\n\t\tif (!gantt.isReadonly(task)) {\n\t\t\tif (cfg.drag_resize) {\n\t\t\t\t_render_pair(planned, \"gantt_task_drag\", task, function (css) {\n\t\t\t\t\tvar el = document.createElement(\"div\");\n\t\t\t\t\tel.className = css;\n\t\t\t\t\treturn el;\n\t\t\t\t}, cfg);\n\t\t\t}\n\t\t\tif (cfg.drag_links && cfg.show_links) {\n\t\t\t\t_render_pair(planned, \"gantt_link_control\", task, function (css) {\n\t\t\t\t\tvar outer = document.createElement(\"div\");\n\t\t\t\t\touter.className = css;\n\t\t\t\t\touter.style.cssText = [\n\t\t\t\t\t\t\"height:\" + height + 'px',\n\t\t\t\t\t\t\"line-height:\" + height + 'px'\n\t\t\t\t\t].join(\";\");\n\t\t\t\t\tvar inner = document.createElement(\"div\");\n\t\t\t\t\tinner.className = \"gantt_link_point\";\n\n\t\t\t\t\tvar showLinkPoints = false;\n\t\t\t\t\tif(state.link_source_id && cfg.touch){\n\t\t\t\t\t\tshowLinkPoints = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tinner.style.display = showLinkPoints ? \"block\" : \"\";\n\t\t\t\t\touter.appendChild(inner);\n\t\t\t\t\treturn outer;\n\t\t\t\t}, cfg, controlsMargin);\n\t\t\t}\n\t\t}\n\t\treturn div;\n\t}\n\n\tfunction _render_side_content(task, template, cssClass, marginStyle) {\n\t\tif (!template) return null;\n\n\t\tvar text = template(task.start_date, task.end_date, task);\n\t\tif (!text) return null;\n\t\tvar content = document.createElement(\"div\");\n\t\tcontent.className = \"gantt_side_content \" + cssClass;\n\t\tcontent.innerHTML = text;\n\t\tif(marginStyle){\n\t\t\tcontent.style[marginStyle.type] = Math.abs(marginStyle.value) + \"px\";\n\t\t}\n\t\treturn content;\n\t}\n\n\tfunction _render_leftside_content(task, cfg, templates, margin) {\n\t\tvar css = \"gantt_left \" + _get_link_crossing_css(!cfg.rtl ? true : false, task, cfg);\n\t\tvar marginStyle = null;\n\t\tif(margin){\n\t\t\tmarginStyle = { type: \"marginRight\", value: margin };\n\t\t}\n\t\treturn _render_side_content(task, templates.leftside_text, css, marginStyle);\n\t}\n\n\tfunction _render_rightside_content(task, cfg, templates, margin) {\n\t\tvar css = \"gantt_right \" + _get_link_crossing_css(!cfg.rtl ? false : true, task, cfg);\n\t\tvar marginStyle = null;\n\t\tif(margin){\n\t\t\tmarginStyle = { type: \"marginLeft\", value: margin };\n\t\t}\n\t\treturn _render_side_content(task, templates.rightside_text, css, marginStyle);\n\t}\n\n\tfunction _get_link_crossing_css(left, task) {\n\t\tvar cond = _get_conditions(left);\n\n\t\tfor (var i in cond) {\n\t\t\tvar links = task[i];\n\t\t\tfor (var ln = 0; ln < links.length; ln++) {\n\t\t\t\tvar link = gantt.getLink(links[ln]);\n\n\t\t\t\tfor (var tp = 0; tp < cond[i].length; tp++) {\n\t\t\t\t\tif (link.type == cond[i][tp]) {\n\t\t\t\t\t\treturn \"gantt_link_crossing\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn \"\";\n\t}\n\n\n\t// function _render_task_content(task, width, templates) {\n\t// \tvar content = document.createElement(\"div\");\n\t// \tif (gantt.getTaskType(task.type) != gantt.config.types.milestone){\n\t// \t\tcontent.innerHTML = templates.task_text(task.start_date, task.end_date, task);\n\t// \t} else if(gantt.getTaskType(task.type) == gantt.config.types.milestone && width) {\n\t// \t\tcontent.style.height = content.style.width = width + \"px\";\n\t// \t}\n\t// \tcontent.className = \"gantt_task_content\";\n\t// \t//content.style.width = width + 'px';\n\t// \treturn content;\n\t// }\n\n\tfunction _render_task_progress(task, element, maxWidth, cfg, templates) {\n\t\tvar done = task.progress * 1 || 0;\n\n\t\tmaxWidth = Math.max(maxWidth - 2, 0);//2px for borders\n\t\tvar pr = document.createElement(\"div\");\n\t\tvar width = Math.round(maxWidth * done);\n\n\t\twidth = Math.min(maxWidth, width);\n\t\tif (task.progressColor) {\n\t\t\tpr.style.backgroundColor = task.progressColor;\n\t\t\tpr.style.opacity = 1;\n\t\t}\n\t\tpr.style.width = width + 'px';\n\t\tpr.className = \"gantt_task_progress\";\n\t\tpr.innerHTML = templates.progress_text(task.start_date, task.end_date, task);\n\n\t\tif(cfg.rtl){\n\t\t\tpr.style.position = \"absolute\";\n\t\t\tpr.style.right = \"0px\";\n\t\t}\n\n\t\tvar wrapper = document.createElement(\"div\");\n\t\twrapper.className = \"gantt_task_progress_wrapper\";\n\t\twrapper.appendChild(pr);\n\t\telement.appendChild(wrapper);\n\n\t\tif (gantt.config.drag_progress && !gantt.isReadonly(task)) {\n\t\t\tvar drag = document.createElement(\"div\");\n\n\t\t\tvar markerPos = width;\n\t\t\tif(cfg.rtl){\n\t\t\t\tmarkerPos = maxWidth - width;\n\t\t\t}\n\n\t\t\tdrag.style.left = markerPos + 'px';\n\t\t\tdrag.className = \"gantt_task_progress_drag\";\n\t\t\tpr.appendChild(drag);\n\t\t\telement.appendChild(drag);\n\t\t}\n\t}\n\n\tfunction _get_conditions(leftside) {\n\t\tif (leftside) {\n\t\t\treturn {\n\t\t\t\t$source: [\n\t\t\t\t\tgantt.config.links.start_to_start\n\t\t\t\t],\n\t\t\t\t$target: [\n\t\t\t\t\tgantt.config.links.start_to_start,\n\t\t\t\t\tgantt.config.links.finish_to_start\n\t\t\t\t]\n\t\t\t};\n\t\t} else {\n\t\t\treturn {\n\t\t\t\t$source: [\n\t\t\t\t\tgantt.config.links.finish_to_start,\n\t\t\t\t\tgantt.config.links.finish_to_finish\n\t\t\t\t],\n\t\t\t\t$target: [\n\t\t\t\t\tgantt.config.links.finish_to_finish\n\t\t\t\t]\n\t\t\t};\n\t\t}\n\t}\n\n\tfunction _combine_item_class(basic, template, itemId, view) {\n\t\tvar cfg = view.$getConfig();\n\t\tvar css = [basic];\n\t\tif (template)\n\t\t\tcss.push(template);\n\n\t\tvar state = gantt.getState();\n\n\t\tvar task = gantt.getTask(itemId);\n\n\t\tif (gantt.getTaskType(task.type) == cfg.types.milestone) {\n\t\t\tcss.push(\"gantt_milestone\");\n\t\t}else if (gantt.getTaskType(task.type) == cfg.types.project) {\n\t\t\tcss.push(\"gantt_project\");\n\t\t}\n\n\t\tcss.push(\"gantt_bar_\" + gantt.getTaskType(task.type));\n\n\n\t\tif (gantt.isSummaryTask(task))\n\t\t\tcss.push(\"gantt_dependent_task\");\n\n\t\tif (gantt.isSplitTask(task) && ((cfg.open_split_tasks && !task.$open) || !cfg.open_split_tasks)) {\n\t\t\tcss.push(\"gantt_split_parent\");\n\t\t}\n\n\t\tif (cfg.select_task && gantt.isSelectedTask(itemId)) {\n\t\t\tcss.push(\"gantt_selected\");\n\t\t}\n\n\t\tif (itemId == state.drag_id) {\n\t\t\tcss.push(\"gantt_drag_\" + state.drag_mode);\n\t\t\tif (state.touch_drag) {\n\t\t\t\tcss.push(\"gantt_touch_\" + state.drag_mode);\n\t\t\t}\n\t\t}\n\n\t\tif (state.link_source_id == itemId)\n\t\t\tcss.push(\"gantt_link_source\");\n\n\t\tif (state.link_target_id == itemId)\n\t\t\tcss.push(\"gantt_link_target\");\n\n\n\t\tif (cfg.highlight_critical_path && gantt.isCriticalTask) {\n\t\t\tif (gantt.isCriticalTask(task))\n\t\t\t\tcss.push(\"gantt_critical_task\");\n\t\t}\n\n\t\tif (state.link_landing_area &&\n\t\t\t(state.link_target_id && state.link_source_id) &&\n\t\t\t(state.link_target_id != state.link_source_id) &&\n\t\t\t(state.link_target_id == itemId || state.link_source_id == itemId)) {\n\n\t\t\tvar from_id = state.link_source_id;\n\t\t\tvar from_start = state.link_from_start;\n\t\t\tvar to_start = state.link_to_start;\n\n\t\t\tvar allowDrag = gantt.isLinkAllowed(from_id, itemId, from_start, to_start);\n\n\t\t\tvar dragClass = \"\";\n\t\t\tif (allowDrag) {\n\t\t\t\tif (to_start)\n\t\t\t\t\tdragClass = \"link_start_allow\";\n\t\t\t\telse\n\t\t\t\t\tdragClass = \"link_finish_allow\";\n\t\t\t} else {\n\t\t\t\tif (to_start)\n\t\t\t\t\tdragClass = \"link_start_deny\";\n\t\t\t\telse\n\t\t\t\t\tdragClass = \"link_finish_deny\";\n\t\t\t}\n\t\t\tcss.push(dragClass);\n\t\t}\n\t\treturn css.join(\" \");\n\t}\n\n\tfunction _render_pair(parent, css, task, content, config, margin) {\n\t\tvar state = gantt.getState();\n\t\tvar className, element;\n\t\tif (+task.start_date >= +state.min_date) {\n\t\t\tclassName = [css, config.rtl ? \"task_right\" : \"task_left\", \"task_start_date\"];\n\t\t\telement = content(className.join(\" \"));\n\t\t\telement.setAttribute(\"data-bind-property\", \"start_date\");\n\t\t\tif(margin){\n\t\t\t\telement.style.marginLeft = margin + \"px\";\n\t\t\t}\n\t\t\tparent.appendChild(element);\n\t\t}\n\n\t\tif (+task.end_date <= +state.max_date){\n\t\t\tclassName = [css, config.rtl ? \"task_left\" : \"task_right\", \"task_end_date\"];\n\t\t\telement = content(className.join(\" \"));\n\t\t\telement.setAttribute(\"data-bind-property\", \"end_date\");\n\t\t\tif(margin){\n\t\t\t\telement.style.marginRight = margin + \"px\";\n\t\t\t}\n\t\t\tparent.appendChild(element);\n\t\t}\n\n\t}\n\n\treturn _render_task_element;\n}\n\nexport default createTaskRenderer;","import createBaseBarRender from \"./task_bar_render\";\nimport isInViewPort from \"./viewport/is_bar_in_viewport\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\n\nfunction createTaskRenderer(gantt){\n\tconst defaultRender = createBaseBarRender(gantt);\n\n\tconst renderedNodes = {};\n\n\tfunction checkVisibility(child, viewPort, timeline, config, gantt){\n\t\tlet isVisible = true;\n\t\t// GS-2123. Don't render rollup tasks that are outside the viewport\n\t\tif (config.smart_rendering){\n\t\t\tisVisible = isInViewPort(child, viewPort, timeline, config, gantt);\n\t\t}\n\t\treturn isVisible;\n\t}\n\n\tfunction generateChildElement(task, child, timeline, sizes){\n\t\tconst childCopy = gantt.copy(gantt.getTask(child.id));\n\t\tchildCopy.$rendered_at = task.id;\n\t\t// a way to filter rollup tasks:\n\t\tconst displayRollup = gantt.callEvent(\"onBeforeRollupTaskDisplay\", [childCopy.id, childCopy, task.id]);\n\t\tif (displayRollup === false){\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = defaultRender(childCopy, timeline);\n\t\tif(!element){\n\t\t\treturn;\n\t\t}\n\n\t\tconst height = timeline.getBarHeight(task.id, child.type == gantt.config.types.milestone);\n\t\tconst padding = Math.floor((timeline.getItemHeight(task.id) - height) / 2);\n\n\t\telement.style.top = (sizes.top + padding) + \"px\";\n\t\telement.classList.add(\"gantt_rollup_child\");\n\t\telement.setAttribute(\"data-rollup-parent-id\", task.id);\n\n\t\treturn element;\n\t}\n\n\tfunction getKey(childId, renderParentId){\n\t\treturn childId + \"_\" + renderParentId;\n\t}\n\n\n\tfunction renderRollupTask(task, timeline, config, viewPort) {\n\t\tif (task.rollup !== false && task.$rollup && task.$rollup.length) {\n\t\t\tconst el = document.createElement('div'),\n\t\t\t\tsizes = gantt.getTaskPosition(task);\n\n\t\t\t// vertical position is not important for the rollup tasks as long as the parent is rendered\n\t\t\tif (viewPort){\n\t\t\t\tviewPort.y = 0;\n\t\t\t\tviewPort.y_end = gantt.$task_bg.scrollHeight;\n\t\t\t}\n\n\t\t\ttask.$rollup.forEach(function(itemId){\n\t\t\t\tif (!gantt.isTaskExists(itemId)){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst child = gantt.getTask(itemId);\n\t\t\t\tlet isVisible = checkVisibility(child, viewPort, timeline, config, gantt);\n\t\t\t\tif (!isVisible){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst element = generateChildElement(task, child, timeline, sizes);\n\t\t\t\tif (element) {\n\t\t\t\t\trenderedNodes[getKey(child.id, task.id)] = element;\n\t\t\t\t\tel.appendChild(element);\n\t\t\t\t} else{\n\t\t\t\t\trenderedNodes[getKey(child.id, task.id)] = false;\n\t\t\t\t}\n\n\t\t\t});\n\n\t\t\treturn el;\n\t\t}\n\t\treturn false;\n\t}\n\n\tfunction repaintRollupTask(task, itemNode, timeline, config, viewPort) {\n\t\tconst el = document.createElement(\"div\"),\n\t\tsizes = gantt.getTaskPosition(task);\n\n\t\t// vertical position is not important for the rollup tasks as long as the parent is rendered\n\t\tviewPort.y = 0;\n\t\tviewPort.y_end = gantt.$task_bg.scrollHeight;\n\n\t\ttask.$rollup.forEach(function(itemId){\n\t\t\tconst child = gantt.getTask(itemId);\n\t\t\tconst rollupKey = getKey(child.id, task.id);\n\t\t\tlet isVisible = checkVisibility(child, viewPort, timeline, config, gantt);\n\t\t\tif (isVisible !== !!renderedNodes[rollupKey]) {\n\n\t\t\t\tif (isVisible) {\n\t\t\t\t\tconst element = generateChildElement(task, child, timeline, sizes);\n\t\t\t\t\trenderedNodes[rollupKey] = element || false;\n\t\t\t\t} else {\n\t\t\t\t\trenderedNodes[rollupKey] = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!!renderedNodes[rollupKey]) {\n\t\t\t\tel.appendChild(renderedNodes[rollupKey]);\n\t\t\t}\n\t\t\titemNode.innerHTML = \"\";\n\t\t\titemNode.appendChild(el);\n\t\t});\n\t}\n\n\n\n\treturn {\n\t\trender: renderRollupTask,\n\t\tupdate: repaintRollupTask,\n\t\t//getRectangle: getBarRectangle\n\t\tisInViewPort: isInViewPort,\n\t\tgetVisibleRange: getVisibleRange\n\t};\n}\n\nexport default createTaskRenderer;","\nimport createBaseBarRender from \"./task_bar_render\";\n//import isInViewPort from \"./viewport/is_split_task_in_viewport\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\n\nimport isInViewPortParent from \"./viewport/is_split_task_in_viewport\";\nimport isInViewPortChild from \"./viewport/is_bar_in_viewport\";\nimport { childrenHaveBaselines, getMilestoneHeight, getInvertedMilestoneHeight } from \"./baseline_helper\";\n\n\n\nfunction createTaskRenderer(gantt){\n\tconst defaultRender = createBaseBarRender(gantt);\n\n\tconst renderedNodes = {};\n\n\tfunction checkVisibility(child, viewPort, timeline, config, gantt){\n\t\tlet isVisible = !child.hide_bar;\n\t\t// GS-1195. Don't render split tasks that are outside the viewport\n\t\tif (config.smart_rendering && isVisible){\n\t\t\tisVisible = isInViewPortChild(child, viewPort, timeline, config, gantt);\n\t\t}\n\t\treturn isVisible;\n\t}\n\n\tfunction generateChildElement(task, child, timeline, sizes, childBaselines){\n\t\tif(child.hide_bar){\n\t\t\treturn;\n\t\t}\n\n\t\tconst isProject = gantt.isSummaryTask(child);\n\t\tif(isProject){\n\t\t\tgantt.resetProjectDates(child);\n\t\t}\n\n\t\tconst childCopy = gantt.copy(gantt.getTask(child.id));\n\t\tchildCopy.$rendered_at = task.id;\n\t\t// a way to filter split tasks:\n\t\tconst showSplitTask = gantt.callEvent(\"onBeforeSplitTaskDisplay\", [childCopy.id, childCopy, task.id]);\n\t\tif (showSplitTask === false){\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = defaultRender(childCopy, timeline);\n\t\tif(!element)\n\t\t\treturn;\n\n\t\tconst milestoneChild = child.type === gantt.config.types.milestone;\n\t\tlet milestoneWidth;\n\n\t\tconst parentHeight = sizes.rowHeight;\n\t\tconst childHeight = timeline.getBarHeight(childCopy.id, milestoneChild);\n\t\tlet padding = Math.floor((timeline.getItemHeight(task.id) - childHeight) / 2);\n\n\t\tif (milestoneChild){\n\t\t\tmilestoneWidth = getMilestoneHeight(childHeight);\n\t\t}\n\n\t\tif (childBaselines/*|| (child.bar_height !== \"full\" && child.bar_height < child.row_height)*/){\n\t\t\tif (milestoneChild){\n\t\t\t\tpadding = Math.floor((milestoneWidth - childHeight) / 2) + 2;\n\t\t\t} else {\n\t\t\t\tpadding = 2;\n\t\t\t}\t\n\t\t}\n\t\t// GS-2270: Split children shouldn't exceed the parent row height\n\t\tconst linkDragLeft = element.querySelector(\".gantt_link_control.task_start_date\");\n\t\tconst linkDragRight = element.querySelector(\".gantt_link_control.task_end_date\");\n\t\tif (milestoneChild){\n\t\t\tif (milestoneWidth > parentHeight){\n\t\t\t\tpadding = 2;\n\t\t\t\telement.style.height = parentHeight - padding + \"px\";\n\t\t\t\tconst offsetHeight = getInvertedMilestoneHeight(parentHeight);\n\t\t\t\tconst offsetMargin = (offsetHeight - parentHeight) / 2;\n\t\t\t\tconst taskContent = element.querySelector(\".gantt_task_content\");\n\t\t\t\tpadding = Math.abs(offsetMargin);\n\n\t\t\t\tlinkDragLeft.style.marginLeft = offsetMargin + \"px\";\n\t\t\t\tlinkDragRight.style.marginRight = offsetMargin + \"px\";\n\t\t\t\tlinkDragLeft.style.height = linkDragRight.style.height = offsetHeight + \"px\";\n\n\t\t\t\telement.style.width = \n\t\t\t\ttaskContent.style.height = \n\t\t\t\ttaskContent.style.width = offsetHeight + \"px\";\n\t\t\t\telement.style.left = timeline.getItemPosition(childCopy).left - offsetHeight / 2 + \"px\";\n\t\t\t}\n\t\t} else if (childHeight + padding > parentHeight){\n\t\t\tpadding = 0;\n\t\t\telement.style.height = \n\t\t\telement.style.lineHeight = \n\t\t\tlinkDragLeft.style.height = \n\t\t\tlinkDragRight.style.height = parentHeight + \"px\";\n\t\t}\n\n\t\telement.style.top = (sizes.top + padding) + \"px\";\n\t\telement.classList.add(\"gantt_split_child\");\n\t\tif(isProject){\n\t\t\telement.classList.add(\"gantt_split_subproject\");\n\t\t}\n\n\t\treturn element;\n\t}\n\n\tfunction getKey(childId, renderParentId){\n\t\treturn childId + \"_\" + renderParentId;\n\t}\n\n\tfunction shouldUseSplitRendering(task, config){\n\t\treturn (gantt.isSplitTask(task) && ((config.open_split_tasks && !task.$open) || !config.open_split_tasks) && gantt.hasChild(task.id));\n\t}\n\n\tfunction renderSplitTask(task, timeline, config, viewPort) {\n\t\tif (shouldUseSplitRendering(task, config)) {\n\t\t\tconst el = document.createElement('div'),\n\t\t\t\tsizes = gantt.getTaskPosition(task);\n\n\t\t\tconst childBaselines = childrenHaveBaselines(gantt, task.id);\n\n\t\t\tif(gantt.hasChild(task.id)){\n\n\t\t\t\tgantt.eachTask(function(child){\n\t\t\t\t\tlet isVisible = checkVisibility(child, viewPort, timeline, config, gantt);\n\t\t\t\t\tif (!isVisible){\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst element = generateChildElement(task, child, timeline, sizes, childBaselines);\n\t\t\t\t\tif (element) {\n\t\t\t\t\t\trenderedNodes[getKey(child.id, task.id)] = element;\n\t\t\t\t\t\tel.appendChild(element);\n\t\t\t\t\t}else{\n\t\t\t\t\t\trenderedNodes[getKey(child.id, task.id)] = false;\n\t\t\t\t\t}\n\n\t\t\t\t}, task.id);\n\t\t\t}\n\t\t\treturn el;\n\t\t}\n\t\treturn false;\n\t}\n\tfunction repaintSplitTask(task, itemNode, timeline, config, viewPort) {\n\t\tif (shouldUseSplitRendering(task, config)) {\n\t\t\tconst el = document.createElement(\"div\"),\n\t\t\tsizes = gantt.getTaskPosition(task);\n\n\t\t\tconst childBaselines = childrenHaveBaselines(gantt, task.id);\n\t\t\tgantt.eachTask(function (child) {\n\t\t\t\tconst splitKey = getKey(child.id, task.id);\n\t\t\t\tlet isVisible = checkVisibility(child, viewPort, timeline, config, gantt);\n\t\t\t\tif (isVisible !== !!renderedNodes[splitKey]) {\n\n\t\t\t\t\tif (isVisible) {\n\t\t\t\t\t\tconst element = generateChildElement(task, child, timeline, sizes, childBaselines);\n\t\t\t\t\t\trenderedNodes[splitKey] = element || false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\trenderedNodes[splitKey] = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!!renderedNodes[splitKey]) {\n\t\t\t\t\tel.appendChild(renderedNodes[splitKey]);\n\t\t\t\t}\n\t\t\t\titemNode.innerHTML = \"\";\n\t\t\t\titemNode.appendChild(el);\n\t\t\t}, task.id);\n\t\t}\n\t}\n\treturn {\n\t\trender: renderSplitTask,\n\t\tupdate: repaintSplitTask,\n\t\tisInViewPort: isInViewPortParent,\n\t\tgetVisibleRange: getVisibleRange\n\t};\n}\n\nexport default createTaskRenderer;","import isInViewPort from \"./viewport/is_link_in_viewport\";\nimport getVisibleRange from \"./viewport/factory/get_visible_link_range\";\nimport { childrenHaveBaselines, getMaxParentHeight } from \"./baseline_helper\";\n\n\nfunction createLinkRender(gantt){\n\nfunction _render_link_element(link, view, config) {\n\tvar source = gantt.getTask(link.source);\n\tif(source.hide_bar){\n\t\treturn;\n\t}\n\n\tvar target = gantt.getTask(link.target);\n\tif(target.hide_bar){\n\t\treturn;\n\t}\n\n\tvar pt = path_builder.get_endpoint(link, view, source, target);\n\tvar dy = pt.e_y - pt.y;\n\tvar dx = pt.e_x - pt.x;\n\tif(!dx && !dy){\n\t\treturn null;\n\t}\n\n\n\tvar dots = path_builder.get_points(link, view, source, target);\n\tconst lines = drawer.get_lines(dots, view);\n\n\tconst shapes = transform_lines_to_shapes(lines.filter(l => l.size > 0), config);\n \n\tconst div = render_shapes(shapes, view, link, config);\n\n\n\tvar css = \"gantt_task_link\";\n\n\tif (link.color) {\n\t\tcss += \" gantt_link_inline_color\";\n\t}\n\tvar cssTemplate = gantt.templates.link_class ? gantt.templates.link_class(link) : \"\";\n\tif (cssTemplate) {\n\t\tcss += \" \" + cssTemplate;\n\t}\n\n\tif (config.highlight_critical_path && gantt.isCriticalLink) {\n\t\tif (gantt.isCriticalLink(link))\n\t\t\tcss += \" gantt_critical_link\";\n\t}\n\n\tdiv.className = css;\n\n\tif(view.$config.link_attribute){\n\t\tdiv.setAttribute(view.$config.link_attribute, link.id);\n\t\tdiv.setAttribute(\"link_id\", link.id);\n\t}\n\tif (link.color) {\n\t\tdiv.style.setProperty(\"--dhx-gantt-link-background\", link.color);\n\t}\n\n\tgantt._waiAria.linkAttr(link, div);\n\n\treturn div;\n}\n\n\tfunction render_shapes(shapes, view, link, config) {\n\t\tconst container = document.createElement(\"div\");\n\n\t\tshapes.forEach(shape => {\n\t\t\tlet element;\n\t\t\tif (shape.type === 'line') {\n\t\t\t\telement = drawer.render_line(shape.data, null, view, link.source);\n\t\t\t} else if (shape.type === 'corner') {\n\t\t\t\telement = drawer.render_corner(shape.data, view);\n\t\t\t}else if (shape.type === 'arrow') {\n\t\t\t\telement = drawer.render_arrow(shape.data, config);\n\t\t\t}\n\n\t\t\tcontainer.appendChild(element);\n\t\t});\n\n\t\treturn container;\n\t}\n\n\tfunction transform_lines_to_shapes(lines, config) {\n\t\tconst radius = config.link_radius || 4;\n\t\tconst arrowSize = config.link_arrow_size || 6; // Arrow size from config\n\t\tconst shapes = [];\n\t\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\tconst line = lines[i];\n\t\t\tconst nextLine = lines[i + 1];\n\t\n\t\t\tif (!nextLine || config.link_radius <= 1) {\n\t\t\t\tshapes.push({ type: 'line', data: line });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tif (line.direction !== nextLine.direction) {\n\t\t\t\tif(line.size < radius || nextLine.size < radius){\n\t\t\t\t\tshapes.push({ type: 'line', data: line });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tline.size -= radius;\n\t\t\t\tshapes.push({ type: 'line', data: line });\n\t\n\t\t\t\tlet cornerX = line.x;\n\t\t\t\tlet cornerY = line.y - config.link_line_width / 2;\n\t\n\t\t\t\tswitch (line.direction) {\n\t\t\t\t\tcase 'right':\n\t\t\t\t\t\tcornerX += line.size;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'left':\n\t\t\t\t\t\tcornerX -= line.size;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'down':\n\t\t\t\t\t\tcornerY += line.size;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'up':\n\t\t\t\t\t\tcornerY -= line.size;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\n\t\t\t\tconst corner = {\n\t\t\t\t\tx: cornerX,\n\t\t\t\t\ty: cornerY,\n\t\t\t\t\tdirection: { from: line.direction, to: nextLine.direction },\n\t\t\t\t\tradius\n\t\t\t\t};\n\t\t\t\tshapes.push({ type: 'corner', data: corner });\n\t\n\t\t\t\tswitch (nextLine.direction) {\n\t\t\t\t\tcase 'right':\n\t\t\t\t\t\tnextLine.x += radius;\n\t\t\t\t\t\tnextLine.size -= radius;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'left':\n\t\t\t\t\t\tnextLine.x -= radius;\n\t\t\t\t\t\tnextLine.size -= radius;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'down':\n\t\t\t\t\t\tnextLine.y += radius;\n\t\t\t\t\t\tnextLine.size -= radius;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'up':\n\t\t\t\t\t\tnextLine.y -= radius;\n\t\t\t\t\t\tnextLine.size -= radius;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tshapes.push({ type: 'line', data: line });\n\t\t\t}\n\t\t}\n\t\n\t\tconst lastLine = lines[lines.length - 1];\n\t\n\t\tif (lastLine.direction === 'right' || lastLine.direction === 'left') {\n\t\t\tlastLine.size -= arrowSize*3/4; \n\t\n\t\t\tlet arrowX = lastLine.direction === 'right' ? (lastLine.x + lastLine.size) : lastLine.x - lastLine.size - arrowSize/2;\n\t\t\tlet arrowY = lastLine.y - (config.link_line_width / 2) - (arrowSize / 2) + 1;\n\t\n\t\t\tif(lastLine.direction === 'left'){\n\t\t\t\tarrowY -= 1;// left pointing arrows for some reason need adjustments\n\t\t\t\tarrowX -= 2;\n\t\t\t}else{\n\t\t\t\tarrowX -= 1;\n\t\t\t}\n\t\t\tconst arrow = {\n\t\t\t\tx: arrowX,\n\t\t\t\ty: arrowY,\n\t\t\t\tsize: arrowSize,\n\t\t\t\tdirection: lastLine.direction\n\t\t\t};\n\t\n\t\t\tshapes.push({ type: 'line', data: lastLine });\n\t\t\tshapes.push({ type: 'arrow', data: arrow });\n\t\t} else {\n\t\t\tshapes.push({ type: 'line', data: lastLine });\n\t\t}\n\t\n\t\treturn shapes;\n\t}\n\t\n\n\nvar drawer = {\n\tcurrent_pos: null,\n\tdirs: {\"left\": 'left', \"right\": 'right', \"up\": 'up', \"down\": 'down'},\n\tpath: [],\n\tclear: function () {\n\t\tthis.current_pos = null;\n\t\tthis.path = [];\n\t},\n\tpoint: function (pos) {\n\t\tthis.current_pos = gantt.copy(pos);\n\t},\n\tget_lines: function (dots) {\n\t\tthis.clear();\n\t\tthis.point(dots[0]);\n\t\tfor (var i = 1; i < dots.length; i++) {\n\t\t\tthis.line_to(dots[i]);\n\t\t}\n\t\treturn this.get_path();\n\t},\n\tline_to: function (pos) {\n\t\tvar next = gantt.copy(pos);\n\t\tvar prev = this.current_pos;\n\n\t\tvar line = this._get_line(prev, next);\n\t\tthis.path.push(line);\n\t\tthis.current_pos = next;\n\t},\n\tget_path: function () {\n\t\treturn this.path;\n\t},\n\tget_wrapper_sizes: function (v, view, itemId) {\n\t\tvar config = view.$getConfig();\n\t\tvar res,\n\t\t\twrapper_size = config.link_wrapper_width,\n\t\t\ty = v.y - (wrapper_size) / 2;\n\t\tswitch (v.direction) {\n\t\t\tcase this.dirs.left:\n\t\t\t\tres = {\n\t\t\t\t\ttop: y,\n\t\t\t\t\theight: wrapper_size,\n\t\t\t\t\tlineHeight: wrapper_size,\n\t\t\t\t\tleft: v.x - v.size - wrapper_size / 2,\n\t\t\t\t\twidth: v.size + wrapper_size\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase this.dirs.right:\n\t\t\t\tres = {\n\t\t\t\t\ttop: y,\n\t\t\t\t\tlineHeight: wrapper_size,\n\t\t\t\t\theight: wrapper_size,\n\t\t\t\t\tleft: v.x - wrapper_size / 2,\n\t\t\t\t\twidth: v.size + wrapper_size\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase this.dirs.up:\n\t\t\t\tres = {\n\t\t\t\t\ttop: y - v.size,\n\t\t\t\t\tlineHeight: v.size + wrapper_size,\n\t\t\t\t\theight: v.size + wrapper_size,\n\t\t\t\t\tleft: v.x - wrapper_size / 2,\n\t\t\t\t\twidth: wrapper_size\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase this.dirs.down:\n\t\t\t\tres = {\n\t\t\t\t\ttop: y /*- wrapper_size/2*/,\n\t\t\t\t\tlineHeight: v.size + wrapper_size,\n\t\t\t\t\theight: v.size + wrapper_size,\n\t\t\t\t\tleft: v.x - wrapper_size / 2,\n\t\t\t\t\twidth: wrapper_size\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn res;\n\t},\n\tget_line_sizes: function (v, view) {\n\t\tvar config = view.$getConfig();\n\t\tvar res,\n\t\t\tline_size = config.link_line_width,\n\t\t\twrapper_size = config.link_wrapper_width,\n\t\t\tsize = v.size + line_size;\n\t\tswitch (v.direction) {\n\t\t\tcase this.dirs.left:\n\t\t\tcase this.dirs.right:\n\t\t\t\tres = {\n\t\t\t\t\theight: line_size,\n\t\t\t\t\twidth: size,\n\t\t\t\t\tmarginTop: (wrapper_size - line_size) / 2,\n\t\t\t\t\tmarginLeft: (wrapper_size - line_size) / 2\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase this.dirs.up:\n\t\t\tcase this.dirs.down:\n\t\t\t\tres = {\n\t\t\t\t\theight: size,\n\t\t\t\t\twidth: line_size,\n\t\t\t\t\tmarginTop: (wrapper_size - line_size) / 2,\n\t\t\t\t\tmarginLeft: (wrapper_size - line_size) / 2\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\n\t\treturn res;\n\t},\n\trender_line: function (v, end, view, itemId) {\n\t\tvar pos = this.get_wrapper_sizes(v, view, itemId);\n\t\tvar wrapper = document.createElement(\"div\");\n\t\twrapper.style.cssText = [\n\t\t\t\"top:\" + pos.top + \"px\",\n\t\t\t\"left:\" + pos.left + \"px\",\n\t\t\t\"height:\" + pos.height + \"px\",\n\t\t\t\"width:\" + pos.width + \"px\"\n\t\t].join(';');\n\t\twrapper.className = \"gantt_line_wrapper\";\n\n\t\tvar innerPos = this.get_line_sizes(v, view);\n\t\tvar inner = document.createElement(\"div\");\n\t\tinner.style.cssText = [\n\t\t\t\"height:\" + innerPos.height + \"px\",\n\t\t\t\"width:\" + innerPos.width + \"px\",\n\t\t\t\"margin-top:\" + innerPos.marginTop + \"px\",\n\t\t\t\"margin-left:\" + innerPos.marginLeft + \"px\"\n\t\t].join(\";\");\n\n\t\tinner.className = \"gantt_link_line_\" + v.direction;\n\t\twrapper.appendChild(inner);\n\n\t\treturn wrapper;\n\t},\n\n\trender_corner: function (corner, view) {\n\t\tconst radius = corner.radius;\n\t\tconst config = view.$getConfig();\n\t\tconst lineWidth = config.link_line_width || 2;\n\t\tconst cornerDiv = document.createElement(\"div\");\n\t\n\t\tcornerDiv.classList.add(\"gantt_link_corner\");\n\t\tcornerDiv.classList.add(`gantt_link_corner_${corner.direction.from}_${corner.direction.to}`);\n\t\n\t\tcornerDiv.style.width = `${radius}px`;\n\t\tcornerDiv.style.height = `${radius}px`;\n\t\n\t\tlet borderVertical;\n\t\tlet borderHorizontal;\n\n\t\tif (corner.direction.from === 'right' && corner.direction.to === 'down') {\n\t\t\tborderVertical = \"Right\";\n\t\t\tborderHorizontal = \"Top\";\n\t\t\tcornerDiv.style.left = `${corner.x - config.link_line_width/2}px`;\n\t\t\tcornerDiv.style.top = `${corner.y}px`;\n\t\t} else if (corner.direction.from === 'down' && corner.direction.to === 'right') {\n\t\t\tborderVertical = \"Left\";\n\t\t\tborderHorizontal = \"Bottom\";\n\t\t\tcornerDiv.style.left = `${corner.x - config.link_line_width/2}px`;\n\t\t\tcornerDiv.style.top = `${corner.y}px`;\n\t\t} else if (corner.direction.from === 'right' && corner.direction.to === 'up') {\n\t\t\tborderVertical = \"Right\";\n\t\t\tborderHorizontal = \"Bottom\";\n\t\t\tcornerDiv.style.left = `${corner.x - config.link_line_width/2}px`;\n\t\t\tcornerDiv.style.top = `${corner.y - radius}px`;\n\t\t} else if (corner.direction.from === 'up' && corner.direction.to === 'right') {\n\t\t\tborderVertical = \"Left\";\n\t\t\tborderHorizontal = \"Top\";\n\t\t\tcornerDiv.style.left = `${corner.x - config.link_line_width/2}px`;\n\t\t\tcornerDiv.style.top = `${corner.y - radius}px`;\n\t\t} else if (corner.direction.from === 'left' && corner.direction.to === 'down') {\n\t\t\tborderVertical = \"Left\";\n\t\t\tborderHorizontal = \"Top\";\n\t\t\tcornerDiv.style.left = `${corner.x - radius - config.link_line_width/2}px`;\n\t\t\tcornerDiv.style.top = `${corner.y}px`;\n\t\t} else if (corner.direction.from === 'down' && corner.direction.to === 'left') {\n\t\t\tborderVertical = \"Right\";\n\t\t\tborderHorizontal = \"Bottom\";\n\t\t\tcornerDiv.style.left = `${corner.x - radius - config.link_line_width/2}px`;\n\t\t\tcornerDiv.style.top = `${corner.y}px`;\n\t\t} else if (corner.direction.from === 'left' && corner.direction.to === 'up') {\n\t\t\tborderVertical = \"Left\";\n\t\t\tborderHorizontal = \"Bottom\";\n\t\t\tcornerDiv.style.left = `${corner.x - radius - config.link_line_width/2}px`;\n\t\t\tcornerDiv.style.top = `${corner.y - radius}px`;\n\t\t} else if (corner.direction.from === 'up' && corner.direction.to === 'left') {\n\t\t\tborderVertical = \"Right\";\n\t\t\tborderHorizontal = \"Top\";\n\t\t\tcornerDiv.style.left = `${corner.x - radius - config.link_line_width/2}px`;\n\t\t\tcornerDiv.style.top = `${corner.y - radius}px`;\n\t\t}\n\n\t\tcornerDiv.style[`border${borderHorizontal}Width`] = `${lineWidth}px`;\n\t\tcornerDiv.style[`border${borderVertical}Width`] = `${lineWidth}px`;\n\t\tcornerDiv.style[`border${borderVertical}Style`] = `solid`;\n\t\tcornerDiv.style[`border${borderHorizontal}Style`] = `solid`;\n\t\tcornerDiv.style[`border${borderHorizontal}${borderVertical}Radius`] = `${radius}px`;\n\n\t\n\t\treturn cornerDiv;\n\t},\n\n\trender_arrow(arrow, config) {\n\t\tvar div = document.createElement(\"div\");\n\t\tvar top = arrow.y;\n\t\tvar left = arrow.x;\n\t\n\t\tvar size = config.link_arrow_size;\n\t\tdiv.style.setProperty(\"--dhx-gantt-icon-size\", `${size}px`);\n\t\n\t\tvar className = \"gantt_link_arrow gantt_link_arrow_\" + arrow.direction;\n\n\t\tdiv.style.top = top + \"px\";\n\t\tdiv.style.left = left + 'px';\n\t\tdiv.className = className;\n\t\n\t\treturn div;\n\t},\n\t\n\t_get_line: function (from, to) {\n\t\tvar direction = this.get_direction(from, to);\n\t\tvar vect = {\n\t\t\tx: from.x,\n\t\t\ty: from.y,\n\t\t\tdirection: this.get_direction(from, to)\n\t\t};\n\t\tif (direction == this.dirs.left || direction == this.dirs.right) {\n\t\t\tvect.size = Math.abs(from.x - to.x);\n\t\t} else {\n\t\t\tvect.size = Math.abs(from.y - to.y);\n\t\t}\n\t\treturn vect;\n\t},\n\tget_direction: function (from, to) {\n\t\tvar direction = 0;\n\t\tif (to.x < from.x) {\n\t\t\tdirection = this.dirs.left;\n\t\t} else if (to.x > from.x) {\n\t\t\tdirection = this.dirs.right;\n\t\t} else if (to.y > from.y) {\n\t\t\tdirection = this.dirs.down;\n\t\t} else {\n\t\t\tdirection = this.dirs.up;\n\t\t}\n\t\treturn direction;\n\t}\n\n};\n\nvar path_builder = {\n\n\tpath: [],\n\tclear: function () {\n\t\tthis.path = [];\n\t},\n\tcurrent: function () {\n\t\treturn this.path[this.path.length - 1];\n\t},\n\tpoint: function (next) {\n\t\tif (!next)\n\t\t\treturn this.current();\n\n\t\tthis.path.push(gantt.copy(next));\n\t\treturn next;\n\t},\n\tpoint_to: function (direction, diff, point) {\n\t\tif (!point)\n\t\t\tpoint = gantt.copy(this.point());\n\t\telse\n\t\t\tpoint = {x: point.x, y: point.y};\n\t\tvar dir = drawer.dirs;\n\t\tswitch (direction) {\n\t\t\tcase (dir.left):\n\t\t\t\tpoint.x -= diff;\n\t\t\t\tbreak;\n\t\t\tcase (dir.right):\n\t\t\t\tpoint.x += diff;\n\t\t\t\tbreak;\n\t\t\tcase (dir.up):\n\t\t\t\tpoint.y -= diff;\n\t\t\t\tbreak;\n\t\t\tcase (dir.down):\n\t\t\t\tpoint.y += diff;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn this.point(point);\n\t},\n\tget_points: function (link, view, source, target) {\n\t\tvar pt = this.get_endpoint(link, view, source, target);\n\t\tvar xy = gantt.config;\n\n\t\tvar dy = pt.e_y - pt.y;\n\t\tvar dx = pt.e_x - pt.x;\n\n\t\tvar dir = drawer.dirs;\n\n\t\tvar rowHeight = view.getItemHeight(link.source);\n\n\t\tthis.clear();\n\t\tthis.point({x: pt.x, y: pt.y});\n\n\t\tvar shiftX = 2 * xy.link_arrow_size;//just random size for first line\n\t\tvar lineType = this.get_line_type(link, view.$getConfig());\n\n\t\tvar forward = (pt.e_x > pt.x);\n\t\tif (lineType.from_start && lineType.to_start) {\n\t\t\tthis.point_to(dir.left, shiftX);\n\t\t\tif (forward) {\n\t\t\t\tthis.point_to(dir.down, dy);\n\t\t\t\tthis.point_to(dir.right, dx);\n\t\t\t} else {\n\t\t\t\tthis.point_to(dir.right, dx);\n\t\t\t\tthis.point_to(dir.down, dy);\n\t\t\t}\n\t\t\tthis.point_to(dir.right, shiftX);\n\n\t\t} else if (!lineType.from_start && lineType.to_start) {\n\t\t\t// GS-2619. No need to add loops for the split tasks (zero dy means the tasks are on the same line)\n\t\t\tif (dy !== 0){\n\t\t\t\tforward = (pt.e_x > (pt.x + 2 * shiftX));\n\t\t\t}\n\t\t\tthis.point_to(dir.right, shiftX);\n\t\t\tif (forward) {\n\t\t\t\tdx -= shiftX;\n\t\t\t\tthis.point_to(dir.down, dy);\n\t\t\t\tthis.point_to(dir.right, dx);\n\t\t\t} else {\n\t\t\t\tdx -= 2 * shiftX;\n\t\t\t\tvar sign = dy > 0 ? 1 : -1;\n\n\t\t\t\tthis.point_to(dir.down, sign * (rowHeight / 2));\n\t\t\t\tthis.point_to(dir.right, dx);\n\t\t\t\tthis.point_to(dir.down, sign * ( Math.abs(dy) - (rowHeight / 2)));\n\t\t\t\tthis.point_to(dir.right, shiftX);\n\t\t\t}\n\n\t\t} else if (!lineType.from_start && !lineType.to_start) {\n\t\t\tthis.point_to(dir.right, shiftX);\n\t\t\tif (forward) {\n\t\t\t\tthis.point_to(dir.right, dx);\n\t\t\t\tthis.point_to(dir.down, dy);\n\t\t\t} else {\n\t\t\t\tthis.point_to(dir.down, dy);\n\t\t\t\tthis.point_to(dir.right, dx);\n\t\t\t}\n\t\t\tthis.point_to(dir.left, shiftX);\n\t\t} else if (lineType.from_start && !lineType.to_start) {\n\t\t\t// GS-2619. No need to add loops for the split tasks (zero dy means the tasks are on the same line)\n\t\t\tif (dy !== 0){\n\t\t\t\tforward = (pt.e_x > (pt.x - 2 * shiftX));\n\t\t\t}\n\t\t\tthis.point_to(dir.left, shiftX);\n\n\t\t\tif (!forward) {\n\t\t\t\tdx += shiftX;\n\t\t\t\tthis.point_to(dir.down, dy);\n\t\t\t\tthis.point_to(dir.right, dx);\n\t\t\t} else {\n\t\t\t\tdx += 2 * shiftX;\n\t\t\t\tvar sign = dy > 0 ? 1 : -1;\n\t\t\t\tthis.point_to(dir.down, sign * (rowHeight / 2));\n\t\t\t\tthis.point_to(dir.right, dx);\n\t\t\t\tthis.point_to(dir.down, sign * ( Math.abs(dy) - (rowHeight / 2)));\n\t\t\t\tthis.point_to(dir.left, shiftX);\n\t\t\t}\n\n\t\t}\n\n\t\treturn this.path;\n\t},\n\tget_line_type: function(link, config){\n\t\tvar types = config.links;\n\t\tvar from_start = false, to_start = false;\n\t\tif (link.type == types.start_to_start) {\n\t\t\tfrom_start = to_start = true;\n\t\t} else if (link.type == types.finish_to_finish) {\n\t\t\tfrom_start = to_start = false;\n\t\t} else if (link.type == types.finish_to_start) {\n\t\t\tfrom_start = false;\n\t\t\tto_start = true;\n\t\t} else if (link.type == types.start_to_finish) {\n\t\t\tfrom_start = true;\n\t\t\tto_start = false;\n\t\t} else {\n\t\t\tgantt.assert(false, \"Invalid link type\");\n\t\t}\n\n\t\tif(config.rtl){\n\t\t\tfrom_start = !from_start;\n\t\t\tto_start = !to_start;\n\t\t}\n\n\t\treturn {from_start: from_start, to_start: to_start};\n\t},\n\n\tget_endpoint: function (link, view, source, target) {\n\t\tvar config = view.$getConfig();\n\n\t\tvar lineType = this.get_line_type(link, config);\n\t\tvar from_start = lineType.from_start,\n\t\t\tto_start = lineType.to_start;\n\n\t\tvar from = getMilestonePosition(source, view, config),\n\t\t\tto = getMilestonePosition(target, view, config);\n\n\t\treturn {\n\t\t\tx: from_start ? from.left : (from.left + from.width),\n\t\t\te_x: to_start ? to.left : (to.left + to.width),\n\t\t\ty: from.top + (from.rowHeight/2) - 1,\n\t\t\te_y: to.top + (to.rowHeight/2) - 1\n\t\t};\n\t}\n};\n\nfunction getMilestonePosition(task, view, config){\n\tvar pos = view.getItemPosition(task);\n\n\t// GS-2270: Link to the split children shouldn't exceed the parent row height\n\tlet splitParams = getMaxParentHeight(gantt, view, task);\n\tlet maxHeight = splitParams.maxHeight;\n\n\tlet splitChild = splitParams.splitChild;\n\tconst baselinesOnDifferentRow = gantt.config.baselines !== false && (gantt.config.baselines.render_mode == \"separateRow\" || gantt.config.baselines.render_mode == \"individualRow\");\n\tconst baselines = baselinesOnDifferentRow && task.baselines && task.baselines.length;\n\n\tif (splitParams.shrinkHeight){\n\t\tpos.rowHeight = maxHeight;\n\t}\n\n\tlet milestoneWidth;\n\tlet milestoneTask = gantt.getTaskType(task.type) == config.types.milestone;\n\tif(milestoneTask){\n\t\tlet milestoneHeight = view.getBarHeight(task.id, true);\n\t\tmilestoneWidth = Math.sqrt(2*milestoneHeight*milestoneHeight);\n\t\tif (splitParams.shrinkHeight && maxHeight < milestoneHeight){\n\t\t\tmilestoneHeight = maxHeight;\n\t\t\tmilestoneWidth = maxHeight;\n\t\t}\n\t\tpos.left -= milestoneWidth / 2;\n\t\tpos.width = milestoneWidth;\n\t} \n\tif (splitChild){\n\t\tif (maxHeight >= pos.height) {\n\t\t\tconst siblingBaselines = childrenHaveBaselines(gantt, task.parent);\n\t\t\tif (baselines || siblingBaselines){\n\t\t\t\tif (milestoneTask){\n\t\t\t\t\tpos.rowHeight = pos.height + 4;\n\t\t\t\t\tpos.left += (pos.width - pos.rowHeight + 4) / 2;\n\t\t\t\t\tpos.width = pos.rowHeight - 3;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpos.rowHeight = pos.height + 6;\n\t\t\t\t}\n\t\t\t} else if (milestoneTask) {\n\t\t\t\tpos.left += (milestoneWidth - pos.height) / 2;\n\t\t\t}\n\t\t} else {\n\t\t\tpos.rowHeight = maxHeight + 2;\n\t\t\tif (milestoneTask){\n\t\t\t\tpos.left += (pos.width - pos.rowHeight + 4) / 2;\n\t\t\t\tpos.width = pos.rowHeight - 3;\n\t\t\t}\n\t\t}\n\t} else if (baselines){\n\t\tpos.rowHeight = pos.height + 4;\n\t}\n\n\treturn pos;\n}\n\n\nreturn {\n\trender: _render_link_element,\n\tupdate: null,\n\t//getRectangle: getLinkRectangle\n\tisInViewPort: isInViewPort,\n\tgetVisibleRange: getVisibleRange()\n};\n}\n\nexport default createLinkRender;","import getRectangle from \"./viewport/get_bg_row_rectangle\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport getVisibleCellsRange from \"./viewport/get_visible_cells_range\";\nimport isColumnVisible from \"./viewport/is_column_visible\";\nimport resourceTimetable from \"../../resource_timetable_builder\";\n\nfunction generateRenderResourceLine(gantt){\n\tvar getResourceLoad = resourceTimetable(gantt);\n\tvar renderedResourceLines = {};\n\n\tfunction renderResourceLineCell(resource, day, templates, config, timeline){\n\t\tvar css = templates.resource_cell_class(day.start_date, day.end_date, resource, day.tasks, day.assignments);\n\t\tvar content = templates.resource_cell_value(day.start_date, day.end_date, resource, day.tasks, day.assignments);\n\t\tvar height = timeline.getItemHeight(resource.id) - 1;\n\n\t\tif (css || content){\n\t\t\tvar sizes = timeline.getItemPosition(resource, day.start_date, day.end_date);\n\t\t\tvar el = document.createElement('div');\n\t\t\tel.setAttribute(timeline.$config.item_attribute, resource.id);\n\t\t\tel.className = [\"gantt_resource_marker\", css].join(\" \");\n\n\t\t\tel.style.cssText = [\n\t\t\t\t'left:' + sizes.left + 'px',\n\t\t\t\t'width:' + sizes.width + 'px',\n\t\t\t\t'height:' + (height) + 'px',\n\t\t\t\t'line-height:' + (height) + 'px',\n\t\t\t\t'top:' + sizes.top + 'px'\n\t\t\t].join(\";\");\n\n\t\t\tif(content)\n\t\t\t\tel.innerHTML = content;\n\n\t\t\treturn el;\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction detachRenderedResourceLine(id, index){\n\t\tif(renderedResourceLines[id] && renderedResourceLines[id][index] &&\n\t\t\trenderedResourceLines[id][index].parentNode\n\t\t\t){\n\t\t\t\trenderedResourceLines[id][index].parentNode.removeChild(renderedResourceLines[id][index]);\n\t\t\t}\n\t}\n\n\tfunction renderResourceLine(resource, timeline, config, viewport) {\n\t\tvar templates = timeline.$getTemplates();\n\t\tvar scale = timeline.getScale();\n\t\tvar timetable = getResourceLoad(resource, config.resource_property, timeline.getScale(), timeline);\n\t\tvar smartRendering = !!viewport;//no viewport means smart rendering is disabled\n\t\tvar cells = [];\n\t\trenderedResourceLines[resource.id] = {};\n\n\t\tvar range = getVisibleCellsRange(scale, viewport);\n\t\tfor (var columnIndex = range.start; columnIndex <= range.end; columnIndex++) {\n\n\t\t\tvar day = timetable[columnIndex];\n\t\t\tif(!day){\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(smartRendering && !isColumnVisible(columnIndex, scale, viewport, gantt)){\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvar cell = renderResourceLineCell(resource, day, templates, config, timeline);\n\t\t\tif(cell){\n\t\t\t\tcells.push(cell);\n\t\t\t\trenderedResourceLines[resource.id][columnIndex] = cell;\n\t\t\t}\n\t\t}\n\n\t\tvar row = null;\n\t\tif(cells.length){\n\t\t\trow = document.createElement(\"div\");\n\t\t\tfor(var i = 0; i < cells.length; i++){\n\t\t\t\trow.appendChild(cells[i]);\n\t\t\t}\n\t\t}\n\t\treturn row;\n\t}\n\n\tfunction updateResourceLine(resource, node, timeline, config, viewport) {\n\t\tvar templates = timeline.$getTemplates();\n\t\tvar scale = timeline.getScale();\n\t\tvar timetable = getResourceLoad(resource, config.resource_property, timeline.getScale(), timeline);\n\n\t\tvar range = getVisibleCellsRange(scale, viewport);\n\n\t\tvar checkedColumns = {};\n\t\tif(renderedResourceLines && renderedResourceLines[resource.id]){\n\t\t\tfor(var i in renderedResourceLines[resource.id]){\n\t\t\t\tcheckedColumns[i] = i;\n\t\t\t}\n\t\t}\n\n\t\tfor (var columnIndex = range.start; columnIndex <= range.end; columnIndex++) {\n\t\t\tvar day = timetable[columnIndex];\n\t\t\tcheckedColumns[columnIndex] = false;\n\t\t\tif(!day){\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(!isColumnVisible(columnIndex, scale, viewport, gantt)){\n\t\t\t\tdetachRenderedResourceLine(resource.id, columnIndex);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(!renderedResourceLines[resource.id] || !renderedResourceLines[resource.id][columnIndex]){\n\t\t\t\tvar cell = renderResourceLineCell(resource, day, templates, config, timeline);\n\t\t\t\tif(cell){\n\t\t\t\t\tnode.appendChild(cell);\n\t\t\t\t\trenderedResourceLines[resource.id][columnIndex] = cell;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if(renderedResourceLines[resource.id] && renderedResourceLines[resource.id][columnIndex] && !renderedResourceLines[resource.id][columnIndex].parentNode){\n\t\t\t\tnode.appendChild(renderedResourceLines[resource.id][columnIndex]);\n\t\t\t}\n\t\t}\n\n\t\tfor(var i in checkedColumns){\n\t\t\tif(checkedColumns[i] !== false){\n\t\t\t\tdetachRenderedResourceLine(resource.id, i);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\trender: renderResourceLine,\n\t\tupdate: updateResourceLine,\n\t\tgetRectangle: getRectangle,\n\t\tgetVisibleRange: getVisibleRange\n\t};\n}\n\nexport default generateRenderResourceLine;","import getRectangle from \"./viewport/get_bg_row_rectangle\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\nimport getVisibleCellsRange from \"./viewport/get_visible_cells_range\";\nimport isColumnVisible from \"./viewport/is_column_visible\";\nimport resourceTimetable from \"../../resource_timetable_builder\";\n\nfunction renderBar(level, start, end, timeline){\n\tvar top = (1 - (level*1||0))*100;\n\tvar left = timeline.posFromDate(start);\n\tvar right = timeline.posFromDate(end);\n\tvar element = document.createElement(\"div\");\n\telement.className = \"gantt_histogram_hor_bar\";\n\telement.style.top = top + '%';\n\telement.style.left = left + \"px\";\n\telement.style.width = (right - left + 1) + \"px\";\n\treturn element;\n}\nfunction renderConnection(prevLevel, nextLevel, left){\n\tif(prevLevel === nextLevel){\n\t\treturn null;\n\t}\n\n\tvar top = 1 - Math.max(prevLevel, nextLevel);\n\tvar height = Math.abs(prevLevel - nextLevel);\n\tvar element = document.createElement(\"div\");\n\telement.className = \"gantt_histogram_vert_bar\";\n\telement.style.top = top*100 + \"%\";\n\telement.style.height = height*100 + \"%\";\n\telement.style.left = left + \"px\";\n\n\treturn element;\n}\n\nfunction generateRenderResourceHistogram(gantt){\n\tvar getResourceLoad = resourceTimetable(gantt);\n\tvar renderedHistogramCells = {};\n\tvar renderedHistogramRows = {};\n\tvar renderedHistogramCapacity = {};\n\n\tfunction detachRenderedHistogramCell(id, index){\n\n\t\tvar renderedRow = renderedHistogramCells[id];\n\t\tif(renderedRow && renderedRow[index] &&\n\t\t\trenderedRow[index].parentNode\n\t\t\t){\n\t\t\t\trenderedRow[index].parentNode.removeChild(renderedRow[index]);\n\t\t\t}\n\t}\n\n\tfunction renderHistogramLine(capacity, timeline, maxCapacity, viewport){\n\t\tvar scale = timeline.getScale();\n\n\t\tvar el = document.createElement(\"div\");\n\n\t\tvar range = getVisibleCellsRange(scale, viewport);\n\t\tfor (var i = range.start; i <= range.end; i++) {\n\t\t\tvar colStart = scale.trace_x[i];\n\t\t\tvar colEnd = scale.trace_x[i + 1] || gantt.date.add(colStart, scale.step, scale.unit);\n\t\t\tvar col = scale.trace_x[i].valueOf();\n\t\t\tvar level = Math.min(capacity[col]/maxCapacity, 1) || 0;\n\t\t\t// do not render histogram for lines with below zero capacity, as it's reserved for folders\n\t\t\tif(level < 0){\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar nextLevel = Math.min(capacity[colEnd.valueOf()]/maxCapacity, 1) || 0;\n\t\t\tvar bar = renderBar(level, colStart, colEnd, timeline);\n\t\t\tif(bar){\n\t\t\t\tel.appendChild(bar);\n\t\t\t}\n\t\t\tvar connection = renderConnection(level, nextLevel, timeline.posFromDate(colEnd));\n\t\t\tif(connection){\n\t\t\t\tel.appendChild(connection);\n\t\t\t}\n\n\t\t}\n\t\treturn el;\n\t}\n\n\tfunction renderCapacityElement(resource, sizes, capacityMatrix, config, timeline, maxCapacity, viewport){\n\n\t\tvar renderedElement = renderedHistogramCapacity[resource.id];\n\t\tif(renderedElement && renderedElement.parentNode){\n\t\t\trenderedElement.parentNode.removeChild(renderedElement);\n\t\t}\n\n\t\tvar capacityElement = renderHistogramLine(capacityMatrix, timeline, maxCapacity, viewport);\n\t\tif (capacityElement && sizes) {\n\t\t\tcapacityElement.setAttribute(\"data-resource-id\", resource.id);\n\t\t\tcapacityElement.setAttribute(timeline.$config.item_attribute, resource.id);\n\t\t\tcapacityElement.style.position = \"absolute\";\n\t\t\tcapacityElement.style.top = (sizes.top + 1) + \"px\";\n\t\t\tcapacityElement.style.height = (timeline.getItemHeight(resource.id) - 1) + \"px\";\n\t\t\tcapacityElement.style.left = 0;\n\t\t}\n\t\treturn capacityElement;\n\t}\n\n\tfunction renderHistogramCell(resource, sizes, maxCapacity, config, templates, day, timeline){\n\t\tvar css = templates.histogram_cell_class(day.start_date, day.end_date, resource, day.tasks, day.assignments);\n\t\tvar content = templates.histogram_cell_label(day.start_date, day.end_date, resource, day.tasks, day.assignments);\n\t\tvar fill = templates.histogram_cell_allocated(day.start_date, day.end_date, resource, day.tasks, day.assignments);\n\t\tvar height = timeline.getItemHeight(resource.id) - 1;\n\t\tif(css || content){\n\t\t\tvar el = document.createElement('div');\n\t\t\tel.className = [\"gantt_histogram_cell\", css].join(\" \");\n\t\t\tel.setAttribute(timeline.$config.item_attribute, resource.id);\n\t\t\tel.style.cssText = [\n\t\t\t\t'left:' + sizes.left + 'px',\n\t\t\t\t'width:' + sizes.width + 'px',\n\t\t\t\t'height:' + (height) + 'px',\n\t\t\t\t'line-height:' + (height) + 'px',\n\t\t\t\t'top:' + (sizes.top + 1) + 'px'\n\t\t\t].join(\";\");\n\n\n\t\t\tif (content) {\n\t\t\t\tcontent = \"
\" + content +\"
\";\n\t\t\t}\n\n\t\t\tif (fill) {\n\t\t\t\tcontent = \"
\" + content;\n\t\t\t}\n\n\t\t\tif (content) {\n\t\t\t\tel.innerHTML = content;\n\t\t\t}\n\n\t\t\treturn el;\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction renderResourceHistogram(resource, timeline, config, viewport) {\n\t\tvar templates = timeline.$getTemplates();\n\t\tvar scale = timeline.getScale();\n\t\tvar timetable = getResourceLoad(resource, config.resource_property, scale, timeline);\n\n\t\tvar cells = [];\n\t\tvar capacityMatrix = {};\n\t\tvar maxCapacity = resource.capacity || timeline.$config.capacity || 24;\n\t\trenderedHistogramCells[resource.id] = {};\n\t\trenderedHistogramRows[resource.id] = null;\n\t\trenderedHistogramCapacity[resource.id] = null;\n\n\t\tvar smartRendering = !!viewport;//no viewport means smart rendering is disabled\n\n\t\tvar range = getVisibleCellsRange(scale, viewport);\n\t\tfor (var columnIndex = range.start; columnIndex <= range.end; columnIndex++) {\n\n\t\t\tvar day = timetable[columnIndex];\n\t\t\tif(!day){\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(smartRendering && !isColumnVisible(columnIndex, scale, viewport, gantt)){\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvar capacity = templates.histogram_cell_capacity(day.start_date, day.end_date, resource, day.tasks, day.assignments);\n\t\t\tcapacityMatrix[day.start_date.valueOf()] = capacity || 0;\n\t\t\tvar sizes = timeline.getItemPosition(resource, day.start_date, day.end_date);\n\n\t\t\tvar el = renderHistogramCell(resource, sizes, maxCapacity, config, templates, day, timeline);\n\t\t\tif(el){\n\t\t\t\tcells.push(el);\n\t\t\t\trenderedHistogramCells[resource.id][columnIndex] = el;\n\t\t\t}\n\t\t}\n\n\t\tvar row = null;\n\t\tif (cells.length) {\n\t\t\trow = document.createElement(\"div\");\n\t\t\tfor (var i = 0; i < cells.length; i++) {\n\t\t\t\trow.appendChild(cells[i]);\n\t\t\t}\n\n\t\t\tvar capacityElement = renderCapacityElement(resource, sizes, capacityMatrix, config, timeline, maxCapacity, viewport);\n\t\t\tif(capacityElement){\n\t\t\t\trow.appendChild(capacityElement);\n\t\t\t\trenderedHistogramCapacity[resource.id] = capacityElement;\n\t\t\t}\n\t\t\trenderedHistogramRows[resource.id] = row;\n\t\t}\n\n\t\treturn row;\n\t}\n\n\tfunction updateResourceHistogram(resource, node, timeline, config, viewport) {\n\t\tvar templates = timeline.$getTemplates();\n\t\tvar scale = timeline.getScale();\n\t\tvar timetable = getResourceLoad(resource, config.resource_property, scale, timeline);\n\t\tvar maxCapacity = resource.capacity || timeline.$config.capacity || 24;\n\t\tvar capacityMatrix = {};\n\n\t\tvar smartRendering = !!viewport;//no viewport means smart rendering is disabled\n\n\t\tvar range = getVisibleCellsRange(scale, viewport);\n\n\t\tvar checkedColumns = {};\n\t\tif(renderedHistogramCells && renderedHistogramCells[resource.id]){\n\t\t\tfor(var i in renderedHistogramCells[resource.id]){\n\t\t\t\tcheckedColumns[i] = i;\n\t\t\t}\n\t\t}\n\n\t\tfor (var columnIndex = range.start; columnIndex <= range.end; columnIndex++) {\n\t\t\tvar day = timetable[columnIndex];\n\t\t\tcheckedColumns[columnIndex] = false;\n\t\t\tif(!day){\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvar capacity = templates.histogram_cell_capacity(day.start_date, day.end_date, resource, day.tasks, day.assignments);\n\t\t\tcapacityMatrix[day.start_date.valueOf()] = capacity || 0;\n\t\t\tvar sizes = timeline.getItemPosition(resource, day.start_date, day.end_date);\n\n\t\t\tif(smartRendering && !isColumnVisible(columnIndex, scale, viewport, gantt)){\n\t\t\t\tdetachRenderedHistogramCell(resource.id, columnIndex);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvar renderedCell = renderedHistogramCells[resource.id];\n\t\t\tif(!renderedCell || !renderedCell[columnIndex]){\n\t\t\t\tvar el = renderHistogramCell(resource, sizes, maxCapacity, config, templates, day, timeline);\n\t\t\t\tif(el){\n\t\t\t\t\tnode.appendChild(el);\n\t\t\t\t\trenderedHistogramCells[resource.id][columnIndex] = el;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if(renderedCell && renderedCell[columnIndex] && !renderedCell[columnIndex].parentNode){\n\t\t\t\tnode.appendChild(renderedCell[columnIndex]);\n\t\t\t}\n\t\t}\n\n\t\tfor(var i in checkedColumns){\n\t\t\tif(checkedColumns[i] !== false){\n\t\t\t\tdetachRenderedHistogramCell(resource.id, i);\n\t\t\t}\n\t\t}\n\n\t\tvar capacityElement = renderCapacityElement(resource, sizes, capacityMatrix, config, timeline, maxCapacity, viewport);\n\t\tif(capacityElement){\n\t\t\tnode.appendChild(capacityElement);\n\t\t\trenderedHistogramCapacity[resource.id] = capacityElement;\n\t\t}\n\t}\n\n\treturn {\n\t\trender: renderResourceHistogram,\n\t\tupdate: updateResourceHistogram,\n\t\tgetRectangle: getRectangle,\n\t\tgetVisibleRange: getVisibleRange\n\t};\n}\n\nexport default generateRenderResourceHistogram;","import getRowRectangle from \"./viewport/get_grid_row_rectangle\";\nimport getVisibleRange from \"./viewport/get_visible_bars_range\";\n\nfunction createGridTaskRowResizerRender(gantt){\n\n\tfunction _render_grid_item(item, view, viewport) {\n\n\t\tvar config = view.$getConfig();\n\t\tvar resize_el = document.createElement(\"div\");\n\t\tresize_el.className = \"gantt_task_grid_row_resize_wrap\";\n\n\t\tresize_el.style.top = (view.getItemTop(item.id) + view.getItemHeight(item.id)) + \"px\";\n\n\t\tresize_el.innerHTML = \"
\";\n\t\tresize_el.setAttribute(config.task_grid_row_resizer_attribute, item.id);\n\n\t\tgantt._waiAria.rowResizerAttr(resize_el);\n\t\treturn resize_el;\n\t}\n\n\treturn {\n\t\trender: _render_grid_item,\n\t\tupdate: null,\n\t\tgetRectangle: getRowRectangle,\n\t\tgetVisibleRange: getVisibleRange\n\t};\n}\n\nexport default createGridTaskRowResizerRender;","function _configure(col, data, force) {\n\tfor (var key in data)\n\t\tif (typeof col[key] == \"undefined\" || force)\n\t\t\tcol[key] = data[key];\n}\n\nfunction _get_skin(force, gantt) {\n\n\tconst styles = getComputedStyle(gantt.$root);\n\tconst themeVar = styles.getPropertyValue(\"--dhx-gantt-theme\");\n\tlet isCssVarTheme = !!themeVar;\n\tlet themeName;\n\n\t\n\tif(isCssVarTheme){\n\t\tthemeName = themeVar;\n\t}else{\n\t\tvar skin = gantt.skin;\n\t\tthemeName = skin;\n\t\tif (!skin || force) {\n\t\t\tvar links = document.getElementsByTagName(\"link\");\n\t\t\tfor (var i = 0; i < links.length; i++) {\n\t\t\t\tvar res = links[i].href.match(\"dhtmlxgantt_([a-z_]+).css\");\n\t\t\t\tif (res) {\n\t\t\t\t\tif (gantt.skins[res[1]] || !skin) {\n\t\t\t\t\t\tthemeName = res[1];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tgantt._theme_info = {\n\t\ttheme: themeName,\n\t\tcssVarTheme: isCssVarTheme\n\t};\n\n\n\n\tgantt.skin = themeName || \"terrace\";\n\tvar skinset = gantt.skins[gantt.skin] || gantt.skins[\"terrace\"];\n\n\t//apply skin related settings\n\t_configure(gantt.config, skinset.config, force);\n\n\tif(!isCssVarTheme){\n\t\tgantt.config.link_radius = 1;\n\t}\n\n\tvar config = gantt.getGridColumns();\n\tif (config[1] && !gantt.defined(config[1].width))\n\t\tconfig[1].width = skinset._second_column_width;\n\tif (config[2] && !gantt.defined(config[2].width))\n\t\tconfig[2].width = skinset._third_column_width;\n\t\n\tfor (var i=0; i column.width) ? column.min_width : column.width;\n\t\t\t\tcolumn.width = (column.max_width && column.max_width < column.width) ? column.max_width : column.width;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (skinset.config.task_height){\n\t\tgantt.config.task_height = skinset.config.task_height || \"full\";\n\t}\n\tif (skinset.config.bar_height){\n\t\tgantt.config.bar_height = skinset.config.bar_height || \"full\";\n\t}\n\n\tif (skinset._lightbox_template)\n\t\tgantt._lightbox_template = skinset._lightbox_template;\n\n\tif (skinset._redefine_lightbox_buttons) {\n\t\tgantt.config.buttons_right = skinset._redefine_lightbox_buttons[\"buttons_right\"];\n\t\tgantt.config.buttons_left = skinset._redefine_lightbox_buttons[\"buttons_left\"];\n\t}\n\n\n\tgantt.resetLightbox();\n}\n\n\n\nexport default function(gantt) {\n\t\n\tif(!gantt.resetSkin){\n\t\tgantt.resetSkin = function () {\n\t\t\tthis.skin = \"\";\n\t\t\t_get_skin(true, this);\n\t\t};\n\t\tgantt.skins = {};\n\n\t\tgantt.attachEvent(\"onGanttLayoutReady\", function(){\n\t\t\t_get_skin(false, this);\n\t\t\tmonitorThemeChange();\n\t\t});\n\t}\n\n\tgantt._addThemeClass = function(){\n\t\tdocument.documentElement.setAttribute(\"data-gantt-theme\", gantt.skin);\n\t};\n\n\tgantt.setSkin = function(value){\n\t\tthis.skin = value;\n\t\tgantt._addThemeClass();\n\t\tmonitorThemeChange();\n\t\tif(gantt.$root){\n\t\t\t_get_skin(true, gantt);\n\t\t\tthis.render();\n\t\t}\n\t\t\n\t\t//\n\t};\n\n\n\tlet monitorIntervalId = null;\n\tfunction monitorThemeChange(){\n\t\tconst container = gantt.$root;\n\t\t\n\t\tif(monitorIntervalId){\n\t\t\tclearInterval(monitorIntervalId);\n\t\t}\n\t\t\n\t\tif(container){\n\t\t\tmonitorIntervalId = setInterval(() => {\n\t\t\t\tconst csstheme = getComputedStyle(container).getPropertyValue('--dhx-gantt-theme');\n\t\t\t\tif(csstheme && csstheme !== gantt.skin){\n\t\t\t\t\tgantt.setSkin(csstheme);\n\t\t\t\t}\n\n\t\t\t}, 100);\n\t\t}\n\t}\n\tgantt.attachEvent(\"onDestroy\", function(){\n\t\tclearInterval(monitorIntervalId);\n\t});\n};","import * as domHelpers from \"../utils/dom_helpers\";\nimport isHeadless from \"../../../utils/is_headless\";\n\nexport default function(gantt){\n\n\tvar scrollRange = 50,\n\t\tscrollStep = 30,\n\t\tscrollDelay = 10,\n\t\tscrollSpeed = 50;\n\n\tvar interval = null,\n\t\tisMove = false,\n\t\tdelayTimeout = null,\n\t\tstartPos = {\n\t\t\tstarted: false\n\t\t},\n\t\teventPos = {};\n\n\n\tfunction isDisplayed(element){\n\t\treturn element &&\n\t\t\tdomHelpers.isChildOf(element, gantt.$root) &&\n\t\t\telement.offsetHeight;\n\t}\n\n\tfunction getAutoscrollContainer(){\n\t\tvar element;\n\t\tif(isDisplayed(gantt.$task)){\n\t\t\telement = gantt.$task;\n\t\t}else if(isDisplayed(gantt.$grid)){\n\t\t\telement = gantt.$grid;\n\t\t}else{\n\t\t\telement = gantt.$root;\n\t\t}\n\n\t\treturn element;\n\t}\n\n\tfunction isScrollState() {\n\t\tvar dragMarker = !!document.querySelector(\".gantt_drag_marker\");\n\t\tvar isResize = !!document.querySelector(\".gantt_drag_marker.gantt_grid_resize_area\")\n\t\t\t|| !!document.querySelector(\".gantt_drag_marker.gantt_row_grid_resize_area\") ;\n\t\tvar isLink = !!document.querySelector(\".gantt_link_direction\");\n\t\tvar state = gantt.getState();\n\t\tvar isClickDrag = state.autoscroll;\n\t\tisMove = dragMarker && !isResize && !isLink;\n\n\t\treturn !((!state.drag_mode && !dragMarker) || isResize) || isClickDrag;\n\t}\n\n\tfunction defineDelayTimeout(state) {\n\t\tif (delayTimeout) {\n\t\t\tclearTimeout(delayTimeout);\n\t\t\tdelayTimeout = null;\n\t\t}\n\t\tif (state) {\n\t\t\tvar speed = gantt.config.autoscroll_speed;\n\t\t\tif (speed && speed < 10) // limit speed value to 10\n\t\t\t\tspeed = 10;\n\n\t\t\tdelayTimeout = setTimeout(function() {\n\t\t\t\tinterval = setInterval(tick, speed || scrollSpeed);\n\t\t\t}, gantt.config.autoscroll_delay || scrollDelay);\n\t\t}\n\t}\n\n\tfunction defineScrollInterval(state) {\n\t\tif (state) {\n\t\t\tdefineDelayTimeout(true);\n\t\t\tif (!startPos.started) {\n\t\t\t\tstartPos.x = eventPos.x;\n\t\t\t\tstartPos.y = eventPos.y;\n\t\t\t\tstartPos.started = true;\n\t\t\t}\n\t\t} else {\n\t\t\tif (interval) {\n\t\t\t\tclearInterval(interval);\n\t\t\t\tinterval = null;\n\t\t\t}\n\t\t\tdefineDelayTimeout(false);\n\t\t\tstartPos.started = false;\n\t\t}\n\t}\n\n\tfunction autoscrollInterval(event) {\n\t\tvar isScroll = isScrollState();\n\n\t\tif ((interval || delayTimeout) && !isScroll) {\n\t\t\tdefineScrollInterval(false);\n\t\t}\n\n\t\tif (!gantt.config.autoscroll || !isScroll) {\n\t\t\treturn false;\n\t\t}\n\n\t\teventPos = {\n\t\t\tx: event.clientX,\n\t\t\ty: event.clientY\n\t\t};\n\n\t\t// if it is a mobile device, we need to detect the touch event coords\n\t\tif (event.type == \"touchmove\"){\n\t\t\teventPos.x = event.targetTouches[0].clientX;\n\t\t\teventPos.y = event.targetTouches[0].clientY;\n\t\t}\n\n\t\tif (!interval && isScroll) {\n\t\t\tdefineScrollInterval(true);\n\t\t}\n\t}\n\n\tfunction tick() {\n\n\t\tif (!isScrollState()) {\n\t\t\tdefineScrollInterval(false);\n\t\t\treturn false;\n\t\t}\n\n\t\tvar container = getAutoscrollContainer();\n\t\tif(!container){\n\t\t\treturn;\n\t\t}\n\t\t// GS-1150: if we reorder or resize something in the grid, we should obtain the grid container\n\t\tvar gridDrag = false;\n\t\tvar gridMarkers = [\n\t\t\t\".gantt_drag_marker.gantt_grid_resize_area\",\n\t\t\t\".gantt_drag_marker .gantt_row.gantt_row_task\",\n\t\t\t\".gantt_drag_marker.gantt_grid_dnd_marker\"\n\t\t];\n\t\tgridMarkers.forEach(function (selector) {\n\t\t\tgridDrag = gridDrag || !!document.querySelector(selector);\n\t\t});\n\t\tif (gridDrag){\n\t\t\tcontainer = gantt.$grid;\n\t\t}\n\n\t\tvar box = domHelpers.getNodePosition(container);\n\n\t\tvar posX = eventPos.x - box.x;\n\t\tvar posY = eventPos.y - box.y + window.scrollY; // GS-1315: window.scrollY here and below for the elements above Gantt\n\n\t\tvar scrollLeft = isMove ? 0 : need_scroll(posX, box.width, startPos.x - box.x);\n\t\tvar scrollTop = need_scroll(posY, box.height, startPos.y - box.y + window.scrollY);\n\n\t\tvar scrollState = gantt.getScrollState();\n\n\t\tvar currentScrollTop = scrollState.y,\n\t\t\tscrollOuterHeight = scrollState.inner_height,\n\t\t\tscrollInnerHeight = scrollState.height,\n\t\t\tcurrentScrollLeft = scrollState.x,\n\t\t\tscrollOuterWidth = scrollState.inner_width,\n\t\t\tscrollInnerWidth = scrollState.width;\n\n\t\t// do scrolling only if we have scrollable area to do so\n\t\tif (scrollTop && !scrollOuterHeight) {\n\t\t\tscrollTop = 0;\n\t\t} else if (scrollTop < 0 && !currentScrollTop) {\n\t\t\tscrollTop = 0;\n\t\t} else if (scrollTop > 0 && currentScrollTop + scrollOuterHeight >= scrollInnerHeight + 2) {\n\t\t\tscrollTop = 0;\n\t\t}\n\n\t\tif (scrollLeft && !scrollOuterWidth) {\n\t\t\tscrollLeft = 0;\n\t\t} else if (scrollLeft < 0 && !currentScrollLeft) {\n\t\t\tscrollLeft = 0;\n\t\t} else if (scrollLeft > 0 && currentScrollLeft + scrollOuterWidth >= scrollInnerWidth) {\n\t\t\tscrollLeft = 0;\n\t\t}\n\n\t\tvar step = gantt.config.autoscroll_step;\n\n\t\tif (step && step < 2) // limit step value to 2\n\t\t\tstep = 2;\n\n\t\tscrollLeft = scrollLeft * (step || scrollStep);\n\t\tscrollTop = scrollTop * (step || scrollStep);\n\n\t\tif (scrollLeft || scrollTop) {\n\t\t\tscroll(scrollLeft, scrollTop);\n\t\t}\n\t}\n\n\tfunction need_scroll(pos, boxSize, startCoord) {\n\t\tif ((pos - scrollRange < 0) && (pos < startCoord))\n\t\t\treturn -1;\n\t\telse if ((pos > boxSize - scrollRange) && (pos > startCoord))\n\t\t\treturn 1;\n\t\treturn 0;\n\t}\n\n\tfunction scroll(left, top) {\n\t\tvar scrollState = gantt.getScrollState();\n\n\t\tvar scrollLeft = null,\n\t\t\tscrollTop = null;\n\n\t\tif (left) {\n\t\t\tscrollLeft = scrollState.x + left;\n\t\t\tscrollLeft = Math.min(scrollState.width, scrollLeft);\n\t\t\tscrollLeft = Math.max(0, scrollLeft);\n\t\t}\n\n\t\tif (top) {\n\t\t\tscrollTop = scrollState.y + top;\n\t\t\tscrollTop = Math.min(scrollState.height, scrollTop);\n\t\t\tscrollTop = Math.max(0, scrollTop);\n\t\t}\n\n\t\tgantt.scrollTo(scrollLeft, scrollTop);\n\t}\n\n\tgantt.attachEvent(\"onGanttReady\", function() {\n\t\tif(!isHeadless(gantt)){\n\t\t\tvar eventElement = domHelpers.getRootNode(gantt.$root) || document.body;\n\t\t\tgantt.eventRemove(eventElement, \"mousemove\", autoscrollInterval);\n\t\t\tgantt.event(eventElement, \"mousemove\", autoscrollInterval);\n\n\t\t\tgantt.eventRemove(eventElement, \"touchmove\", autoscrollInterval);\n\t\t\tgantt.event(eventElement, \"touchmove\", autoscrollInterval);\n\n\t\t\tgantt.eventRemove(eventElement, \"pointermove\", autoscrollInterval);\n\t\t\tgantt.event(eventElement, \"pointermove\", autoscrollInterval);\n\t\t}\n\t});\n\n\tgantt.attachEvent(\"onDestroy\", function(){\n\t\tdefineScrollInterval(false);\n\t});\n\n};","if (window.dhtmlx){\n\n\tif (!window.dhtmlx.attaches)\n\twindow.dhtmlx.attaches = {};\n\n\twindow.dhtmlx.attaches.attachGantt=function(start, end, gantt){\n\t\tvar obj = document.createElement(\"DIV\");\n\n\t\tgantt = gantt || window.gantt;\n\n\t\tobj.id = \"gantt_\"+ gantt.uid();\n\t\tobj.style.width = \"100%\";\n\t\tobj.style.height = \"100%\";\n\t\tobj.cmp = \"grid\";\n\n\t\tdocument.body.appendChild(obj);\n\t\tthis.attachObject(obj.id);\n\t\tthis.dataType = \"gantt\";\n\t\tthis.dataObj = gantt;\n\n\t\tvar that = this.vs[this.av];\n\t\tthat.grid = gantt;\n\n\t\tgantt.init(obj.id, start, end);\n\t\tobj.firstChild.style.border = \"none\";\n\n\t\tthat.gridId = obj.id;\n\t\tthat.gridObj = obj;\n\n\t\tvar method_name=\"_viewRestore\";\n\t\treturn this.vs[this[method_name]()].grid;\n\t};\n\n}\nif (typeof(window.dhtmlXCellObject) != \"undefined\") {\n\n\twindow.dhtmlXCellObject.prototype.attachGantt=function(start, end, gantt){\n\t\tgantt = gantt || window.gantt;\n\n\t\tvar obj = document.createElement(\"DIV\");\n\t\tobj.id = \"gantt_\"+gantt.uid();\n\t\tobj.style.width = \"100%\";\n\t\tobj.style.height = \"100%\";\n\t\tobj.cmp = \"grid\";\n\n\t\tdocument.body.appendChild(obj);\n\t\tthis.attachObject(obj.id);\n\n\t\tthis.dataType = \"gantt\";\n\t\tthis.dataObj = gantt;\n\n\t\tgantt.init(obj.id, start, end);\n\t\tobj.firstChild.style.border = \"none\";\n\n\t\tobj = null;\n\t\tthis.callEvent(\"_onContentAttach\",[]);\n\n\t\treturn this.dataObj;\n\t};\n}\n\nexport default null;","import env from \"../../../utils/env\";\nimport eventable from \"../../../utils/eventable\";\nimport { IScale, TModifierKeys } from \"../../common/config\";\n\ninterface ITimelineZoomConfig {\n\thandler?: (e: Event) => {};\n\tstartDate?: Date;\n\tendDate?: Date;\n\tlevels: IZoomLevel[];\n\tactiveLevelIndex?: number;\n\twidthStep?: number;\n\tminColumnWidth?: number;\n\tmaxColumnWidth?: number;\n\tuseKey?: \"ctrlKey\" | \"altKey\" | \"shiftKey\";\n\ttrigger?: \"wheel\" | null | undefined;\n\telement?: Element | (() => Element);\n}\n\nconst USE_KEY = [\"ctrlKey\", \"altKey\", \"shiftKey\", \"metaKey\"];\n\ninterface IZoomLevel {\n\tname?: string;\n\tscale_height?: number;\n\tmin_column_width: number;\n\tscales: IScale[];\n}\n\nconst _defaultScales = [\n\t[\n\t\t{\n\t\t\tunit: \"month\",\n\t\t\tdate: \"%M\",\n\t\t\tstep: 1\n\t\t},\n\t\t{\n\t\t\tunit: \"day\",\n\t\t\tdate: \"%d\",\n\t\t\tstep: 1\n\t\t}\n\t],\n\t[\n\t\t{\n\t\t\tunit: \"day\",\n\t\t\tdate: \"%d %M\",\n\t\t\tstep: 1\n\t\t}\n\t],\n\t[\n\t\t{\n\t\t\tunit: \"day\",\n\t\t\tdate: \"%d %M\",\n\t\t\tstep: 1\n\t\t},\n\t\t{\n\t\t\tunit: \"hour\",\n\t\t\tdate: \"%H:00\",\n\t\t\tstep: 8\n\t\t}\n\t],\n\t[\n\t\t{\n\t\t\tunit: \"day\",\n\t\t\tdate: \"%d %M\",\n\t\t\tstep: 1\n\t\t},\n\t\t{\n\t\t\tunit: \"hour\",\n\t\t\tdate: \"%H:00\",\n\t\t\tstep: 1\n\t\t}\n\t]\n];\n\nexport default class TimelineZoom {\n\tpublic attachEvent: (eventName: string, handler: () => void) => string;\n\tpublic callEvent: (eventName: string, args: any[]) => any;\n\tpublic detachEvent: (eventName: string) => any;\n\tprotected _initialStartDate: Date;\n\tprotected _initialEndDate: Date;\n\tprotected _activeLevelIndex: number;\n\tprotected _levels: IZoomLevel[];\n\tprotected _handler: (e: any) => void;\n\tprotected $gantt;\n\tprotected _widthStep: number;\n\tprotected _minColumnWidth: number;\n\tprotected _maxColumnWidth: number;\n\tprotected _useKey: TModifierKeys;\n\tprotected _visibleDate: Date;\n\tprotected _initialized: boolean;\n\tprotected _domEvents: any;\n\n\tconstructor(gantt) {\n\t\tthis.$gantt = gantt;\n\t\tthis._domEvents = this.$gantt._createDomEventScope();\n\t}\n\n\tpublic init(config: ITimelineZoomConfig) {\n\t\t// GS-1354 and GS-1318. If we check the headless mode using the function,\n\t\t// it will return false when Gantt is not initialized, but we may want to do it later\n\t\tif(this.$gantt.env.isNode){\n\t\t\treturn;\n\t\t}\n\t\tthis._initialStartDate = config.startDate;\n\t\tthis._initialEndDate = config.endDate;\n\t\tthis._activeLevelIndex = config.activeLevelIndex ? config.activeLevelIndex : 0;\n\t\tthis._levels = this._mapScales(config.levels || _defaultScales);\n\t\tthis._handler = config.handler || this._defaultHandler;\n\t\tthis._minColumnWidth = config.minColumnWidth || 60;\n\t\tthis._maxColumnWidth = config.maxColumnWidth || 240;\n\t\tthis._widthStep = config.widthStep || 3/8 * config.minColumnWidth;\n\t\tthis._useKey = config.useKey;\n\n\t\tif(!this._initialized){\n\t\t\teventable(this);\n\t\t\tthis.$gantt.attachEvent(\"onGanttScroll\", () => {\n\t\t\t\tthis._getVisibleDate();\n\t\t\t});\n\t\t}\n\n\t\tthis._domEvents.detachAll();\n\n\t\tif(config.trigger === \"wheel\"){\n\t\t\tif(this.$gantt.$root){\n\t\t\t\tthis._attachWheelEvent(config);\n\t\t\t}else{\n\t\t\t\tthis.$gantt.attachEvent(\"onGanttReady\", () => {\n\t\t\t\t\tthis._attachWheelEvent(config);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis._initialized = true;\n\t\tthis.setLevel(this._activeLevelIndex);\n\t}\n\n\tpublic zoomIn = () => {\n\t\tconst index = this.getCurrentLevel() - 1;\n\t\tif(index < 0){\n\t\t\treturn;\n\t\t}\n\t\tthis.setLevel(index);\n\t};\n\n\tpublic zoomOut = () => {\n\t\tconst index = this.getCurrentLevel() + 1;\n\t\tif(index > this._levels.length - 1){\n\t\t\treturn;\n\t\t}\n\t\tthis.setLevel(index);\n\t};\n\n\tpublic getCurrentLevel = () => {\n\t\treturn this._activeLevelIndex;\n\t};\n\n\tpublic getLevels = () => {\n\t\treturn this._levels;\n\t};\n\n\tpublic setLevel = (level: number|string) => {\n\t\tconst zoomLevel = this._getZoomIndexByName(level);\n\n\t\tif(zoomLevel === -1){\n\t\t\tthis.$gantt.assert(zoomLevel !== -1, \"Invalid zoom level for gantt.ext.zoom.setLevel. \" + level + \" is not an expected value.\");\n\t\t}\n\t\tthis._setLevel(zoomLevel, 0);\n\t};\n\n\tprotected _getZoomIndexByName = (levelName: number|string) => {\n\t\tlet zoomLevel:number = -1;\n\t\tif(typeof levelName === \"string\"){\n\t\t\tif(!isNaN(Number(levelName)) && this._levels[Number(levelName)]){\n\t\t\t\tzoomLevel = Number(levelName);\n\t\t\t}else{\n\t\t\t\tfor(let i = 0; i < this._levels.length; i++){\n\t\t\t\t\tif(this._levels[i].name === levelName){\n\t\t\t\t\t\tzoomLevel = i;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}else{\n\t\t\tzoomLevel = levelName;\n\t\t}\n\t\treturn zoomLevel;\n\t};\n\n\tprotected _mapScales(levels: IScale[][] | any): IZoomLevel[]{\n\t\treturn levels.map((l) => {\n\t\t\tif(Array.isArray(l)){\n\t\t\t\treturn {\n\t\t\t\t\tscales: l\n\t\t\t\t};\n\t\t\t}else{\n\t\t\t\treturn l;\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected _getVisibleDate = () => {\n\t\t// GS-1450. Don't try to get the visible date if there is no timeline\n\t\tif (!this.$gantt.$task){\n\t\t\treturn null;\n\t\t}\n\t\tconst scrollPos = this.$gantt.getScrollState().x;\n\t\tconst viewPort = this.$gantt.$task.offsetWidth;\n\t\tthis._visibleDate = this.$gantt.dateFromPos(scrollPos + viewPort/2);\n\t};\n\n\tprotected _setLevel = (level: number, cursorOffset: number) => {\n\t\tthis._activeLevelIndex = level;\n\n\t\tconst gantt = this.$gantt;\n\t\tconst nextConfig = gantt.copy(this._levels[this._activeLevelIndex]);\n\t\tconst chartConfig = gantt.copy(nextConfig);\n\t\tdelete chartConfig.name;\n\n\t\tgantt.mixin(gantt.config, chartConfig, true);\n\n\t\t// GS-1148: Change scales for the resource views\n\t\tconst resourceViews = [\n\t\t\t\"resourceTimeline\",\n\t\t\t\"resourceHistogram\"\n\t\t];\n\n\t\tresourceViews.forEach(function(name){\n\t\t\tconst resourceView = gantt.$ui.getView(name);\n\t\t\tif (resourceView){\n\t\t\t\tconst resourceConfig = resourceView.$getConfig();\n\t\t\t\tif (!resourceConfig.fixed_scales){\n\t\t\t\t\tgantt.mixin(resourceConfig, chartConfig, true);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tconst isRendered = !!gantt.$root && !!gantt.$task;\n\n\t\tif(isRendered){\n\t\t\tif(cursorOffset){\n\t\t\t\tconst cursorDate = this.$gantt.dateFromPos(cursorOffset + this.$gantt.getScrollState().x);\n\t\t\t\tthis.$gantt.render();\n\t\t\t\tconst newPosition = this.$gantt.posFromDate(cursorDate);\n\t\t\t\tthis.$gantt.scrollTo(newPosition - cursorOffset);\n\t\t\t}else{\n\t\t\t\tconst viewPort = this.$gantt.$task.offsetWidth;\n\t\t\t\tif(!this._visibleDate){\n\t\t\t\t\tthis._getVisibleDate();\n\t\t\t\t}\n\t\t\t\tconst middleDate = this._visibleDate;\n\t\t\t\tthis.$gantt.render();\n\t\t\t\tconst newPosition = this.$gantt.posFromDate(middleDate);\n\t\t\t\tthis.$gantt.scrollTo(newPosition - viewPort/2);\n\t\t\t}\n\n\t\t\tthis.callEvent(\"onAfterZoom\", [this._activeLevelIndex, nextConfig]);\n\t\t}\n\t};\n\n\tprivate _attachWheelEvent = (config) => {\n\t\tconst event = env.isFF ? \"wheel\" : \"mousewheel\";\n\t\tlet el: Element;\n\t\tif(typeof config.element === \"function\"){\n\t\t\tel = config.element();\n\t\t}else{\n\t\t\tel = config.element as Element;\n\t\t}\n\t\tif (!el){\n\t\t\treturn;\n\t\t}\n\n\t\tthis._domEvents.attach(el, event, this.$gantt.bind(function(e) {\n\t\t\tif (this._useKey) {\n\t\t\t\tif (USE_KEY.indexOf(this._useKey) < 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (!e[this._useKey]) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof this._handler === \"function\") {\n\t\t\t\tthis._handler.apply(this, [e]);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}, this), {passive: false});\n\t};\n\n\tprivate _defaultHandler = (e: any):void => {\n\t\tconst timelineOffset = this.$gantt.$task.getBoundingClientRect().x;\n\t\tconst cursorOffset = e.clientX - timelineOffset;\n\t\tconst wheelY = this.$gantt.env.isFF ? (e.deltaY*-40) : e.wheelDelta;\n\t\tlet wheelUp = false;\n\t\tif (wheelY > 0) {\n\t\t\twheelUp = true;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tthis._setScaleSettings(wheelUp, cursorOffset);\n\t};\n\n\tprivate _setScaleSettings(wheelUp: boolean, cursorOffset: number) {\n\t\tif (wheelUp) {\n\t\t\tthis._stepUp(cursorOffset);\n\t\t} else {\n\t\t\tthis._stepDown(cursorOffset);\n\t\t}\n\t}\n\n\tprivate _setScaleDates = () => {\n\t\tif(this._initialStartDate && this._initialEndDate){\n\t\t\tthis.$gantt.config.start_date = this._initialStartDate;\n\t\t\tthis.$gantt.config.end_date = this._initialEndDate;\n\t\t}\n\t};\n\n\tprivate _stepUp(cursorOffset) {\n\t\tif (this._activeLevelIndex >= this._levels.length - 1) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet nextLevel = this._activeLevelIndex;\n\t\tthis._setScaleDates();\n\n\t\tif(this._widthStep){\n\t\t\tlet newColumnWidth = this.$gantt.config.min_column_width + this._widthStep;\n\t\t\tif (newColumnWidth > this._maxColumnWidth) {\n\t\t\t\tnewColumnWidth = this._minColumnWidth;\n\t\t\t\tnextLevel++;\n\t\t\t}\n\n\t\t\tthis.$gantt.config.min_column_width = newColumnWidth;\n\t\t}else{\n\t\t\tnextLevel++;\n\t\t}\n\t\tthis._setLevel(nextLevel, cursorOffset);\n\t}\n\tprivate _stepDown(cursorOffset) {\n\t\tif (this._activeLevelIndex < 1) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet nextLevel = this._activeLevelIndex;\n\t\tthis._setScaleDates();\n\n\t\tif(this._widthStep){\n\t\t\tlet newColumnWidth = this.$gantt.config.min_column_width - this._widthStep;\n\t\t\tif (newColumnWidth < this._minColumnWidth) {\n\t\t\t\tnewColumnWidth = this._maxColumnWidth;\n\t\t\t\tnextLevel--;\n\t\t\t}\n\t\t\tthis.$gantt.config.min_column_width = newColumnWidth;\n\t\t}else{\n\t\t\tnextLevel--;\n\t\t}\n\t\tthis._setLevel(nextLevel, cursorOffset);\n\t}\n}","function dummy() {\n\t// eslint-disable-next-line\n\tconsole.log(\"Method is not implemented.\"); \n}\nfunction BaseControl() {\n}\n\n// base methods will be runned in gantt context\nBaseControl.prototype.render = dummy; // arguments: sns\nBaseControl.prototype.set_value = dummy; // arguments: node, value, ev, sns(config)\nBaseControl.prototype.get_value = dummy; // arguments node, ev, sns(config)\nBaseControl.prototype.focus = dummy; // arguments: node\n\nexport default function(gantt) { // we could send current instance of gantt to module\n\treturn BaseControl;\n};","import * as helpers from \"../../../utils/helpers\";\n\nvar htmlHelpers = {\n\tgetHtmlSelect: function(options, attributes, value) {\n\t\tvar innerHTML = \"\";\n\t\tvar _this = this;\n\n\t\toptions = options || [];\n\t\t\n\t\thelpers.forEach(options, function(entry) {\n\t\t\tvar _attributes = [{ key: \"value\", value: entry.key }];\n\n\t\t\tif (value == entry.key) {\n\t\t\t\t_attributes[_attributes.length] = { key: \"selected\", value: \"selected\" };\n\t\t\t}\n\t\t\tif (entry.attributes) {\n\t\t\t\t_attributes = _attributes.concat(entry.attributes);\n\t\t\t}\n\t\t\tinnerHTML += _this.getHtmlOption({ innerHTML: entry.label }, _attributes);\n\t\t});\n\n\t\treturn _getHtmlContainer(\"select\", { innerHTML: innerHTML }, attributes);\n\t},\n\tgetHtmlOption: function(options, attributes) { return _getHtmlContainer(\"option\", options, attributes); },\n\tgetHtmlButton: function(options, attributes) { return _getHtmlContainer(\"button\", options, attributes); },\n\tgetHtmlDiv: function(options, attributes) { return _getHtmlContainer(\"div\", options, attributes); },\n\tgetHtmlLabel: function(options, attributes) { return _getHtmlContainer(\"label\", options, attributes); },\n\tgetHtmlInput: function(attributes) {\n\t\treturn \"\";\n\t}\n};\n\nfunction _getHtmlContainer(tag, options, attributes) {\n\tvar html;\n\n\toptions = options || [];\n\t\n\thtml = \"<\" + tag + _getHtmlAttributes(attributes || []) + \">\" + (options.innerHTML || \"\") + \"\";\n\treturn html;\n\n}\n\nfunction _getHtmlAttributes(attributes) {\n\tvar html = \"\";\n\n\thelpers.forEach(attributes, function(entry) {\n\t\thtml += \" \" + entry.key + \"='\" + entry.value + \"'\";\n\t});\n\treturn html;\n}\n\nexport default htmlHelpers;","import __extends from \"../../../../utils/extends\";\nimport htmlHelpers from \"../../utils/html_helpers\";\n\nimport Super from \"./base_control\";\n\nexport default function(gantt) {\n\tconst _super = Super(gantt);\n\n\tfunction SelectControl() {\n\t\tvar self = _super.apply(this, arguments) || this;\n\t\n\t\treturn self; \n\t}\n\t\n\t__extends(SelectControl, _super);\n\t\n\tSelectControl.prototype.render = function(sns) {\n\t\tconst height = sns.height ? `height:${sns.height}px;` : '';\n\t\tlet html = `
`;\n\n\t\thtml += htmlHelpers.getHtmlSelect(sns.options, [{ key: \"style\", value: \"width:100%;\" }, { key: \"title\", value: sns.name }]);\n\t\thtml += \"
\";\n\t\treturn html;\n\t};\n\n\tSelectControl.prototype.set_value = function(node, value, ev, sns) {\n\t\tvar select = node.firstChild;\n\t\tif (!select._dhx_onchange && sns.onchange) {\n\t\t\tselect.onchange = sns.onchange;\n\t\t\tselect._dhx_onchange = true;\n\t\t}\n\t\tif (typeof value === \"undefined\")\n\t\t\tvalue = (select.options[0] || {}).value;\n\t\tselect.value = value || \"\";\n\t};\n\t\n\tSelectControl.prototype.get_value = function(node) {\n\t\treturn node.firstChild.value;\n\t};\n\t\n\tSelectControl.prototype.focus = function(node) {\n\t\tvar a = node.firstChild;\n\t\tgantt._focus(a, true);\n\t};\n\t\n\treturn SelectControl;\n};","export default class DurationFormatterNumeric implements IDurationFormatter {\n\tstatic create = (settings: IDurationFormatterConfig = null): IDurationFormatter => {\n\t\treturn new DurationFormatterNumeric();\n\t};\n\tcanParse = (value: string) : boolean => {\n\t\treturn !isNaN(this.parse(value));\n\t};\n\tformat = (value: number) : string => {\n\t\treturn String(value);\n\t};\n\tparse = (value: string) : number => {\n\t\treturn parseInt(value, 10);\n\t};\n}","import __extends from \"../../../../utils/extends\";\nimport SelectControl from \"./select_control\";\nexport default function(gantt) {\n\tvar _super = SelectControl(gantt);\n\n\tfunction ParentControl() {\n\t\tvar self = _super.apply(this, arguments) || this; \n\n\t\treturn self; \n\t}\n\n\t__extends(ParentControl, _super);\n\n\n\tParentControl.prototype.render = function(sns) {\n\t\treturn _display(sns, false);\n\t};\n\n\tParentControl.prototype.set_value = function(node, value, ev, config) {\n\t\t// GS-1051. If the value is `0`, the set_value function in the select control won't select \n\t\t// the first child because (0 || '') = '';\n\t\tif (value === 0) value = \"0\";\n\n\t\tvar tmpDom = document.createElement(\"div\");\n\t\ttmpDom.innerHTML = _display(config, ev.id);\n\t\tvar newOptions = tmpDom.removeChild(tmpDom.firstChild);\n\t\tnode.onselect = null;\n\t\tnode.parentNode.replaceChild(newOptions, node);\n\n\t\treturn gantt.form_blocks.select.set_value.apply(gantt, [newOptions, value, ev, config]);\n\t};\n\n\tfunction _display(config, item_id) {\n\t\tvar tasks = [],\n\t\t\toptions = [];\n\t\tif (item_id) {\n\t\t\ttasks = gantt.getTaskByTime();\n\t\t\tif (config.allow_root) {\n\t\t\t\ttasks.unshift({id: gantt.config.root_id, text: config.root_label || \"\"});\n\t\t\t}\n\t\t\ttasks = _filter(tasks, config, item_id);\n\t\t\tif (config.sort) {\n\t\t\t\ttasks.sort(config.sort);\n\t\t\t}\n\t\t}\n\t\tvar text = config.template || gantt.templates.task_text;\n\t\tfor (var i = 0; i < tasks.length; i++) {\n\t\t\tvar label = text.apply(gantt, [tasks[i].start_date, tasks[i].end_date, tasks[i]]);\n\t\t\tif (label === undefined) {\n\t\t\t\tlabel = \"\";\n\t\t\t}\n\t\t\toptions.push({\n\t\t\t\tkey: tasks[i].id,\n\t\t\t\tlabel: label\n\t\t\t});\n\t\t}\n\t\tconfig.options = options;\n\t\tconfig.map_to = config.map_to || \"parent\";\n\t\treturn gantt.form_blocks.select.render.apply(this, arguments);\n\t}\n\n\tfunction _filter(options, config, item_id) {\n\t\tvar filter = config.filter || function() {\n\t\t\treturn true;\n\t\t};\n\n\t\toptions = options.slice(0);\n\n\t\tfor (var i = 0; i < options.length; i++) {\n\t\t\tvar task = options[i];\n\t\t\tif (task.id == item_id || gantt.isChildOf(task.id, item_id) || filter(task.id, task) === false) {\n\t\t\t\toptions.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t\treturn options;\n\t}\n\treturn ParentControl;\n};","import extensions from \"./ext/extensions_all\";\nimport GanttFactory from \"./factory/gantt_factory\";\nimport factoryMethod from \"./factory/make_instance_web\";\n// tslint:disable-next-line variable-name\nconst Gantt = new GanttFactory(factoryMethod, extensions);\nconst gantt = Gantt.getGanttInstance();\n\nexport { Gantt, gantt };\n","\nimport ExtensionsManager from \"../ext/extension_manager\";\nimport scope from \"../utils/global\";\n\nclass GanttFactory implements IGanttFactory{\n\tprotected _seed: number;\n\tprotected _ganttPlugin: GanttPlugin[];\n\tprotected _factoryMethod: (bundledExtensions: {[key:string]: GanttPlugin}) => any;\n\tprotected _bundledExtensions: {[key:string]: GanttPlugin};\n\tprotected _extensionsManager: ExtensionsManager;\n\n\tconstructor(factoryMethod: ()=>any, _bundledExtensions:{[key:string]: GanttPlugin}) {\n\t\tthis._seed = 0;\n\t\tthis._ganttPlugin = [];\n\t\tthis._factoryMethod = factoryMethod;\n\t\tthis._bundledExtensions = _bundledExtensions;\n\t\tthis._extensionsManager = new ExtensionsManager(_bundledExtensions);\n\t}\n\n\tplugin = (code: GanttPlugin):void => {\n\t\tthis._ganttPlugin.push(code);\n\n\t\tif(scope.gantt !== undefined && scope.gantt.getTask){\n\t\t\tcode(scope.gantt);\n\t\t}\n\t};\n\n\tgetGanttInstance = (initConfig?: IGanttInitializationConfig):any => {\n\t\tconst gantt = this._factoryMethod(this._bundledExtensions);\n\t\tfor (let i=0; i {\n\t\tif(initConfig.plugins){\n\t\t\tfor(const i in initConfig.plugins){\n\t\t\t\tconst ext = this._extensionsManager.getExtension(i);\n\t\t\t\tif(ext){\n\t\t\t\t\tgantt.plugins({[i]: true});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(initConfig.config){\n\t\t\tgantt.mixin(gantt.config, initConfig.config, true);\n\t\t}\n\n\t\tif(initConfig.templates){\n\t\t\tgantt.attachEvent(\"onTemplatesReady\", function(){\n\t\t\t\tgantt.mixin(gantt.templates, initConfig.templates, true);\n\t\t\t}, {once: true});\n\t\t}\n\n\t\tif(initConfig.events){\n\t\t\tfor(const event in initConfig.events){\n\t\t\t\tgantt.attachEvent(event, initConfig.events[event]);\n\t\t\t}\n\t\t}\n\n\t\tif(initConfig.locale){\n\t\t\tgantt.i18n.setLocale(initConfig.locale);\n\t\t}\n\n\t\tif(Array.isArray(initConfig.calendars)){\n\t\t\tinitConfig.calendars.forEach(function(calendar){\n\t\t\t\tgantt.addCalendar(calendar);\n\t\t\t});\n\t\t}\n\n\t\tif(initConfig.container){\n\t\t\tgantt.init(initConfig.container);\n\t\t} else {\n\t\t\tgantt.init();\n\t\t}\n\n\t\tif(initConfig.data){\n\t\t\tif(typeof initConfig.data === \"string\"){\n\t\t\t\tgantt.load(initConfig.data);\n\t\t\t}else{\n\t\t\t\tgantt.parse(initConfig.data);\n\t\t\t}\n\t\t}\n\n\n\t};\n}\n\nexport default GanttFactory;","import \"../css/dhtmlxgantt.less\";\n\nimport factory from \"./make_instance_common\";\nimport ui from \"../core/ui_core\";\nimport ajaxLoading from \"../core/loading/ajax_loading\";\nimport dynamicLoading from \"../core/loading/dynamic_loading\";\n\nexport default function(supportedExtensions) {\n\tvar gantt = factory(supportedExtensions);\n\n\tif(!gantt.env.isNode){\n\t\tui(gantt);\n\t\tajaxLoading(gantt);\n\t\tdynamicLoading(gantt);\n\t}\n\n\treturn gantt;\n};","// TODO: rework public api for date methods\nimport * as utils from \"../../utils/utils\";\n\nvar createWorkTimeFacade = function(calendarManager, timeCalculator){\n\treturn {\n\t\tgetWorkHours: function (date) {\n\t\t\treturn timeCalculator.getWorkHours(date);\n\t\t},\n\n\t\tsetWorkTime: function (config) {\n\t\t\treturn timeCalculator.setWorkTime(config);\n\t\t},\n\n\t\tunsetWorkTime: function (config) {\n\t\t\ttimeCalculator.unsetWorkTime(config);\n\t\t},\n\n\t\tisWorkTime: function (date, unit, task) {\n\t\t\treturn timeCalculator.isWorkTime(date, unit, task);\n\t\t},\n\n\t\tgetClosestWorkTime: function (config) {\n\t\t\treturn timeCalculator.getClosestWorkTime(config);\n\t\t},\n\n\t\tcalculateDuration: function (start_date, end_date, task) {\n\t\t\treturn timeCalculator.calculateDuration(start_date, end_date, task);\n\t\t},\n\t\t_hasDuration: function (start_date, end_date, task) {\n\t\t\treturn timeCalculator.hasDuration(start_date, end_date, task);\n\t\t},\n\n\t\tcalculateEndDate: function (start, duration, unit, task) {\n\t\t\treturn timeCalculator.calculateEndDate(start, duration, unit, task);\n\t\t},\n\n\t\tmergeCalendars: utils.bind(calendarManager.mergeCalendars, calendarManager),\n\t\tcreateCalendar: utils.bind(calendarManager.createCalendar, calendarManager),\n\t\taddCalendar: utils.bind(calendarManager.addCalendar, calendarManager),\n\t\tgetCalendar: utils.bind(calendarManager.getCalendar, calendarManager),\n\t\tgetCalendars: utils.bind(calendarManager.getCalendars, calendarManager),\n\t\tgetResourceCalendar: utils.bind(calendarManager.getResourceCalendar, calendarManager),\n\t\tgetTaskCalendar: utils.bind(calendarManager.getTaskCalendar, calendarManager),\n\t\tdeleteCalendar: utils.bind(calendarManager.deleteCalendar, calendarManager)\n\t};\n};\n\n\nexport default { create: createWorkTimeFacade };","export default function(){\n\tvar services = {};\n\tfunction register (name, getter){\n\t\tservices[name] = getter;\n\t}\n\n\tfunction getService(name){\n\t\tif(!services[name]){\n\t\t\treturn null;\n\t\t}\n\t\treturn services[name]();\n\t}\n\n\tfunction dropService(name) {\n\t\tif (services[name]) {\n\t\t\tdelete services[name];\n\t\t}\n\t}\n\n\tvar servicesEnum = {};\n\n\treturn {\n\t\tservices: servicesEnum,\n\t\tsetService: register,\n\t\tgetService: getService,\n\t\tdropService: dropService,\n\t\tdestructor: function(){\n\t\t\tfor(var i in services){\n\t\t\t\tif(services[i]){\n\t\t\t\t\tvar service = services[i];\n\t\t\t\t\tif(service && service.destructor){\n\t\t\t\t\t\tservice.destructor();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tservices = null;\n\t\t}\n\t};\n};\n","import CalendarManager from \"./calendar_manager\";\nimport TimeCalculator from \"./time_calculator\";\nimport worktimeFacadeFactory from \"../facades/worktime_calendars\";\nimport * as utils from \"../../utils/utils\";\n\nexport default function (gantt) {\n\tvar manager = new CalendarManager(gantt),\n\ttimeCalculator = new TimeCalculator(manager);\n\tvar facade = worktimeFacadeFactory.create(manager, timeCalculator);\n\tutils.mixin(gantt, facade);\n};\n","import eventable from \"../../utils/eventable\";\nimport * as utils from \"../../utils/utils\";\nimport timeout from \"../../utils/timeout\";\nimport global from \"../../utils/global\";\nimport * as domHelpers from \"../ui/utils/dom_helpers\";\n\nexport default function(gantt){\n\n\tfunction copyDomEvent(e){\n\t\treturn {\n\t\t\ttarget: e.target || e.srcElement,\n\t\t\tpageX: e.pageX,\n\t\t\tpageY: e.pageY,\n\t\t\tclientX: e.clientX,\n\t\t\tclientY: e.clientY,\n\t\t\tmetaKey: e.metaKey,\n\t\t\tshiftKey: e.shiftKey,\n\t\t\tctrlKey: e.ctrlKey,\n\t\t\taltKey: e.altKey\n\t\t};\n\t}\n\n\tfunction DnD(obj, config) {\n\t\tthis._obj = obj;\n\t\tthis._settings = config || {};\n\t\teventable(this);\n\n\t\tvar inputMethods = this.getInputMethods();\n\n\t\tthis._drag_start_timer = null;\n\t\tgantt.attachEvent(\"onGanttScroll\", utils.bind(function (left, top) {\n\t\t\tthis.clearDragTimer();\n\t\t}, this));\n\n\t\tvar lastDown = 0;\n\t\tvar eventParams = {passive: false};\n\t\tfor(var i = 0; i < inputMethods.length; i++){\n\t\t\t(utils.bind(function(input){\n\n\t\t\t\tgantt.event(obj, input.down, utils.bind(function (e) {\n\t\t\t\t\tif(!input.accessor(e)){\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof e.button !== 'undefined' && e.button !== 0) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif(config.preventDefault && config.selector && domHelpers.closest(e.target, config.selector)){\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (gantt.config.touch && e.timeStamp && e.timeStamp - lastDown < 300) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._settings.original_target = copyDomEvent(e);\n\n\t\t\t\t\tthis._settings.original_element_sizes = {\n\t\t\t\t\t\t...domHelpers.getRelativeEventPosition(e, domHelpers.getClosestSizedElement(obj)), \n\t\t\t\t\t\twidth: e.target.offsetWidth,\n\t\t\t\t\t\theight: e.target.offsetHeight\n\t\t\t\t\t};\n\n\t\t\t\t\tif (gantt.config.touch) {\n\t\t\t\t\t\tthis.clearDragTimer();\n\t\t\t\t\t\tthis._drag_start_timer = setTimeout(utils.bind(function () {\n\t\t\t\t\t\t\tif(gantt.getState().lightbox){\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.dragStart(obj, e, input);\n\t\t\t\t\t\t}, this), gantt.config.touch_drag);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.dragStart(obj, e, input);\n\t\t\t\t\t}\n\t\t\t\t}, this), eventParams);\n\t\t\t\tvar eventElement = document.body;\n\t\t\t\tgantt.event(eventElement, input.up, utils.bind(function (e) {\n\t\t\t\t\tif(!input.accessor(e)){\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis.clearDragTimer();\n\t\t\t\t}, this), eventParams);\n\n\t\t\t}, this))(inputMethods[i]);\n\t\t}\n\t}\n\n\tDnD.prototype = {\n\t\ttraceDragEvents: function (domElement, inputMethod) {\n\t\t\tvar mousemove = utils.bind(function (e) {\n\t\t\t\treturn this.dragMove(domElement, e, inputMethod.accessor);\n\t\t\t}, this);\n\t\t\tutils.bind(function (e) {\n\t\t\t\treturn this.dragScroll(domElement, e);\n\t\t\t}, this);\n\n\t\t\tvar limited_mousemove = utils.bind(function (e) {\n\t\t\t\tif (this.config.started && utils.defined(this.config.updates_per_second)) {\n\t\t\t\t\tif (!timeout(this, this.config.updates_per_second))\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar dndActive = mousemove(e);\n\n\t\t\t\tif (dndActive) {\n\t\t\t\t\ttry{\n\t\t\t\t\t\tif (e && e.preventDefault && e.cancelable){//e.cancelable condition - because navigator.vibrate is blocked by Chrome\n\t\t\t\t\t\t\te.preventDefault();//Cancel default action on DND\n\t\t\t\t\t\t} //Cancel default action on DND\n\t\t\t\t\t}catch (e){\n\t\t\t\t\t\t// just suppress the exception, nothing needed to be done here\n\t\t\t\t\t}\n\n\t\t\t\t\t//e.cancelBubble = true;\n\t\t\t\t}\n\n\t\t\t\treturn dndActive;\n\t\t\t}, this);\n\t\t\tvar eventElement = domHelpers.getRootNode(gantt.$root);\n\t\t\tvar mousemoveContainer = this.config.mousemoveContainer || domHelpers.getRootNode(gantt.$root);\n\n\t\t\tvar eventParams = {passive: false};\n\t\t\tvar mouseup = utils.bind(function (e) {\n\t\t\t\tgantt.eventRemove(mousemoveContainer, inputMethod.move, limited_mousemove);\n\t\t\t\tgantt.eventRemove(eventElement, inputMethod.up, mouseup, eventParams);\n\t\t\t\treturn this.dragEnd(domElement);\n\t\t\t}, this);\n\n\t\t\tgantt.event(mousemoveContainer, inputMethod.move, limited_mousemove, eventParams);\n\t\t\tgantt.event(eventElement, inputMethod.up, mouseup, eventParams);\n\t\t},\n\t\tcheckPositionChange: function (pos) {\n\t\t\tvar diff_x = pos.x - this.config.pos.x;\n\t\t\tvar diff_y = pos.y - this.config.pos.y;\n\t\t\tvar distance = Math.sqrt(Math.pow(Math.abs(diff_x), 2) + Math.pow(Math.abs(diff_y), 2));\n\n\t\t\tif (distance > this.config.sensitivity) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tinitDnDMarker: function () {\n\t\t\t// create dnd placeholder and put it in dom\n\t\t\tvar marker = this.config.marker = document.createElement(\"div\");\n\t\t\tmarker.className = \"gantt_drag_marker\";\n\t\t\t// GS-1333: don't show any message when we resize grid columns\n\t\t\tmarker.innerHTML = \"\";\n\t\t\tdocument.body.appendChild(marker);\n\t\t},\n\t\tbackupEventTarget: function (domEvent, getEvent) {\n\t\t\tif (!gantt.config.touch) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// keep original event target in DOM in order to keep dnd on touchmove event\n\t\t\tvar e = getEvent(domEvent);\n\n\t\t\tvar el = e.target || e.srcElement;\n\t\t\tvar copy = el.cloneNode(true);\n\t\t\t//this.config.target.target = copy;\n\t\t\tthis.config.original_target = copyDomEvent(e);\n\t\t\tthis.config.original_target.target = copy;\n\t\t\tthis.config.backup_element = el;\n\t\t\tel.parentNode.appendChild(copy);\n\n\t\t\tel.style.display = \"none\";\n\t\t\tvar mousemoveContainer = this.config.mousemoveContainer || document.body;\n\t\t\tmousemoveContainer.appendChild(el);\n\t\t},\n\t\tgetInputMethods: function () {\n\t\t\t// bind actions to browser events\n\t\t\tvar inputMethods = [];\n\n\t\t\tinputMethods.push({\n\t\t\t\t\"move\": \"mousemove\",\n\t\t\t\t\"down\": \"mousedown\",\n\t\t\t\t\"up\": \"mouseup\",\n\t\t\t\t\"accessor\": function (e) {\n\t\t\t\t\treturn e;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (gantt.config.touch) {\n\n\t\t\t\tvar touchEventsSupported = true;\n\t\t\t\ttry{\n\t\t\t\t\tdocument.createEvent(\"TouchEvent\");\n\t\t\t\t}catch (e){\n\t\t\t\t\ttouchEventsSupported = false;\n\t\t\t\t}\n\n\t\t\t\tif(touchEventsSupported){\n\t\t\t\t\tinputMethods.push({\n\t\t\t\t\t\t\"move\": \"touchmove\",\n\t\t\t\t\t\t\"down\": \"touchstart\",\n\t\t\t\t\t\t\"up\": \"touchend\",\n\t\t\t\t\t\t\"accessor\": function (ev) {\n\t\t\t\t\t\t\tif (ev.touches && ev.touches.length > 1) return null;\n\t\t\t\t\t\t\tif (ev.touches[0])\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\ttarget: document.elementFromPoint(ev.touches[0].clientX, ev.touches[0].clientY),\n\t\t\t\t\t\t\t\t\tpageX: ev.touches[0].pageX,\n\t\t\t\t\t\t\t\t\tpageY: ev.touches[0].pageY,\n\t\t\t\t\t\t\t\t\tclientX: ev.touches[0].clientX,\n\t\t\t\t\t\t\t\t\tclientY: ev.touches[0].clientY\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\treturn ev;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}else if(global.navigator.pointerEnabled){\n\t\t\t\t\tinputMethods.push({\n\t\t\t\t\t\t\"move\": \"pointermove\",\n\t\t\t\t\t\t\"down\": \"pointerdown\",\n\t\t\t\t\t\t\"up\": \"pointerup\",\n\t\t\t\t\t\t\"accessor\": function (ev) {\n\t\t\t\t\t\t\tif (ev.pointerType == \"mouse\") return null;\n\t\t\t\t\t\t\treturn ev;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t}else if (global.navigator.msPointerEnabled){\n\t\t\t\t\tinputMethods.push({\n\t\t\t\t\t\t\"move\": \"MSPointerMove\",\n\t\t\t\t\t\t\"down\": \"MSPointerDown\",\n\t\t\t\t\t\t\"up\": \"MSPointerUp\",\n\t\t\t\t\t\t\"accessor\": function (ev) {\n\t\t\t\t\t\t\tif (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE) return null;\n\t\t\t\t\t\t\treturn ev;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn inputMethods;\n\t\t},\n\t\tclearDragTimer: function () {\n\t\t\tif (this._drag_start_timer) {\n\t\t\t\tclearTimeout(this._drag_start_timer);\n\t\t\t\tthis._drag_start_timer = null;\n\t\t\t}\n\t\t},\n\t\tdragStart: function (obj, e, inputMethod) {\n\t\t\tif (this.config && this.config.started) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.config = {\n\t\t\t\tobj: obj,\n\t\t\t\tmarker: null,\n\t\t\t\tstarted: false,\n\t\t\t\tpos: this.getPosition(e),\n\t\t\t\tsensitivity: 4\n\t\t\t};\n\t\t\tif (this._settings)\n\t\t\t\tutils.mixin(this.config, this._settings, true);\n\n\n\t\t\tthis.traceDragEvents(obj, inputMethod);\n\n\t\t\tgantt._prevent_touch_scroll = true;\n\t\t\tdocument.body.classList.add(\"gantt_noselect\");\n\n\t\t\tif (gantt.config.touch) {\n\t\t\t\tthis.dragMove(obj, e, inputMethod.accessor);\n\t\t\t}\n\n\t\t},\n\t\tdragMove: function (obj, e, getEvent) {\n\t\t\tvar source = getEvent(e);\n\t\t\tif (!source) return false;\n\n\t\t\tif (!this.config.marker && !this.config.started) {\n\t\t\t\tvar pos = this.getPosition(source);\n\n\t\t\t\tif (gantt.config.touch || this.checkPositionChange(pos)) {\n\t\t\t\t\t// real drag starts here,\n\t\t\t\t\t// when user moves mouse at first time after onmousedown\n\t\t\t\t\tthis.config.started = true;\n\t\t\t\t\tthis.config.ignore = false;\n\t\t\t\t\tgantt._touch_drag = true;\n\t\t\t\t\tif (this.callEvent(\"onBeforeDragStart\", [obj, this.config.original_target]) === false) {\n\t\t\t\t\t\tthis.config.ignore = true;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tthis.backupEventTarget(e, getEvent);\n\t\t\t\t\tthis.initDnDMarker();\n\t\t\t\t\tgantt._touch_feedback();\n\t\t\t\t\tthis.callEvent(\"onAfterDragStart\", [obj, this.config.original_target]);\n\t\t\t\t} else {\n\t\t\t\t\tthis.config.ignore = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!this.config.ignore) {\n\t\t\t\t// GS-1279 Gantt crashes on Mobile Firefox after starting to create a link and moving finger outisde the page.\n\t\t\t\tif (e.targetTouches && !source.target) return;\n\t\t\t\t\n\t\t\t\tsource.pos = this.getPosition(source);\n\t\t\t\tthis.config.marker.style.left = source.pos.x + \"px\";\n\t\t\t\tthis.config.marker.style.top = source.pos.y + \"px\";\n\t\t\t\tthis.callEvent(\"onDragMove\", [obj, source]);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\n\t\tdragEnd: function (obj) {\n\t\t\tvar target = this.config.backup_element;\n\t\t\tif (target && target.parentNode) {\n\t\t\t\ttarget.parentNode.removeChild(target);\n\t\t\t}\n\t\t\tgantt._prevent_touch_scroll = false;\n\t\t\tif (this.config.marker) {\n\t\t\t\tthis.config.marker.parentNode.removeChild(this.config.marker);\n\t\t\t\tthis.config.marker = null;\n\n\t\t\t\tthis.callEvent(\"onDragEnd\", []);\n\t\t\t}\n\t\t\tthis.config.started = false;\n\t\t\tgantt._touch_drag = false;\n\t\t\tdocument.body.classList.remove(\"gantt_noselect\");\n\t\t},\n\n\t\tgetPosition: function (e) {\n\t\t\tvar x = 0, y = 0;\n\t\t\tif (e.pageX || e.pageY) {\n\t\t\t\tx = e.pageX;\n\t\t\t\ty = e.pageY;\n\t\t\t} else if (e.clientX || e.clientY) {\n\t\t\t\tx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;\n\t\t\t\ty = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;\n\t\t\t}\n\t\t\treturn {x: x, y: y};\n\t\t}\n\t};\n\n\treturn DnD;\n};\n","export default function(gantt) {\n\n\tvar regTemplates = {};\n\n\tfunction initTemplate(name, initial, template_name) {\n\t\ttemplate_name = template_name || name;\n\t\tvar config = gantt.config,\n\t\t\ttemplates = gantt.templates;\n\n\t\tif (gantt.config[name] && regTemplates[template_name] != config[name]) {\n\t\t\tif (!(initial && templates[template_name])) {\n\t\t\t\ttemplates[template_name] = gantt.date.date_to_str(config[name]);\n\t\t\t\tregTemplates[template_name] = config[name];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction initTemplates() {\n\t\tvar labels = gantt.locale.labels;\n\t\tlabels.gantt_save_btn = labels.icon_save;\n\t\tlabels.gantt_cancel_btn = labels.icon_cancel;\n\t\tlabels.gantt_delete_btn = labels.icon_delete;\n\n\n\t\tvar date = gantt.date;\n\n\t\t//build configuration based templates\n\t\tvar d = date.date_to_str;\n\t\tvar c = gantt.config;\n\t\tvar format_date = d(c.xml_date || c.date_format, c.server_utc);\n\t\tvar parse_date = date.str_to_date(c.xml_date || c.date_format, c.server_utc);\n\n\t\tinitTemplate(\"date_scale\", true, undefined, gantt.config, gantt.templates);\n\t\tinitTemplate(\"date_grid\", true, \"grid_date_format\", gantt.config, gantt.templates);\n\t\tinitTemplate(\"task_date\", true, undefined, gantt.config, gantt.templates);\n\n\t\tgantt.mixin(gantt.templates, {\n\t\t\txml_format: undefined, // deprecated\n\t\t\tformat_date: format_date,\n\n\t\t\txml_date: undefined, // deprecated\n\t\t\tparse_date: parse_date,\n\n\t\t\tprogress_text: function (start, end, task) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\t\t\tgrid_header_class: function (column, config) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\n\t\t\ttask_text: function (start, end, task) {\n\t\t\t\treturn task.text;\n\t\t\t},\n\t\t\ttask_class: function (start, end, task) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\t\t\ttask_end_date: function (date) {\n\t\t\t\treturn gantt.templates.task_date(date);\n\t\t\t},\n\t\t\tgrid_row_class: function (start, end, task) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\t\t\ttask_row_class: function (start, end, task) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\t\t\ttimeline_cell_class: function (item, date) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\t\t\ttimeline_cell_content: function (item, date) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\t\t\tscale_cell_class: function (date) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\t\t\tscale_row_class: function (date) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\n\t\t\tgrid_indent: function (item) {\n\t\t\t\treturn \"
\";\n\t\t\t},\n\t\t\tgrid_folder: function (item) {\n\t\t\t\treturn \"
\";\n\t\t\t},\n\t\t\tgrid_file: function (item) {\n\t\t\t\treturn \"
\";\n\t\t\t},\n\t\t\tgrid_open: function (item) {\n\t\t\t\treturn \"
\";\n\t\t\t},\n\t\t\tgrid_blank: function (item) {\n\t\t\t\treturn \"
\";\n\t\t\t},\n\t\t\tdate_grid: function (date, item, column) {\n\t\t\t\tif (item && gantt.isUnscheduledTask(item) && gantt.config.show_unscheduled) {\n\t\t\t\t\treturn gantt.templates.task_unscheduled_time(item);\n\t\t\t\t} else {\n\t\t\t\t\treturn gantt.templates.grid_date_format(date, column);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\ttask_time: function (start, end, ev) {\n\t\t\t\tif (gantt.isUnscheduledTask(ev) && gantt.config.show_unscheduled) {\n\t\t\t\t\treturn gantt.templates.task_unscheduled_time(ev);\n\t\t\t\t} else {\n\t\t\t\t\treturn gantt.templates.task_date(start) + \" - \" + gantt.templates.task_end_date(end);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\ttask_unscheduled_time: function (task) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\n\t\t\ttime_picker: d(c.time_picker),\n\t\t\tlink_class: function (link) {\n\t\t\t\treturn \"\";\n\t\t\t},\n\t\t\tlink_description: function (link) {\n\t\t\t\tvar from = gantt.getTask(link.source),\n\t\t\t\t\tto = gantt.getTask(link.target);\n\n\t\t\t\treturn \"\" + from.text + \"\" + to.text + \"\";\n\t\t\t},\n\n\t\t\tdrag_link: function (from, from_start, to, to_start) {\n\t\t\t\tfrom = gantt.getTask(from);\n\t\t\t\tvar labels = gantt.locale.labels;\n\n\t\t\t\tvar text = \"\" + from.text + \" \" + (from_start ? labels.link_start : labels.link_end) + \"
\";\n\t\t\t\tif (to) {\n\t\t\t\t\tto = gantt.getTask(to);\n\t\t\t\t\ttext += \" \" + to.text + \" \" + (to_start ? labels.link_start : labels.link_end) + \"
\";\n\t\t\t\t}\n\t\t\t\treturn text;\n\t\t\t},\n\t\t\tdrag_link_class: function (from, from_start, to, to_start) {\n\t\t\t\tvar add = \"\";\n\n\t\t\t\tif (from && to) {\n\t\t\t\t\tvar allowed = gantt.isLinkAllowed(from, to, from_start, to_start);\n\t\t\t\t\tadd = \" \" + (allowed ? \"gantt_link_allow\" : \"gantt_link_deny\");\n\t\t\t\t}\n\n\t\t\t\treturn \"gantt_link_tooltip\" + add;\n\t\t\t},\n\n\t\t\t/* used for aria-labels of bar elements and for tooltip.js */\n\t\t\ttooltip_date_format: date.date_to_str(\"%Y-%m-%d\"),\n\t\t\ttooltip_text: function (start, end, event) {\n\t\t\t\treturn `
Task: ${event.text}
\n\t\t\t\t
Start date: ${gantt.templates.tooltip_date_format(start)}
\n\t\t\t\t
End date: ${gantt.templates.tooltip_date_format(end)}
`;\n\t\t\t},\n\t\t\tbaseline_text: function (task, baseline, index) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t});\n\t}\n\n\treturn {\n\t\tinitTemplates: initTemplates,\n\t\tinitTemplate: initTemplate\n\t};\n\n};","import * as utils from \"../../utils/utils\";\nimport facadeFactory from \"./../facades/datastore\";\nimport calculateScaleRange from \"../gantt_data_range\";\nimport isPlaceholderTask from \"../../utils/placeholder_task\";\n\nimport treeHelper from \"../../utils/task_tree_helpers\";\n\nfunction initDataStores(gantt){\n\n\tvar facade = facadeFactory.create();\n\tutils.mixin(gantt, facade);\n\tvar tasksStore = gantt.createDatastore({\n\t\tname: \"task\",\n\t\ttype: \"treeDatastore\",\n\t\trootId: function() { return gantt.config.root_id; },\n\t\tinitItem: utils.bind(_init_task, gantt),\n\t\tgetConfig: function() { return gantt.config; }\n\t});\n\n\tvar linksStore = gantt.createDatastore({\n\t\tname: \"link\",\n\t\tinitItem: utils.bind(_init_link, gantt)\n\t});\n\n\tgantt.attachEvent(\"onDestroy\", function(){\n\t\ttasksStore.destructor();\n\t\tlinksStore.destructor();\n\t});\n\n\tgantt.attachEvent(\"onLinkValidation\", function(link){\n\t\tif(gantt.isLinkExists(link.id) || link.id === \"predecessor_generated\"){\n\t\t\t// link was already added into gantt\n\t\t\treturn true;\n\t\t}\n\t\tvar source = gantt.getTask(link.source);\n\t\tvar taskLinks = source.$source;\n\t\tfor (var i = 0; i < taskLinks.length; i++) {\n\t\t\tvar existingLink = gantt.getLink(taskLinks[i]);\n\n\t\t\tvar sourceMatch = link.source == existingLink.source;\n\t\t\tvar targetMatch = link.target == existingLink.target;\n\t\t\tvar typeMatch = link.type == existingLink.type;\n\n\t\t\t// prevent creating duplicated links from the UI\n\t\t\tif (sourceMatch && targetMatch && typeMatch) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t});\n\n\ttasksStore.attachEvent(\"onBeforeRefreshAll\", function(){\n\n\t\t// GS-2170 do not recalculate indexes and dates as the event will be called later in the onStoreUpdate event\n\t\tif (tasksStore._skipTaskRecalculation){\n\t\t\treturn;\n\t\t}\n\n\t\tvar order = tasksStore.getVisibleItems();\n\n\t\tfor(var i=0; i < order.length; i++){\n\t\t\tvar item = order[i];\n\t\t\titem.$index = i;\n\t\t\titem.$local_index = gantt.getTaskIndex(item.id);\n\t\t\tgantt.resetProjectDates(item);\n\t\t}\n\n\t});\n\n\ttasksStore.attachEvent(\"onFilterItem\", function(id, task) {\n\t\tif (gantt.config.show_tasks_outside_timescale) {\n\t\t\treturn true;\n\t\t}\n\t\tvar min = null, max = null;\n\t\tif (gantt.config.start_date && gantt.config.end_date) {\n\t\t\tif (gantt._isAllowedUnscheduledTask(task)) return true;\n\t\t\tmin = gantt.config.start_date.valueOf();\n\t\t\tmax = gantt.config.end_date.valueOf();\n\n\t\t\tif (+task.start_date > max || +task.end_date < +min)\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t});\n\n\ttasksStore.attachEvent(\"onIdChange\", function(oldId, newId){\n\t\tgantt._update_flags(oldId, newId);\n\n\t\tvar changedTask = gantt.getTask(newId);\n\t\tif(!tasksStore.isSilent()){\n\t\t\tif(changedTask.$split_subtask || changedTask.rollup){\n\t\t\t\tgantt.eachParent(function(parent){\n\t\t\t\t\tgantt.refreshTask(parent.id);\n\t\t\t\t}, newId);\n\t\t\t}\n\t\t}\n\t});\n\n\ttasksStore.attachEvent(\"onAfterUpdate\", function(id){\n\t\tgantt._update_parents(id);\n\t\tif(gantt.getState(\"batchUpdate\").batch_update){\n\t\t\treturn true;\n\t\t}\n\n\t\tvar task = tasksStore.getItem(id);\n\t\tif (!task.$source) task.$source = [];\n\t\tfor (var i = 0; i < task.$source.length; i++) {\n\t\t\tlinksStore.refresh(task.$source[i]);\n\t\t}\n\t\tif (!task.$target) task.$target = [];\n\t\tfor (var i = 0; i < task.$target.length; i++) {\n\t\t\tlinksStore.refresh(task.$target[i]);\n\t\t}\n\t});\n\n\ttasksStore.attachEvent(\"onBeforeItemMove\", function(sid, parent, tindex){\n\t\t// GS-125. Don't allow users to move the placeholder task\n\t\tif (isPlaceholderTask(sid, gantt, tasksStore)){\n\t\t\t//eslint-disable-next-line\n\t\t\tconsole.log(\"The placeholder task cannot be moved to another position.\");\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t});\n\n\ttasksStore.attachEvent(\"onAfterItemMove\", function(sid, parent, tindex){\n\t\tvar source = gantt.getTask(sid);\n\n\t\tif(this.getNextSibling(sid) !== null){\n\t\t\tsource.$drop_target = this.getNextSibling(sid);\n\t\t} else if(this.getPrevSibling(sid) !== null){\n\t\t\tsource.$drop_target = \"next:\" + this.getPrevSibling(sid);\n\t\t}else{\n\t\t\tsource.$drop_target = \"next:null\";\n\t\t}\n\n\t});\n\n\ttasksStore.attachEvent(\"onStoreUpdated\", function(id, item, action){\n\t\tif(action == \"delete\"){\n\t\t\tgantt._update_flags(id, null);\n\t\t}\n\n\t\tvar state = gantt.$services.getService(\"state\");\n\t\tif(state.getState(\"batchUpdate\").batch_update){\n\t\t\treturn;\n\t\t}\n\n\t\tif(gantt.config.fit_tasks && action !== \"paint\"){\n\t\t\tvar oldState = gantt.getState();\n\t\t\tcalculateScaleRange(gantt);\n\t\t\tvar newState = gantt.getState();\n\n\t\t\t//this._init_tasks_range();\n\t\t\tif (+oldState.min_date != +newState.min_date || +oldState.max_date != +newState.max_date) {\n\t\t\t\tgantt.render();\n\n\t\t\t\tgantt.callEvent(\"onScaleAdjusted\", []);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t}\n\n\t\tif(action == \"add\" || action == \"move\" || action == \"delete\"){\n\t\t\tif(gantt.$layout){\n\t\t\t\t// GS-2170. Do not recalculate the indexes and dates of other tasks in the\n\t\t\t\t// onBeforeResize layout event, but do it later. If lightbox is opened, it will\n\t\t\t\t// trigger the refreshData, so the indexes and dates will be recalculated there\n\t\t\t\tif (this.$config.name == \"task\" && (action == \"add\" || action == \"delete\")){\n\t\t\t\t\tif (this._skipTaskRecalculation != \"lightbox\"){\n\t\t\t\t\t\tthis._skipTaskRecalculation = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tgantt.$layout.resize();\n\t\t\t}\n\n\t\t}else if(!id){\n\t\t\tlinksStore.refresh();\n\t\t}\n\n\t});\n\n\tlinksStore.attachEvent(\"onAfterAdd\", function(id, link){\n\t\tsync_link(link);\n\t});\n\tlinksStore.attachEvent(\"onAfterUpdate\", function(id, link){\n\t\tsync_links();\n\t});\n\tlinksStore.attachEvent(\"onAfterDelete\", function(id, link){\n\t\tsync_link_delete(link);\n\t});\n\tlinksStore.attachEvent(\"onAfterSilentDelete\", function(id, link){\n\t\tsync_link_delete(link);\n\t});\n\tlinksStore.attachEvent(\"onBeforeIdChange\", function(oldId, newId){\n\t\tsync_link_delete(gantt.mixin({id:oldId}, gantt.$data.linksStore.getItem(newId)));\n\t\tsync_link(gantt.$data.linksStore.getItem(newId));\n\t});\n\n\tfunction checkLinkedTaskVisibility(taskId){\n\t\tvar isVisible = gantt.isTaskVisible(taskId);\n\t\tif(!isVisible && gantt.isTaskExists(taskId)){\n\t\t\tvar parent = gantt.getParent(taskId);\n\t\t\tif(gantt.isTaskExists(parent) && gantt.isTaskVisible(parent)){\n\t\t\t\tparent = gantt.getTask(parent);\n\t\t\t\tif(gantt.isSplitTask(parent)){\n\t\t\t\t\tisVisible = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn isVisible;\n\t}\n\n\tlinksStore.attachEvent(\"onFilterItem\", function(id, link){\n\t\tif (!gantt.config.show_links) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar sourceVisible = checkLinkedTaskVisibility(link.source);\n\t\tvar targetVisible = checkLinkedTaskVisibility(link.target);\n\n\t\tif (!(sourceVisible && targetVisible) ||\n\t\t\tgantt._isAllowedUnscheduledTask(gantt.getTask(link.source)) || gantt._isAllowedUnscheduledTask(gantt.getTask(link.target)))\n\t\t\treturn false;\n\n\t\treturn gantt.callEvent(\"onBeforeLinkDisplay\", [id, link]);\n\t});\n\n\n\t(function(){\n\t\t// delete all connected links after task is deleted\n\t\tvar deletedLinks = {};\n\n\t\tgantt.attachEvent(\"onBeforeTaskDelete\", function(id, item){\n\t\t\tdeletedLinks[id] = treeHelper.getSubtreeLinks(gantt, id);\n\t\t\treturn true;\n\t\t});\n\n\t\tgantt.attachEvent(\"onAfterTaskDelete\", function(id, item) {\n\t\t\tif(deletedLinks[id]){\n\t\t\t\tgantt.$data.linksStore.silent(function(){\n\t\t\t\t\tfor(var i in deletedLinks[id]){\n\t\t\t\t\t\tif (gantt.isLinkExists(i)){\n\t\t\t\t\t\t\tgantt.$data.linksStore.removeItem(i);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsync_link_delete(deletedLinks[id][i]);\n\t\t\t\t\t}\n\n\t\t\t\t\tdeletedLinks[id] = null;\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t})();\n\n\tgantt.attachEvent(\"onAfterLinkDelete\", function(id, link) {\n\t\tgantt.refreshTask(link.source);\n\t\tgantt.refreshTask(link.target);\n\t});\n\n\tgantt.attachEvent(\"onParse\", sync_links);\n\n\tmapEvents({\n\t\tsource: linksStore,\n\t\ttarget: gantt,\n\t\tevents:{\n\t\t\t\"onItemLoading\":\"onLinkLoading\",\n\t\t\t\"onBeforeAdd\":\"onBeforeLinkAdd\",\n\t\t\t\"onAfterAdd\":\"onAfterLinkAdd\",\n\t\t\t\"onBeforeUpdate\":\"onBeforeLinkUpdate\",\n\t\t\t\"onAfterUpdate\":\"onAfterLinkUpdate\",\n\t\t\t\"onBeforeDelete\":\"onBeforeLinkDelete\",\n\t\t\t\"onAfterDelete\":\"onAfterLinkDelete\",\n\t\t\t\"onIdChange\":\"onLinkIdChange\"\n\t\t}\n\t});\n\n\tmapEvents({\n\t\tsource: tasksStore,\n\t\ttarget: gantt,\n\t\tevents:{\n\t\t\t\"onItemLoading\":\"onTaskLoading\",\n\t\t\t\"onBeforeAdd\":\"onBeforeTaskAdd\",\n\t\t\t\"onAfterAdd\":\"onAfterTaskAdd\",\n\t\t\t\"onBeforeUpdate\":\"onBeforeTaskUpdate\",\n\t\t\t\"onAfterUpdate\":\"onAfterTaskUpdate\",\n\t\t\t\"onBeforeDelete\":\"onBeforeTaskDelete\",\n\t\t\t\"onAfterDelete\":\"onAfterTaskDelete\",\n\t\t\t\"onIdChange\":\"onTaskIdChange\",\n\t\t\t\"onBeforeItemMove\":\"onBeforeTaskMove\",\n\t\t\t\"onAfterItemMove\":\"onAfterTaskMove\",\n\t\t\t\"onFilterItem\":\"onBeforeTaskDisplay\",\n\t\t\t\"onItemOpen\":\"onTaskOpened\",\n\t\t\t\"onItemClose\":\"onTaskClosed\",\n\t\t\t\"onBeforeSelect\":\"onBeforeTaskSelected\",\n\t\t\t\"onAfterSelect\":\"onTaskSelected\",\n\t\t\t\"onAfterUnselect\":\"onTaskUnselected\"\n\t\t}\n\t});\n\n\tgantt.$data = {\n\t\ttasksStore: tasksStore,\n\t\tlinksStore: linksStore\n\t};\n\n\tfunction sync_link(link){\n\t\tif(gantt.isTaskExists(link.source)){\n\t\t\tvar sourceTask = gantt.getTask(link.source);\n\t\t\tsourceTask.$source = sourceTask.$source || [];\n\t\t\tsourceTask.$source.push(link.id);\n\t\t}\n\t\tif(gantt.isTaskExists(link.target)){\n\t\t\tvar targetTask = gantt.getTask(link.target);\n\t\t\ttargetTask.$target = targetTask.$target || [];\n\t\t\ttargetTask.$target.push(link.id);\n\t\t}\n\t}\n\n\tfunction sync_link_delete(link){\n\t\tif(gantt.isTaskExists(link.source)){\n\t\t\tvar sourceTask = gantt.getTask(link.source);\n\t\t\tfor(var i = 0; i < sourceTask.$source.length; i++){\n\t\t\t\tif(sourceTask.$source[i] == link.id){\n\t\t\t\t\tsourceTask.$source.splice(i, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(gantt.isTaskExists(link.target)){\n\t\t\tvar targetTask = gantt.getTask(link.target);\n\t\t\tfor(var i = 0; i < targetTask.$target.length; i++){\n\t\t\t\tif(targetTask.$target[i] == link.id){\n\t\t\t\t\ttargetTask.$target.splice(i, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction sync_links() {\n\t\tvar task = null;\n\t\tvar tasks = gantt.$data.tasksStore.getItems();\n\n\t\tfor(var i = 0, len = tasks.length; i < len; i++){\n\t\t\ttask = tasks[i];\n\t\t\ttask.$source = [];\n\t\t\ttask.$target = [];\n\t\t}\n\n\t\tvar links = gantt.$data.linksStore.getItems();\n\t\tfor (var i = 0, len = links.length; i < len; i++) {\n\n\t\t\tvar link = links[i];\n\t\t\tsync_link(link);\n\t\t}\n\t}\n\n\tfunction mapEvents(conf){\n\t\tvar mapFrom = conf.source;\n\t\tvar mapTo = conf.target;\n\t\tfor(var i in conf.events){\n\t\t\t(function(sourceEvent, targetEvent){\n\t\t\t\tmapFrom.attachEvent(sourceEvent, function(){\n\t\t\t\t\treturn mapTo.callEvent(targetEvent, Array.prototype.slice.call(arguments));\n\t\t\t\t}, targetEvent);\n\t\t\t})(i, conf.events[i]);\n\t\t}\n\t}\n\n\tfunction _init_task(task) {\n\t\tif (!this.defined(task.id))\n\t\t\ttask.id = this.uid();\n\n\t\tif (task.start_date)\n\t\t\ttask.start_date = gantt.date.parseDate(task.start_date, \"parse_date\");\n\t\tif (task.end_date)\n\t\t\ttask.end_date = gantt.date.parseDate(task.end_date, \"parse_date\");\n\n\n\t\tvar duration = null;\n\t\tif (task.duration || task.duration === 0) {\n\t\t\ttask.duration = duration = task.duration * 1;\n\t\t}\n\n\t\tif (duration) {\n\t\t\tif (task.start_date && !task.end_date) {\n\t\t\t\ttask.end_date = this.calculateEndDate(task);\n\t\t\t} else if (!task.start_date && task.end_date) {\n\t\t\t\ttask.start_date = this.calculateEndDate({\n\t\t\t\t\tstart_date: task.end_date,\n\t\t\t\t\tduration: -task.duration,\n\t\t\t\t\ttask: task\n\t\t\t\t});\n\t\t\t}\n\t\t\t//task.$calculate_duration = false;\n\t\t}\n\n\t\tif (gantt.config.deadlines !== false && task.deadline){\n\t\t\ttask.deadline = gantt.date.parseDate(task.deadline, \"parse_date\");\n\t\t}\n\n\t\ttask.progress = Number(task.progress) || 0;\n\n\t\tif (this._isAllowedUnscheduledTask(task)) {\n\t\t\tthis._set_default_task_timing(task);\n\t\t}\n\t\tthis._init_task_timing(task);\n\t\tif (task.start_date && task.end_date)\n\t\t\tthis.correctTaskWorkTime(task);\n\n\t\ttask.$source = [];\n\t\ttask.$target = [];\n\n\t\tvar originalTask = this.$data.tasksStore.getItem(task.id);\n\t\tif (originalTask && !utils.defined(task.open)) {\n\t\t\t// if a task with the same id is already in the gantt and the new object doesn't specify the `open` state -\n\t\t\t// restore the `open` state we already have in the chart\n\t\t\ttask.$open = originalTask.$open;\n\t\t}\n\n\t\tif (task.parent === undefined) {\n\t\t\ttask.parent = this.config.root_id;\n\t\t}\n\t\tif(task.open){\n\t\t\ttask.$open = true;\n\t\t}\n\t\treturn task;\n\t}\n\n\tfunction _init_link(link) {\n\t\tif (!this.defined(link.id))\n\t\t\tlink.id = this.uid();\n\t\treturn link;\n\t}\n}\n\n\nexport default initDataStores;\n","import batch_update from \"./batch_update\";\nimport wbs from \"./wbs\";\nimport resources from \"./resources\";\nimport resource_assignments from \"./resource_assignments\";\nimport new_task_placeholder from \"./new_task_placeholder\";\nimport auto_task_types from \"./auto_task_types\";\nimport formatters from \"./formatters\";\nimport empty_state_screen from \"./empty_state_screen\";\nimport baselines from \"./baselines\";\n\nexport default function(gantt){\n\tif(!gantt.ext){\n\t\tgantt.ext = {};\n\t}\n\n\tvar modules = [\n\t\tbatch_update,\n\t\twbs,\n\t\tresources,\n\t\tresource_assignments,\n\t\tnew_task_placeholder,\n\t\tauto_task_types,\n\t\tformatters,\n\t\tempty_state_screen,\n\t\tbaselines\n\t];\n\n\tfor(var i = 0; i < modules.length; i++){\n\t\tif(modules[i])\n\t\t\tmodules[i](gantt);\n\t}\n};","export default function(gantt) {\n\tgantt.getGridColumn = function(name) {\n\t\tvar columns = gantt.config.columns;\n\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tif (columns[i].name == name)\n\t\t\t\treturn columns[i];\n\t\t}\n\n\t\treturn null;\n\t};\n\n\tgantt.getGridColumns = function() {\n\t\treturn gantt.config.columns.slice();\n\t};\n};","import Grid from \"./ui/grid/grid\";\nimport gridColumnApiGPL from \"./grid_column_api.gpl\";\n\nexport default function(gantt) {\n\tgridColumnApiGPL(gantt);\n\tGrid.prototype.getGridColumns = function () {\n\t\tvar config = this.$getConfig();\n\t\tvar columns = config.columns,\n\t\t\tvisibleColumns = [];\n\n\t\tfor (var i = 0; i < columns.length; i++) {\n\t\t\tif (!columns[i].hide)\n\t\t\t\tvisibleColumns.push(columns[i]);\n\t\t}\n\n\t\treturn visibleColumns;\n\t};\n};","export default function(gantt) {\n\tgantt.isReadonly = function (item) {\n\n\t\tif((typeof item == \"number\" || typeof item == \"string\") && gantt.isTaskExists(item)){\n\t\t\titem = gantt.getTask(item);\n\t\t}\n\t\tif (item && item[this.config.editable_property]) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn (item && item[this.config.readonly_property]) || this.config.readonly;\n\t\t}\n\t};\n};","import * as helpers from \"../../utils/helpers\";\n\nexport default function(gantt) {\n\tgantt.load = function(){\n\t\tthrow new Error(\"gantt.load() method is not available in the node.js, use gantt.parse() instead\");\n\t};\n\tgantt.parse = function (data, type) {\n\t\tthis.on_load({xmlDoc: {responseText: data}}, type);\n\t};\n\n\tgantt.serialize = function (type) {\n\t\ttype = type || \"json\";\n\t\treturn this[type].serialize();\n\t};\n\n\t/*\n\ttasks and relations\n\t{\n\tdata:[\n\t\t{\n\t\t\t\"id\":\"string\",\n\t\t\t\"text\":\"...\",\n\t\t\t\"start_date\":\"Date or string\",\n\t\t\t\"end_date\":\"Date or string\",\n\t\t\t\"duration\":\"number\",\n\t\t\t\"progress\":\"0..1\",\n\t\t\t\"parent_id\":\"string\",\n\t\t\t\"order\":\"number\"\n\t\t},...],\n\tlinks:[\n\t\t{\n\t\t\tid:\"string\",\n\t\t\tsource:\"string\",\n\t\t\ttarget:\"string\",\n\t\t\ttype:\"string\"\n\t\t},...],\n\tcollections:{\n\t\t\tcollectionName:[\n\t\t\t\t{key:, label:, optional:...},...\n\t\t\t],...\n\t\t}\n\t}\n\n\t* */\n\n\tgantt.on_load = function (resp, type) {\n\t\tif(resp.xmlDoc && resp.xmlDoc.status === 404){ // work if we don't have a file at current url\n\t\t\tthis.assert(false, \"Failed to load the data from \" \n\t\t\t\t+ resp.xmlDoc.responseURL + \", server returns 404\");\n\t\t\treturn;\n\t\t}\n\t\tif(gantt.$destroyed){\n\t\t\treturn;\n\t\t}\n\t\tthis.callEvent(\"onBeforeParse\", []);\n\t\tif (!type)\n\t\t\ttype = \"json\";\n\t\tthis.assert(this[type], \"Invalid data type:'\" + type + \"'\");\n\n\t\tvar raw = resp.xmlDoc.responseText;\n\n\t\tvar data = this[type].parse(raw, resp);\n\t\tthis._process_loading(data);\n\t};\n\n\tfunction attachAssignmentsToTasks(tasks, assignments) {\n\t\tconst assignmentsByTasks = {};\n\t\tassignments.forEach((a)=>{\n\t\t\tif(!assignmentsByTasks[a.task_id]) {\n\t\t\t\tassignmentsByTasks[a.task_id] = [];\n\t\t\t}\n\t\t\tassignmentsByTasks[a.task_id].push(a);\n\t\t});\n\t\ttasks.forEach((t) => {\n\t\t\tt[gantt.config.resource_property] = assignmentsByTasks[t.id] || [];\n\t\t});\t\n\t}\n\t\n\tgantt._process_loading = function (data) {\n\t\tif(data.collections)\n\t\t\tthis._load_collections(data.collections);\n\n\t\tif(data.resources && this.$data.resourcesStore){\n\t\t\tthis.$data.resourcesStore.parse(data.resources);\n\t\t}\n\t\tif(gantt.config.baselines !== false && data.baselines && this.$data.baselineStore){\n\t\t\tthis.$data.baselineStore.parse(data.baselines);\n\t\t}\n\t\t\n\t\tconst tasks = data.data || data.tasks;\n\t\tif(data.assignments){\n\t\t\tattachAssignmentsToTasks(tasks, data.assignments);\n\t\t}\n\n\t\tthis.$data.tasksStore.parse(tasks);\n\t\tvar links = data.links || (data.collections ? data.collections.links : []);\n\t\tthis.$data.linksStore.parse(links);\n\n\t\t//this._sync_links();\n\t\tthis.callEvent(\"onParse\", []);\n\t\tthis.render();\n\t};\n\n\tgantt._load_collections = function (collections) {\n\t\tvar collections_loaded = false;\n\t\tfor (var key in collections) {\n\t\t\tif (collections.hasOwnProperty(key)) {\n\t\t\t\tcollections_loaded = true;\n\t\t\t\tvar collection = collections[key];\n\t\t\t\t// GS-1728. Create an empty serverList if it doesn't exist\n\t\t\t\tthis.serverList[key] = this.serverList[key] || [];\n\t\t\t\tvar arr = this.serverList[key];\n\t\t\t\tif (!arr) continue;\n\t\t\t\tarr.splice(0, arr.length); //clear old options\n\t\t\t\tfor (var j = 0; j < collection.length; j++) {\n\t\t\t\t\tvar option = collection[j];\n\t\t\t\t\tvar obj = this.copy(option);\n\t\t\t\t\tobj.key = obj.value;// resulting option object\n\n\t\t\t\t\tfor (var option_key in option) {\n\t\t\t\t\t\tif (option.hasOwnProperty(option_key)) {\n\t\t\t\t\t\t\tif (option_key == \"value\" || option_key == \"label\")\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\tobj[option_key] = option[option_key]; // obj['value'] = option['value']\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tarr.push(obj);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (collections_loaded)\n\t\t\tthis.callEvent(\"onOptionsLoad\", []);\n\t};\n\n\tgantt.attachEvent(\"onBeforeTaskDisplay\", function (id, task) {\n\t\treturn !task.$ignore;\n\t});\n\n\tfunction jsonParseError(data){\n\t\tgantt.assert(false, \"Can't parse data: incorrect value of gantt.parse or gantt.load method. \"\n\t\t\t+ \"Actual argument value: \" + JSON.stringify(data));\n\t\tthrow new Error(\"Invalid argument for gantt.parse or gantt.load. An object or a JSON string of format https://docs.dhtmlx.com/gantt/desktop__supported_data_formats.html#json is expected. Actual argument value: \"\n\t\t\t+ JSON.stringify(data));\n\t}\n\n\tgantt.json = {\n\t\tparse: function (data) {\n\t\t\tif(!data){\n\t\t\t\tjsonParseError(data);\n\t\t\t}\n\n\t\t\tif (typeof data == \"string\") {\n\t\t\t\tif (typeof JSON != undefined){\n\t\t\t\t\ttry{\n\t\t\t\t\t\tdata = JSON.parse(data);\n\t\t\t\t\t}\n\t\t\t\t\tcatch(e) {\n\t\t\t\t\t\tjsonParseError(data);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tgantt.assert(false, \"JSON is not supported\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(!data.data && !data.tasks){\n\t\t\t\tjsonParseError(data);\n\t\t\t}\n\n\t\t\tif (data.dhx_security)\n\t\t\t\tgantt.security_key = data.dhx_security;\n\t\t\treturn data;\n\t\t},\n\t\tserializeTask: function (task) {\n\t\t\treturn this._copyObject(task);\n\t\t},\n\t\tserializeLink: function (link) {\n\t\t\treturn this._copyLink(link);\n\t\t},\n\t\t_copyLink: function (obj) {\n\t\t\tvar copy = {};\n\t\t\tfor (var key in obj)\n\t\t\t\tcopy[key] = obj[key];\n\t\t\treturn copy;\n\t\t},\n\t\t_copyObject: function (obj) {\n\t\t\tvar copy = {};\n\t\t\tfor (var key in obj) {\n\t\t\t\tif (key.charAt(0) == \"$\")\n\t\t\t\t\tcontinue;\n\t\t\t\tcopy[key] = obj[key];\n\n\t\t\t\tif (helpers.isDate(copy[key])) {\n\t\t\t\t\tcopy[key] = gantt.defined(gantt.templates.xml_format) ? gantt.templates.xml_format(copy[key]) : gantt.templates.format_date(copy[key]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn copy;\n\t\t},\n\t\tserialize: function () {\n\t\t\tvar tasks = [];\n\t\t\tvar links = [];\n\t\t\tlet baselines = [];\n\n\t\t\tgantt.eachTask(function (obj) {\n\t\t\t\tgantt.resetProjectDates(obj);\n\t\t\t\ttasks.push(this.serializeTask(obj));\n\t\t\t}, gantt.config.root_id, this);\n\n\t\t\tvar rawLinks = gantt.getLinks();\n\t\t\tfor (var i = 0; i < rawLinks.length; i++) {\n\t\t\t\tlinks.push(this.serializeLink(rawLinks[i]));\n\t\t\t}\n\n\t\t\tconst baselineStore = gantt.getDatastore(\"baselines\");\n\t\t\tbaselineStore.eachItem(function(baseline){\n\t\t\t\tconst baselineCopy = gantt.json.serializeTask(baseline);\n\t\t\t\tbaselines.push(baselineCopy);\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tdata: tasks,\n\t\t\t\tlinks,\n\t\t\t\tbaselines\n\t\t\t};\n\t\t}\n\t};\n\n\t/*\n\t\n\t\t\n\t\t\tMy task 1\n\t\t\t16.08.2013\n\t\t\t22.08.2013\n\t\t\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t\n\t*/\n\n\tfunction xmlParseError(data){\n\t\tgantt.assert(false, \"Can't parse data: incorrect value of gantt.parse or gantt.load method. \"\n\t\t\t+ \"Actual argument value: \" + JSON.stringify(data));\n\t\tthrow new Error(\"Invalid argument for gantt.parse or gantt.load. An XML of format https://docs.dhtmlx.com/gantt/desktop__supported_data_formats.html#xmldhtmlxgantt20 is expected. Actual argument value: \"\n\t\t\t+ JSON.stringify(data));\n\t}\n\n\tgantt.xml = {\n\t\t_xmlNodeToJSON: function (node, attrs_only) {\n\t\t\tvar t = {};\n\t\t\tfor (var i = 0; i < node.attributes.length; i++)\n\t\t\t\tt[node.attributes[i].name] = node.attributes[i].value;\n\n\t\t\tif (!attrs_only) {\n\t\t\t\tfor (var i = 0; i < node.childNodes.length; i++) {\n\t\t\t\t\tvar child = node.childNodes[i];\n\t\t\t\t\tif (child.nodeType == 1)\n\t\t\t\t\t\tt[child.tagName] = child.firstChild ? child.firstChild.nodeValue : \"\";\n\t\t\t\t}\n\n\t\t\t\tif (!t.text) t.text = node.firstChild ? node.firstChild.nodeValue : \"\";\n\t\t\t}\n\n\t\t\treturn t;\n\t\t},\n\t\t_getCollections: function (loader) {\n\t\t\tvar collection = {};\n\t\t\tvar opts = gantt.ajax.xpath(\"//coll_options\", loader);\n\t\t\tfor (var i = 0; i < opts.length; i++) {\n\t\t\t\tvar bind = opts[i].getAttribute(\"for\");\n\t\t\t\tvar arr = collection[bind] = [];\n\t\t\t\tvar itms = gantt.ajax.xpath(\".//item\", opts[i]);\n\t\t\t\tfor (var j = 0; j < itms.length; j++) {\n\t\t\t\t\tvar itm = itms[j];\n\t\t\t\t\tvar attrs = itm.attributes;\n\t\t\t\t\tvar obj = {key: itms[j].getAttribute(\"value\"), label: itms[j].getAttribute(\"label\")};\n\t\t\t\t\tfor (var k = 0; k < attrs.length; k++) {\n\t\t\t\t\t\tvar attr = attrs[k];\n\t\t\t\t\t\tif (attr.nodeName == \"value\" || attr.nodeName == \"label\")\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tobj[attr.nodeName] = attr.nodeValue;\n\t\t\t\t\t}\n\t\t\t\t\tarr.push(obj);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn collection;\n\t\t},\n\t\t_getXML: function (text, loader, toptag) {\n\t\t\ttoptag = toptag || \"data\";\n\t\t\tif (!loader.getXMLTopNode) {\n\t\t\t\tloader = gantt.ajax.parse(loader);\n\t\t\t}\n\n\t\t\tvar xml = gantt.ajax.xmltop(toptag, loader.xmlDoc);\n\t\t\tif (!xml || xml.tagName != toptag) {\n\t\t\t\txmlParseError(text);\n\t\t\t}\n\n\t\t\tvar skey = xml.getAttribute(\"dhx_security\");\n\t\t\tif (skey)\n\t\t\t\tgantt.security_key = skey;\n\n\t\t\treturn xml;\n\t\t},\n\t\tparse: function (text, loader) {\n\t\t\tloader = this._getXML(text, loader);\n\t\t\tvar data = {};\n\n\t\t\tvar evs = data.data = [];\n\t\t\tvar xml = gantt.ajax.xpath(\"//task\", loader);\n\n\t\t\tfor (var i = 0; i < xml.length; i++)\n\t\t\t\tevs[i] = this._xmlNodeToJSON(xml[i]);\n\n\t\t\tdata.collections = this._getCollections(loader);\n\t\t\treturn data;\n\t\t},\n\t\t_copyLink: function (obj) {\n\t\t\treturn \"\";\n\t\t},\n\t\t_copyObject: function (obj) {\n\t\t\treturn \"\";\n\t\t},\n\t\tserialize: function () {\n\t\t\tvar tasks = [];\n\t\t\tvar links = [];\n\n\t\t\tvar json = gantt.json.serialize();\n\t\t\tfor (var i = 0, len = json.data.length; i < len; i++) {\n\t\t\t\ttasks.push(this._copyObject(json.data[i]));\n\t\t\t}\n\t\t\tfor (var i = 0, len = json.links.length; i < len; i++) {\n\t\t\t\tlinks.push(this._copyLink(json.links[i]));\n\t\t\t}\n\t\t\treturn \"\" + tasks.join(\"\") + \"\" + links.join(\"\") + \"\";\n\t\t}\n\t};\n\n\n\tgantt.oldxml = {\n\t\tparse: function (text, loader) {\n\t\t\tloader = gantt.xml._getXML(text, loader, \"projects\");\n\t\t\tvar data = {collections: {links: []}};\n\n\t\t\tvar evs = data.data = [];\n\t\t\tvar xml = gantt.ajax.xpath(\"//task\", loader);\n\n\t\t\tfor (var i = 0; i < xml.length; i++) {\n\t\t\t\tevs[i] = gantt.xml._xmlNodeToJSON(xml[i]);\n\t\t\t\tvar parent = xml[i].parentNode;\n\n\t\t\t\tif (parent.tagName == \"project\")\n\t\t\t\t\tevs[i].parent = \"project-\" + parent.getAttribute(\"id\");\n\t\t\t\telse\n\t\t\t\t\tevs[i].parent = parent.parentNode.getAttribute(\"id\");\n\t\t\t}\n\n\t\t\txml = gantt.ajax.xpath(\"//project\", loader);\n\t\t\tfor (var i = 0; i < xml.length; i++) {\n\t\t\t\tvar ev = gantt.xml._xmlNodeToJSON(xml[i], true);\n\t\t\t\tev.id = \"project-\" + ev.id;\n\t\t\t\tevs.push(ev);\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < evs.length; i++) {\n\t\t\t\tvar ev = evs[i];\n\t\t\t\tev.start_date = ev.startdate || ev.est;\n\t\t\t\tev.end_date = ev.enddate;\n\t\t\t\tev.text = ev.name;\n\t\t\t\tev.duration = ev.duration / 8;\n\t\t\t\tev.open = 1;\n\t\t\t\tif (!ev.duration && !ev.end_date) ev.duration = 1;\n\t\t\t\tif (ev.predecessortasks)\n\t\t\t\t\tdata.collections.links.push({\n\t\t\t\t\t\ttarget: ev.id,\n\t\t\t\t\t\tsource: ev.predecessortasks,\n\t\t\t\t\t\ttype: gantt.config.links.finish_to_start\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn data;\n\t\t},\n\t\tserialize: function () {\n\t\t\tgantt.message(\"Serialization to 'old XML' is not implemented\");\n\t\t}\n\t};\n\n\tgantt.serverList = function (name, array) {\n\t\tif (array) {\n\t\t\tthis.serverList[name] = array.slice(0);\n\t\t} else if (!this.serverList[name]) {\n\t\t\tthis.serverList[name] = [];\n\t\t}\n\t\treturn this.serverList[name];\n\t};\n\n};","import * as helpers from \"../utils/helpers\";\n\nexport default function(gantt) {\n\n\tgantt.isUnscheduledTask = function (task) {\n\t\tgantt.assert(task && task instanceof Object, \"Invalid argument task=\"+task+\" of gantt.isUnscheduledTask. Task object was expected\");\n\t\treturn (!!task.unscheduled || !task.start_date);\n\t};\n\n\tgantt._isAllowedUnscheduledTask = function (task) {\n\t\treturn !!(task.unscheduled && gantt.config.show_unscheduled);\n\t};\n\n\tgantt._isTaskInTimelineLimits = function(task) {\n\t\tvar taskStart = task.start_date ? task.start_date.valueOf() : null;\n\t\tvar taskEnd = task.end_date ? task.end_date.valueOf() : null;\n\t\treturn !!(taskStart && taskEnd && taskStart <= this._max_date.valueOf() && taskEnd >= this._min_date.valueOf());\n\t};\n\tgantt.isTaskVisible = function (id) {\n\t\tif (!this.isTaskExists(id)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar task = this.getTask(id);\n\t\tif (!(this._isAllowedUnscheduledTask(task) || this._isTaskInTimelineLimits(task))) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!(this.getGlobalTaskIndex(id) >= 0);\n\t};\n\n\tgantt._getProjectEnd = function() {\n\t\tif(gantt.config.project_end){\n\t\t\treturn gantt.config.project_end;\n\t\t}else{\n\t\t\tvar tasks = gantt.getTaskByTime();\n\t\t\ttasks = tasks.sort(function (a, b) {\n\t\t\t\treturn +a.end_date > +b.end_date ? 1 : -1;\n\t\t\t});\n\t\t\treturn tasks.length ? tasks[tasks.length - 1].end_date : null;\n\t\t}\n\t};\n\tgantt._getProjectStart = function() {\n\t\tif (gantt.config.project_start) {\n\t\t\treturn gantt.config.project_start;\n\t\t}\n\n\t\t// use timeline start if project start is not specified\n\t\tif (gantt.config.start_date) {\n\t\t\treturn gantt.config.start_date;\n\t\t}\n\t\tif (gantt.getState().min_date) {\n\t\t\treturn gantt.getState().min_date;\n\t\t}\n\n\t\t// earliest task start if neither project start nor timeline are specified\n\t\tvar tasks = gantt.getTaskByTime();\n\t\ttasks = tasks.sort(function (a, b) {\n\t\t\treturn +a.start_date > +b.start_date ? 1 : -1;\n\t\t});\n\t\treturn tasks.length ? tasks[0].start_date : null;\n\t};\n\n\tvar getDefaultTaskDate = function (item, parent_id) {\n\t\tvar parentExists = parent_id && parent_id != gantt.config.root_id && gantt.isTaskExists(parent_id);\n\t\tvar parent = parentExists ? gantt.getTask(parent_id) : false,\n\t\t\tstartDate = null;\n\t\tif (parent) {\n\t\t\tif(gantt.config.schedule_from_end){\n\t\t\t\tstartDate = gantt.calculateEndDate({\n\t\t\t\t\tstart_date: parent.end_date,\n\t\t\t\t\tduration: - gantt.config.duration_step,\n\t\t\t\t\ttask:item\n\t\t\t\t});\n\t\t\t}else{\n\t\t\t\tif(!parent.start_date){\n\t\t\t\t\treturn getDefaultTaskDate(parent, gantt.getParent(parent));\n\t\t\t\t}\n\t\t\t\tstartDate = parent.start_date;\n\t\t\t}\n\n\t\t} else if(gantt.config.schedule_from_end) {\n\t\t\tstartDate = gantt.calculateEndDate({\n\t\t\t\tstart_date: gantt._getProjectEnd(),\n\t\t\t\tduration: - gantt.config.duration_step,\n\t\t\t\ttask:item\n\t\t\t});\n\t\t} else {\n\t\t\tconst first = gantt.getTaskByIndex(0);\n\t\t\tconst minDate = gantt.config.start_date || gantt.getState().min_date;\n\n\t\t\tif (first){\n\t\t\t\tif (first.start_date){\n\t\t\t\t\tstartDate = first.start_date;\n\t\t\t\t}\n\t\t\t\telse if (first.end_date){\n\t\t\t\t\tstartDate = gantt.calculateEndDate({\n\t\t\t\t\t\tstart_date: first.end_date,\n\t\t\t\t\t\tduration: -gantt.config.duration_step,\n\t\t\t\t\t\ttask:item\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tstartDate = minDate;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstartDate = minDate;\n\t\t\t}\n\t\t}\n\t\tgantt.assert(startDate, \"Invalid dates\");\n\t\treturn new Date(startDate);\n\t};\n\n\tgantt._set_default_task_timing = function (task) {\n\t\ttask.start_date = task.start_date || getDefaultTaskDate(task, gantt.getParent(task));\n\t\ttask.duration = task.duration || gantt.config.duration_step;\n\t\ttask.end_date = task.end_date || gantt.calculateEndDate(task);\n\t};\n\n\tgantt.createTask = function (item, parent, index) {\n\t\titem = item || {};\n\n\t\tif (!gantt.defined(item.id))\n\t\t\titem.id = gantt.uid();\n\n\t\tif (!item.start_date) {\n\t\t\titem.start_date = getDefaultTaskDate(item, parent);\n\t\t}\n\t\tif (item.text === undefined) {\n\t\t\titem.text = gantt.locale.labels.new_task;\n\t\t}\n\t\tif (item.duration === undefined) {\n\t\t\titem.duration = 1;\n\t\t}\n\n\t\tif (this.isTaskExists(parent)) {\n\t\t\tthis.setParent(item, parent, true);\n\t\t\tvar parentObj = this.getTask(parent);\n\t\t\tparentObj.$open = true;\n\t\t\t// GS-1583. Save the $open state to the Undo Stack\n\t\t\tif (!this.config.details_on_create){\n\t\t\t\tthis.callEvent(\"onAfterParentExpand\", [parent, parentObj]);\n\t\t\t}\n\t\t}\n\n\t\tif (!this.callEvent(\"onTaskCreated\", [item])) {\n\t\t\treturn null;\n\t\t}\n\t\tif (this.config.details_on_create) {\n\t\t\t//GS-761: assert unique ID\n\t\t\tif (gantt.isTaskExists(item.id)){\n\t\t\t\tvar task = gantt.getTask(item.id);\n\t\t\t\tif (task.$index != item.$index) {\n\t\t\t\t\t// Someone may try to mistakenly add a task with the same ID, and most likely\n\t\t\t\t\t// use the string format for the dates. Gantt shouldn't break in this scenario\n\t\t\t\t\tif (item.start_date && typeof item.start_date === \"string\"){\n\t\t\t\t\t\titem.start_date = this.date.parseDate(item.start_date, \"parse_date\");\n\t\t\t\t\t}\n\t\t\t\t\tif (item.end_date && typeof item.end_date === \"string\"){\n\t\t\t\t\t\titem.end_date = this.date.parseDate(item.end_date, \"parse_date\");\n\t\t\t\t\t}\n\t\t\t\t\tthis.$data.tasksStore.updateItem(item.id, item);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\titem.$new = true;\n\t\t\t\tthis.silent(function(){\n\t\t\t\t\tgantt.$data.tasksStore.addItem(item, index);\n\t\t\t\t});\t\n\t\t\t}\n\t\t\tthis.selectTask(item.id);\n\t\t\tthis.refreshData();\n\t\t\tthis.showLightbox(item.id);\n\t\t} else {\n\t\t\tif (this.addTask(item, parent, index)) {\n\t\t\t\tthis.showTask(item.id);\n\t\t\t\tthis.selectTask(item.id);\n\t\t\t}\n\t\t}\n\t\treturn item.id;\n\t};\n\n\tgantt._update_flags = function (oldid, newid) {\n\t\t// TODO: need a proper way to update all possible flags\n\t\tvar store = gantt.$data.tasksStore;\n\t\tif (oldid === undefined) {\n\t\t\tthis._lightbox_id = null;\n\n\t\t\tstore.silent(function(){\n\t\t\t\tstore.unselect();\n\t\t\t});\n\t\t\t// GS-1522. If we have multiselect, unselect all previously selected tasks\n\t\t\tif (this.getSelectedTasks) {\n\t\t\t\tthis._multiselect.reset();\n\t\t\t}\n\n\t\t\tif (this._tasks_dnd && this._tasks_dnd.drag) {\n\t\t\t\tthis._tasks_dnd.drag.id = null;\n\t\t\t}\n\t\t} else {\n\t\t\tif (this._lightbox_id == oldid)\n\t\t\t\tthis._lightbox_id = newid;\n\n\t\t\t// TODO: probably can be removed\n\t\t\tif (store.getSelectedId() == oldid) {\n\t\t\t\tstore.silent(function(){\n\t\t\t\t\tstore.unselect(oldid);\n\t\t\t\t\tstore.select(newid);\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (this._tasks_dnd && this._tasks_dnd.drag && this._tasks_dnd.drag.id == oldid) {\n\t\t\t\tthis._tasks_dnd.drag.id = newid;\n\t\t\t}\n\t\t}\n\t};\n\n\tvar getTaskTimingMode = function (task, force) {\n\t\tvar task_type = gantt.getTaskType(task.type);\n\n\t\tvar state = {\n\t\t\ttype: task_type,\n\t\t\t$no_start: false,\n\t\t\t$no_end: false,\n\t\t\tscheduled_summary: false\n\t\t};\n\n\t\tif(task_type === gantt.config.types.project && task.auto_scheduling === false){\n\t\t\tstate.scheduled_summary = true;\n\t\t}\n\n\t\tif (!force && task_type == task.$rendered_type) {\n\t\t\tstate.$no_start = task.$no_start;\n\t\t\tstate.$no_end = task.$no_end;\n\t\t\treturn state;\n\t\t}\n\n\t\tif (task_type == gantt.config.types.project) {\n\t\t\t//project duration is always defined by children duration\n\t\t\tstate.$no_end = state.$no_start = true;\n\t\t} else if (task_type != gantt.config.types.milestone) {\n\t\t\t//tasks can have fixed duration, children duration(as projects), or one date fixed, and other defined by nested items\n\t\t\tstate.$no_end = !(task.end_date || task.duration);\n\t\t\tstate.$no_start = !task.start_date;\n\n\t\t\tif (gantt._isAllowedUnscheduledTask(task)) {\n\t\t\t\tstate.$no_end = state.$no_start = false;\n\t\t\t}\n\t\t}\n\n\t\treturn state;\n\t};\n\n\tgantt._init_task_timing = function (task) {\n\t\tvar task_mode = getTaskTimingMode(task, true);\n\n\t\tvar dirty = task.$rendered_type != task_mode.type;\n\n\t\tvar task_type = task_mode.type;\n\n\t\tif (dirty) {\n\t\t\ttask.$no_start = task_mode.$no_start;\n\t\t\ttask.$no_end = task_mode.$no_end;\n\t\t\ttask.$rendered_type = task_mode.type;\n\t\t}\n\n\t\tif (dirty && task_type != this.config.types.milestone) {\n\t\t\tif (task_type == this.config.types.project) {\n\t\t\t\t//project duration is always defined by children duration\n\t\t\t\tthis._set_default_task_timing(task);\n\t\t\t\ttask.$calculate_duration = false;// do not recalculate duration below\n\t\t\t}\n\t\t}\n\n\t\tif (task_type == this.config.types.milestone) {\n\t\t\ttask.end_date = task.start_date;\n\t\t}\n\t\tif (task.start_date && task.end_date && task.$calculate_duration !== false) {\n\t\t\ttask.duration = this.calculateDuration(task);\n\t\t}\n\n\t\tif(!task.$calculate_duration){\n\t\t\ttask.$calculate_duration = true;\n\t\t}\n\n\t\tif (!task.end_date) {\n\t\t\ttask.end_date = task.start_date;\n\t\t}\n\n\t\ttask.duration = task.duration || 0;\n\t\t// GS-1145. We should let tasks to have 0 duration if user wants it\n\t\tif (this.config.min_duration === 0 && task.duration === 0){\n\t\t\ttask.$no_end = false;\n\t\t}\n\n\t\t// work calendar of task has changed\n\t\tvar effectiveCalendar = this.getTaskCalendar(task);\n\t\tif(task.$effective_calendar && task.$effective_calendar !== effectiveCalendar.id){\n\t\t\tupdateTaskTiming(task);\n\t\t\tif(this.config.inherit_calendar && this.isSummaryTask(task)){\n\t\t\t\tthis.eachTask(function(child){\n\t\t\t\t\tupdateTaskTiming(child);\n\t\t\t\t}, task.id);\n\t\t\t}\n\t\t}\n\n\t\ttask.$effective_calendar = effectiveCalendar.id;\n\t};\n\n\tfunction updateTaskTiming(task) {\n\t\ttask.$effective_calendar = gantt.getTaskCalendar(task).id;\n\t\ttask.start_date = gantt.getClosestWorkTime({\n\t\t\tdir: \"future\",\n\t\t\tdate: task.start_date,\n\t\t\tunit: gantt.config.duration_unit,\n\t\t\ttask: task\n\t\t});\n\t\ttask.end_date = gantt.calculateEndDate(task);\n\t}\n\n\tgantt.isSummaryTask = function (task) {\n\t\tgantt.assert(task && task instanceof Object, \"Invalid argument task=\"+task+\" of gantt.isSummaryTask. Task object was expected\");\n\n\t\tvar mode = getTaskTimingMode(task);\n\n\t\treturn !!(mode.$no_end || mode.$no_start);\n\t};\n\n// downward calculation of project duration\n\tgantt.resetProjectDates = function (task) {\n\t\tvar taskMode = getTaskTimingMode(task);\n\t\tif (taskMode.$no_end || taskMode.$no_start) {\n\t\t\tvar info = getSubtaskInfo(task.id);\n\t\t\tassignProjectDates.call(this, task, taskMode, info.start_date, info.end_date);\n\t\t\ttask.$rollup = info.rollup;\n\t\t}\n\t};\n\n\tfunction assignProjectDates(task, taskTiming, from, to) {\n\n\t\tconst summaryDateFields = {\n\t\t\tstart: \"start_date\",\n\t\t\tend: \"end_date\"\n\t\t};\n\t\tconst manuallyScheduledSummaryDateFields = {\n\t\t\tstart: \"$auto_start_date\",\n\t\t\tend: \"$auto_end_date\"\n\t\t};\n\n\t\tlet dateFields;\n\t\tif(task.type === gantt.config.types.project && task.auto_scheduling === false){\n\t\t\tdateFields = manuallyScheduledSummaryDateFields;\n\t\t}else{\n\t\t\tdateFields = summaryDateFields;\n\t\t}\n\n\t\tif (taskTiming.$no_start) {\n\t\t\tif (from) {\n\t\t\t\ttask[dateFields.start] = new Date(from);\n\t\t\t} else {\n\t\t\t\ttask[dateFields.start] = getDefaultTaskDate(task, this.getParent(task));\n\t\t\t}\n\t\t}\n\n\t\tif (taskTiming.$no_end) {\n\t\t\tif (to) {\n\t\t\t\ttask[dateFields.end] = new Date(to);\n\t\t\t} else {\n\t\t\t\ttask[dateFields.end] = this.calculateEndDate({\n\t\t\t\t\tstart_date: task[dateFields.start],\n\t\t\t\t\tduration: this.config.duration_step,\n\t\t\t\t\ttask: task\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tif (taskTiming.$no_start || taskTiming.$no_end) {\n\t\t\tthis._init_task_timing(task);\n\t\t}\n\t}\n\n\tgantt.getSubtaskDuration = function (taskId) {\n\t\tvar res = 0,\n\t\t\troot = taskId !== undefined ? taskId : gantt.config.root_id;\n\n\t\tthis.eachTask(function (child) {\n\t\t\tif (this.getTaskType(child.type) == gantt.config.types.project || this.isUnscheduledTask(child))\n\t\t\t\treturn;\n\n\t\t\tres += child.duration;\n\t\t}, root);\n\n\t\treturn res;\n\t};\n\n\tfunction getSubtaskInfo (taskId){\n\t\tvar min = null,\n\t\t\tmax = null,\n\t\t\troot = taskId !== undefined ? taskId : gantt.config.root_id,\n\t\t\trollup = [];\n\n\t\tgantt.eachTask(function (child) {\n\t\t\tconst isScheduledSummary = (gantt.getTaskType(child.type) == gantt.config.types.project && (child.auto_scheduling === false));\n\t\t\tif ((gantt.getTaskType(child.type) == gantt.config.types.project && !isScheduledSummary) || gantt.isUnscheduledTask(child))\n\t\t\t\treturn;\n\t\t\t\n\t\t\tif(child.rollup){\n\t\t\t\trollup.push(child.id);\n\t\t\t}\n\n\t\t\tif ((child.start_date && (!child.$no_start || isScheduledSummary)) && (!min || min > child.start_date.valueOf()))\n\t\t\t\tmin = child.start_date.valueOf();\n\t\t\tif ((child.end_date && (!child.$no_end || isScheduledSummary)) && (!max || max < child.end_date.valueOf()))\n\t\t\t\tmax = child.end_date.valueOf();\n\t\t}, root);\n\n\t\treturn {\n\t\t\tstart_date: min ? new Date(min) : null,\n\t\t\tend_date: max ? new Date(max) : null,\n\t\t\trollup: rollup\n\t\t};\n\t}\n\n\tgantt.getSubtaskDates = function (task_id) {\n\t\tvar info = getSubtaskInfo(task_id);\n\t\treturn {\n\t\t\tstart_date: info.start_date,\n\t\t\tend_date: info.end_date\n\t\t};\n\t};\n\n\n// upward calculation of project duration\n\tgantt._update_parents = function (taskId, silent, updateAll) {\n\t\tif (!taskId) return;\n\n\t\tvar task = this.getTask(taskId);\n\t\tif(task.rollup){\n\t\t\tupdateAll = true;\n\t\t}\n\t\tvar pid = this.getParent(task);\n\n\t\tvar taskTiming = getTaskTimingMode(task);\n\n\t\tvar has_changed = true;\n\t\t// GS-761 the dates check is necessary for adding empty tasks: gantt.addTask({id:\"2\"})\n\t\tif (updateAll || (task.start_date && task.end_date && (taskTiming.$no_start || taskTiming.$no_end))) {\n\n\t\t\tconst startDateField = task.$auto_start_date ? \"$auto_start_date\" : \"start_date\";\n\t\t\tconst endDateField = task.$auto_end_date ? \"$auto_end_date\" : \"end_date\";\n\n\t\t\tvar oldStart = task[startDateField].valueOf(),\n\t\t\t\toldEnd = task[endDateField].valueOf();\n\n\t\t\tgantt.resetProjectDates(task);\n\n\t\t\t// not refresh parent projects if dates hasn't changed\n\t\t\tif (!updateAll && oldStart == task[startDateField].valueOf() && oldEnd == task[endDateField].valueOf()) {\n\t\t\t\thas_changed = false;\n\t\t\t}\n\n\t\t\tif (has_changed && !silent) {\n\t\t\t\tthis.refreshTask(task.id, true);\n\t\t\t}\n\n\t\t\tif(taskTiming.scheduled_summary){\n\t\t\t\thas_changed = true;//recalculate upwards from scheduled summaries\n\t\t\t}\n\t\t}\n\n\n\t\tif (has_changed && pid && this.isTaskExists(pid)) {\n\t\t\tthis._update_parents(pid, silent, updateAll);\n\t\t}\n\t};\n\n\tgantt.roundDate = function (config) {\n\t\tvar scale = gantt.getScale();\n\n\t\tif (helpers.isDate(config)) {\n\t\t\tconfig = {\n\t\t\t\tdate: config,\n\t\t\t\tunit: scale ? scale.unit : gantt.config.duration_unit,\n\t\t\t\tstep: scale ? scale.step : gantt.config.duration_step\n\t\t\t};\n\t\t}\n\t\tvar date = config.date,\n\t\t\tsteps = config.step,\n\t\t\tunit = config.unit;\n\n\t\tif(!scale){\n\t\t\treturn date;\n\t\t}\n\n\t\tvar upper, lower, colIndex;\n\t\tif (unit == scale.unit && steps == scale.step &&\n\t\t\t+date >= +scale.min_date && +date <= +scale.max_date) {\n\t\t\t//find date in time scale config\n\t\t\tcolIndex = Math.floor(gantt.columnIndexByDate(date));\n\n\t\t\tif (!scale.trace_x[colIndex]) {\n\t\t\t\tcolIndex -= 1;// end of time scale\n\t\t\t\tif(scale.rtl){\n\t\t\t\t\tcolIndex = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlower = new Date(scale.trace_x[colIndex]);\n\t\t\tupper = gantt.date.add(lower, steps, unit);\n\t\t} else {\n\t\t\tcolIndex = Math.floor(gantt.columnIndexByDate(date));\n\n\t\t\tupper = gantt.date[unit + \"_start\"](new Date(scale.min_date));\n\t\t\tif (scale.trace_x[colIndex]) {\n\t\t\t\tupper = gantt.date[unit + \"_start\"](scale.trace_x[colIndex]);// end of time scale\n\t\t\t}\n\n\t\t\twhile (+upper < +date) {\n\t\t\t\tupper = gantt.date[unit + \"_start\"](gantt.date.add(upper, steps, unit));\n\n\t\t\t\tvar tzOffset = upper.getTimezoneOffset();\n\n\t\t\t\tupper = gantt._correct_dst_change(upper, tzOffset, upper, unit);\n\t\t\t\tif (gantt.date[unit + '_start'])\n\t\t\t\t\tupper = gantt.date[unit + '_start'](upper);\n\t\t\t}\n\n\t\t\tlower = gantt.date.add(upper, -1 * steps, unit);\n\n\t\t}\n\t\tif (config.dir && config.dir == 'future')\n\t\t\treturn upper;\n\t\tif (config.dir && config.dir == 'past')\n\t\t\treturn lower;\n\n\t\tif (Math.abs(date - lower) < Math.abs(upper - date)) {\n\t\t\treturn lower;\n\t\t} else {\n\t\t\treturn upper;\n\t\t}\n\n\t};\n\n\tgantt.correctTaskWorkTime = function (task) {\n\t\tif (gantt.config.work_time && gantt.config.correct_work_time) {\n\t\t\tif (!this.isWorkTime(task.start_date, undefined, task)) {\n\t\t\t\ttask.start_date = this.getClosestWorkTime({date: task.start_date, dir: 'future', task: task});\n\t\t\t\ttask.end_date = this.calculateEndDate(task);\n\t\t\t} else if (!this.isWorkTime(new Date(+task.end_date - 1), undefined, task)) {\n\t\t\t\ttask.end_date = this.calculateEndDate(task);\n\t\t\t}\n\t\t}\n\t};\n\n\tgantt.attachEvent(\"onBeforeTaskUpdate\", function (id, task) {\n\t\tgantt._init_task_timing(task);\n\t\treturn true;\n\t});\n\tgantt.attachEvent(\"onBeforeTaskAdd\", function (id, task) {\n\t\tgantt._init_task_timing(task);\n\t\treturn true;\n\t});\n\n\tgantt.attachEvent(\"onAfterTaskMove\", function (id, parent, tindex) {\n\t\tgantt._init_task_timing(gantt.getTask(id));\n\t\treturn true;\n\t});\n\n};","export default function(gantt) {\n\tgantt.getTaskType = function (type) {\n\t\tvar checkType = type;\n\t\tif(type && typeof type == \"object\"){\n\t\t\tcheckType = type.type;\n\t\t}\n\n\t\tfor (var i in this.config.types) {\n\t\t\tif (this.config.types[i] == checkType) {\n\t\t\t\treturn checkType;\n\t\t\t}\n\t\t}\n\t\treturn gantt.config.types.task;\n\t};\n};","/*\n reuse results of functions that can be recalculated during rendering\n greatly increases the rendering speed when critical path enabled\n Sample - 94_dev/critical_path.html\n\n */\nexport default function(gantt){\n\ngantt._cached_functions = {\n\tcache: {},\n\tmode: false,\n\tcritical_path_mode: false,\n\twrap_methods : function(methods, object){\n\t\tif(object._prefetch_originals){\n\t\t\tfor(var i in object._prefetch_originals){\n\t\t\t\tobject[i] = object._prefetch_originals[i];\n\t\t\t}\n\t\t}\n\t\tobject._prefetch_originals = {};\n\t\tfor(var i = 0; i < methods.length; i++)\n\t\t\tthis.prefetch(methods[i], object);\n\n\t},\n\tprefetch : function(methodname, host){\n\t\tvar original = host[methodname];\n\t\tif(original){\n\t\t\tvar optimizer = this;\n\n\t\t\thost._prefetch_originals[methodname] = original;\n\t\t\thost[methodname] = function get_prefetched_value(){\n\n\t\t\t\tvar argumentsArray = new Array(arguments.length);\n\t\t\t\tfor (var i = 0, l = arguments.length; i < l; i++) {\n\t\t\t\t\targumentsArray[i] = arguments[i];\n\t\t\t\t}\n\n\t\t\t\tif(optimizer.active){\n\t\t\t\t\tvar args = optimizer.get_arguments_hash(Array.prototype.slice.call(argumentsArray));\n\t\t\t\t\tif(!optimizer.cache[methodname]){\n\t\t\t\t\t\toptimizer.cache[methodname] = {};\n\t\t\t\t\t}\n\n\t\t\t\t\tvar cached_values = optimizer.cache[methodname];\n\n\t\t\t\t\tif(optimizer.has_cached_value(cached_values, args)){\n\t\t\t\t\t\treturn optimizer.get_cached_value(cached_values, args);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tvar value = original.apply(this, argumentsArray);\n\t\t\t\t\t\toptimizer.cache_value(cached_values, args, value);\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn original.apply(this, argumentsArray);\n\t\t\t};\n\t\t}\n\t\treturn original;\n\t},\n\tcache_value: function(cache, arguments_hash, value){\n\t\tif(this.is_date(value))\n\t\t\tvalue = new Date(value);\n\t\tcache[arguments_hash] = value;\n\t},\n\thas_cached_value: function(cache, arguments_hash){\n\t\treturn cache.hasOwnProperty(arguments_hash);\n\t},\n\tget_cached_value: function(cache, arguments_hash){\n\t\tvar data = cache[arguments_hash];\n\n\t\t//for cached dates - return copy\n\t\tif(this.is_date(data)){\n\t\t\tdata = new Date(data);\n\t\t}\n\t\treturn data;\n\t},\n\tis_date: function(value){\n\t\treturn (value && value.getUTCDate);\n\t},\n\tget_arguments_hash:function(args){\n\t\tvar values = [];\n\t\tfor(var i = 0; i < args.length; i++){\n\t\t\tvalues.push(this.stringify_argument(args[i]));\n\t\t}\n\t\treturn \"(\" + values.join(\";\") + \")\";\n\t},\n\tstringify_argument: function(value){\n\t\t//expecting task or link, or any other data entries, dates and primitive values\n\t\tvar ret = \"\";\n\t\tif(value.id){\n\t\t\tret = value.id;\n\t\t}else if(this.is_date(value)){\n\t\t\tret = value.valueOf();\n\t\t}else{\n\t\t\tret = value;\n\t\t}\n\t\treturn ret + \"\";\n\t},\n\tactivate: function(){\n\t\tthis.clear();\n\t\tthis.active = true;\n\t},\n\tdeactivate: function(){\n\t\tthis.clear();\n\t\tthis.active = false;\n\t},\n\tclear: function(){\n\t\tthis.cache = {};\n\t},\n\n\tsetup: function(gantt){\n\t\tvar override_gantt = [];\n\n\t\tvar gantt_methods = [\n\t\t\t'_isProjectEnd',\n\t\t\t'_getProjectEnd',\n\t\t\t'_getSlack'\n\t\t];\n\n\n\n\t\tif(this.mode == 'auto'){\n\t\t\tif(gantt.config.highlight_critical_path){\n\t\t\t\toverride_gantt = gantt_methods;\n\t\t\t}\n\t\t}else if(this.mode === true){\n\t\t\toverride_gantt = gantt_methods;\n\t\t}\n\n\t\tthis.wrap_methods(override_gantt, gantt);\n\n\t},\n\tupdate_if_changed: function(gantt){\n\t\tvar changed = (this.critical_path_mode != gantt.config.highlight_critical_path ||\n\t\t\t\t\t\tthis.mode !== gantt.config.optimize_render);\n\t\tif(changed){\n\t\t\tthis.critical_path_mode = gantt.config.highlight_critical_path;\n\t\t\tthis.mode = gantt.config.optimize_render;\n\t\t\tthis.setup(gantt);\n\t\t}\n\t}\n};\n\nfunction activate(){\n\tgantt._cached_functions.update_if_changed(gantt);\n\tif(!gantt._cached_functions.active){\n\t\tgantt._cached_functions.activate();\n\t}\n\treturn true;\n}\ngantt.attachEvent(\"onBeforeGanttRender\", activate);\ngantt.attachEvent(\"onBeforeDataRender\", activate);\ngantt.attachEvent(\"onBeforeSmartRender\", function(){\n\tactivate();\n});\ngantt.attachEvent(\"onBeforeParse\", activate);\ngantt.attachEvent(\"onDataRender\", function(){\n\tgantt._cached_functions.deactivate();\n});\nvar deactivTimeout = null;\ngantt.attachEvent(\"onSmartRender\", function(){\n\tif(deactivTimeout)\n\t\tclearTimeout(deactivTimeout);\n\tdeactivTimeout = setTimeout(function(){\n\t\tgantt._cached_functions.deactivate();\n\t}, 1000);\n});\n\ngantt.attachEvent(\"onBeforeGanttReady\", function(){\n\tgantt._cached_functions.update_if_changed(gantt);\n\treturn true;\n});\n\n};","import * as domHelpers from \"./ui/utils/dom_helpers\";\nimport * as helpers from \"../utils/helpers\";\nimport isHeadless from \"../utils/is_headless\";\nimport addResizeListener from \"./ui/resize_listener\";\nimport calculateScaleRange from \"./gantt_data_range\";\nimport assert from \"./common/assert\";\n\nexport default function(gantt){\n\t\n\n\tgantt.assert = assert(gantt);\n\n\tfunction isHTMLElement(node){\n\t\ttry {\n\t\t\tnode.cloneNode(false);\n\t\t}\n\t\tcatch (e){\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tvar invalidContainerMessage = \"Invalid value of the first argument of `gantt.init`. Supported values: HTMLElement, String (element id).\" +\n\t\"This error means that either invalid object is passed into `gantt.init` or that the element with the specified ID doesn't exist on the page when `gantt.init` is called.\";\n\n\tfunction validateNode(node){\n\t\tif (!node || (typeof node == 'string' && document.getElementById(node))) return true;\n\t\tif (isHTMLElement(node)) return true;\n\n\t\tgantt.assert(false, invalidContainerMessage);\n\t\tthrow new Error(invalidContainerMessage);\n\t}\n\n//initial initialization\n\tgantt.init = function(node, from, to){\n\t\tif (gantt.env.isNode) { \n\t\t\tnode = null; // for the nodejs version\n\t\t} else {\n\t\t\tvalidateNode(node); // for the web version\n\t\t}\n\n\t\tif(from && to){\n\t\t\tthis.config.start_date = this._min_date = new Date(from);\n\t\t\tthis.config.end_date = this._max_date = new Date(to);\n\t\t}\n\t\tthis.date.init();\n\n\t\t//can be called only once\n\t\tthis.init = function(node){\n\t\t\tif (gantt.env.isNode) { \n\t\t\t\tnode = null; // for the nodejs version\n\t\t\t} else {\n\t\t\t\tvalidateNode(node); // for the web version\n\t\t\t}\n\n\t\t\tif (this.$container && this.$container.parentNode){\n\t\t\t\tthis.$container.parentNode.removeChild(this.$container);\n\t\t\t\tthis.$container = null;\n\t\t\t}\n\n\t\t\tif(this.$layout){\n\t\t\t\tthis.$layout.clear();\n\t\t\t}\n\t\t\tthis._reinit(node);\n\t\t};\n\t\tthis._reinit(node);\n\t};\n\n\tgantt._quickRefresh = function(code){\n\t\tvar stores = this._getDatastores.call(this);\n\t\tfor(var i = 0; i < stores.length; i++){\n\t\t\tstores[i]._quick_refresh = true;\n\t\t}\n\n\t\tcode();\n\n\t\tfor(var i = 0; i < stores.length; i++){\n\t\t\tstores[i]._quick_refresh = false;\n\t\t}\n\t};\n\n\tvar dropLayout = (function dropLayout(){\n\t\tif(this._clearTaskLayers){\n\t\t\tthis._clearTaskLayers();\n\t\t}\n\n\t\tif(this._clearLinkLayers){\n\t\t\tthis._clearLinkLayers();\n\t\t}\n\n\t\tif(this.$layout){\n\t\t\tthis.$layout.destructor();\n\t\t\tthis.$layout = null;\n\t\t\tthis.$ui.reset();\n\t\t}\n\t}).bind(gantt);\n\n\tvar rebuildLayout = (function rebuildLayout(){\n\t\tif(isHeadless(gantt)){\n\t\t\treturn;\n\t\t}\n\n\t\tthis.$root.innerHTML = \"\";\n\n\t\tthis.$root.gantt = this;\n\t\tcalculateScaleRange(this);\n\t\tthis.config.layout.id = \"main\";\n\t\tthis.$layout = this.$ui.createView(\"layout\", this.$root, this.config.layout);\n\n\t\tthis.$layout.attachEvent(\"onBeforeResize\", function(){\n\t\t\tvar storeNames = gantt.$services.getService(\"datastores\");\n\t\t\tfor(var i = 0; i < storeNames.length; i++){\n\t\t\t\tgantt.getDatastore(storeNames[i]).filter();\n\t\t\t\tif (gantt.$data.tasksStore._skipTaskRecalculation){\n\t\t\t\t\t// do not repaint items, they will be repainted later in the onStoreUpdate event\n\t\t\t\t\tif (gantt.$data.tasksStore._skipTaskRecalculation != \"lightbox\"){\n\t\t\t\t\t\tgantt.$data.tasksStore._skipTaskRecalculation = false;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t} else {\n\t\t\t\t\tgantt.getDatastore(storeNames[i]).callEvent(\"onBeforeRefreshAll\", []);\t\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.$layout.attachEvent(\"onResize\", function(){\n\t\t\tgantt._quickRefresh(function(){\n\t\t\t\tgantt.refreshData();\n\t\t\t});\n\t\t});\n\n\t\tthis.callEvent(\"onGanttLayoutReady\", []);\n\t\tthis.$layout.render();\n\n\t\tthis.$container = this.$layout.$container.firstChild;\n\n\t\taddResizeListener(this);\n\t}).bind(gantt);\n\n\tgantt.resetLayout = function(){\n\t\tdropLayout();\n\t\trebuildLayout();\n\t\tthis.render();\n\t};\n\n\tgantt._reinit = function(node){\n\t\tthis.callEvent(\"onBeforeGanttReady\", []);\n\t\tthis._update_flags();\n\n\t\tvar config = this.$services.getService(\"templateLoader\");\n\t\tconfig.initTemplates(this);\n\n\t\tdropLayout();\n\n\t\tthis.$root = null;\n\t\tif(node){\n\t\t\tthis.$root = domHelpers.toNode(node);\n\t\t\trebuildLayout();\n\t\t\tthis.$mouseEvents.reset(this.$root);\n\t\t\taddMinimalSizes(gantt);\n\t\t}\n\n\t\tthis.callEvent(\"onTemplatesReady\",[]);\n\n\t\tthis.callEvent(\"onGanttReady\", []);\n\n\t\tthis.render();\n\t};\n\n\tfunction addMinimalSizes(gantt) {\n\t\tif (gantt.$container && !gantt.config.autosize) {\n\t\t\tif (gantt.$root.offsetHeight < 50) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`The Gantt container has a small height, so you cannot see its content. If it is not intended, you need to set the 'height' style rule to the container:\nhttps://docs.dhtmlx.com/gantt/faq.html#theganttchartisntrenderedcorrectly`);\n\t\t\t}\n\t\t}\n\t}\n\n\tgantt.$click={\n\t\tbuttons:{\n\t\t\t\"edit\": function(id) {\n\t\t\t\tif (gantt.isReadonly(gantt.getTask(id))) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tgantt.showLightbox(id);\n\t\t\t},\n\t\t\t\"delete\": function(id) {\n\t\t\t\tvar task = gantt.getTask(id);\n\t\t\t\tif (gantt.isReadonly(task)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tvar question = gantt.locale.labels.confirm_deleting;\n\t\t\t\tvar title = gantt.locale.labels.confirm_deleting_title;\n\n\t\t\t\tgantt._simple_confirm(question, title, function(){\n\t\t\t\t\tif(!gantt.isTaskExists(id)){\n\t\t\t\t\t\tgantt.hideLightbox();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif(task.$new){\n\t\t\t\t\t\t// GS-2170. Do not recalculate the indexes and dates of other tasks\n\t\t\t\t\t\t// as they will be recalculated in the `refreshData`\n\t\t\t\t\t\tgantt.$data.tasksStore._skipTaskRecalculation = \"lightbox\";\n\t\t\t\t\t\tgantt.silent(function(){\n\t\t\t\t\t\t\tgantt.deleteTask(id, true);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tgantt.$data.tasksStore._skipTaskRecalculation = false;\n\t\t\t\t\t\tgantt.refreshData();\n\t\t\t\t\t}else{\n\t\t\t\t\t\tgantt.$data.tasksStore._skipTaskRecalculation = true;\n\t\t\t\t\t\tgantt.deleteTask(id);\n\t\t\t\t\t}\n\n\t\t\t\t\tgantt.hideLightbox();\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\n//renders self\n\tgantt.render = function(){\n\t\tthis.callEvent(\"onBeforeGanttRender\", []);\n\n\t\tvar visibleDate;\n\t\tif(!isHeadless(gantt)){\n\t\t\tif (!this.config.sort && this._sort) {\n\t\t\t\tthis._sort = undefined;\n\t\t\t}\n\n\t\t\tif(this.$root){\n\t\t\t\tif(this.config.rtl){\n\t\t\t\t\tthis.$root.classList.add(\"gantt_rtl\");\n\t\t\t\t\tthis.$root.firstChild.classList.add(\"gantt_rtl\"); // GS-1499\n\t\t\t\t}else{\n\t\t\t\t\tthis.$root.classList.remove(\"gantt_rtl\");\n\t\t\t\t\tthis.$root.firstChild.classList.remove(\"gantt_rtl\"); // GS-1499\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar pos = this.getScrollState();\n\t\t\tvar posX = pos ? pos.x : 0;\n\t\t\tif(this._getHorizontalScrollbar()){\n\t\t\t\tvar scrollbar = this._getHorizontalScrollbar();\n\t\t\t\tposX = scrollbar.$config.codeScrollLeft || posX || 0;\n\t\t\t}\n\n\n\t\t\tvisibleDate = null;\n\t\t\tif(posX){\n\t\t\t\tvisibleDate = gantt.dateFromPos(posX + this.config.task_scroll_offset);\n\t\t\t}\n\t\t}\n\n\t\tcalculateScaleRange(this);\n\n\t\tif(!isHeadless(gantt)){\n\t\t\tthis.$layout.$config.autosize = this.config.autosize;\n\t\t\tvar preserveScroll = this.config.preserve_scroll;\n\t\t\tthis.config.preserve_scroll = false; // prevent scrolling from layout resize, scroll will be called here later on\n\t\t\tthis.$layout.resize();\n\t\t\tthis.config.preserve_scroll = preserveScroll;\n\n\t\t\tif(this.config.preserve_scroll && pos){\n\n\t\t\t\t// GS-1640: We need pos.y, otherwise part of the timeline won't be rendered if the scrollbar disappeared\n\t\t\t\tif (posX || pos.y) {\n\t\t\t\t\tvar new_pos = gantt.getScrollState();\n\t\t\t\t\tvar new_date = gantt.dateFromPos(new_pos.x);\n\t\t\t\t\tif(!(+visibleDate == +new_date && new_pos.y == pos.y)){\n\t\t\t\t\t\tvar posX = null;\n\t\t\t\t\t\tvar posY = null;\n\t\t\t\t\t\tif(visibleDate){\n\t\t\t\t\t\t\tvar posX = Math.max(gantt.posFromDate(visibleDate) - gantt.config.task_scroll_offset, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(pos.y){\n\t\t\t\t\t\t\tposY = pos.y;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgantt.scrollTo(posX, posY);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// GS-1640: We need to reset the scroll position for the grid if the scrollbar disappeared and\n\t\t\t\t// the grid and timeline have different scrollbars\n\t\t\t\tvar gridCell = gantt.$ui.getView(\"grid\");\n\t\t\t\tif (gridCell) {\n\t\t\t\t\tvar attachedScrollbar = gridCell.$config.scrollY;\n\t\t\t\t\tvar verticalScrollbar = gantt.$ui.getView(attachedScrollbar);\n\t\t\t\t\tif (verticalScrollbar) {\n\t\t\t\t\t\tvar scrollbarNodeVisible = gantt.utils.dom.isChildOf(verticalScrollbar.$view, gantt.$container);\n\t\t\t\t\t\tif (!scrollbarNodeVisible) {\n\t\t\t\t\t\t\tgridCell.scrollTo(undefined, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}else{\n\t\t\tgantt.refreshData();\n\t\t}\n\t\tthis.callEvent(\"onGanttRender\", []);\n\t};\n\n\t//TODO: add layout.resize method that wouldn't trigger data repaint\n\tgantt.setSizes = gantt.render;\n\n\n\tgantt.getTaskRowNode = function(id) {\n\t\tvar els = this.$grid_data.childNodes;\n\t\tvar attribute = this.config.task_attribute;\n\t\tfor (var i = 0; i < els.length; i++) {\n\t\t\tif (els[i].getAttribute) {\n\t\t\t\tvar value = els[i].getAttribute(attribute);\n\t\t\t\tif (value == id) return els[i];\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t};\n\n\tgantt.changeLightboxType = function(type){\n\t\tif(this.getLightboxType() == type)\n\t\t\treturn true;\n\t\tgantt._silent_redraw_lightbox(type);\n\t};\n\n\tgantt._get_link_type = function (from_start, to_start) {\n\t\tvar type = null;\n\t\tif (from_start && to_start) {\n\t\t\ttype = gantt.config.links.start_to_start;\n\t\t} else if (!from_start && to_start) {\n\t\t\ttype = gantt.config.links.finish_to_start;\n\t\t} else if (!from_start && !to_start) {\n\t\t\ttype = gantt.config.links.finish_to_finish;\n\t\t} else if (from_start && !to_start) {\n\t\t\ttype = gantt.config.links.start_to_finish;\n\t\t}\n\t\treturn type;\n\t};\n\n\tgantt.isLinkAllowed = function (from, to, from_start, to_start) {\n\t\tvar link = null;\n\t\tif (typeof(from) == \"object\") {\n\t\t\tlink = from;\n\t\t} else {\n\t\t\tlink = {source: from, target: to, type: this._get_link_type(from_start, to_start)};\n\t\t}\n\n\t\tif (!link) return false;\n\t\tif (!(link.source && link.target && link.type)) return false;\n\t\tif (link.source == link.target) return false;\n\n\t\tvar res = true;\n\t\t//any custom rules\n\t\tif (this.checkEvent(\"onLinkValidation\"))\n\t\t\tres = this.callEvent(\"onLinkValidation\", [link]);\n\n\t\treturn res;\n\t};\n\n\n\tgantt._correct_dst_change = function(date, prevOffset, step, unit){\n\t\tvar time_unit = helpers.getSecondsInUnit(unit) * step;\n\t\tif(time_unit > 60*60 && time_unit < 60*60*24){\n\t\t\t//correct dst change only if current unit is more than one hour and less than day (days have own checking), e.g. 12h\n\t\t\tvar offsetChanged = date.getTimezoneOffset() - prevOffset;\n\t\t\tif(offsetChanged){\n\t\t\t\tdate = gantt.date.add(date, offsetChanged, \"minute\");\n\t\t\t}\n\t\t}\n\t\treturn date;\n\t};\n\n\tgantt.isSplitTask = function(task){\n\t\tgantt.assert(task && task instanceof Object, \"Invalid argument task=\"+task+\" of gantt.isSplitTask. Task object was expected\");\n\t\treturn this.$data.tasksStore._isSplitItem(task);\n\t};\n\n\tgantt._is_icon_open_click = function(e) {\n\t\tif (!e)\n\t\t\treturn false;\n\t\tvar target = e.target || e.srcElement;\n\t\tif (!(target && target.className))\n\t\t\treturn false;\n\t\tvar className = domHelpers.getClassName(target);\n\t\tif (className.indexOf(\"gantt_tree_icon\") !== -1 && (className.indexOf(\"gantt_close\") !== -1 || className.indexOf(\"gantt_open\") !== -1))\n\t\t\treturn true;\n\t\treturn false;\n\t};\n\n};","/*\n \tasserts will be removed in final code, so you can place them anythere\n\twithout caring about performance impacts\n*/\n\nexport default function(gantt){\n\treturn function assert(check, message){\n\t\tif (!check){\n\t\t\tif(gantt.config.show_errors && gantt.callEvent(\"onError\",[message]) !== false) {\n\t\t\t\tif (gantt.message) {\n\t\t\t\t\tgantt.message({type: \"error\", text: message, expire: -1});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// eslint-disable-next-line\n\t\t\t\t\tconsole.log(message);\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line no-debugger\n\t\t\t\tdebugger;\n\t\t\t}\n\t\t}\n\t};\n};","function extend(gantt){\n\n\tgantt.destructor = function(){\n\t\tthis.clearAll();\n\t\tthis.callEvent(\"onDestroy\", []);\n\n\t\tif(this.$root){\n\t\t\tdelete this.$root.gantt;\n\t\t}\n\n\t\tif(this._eventRemoveAll){\n\t\t\tthis._eventRemoveAll();\n\t\t}\n\n\t\tif(this.$layout){\n\t\t\tthis.$layout.destructor();\n\t\t}\n\n\t\tif(this.resetLightbox){\n\t\t\tthis.resetLightbox();\n\t\t}\n\n\t\t// GS-99. Call this here to detach the events\n\t\tif (this.ext.inlineEditors) {\n\t\t\tthis.ext.inlineEditors.destructor();\n\t\t}\n\n\t\tif(this._dp && this._dp.destructor){\n\t\t\tthis._dp.destructor();\n\t\t}\n\t\tthis.$services.destructor();\n\n\t\t// detachAllEvents should be called last, because in components may be attached events\n\t\tthis.detachAllEvents();\n\n\t\tfor(var i in this){\n\t\t\tif(i.indexOf(\"$\") === 0){\n\t\t\t\tdelete this[i];\n\t\t\t}\n\t\t}\n\t\tthis.$destroyed = true;\n\t};\n}\n\nexport default extend;\n","import ar from \"./locale_ar\";\nimport be from \"./locale_be\";\nimport ca from \"./locale_ca\";\nimport cn from \"./locale_cn\";\nimport cs from \"./locale_cs\";\nimport da from \"./locale_da\";\nimport de from \"./locale_de\";\nimport el from \"./locale_el\";\nimport en from \"./locale_en\";\nimport es from \"./locale_es\";\nimport fa from \"./locale_fa\";\nimport fi from \"./locale_fi\";\nimport fr from \"./locale_fr\";\nimport he from \"./locale_he\";\nimport hr from \"./locale_hr\";\nimport hu from \"./locale_hu\";\nimport id from \"./locale_id\";\nimport it from \"./locale_it\";\nimport jp from \"./locale_jp\";\nimport kr from \"./locale_kr\";\n\nimport LocaleManager from \"./locale_manager\";\n\nimport nb from \"./locale_nb\";\nimport nl from \"./locale_nl\";\nimport no from \"./locale_no\";\nimport pl from \"./locale_pl\";\nimport pt from \"./locale_pt\";\nimport ro from \"./locale_ro\";\nimport ru from \"./locale_ru\";\nimport si from \"./locale_si\";\nimport sk from \"./locale_sk\";\nimport sv from \"./locale_sv\";\nimport tr from \"./locale_tr\";\nimport ua from \"./locale_ua\";\n\nexport default function(){\n\treturn new LocaleManager({\n\t\ten,\n\t\tar,\n\t\tbe,\n\t\tca,\n\t\tcn,\n\t\tcs,\n\t\tda,\n\t\tde,\n\t\tel,\n\t\tes,\n\t\tfa,\n\t\tfi,\n\t\tfr,\n\t\the,\n\t\thr,\n\t\thu,\n\t\tid,\n\t\tit,\n\t\tjp,\n\t\tkr,\n\t\tnb,\n\t\tnl,\n\t\tno,\n\t\tpl,\n\t\tpt,\n\t\tro,\n\t\tru,\n\t\tsi,\n\t\tsk,\n\t\tsv,\n\t\ttr,\n\t\tua\n\t});\n}","import * as utils from \"../utils/utils\";\nimport env from \"../utils/env\";\nimport isHeadless from \"../utils/is_headless\";\nimport * as domHelpers from \"./ui/utils/dom_helpers\";\nimport * as codeHelpers from \"../utils/helpers\";\nimport domEventScope from \"./ui/utils/dom_event_scope\";\nimport messages from \"./ui/message\";\nimport ui from \"./ui/index\";\nimport createLayoutFacade from \"./facades/layout\";\nimport taskLayers from \"./data_task_layers\";\n\nimport skin from \"./ui/skin\";\nimport skyblue from \"../css/skins/skyblue\";\nimport meadow from \"../css/skins/meadow\";\nimport terrace from \"../css/skins/terrace\";\nimport broadway from \"../css/skins/broadway\";\nimport material from \"../css/skins/material\";\nimport dark from \"../css/skins/dark\";\nimport contrast_black from \"../css/skins/contrast_black\";\nimport contrast_white from \"../css/skins/contrast_white\";\nimport plugins from \"./ui/plugins\";\nimport touch from \"./ui/touch\";\nimport lightbox from \"./ui/lightbox\";\nimport lightbox_optional_time from \"./ui/lightbox/lightbox_optional_time\";\nimport wai_aria from \"./ui/wai_aria\";\n\n\nexport default function(gantt) {\n\n\tif(!env.isNode){\n\n\t\tgantt.utils = {\n\t\t\tarrayFind: codeHelpers.arrayFind,\n\t\t\tdom: domHelpers\n\t\t};\n\n\t\tvar domEvents = domEventScope();\n\t\tgantt.event = domEvents.attach;\n\t\tgantt.eventRemove = domEvents.detach;\n\t\tgantt._eventRemoveAll = domEvents.detachAll;\n\t\tgantt._createDomEventScope = domEvents.extend;\n\n\t\tutils.mixin(gantt, messages(gantt));\n\t\tvar uiApi = ui.init(gantt);\n\t\tgantt.$ui = uiApi.factory;\n\t\tgantt.$ui.layers = uiApi.render;\n\t\tgantt.$mouseEvents = uiApi.mouseEvents;\n\t\tgantt.$services.setService(\"mouseEvents\", function () {\n\t\t\treturn gantt.$mouseEvents;\n\t\t});\n\t\tgantt.mixin(gantt, uiApi.layersApi);\n\n\t\ttaskLayers(gantt);\n\n\t\tgantt.$services.setService(\"layers\", function () {\n\t\t\treturn uiApi.layersService;\n\t\t});\n\n\t\tgantt.mixin(gantt, createLayoutFacade());\n\t\tskin(gantt);\n\t\tskyblue(gantt);\n\t\tdark(gantt);\n\t\tmeadow(gantt);\n\t\tterrace(gantt);\n\t\tbroadway(gantt);\n\t\tmaterial(gantt);\n\t\tcontrast_black(gantt);\n\t\tcontrast_white(gantt);\n\t\tplugins(gantt);\n\t\ttouch(gantt);\n\t\tlightbox(gantt);\n\t\tlightbox_optional_time(gantt);\n\t\twai_aria(gantt);\n\n\t\tgantt.locate = function(e) {\n\t\t\tvar trg = domHelpers.getTargetNode(e);\n\n\t\t\t// ignore empty rows/cells of the timeline\n\t\t\tif(domHelpers.closest(trg, \".gantt_task_row\")){\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar targetAttribute = arguments[1] || this.config.task_attribute;\n\n\t\t\tvar node = domHelpers.locateAttribute(trg, targetAttribute);\n\t\t\tif(node){\n\t\t\t\treturn node.getAttribute(targetAttribute);\n\t\t\t}else{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t};\n\n\t\tgantt._locate_css = function(e, classname, strict){\n\t\t\treturn domHelpers.locateClassName(e, classname, strict);\n\t\t};\n\n\t\tgantt._locateHTML = function(e, attribute) {\n\t\t\treturn domHelpers.locateAttribute(e, attribute || this.config.task_attribute);\n\t\t};\n\t}\n\n\tgantt.attachEvent(\"onParse\", function(){\n\t\tif(!isHeadless(gantt)){\n\t\t\tgantt.attachEvent(\"onGanttRender\", function(){\n\t\t\t\tif(gantt.config.initial_scroll){\n\t\t\t\t\tvar firstTask = gantt.getTaskByIndex(0);\n\t\t\t\t\tvar id = firstTask ? firstTask.id : gantt.config.root_id;\n\t\t\t\t\t// GS-1450. Don't scroll to the task if there is no timeline\n\t\t\t\t\tif(gantt.isTaskExists(id) && gantt.$task && gantt.utils.dom.isChildOf(gantt.$task, gantt.$container)){\n\t\t\t\t\t\tgantt.showTask(id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, {once: true});\n\t\t}\n\n\t});\n\n\tgantt.attachEvent(\"onBeforeGanttReady\", function(){\n\t\tif (!this.config.scroll_size)\n\t\t\tthis.config.scroll_size = domHelpers.getScrollSize() || 15;\n\n\t\tif(!isHeadless(gantt)){\n\t\t\t// detach listeners before clearing old DOM, possible IE errors when accessing detached nodes\n\t\t\tthis._eventRemoveAll();\n\t\t\tthis.$mouseEvents.reset();\n\n\t\t\tthis.resetLightbox();\n\t\t}\n\n\t});\n\n\t// GS-1261: scroll the views to the right side when RTL is enabled\n\tgantt.attachEvent(\"onGanttReady\", function(){\n\t\tif(!isHeadless(gantt) && gantt.config.rtl){\n\t\t\tgantt.$layout.getCellsByType(\"viewCell\").forEach(function(cell){ \n\t\t\t\tvar attachedScrollbar = cell.$config.scrollX;\n\t\t\t\tif (!attachedScrollbar) return;\n\n\t\t\t\tvar scrollbar = gantt.$ui.getView(attachedScrollbar);\n\t\t\t\tif (scrollbar) scrollbar.scrollTo(scrollbar.$config.scrollSize,0);\n\n\t\t\t});\n\t\t}\n\t});\n\n\t// GS-1649: check if extensions are connected via files\n\tgantt.attachEvent(\"onGanttReady\", function(){\n\t\tif(!isHeadless(gantt)){\n\n\t\t\tvar activePlugins = gantt.plugins();\n\n\t\t\tvar availablePlugins = {\n\t\t\t\tauto_scheduling: gantt.autoSchedule,\n\t\t\t\tclick_drag: gantt.ext.clickDrag,\n\t\t\t\tcritical_path: gantt.isCriticalTask,\n\t\t\t\tdrag_timeline: gantt.ext.dragTimeline,\n\t\t\t\texport_api: gantt.exportToPDF,\n\t\t\t\tfullscreen: gantt.ext.fullscreen,\n\t\t\t\tgrouping: gantt.groupBy,\n\t\t\t\tkeyboard_navigation: gantt.ext.keyboardNavigation,\n\t\t\t\tmarker: gantt.addMarker,\n\t\t\t\tmultiselect: gantt.eachSelectedTask,\n\t\t\t\toverlay: gantt.ext.overlay,\n\t\t\t\tquick_info: gantt.templates.quick_info_content,\n\t\t\t\ttooltip: gantt.ext.tooltips,\n\t\t\t\tundo: gantt.undo\n\t\t\t};\n\n\t\t\tfor (let plugin in availablePlugins){\n\t\t\t\tif (availablePlugins[plugin] && !activePlugins[plugin]){\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(`You connected the '${plugin}' extension via an obsolete file. \nTo fix it, you need to remove the obsolete file and connect the extension via the plugins method: https://docs.dhtmlx.com/gantt/api__gantt_plugins.html`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n};","import * as utils from \"../../utils/utils\";\nimport * as domHelpers from \"./utils/dom_helpers\";\n\nexport default function(gantt) {\n\n\tvar boxAttribute = \"data-dhxbox\";\n\n\tvar _dhx_msg_cfg = null;\n\n\tfunction callback(config, result) {\n\t\tvar usercall = config.callback;\n\t\tmodalBox.hide(config.box);\n\n\t\t_dhx_msg_cfg = config.box = null;\n\t\tif (usercall)\n\t\t\tusercall(result);\n\t}\n\n\tfunction modal_key(event) {\n\t\tif (_dhx_msg_cfg) {\n\n\t\t\tvar code = event.which || event.keyCode;\n\t\t\tvar preventDefault = false;\n\n\t\t\tif (messageBox.keyboard) {\n\t\t\t\tif (code == 13 || code == 32) {\n\t\t\t\t\t// default behavior is to confirm/submit popup on space/enter\n\t\t\t\t\t// if browser focus is set on button element - do button click instead of default behavior\n\t\t\t\t\tvar target = event.target || event.srcElement;\n\t\t\t\t\tif (domHelpers.getClassName(target).indexOf(\"gantt_popup_button\") > -1 && target.click) {\n\t\t\t\t\t\ttarget.click();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcallback(_dhx_msg_cfg, true);\n\t\t\t\t\t\tpreventDefault = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (code == 27) {\n\t\t\t\t\tcallback(_dhx_msg_cfg, false);\n\t\t\t\t\tpreventDefault = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (preventDefault) {\n\t\t\t\tif (event.preventDefault){\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t\treturn !(event.cancelBubble = true);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\tvar eventElement = domHelpers.getRootNode(gantt.$root) || document;\n\tgantt.event(eventElement, \"keydown\", modal_key, true);\n\n\tfunction modality(mode) {\n\t\tif (!modality.cover) {\n\t\t\tmodality.cover = document.createElement(\"div\");\n\t\t\t//necessary for IE only\n\t\t\tmodality.cover.onkeydown = modal_key;\n\t\t\tmodality.cover.className = \"dhx_modal_cover\";\n\t\t\tdocument.body.appendChild(modality.cover);\n\t\t}\n\n\t\tmodality.cover.style.display = mode ? \"inline-block\" : \"none\";\n\t}\n\n\tfunction button(text, className, result) {\n\t\tvar buttonAriaAttrs = gantt._waiAria.messageButtonAttrString(text);\n\t\tvar name = className.toLowerCase().replace(/ /g, \"_\");\n\t\tvar button_css = \"gantt_\" + name + \"_button\";\n\t\treturn \"
\" + text + \"
\";\n\t}\n\n\tfunction info(text) {\n\t\tif (!messageBox.area) {\n\t\t\tmessageBox.area = document.createElement(\"div\");\n\t\t\tmessageBox.area.className = \"gantt_message_area\";\n\t\t\tmessageBox.area.style[messageBox.position] = \"5px\";\n\t\t\tdocument.body.appendChild(messageBox.area);\n\t\t}\n\n\t\tmessageBox.hide(text.id);\n\t\tvar message = document.createElement(\"div\");\n\t\tmessage.innerHTML = \"
\" + text.text + \"
\";\n\t\tmessage.className = \"gantt-info gantt-\" + text.type;\n\t\tmessage.onclick = function () {\n\t\t\tmessageBox.hide(text.id);\n\t\t\ttext = null;\n\t\t};\n\n\t\tgantt._waiAria.messageInfoAttr(message);\n\n\t\tif (messageBox.position == \"bottom\" && messageBox.area.firstChild)\n\t\t\tmessageBox.area.insertBefore(message, messageBox.area.firstChild);\n\t\telse\n\t\t\tmessageBox.area.appendChild(message);\n\n\t\tif (text.expire > 0)\n\t\t\tmessageBox.timers[text.id] = window.setTimeout(function () {\n\t\t\t\t// GS-1213: We need that when Gantt is destroyed\n\t\t\t\tif (messageBox) messageBox.hide(text.id);\n\t\t\t}, text.expire);\n\n\t\tmessageBox.pull[text.id] = message;\n\t\tmessage = null;\n\n\t\treturn text.id;\n\t}\n\n\tfunction getFirstDefined() {\n\t\tvar values = [].slice.apply(arguments, [0]);\n\n\t\tfor (var i = 0; i < values.length; i++) {\n\t\t\tif (values[i]) {\n\t\t\t\treturn values[i];\n\t\t\t}\n\t\t}\n\n\t}\n\n\tfunction _boxStructure(config, ok, cancel) {\n\t\tvar box = document.createElement(\"div\");\n\n\t\tvar contentId = utils.uid();\n\t\tgantt._waiAria.messageModalAttr(box, contentId);\n\n\n\t\tbox.className = \" gantt_modal_box gantt-\" + config.type;\n\t\tbox.setAttribute(boxAttribute, 1);\n\n\t\tvar inner = '';\n\n\t\tif (config.width)\n\t\t\tbox.style.width = config.width;\n\t\tif (config.height)\n\t\t\tbox.style.height = config.height;\n\t\tif (config.title)\n\t\t\tinner += '
' + config.title + '
';\n\t\tinner += '
' + (config.content ? '' : config.text) + '
';\n\t\tif (ok)\n\t\t\tinner += button(getFirstDefined(config.ok, gantt.locale.labels.message_ok, \"OK\"), \"ok\", true);\n\t\tif (cancel)\n\t\t\tinner += button(getFirstDefined(config.cancel, gantt.locale.labels.message_cancel, \"Cancel\"), \"cancel\", false);\n\n\t\tif (config.buttons) {\n\t\t\tfor (var i = 0; i < config.buttons.length; i++) {\n\t\t\t\tvar btn = config.buttons[i];\n\t\t\t\tif (typeof btn == \"object\") {\n\t\t\t\t\t// Support { label:\"Save\", css:\"main_button\", value:\"save\" }\n\t\t\t\t\tvar label = btn.label;\n\t\t\t\t\tvar css = btn.css || (\"gantt_\" + btn.label.toLowerCase() + \"_button\");\n\t\t\t\t\tvar value = btn.value || i;\n\t\t\t\t\tinner += button(label, css, value);\n\t\t\t\t} else {\n\t\t\t\t\tinner += button(btn, btn, i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tinner += '
';\n\t\tbox.innerHTML = inner;\n\n\t\tif (config.content) {\n\t\t\tvar node = config.content;\n\t\t\tif (typeof node == \"string\")\n\t\t\t\tnode = document.getElementById(node);\n\t\t\tif (node.style.display == 'none')\n\t\t\t\tnode.style.display = \"\";\n\t\t\tbox.childNodes[config.title ? 1 : 0].appendChild(node);\n\t\t}\n\n\t\tbox.onclick = function (event) {\n\t\t\tvar source = event.target || event.srcElement;\n\t\t\tif (!source.className) source = source.parentNode;\n\t\t\tif (domHelpers.closest(source, \".gantt_popup_button\")) {\n\t\t\t\tvar result = source.getAttribute(\"data-result\");\n\t\t\t\tresult = (result == \"true\") || (result == \"false\" ? false : result);\n\t\t\t\tcallback(config, result);\n\t\t\t}\n\t\t};\n\t\tconfig.box = box;\n\t\tif (ok || cancel)\n\t\t\t_dhx_msg_cfg = config;\n\n\t\treturn box;\n\t}\n\n\tfunction _createBox(config, ok, cancel) {\n\t\tvar box = config.tagName ? config : _boxStructure(config, ok, cancel);\n\n\t\tif (!config.hidden)\n\t\t\tmodality(true);\n\t\tdocument.body.appendChild(box);\n\t\tvar x = Math.abs(Math.floor(((window.innerWidth || document.documentElement.offsetWidth) - box.offsetWidth) / 2));\n\t\tvar y = Math.abs(Math.floor(((window.innerHeight || document.documentElement.offsetHeight) - box.offsetHeight) / 2));\n\t\tif (config.position == \"top\")\n\t\t\tbox.style.top = \"-3px\";\n\t\telse\n\t\t\tbox.style.top = y + 'px';\n\t\tbox.style.left = x + 'px';\n\t\t//necessary for IE only\n\t\tbox.onkeydown = modal_key;\n\n\t\tmodalBox.focus(box);\n\n\t\tif (config.hidden)\n\t\t\tmodalBox.hide(box);\n\n\t\tgantt.callEvent(\"onMessagePopup\", [box]);\n\t\treturn box;\n\t}\n\n\tfunction alertPopup(config) {\n\t\treturn _createBox(config, true, false);\n\t}\n\n\tfunction confirmPopup(config) {\n\t\treturn _createBox(config, true, true);\n\t}\n\n\tfunction boxPopup(config) {\n\t\treturn _createBox(config);\n\t}\n\n\tfunction box_params(text, type, callback) {\n\t\tif (typeof text != \"object\") {\n\t\t\tif (typeof type == \"function\") {\n\t\t\t\tcallback = type;\n\t\t\t\ttype = \"\";\n\t\t\t}\n\t\t\ttext = {text: text, type: type, callback: callback};\n\t\t}\n\t\treturn text;\n\t}\n\n\tfunction params(text, type, expire, id) {\n\t\tif (typeof text != \"object\")\n\t\t\ttext = {text: text, type: type, expire: expire, id: id};\n\t\ttext.id = text.id || utils.uid();\n\t\ttext.expire = text.expire || messageBox.expire;\n\t\treturn text;\n\t}\n\n\tvar alertBox = function () {\n\t\tvar text = box_params.apply(this, arguments);\n\t\ttext.type = text.type || \"confirm\";\n\t\treturn alertPopup(text);\n\t};\n\tvar confirmBox = function () {\n\t\tvar text = box_params.apply(this, arguments);\n\t\ttext.type = text.type || \"alert\";\n\t\treturn confirmPopup(text);\n\t};\n\tvar modalBox = function () {\n\t\tvar text = box_params.apply(this, arguments);\n\t\ttext.type = text.type || \"alert\";\n\t\treturn boxPopup(text);\n\t};\n\tmodalBox.hide = function (node) {\n\t\twhile (node && node.getAttribute && !node.getAttribute(boxAttribute))\n\t\t\tnode = node.parentNode;\n\t\tif (node) {\n\t\t\tnode.parentNode.removeChild(node);\n\t\t\tmodality(false);\n\n\t\t\tgantt.callEvent(\"onAfterMessagePopup\", [node]);\n\t\t}\n\t};\n\n\tmodalBox.focus = function (node) {\n\t\tsetTimeout(function () {\n\t\t\tvar focusable = domHelpers.getFocusableNodes(node);\n\t\t\tif (focusable.length) {\n\t\t\t\tif (focusable[0].focus) focusable[0].focus();\n\t\t\t}\n\t\t}, 1);\n\t};\n\n\tvar messageBox = function (text, type, expire, id) {\n\t\ttext = params.apply(this, arguments);\n\t\ttext.type = text.type || \"info\";\n\n\t\tvar subtype = text.type.split(\"-\")[0];\n\t\tswitch (subtype) {\n\t\t\tcase \"alert\":\n\t\t\t\treturn alertPopup(text);\n\t\t\tcase \"confirm\":\n\t\t\t\treturn confirmPopup(text);\n\t\t\tcase \"modalbox\":\n\t\t\t\treturn boxPopup(text);\n\t\t\tdefault:\n\t\t\t\treturn info(text);\n\t\t}\n\t};\n\n\tmessageBox.seed = (new Date()).valueOf();\n\tmessageBox.uid = utils.uid;\n\tmessageBox.expire = 4000;\n\tmessageBox.keyboard = true;\n\tmessageBox.position = \"top\";\n\tmessageBox.pull = {};\n\tmessageBox.timers = {};\n\n\tmessageBox.hideAll = function () {\n\t\tfor (var key in messageBox.pull)\n\t\t\tmessageBox.hide(key);\n\t};\n\tmessageBox.hide = function (id) {\n\t\tvar obj = messageBox.pull[id];\n\t\tif (obj && obj.parentNode) {\n\t\t\twindow.setTimeout(function () {\n\t\t\t\tobj.parentNode.removeChild(obj);\n\t\t\t\tobj = null;\n\t\t\t}, 2000);\n\t\t\tobj.className += \" hidden\";\n\n\t\t\tif (messageBox.timers[id])\n\t\t\t\twindow.clearTimeout(messageBox.timers[id]);\n\t\t\tdelete messageBox.pull[id];\n\t\t}\n\t};\n\n\tvar popups = [];\n\tgantt.attachEvent(\"onMessagePopup\", function(box){\n\t\tpopups.push(box);\n\t});\n\tgantt.attachEvent(\"onAfterMessagePopup\", function(box){\n\t\tfor(var i = 0; i < popups.length; i++){\n\t\t\tif(popups[i] === box){\n\t\t\t\tpopups.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t});\n\n\tgantt.attachEvent(\"onDestroy\", function(){\n\t\tif(modality.cover && modality.cover.parentNode){\n\t\t\tmodality.cover.parentNode.removeChild(modality.cover);\n\t\t}\n\n\t\tfor(var i = 0; i < popups.length; i++){\n\t\t\tif(popups[i].parentNode){\n\t\t\t\tpopups[i].parentNode.removeChild(popups[i]);\n\t\t\t}\n\t\t}\n\t\tpopups = null;\n\n\t\tif(messageBox.area && messageBox.area.parentNode){\n\t\t\tmessageBox.area.parentNode.removeChild(messageBox.area);\n\t\t}\n\t\tmessageBox = null;\n\t});\n\n\treturn {\n\t\talert: alertBox,\n\t\tconfirm: confirmBox,\n\t\tmessage: messageBox,\n\t\tmodalbox: modalBox\n\t};\n};","function createLayoutFacade(){\n\n\tfunction getTimeline(gantt){\n\t\treturn gantt.$ui.getView(\"timeline\");\n\t}\n\n\tfunction getGrid(gantt){\n\t\treturn gantt.$ui.getView(\"grid\");\n\t}\n\n\tfunction getBaseCell(gantt){\n\t\tvar timeline = getTimeline(gantt);\n\t\tif (timeline && !timeline.$config.hidden){\n\t\t\treturn timeline;\n\t\t} else{\n\t\t\tvar grid = getGrid(gantt);\n\t\t\tif (grid && !grid.$config.hidden){\n\t\t\t\treturn grid;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction getVerticalScrollbar(gantt){\n\t\tvar baseCell = null;\n\t\t// GS-1150: if we reorder or resize something in the grid, we should obtain the grid container\n\t\tvar gridDrag = false;\n\t\tvar gridMarkers = [\n\t\t\t\".gantt_drag_marker.gantt_grid_resize_area\",\n\t\t\t\".gantt_drag_marker .gantt_row.gantt_row_task\",\n\t\t\t\".gantt_drag_marker.gantt_grid_dnd_marker\"\n\t\t];\n\t\tgridMarkers.forEach(function (selector) {\n\t\t\tgridDrag = gridDrag || !!document.querySelector(selector);\n\t\t});\n\t\tif (gridDrag){\n\t\t\tbaseCell = getGrid(gantt);\n\t\t} else{\n\t\t\tbaseCell = getBaseCell(gantt);\n\t\t}\n\n\t\t// GS-1827. If there is no grid and timeline, there is no scrollbar for them\n\t\tif (!baseCell){\n\t\t\treturn null;\n\t\t}\n\n\t\tvar verticalScrollbar = getAttachedScrollbar(gantt, baseCell, \"scrollY\");\n\t\treturn verticalScrollbar;\n\t}\n\n\tfunction getHorizontalScrollbar(gantt){\n\t\tvar baseCell = getBaseCell(gantt);\n\t\tif (!baseCell || baseCell.id == \"grid\"){\n\t\t\treturn null; // if the timeline is not displayed, do not return the scrollbar\n\t\t}\n\t\tvar horizontalScrollbar = getAttachedScrollbar(gantt, baseCell, \"scrollX\");\n\t\treturn horizontalScrollbar;\n\t}\n\n\tfunction getAttachedScrollbar(gantt, cell, type){\n\t\tvar attachedScrollbar = cell.$config[type];\n\t\tvar scrollbarView = gantt.$ui.getView(attachedScrollbar);\n\t\treturn scrollbarView;\n\t}\n\n\tvar DEFAULT_VALUE = \"DEFAULT_VALUE\";\n\n\tfunction tryCall(getView, method, args, fallback){\n\t\tvar view = getView(this);\n\t\tif (!(view && view.isVisible())) {\n\t\t\tif(fallback){\n\t\t\t\treturn fallback();\n\t\t\t}else{\n\t\t\t\treturn DEFAULT_VALUE;\n\t\t\t}\n\t\t} else {\n\t\t\treturn view[method].apply(view, args);\n\t\t}\n\t}\n\n\treturn {\n\n\t\tgetColumnIndex: function(name) {\n\t\t\tvar res = tryCall.call(this, getGrid, \"getColumnIndex\", [name]);\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\t\tdateFromPos: function(x) {\n\t\t\tvar res = tryCall.call(this, getTimeline, \"dateFromPos\", Array.prototype.slice.call(arguments));\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn this.getState().min_date;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\t\tposFromDate: function(date) {\n\t\t\tvar res = tryCall.call(this, getTimeline, \"posFromDate\", [date]);\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\t\tgetRowTop: function(index) {\n\t\t\tvar self = this;\n\t\t\tvar res = tryCall.call(self, getTimeline, \"getRowTop\", [index],\n\t\t\t\tfunction(){ return tryCall.call(self, getGrid, \"getRowTop\", [index]);}\n\t\t\t\t);\n\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\t\tgetTaskTop: function(id) {\n\t\t\tvar self = this;\n\t\t\tvar res = tryCall.call(self, getTimeline, \"getItemTop\", [id],\n\t\t\t\tfunction(){ return tryCall.call(self, getGrid, \"getItemTop\", [id]);}\n\t\t\t);\n\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\n\t\tgetTaskPosition: function(task, start_date, end_date) {\n\t\t\tvar res = tryCall.call(this, getTimeline, \"getItemPosition\", [task, start_date, end_date]);\n\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\tvar top = this.getTaskTop(task.id);\n\t\t\t\tvar height = this.getTaskBarHeight(task.id);\n\n\t\t\t\treturn {\n\t\t\t\t\tleft: 0,\n\t\t\t\t\ttop: top,\n\t\t\t\t\theight: height,\n\t\t\t\t\twidth: 0\n\t\t\t\t};\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\t\tgetTaskBarHeight: function(taskId, isMilestoneRender) {\n\t\t\tvar self = this;\n\t\t\tvar res = tryCall.call(self, getTimeline, \"getBarHeight\", [taskId, isMilestoneRender],\n\t\t\t\tfunction(){ return tryCall.call(self, getGrid, \"getItemHeight\", [taskId]);}\n\t\t\t);\n\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\t\tgetTaskHeight: function(taskId) {\n\t\t\tvar self = this;\n\t\t\tvar res = tryCall.call(self, getTimeline, \"getItemHeight\", [taskId],\n\t\t\t\tfunction(){ return tryCall.call(self, getGrid, \"getItemHeight\", [taskId]);}\n\t\t\t);\n\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\n\t\tcolumnIndexByDate: function(date) {\n\t\t\tvar res = tryCall.call(this, getTimeline, \"columnIndexByDate\", [date]);\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\t\troundTaskDates: function() {\n\t\t\ttryCall.call(this, getTimeline, \"roundTaskDates\", []);\n\t\t},\n\n\t\tgetScale: function() {\n\t\t\tvar res = tryCall.call(this, getTimeline, \"getScale\", []);\n\t\t\tif(res === DEFAULT_VALUE){\n\t\t\t\treturn null;\n\t\t\t}else{\n\t\t\t\treturn res;\n\t\t\t}\n\t\t},\n\n\t\tgetTaskNode: function(id) {\n\t\t\tvar timeline = getTimeline(this);\n\t\t\tif (!timeline || !timeline.isVisible()) {\n\t\t\t\treturn null;\n\t\t\t} else {\n\t\t\t\tvar node = timeline._taskRenderer.rendered[id];\n\t\t\t\tif(!node){\n\t\t\t\t\tvar domAttr = timeline.$config.item_attribute;\n\t\t\t\t\tnode = timeline.$task_bars.querySelector(\"[\" +domAttr+ \"='\"+id+\"']\");\n\t\t\t\t}\n\n\t\t\t\treturn node || null;\n\t\t\t}\n\t\t},\n\n\n\t\tgetLinkNode: function(id) {\n\t\t\tvar timeline = getTimeline(this);\n\t\t\tif (!timeline.isVisible()) {\n\t\t\t\treturn null;\n\t\t\t} else {\n\t\t\t\treturn timeline._linkRenderer.rendered[id];\n\t\t\t}\n\t\t},\n\n\t\tscrollTo: function(left, top){\n\t\t\tvar vertical = getVerticalScrollbar(this);\n\t\t\tvar horizontal = getHorizontalScrollbar(this);\n\n\t\t\tvar oldH = {position: 0},\n\t\t\t\toldV = {position: 0};\n\n\t\t\tif(vertical){\n\t\t\t\toldV = vertical.getScrollState();\n\t\t\t}\n\t\t\tif(horizontal){\n\t\t\t\toldH = horizontal.getScrollState();\n\t\t\t}\n\n\t\t\tvar scrollHorizontal = (horizontal && left*1 == left);\n\t\t\tvar scrollVertical = (vertical && top*1 == top);\n\t\t\tvar scrollBoth = scrollHorizontal && scrollVertical;\n\n\t\t\tif(scrollBoth){\n\t\t\t\t// some views will be scrolled both horizontally and vertically and smart rendering can be called twice\n\t\t\t\t// set flag in order not to invoke smart rendering at the horizontal scroll stage\n\t\t\t\t// so it will repaint only once when the scroll is completed\n\t\t\t\tvar verticalViews = vertical._getLinkedViews();\n\t\t\t\tvar horizontalViews = horizontal._getLinkedViews();\n\n\t\t\t\tvar commonViews = [];\n\t\t\t\tfor(var i = 0; i < verticalViews.length; i++){\n\t\t\t\t\tfor(var j = 0; j < horizontalViews.length; j++){\n\n\t\t\t\t\t\tif(verticalViews[i].$config.id && horizontalViews[j].$config.id && verticalViews[i].$config.id === horizontalViews[j].$config.id){\n\t\t\t\t\t\t\tcommonViews.push(verticalViews[i].$config.id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (scrollHorizontal){\n\t\t\t\tif(commonViews){\n\t\t\t\t\tcommonViews.forEach((function(viewId){\n\t\t\t\t\t\tthis.$ui.getView(viewId).$config.$skipSmartRenderOnScroll = true;\n\t\t\t\t\t}).bind(this));\n\t\t\t\t}\n\n\t\t\t\thorizontal.scroll(left);\n\t\t\t\tif(commonViews){\n\t\t\t\t\tcommonViews.forEach((function(viewId){\n\t\t\t\t\t\tthis.$ui.getView(viewId).$config.$skipSmartRenderOnScroll = false;\n\t\t\t\t\t}).bind(this));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(scrollVertical){\n\t\t\t\tvertical.scroll(top);\n\t\t\t}\n\n\t\t\tvar newV = {position: 0},\n\t\t\t\tnewH = {position: 0};\n\t\t\tif(vertical){\n\t\t\t\tnewV = vertical.getScrollState();\n\t\t\t}\n\t\t\tif(horizontal){\n\t\t\t\tnewH = horizontal.getScrollState();\n\t\t\t}\n\n\t\t\tthis.callEvent(\"onGanttScroll\", [oldH.position, oldV.position, newH.position, newV.position]);\n\t\t},\n\n\t\tshowDate: function(date){\n\t\t\tvar date_x = this.posFromDate(date);\n\t\t\tvar scroll_to = Math.max(date_x - this.config.task_scroll_offset, 0);\n\t\t\tthis.scrollTo(scroll_to);\n\t\t},\n\t\tshowTask: function(id) {\n\t\t\tvar pos = this.getTaskPosition(this.getTask(id));\n\n\t\t\t// GS-1261: we need to show the start_date even in the RTL mode\n\t\t\tvar leftPos = pos.left;\n\t\t\tif (this.config.rtl) leftPos = pos.left + pos.width;\n\n\t\t\tvar left = Math.max(leftPos - this.config.task_scroll_offset, 0);\n\n\t\t\tvar dataHeight = this._scroll_state().y;\n\t\t\tvar top;\n\t\t\tif(!dataHeight){\n\t\t\t\ttop = pos.top;\n\t\t\t}else{\n\t\t\t\ttop = pos.top - (dataHeight - this.getTaskBarHeight(id))/2;\n\t\t\t}\n\n\t\t\tthis.scrollTo(left, top);\n\t\t\t// GS-1150: if the grid and timeline have different scrollbars, we need to scroll thegrid to show the task\n\t\t\tvar gridCell = getGrid(this);\n\t\t\tvar timelineCell = getTimeline(this);\n\t\t\tif (gridCell && timelineCell && gridCell.$config.scrollY != timelineCell.$config.scrollY){\n\t\t\t\tvar gridScrollbar = getAttachedScrollbar(this, gridCell, \"scrollY\");\n\t\t\t\tgridScrollbar.scrollTo(null, top);\n\t\t\t}\n\t\t},\n\t\t_scroll_state: function(){\n\t\t\tvar result = {\n\t\t\t\tx: false,\n\t\t\t\ty: false,\n\t\t\t\tx_pos: 0,\n\t\t\t\ty_pos: 0,\n\t\t\t\tscroll_size: this.config.scroll_size + 1,//1px for inner content\n\t\t\t\tx_inner: 0,\n\t\t\t\ty_inner: 0\n\t\t\t};\n\n\t\t\tvar scrollVer = getVerticalScrollbar(this),\n\t\t\t\tscrollHor = getHorizontalScrollbar(this);\n\t\t\tif(scrollHor){\n\t\t\t\tvar horState = scrollHor.getScrollState();\n\t\t\t\tif(horState.visible){\n\t\t\t\t\tresult.x = horState.size;\n\t\t\t\t\tresult.x_inner = horState.scrollSize;\n\t\t\t\t}\n\t\t\t\tresult.x_pos = horState.position || 0;\n\t\t\t}\n\n\t\t\tif(scrollVer){\n\t\t\t\tvar verState = scrollVer.getScrollState();\n\t\t\t\tif(verState.visible){\n\t\t\t\t\tresult.y = verState.size;\n\n\t\t\t\t\tresult.y_inner = verState.scrollSize;\n\t\t\t\t}\n\t\t\t\tresult.y_pos = verState.position || 0;\n\t\t\t}\n\n\t\t\treturn result;\n\t\t},\n\t\tgetScrollState: function(){\n\t\t\tvar state = this._scroll_state();\n\t\t\treturn { x:state.x_pos, y:state.y_pos, inner_width:state.x, inner_height:state.y, width: state.x_inner, height: state.y_inner };\n\t\t},\n\n\t\tgetLayoutView: function(cellName){\n\t\t\treturn this.$ui.getView(cellName);\n\t\t},\n\n\t\tscrollLayoutCell: function(cellName, left, top){\n\t\t\tconst cell = this.$ui.getView(cellName);\n\t\t\tif (!cell){\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (left !== null){\n\t\t\t\tconst horizontalScroll = this.$ui.getView(cell.$config.scrollX);\n\t\t\t\tif (horizontalScroll){\n\t\t\t\t\thorizontalScroll.scrollTo(left, null);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (top !== null){\n\t\t\t\tconst verticalScroll = this.$ui.getView(cell.$config.scrollY);\n\t\t\t\tif (verticalScroll){\n\t\t\t\t\tverticalScroll.scrollTo(null, top);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t};\n\n}\n\nexport default createLayoutFacade;","export default function(gantt) {\ngantt.skins.skyblue = {\n\tconfig:{\n\t\tgrid_width:370,\n\t\trow_height: 27,\n\t\tbar_height_padding:4,\n\t\tscale_height: 27,\n\t\tlink_line_width:1,\n\t\tlink_arrow_size:8,\n\t\tlink_radius:2,\n\t\tlightbox_additional_height:75\n\t},\n\t_second_column_width:95,\n\t_third_column_width:80\n};\n\n};","export default function(gantt) {\ngantt.skins.dark = {\n\tconfig:{\n\t\tgrid_width:390,\n\t\trow_height: 36,\n\t\tscale_height: 36,\n\t\tlink_line_width:2,\n\t\tlink_arrow_size:12,\n\t\tbar_height_padding:9,\n\t\tlightbox_additional_height:75\n\t},\n\t_second_column_width:100,\n\t_third_column_width:70\t\t\n};\n\n};","export default function(gantt) {\ngantt.skins.meadow = {\n\tconfig:{\n\t\tgrid_width:380,\n\t\trow_height: 27,\n\t\tscale_height: 30,\n\t\tlink_line_width:2,\n\t\tlink_arrow_size:10,\n\t\tbar_height_padding:4,\n\t\tlightbox_additional_height:72\n\t},\n\t_second_column_width:95,\n\t_third_column_width:80\n};\n\n};","export default function(gantt) {\ngantt.skins.terrace = {\n\tconfig:{\n\t\tgrid_width:390,\n\t\trow_height: 36,\n\t\tscale_height: 36,\n\t\tlink_line_width:2,\n\t\tlink_arrow_size:12,\n\t\tbar_height_padding:9,\n\t\tlightbox_additional_height:75\n\t},\n\t_second_column_width:100,\n\t_third_column_width:70\t\t\n};\n\n};","export default function(gantt) {\n\tgantt.skins.broadway = {\n\t\tconfig: {\n\t\t\tgrid_width: 390,\n\t\t\trow_height: 35,\n\t\t\tscale_height: 35,\n\t\t\tlink_line_width: 1,\n\t\t\tlink_arrow_size: 9,\n\t\t\tbar_height_padding:4,\n\t\t\tlightbox_additional_height: 86\n\t\t},\n\t\t_second_column_width: 100,\n\t\t_third_column_width: 80,\n\n\t\t_lightbox_template: \"
 
\",\n\t\t_config_buttons_left: {},\n\t\t_config_buttons_right: {\n\t\t\t\"gantt_delete_btn\": \"icon_delete\",\n\t\t\t\"gantt_save_btn\": \"icon_save\"\n\t\t}\n\t};\n};","export default function(gantt) {\n\tgantt.skins.material = {\n\t\tconfig: {\n\t\t\tgrid_width: 411,\n\t\t\trow_height: 34,\n\t\t\tscale_height: 36,\n\t\t\tlink_line_width: 2,\n\t\t\tlink_arrow_size: 12,\n\t\t\tbar_height_padding:9,\n\t\t\tlightbox_additional_height: 80\n\t\t},\n\t\t_second_column_width: 110,\n\t\t_third_column_width: 75,\n\t\t_redefine_lightbox_buttons: {\n\t\t\t\"buttons_left\": [\"dhx_delete_btn\"],\n\t\t\t\"buttons_right\": [\"dhx_cancel_btn\", \"dhx_save_btn\"]\n\t\t}\n\t};\n\n\tgantt.attachEvent(\"onAfterTaskDrag\", function (id) {\n\t\tvar t = gantt.getTaskNode(id);\n\t\tif (t) {\n\t\t\tt.className += \" gantt_drag_animation\";\n\t\t\tsetTimeout(function () {\n\t\t\t\tvar indx = t.className.indexOf(\" gantt_drag_animation\");\n\t\t\t\tif (indx > -1) {\n\t\t\t\t\tt.className = t.className.slice(0, indx);\n\t\t\t\t}\n\t\t\t}, 200);\n\t\t}\n\t});\n\n};","export default function(gantt) {\ngantt.skins[\"contrast_black\"] = {\n\tconfig:{\n\t\tgrid_width:390,\n\t\trow_height: 35,\n\t\tscale_height: 35,\n\t\tlink_line_width:2,\n\t\tlink_arrow_size:12,\n\t\tlightbox_additional_height:75\n\t},\n\t_second_column_width:100,\n\t_third_column_width:80\n};\n\n};","export default function(gantt) {\ngantt.skins[\"contrast_white\"] = {\n\tconfig:{\n\t\tgrid_width:390,\n\t\trow_height: 35,\n\t\tscale_height: 35,\n\t\tlink_line_width:2,\n\t\tlink_arrow_size:12,\n\t\tlightbox_additional_height:75\n\t},\n\t_second_column_width:100,\n\t_third_column_width:80\n};\n\n};","import autoscroll from \"./autoscroll\";\nimport jquery_hooks from \"./jquery_hooks\";\nimport dhtmlx_hooks from \"./dhtmlx_hooks\";\nimport TimelineZoom from \"./timeline_zoom\";\n\n\nexport default function(gantt){\n\tif(!gantt.ext){\n\t\tgantt.ext = {};\n\t}\n\n\tvar modules = [\n\t\tautoscroll,\n\t\tjquery_hooks,\n\t\tdhtmlx_hooks\n\t];\n\n\tfor(var i = 0; i < modules.length; i++){\n\t\tif(modules[i])\n\t\t\tmodules[i](gantt);\n\t}\n\n\tgantt.ext.zoom = new TimelineZoom(gantt);\n};","export default function(gantt) {\n\n\tgantt.config.touch_drag = 75; //nearly immediate dnd\n\tgantt.config.touch = true;\n\tgantt.config.touch_feedback = true;\n\tgantt.config.touch_feedback_duration = 1;\n\tgantt._prevent_touch_scroll = false;\n\n\n\tgantt._touch_feedback = function () {\n\t\tif (gantt.config.touch_feedback) {\n\t\t\tif (navigator.vibrate)\n\t\t\t\tnavigator.vibrate(gantt.config.touch_feedback_duration);\n\t\t}\n\t};\n\n\tgantt.attachEvent(\"onGanttReady\", function(){\n\t\tif (gantt.$container)\t{\n\t\t\taddTouchEvents();\n\t\t}\n\t});\n\tgantt.attachEvent(\"onGanttLayoutReady\", function(){\n\t\tif (gantt.$container)\t{\n\t\t\t\tgantt.attachEvent(\"onGanttRender\", addTouchEvents, {once: true});\n\t\t}\n\t});\n\n\tfunction addTouchEvents(){\n\t\tif (gantt.config.touch != \"force\")\n\t\t\tgantt.config.touch = gantt.config.touch &&\n\t\t\t\t((navigator.userAgent.indexOf(\"Mobile\") != -1) ||\n\t\t\t\t\t(navigator.userAgent.indexOf(\"iPad\") != -1) ||\n\t\t\t\t\t(navigator.userAgent.indexOf(\"Android\") != -1) ||\n\t\t\t\t\t(navigator.userAgent.indexOf(\"Touch\") != -1)) ||\n\t\t\t\t\t((navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1));\n\n\t\tif (gantt.config.touch) {\n\n\t\t\tvar touchEventsSupported = true;\n\t\t\ttry {\n\t\t\t\tdocument.createEvent(\"TouchEvent\");\n\t\t\t} catch (e) {\n\t\t\t\ttouchEventsSupported = false;\n\t\t\t}\n\n\t\t\tif (touchEventsSupported) {\n\t\t\t\tgantt._touch_events([\"touchmove\", \"touchstart\", \"touchend\"], function (ev) {\n\t\t\t\t\tif (ev.touches && ev.touches.length > 1) return null;\n\t\t\t\t\tif (ev.touches[0])\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttarget: ev.target,\n\t\t\t\t\t\t\tpageX: ev.touches[0].pageX,\n\t\t\t\t\t\t\tpageY: ev.touches[0].pageY,\n\t\t\t\t\t\t\tclientX: ev.touches[0].clientX,\n\t\t\t\t\t\t\tclientY: ev.touches[0].clientY\n\t\t\t\t\t\t};\n\t\t\t\t\telse\n\t\t\t\t\t\treturn ev;\n\t\t\t\t}, function () {\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t} else if (window.navigator.pointerEnabled) {\n\t\t\t\tgantt._touch_events([\"pointermove\", \"pointerdown\", \"pointerup\"], function (ev) {\n\t\t\t\t\tif (ev.pointerType == \"mouse\") return null;\n\t\t\t\t\treturn ev;\n\t\t\t\t}, function (ev) {\n\t\t\t\t\treturn (!ev || (ev.pointerType == \"mouse\" ));\n\t\t\t\t});\n\t\t\t} else if (window.navigator.msPointerEnabled) {\n\t\t\t\tgantt._touch_events([\"MSPointerMove\", \"MSPointerDown\", \"MSPointerUp\"], function (ev) {\n\t\t\t\t\tif (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE) return null;\n\t\t\t\t\treturn ev;\n\t\t\t\t}, function (ev) {\n\t\t\t\t\treturn (!ev || ev.pointerType == ev.MSPOINTER_TYPE_MOUSE);\n\t\t\t\t});\n\t\t\t}\n\n\t\t}\n\t}\n\n\n\tfunction findTargetView(event){\n\t\tvar allViews = gantt.$layout.getCellsByType(\"viewCell\");\n\n\t\tfor(var i = 0; i < allViews.length; i++){\n\t\t\tvar box = allViews[i].$view.getBoundingClientRect();\n\t\t\tif(event.clientX >= box.left && event.clientX <= box.right &&\n\t\t\t\tevent.clientY <= box.bottom && event.clientY >= box.top){\n\t\t\t\t\treturn allViews[i];\n\t\t\t\t}\n\t\t}\n\t}\n\n\tfunction getScrollState(view){\n\t\tvar scrollX = view.$config.scrollX ? gantt.$ui.getView(view.$config.scrollX) : null;\n\t\tvar scrollY = view.$config.scrollY ? gantt.$ui.getView(view.$config.scrollY) : null;\n\n\t\tvar scrollState = {x: null, y: null};\n\t\tif(scrollX){\n\t\t\tvar state = scrollX.getScrollState();\n\t\t\tif(state.visible){\n\t\t\t\tscrollState.x = scrollX.$view.scrollLeft;\n\t\t\t}\n\t\t}\n\t\tif(scrollY){\n\t\t\tvar state = scrollY.getScrollState();\n\t\t\tif(state.visible){\n\t\t\t\tscrollState.y = scrollY.$view.scrollTop;\n\t\t\t}\n\t\t}\n\t\treturn scrollState;\n\t}\n\n\tfunction scrollView(view, left, top){\n\t\tvar scrollX = view.$config.scrollX ? gantt.$ui.getView(view.$config.scrollX) : null;\n\t\tvar scrollY = view.$config.scrollY ? gantt.$ui.getView(view.$config.scrollY) : null;\n\n\t\tif(scrollX){\n\t\t\tscrollX.scrollTo(left, null);\n\t\t}\n\t\tif(scrollY){\n\t\t\tscrollY.scrollTo(null, top);\n\t\t}\n\t}\n\n\tfunction getTaskDND(){\n\t\tvar tasksDnD;\n\t\tif(gantt.$ui.getView(\"timeline\")){\n\t\t\ttasksDnD = gantt.$ui.getView(\"timeline\")._tasks_dnd;\n\t\t}\n\t\treturn tasksDnD;\n\t}\n\n\tvar touchHandlers = [];\n\n//we can't use native scrolling, as we need to sync momentum between different parts\n//so we will block native scroll and use the custom one\n//in future we can add custom momentum\n\tgantt._touch_events = function (names, accessor, ignore) {\n\t\t//webkit on android need to be handled separately\n\t\tvar dblclicktime = 0;\n\t\tvar actionMode = false;\n\t\tvar scrollMode = false;\n\t\tvar actionStart = null;\n\t\tvar scrollState;\n\t\tvar longTapTimer = null;\n\t\tvar currentDndId = null;\n\t\tvar dndNodes = [];\n\t\tvar targetView = null;\n\t\tlet multiTouchEvents = {};\n\n\t\tfor(var i = 0; i < touchHandlers.length; i++){\n\t\t\tgantt.eventRemove(touchHandlers[i][0], touchHandlers[i][1], touchHandlers[i][2]);\n\t\t}\n\t\ttouchHandlers = [];\n\n\t\t//touch move\n\t\ttouchHandlers.push([gantt.$container, names[0], function (e) {\n\t\t\tvar tasksDnD = getTaskDND();\n\n\t\t\t\tif (ignore(e)) return;\n\n\t\t\t\t//ignore common and scrolling moves\n\t\t\t\tif (!actionMode) return;\n\n\t\t\t\tif (longTapTimer) clearTimeout(longTapTimer);\n\n\t\t\t\tvar source = accessor(e);\n\t\t\t\tif (tasksDnD && (tasksDnD.drag.id || tasksDnD.drag.start_drag)) {\n\t\t\t\t\ttasksDnD.on_mouse_move(source);\n\t\t\t\t\tif (e.preventDefault)\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.cancelBubble = true;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (!gantt._prevent_touch_scroll) {\n\t\t\t\t\tif (source && actionStart) {\n\t\t\t\t\t\tvar dx = actionStart.pageX - source.pageX;\n\t\t\t\t\t\tvar dy = actionStart.pageY - source.pageY;\n\t\t\t\t\t\tif (!scrollMode && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {\n\t\t\t\t\t\t\tscrollMode = true;\n\t\t\t\t\t\t\t//gantt._touch_scroll_active = scroll_mode = true;\n\t\t\t\t\t\t\tdblclicktime = 0;\n\n\t\t\t\t\t\t\tif(targetView){\n\t\t\t\t\t\t\t\tscrollState = getScrollState(targetView);\n\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\tscrollState = gantt.getScrollState();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (scrollMode) {\n\n\t\t\t\t\t\t\tvar newScrollState;\n\t\t\t\t\t\t\tvar scrollX = scrollState.x + dx;\n\t\t\t\t\t\t\tvar scrollY = scrollState.y + dy;\n\t\t\t\t\t\t\tif(targetView){\n\t\t\t\t\t\t\t\tscrollView(targetView, scrollX, scrollY);\n\t\t\t\t\t\t\t\tnewScrollState = getScrollState(targetView);\n\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\tgantt.scrollTo(scrollX, scrollY);\n\t\t\t\t\t\t\t\tnewScrollState = gantt.getScrollState();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ((scrollState.x != newScrollState.x && dy > 2 * dx) ||\n\t\t\t\t\t\t\t\t(scrollState.y != newScrollState.y && dx > 2 * dy )) {\n\t\t\t\t\t\t\t\treturn block_action(e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn block_action(e);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}]);\n\n\t\t// prevent page drag on touch move\n\t\ttry{\n\t\t\tdocument.addEventListener('touchmove', function(e) {\n\t\t\t\tif (gantt._touch_drag) {\n\t\t\t\t\tblock_action(e);\n\t\t\t\t}\n\t\t\t}, { passive: false });\n\t\t}\n\t\tcatch(e){\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(\"Cannot prevent touch event for the page drag\");\n\t\t}\n\n\t\t//block touch context menu in IE10\n\t\ttouchHandlers.push([this.$container, \"contextmenu\", function (e) {\n\t\t\tif (actionMode)\n\t\t\t\treturn block_action(e);\n\t\t}]);\n\n\t\t//touch start\n\t\ttouchHandlers.push([this.$container, names[1], function (e) {\n\t\t\tmultiTouchEvents = e.touches.length;\n\t\t\t// block pull-to-refresh\n\t\t\tif(document && document.body){\n\t\t\t\tdocument.body.classList.add(\"gantt_touch_active\");\n\t\t\t}\n\n\t\t\tif (ignore(e)) return;\n\t\t\tif (e.touches && e.touches.length > 1) {\n\t\t\t\tactionMode = false;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tactionStart = accessor(e);\n\t\t\ttargetView = findTargetView(actionStart);\n\t\t\tif (!gantt._locate_css(actionStart, \"gantt_hor_scroll\") && !gantt._locate_css(actionStart, \"gantt_ver_scroll\")) {\n\t\t\t\tactionMode = true;\n\t\t\t}\n\t\t\tvar tasksDnD = getTaskDND();\n\n\t\t\t//long tap\n\t\t\tlongTapTimer = setTimeout(function () {\n\t\t\t\tvar taskId = gantt.locate(actionStart);\n\t\t\t\tif (tasksDnD && (taskId && !gantt._locate_css(actionStart, \"gantt_link_control\") && !gantt._locate_css(actionStart, \"gantt_grid_data\"))) {\n\t\t\t\t\ttasksDnD.on_mouse_down(actionStart);\n\n\t\t\t\t\tif (tasksDnD.drag && tasksDnD.drag.start_drag) {\n\t\t\t\t\t\t// we need that as touch events break if the target node is removed from the DOM\n\t\t\t\t\t\tcloneTaskRendered(taskId);\n\t\t\t\t\t\ttasksDnD._start_dnd(actionStart);\n\t\t\t\t\t\tgantt._touch_drag = true;\n\n\t\t\t\t\t\tgantt.refreshTask(taskId);\n\n\t\t\t\t\t\tgantt._touch_feedback();\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tlongTapTimer = null;\n\t\t\t}, gantt.config.touch_drag);\n\t\t}]);\n\n\t\t//touch end\n\t\ttouchHandlers.push([this.$container, names[2], function (e) {\n\t\t\tif(document && document.body){\n\t\t\t\tdocument.body.classList.remove(\"gantt_touch_active\");\n\t\t\t}\n\t\t\tif (ignore(e)) return;\n\t\t\tif (longTapTimer) clearTimeout(longTapTimer);\n\t\t\tgantt._touch_drag = false;\n\t\t\tactionMode = false;\n\t\t\tvar source = accessor(e);\n\n\t\t\tvar tasksDnD = getTaskDND();\n\n\t\t\tif(tasksDnD)\n\t\t\t\ttasksDnD.on_mouse_up(source);\n\n\t\t\tif (currentDndId && gantt.isTaskExists(currentDndId)) {\n\t\t\t\tgantt.refreshTask(currentDndId);\n\t\t\t\tif(dndNodes.length){\n\t\t\t\t\tdndNodes.forEach(function(node){\n\t\t\t\t\t\tif(node.parentNode){\n\t\t\t\t\t\t\tnode.parentNode.removeChild(node);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tgantt._touch_feedback();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t//gantt._touch_scroll_active = action_mode = scroll_mode = false;\n\t\t\tactionMode = scrollMode = false;\n\t\t\tdndNodes = [];\n\t\t\tcurrentDndId = null;\n\n\t\t\t//dbl-tap handling\n\t\t\tif (actionStart && dblclicktime) {\n\t\t\t\tvar now = new Date();\n\t\t\t\t// doubletap shouldn't happen with multitouch\n\t\t\t\tif ((now - dblclicktime) < 500 && multiTouchEvents <= 1) {\n\n\t\t\t\t\tvar mouseEvents = gantt.$services.getService(\"mouseEvents\");\n\t\t\t\t\tmouseEvents.onDoubleClick(actionStart);\n\t\t\t\t\tblock_action(e);\n\t\t\t\t} else\n\t\t\t\t\tdblclicktime = now;\n\t\t\t} else {\n\t\t\t\tdblclicktime = new Date();\n\t\t\t}\n\t\t}]);\n\n\t\tfor(var i = 0; i < touchHandlers.length; i++){\n\t\t\tgantt.event(touchHandlers[i][0], touchHandlers[i][1], touchHandlers[i][2]);\n\t\t}\n\n\t\t//common helper, prevents event\n\t\tfunction block_action(e) {\n\t\t\tif (e && e.preventDefault && e.cancelable){\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t\te.cancelBubble = true;\n\t\t\treturn false;\n\t\t}\n\n\t\tfunction cloneTaskRendered(taskId) {\n\t\t\tconst renders = gantt._getTaskLayers();\n\t\t\tlet task = gantt.getTask(taskId);\n\t\t\tif (task) {\n\t\t\t\tlet visible = gantt.isTaskVisible(taskId);\n\t\t\t\tif (visible){\n\t\t\t\t\tcurrentDndId = taskId;\n\t\t\t\t\tfor (let i = 0; i < renders.length; i++) {\n\t\t\t\t\t\ttask = renders[i].rendered[taskId];\n\t\t\t\t\t\tif (task && task.getAttribute(gantt.config.task_attribute) && task.getAttribute(gantt.config.task_attribute) == taskId) {\n\t\t\t\t\t\t\tconst copy = task.cloneNode(true);\n\t\t\t\t\t\t\tdndNodes.push(task);\n\t\t\t\t\t\t\trenders[i].rendered[taskId] = copy;\n\t\t\t\t\t\t\ttask.style.display = \"none\";\n\t\t\t\t\t\t\tcopy.className += \" gantt_drag_move \";\n\t\t\t\t\t\t\ttask.parentNode.appendChild(copy);\n\t\t\t\t\t\t\t//return copy;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (task.$split_subtask){\n\t\t\t\t\tlet renderedParent = task.$rendered_parent;\n\t\t\t\t\tvisible = gantt.isTaskVisible(renderedParent);\n\t\t\t\t\tif (!visible){\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcurrentDndId = taskId;\n\t\t\t\t\tfor (let i = 0; i < renders.length; i++) {\n\t\t\t\t\t\tconst parent = renders[i].rendered[renderedParent];\n\t\t\t\t\t\tlet taskNode;\n\t\t\t\t\t\tif (parent && parent.childNodes){\n\t\t\t\t\t\t\ttaskNode = parent.querySelector(`[${gantt.config.task_attribute}=\"${task.id}\"]`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (taskNode) {\n\t\t\t\t\t\t\t// move the child node to a different parent as the task bar will be repainted\n\t\t\t\t\t\t\t// and the initial node will be lost\n\t\t\t\t\t\t\tconst copy = taskNode.cloneNode(true);\n\t\t\t\t\t\t\ttaskNode.parentNode.appendChild(copy);\n\n\t\t\t\t\t\t\tgantt.$task_bars.appendChild(taskNode);\n\t\t\t\t\t\t\ttaskNode.style.display = \"none\";\n\n\t\t\t\t\t\t\t// don't add the node as rendered otherwise it will be lost:\n\t\t\t\t\t\t\t// renders[i].rendered[taskId] = taskNode;\n\t\t\t\t\t\t\t// instead, add it to dndNodes as its elements will be removed after drag\n\t\t\t\t\t\t\tdndNodes.push(taskNode);\n\n\t\t\t\t\t\t\ttaskNode = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n};","import TemplateControlConstructor from \"./controls/template_control\";\nimport TextareaControlConstructor from \"./controls/textarea_control\";\nimport TimeControlConstructor from \"./controls/time_control\";\nimport SelectControlConstructor from \"./controls/select_control\";\nimport CheckboxControlConstructor from \"./controls/checkbox_control\";\nimport RadioControlConstructor from \"./controls/radio_control\";\nimport DurationControlConstructor from \"./controls/duration_control\";\nimport ParentControlConstructor from \"./controls/parent_control\";\nimport ResourcesControlConstructor from \"./controls/resources_control\";\nimport ConstraintControlConstructor from \"./controls/constraint_control\";\nimport TypeselectControlConstructor from \"./controls/typeselect_control\";\nimport BaselineControlConstructor from \"./controls/baseline_control\";\n\nimport * as domHelpers from \"../utils/dom_helpers\";\nimport * as helpers from \"../../../utils/helpers\";\n\t\n\nexport default function (gantt) {\n\n\n\tvar TemplateControl = TemplateControlConstructor(gantt);\n\tvar TextareaControl = TextareaControlConstructor(gantt);\n\tvar TimeControl = TimeControlConstructor(gantt);\n\tvar SelectControl = SelectControlConstructor(gantt);\n\tvar CheckboxControl = CheckboxControlConstructor(gantt);\n\tvar RadioControl = RadioControlConstructor(gantt);\n\tvar DurationControl = DurationControlConstructor(gantt);\n\tvar ParentControl = ParentControlConstructor(gantt);\n\tvar ResourcesControl = ResourcesControlConstructor(gantt);\n\tvar ConstraintControl = ConstraintControlConstructor(gantt);\n\tvar TypeselectControl = TypeselectControlConstructor(gantt);\n\tvar BaselineControl = BaselineControlConstructor(gantt);\n\n\tgantt._lightbox_methods = {};\n\tgantt._lightbox_template = \"
 
\";\n\tgantt._lightbox_template = `
 \n
\n
\n\t\n\n
`;\n\n\t// GS-1952. Attaching the lightbox to the BODY element is not considered secure.\n\t// Attach it to Gantt container for Salesforce and other secure environments\n\tgantt._lightbox_root = gantt.$root;\n\tfunction setParentNode() {\n\t\tconst cspEnvironment = gantt.config.csp === true;\n\t\tconst salesforceEnvironment = !!window[\"Sfdc\"] || !!window[\"$A\"] || window[\"Aura\"] || ('$shadowResolver$' in document.body);\n\t\tif (cspEnvironment || salesforceEnvironment) {\n\t\t\tgantt._lightbox_root = gantt.$root;\n\t\t} else {\n\t\t\tgantt._lightbox_root = document.body;\n\t\t}\n\t}\n\n\t//TODO: gantt._lightbox_id is changed from data.js and accessed from autoscheduling, check if it can be removed from gantt object\n\tvar state = gantt.$services.getService(\"state\");\n\tstate.registerProvider(\"lightbox\", function () {\n\t\treturn {\n\t\t\tlightbox: gantt._lightbox_id\n\t\t};\n\t});\n\n\tgantt.showLightbox = function (id) {\n\t\tvar task = this.getTask(id);\n\t\tif (!this.callEvent(\"onBeforeLightbox\", [id])) {\n\t\t\tif(gantt.isTaskExists(id) && gantt.getTask(id).$new){\n\t\t\t\t//GS-2340 if 'onBeforeLightbox' returns 'false' need update the order in datastore\n\t\t\t\tthis.$data.tasksStore._updateOrder();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tvar box = this.getLightbox(this.getTaskType(task.type));\n\n\t\tthis.showCover(box);\n\t\tthis._fill_lightbox(id, box);\n\t\tthis._setLbPosition(box);\n\t\tthis._waiAria.lightboxVisibleAttr(box);\n\n\t\tthis.callEvent(\"onLightbox\", [id]);\n\t};\n\n\tfunction _is_chart_visible(gantt) {\n\t\tvar timeline = gantt.$ui.getView(\"timeline\");\n\t\tif (timeline && timeline.isVisible()) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tgantt._get_timepicker_step = function () {\n\t\tif (this.config.round_dnd_dates) {\n\t\t\tvar step;\n\t\t\tif (_is_chart_visible(this)) {\n\t\t\t\tvar scale = gantt.getScale();\n\t\t\t\tstep = (helpers.getSecondsInUnit(scale.unit) * scale.step) / 60;//timepicker step is measured in minutes\n\t\t\t}\n\n\t\t\tif (!step || step >= 60 * 24) {\n\t\t\t\tstep = this.config.time_step;\n\t\t\t}\n\t\t\treturn step;\n\t\t}\n\t\treturn this.config.time_step;\n\t};\n\tgantt.getLabel = function (property, key) {\n\t\tvar sections = this._get_typed_lightbox_config();\n\t\tfor (var i = 0; i < sections.length; i++) {\n\t\t\tif (sections[i].map_to == property) {\n\t\t\t\tvar options = sections[i].options;\n\t\t\t\tfor (var j = 0; j < options.length; j++) {\n\t\t\t\t\tif (options[j].key == key) {\n\t\t\t\t\t\treturn options[j].label;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn \"\";\n\t};\n\n\tgantt.updateCollection = function (list_name, collection) {\n\t\tcollection = collection.slice(0);\n\t\tvar list = gantt.serverList(list_name);\n\t\tif (!list) return false;\n\t\tlist.splice(0, list.length);\n\t\tlist.push.apply(list, collection || []);\n\t\tgantt.resetLightbox();\n\t};\n\tgantt.getLightboxType = function () {\n\t\treturn this.getTaskType(this._lightbox_type);\n\t};\n\tgantt.getLightbox = function (type) {\n\t\tvar lightboxDiv;\n\t\tvar fullWidth;\n\t\tvar html;\n\t\tvar sns;\n\t\tvar ds;\n\t\tvar classNames = \"\";\n\t\tsetParentNode();\n\n\t\tif (type === undefined)\n\t\t\ttype = this.getLightboxType();\n\n\t\tif (!this._lightbox || this.getLightboxType() != this.getTaskType(type)) {\n\t\t\tthis._lightbox_type = this.getTaskType(type);\n\t\t\tlightboxDiv = document.createElement(\"div\");\n\t\t\tclassNames = \"gantt_cal_light\";\n\t\t\tfullWidth = this._is_lightbox_timepicker();\n\n\t\t\tif (gantt.config.wide_form)\n\t\t\t\tclassNames += \" gantt_cal_light_wide\";\n\n\t\t\tif (fullWidth) {\n\t\t\t\tclassNames += \" gantt_cal_light_full\";\n\t\t\t}\n\n\t\t\tlightboxDiv.className = classNames;\n\n\t\t\tlightboxDiv.style.visibility = \"hidden\";\n\t\t\thtml = this._lightbox_template;\n\t\t\thtml += \"
\";\n\t\t\thtml += getHtmlButtons(this.config.buttons_left);\n\t\t\thtml += \"
\";\n\t\t\thtml += getHtmlButtons(this.config.buttons_right, true);\n\t\t\thtml += \"
\";\n\n\t\t\tlightboxDiv.innerHTML = html;\n\n\t\t\tgantt._waiAria.lightboxAttr(lightboxDiv);\n\n\t\t\tif (gantt.config.drag_lightbox) {\n\t\t\t\tlightboxDiv.firstChild.onmousedown = gantt._ready_to_dnd;\n\t\t\t\tlightboxDiv.firstChild.ontouchstart = function (e){\n\t\t\t\t\tgantt._ready_to_dnd(e.touches[0]);\n\t\t\t\t};\n\t\t\t\tlightboxDiv.firstChild.onselectstart = function () {\n\t\t\t\t\treturn false;\n\t\t\t\t};\n\t\t\t\tlightboxDiv.firstChild.style.cursor = \"pointer\";\n\t\t\t\tgantt._init_dnd_events();\n\t\t\t}\n\n\t\t\t// GS-1428: If there is lightbox node, we need to remove it from the DOM\n\t\t\tif (this._lightbox){\n\t\t\t\tthis.resetLightbox();\n\t\t\t}\n\t\t\tshow_cover();\n\t\t\tthis._cover.insertBefore(lightboxDiv, this._cover.firstChild);\n\t\t\tthis._lightbox = lightboxDiv;\n\n\t\t\tsns = this._get_typed_lightbox_config(type);\n\t\t\thtml = this._render_sections(sns);\n\n\t\t\tds = lightboxDiv.querySelector(\"div.gantt_cal_larea\");\n\t\t\t\n\t\t\t//GS-1131. If gantt_cal_larea is displayed, Firefox renders buttons incorrectly;\n\t\t\tvar backup_overflow = ds.style.overflow;\n\t\t\tds.style.overflow = 'hidden';\n\n\t\t\tds.innerHTML = html;\n\n\t\t\t\n\n\t\t\tbindLabelsToInputs(sns);\n\n\t\t\tds.style.overflow = backup_overflow;\n\n\t\t\tthis._init_lightbox_events(this);\n\t\t\tlightboxDiv.style.display = \"none\";\n\t\t\tlightboxDiv.style.visibility = \"visible\";\n\t\t}\n\t\treturn this._lightbox;\n\t};\n\n\tgantt._render_sections = function (sns) {\n\t\tvar html = \"\";\n\t\tfor (var i = 0; i < sns.length; i++) {\n\t\t\tvar block = this.form_blocks[sns[i].type];\n\t\t\tif (!block) continue; //ignore incorrect blocks\n\t\t\tsns[i].id = \"area_\" + this.uid();\n\n\t\t\tvar display = sns[i].hidden ? \" style='display:none'\" : \"\";\n\t\t\tvar button = \"\";\n\t\t\tif (sns[i].button) {\n\t\t\t\tbutton = \"
\" + this.locale.labels[\"button_\" + sns[i].button] + \"
\";\n\t\t\t}\n\t\t\tif (sns[i].type == \"baselines\") {\n\t\t\t\tbutton = \"
\" + this.locale.labels.baselines_remove_all_button + \"
\" +\n\t\t\t\t\"
\" + this.locale.labels.baselines_add_button + \"
\";\n\t\t\t}\n\t\t\tif (this.config.wide_form) {\n\t\t\t\thtml += \"
\";\n\t\t\t}\n\t\t\thtml += \"
\" + block.render.call(this, sns[i]);\n\t\t\thtml += \"
\";\n\t\t}\n\t\treturn html;\n\t};\n\n\tgantt._center_lightbox = function(box){\n\t\tgantt._setLbPosition(box);\n\t};\n\tgantt._setLbPosition = function(box) {\n\t\tif(!box){\n\t\t\treturn;\n\t\t}\n\t\tconst rootElement = gantt._lightbox_root || gantt.$root;\n\t\tbox.style.top = Math.max(rootElement.offsetHeight / 2 - box.offsetHeight/2, 0) + \"px\";\n\t\tbox.style.left = Math.max(rootElement.offsetWidth / 2 - box.offsetWidth/2, 0) + \"px\";\n\t};\n\n\tgantt.showCover = function (box) {\n\t\tif (box){\n\t\t\tbox.style.display=\"block\";\n\t\n\t\t\tthis._setLbPosition(box);\n\t\t}\n\t\tshow_cover();\n\t\tthis._cover.style.display = \"\";\n\t};\n\tconst show_cover=function(){\n\t\tif(gantt._cover) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tgantt._cover=document.createElement(\"div\");\n\t\tgantt._cover.className=\"gantt_cal_cover\";\n\t\tgantt._cover.style.display = \"none\";\n\t\n\t\tgantt.event(gantt._cover, \"mousemove\", gantt._move_while_dnd);\n\t\tgantt.event(gantt._cover, \"mouseup\", gantt._finish_dnd);\n\t\n\t\tconst rootElement = gantt._lightbox_root || gantt.$root;\n\t\trootElement.appendChild(gantt._cover);\n\t};\n\n\tgantt._init_lightbox_events = function () {\n\t\tgantt.lightbox_events = {};\n\n\n\t\tgantt.lightbox_events.gantt_save_btn = function () {\n\t\t\tgantt._save_lightbox();\n\t\t};\n\n\n\t\tgantt.lightbox_events.gantt_delete_btn = function () {\n\t\t\tgantt._lightbox_current_type = null;\n\t\t\tif (!gantt.callEvent(\"onLightboxDelete\", [gantt._lightbox_id]))\n\t\t\t\treturn;\n\n\t\t\tif (gantt.isTaskExists(gantt._lightbox_id)) {\n\t\t\t\tgantt.$click.buttons[\"delete\"](gantt._lightbox_id);\n\t\t\t} else {\n\t\t\t\tgantt.hideLightbox();\n\t\t\t}\n\n\t\t};\n\n\n\t\tgantt.lightbox_events.gantt_cancel_btn = function () {\n\t\t\tgantt._cancel_lightbox();\n\t\t};\n\n\n\t\tgantt.lightbox_events[\"default\"] = function (e, src) {\n\t\t\tif (src.getAttribute(\"data-dhx-button\")) {\n\t\t\t\tgantt.callEvent(\"onLightboxButton\", [src.className, src, e]);\n\t\t\t} else {\n\t\t\t\tvar index, block, sec;\n\n\t\t\t\tvar className = domHelpers.getClassName(src);\n\t\t\t\tif (className.indexOf(\"gantt_custom_button\") != -1) {\n\t\t\t\t\tif (className.indexOf(\"gantt_custom_button_\") != -1) {\n\t\t\t\t\t\tindex = src.parentNode.getAttribute(\"data-index\");\n\t\t\t\t\t\tsec = src;\n\t\t\t\t\t\twhile (sec && domHelpers.getClassName(sec).indexOf(\"gantt_cal_lsection\") == -1) {\n\t\t\t\t\t\t\tsec = sec.parentNode;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tindex = src.getAttribute(\"data-index\");\n\t\t\t\t\t\tsec = src.closest(\".gantt_cal_lsection\");\n\t\t\t\t\t\tsrc = src.firstChild;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar sections = gantt._get_typed_lightbox_config();\n\n\t\t\t\tif (index) {\n\t\t\t\t\tindex = index * 1;\n\t\t\t\t\tblock = gantt.form_blocks[sections[index * 1].type];\n\t\t\t\t\tblock.button_click(index, src, sec, sec.nextSibling);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tthis.event(gantt.getLightbox(), \"click\", function (e) {\n\t\t\tif(e.target.closest(\".gantt_cal_ltitle_close_btn\")){\n\t\t\t\tgantt._cancel_lightbox();\n\t\t\t}\n\t\t\tvar src = domHelpers.getTargetNode(e);\n\n\t\t\tvar className = domHelpers.getClassName(src);\n\t\t\tif (!className) {\n\t\t\t\tsrc = src.previousSibling;\n\t\t\t\tclassName = domHelpers.getClassName(src);\n\t\t\t}\n\t\t\tif (src && className && className.indexOf(\"gantt_btn_set\") === 0) {\n\t\t\t\tsrc = src.firstChild;\n\t\t\t\tclassName = domHelpers.getClassName(src);\n\t\t\t}\n\t\t\tif (src && className) {\n\t\t\t\tvar func = gantt.defined(gantt.lightbox_events[src.className]) ? gantt.lightbox_events[src.className] : gantt.lightbox_events[\"default\"];\n\t\t\t\treturn func(e, src);\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\tgantt.getLightbox().onkeydown = function (e) {\n\t\t\tvar event = e || window.event;\n\t\t\tvar target = e.target || e.srcElement;\n\t\t\tvar buttonTarget = domHelpers.getClassName(target).indexOf(\"gantt_btn_set\") > -1;\n\n\t\t\tswitch ((e || event).keyCode) {\n\t\t\t\tcase gantt.constants.KEY_CODES.SPACE: {\n\t\t\t\t\tif ((e || event).shiftKey) return;\n\t\t\t\t\tif (buttonTarget && target.click) {\n\t\t\t\t\t\ttarget.click();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase gantt.keys.edit_save:\n\t\t\t\t\tif ((e || event).shiftKey) return;\n\t\t\t\t\tif (buttonTarget && target.click) {\n\t\t\t\t\t\ttarget.click();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tgantt._save_lightbox();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase gantt.keys.edit_cancel:\n\t\t\t\t\tgantt._cancel_lightbox();\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t};\n\t};\n\n\tgantt._cancel_lightbox = function () {\n\t\tvar task = this.getLightboxValues();\n\t\tgantt._lightbox_current_type = null;\n\t\tthis.callEvent(\"onLightboxCancel\", [this._lightbox_id, task.$new]);\n\t\tif (gantt.isTaskExists(task.id) && task.$new) {\n\t\t\tthis.silent(function () {\n\t\t\t\tgantt.$data.tasksStore.removeItem(task.id);\n\t\t\t\tgantt._update_flags(task.id, null);\n\t\t\t});\n\t\t\tthis.refreshData();\n\t\t}\n\n\t\tthis.hideLightbox();\n\t};\n\n\tgantt._save_lightbox = function () {\n\t\tvar task = this.getLightboxValues();\n\t\tgantt._lightbox_current_type = null;\n\t\tif (!this.callEvent(\"onLightboxSave\", [this._lightbox_id, task, !!task.$new]))\n\t\t\treturn;\n\n\t\t// GS-2170. Do not recalculate the indexes and dates of other tasks\n\t\t// as they will be recalculated in the `refreshData`\n\t\tgantt.$data.tasksStore._skipTaskRecalculation = \"lightbox\";\n\t\tif (task.$new) {\n\t\t\tdelete task.$new;\n\t\t\tthis.addTask(task, task.parent, this.getTaskIndex(task.id));\n\t\t} else if (this.isTaskExists(task.id)) {\n\t\t\tthis.mixin(this.getTask(task.id), task, true);\n\t\t\tthis.refreshTask(task.id);\n\t\t\tthis.updateTask(task.id);\n\t\t}\n\t\tgantt.$data.tasksStore._skipTaskRecalculation = false;\n\t\tthis.refreshData();\n\n\t\t// TODO: do we need any blockable events here to prevent closing lightbox?\n\t\tthis.hideLightbox();\n\t};\n\n\tgantt._resolve_default_mapping = function (section) {\n\t\tvar mapping = section.map_to;\n\t\tvar time_controls = { \"time\": true, \"time_optional\": true, \"duration\": true, \"duration_optional\": true };\n\t\tif (time_controls[section.type]) {\n\t\t\tif (section.map_to == \"auto\") {\n\t\t\t\tmapping = { start_date: \"start_date\", end_date: \"end_date\", duration: \"duration\" };\n\t\t\t} else if (typeof (section.map_to) === \"string\") {\n\t\t\t\tmapping = { start_date: section.map_to };\n\t\t\t}\n\t\t} else if (section.type === \"constraint\") {\n\t\t\tif (!section.map_to || typeof (section.map_to) === \"string\") {\n\t\t\t\tmapping = { constraint_type: \"constraint_type\", constraint_date: \"constraint_date\" };\n\t\t\t}\n\t\t}\n\n\t\treturn mapping;\n\t};\n\n\tgantt.getLightboxValues = function () {\n\t\tvar task = {};\n\n\t\tif (gantt.isTaskExists(this._lightbox_id)) {\n\t\t\ttask = this.mixin({}, this.getTask(this._lightbox_id));\n\t\t}\n\n\t\tvar sns = this._get_typed_lightbox_config();\n\t\tfor (var i = 0; i < sns.length; i++) {\n\t\t\tvar node = gantt._lightbox_root.querySelector(\"#\" + sns[i].id);\n\t\t\tnode = (node ? node.nextSibling : node);\n\t\t\tvar block = this.form_blocks[sns[i].type];\n\t\t\tif (!block) continue;\n\t\t\tvar res = block.get_value.call(this, node, task, sns[i]);\n\t\t\tvar map_to = gantt._resolve_default_mapping(sns[i]);\n\t\t\tif (typeof map_to == \"string\" && map_to != \"auto\") {\n\t\t\t\ttask[map_to] = res;\n\t\t\t} else if (typeof map_to == \"object\") {\n\t\t\t\tfor (var property in map_to) {\n\t\t\t\t\tif (map_to[property])\n\t\t\t\t\t\ttask[map_to[property]] = res[property];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// GS-1282 We need to preserve the task type even if the lightbox doesn't have the typeselect section\n\t\t// GS-2460 set the current type from selector\n\t\tif (gantt._lightbox_current_type) {\n\t\t\ttask.type = gantt._lightbox_current_type;\n\t\t}\n\n\t\treturn task;\n\t};\n\n\n\tgantt.hideLightbox = function () {\n\t\tvar box = this.getLightbox();\n\t\tif (box) box.style.display = \"none\";\n\n\t\tthis._waiAria.lightboxHiddenAttr(box);\n\t\tthis._lightbox_id = null;\n\n\t\tthis.hideCover(box);\n\t\tthis.resetLightbox();\n\t\tthis.callEvent(\"onAfterLightbox\", []);\n\t};\n\tgantt.hideCover = function (box) {\n\t\tif(box){\n\t\t\tbox.style.display = \"none\";\n\t\t}\n\t\tif (this._cover)\n\t\t\tthis._cover.parentNode.removeChild(this._cover);\n\t\tthis._cover = null;\n\t};\n\n\tgantt.resetLightbox = function () {\n\t\tif (gantt._lightbox && !gantt._custom_lightbox)\n\t\t\tgantt._lightbox.remove();\n\t\tgantt._lightbox = null;\n\t};\n\tgantt._set_lightbox_values = function (data, box) {\n\t\tvar task = data;\n\t\tvar s = box.getElementsByTagName(\"span\");\n\t\tvar lightboxHeader = [];\n\t\tif (gantt.templates.lightbox_header) {\n\t\t\tlightboxHeader.push(\"\");\n\t\t\tlightboxHeader.push(gantt.templates.lightbox_header(task.start_date, task.end_date, task));\n\t\t\ts[1].innerHTML = \"\";\n\t\t\ts[2].innerHTML = gantt.templates.lightbox_header(task.start_date, task.end_date, task);\n\t\t} else {\n\t\t\tlightboxHeader.push(this.templates.task_time(task.start_date, task.end_date, task));\n\t\t\tlightboxHeader.push(String(this.templates.task_text(task.start_date, task.end_date, task) || \"\").substr(0, 70)); //IE6 fix\n\t\t\ts[1].innerHTML = this.templates.task_time(task.start_date, task.end_date, task);\n\t\t\ts[2].innerHTML = String(this.templates.task_text(task.start_date, task.end_date, task) || \"\").substr(0, 70); //IE6 fix\n\t\t}\n\t\ts[1].innerHTML = lightboxHeader[0];\n\t\ts[2].innerHTML = lightboxHeader[1];\n\n\t\tgantt._waiAria.lightboxHeader(box, lightboxHeader.join(\" \"));\n\n\t\tvar sns = this._get_typed_lightbox_config(this.getLightboxType());\n\t\tfor (var i = 0; i < sns.length; i++) {\n\t\t\tvar section = sns[i];\n\n\t\t\tif (!this.form_blocks[section.type]) {\n\t\t\t\tcontinue;//skip incorrect sections, same check is done during rendering\n\t\t\t}\n\n\n\t\t\tvar node = gantt._lightbox_root.querySelector(\"#\" + section.id).nextSibling;\n\t\t\tvar block = this.form_blocks[section.type];\n\t\t\tvar map_to = gantt._resolve_default_mapping(sns[i]);\n\t\t\tvar value = this.defined(task[map_to]) ? task[map_to] : section.default_value;\n\t\t\tblock.set_value.call(gantt, node, value, task, section);\n\n\t\t\tif (section.focus)\n\t\t\t\tblock.focus.call(gantt, node);\n\t\t}\n\t\tif (gantt.isTaskExists(data.id)){\n\t\t\tgantt._lightbox_id = data.id;\n\t\t}\n\t};\n\tgantt._fill_lightbox = function (id, box) {\n\t\tvar task = this.getTask(id);\n\t\tthis._set_lightbox_values(task, box);\n\t};\n\n\n\tgantt.getLightboxSection = function (name) {\n\t\tvar config = this._get_typed_lightbox_config();\n\t\tvar i = 0;\n\t\tfor (i; i < config.length; i++)\n\t\t\tif (config[i].name == name)\n\t\t\t\tbreak;\n\t\tvar section = config[i];\n\t\tif (!section)\n\t\t\treturn null;\n\n\t\tif (!this._lightbox)\n\t\t\tthis.getLightbox();\n\t\tvar header = gantt._lightbox_root.querySelector(\"#\" + section.id);\n\t\tvar node = header.nextSibling;\n\n\t\tvar result = {\n\t\t\tsection: section,\n\t\t\theader: header,\n\t\t\tnode: node,\n\t\t\tgetValue: function (ev) {\n\t\t\t\treturn gantt.form_blocks[section.type].get_value.call(gantt, node, (ev || {}), section);\n\t\t\t},\n\t\t\tsetValue: function (value, ev) {\n\t\t\t\treturn gantt.form_blocks[section.type].set_value.call(gantt, node, value, (ev || {}), section);\n\t\t\t}\n\t\t};\n\n\t\tvar handler = this._lightbox_methods[\"get_\" + section.type + \"_control\"];\n\t\treturn handler ? handler(result) : result;\n\t};\n\n\tgantt._lightbox_methods.get_template_control = function (result) {\n\t\tresult.control = result.node;\n\t\treturn result;\n\t};\n\tgantt._lightbox_methods.get_select_control = function (result) {\n\t\tresult.control = result.node.getElementsByTagName(\"select\")[0];\n\t\treturn result;\n\t};\n\tgantt._lightbox_methods.get_textarea_control = function (result) {\n\t\tresult.control = result.node.getElementsByTagName(\"textarea\")[0];\n\t\treturn result;\n\t};\n\tgantt._lightbox_methods.get_time_control = function (result) {\n\t\tresult.control = result.node.getElementsByTagName(\"select\"); // array\n\t\treturn result;\n\t};\n\n\n\tgantt._init_dnd_events = function () {\n\t\tvar eventElement = gantt._lightbox_root;\n\t\tthis.event(eventElement, \"mousemove\", gantt._move_while_dnd);\n\t\tthis.event(eventElement, \"mouseup\", gantt._finish_dnd);\n\t\tthis.event(eventElement, \"touchmove\", function (e){\n\t\t\tgantt._move_while_dnd(e.touches[0]);\n\t\t});\n\t\tthis.event(eventElement, \"touchend\", function (e){\n\t\t\tgantt._finish_dnd(e.touches[0]);\n\t\t});\n\t\t// GS-1952: In Salesforce environment, the lightbox is attached to the Gantt container. \n\t\t// So when Gantt is reinitialized, the events are no longer attached to the Gantt container.\n\t\t// gantt._init_dnd_events = function () {\n\t\t// };\n\t};\n\tgantt._move_while_dnd = function (event) {\n\t\tif (gantt._dnd_start_lb) {\n\t\t\tif (!document.gantt_unselectable) {\n\t\t\t\tgantt._lightbox_root.className += \" gantt_unselectable\";\n\t\t\t\tdocument.gantt_unselectable = true;\n\t\t\t}\n\t\t\tvar lb = gantt.getLightbox();\n\t\t\tvar now = [event.pageX, event.pageY];\n\t\t\tlb.style.top = gantt._lb_start[1] + now[1] - gantt._dnd_start_lb[1] + \"px\";\n\t\t\tlb.style.left = gantt._lb_start[0] + now[0] - gantt._dnd_start_lb[0] + \"px\";\n\t\t}\n\t};\n\tgantt._ready_to_dnd = function (event) {\n\t\tvar lb = gantt.getLightbox();\n\t\tgantt._lb_start = [lb.offsetLeft, lb.offsetTop];\n\t\tgantt._dnd_start_lb = [event.pageX, event.pageY];\n\t};\n\tgantt._finish_dnd = function () {\n\t\tif (gantt._lb_start) {\n\t\t\tgantt._lb_start = gantt._dnd_start_lb = false;\n\t\t\tgantt._lightbox_root.className = gantt._lightbox_root.className.replace(\" gantt_unselectable\", \"\");\n\t\t\tdocument.gantt_unselectable = false;\n\t\t}\n\t};\n\n\n\tgantt._focus = function (node, select) {\n\t\tif (node && node.focus) {\n\t\t\tif (gantt.config.touch) {\n\t\t\t\t//do not focus editor, to prevent auto-zoom\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tif (select && node.select) node.select();\n\t\t\t\t\tnode.focus();\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// silent errors\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\n\tgantt.form_blocks = {\n\t\tgetTimePicker: function (sns, hidden) {\n\t\t\tvar html = \"\";\n\t\t\tvar cfg = this.config;\n\t\t\tvar i;\n\t\t\tvar options;\n\t\t\tvar ariaAttrs;\n\t\t\tvar readonly;\n\t\t\tvar display;\n\t\t\tvar settings = {\n\t\t\t\tfirst: 0,\n\t\t\t\tlast: 24 * 60,\n\t\t\t\tdate: this.date.date_part(new Date(gantt._min_date.valueOf())),\n\t\t\t\ttimeFormat: getTimeFormat(sns)\n\t\t\t};\n\n\t\t\t// map: default order => real one\n\t\t\tsns._time_format_order = { size: 0 };\n\n\t\t\tif (gantt.config.limit_time_select) {\n\t\t\t\tsettings.first = 60 * cfg.first_hour;\n\t\t\t\tsettings.last = 60 * cfg.last_hour + 1;\n\t\t\t\tsettings.date.setHours(cfg.first_hour);\n\t\t\t}\n\n\t\t\tfor (i = 0; i < settings.timeFormat.length; i++) {\n\t\t\t\t// adding spaces between selects\n\t\t\t\tif (i > 0) {\n\t\t\t\t\thtml += \" \";\n\t\t\t\t}\n\n\t\t\t\toptions = getHtmlTimePickerOptions(sns, i, settings);\n\n\t\t\t\tif (options) {\n\t\t\t\t\tariaAttrs = gantt._waiAria.lightboxSelectAttrString(settings.timeFormat[i]);\n\t\t\t\t\treadonly = sns.readonly ? \"disabled='disabled'\" : \"\";\n\t\t\t\t\tdisplay = hidden ? \" style='display:none' \" : \"\";\n\t\t\t\t\thtml += \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn html;\n\t\t},\n\t\tgetTimePickerValue: function (selects, config, offset) {\n\t\t\tvar map = config._time_format_order;\n\t\t\tvar needSetTime = gantt.defined(map[3]);\n\n\t\t\tvar time;\n\t\t\tvar hours = 0;\n\t\t\tvar minutes = 0;\n\n\t\t\tvar mapOffset = offset || 0;\n\n\t\t\tif (needSetTime) {\n\t\t\t\ttime = parseInt(selects[map[3] + mapOffset].value, 10);\n\t\t\t\thours = Math.floor(time / 60);\n\t\t\t\tminutes = time % 60;\n\t\t\t}\n\t\t\treturn new Date(selects[map[2] + mapOffset].value, selects[map[1] + mapOffset].value, selects[map[0] + mapOffset].value, hours, minutes);\n\t\t},\n\n\t\t_fill_lightbox_select: function (s, i, d, map) {\n\t\t\ts[i + map[0]].value = d.getDate();\n\t\t\ts[i + map[1]].value = d.getMonth();\n\t\t\ts[i + map[2]].value = d.getFullYear();\n\t\t\tif (gantt.defined(map[3])) {\n\t\t\t\tvar v = d.getHours() * 60 + d.getMinutes();\n\t\t\t\tv = Math.round(v / gantt._get_timepicker_step()) * gantt._get_timepicker_step();\n\t\t\t\tvar input = s[i + map[3]];\n\t\t\t\tinput.value = v;\n\t\t\t\t//in case option not shown\n\t\t\t\tinput.setAttribute(\"data-value\", v);\n\t\t\t}\n\t\t},\n\t\ttemplate: new TemplateControl(),\n\t\ttextarea: new TextareaControl(),\n\t\tselect: new SelectControl(),\n\t\ttime: new TimeControl(),\n\t\tduration: new DurationControl(),\n\t\tparent: new ParentControl(),\n\t\tradio: new RadioControl(),\n\t\tcheckbox: new CheckboxControl(),\n\t\tresources: new ResourcesControl(),\n\t\tconstraint: new ConstraintControl(),\n\t\tbaselines: new BaselineControl(),\n\t\ttypeselect: new TypeselectControl()\n\t};\n\n\tgantt._is_lightbox_timepicker = function () {\n\t\tvar s = this._get_typed_lightbox_config();\n\t\tfor (var i = 0; i < s.length; i++)\n\t\t\tif (s[i].name == \"time\" && s[i].type == \"time\")\n\t\t\t\treturn true;\n\t\treturn false;\n\t};\n\n\tgantt._simple_confirm = function (message, title, callback, ok) {\n\t\tif (!message)\n\t\t\treturn callback();\n\t\tvar opts = { text: message };\n\t\tif (title)\n\t\t\topts.title = title;\n\t\tif (ok) {\n\t\t\topts.ok = ok;\n\t\t}\n\t\tif (callback) {\n\t\t\topts.callback = function (result) {\n\t\t\t\tif (result)\n\t\t\t\t\tcallback();\n\t\t\t};\n\t\t}\n\t\tgantt.confirm(opts);\n\t};\n\n\tfunction _get_type_name(type_value) {\n\t\tfor (var i in this.config.types) {\n\t\t\tif (this.config.types[i] == type_value) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn \"task\";\n\t}\n\n\tgantt._get_typed_lightbox_config = function (type) {\n\t\tif (type === undefined) {\n\t\t\ttype = this.getLightboxType();\n\t\t}\n\n\t\tvar field = _get_type_name.call(this, type);\n\n\t\tif (gantt.config.lightbox[field + \"_sections\"]) {\n\t\t\treturn gantt.config.lightbox[field + \"_sections\"];\n\t\t} else {\n\t\t\treturn gantt.config.lightbox.sections;\n\t\t}\n\t};\n\n\tgantt._silent_redraw_lightbox = function (type) {\n\t\tvar oldType = this.getLightboxType();\n\n\t\tif (this.getState().lightbox) {\n\t\t\tvar taskId = this.getState().lightbox;\n\t\t\tvar formData = this.getLightboxValues(),\n\t\t\t\ttask = this.copy(this.getTask(taskId));\n\n\t\t\tthis.resetLightbox();\n\n\t\t\tvar updTask = this.mixin(task, formData, true);\n\t\t\tvar box = this.getLightbox(type ? type : undefined);\n\t\t\tthis._set_lightbox_values(updTask, box);\n\t\t\tthis.showCover(box);\n\t\t} else {\n\t\t\tthis.resetLightbox();\n\t\t\tthis.getLightbox(type ? type : undefined);\n\t\t}\n\t\tthis.callEvent(\"onLightboxChange\", [oldType, this.getLightboxType()]);\n\t};\n\n\tfunction bindLabelsToInputs(sns) {\n\t\tvar section;\n\t\tvar label;\n\t\tvar labelBlock;\n\t\tvar inputBlock;\n\t\tvar input;\n\t\tvar i;\n\n\t\tfor (i = 0; i < sns.length; i++) {\n\t\t\tsection = sns[i];\n\t\t\tlabelBlock = gantt._lightbox_root.querySelector(\"#\" + section.id);\n\n\t\t\tif (!section.id || !labelBlock) continue;\n\n\t\t\tlabel = labelBlock.querySelector(\"label\");\n\t\t\tinputBlock = labelBlock.nextSibling;\n\n\t\t\tif (!inputBlock) continue;\n\n\t\t\tinput = inputBlock.querySelector(\"input, select, textarea\");\n\t\t\tif (input) {\n\t\t\t\tinput.id = input.id || \"input_\" + gantt.uid();\n\t\t\t\tsection.inputId = input.id;\n\t\t\t\tlabel.setAttribute(\"for\", section.inputId);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction getHtmlButtons(buttons, floatRight) {\n\t\tvar button;\n\t\tvar ariaAttr;\n\t\tvar html = \"\";\n\t\tvar i;\n\n\t\tfor (i = 0; i < buttons.length; i++) {\n\t\t\t// needed to migrate from 'dhx_something' to 'gantt_something' naming in a lightbox\n\t\t\tbutton = gantt.config._migrate_buttons[buttons[i]] ? gantt.config._migrate_buttons[buttons[i]] : buttons[i];\n\n\t\t\tariaAttr = gantt._waiAria.lightboxButtonAttrString(button);\n\t\t\thtml += \"
\" + gantt.locale.labels[button] + \"
\";\n\t\t}\n\t\treturn html;\n\t}\n\n\tfunction getTimeFormat(sns) {\n\t\tvar scale;\n\t\tvar unit;\n\t\tvar result;\n\n\t\tif (sns.time_format) return sns.time_format;\n\n\t\t// default order\n\t\tresult = [\"%d\", \"%m\", \"%Y\"];\n\t\tscale = gantt.getScale();\n\t\tunit = scale ? scale.unit : gantt.config.duration_unit;\n\t\tif (helpers.getSecondsInUnit(unit) < helpers.getSecondsInUnit(\"day\")) {\n\t\t\tresult.push(\"%H:%i\");\n\t\t}\n\t\treturn result;\n\t}\n\n\tfunction getHtmlTimePickerOptions(sns, index, settings) {\n\t\tvar range;\n\t\tvar offset;\n\t\tvar start_year;\n\t\tvar end_year;\n\t\tvar i;\n\t\tvar time;\n\t\tvar diff;\n\t\tvar tdate;\n\t\tvar html = \"\";\n\n\t\tswitch (settings.timeFormat[index]) {\n\t\t\tcase \"%Y\":\n\t\t\t\tsns._time_format_order[2] = index;\n\t\t\t\tsns._time_format_order.size++;\n\t\t\t\t//year\n\n\t\t\t\tif (sns.year_range) {\n\t\t\t\t\tif (!isNaN(sns.year_range)) {\n\t\t\t\t\t\trange = sns.year_range;\n\t\t\t\t\t} else if (sns.year_range.push) {\n\t\t\t\t\t\t// if\n\t\t\t\t\t\tstart_year = sns.year_range[0];\n\t\t\t\t\t\tend_year = sns.year_range[1];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trange = range || 10;\n\t\t\t\toffset = offset || Math.floor(range / 2);\n\t\t\t\tstart_year = start_year || settings.date.getFullYear() - offset;\n\t\t\t\tend_year = end_year || gantt.getState().max_date.getFullYear() + offset;\n\n\t\t\t\tfor (i = start_year; i < end_year; i++)\n\t\t\t\t\thtml += \"\";\n\t\t\t\tbreak;\n\t\t\tcase \"%m\":\n\t\t\t\tsns._time_format_order[1] = index;\n\t\t\t\tsns._time_format_order.size++;\n\t\t\t\t//month\n\t\t\t\tfor (i = 0; i < 12; i++)\n\t\t\t\t\thtml += \"\";\n\t\t\t\tbreak;\n\t\t\tcase \"%d\":\n\t\t\t\tsns._time_format_order[0] = index;\n\t\t\t\tsns._time_format_order.size++;\n\t\t\t\t//days\n\t\t\t\tfor (i = 1; i < 32; i++)\n\t\t\t\t\thtml += \"\";\n\t\t\t\tbreak;\n\t\t\tcase \"%H:%i\":\n\t\t\t\t// var last = 24*60, first = 0;\n\t\t\t\tsns._time_format_order[3] = index;\n\t\t\t\tsns._time_format_order.size++;\n\t\t\t\t//hours\n\t\t\t\ti = settings.first;\n\t\t\t\ttdate = settings.date.getDate();\n\t\t\t\tsns._time_values = [];\n\n\t\t\t\twhile (i < settings.last) {\n\t\t\t\t\ttime = gantt.templates.time_picker(settings.date);\n\t\t\t\t\thtml += \"\";\n\t\t\t\t\tsns._time_values.push(i);\n\t\t\t\t\tsettings.date.setTime(settings.date.valueOf() + gantt._get_timepicker_step() * 60 * 1000);\n\t\t\t\t\tdiff = (settings.date.getDate() != tdate) ? 1 : 0; // moved or not to the next day\n\t\t\t\t\ti = diff * 24 * 60 + settings.date.getHours() * 60 + settings.date.getMinutes();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn html;\n\t}\n};","import __extends from \"../../../../utils/extends\";\n\nimport Super from \"./base_control\";\n\nexport default function(gantt) {\n\tconst _super = Super(gantt);\n\n\tfunction TemplateControl() {\n\t\tvar self = _super.apply(this, arguments) || this; \n\t\treturn self; \n\t}\n\n\t__extends(TemplateControl, _super);\n\n\n\tTemplateControl.prototype.render = function(sns) {\n\t\tlet height = sns.height ? `${sns.height}px` : '';\n\t\treturn `
`;\n\t};\n\n\tTemplateControl.prototype.set_value = function(node, value) {\n\t\tnode.innerHTML = value || \"\";\n\t};\n\n\tTemplateControl.prototype.get_value = function(node) {\n\t\treturn node.innerHTML || \"\";\n\t};\n\n\tTemplateControl.prototype.focus = function() {};\n\n\treturn TemplateControl;\n};","import __extends from \"../../../../utils/extends\";\n\nimport Super from \"./base_control\";\n\nexport default function(gantt) {\n\tconst _super = Super(gantt);\n\n\tfunction TextareaControl() {\n\t\tvar self = _super.apply(this, arguments) || this;\n\n\t\treturn self; \n\t}\n\n\t__extends(TextareaControl, _super);\n\n\tTextareaControl.prototype.render = function(sns) {\n\t\tconst height = (sns.height || \"130\") + \"px\";\n\t\tconst placeholder = sns.placeholder ? `placeholder='${sns.placeholder}'` : \"\";\n\t\treturn `
`;\n\t};\n\n\tTextareaControl.prototype.set_value = function(node, value) {\n\t\tgantt.form_blocks.textarea._get_input(node).value = value || \"\";\n\t};\n\n\tTextareaControl.prototype.get_value = function(node) {\n\t\treturn gantt.form_blocks.textarea._get_input(node).value;\n\t};\n\n\tTextareaControl.prototype.focus = function(node) {\n\t\tvar a = gantt.form_blocks.textarea._get_input(node);\n\t\tgantt._focus(a, true);\n\t};\n\n\tTextareaControl.prototype._get_input = function(node) {\n\t\treturn node.querySelector(\"textarea\");\n\t};\n\n\treturn TextareaControl;\n};","import __extends from \"../../../../utils/extends\";\n\nimport Super from \"./base_control\";\n\nexport default function(gantt) {\n\tconst _super = Super(gantt);\n\n\tfunction TimeControl() {\n\t\tvar self = _super.apply(this, arguments) || this;\n\n\t\treturn self;\n\t}\n\n\t__extends(TimeControl, _super);\n\n\tTimeControl.prototype.render = function (sns) {\n\t\tvar time = gantt.form_blocks.getTimePicker.call(this, sns);\n\t\tlet sectionClassName = \"gantt_section_time\";\n\t\tif (sns.name !== \"time\"){\n\t\t\tsectionClassName += \" gantt_section_\" + sns.name;\n\t\t}\n\t\tvar html = \"
\";\n\t\thtml += time;\n\n\t\tif (sns.single_date) {\n\t\t\ttime = gantt.form_blocks.getTimePicker.call(this, sns, true);\n\t\t\thtml += \"\";\n\t\t} else {\n\t\t\thtml += \"  –  \";\n\t\t}\n\n\t\thtml += time;\n\t\thtml += \"
\";\n\t\treturn html;\n\t};\n\n\tTimeControl.prototype.set_value = function (node, value, ev, config) {\n\t\tvar cfg = config;\n\t\tvar s = node.getElementsByTagName(\"select\");\n\t\tvar map = config._time_format_order;\n\n\t\tif (cfg.auto_end_date) {\n\t\t\tvar _update_lightbox_select = function () {\n\t\t\t\tstart_date = new Date(s[map[2]].value, s[map[1]].value, s[map[0]].value, 0, 0);\n\t\t\t\tend_date = gantt.calculateEndDate({ start_date: start_date, duration: 1, task: ev });\n\t\t\t\tgantt.form_blocks._fill_lightbox_select(s, map.size, end_date, map, cfg);\n\t\t\t};\n\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\ts[i].onchange = _update_lightbox_select;\n\t\t\t}\n\t\t}\n\n\t\tvar mapping = gantt._resolve_default_mapping(config);\n\n\t\tif (typeof (mapping) === \"string\") mapping = { start_date: mapping };\n\n\t\tvar start_date = ev[mapping.start_date] || new Date();\n\t\tvar end_date = ev[mapping.end_date] || gantt.calculateEndDate({\n\t\t\tstart_date: start_date,\n\t\t\tduration: 1,\n\t\t\ttask: ev\n\t\t});\n\n\t\tgantt.form_blocks._fill_lightbox_select(s, 0, start_date, map, cfg);\n\t\tgantt.form_blocks._fill_lightbox_select(s, map.size, end_date, map, cfg);\n\t};\n\n\tTimeControl.prototype.get_value = function (node, ev, config) {\n\t\tvar selects = node.getElementsByTagName(\"select\");\n\t\tvar startDate;\n\t\tvar map = config._time_format_order;\n\t\tfunction _getEndDate(selects, map, startDate) {\n\t\t\tvar endDate = gantt.form_blocks.getTimePickerValue(selects, config, map.size);\n\t\t\t// GS-1010: We need to add a way to obtain exact end_date for validation\n\t\t\tif (endDate <= startDate) { // when end date seems wrong\n\t\t\t\tif (config.autofix_end !== false || config.single_date) { // auto correct it in two cases - when the auto correction is not disabled, or when we have 'single date' control and the user don't have the UI to specify the end date\n\t\t\t\t\treturn gantt.date.add(startDate, gantt._get_timepicker_step(), \"minute\");\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn endDate;\n\t\t}\n\n\t\tstartDate = gantt.form_blocks.getTimePickerValue(selects, config);\n\n\t\tif (typeof gantt._resolve_default_mapping(config) === \"string\") {\n\t\t\treturn startDate;\n\t\t}\n\n\t\treturn {\n\t\t\tstart_date: startDate,\n\t\t\tend_date: _getEndDate(selects, map, startDate)\n\t\t};\n\t};\n\n\tTimeControl.prototype.focus = function (node) {\n\t\tgantt._focus(node.getElementsByTagName(\"select\")[0]);\n\t};\n\n\treturn TimeControl;\n};","import * as helpers from \"../../../../utils/helpers\";\nimport __extends from \"../../../../utils/extends\";\nimport BaseConstrutor from \"./base_control\";\n\nexport default function(gantt) {\n\tvar _super = BaseConstrutor(gantt);\n\n\tfunction CheckboxControl() {\n\t\tvar self = _super.apply(this, arguments) || this;\n\n\t\treturn self; \n\t}\n\n\t__extends(CheckboxControl, _super);\n\n\tCheckboxControl.prototype.render = function(sns) {\n\t\tconst height = sns.height ? `height:${sns.height}px;` : '';\n\t\tlet html = `
`;\n\n\t\tif (sns.options && sns.options.length) {\n\t\t\tfor (var i = 0; i < sns.options.length; i++) {\n\t\t\t\thtml += \"\";\n\t\t\t}\n\t\t}else{\n\t\t\tsns.single_value = true;\n\t\t\thtml += \"\";\n\t\t}\n\t\thtml += \"
\";\n\t\treturn html;\n\t};\n\n\tCheckboxControl.prototype.set_value = function(node, value, ev, sns) {\n\t\tvar checkboxes = Array.prototype.slice.call(node.querySelectorAll(\"input[type=checkbox]\"));\n\n\t\tif (!node._dhx_onchange && sns.onchange) {\n\t\t\tnode.onchange = sns.onchange;\n\t\t\tnode._dhx_onchange = true;\n\t\t}\n\n\t\tif(sns.single_value){\n\t\t\tvar box = checkboxes[0];\n\t\t\tbox.checked = !!value;\n\t\t}else{\n\t\t\thelpers.forEach(checkboxes, function(entry) {\n\t\t\t\tentry.checked = value ? value.indexOf(entry.value) >= 0 : false;\n\t\t\t});\n\t\t}\n\t};\n\n\tCheckboxControl.prototype.get_value = function(node, task, sns) {\n\t\tif(sns.single_value){\n\t\t\tvar box = node.querySelector(\"input[type=checkbox]\");\n\t\t\treturn box.checked;\n\t\t}else{\n\t\t\treturn helpers.arrayMap(Array.prototype.slice.call(node.querySelectorAll(\"input[type=checkbox]:checked\")), function(entry) {\n\t\t\t\treturn entry.value;\n\t\t\t});\n\t\t}\n\t};\n\n\tCheckboxControl.prototype.focus = function(node) {\n\t\tgantt._focus(node.querySelector(\"input[type=checkbox]\"));\n\t};\n\n\treturn CheckboxControl;\n};","import __extends from \"../../../../utils/extends\";\nimport Super from \"./base_control\";\n\nexport default function(gantt) {\n\tconst _super = Super(gantt);\n\n\tfunction RadioControl() {\n\t\tvar self = _super.apply(this, arguments) || this;\n\n\t\treturn self; \n\t}\n\n\t__extends(RadioControl, _super);\n\n\tRadioControl.prototype.render = function(sns) {\n\t\tconst height = sns.height ? `${sns.height}px` : '';\n\t\tlet html = `
`;\n\n\t\tif (sns.options && sns.options.length) {\n\t\t\tfor (var i = 0; i < sns.options.length; i++) {\n\t\t\t\thtml += \"\";\n\t\t\t}\n\t\t}\n\n\t\thtml += \"
\";\n\t\treturn html;\n\t};\n\n\tRadioControl.prototype.set_value = function(node, value, ev, sns) {\n\t\tvar radio;\n\n\t\tif (!sns.options || !sns.options.length) return;\n\n\t\tradio = node.querySelector(\"input[type=radio][value='\" + value + \"']\") ||\n\t\t\t\tnode.querySelector(\"input[type=radio][value='\" + sns.default_value + \"']\");\n\n\t\tif (!radio) return;\n\n\t\tif (!node._dhx_onchange && sns.onchange) {\n\t\t\tnode.onchange = sns.onchange;\n\t\t\tnode._dhx_onchange = true;\n\t\t}\n\n\t\tradio.checked = true;\n\t};\n\n\tRadioControl.prototype.get_value = function(node, ev) {\n\t\tvar result = node.querySelector(\"input[type=radio]:checked\");\n\n\t\treturn result ? result.value : \"\";\n\t};\n\n\tRadioControl.prototype.focus = function(node) {\n\t\tgantt._focus(node.querySelector(\"input[type=radio]\"));\n\t};\n\n\treturn RadioControl;\n};","import __extends from \"../../../../utils/extends\";\n\nimport DurationFormatterNumeric from \"../../../common/duration_formatter_numeric\";\nimport BaseConstrutor from \"./base_control\";\n\nexport default function(gantt) {\n\tvar _super = BaseConstrutor(gantt);\n\n\tfunction DurationControl() {\n\t\tvar self = _super.apply(this, arguments) || this; \n\n\t\treturn self; \n\t}\n\n\tfunction getFormatter(config) {\n\t\treturn config.formatter || new DurationFormatterNumeric();\n\t}\n\n\t__extends(DurationControl, _super);\n\n\tDurationControl.prototype.render = function(sns) {\n\t\tvar time = \"
\" + gantt.form_blocks.getTimePicker.call(this, sns) + \"
\";\n\t\tvar label = \" \"+ gantt.locale.labels[gantt.config.duration_unit + \"s\"] +\" \";\n\t\tvar singleDate = sns.single_date ? \" style='display:none'\" : \"\";\n\t\tvar readonly = sns.readonly ? \" disabled='disabled'\" : \"\";\n\t\tvar ariaAttr = gantt._waiAria.lightboxDurationInputAttrString(sns);\n\n\t\tvar durationInputClass = \"gantt_duration_value\";\n\t\tif(sns.formatter) {\n\t\t\tlabel = \"\";\n\t\t\tdurationInputClass += \" gantt_duration_value_formatted\" ;\n\t\t}\n\n\t\tvar duration = \"
\" +\n\t\t\"
\" +\n\t\t\t\"\" +\n\t\t\t\"\" +\n\t\t\t\"\"+\n\t\t\t\"
\" +\n\t\t\t\"
\"+label+\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"\";\n\t\tlet sectionClassName = \"gantt_section_time gantt_section_duration\";\n\t\tif (sns.name !== \"time\"){\n\t\t\tsectionClassName += \" gantt_section_\" + sns.name;\n\t\t}\t\n\t\tvar html = \"
\" + time + \" \" + duration + \"
\";\n\t\treturn html;\n\t};\n\n\tDurationControl.prototype.set_value = function(node, value, ev, config) {\n\t\tvar s = node.getElementsByTagName(\"select\");\n\t\tvar inps = node.getElementsByTagName(\"input\");\n\t\tvar duration = inps[1];\n\t\tvar btns = [inps[0], inps[2]];\n\t\tvar endspan = node.getElementsByTagName(\"span\")[0];\n\t\tvar map = config._time_format_order;\n\t\tvar mapping;\n\t\tvar start_date;\n\t\tvar end_date;\n\t\tvar duration_val;\n\n\t\tfunction _calc_date() {\n\t\t\tvar start_date = _getStartDate.call(gantt, node, config);\n\t\t\tvar duration = _getDuration.call(gantt, node, config);\n\t\t\tvar end_date = gantt.calculateEndDate({start_date: start_date, duration: duration, task: ev});\n\n\t\t\tvar template = gantt.templates.task_end_date || gantt.templates.task_date;\n\t\t\tendspan.innerHTML = template(end_date);\n\t\t}\n\n\t\tfunction _change_duration(step) {\n\t\t\tvar value = duration.value;\n\n\t\t\tvalue = getFormatter(config).parse(value);\n\t\t\tif (window.isNaN(value))\n\t\t\t\tvalue = 0;\n\t\t\tvalue += step;\n\t\t\tif (value < 1) value = 1;\n\t\t\tduration.value = getFormatter(config).format(value);\n\t\t\t_calc_date();\n\t\t}\n\n\t\tbtns[0].onclick = gantt.bind(function() {\n\t\t\t_change_duration(-1 * gantt.config.duration_step);\n\t\t}, this);\n\t\tbtns[1].onclick = gantt.bind(function() {\n\t\t\t_change_duration(1 * gantt.config.duration_step);\n\t\t}, this);\n\t\ts[0].onchange = _calc_date;\n\t\ts[1].onchange = _calc_date;\n\t\ts[2].onchange = _calc_date;\n\t\tif (s[3]) s[3].onchange = _calc_date;\n\n\t\tduration.onkeydown = gantt.bind(function(e) {\n\t\t\tvar code; \n\n\t\t\te = e || window.event;\n\t\t\tcode = (e.charCode || e.keyCode || e.which);\n\t\t\t\n\t\t\tif (code == gantt.constants.KEY_CODES.DOWN) {\n\t\t\t\t_change_duration(-1 * gantt.config.duration_step);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (code == gantt.constants.KEY_CODES.UP) {\n\t\t\t\t_change_duration(1 * gantt.config.duration_step);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\twindow.setTimeout(_calc_date, 1);\n\t\t}, this);\n\n\t\tduration.onchange = gantt.bind(_calc_date, this);\n\n\t\tmapping = gantt._resolve_default_mapping(config);\n\t\tif (typeof(mapping) === \"string\") mapping = {start_date: mapping};\n\n\t\tstart_date = ev[mapping.start_date] || new Date();\n\t\tend_date = ev[mapping.end_date] || gantt.calculateEndDate({\n\t\t\tstart_date: start_date,\n\t\t\tduration: 1,\n\t\t\ttask: ev\n\t\t});\n\t\tduration_val = Math.round(ev[mapping.duration]) || gantt.calculateDuration({\n\t\t\tstart_date: start_date,\n\t\t\tend_date: end_date,\n\t\t\ttask: ev\n\t\t});\n\t\tduration_val = getFormatter(config).format(duration_val);\n\n\t\tgantt.form_blocks._fill_lightbox_select(s, 0, start_date, map, config);\n\t\tduration.value = duration_val;\n\t\t_calc_date();\n\t};\n\n\tDurationControl.prototype.get_value = function(node, ev, config) {\n\t\tvar startDate = _getStartDate(node, config);\n\t\tvar duration = _getDuration(node, config);\n\t\tvar endDate = gantt.calculateEndDate({start_date: startDate, duration: duration, task: ev});\n\n\t\tif (typeof gantt._resolve_default_mapping(config) == \"string\") {\n\t\t\treturn startDate;\n\t\t}\n\n\t\treturn {\n\t\t\tstart_date: startDate,\n\t\t\tend_date: endDate,\n\t\t\tduration: duration\n\t\t};\n\t};\n\n\tDurationControl.prototype.focus = function(node) {\n\t\tgantt._focus(node.getElementsByTagName(\"select\")[0]);\n\t};\n\n\n\tfunction _getStartDate(node, config) {\n\t\tvar s = node.getElementsByTagName(\"select\");\n\t\tvar map = config._time_format_order;\n\t\tvar hours = 0;\n\t\tvar minutes = 0;\n\n\t\tif (gantt.defined(map[3])) {\n\t\t\tvar input = s[map[3]];\n\t\t\tvar time = parseInt(input.value, 10);\n\t\t\tif (isNaN(time) && input.hasAttribute(\"data-value\")) {\n\t\t\t\ttime = parseInt(input.getAttribute(\"data-value\"), 10);\n\t\t\t}\n\n\t\t\thours = Math.floor(time / 60);\n\t\t\tminutes = time % 60;\n\t\t}\n\t\treturn new Date(s[map[2]].value, s[map[1]].value, s[map[0]].value, hours, minutes);\n\t}\n\n\tfunction _getDuration(node, config) {\n\t\tvar duration = node.getElementsByTagName(\"input\")[1];\n\n\t\tduration = getFormatter(config).parse(duration.value);\n\t\tif (!duration || window.isNaN(duration)) duration = 1;\n\t\tif (duration < 0) duration *= -1;\n\t\treturn duration;\n\t}\n\n\treturn DurationControl; \n};","import * as helpers from \"../../../../utils/helpers\";\nimport * as domHelpers from \"../../utils/dom_helpers\";\nimport htmlHelpers from \"../../utils/html_helpers\";\nimport __extends from \"../../../../utils/extends\";\n\nimport Super from \"./base_control\";\n\nexport default function(gantt) {\n\tconst _super = Super(gantt);\n\tvar localCache = {\n\t\tresources: {},\n\t\tresourcesValues: {},\n\t\tfilter: {},\n\t\teventsInitialized: {}\n\t};\n\n\tgantt.attachEvent(\"onAfterLightbox\", _clearCached);\n\n\tfunction ResourcesControl() {\n\t\tvar self = _super.apply(this, arguments) || this;\n\n\t\treturn self;\n\t}\n\n\t__extends(ResourcesControl, _super);\n\n\tResourcesControl.prototype.render = function(sns) {\n\t\tif(!sns.options){\n\t\t\tsns.options = gantt.serverList(\"resourceOptions\");\n\t\t}\n\t\t\n\t\tif(!sns.map_to || sns.map_to == \"auto\"){\n\t\t\tsns.map_to = gantt.config.resource_property;\n\t\t}\n\t\tvar html;\n\t\tvar resourceFilterPlaceholder = gantt.locale.labels.resources_filter_placeholder || sns.filter_placeholder || \"type to filter\";\n\t\tvar resourceFilterLabel = gantt.locale.labels.resources_filter_label || \"hide empty\";\n\t\t// if set fixed height for this element, then resize of lightbox will be calculated improperly\n\t\thtml = \"\";\n\t\thtml += \"
\";\n\t\thtml += \"
\";\n\t\thtml += \"\";\n\t\treturn html;\n\t};\n\n\tResourcesControl.prototype.set_value = function(node, value, ev, sns) {\n\t\tvar resourcesElement = _setResourcesElement(node, sns);\n\t\tvar htmlResourceRow = \"\";\n\t\tvar data;\n\n\t\t_setFilterCache(node, sns);\n\t\t_initEvents(node, ev, sns, this);\n\t\thelpers.forEach(sns.options, function(entry, index) {\n\t\t\tif (sns.unassigned_value == entry.key) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdata = _getDisplayValues(sns, value, entry);\n\n\t\t\thtmlResourceRow += [\n\t\t\t\t\"\"\n\t\t\t].join(\"\");\n\t\t});\n\t\tresourcesElement.innerHTML = htmlResourceRow;\n\t\t// weird element sizes in ie11 when display empty resource list, use zoom to force repaint\n\t\tresourcesElement.style.zoom = \"1\";\n\t\tresourcesElement._offsetSizes = resourcesElement.offsetHeight;\n\t\tresourcesElement.style.zoom = \"\";\n\n\t\tgantt._center_lightbox(gantt.getLightbox());\n\t};\n\n\tResourcesControl.prototype.get_value = function(node, ev, sns) {\n\n\t\tvar amountElement = _getResourcesElement(sns);\n\t\tvar result = [];\n\t\tvar selectorAdd = _getInputElementSelector(true);\n\t\tvar selectorSub = _getInputElementSelector(false);\n\t\tvar filterCache = _getFilterCache(sns);\n\t\tvar settedValuesHash = gantt.copy(localCache.resourcesValues[sns.id]) || {};\n\n\t\tvar itemsAdd = amountElement.querySelectorAll(selectorAdd);\n\t\tvar itemsSub = amountElement.querySelectorAll(selectorSub);\n\n\t\tfor (var i = 0; i < itemsSub.length; i++) {\n\t\t\tdelete settedValuesHash[itemsSub[i].getAttribute(\"data-item-id\")];\n\t\t}\n\n\t\tfor (var i = 0; i < itemsAdd.length; i++) {\n\t\t\tvar originalId = itemsAdd[i].getAttribute(\"data-assignment-id\");\n\t\t\tvar resourceId = itemsAdd[i].getAttribute(\"data-item-id\");\n\t\t\tvar amount = itemsAdd[i].value.trim();\n\n\t\t\tif (amount !== \"\" && amount !== \"0\") {\n\t\t\t\tdelete settedValuesHash[resourceId];\n\t\t\t\tresult[result.length] = { resource_id: resourceId, value: amount };\n\t\t\t\tif (originalId){\n\t\t\t\t\tresult[result.length - 1] = { ...result[result.length - 1], id: originalId };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (filterCache.filterApplied) {\n\t\t\tfor (var item in settedValuesHash) {\n\t\t\t\tresult[result.length] = { resource_id: item, value: settedValuesHash[item].value, id: settedValuesHash[item].id };\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t};\n\n\tResourcesControl.prototype.focus = function(node) {\n\t\tgantt._focus(node.querySelector(\".gantt_resources\"));\n\t};\n\n\tfunction _getAmountInput(item, value, disabled, assignmentId) {\n\t\tvar _attributes;\n\t\tvar innerHTML = \"\";\n\n\t\tif (!item) return;\n\n\t\t_attributes = [{ key: \"data-item-id\", value: item.key }, { key: \"data-assignment-id\", value: assignmentId || \"\"}, { key: \"class\", value: \"gantt_resource_amount_input\"}];\n\t\tif (disabled) {\n\t\t\t_attributes.push({ key: \"disabled\", value: \"disabled\" });\n\t\t}\n\n\t\tif (item.options) {\n\t\t\tinnerHTML += htmlHelpers.getHtmlSelect(item.options, _attributes, value);\n\t\t} else {\n\t\t\t_attributes[_attributes.length] = { key: \"value\", value: value || \"\" };\n\t\t\tinnerHTML += htmlHelpers.getHtmlInput(_attributes);\n\t\t}\n\t\treturn innerHTML;\n\t}\n\n\tfunction _getValue(el) {\n\t\treturn el.value.trim();\n\t}\n\n\tfunction _initEvents(node, ev, sns, context) {\n\t\tif (localCache.eventsInitialized[sns.id]) return;\n\n\t\tvar _applyFilter = function(e) {\n\t\t\t_saveValues(sns, node);\n\t\t\tvar resultSns;\n\t\t\tvar query;\n\t\t\tvar hideUnsetted;\n\t\t\tvar input;\n\t\t\tvar checkbox;\n\t\t\tvar filterCache = _getFilterCache(sns);\n\n\t\t\tcheckbox = filterCache.checkbox;\n\t\t\tinput = filterCache.input;\n\n\t\t\thideUnsetted = checkbox.checked;\n\t\t\tquery = _getValue(input);\n\t\t\tfilterCache.filterApplied = !!query;\n\t\t\tif (gantt.getState().lightbox) {\n\t\t\t\tev = gantt.getLightboxValues();\n\t\t\t}\n\t\t\tresultSns = _getSnsToHideUnsetted(sns, ev, query, hideUnsetted);\n\t\t\tvar value = ev[sns.map_to];\n\t\t\tcontext.form_blocks.resources.set_value(node, value, ev, resultSns);\n\t\t};\n\n\t\tfunction _resourceChangeListener(e) {\n\t\t\tvar target = e.target;\n\t\t\tvar parent;\n\t\t\tvar input;\n\n\t\t\tif (e.target.type === \"checkbox\") {\n\t\t\t\tparent = target.parentNode;\n\t\t\t\tinput = parent.querySelector(_getInputElementSelector());\n\t\t\t\tinput.disabled = !target.checked;\n\t\t\t\tvar itemId = input.getAttribute(\"data-item-id\");\n\t\t\t\tvar row = domHelpers.locateClassName(e, \"gantt_resource_row\");\n\t\t\t\tvar valueInput = row.querySelector(\".gantt_resource_amount_input\");\n\t\t\t\trow.setAttribute(\"data-checked\", target.checked);\n\t\t\t\tif (target.checked) {\n\t\t\t\t\tif (input.nodeName.toLowerCase() === \"select\") {\n\t\t\t\t\t\tgantt.callEvent(\"onResourcesSelectActivated\", [{ target: input }]);\n\t\t\t\t\t}\n\n\t\t\t\t\tvar resId = itemId;\n\t\t\t\t\tvar defaultValue = sns.default_value;\n\t\t\t\t\tsns.options.forEach(function(option){\n\t\t\t\t\t\tif(option.key == resId && option.default_value){\n\t\t\t\t\t\t\tdefaultValue = option.default_value;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tif(valueInput && !valueInput.value && defaultValue !== undefined){\n\t\t\t\t\t\tvalueInput.value = defaultValue;\n\t\t\t\t\t\t_saveValues(sns, this);\n\t\t\t\t\t}\n\n\t\t\t\t\tif(valueInput.select) {\n\t\t\t\t\t\tvalueInput.select();\n\t\t\t\t\t}else if(valueInput.focus){\n\t\t\t\t\t\tvalueInput.focus();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\n\t\t\t\t\tif (localCache.resourcesValues[sns.id]) {\n\t\t\t\t\t\tdelete localCache.resourcesValues[sns.id][itemId];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e.target.type === \"text\" || e.target.nodeName.toLowerCase() === \"select\") {\n\t\t\t\tparent = target.parentNode.parentNode;\n\n\t\t\t\tinput = e.target;\n\t\t\t\t_saveValues(sns, this);\n\t\t\t}\n\t\t}\n\t\t\n\n\t\tfunction _saveValues(sns, domElement) {\n\t\t\tvar selector = _getInputElementSelector();\n\t\t\tvar inputs = domElement.querySelectorAll(selector);\n\n\t\t\tlocalCache.resourcesValues[sns.id] = localCache.resourcesValues[sns.id] || {};\n\n\t\t\tfor (var i = 0; i < inputs.length; i++) {\n\t\t\t\tvar key = inputs[i].getAttribute(\"data-item-id\");\n\t\t\t\tvar originalAssignmentId = inputs[i].getAttribute(\"data-assignment-id\");\n\t\t\t\tif (!inputs[i].disabled) {\n\t\t\t\t\tlocalCache.resourcesValues[sns.id][key] = {value: inputs[i].value, id: originalAssignmentId};\n\t\t\t\t} else {\n\t\t\t\t\tdelete localCache.resourcesValues[sns.id][key];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t_applyFilter = helpers.throttle(_applyFilter, 100);\n\n\t\t_getFilterCache(sns).container.addEventListener(\"keyup\", _applyFilter);\n\t\t_getFilterCache(sns).container.addEventListener(\"input\", _applyFilter, true);\n\t\t_getFilterCache(sns).container.addEventListener(\"change\", _applyFilter, true);\n\t\t_getResourcesElement(sns).addEventListener(\"input\", _resourceChangeListener);\n\t\t_getResourcesElement(sns).addEventListener(\"change\", _resourceChangeListener);\n\t\tgantt.attachEvent(\"onResourcesSelectActivated\", gantt.bind(_resourceChangeListener, _getResourcesElement(sns)));\n\t\tlocalCache.eventsInitialized[sns.id] = true;\n\t}\n\n\tfunction _getSnsToHideUnsetted(controlConfig, task, query, hideUnsetted) {\n\t\tvar comparison;\n\t\tvar resultConfig;\n\n\t\tif (!hideUnsetted) {\n\t\t\tif (query === \"\") {// show all\n\t\t\t\treturn controlConfig;\n\t\t\t}\n\n\t\t\tcomparison = function(entry) {// show matching labels only\n\t\t\t\tif (entry.label.toLowerCase().indexOf(query.toLowerCase()) >= 0) {\n\t\t\t\t\treturn entry;\n\t\t\t\t}\n\t\t\t};\n\t\t} else {\n\t\t\tvar collection = task[controlConfig.map_to] || [];\n\n\t\t\tif (!helpers.isArray(collection)) {\n\t\t\t\tcollection = [collection];\n\t\t\t}\n\n\t\t\t// copy section array in order not to modify ev[sns.map_to]\n\t\t\tcollection = collection.slice();\n\n\t\t\tif (collection.length === 0) {//nothing setted\n\t\t\t\tcollection = [];\n\t\t\t\tresultConfig = gantt.copy(controlConfig);\n\t\t\t\tresultConfig.options = [];\n\t\t\t\tfor (var key in localCache.resourcesValues[controlConfig.id]) {\n\t\t\t\t\tvar cachedValue = localCache.resourcesValues[controlConfig.id][key];\n\t\t\t\t\tif (cachedValue.value !== \"\") {\n\t\t\t\t\t\tcollection.push({resource_id: key, value: cachedValue.value, id: cachedValue.id});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (collection.length === 0) {\n\t\t\t\t\treturn resultConfig;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (var key in localCache.resourcesValues[controlConfig.id]) {\n\t\t\t\t\tvar cachedValue = localCache.resourcesValues[controlConfig.id][key];\n\t\t\t\t\tif (cachedValue.value !== \"\") {\n\t\t\t\t\t\tvar searchResult = helpers.arrayFind(collection, function(entry) {\n\t\t\t\t\t\t\treturn entry.id == key;\n\t\t\t\t\t\t});\n\t\n\t\t\t\t\t\tif (!searchResult) {\n\t\t\t\t\t\t\tcollection.push({resource_id: key, value: cachedValue.value, id: cachedValue.id});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar itemIds = {};\n\n\t\t\tfor (var i=0; i < collection.length; i++) {\n\t\t\t\titemIds[collection[i].resource_id] = true;\n\t\t\t}\n\t\t\tcomparison = function(entry) {//show setted and filtered if field is filled\n\t\t\t\tif (itemIds[String(entry.key)] && (query === \"\" || entry.label.toLowerCase().indexOf(query.toLowerCase()) >= 0)) {\n\t\t\t\t\treturn entry;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\tresultConfig = gantt.copy(controlConfig);\n\t\tresultConfig.options = helpers.arrayFilter(resultConfig.options, comparison);\n\t\treturn resultConfig;\n\t}\n\n\tfunction _getInputElementSelector(isChecked) {\n\t\tif(isChecked === undefined){\n\t\t\treturn \".gantt_resource_amount_input\";\n\t\t}else{\n\t\t\treturn \"[data-checked='\"+(isChecked ? \"true\" : \"false\") + \"'] .gantt_resource_amount_input\";\n\t\t}\n\t}\n\n\tfunction _setResourcesElement(node, sns) {\n\t\tif (!localCache.resources[sns.id]) {\n\t\t\tlocalCache.resources[sns.id] = node.querySelector(\".gantt_resources\");\n\t\t}\n\t\treturn localCache.resources[sns.id];\n\t}\n\n\tfunction _getResourcesElement(sns) {\n\t\treturn localCache.resources[sns.id];\n\t}\n\n\tfunction _setFilterCache(node, sns) {\n\t\tif (!localCache.filter[sns.id]) {\n\t\t\tvar container = node.querySelector(\".gantt_resources_filter\");\n\t\t\tvar input = container.querySelector(\".gantt_resources_filter_input\");\n\t\t\tvar checkbox = container.querySelector(\".switch_unsetted\");\n\n\t\t\tlocalCache.filter[sns.id] = {\n\t\t\t\tcontainer: container,\n\t\t\t\tinput: input,\n\t\t\t\tcheckbox: checkbox,\n\t\t\t\tfilterApplied: false\n\t\t\t};\n\t\t}\n\t\treturn localCache.filter[sns.id];\n\t}\n\n\tfunction _getFilterCache(sns) {\n\t\treturn localCache.filter[sns.id];\n\t}\n\n\tfunction _clearCached() {\n\t\tfor (var key in localCache.filter) {\n\t\t\tlocalCache.filter[key].checkbox.checked = false;\n\t\t\tlocalCache.filter[key].input.value = \"\";\n\t\t\tlocalCache.filter[key].filterApplied = false;\n\t\t}\n\t\tlocalCache.resourcesValues = {};\n\t}\n\n\tfunction _getDisplayValues(sns, value, option) {\n\t\tvar data = {};\n\n\t\tif (value) {\n\t\t\tvar searchResult;\n\n\t\t\tif (helpers.isArray(value)) {\n\t\t\t\tsearchResult = helpers.arrayFind(value, function(val) {\n\t\t\t\t\treturn (val.resource_id == option.key);\n\t\t\t\t});\n\t\t\t} else if (value.resource_id == option.key) {\n\t\t\t\tsearchResult = value;\n\t\t\t}\n\n\t\t\tif (searchResult) {\n\t\t\t\tdata.value = searchResult.value;\n\t\t\t\tdata.id = searchResult.id;\n\t\t\t}\n\t\t}\n\t\tif (localCache.resourcesValues[sns.id] && localCache.resourcesValues[sns.id][option.key]) {\n\t\t\tdata.value = localCache.resourcesValues[sns.id][option.key].value;\n\t\t\tdata.id = localCache.resourcesValues[sns.id][option.key].id;\n\t\t}\n\t\treturn data;\n\t}\n\n\treturn ResourcesControl;\n};","import __extends from \"../../../../utils/extends\";\nimport htmlHelpers from \"../../utils/html_helpers\";\nimport BaseConstrutor from \"./base_control\";\n\nexport default function(gantt) {\n\tvar _super = BaseConstrutor(gantt);\n\n\tfunction ConstraintControl() {\n\t\tvar self = _super.apply(this, arguments) || this;\n\t\treturn self;\n\t}\n\n\t__extends(ConstraintControl, _super);\n\n\tfunction isNonTimedConstraint(value) {\n\t\tif (!value || value === gantt.config.constraint_types.ASAP || value === gantt.config.constraint_types.ALAP) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfunction toggleTimeSelect(timeSelects, typeValue) {\n\t\tvar isNonTimed = isNonTimedConstraint(typeValue);\n\t\tfor (var i = 0; i < timeSelects.length; i++) {\n\t\t\ttimeSelects[i].disabled = isNonTimed;\n\t\t}\n\t}\n\n\tConstraintControl.prototype.render = function (sns) {\n\t\tconst height = sns.height ? `height:${sns.height}px;` : '';\n\t\tlet html = `
`;\n\n\t\tvar options = [];\n\t\tfor (var i in gantt.config.constraint_types) {\n\t\t\toptions.push({ key: gantt.config.constraint_types[i], label: gantt.locale.labels[gantt.config.constraint_types[i]] });\n\t\t}\n\n\t\tsns.options = sns.options || options;\n\n\t\thtml += \"\" + htmlHelpers.getHtmlSelect(sns.options, [{ key: \"data-type\", value: \"constraint-type\" }]) + \"\";\n\n\t\tvar timeLabel = gantt.locale.labels[\"constraint_date\"] || \"Constraint date\";\n\t\thtml += \"\";\n\n\t\thtml += \"
\";\n\t\treturn html;\n\t};\n\n\tConstraintControl.prototype.set_value = function (node, value, task, config) {\n\t\tvar typeSelect = node.querySelector(\"[data-constraint-type-select] select\");\n\t\tvar timeSelects = node.querySelectorAll(\"[data-constraint-time-select] select\");\n\t\tvar map = config._time_format_order;\n\n\t\tvar mapping = gantt._resolve_default_mapping(config);\n\n\t\tif (!typeSelect._eventsInitialized) {\n\t\t\ttypeSelect.addEventListener(\"change\", function (e) {\n\t\t\t\ttoggleTimeSelect(timeSelects, e.target.value);\n\t\t\t});\n\t\t\ttypeSelect._eventsInitialized = true;\n\t\t}\n\n\t\tvar constraintDate = task[mapping.constraint_date] || new Date();\n\t\tgantt.form_blocks._fill_lightbox_select(timeSelects, 0, constraintDate, map, config);\n\n\t\tvar constraintType = task[mapping.constraint_type] || gantt.getConstraintType(task);\n\t\ttypeSelect.value = constraintType;\n\t\ttoggleTimeSelect(timeSelects, constraintType);\n\t};\n\n\tConstraintControl.prototype.get_value = function (node, task, config) {\n\t\tvar typeSelect = node.querySelector(\"[data-constraint-type-select] select\");\n\t\tvar timeSelects = node.querySelectorAll(\"[data-constraint-time-select] select\");\n\n\t\tvar constraintType = typeSelect.value;\n\t\tvar constraintDate = null;\n\t\tif (!isNonTimedConstraint(constraintType)) {\n\t\t\tconstraintDate = gantt.form_blocks.getTimePickerValue(timeSelects, config);\n\t\t}\n\n\t\treturn {\n\t\t\tconstraint_type: constraintType,\n\t\t\tconstraint_date: constraintDate\n\t\t};\n\t};\n\n\tConstraintControl.prototype.focus = function (node) {\n\t\tgantt._focus(node.querySelector(\"select\"));\n\t};\n\n\treturn ConstraintControl;\n};","import __extends from \"../../../../utils/extends\";\n\nimport Super from \"./select_control\";\n\nexport default function(gantt) {\n\tconst _super = Super(gantt);\n\n\tfunction TypeselectControl() {\n\t\tvar self = _super.apply(this, arguments) || this;\n\n\t\treturn self;\n\t}\n\n\t__extends(TypeselectControl, _super);\n\n\tTypeselectControl.prototype.render = function(sns) {\n\t\tvar types = gantt.config.types,\n\t\t\tlocale = gantt.locale.labels,\n\t\t\toptions = [];\n\n\t\tvar filter = sns.filter || function (typeKey, typeValue) {\n\t\t\tif (!types.placeholder || typeValue !== types.placeholder) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\t\tfor (var i in types) {\n\t\t\tif (!filter(i, types[i]) === false) {\n\t\t\t\toptions.push({ key: types[i], label: locale[\"type_\" + i] });\n\t\t\t}\n\t\t}\n\t\tsns.options = options;\n\n\t\tvar oldOnChange = sns.onchange;\n\t\tsns.onchange = function () {\n\t\t\tgantt._lightbox_current_type = this.value;\n\t\t\tgantt.changeLightboxType(this.value);\n\t\t\tif (typeof oldOnChange == 'function') {\n\t\t\t\toldOnChange.apply(this, arguments);\n\t\t\t}\n\t\t};\n\n\t\treturn _super.prototype.render.apply(this, arguments);\n\t};\n\n\treturn TypeselectControl;\n};\n","\nimport __extends from \"../../../../utils/extends\";\nimport DurationFormatterNumeric from \"../../../common/duration_formatter_numeric\";\nimport BaseConstrutor from \"./base_control\";\n\nexport default function(gantt) {\n\tvar _super = BaseConstrutor(gantt);\n\n\tfunction DurationControl() {\n\t\tvar self = _super.apply(this, arguments) || this; \n\n\t\treturn self; \n\t}\n\n\tfunction getFormatter(config) {\n\t\treturn config.formatter || new DurationFormatterNumeric();\n\t}\n\n\tfunction _generateBaselineRow (node, baseline, task, config){\n\t\tconst time = \"
\" + gantt.form_blocks.getTimePicker.call(gantt, config) + \"
\";\n\t\tlet durationLabel = \" \"+ gantt.locale.labels[gantt.config.duration_unit + \"s\"] +\" \";\n\t\tconst singleDate = config.single_date ? \" style='display:none'\" : \"\";\n\t\tconst readonly = config.readonly ? \" disabled='disabled'\" : \"\";\n\t\tconst ariaAttr = gantt._waiAria.lightboxDurationInputAttrString(config);\n\t\tconst deleteLabel = gantt.locale.labels.baselines_remove_button;\n\n\t\tlet durationInputClass = \"gantt_duration_value\";\n\t\tif(config.formatter) {\n\t\t\tdurationLabel = \"\";\n\t\t\tdurationInputClass += \" gantt_duration_value_formatted\";\n\t\t}\n\n\t\tconst durationEl = \"
\" +\n\t\t\"
\" +\n\t\t\t\"\" +\n\t\t\t\"\" +\n\t\t\t\"\"+\n\t\t\t\"
\" +\n\t\t\t\"
\"+durationLabel+\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"\";\n\n\t\tconst deleteButton = `
${deleteLabel}
`;\n\n\t\tconst baselineRow = document.createElement(\"div\");\n\t\tbaselineRow.className = \"gantt_section_time gantt_section_duration\";\n\t\tbaselineRow.setAttribute(\"data-baseline-id\", baseline.id);\n\t\tbaselineRow.innerHTML = time + durationEl + deleteButton + \"
\";\n\t\tnode.appendChild(baselineRow);\n\n\t\tvar s = baselineRow.getElementsByTagName(\"select\");\n\t\tvar inps = baselineRow.getElementsByTagName(\"input\");\n\t\tvar duration = inps[1];\n\t\tvar btns = [inps[0], inps[2]];\n\t\tvar endspan = baselineRow.getElementsByTagName(\"span\")[0];\n\t\tvar map = config._time_format_order;\n\t\tvar mapping;\n\t\tvar start_date;\n\t\tvar end_date;\n\t\tvar duration_val;\n\n\t\tconst deleteEl = baselineRow.querySelector(\".baseline_delete_button\");\n\t\tdeleteEl.onclick = function(e){\n\t\t\tconst section = baselineRow.parentNode;\n\t\t\tbaselineRow.innerHTML = \"\";\n\t\t\tbaselineRow.remove();\n\t\t\tif (section.innerHTML === \"\"){\n\t\t\t\tsection.innerHTML = gantt.locale.labels.baselines_section_placeholder;\n\t\t\t}\n\t\t};\n\t\t\n\n\t\tfunction _calc_date() {\n\t\t\tvar start_date = _getStartDate.call(gantt, baselineRow, config);\n\t\t\tvar duration = _getDuration.call(gantt, baselineRow, config);\n\t\t\tvar end_date = gantt.calculateEndDate({start_date: start_date, duration: duration, task: task});\n\n\t\t\tvar template = gantt.templates.task_end_date || gantt.templates.task_date;\n\t\t\tendspan.innerHTML = template(end_date);\n\t\t}\n\n\t\tfunction _change_duration(step) {\n\t\t\tvar value = duration.value;\n\n\t\t\tvalue = getFormatter(config).parse(value);\n\t\t\tif (window.isNaN(value))\n\t\t\t\tvalue = 0;\n\t\t\tvalue += step;\n\t\t\tif (value < 1) value = 1;\n\t\t\tduration.value = getFormatter(config).format(value);\n\t\t\t_calc_date();\n\t\t}\n\n\t\tbtns[0].onclick = gantt.bind(function() {\n\t\t\t_change_duration(-1 * gantt.config.duration_step);\n\t\t}, gantt);\n\t\tbtns[1].onclick = gantt.bind(function() {\n\t\t\t_change_duration(1 * gantt.config.duration_step);\n\t\t}, gantt);\n\t\ts[0].onchange = _calc_date;\n\t\ts[1].onchange = _calc_date;\n\t\ts[2].onchange = _calc_date;\n\t\tif (s[3]) s[3].onchange = _calc_date;\n\n\t\tduration.onkeydown = gantt.bind(function(e) {\n\t\t\tvar code; \n\n\t\t\te = e || window.event;\n\t\t\tcode = (e.charCode || e.keyCode || e.which);\n\t\t\t\n\t\t\tif (code == gantt.constants.KEY_CODES.DOWN) {\n\t\t\t\t_change_duration(-1 * gantt.config.duration_step);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (code == gantt.constants.KEY_CODES.UP) {\n\t\t\t\t_change_duration(1 * gantt.config.duration_step);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\twindow.setTimeout(_calc_date, 1);\n\t\t}, gantt);\n\n\t\tduration.onchange = gantt.bind(_calc_date, gantt);\n\n\t\tmapping = gantt._resolve_default_mapping(config);\n\t\tif (typeof(mapping) === \"string\") mapping = {start_date: mapping};\n\n\t\tstart_date = baseline.start_date || new Date();\n\t\tend_date = baseline.end_date || gantt.calculateEndDate({\n\t\t\tstart_date: start_date,\n\t\t\tduration: 1,\n\t\t\ttask\n\t\t});\n\t\tduration_val = gantt.calculateDuration({\n\t\t\tstart_date: start_date,\n\t\t\tend_date: end_date,\n\t\t\ttask\n\t\t});\n\t\tduration_val = getFormatter(config).format(duration_val);\n\n\t\tgantt.form_blocks._fill_lightbox_select(s, 0, start_date, map, config);\n\t\tduration.value = duration_val;\n\t\t_calc_date();\n\t}\n\n\t__extends(DurationControl, _super);\n\n\tDurationControl.prototype.render = function(sns) {\n\t\tconst baselineSection = `
`;\n\t\treturn baselineSection;\n\t};\n\n\tDurationControl.prototype.set_value = function(node, value, task, config) {\n\t\tif (task.baselines){\n\t\t\tnode.innerHTML = \"\";\n\n\t\t\ttask.baselines.forEach((baseline)=>{\n\t\t\t\t_generateBaselineRow(node, baseline, task, config);\n\t\t\t});\n\t\t} else {\n\t\t\tnode.innerHTML = gantt.locale.labels.baselines_section_placeholder;\n\t\t}\t\t\n\n\t};\n\n\tDurationControl.prototype.get_value = function(node, task, config) {\n\t\tconst baselines = [];\n\t\tconst baselineRows = node.querySelectorAll(`[data-baseline-id]`);\n\t\tbaselineRows.forEach((baselineNode)=>{\n\t\t\tconst baselineId = baselineNode.dataset.baselineId;\n\t\t\tconst baselineStore = gantt.getDatastore(\"baselines\");\n\t\t\tlet baseline = baselineStore.getItem(baselineId);\n\t\t\tlet updatedBaseline;\n\t\t\tif (baseline){\n\t\t\t\tupdatedBaseline = gantt.copy(baseline);\n\t\t\t} else {\n\t\t\t\tupdatedBaseline = {\n\t\t\t\t\tid: gantt.uid(),\n\t\t\t\t\ttask_id: task.id,\n\t\t\t\t\ttext: \"Baseline 1\"\n\t\t\t\t};\n\t\t\t}\n\t\t\tupdatedBaseline.start_date = _getStartDate(baselineNode, config);\n\t\t\tupdatedBaseline.duration = _getDuration(baselineNode, config);\n\t\t\tupdatedBaseline.end_date = gantt.calculateEndDate({start_date: updatedBaseline.start_date, duration: updatedBaseline.duration, task});\n\n\t\t\tbaselines.push(updatedBaseline);\n\t\t});\n\n\t\treturn baselines;\n\t};\n\n\tDurationControl.prototype.button_click = function (index, el, section, container) {\n\t\tif (gantt.callEvent(\"onSectionButton\", [gantt._lightbox_id, section]) === false) {\n\t\t\treturn;\n\t\t}\n\t\tif (el.closest(\".gantt_custom_button.gantt_remove_baselines\")){\n\t\t\tcontainer.innerHTML = gantt.locale.labels.baselines_section_placeholder;\n\t\t}\n\t\tif (el.closest(\".gantt_custom_button.gantt_add_baselines\")){\n\t\t\tif (container.innerHTML == gantt.locale.labels.baselines_section_placeholder){\n\t\t\t\tcontainer.innerHTML = \"\";\n\t\t\t}\n\t\t\tconst task = gantt.getTask(gantt._lightbox_id);\n\t\t\tconst baseline = {\n\t\t\t\tid: gantt.uid(),\n\t\t\t\ttask_id: task.id,\n\t\t\t\ttext: \"Baseline 1\",\n\t\t\t\tstart_date: task.start_date,\n\t\t\t\tend_date: task.end_date\n\t\t\t};\n\t\t\tconst config = gantt._get_typed_lightbox_config()[index];\n\t\t\t_generateBaselineRow(container, baseline, task, config);\n\t\t}\n\t};\n\n\tDurationControl.prototype.focus = function(node) {\n\t\tgantt._focus(node.getElementsByTagName(\"select\")[0]);\n\t};\n\n\n\tfunction _getStartDate(node, config) {\n\t\tvar s = node.getElementsByTagName(\"select\");\n\t\tvar map = config._time_format_order;\n\t\tvar hours = 0;\n\t\tvar minutes = 0;\n\n\t\tif (gantt.defined(map[3])) {\n\t\t\tvar input = s[map[3]];\n\t\t\tvar time = parseInt(input.value, 10);\n\t\t\tif (isNaN(time) && input.hasAttribute(\"data-value\")) {\n\t\t\t\ttime = parseInt(input.getAttribute(\"data-value\"), 10);\n\t\t\t}\n\n\t\t\thours = Math.floor(time / 60);\n\t\t\tminutes = time % 60;\n\t\t}\n\t\treturn new Date(s[map[2]].value, s[map[1]].value, s[map[0]].value, hours, minutes);\n\t}\n\n\tfunction _getDuration(node, config) {\n\t\tvar duration = node.getElementsByTagName(\"input\")[1];\n\n\t\tduration = getFormatter(config).parse(duration.value);\n\t\tif (!duration || window.isNaN(duration)) duration = 1;\n\t\tif (duration < 0) duration *= -1;\n\t\treturn duration;\n\t}\n\n\treturn DurationControl; \n};","export default function(gantt) {\n\n\tgantt._extend_to_optional = function (lightbox_block) {\n\n\t\tvar duration = lightbox_block;\n\t\tvar optional_time = {\n\t\t\trender: duration.render,\n\t\t\tfocus: duration.focus,\n\t\t\tset_value: function (node, value, task, section) {\n\t\t\t\tvar mapping = gantt._resolve_default_mapping(section);\n\t\t\t\tif (!task[mapping.start_date] || (mapping.start_date == \"start_date\" && this._isAllowedUnscheduledTask(task))) {\n\t\t\t\t\toptional_time.disable(node, section);\n\t\t\t\t\tvar val = {};\n\n\t\t\t\t\tfor (var i in mapping) {\n\t\t\t\t\t\t//take default values from the time control from task start/end dates\n\t\t\t\t\t\tval[mapping[i]] = task[i];\n\t\t\t\t\t}\n\n\t\t\t\t\treturn duration.set_value.call(gantt, node, value, val, section);//set default value\n\t\t\t\t} else {\n\t\t\t\t\toptional_time.enable(node, section);\n\t\t\t\t\treturn duration.set_value.call(gantt, node, value, task, section);\n\t\t\t\t}\n\t\t\t},\n\t\t\tget_value: function (node, task, section) {\n\t\t\t\tif (section.disabled) {\n\t\t\t\t\treturn {start_date: null};\n\t\t\t\t} else {\n\t\t\t\t\treturn duration.get_value.call(gantt, node, task, section);\n\t\t\t\t}\n\t\t\t},\n\t\t\tupdate_block: function (node, section) {\n\t\t\t\tgantt.callEvent(\"onSectionToggle\", [gantt._lightbox_id, section]);\n\t\t\t\tnode.style.display = section.disabled ? \"none\" : \"\";\n\n\t\t\t\tif (section.button) {\n\t\t\t\t\tvar button = node.previousSibling.querySelector(\".gantt_custom_button_label\"),\n\t\t\t\t\t\tlabels = gantt.locale.labels;\n\n\t\t\t\t\tvar button_text = section.disabled ? labels[section.name + \"_enable_button\"] : labels[section.name + \"_disable_button\"];\n\n\t\t\t\t\tbutton.innerHTML = button_text;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdisable: function (node, section) {\n\t\t\t\tsection.disabled = true;\n\t\t\t\toptional_time.update_block(node, section);\n\n\t\t\t},\n\t\t\tenable: function (node, section) {\n\t\t\t\tsection.disabled = false;\n\t\t\t\toptional_time.update_block(node, section);\n\t\t\t},\n\t\t\tbutton_click: function (index, el, section, container) {\n\t\t\t\tif (gantt.callEvent(\"onSectionButton\", [gantt._lightbox_id, section]) === false) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tvar config = gantt._get_typed_lightbox_config()[index];\n\t\t\t\tif (config.disabled) {\n\t\t\t\t\toptional_time.enable(container, config);\n\t\t\t\t} else {\n\t\t\t\t\toptional_time.disable(container, config);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\treturn optional_time;\n\t};\n\n\tgantt.form_blocks.duration_optional = gantt._extend_to_optional(gantt.form_blocks.duration);\n\tgantt.form_blocks.time_optional = gantt._extend_to_optional(gantt.form_blocks.time);\n\n};","export default function(gantt){\n\tvar htmlTags = new RegExp(\"<(?:.|\\n)*?>\", \"gm\");\n\tvar extraSpaces = new RegExp(\" +\", \"gm\");\n\n\tfunction stripHTMLLite(htmlText){\n\t\treturn (htmlText + \"\")\n\t\t\t.replace(htmlTags, \" \").\n\t\t\treplace(extraSpaces, \" \");\n\t}\n\n\tvar singleQuotes = new RegExp(\"'\", \"gm\");\n\tfunction escapeQuotes(text){\n\t\treturn (text + \"\").replace(singleQuotes, \"'\");\n\t}\n\n\tgantt._waiAria = {\n\t\tgetAttributeString: function(attr){\n\t\t\tvar attributes = [\" \"];\n\t\t\tfor(var i in attr){\n\t\t\t\tvar text = escapeQuotes(stripHTMLLite(attr[i]));\n\t\t\t\tattributes.push(i + \"='\" + text + \"'\");\n\t\t\t}\n\t\t\tattributes.push(\" \");\n\t\t\treturn attributes.join(\" \");\n\n\t\t},\n\n\t\tgetTimelineCellAttr:function(dateString){\n\n\t\t\treturn gantt._waiAria.getAttributeString({\"aria-label\": dateString});\n\t\t},\n\n\t\t_taskCommonAttr: function(task, div){\n\n\t\t\tif(!(task.start_date && task.end_date))\n\t\t\t\treturn;\n\n\t\t\tdiv.setAttribute(\"aria-label\", stripHTMLLite(gantt.templates.tooltip_text(task.start_date, task.end_date, task)));\n\n\t\t\tif(task.$dataprocessor_class){\n\t\t\t\tdiv.setAttribute(\"aria-busy\", true);\n\t\t\t}\n\n\t\t},\n\n\t\tsetTaskBarAttr: function(task, div){\n\t\t\tthis._taskCommonAttr(task, div);\n\n\t\t\t// task bars are complex elements that should be treated as a single element\n\t\t\tdiv.setAttribute(\"role\", \"img\");\n\n\t\t\tif(!gantt.isReadonly(task) && gantt.config.drag_move){\n\t\t\t\tif(task.id != gantt.getState(\"tasksDnd\").drag_id){\n\t\t\t\t\tdiv.setAttribute(\"aria-grabbed\", false);\n\t\t\t\t}else{\n\t\t\t\t\tdiv.setAttribute(\"aria-grabbed\", true);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\ttaskRowAttr: function(task, div){\n\n\t\t\tthis._taskCommonAttr(task, div);\n\n\t\t\tif(!gantt.isReadonly(task) && gantt.config.order_branch){\n\t\t\t\tdiv.setAttribute(\"aria-grabbed\", false);\n\t\t\t}\n\n\t\t\tdiv.setAttribute(\"role\", \"row\");\n\t\t\t// selected attribute should be added only to the grid because\n\t\t\t// other parts don't have the keyboard navigation\n\t\t\tdiv.setAttribute(\"aria-selected\", gantt.isSelectedTask(task.id) ? \"true\" : \"false\");\n\n\t\t\t// allowed values start from 1, set 1 for non-tree datastores\n\t\t\tdiv.setAttribute(\"aria-level\", task.$level + 1 || 1);\n\n\t\t\tif(gantt.hasChild(task.id)){\n\t\t\t\tdiv.setAttribute(\"aria-expanded\", task.$open ? \"true\" : \"false\");\n\t\t\t}\n\t\t},\n\n\t\tlinkAttr: function(link, div){\n\n\t\t\tvar linkTypes = gantt.config.links;\n\n\t\t\tvar toStart = link.type == linkTypes.finish_to_start || link.type == linkTypes.start_to_start;\n\t\t\tvar fromStart = link.type == linkTypes.start_to_start || link.type == linkTypes.start_to_finish;\n\n\t\t\tvar content = gantt.locale.labels.link + \" \" + gantt.templates.drag_link(link.source, fromStart, link.target, toStart);\n\n\t\t\t// links are complex elements that should be treated as a single element\n\t\t\tdiv.setAttribute(\"role\", \"img\");\n\n\t\t\tdiv.setAttribute(\"aria-label\", stripHTMLLite(content));\n\t\t\tif(gantt.isReadonly(link)){\n\t\t\t\tdiv.setAttribute(\"aria-readonly\", true);\n\t\t\t}\n\t\t},\n\n\t\tgridSeparatorAttr: function(div){\n\t\t\t// the only valid role for the grid header\n\t\t\tdiv.setAttribute(\"role\", \"columnheader\");\n\t\t},\n\t\trowResizerAttr: function(div){\n\t\t\t// the only valid role for the grid header\n\t\t\tdiv.setAttribute(\"role\", \"row\");\n\t\t},\n\n\t\tlightboxHiddenAttr: function(div){\n\t\t\tdiv.setAttribute(\"aria-hidden\", \"true\");\n\t\t},\n\n\t\tlightboxVisibleAttr: function(div){\n\t\t\tdiv.setAttribute(\"aria-hidden\", \"false\");\n\t\t},\n\n\t\tlightboxAttr: function(div){\n\t\t\tdiv.setAttribute(\"role\", \"dialog\");\n\t\t\tdiv.setAttribute(\"aria-hidden\", \"true\");\n\t\t\tdiv.firstChild.setAttribute(\"role\", \"heading\");\n\t\t\tdiv.firstChild.setAttribute(\"aria-level\", \"1\");\n\t\t},\n\n\t\tlightboxButtonAttrString:function(buttonName){\n\t\t\treturn this.getAttributeString({\"role\":\"button\", \"aria-label\":gantt.locale.labels[buttonName], \"tabindex\":\"0\"});\n\t\t},\n\n\t\tlightboxHeader: function(div, headerText){\n\t\t\tdiv.setAttribute(\"aria-label\", headerText);\n\t\t},\n\n\t\tlightboxSelectAttrString: function(time_option){\n\t\t\tvar label = \"\";\n\n\t\t\tswitch (time_option) {\n\t\t\t\tcase \"%Y\":\n\t\t\t\t\tlabel = gantt.locale.labels.years;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%m\":\n\t\t\t\t\tlabel = gantt.locale.labels.months;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%d\":\n\t\t\t\t\tlabel = gantt.locale.labels.days;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"%H:%i\":\n\t\t\t\t\tlabel = gantt.locale.labels.hours + gantt.locale.labels.minutes;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn gantt._waiAria.getAttributeString({\"aria-label\": label});\n\t\t},\n\n\t\tlightboxDurationInputAttrString: function(section){\n\t\t\treturn this.getAttributeString({\n\t\t\t\t\"aria-label\": gantt.locale.labels.column_duration,\n\t\t\t\t\"aria-valuemin\": \"0\",\n\t\t\t\t\"role\": \"spinbutton\"\n\t\t\t});\n\t\t},\n\n\t\tinlineEditorAttr: function(div){\n\t\t\tdiv.setAttribute(\"role\", \"row\");\n\t\t},\n\n\t\tgridAttrString: function(){\n\t\t\treturn [\" role='treegrid'\", gantt.config.multiselect ? \"aria-multiselectable='true'\" : \"aria-multiselectable='false'\", \" \"].join(\" \");\n\t\t},\n\n\n\t\tgridScaleRowAttrString: function(){\n\t\t\treturn \"role='row'\";\n\t\t},\n\n\t\tgridScaleCellAttrString: function(column, label){\n\t\t\tvar attrs = \"\";\n\t\t\tif(column.name == \"add\"){\n\t\t\t\t// a more precise role is button, but it is not valid for the grid header\n\t\t\t\tattrs = this.getAttributeString({\"role\":\"columnheader\", \"aria-label\": gantt.locale.labels.new_task});\n\t\t\t}else{\n\n\t\t\t\tvar attributes = {\n\t\t\t\t\t\"role\":\"columnheader\",\n\t\t\t\t\t\"aria-label\": label\n\t\t\t\t};\n\n\t\t\t\tif(gantt._sort && gantt._sort.name == column.name){\n\t\t\t\t\tif(gantt._sort.direction == \"asc\"){\n\t\t\t\t\t\tattributes[\"aria-sort\"] = \"ascending\";\n\t\t\t\t\t}else{\n\t\t\t\t\t\tattributes[\"aria-sort\"] = \"descending\";\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tattrs = this.getAttributeString(attributes);\n\t\t\t}\n\t\t\treturn attrs;\n\t\t},\n\n\t\tgridDataAttrString: function(){\n\t\t\treturn \"role='rowgroup'\";\n\t\t},\n\n\t\treorderMarkerAttr: function(div){\n\t\t\tdiv.setAttribute(\"role\", \"grid\");\n\t\t\tdiv.firstChild.removeAttribute(\"aria-level\");\n\t\t\tdiv.firstChild.setAttribute(\"aria-grabbed\", \"true\");\n\t\t},\n\n\t\tgridCellAttrString: function(column, textValue, task){\n\t\t\tvar attributes = {\"role\":\"gridcell\", \"aria-label\": textValue};\n\t\t\tif(!column.editor || gantt.isReadonly(task)){\n\t\t\t\tattributes[\"aria-readonly\"] = true;\n\t\t\t}\n\n\t\t\treturn this.getAttributeString(attributes);\n\t\t},\n\n\t\tgridAddButtonAttrString: function(column){\n\t\t\treturn this.getAttributeString({\"role\":\"button\", \"aria-label\": gantt.locale.labels.new_task});\n\t\t},\n\n\t\tmessageButtonAttrString: function(buttonLabel){\n\t\t\treturn \"tabindex='0' role='button' aria-label='\"+buttonLabel+\"'\";\n\t\t},\n\n\t\tmessageInfoAttr: function(div){\n\t\t\tdiv.setAttribute(\"role\", \"alert\");\n\t\t\t//div.setAttribute(\"tabindex\", \"-1\");\n\t\t},\n\n\t\tmessageModalAttr: function(div, uid){\n\t\t\tdiv.setAttribute(\"role\", \"dialog\");\n\t\t\tif(uid){\n\t\t\t\tdiv.setAttribute(\"aria-labelledby\", uid);\n\t\t\t}\n\n\t\t//\tdiv.setAttribute(\"tabindex\", \"-1\");\n\t\t},\n\n\t\tquickInfoAttr: function(div){\n\t\t\tdiv.setAttribute(\"role\", \"dialog\");\n\t\t},\n\n\t\tquickInfoHeaderAttrString: function(){\n\t\t\treturn \" role='heading' aria-level='1' \";\n\t\t},\n\n\t\tquickInfoHeader: function(div, header){\n\t\t\tdiv.setAttribute(\"aria-label\", header);\n\t\t},\n\n\t\tquickInfoButtonAttrString: function(label){\n\t\t\treturn gantt._waiAria.getAttributeString({\"role\":\"button\", \"aria-label\":label, \"tabindex\":\"0\"});\n\t\t},\n\n\t\ttooltipAttr: function(div){\n\t\t\tdiv.setAttribute(\"role\", \"tooltip\");\n\t\t},\n\n\t\ttooltipVisibleAttr: function(div){\n\t\t\tdiv.setAttribute(\"aria-hidden\", \"false\");\n\t\t},\n\n\t\ttooltipHiddenAttr: function(div){\n\t\t\tdiv.setAttribute(\"aria-hidden\", \"true\");\n\t\t}\n\t};\n\n\tfunction isDisabled(){\n\t\treturn !gantt.config.wai_aria_attributes;\n\t}\n\n\tfor(var i in gantt._waiAria){\n\t\tgantt._waiAria[i] = (function(payload){\n\t\t\treturn function(){\n\t\t\t\tif(isDisabled()){\n\t\t\t\t\treturn \"\";\n\t\t\t\t}\n\t\t\t\treturn payload.apply(this, arguments);\n\t\t\t};\n\t\t})(gantt._waiAria[i]);\n\t}\n\n\n};","export default function(gantt) {\n\tgantt.load = function (url, type, callback) {\n\t\tthis._load_url = url;\n\t\tthis.assert(arguments.length, \"Invalid load arguments\");\n\n\t\tvar tp = 'json', cl = null;\n\t\tif (arguments.length >= 3) {\n\t\t\ttp = type;\n\t\t\tcl = callback;\n\t\t} else {\n\t\t\tif (typeof arguments[1] == \"string\")\n\t\t\t\ttp = arguments[1];\n\t\t\telse if (typeof arguments[1] == \"function\")\n\t\t\t\tcl = arguments[1];\n\t\t}\n\n\t\tthis._load_type = tp;\n\n\t\tthis.callEvent(\"onLoadStart\", [url, tp]);\n\n\t\treturn this.ajax.get(url, gantt.bind(function (l) {\n\t\t\tthis.on_load(l, tp);\n\t\t\tthis.callEvent(\"onLoadEnd\", [url, tp]);\n\t\t\tif (typeof cl == \"function\")\n\t\t\t\tcl.call(this);\n\t\t}, this));\n\t};\n};","import TreeDataStore from \"../datastore/treedatastore\";\n\nexport default function(gantt) {\n\n\tvar loadedBranches = {};\n\tgantt.attachEvent(\"onClearAll\", function(){\n\t\tloadedBranches = {};\n\t});\n\n\tvar oldHasChildren = TreeDataStore.prototype.hasChild;\n\tgantt.$data.tasksStore.hasChild = function (id) {\n\t\tif(!gantt.config.branch_loading){\n\t\t\treturn oldHasChildren.call(this, id);\n\t\t}else{\n\t\t\tif (oldHasChildren.call(this, id))\n\t\t\t\treturn true;\n\t\t\tif (this.exists(id)) {\n\t\t\t\treturn this.getItem(id)[gantt.config.branch_loading_property];\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t};\n\n\tfunction needLoading(id) {\n\t\tif (gantt.config.branch_loading && gantt._load_url) {\n\t\t\tvar alreadyLoaded = !!loadedBranches[id];\n\t\t\t// call ajax only if branch has children\n\t\t\tif (!alreadyLoaded && (!gantt.getChildren(id).length && gantt.hasChild(id))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tgantt.attachEvent(\"onTaskOpened\", function (id) {\n\t\tif (gantt.config.branch_loading && gantt._load_url) {\n\t\t\t// call ajax only if branch has children\n\t\t\tif (needLoading(id)) {\n\t\t\t\tvar url = gantt._load_url;\n\t\t\t\turl = url.replace(/(\\?|&)?parent_id=.+&?/, \"\");\n\t\t\t\tvar param = url.indexOf(\"?\") >= 0 ? \"&\" : \"?\";\n\t\t\t\tvar y = gantt.getScrollState().y || 0;\n\n\t\t\t\tvar requestData = {\n\t\t\t\t\ttaskId: id,\n\t\t\t\t\turl: url + param + \"parent_id=\" + encodeURIComponent(id)\n\t\t\t\t};\n\n\t\t\t\tif(gantt.callEvent(\"onBeforeBranchLoading\", [requestData]) === false){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tgantt.load(requestData.url, this._load_type, function () {\n\t\t\t\t\tif (y) {\n\t\t\t\t\t\tgantt.scrollTo(null, y);\n\t\t\t\t\t}\n\t\t\t\t\tgantt.callEvent(\"onAfterBranchLoading\", [requestData]);\n\t\t\t\t});\n\t\t\t\tloadedBranches[id] = true;\n\t\t\t}\n\t\t}\n\t});\n\n};","import auto_scheduling from \"./auto_scheduling\";\nimport click_drag from \"./click_drag\";\nimport critical_path from \"./critical_path\";\nimport drag_timeline from \"./drag_timeline\";\nimport export_api from \"./export_api\";\nimport fullscreen from \"./fullscreen\";\nimport grouping from \"./grouping\";\nimport keyboard_navigation from \"./keyboard_navigation\";\nimport marker from \"./marker\";\nimport multiselect from \"./multiselect\";\nimport overlay from \"./overlay\";\nimport quick_info from \"./quick_info\";\nimport tooltip from \"./tooltip\";\nimport undo from \"./undo\";\n\nexport default {\n\tauto_scheduling,\n\tclick_drag,\n\tcritical_path,\n\tdrag_timeline,\n\tfullscreen,\n\tkeyboard_navigation,\n\tquick_info,\n\ttooltip,\n\tundo,\n\tgrouping,\n\tmarker,\n\tmultiselect,\n\toverlay,\n\texport_api\n};","\nimport auto_scheduling_configs from \"./auto_scheduling_configs\";\nimport links_common from \"../core/relations/links_common\";\nimport graph_helper from \"../core/relations/graph_helper\";\n\nimport LinksBuilder from \"../core/relations/links_builder\";\nimport {ConstraintTypes} from \"./auto_scheduling/constraint_types\";\nimport {ConstraintsHelper} from \"./auto_scheduling/constraints\";\nimport {AutoSchedulingPlanner} from \"./auto_scheduling/planner\";\nimport {ConnectedGroupsHelper} from \"./auto_scheduling/connected_groups\";\nimport {LoopsFinder} from \"./auto_scheduling/loops_finder\";\n\nimport {attachUIHandlers} from \"./auto_scheduling/ui_handlers\";\n\nexport default function(gantt){\n\n\tauto_scheduling_configs(gantt);\n\tlinks_common(gantt);\n\nvar linksBuilder = LinksBuilder(gantt);\nvar graphHelper = graph_helper(gantt);\n\n\nvar constraintsHelper = ConstraintsHelper.Create(\n\tgantt\n);\n\n\nvar planner = new AutoSchedulingPlanner(gantt, graphHelper, constraintsHelper);\n\nvar connectedGroups = new ConnectedGroupsHelper(gantt, linksBuilder);\n\nvar loopsFinder = new LoopsFinder(\n\tgantt,\n\tgraphHelper,\n\tlinksBuilder\n);\n\ngantt.getConnectedGroup = connectedGroups.getConnectedGroup;\ngantt.getConstraintType = constraintsHelper.getConstraintType;\ngantt.getConstraintLimitations = function (task) {\n\tvar plan = constraintsHelper.processConstraint(task, null);\n\tif (plan) {\n\t\treturn {\n\t\t\tearliestStart: plan.earliestStart || null,\n\t\t\tearliestEnd: plan.earliestEnd || null,\n\t\t\tlatestStart: plan.latestStart || null,\n\t\t\tlatestEnd: plan.latestEnd || null\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\tearliestStart: null,\n\t\t\tearliestEnd: null,\n\t\t\tlatestStart: null,\n\t\t\tlatestEnd: null\n\t\t};\n\t}\n};\n\ngantt.isCircularLink = loopsFinder.isCircularLink;\ngantt.findCycles = loopsFinder.findCycles;\n\ngantt.config.constraint_types = ConstraintTypes;\ngantt.config.auto_scheduling = false;\ngantt.config.auto_scheduling_descendant_links = false;\ngantt.config.auto_scheduling_initial = true;\ngantt.config.auto_scheduling_strict = false;\ngantt.config.auto_scheduling_move_projects = true;\ngantt.config.project_start = null;\ngantt.config.project_end = null;\ngantt.config.schedule_from_end = false;\n\nfunction preferInitialTaskDates(startTask, relations) {\n\t// TODO: remove in 7.0\n\tif (!gantt.config.auto_scheduling_compatibility) {\n\t\treturn;\n\t}\n\n\t// .preferredStart still exists only to emulate pre 6.1 auto scheduling behavior\n\t// will be removed in future versions\n\tfor (var i = 0; i < relations.length; i++) {\n\t\tvar rel = relations[i];\n\t\tvar task = gantt.getTask(rel.target);\n\n\t\tif (!gantt.config.auto_scheduling_strict || rel.target == startTask) {\n\t\t\trel.preferredStart = new Date(task.start_date);\n\t\t}\n\t}\n}\n\nvar afterRenderBeforeFirstRepaint = false;\ngantt.attachEvent(\"onParse\", function(){\n\tafterRenderBeforeFirstRepaint = true;\n\treturn true;\n});\n\ngantt.attachEvent(\"onBeforeGanttRender\", function(){\n\tafterRenderBeforeFirstRepaint = false;\n\treturn true;\n});\n\nfunction updateParentsAndCallEvents(updatedTasks) {\n\tif(!updatedTasks.length){\n\t\treturn;\n\t}\n\n\tgantt.batchUpdate(function payload() {\n\t\tfor (var i = 0; i < updatedTasks.length; i++) {\n\t\t\tgantt.updateTask(updatedTasks[i]);\n\t\t}\n\t}, afterRenderBeforeFirstRepaint); // don't call repaint if auto scheduling on parse before initial repain\n}\n\ngantt._autoSchedule = function (id, relations) {\n\tif (gantt.callEvent(\"onBeforeAutoSchedule\", [id]) === false) {\n\t\treturn;\n\t}\n\tgantt._autoscheduling_in_progress = true;\n\n\tvar constraints = constraintsHelper.getConstraints(\n\t\tid,\n\t\tgantt.isTaskExists(id) ? relations : null\n\t);\n\n\tvar updatedTasks = [];\n\n\tvar cycles = graphHelper.findLoops(relations);\n\tif (cycles.length) {\n\t\tgantt.callEvent(\"onAutoScheduleCircularLink\", [cycles]);\n\t} else {\n\t\tpreferInitialTaskDates(id, relations);\n\n\t\t// GS-2427. Auto-schedule twice when there are links with project tasks\n\t\t// as we cannot be sure that the project duration doesn't change\n\t\tfor (let i = 0; i < relations.length; i++) {\n\t\t\tif (relations[i].subtaskLink){\n\t\t\t\tplanner._secondIterationRequired = true;\n\t\t\t\tplanner._secondIteration = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tvar plan = planner.generatePlan(relations, constraints);\n\t\tupdatedTasks = planner.applyProjectPlan(plan);\n\n\t\tupdateParentsAndCallEvents(updatedTasks);\n\t}\n\n\tgantt._autoscheduling_in_progress = false;\n\tgantt.callEvent(\"onAfterAutoSchedule\", [id, updatedTasks]);\n};\n\ngantt.autoSchedule = function (id, inclusive) {\n\tif (inclusive === undefined) {\n\t\tinclusive = true;\n\t} else {\n\t\tinclusive = !!inclusive;\n\t}\n\n\tvar relations;\n\tif (id !== undefined) {\n\t\tif (gantt.config.auto_scheduling_compatibility) {\n\t\t\trelations = linksBuilder.getLinkedTasks(id, inclusive);\n\t\t} else {\n\t\t\trelations = connectedGroups.getConnectedGroupRelations(id);\n\t\t}\n\t} else {\n\t\trelations = linksBuilder.getLinkedTasks();\n\t}\n\n\tgantt._autoSchedule(id, relations);\n};\n\ngantt.attachEvent(\"onTaskLoading\", function (task) {\n\tif (task.constraint_date && typeof task.constraint_date === \"string\") {\n\t\ttask.constraint_date = gantt.date.parseDate(task.constraint_date, \"parse_date\");\n\t}\n\ttask.constraint_type = gantt.getConstraintType(task);\n\treturn true;\n});\ngantt.attachEvent(\"onTaskCreated\", function (task) {\n\ttask.constraint_type = gantt.getConstraintType(task);\n\treturn true;\n});\n\nattachUIHandlers(gantt, linksBuilder, loopsFinder, connectedGroups);\n\n};","import { ConnectedGroupsHelper } from \"./connected_groups\";\n\nexport function attachUIHandlers(\n\tgantt: any,\n\tlinksBuilder: any,\n\tloopsFinder: any,\n\tconnectedGroupsHelper: ConnectedGroupsHelper\n) {\n\tconst _attachAutoSchedulingHandlers = function() {\n\t\tlet _scheduleAfterBatchUpdate = false;\n\t\tgantt.attachEvent(\"onAfterBatchUpdate\", function(){\n\n\t\t\tif(_scheduleAfterBatchUpdate){\n\t\t\t\tgantt.autoSchedule();\n\t\t\t}\n\t\t\t_scheduleAfterBatchUpdate = false;\n\t\t});\n\n\t\tfunction _autoScheduleAfterLinkChange(id: LinkID, link: ILink) {\n\t\t\tif (gantt.config.auto_scheduling && !gantt._autoscheduling_in_progress) {\n\t\t\t\tif(gantt.getState().batch_update){\n\t\t\t\t\t_scheduleAfterBatchUpdate = true;\n\t\t\t\t}else{\n\t\t\t\t\tgantt.autoSchedule(link.source);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tgantt.attachEvent(\"onAfterLinkUpdate\", _autoScheduleAfterLinkChange);\n\t\tgantt.attachEvent(\"onAfterLinkAdd\", _autoScheduleAfterLinkChange);\n\n\t\tgantt.attachEvent(\"onAfterLinkDelete\", function(id: LinkID, link: ILink) {\n\t\t\tif (\n\t\t\t\tgantt.config.auto_scheduling &&\n\t\t\t\t!gantt._autoscheduling_in_progress &&\n\t\t\t\tgantt.isTaskExists(link.target)\n\t\t\t) {\n\t\t\t\t// after link deleted - auto schedule target for other relations that may be left\n\t\t\t\tconst target = gantt.getTask(link.target);\n\t\t\t\tconst predecessors = gantt._getPredecessors(target);\n\t\t\t\tif (predecessors.length) {\n\t\t\t\t\tif(gantt.getState().batch_update){\n\t\t\t\t\t\t_scheduleAfterBatchUpdate = true;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tgantt.autoSchedule(predecessors[0].source, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tgantt.attachEvent(\"onParse\", function() {\n\t\t\tif (\n\t\t\t\tgantt.config.auto_scheduling &&\n\t\t\t\tgantt.config.auto_scheduling_initial\n\t\t\t) {\n\t\t\t\tgantt.autoSchedule();\n\t\t\t}\n\t\t});\n\n\t\tfunction _preventCircularLink(id: LinkID, link: ILink): boolean {\n\t\t\tconst slackConfigValue = gantt.config.auto_scheduling_use_progress;\n\t\t\tgantt.config.auto_scheduling_use_progress = false;\n\n\t\t\tif (gantt.isCircularLink(link)) {\n\t\t\t\tgantt.callEvent(\"onCircularLinkError\", [\n\t\t\t\t\tlink,\n\t\t\t\t\tloopsFinder.getLoopContainingLink(link)\n\t\t\t\t]);\n\t\t\t\tgantt.config.auto_scheduling_use_progress = slackConfigValue;\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\tgantt.config.auto_scheduling_use_progress = slackConfigValue;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tfunction _preventDescendantLink(id: LinkID, link: ILink): boolean {\n\t\t\tconst source = gantt.getTask(link.source);\n\t\t\tconst target = gantt.getTask(link.target);\n\n\t\t\tif (!gantt.config.auto_scheduling_descendant_links) {\n\t\t\t\tif (\n\t\t\t\t\t(gantt.isChildOf(source.id, target.id) &&\n\t\t\t\t\t\tgantt.isSummaryTask(target)) ||\n\t\t\t\t\t(gantt.isChildOf(target.id, source.id) && gantt.isSummaryTask(source))\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tgantt.attachEvent(\"onBeforeLinkAdd\", _preventCircularLink);\n\t\tgantt.attachEvent(\"onBeforeLinkAdd\", _preventDescendantLink);\n\t\tgantt.attachEvent(\"onBeforeLinkUpdate\", _preventCircularLink);\n\t\tgantt.attachEvent(\"onBeforeLinkUpdate\", _preventDescendantLink);\n\n\t\tfunction _datesNotEqual(\n\t\t\tdateA: Date,\n\t\t\tdateB: Date,\n\t\t\ttaskA: ITask,\n\t\t\ttaskB: ITask\n\t\t): boolean {\n\t\t\tif (!!dateA !== !!dateB) {\n\t\t\t\t// if one of dates is empty or null and the other is not\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (!dateA && !dateB) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (dateA.valueOf() > dateB.valueOf()) {\n\t\t\t\treturn gantt._hasDuration({\n\t\t\t\t\tstart_date: dateB,\n\t\t\t\t\tend_date: dateA,\n\t\t\t\t\ttask: taskB\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\treturn gantt._hasDuration({\n\t\t\t\t\tstart_date: dateA,\n\t\t\t\t\tend_date: dateB,\n\t\t\t\t\ttask: taskA\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tfunction _notEqualTaskDates(task1: ITask, task2: ITask): boolean {\n\t\t\tif (_datesNotEqual(task1.start_date, task2.start_date, task1, task2)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (gantt.getConstraintType(task1) !== gantt.getConstraintType(task2)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t_datesNotEqual(\n\t\t\t\t\ttask1.constraint_date,\n\t\t\t\t\ttask2.constraint_date,\n\t\t\t\t\ttask1,\n\t\t\t\t\ttask2\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t_datesNotEqual(task1.start_date, task2.start_date, task1, task2) ||\n\t\t\t\t((_datesNotEqual(task1.end_date, task2.end_date, task1, task2) ||\n\t\t\t\t\ttask1.duration !== task2.duration) &&\n\t\t\t\t\ttask1.type !== gantt.config.types.milestone)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tfunction getRelations(id: TaskID) {\n\t\t\t// collect relations before drag and drop in order to have original positions of subtasks within project since they are used as lag when moving dependent project\n\n\t\t\t// TODO: remove in 7.0\n\t\t\tif (gantt.config.auto_scheduling_compatibility) {\n\t\t\t\t// collect only downstream dependencies since there is no backward or ALAP scheduling in pre 6.1 auto scheduling\n\t\t\t\treturn linksBuilder.getLinkedTasks(id, true);\n\t\t\t} else {\n\t\t\t\t// get all connected group (both upstream and downstream dependencies)\n\t\t\t\treturn connectedGroupsHelper.getConnectedGroupRelations(id);\n\t\t\t}\n\t\t}\n\n\t\tlet relations;\n\t\tlet movedTask;\n\t\tgantt.attachEvent(\"onBeforeTaskDrag\", function(\n\t\t\tid: TaskID,\n\t\t\tmode: string,\n\t\t\ttask: ITask\n\t\t) {\n\t\t\tif (\n\t\t\t\tgantt.config.auto_scheduling\n\t\t\t\t// We need to get the movedTask so that we can use it later internally\n\t\t\t\t// && gantt.config.auto_scheduling_move_projects\n\t\t\t) {\n\t\t\t\t// collect relations before drag and drop in order to have original positions of subtasks within project since they are used as lag when moving dependent project\n\t\t\t\tif(gantt.getState().drag_mode !== \"progress\"){\n\t\t\t\t\trelations = getRelations(id);\n\t\t\t\t}\n\n\t\t\t\tmovedTask = id;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tfunction resetToStartLinksLags(taskId, relationsArray) {\n\t\t\t// task duration is used as lag when converting start_to_start and start_to_finish into finish_to_start links\n\t\t\t// recalculate these links if task duration has changed\n\n\t\t\tlet skipped = false;\n\t\t\tfor (let i = 0; i < relations.length; i++) {\n\t\t\t\tconst originalLink = gantt.getLink(relationsArray[i].id);\n\t\t\t\tif (\n\t\t\t\t\toriginalLink &&\n\t\t\t\t\t(originalLink.type === gantt.config.links.start_to_start ||\n\t\t\t\t\t\toriginalLink.type === gantt.config.links.start_to_finish)\n\t\t\t\t) {\n\t\t\t\t\trelationsArray.splice(i, 1);\n\t\t\t\t\ti--;\n\t\t\t\t\tskipped = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (skipped) {\n\t\t\t\tconst presentLinks = {};\n\t\t\t\tfor (let i = 0; i < relationsArray.length; i++) {\n\t\t\t\t\tpresentLinks[relationsArray[i].id] = true;\n\t\t\t\t}\n\n\t\t\t\tconst updatedLinks = getRelations(taskId);\n\n\t\t\t\tfor (let i = 0; i < updatedLinks.length; i++) {\n\t\t\t\t\tif (!presentLinks[updatedLinks[i].id]) {\n\t\t\t\t\t\trelationsArray.push(updatedLinks[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// GS-686. We shouldn't change the constraint after changing only the duration or end_date\n\t\tfunction shouldKeepConstraints(task, oldTask){\n\t\t\tif (gantt.config.schedule_from_end) {\n\t\t\t\tif (oldTask.end_date && task.end_date && task.end_date.valueOf() === oldTask.end_date.valueOf()){\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (oldTask.start_date && task.start_date && task.start_date.valueOf() === oldTask.start_date.valueOf()){\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction updateTaskConstraints(task){\n\t\t\t// GS-1487. Don't add a constraint if auto-scheduling is cancelled\n\t\t\tif (task.auto_scheduling === false){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// GS-2452. We should keep the constraints type if it doesn't affect the task dates\n\t\t\tconst constraintTypes = gantt.config.constraint_types;\n\t\t\tconst backwardConstraints = [\n\t\t\t\tconstraintTypes.SNLT,\n\t\t\t\tconstraintTypes.FNLT,\n\t\t\t\tconstraintTypes.MSO,\n\t\t\t\tconstraintTypes.MFO\n\t\t\t];\n\t\t\tconst forwardConstraints = [\n\t\t\t\tconstraintTypes.SNET,\n\t\t\t\tconstraintTypes.FNET,\n\t\t\t\tconstraintTypes.MSO,\n\t\t\t\tconstraintTypes.MFO\n\t\t\t];\n\n\t\t\tif (gantt.config.schedule_from_end) {\n\t\t\t\tif (backwardConstraints.indexOf(task.constraint_type) > -1) {\n\t\t\t\t\t// keep the constraint type\n\t\t\t\t\tif (task.constraint_type == constraintTypes.SNLT ||\n\t\t\t\t\t\ttask.constraint_type == constraintTypes.MSO) {\n\t\t\t\t\t\ttask.constraint_date = new Date(task.start_date);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttask.constraint_date = new Date(task.end_date);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// set the default constraint\n\t\t\t\t\ttask.constraint_type = constraintTypes.FNLT;\n\t\t\t\t\ttask.constraint_date = new Date(task.end_date);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (forwardConstraints.indexOf(task.constraint_type) > -1) {\n\t\t\t\t\t// keep the constraint type\n\t\t\t\t\tif (task.constraint_type == constraintTypes.SNET ||\n\t\t\t\t\t\ttask.constraint_type == constraintTypes.MSO) {\n\t\t\t\t\t\ttask.constraint_date = new Date(task.start_date);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttask.constraint_date = new Date(task.end_date);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// set the default constraint\n\t\t\t\t\ttask.constraint_type = constraintTypes.SNET;\n\t\t\t\t\ttask.constraint_date = new Date(task.start_date);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction finalizeTaskConstraints(task){\n\t\t\t// TODO: remove in 7.0\n\t\t\tif (gantt.config.auto_scheduling_compatibility) {\n\t\t\t\tif (task.constraint_type === gantt.config.constraint_types.SNET ||\n\t\t\t\t\ttask.constraint_type === gantt.config.constraint_types.FNLT) {\n\t\t\t\t\t\ttask.constraint_type = null;\n\t\t\t\t\t\ttask.constraint_date = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst _processConstraints = function(taskId, oldTask) {\n\t\t\tconst newTask = gantt.getTask(taskId);\n\t\t\tif (shouldKeepConstraints(newTask, oldTask)) {\n\t\t\t\t// don't change constraints\n\t\t\t} else {\n\t\t\t\tupdateTaskConstraints(newTask);\n\t\t\t}\n\t\t};\n\n\t\tconst _autoScheduleAfterDND = function(taskId, task) {\n\t\t\tif (gantt.config.auto_scheduling && !gantt._autoscheduling_in_progress) {\n\t\t\t\tconst newTask = gantt.getTask(taskId);\n\n\t\t\t\tconst progressScheduling = (gantt.config.auto_scheduling_use_progress && ((task.progress === 1) !== (newTask.progress === 1)));\n\n\t\t\t\tif (_notEqualTaskDates(task, newTask)) {\n\t\t\t\t\t_processConstraints(taskId, task);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tgantt.config.auto_scheduling_move_projects &&\n\t\t\t\t\t\t// tslint:disable-next-line triple-equals\n\t\t\t\t\t\tmovedTask == taskId\n\t\t\t\t\t) {\n\t\t\t\t\t\tlet shouldResetSSandSFLinkLags = true;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tgantt.calculateDuration(task) !== gantt.calculateDuration(newTask)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// task duration is used as lag when converting start_to_start and start_to_finish into finish to start links\n\t\t\t\t\t\t\t// recalculate these links if task duration has changed\n\t\t\t\t\t\t\tresetToStartLinksLags(taskId, relations);\n\t\t\t\t\t\t\t// to not call the function above twice\n\t\t\t\t\t\t\tshouldResetSSandSFLinkLags = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(progressScheduling){\n\t\t\t\t\t\t\tgantt.autoSchedule();\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t// GS-2588. The duration of the project tasks can be changed after the child drag,\n\t\t\t\t\t\t\t// so, we need to update that information for the SS and SF links\n\t\t\t\t\t\t\tif (shouldResetSSandSFLinkLags) {\n\t\t\t\t\t\t\t\tresetToStartLinksLags(taskId, relations);\n\t\t\t\t\t\t\t}\t\t\t\t\t\n\t\t\t\t\t\t\tgantt._autoSchedule(taskId, relations);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tgantt.autoSchedule(newTask.id);\n\t\t\t\t\t}\n\n\t\t\t\t\tfinalizeTaskConstraints(newTask);\n\t\t\t\t}\n\t\t\t}\n\t\t\trelations = null;\n\t\t\tmovedTask = null;\n\t\t\treturn true;\n\t\t};\n\n\n\n\n\t\tlet modifiedTaskId = null;\n\t\tif (gantt.ext && gantt.ext.inlineEditors) {\n\t\t\tconst inlineEditors = gantt.ext.inlineEditors;\n\t\t\tconst autoscheduleColumns = {\n\t\t\t\tstart_date: true,\n\t\t\t\tend_date: true,\n\t\t\t\tduration: true,\n\t\t\t\tconstraint_type: true,\n\t\t\t\tconstraint_date: true\n\t\t\t};\n\n\t\t\tinlineEditors.attachEvent(\"onBeforeSave\", function(state) {\n\t\t\t\tif (autoscheduleColumns[state.columnName]) {\n\t\t\t\t\tmodifiedTaskId = state.id;\n\t\t\t\t\t// GS-711. The constraint type set by the user should be saved\n\t\t\t\t\tif (state.columnName === \"constraint_type\"){\n\t\t\t\t\t\tchangedConstraint = true;\n\t\t\t\t\t}\n\t\t\t\t\t// GS-686. We shouldn't change the constraint after changing only the duration or end_date\n\t\t\t\t\tconst durationColumn = state.columnName === \"duration\";\n\t\t\t\t\tconst startDateColumn = gantt.config.schedule_from_end && (state.columnName === \"start_date\");\n\t\t\t\t\tconst endDateColumn = !gantt.config.schedule_from_end && (state.columnName === \"end_date\");\n\n\t\t\t\t\tconst linkedDateModification = gantt.config.inline_editors_date_processing !== \"keepDuration\";\n\t\t\t\t\tconst linkedColumnEdit = linkedDateModification && (startDateColumn || endDateColumn);\n\n\t\t\t\t\tconst constraintDateColumn = state.columnName === \"constraint_date\";\n\n\t\t\t\t\tconst keepConstraints = durationColumn || linkedColumnEdit || constraintDateColumn;\n\n\t\t\t\t\tif (keepConstraints) {\n\t\t\t\t\t\tconst task = gantt.getTask(state.id);\n\t\t\t\t\t\ttask.$keep_constraints = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t}\n\n\t\tlet changedConstraint;\n\t\tfunction onBeforeLigthboxSaveHandler(taskId: TaskID, task: ITask): boolean {\n\t\t\tif (gantt.config.auto_scheduling && !gantt._autoscheduling_in_progress) {\n\t\t\t\tchangedConstraint = false;\n\t\t\t\tconst oldTask = gantt.getTask(taskId);\n\t\t\t\tif (_notEqualTaskDates(task, oldTask)) {\n\t\t\t\t\tmodifiedTaskId = taskId;\n\t\t\t\t\tif (shouldKeepConstraints(task, oldTask)){\n\t\t\t\t\t\ttask.$keep_constraints = true;\n\t\t\t\t\t}\n\t\t\t\t\tif(gantt.getConstraintType(task) !== gantt.getConstraintType(oldTask) ||\n\t\t\t\t\t\t+task.constraint_date !== +oldTask.constraint_date\n\t\t\t\t\t){\n\t\t\t\t\t\tchangedConstraint = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\tfunction onAfterTaskUpdateHandler(taskId: TaskID, task: ITask): boolean {\n\t\t\tif (gantt.config.auto_scheduling && !gantt._autoscheduling_in_progress) {\n\t\t\t\tif (\n\t\t\t\t\tmodifiedTaskId !== null &&\n\t\t\t\t\t// tslint:disable-next-line triple-equals\n\t\t\t\t\tmodifiedTaskId == taskId\n\t\t\t\t) {\n\t\t\t\t\tmodifiedTaskId = null;\n\t\t\t\t\tif (task.$keep_constraints){\n\t\t\t\t\t\tdelete task.$keep_constraints;\n\t\t\t\t\t} else if(!changedConstraint){\n\t\t\t\t\t\tupdateTaskConstraints(task);\n\t\t\t\t\t}\n\t\t\t\t\tgantt.autoSchedule(task.id);\n\n\t\t\t\t\tif(!changedConstraint){\n\t\t\t\t\t\tfinalizeTaskConstraints(task);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tconst draggedTask = {};\n\t\tlet timeout;\n\t\tgantt.attachEvent(\"onBeforeTaskChanged\", function(\n\t\t\tid: TaskID,\n\t\t\tmode: string,\n\t\t\ttask: ITask\n\t\t) {\n\t\t\t_processConstraints(id, task);\n\t\t\tdraggedTask[id] = task;\n\t\t\treturn true;\n\t\t});\n\n\t\t// GS-499, GS-264 and GS-836. Autoschedule only after finishing dragging the task\n\t\tgantt.attachEvent(\"onAfterTaskDrag\", function(id, mode, e) {\n\t\t\tif (id === movedTask) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\ttimeout = setTimeout(function() {\n\t\t\t\t\t_autoScheduleAfterDND(id, draggedTask[id]);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\tif(gantt.ext.inlineEditors){\n\t\t\tgantt.ext.inlineEditors.attachEvent(\"onBeforeSave\", function(state){\n\t\t\t\tif (gantt.config.auto_scheduling && !gantt._autoscheduling_in_progress) {\n\t\t\t\t\tconst api = gantt.ext.inlineEditors;\n\t\t\t\t\tconst editorConfig = api.getEditorConfig(state.columnName);\n\t\t\t\t\tif(editorConfig.map_to === \"start_date\" || editorConfig.map_to === \"end_date\" || editorConfig.map_to === \"duration\"){\n\t\t\t\t\t\tmodifiedTaskId = state.id;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t}\n\n\t\tgantt.attachEvent(\"onLightboxSave\", onBeforeLigthboxSaveHandler);\n\t\tgantt.attachEvent(\"onAfterTaskUpdate\", onAfterTaskUpdateHandler);\n\t};\n\n\tgantt.attachEvent(\"onGanttReady\", function() {\n\t\t_attachAutoSchedulingHandlers();\n\t\t// attach handlers only when initialized for the first time\n\t}, {once: true});\n}\n","import { EventsManager } from \"./eventsManager\";\nimport { ISelectedRegionConfig, SelectedRegion } from \"./selectedRegion\";\n\nexport default function(gantt: any){\n\tif (!gantt.ext) {\n\t\tgantt.ext = {};\n\t}\n\n\tconst defaultConfig: ISelectedRegionConfig = {\n\t\tclassName: \"gantt_click_drag_rect\",\n\t\tuseRequestAnimationFrame: true,\n\t\tcallback: undefined,\n\t\tsingleRow: false\n\t};\n\n\tconst eventsManager = new EventsManager(gantt);\n\n\tgantt.ext.clickDrag = eventsManager;\n\n\tgantt.attachEvent(\"onGanttReady\", () => {\n\t\tconst config: ISelectedRegionConfig = { viewPort: gantt.$task_data, ...defaultConfig };\n\t\tif (gantt.config.click_drag){\n\t\t\tconst clickDrag = gantt.config.click_drag;\n\t\t\tconfig.render = clickDrag.render || defaultConfig.render;\n\t\t\tconfig.className = clickDrag.className || defaultConfig.className;\n\t\t\tconfig.callback = clickDrag.callback || defaultConfig.callback;\n\t\t\tconfig.viewPort = clickDrag.viewPort || gantt.$task_data;\n\t\t\tconfig.useRequestAnimationFrame = clickDrag.useRequestAnimationFrame === undefined ?\n\t\t\t\tdefaultConfig.useRequestAnimationFrame : clickDrag.useRequestAnimationFrame;\n\n\t\t\tconfig.singleRow = clickDrag.singleRow === undefined ? defaultConfig.singleRow : clickDrag.singleRow;\n\t\t\tconst timeline = gantt.$ui.getView(\"timeline\");\n\t\t\tconst selectedRegion = new SelectedRegion(config, gantt, timeline);\n\t\t\tgantt.ext.clickDrag.attach(selectedRegion, clickDrag.useKey, clickDrag.ignore);\n\t\t}\n\t});\n\n\tgantt.attachEvent(\"onDestroy\", () => {\n\t\teventsManager.destructor();\n\t});\n\n}","\n\nimport auto_scheduling_configs from \"./auto_scheduling_configs\";\nimport links_common from \"../core/relations/links_common\";\nimport slackPrivate from \"./critical_path/slack\";\nimport critical_path from \"./critical_path/critical_path\";\n\n\nexport default function(gantt){\n\n\tauto_scheduling_configs(gantt);\n\tlinks_common(gantt);\n\nvar _private = slackPrivate(gantt);\n_private.init();\n\ngantt.getFreeSlack = function(task) {\n\treturn _private.getFreeSlack(task);\n};\n\ngantt.getTotalSlack = function(task) {\n\treturn _private.getTotalSlack(task);\n};\n\nvar criticalPath = critical_path(gantt);\ngantt.config.highlight_critical_path = false;\ncriticalPath.init(_private);\n\ngantt.isCriticalTask = function (task) {\n\tgantt.assert(!!(task && task.id !== undefined), \"Invalid argument for gantt.isCriticalTask\");\n\treturn criticalPath.isCriticalTask(task);\n};\n\ngantt.isCriticalLink = function (link) {\n\treturn this.isCriticalTask(gantt.getTask(link.source));\n};\n\n\ngantt.getSlack = function(task1, task2) {\n\tvar minSlack = 0;\n\tvar relations = [];\n\tvar common = {};\n\n\tfor (var i = 0; i < task1.$source.length; i++) {\n\t\tcommon[task1.$source[i]] = true;\n\t}\n\tfor (var i = 0; i < task2.$target.length; i++) {\n\t\tif(common[task2.$target[i]])\n\t\t\trelations.push(task2.$target[i]);\n\t}\n\t// there is at least one link\n\tif (relations[0]){\n\t\tfor (var i = 0; i < relations.length; i++) {\n\t\t\tvar link = this.getLink(relations[i]);\n\t\t\tvar newSlack = this._getSlack(task1, task2, this._convertToFinishToStartLink(link.id, link, task1, task2, task1.parent, task2.parent));\n\n\t\t\tif (minSlack > newSlack || i === 0) {\n\t\t\t\tminSlack = newSlack;\n\t\t\t}\n\t\t}\n\t}\n\telse { // there are no links, but we still need the slack (for the children of a project task)\n\t\tminSlack = this._getSlack(task1, task2, {});\n\t}\n\treturn minSlack;\n};\n\ngantt._getSlack = function (task, next_task, relation) {\n\t// relation - link expressed as finish-to-start (gantt._convertToFinishToStartLink)\n\tvar types = this.config.types;\n\n\tvar from = null;\n\tif (this.getTaskType(task.type) == types.milestone) {\n\t\tfrom = task.start_date;\n\t} else {\n\t\tfrom = task.end_date;\n\t}\n\n\tvar to = next_task.start_date;\n\n\tvar duration = 0;\n\tif (+from > +to) {\n\t\tduration = -this.calculateDuration({start_date: to, end_date: from, task: task});\n\t} else {\n\t\tduration = this.calculateDuration({start_date: from, end_date: to, task: task});\n\t}\n\n\tvar lag = relation.lag;\n\tif (lag && lag*1 == lag) {\n\t\tduration -= lag;\n\t}\n\n\treturn duration;\n};\n\n\n};","import LinksBuilder from \"../../core/relations/links_builder\";\nimport GraphHelper from \"../../core/relations/graph_helper\";\n\nexport default function(gantt) {\n\tvar linksBuilder = LinksBuilder(gantt);\n\tvar graphHelper = GraphHelper(gantt);\n\tvar _private = {\n\t\t_freeSlack: {},\n\t\t_totalSlack: {},\n\t\t_slackNeedCalculate: true,\n\t\t_linkedTasksById: {},\n\t\t_successorsByTaskId: {},\n\t\t_projectEnd: null,\n\t\t\n\t\t_calculateSlacks: function(){\n\t\t\tvar linkedTasks = linksBuilder.getLinkedTasks();\n\t\t\t\n\t\t\tvar loops = graphHelper.findLoops(linkedTasks);\n\t\t\tif(loops.length){\n\t\t\t\tgantt.callEvent(\"onAutoScheduleCircularLink\", [loops]);\n\t\t\t\tvar loopLinks = {};\n\t\t\t\t\n\t\t\t\tloops.forEach(function(loop){\n\t\t\t\t\t// remove loop\n\t\t\t\t\tloop.linkKeys.forEach(function(key){\n\t\t\t\t\t\tloopLinks[key] = true;\n\t\t\t\t\t});\n\t\t\t\t\t//const problemLink = loop.linkKeys[0];\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tfor(var i = 0; i < linkedTasks.length; i++){\n\t\t\t\t\tif(linkedTasks[i].hashSum in loopLinks){\n\t\t\t\t\t\tlinkedTasks.splice(i, 1);\n\t\t\t\t\t\ti--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tconst reversedOrder = graphHelper.topologicalSort(linkedTasks).reverse();\n\t\t\tconst successorsByTaskId = {};\n\t\t\tlinkedTasks.forEach((entry) => {\n\n\t\t\t\t// get successors\n\t\t\t\tif (!successorsByTaskId[entry.source]) {\n\t\t\t\t\tsuccessorsByTaskId[entry.source] = {\n\t\t\t\t\t\tlinked: []\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tsuccessorsByTaskId[entry.source].linked.push({\n\t\t\t\t\ttarget: entry.target,\n\t\t\t\t\tlink: entry\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tconst distCalculator = {\n\t\t\t\t_cache: {},\n\t\t\t\tgetDist: function(source, target){\n\t\t\t\t\tconst key = `${source.id}_${target.id}`;\n\t\t\t\t\tif(this._cache[key]){\n\t\t\t\t\t\treturn this._cache[key];\n\t\t\t\t\t}else{\n\t\t\t\t\t\tconst dist = gantt.calculateDuration({\n\t\t\t\t\t\t\tstart_date: source.end_date,\n\t\t\t\t\t\t\tend_date: target.start_date,\n\t\t\t\t\t\t\ttask: source});\n\t\t\t\t\t\t\n\t\t\t\t\t\tthis._cache[key] = dist;\n\t\t\t\t\t\treturn dist;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis._projectEnd = gantt.getSubtaskDates().end_date;\n\t\t\tthis._calculateFreeSlack(linkedTasks, reversedOrder, successorsByTaskId, distCalculator);\n\t\t\tthis._calculateTotalSlack(linkedTasks, reversedOrder, successorsByTaskId, distCalculator);\n\t\t},\n\t\t_isCompletedTask: function(task){\n\t\t\treturn gantt.config.auto_scheduling_use_progress && task.progress == 1;\n\t\t},\n\t\t_calculateFreeSlack: function(linkedTasks, orderedFromEnd, successorsMap, distCalculator){\n\t\t\t\n\t\t\tconst freeSlack = this._freeSlack = {};\n\t\t\tconst tasksToDo = {};\n\t\t\tgantt.eachTask(function(task){\n\t\t\t\tif(!gantt.isSummaryTask(task)){\n\t\t\t\t\ttasksToDo[task.id] = task;\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst processedTasks = {};\n\t\t\tlinkedTasks.forEach((entry) => {\n\t\t\t\tconst task = tasksToDo[entry.source];\n\t\t\t\t// GS-1995: Don't calculate slack if the task's parent is not loaded\n\t\t\t\tif (!task){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tprocessedTasks[entry.source] = true;\n\t\t\t\tlet ownSlack = distCalculator.getDist(task, gantt.getTask(entry.target));\n\t\t\t\townSlack -= entry.lag || 0;\n\n\t\t\t\tif(freeSlack[entry.source] !== undefined){\n\t\t\t\t\tfreeSlack[entry.source] = Math.min(ownSlack, freeSlack[entry.source]);\n\t\t\t\t}else{\n\t\t\t\t\tfreeSlack[entry.source] = ownSlack;\n\t\t\t\t}\n\t\t\t});\n\t\t\tfor(const id in tasksToDo){\n\t\t\t\tif(processedTasks[id]){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst task = tasksToDo[id];\n\t\t\t\tif(this._isCompletedTask(task) || task.unscheduled){\n\t\t\t\t\tfreeSlack[task.id] = 0;\n\t\t\t\t}else{\n\t\t\t\t\tfreeSlack[task.id] = gantt.calculateDuration({start_date: task.end_date, end_date: this._projectEnd, task:task});\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\treturn this._freeSlack;\n\n\t\t},\n\t\t_disconnectedTaskSlack(task){\n\t\t\tif(this._isCompletedTask(task)){\n\t\t\t\treturn 0;\n\t\t\t}else{\n\t\t\t\treturn Math.max(gantt.calculateDuration(task.end_date, this._projectEnd), 0);\n\t\t\t}\n\t\t},\n\t\t_calculateTotalSlack: function(linkedTasks, orderedFromEnd, successorsMap, distCalculator) {\n\t\t\tthis._totalSlack = {};\n\t\t\tthis._slackNeedCalculate = false;\n\t\t\tvar totalSlackByTaskId = {};\n\t\t\tvar tasks = gantt.getTaskByTime();\n\n\t\t\tfor(var i = 0; i < orderedFromEnd.length; i++){\n\t\t\t\tconst task = gantt.getTask(orderedFromEnd[i]);\n\t\t\t\t\n\t\t\t\tif(this._isCompletedTask(task)){\n\t\t\t\t\ttotalSlackByTaskId[task.id] = 0;\n\t\t\t\t} else if(!successorsMap[task.id] && !gantt.isSummaryTask(task)){\n\t\t\t\t\ttotalSlackByTaskId[task.id] = this.getFreeSlack(task);\n\t\t\t\t}else{\n\t\t\t\t\tconst successorLinks = successorsMap[task.id].linked;\n\t\t\t\t\tlet totalSlack = null;\n\t\t\t\t\tfor(var j = 0; j < successorLinks.length; j++){\n\t\t\t\t\t\tconst successorLink = successorLinks[j];\n\t\t\t\t\t\tconst successor = gantt.getTask(successorLink.target);\n\t\t\t\t\t\tlet successorSlack = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(totalSlackByTaskId[successor.id] !== undefined){\n\t\t\t\t\t\t\tsuccessorSlack += totalSlackByTaskId[successor.id];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tsuccessorSlack += distCalculator.getDist(task, successor);\n\n\t\t\t\t\t\tsuccessorSlack -= successorLink.link.lag || 0;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tif(totalSlack === null){\n\t\t\t\t\t\t\ttotalSlack = successorSlack;\n\t\t\t\t\t\t} else{\n\t\t\t\t\t\t\ttotalSlack = Math.min(totalSlack, successorSlack);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttotalSlackByTaskId[task.id] = totalSlack || 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\ttasks.forEach(function(task){\n\t\t\t\tif(totalSlackByTaskId[task.id] === undefined && !gantt.isSummaryTask(task)){\n\t\t\t\t\ttotalSlackByTaskId[task.id] = this.getFreeSlack(task);\n\t\t\t\t}\n\t\t\t}.bind(this));\n\t\t\t\n\t\t\tthis._totalSlack = totalSlackByTaskId;\n\t\t\treturn this._totalSlack;\n\t\t},\n\n\t\t_resetTotalSlackCache: function() {\n\t\t\tthis._slackNeedCalculate = true;\n\t\t},\n\n\t\t_shouldCalculateTotalSlack: function() {\n\t\t\treturn this._slackNeedCalculate;\n\t\t},\n\n\t\tgetFreeSlack: function(task) {\n\t\t\tif (this._shouldCalculateTotalSlack()) {\n\t\t\t\tthis._calculateSlacks();\n\t\t\t}\n\t\t\tif (!gantt.isTaskExists(task.id)) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(this._isCompletedTask(task)){\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif(gantt.isSummaryTask(task)){\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\treturn this._freeSlack[task.id] || 0; \n\t\t},\n\n\t\tgetTotalSlack: function(task) {\n\t\t\tif (this._shouldCalculateTotalSlack()) {\n\t\t\t\tthis._calculateSlacks();\n\t\t\t}\n\t\t\tif (task === undefined) {\n\t\t\t\treturn this._totalSlack;\n\t\t\t}\n\t\t\t\n\t\t\tvar id;\n\t\t\tif (task.id !== undefined){\n\t\t\t\tid = task.id;\n\t\t\t}else{\n\t\t\t\tid = task;\n\t\t\t}\n\n\t\t\tif(this._isCompletedTask(task)){\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(this._totalSlack[id] === undefined){\n\t\t\t\tif(gantt.isSummaryTask(gantt.getTask(id))){\n\t\t\t\t\tvar minSlack = null;\n\t\t\t\t\tgantt.eachTask(function(child){\n\t\t\t\t\t\tvar childSlack = this._totalSlack[child.id];\n\t\t\t\t\t\tif(childSlack !== undefined && (minSlack === null || childSlack < minSlack)){\n\t\t\t\t\t\t\tminSlack = childSlack;\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this), id);\n\t\t\t\t\t\n\t\t\t\t\tif(minSlack !== null){\n\t\t\t\t\t\tthis._totalSlack[id] = minSlack;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tthis._totalSlack[id] = gantt.calculateDuration({\n\t\t\t\t\t\t\tstart_date: task.end_date,\n\t\t\t\t\t\t\tend_date: this._projectEnd,\n\t\t\t\t\t\t\ttask: task\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn this._totalSlack[id];\n\t\t\t\t\t\n\t\t\t\t}else{\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\treturn this._totalSlack[id] || 0;\n\t\t\t}\n\t\t},\n\n\t\tdropCachedFreeSlack: function() {\n\t\t\tthis._freeSlack = {};\n\t\t\tthis._resetTotalSlackCache();\n\t\t},\n\n\t\tinit: function(){\n\t\t\tfunction slackHandler(){\n\t\t\t\t_private.dropCachedFreeSlack();\n\t\t\t}\n\n\t\t\tgantt.attachEvent(\"onAfterLinkAdd\", slackHandler);\n\t\t\tgantt.attachEvent(\"onTaskIdChange\", slackHandler);\n\t\t\tgantt.attachEvent(\"onAfterLinkUpdate\", slackHandler);\n\t\t\tgantt.attachEvent(\"onAfterLinkDelete\", slackHandler);\n\t\t\tgantt.attachEvent(\"onAfterTaskAdd\", slackHandler);\n\t\t\tgantt.attachEvent(\"onAfterTaskUpdate\", slackHandler);\n\t\t\tgantt.attachEvent(\"onAfterTaskDelete\", slackHandler);\n\t\t\tgantt.attachEvent(\"onRowDragEnd\", slackHandler);\n\t\t\tgantt.attachEvent(\"onAfterTaskMove\", slackHandler);\n\t\t\tgantt.attachEvent(\"onParse\", slackHandler);\n\t\t\tgantt.attachEvent(\"onClearAll\", slackHandler);\n\t\t}\n\t};\n\n\treturn _private;\n};","export default function(gantt){\n\tgantt._isProjectEnd = function(task) {\n\t\treturn !(this._hasDuration({\n\t\t\tstart_date: task.end_date,\n\t\t\tend_date: this._getProjectEnd(),\n\t\t\ttask: task\n\t\t}));\n\t};\n\n\treturn {\n\t\t_cache: {},\n\t\t_slackHelper: null,\n\t\treset: function(){\n\t\t\tthis._cache = {};\n\t\t},\n\t\t_calculateCriticalPath: function(){\n\t\t\tthis.reset();\n\t\t},\n\t\t\n\t\tisCriticalTask: function(task){\n\t\t\tif(!task) return false;\n\n\t\t\tif(gantt.config.auto_scheduling_use_progress && task.progress === 1){\n\t\t\t\tthis._cache[task.id] = false;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (task.unscheduled){\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif(this._cache[task.id] === undefined){\n\t\t\t\tif(gantt.isSummaryTask(task)){\n\t\t\t\t\tlet hasCritical = false;\n\t\t\t\t\tgantt.eachTask((function(child){\n\t\t\t\t\t\tif(!hasCritical){\n\t\t\t\t\t\t\thasCritical = this.isCriticalTask(child);\n\t\t\t\t\t\t}\n\t\t\t\t\t}).bind(this), task.id);\n\t\t\t\t\t\n\t\t\t\t\tthis._cache[task.id] = hasCritical;\n\t\t\t\t}else{\n\t\t\t\t\tthis._cache[task.id] = this._slackHelper.getTotalSlack(task) <= 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn this._cache[task.id];\n\t\t},\n\n\t\tinit: function(slackHelper){\n\t\t\tthis._slackHelper = slackHelper;\n\t\t\tvar resetCache = gantt.bind(function(){\n\t\t\t\tthis.reset();\n\t\t\t\treturn true;\n\t\t\t}, this);\n\n\t\t\tvar handleTaskIdChange = gantt.bind(function (oldId, newId) {\n\t\t\t\tif (this._cache) {\n\t\t\t\t\tthis._cache[newId] = this._cache[oldId];\n\t\t\t\t\tdelete this._cache[oldId];\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}, this);\n\n\t\t\tgantt.attachEvent(\"onAfterLinkAdd\", resetCache);\n\t\t\tgantt.attachEvent(\"onAfterLinkUpdate\", resetCache);\n\t\t\tgantt.attachEvent(\"onAfterLinkDelete\", resetCache);\n\t\t\tgantt.attachEvent(\"onAfterTaskAdd\", resetCache);\n\t\t\tgantt.attachEvent(\"onTaskIdChange\", handleTaskIdChange);\n\t\t\tgantt.attachEvent(\"onAfterTaskUpdate\", resetCache);\n\t\t\tgantt.attachEvent(\"onAfterTaskDelete\", resetCache);\n\t\t\tgantt.attachEvent(\"onParse\", resetCache);\n\t\t\tgantt.attachEvent(\"onClearAll\", resetCache);\n\n\n\t\t\tvar criticalPathHandler = function(){\n\t\t\t\tif(gantt.config.highlight_critical_path && !gantt.getState(\"batchUpdate\").batch_update)\n\t\t\t\t\tgantt.render();\n\t\t\t};\n\t\t\tgantt.attachEvent(\"onAfterLinkAdd\", criticalPathHandler);\n\t\t\tgantt.attachEvent(\"onAfterLinkUpdate\", criticalPathHandler);\n\t\t\tgantt.attachEvent(\"onAfterLinkDelete\", criticalPathHandler);\n\t\t\tgantt.attachEvent(\"onAfterTaskAdd\", criticalPathHandler);\n\t\t\tgantt.attachEvent(\"onTaskIdChange\", function (oldId, newId) {\n\t\t\t\tif (gantt.config.highlight_critical_path && gantt.isTaskExists(newId)) {\n\t\t\t\t\tgantt.refreshTask(newId);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tgantt.attachEvent(\"onAfterTaskUpdate\", criticalPathHandler);\n\t\t\tgantt.attachEvent(\"onAfterTaskDelete\", criticalPathHandler);\n\t\t}\n\t};\n};","import { EventsManager } from \"./eventsManager\";\nexport default function(gantt: any){\n\tif (!gantt.ext){\n\t\tgantt.ext = {};\n\t}\n\n\tgantt.ext.dragTimeline = {\n\t\tcreate: () => EventsManager.create(gantt)\n\t};\n\n\tgantt.config.drag_timeline = {\n\t\tenabled: true,\n\t\trender: false\n\t};\n}","export default function(gantt: any){\n\ninterface IBody extends HTMLElement {\n\tmsRequestFullscreen?: () => void;\n\tmozRequestFullScreen?: () => void;\n\twebkitRequestFullscreen?: (ALLOW_KEYBOARD_INPUT: any) => void;\n}\n\n\ninterface IConsole extends Console {\n\twarning?: (str: string) => void;\n}\n\ninterface IDocument extends Document {\n\tfullscreenElement: Element;\n\tmozFullScreenElement?: Element;\n\twebkitFullscreenElement?: Element;\n\tmsFullscreenElement?: Element;\n\twebkitFullscreenEnabled?: boolean;\n\tmozFullScreenEnabled?: boolean;\n\tmsFullscreenEnabled?: boolean;\n\tmsExitFullscreen?: () => void;\n\tmozCancelFullScreen?: () => void;\n\twebkitExitFullscreen?: () => void;\n}\n\ninterface IElement extends Element {\n\tALLOW_KEYBOARD_INPUT?: boolean;\n}\n\ninterface IElementSizes extends ISizes {\n\tmodified: boolean;\n}\n\ninterface ISizes {\n\twidth: null | string;\n\theight: null | string;\n\ttop: null | string;\n\tleft: null | string;\n\tposition: null | string;\n\tzIndex: null | number;\n}\n\nfunction isExpanded() {\n\tconst element = ((document as IDocument).fullscreenElement ||\n\t\t(document as IDocument).mozFullScreenElement ||\n\t\t(document as IDocument).webkitFullscreenElement ||\n\t\t(document as IDocument).msFullscreenElement);\n\treturn !!(element && element === document.body);\n}\n\nfunction isFullscreenAvailable() {\n\ttry {\n\t\treturn (document as IDocument).fullscreenEnabled ||\n\t\t\t(document as IDocument).webkitFullscreenEnabled ||\n\t\t\t(document as IDocument).mozFullScreenEnabled ||\n\t\t\t(document as IDocument).msFullscreenEnabled;\n\t} catch (e) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(\"Fullscreen is not available:\", e); \n\t}\n}\n\nconst state = gantt.$services.getService(\"state\");\nstate.registerProvider(\"fullscreen\", () => {\n\tif (isFullscreenAvailable()){\n\t\treturn { fullscreen: isExpanded() };\n\t} else {\n\t\treturn undefined;\n\t}\n});\n\nlet backupBodyPadding = {\n\toverflow: null,\n\tpadding: null,\n\tpaddingTop: null,\n\tpaddingRight: null,\n\tpaddingBottom: null,\n\tpaddingLeft: null\n};\n\nconst backupElementSizes: IElementSizes = {\n\twidth: null,\n\theight: null,\n\ttop: null,\n\tleft: null,\n\tposition: null,\n\tzIndex: null,\n\tmodified: false\n};\n\nlet backupPositioning = null;\nfunction resetParentPositioning(root){\n\tlet parent = root.parentNode;\n\tconst positions = [];\n\twhile(parent && parent.style){\n\t\tpositions.push({\n\t\t\telement: parent,\n\t\t\toriginalPositioning: parent.style.position\n\t\t});\n\t\tparent.style.position = \"static\";\n\t\tparent = parent.parentNode;\n\t}\n\treturn positions;\n}\n\nfunction restoreParentPositioning(positions: any[]){\n\tpositions.forEach(record => {\n\t\trecord.element.style.position = record.originalPositioning;\n\t});\n}\n\n// expand gantt root element to fullscreen automatically\nfunction setFullScreenSizes() {\n\tconst root = gantt.ext.fullscreen.getFullscreenElement();\n\tconst body = document.body;\n\tupdateSizes(root.style, backupElementSizes);\n\tbackupBodyPadding = {\n\t\toverflow: body.style.overflow,\n\t\tpadding: body.style.padding ? body.style.padding : null,\n\t\tpaddingTop: body.style.paddingTop ? body.style.paddingTop : null,\n\t\tpaddingRight: body.style.paddingRight ? body.style.paddingRight : null,\n\t\tpaddingBottom: body.style.paddingBottom ? body.style.paddingBottom : null,\n\t\tpaddingLeft: body.style.paddingLeft ? body.style.paddingLeft : null\n\t};\n\n\tif (body.style.padding) {\n\t\tbody.style.padding = \"0\";\n\t}\n\tif (body.style.paddingTop) {\n\t\tbody.style.paddingTop = \"0\";\n\t}\n\tif (body.style.paddingRight) {\n\t\tbody.style.paddingRight = \"0\";\n\t}\n\tif (body.style.paddingBottom) {\n\t\tbody.style.paddingBottom = \"0\";\n\t}\n\tif (body.style.paddingLeft) {\n\t\tbody.style.paddingLeft = \"0\";\n\t}\n\n\tbody.style.overflow = \"hidden\";\n\n\troot.style.width = \"100vw\";\n\troot.style.height = \"100vh\";\n\troot.style.top = \"0px\";\n\troot.style.left = \"0px\";\n\troot.style.position = \"absolute\";\n\troot.style.zIndex = 1;\n\tbackupElementSizes.modified = true;\n\tbackupPositioning = resetParentPositioning(root);\n}\n\nfunction restoreSizes() {\n\tconst root = gantt.ext.fullscreen.getFullscreenElement();\n\tconst body = document.body;\n\tif (backupElementSizes.modified) {\n\t\tif (backupBodyPadding.padding) {\n\t\t\tbody.style.padding = backupBodyPadding.padding;\n\t\t}\n\t\tif (backupBodyPadding.paddingTop) {\n\t\t\tbody.style.paddingTop = backupBodyPadding.paddingTop;\n\t\t}\n\t\tif (backupBodyPadding.paddingRight) {\n\t\t\tbody.style.paddingRight = backupBodyPadding.paddingRight;\n\t\t}\n\t\tif (backupBodyPadding.paddingBottom) {\n\t\t\tbody.style.paddingBottom = backupBodyPadding.paddingBottom;\n\t\t}\n\t\tif (backupBodyPadding.paddingLeft) {\n\t\t\tbody.style.paddingLeft = backupBodyPadding.paddingLeft;\n\t\t}\n\n\t\tbody.style.overflow = backupBodyPadding.overflow;\n\t\tbackupBodyPadding = {\n\t\t\toverflow: null,\n\t\t\tpadding: null,\n\t\t\tpaddingTop: null,\n\t\t\tpaddingRight: null,\n\t\t\tpaddingBottom: null,\n\t\t\tpaddingLeft: null\n\t\t};\n\t\tupdateSizes(backupElementSizes, root.style);\n\t\tbackupElementSizes.modified = false;\n\t}\n\trestoreParentPositioning(backupPositioning);\n\tbackupPositioning = null;\n}\n\nfunction updateSizes(source: ISizes, target: ISizes) {\n\ttarget.width = source.width;\n\ttarget.height = source.height;\n\ttarget.top = source.top;\n\ttarget.left = source.left;\n\ttarget.position = source.position;\n\ttarget.zIndex = source.zIndex;\n}\n\nfunction addDOMEvents() {\n\tgantt.event(document, \"webkitfullscreenchange\", onFullScreenChange);\n\tgantt.event(document, \"mozfullscreenchange\", onFullScreenChange);\n\tgantt.event(document, \"MSFullscreenChange\", onFullScreenChange);\n\t// For IE on Win 10\n\tgantt.event(document, \"fullscreenChange\", onFullScreenChange);\n\tgantt.event(document, \"fullscreenchange\", onFullScreenChange);\n}\n\nlet expandGantt = false;\nfunction onFullScreenChange() {\n\tif (!gantt.$container) {\n\t\t// do nothing if gantt is not yet initialized\n\t\treturn;\n\t}\n\tlet event: \"onExpand\" | \"onCollapse\";\n\tconst isBodyExpanded = isExpanded();\n\n\tif (isBodyExpanded) {\n\t\tif (expandGantt) {\n\t\t\tevent = \"onExpand\";\n\t\t\tsetFullScreenSizes();\n\t\t}\n\t} else if (expandGantt) {\n\t\texpandGantt = false;\n\t\tevent = \"onCollapse\";\n\t\trestoreSizes();\n\t}\n\tsetTimeout(() => {\n\t\tgantt.render();\n\t});\n\tsetTimeout(() => {\n\t\tgantt.callEvent(event, [gantt.ext.fullscreen.getFullscreenElement()]);\n\t});\n}\n\nfunction cantFullscreen() {\n\tif (!gantt.$container) { // check is gantt initialized or not\n\t\treturn true;\n\t}\n\tif (!gantt.ext.fullscreen.getFullscreenElement()) {\n\t\treturn true;\n\t}\n\tif (!isFullscreenAvailable()) {\n\t\t// eslint-disable-next-line no-console\n\t\tconst method = (console as IConsole).warning || console.log;\n\t\tmethod(\"The `fullscreen` feature not being allowed, or full-screen mode not being supported\");\n\t\treturn true;\n\t}\n\treturn false;\n}\n\ngantt.ext.fullscreen = {\n\texpand(): void {\n\t\tif (cantFullscreen()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (isExpanded()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!gantt.callEvent(\"onBeforeExpand\", [this.getFullscreenElement()])) {\n\t\t\treturn;\n\t\t}\n\t\texpandGantt = true;\n\n\t\t// we switch body to fullscreen and then expand fullscreen element to viewport\n\t\t// we do it to correct display common elements: lightboxes, tooltip etc.\n\t\tconst element = document.body as IBody;\n\t\tconst requestArguments = element.webkitRequestFullscreen ?\n\t\t\t[(Element as unknown as IElement).ALLOW_KEYBOARD_INPUT] : [];\n\n\t\tconst requestFullscreen = element.msRequestFullscreen ||\n\t\t\telement.mozRequestFullScreen ||\n\t\t\telement.webkitRequestFullscreen ||\n\t\t\telement.requestFullscreen;\n\n\t\tif (requestFullscreen) {\n\t\t\trequestFullscreen.apply(element, requestArguments);\n\t\t}\n\t},\n\tcollapse(): void {\n\t\tif (cantFullscreen()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!isExpanded()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!gantt.callEvent(\"onBeforeCollapse\", [this.getFullscreenElement()])) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst requestExitFullscreen = (document as IDocument).msExitFullscreen ||\n\t\t\t(document as IDocument).mozCancelFullScreen ||\n\t\t\t(document as IDocument).webkitExitFullscreen ||\n\t\t\t(document as IDocument).exitFullscreen;\n\n\t\tif (requestExitFullscreen) {\n\t\t\trequestExitFullscreen.apply(document);\n\t\t}\n\t},\n\ttoggle(): void {\n\t\tif (cantFullscreen()) {\n\t\t\treturn;\n\t\t}\n\t\tif (!isExpanded()) {\n\t\t\tthis.expand();\n\t\t} else {\n\t\t\tthis.collapse();\n\t\t}\n\n\t},\n\tgetFullscreenElement(): HTMLElement {\n\t\treturn gantt.$root;\n\t}\n};\n\ngantt.expand = function() {\n\tgantt.ext.fullscreen.expand();\n};\n\ngantt.collapse = function(){\n\tgantt.ext.fullscreen.collapse();\n};\n\ngantt.attachEvent(\"onGanttReady\", addDOMEvents);\n\n}","import eventable from \"../utils/eventable\";\nimport * as domHelpers from \"../core/ui/utils/dom_helpers\";\n\nimport keyboard_shortcuts from \"./keyboard_navigation/common/keyboard_shortcuts\";\nimport eventhandler from \"./keyboard_navigation/common/eventhandler\";\nimport trap_modal_focus from \"./keyboard_navigation/common/trap_modal_focus\";\nimport gantt_node from \"./keyboard_navigation/elements/gantt_node\";\nimport nav_node from \"./keyboard_navigation/elements/nav_node\";\nimport header_cell from \"./keyboard_navigation/elements/header_cell\";\nimport task_row from \"./keyboard_navigation/elements/task_row\";\nimport task_cell from \"./keyboard_navigation/elements/task_cell\";\nimport modals from \"./keyboard_navigation/modals\";\nimport core from \"./keyboard_navigation/core\";\n\n\n\nexport default function(gantt){\n\tfunction setupKeyNav(gantt){\n\t\tgantt.config.keyboard_navigation = true;\n\t\tgantt.config.keyboard_navigation_cells = false;\n\n\t\tgantt.$keyboardNavigation = {};\n\n\t\tgantt._compose = function(){\n\t\t\tvar parts = Array.prototype.slice.call(arguments, 0);\n\t\t\tvar res = {};\n\t\t\tfor(var i = 0; i < parts.length; i++){\n\t\t\t\tvar obj = parts[i];\n\t\t\t\tif(typeof obj == \"function\"){\n\t\t\t\t\tobj = new obj();\n\t\t\t\t}\n\n\t\t\t\tfor(var p in obj){\n\t\t\t\t\tres[p] = obj[p];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn res;\n\t\t};\n\n\t\tkeyboard_shortcuts(gantt);\n\t\teventhandler(gantt);\n\t\ttrap_modal_focus(gantt);\n\t\tgantt_node(gantt);\n\t\tnav_node(gantt);\n\t\theader_cell(gantt);\n\t\ttask_row(gantt);\n\t\ttask_cell(gantt);\n\t\tmodals(gantt);\n\t\tcore(gantt);\n\n\n\t\t(function(){\n\t\t\tvar dispatcher = gantt.$keyboardNavigation.dispatcher;\n\n\t\t\tdispatcher.isTaskFocused = function(id){\n\t\t\t\tvar node = dispatcher.activeNode;\n\t\t\t\tif(node instanceof gantt.$keyboardNavigation.TaskRow || node instanceof gantt.$keyboardNavigation.TaskCell) {\n\t\t\t\t\tif (node.taskId == id) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t};\n\n\t\t\tvar keyDownHandler = function(e){\n\t\t\t\tif(!gantt.config.keyboard_navigation) return;\n\t\t\t\t// GS-734 & GS-1078: we don't need keyboard navigation inside inline editors\n\t\t\t\tif(!gantt.config.keyboard_navigation_cells && isInlineEditorCell(e)) return;\n\n\t\t\t\tif (isNoKeyboardNavigationElement(e) || isLightboxElement(e)){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treturn dispatcher.keyDownHandler(e);\n\t\t\t};\n\n\t\t\tvar focusHandler = function(e){\n\t\t\t\tif(dispatcher.$preventDefault){\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tgantt.$container.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t// do nothing if key-nav focus is already planned\n\t\t\t\t} else if (!dispatcher.awaitsFocus()) {\n\t\t\t\t\t// otherwise - re-focus key-nav element on gantt focus\n\t\t\t\t\tdispatcher.focusGlobalNode();\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t\tvar reFocusActiveNode = function(){\n\t\t\t\tif(!dispatcher.isEnabled())\n\t\t\t\t\treturn;\n\n\t\t\t\tconst outsideGantt = !domHelpers.isChildOf(document.activeElement, gantt.$container) && document.activeElement.localName != \"body\";\n\t\t\t\tvar activeNode = dispatcher.getActiveNode();\n\t\t\t\tif(!activeNode || outsideGantt)\n\t\t\t\t\treturn;\n\n\t\t\t\tvar domElement = activeNode.getNode();\n\t\t\t\tvar top, left;\n\t\t\t\tif(domElement && domElement.parentNode){\n\t\t\t\t\ttop = domElement.parentNode.scrollTop;\n\t\t\t\t\tleft = domElement.parentNode.scrollLeft;\n\n\t\t\t\t}\n\n\t\t\t\tactiveNode.focus(true);\n\n\t\t\t\tif(domElement && domElement.parentNode){\n\t\t\t\t\tdomElement.parentNode.scrollTop = top;\n\t\t\t\t\tdomElement.parentNode.scrollLeft = left;\n\t\t\t\t}\n\t\t\t};\n\n\n\t\t\tgantt.attachEvent(\"onDataRender\", function(){\n\t\t\t\tif(!gantt.config.keyboard_navigation) return;\n\t\t\t\treFocusActiveNode();\n\t\t\t});\n\n\t\t\tgantt.attachEvent(\"onGanttRender\", function(){\n\t\t\t\t//GS-2230: in case if `getGanttInstance` created without container\n\t\t\t\tif(!gantt.$root) return;\n\t\t\t\tgantt.eventRemove(gantt.$root, \"keydown\", keyDownHandler);\n\t\t\t\tgantt.eventRemove(gantt.$container, \"focus\", focusHandler);\n\t\t\t\tgantt.eventRemove(gantt.$container, \"mousedown\", mousedownHandler);\n\n\t\t\t\tif(gantt.config.keyboard_navigation){\n\n\t\t\t\t\tgantt.event(gantt.$root, \"keydown\", keyDownHandler);\n\t\t\t\t\tgantt.event(gantt.$container, \"focus\", focusHandler);\n\t\t\t\t\tgantt.event(gantt.$container, \"mousedown\", mousedownHandler);\n\t\t\t\t\tgantt.$container.setAttribute(\"tabindex\", \"0\");\n\n\t\t\t\t}else{\n\t\t\t\t\tgantt.$container.removeAttribute(\"tabindex\");\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tfunction getTaskNodeConstructor(){\n\t\t\t\tif (gantt.config.keyboard_navigation_cells) {\n\t\t\t\t\treturn gantt.$keyboardNavigation.TaskCell;\n\t\t\t\t} else {\n\t\t\t\t\treturn gantt.$keyboardNavigation.TaskRow;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction isInlineEditorCell(e){\n\t\t\t\treturn !!domHelpers.closest(e.target, \".gantt_grid_editor_placeholder\");\n\t\t\t}\n\t\t\t// GS-1445. Cancel keyboard navigation within custom elements\n\t\t\tfunction isNoKeyboardNavigationElement(e){\n\t\t\t\treturn !!domHelpers.closest(e.target, \".no_keyboard_navigation\");\n\t\t\t}\n\t\t\tfunction isLightboxElement(e){\n\t\t\t\treturn !!domHelpers.closest(e.target, \".gantt_cal_light\");\n\t\t\t}\n\n\t\t\tfunction mousedownHandler(e){\n\t\t\t\tif(!gantt.config.keyboard_navigation) return true;\n\t\t\t\t// GS-734 & GS-1078: we don't need keyboard navigation inside inline editors\n\t\t\t\tif(!gantt.config.keyboard_navigation_cells && isInlineEditorCell(e)) return true;\n\n\t\t\t\tif (isNoKeyboardNavigationElement(e)){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar focusNode;\n\t\t\t\tvar locateTask = dispatcher.fromDomElement(e);\n\t\t\t\tif(locateTask){\n\t\t\t\t\t//var node = getTaskNodeConstructor();\n\t\t\t\t\tif(dispatcher.activeNode instanceof gantt.$keyboardNavigation.TaskCell && domHelpers.isChildOf(e.target, gantt.$task)){\n\t\t\t\t\t\tlocateTask = new gantt.$keyboardNavigation.TaskCell(locateTask.taskId, dispatcher.activeNode.columnIndex);\n\t\t\t\t\t}\n\t\t\t\t\tfocusNode = locateTask;\n\t\t\t\t}\n\t\t\t\tif (focusNode) {\n\t\t\t\t\tif (!dispatcher.isEnabled()) {\n\t\t\t\t\t\tdispatcher.activeNode = focusNode;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatcher.delay(function () {\n\t\t\t\t\t\t\tdispatcher.setActiveNode(focusNode);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// empty click should drop focus from gantt, insert of reselecting default node\n\t\t\t\t\tdispatcher.$preventDefault = true;\n\t\t\t\t\tsetTimeout(function(){\n\t\t\t\t\t\tdispatcher.$preventDefault = false;\n\t\t\t\t\t}, 300);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar onReady = gantt.attachEvent(\"onGanttReady\", function(){\n\t\t\t\t// restore focus on repainted tasks\n\t\t\t\tgantt.detachEvent(onReady);\n\n\t\t\t\tgantt.$data.tasksStore.attachEvent(\"onStoreUpdated\", function(id){\n\t\t\t\t\tif (gantt.config.keyboard_navigation && dispatcher.isEnabled()) {\n\t\t\t\t\t\tconst currentNode = dispatcher.getActiveNode();\n\t\t\t\t\t\tconst grid = gantt.$ui.getView(\"grid\");\n\t\t\t\t\t\tconst top = grid.getItemTop(id);\n\t\t\t\t\t\tconst gridDataTopScroll = grid.$grid_data.scrollTop;\n\t\t\t\t\t\tconst gridDataBottomScroll = gridDataTopScroll + grid.$grid_data.getBoundingClientRect().height;\n\t\t\t\t\t\tif(currentNode && currentNode.taskId == id){\n\t\t\t\t\t\t\t// GS-2539: Don't refocus the node if it is selected and outside the visible range in the grid\n\t\t\t\t\t\t\tif(gridDataTopScroll <= top && gridDataBottomScroll >= top){\n\t\t\t\t\t\t\t\treFocusActiveNode();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif(gantt._smart_render){\n\t\t\t\t\tvar updateRender = gantt._smart_render._redrawTasks;\n\t\t\t\t\tgantt._smart_render._redrawTasks = function(renderers, items){\n\t\t\t\t\t\tif(gantt.config.keyboard_navigation && dispatcher.isEnabled()){\n\t\t\t\t\t\t\tvar currentNode = dispatcher.getActiveNode();\n\t\t\t\t\t\t\tif(currentNode && currentNode.taskId !== undefined){\n\t\t\t\t\t\t\t\tvar focusedItemVisible = false;\n\t\t\t\t\t\t\t\tfor(var i = 0; i < items.length; i++){\n\t\t\t\t\t\t\t\t\tif(items[i].id == currentNode.taskId && items[i].start_date){\n\t\t\t\t\t\t\t\t\t\tfocusedItemVisible = true;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(!focusedItemVisible){\n\t\t\t\t\t\t\t\t\titems.push(gantt.getTask(currentNode.taskId));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar res = updateRender.apply(this, arguments);\n\n\t\t\t\t\t\treturn res;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t\tlet createdTaskId = null;\n\t\t\tlet keepFocusOnNewTask = false;\n\t\t\tgantt.attachEvent(\"onTaskCreated\", function (task) {\n\t\t\t\tcreatedTaskId = task.id;\n\t\t\t\treturn true;\n\t\t\t});\n\n\t\t\tgantt.attachEvent(\"onAfterTaskAdd\", function(id,item){\n\t\t\t\tif(!gantt.config.keyboard_navigation) return true;\n\t\t\t\tif(dispatcher.isEnabled()){\n\n\t\t\t\t\t// GS-1394. After adding a new task, the focus shouldn't change to the placeholder task\n\t\t\t\t\tif (id == createdTaskId) {\n\t\t\t\t\t\tkeepFocusOnNewTask = true;\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tkeepFocusOnNewTask = false;\n\t\t\t\t\t\t\tcreatedTaskId = null;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (keepFocusOnNewTask && item.type == gantt.config.types.placeholder) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar columnIndex = 0;\n\t\t\t\t\tvar node = dispatcher.activeNode;\n\t\t\t\t\tif(node instanceof gantt.$keyboardNavigation.TaskCell){\n\t\t\t\t\t\tcolumnIndex = node.columnIndex;\n\t\t\t\t\t}\n\t\t\t\t\tvar nodeConstructor = getTaskNodeConstructor();\n\n\t\t\t\t\tif (item.type == gantt.config.types.placeholder && gantt.config.placeholder_task.focusOnCreate === false) {\n\t\t\t\t\t\t// do not focus on the placeholder task\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatcher.setActiveNode(new nodeConstructor(id, columnIndex));\n\t\t\t\t\t}\n\n\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tgantt.attachEvent(\"onTaskIdChange\", function(oldId, newId){\n\t\t\t\tif(!gantt.config.keyboard_navigation) return true;\n\n\t\t\t\tvar node = dispatcher.activeNode;\n\t\t\t\tif(dispatcher.isTaskFocused(oldId)){\n\t\t\t\t\tnode.taskId = newId;\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t});\n\n\t\t\tvar interval = setInterval(function(){\n\t\t\t\tif(!gantt.config.keyboard_navigation) return;\n\t\t\t\tif(!dispatcher.isEnabled()){\n\t\t\t\t\tdispatcher.enable();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}, 500);\n\n\t\t\tgantt.attachEvent(\"onDestroy\", function(){\n\t\t\t\tclearInterval(interval);\n\t\t\t});\n\n\t\t\tfunction getScopeName(obj){\n\t\t\t\tif(obj instanceof gantt.$keyboardNavigation.GanttNode){\n\t\t\t\t\treturn \"gantt\";\n\t\t\t\t}else if(obj instanceof gantt.$keyboardNavigation.HeaderCell){\n\t\t\t\t\treturn \"headerCell\";\n\t\t\t\t}else if(obj instanceof gantt.$keyboardNavigation.TaskRow){\n\t\t\t\t\treturn \"taskRow\";\n\t\t\t\t}else if(obj instanceof gantt.$keyboardNavigation.TaskCell){\n\t\t\t\t\treturn \"taskCell\";\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tfunction getScope(mode){\n\t\t\t\tvar scopes = {\n\t\t\t\t\t\"gantt\":gantt.$keyboardNavigation.GanttNode,\n\t\t\t\t\t\"headerCell\": gantt.$keyboardNavigation.HeaderCell,\n\t\t\t\t\t\"taskRow\": gantt.$keyboardNavigation.TaskRow,\n\t\t\t\t\t\"taskCell\": gantt.$keyboardNavigation.TaskCell\n\t\t\t\t};\n\n\t\t\t\treturn scopes[mode] || scopes.gantt;\n\t\t\t}\n\n\t\t\tfunction findVisibleColumnIndex(columnName) {\n\t\t\t\tvar columns = gantt.getGridColumns();\n\t\t\t\tfor (var i = 0; i < columns.length; i++){\n\t\t\t\t\tif(columns[i].name == columnName){\n\t\t\t\t\t\treturn i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tvar keyNavFacade = {};\n\t\t\teventable(keyNavFacade);\n\t\t\tgantt.mixin(keyNavFacade, {\n\t\t\t\taddShortcut: function(shortcut, handler, scope){\n\t\t\t\t\tvar scopeObject = getScope(scope);\n\t\t\t\t\tif(scopeObject){\n\t\t\t\t\t\tscopeObject.prototype.bind(shortcut, handler);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetShortcutHandler: function(shortcut, scope){\n\t\t\t\t\tvar commands = gantt.$keyboardNavigation.shortcuts.parse(shortcut);\n\t\t\t\t\tif(commands.length){\n\t\t\t\t\t\treturn keyNavFacade.getCommandHandler(commands[0], scope);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tgetCommandHandler: function(command, scope){\n\t\t\t\t\tvar scopeObject = getScope(scope);\n\t\t\t\t\tif(scopeObject){\n\t\t\t\t\t\tif(command){\n\t\t\t\t\t\t\treturn scopeObject.prototype.findHandler(command);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tremoveShortcut: function(shortcut, scope){\n\t\t\t\t\tvar scopeObject = getScope(scope);\n\t\t\t\t\tif(scopeObject){\n\t\t\t\t\t\tscopeObject.prototype.unbind(shortcut);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tfocus: function(config){\n\t\t\t\t\tvar type = config ? config.type : null;\n\t\t\t\t\tvar constructor = getScope(type);\n\t\t\t\t\tvar node;\n\t\t\t\t\tswitch (type){\n\t\t\t\t\t\tcase \"taskCell\":\n\t\t\t\t\t\t\tnode = new constructor(config.id, findVisibleColumnIndex(config.column));\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"taskRow\":\n\t\t\t\t\t\t\tnode = new constructor(config.id);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"headerCell\":\n\t\t\t\t\t\t\tnode = new constructor(findVisibleColumnIndex(config.column));\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdispatcher.delay(function(){\n\t\t\t\t\t\tif(node){\n\t\t\t\t\t\t\tdispatcher.setActiveNode(node);\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tdispatcher.enable();\n\t\t\t\t\t\t\tif(!dispatcher.getActiveNode()){\n\n\t\t\t\t\t\t\t\tdispatcher.setDefaultNode();\n\t\t\t\t\t\t\t}else{\n\n\t\t\t\t\t\t\t\tif(!dispatcher.awaitsFocus()){\n\t\t\t\t\t\t\t\t\tdispatcher.enable();\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\tgetActiveNode: function(){\n\t\t\t\t\tif(dispatcher.isEnabled()){\n\t\t\t\t\t\tvar node = dispatcher.getActiveNode();\n\t\t\t\t\t\tvar scope = getScopeName(node);\n\t\t\t\t\t\tvar columns = gantt.getGridColumns();\n\t\t\t\t\t\tswitch (scope){\n\t\t\t\t\t\t\tcase \"taskCell\":\n\t\t\t\t\t\t\t\treturn {type:\"taskCell\", id:node.taskId, column:columns[node.columnIndex].name};\n\t\t\t\t\t\t\tcase \"taskRow\":\n\t\t\t\t\t\t\t\treturn {type:\"taskRow\", id:node.taskId};\n\t\t\t\t\t\t\tcase \"headerCell\":\n\t\t\t\t\t\t\t\treturn {type:\"headerCell\", column:columns[node.index].name};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tgantt.$keyboardNavigation.facade = keyNavFacade;\n\n\t\t\tgantt.ext.keyboardNavigation = keyNavFacade;\n\t\t\tgantt.focus = function(){\n\t\t\t\tkeyNavFacade.focus();\n\t\t\t};\n\t\t\tgantt.addShortcut = keyNavFacade.addShortcut;\n\t\t\tgantt.getShortcutHandler = keyNavFacade.getShortcutHandler;\n\t\t\tgantt.removeShortcut = keyNavFacade.removeShortcut;\n\t\t})();\n\n\n\t}\n\n\tsetupKeyNav(gantt);\n\n\n\n};","export default function(gantt) {\n\n\tgantt.$keyboardNavigation.shortcuts = {\n\t\tcreateCommand: function () {\n\t\t\treturn {\n\t\t\t\tmodifiers: {\n\t\t\t\t\t\"shift\": false,\n\t\t\t\t\t\"alt\": false,\n\t\t\t\t\t\"ctrl\": false,\n\t\t\t\t\t\"meta\": false\n\t\t\t\t},\n\t\t\t\tkeyCode: null\n\t\t\t};\n\t\t},\n\t\tparse: function (shortcut) {\n\t\t\tvar commands = [];\n\n\t\t\tvar expr = this.getExpressions(this.trim(shortcut));\n\t\t\tfor (var i = 0; i < expr.length; i++) {\n\t\t\t\tvar words = this.getWords(expr[i]);\n\n\t\t\t\tvar command = this.createCommand();\n\n\t\t\t\tfor (var j = 0; j < words.length; j++) {\n\t\t\t\t\tif (this.commandKeys[words[j]]) {\n\t\t\t\t\t\tcommand.modifiers[words[j]] = true;\n\t\t\t\t\t} else if (this.specialKeys[words[j]]) {\n\t\t\t\t\t\tcommand.keyCode = this.specialKeys[words[j]];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcommand.keyCode = words[j].charCodeAt(0);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcommands.push(command);\n\t\t\t}\n\t\t\treturn commands;\n\t\t},\n\n\t\tgetCommandFromEvent: function (domEvent) {\n\t\t\tvar command = this.createCommand();\n\t\t\tcommand.modifiers.shift = !!domEvent.shiftKey;\n\t\t\tcommand.modifiers.alt = !!domEvent.altKey;\n\t\t\tcommand.modifiers.ctrl = !!domEvent.ctrlKey;\n\t\t\tcommand.modifiers.meta = !!domEvent.metaKey;\n\t\t\tcommand.keyCode = domEvent.which || domEvent.keyCode;\n\n\t\t\tif(command.keyCode >= 96 && command.keyCode <= 105){\n\t\t\t\t// numpad keys 96-105 -> 48-57\n\t\t\t\tcommand.keyCode -= 48;//convert numpad number code to regular number code\n\t\t\t}\n\n\t\t\tvar printableKey = String.fromCharCode(command.keyCode);\n\t\t\tif (printableKey) {\n\t\t\t\tcommand.keyCode = printableKey.toLowerCase().charCodeAt(0);\n\t\t\t}\n\t\t\treturn command;\n\t\t},\n\n\t\tgetHashFromEvent: function (domEvent) {\n\t\t\treturn this.getHash(this.getCommandFromEvent(domEvent));\n\t\t},\n\n\t\tgetHash: function (command) {\n\t\t\tvar parts = [];\n\t\t\tfor (var i in command.modifiers) {\n\t\t\t\tif (command.modifiers[i]) {\n\t\t\t\t\tparts.push(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tparts.push(command.keyCode);\n\n\t\t\treturn parts.join(this.junctionChar);\n\t\t},\n\n\t\tgetExpressions: function (shortcut) {\n\t\t\treturn shortcut.split(this.junctionChar);\n\t\t},\n\t\tgetWords: function (term) {\n\t\t\treturn term.split(this.combinationChar);\n\t\t},\n\t\ttrim: function (shortcut) {\n\t\t\treturn shortcut.replace(/\\s/g, \"\");\n\t\t},\n\t\tjunctionChar: \",\",\n\t\tcombinationChar: \"+\",\n\t\tcommandKeys: {\n\t\t\t\"shift\": 16,\n\t\t\t\"alt\": 18,\n\t\t\t\"ctrl\": 17,\n\t\t\t\"meta\": true\n\t\t},\n\t\tspecialKeys: {\n\t\t\t\"backspace\": 8,\n\t\t\t\"tab\": 9,\n\t\t\t\"enter\": 13,\n\t\t\t\"esc\": 27,\n\t\t\t\"space\": 32,\n\t\t\t\"up\": 38,\n\t\t\t\"down\": 40,\n\t\t\t\"left\": 37,\n\t\t\t\"right\": 39,\n\t\t\t\"home\": 36,\n\t\t\t\"end\": 35,\n\t\t\t\"pageup\": 33,\n\t\t\t\"pagedown\": 34,\n\t\t\t\"delete\": 46,\n\t\t\t\"insert\": 45,\n\t\t\t\"plus\": 107,\n\t\t\t\"f1\": 112,\n\t\t\t\"f2\": 113,\n\t\t\t\"f3\": 114,\n\t\t\t\"f4\": 115,\n\t\t\t\"f5\": 116,\n\t\t\t\"f6\": 117,\n\t\t\t\"f7\": 118,\n\t\t\t\"f8\": 119,\n\t\t\t\"f9\": 120,\n\t\t\t\"f10\": 121,\n\t\t\t\"f11\": 122,\n\t\t\t\"f12\": 123\n\t\t}\n\t};\n};","export default function(gantt) {\n\n\tgantt.$keyboardNavigation.EventHandler = {\n\t\t_handlers: null,\n\t\tfindHandler: function (command) {\n\t\t\tif (!this._handlers) this._handlers = {};\n\t\t\tvar shortcuts = gantt.$keyboardNavigation.shortcuts;\n\t\t\tvar hash = shortcuts.getHash(command);\n\n\t\t\treturn this._handlers[hash];\n\t\t},\n\n\t\tdoAction: function (command, e) {\n\t\t\tvar handler = this.findHandler(command);\n\t\t\tif (handler) {\n\t\t\t\tvar eventFacade = gantt.$keyboardNavigation.facade;\n\n\t\t\t\tif(eventFacade.callEvent(\"onBeforeAction\", [command, e]) === false){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\thandler.call(this, e);\n\n\t\t\t\tif (e.preventDefault) e.preventDefault();\n\t\t\t\telse e.returnValue = false;\n\n\t\t\t}\n\t\t},\n\t\tbind: function (shortcut, handler) {\n\t\t\tif (!this._handlers) this._handlers = {};\n\n\t\t\tvar shortcuts = gantt.$keyboardNavigation.shortcuts;\n\n\t\t\tvar commands = shortcuts.parse(shortcut);\n\t\t\tfor (var i = 0; i < commands.length; i++) {\n\t\t\t\tthis._handlers[shortcuts.getHash(commands[i])] = handler;\n\t\t\t}\n\t\t},\n\t\tunbind: function (shortcut) {\n\t\t\tvar shortcuts = gantt.$keyboardNavigation.shortcuts;\n\n\t\t\tvar commands = shortcuts.parse(shortcut);\n\t\t\tfor (var i = 0; i < commands.length; i++) {\n\t\t\t\tif (this._handlers[shortcuts.getHash(commands[i])]) {\n\t\t\t\t\tdelete this._handlers[shortcuts.getHash(commands[i])];\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tbindAll: function (map) {\n\t\t\tfor (var i in map) {\n\t\t\t\tthis.bind(i, map[i]);\n\t\t\t}\n\t\t},\n\t\tinitKeys: function () {\n\t\t\tif (!this._handlers)\n\t\t\t\tthis._handlers = {};\n\t\t\tif (this.keys) {\n\t\t\t\tthis.bindAll(this.keys);\n\t\t\t}\n\t\t}\n\t};\n\n};","import * as domHelpers from \"../../../core/ui/utils/dom_helpers\";\n\nexport default function(gantt) {\n\n\t(function () {\n\t\t\n\t\tgantt.$keyboardNavigation.getFocusableNodes = domHelpers.getFocusableNodes;\n\n\t\tgantt.$keyboardNavigation.trapFocus = function trapFocus(root, e) {\n\t\t\tif (e.keyCode != 9) return false;\n\n\t\t\tvar focusable = gantt.$keyboardNavigation.getFocusableNodes(root);\n\t\t\tvar currentFocus = domHelpers.getActiveElement();\n\t\t\tvar currentIndex = -1;\n\t\t\tfor (var i = 0; i < focusable.length; i++) {\n\t\t\t\tif (focusable[i] == currentFocus) {\n\t\t\t\t\tcurrentIndex = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (e.shiftKey) {\n\t\t\t\t// back tab\n\t\t\t\tif (currentIndex <= 0) {\n\t\t\t\t\t// go to the last element if we focused on the first\n\t\t\t\t\tvar lastItem = focusable[focusable.length - 1];\n\t\t\t\t\tif (lastItem) {\n\t\t\t\t\t\tlastItem.focus();\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\t// forward tab\n\t\t\t\tif (currentIndex >= focusable.length - 1) {\n\t\t\t\t\t// forward tab from last element should go back to the first element\n\t\t\t\t\tvar firstItem = focusable[0];\n\t\t\t\t\tif (firstItem) {\n\t\t\t\t\t\tfirstItem.focus();\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t};\n\t})();\n\n};","export default function(gantt) {\n\n\tgantt.$keyboardNavigation.GanttNode = function () {\n\t};\n\n\tgantt.$keyboardNavigation.GanttNode.prototype = gantt._compose(\n\t\tgantt.$keyboardNavigation.EventHandler,\n\t\t{\n\n\t\t\tfocus: function () {\n\t\t\t\tgantt.focus();\n\t\t\t},\n\n\t\t\tblur: function () {\n\n\t\t\t},\n\n\t\t\tisEnabled: function () {\n\t\t\t\treturn gantt.$container.hasAttribute(\"tabindex\");\n\t\t\t},\n\n\t\t\tscrollHorizontal: function scrollHorizontal(dir) {\n\t\t\t\tvar date = gantt.dateFromPos(gantt.getScrollState().x);\n\t\t\t\tvar scale = gantt.getScale();\n\t\t\t\tvar step = dir < 0 ? -scale.step : scale.step;\n\t\t\t\tdate = gantt.date.add(date, step, scale.unit);\n\t\t\t\tgantt.scrollTo(gantt.posFromDate(date));\n\t\t\t},\n\n\t\t\tscrollVertical: function scrollVertical(dir) {\n\t\t\t\tvar top = gantt.getScrollState().y;\n\t\t\t\tvar step = gantt.config.row_height;\n\t\t\t\tgantt.scrollTo(null, top + (dir < 0 ? -1 : 1) * step);\n\t\t\t},\n\n\t\t\tkeys: {\n\t\t\t\t\"alt+left\": function (e) {\n\t\t\t\t\tthis.scrollHorizontal(-1);\n\t\t\t\t},\n\t\t\t\t\"alt+right\": function (e) {\n\t\t\t\t\tthis.scrollHorizontal(1);\n\t\t\t\t},\n\t\t\t\t\"alt+up\": function (e) {\n\t\t\t\t\tthis.scrollVertical(-1);\n\t\t\t\t},\n\t\t\t\t\"alt+down\": function (e) {\n\t\t\t\t\tthis.scrollVertical(1);\n\t\t\t\t},\n\n\t\t\t\t// undo\n\t\t\t\t\"ctrl+z\": function () {\n\t\t\t\t\tif (gantt.undo) gantt.undo();\n\t\t\t\t},\n\n\t\t\t\t// redo\n\t\t\t\t\"ctrl+r\": function () {\n\t\t\t\t\tif (gantt.redo) gantt.redo();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t);\n\n\tgantt.$keyboardNavigation.GanttNode.prototype.bindAll(gantt.$keyboardNavigation.GanttNode.prototype.keys);\n\n};","export default function(gantt) {\n\n\tgantt.$keyboardNavigation.KeyNavNode = function () {\n\t};\n\n\tgantt.$keyboardNavigation.KeyNavNode.prototype = gantt._compose(\n\t\tgantt.$keyboardNavigation.EventHandler,\n\t\t{\n\t\t\tisValid: function () {\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\tfallback: function () {\n\t\t\t\treturn null;\n\t\t\t},\n\n\t\t\tmoveTo: function (element) {\n\t\t\t\tgantt.$keyboardNavigation.dispatcher.setActiveNode(element);\n\t\t\t},\n\n\t\t\tcompareTo: function (b) {\n\t\t\t\t// good enough comparison of two random objects\n\t\t\t\tif (!b) return false;\n\t\t\t\tfor (var i in this) {\n\t\t\t\t\tif (!!this[i] != !!b[i]) return false;\n\n\t\t\t\t\tvar canStringifyThis = !!(this[i] && this[i].toString);\n\t\t\t\t\tvar canStringifyThat = !!(b[i] && b[i].toString);\n\t\t\t\t\tif (canStringifyThat != canStringifyThis) return false;\n\t\t\t\t\tif (!(canStringifyThat && canStringifyThis)) {\n\t\t\t\t\t\tif (b[i] != this[i]) return false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (b[i].toString() != this[i].toString())\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\tgetNode: function () {\n\t\t\t},\n\t\t\tfocus: function () {\n\t\t\t\tvar node = this.getNode();\n\t\t\t\tif(!node)\n\t\t\t\t\treturn;\n\n\t\t\t\tvar eventFacade = gantt.$keyboardNavigation.facade;\n\n\t\t\t\tif(eventFacade.callEvent(\"onBeforeFocus\", [node]) === false){\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (node) {\n\t\t\t\t\tnode.setAttribute(\"tabindex\", \"-1\");\n\t\t\t\t\tif(!node.$eventAttached){\n\t\t\t\t\t\tnode.$eventAttached = true;\n\t\t\t\t\t\tgantt.event(node, \"focus\",function(e){\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}, false);\n\t\t\t\t\t}\n\t\t\t\t\t//node.className += \" gantt_focused\";\n\t\t\t\t\tif (gantt.utils.dom.isChildOf(document.activeElement, node)){\n\t\t\t\t\t\tnode = document.activeElement;\n\t\t\t\t\t}\n\t\t\t\t\tif (node.focus) node.focus();\n\n\t\t\t\t\teventFacade.callEvent(\"onFocus\", [this.getNode()]);\n\t\t\t\t}\n\n\t\t\t},\n\t\t\tblur: function () {\n\t\t\t\tvar node = this.getNode();\n\t\t\t\tif (node) {\n\t\t\t\t\tvar eventFacade = gantt.$keyboardNavigation.facade;\n\t\t\t\t\teventFacade.callEvent(\"onBlur\", [node]);\n\t\t\t\t\tnode.setAttribute(\"tabindex\", \"-1\");\n\t\t\t\t\t//node.className = (node.className || \"\").replace(/ ?gantt_focused/g, \"\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t);\n\n};","import * as domHelpers from \"../../../core/ui/utils/dom_helpers\";\n\nexport default function(gantt) {\n\n\tgantt.$keyboardNavigation.HeaderCell = function (index) {\n\t\tthis.index = index || 0;\n\t};\n\n\tgantt.$keyboardNavigation.HeaderCell.prototype = gantt._compose(\n\t\tgantt.$keyboardNavigation.KeyNavNode,\n\t\t{\n\t\t\t_handlers: null,\n\n\t\t\tisValid: function () {\n\t\t\t\tif (!gantt.config.show_grid) {\n\t\t\t\t\tif (gantt.getVisibleTaskCount())\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn !!gantt.getGridColumns()[this.index] || !gantt.getVisibleTaskCount();\n\t\t\t},\n\t\t\tfallback: function () {\n\t\t\t\tif (!gantt.config.show_grid) {\n\t\t\t\t\tif (gantt.getVisibleTaskCount()) {\n\t\t\t\t\t\treturn new gantt.$keyboardNavigation.TaskRow();\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tvar visibleColumns = gantt.getGridColumns();\n\t\t\t\tvar index = this.index;\n\t\t\t\twhile (index >= 0) {\n\t\t\t\t\tif (visibleColumns[index])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tindex--;\n\t\t\t\t}\n\t\t\t\tif (visibleColumns[index]) {\n\t\t\t\t\treturn new gantt.$keyboardNavigation.HeaderCell(index);\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tfromDomElement: function(el){\n\t\t\t\tvar cellElement = domHelpers.locateClassName(el, \"gantt_grid_head_cell\");\n\t\t\t\tif(cellElement){\n\t\t\t\t\tvar index = 0;\n\t\t\t\t\twhile(cellElement && cellElement.previousSibling){\n\t\t\t\t\t\tcellElement = cellElement.previousSibling;\n\t\t\t\t\t\tindex += 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn new gantt.$keyboardNavigation.HeaderCell(index);\n\t\t\t\t}else{\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetNode: function () {\n\t\t\t\tvar cells = gantt.$grid_scale.childNodes;\n\t\t\t\treturn cells[this.index];\n\t\t\t},\n\n\n\t\t\tkeys: {\n\n\t\t\t\t\"left\": function () {\n\t\t\t\t\tif (this.index > 0) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.HeaderCell(this.index - 1));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"right\": function () {\n\t\t\t\t\tvar columns = gantt.getGridColumns();\n\t\t\t\t\tif (this.index < columns.length - 1) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.HeaderCell(this.index + 1));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"down\": function () {\n\t\t\t\t\tvar taskRow;\n\t\t\t\t\tvar rootLevel = gantt.getChildren(gantt.config.root_id);\n\t\t\t\t\tif (gantt.isTaskExists(rootLevel[0])) {\n\t\t\t\t\t\ttaskRow = rootLevel[0];\n\t\t\t\t\t}\n\t\t\t\t\tif (taskRow) {\n\t\t\t\t\t\tif (gantt.config.keyboard_navigation_cells) {\n\t\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskCell(taskRow, this.index));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskRow(taskRow));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t\"end\": function () {\n\t\t\t\t\tvar columns = gantt.getGridColumns();\n\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.HeaderCell(columns.length - 1));\n\t\t\t\t},\n\t\t\t\t\"home\": function () {\n\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.HeaderCell(0));\n\t\t\t\t},\n\n\n\t\t\t\t// press header button\n\t\t\t\t\"enter, space\": function () {\n\t\t\t\t\tvar node = domHelpers.getActiveElement();\n\t\t\t\t\tnode.click();\n\t\t\t\t},\n\n\t\t\t\t// add new task\n\t\t\t\t\"ctrl+enter\": function () {\n\t\t\t\t\tif (gantt.isReadonly(this)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tgantt.createTask({}, this.taskId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t);\n\n\tgantt.$keyboardNavigation.HeaderCell.prototype.bindAll(gantt.$keyboardNavigation.HeaderCell.prototype.keys);\n\n};","export default function(gantt) {\n\n\tgantt.$keyboardNavigation.TaskRow = function (taskId) {\n\t\tif (!taskId) {\n\t\t\tvar rootLevel = gantt.getChildren(gantt.config.root_id);\n\t\t\tif (rootLevel[0]) {\n\t\t\t\ttaskId = rootLevel[0];\n\t\t\t}\n\t\t}\n\t\tthis.taskId = taskId;\n\t\tif (gantt.isTaskExists(this.taskId)) {\n\t\t\tthis.index = gantt.getTaskIndex(this.taskId);\n\t\t\tthis.globalIndex = gantt.getGlobalTaskIndex(this.taskId);\n\t\t\tthis.splitItem = !!gantt.getTask(this.taskId).$split_subtask;\n\t\t\tthis.parentId = gantt.getParent(this.taskId);\n\t\t}\n\t};\n\n\tgantt.$keyboardNavigation.TaskRow.prototype = gantt._compose(\n\t\tgantt.$keyboardNavigation.KeyNavNode,\n\t\t{\n\t\t\t_handlers: null,\n\t\t\tisValid: function () {\n\t\t\t\treturn gantt.isTaskExists(this.taskId) && (gantt.getTaskIndex(this.taskId) > -1);\n\t\t\t},\n\t\t\tfallback: function () {\n\t\t\t\tif (!gantt.getVisibleTaskCount()) {\n\t\t\t\t\tvar header = new gantt.$keyboardNavigation.HeaderCell();\n\t\t\t\t\tif (!header.isValid()) return null;\n\t\t\t\t\telse return header;\n\t\t\t\t} else {\n\n\t\t\t\t\tif(!this.splitItem){\n\t\t\t\t\t\tvar nextIndex = -1;\n\t\t\t\t\t\t// GS-1393. When Gantt tries to restore the focus, it should rely on the global index\n\t\t\t\t\t\tif (gantt.getTaskByIndex(this.globalIndex - 1)) {\n\t\t\t\t\t\t\tnextIndex = this.globalIndex - 1;\n\t\t\t\t\t\t} else if (gantt.getTaskByIndex(this.globalIndex + 1)) {\n\t\t\t\t\t\t\tnextIndex = this.globalIndex + 1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar globalIndex = this.globalIndex;\n\t\t\t\t\t\t\twhile (globalIndex >= 0) {\n\t\t\t\t\t\t\t\tif (gantt.getTaskByIndex(globalIndex)) {\n\t\t\t\t\t\t\t\t\tnextIndex = globalIndex;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tglobalIndex--;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (nextIndex > -1) {\n\t\t\t\t\t\t\treturn new gantt.$keyboardNavigation.TaskRow(gantt.getTaskByIndex(nextIndex).id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}else {\n\t\t\t\t\t\treturn new gantt.$keyboardNavigation.TaskRow(this.parentId);\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tfromDomElement: function(el){\n\t\t\t\tif(gantt.config.keyboard_navigation_cells){\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tvar taskId = gantt.locate(el);\n\t\t\t\tif(gantt.isTaskExists(taskId)){\n\t\t\t\t\treturn new gantt.$keyboardNavigation.TaskRow(taskId);\n\t\t\t\t}else{\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetNode: function () {\n\t\t\t\tif (gantt.isTaskExists(this.taskId) && gantt.isTaskVisible(this.taskId)) {\n\t\t\t\t\tif (gantt.config.show_grid) {\n\t\t\t\t\t\treturn gantt.$grid.querySelector(\".gantt_row[\" + gantt.config.task_attribute + \"='\" + this.taskId + \"']\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn gantt.getTaskNode(this.taskId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tfocus: function (keptFocus) {\n\t\t\t\tif(!keptFocus) {\n\t\t\t\t\tconst pos = gantt.getTaskPosition(gantt.getTask(this.taskId));\n\t\t\t\t\tconst height = gantt.getTaskHeight(this.taskId);\n\t\t\t\t\tconst scroll = gantt.getScrollState();\n\n\t\t\t\t\tlet viewWidth;\n\t\t\t\t\tif(gantt.$task){\n\t\t\t\t\t\tviewWidth = gantt.$task.offsetWidth;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tviewWidth = scroll.inner_width;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet viewHeight;\n\t\t\t\t\tif(gantt.$grid_data || gantt.$task_data){\n\t\t\t\t\t\tviewHeight = (gantt.$grid_data || gantt.$task_data).offsetHeight;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tviewHeight = scroll.inner_height;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (pos.top < scroll.y || pos.top + height > (scroll.y + viewHeight)) {\n\t\t\t\t\t\t// GS-2346: additional scrolling to be sure that the task will be in the required range\n\t\t\t\t\t\tgantt.scrollTo(null, pos.top - 20);\n\t\t\t\t\t} else if (gantt.config.scroll_on_click && gantt.config.show_chart) {\n\t\t\t\t\t\t// horizontal scroll activated\n\t\t\t\t\t\tif (pos.left > (scroll.x + viewWidth)) { // scroll forward to the start of the task\n\t\t\t\t\t\t\tgantt.scrollTo(pos.left - gantt.config.task_scroll_offset);\n\t\t\t\t\t\t} else if (pos.left + pos.width < scroll.x) { // scroll back to the end of the task\n\t\t\t\t\t\t\tgantt.scrollTo(pos.left + pos.width - gantt.config.task_scroll_offset);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tgantt.$keyboardNavigation.KeyNavNode.prototype.focus.apply(this, [keptFocus]);\n\n\t\t\t\t// GS-152 if there are scrollbars with custom names, change their scroll position\n\t\t\t\tscrollGrid();\n\n\t\t\t\tfunction scrollGrid() {\n\t\t\t\t\tvar grid = gantt.$ui.getView(\"grid\");\n\t\t\t\t\tvar scrollPositionX = parseInt(grid.$grid.scrollLeft);\n\t\t\t\t\tvar scrollPositionY = parseInt(grid.$grid_data.scrollTop);\n\n\t\t\t\t\tvar attachedScrollbarHorizontal = grid.$config.scrollX;\n\n\t\t\t\t\tif (attachedScrollbarHorizontal && grid.$config.scrollable) {\n\t\t\t\t\t\tvar scrollbarHorizontal = gantt.$ui.getView(attachedScrollbarHorizontal);\n\t\t\t\t\t\tif (scrollbarHorizontal) {\n\t\t\t\t\t\t\tscrollbarHorizontal.scrollTo(scrollPositionX, scrollPositionY);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tvar attachedScrollbarVertical = grid.$config.scrollY;\n\n\t\t\t\t\tif (attachedScrollbarVertical) {\n\t\t\t\t\t\tvar scrollbarVertical = gantt.$ui.getView(attachedScrollbarVertical);\n\t\t\t\t\t\tif (scrollbarVertical) {\n\t\t\t\t\t\t\tscrollbarVertical.scrollTo(scrollPositionX, scrollPositionY);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tkeys: {\n\t\t\t\t\"pagedown\": function () {\n\t\t\t\t\tif (gantt.getVisibleTaskCount()) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskRow(gantt.getTaskByIndex(gantt.getVisibleTaskCount() - 1).id));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"pageup\": function () {\n\t\t\t\t\tif (gantt.getVisibleTaskCount()) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskRow(gantt.getTaskByIndex(0).id));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"up\": function () {\n\t\t\t\t\tvar nextElement = null;\n\t\t\t\t\tvar prevTask = gantt.getPrev(this.taskId);\n\t\t\t\t\tif (!gantt.isTaskExists(prevTask)) {\n\t\t\t\t\t\tnextElement = new gantt.$keyboardNavigation.HeaderCell();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnextElement = new gantt.$keyboardNavigation.TaskRow(prevTask);\n\t\t\t\t\t}\n\t\t\t\t\tthis.moveTo(nextElement);\n\t\t\t\t},\n\t\t\t\t\"down\": function () {\n\t\t\t\t\tvar nextTask = gantt.getNext(this.taskId);\n\t\t\t\t\tif (gantt.isTaskExists(nextTask)) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskRow(nextTask));\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t\"shift+down\": function(){\n\t\t\t\t\tif(gantt.hasChild(this.taskId) && !gantt.getTask(this.taskId).$open){\n\t\t\t\t\t\tgantt.open(this.taskId);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"shift+up\": function(){\n\t\t\t\t\tif(gantt.hasChild(this.taskId) && gantt.getTask(this.taskId).$open){\n\t\t\t\t\t\tgantt.close(this.taskId);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"shift+right\": function() {\n\t\t\t\t\tif (gantt.isReadonly(this)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tvar prevId = gantt.getPrevSibling(this.taskId);\n\t\t\t\t\tif(gantt.isTaskExists(prevId) && !gantt.isChildOf(this.taskId, prevId)){\n\t\t\t\t\t\tvar parent = gantt.getTask(prevId);\n\t\t\t\t\t\tparent.$open = true;\n\t\t\t\t\t\tvar result = gantt.moveTask(this.taskId, -1, prevId);\n\t\t\t\t\t\tif(result !== false)\n\t\t\t\t\t\t\tgantt.updateTask(this.taskId);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"shift+left\": function() {\n\t\t\t\t\tif (gantt.isReadonly(this)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tvar parent = gantt.getParent(this.taskId);\n\t\t\t\t\tif(gantt.isTaskExists(parent)){\n\t\t\t\t\t\tvar result = gantt.moveTask(this.taskId, gantt.getTaskIndex(parent) + 1, gantt.getParent(parent));\n\t\t\t\t\t\tif(result !== false)\n\t\t\t\t\t\t\tgantt.updateTask(this.taskId);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// select\n\t\t\t\t\"space\": function (e) {\n\t\t\t\t\tif (!gantt.isSelectedTask(this.taskId)) {\n\t\t\t\t\t\tgantt.selectTask(this.taskId);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tgantt.unselectTask(this.taskId);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// collapse\n\t\t\t\t\"ctrl+left\": function (e) {\n\t\t\t\t\tgantt.close(this.taskId);\n\t\t\t\t},\n\t\t\t\t// expand\n\t\t\t\t\"ctrl+right\": function (e) {\n\t\t\t\t\tgantt.open(this.taskId);\n\t\t\t\t},\n\n\t\t\t\t// delete task\n\t\t\t\t\"delete\": function (e) {\n\t\t\t\t\tif (gantt.isReadonly(this)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tgantt.$click.buttons[\"delete\"](this.taskId);\n\t\t\t\t},\n\n\t\t\t\t// open lightbox\n\t\t\t\t\"enter\": function () {\n\t\t\t\t\tif (gantt.isReadonly(this)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tgantt.showLightbox(this.taskId);\n\t\t\t\t},\n\n\t\t\t\t// add subtask\n\t\t\t\t\"ctrl+enter\": function () {\n\t\t\t\t\tif (gantt.isReadonly(this)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tgantt.createTask({}, this.taskId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t);\n\tgantt.$keyboardNavigation.TaskRow.prototype.bindAll(gantt.$keyboardNavigation.TaskRow.prototype.keys);\n\n};","import * as domHelpers from \"../../../core/ui/utils/dom_helpers\";\nimport {replaceValidZeroId} from \"../../../utils/helpers\";\n\nexport default function(gantt) {\n\n\n\tgantt.$keyboardNavigation.TaskCell = function (taskId, index) {\n\t\ttaskId = replaceValidZeroId(taskId, gantt.config.root_id);\n\t\tif (!taskId) {\n\t\t\tvar rootLevel = gantt.getChildren(gantt.config.root_id);\n\t\t\tif (rootLevel[0]) {\n\t\t\t\ttaskId = rootLevel[0];\n\t\t\t}\n\t\t}\n\t\tthis.taskId = taskId;\n\t\tthis.columnIndex = index || 0;\n\t\t// provided task may not exist, in this case node will be detectes as invalid\n\t\tif (gantt.isTaskExists(this.taskId)) {\n\t\t\tthis.index = gantt.getTaskIndex(this.taskId);\n\t\t\tthis.globalIndex = gantt.getGlobalTaskIndex(this.taskId);\n\t\t}\n\t};\n\n\tgantt.$keyboardNavigation.TaskCell.prototype = gantt._compose(\n\t\tgantt.$keyboardNavigation.TaskRow,\n\t\t{\n\t\t\t_handlers: null,\n\t\t\tisValid: function () {\n\n\t\t\t\treturn gantt.$keyboardNavigation.TaskRow.prototype.isValid.call(this) && !!gantt.getGridColumns()[this.columnIndex];\n\t\t\t},\n\t\t\tfallback: function () {\n\n\t\t\t\tvar node = gantt.$keyboardNavigation.TaskRow.prototype.fallback.call(this);\n\t\t\t\tvar result = node;\n\t\t\t\tif (node instanceof gantt.$keyboardNavigation.TaskRow) {\n\t\t\t\t\tvar visibleColumns = gantt.getGridColumns();\n\t\t\t\t\tvar index = this.columnIndex;\n\t\t\t\t\twhile (index >= 0) {\n\t\t\t\t\t\tif (visibleColumns[index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tindex--;\n\t\t\t\t\t}\n\t\t\t\t\tif (visibleColumns[index]) {\n\t\t\t\t\t\tresult = new gantt.$keyboardNavigation.TaskCell(node.taskId, index);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t},\n\n\t\t\tfromDomElement: function(el){\n\t\t\t\tif(!gantt.config.keyboard_navigation_cells){\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tvar taskId = gantt.locate(el);\n\t\t\t\tif(gantt.isTaskExists(taskId)){\n\t\t\t\t\tvar index = 0;\n\t\t\t\t\tvar cellElement = domHelpers.locateAttribute(el, \"data-column-index\");\n\n\t\t\t\t\tif(cellElement){\n\t\t\t\t\t\tindex = cellElement.getAttribute(\"data-column-index\")*1;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn new gantt.$keyboardNavigation.TaskCell(taskId, index);\n\t\t\t\t}else{\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetNode: function () {\n\t\t\t\tif (gantt.isTaskExists(this.taskId) && gantt.isTaskVisible(this.taskId)) {\n\t\t\t\t\tif (gantt.config.show_grid) {\n\t\t\t\t\t\tvar row = gantt.$grid.querySelector(\".gantt_row[\" + gantt.config.task_attribute + \"='\" + this.taskId + \"']\");\n\t\t\t\t\t\tif(!row)\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\treturn row.querySelector(\"[data-column-index='\"+this.columnIndex+\"']\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn gantt.getTaskNode(this.taskId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tkeys: {\n\t\t\t\t\"up\": function () {\n\n\t\t\t\t\tvar nextElement = null;\n\t\t\t\t\tvar prevTask = gantt.getPrev(this.taskId);\n\t\t\t\t\tif (!gantt.isTaskExists(prevTask)) {\n\t\t\t\t\t\tnextElement = new gantt.$keyboardNavigation.HeaderCell(this.columnIndex);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnextElement = new gantt.$keyboardNavigation.TaskCell(prevTask, this.columnIndex);\n\t\t\t\t\t}\n\t\t\t\t\tthis.moveTo(nextElement);\n\t\t\t\t},\n\t\t\t\t\"down\": function () {\n\t\t\t\t\tvar nextTask = gantt.getNext(this.taskId);\n\t\t\t\t\tif (gantt.isTaskExists(nextTask)) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskCell(nextTask, this.columnIndex));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"left\": function () {\n\t\t\t\t\tif (this.columnIndex > 0) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskCell(this.taskId, this.columnIndex - 1));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"right\": function () {\n\t\t\t\t\tvar columns = gantt.getGridColumns();\n\t\t\t\t\tif (this.columnIndex < columns.length - 1) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskCell(this.taskId, this.columnIndex + 1));\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t\"end\": function () {\n\t\t\t\t\tvar columns = gantt.getGridColumns();\n\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskCell(this.taskId, columns.length - 1));\n\t\t\t\t},\n\t\t\t\t\"home\": function () {\n\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskCell(this.taskId, 0));\n\t\t\t\t},\n\t\t\t\t\"pagedown\": function () {\n\t\t\t\t\tif (gantt.getVisibleTaskCount()) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskCell(gantt.getTaskByIndex(gantt.getVisibleTaskCount() - 1).id, this.columnIndex));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"pageup\": function () {\n\t\t\t\t\tif (gantt.getVisibleTaskCount()) {\n\t\t\t\t\t\tthis.moveTo(new gantt.$keyboardNavigation.TaskCell(gantt.getTaskByIndex(0).id, this.columnIndex));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t);\n\n\n\tgantt.$keyboardNavigation.TaskCell.prototype.bindAll(gantt.$keyboardNavigation.TaskRow.prototype.keys);\n\tgantt.$keyboardNavigation.TaskCell.prototype.bindAll(gantt.$keyboardNavigation.TaskCell.prototype.keys);\n\n};","export default function(gantt) {\n\n\tgantt.$keyboardNavigation.dispatcher = {\n\t\tisActive: false,\n\t\tactiveNode: null,\n\t\tglobalNode: new gantt.$keyboardNavigation.GanttNode(),\n\n\t\tenable: function () {\n\t\t\tthis.isActive = true;\n\t\t\tthis.setActiveNode(this.getActiveNode());\n\t\t},\n\n\t\tdisable: function () {\n\t\t\tthis.isActive = false;\n\t\t},\n\n\t\tisEnabled: function () {\n\t\t\treturn !!this.isActive;\n\t\t},\n\n\t\tgetDefaultNode: function () {\n\t\t\tvar node;\n\t\t\tif (gantt.config.keyboard_navigation_cells) {\n\t\t\t\tnode = new gantt.$keyboardNavigation.TaskCell();\n\t\t\t} else {\n\t\t\t\tnode = new gantt.$keyboardNavigation.TaskRow();\n\t\t\t}\n\n\t\t\tif (!node.isValid()) {\n\t\t\t\tnode = node.fallback();\n\t\t\t}\n\t\t\treturn node;\n\t\t},\n\n\t\tsetDefaultNode: function () {\n\t\t\tthis.setActiveNode(this.getDefaultNode());\n\t\t},\n\n\t\tgetActiveNode: function () {\n\t\t\tvar node = this.activeNode;\n\t\t\tif (node && !node.isValid()) {\n\t\t\t\tnode = node.fallback();\n\t\t\t}\n\t\t\treturn node;\n\t\t},\n\n\t\tfromDomElement: function(e){\n\t\t\tvar inputs = [\n\t\t\t\tgantt.$keyboardNavigation.TaskRow,\n\t\t\t\tgantt.$keyboardNavigation.TaskCell,\n\t\t\t\tgantt.$keyboardNavigation.HeaderCell\n\t\t\t];\n\t\t\tfor(var i = 0; i < inputs.length; i++){\n\t\t\t\tif(inputs[i].prototype.fromDomElement){\n\t\t\t\t\tvar node = inputs[i].prototype.fromDomElement(e);\n\t\t\t\t\tif(node) return node;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\n\t\tfocusGlobalNode: function () {\n\t\t\tthis.blurNode(this.globalNode);\n\t\t\tthis.focusNode(this.globalNode);\n\t\t},\n\n\t\tsetActiveNode: function (el) {\n\t\t\t//console.trace()\n\t\t\tvar focusChanged = true;\n\t\t\tif (this.activeNode) {\n\t\t\t\tif (this.activeNode.compareTo(el)) {\n\t\t\t\t\tfocusChanged = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.isEnabled()) {\n\t\t\t\tif(focusChanged)\n\t\t\t\t\tthis.blurNode(this.activeNode);\n\n\t\t\t\tthis.activeNode = el;\n\t\t\t\tthis.focusNode(this.activeNode, !focusChanged);\n\t\t\t}\n\t\t},\n\n\t\tfocusNode: function (el, keptFocus) {\n\t\t\tif (el && el.focus) {\n\t\t\t\tel.focus(keptFocus);\n\t\t\t}\n\t\t},\n\t\tblurNode: function (el) {\n\t\t\tif (el && el.blur) {\n\t\t\t\tel.blur();\n\t\t\t}\n\t\t},\n\n\t\tkeyDownHandler: function (e) {\n\n\t\t\tif (gantt.$keyboardNavigation.isModal())\n\t\t\t\treturn;\n\n\t\t\tif (!this.isEnabled())\n\t\t\t\treturn;\n\n\t\t\tif(e.defaultPrevented){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar ganttNode = this.globalNode;\n\n\t\t\tvar command = gantt.$keyboardNavigation.shortcuts.getCommandFromEvent(e);\n\n\t\t\tvar activeElement = this.getActiveNode();\n\t\t\tvar eventFacade = gantt.$keyboardNavigation.facade;\n\t\t\tif(eventFacade.callEvent(\"onKeyDown\", [command, e]) === false){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!activeElement) {\n\t\t\t\tthis.setDefaultNode();\n\t\t\t} else if (activeElement.findHandler(command)) {\n\t\t\t\tactiveElement.doAction(command, e);\n\t\t\t} else if (ganttNode.findHandler(command)) {\n\t\t\t\tganttNode.doAction(command, e);\n\t\t\t}\n\n\t\t},\n\t\t_timeout: null,\n\t\tawaitsFocus: function(){\n\t\t\treturn this._timeout !== null;\n\t\t},\n\t\tdelay: function(callback, delay){\n\n\t\t\tclearTimeout(this._timeout);\n\t\t\tthis._timeout = setTimeout(gantt.bind(function(){\n\t\t\t\tthis._timeout = null;\n\t\t\t\tcallback();\n\t\t\t}, this) , delay || 1);\n\n\t\t},\n\t\tclearDelay: function(){\n\t\t\tclearTimeout(this._timeout);\n\t\t}\n\t};\n\n};","import { QuickInfo } from \"./quickInfo\";\n\nexport default function(gantt: any){\n\nif (!gantt.ext) {\n\tgantt.ext = {};\n}\ngantt.ext.quickInfo = new QuickInfo(gantt);\n\ngantt.config.quickinfo_buttons = [\"icon_edit\", \"icon_delete\"];\ngantt.config.quick_info_detached = true;\ngantt.config.show_quick_info = true;\n\ngantt.templates.quick_info_title = function(start, end, ev){ return ev.text.substr(0,50); };\ngantt.templates.quick_info_content = function(start, end, ev){ return ev.details || ev.text; };\ngantt.templates.quick_info_date = function(start, end, ev){\n\treturn gantt.templates.task_time(start, end, ev);\n};\ngantt.templates.quick_info_class = function(start, end, task){ return \"\"; };\n\ngantt.attachEvent(\"onTaskClick\", function(id,e){\n\t// GS-1460 Don't show Quick Info when clicking on the \"+\" button\n\tif (!gantt.utils.dom.closest(e.target, \".gantt_add\")){\n\t\tsetTimeout(function() {\n\t\t\tgantt.ext.quickInfo.show(id);\n\t\t}, 0);\n\t}\n\n\treturn true;\n});\n\nconst events = [\"onViewChange\", \"onLightbox\", \"onBeforeTaskDelete\", \"onBeforeDrag\"];\nconst hidingFunction = function(){\n\tgantt.ext.quickInfo.hide();\n\treturn true;\n};\nfor (let i=0; i {\n\t\t\tif (gantt.config.touch && !gantt.config.touch_tooltip) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst targetTaskId = gantt.locate(event);\n\t\t\tif(gantt.isTaskExists(targetTaskId)){\n\t\t\t\tconst task = gantt.getTask(targetTaskId);\n\t\t\t\treturn gantt.templates.tooltip_text(task.start_date, task.end_date, task);\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tglobal: false\n\t});\n});\n\ngantt.attachEvent(\"onDestroy\", function() {\n\ttooltipManager.destructor();\n});\n\ngantt.attachEvent(\"onLightbox\", function() {\n\ttooltipManager.hideTooltip();\n});\nconst isLinkCreate = () => {\n\tconst state = gantt.getState();\n\treturn !!state.link_source_id;\n};\ngantt.attachEvent(\"onBeforeTooltip\", function() {\n\tif (isLinkCreate()){\n\t\treturn false;\n\t}\n});\n\ngantt.attachEvent(\"onGanttScroll\", function(){\n\ttooltipManager.hideTooltip();\n});\n\n}","import { Monitor } from \"./monitor\";\nimport { IMonitor, IUndoCommand, TEntityType, TUndoStack } from \"./types\";\nimport { Undo } from \"./undo\";\n\nexport default function(gantt: any){\n\nconst _undo = new Undo(gantt);\nconst monitor: IMonitor = new Monitor(_undo, gantt);\n\ngantt.config.undo = true;\ngantt.config.redo = true;\n\n/**\n * entities that require different processing for undoing-redoing changes\n * @type {{link: string, task: string}}\n */\ngantt.config.undo_types = {\n\tlink: \"link\",\n\ttask: \"task\"\n};\n\n/**\n * types of traced actions\n * @type {{update: string, remove: string, add: string}}\n */\ngantt.config.undo_actions = {\n\tupdate: \"update\",\n\tremove: \"remove\", // remove item from datastore\n\tadd: \"add\",\n\tmove: \"move\" // move task in grid\n};\n\nif (!gantt.ext) {\n\tgantt.ext = {};\n}\n\ngantt.ext.undo = {\n\tundo: () => _undo.undo(),\n\tredo: () => _undo.redo(),\n\tgetUndoStack: () => _undo.getUndoStack(),\n\tsetUndoStack: (stack:[]) => _undo.setUndoStack(stack),\n\tgetRedoStack: () => _undo.getRedoStack(),\n\tsetRedoStack: (stack:[]) => _undo.setRedoStack(stack),\n\tclearUndoStack: () => _undo.clearUndoStack(),\n\tclearRedoStack: () => _undo.clearRedoStack(),\n\tsaveState: (id: TaskID | LinkID, type: TEntityType) => monitor.store(id, type, true),\n\tgetInitialState: (id: TaskID | LinkID, type: TEntityType) => {\n\t\tif(type === gantt.config.undo_types.link){\n\t\t\treturn monitor.getInitialLink(id);\n\t\t}else{\n\t\t\treturn monitor.getInitialTask(id);\n\t\t}\n\t}\n};\n\ngantt.undo = gantt.ext.undo.undo;\ngantt.redo = gantt.ext.undo.redo;\ngantt.getUndoStack = gantt.ext.undo.getUndoStack;\ngantt.getRedoStack = gantt.ext.undo.getRedoStack;\ngantt.clearUndoStack = gantt.ext.undo.clearUndoStack;\ngantt.clearRedoStack = gantt.ext.undo.clearRedoStack;\n\nfunction updTask(task: ITask, oldId: TaskID, newId: TaskID) {\n\tif (!task) { return; }\n\n\tif (task.id === oldId) {\n\t\ttask.id = newId;\n\t}\n\n\tif (task.parent === oldId) {\n\t\ttask.parent = newId;\n\t}\n}\n\nfunction changeTaskCommandId(command: IUndoCommand, oldId: TaskID, newId: TaskID) {\n\tupdTask(command.value, oldId, newId);\n\tupdTask(command.oldValue, oldId, newId);\n}\n\nfunction updLink(link: ILink, oldTaskId: TaskID, newTaskId: TaskID) {\n\tif (!link) { return; }\n\tif (link.source === oldTaskId) {\n\t\tlink.source = newTaskId;\n\t}\n\tif (link.target === oldTaskId) {\n\t\tlink.target = newTaskId;\n\t}\n}\n\nfunction changeLinkCommandId(command: IUndoCommand, oldId: LinkID, newId: LinkID) {\n\tupdLink(command.value, oldId, newId);\n\tupdLink(command.oldValue, oldId, newId);\n}\n\nfunction updateTasksIds(log: TUndoStack, oldId: TaskID, newId: TaskID) {\n\tconst undo = _undo;\n\n\tfor (let i = 0; i < log.length; i++) {\n\t\tconst entry = log[i];\n\t\tfor (let j = 0; j < entry.commands.length; j++) {\n\t\t\tif (entry.commands[j].entity === undo.command.entity.task) {\n\t\t\t\tchangeTaskCommandId(entry.commands[j], oldId, newId);\n\t\t\t} else if (entry.commands[j].entity === undo.command.entity.link) {\n\t\t\t\tchangeLinkCommandId(entry.commands[j], oldId, newId);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction updateLinksIds(log: TUndoStack, oldId: LinkID, newId: LinkID) {\n\tconst undo = _undo;\n\n\tfor (let i = 0; i < log.length; i++) {\n\t\tconst entry = log[i];\n\t\tfor (let j = 0; j < entry.commands.length; j++) {\n\t\t\tconst command = entry.commands[j];\n\t\t\tif (command.entity === undo.command.entity.link) {\n\t\t\t\tif (command.value && command.value.id === oldId) {\n\t\t\t\t\tcommand.value.id = newId;\n\t\t\t\t}\n\t\t\t\tif (command.oldValue && command.oldValue.id === oldId) {\n\t\t\t\t\tcommand.oldValue.id = newId;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\ngantt.attachEvent(\"onTaskIdChange\", (oldId: TaskID, newId: TaskID) => {\n\tconst undo = _undo;\n\tupdateTasksIds(undo.getUndoStack(), oldId, newId);\n\tupdateTasksIds(undo.getRedoStack(), oldId, newId);\n});\n\ngantt.attachEvent(\"onLinkIdChange\", (oldId: LinkID, newId: LinkID) => {\n\tconst undo = _undo;\n\tupdateLinksIds(undo.getUndoStack(), oldId, newId);\n\tupdateLinksIds(undo.getRedoStack(), oldId, newId);\n});\n\ngantt.attachEvent(\"onGanttReady\", () => {\n\t_undo.updateConfigs();\n});\n\n}","import * as helpers from \"../utils/helpers\";\n\nexport default function(gantt){\n\ngantt._groups = {\n\trelation_property: null,\n\trelation_id_property: '$group_id',\n\tgroup_id: null,\n\tgroup_text: null,\n\tloading: false,\n\tloaded: 0,\n\tdynamicGroups: false,\n\tset_relation_value: undefined,\n\t_searchCache: null,\n\tinit: function(gantt){\n\t\tvar self = this;\n\n\t\tgantt.attachEvent(\"onClear\", function(){\n\t\t\tself.clear();\n\t\t});\n\t\tself.clear();\n\n\t\tvar originalGetParent = gantt.$data.tasksStore.getParent; // gantt._get_parent_id;\n\t\tthis._searchCache = null;\n\t\tgantt.attachEvent(\"onBeforeTaskMove\", function(id, parent, tindex) {\n\t\t\t// GS-504: If we allow several owners/resources, the task should be moved to \n\t\t\t// a new position only if there is the function that handles that logic\n\t\t\tvar invalidParent = parent === this.config.root_id;\n\t\t\tvar noRelationValueFunction = this._groups.dynamicGroups && !(this._groups.set_relation_value instanceof Function);\n\n\t\t\tif (self.is_active() && (invalidParent || noRelationValueFunction)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar task = gantt.getTask(id);\n\t\t\t// to allow reordering from regular task to virtual task in the group mode\n\t\t\tif (this._groups.save_tree_structure && gantt.isTaskExists(task.parent) && gantt.isTaskExists(parent)) {\n\t\t\t\tvar oldParentTask = gantt.getTask(task.parent);\n\t\t\t\tvar newParentTask = gantt.getTask(parent);\n\t\t\t\tif (newParentTask.$virtual && gantt.isChildOf(oldParentTask.id, newParentTask.id)) {\n\t\t\t\t\ttask.parent = gantt.config.root_id;\n\t\t\t\t}\n\t\t\t\t// avoid cyclic tree:\n\t\t\t\tlet cyclicTree = false;\n\t\t\t\tlet parentTask = newParentTask;\n\t\t\t\twhile (parentTask) {\n\t\t\t\t\tif (id == parentTask.parent) {\n\t\t\t\t\t\tcyclicTree = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (gantt.isTaskExists(parentTask.parent)) {\n\t\t\t\t\t\tparentTask = gantt.getTask(parentTask.parent);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparentTask = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (cyclicTree) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\t// restore initial parent if the task is moved to a different group on the root level\n\t\tgantt.attachEvent(\"onRowDragStart\", function (id, target) {\n\t\t\tvar task = gantt.getTask(id);\n\t\t\tif (this._groups.save_tree_structure && gantt.isTaskExists(task.parent) && gantt.config.order_branch && gantt.config.order_branch != \"marker\") {\n\t\t\t\ttask.$initial_parent = task.parent;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tgantt.attachEvent(\"onRowDragEnd\", function (id, target) {\n\t\t\tif (gantt.config.order_branch && gantt.config.order_branch != \"marker\") {\n\t\t\t\tvar task = gantt.getTask(id);\n\t\t\t\tif (task.$initial_parent) {\n\t\t\t\t\tif (task.parent == gantt.config.root_id) {\n\t\t\t\t\t\tvar renderedParent = gantt.getTask(task.$rendered_parent);\n\t\t\t\t\t\tvar initialParent = gantt.getTask(task.$initial_parent);\n\t\t\t\t\t\tvar restoreParent = false;\n\t\t\t\t\t\tif (this._groups.dynamicGroups && renderedParent[this._groups.group_id] != initialParent[this._groups.group_id]) {\n\t\t\t\t\t\t\trestoreParent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!this._groups.dynamicGroups && renderedParent[this._groups.group_id] != initialParent[this._groups.relation_property]) {\n\t\t\t\t\t\t\trestoreParent = true;\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (restoreParent) {\n\t\t\t\t\t\t\ttask.parent = task.$initial_parent;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdelete task.$initial_parent;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tgantt.$data.tasksStore._listenerToDrop = gantt.$data.tasksStore.attachEvent(\"onStoreUpdated\", gantt.bind(_initBeforeDataRender, gantt));\n\n\t\tgantt.$data.tasksStore.getParent = function(task) {\n\t\t\tif (self.is_active()) {\n\t\t\t\treturn self.get_parent(gantt, task);\n\t\t\t} else {\n\t\t\t\treturn originalGetParent.apply(this, arguments);\n\t\t\t}\n\t\t};\n\n\t\tvar originalSetParent = gantt.$data.tasksStore.setParent;\n\n\t\tgantt.$data.tasksStore.setParent = function(task, new_pid) {\n\t\t\tif (!self.is_active()) {\n\t\t\t\treturn originalSetParent.apply(this, arguments);\n\t\t\t} else if (self.set_relation_value instanceof Function && gantt.isTaskExists(new_pid)) {\n\t\t\t\tvar parent = gantt.getTask(new_pid);\n\t\t\t\tvar groupIds = parent[self.relation_id_property];\n\t\t\t\tif (!parent.$virtual) {\n\t\t\t\t\tvar groupId = _getGroupId(parent, self.relation_property);\n\t\t\t\t\tif (!self._searchCache) {\n\t\t\t\t\t\tself._buildCache();\n\t\t\t\t\t}\n\t\t\t\t\tvar virtualParentId = self._searchCache[groupId];\n\t\t\t\t\tvar virtualParent = gantt.getTask(virtualParentId);\n\t\t\t\t\tgroupIds = virtualParent[self.relation_id_property];\n\t\t\t\t}\n\t\t\t\tif (task[self.group_id] === undefined) {\n\t\t\t\t\t// to avoid nulling of relation_property if the group is not set\n\t\t\t\t\ttask[self.group_id] = groupIds;\n\t\t\t\t}\n\n\t\t\t\tif (self.save_tree_structure && task[self.group_id] != groupIds) {\n\t\t\t\t\ttask[self.group_id] = groupIds;\n\t\t\t\t}\n\n\t\t\t\tif (groupIds){\n\t\t\t\t\tif (typeof groupIds == \"string\"){\n\t\t\t\t\t\tgroupIds = groupIds.split(\",\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tgroupIds = [groupIds];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// GS-504: This is a way to save the relation_property and customize the logic\n\t\t\t\ttask[self.relation_property] = self.set_relation_value(groupIds, task.id, task[self.relation_property]) || groupIds;\n\n\t\t\t} else if (gantt.isTaskExists(new_pid)) {\n\t\t\t\tvar parent = gantt.getTask(new_pid);\n\n\t\t\t\tif (!self.dynamicGroups) {\n\t\t\t\t\tif (parent.$virtual) {\n\t\t\t\t\t\ttask[self.relation_property] = parent[self.relation_id_property];\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttask[self.relation_property] = parent[self.relation_property];\n\t\t\t\t\t}\n\t\t\t\t\t// task[self.group_id] = parent[self.group_id] || task[self.group_id];\n\t\t\t\t}\n\n\t\t\t\tthis._setParentInner.apply(this, arguments);\n\t\t\t} else if(self.dynamicGroups) {\n\t\t\t\tif (task[self.group_id] === undefined || (!task.$virtual && task[self.relation_property][0] === [][0])) {\n\t\t\t\t\t// GS-1332 the tasks without the group should be moved to the default group:\n\t\t\t\t\ttask[self.relation_property] = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// GS-1449. Update the parent when it was changed in the group mode\n\t\t\tif (gantt.isTaskExists(new_pid)) {\n\t\t\t\ttask.$rendered_parent = new_pid;\n\t\t\t\tif (!gantt.getTask(new_pid).$virtual) {\n\t\t\t\t\treturn originalSetParent.apply(this, arguments) || new_pid;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tgantt.attachEvent(\"onBeforeTaskDisplay\", function(id, task){\n\t\t\tif(self.is_active()){\n\t\t\t\tif(task.type == gantt.config.types.project && !task.$virtual)\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tgantt.attachEvent(\"onBeforeParse\", function(){\n\t\t\tself.loading = true;\n\t\t\tself._clearCache();\n\t\t});\n\n\t\tgantt.attachEvent(\"onTaskLoading\", function(){\n\t\t\tif(self.is_active()){\n\t\t\t\tself.loaded--;\n\t\t\t\tif(self.loaded <= 0){\n\t\t\t\t\tself.loading = false;\n\t\t\t\t\tself._clearCache();\n\t\t\t\t\tgantt.eachTask(gantt.bind(function(t){\n\t\t\t\t\t\tthis.get_parent(gantt, t);\n\t\t\t\t\t}, self));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\n\t\t});\n\t\tgantt.attachEvent(\"onParse\", function(){\n\t\t\tself.loading = false;\n\t\t\tself.loaded = 0;\n\t\t});\n\t},\n\n\t_clearCache: function(){\n\t\tthis._searchCache = null;\n\t},\n\t_buildCache: function(){\n\t\tthis._searchCache = {};\n\t\tvar items = gantt.$data.tasksStore.getItems();\n\t\tfor(var i = 0; i < items.length; i++){\n\t\t\tthis._searchCache[items[i][this.relation_id_property]] = items[i].id;\n\t\t}\n\n\t},\n\tget_parent: function(gantt, task, tasks) {\n\t\tif (task.id === undefined) {\n\t\t\ttask = gantt.getTask(task);\n\t\t}\n\n\t\tvar group_id = _getGroupId(task, this.relation_property);\n\n\t\tif (this.save_tree_structure && gantt.isTaskExists(task.parent)) {\n\t\t\tlet parentTask = gantt.getTask(task.parent);\n\n\t\t\tconst parent_group_id = _getGroupId(parentTask, this.relation_property);\n\n\t\t\tif (parentTask.type != \"project\" && group_id == parent_group_id) {\n\t\t\t\treturn task.parent;\n\t\t\t}\n\t\t}\n\n\t\tif (this._groups_pull[group_id] === task.id){\n\t\t\treturn gantt.config.root_id;\n\t\t}\n\t\tif (this._groups_pull[group_id] !== undefined) {\n\t\t\treturn this._groups_pull[group_id];\n\t\t}\n\n\t\tvar parent_id = gantt.config.root_id;\n\n\t\tif (!this.loading && group_id !== undefined) {\n\n\t\t\tif(!this._searchCache){\n\t\t\t\tthis._buildCache();\n\t\t\t}\n\t\t\tvar parent = this._searchCache[group_id];\n\t\t\tif(gantt.isTaskExists(parent) && parent != task.id){\n\t\t\t\tparent_id = this._searchCache[group_id];\n\t\t\t}\n\n\t\t\tthis._groups_pull[group_id] = parent_id;\n\t\t}\n\n\t\treturn parent_id;\n\t},\n\n\tclear: function(){\n\t\tthis._groups_pull = {};\n\t\tthis.relation_property = null;\n\t\tthis.group_id = null;\n\t\tthis.group_text = null;\n\t\tthis._clearCache();\n\t},\n\tis_active: function(){\n\t\treturn !!(this.relation_property);\n\t},\n\tgenerate_sections: function(list, groups_type){\n\t\tvar groups = [];\n\t\tfor(var i = 0; i < list.length; i++){\n\t\t\tvar group = gantt.copy(list[i]);\n\t\t\tgroup.type = groups_type;\n\t\t\tif(group.open === undefined){\n\t\t\t\tgroup.open = true;\n\t\t\t}\n\t\t\tgroup.$virtual = true;\n\t\t\tgroup.readonly = true;\n\t\t\tgroup[this.relation_id_property] = group[this.group_id];\n\t\t\tgroup.text = group[this.group_text];\n\t\t\tgroups.push(group);\n\t\t}\n\t\treturn groups;\n\n\t},\n\tclear_temp_tasks: function(tasks){\n\t\tfor(var i =0; i < tasks.length; i++){\n\t\t\tif(tasks[i].$virtual){\n\t\t\t\ttasks.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t},\n\n\tgenerate_data: function(gantt, groups){\n\t\tvar links = gantt.getLinks();\n\t\tvar tasks = gantt.getTaskByTime();\n\n\t\tthis.clear_temp_tasks(tasks);\n\n\t\ttasks.forEach(function(task){\n\t\t\ttask.$calculate_duration = false;// no need to recalculate durations of tasks after group by\n\t\t});\n\n\t\tvar categories = [];\n\t\tif(this.is_active() && groups && groups.length){\n\t\t\tcategories = this.generate_sections(groups, gantt.config.types.project);\n\t\t}\n\n\t\tvar data = {links: links};\n\t\tdata.data = categories.concat(tasks);\n\n\t\treturn data;\n\t},\n\tupdate_settings: function(relation, group_id, group_text){\n\t\tthis.clear();\n\t\tthis.relation_property = relation;\n\t\tthis.group_id = group_id;\n\t\tthis.group_text = group_text;\n\t},\n\tgroup_tasks: function (gantt, groups_array, relation_property, group_id, group_text){\n\t\tthis.update_settings(relation_property, group_id, group_text);\n\t\tvar data = this.generate_data(gantt, groups_array);\n\t\tthis.loaded = data.data.length;\n\n\t\t// save task selection before grouping tasks\n\t\t// We need to iterate selected tasks with the \"isSelectedTask\" method\n\t\t// because it will work with and without the multiselect extension\n\t\tvar selectedTasks = [];\n\t\tgantt.eachTask(function(task){\n\t\t\tif (gantt.isSelectedTask(task.id)){\n\t\t\t\tselectedTasks.push(task.id);\n\t\t\t}\n\t\t});\n\n\t\tgantt._clear_data();\n\t\tvar schedulingOnParse = gantt.config.auto_scheduling_initial;\n\t\tgantt.config.auto_scheduling_initial = false;\n\t\tgantt.parse(data);\n\n\t\t// restore task selection after grouping tasks\n\t\tselectedTasks.forEach(function(taskId){\n\t\t\tif (gantt.isTaskExists(taskId)){\n\t\t\t\tgantt.selectTask(taskId);\n\t\t\t}\n\t\t});\n\n\t\tgantt.config.auto_scheduling_initial = schedulingOnParse;\n\t}\n};\n\ngantt._groups.init(gantt);\n\nfunction setRelationValueForAssignmentsArray(newGroupValues, id, oldRelationProperty) {\n\tif (!newGroupValues) {\n\t\treturn 0;\n\t}\n\n\tif (Array.isArray(oldRelationProperty) && !oldRelationProperty[0]) {\n\t\treturn 0;\n\t}\n\n\tif (newGroupValues && !Array.isArray(oldRelationProperty)) {\n\t\tconst resources = [];\n\t\tnewGroupValues.map(function(id){\n\t\t\tresources.push({ resource_id: id, value: 8 });\n\t\t});\n\t\treturn resources;\n\t}\n\tif (!oldRelationProperty[0].resource_id) {\n\t\toldRelationProperty = [{ resource_id: oldRelationProperty, value: 8 }];\n\t}\n\n\tif (typeof newGroupValues == \"string\") {\n\t\tnewGroupValues = newGroupValues.split(',');\n\t}\n\n\tif (newGroupValues.length == 1) {\n\t\toldRelationProperty[0].resource_id = newGroupValues[0];\n\t\treturn [oldRelationProperty[0]];\n\t}\n\n\tconst newRelationProperty = [];\n\t// GS-2493: need to take into account that task could have assigments on different dates\n\t// with the same resource\n\tif (newGroupValues.length > 1) {\n\t\tnewGroupValues = [...new Set(newGroupValues)]; // need to remove repeated ids if they exist\n\t}\n\t\n\tfor (let i = 0; i < newGroupValues.length; i++) {\n\t\tlet new_value = newGroupValues[i];\n\t\tlet arrOfResourceIds = oldRelationProperty.map(function (e) { return e.resource_id; });\n\t\t// need to get the positions of the resources\n\t\tlet pos = arrOfResourceIds.reduce(function(resourceAssignmentIndexes, resourceId, index) {\n\t\t\tif (resourceId === new_value)\n\t\t\t\tresourceAssignmentIndexes.push(index);\n\t\t\treturn resourceAssignmentIndexes;\n\t\t}, []);\n\t\t\n\t\tif (pos.length > 0) {\n\t\t\tpos.forEach((assignmentIndex) => {\n\t\t\t\toldRelationProperty[assignmentIndex].resource_id = new_value;\n\t\t\t\tnewRelationProperty.push(oldRelationProperty[assignmentIndex]);\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\tlet copy = gantt.copy(oldRelationProperty[0]);\n\t\t\tcopy.resource_id = new_value;\n\t\t\tnewRelationProperty.push(copy);\n\t\t}\n\t}\n\treturn newRelationProperty;\n}\n\nfunction setRelationValueForPrimitivesArray(newGroupValues, id, oldRelationProperty) {\n\treturn newGroupValues;\n}\n\nfunction inspectRelationProperty(tasks, relationProperty){\n\tvar resourceAssignments = false;\n\tvar arrays = false;\n\tfor(var i = 0; i < tasks.length; i++){\n\t\tvar value = tasks[i][relationProperty];\n\t\tif(Array.isArray(value)){\n\t\t\tarrays = true;\n\t\t\tif(value.length) {\n\t\t\t\tif(value[0].resource_id !== undefined){\n\t\t\t\t\tresourceAssignments = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\thaveArrays: arrays,\n\t\thaveResourceAssignments: resourceAssignments\n\t};\n}\n\nfunction selectRelationFunction(relationInfo){\n\tif(relationInfo.haveResourceAssignments){\n\t\treturn setRelationValueForAssignmentsArray;\n\t}else if(relationInfo.haveArrays){\n\t\treturn setRelationValueForPrimitivesArray;\n\t}\n\treturn null;\n}\n\ngantt.groupBy = function(config) {\n\tvar _this = this;\n\tvar tasks = gantt.getTaskByTime();\n\n\tthis._groups.set_relation_value = config.set_relation_value;\n\tthis._groups.dynamicGroups = false;\n\tthis._groups.save_tree_structure = config.save_tree_structure;\n\n\tvar relationInfo = inspectRelationProperty(tasks, config.relation_property);\n\n\tif(relationInfo.haveArrays){\n\t\tthis._groups.dynamicGroups = true;\n\t}\n\n\tif(!this._groups.set_relation_value) {\n\t\tthis._groups.set_relation_value = selectRelationFunction(relationInfo);\n\t}\n\n\tconfig = config || {};\n\tconfig.default_group_label = config.default_group_label || this.locale.labels.default_group || \"None\";\n\n\tvar relation_property = config.relation_property || null;\n\tvar group_id = config.group_id || \"key\";\n\tvar group_text = config.group_text || \"label\";\n\n\tthis._groups.regroup = function() {\n\t\tvar tasks = gantt.getTaskByTime();\n\t\tvar groupOpenCloseState = {};\n\t\tvar restoreOpenCloseState = false;\n\t\ttasks.forEach(function(task){\n\t\t\tif(task.$virtual && task.$open !== undefined){\n\t\t\t\tgroupOpenCloseState[task[group_id]] = task.$open;\n\t\t\t\trestoreOpenCloseState = true;\n\t\t\t}\n\t\t});\n\t\tvar groups = _initGroups(config, tasks, gantt);\n\t\tif(groups && restoreOpenCloseState){\n\t\t\tgroups.forEach(function(group){\n\t\t\t\tif(groupOpenCloseState[group[group_id]] !== undefined){\n\t\t\t\t\tgroup.open = groupOpenCloseState[group[group_id]];\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\t_this._groups.group_tasks(_this, groups, relation_property, group_id, group_text);\n\t\treturn true;\n\t};\n\tthis._groups.regroup();\n};\n\nfunction _initGroups(config, tasks, gantt) {\n\tvar groups;\n\tif (config.groups) {\n\t\tif (gantt._groups.dynamicGroups) {\n\t\t\tgroups = _getGroupForMultiItems(tasks, config);\n\t\t} else {\n\t\t\tgroups = config.groups;\n\t\t}\n\n\t} else {\n\t\tgroups = null;\n\t}\n\treturn groups;\n}\n\nfunction _getResourcesIds(resources){\n\treturn resources.map(_getEntryId).sort().join(\",\");\n}\n\nfunction _getEntryId(entry){\n\tif(entry && typeof entry == \"object\"){\n\t\treturn String(entry.resource_id);\n\t}else{\n\t\treturn String(entry);\n\t}\n}\n\nfunction _getGroupId(task, relationProperty) {\n\tvar group_id;\n\tif (task[relationProperty] instanceof Array) {\n\t\t// GS-1332 We want to assign tasks with the empty relationProperty to a default group\n\t\tif (!task[relationProperty].length) {\n\t\t\tgroup_id = 0;\n\t\t}\n\t\telse {\n\t\t\tgroup_id = _getResourcesIds(task[relationProperty]);\n\t\t}\n\t} else {\n\t\tgroup_id = task[relationProperty];\n\t}\n\treturn group_id;\n}\n\nfunction _getGroupForMultiItems(tasks, config) {\n\tvar resultObj = {};\n\tvar result = [];\n\tvar itemsByKey = {};\n\tvar property = config.relation_property;\n\tvar delimiter = config.delimiter || \",\";\n\n\tvar hasDefaultGroup = false;\n\tvar defaultGroupId = 0;\n\n\thelpers.forEach(config.groups, function(entry) {\n\t\tif(entry.default){\n\t\t\thasDefaultGroup = true;\n\t\t\tdefaultGroupId = entry.group_id;\n\t\t}\n\t\titemsByKey[entry.key || entry[config.group_id]] = entry;\n\t});\n\n\tfor (var i=0; i < tasks.length; i++) {\n\t\tvar key;\n\t\tvar label;\n\t\tvar task = tasks[i];\n\t\tvar taskGroupValue = task[property];\n\n\t\tif (helpers.isArray(taskGroupValue)) {\n\t\t\tif(taskGroupValue.length > 0) {\n\t\t\t\tkey = _getResourcesIds(taskGroupValue);\n\t\t\t\tlabel = taskGroupValue.map(function(entry, index) {\n\t\t\t\t\tvar key;\n\t\t\t\t\tif (entry && typeof entry == \"object\") {\n\t\t\t\t\t\tkey = entry.resource_id;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tkey = entry;\n\t\t\t\t\t}\n\t\t\t\t\tentry = itemsByKey[key];\n\t\t\t\t\treturn entry.label || entry.text;\n\t\t\t\t}).sort();\n\t\t\t\t// GS-2493: need to take into account that task could have assigments on different dates\n\t\t\t\t// with the same resource\n\t\t\t\tlabel = [...new Set(label)].join(delimiter);\n\t\t\t} else {\n\t\t\t\tif(hasDefaultGroup)\n\t\t\t\t\tcontinue;\n\t\t\t\tkey = 0;\n\t\t\t\tlabel = config.default_group_label;\n\t\t\t}\n\t\t} else if (taskGroupValue) {\n\t\t\tkey = taskGroupValue;\n\t\t\tlabel = itemsByKey[key].label || itemsByKey[key].text;\n\t\t} else {\n\t\t\tif(hasDefaultGroup)\n\t\t\t\tcontinue;\n\t\t\tkey = 0;\n\t\t\tlabel = config.default_group_label;\n\t\t}\n\t\tif (key === undefined || resultObj[key] !== undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tresultObj[key] = { key: key, label: label };\n\t\tif(key === defaultGroupId){\n\t\t\tresultObj[key].default = true;\n\t\t}\n\t\tresultObj[key][config.group_text] = label;\n\t\tresultObj[key][config.group_id] = key;\n\t}\n\tresult = helpers.hashToArray(resultObj);\n\tresult.forEach(function(group){\n\t\tif(group.key == defaultGroupId){\n\t\t\tgroup.default = true;\n\t\t}\n\t});\n\treturn result;\n}\n\nvar state = gantt.$services.getService(\"state\");\nstate.registerProvider(\"groupBy\", function () {\n\treturn {\n\t\tgroup_mode: gantt._groups.is_active() ? gantt._groups.relation_property : null\n\t};\n});\n\nfunction _initBeforeDataRender() {\n\tvar _this = this;\n\tif (this.$data.tasksStore._listenerToDrop) {\n\t\tthis.$data.tasksStore.detachEvent(this.$data.tasksStore._listenerToDrop);\n\t}\n\n\t// updateTask can be called many times from batchUpdate or autoSchedule,\n\t// add a delay in order to perform grouping only once when everything is done\n\tvar delayedFunction = helpers.delay(function() {\n\t\tif (!_this._groups.dynamicGroups) {\n\t\t\treturn true;\n\t\t}\n\t\tif (_this._groups.regroup) {\n\t\t\tvar scrollState = gantt.getScrollState();\n\t\t\t_this._groups.regroup();\n\t\t\tif(scrollState){\n\t\t\t\tgantt.scrollTo(scrollState.x, scrollState.y);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t});\n\n\tthis.$data.tasksStore.attachEvent(\"onAfterUpdate\", function(){\n\t\t// do not reset delayed function each time since onAfterUpdate can be called huge number of times and clearTimeout/setTimeout gets expensive\n\t\tif(!delayedFunction.$pending){\n\t\t\tdelayedFunction();\n\t\t}\n\t\treturn true;\n\t});\n}\n\n};\n","\nexport default function(gantt){\n\nif(!gantt._markers) {\n\tgantt._markers = gantt.createDatastore({\n\t\tname: \"marker\",\n\t\tinitItem: function (marker) {\n\t\t\tmarker.id = marker.id || gantt.uid();\n\t\t\treturn marker;\n\t\t}\n\t});\n}\n\ngantt.config.show_markers = true;\n\nfunction render_marker(marker){\n\tif(!gantt.config.show_markers)\n\t\treturn false;\n\n\tif(!marker.start_date)\n\t\treturn false;\n\n\tvar state = gantt.getState();\n\tif(+marker.start_date > +state.max_date)\n\t\treturn;\n\tif((!marker.end_date || +marker.end_date < +state.min_date) && +marker.start_date < +state.min_date)\n\t\treturn;\n\n\tvar div = document.createElement(\"div\");\n\n\tdiv.setAttribute(\"data-marker-id\", marker.id);\n\n\tvar css = \"gantt_marker\";\n\tif(gantt.templates.marker_class)\n\t\tcss += \" \" + gantt.templates.marker_class(marker);\n\n\tif(marker.css){\n\t\tcss += \" \" + marker.css;\n\t}\n\n\tif(gantt.templates.marker_class)\n\t\tcss += \" \" + gantt.templates.marker_class(marker);\n\n\tif(marker.title){\n\t\tdiv.title = marker.title;\n\t}\n\tdiv.className = css;\n\n\tvar start = gantt.posFromDate(marker.start_date);\n\tdiv.style.left = start + \"px\";\n\tlet markerHeight = Math.max(gantt.getRowTop(gantt.getVisibleTaskCount()), 0) + \"px\";\n\tif (gantt.config.timeline_placeholder && gantt.$task_data){\n\t\tmarkerHeight = gantt.$task_data.scrollHeight + \"px\";\n\t}\n\tdiv.style.height = markerHeight;\n\tif(marker.end_date){\n\t\tvar end = gantt.posFromDate(marker.end_date);\n\t\tdiv.style.width = Math.max((end - start), 0) + \"px\";\n\n\t}\n\n\tif(marker.text){\n\t\tdiv.innerHTML = \"
\" + marker.text + \"
\";\n\t}\n\n\treturn div;\n}\n\nfunction initMarkerArea(){\n\tif(!gantt.$task_data)\n\t\treturn;\n\n\tvar markerArea = document.createElement(\"div\");\n\tmarkerArea.className = \"gantt_marker_area\";\n\tgantt.$task_data.appendChild(markerArea);\n\tgantt.$marker_area = markerArea;\n}\n\ngantt.attachEvent(\"onBeforeGanttRender\", function(){\n\tif(!gantt.$marker_area)\n\t\tinitMarkerArea();\n});\n\ngantt.attachEvent(\"onDataRender\", function(){\n\tif(!gantt.$marker_area){\n\t\tinitMarkerArea();\n\t\tgantt.renderMarkers();\n\t}\n});\n\ngantt.attachEvent(\"onGanttLayoutReady\", function(){\n\t// GS-1304 - markers should attach when layout is initialized, both on gantt.init and gantt.resetLayout\n\t// wait for \"onBeforeGanttRender\", so all layout elements will be in DOM\n\tgantt.attachEvent(\"onBeforeGanttRender\", function(){\n\t\tinitMarkerArea();\n\n\t\tvar layers = gantt.$services.getService(\"layers\");\n\t\tvar markerRenderer = layers.createDataRender({\n\t\t\tname: \"marker\",\n\t\t\tdefaultContainer: function(){ return gantt.$marker_area;}\n\t\t});\n\t\tmarkerRenderer.addLayer(render_marker);\n\t}, {once: true});\n});\n\ngantt.getMarker = function(id){\n\tif(!this._markers) return null;\n\n\treturn this._markers.getItem(id);\n};\n\ngantt.addMarker = function(marker){\n\treturn this._markers.addItem(marker);\n};\n\ngantt.deleteMarker = function(id){\n\tif(!this._markers.exists(id))\n\t\treturn false;\n\n\tthis._markers.removeItem(id);\n\treturn true;\n};\ngantt.updateMarker = function(id){\n\tthis._markers.refresh(id);\n};\n\ngantt._getMarkers = function(){\n\treturn this._markers.getItems();\n};\n\ngantt.renderMarkers = function () {\n\tthis._markers.refresh();\n};\n\n};","import {replaceValidZeroId} from \"../utils/helpers\";\n\nexport default function(gantt){\n\ngantt.config.multiselect = true;\ngantt.config.multiselect_one_level = false;\n\ngantt._multiselect = {\n\t_selected: {},\n\t_one_level: false,\n\t_active: true,\n\t_first_selected_when_shift: null,\n\tgetDefaultSelected: function() {\n\t\tvar selected = this.getSelected();\n\t\treturn selected.length ? selected[selected.length - 1] : null;\n\t},\n\tsetFirstSelected: function(id) {\n\t\tthis._first_selected_when_shift = id;\n\t},\n\tgetFirstSelected: function() {\n\t\treturn this._first_selected_when_shift;\n\t},\n\tisActive: function() {\n\t\tthis.updateState();\n\t\treturn this._active;\n\t},\n\tupdateState: function() {\n\t\tthis._one_level = gantt.config.multiselect_one_level;\n\t\tvar active = this._active;\n\t\tthis._active = gantt.config.select_task;\n\t\tif (this._active != active) {\n\t\t\tthis.reset();\n\t\t}\n\t},\n\treset: function () {\n\t\tthis._selected = {};\n\t},\n\tsetLastSelected: function (id) {\n\t\tgantt.$data.tasksStore.silent(function(){\n\t\t\tvar store = gantt.$data.tasksStore;\n\t\t\tif (id)\n\t\t\t\tstore.select(id+\"\");\n\t\t\telse\n\t\t\t\tstore.unselect(null);\n\t\t});\n\t},\n\tgetLastSelected: function () {\n\t\tvar last = gantt.$data.tasksStore.getSelectedId();\n\t\tif (last && gantt.isTaskExists(last))\n\t\t\treturn last;\n\t\treturn null;\n\t},\n\tselect: function (id, e) {\n\t\tif (id && gantt.callEvent(\"onBeforeTaskMultiSelect\", [id, true, e]) && gantt.callEvent(\"onBeforeTaskSelected\", [id])) {\n\t\t\tthis._selected[id] = true;\n\t\t\tthis.setLastSelected(id);\n\t\t\tthis.afterSelect(id);\n\t\t\tgantt.callEvent(\"onTaskMultiSelect\", [id, true, e]);\n\t\t\tgantt.callEvent(\"onTaskSelected\", [id]);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t},\n\ttoggle: function (id, e) {\n\t\tif (this._selected[id]) {\n\t\t\tthis.unselect(id, e);\n\t\t} else {\n\t\t\tthis.select(id, e);\n\t\t}\n\t},\n\tunselect: function (id, e) {\n\t\tif (id && gantt.callEvent(\"onBeforeTaskMultiSelect\", [id, false, e])) {\n\t\t\tthis._selected[id] = false;\n\t\t\tif (this.getLastSelected() == id)\n\t\t\t\tthis.setLastSelected(this.getDefaultSelected());\n\t\t\tthis.afterSelect(id);\n\t\t\tgantt.callEvent(\"onTaskMultiSelect\", [id, false, e]);\n\t\t\tgantt.callEvent(\"onTaskUnselected\", [id]);\n\t\t}\n\t},\n\tisSelected: function (id) {\n\t\treturn !!(gantt.isTaskExists(id) && this._selected[id]);\n\t},\n\tgetSelected: function () {\n\t\tvar res = [];\n\t\tfor (var i in this._selected) {\n\t\t\tif (this._selected[i] && gantt.isTaskExists(i)) {\n\t\t\t\tres.push(i);\n\t\t\t} else {\n\t\t\t\tthis._selected[i] = false;\n\t\t\t}\n\t\t}\n\t\tres.sort(function(a, b) {\n\t\t\treturn gantt.getGlobalTaskIndex(a) > gantt.getGlobalTaskIndex(b) ? 1 : -1;\n\t\t});\n\t\treturn res;\n\t},\n\tforSelected: function (callback) {\n\t\tvar selected = this.getSelected();\n\t\tfor (var i = 0; i < selected.length; i++) {\n\t\t\tcallback(selected[i]);\n\t\t}\n\t},\n\tisSameLevel: function(id) {\n\t\tif (!this._one_level)\n\t\t\treturn true;\n\t\tvar last = this.getLastSelected();\n\t\tif (!last)\n\t\t\treturn true;\n\t\tif (!(gantt.isTaskExists(last) && gantt.isTaskExists(id)))\n\t\t\treturn true;\n\t\treturn !!(gantt.calculateTaskLevel(gantt.getTask(last)) == gantt.calculateTaskLevel(gantt.getTask(id)));\n\t},\n\tafterSelect: function(id) {\n\t\tif (gantt.isTaskExists(id)){\n\t\t\t// FIXME: quick workaround to prevent re-filtering inside refresh on multiselect\n\t\t\tgantt._quickRefresh(function(){\n\t\t\t\tgantt.refreshTask(id);\n\t\t\t});\n\t\t}\n\t},\n\tdoSelection: function(e) {\n\t\tif (!this.isActive())\n\t\t\treturn false;\n\n\t\t// deny selection when click on 'expand' or 'collapse' icons\n\t\tif (gantt._is_icon_open_click(e))\n\t\t\treturn false;\n\n\t\tvar target_ev = gantt.locate(e);\n\t\tif (!target_ev)\n\t\t\treturn false;\n\n\t\tif (!gantt.callEvent(\"onBeforeMultiSelect\", [e]))\n\t\t\treturn false;\n\n\t\tvar selected = this.getSelected();\n\t\tvar defaultLast = this.getFirstSelected();\n\t\tvar isLast = false;\n\t\tvar last = this.getLastSelected();\n\t\tvar multiSelect = gantt.config.multiselect;\n\n\n\t\tvar singleSelection = (function () {\n\t\t\t// GS-719: If the multiselect extension is added we still need a way\n\t\t\t// to open the inline editors after clicking on the cells in the grid\n\t\t\tvar controller = gantt.ext.inlineEditors;\n\t\t\tvar state = controller.getState();\n\t\t\tvar cell = controller.locateCell(e.target);\n\n\t\t\tif (gantt.config.inline_editors_multiselect_open && cell && controller.getEditorConfig(cell.columnName)) {\n\t\t\t\tif (controller.isVisible() && state.id == cell.id && state.columnName == cell.columnName) {\n\t\t\t\t\t// do nothing if editor is already active in this cell\n\t\t\t\t} else {\n\t\t\t\t\tcontroller.startEdit(cell.id, cell.columnName);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.setFirstSelected(target_ev);\n\n\t\t\tif (!this.isSelected(target_ev)) {\n\t\t\t\tthis.select(target_ev, e);\n\t\t\t}\n\t\t\tselected = this.getSelected();\n\t\t\tfor (var i = 0; i < selected.length; i++) {\n\t\t\t\tif (selected[i] !== target_ev) {\n\t\t\t\t\tthis.unselect(selected[i], e);\n\t\t\t\t}\n\t\t\t}\n\t\t}).bind(this);\n\n\t\tvar blockSelection = (function(){\n\t\t\tif (!last)\n\t\t\t\tlast = target_ev;\n\t\t\telse if (target_ev) {\n\t\t\t\tvar first_indx = gantt.getGlobalTaskIndex(this.getFirstSelected());\n\t\t\t\tvar target_indx = gantt.getGlobalTaskIndex(target_ev);\n\t\t\t\tvar last_indx = gantt.getGlobalTaskIndex(last);\n\t\t\t\t// GS-1969: if the selected tasks are collapsed, need to remove them\n\t\t\t\tif(first_indx == -1 || last_indx == -1){\n\t\t\t\t\tfirst_indx = target_indx;\n\t\t\t\t\tthis.reset();\n\t\t\t\t}\n\t\t\t\t// clear prev selection\n\t\t\t\tvar tmp = last;\n\t\t\t\twhile (gantt.getGlobalTaskIndex(tmp) !== first_indx) {\n\t\t\t\t\tthis.unselect(tmp, e);\n\t\t\t\t\ttmp = (first_indx > last_indx) ? gantt.getNext(tmp) : gantt.getPrev(tmp);\n\t\t\t\t}\n\t\t\t\ttmp = target_ev;\n\t\t\t\twhile (gantt.getGlobalTaskIndex(tmp) !== first_indx) {\n\t\t\t\t\tif (this.select(tmp, e) && !isLast) {\n\t\t\t\t\t\tisLast = true;\n\t\t\t\t\t\tdefaultLast = tmp;\n\t\t\t\t\t}\n\t\t\t\t\ttmp = (first_indx > target_indx) ? gantt.getNext(tmp) : gantt.getPrev(tmp);\n\t\t\t\t}\n\t\t\t}\n\t\t}).bind(this);\n\n\n\t\tif (multiSelect && (e.ctrlKey || e.metaKey)) {\n\t\t\tif (!this.isSelected(target_ev))\n\t\t\t\tthis.setFirstSelected(target_ev);\n\n\t\t\tif (target_ev) {\n\t\t\t\tthis.toggle(target_ev, e);\n\t\t\t}\n\t\t}\n\n\t\telse if (multiSelect && e.shiftKey) {\n\t\t\tif (!gantt.isTaskExists(this.getFirstSelected()) || this.getFirstSelected() === null) {\n\t\t\t\tthis.setFirstSelected(target_ev);\n\t\t\t}\n\n\t\t\tif (selected.length) { // select a group of tasks\n\t\t\t\tblockSelection();\n\t\t\t}\n\t\t\telse { // select a task when no task is selected and Shift is pressed\n\t\t\t\tsingleSelection();\n\t\t\t}\n\t\t}\n\t\t\n\t\telse { // no key press or no multiple selection on the mouse click\n\t\t\tsingleSelection();\n\t\t}\n\n\n\t\tif (this.isSelected(target_ev)) {\n\t\t\tthis.setLastSelected(target_ev);\n\t\t} else if (defaultLast) {\n\t\t\tif (target_ev == last)\n\t\t\t\tthis.setLastSelected(e.shiftKey ? defaultLast : this.getDefaultSelected());\n\t\t} else {\n\t\t\tthis.setLastSelected(null);\n\t\t}\n\n\t\tif (!this.getSelected().length)\n\t\t\tthis.setLastSelected(null);\n\n\t\tif (!this.getLastSelected() || !this.isSelected(this.getFirstSelected()))\n\t\t\tthis.setFirstSelected(this.getLastSelected());\n\n\t\treturn true;\n\t}\n};\n\n(function(){\n\tvar old_selectTask = gantt.selectTask;\n\tgantt.selectTask = function(id) {\n\t\tid = replaceValidZeroId(id, this.config.root_id);\n\t\tif (!id)\n\t\t\treturn false;\n\t\tvar multiselect = gantt._multiselect;\n\t\tvar res = id;\n\t\tif (multiselect.isActive()) {\n\t\t\tif (multiselect.select(id, null)) {\n\t\t\t\tmultiselect.setLastSelected(id);\n\t\t\t}\n\t\t\tmultiselect.setFirstSelected(multiselect.getLastSelected());\n\t\t} else {\n\t\t\tres = old_selectTask.call(this, id);\n\t\t}\n\t\treturn res;\n\t};\n\n\tvar old_unselectTask = gantt.unselectTask;\n\tgantt.unselectTask = function(id) {\n\t\tvar multiselect = gantt._multiselect;\n\t\tvar isActive = multiselect.isActive();\n\t\tid = id || multiselect.getLastSelected();\n\t\tif(id && isActive) {\n\t\t\tmultiselect.unselect(id, null);\n\t\t\tif (id == multiselect.getLastSelected())\n\t\t\t\tmultiselect.setLastSelected(null);\n\t\t\tgantt.refreshTask(id);\n\t\t\tmultiselect.setFirstSelected(multiselect.getLastSelected());\n\t\t}\n\t\tvar res = id;\n\t\tif (!isActive)\n\t\t\tres = old_unselectTask.call(this, id);\n\t\treturn res;\n\t};\n\n\tgantt.toggleTaskSelection = function(id) {\n\t\tvar multiselect = gantt._multiselect;\n\t\tif (id && multiselect.isActive()) {\n\t\t\tmultiselect.toggle(id);\n\t\t\tmultiselect.setFirstSelected(multiselect.getLastSelected());\n\t\t}\n\t};\n\tgantt.getSelectedTasks = function() {\n\t\tvar multiselect = gantt._multiselect;\n\t\tmultiselect.isActive();\n\t\treturn multiselect.getSelected();\n\t};\n\tgantt.eachSelectedTask = function(callback){\n\t\treturn this._multiselect.forSelected(callback);\n\t};\n\tgantt.isSelectedTask = function(id){\n\t\treturn this._multiselect.isSelected(id);\n\t};\n\tgantt.getLastSelectedTask = function(){\n\t\treturn this._multiselect.getLastSelected();\n\t};\n\tgantt.attachEvent(\"onGanttReady\", function(){\n\t\tvar old_isSelected = gantt.$data.tasksStore.isSelected;\n\t\tgantt.$data.tasksStore.isSelected = function(id){\n\t\t\tif (gantt._multiselect.isActive()) {\n\t\t\t\treturn gantt._multiselect.isSelected(id);\n\t\t\t}\n\t\t\treturn old_isSelected.call(this, id);\n\t\t};\n\t});\n})();\n\ngantt.attachEvent(\"onTaskIdChange\", function (id, new_id) {\n\tvar multiselect = gantt._multiselect;\n\tif (!multiselect.isActive())\n\t\treturn true;\n\tif (gantt.isSelectedTask(id)) {\n\t\tmultiselect.unselect(id, null);\n\t\tmultiselect.select(new_id, null);\n\t}\n});\n\ngantt.attachEvent(\"onAfterTaskDelete\", function (id, item) {\n\tvar multiselect = gantt._multiselect;\n\tif (!multiselect.isActive())\n\t\treturn true;\n\n\tif (multiselect._selected[id]) {\n\t\t// GS-1057: don't unselect the task here because the task is already unselected \n\t\t// it was in the select.js file before it was deleted\n\t\t// multiselect.unselect(id, null);\n\t\tmultiselect._selected[id] = false;\n\t\tmultiselect.setLastSelected(multiselect.getDefaultSelected());\n\t}\n\n\tmultiselect.forSelected(function (task_id) {\n\t\tif (!gantt.isTaskExists(task_id))\n\t\t\tmultiselect.unselect(task_id, null);\n\t});\n});\n\ngantt.attachEvent(\"onBeforeTaskMultiSelect\", function(id, state, e){\n\tconst multiselect = gantt._multiselect;\n\tif (state && multiselect.isActive()) {\n\t\t//GS-1321: prevent unselecting task\n\t\tlet oldSelectedId = gantt.getSelectedId();\n\t\tlet oldSelectedTask = null;\n\t\tif (oldSelectedId) {\n\t\t\toldSelectedTask = gantt.getTask(oldSelectedId);\n\t\t}\n\t\tlet newSelectedTask = gantt.getTask(id);\n\t\tlet differentTreeLevel = false;\n\t\tif (oldSelectedTask && oldSelectedTask.$level != newSelectedTask.$level){\n\t\t\tdifferentTreeLevel = true;\n\t\t}\n\n\t\tif (gantt.config.multiselect_one_level && differentTreeLevel && !e.ctrlKey && !e.shiftKey) {\n\t\t\treturn true;\n\t\t}\n\t\tif (multiselect._one_level) {\n\t\t\treturn multiselect.isSameLevel(id);\n\t\t}\n\t}\n\treturn true;\n});\n\ngantt.attachEvent(\"onTaskClick\", function(id, e) {\n\tif (gantt._multiselect.doSelection(e))\n\t\tgantt.callEvent(\"onMultiSelect\", [e]);\n\treturn true;\n});\n\n};","export default function(gantt) {\n\tif (!gantt.ext) {\n\t\tgantt.ext = {};\n\t}\n\n\tgantt.ext.overlay = {};\n\n\tvar overlays = {};\n\n\tfunction createOverlay(id, render) {\n\t\tvar div = document.createElement(\"div\");\n\t\tdiv.setAttribute(\"data-overlay-id\", id);\n\t\tvar css = \"gantt_overlay\";\n\t\tdiv.className = css;\n\t\tdiv.style.display = \"none\";\n\t\treturn {\n\t\t\tid: id,\n\t\t\trender: render,\n\t\t\tisVisible: false,\n\t\t\tisAttached: false,\n\t\t\tnode: div\n\t\t};\n\t}\n\n\tfunction initOverlayArea() {\n\t\tif(!gantt.$task_data) {\n\t\t\treturn;\n\t\t}\n\t\tgantt.event(gantt.$task_data, \"scroll\", function(e){\n\t\t\tif (!gantt.ext.$overlay_area) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tgantt.ext.$overlay_area.style.top = e.target.scrollTop + \"px\";\n\t\t});\n\t\tvar overlayArea = document.createElement(\"div\");\n\t\toverlayArea.className = \"gantt_overlay_area\";\n\t\tgantt.$task_data.appendChild(overlayArea);\n\t\tgantt.ext.$overlay_area = overlayArea;\n\n\t\tattachUnnattached();\n\t}\n\n\tfunction attachUnnattached(){\n\t\tfor(var i in overlays){\n\t\t\tvar overlay = overlays[i];\n\t\t\tif(!overlay.isAttached){\n\t\t\t\tattachOverlay(overlay);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction attachOverlay(overlay){\n\t\tgantt.ext.$overlay_area.appendChild(overlay.node);\n\t\toverlay.isAttached = true;\n\t}\n\n\tfunction showOverlayArea(){\n\t\tgantt.ext.$overlay_area.style.display = \"block\";\n\t}\n\n\tfunction hideIfNoVisibleLayers(){\n\t\tvar any = false;\n\t\tfor(var i in overlays){\n\t\t\tvar overlay = overlays[i];\n\t\t\tif(overlay.isVisible){\n\t\t\t\tany = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif(!any){\n\t\t\tgantt.ext.$overlay_area.style.display = \"none\";\n\t\t}\n\t}\n\n\tgantt.attachEvent(\"onBeforeGanttRender\", function() {\n\t\t//GS-2230: in case if `getGanttInstance` created without container\n\t\tif(!gantt.$root) return;\n\t\tif (!gantt.ext.$overlay_area) {\n\t\t\tinitOverlayArea();\n\t\t}\n\n\t\tif (!gantt.ext.$overlay_area.isConnected){\n\t\t\tgantt.ext.$overlay_area.innerHTML = \"\";\n\t\t\tgantt.ext.$overlay_area.remove();\n\t\t\tgantt.ext.$overlay_area = null;\n\t\t\tinitOverlayArea();\n\t\n\t\t\tfor(var i in overlays){\n\t\t\t\toverlays[i].isAttached = false;\n\t\t\t}\n\t\t}\n\n\t\tattachUnnattached();\n\t\thideIfNoVisibleLayers();\n\t});\n\n\tgantt.attachEvent(\"onGanttReady\", function() {\n\t\t//GS-2230: in case if `getGanttInstance` created without container\n\t\tif(!gantt.$root) return;\n\t\tinitOverlayArea();\n\t\tattachUnnattached();\n\t\thideIfNoVisibleLayers();\n\t});\n\n\tgantt.ext.overlay.addOverlay = function(render, id) {\n\t\tvar id = id || gantt.uid();\n\t\toverlays[id] = createOverlay(id, render);\n\t\treturn id;\n\t};\n\n\tgantt.ext.overlay.deleteOverlay = function(id) {\n\t\tif (!overlays[id])\n\t\t\treturn false;\n\n\t\tdelete overlays[id];\n\t\thideIfNoVisibleLayers();\n\t\treturn true;\n\t};\n\n\tgantt.ext.overlay.getOverlaysIds = function() {\n\t\tvar ids = [];\n\t\tfor(var i in overlays){\n\t\t\tids.push(i);\n\t\t}\n\t\treturn ids;\n\t};\n\n\tgantt.ext.overlay.refreshOverlay = function(id) {\n\t\tshowOverlayArea();\n\t\toverlays[id].isVisible = true;\n\t\toverlays[id].node.innerHTML = \"\";\n\t\toverlays[id].node.style.display = \"block\";\n\t\toverlays[id].render(overlays[id].node);\n\t};\n\n\tgantt.ext.overlay.showOverlay = function(id) {\n\t\tshowOverlayArea();\n\t\tthis.refreshOverlay(id);\n\t};\n\n\tgantt.ext.overlay.hideOverlay = function(id) {\n\n\t\toverlays[id].isVisible = false;\n\t\toverlays[id].node.style.display = \"none\";\n\t\thideIfNoVisibleLayers();\n\t};\n\tgantt.ext.overlay.isOverlayVisible = function(id) {\n\t\tif (!id) {\n\t\t\treturn false;\n\t\t}\n\t\treturn overlays[id].isVisible;\n\t};\n};","/* eslint-disable */\n\nexport default function(gantt: any) {\n\n\tgantt.ext = gantt.ext || {};\n\n\tgantt.ext.export_api = gantt.ext.export_api || {\n\n\t\t_apiUrl: \"https://export.dhtmlx.com/gantt\",\n\n\t\t_preparePDFConfigRaw(config, type){\n\t\t\tlet previousDateRage:any = null;\n\t\t\tif (config.start && config.end){\n\t\t\t\tpreviousDateRage = {\n\t\t\t\t\tstart_date: gantt.config.start_date,\n\t\t\t\t\tend_date: gantt.config.end_date,\n\t\t\t\t};\n\t\t\t\tgantt.config.start_date = gantt.date.str_to_date(gantt.config.date_format)(config.start);\n\t\t\t\tgantt.config.end_date = gantt.date.str_to_date(gantt.config.date_format)(config.end);\n\t\t\t}\n\n\t\t\tconfig = gantt.mixin(config, {\n\t\t\t\tname: \"gantt.\" + type, data: gantt.ext.export_api._serializeHtml()\n\t\t\t});\n\n\t\t\tif (previousDateRage){\n\t\t\t\tgantt.config.start_date = previousDateRage.start_date;\n\t\t\t\tgantt.config.end_date = previousDateRage.end_date;\n\t\t\t}\n\t\t},\n\n\t\t_prepareConfigPDF(config, type){\n\t\t\tconfig = gantt.mixin((config || {}), {\n\t\t\t\tname: \"gantt.\" + type,\n\t\t\t\tdata: gantt.ext.export_api._serializeAll(),\n\t\t\t\tconfig: gantt.config\n\t\t\t});\n\t\t\tgantt.ext.export_api._fixColumns(config.config.columns);\n\t\t\treturn config;\n\t\t},\n\n\t\t_pdfExportRouter(config, type){\n\t\t\tif (config && config.raw) {\n\t\t\t\tgantt.ext.export_api._preparePDFConfigRaw(config, type);\n\t\t\t} else {\n\t\t\t\tconfig = gantt.ext.export_api._prepareConfigPDF(config, type);\n\t\t\t}\n\t\t\tconfig.version = gantt.version;\n\t\t\tgantt.ext.export_api._sendToExport(config, type);\n\t\t},\n\n\t\texportToPDF(config) {\n\t\t\tgantt.ext.export_api._pdfExportRouter(config, \"pdf\");\n\t\t},\n\n\t\texportToPNG(config) {\n\t\t\tgantt.ext.export_api._pdfExportRouter(config, \"png\");\n\t\t},\n\n\n\t\texportToICal(config) {\n\t\t\tconfig = gantt.mixin((config || {}), {\n\t\t\t\tname: \"gantt.ical\",\n\t\t\t\tdata: gantt.ext.export_api._serializePlain().data,\n\t\t\t\tversion: gantt.version\n\t\t\t});\n\t\t\tgantt.ext.export_api._sendToExport(config, \"ical\");\n\t\t},\n\n\t\texportToExcel(config) {\n\t\t\tconfig = config || {};\n\n\t\t\tlet tasks;\n\t\t\tlet dates;\n\t\t\tlet state;\n\t\t\tlet scroll;\n\t\t\t// GS-2124, we need to get all task nodes to correctly obtain the colors\n\t\t\tconst smartRendering = gantt.config.smart_rendering;\n\t\t\tif (config.visual === \"base-colors\"){\n\t\t\t\tgantt.config.smart_rendering = false;\n\t\t\t}\n\n\t\t\tif (config.start || config.end) {\n\t\t\t\tstate = gantt.getState();\n\t\t\t\tdates = [gantt.config.start_date, gantt.config.end_date];\n\t\t\t\tscroll = gantt.getScrollState();\n\t\t\t\tconst convert = gantt.date.str_to_date(gantt.config.date_format);\n\t\t\t\ttasks = gantt.eachTask;\n\n\t\t\t\tif (config.start){\n\t\t\t\t\tgantt.config.start_date = convert(config.start);\n\t\t\t\t}\n\t\t\t\tif (config.end){\n\t\t\t\t\tgantt.config.end_date = convert(config.end);\n\t\t\t\t}\n\n\t\t\t\tgantt.render();\n\t\t\t\tgantt.config.smart_rendering = smartRendering;\n\n\t\t\t\tgantt.eachTask = gantt.ext.export_api._eachTaskTimed(gantt.config.start_date, gantt.config.end_date);\n\t\t\t} else if (config.visual === \"base-colors\"){\n\t\t\t\tgantt.render();\n\t\t\t\tgantt.config.smart_rendering = smartRendering;\n\t\t\t}\n\n\t\t\tgantt._no_progress_colors = config.visual === \"base-colors\";\n\n\t\t\tconfig = gantt.mixin(config, {\n\t\t\t\tname: \"gantt.xlsx\",\n\t\t\t\ttitle: \"Tasks\",\n\t\t\t\tdata: gantt.ext.export_api._serializeTimeline(config).data,\n\t\t\t\tcolumns: gantt.ext.export_api._serializeGrid({ rawDates: true }),\n\t\t\t\tversion: gantt.version\n\t\t\t});\n\n\t\t\tif (config.visual){\n\t\t\t\tconfig.scales = gantt.ext.export_api._serializeScales(config);\n\t\t\t}\n\n\t\t\tgantt.ext.export_api._sendToExport(config, \"excel\");\n\n\t\t\tif (config.start || config.end) {\n\t\t\t\tgantt.config.start_date = state.min_date;\n\t\t\t\tgantt.config.end_date = state.max_date;\n\t\t\t\tgantt.eachTask = tasks;\n\n\t\t\t\tgantt.render();\n\t\t\t\tgantt.scrollTo(scroll.x, scroll.y);\n\n\t\t\t\tgantt.config.start_date = dates[0];\n\t\t\t\tgantt.config.end_date = dates[1];\n\t\t\t}\n\t\t},\n\n\t\texportToJSON(config) {\n\t\t\tconfig = gantt.mixin((config || {}), {\n\t\t\t\tname: \"gantt.json\",\n\t\t\t\tdata: gantt.ext.export_api._serializeAll(),\n\t\t\t\tconfig: gantt.config,\n\t\t\t\tcolumns: gantt.ext.export_api._serializeGrid(),\n\t\t\t\tworktime: gantt.ext.export_api._getWorktimeSettings(),\n\t\t\t\tversion: gantt.version\n\t\t\t});\n\t\t\tgantt.ext.export_api._sendToExport(config, \"json\");\n\t\t},\n\n\n\t\timportFromExcel(config) {\n\t\t\ttry {\n\t\t\t\tconst formData = config.data;\n\t\t\t\tif (formData instanceof File) {\n\t\t\t\t\tconst data = new FormData();\n\t\t\t\t\tdata.append(\"file\", formData);\n\t\t\t\t\tconfig.data = data;\n\t\t\t\t}\n\t\t\t} catch (error) {}\n\t\t\tgantt.ext.export_api._sendImportAjaxExcel(config);\n\t\t},\n\n\t\timportFromMSProject(config) {\n\t\t\tconst formData = config.data;\n\t\t\ttry {\n\t\t\t\tif (formData instanceof File) {\n\t\t\t\t\tconst data = new FormData();\n\t\t\t\t\tdata.append(\"file\", formData);\n\t\t\t\t\tconfig.data = data;\n\t\t\t\t}\n\t\t\t} catch (error) {}\n\t\t\tgantt.ext.export_api._sendImportAjaxMSP(config);\n\t\t},\n\n\t\timportFromPrimaveraP6(config) {\n\t\t\tconfig.type = \"primaveraP6-parse\";\n\t\t\treturn gantt.importFromMSProject(config);\n\t\t},\n\n\t\texportToMSProject(config) {\n\t\t\tconfig = config || {};\n\t\t\tconfig.skip_circular_links = config.skip_circular_links === undefined ? true : !!config.skip_circular_links;\n\n\t\t\tconst oldXmlFormat = gantt.templates.xml_format;\n\t\t\tconst oldFormatDate = gantt.templates.format_date;\n\t\t\tconst oldXmlDate = gantt.config.xml_date;\n\t\t\tconst oldDateFormat = gantt.config.date_format;\n\n\t\t\tconst exportServiceDateFormat = \"%d-%m-%Y %H:%i:%s\";\n\n\t\t\tgantt.config.xml_date = exportServiceDateFormat;\n\t\t\tgantt.config.date_format = exportServiceDateFormat;\n\t\t\tgantt.templates.xml_format = gantt.date.date_to_str(exportServiceDateFormat);\n\t\t\tgantt.templates.format_date = gantt.date.date_to_str(exportServiceDateFormat);\n\t\t\tconst data = gantt.ext.export_api._serializeAll();\n\n\t\t\tgantt.ext.export_api._customProjectProperties(data, config);\n\n\t\t\tgantt.ext.export_api._customTaskProperties(data, config);\n\n\t\t\tif (config.skip_circular_links) {\n\t\t\t\tgantt.ext.export_api._clearRecLinks(data);\n\t\t\t}\n\n\t\t\tconfig = gantt.ext.export_api._exportConfig(data, config);\n\n\t\t\tgantt.ext.export_api._sendToExport(config, config.type || \"msproject\");\n\t\t\tgantt.config.xml_date = oldXmlDate;\n\t\t\tgantt.config.date_format = oldDateFormat;\n\t\t\tgantt.templates.xml_format = oldXmlFormat;\n\t\t\tgantt.templates.format_date = oldFormatDate;\n\n\t\t\tgantt.config.$custom_data = null;\n\t\t\tgantt.config.custom = null;\n\t\t},\n\n\t\texportToPrimaveraP6(config) {\n\t\t\tconfig = config || {};\n\t\t\tconfig.type = \"primaveraP6\";\n\t\t\treturn gantt.exportToMSProject(config);\n\t\t},\n\n\t\t_fixColumns(columns) {\n\t\t\tfor (let i = 0; i < columns.length; i++) {\n\t\t\t\tcolumns[i].label = columns[i].label || gantt.locale.labels[\"column_\" + columns[i].name];\n\t\t\t\tif (typeof columns[i].width === \"string\") {\n\t\t\t\t\tcolumns[i].width = columns[i].width * 1;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_xdr(url, pack, cb) {\n\t\t\tgantt.ajax.post(url, pack, cb);\n\t\t},\n\n\t\t_markColumns(base) {\n\t\t\tconst columns = base.config.columns;\n\t\t\tif (columns){\n\t\t\t\tfor (let i = 0; i < columns.length; i++) {\n\t\t\t\t\tif (columns[i].template){\n\t\t\t\t\t\tcolumns[i].$template = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\n\t\t_sendImportAjaxExcel(config) {\n\t\t\tconst url = config.server || gantt.ext.export_api._apiUrl;\n\t\t\tconst store = config.store || 0;\n\t\t\tconst formData = config.data;\n\t\t\tconst callback = config.callback;\n\n\t\t\tformData.append(\"type\", \"excel-parse\");\n\t\t\tformData.append(\"data\", JSON.stringify({\n\t\t\t\tsheet: config.sheet || 0\n\t\t\t}));\n\n\t\t\tif (store){\n\t\t\t\tformData.append(\"store\", store);\n\t\t\t}\n\n\t\t\tconst xhr = new XMLHttpRequest();\n\t\t\txhr.onreadystatechange = function(e) {\n\t\t\t\tif (xhr.readyState === 4 && xhr.status === 0) {// network error\n\t\t\t\t\tif (callback) {\n\t\t\t\t\t\tcallback(null);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\txhr.onload = function() {\n\t\t\t\tconst fail = xhr.status > 400;\n\t\t\t\tlet info = null;\n\n\t\t\t\tif (!fail) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinfo = JSON.parse(xhr.responseText);\n\t\t\t\t\t} catch (e) { }\n\t\t\t\t}\n\n\t\t\t\tif (callback) {\n\t\t\t\t\tcallback(info);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\txhr.open(\"POST\", url, true);\n\t\t\txhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n\t\t\txhr.send(formData);\n\t\t},\n\n\n\t\t_ajaxToExport(data, type, callback) {\n\t\t\tdelete data.callback;\n\n\t\t\tconst url = data.server || gantt.ext.export_api._apiUrl;\n\t\t\tconst pack = \"type=\" + type + \"&store=1&data=\" + encodeURIComponent(JSON.stringify(data));\n\n\t\t\tconst cb = function(loader) {\n\t\t\t\tconst xdoc = loader.xmlDoc || loader;\n\t\t\t\tconst fail = xdoc.status > 400;\n\t\t\t\tlet info = null;\n\n\t\t\t\tif (!fail) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinfo = JSON.parse(xdoc.responseText);\n\t\t\t\t\t} catch (e) { }\n\t\t\t\t}\n\t\t\t\tcallback(info);\n\t\t\t};\n\n\t\t\tgantt.ext.export_api._xdr(url, pack, cb);\n\t\t},\n\t\t_serializableGanttConfig(config) {\n\t\t\tconst result = gantt.mixin({}, config);\n\n\t\t\tif (result.columns) {\n\t\t\t\tresult.columns = result.columns.map(function(col) {\n\t\t\t\t\tconst copy = gantt.mixin({}, col);\n\t\t\t\t\tdelete copy.editor;\n\t\t\t\t\treturn copy;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tdelete result.editor_types;\n\t\t\treturn result;\n\t\t},\n\n\t\t_sendToExport(data, type) {\n\t\t\tconst convert = gantt.date.date_to_str(gantt.config.date_format || gantt.config.xml_date);\n\t\t\tif(!data.skin){\n\t\t\t\tdata.skin = gantt.skin;\n\t\t\t}\n\t\t\tif (data.config) {\n\t\t\t\tdata.config = gantt.copy(gantt.ext.export_api._serializableGanttConfig(data.config));\n\t\t\t\tgantt.ext.export_api._markColumns(data, type);\n\n\t\t\t\tif (data.config.start_date && data.config.end_date) {\n\t\t\t\t\tif (data.config.start_date instanceof Date) {\n\t\t\t\t\t\tdata.config.start_date = convert(data.config.start_date);\n\t\t\t\t\t}\n\t\t\t\t\tif (data.config.end_date instanceof Date) {\n\t\t\t\t\t\tdata.config.end_date = convert(data.config.end_date);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (data.callback) {\n\t\t\t\treturn gantt.ext.export_api._ajaxToExport(data, type, data.callback);\n\t\t\t}\n\n\t\t\tconst form = gantt.ext.export_api._createHiddenForm();\n\t\t\tform.firstChild.action = data.server || gantt.ext.export_api._apiUrl;\n\t\t\tform.firstChild.childNodes[0].value = JSON.stringify(data);\n\t\t\tform.firstChild.childNodes[1].value = type;\n\t\t\tform.firstChild.submit();\n\t\t},\n\n\t\t_createHiddenForm() {\n\t\t\tif (!gantt.ext.export_api._hidden_export_form) {\n\t\t\t\tconst t = gantt.ext.export_api._hidden_export_form = document.createElement(\"div\");\n\t\t\t\tt.style.display = \"none\";\n\t\t\t\tt.innerHTML = \"
\";\n\t\t\t\tdocument.body.appendChild(t);\n\t\t\t}\n\t\t\treturn gantt.ext.export_api._hidden_export_form;\n\t\t},\n\n\n\t\t_copyObjectBase(obj) {\n\t\t\tconst copy = {\n\t\t\t\tstart_date: undefined,\n\t\t\t\tend_date: undefined,\n\t\t\t\tconstraint_date: undefined,\n\t\t\t\tdeadline: undefined\n\t\t\t};\n\t\t\tfor (const key in obj) {\n\t\t\t\tif (key.charAt(0) === \"$\" || key === \"baselines\"){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcopy[key] = obj[key];\n\t\t\t}\n\t\t\tconst formatDate = gantt.templates.xml_format || gantt.templates.format_date;\n\n\t\t\tcopy.start_date = formatDate(copy.start_date);\n\t\t\tif (copy.end_date){\n\t\t\t\tcopy.end_date = formatDate(copy.end_date);\n\t\t\t}\n\t\t\tif (copy.constraint_date){\n\t\t\t\tcopy.constraint_date = formatDate(copy.constraint_date);\n\t\t\t}\n\t\t\tif (copy.deadline){\n\t\t\t\tcopy.deadline = formatDate(copy.deadline);\n\t\t\t}\n\n\t\t\treturn copy;\n\t\t},\n\n\n\t\t_color_box: null,\n\t\t_color_hash: {},\n\n\t\t_getStyles(css) {\n\t\t\tif (!gantt.ext.export_api._color_box) {\n\t\t\t\tgantt.ext.export_api._color_box = document.createElement(\"DIV\");\n\t\t\t\tgantt.ext.export_api._color_box.style.cssText = \"position:absolute; display:none;\";\n\t\t\t\tdocument.body.appendChild(gantt.ext.export_api._color_box);\n\t\t\t}\n\t\t\tif (gantt.ext.export_api._color_hash[css]){\n\t\t\t\treturn gantt.ext.export_api._color_hash[css];\n\t\t\t}\n\n\t\t\tgantt.ext.export_api._color_box.className = css;\n\t\t\tconst color = gantt.ext.export_api._getColor(gantt.ext.export_api._color_box, \"color\");\n\t\t\tconst backgroundColor = gantt.ext.export_api._getColor(gantt.ext.export_api._color_box, \"backgroundColor\");\n\t\t\treturn (gantt.ext.export_api._color_hash[css] = color + \";\" + backgroundColor);\n\t\t},\n\n\n\t\t_getMinutesWorktimeSettings(parsedRanges) {\n\t\t\tconst minutes:any = [];\n\t\t\tparsedRanges.forEach(function(range) {\n\t\t\t\tminutes.push(range.startMinute);\n\t\t\t\tminutes.push(range.endMinute);\n\t\t\t});\n\t\t\treturn minutes;\n\t\t},\n\n\t\t_getWorktimeSettings() {\n\n\t\t\tconst defaultWorkTimes = {\n\t\t\t\thours: [0, 24],\n\t\t\t\tminutes: null,\n\t\t\t\tdates: { 0: true, 1: true, 2: true, 3: true, 4: true, 5: true, 6: true }\n\t\t\t};\n\n\t\t\tlet time;\n\t\t\tif (!gantt.config.work_time) {\n\t\t\t\ttime = defaultWorkTimes;\n\t\t\t} else {\n\t\t\t\tconst wTime = gantt._working_time_helper;\n\t\t\t\tif (wTime && wTime.get_calendar) {\n\t\t\t\t\ttime = wTime.get_calendar();\n\t\t\t\t} else if (wTime) {\n\t\t\t\t\ttime = {\n\t\t\t\t\t\thours: wTime.hours,\n\t\t\t\t\t\tminutes: null,\n\t\t\t\t\t\tdates: wTime.dates\n\t\t\t\t\t};\n\t\t\t\t} else if (gantt.config.worktimes && gantt.config.worktimes.global) {\n\t\t\t\t\tconst settings = gantt.config.worktimes.global;\n\n\t\t\t\t\tif (settings.parsed) {\n\t\t\t\t\t\tconst minutes = gantt.ext.export_api._getMinutesWorktimeSettings(settings.parsed.hours);\n\t\t\t\t\t\ttime = {\n\t\t\t\t\t\t\thours: null,\n\t\t\t\t\t\t\tminutes,\n\t\t\t\t\t\t\tdates: {}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tfor (const i in settings.parsed.dates) {\n\t\t\t\t\t\t\tif (Array.isArray(settings.parsed.dates[i])) {\n\t\t\t\t\t\t\t\ttime.dates[i] = gantt.ext.export_api._getMinutesWorktimeSettings(settings.parsed.dates[i]);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ttime.dates[i] = settings.parsed.dates[i];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttime = {\n\t\t\t\t\t\t\thours: settings.hours,\n\t\t\t\t\t\t\tminutes: null,\n\t\t\t\t\t\t\tdates: settings.dates\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\ttime = defaultWorkTimes;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn time;\n\t\t},\n\n\n\t\t_eachTaskTimed(start, end) {\n\t\t\treturn function(code, parent, master) {\n\t\t\t\tparent = parent || gantt.config.root_id;\n\t\t\t\tmaster = master || gantt;\n\n\t\t\t\tconst branch = gantt.getChildren(parent);\n\t\t\t\tif (branch){\n\t\t\t\t\tfor (let i = 0; i < branch.length; i++) {\n\t\t\t\t\t\tconst item = gantt._pull[branch[i]];\n\t\t\t\t\t\tif ((!start || item.end_date > start) && (!end || item.start_date < end)){\n\t\t\t\t\t\t\tcode.call(master, item);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (gantt.hasChild(item.id)){\n\t\t\t\t\t\t\tgantt.eachTask(code, item.id, master);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\n\n\t\t// patch broken json serialization in gantt 2.1\n\t\t_originalCopyObject: gantt.json._copyObject,\n\n\n\t\t_copyObjectPlain(obj) {\n\t\t\tconst text = gantt.templates.task_text(obj.start_date, obj.end_date, obj);\n\n\t\t\tconst copy = gantt.ext.export_api._copyObjectBase(obj);\n\t\t\tcopy.text = text || copy.text;\n\n\t\t\treturn copy;\n\t\t},\n\n\t\t_getColor(node, style) {\n\t\t\tconst value = node.currentStyle ? node.currentStyle[style] : getComputedStyle(node, null)[style];\n\t\t\tconst rgb = value.replace(/\\s/g, \"\").match(/^rgba?\\((\\d+),(\\d+),(\\d+)/i);\n\t\t\treturn ((rgb && rgb.length === 4) ?\n\t\t\t\t(\"0\" + parseInt(rgb[1], 10).toString(16)).slice(-2) +\n\t\t\t\t(\"0\" + parseInt(rgb[2], 10).toString(16)).slice(-2) +\n\t\t\t\t(\"0\" + parseInt(rgb[3], 10).toString(16)).slice(-2) : value).replace(\"#\", \"\");\n\t\t},\n\n\n\t\t// excel serialization\n\t\t_copyObjectTable(obj) {\n\t\t\t// Excel interprets UTC time as local time in every timezone, send local time instead of actual UTC time.\n\t\t\t// https://github.com/SheetJS/js-xlsx/issues/126#issuecomment-60531614\n\t\t\tconst toISOstring = gantt.date.date_to_str(\"%Y-%m-%dT%H:%i:%s.000Z\");\n\n\t\t\tconst copy = gantt.ext.export_api._copyObjectColumns(obj, gantt.ext.export_api._copyObjectPlain(obj));\n\t\t\tif (copy.start_date){\n\t\t\t\tcopy.start_date = toISOstring(obj.start_date);\n\t\t\t}\n\t\t\tif (copy.end_date){\n\t\t\t\tcopy.end_date = toISOstring(obj.end_date);\n\t\t\t}\n\n\t\t\t// private gantt._day_index_by_date was replaced by public gantt.columnIndexByDate in gantt 5.0\n\t\t\tconst getDayIndex = gantt._day_index_by_date ? gantt._day_index_by_date : gantt.columnIndexByDate;\n\n\t\t\tcopy.$start = getDayIndex.call(gantt, obj.start_date);\n\t\t\tcopy.$end = getDayIndex.call(gantt, obj.end_date);\n\n\t\t\t// GS-2100. Correct bar position considering hidden cells\n\t\t\tlet hiddenCells = 0;\n\t\t\tconst scaleCellsWidth = gantt.getScale().width;\n\t\t\tif (scaleCellsWidth.indexOf(0) > -1) {\n\t\t\t\tlet i = 0;\n\t\t\t\tfor (i; i < copy.$start; i++) {\n\t\t\t\t\tif (!scaleCellsWidth[i]) {\n\t\t\t\t\t\thiddenCells++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcopy.$start -= hiddenCells;\n\n\t\t\t\tfor (i; i < copy.$end; i++) {\n\t\t\t\t\tif (!scaleCellsWidth[i]) {\n\t\t\t\t\t\thiddenCells++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcopy.$end -= hiddenCells;\n\t\t\t}\n\n\t\t\tcopy.$level = obj.$level;\n\t\t\tcopy.$type = obj.$rendered_type;\n\n\t\t\tconst tmps = gantt.templates;\n\t\t\tcopy.$text = tmps.task_text(obj.start, obj.end_date, obj);\n\t\t\tcopy.$left = tmps.leftside_text ? tmps.leftside_text(obj.start, obj.end_date, obj) : \"\";\n\t\t\tcopy.$right = tmps.rightside_text ? tmps.rightside_text(obj.start, obj.end_date, obj) : \"\";\n\n\t\t\treturn copy;\n\t\t},\n\n\t\t_copyObjectColors(obj) {\n\t\t\tconst copy = gantt.ext.export_api._copyObjectTable(obj);\n\n\t\t\tconst node = gantt.getTaskNode(obj.id);\n\t\t\tif (node && node.firstChild) {\n\t\t\t\tlet color = gantt.ext.export_api._getColor((gantt._no_progress_colors ? node : node.firstChild), \"backgroundColor\");\n\t\t\t\tif (color === \"363636\"){\n\t\t\t\t\tcolor = gantt.ext.export_api._getColor(node, \"backgroundColor\");\n\t\t\t\t}\n\n\t\t\t\tcopy.$color = color;\n\t\t\t} else if (obj.color){\n\t\t\t\tcopy.$color = obj.color;\n\t\t\t}\n\n\t\t\treturn copy;\n\t\t},\n\n\t\t_copyObjectColumns(obj, copy) {\n\t\t\tfor (let i = 0; i < gantt.config.columns.length; i++) {\n\t\t\t\tconst ct = gantt.config.columns[i].template;\n\t\t\t\tif (ct) {\n\t\t\t\t\tlet val = ct(obj);\n\t\t\t\t\tif (val instanceof Date){\n\t\t\t\t\t\tval = gantt.templates.date_grid(val, obj);\n\t\t\t\t\t}\n\t\t\t\t\tcopy[\"_\" + i] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn copy;\n\t\t},\n\n\t\t_copyObjectAll(obj) {\n\t\t\tconst copy = gantt.ext.export_api._copyObjectBase(obj);\n\n\t\t\tconst templates = [\n\t\t\t\t\"leftside_text\",\n\t\t\t\t\"rightside_text\",\n\t\t\t\t\"task_text\",\n\t\t\t\t\"progress_text\",\n\t\t\t\t\"task_class\"\n\t\t\t];\n\n\t\t\t// serialize all text templates\n\t\t\tfor (let i = 0; i < templates.length; i++) {\n\t\t\t\tconst template = gantt.templates[templates[i]];\n\t\t\t\tif (template){\n\t\t\t\t\tcopy[\"$\" + i] = template(obj.start_date, obj.end_date, obj);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tgantt.ext.export_api._copyObjectColumns(obj, copy);\n\t\t\tcopy.open = obj.$open;\n\t\t\treturn copy;\n\t\t},\n\n\n\t\t_serializeHtml() {\n\t\t\tconst smartScales = gantt.config.smart_scales;\n\t\t\tconst smartRendering = gantt.config.smart_rendering;\n\t\t\tif (smartScales || smartRendering) {\n\t\t\t\tgantt.config.smart_rendering = false;\n\t\t\t\tgantt.config.smart_scales = false;\n\t\t\t\tgantt.render();\n\t\t\t}\n\n\t\t\tconst html = gantt.$container.parentNode.innerHTML;\n\n\t\t\tif (smartScales || smartRendering) {\n\t\t\t\tgantt.config.smart_scales = smartScales;\n\t\t\t\tgantt.config.smart_rendering = smartRendering;\n\t\t\t\tgantt.render();\n\t\t\t}\n\n\t\t\treturn html;\n\t\t},\n\n\t\t_serializeAll() {\n\t\t\tgantt.json._copyObject = gantt.ext.export_api._copyObjectAll;\n\t\t\tconst data = gantt.ext.export_api._exportSerialize();\n\t\t\tgantt.json._copyObject = gantt.ext.export_api._originalCopyObject;\n\t\t\treturn data;\n\t\t},\n\n\t\t_serializePlain() {\n\t\t\tconst oldXmlFormat = gantt.templates.xml_format;\n\t\t\tconst oldFormatDate = gantt.templates.format_date;\n\t\t\tgantt.templates.xml_format = gantt.date.date_to_str(\"%Y%m%dT%H%i%s\", true);\n\t\t\tgantt.templates.format_date = gantt.date.date_to_str(\"%Y%m%dT%H%i%s\", true);\n\t\t\tgantt.json._copyObject = gantt.ext.export_api._copyObjectPlain;\n\n\t\t\tconst data = gantt.ext.export_api._exportSerialize();\n\n\t\t\tgantt.templates.xml_format = oldXmlFormat;\n\t\t\tgantt.templates.format_date = oldFormatDate;\n\t\t\tgantt.json._copyObject = gantt.ext.export_api._originalCopyObject;\n\n\t\t\tdelete data.links;\n\t\t\treturn data;\n\t\t},\n\n\t\t_getRaw() {\n\t\t\t// support Gantt < 5.0\n\t\t\tif (gantt._scale_helpers) {\n\t\t\t\tconst scales = gantt._get_scales();\n\t\t\t\tconst\tminWidth = gantt.config.min_column_width;\n\t\t\t\tconst\tautosizeMinWidth = gantt._get_resize_options().x ? Math.max(gantt.config.autosize_min_width, 0) : gantt.config.$task.offsetWidth;\n\t\t\t\tconst\theight = gantt.config.config.scale_height - 1;\n\t\t\t\treturn gantt._scale_helpers.prepareConfigs(scales, minWidth, autosizeMinWidth, height);\n\t\t\t} else { // Gantt >= 5.0\n\t\t\t\tconst timeline = gantt.$ui.getView(\"timeline\");\n\t\t\t\tif (timeline) {\n\t\t\t\t\tlet availWidth = timeline.$config.width;\n\t\t\t\t\tif (gantt.config.autosize === \"x\" || gantt.config.autosize === \"xy\") {\n\t\t\t\t\t\tavailWidth = Math.max(gantt.config.autosize_min_width, 0);\n\t\t\t\t\t}\n\t\t\t\t\tconst state = gantt.getState();\n\t\t\t\t\tconst\tscales = timeline._getScales();\n\t\t\t\t\tconst\tminWidth = gantt.config.min_column_width;\n\t\t\t\t\tconst\theight = gantt.config.scale_height - 1;\n\t\t\t\t\tconst\trtl = gantt.config.rtl;\n\t\t\t\t\treturn timeline.$scaleHelper.prepareConfigs(scales, minWidth, availWidth, height, state.min_date, state.max_date, rtl);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_serializeTimeline(config) {\n\t\t\tgantt.json._copyObject = config.visual ? gantt.ext.export_api._copyObjectColors : gantt.ext.export_api._copyObjectTable;\n\t\t\tconst data = gantt.ext.export_api._exportSerialize();\n\t\t\tgantt.json._copyObject = gantt.ext.export_api._originalCopyObject;\n\n\t\t\tdelete data.links;\n\n\t\t\tif (config.cellColors) {\n\t\t\t\tconst css = gantt.templates.timeline_cell_class || gantt.templates.task_cell_class;\n\t\t\t\tif (css) {\n\t\t\t\t\tconst raw = gantt.ext.export_api._getRaw();\n\t\t\t\t\tlet steps = raw[0].trace_x;\n\t\t\t\t\tfor (let i = 1; i < raw.length; i++){\n\t\t\t\t\t\tif (raw[i].trace_x.length > steps.length){\n\t\t\t\t\t\t\tsteps = raw[i].trace_x;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (let i = 0; i < data.data.length; i++) {\n\t\t\t\t\t\tdata.data[i].styles = [];\n\t\t\t\t\t\tconst task = gantt.getTask(data.data[i].id);\n\t\t\t\t\t\tfor (let j = 0; j < steps.length; j++) {\n\t\t\t\t\t\t\tconst date = steps[j];\n\t\t\t\t\t\t\tconst cellCss = css(task, date);\n\t\t\t\t\t\t\tif (cellCss){\n\t\t\t\t\t\t\t\tdata.data[i].styles.push({ index: j, styles: gantt.ext.export_api._getStyles(cellCss) });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn data;\n\t\t},\n\n\t\t_serializeScales(config) {\n\t\t\tconst scales:any = [];\n\t\t\tconst raw = gantt.ext.export_api._getRaw();\n\n\t\t\tlet min = Infinity;\n\t\t\tlet max = 0;\n\t\t\tfor (let i = 0; i < raw.length; i++) {\n\t\t\t\tmin = Math.min(min, raw[i].col_width);\n\t\t\t}\n\n\t\t\tfor (let i = 0; i < raw.length; i++) {\n\t\t\t\tlet start = 0;\n\t\t\t\tlet end = 0;\n\t\t\t\tconst row:any = [];\n\n\t\t\t\tscales.push(row);\n\t\t\t\tconst step = raw[i];\n\t\t\t\tmax = Math.max(max, step.trace_x.length);\n\t\t\t\tconst template = step.format || step.template || (step.date ? gantt.date.date_to_str(step.date) : gantt.config.date_scale);\n\n\t\t\t\tfor (let j = 0; j < step.trace_x.length; j++) {\n\t\t\t\t\tconst date = step.trace_x[j];\n\t\t\t\t\tend = start + Math.round(step.width[j] / min);\n\n\t\t\t\t\tconst scaleCell = { text: template(date), start, end, styles: \"\" };\n\n\t\t\t\t\tif (config.cellColors) {\n\t\t\t\t\t\tconst css = step.css || gantt.templates.scaleCell_class;\n\t\t\t\t\t\tif (css) {\n\t\t\t\t\t\t\tconst scaleCss = css(date);\n\t\t\t\t\t\t\tif (scaleCss){\n\t\t\t\t\t\t\t\tscaleCell.styles = gantt.ext.export_api._getStyles(scaleCss);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\trow.push(scaleCell);\n\t\t\t\t\tstart = end;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { width: max, height: scales.length, data: scales };\n\t\t},\n\n\t\t_serializeGrid(config) {\n\t\t\tgantt.exportMode = true;\n\n\t\t\tconst columns:any = [];\n\t\t\tconst cols = gantt.config.columns;\n\n\t\t\tlet ccount = 0;\n\t\t\tfor (let i = 0; i < cols.length; i++) {\n\t\t\t\tif (cols[i].name === \"add\" || cols[i].name === \"buttons\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcolumns[ccount] = {\n\t\t\t\t\tid: ((cols[i].template) ? (\"_\" + i) : cols[i].name),\n\t\t\t\t\theader: cols[i].label || gantt.locale.labels[\"column_\" + cols[i].name],\n\t\t\t\t\twidth: (cols[i].width ? Math.floor(cols[i].width / 4) : \"\"),\n\t\t\t\t\ttree: cols[i].tree || false\n\t\t\t\t};\n\n\t\t\t\tif (cols[i].name === \"duration\"){\n\t\t\t\t\tcolumns[ccount].type = \"number\";\n\t\t\t\t}\n\t\t\t\tif (cols[i].name === \"start_date\" || cols[i].name === \"end_date\") {\n\t\t\t\t\tcolumns[ccount].type = \"date\";\n\t\t\t\t\tif (config && config.rawDates){\n\t\t\t\t\t\tcolumns[ccount].id = cols[i].name;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tccount++;\n\t\t\t}\n\n\t\t\tgantt.exportMode = false;\n\t\t\treturn columns;\n\t\t},\n\n\t\t_exportSerialize() {\n\t\t\tgantt.exportMode = true;\n\n\t\t\tconst xmlFormat = gantt.templates.xml_format;\n\t\t\tconst formatDate = gantt.templates.format_date;\n\n\t\t\t// use configuration date format for serialization so date could be parsed on the export\n\t\t\t// required when custom format date function is defined\n\t\t\tgantt.templates.xml_format =\n\t\t\t\tgantt.templates.format_date =\n\t\t\t\tgantt.date.date_to_str(gantt.config.date_format || gantt.config.xml_date);\n\n\t\t\tconst data = gantt.serialize();\n\n\t\t\tgantt.templates.xml_format = xmlFormat;\n\t\t\tgantt.templates.format_date = formatDate;\n\t\t\tgantt.exportMode = false;\n\t\t\treturn data;\n\t\t},\n\n\n\t\t_setLevel(data) {\n\t\t\tfor (let i = 0; i < data.length; i++) {\n\t\t\t\t// tslint:disable-next-line triple-equals\n\t\t\t\tif (data[i].parent == 0) {\n\t\t\t\t\tdata[i]._lvl = 1;\n\t\t\t\t}\n\t\t\t\tfor (let j = i + 1; j < data.length; j++) {\n\t\t\t\t\t// tslint:disable-next-line triple-equals\n\t\t\t\t\tif (data[i].id == data[j].parent) {\n\t\t\t\t\t\tdata[j]._lvl = data[i]._lvl + 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_clearLevel(data) {\n\t\t\tfor (let i = 0; i < data.length; i++) {\n\t\t\t\tdelete data[i]._lvl;\n\t\t\t}\n\t\t},\n\n\t\t_clearRecLinks(data) {\n\t\t\tgantt.ext.export_api._setLevel(data.data);\n\t\t\tconst tasks = {};\n\t\t\tfor (let i = 0; i < data.data.length; i++) {\n\t\t\t\ttasks[data.data[i].id] = data.data[i];\n\t\t\t}\n\n\t\t\tconst links = {};\n\n\t\t\tfor (let i = 0; i < data.links.length; i++) {\n\t\t\t\tconst link = data.links[i];\n\t\t\t\tif (gantt.isTaskExists(link.source) && gantt.isTaskExists(link.target) &&\n\t\t\t\t\ttasks[link.source] && tasks[link.target]) {\n\t\t\t\t\tlinks[link.id] = link;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const j in links) {\n\t\t\t\tgantt.ext.export_api._makeLinksSameLevel(links[j], tasks);\n\t\t\t}\n\n\t\t\tconst skippedLinks = {};\n\t\t\tfor (const j in tasks) {\n\t\t\t\tgantt.ext.export_api._clearCircDependencies(tasks[j], links, tasks, {}, skippedLinks, null);\n\t\t\t}\n\n\t\t\tif (Object.keys(links)) {\n\t\t\t\tgantt.ext.export_api._clearLinksSameLevel(links, tasks);\n\t\t\t}\n\n\t\t\tfor (let i = 0; i < data.links.length; i++) {\n\t\t\t\tif (!links[data.links[i].id]) {\n\t\t\t\t\tdata.links.splice(i, 1);\n\t\t\t\t\ti--;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tgantt.ext.export_api._clearLevel(data.data);\n\t\t},\n\n\t\t_clearCircDependencies(task, links, tasks, usedTasks, skippedLinks, prevLink) {\n\t\t\tconst sources = task.$_source;\n\t\t\tif (!sources) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (usedTasks[task.id]) {\n\t\t\t\tgantt.ext.export_api._onCircDependencyFind(prevLink, links, usedTasks, skippedLinks);\n\t\t\t}\n\n\t\t\tusedTasks[task.id] = true;\n\n\t\t\tconst targets = {};\n\n\t\t\tfor (let i = 0; i < sources.length; i++) {\n\t\t\t\tif (skippedLinks[sources[i]]) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst curLink = links[sources[i]];\n\t\t\t\tconst targetTask = tasks[curLink._target];\n\t\t\t\tif (targets[targetTask.id]) { // two link from one task to another\n\t\t\t\t\tgantt.ext.export_api._onCircDependencyFind(curLink, links, usedTasks, skippedLinks);\n\t\t\t\t}\n\t\t\t\ttargets[targetTask.id] = true;\n\t\t\t\tgantt.ext.export_api._clearCircDependencies(targetTask, links, tasks, usedTasks, skippedLinks, curLink);\n\t\t\t}\n\t\t\tusedTasks[task.id] = false;\n\t\t},\n\n\t\t_onCircDependencyFind(link, links, usedTasks, skippedLinks) {\n\t\t\tif (link) {\n\t\t\t\tif (gantt.callEvent(\"onExportCircularDependency\", [link.id, link])) {\n\t\t\t\t\tdelete links[link.id];\n\t\t\t\t}\n\n\t\t\t\tdelete usedTasks[link._source];\n\t\t\t\tdelete usedTasks[link._target];\n\t\t\t\tskippedLinks[link.id] = true;\n\t\t\t}\n\t\t},\n\n\t\t_makeLinksSameLevel(link, tasks) {\n\t\t\tlet task;\n\t\t\tlet targetLvl;\n\t\t\tconst linkT = {\n\t\t\t\ttarget: tasks[link.target],\n\t\t\t\tsource: tasks[link.source]\n\t\t\t};\n\t\t\t// tslint:disable-next-line triple-equals\n\t\t\tif (linkT.target._lvl != linkT.source._lvl) {\n\t\t\t\tif (linkT.target._lvl < linkT.source._lvl) {\n\t\t\t\t\ttask = \"source\";\n\t\t\t\t\ttargetLvl = linkT.target._lvl;\n\t\t\t\t} else {\n\t\t\t\t\ttask = \"target\";\n\t\t\t\t\ttargetLvl = linkT.source._lvl;\n\t\t\t\t}\n\n\t\t\t\tdo {\n\t\t\t\t\tconst parent = tasks[linkT[task].parent];\n\t\t\t\t\tif (!parent) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tlinkT[task] = parent;\n\t\t\t\t} while (linkT[task]._lvl < targetLvl);\n\n\t\t\t\tlet sourceParent = tasks[linkT.source.parent];\n\t\t\t\tlet\ttargetParent = tasks[linkT.target.parent];\n\t\t\t\t// tslint:disable-next-line triple-equals\n\t\t\t\twhile (sourceParent && targetParent && sourceParent.id != targetParent.id) {\n\t\t\t\t\tlinkT.source = sourceParent;\n\t\t\t\t\tlinkT.target = targetParent;\n\t\t\t\t\tsourceParent = tasks[linkT.source.parent];\n\t\t\t\t\ttargetParent = tasks[linkT.target.parent];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlink._target = linkT.target.id;\n\t\t\tlink._source = linkT.source.id;\n\n\t\t\tif (!linkT.target.$_target){\n\t\t\t\tlinkT.target.$_target = [];\n\t\t\t}\n\t\t\tlinkT.target.$_target.push(link.id);\n\n\t\t\tif (!linkT.source.$_source){\n\t\t\t\tlinkT.source.$_source = [];\n\t\t\t}\n\t\t\tlinkT.source.$_source.push(link.id);\n\t\t},\n\n\t\t_clearLinksSameLevel(links, tasks) {\n\t\t\tfor (const link in links) {\n\t\t\t\tdelete links[link]._target;\n\t\t\t\tdelete links[link]._source;\n\t\t\t}\n\n\t\t\tfor (const task in tasks) {\n\t\t\t\tdelete tasks[task].$_source;\n\t\t\t\tdelete tasks[task].$_target;\n\t\t\t}\n\t\t},\n\n\n\t\t_customProjectProperties(data, config) {\n\t\t\tif (config && config.project) {\n\t\t\t\tfor (const i in config.project) {\n\t\t\t\t\tif (!gantt.config.$custom_data){\n\t\t\t\t\t\tgantt.config.$custom_data = {};\n\t\t\t\t\t}\n\t\t\t\t\tgantt.config.$custom_data[i] = typeof config.project[i] === \"function\" ? config.project[i](gantt.config) : config.project[i];\n\t\t\t\t}\n\t\t\t\tdelete config.project;\n\t\t\t}\n\t\t},\n\n\t\t_customTaskProperties(data, config) {\n\t\t\tif (config && config.tasks) {\n\t\t\t\tdata.data.forEach(function(el) {\n\t\t\t\t\tfor (const i in config.tasks) {\n\t\t\t\t\t\tif (!el.$custom_data){\n\t\t\t\t\t\t\tel.$custom_data = {};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tel.$custom_data[i] = typeof config.tasks[i] === \"function\" ? config.tasks[i](el, gantt.config) : config.tasks[i];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tdelete config.tasks;\n\t\t\t}\n\t\t},\n\n\t\t_exportConfig(data, config) {\n\t\t\tconst projectName = config.name || \"gantt.xml\";\n\t\t\tdelete config.name;\n\n\t\t\tgantt.config.custom = config;\n\n\t\t\tconst time = gantt.ext.export_api._getWorktimeSettings();\n\n\t\t\tconst projectDates = gantt.getSubtaskDates();\n\t\t\tif (projectDates.start_date && projectDates.end_date) {\n\t\t\t\tconst formatDate = gantt.templates.format_date || gantt.templates.xml_format;\n\t\t\t\tgantt.config.start_end = {\n\t\t\t\t\tstart_date: formatDate(projectDates.start_date),\n\t\t\t\t\tend_date: formatDate(projectDates.end_date)\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst manual = config.auto_scheduling === undefined ? false : !!config.auto_scheduling;\n\n\t\t\tconst res = {\n\t\t\t\tcallback: config.callback || null,\n\t\t\t\tconfig: gantt.config,\n\t\t\t\tdata,\n\t\t\t\tmanual,\n\t\t\t\tname: projectName,\n\t\t\t\tworktime: time\n\t\t\t};\n\t\t\tfor (const i in config) {\n\t\t\t\tres[i] = config[i];\n\t\t\t}\n\t\t\treturn res;\n\t\t},\n\n\n\t\t_sendImportAjaxMSP(config) {\n\t\t\tconst url = config.server || gantt.ext.export_api._apiUrl;\n\t\t\tconst store = config.store || 0;\n\t\t\tconst formData = config.data;\n\t\t\tconst callback = config.callback;\n\n\t\t\tconst settings = {\n\t\t\t\tdurationUnit: config.durationUnit || undefined,\n\t\t\t\tprojectProperties: config.projectProperties || undefined,\n\t\t\t\ttaskProperties: config.taskProperties || undefined\n\t\t\t};\n\n\t\t\tformData.append(\"type\", config.type || \"msproject-parse\");\n\t\t\tformData.append(\"data\", JSON.stringify(settings));\n\n\t\t\tif (store){\n\t\t\t\tformData.append(\"store\", store);\n\t\t\t}\n\n\t\t\tconst xhr = new XMLHttpRequest();\n\t\t\txhr.onreadystatechange = function(e) {\n\t\t\t\tif (xhr.readyState === 4 && xhr.status === 0) {// network error\n\t\t\t\t\tif (callback) {\n\t\t\t\t\t\tcallback(null);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\txhr.onload = function(){\n\t\t\t\tconst fail = xhr.status > 400;\n\t\t\t\tlet info = null;\n\n\t\t\t\tif (!fail) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinfo = JSON.parse(xhr.responseText);\n\t\t\t\t\t} catch (e) { }\n\t\t\t\t}\n\n\t\t\t\tif (callback) {\n\t\t\t\t\tcallback(info);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\txhr.open(\"POST\", url, true);\n\t\t\txhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n\t\t\txhr.send(formData);\n\t\t}\n\n\t};\n\n\n\tgantt.exportToPDF = gantt.ext.export_api.exportToPDF;\n\tgantt.exportToPNG = gantt.ext.export_api.exportToPNG;\n\tgantt.exportToICal = gantt.ext.export_api.exportToICal;\n\tgantt.exportToExcel = gantt.ext.export_api.exportToExcel;\n\tgantt.exportToJSON = gantt.ext.export_api.exportToJSON;\n\tgantt.importFromExcel = gantt.ext.export_api.importFromExcel;\n\tgantt.importFromMSProject = gantt.ext.export_api.importFromMSProject;\n\tgantt.exportToMSProject = gantt.ext.export_api.exportToMSProject;\n\tgantt.importFromPrimaveraP6 = gantt.ext.export_api.importFromPrimaveraP6;\n\tgantt.exportToPrimaveraP6 = gantt.ext.export_api.exportToPrimaveraP6;\n\n\n\treturn gantt.ext.export_api;\n}\n","import { gantt, Gantt } from \"./dhtmlxgantt.web\";\nimport scope from \"./utils/global\";\n\n(scope as any).gantt = gantt;\n(scope as any).Gantt = Gantt;\n\nexport default gantt;\n\nexport { gantt, Gantt };","import * as Sentry from '@sentry/browser';\nimport {injectable} from 'inversify';\n\ntype TaskUpdateJob = (tempIdMap: Map) => Promise;\n\ntype QueueEntry = {\n job: TaskUpdateJob;\n resolve: (any) => void;\n reject: (e: Error) => void;\n};\n\nexport const FifoQueueStatusTypes = {idle: 'idle', running: 'running'} as const;\ntype FifoQueueStatus = keyof typeof FifoQueueStatusTypes;\n\n@injectable()\nexport class TaskUpdateFifoQueue {\n private _jobQueue: QueueEntry[] = [];\n private _queueStatus: FifoQueueStatus = FifoQueueStatusTypes.idle;\n private _idMap: Map = new Map();\n\n private start() {\n if (this._jobQueue.length && this._queueStatus === FifoQueueStatusTypes.idle) {\n this._queueStatus = FifoQueueStatusTypes.running;\n const {job, reject, resolve} = this._jobQueue.shift();\n job(this._idMap)\n .then(resolve)\n .catch((e) => {\n Sentry.captureException(e);\n reject(e);\n })\n .finally(() => {\n this._queueStatus = FifoQueueStatusTypes.idle;\n this.start();\n });\n }\n }\n\n get queueStatus() {\n return this._queueStatus;\n }\n\n get idMap() {\n return this._idMap;\n }\n\n get jobQueue() {\n return this._jobQueue;\n }\n\n public changeId(oldId: number, newId: string) {\n this._idMap.set(oldId, newId);\n }\n\n public enqueue(job: TaskUpdateJob) {\n return new Promise((resolve, reject) => {\n this._jobQueue.push({job, resolve, reject});\n this.start();\n });\n }\n}\n","import {VirtualElement} from '@floating-ui/react';\nimport {makeAutoObservable} from 'mobx';\n\nimport {ReferenceType} from 'modules/Tasks/components/Gantt/hooks/useHideContextOnGanttScroll';\nimport {GanttTask} from 'modules/Tasks/components/Gantt/types';\nimport {EditActionTypes} from 'modules/Tasks/components/Gantt/utils/constants';\n\nexport type GanttContextStoreType = Omit;\n\nexport class GanttContextMenuStore implements GanttContextStoreType {\n taskSelectorElementRef: ReferenceType = null;\n floatingMenuElementRef: VirtualElement = null;\n activeGanttTask: GanttTask = null;\n currentEditAction: EditActionTypes = null;\n\n constructor() {\n makeAutoObservable(this);\n }\n\n updateTaskSelectorRef = (elementRef: ReferenceType) => {\n this.taskSelectorElementRef = elementRef;\n };\n\n updateFloatingMenuRef = (elementRef: VirtualElement) => {\n this.floatingMenuElementRef = elementRef;\n };\n\n selectGanttTask = (task: GanttTask) => {\n this.activeGanttTask = task;\n };\n\n setActiveTask(task: GanttTask | null) {\n this.activeGanttTask = task;\n }\n\n resetContextMenuState() {\n if (this?.taskSelectorElementRef && this.taskSelectorElementRef) {\n this.activeGanttTask = null;\n this.taskSelectorElementRef = null;\n this.floatingMenuElementRef = null;\n }\n }\n}\n","import {GanttStatic} from 'dhtmlx-gantt';\n\nimport {TaskDependencyDto, TaskDependencyToGanttLinkType} from 'shared/models/TaskDependency';\n\nexport const mapDependencyToGanttLink = (gantt: GanttStatic, dep: TaskDependencyDto) => {\n return {\n id: dep.id,\n target: dep.taskId,\n source: dep.predTaskId,\n type: gantt.config.links[TaskDependencyToGanttLinkType[dep.depType]],\n };\n};\n","import * as Sentry from '@sentry/browser';\nimport {Link, type GanttStatic} from 'dhtmlx-gantt';\nimport equal from 'fast-deep-equal';\nimport {inject, injectable} from 'inversify';\nimport debounce from 'lodash/debounce';\nimport {IArrayDidChange, observe, runInAction, when} from 'mobx';\n\nimport {transformLookaheadData} from 'modules/Tasks/components/Gantt/utils/functions';\nimport {isPlaceholderTask, OSKMap} from 'modules/Tasks/components/Gantt/utils/gantt';\nimport {refreshTask, updateCollapseIcon} from 'modules/Tasks/utils/functions';\nimport {GanttNames} from 'shared/constants/gantt';\nimport Gantt from 'shared/models/Gantt';\nimport {IOC_TYPES} from 'shared/models/ioc';\nimport {TaskModelRawDTO} from 'shared/models/task/task';\nimport {TaskDependency} from 'shared/models/TaskDependency';\nimport {mapDependencyToGanttLink} from 'shared/utils/mapDependencyToGanttLink';\n\nimport {type TasksStoreType} from './TasksStore';\nimport {tasksToGanttTasks} from './utils/transforms';\n\nconst ObserverChangeTypes = {\n splice: 'splice',\n update: 'update',\n add: 'add',\n remove: 'remove',\n} as const;\n\nexport type GanttStoreType = Omit;\n\n// refreshTask takes about 2ms and redrawing the whole table takes about 50ms.\n// If you're going to redraw more than 25 rows, do it as a batch for efficiency.\nconst REPAINT_FULL_TABLE_THRESHOLD = 25;\n\n@injectable()\nexport class GanttStore implements GanttStoreType {\n @inject(IOC_TYPES.TasksStore) private tasksStore: TasksStoreType;\n\n ganttInstance: GanttStatic | null = null;\n idRownumMap: Record = {};\n rownumIDMap: Record = {};\n disposers: (() => void)[] = [];\n filterIds: Set = new Set();\n collapseAccessor: () => string[];\n\n constructor() {\n // do nothing\n }\n\n initSideEffects() {\n try {\n when(\n () => !this.tasksStore.isLoading && this.tasksStore.tasksLoaded,\n () => {\n this.parseTasks();\n },\n );\n\n this.disposers.push(observe(this.tasksStore.tasks, (change) => this.taskListChanged(change)));\n this.disposers.push(\n observe(this.tasksStore.dependencies, () => {\n this.debouncedLinkDependencies();\n }),\n );\n } catch (e) {\n Sentry.captureException(e);\n }\n }\n\n setCollapseAccessor(accessor: () => string[]) {\n this.collapseAccessor = accessor;\n }\n\n setFilterIds(ids: Set | string[]) {\n this.filterIds.clear();\n for (const id of ids) {\n this.filterIds.add(id);\n }\n if (this.ganttInstance) {\n this.parseTasks();\n }\n }\n\n changeTaskId(oldTaskId: number, newTaskId: string) {\n this.filterIds.delete(oldTaskId);\n this.filterIds.add(newTaskId);\n }\n\n setGanttInstance(viewMode: string) {\n this.ganttInstance = Gantt.getInstance(GanttNames[viewMode]);\n this.parseTasks();\n }\n\n destroySideEffects() {\n while (this.disposers.length) {\n const disposer = this.disposers.pop();\n disposer();\n }\n }\n\n private refreshOneTask(taskModel: TaskModelRawDTO) {\n // Tasks cannot be refreshed and moved in a single operation or gantt\n // will scramble the arrangement of rows. Extract parent and index,\n // refresh the task, then decide if ganttInstance.move is needed.\n const {parent, index, ...model} = tasksToGanttTasks(\n [taskModel],\n this.tasksStore.tasks.filter((task) => this.filterIds.has(task.id)),\n this.tasksStore.projectId,\n )[0];\n\n const ganttTask = this.ganttInstance.getTask(model.id);\n let tasksNeedsToMove = false;\n\n if (ganttTask && (index !== ganttTask?.$local_index || parent !== ganttTask?.parent)) {\n tasksNeedsToMove = true;\n }\n\n refreshTask(this.ganttInstance, model.id, model);\n\n if (tasksNeedsToMove) {\n this.ganttInstance.moveTask(ganttTask.id, index, parent);\n }\n\n // WBS OSK is updated on drag and drop WBS gets new ID and the state of the task store does not have children\n // when the children get updated we need to re-associate the children with their parent\n if (ganttTask && ganttTask?.parent !== this.ganttInstance?.config?.root_id) {\n const taskParent = this.ganttInstance.getTask(parent);\n const taskChildren = this.ganttInstance.getChildren(ganttTask.parent);\n\n // if an update updates the OSK ensure parent has $has_child is accurate\n if (taskParent.has_child !== taskChildren.length) {\n refreshTask(this.ganttInstance, taskParent.id, {has_child: taskChildren.length});\n }\n }\n\n this.updateRownums();\n }\n\n private createOrRefreshTask(taskModel: TaskModelRawDTO) {\n if (this.ganttInstance.isTaskExists(taskModel.id)) {\n this.refreshOneTask(taskModel);\n } else {\n const filteredTasks = this.tasksStore.tasks.filter((task) => this.filterIds.has(task.id));\n const model = tasksToGanttTasks([taskModel], filteredTasks, this.tasksStore.projectId)[0];\n this.ganttInstance.addTask(model, model.parent, model.index);\n\n // Handle WBS relationships for new tasks\n if (model?.parent !== this.ganttInstance?.config?.root_id) {\n const taskParent = this.ganttInstance.getTask(model.parent);\n const taskChildren = this.ganttInstance.getChildren(model.parent);\n\n // Update parent's $has_child count while preserving its current $open state\n if (taskParent.has_child !== taskChildren.length) {\n refreshTask(this.ganttInstance, taskParent.id, {\n has_child: taskChildren.length,\n $open: true,\n });\n }\n }\n }\n }\n\n private createOrRefreshTasks(tasks: TaskModelRawDTO[]) {\n if (tasks.length > REPAINT_FULL_TABLE_THRESHOLD) {\n this.ganttInstance.batchUpdate(() => {\n for (const task of tasks) {\n this.createOrRefreshTask(task);\n }\n });\n } else {\n for (const task of tasks) {\n this.createOrRefreshTask(task);\n }\n }\n }\n\n private handleRemoveTasks() {\n const gantt = this.ganttInstance;\n const taskIds = gantt.getSelectedTasks();\n const parents: Record = {};\n\n if (taskIds?.length) {\n gantt.batchUpdate(() => {\n taskIds.forEach((id) => {\n if (gantt.isTaskExists(id)) {\n const task = gantt.getTask(id);\n if (task.parent && task.parent !== gantt.config.root_id) {\n parents[task.parent] = !parents?.[task.parent] ? 1 : ++parents[task.parent];\n }\n gantt.unselectTask(id);\n gantt.silent(() => gantt.deleteTask(id));\n gantt.callEvent('bulkDelete', [taskIds]);\n }\n });\n });\n\n Object.entries(parents).forEach(([id, count]) => {\n updateCollapseIcon(gantt, id, count * -1);\n });\n }\n\n this.updateRownums();\n }\n\n private taskListChanged(change: IArrayDidChange) {\n if (this.tasksStore.isLoading || this.tasksStore.silent || this.ganttInstance.name === GanttNames.issues) {\n return;\n }\n\n // Four cases to handle\n // 1. splice with removed -- pull out of gantt, although some operations may look like\n // a remove but effectively be an array rearrangement\n // 2. splice with added on first load -- gantt is empty, so just do the full parseTasks\n // 3. splice with added after first load -- normally this would be adding one new row,\n // but could be caused by array sorting or something where some or all of the tasks\n // are alredy present in the gantt table. Transform all the values then add or update\n // as appropriate\n // 4. update -- one array element was altered. Transform the value and update the gantt\n if (change.type === ObserverChangeTypes.splice && change.removedCount) {\n for (const task of change.removed) {\n if (this.ganttInstance.isTaskExists(task.id)) {\n this.ganttInstance.silent(() => {\n this.handleRemoveTasks();\n });\n }\n\n this.ganttInstance.render();\n }\n }\n\n if (change.type === ObserverChangeTypes.splice && change.addedCount) {\n // Filter the added tasks\n for (const task of change.added) {\n this.filterIds.add(task.id);\n }\n\n if (this.ganttInstance.getTaskCount() <= 1) {\n // This case will be handled by the when in initSideEffects by calling parseTasks, so that we get\n // correct behavior for both empty task (which doesn't fire arrayChanged) and\n // for non-empty lists.\n } else {\n this.createOrRefreshTasks(change.added);\n }\n\n this.updateRownums();\n }\n\n if (change.type === ObserverChangeTypes.update) {\n if (!this.filterIds.has(change.newValue.id)) return;\n\n this.createOrRefreshTask(change.newValue);\n }\n }\n\n private buildDepsCache(taskDeps: TaskDependency[], rownumbers: Record) {\n const sourceMap = new Map();\n const targetMap = new Map();\n\n // pre-compute all dependencies with rownums\n taskDeps.forEach((dep) => {\n const depWithRownum = {...dep, rownum: rownumbers[dep.predTaskId]};\n\n // cache source dependencies\n if (!sourceMap.has(dep.taskId)) {\n sourceMap.set(dep.taskId, []);\n }\n sourceMap.get(dep.taskId).push(depWithRownum);\n\n // cache target dependencies\n if (!targetMap.has(dep.predTaskId)) {\n targetMap.set(dep.predTaskId, []);\n }\n targetMap.get(dep.predTaskId).push(dep);\n });\n\n // pre-sort all source dependencies\n for (const deps of sourceMap.values()) {\n deps.sort((a, b) => b.rownum - a.rownum);\n }\n\n return {sourceMap, targetMap};\n }\n\n private debouncedRender = debounce(() => {\n this.ganttInstance.render();\n }, 16);\n\n private debouncedLinkDependencies = debounce(() => {\n this.linkDependenciesToTasks();\n }, 100);\n\n private linkDependenciesToTasks() {\n const taskDeps = this.tasksStore.dependencies;\n const gantt = this.ganttInstance;\n const rownumbers = this.idRownumMap;\n let needRefresh = false;\n\n if (!Array.isArray(taskDeps)) {\n return;\n }\n\n const {sourceMap, targetMap} = this.buildDepsCache(taskDeps, rownumbers);\n\n gantt.silent(() => {\n gantt.eachTask((task) => {\n if (isPlaceholderTask(this.ganttInstance, task)) return;\n\n const sourceDeps =\n sourceMap\n .get(task.id)\n ?.map((dep) => ({\n ...dep,\n rownum: rownumbers[dep.predTaskId],\n }))\n .sort((a, b) => b.rownum - a.rownum) ?? [];\n\n const targetDeps = targetMap.get(task.id) ?? [];\n\n if (!equal(sourceDeps, task.sourceDeps) || !equal(targetDeps, task.targetDeps)) {\n needRefresh = true;\n Object.assign(task, {\n sourceDeps,\n targetDeps,\n });\n }\n });\n\n this.processLinksInBatches(taskDeps, gantt);\n });\n\n if (needRefresh) {\n gantt.refreshData();\n }\n\n this.debouncedRender();\n }\n\n private processLinksInBatches(taskDeps: TaskDependency[], gantt: GanttStatic) {\n const LINK_BATCH_SIZE = 1000;\n const deps = new Map(taskDeps.map((dep) => [dep.id, dep]));\n\n const existingLinks = gantt.getLinks();\n for (let i = 0; i < existingLinks.length; i += LINK_BATCH_SIZE) {\n const batch = existingLinks.slice(i, i + LINK_BATCH_SIZE);\n this.processLinkBatch(batch, deps, gantt);\n }\n\n const depsArray = Array.from(deps.entries());\n for (let i = 0; i < depsArray.length; i += LINK_BATCH_SIZE) {\n const batch = depsArray.slice(i, i + LINK_BATCH_SIZE);\n this.processNewLinksBatch(batch, gantt);\n }\n }\n\n private processLinkBatch(links: Link[], deps: Map, gantt: GanttStatic) {\n links.forEach((link) => {\n const dep = deps.get(link.id as string);\n if (dep) {\n const currentLink = gantt.getLink(link.id);\n const update = mapDependencyToGanttLink(gantt, dep);\n if (!equal(update, currentLink)) {\n Object.assign(currentLink, update);\n gantt.refreshLink(link.id);\n }\n } else if (gantt.isTaskExists(link.target) && gantt.isTaskExists(link.source)) {\n gantt.deleteLink(link.id);\n }\n });\n }\n\n private processNewLinksBatch(depEntries: [string, TaskDependency][], gantt: GanttStatic) {\n depEntries.forEach(([key, dep]) => {\n if (!gantt.isLinkExists(key)) {\n gantt.addLink(mapDependencyToGanttLink(gantt, dep));\n }\n });\n }\n\n private parseTasks() {\n if (this.ganttInstance.name === GanttNames.issues) {\n return;\n }\n\n const oskMap: OSKMap = new Map();\n const collapsed: Set = this.collapseAccessor ? new Set(this.collapseAccessor()) : new Set();\n\n const visibleTasks = this.tasksStore.tasks.filter((task) => this.filterIds.has(task.id));\n\n const tasksAndLinks = transformLookaheadData({\n tasks: visibleTasks,\n projectId: this.tasksStore.projectId,\n flatList: false,\n oskMap,\n collapsed,\n });\n\n this.ganttInstance.clearAll();\n this.ganttInstance.parse({\n tasks: tasksAndLinks?.tasks || [],\n links: this.tasksStore.dependencies as unknown as Link[],\n });\n this.linkDependenciesToTasks();\n this.updateRownums();\n }\n\n private updateRownumMaps() {\n const idToRownum = {};\n const rownumToID = {};\n const sortedTasks = this.tasksStore.tasks?.filter((task) => !!task.outline_sort_key);\n\n for (let i = 0; i < sortedTasks?.length; i++) {\n idToRownum[sortedTasks[i].id] = i + 1;\n rownumToID[i + 1] = sortedTasks[i].id;\n }\n\n this.idRownumMap = idToRownum;\n this.rownumIDMap = rownumToID;\n }\n\n private applyRownums() {\n const gantt = this.ganttInstance;\n\n // Update the Gantt chart's row number mapping\n gantt.rownumbersMap = this.idRownumMap;\n\n // No way to be certain how many row numbers will get modified, but can't afford\n // a batchUpdate here because we can't tell in advance how many rows will need to\n // be modified, so no way to judge whether we need to skip batchUpdate to optimize\n // for the common case (added one row at the bottom)\n const modified = [];\n gantt.eachTask((task) => {\n // Check if the task's row number has changed\n if (this.idRownumMap[task.id] && this.idRownumMap[task.id] !== task.rownum) {\n // Update the task's row number\n task.rownum = this.idRownumMap[task.id];\n\n // Add the task ID to the modified list for efficient updating\n modified.push(task.id);\n }\n });\n\n if (modified.length > REPAINT_FULL_TABLE_THRESHOLD) {\n // If many tasks were modified, re-render the entire chart\n this.ganttInstance.render();\n } else {\n // If only a few tasks were modified, update them individually\n modified.forEach((id) => {\n // Refresh each modified task without triggering a full re-render\n // The 'false' parameter prevents unnecessary calculations\n gantt.refreshTask(id, false);\n });\n }\n }\n\n private updateRownums() {\n runInAction(() => {\n this.updateRownumMaps();\n this.applyRownums();\n this.ganttInstance.render();\n });\n }\n}\n","import * as Sentry from '@sentry/react';\nimport {InterruptedException} from 'effect/Cause';\nimport {inject, injectable} from 'inversify';\nimport {IObservableArray, makeObservable, observable, runInAction} from 'mobx';\n\nimport FeedbackService from 'api/feedback';\nimport {loadAllTasks, loadProjectDependencies} from 'modules/Tasks/components/Gantt/utils/load';\nimport {extractAxiosError} from 'shared/helpers/axios';\nimport {DailyType, MessageTypeMap} from 'shared/models/feedback';\nimport {IOC_TYPES} from 'shared/models/ioc';\nimport {TaskModelRawDTO, FeedbackProjectModelDTO, FeedbackByDateTaskRaw} from 'shared/models/task/task';\nimport {TaskDependencyDto} from 'shared/models/TaskDependency';\n\ntype EnrichedTask = TaskModelRawDTO & {feedback: FeedbackProjectModelDTO[]};\n\nimport type {UIStoreType} from './UIStore';\n\nexport function nullsFirstOSKSort(a: TaskModelRawDTO, b: TaskModelRawDTO) {\n if (a.outline_sort_key === b.outline_sort_key) {\n return 0;\n }\n if (!a.outline_sort_key) {\n return -1;\n } else if (!b.outline_sort_key) {\n return 1;\n } else {\n return a.outline_sort_key.localeCompare(b.outline_sort_key);\n }\n}\n\nexport type TasksStoreType = Pick>;\n\n@injectable()\nexport class TasksStore implements TasksStoreType {\n @inject(IOC_TYPES.UIStore) private uiStore: UIStoreType;\n\n tasks: TaskModelRawDTO[] = [];\n dependencies: TaskDependencyDto[] = [];\n isLoading = false;\n projectId: string | null = null;\n tasksLoaded = false;\n error = null;\n loadDeleted = false;\n silent = false;\n projectFeedback: FeedbackProjectModelDTO[] = [];\n\n constructor() {\n // eslint-disable-next-line mobx/exhaustive-make-observable\n makeObservable(this, {\n tasks: observable.shallow,\n dependencies: observable.shallow,\n projectFeedback: observable.shallow,\n isLoading: observable,\n projectId: observable,\n tasksLoaded: observable,\n error: observable,\n loadDeleted: observable,\n silent: observable,\n });\n }\n\n async setLoadDeleted(loadDeleted: boolean) {\n if (this.loadDeleted !== loadDeleted) {\n this.loadDeleted = loadDeleted;\n return this.loadTasks();\n }\n }\n\n setTasks(tasks: TaskModelRawDTO[]) {\n tasks.sort(nullsFirstOSKSort);\n (this.tasks as IObservableArray).replace(tasks);\n }\n\n getSortedTasksCopy() {\n return JSON.parse(JSON.stringify(this.tasks)).sort(nullsFirstOSKSort);\n }\n\n setError(error: unknown) {\n this.error = error;\n }\n\n setDependencies(dependencies: TaskDependencyDto[]) {\n (this.dependencies as IObservableArray).replace(dependencies);\n }\n\n removeDependency(dependencyId: string) {\n if (!dependencyId || !this.dependencies.length) return;\n\n runInAction(() => {\n const index = this.dependencies.findIndex((dep) => dep.id === dependencyId);\n if (index !== -1) {\n // Remove just this dependency\n (this.dependencies as IObservableArray).splice(index, 1);\n\n // If it was the last one, clear the list\n if (this.dependencies.length === 0) {\n (this.dependencies as IObservableArray).clear();\n }\n }\n });\n }\n\n setIsLoading(loading: boolean) {\n this.isLoading = loading;\n this.uiStore.setLoading(loading);\n }\n\n setTasksLoaded(loaded: boolean) {\n this.tasksLoaded = loaded;\n }\n\n getTaskById(taskId: string) {\n return this.tasks.find((task) => task.id === taskId);\n }\n\n async setProjectId(projectId: string) {\n if (this.projectId !== projectId || !this.tasks.length) {\n this.projectId = projectId;\n await this.loadTasks();\n }\n }\n\n addTasks(addedTasks: TaskModelRawDTO[]) {\n addedTasks.sort(nullsFirstOSKSort);\n if (this.tasks.length) {\n for (const task of addedTasks) {\n // this.tasks is an array sorted by outline_sort_key that does not contain task.\n // Find the correct offset to insert task into this.tasks\n // The most common case where the new tasks outline sort key already exists is when\n // a subsequent updateTasks is anticipated that will move those out of the way, so\n // prefer inserting the newest task before any task with matching OSK, so >=.\n const offset = this.tasks.findIndex((t) => t.outline_sort_key >= task.outline_sort_key);\n if (offset === -1) {\n this.tasks.push(task);\n } else {\n this.tasks.splice(offset, 0, task);\n }\n }\n } else {\n this.tasks.push(...addedTasks);\n }\n }\n\n updateTasks(tasks: Partial[]) {\n // Find the task in the store matching the provided tasks and overwrite the attributes\n const updateMap = new Map(tasks.map((task) => [task.id, task]));\n // This double-pass looks lame, but it's getting around the fact that observe doesn't\n // support transactions. Also, it isn't actually much more costly.\n for (let i = 0; i < this.tasks.length; i++) {\n if (updateMap.has(this.tasks[i].id)) {\n Object.assign(this.tasks[i], updateMap.get(this.tasks[i].id));\n }\n }\n\n this.silent = true;\n this.tasks.sort(nullsFirstOSKSort);\n this.silent = false;\n\n for (let i = 0; i < this.tasks.length; i++) {\n if (updateMap.has(this.tasks[i].id)) {\n // Object.assign, which would seem more natural here, doesn't fire the listener\n // Also, no need to be granular, I'm going to transform the entire task anyway\n this.tasks[i] = {...this.tasks[i]};\n }\n }\n }\n\n changeTaskId(oldId: number, newId: string) {\n const task = this.tasks.find((task: TaskModelRawDTO) => typeof task.id === 'number' && task.id === oldId);\n if (task) {\n task.id = newId;\n }\n }\n\n removeTasks(taskIds: string[]) {\n const taskIdsSet = new Set(taskIds);\n runInAction(() => {\n let startIdx = 0;\n let endIdx = 0;\n\n // This reduces calls to ganttStore.taskListChanged by removing tasks in ranges.\n while (endIdx < this.tasks.length) {\n if (taskIdsSet.has(this.tasks[endIdx].id)) {\n endIdx++;\n } else {\n // If the task ID isn't on set of IDs and our startIdx is different to endIdx, it removes the tasks in that range.\n // After that, we reset endIdx to startIdx to start a new range.\n if (startIdx !== endIdx) {\n this.tasks.splice(startIdx, endIdx - startIdx);\n endIdx = startIdx;\n } else {\n // If startIdx equals endIdx, increment both.\n startIdx++;\n endIdx++;\n }\n }\n }\n\n // If loop exited with startIdx !== endIdx, it removes remaining tasks in that range.\n if (startIdx !== endIdx) {\n this.tasks.splice(startIdx, endIdx - startIdx);\n }\n });\n }\n\n addProjectFeedback(newFeedback: FeedbackProjectModelDTO[]) {\n this.projectFeedback = (this.projectFeedback || []).concat(newFeedback);\n }\n\n deleteProjectFeedback(id: string) {\n const feedbackIndex = this.projectFeedback.findIndex((feedback) => feedback.id === id);\n if (feedbackIndex !== -1) {\n this.projectFeedback.splice(feedbackIndex, 1);\n }\n }\n\n private async loadProjectFeedback() {\n const feedback = await FeedbackService.getAllFeedBackForProject(this.projectId);\n this.projectFeedback = feedback;\n }\n\n private mergeTaskRelatedData(): TaskModelRawDTO[] {\n const feedbackByTask: Record = {};\n const commentCountByTask: Record = {};\n\n // Group feedback by task\n this.projectFeedback?.forEach((feedback) => {\n if (!feedbackByTask[feedback.taskId]) {\n feedbackByTask[feedback.taskId] = [];\n }\n feedbackByTask[feedback.taskId].push(feedback);\n\n // Count comments\n if (\n feedback.feedbackType === MessageTypeMap.message ||\n feedback.feedbackType === MessageTypeMap.image ||\n feedback.feedbackType === MessageTypeMap.extChatEvent\n ) {\n commentCountByTask[feedback.taskId] = (commentCountByTask[feedback.taskId] || 0) + 1;\n }\n });\n\n // Merge task related data into tasks\n return this.tasks.map((task) => {\n const taskFeedback = feedbackByTask[task.id] || [];\n const commentCount = commentCountByTask[task.id] || 0;\n\n const feedbackByDate: FeedbackByDateTaskRaw[] = [];\n\n taskFeedback.forEach((feedback) => {\n const feedbackField = feedback.feedbackType as DailyType;\n\n let feedbackByDateEntry = feedbackByDate.find((entry) => entry.field === feedbackField);\n\n if (!feedbackByDateEntry) {\n feedbackByDateEntry = {field: feedbackField, feedback_by_date: []};\n feedbackByDate.push(feedbackByDateEntry);\n }\n\n const {date, workerId, timeCreated} = feedback;\n const {valueInteger} = feedback.payload;\n\n const newFeedbackEntry = {\n date,\n time_created: timeCreated,\n value: valueInteger,\n worker_id: workerId,\n };\n\n // Check if there's already an entry for this date and time_created\n const existingEntryIndex = feedbackByDateEntry.feedback_by_date.findIndex(\n (entry) => entry.time_created === feedback.timeCreated && entry.date === feedback.date,\n );\n\n if (existingEntryIndex > -1) {\n // Update existing entry if found\n feedbackByDateEntry.feedback_by_date[existingEntryIndex] = newFeedbackEntry;\n } else {\n // Add new entry if not found\n feedbackByDateEntry.feedback_by_date.push(newFeedbackEntry);\n }\n });\n\n const enrichedTask = Object.assign({}, task) as EnrichedTask;\n enrichedTask.feedback = taskFeedback;\n enrichedTask.comment_count = commentCount;\n enrichedTask.feedback_by_date = feedbackByDate;\n\n return enrichedTask;\n });\n }\n\n private async loadTaskDependencies(requestProjectId: string) {\n try {\n const deps = await loadProjectDependencies(requestProjectId);\n return deps;\n } catch (error) {\n throw error;\n }\n }\n\n private async loadAllTasks(requestProjectId: string, loadDeleted: boolean) {\n try {\n const tasks = loadAllTasks(requestProjectId, loadDeleted);\n return tasks;\n } catch (error) {\n throw error;\n }\n }\n\n async loadTasks() {\n const requestProjectId = this.projectId;\n\n try {\n this.setIsLoading(true);\n this.setError(null);\n this.setDependencies([]);\n this.setTasks([]);\n this.setTasksLoaded(false);\n const loadDeleted = this.loadDeleted;\n\n const results = await Promise.allSettled([\n this.loadAllTasks(requestProjectId, loadDeleted),\n this.loadTaskDependencies(requestProjectId),\n this.loadProjectFeedback(),\n ]);\n\n const [loadAllTasksResult, dependenciesResult, feedbackResult] = results;\n\n if (loadAllTasksResult.status === 'fulfilled') {\n const loadAllTasksResponse = loadAllTasksResult.value;\n if (loadAllTasksResponse instanceof InterruptedException) {\n return;\n }\n\n runInAction(() => {\n this.setTasks(loadAllTasksResponse);\n });\n } else {\n Sentry.withScope((scope) => {\n scope.setExtra('projectId', requestProjectId);\n scope.setExtra('loadDeleted', loadDeleted);\n scope.setExtra('operation', 'loadAllTasks');\n scope.setLevel('error');\n Sentry.captureException(loadAllTasksResult.reason);\n });\n }\n\n if (feedbackResult.status === 'fulfilled') {\n const tasksWithFeedback = this.mergeTaskRelatedData();\n runInAction(() => {\n this.setTasks(tasksWithFeedback);\n });\n } else {\n Sentry.withScope((scope) => {\n scope.setExtra('projectId', this.projectId);\n scope.setExtra('operation', 'loadProjectFeedback');\n scope.setExtra('timestamp', new Date().toISOString());\n scope.setTag('errorType', feedbackResult.reason?.name || 'Unknown');\n scope.setLevel('error');\n\n // Add additional context about the state when the error occurred\n scope.setContext('projectState', {\n hasLoadedTasks: loadAllTasksResult.status === 'fulfilled',\n hasDependencies: dependenciesResult.status === 'fulfilled',\n });\n\n Sentry.captureException(feedbackResult.reason, {\n extra: {\n errorMessage: feedbackResult.reason?.message,\n errorStack: feedbackResult.reason?.stack,\n },\n });\n });\n }\n\n if (dependenciesResult.status === 'fulfilled') {\n const dependencies = dependenciesResult.value;\n if (dependencies instanceof InterruptedException) {\n return;\n }\n\n runInAction(() => {\n this.setDependencies(dependencies);\n });\n } else {\n Sentry.withScope((scope) => {\n scope.setExtra('projectId', this.projectId);\n scope.setExtra('operation', 'loadTaskDependencies');\n scope.setLevel('error');\n Sentry.captureException(dependenciesResult.reason);\n });\n }\n\n runInAction(() => {\n this.setIsLoading(false);\n this.setTasksLoaded(true);\n });\n } catch (error) {\n Sentry.captureException(error, {\n extra: {\n projectId: requestProjectId,\n },\n });\n extractAxiosError(error);\n runInAction(() => {\n this.setError(error);\n this.setIsLoading(false);\n });\n }\n }\n}\n","import {Container} from 'inversify';\n\nimport {TaskUpdateFifoQueue} from 'services/TaskUpdateFifoQueue';\nimport {IOC_TYPES} from 'shared/models/ioc';\nimport {GanttContextMenuStore} from 'shared/stores/GanttContextMenuStore';\nimport {GanttStore} from 'shared/stores/GanttStore';\nimport {TasksStore} from 'shared/stores/TasksStore';\nimport {UIStoreType, UIStore} from 'shared/stores/UIStore';\n\nexport class IocContainer {\n container: Container;\n\n constructor() {\n this.container = new Container({\n autoBindInjectable: true,\n defaultScope: 'Transient',\n });\n }\n\n init = () => {\n this.container.bind(IOC_TYPES.TasksStore).to(TasksStore).inSingletonScope();\n this.container.bind(IOC_TYPES.GanttStore).to(GanttStore).inSingletonScope();\n this.container.bind(IOC_TYPES.TaskUpdateFifoQueue).to(TaskUpdateFifoQueue).inSingletonScope();\n this.container.bind(IOC_TYPES.UIStore).to(UIStore).inSingletonScope();\n this.container\n .bind(IOC_TYPES.GanttContextStore)\n .to(GanttContextMenuStore)\n .inSingletonScope();\n\n return this.container;\n };\n}\n\nexport const container = new IocContainer().init();\n","import axios from 'axios';\nimport {camelizeKeys, decamelizeKeys, HumpsProcessor} from 'humps';\n\nimport {FirebaseTokenProvider} from 'services/Firebase/FirebaseTokenProvider';\nimport {TasksObserver} from 'services/TasksObserver/TasksObserver';\nimport env from 'shared/constants/env';\nimport {throttle} from 'shared/helpers/throttle';\nimport {CompanyStatus} from 'shared/models/company';\nimport store from 'store';\nimport {profileActions} from 'store/profile';\nimport {getActiveProjectFromLocalStorage} from 'store/profile/utils';\n\nimport CompanyApi from './company';\n\nconst ApiAxios = axios.create({baseURL: env.API_URL});\n\nexport const camelCaseConverter: HumpsProcessor = (key, convert, options) => {\n // for example: \"x-amz\" or \"2023-01-01\" in task.perDateOverrides\n if (key.includes('-')) return key;\n return convert(key, options);\n};\n\nexport function initApiInterceptors(tokenProvider: FirebaseTokenProvider) {\n // authentication interceptor, add Authorization header for any request to /api\n ApiAxios.interceptors.request.use(async (req) => {\n const token = await tokenProvider.getUserIdToken();\n if (!!token && !req.headers.Authorization) {\n req.headers.Authorization = `Bearer ${token}`;\n }\n return req;\n });\n\n // set platform header for any requests to /api\n ApiAxios.interceptors.request.use(async (req) => {\n req.headers['X-Journey-Platform'] = 'c4';\n if (window.location.pathname.includes('signup/alt-a')) {\n req.headers['X-Journey-Platform'] = 'c4_konvert';\n }\n return req;\n });\n\n // request body transformation from/to camel/snake case\n ApiAxios.interceptors.response.use((res) => {\n if (res.config.disableCamelCaseConverter) {\n return res;\n }\n if (res.data && res.headers['content-type'] === 'application/json') {\n // emit changes to observer\n if (\n !res.config.ignoreAffectedTaskIds &&\n res?.data?.affected_task_ids &&\n Array.isArray(res.data.affected_task_ids) &&\n res.data.affected_task_ids.length\n ) {\n const inst = TasksObserver.getInstance();\n inst.load({\n ids: res.data.affected_task_ids as string[],\n projectId: getActiveProjectFromLocalStorage(\n store.getState().profile.worker?.id,\n store.getState().profile.activeCompanyId,\n ),\n });\n }\n // exclusion case for import phase\n let savedSamplesFromCamelize = [];\n if (res.config.url.includes('prep/status') && res.data?.result?.samples) {\n savedSamplesFromCamelize = [...res.data.result.samples];\n }\n res.data = camelizeKeys(res.data, camelCaseConverter);\n if (savedSamplesFromCamelize.length) {\n res.data.result.samples = savedSamplesFromCamelize;\n }\n }\n return res;\n });\n\n ApiAxios.interceptors.request.use((req) => {\n const config = {...req};\n if (\n config.headers['Content-Type'] &&\n typeof config.headers['Content-Type'] === 'string' &&\n config.headers['Content-Type'].includes('multipart/form-data')\n ) {\n return config;\n }\n\n config.params = req.params && decamelizeKeys(req.params, camelCaseConverter);\n config.data = req.data && decamelizeKeys(req.data, camelCaseConverter);\n return config;\n });\n\n const dispatchShowAccessDeniedPopup = throttle(async () => {\n const activeCompanyId = store.getState().profile.activeCompanyId;\n const company = await CompanyApi.getCompany(activeCompanyId);\n if (company.status === CompanyStatus.Disabled) {\n if (!store.getState().profile.showAccessDeniedPopup) {\n store.dispatch(profileActions.showAccessDeniedPopup(true));\n }\n }\n }, 1500);\n\n ApiAxios.interceptors.response.use(\n (res) => res,\n (rej) => {\n if (rej.response?.status === 403) {\n dispatchShowAccessDeniedPopup();\n }\n return Promise.reject(rej);\n },\n );\n}\n\nexport default ApiAxios;\n\ndeclare module 'axios' {\n export interface AxiosRequestConfig {\n disableCamelCaseConverter?: boolean;\n ignoreAffectedTaskIds?: boolean;\n }\n}\n","import axios, {AxiosHeaders, InternalAxiosRequestConfig} from 'axios';\nimport {camelizeKeys} from 'humps';\n\nimport TasksApi from 'api/tasks';\nimport {AppConstantsResponse} from 'shared/hooks/useAppConstants';\n\nimport {camelCaseConverter} from './axios';\n\nexport async function createMatrixAxiosInstance(accessToken?: string, contentType = 'application/json') {\n const appConstants: AppConstantsResponse = await TasksApi.getAppConstants();\n if (appConstants) {\n const instance = axios.create({\n baseURL: appConstants.locales.uS.matrix.homeserver,\n });\n\n instance.interceptors.request.use(\n (config: InternalAxiosRequestConfig) => {\n if (!config.headers) {\n config.headers = new AxiosHeaders();\n }\n\n config.headers.set('Content-Type', contentType);\n\n if (accessToken) {\n config.headers.set('Authorization', `Bearer ${accessToken}`);\n }\n\n return config;\n },\n (error) => {\n return Promise.reject(error);\n },\n );\n\n instance.interceptors.response.use((res) => {\n if (res.config.disableCamelCaseConverter) {\n return res;\n }\n if (res.data && res.headers['content-type'] === 'application/json') {\n res.data = camelizeKeys(res.data, camelCaseConverter);\n }\n return res;\n });\n\n return instance;\n } else {\n throw new Error('Failed to fetch configuration');\n }\n}\n","import {\n MatrixConnectionToken,\n MatrixSessionBody,\n MatrixSessionResponse,\n Unread,\n UnreadInfo,\n} from 'shared/models/task/chat';\n\nimport ApiAxios from './axios';\nimport {createMatrixAxiosInstance} from './matrix';\n\nclass ChatService {\n private static instance: ChatService | null = null;\n private mediaEndpoint = '/_matrix/media/v3';\n private clientEndpoint = '/_matrix/client/v3';\n\n public static getInstance(): ChatService {\n if (!ChatService.instance) {\n ChatService.instance = new ChatService();\n }\n return ChatService.instance;\n }\n\n private async getMatrixConnectionToken(workerId: string) {\n const res = await ApiAxios.get(`/workers/${workerId}/chatauth`);\n return res.data;\n }\n\n async getMatrixServerConfig(accessToken: string) {\n const ChatServiceAxios = await createMatrixAxiosInstance(accessToken);\n const res = await ChatServiceAxios.get<{'m.upload.size': number}>(`${this.mediaEndpoint}/config`);\n return res.data;\n }\n\n async initializeMatrixSession(workerId: string) {\n const credentials = await this.getMatrixConnectionToken(workerId);\n const body: MatrixSessionBody = {\n type: 'm.login.password',\n identifier: {\n type: 'm.id.user',\n user: credentials.id,\n },\n password: credentials.password,\n };\n const ChatServiceAxios = await createMatrixAxiosInstance();\n const res = await ChatServiceAxios.post(`${this.clientEndpoint}/login`, body);\n return res.data;\n }\n\n async uploadAssetToMatrix(accessToken: string, file: File) {\n const body = await file.arrayBuffer();\n const ChatServiceAxios = await createMatrixAxiosInstance(accessToken, file.type);\n const res = await ChatServiceAxios.post<{contentUri: string}>(\n `${this.mediaEndpoint}/upload?filename=${file.name}`,\n body,\n );\n return res.data;\n }\n\n async getJoinedRooms(accessToken: string) {\n const ChatServiceAxios = await createMatrixAxiosInstance(accessToken);\n\n const res = await ChatServiceAxios.get<{joinedRooms: string[]}>(`${this.clientEndpoint}/joined_rooms`);\n\n return res.data.joinedRooms;\n }\n\n async getUnreadCount(accessToken: string, roomIds: string[]) {\n const ChatServiceAxios = await createMatrixAxiosInstance(accessToken);\n if (!roomIds?.length) {\n return;\n }\n\n const unreadInfos: UnreadInfo[] = [];\n\n const syncFilter = {\n room: {\n timeline: {limit: 1},\n includeLeave: false,\n },\n };\n\n const syncResponse = await ChatServiceAxios.get(\n `${this.clientEndpoint}/sync?filter=${encodeURIComponent(JSON.stringify(syncFilter))}&timeout=0`,\n );\n for (const roomId of roomIds) {\n if (syncResponse.data.rooms?.join?.[roomId]) {\n const roomInfo = syncResponse.data.rooms.join[roomId];\n if (roomInfo.unreadNotifications) {\n unreadInfos.push({\n roomId,\n total: roomInfo.unreadNotifications.notificationCount || 0,\n highlight: roomInfo.unreadNotifications.highlightCount || 0,\n });\n }\n }\n }\n\n const unread: Unread = {\n total: 0,\n highlight: 0,\n from: new Set(),\n };\n\n unreadInfos.forEach((info) => {\n if (info.total > 0) {\n unread.total += info.total;\n unread.highlight += info.highlight;\n unread.from?.add(info.roomId);\n }\n });\n\n return unread;\n }\n}\n\nexport default ChatService.getInstance();\n","import {CompanyModel, CompanyOrgs} from 'shared/models/company';\nimport {CompanyCreateRequest} from 'shared/models/onboardingForms';\nimport {ReportTimelineResult} from 'shared/models/reports';\nimport {InvitedWorker} from 'shared/models/worker';\n\nimport ApiAxios from './axios';\n\nconst MAX_ORGS = 1000;\n\nclass CompanyService {\n private getWorkerCompanyBasePath(workerId: string) {\n return `/workers/${workerId}/companies`;\n }\n private getCompanyBasePath(companyId: string) {\n return `/companies/${companyId}`;\n }\n\n createCompany(companyRequest: CompanyCreateRequest, workerId: string) {\n return ApiAxios.post(this.getWorkerCompanyBasePath(workerId), {\n ...companyRequest,\n type: 'company',\n }).then((res) => {\n return res.data;\n });\n }\n\n updateCompany(model: CompanyModel, workerId: string) {\n return ApiAxios.post(`${this.getWorkerCompanyBasePath(workerId)}/${model.id}`, model).then(\n (res) => res.data,\n );\n }\n\n uploadCompanyLogo(file: File, companyId: string) {\n const payload = new FormData();\n payload.append('logo_pic', file);\n return ApiAxios.post<{url: string}>(`${this.getCompanyBasePath(companyId)}/logo`, payload, {\n headers: {'Content-Type': 'multipart/form-data'},\n }).then((res) => res.data);\n }\n\n getCompanyOrgs(companyId: string) {\n return ApiAxios.get(`${this.getCompanyBasePath(companyId)}/companyorgs`, {\n params: {\n limit: MAX_ORGS,\n offset: 0,\n },\n }).then((res) => res.data);\n }\n\n getCompany(companyId: string) {\n return ApiAxios.get(`${this.getCompanyBasePath(companyId)}`).then((res) => res.data);\n }\n\n getInvitedWorkerByCode(inviteCode: string) {\n return ApiAxios.get('/companyinvite', {params: {invite_code: inviteCode}}).then((res) => res.data);\n }\n\n async getLaborTimeline(companyId: string) {\n return ApiAxios.get(`${this.getCompanyBasePath(companyId)}/reports/timeline`).then(\n (res) => res.data,\n );\n }\n}\n\nexport default new CompanyService();\n","import dayjs from 'dayjs';\n\nimport {Feedback} from 'shared/models/feedback';\nimport {FeedbackProjectModelDTO} from 'shared/models/task/task';\n\nimport ApiAxios from './axios';\n\nclass FeedbackService {\n private static instance: FeedbackService | null = null;\n private getBasePath(taskId: string) {\n return `/tasks/${taskId}/feedback`;\n }\n private issueFeedbackPath(projectId: string, issueId: string) {\n return `/projects/${projectId}/issues/${issueId}/feedback`;\n }\n\n public static getInstance(): FeedbackService {\n if (!FeedbackService.instance) {\n FeedbackService.instance = new FeedbackService();\n }\n return FeedbackService.instance;\n }\n\n async postFeedback(taskId: string, body: Feedback[]): Promise {\n const res = await ApiAxios.post(this.getBasePath(taskId), body);\n return res.data;\n }\n\n async getFeedback(taskId: string) {\n const res = await ApiAxios.get(this.getBasePath(taskId));\n return res.data;\n }\n\n async postIssueFeedback(\n {issueId, projectId}: {issueId: string; projectId: string},\n body: Feedback[],\n ): Promise {\n const res = await ApiAxios.post(this.issueFeedbackPath(projectId, issueId), body);\n return res.data;\n }\n\n async getIssueFeedback(issueId: string, projectId: string) {\n const res = await ApiAxios.get(`/projects/${projectId}/issues/${issueId}/feedback`);\n return res.data;\n }\n\n async getAllFeedBackForProject(projectId: string, afterTimeCreated?: Date) {\n const isoDate = dayjs(afterTimeCreated).toISOString();\n const queryString = afterTimeCreated ? `?after_time_created=${isoDate}` : '';\n const res = await ApiAxios.get(`/projects/${projectId}/feedback${queryString}`);\n return res.data;\n }\n}\n\nexport default FeedbackService.getInstance();\n","import axios from 'axios';\n\nimport {runPollingEffect} from 'services/Effect/api/runPollingEffect';\nimport {\n DocumentTransferStatusResponse,\n TaskImportPrepResponse,\n TaskImportResponse,\n AsyncCommitResult,\n ImportPollingParams,\n} from 'shared/components/TasksImport/utils/types';\nimport {ExternalServices} from 'shared/constants/common';\nimport {pollResults} from 'shared/helpers/api';\nimport {compressFile} from 'shared/helpers/common';\nimport {DocumentTransferStartResponse, S3UploadResponse, TaskImportPayload} from 'shared/models/import';\n\nimport ApiAxios from './axios';\n\ntype StartImportRequestBody =\n | {\n filename: string;\n type: 'file_upload';\n }\n | {type: 'procore'};\n\ntype StartDocumentTransferRequestBody = {\n service: 'procore';\n serviceId: string;\n fileId: string;\n fileName: string;\n};\n\nclass ImportService {\n private static instance: ImportService | null = null;\n\n public static getInstance(): ImportService {\n if (!ImportService.instance) {\n ImportService.instance = new ImportService();\n }\n return ImportService.instance;\n }\n\n private static getBasePath(projectId: string) {\n return `/projects/${projectId}/bulktaskimport`;\n }\n\n startDocumentTransfer(projectId: string, serviceId: string, fileId: string, fileName: string) {\n const requestBody: StartDocumentTransferRequestBody = {\n service: ExternalServices.Procore,\n serviceId,\n fileId,\n fileName,\n };\n\n return ApiAxios.post(`/projects/${projectId}/externalfiletransfer`, requestBody);\n }\n\n transferStatus(projectId: string, importId: string) {\n return ApiAxios.get(\n `projects/${projectId}/externalfiletransfer/${importId}/start/status`,\n );\n }\n\n pollTransferResponse(projectId: string, importId: string, maxWaitSec: number) {\n return pollResults({\n importId,\n maxWaitSec,\n fetcher: () => this.transferStatus(projectId, importId),\n });\n }\n\n startImport(projectId: string, filename?: string) {\n const requestBody: StartImportRequestBody = filename ? {filename, type: 'file_upload'} : {type: 'procore'};\n return ApiAxios.post(ImportService.getBasePath(projectId), requestBody);\n }\n\n async uploadFileToS3(file: File, url: string) {\n const compressed = await compressFile(file);\n return axios.put(url, compressed, {headers: {'Content-Encoding': 'gzip'}});\n }\n\n prepRun(projectId: string, importId: string) {\n return ApiAxios.post(`${ImportService.getBasePath(projectId)}/${importId}/prep`);\n }\n\n prepStatus(projectId: string, importId: string) {\n return ApiAxios.get(`${ImportService.getBasePath(projectId)}/${importId}/prep/status`);\n }\n\n async pollPrepResults({projectId, importId, maxWaitSec}: ImportPollingParams) {\n return runPollingEffect({\n importId,\n maxWaitSec,\n fetcher: () => this.prepStatus(projectId, importId),\n });\n }\n\n dryRun(projectId: string, importId: string, payload: Partial) {\n return ApiAxios.post(`${ImportService.getBasePath(projectId)}/${importId}/dryrun`, payload);\n }\n\n dryRunStatus(projectId: string, importId: string) {\n return ApiAxios.get(`${ImportService.getBasePath(projectId)}/${importId}/dryrun/status`);\n }\n\n async pollDryRunResults({projectId, importId, maxWaitSec, completePercentage}: ImportPollingParams) {\n return runPollingEffect({\n importId,\n maxWaitSec,\n completePercentage,\n fetcher: () => this.dryRunStatus(projectId, importId),\n });\n }\n\n commit(projectId: string, importId: string, payload: Partial) {\n return ApiAxios.post(`${ImportService.getBasePath(projectId)}/${importId}/commit`, payload);\n }\n\n commitStatus(projectId: string, importId: string) {\n return ApiAxios.get(`${ImportService.getBasePath(projectId)}/${importId}/commit/status`);\n }\n\n async pollCommitResults({projectId, importId, maxWaitSec, completePercentage}: ImportPollingParams) {\n return runPollingEffect({\n importId,\n maxWaitSec,\n completePercentage,\n fetcher: () => this.commitStatus(projectId, importId),\n });\n }\n\n extract(projectId: string, importId: string, sourceId: string) {\n return ApiAxios.post(`${ImportService.getBasePath(projectId)}/${importId}/extract`, {\n service: 'procore',\n sourceIdentifier: sourceId,\n });\n }\n\n extractStatus(projectId: string, importId: string) {\n return ApiAxios.get>>(\n `${ImportService.getBasePath(projectId)}/${importId}/extract/status`,\n );\n }\n\n pollExtractResult(projectId: string, importId: string, maxWaitSec: number) {\n return runPollingEffect({\n importId,\n maxWaitSec,\n fetcher: () => this.extractStatus(projectId, importId),\n });\n }\n}\n\nexport default ImportService.getInstance();\n","import {ExternalServices} from 'shared/constants/common';\n\nimport ApiAxios from './axios';\n\ntype OAuthStatus = 'authorized' | 'unauthorized';\n\ninterface OAuthCheckResponse {\n status: OAuthStatus;\n}\n\ninterface OAuthReturnParams {\n code: 'string';\n service: ExternalServices;\n}\n\ninterface OAuthStartParams {\n redirectUri: 'string';\n service: ExternalServices;\n}\n\ninterface OAuthStartResponse {\n authUrl: 'string';\n}\n\nclass OAuthService {\n check(service: ExternalServices = ExternalServices.Procore): Promise {\n return ApiAxios.get('/oauth/check', {params: {service}}).then((res) => {\n return res.data?.status === 'authorized';\n });\n }\n\n start(service: ExternalServices = ExternalServices.Procore, redirectUri = `${window.origin}/oauth/return`) {\n return ApiAxios.post('/oauth/start', {service, redirectUri} as OAuthStartParams).then(\n (res) => res.data.authUrl,\n );\n }\n return(code: string, service: ExternalServices = ExternalServices.Procore) {\n return ApiAxios.post('/oauth/return', {service, code} as OAuthReturnParams);\n }\n}\n\nexport default new OAuthService();\n","import {AxiosResponse, CancelTokenSource} from 'axios';\nimport {decamelize, decamelizeKeys} from 'humps';\n\nimport {runPollingEffect} from 'services/Effect/api/runPollingEffect';\nimport {AsyncCommitResult} from 'shared/components/TasksImport/utils/types';\nimport {CompletePercentageFunc} from 'shared/helpers/api';\nimport {isAxiosError} from 'shared/helpers/axios';\nimport {prepareWorkerFiltersForUrl} from 'shared/helpers/worker';\nimport {CompanyOrgs, CompanyOrgsGroup} from 'shared/models/company';\nimport {Feedback} from 'shared/models/feedback';\nimport {\n ProjectModel,\n ProjectWorkflow,\n ProjectCollabRequest,\n ProjectCollabInfo,\n ProjectCustomFieldDef,\n} from 'shared/models/project';\nimport {ProjectDependenciesParams} from 'shared/models/task/project';\nimport {\n TaskOutlineBasicModel,\n TaskOutlineModelDTO,\n FeedbackProjectModelDTO,\n WakeCapCrews,\n WakeCapZones,\n} from 'shared/models/task/task';\nimport {TaskDependencyDto} from 'shared/models/TaskDependency';\nimport {CompanyWorker, CompanyWorkerRequestParams} from 'shared/models/worker';\n\nimport ApiAxios from './axios';\n\nclass ProjectsService {\n private static instance: ProjectsService | null = null;\n\n public static getInstance(): ProjectsService {\n if (!ProjectsService.instance) {\n ProjectsService.instance = new ProjectsService();\n }\n return ProjectsService.instance;\n }\n\n private getBasePath(companyId: string) {\n return `/companies/${companyId}/projects`;\n }\n\n private getProjectsPath(projectId: string) {\n return `/projects/${projectId}`;\n }\n\n getProjects(companyId: string) {\n return ApiAxios.get(this.getBasePath(companyId)).then((res) => res.data);\n }\n\n getProject(projectId: string) {\n return ApiAxios.get(this.getProjectsPath(projectId)).then((res) => res.data);\n }\n\n createProject(companyId: string, project: ProjectModel) {\n return ApiAxios.post(this.getBasePath(companyId), project).then((res) => res.data);\n }\n\n updateProject(project: Partial) {\n return ApiAxios.post(this.getProjectsPath(project.id), project).then((res) => res.data);\n }\n\n deleteProject(projectId: string) {\n return ApiAxios.delete(this.getProjectsPath(projectId)).then((res) => res.data);\n }\n\n getProjectTaskTypes(projectId: string) {\n return ApiAxios.get(`${this.getProjectsPath(projectId)}/task_types`).then((res) => res.data);\n }\n\n getOutline(projectId: string) {\n return ApiAxios.get(`${this.getProjectsPath(projectId)}/outline`);\n }\n\n getOutlineTasks(companyId: string, taskIds: string[], cancelToken?: CancelTokenSource) {\n return ApiAxios.get(`/companies/${companyId}/outline_tasks`, {\n params: {taskids: taskIds.join(',')},\n cancelToken: cancelToken?.token,\n });\n }\n\n getProjectWorkers(\n projectId: string,\n {offset, limit, filterParams, sortOrder, sortField}: CompanyWorkerRequestParams,\n returnType?: RT,\n ): RT extends 'data' ? Promise : Promise>;\n getProjectWorkers(\n projectId: string,\n {offset, limit, filterParams, sortOrder, sortField}: CompanyWorkerRequestParams,\n returnType: 'data' | 'response' = 'data',\n ) {\n const preparedSort = {\n sortField: sortField ? decamelize(sortField) : undefined,\n sortOrder: sortOrder ? sortOrder : undefined,\n };\n return ApiAxios.get(`${this.getProjectsPath(projectId)}/companyworkers`, {\n params: {\n offset,\n limit,\n filterParams: JSON.stringify(decamelizeKeys(prepareWorkerFiltersForUrl(filterParams))),\n ...preparedSort,\n },\n }).then((res) => (returnType === 'data' ? res.data : res));\n }\n\n async getOrgs(projectId: string) {\n const res = await ApiAxios.get(`${this.getProjectsPath(projectId)}/companyorgs`);\n return res.data\n ? res.data.sort((companyA, companyB) => {\n return companyA?.group?.name.localeCompare(companyB?.group?.name);\n })\n : res.data;\n }\n\n createOrg(projectId: string, payload?: Partial | string) {\n return ApiAxios.post(\n `${this.getProjectsPath(projectId)}/companyorgs`,\n typeof payload === 'string' ? {name: payload} : payload,\n )\n .then((res) => res.data)\n .catch((e) => {\n if (isAxiosError<{companyorg: CompanyOrgs}>(e)) {\n const {\n response: {\n data: {companyorg = null},\n status,\n },\n } = e;\n if (status === 409 && companyorg) {\n return companyorg;\n }\n }\n throw e;\n });\n }\n\n updateOrg(projectId: string, orgId: string, payload: Partial) {\n return ApiAxios.post(`${this.getProjectsPath(projectId)}/companyorgs/${orgId}`, payload).then(\n (res) => res.data,\n );\n }\n\n deleteOrg(projectId: string, orgId: string) {\n return ApiAxios.delete(`${this.getProjectsPath(projectId)}/companyorgs/${orgId}`).then((res) => res.data);\n }\n\n getProjectSub(projectId: string, subId: string) {\n return ApiAxios.get(`${this.getProjectsPath(projectId)}/companyorgs/${subId}`).then((res) => res.data);\n }\n\n getWorkflow(projectId: string) {\n return ApiAxios.get(`${this.getProjectsPath(projectId)}/workflow`).then((res) => res.data);\n }\n\n getTaskDependencies(\n projectId: string,\n taskIds: string[] = [],\n {offset, limit, cancelToken}: ProjectDependenciesParams = {},\n ) {\n const requestParams = {\n taskIds,\n limit,\n offset,\n };\n\n return ApiAxios.post<{dependencies: TaskDependencyDto[]}>(\n `${this.getProjectsPath(projectId)}/get_dependencies`,\n requestParams,\n {cancelToken},\n );\n }\n\n sendCollabRequest(projectId: string, payload: ProjectCollabRequest) {\n return ApiAxios.post(`${this.getProjectsPath(projectId)}/collaborate`, payload).then((res) => res.data);\n }\n\n getMostRecentCollabUsers(projectId: string) {\n return ApiAxios.get(`${this.getProjectsPath(projectId)}/collaborate/most_recent`).then(\n (res) => res.data,\n );\n }\n\n getCollaborationInfo(projectId: string, collabId: string) {\n return ApiAxios.get(`${this.getProjectsPath(projectId)}/collaboration/${collabId}`).then(\n (res) => res.data,\n );\n }\n\n cloneProject(projectId: string, name: string) {\n return ApiAxios.post(`${this.getProjectsPath(projectId)}/clone/start`, {name}, {}).then(\n (res) => res.data,\n );\n }\n\n cloneProjectStatus(projectId: string, asyncUploadId: string) {\n return ApiAxios.get>>(\n `${this.getProjectsPath(projectId)}/clone/status/${asyncUploadId}`,\n {},\n );\n }\n\n async pollExtractResult(projectId: string, asyncUploadId: string, onProgress: CompletePercentageFunc) {\n return runPollingEffect({\n importId: asyncUploadId,\n maxWaitSec: 100,\n completePercentage: onProgress,\n fetcher: () => this.cloneProjectStatus(projectId, asyncUploadId),\n });\n }\n\n createCustomFieldDef(projectId: string, payload: ProjectCustomFieldDef) {\n return ApiAxios.post(`${this.getProjectsPath(projectId)}/custom_field_def`, payload).then(\n (res) => res.data,\n );\n }\n\n updateCustomFieldDef(projectId: string, payload: Omit) {\n const {internalFieldName, fieldData, fieldName} = payload;\n return ApiAxios.post(\n `${this.getProjectsPath(projectId)}/custom_field_def/${internalFieldName}`,\n {fieldData, fieldName},\n ).then(() => true);\n }\n\n async deleteCustomFieldDef(projectId: string, internalFieldName: string): Promise {\n const res = await ApiAxios.delete(`${this.getProjectsPath(projectId)}/custom_field_def/${internalFieldName}`);\n return res.data;\n }\n\n async postProjectFeedback(projectId: string, payload: Feedback[]) {\n const res = await ApiAxios.post(`${this.getProjectsPath(projectId)}/feedback`, payload);\n return res.data;\n }\n\n async deleteProjectFeedback(projectId: string, id: string) {\n const res = await ApiAxios.delete(`${this.getProjectsPath(projectId)}/feedback/${id}`);\n return res.data;\n }\n\n async getAllProjectsForWorker(workerId: string) {\n const res = await ApiAxios.get(`/workers/${workerId}/projects`);\n return res.data;\n }\n\n async getWakeCapCrews(projectId: string) {\n const res = await ApiAxios.get(`${this.getProjectsPath(projectId)}/wakecap_crews`);\n return res.data;\n }\n\n async getWakeCapZones(projectId: string) {\n const res = await ApiAxios.get(`${this.getProjectsPath(projectId)}/wakecap_zones`);\n return res.data;\n }\n}\n\nexport default ProjectsService.getInstance();\n","import {CancelToken} from 'axios';\nimport {decamelize, decamelizeKeys} from 'humps';\n\nimport env from 'shared/constants/env';\nimport {isAxiosError} from 'shared/helpers/axios';\nimport {getApiResponseDataRange} from 'shared/helpers/common';\nimport {prepareTaskFilters} from 'shared/helpers/tasks';\nimport {WithAffectedIds} from 'shared/models/common';\nimport {ProjectWorkflow} from 'shared/models/project';\nimport {TaskChatHistoryStatusResponse} from 'shared/models/task/chat';\nimport {TaskProjection} from 'shared/models/task/const';\nimport {IssuesParams, TaskParams} from 'shared/models/task/filter';\nimport {IssueModel, IssueWithAssigneesDTO} from 'shared/models/task/issue';\nimport {TaskAssignees} from 'shared/models/task/member';\nimport {\n IssueModelDTO,\n IssueModelRawDTO,\n TaskDetailsModelDTO,\n TasksResponseType,\n TaskWithAffectedResponse,\n CreateTaskResponse,\n TaskMoveRequest,\n TaskRelativeMoveRequest,\n TaskModelRawDTO,\n ConfigSharedTask,\n TaskCopyRequest,\n CreateSnapshotPayload,\n ResponseBaselineTasks,\n DeleteSnapshotPayload,\n BaselineTasks,\n AddIssueDayPayload,\n SharedTaskDetailsModelDTO,\n V2TasksResponseType,\n} from 'shared/models/task/task';\nimport {TaskDependencyDto} from 'shared/models/TaskDependency';\n\nimport ApiAxios from './axios';\n\nclass TasksService {\n getBasePath(companyId: string) {\n return `/companies/${companyId}/tasks`;\n }\n\n private getIssuesWithFilters(\n projectId: string,\n {offset, limit, sortParams: {sortOrder, sortField} = {}, filterParams = {}, cancelToken}: IssuesParams = {},\n disableCamelCaseConverter = false,\n ) {\n const url = `/projects/${projectId}/issues`;\n const preparedSort = {};\n sortField ? Object.assign(preparedSort, {sortField: decamelize(sortField)}) : '';\n sortOrder ? Object.assign(preparedSort, {sortOrder}) : '';\n\n return ApiAxios.get(url, {\n disableCamelCaseConverter,\n params: {\n filter_params: JSON.stringify(prepareTaskFilters(filterParams)),\n limit,\n offset,\n ...preparedSort,\n },\n cancelToken,\n });\n }\n\n getTaskIssues(projectId: string, params: IssuesParams) {\n return this.getIssuesWithFilters(projectId, params, true);\n }\n\n async getAllIssues(projectId: string, params?: IssuesParams) {\n const result = await this.getIssuesWithFilters(projectId, params, true);\n return result.data;\n }\n\n async getTaskIssuesById(projectId: string, issueTaskIds: string[]): Promise {\n const result = await this.getIssuesWithFilters(projectId, {\n filterParams: {ids: issueTaskIds},\n });\n return result.data;\n }\n\n updateIssue(task: Partial, isScopedUpdate = false) {\n const url = `${isScopedUpdate ? '/scoped' : ''}/projects/${task.projectId}/issues/${task.id}`;\n return ApiAxios.post(url, task).then((res) => res.data);\n }\n\n deleteIssue(issueId: string, projectId: string) {\n return ApiAxios.delete(`/projects/${projectId}/issues/${issueId}`).then((res) => res.data);\n }\n\n addIssueAssignee(projectId: string, issueId: string, assignee: TaskAssignees) {\n return ApiAxios.post(`/projects/${projectId}/issues/${issueId}/assign`, assignee).then(\n (res) => res.data,\n );\n }\n\n createIssue(issue: IssueWithAssigneesDTO, isScopedCreate = false) {\n return ApiAxios.post(\n `${isScopedCreate ? '/scoped' : ''}/projects/${issue.projectId}/issues`,\n issue,\n ).then((res) => res.data);\n }\n\n private getTasksWithFilters(\n url: string,\n {\n limit = 20,\n offset = 0,\n params = {},\n sortField,\n sortOrder,\n projection,\n includeSummaryTasks,\n cancelToken,\n }: TaskParams = {},\n ) {\n const preparedSort = {};\n sortField ? Object.assign(preparedSort, {sortField: decamelize(sortField)}) : '';\n sortOrder ? Object.assign(preparedSort, {sortOrder}) : '';\n\n return ApiAxios.get(url, {\n disableCamelCaseConverter: projection === TaskProjection.task,\n params: {\n filter_params: JSON.stringify(prepareTaskFilters(params)),\n offset,\n limit,\n projection,\n includeSummaryTasks,\n ...preparedSort,\n },\n cancelToken,\n });\n }\n\n private getV2TasksWithFilters(\n url: string,\n {limit = 20, offset = 0, params = {}, sortField, sortOrder, includeSummaryTasks, cancelToken}: TaskParams = {},\n ) {\n const preparedSort = {};\n sortField ? Object.assign(preparedSort, {sortField: decamelize(sortField)}) : '';\n sortOrder ? Object.assign(preparedSort, {sortOrder}) : '';\n\n return ApiAxios.get(url, {\n disableCamelCaseConverter: true,\n params: {\n filter_params: JSON.stringify(prepareTaskFilters(params)),\n offset,\n limit,\n includeSummaryTasks,\n ...preparedSort,\n },\n baseURL: env.API_URL_V2,\n cancelToken,\n });\n }\n\n getV2ProjectTasks(params: TaskParams) {\n return this.getV2TasksWithFilters(`/projects/${params.params.projectId}/tasks`, params);\n }\n\n getProjectTasks(params: TaskParams) {\n return this.getTasksWithFilters(`/projects/${params.params.projectId}/tasks`, params);\n }\n\n getTasksCount(companyId: string) {\n return this.getTasksWithFilters(this.getBasePath(companyId), {limit: 1, offset: 0}).then((res) => {\n return getApiResponseDataRange(res);\n });\n }\n\n getTasksForExport(companyId: string, params: TaskParams) {\n return this.getTasksWithFilters(`${this.getBasePath(companyId)}/export`, params).then((res) => {\n const range = res.headers['content-range'] as string;\n const match = range.match(/.+(\\d+-\\d+)\\/(\\d+)/);\n return {\n data: res.data,\n total: match && parseInt(match[2], 10),\n };\n });\n }\n\n getTask(taskId: string, options?: {cancelToken?: CancelToken}) {\n return ApiAxios.get(`/tasks/${taskId}`, {\n cancelToken: options?.cancelToken,\n }).then((res) => res.data);\n }\n\n getTasks(taskIds: string[], options?: {cancelToken?: CancelToken}) {\n const tasksPromises = taskIds.map((taskId) => this.getTask(taskId, {cancelToken: options?.cancelToken}));\n return Promise.all(tasksPromises);\n }\n\n /*\n * isScopedUpdate param is used to determine\n * if task has been changed by non-admin user (worker or foreman)?\n */\n updateTask(task: Partial, isScopedUpdate = false, ignoreAffectedTaskIds = false) {\n return ApiAxios.post(`${isScopedUpdate ? 'scoped' : ''}/tasks/${task.id}`, task, {\n ignoreAffectedTaskIds,\n }).then((res) => res.data);\n }\n\n updateTaskWithAffected(task: Partial) {\n /*\n * 2.0.0 endpoint returns\n * { task: , affected_tasks: }\n */\n return ApiAxios.post(`tasks/${task.id}`, task, {\n baseURL: env.API_URL_V2,\n disableCamelCaseConverter: true,\n }).then((res) => res.data);\n }\n\n createTask(task: Partial) {\n return ApiAxios.post(`/projects/${task.projectId}/tasks`, task).then((res) => res.data);\n }\n\n async createTaskRaw(task: Partial) {\n const res = await ApiAxios.post(`/projects/${task.projectId}/tasks`, task, {\n disableCamelCaseConverter: true,\n });\n return res.data;\n }\n\n deleteTask(taskId: string) {\n return ApiAxios.delete(`/tasks/${taskId}`).then((res) => res.data);\n }\n\n deleteTasks(projectId: string, taskIds: string[]) {\n return ApiAxios.post<{\n affectedTasks: string[];\n deletedDependencyIds: string[];\n deletedTaskIds: string[];\n }>(\n `projects/${projectId}/tasks/delete`,\n {taskIds},\n {\n baseURL: env.API_URL_V2,\n },\n ).then((res) => res.data);\n }\n\n restoreTask(taskId: string) {\n return ApiAxios.post(`/tasks/${taskId}/undelete`).then((res) => res.data);\n }\n\n startAsyncChatHistory(taskId: string) {\n return ApiAxios.post<{id: string}>(`tasks/${taskId}/chat_history`).then((res) => res.data);\n }\n\n checkAsyncStatusChatHistory(taskId: string, asyncUploadId: string) {\n return ApiAxios.get(`tasks/${taskId}/chat_history/${asyncUploadId}/status`).then(\n (res) => res.data,\n );\n }\n\n tasksMove(payload: TaskMoveRequest) {\n if (payload.parentTaskId === '0') {\n delete payload.parentTaskId;\n }\n return ApiAxios.post(`tasks/move`, payload).then((res) => {\n return res.data;\n });\n }\n\n taskRelativeMove(payload: TaskRelativeMoveRequest) {\n return ApiAxios.post('tasks/move_relative', payload, {\n disableCamelCaseConverter: true,\n ignoreAffectedTaskIds: true,\n }).then((res) => res.data);\n }\n\n getSharedTask(taskId: string) {\n return ApiAxios.get(`shared/tasks/${taskId}`).then((res) => res.data);\n }\n\n getSharedTaskWorkflow(taskId: string) {\n return ApiAxios.get(`shared/tasks/${taskId}/workflow`).then((res) => res.data);\n }\n\n updateSharedTask(taskId: string, payload: Partial, config?: ConfigSharedTask) {\n return ApiAxios.post(`shared/tasks/${taskId}`, payload, config).then((res) => res.data);\n }\n\n getDependencies(taskId: string) {\n return ApiAxios.get(`tasks/${taskId}/dependencies`).then((res) => res.data);\n }\n\n saveDependency(\n taskId: string,\n dependency: Omit,\n headers?: Record,\n ) {\n return ApiAxios.post>(`tasks/${taskId}/dependencies`, dependency, {\n headers,\n }).then((res) => res.data);\n }\n\n updateDependency(taskId: string, dependency: Partial, headers?: Record) {\n return ApiAxios.post>(\n `/tasks/${taskId}/dependencies/${dependency.id}`,\n dependency,\n {headers},\n ).then((res) => res.data);\n }\n\n deleteDependency(taskId: string, depId: string, headers?: Record) {\n return ApiAxios.post(`tasks/${taskId}/dependencies/${depId}/delete`, undefined, {headers});\n }\n\n addAssignee(taskId: string, assignee: TaskAssignees) {\n return ApiAxios.post(`tasks/${taskId}/assignees`, assignee).then((res) => res.data);\n }\n\n updateAssignee(taskId: string, assignee: TaskAssignees[]) {\n return ApiAxios.patch(`tasks/${taskId}/assignees`, assignee).then((res) => res.data);\n }\n\n addAssignees(taskId: string, assignees: TaskAssignees[]) {\n return ApiAxios.post(`tasks/${taskId}/assignees`, assignees, {baseURL: env.API_URL_V2}).then((res) => res.data);\n }\n\n // TODO: temporary hardcode app version\n getAppConstants() {\n return ApiAxios.get('appconstants', {params: {appVersion: '4.0.6'}}).then((res) => res.data);\n }\n\n indentOrOutdentTasks(projectId: string, taskIds: string[], action: 'indent' | 'outdent') {\n return ApiAxios.post<{affectedTaskIds: string[]}>(\n `projects/${projectId}/${action}_tasks`,\n {taskIds},\n {ignoreAffectedTaskIds: true},\n )\n .then((res) => {\n return res.data;\n })\n .catch((e) => {\n if (isAxiosError(e)) {\n if (e.response && e.response.data) {\n return Promise.reject(e.response.data);\n }\n throw e;\n }\n throw e;\n });\n }\n\n clone(payload: TaskCopyRequest, ignoreAffectedTaskIds = true) {\n return ApiAxios.post>(`/tasks/clone`, payload, {\n ignoreAffectedTaskIds,\n }).then((res) => {\n return res.data;\n });\n }\n\n createSnapshot(payload: CreateSnapshotPayload) {\n return ApiAxios.post(`projects/${payload.id}`, payload).then((res) => res.data);\n }\n\n getBaselineTasks(projectId: string, cutoff: string, taskIds?: string[]) {\n return ApiAxios.get(`projects/${projectId}/baseline`, {\n params: {cutoff: cutoff, taskids: taskIds ? taskIds.toString() : undefined},\n }).then((res) => decamelizeKeys(res.data) as ResponseBaselineTasks);\n }\n\n deleteSnapshot(projectId: string, payload: DeleteSnapshotPayload) {\n return ApiAxios.post<{tasks: BaselineTasks[]}>(`projects/${projectId}`, payload).then((res) => res.data);\n }\n\n addIssueDay(taskId: string, payload: AddIssueDayPayload) {\n return ApiAxios.post<{affectedTasks: TaskDetailsModelDTO[]; task: TaskDetailsModelDTO}>(\n `/tasks/${taskId}/issue_day`,\n payload,\n ).then((res) => res.data);\n }\n}\n\nexport default new TasksService();\n","export function calculateDynamicTimeout(\n fileSizeInBytes: number,\n operationType: 'normal' | 'extended' = 'normal',\n): number {\n const fileSizeInMB = fileSizeInBytes / (1024 * 1024);\n\n if (operationType === 'normal') {\n const baseTimeoutInSeconds = 10;\n const timeoutPerMB = 8;\n const calculatedTimeout = baseTimeoutInSeconds + fileSizeInMB * timeoutPerMB;\n return Math.min(Math.max(calculatedTimeout, 60), 300); // Between 1-5 minutes\n } else {\n const baseTimeoutInSeconds = 30;\n const timeoutPerMB = 25; // Significantly higher multiplier\n const calculatedTimeout = baseTimeoutInSeconds + fileSizeInMB * timeoutPerMB;\n return Math.min(Math.max(calculatedTimeout, 180), 1800); // Between 3-30 minutes\n }\n}\n","import * as Sentry from '@sentry/browser';\nimport {TFunction} from 'i18next';\nimport {toast} from 'react-toastify';\n\nimport {BadGatewayError, GatewayTimeoutError, HttpError} from 'services/Effect/errors';\n\ntype PollingTags = {\n context: string; // example: 'PDF Upload API error'\n projectId: string;\n fileName: string; // file.name || 'unknown file name'\n};\n\nexport function handlePollingErrors(error: unknown, t: TFunction, tags: PollingTags) {\n Sentry.captureException(error, {tags});\n if (error instanceof BadGatewayError || error instanceof GatewayTimeoutError) {\n toast.error(t('errors:polling.connection_issue', 'Connection issue detected. Please try again.'));\n } else if (error instanceof HttpError) {\n toast.error(t('errors:polling.server_error', 'Server error occurred'));\n } else {\n toast.error(t('errors:polling.upload_failed', 'File upload failed'));\n }\n return null;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable new-cap */\n/* eslint-disable @typescript-eslint/naming-convention */\nimport * as Sentry from '@sentry/browser';\nimport {User, UserCredential} from 'firebase/auth';\n\nimport {convertKeys} from 'shared/helpers/common';\nimport {isValidDate, toShortIso} from 'shared/helpers/dates';\nimport {CompanyModel} from 'shared/models/company';\nimport {CompanyWorkerSmall, Worker, WorkerCertificate, WorkerExperience} from 'shared/models/worker';\n\nimport ApiAxios from './axios';\n\nconst BASE_PATH = '/workers';\nconst SIGNUP_PATH = '/loginOrSignupWorker';\nconst CHECK_SIGNUP = '/checksignup';\nconst TRADE_OPTIONS = '/trades';\n\nexport type SupportedLoginTypes = 'phone' | 'password' | 'anonymous';\n\ntype TokenLoginResponse = {\n firebaseToken?: string;\n firebaseUid?: string;\n errors?: string[];\n authPrefill?: {\n email?: string;\n phoneNumber?: string;\n };\n};\n\ninterface LoginOrSignupWorkerParams {\n user: User;\n idToken?: string;\n loginType?: SupportedLoginTypes;\n phoneNumber?: string;\n inviteCode?: string;\n}\n\nfunction mapSignupFields({user, loginType, phoneNumber, inviteCode}: LoginOrSignupWorkerParams) {\n const signupFields = {\n api_key: process.env.REACT_APP_FIREBASE_API_KEY,\n refresh_token: user.refreshToken,\n firebase_uid: user.uid,\n last_login_at: new Date(user.metadata.lastSignInTime).getTime(),\n created_at: new Date(user.metadata.creationTime).getTime(),\n expiration_time: Date.parse(user.metadata.lastSignInTime) + 3600000,\n login_type: loginType === 'password' ? 'email' : loginType,\n source: 'web',\n };\n if (inviteCode) Object.assign(signupFields, {invite_code: inviteCode});\n if (loginType === 'phone') {\n Object.assign(signupFields, {phone_number: user.phoneNumber});\n }\n if (loginType === 'password') {\n Object.assign(signupFields, {email: user.email, phone_number: phoneNumber});\n }\n\n return signupFields;\n}\n\nfunction transformWorkerToCamel(workerObject: Worker) {\n let worker = {...workerObject};\n worker = convertKeys('camel', worker);\n return worker;\n}\n\nexport default {\n getWorkerById(id: string) {\n return ApiAxios.get(`${BASE_PATH}/${id}`)\n .then((res) => {\n return transformWorkerToCamel(res.data);\n })\n .catch((res) => Promise.reject(res));\n },\n\n loginOrSignupWorker({user, idToken, loginType = 'phone', phoneNumber, inviteCode}: LoginOrSignupWorkerParams) {\n return ApiAxios.post(\n SIGNUP_PATH,\n mapSignupFields({\n user,\n loginType,\n phoneNumber,\n inviteCode,\n }),\n {\n headers: {\n Authorization: idToken ? `Bearer ${idToken}` : undefined,\n },\n },\n )\n .then((res) => {\n return transformWorkerToCamel(res.data) as Worker;\n })\n .catch((res) => {\n Sentry.setExtra('user', {...user});\n Sentry.captureException(res);\n return Promise.reject(res);\n });\n },\n\n getTradeOptions(): Promise {\n return ApiAxios.get(TRADE_OPTIONS).then((res) => res.data);\n },\n\n loginOrSignupAnonymWorker(signup: UserCredential, idToken: string) {\n return ApiAxios.post(\n SIGNUP_PATH,\n mapSignupFields({\n user: signup.user,\n idToken: idToken,\n loginType: 'anonymous',\n }),\n )\n .then((res) => {\n const worker = res.data;\n return convertKeys('camel', worker);\n })\n .catch((res) => Promise.reject(res));\n },\n\n updateWorkerData(workerResume: Worker, id: string, token?: string) {\n const model = {...workerResume};\n if (model.certifications) {\n model.certifications = model.certifications.map((certificate: WorkerCertificate) => {\n return {\n ...certificate,\n issuedDate: isValidDate(certificate?.issuedDate) ? toShortIso(certificate?.issuedDate) : undefined,\n expirationDate: isValidDate(certificate?.expirationDate)\n ? toShortIso(certificate?.expirationDate)\n : undefined,\n } as any; // provide correct typing later\n });\n }\n if (model.workExperiences) {\n model.workExperiences = model.workExperiences.map((item: WorkerExperience) => {\n return {\n ...item,\n startDate: isValidDate(item.startDate) ? toShortIso(item.startDate) : undefined,\n endDate: isValidDate(item.endDate) ? toShortIso(item.endDate) : undefined,\n } as any; // provide correct typing later\n });\n }\n\n const converted = convertKeys('snake', model);\n\n return ApiAxios.post(`${BASE_PATH}/${id}`, convertKeys('snake', converted), {\n headers: {\n Authorization: token ? `Bearer ${token}` : undefined,\n },\n })\n .then((res) => {\n return transformWorkerToCamel(res.data);\n })\n .catch((errors) => {\n Sentry.setExtra('workerResume', {...workerResume, id});\n Sentry.captureException(errors);\n throw errors;\n });\n },\n\n uploadWorkerImage(id: string, workerAvatar: File) {\n const payload = new FormData();\n payload.append('profilepic', workerAvatar);\n return ApiAxios.post(`${BASE_PATH}/${id}/profilepic`, payload, {\n headers: {'Content-Type': 'multipart/form-data'},\n }).then((res) => res.data);\n },\n\n closeWorkerAccout(id: string) {\n return ApiAxios.delete(`${BASE_PATH}/${id}`).catch((error) => {\n console.error(error);\n return Promise.reject(error);\n });\n },\n\n checkSignUp(firebaseUID: string): Promise {\n return ApiAxios.get(`${CHECK_SIGNUP}/${firebaseUID}`).then((res) => res.data);\n },\n\n getWorkerCompanies(workerId: string) {\n return ApiAxios.get(`${BASE_PATH}/${workerId}/companies`).then((res) => res.data);\n },\n\n getWorkerCompanyWorkers(workerId: string) {\n return ApiAxios.get(`${BASE_PATH}/${workerId}/companyworkers`, {\n params: {\n smallObject: true,\n },\n }).then((res) => res.data);\n },\n\n loginWithToken(ownerId: string, token: string) {\n return ApiAxios.post(`/loginWithToken/${ownerId}/${token}`).then((res) => res.data);\n },\n\n getSharedLoginToken(workerId: string, taskId: string) {\n return ApiAxios.post<{token: string; url: string}>(`/workers/${workerId}/sharedlogin`, {\n scopes: ['specific_task'],\n taskIds: [taskId],\n }).then((res) => res.data);\n },\n\n updateWorker(worker: Partial) {\n return ApiAxios.post(`${BASE_PATH}/${worker.id}`, worker).then((res) => res.data);\n },\n};\n","import {AxiosResponse} from 'axios';\nimport {decamelize, decamelizeKeys} from 'humps';\n\nimport {prepareWorkerFiltersForUrl} from 'shared/helpers/worker';\nimport {ProjectModel} from 'shared/models/project';\nimport {TaskDetailsModelDTO} from 'shared/models/task/task';\nimport {CompanyInvite, CompanyWorker, CompanyWorkerRequestParams, WorkerTaskLoad} from 'shared/models/worker';\n\nimport ApiAxios from './axios';\n\ntype InviteQueryParams = {\n sendInviteSms: boolean;\n sendInviteEmail: boolean;\n inviteAsAdmin: boolean;\n inviteAsForeman: boolean;\n};\n\nconst defaultInviteQueryParams: InviteQueryParams = {\n sendInviteSms: true,\n sendInviteEmail: false,\n inviteAsAdmin: false,\n inviteAsForeman: false,\n};\n\nclass CompanyWorkersService {\n private getBasePath(companyId: string) {\n return `/companies/${companyId}/companyworkers`;\n }\n\n private getBasePathProjects(projectId: string) {\n return `/projects/${projectId}/companyworkers`;\n }\n\n getAll(\n companyId: string,\n {offset, limit, filterParams, sortOrder, sortField}: CompanyWorkerRequestParams,\n returnType?: RT,\n ): RT extends 'data' ? Promise : Promise>;\n getAll(\n path: string,\n {offset, limit, filterParams, sortOrder, sortField}: CompanyWorkerRequestParams,\n returnType: 'data' | 'response' = 'data',\n ) {\n const preparedSort = {};\n sortField ? Object.assign(preparedSort, {sortField: decamelize(sortField)}) : '';\n sortOrder ? Object.assign(preparedSort, {sortOrder}) : '';\n return ApiAxios.get(path, {\n params: {\n offset,\n limit,\n filterParams: JSON.stringify(decamelizeKeys(prepareWorkerFiltersForUrl(filterParams))),\n ...preparedSort,\n },\n }).then((res) => (returnType === 'data' ? res.data : res));\n }\n\n getWorkerTaskLoad(companyId: string, dateBegin: string | Date) {\n return ApiAxios.get(`/companies/${companyId}/worker_task_load`, {params: {dateBegin}}).then(\n (res) => res.data,\n );\n }\n\n getCompanyWorker(companyId: string, companyWorkerId: string) {\n return ApiAxios.get(`${this.getBasePath(companyId)}/${companyWorkerId}`).then((res) => res.data);\n }\n\n getAllCompaniesWorkers(\n companyId: string,\n params: CompanyWorkerRequestParams,\n type?: RT,\n ) {\n return this.getAll(this.getBasePath(companyId), params, type).then((res) => res);\n }\n\n getAllProjectWorkers(\n projectId: string,\n params: CompanyWorkerRequestParams,\n type?: RT,\n ) {\n return this.getAll(this.getBasePathProjects(projectId), params, type).then((res) => res);\n }\n\n updateCompanyWorker(worker: Partial) {\n return ApiAxios.post(`${this.getBasePath(worker.companyId)}/${worker.id}`, worker).then(\n (res) => res.data,\n );\n }\n\n updateInvitedCompanyWorker({\n companyId,\n companyWorkerId,\n sendInviteEmail,\n sendInviteSms,\n ...payload\n }: UpdateCompanyWorkerPayload) {\n return ApiAxios.post(\n `${this.getBasePath(companyId)}/${companyWorkerId}/worker`,\n payload,\n {params: {sendInviteEmail, sendInviteSms}},\n ).then((res) => res.data);\n }\n\n updateInvitedProjectWorker({\n projectId,\n companyWorkerId,\n sendInviteEmail,\n sendInviteSms,\n ...payload\n }: UpdateCompanyWorkerPayload) {\n return ApiAxios.post(\n `${this.getBasePathProjects(projectId)}/${companyWorkerId}/worker`,\n payload,\n {params: {sendInviteEmail, sendInviteSms}},\n ).then((res) => res.data);\n }\n\n getTasks(companyId: string, companyWorkerId: string) {\n return ApiAxios.get(`${this.getBasePath(companyId)}/${companyWorkerId}/tasks`).then(\n (res) => res.data,\n );\n }\n\n getProjects(companyId: string, companyWorkerId: string) {\n return ApiAxios.get(`${this.getBasePath(companyId)}/${companyWorkerId}/projects`).then(\n (res) => res.data,\n );\n }\n\n inviteToCompany(payload: InviteWorkerPayload, queryParams: InviteQueryParams = defaultInviteQueryParams) {\n return this.invite(payload, queryParams, `/companies/${payload.companyId}/invitecontact`);\n }\n\n inviteToProject(payload: InviteWorkerPayload, queryParams: InviteQueryParams = defaultInviteQueryParams) {\n return this.invite(payload, queryParams, `/projects/${payload.projectId}/invitecontact`);\n }\n\n invite(payload: InviteWorkerPayload, queryParams: InviteQueryParams = defaultInviteQueryParams, url: string) {\n return ApiAxios.post(url, payload, {\n params: queryParams,\n }).then((res) => res.data);\n }\n}\n\nexport default new CompanyWorkersService();\n\ntype InviteWorkerPayload = {\n companyId: string;\n workerName: string;\n workerPhoneNumber: string;\n workerEmail: string;\n trade: string;\n orgMappingIds: string[];\n} & CompanyInvite;\n\ntype UpdateCompanyWorkerPayload = {\n companyWorkerId: string;\n companyId?: string;\n projectId?: string;\n fullName: string;\n trade: string;\n mobileNumber: string;\n email: string;\n orgMappingIds: string[];\n sendInviteEmail?: boolean;\n sendInviteSms?: boolean;\n};\nexport type UpdateCompanyWorkerResponse = {\n fullName: string;\n mobileNumber: string;\n trade: string;\n id: string;\n};\n","/*! modernizr 3.6.0 (Custom Build) | MIT *\n * https://modernizr.com/download/?-touchevents-setclasses !*/\n!function(e,n,t){function o(e,n){return typeof e===n}function s(){var e,n,t,s,a,i,r;for(var l in c)if(c.hasOwnProperty(l)){if(e=[],n=c[l],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t {\n await ui.waitForInitialization();\n // Grumble grumble Foxit index.d.ts sketchy.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const i18n = ui.i18n as any as i18next.i18n;\n Object.keys(translationMap).forEach((lang) => {\n i18n.addResourceBundle(lang, 'ui_', translationMap[lang], true, true);\n });\n const root = await ui.getRootComponent();\n root.localize();\n ui.redraw();\n};\n","import {\n DAILIES_TASK_DEFAULT_FILTER_PARAMS,\n GANTT_TASK_DEFAULT_FILTER_PARAMS,\n GANTT_VISUAL_DEFAULT_FILTER_PARAMS,\n ISSUES_TASK_DEFAULT_FILTER_PARAMS,\n LOOKAHEAD_TASK_DEFAULT_FILTER_PARAMS,\n TASK_DEFAULT_FILTER_PARAMS,\n} from 'modules/Tasks/components/Filters/utils/constants';\nimport {FiltersState} from 'modules/Tasks/components/Filters/utils/types';\nimport {TasksViewMode} from 'shared/constants/common';\nimport {deleteNullOrEmptyFields} from 'shared/helpers/common';\nimport {isSame} from 'shared/helpers/dates';\nimport {TaskStates} from 'shared/models/task/const';\nimport {TaskFilterQuery} from 'shared/models/task/filter';\n\nfunction getFilterDirtyFields(queryParams: Partial, defaultParams: T) {\n return (Object.keys(defaultParams) as (keyof T)[]).filter((param) => {\n if (queryParams?.[param] === undefined) {\n return false;\n }\n\n return queryParams[param] instanceof Date\n ? !isSame(defaultParams[param] as Date, queryParams[param] as Date)\n : param in queryParams && queryParams[param] !== defaultParams[param];\n });\n}\n\nexport function isFilterFieldsDirty({\n queryParams,\n fields,\n exclude,\n strict,\n exact,\n initialValues,\n}: {\n queryParams: Partial;\n fields?: (keyof T)[];\n exclude?: (keyof T)[];\n strict?: boolean; // if true all fields should be dirty\n exact?: boolean; // if true only specified fields should be dirty\n initialValues: T;\n}) {\n const filterDirtyFields = getFilterDirtyFields(queryParams, initialValues);\n const targetDirtyFields = filterDirtyFields.filter(\n (field) => (!fields || fields.includes(field)) && (!exclude || !exclude.includes(field)),\n );\n // eslint-disable-next-line no-console\n const isStrict = fields?.length === targetDirtyFields?.length;\n if (exact && fields) {\n return filterDirtyFields.length === fields.length && isStrict;\n }\n if (strict) {\n return isStrict;\n }\n return !!targetDirtyFields.length;\n}\n\nexport function getFilterNumberFilledFields(queryParams: Partial, viewMode: TasksViewMode) {\n const dirtyFields = getFilterDirtyFields(queryParams, getDefaultFilterParamsByViewMode(viewMode));\n let count = dirtyFields.length;\n // exclude pair filters\n if (dirtyFields.filter((key) => key.startsWith('schedStart')).length === 2) {\n count--;\n }\n if (dirtyFields.filter((key) => key.startsWith('schedEnd')).length === 2) {\n count--;\n }\n if (dirtyFields.includes('schedWeeks') || dirtyFields.includes('schedEndFirst')) {\n count--;\n }\n\n return count;\n}\n\nexport function getDefaultFilterParamsByViewMode(viewMode: TasksViewMode) {\n switch (viewMode) {\n case TasksViewMode.lookahead:\n return LOOKAHEAD_TASK_DEFAULT_FILTER_PARAMS;\n case TasksViewMode.gantt:\n return GANTT_TASK_DEFAULT_FILTER_PARAMS;\n case TasksViewMode.ganttVisual:\n return GANTT_VISUAL_DEFAULT_FILTER_PARAMS;\n case TasksViewMode.issues:\n return ISSUES_TASK_DEFAULT_FILTER_PARAMS;\n case TasksViewMode.dailies:\n return DAILIES_TASK_DEFAULT_FILTER_PARAMS;\n default:\n return TASK_DEFAULT_FILTER_PARAMS;\n }\n}\n\nexport function getInitialValues(initialValues?: Partial): FiltersState {\n const incoming: Partial = initialValues ? deleteNullOrEmptyFields({...initialValues}) : {};\n return Object.values(TasksViewMode).reduce(\n (acc, viewMode) => ({\n ...acc,\n [viewMode]: {\n active: {...getDefaultFilterParamsByViewMode(viewMode), ...incoming, view: viewMode},\n deleted: {\n ...getDefaultFilterParamsByViewMode(viewMode),\n ...incoming,\n view: viewMode,\n state: TaskStates.deleted,\n },\n },\n }),\n {} as FiltersState,\n );\n}\n","import {GanttTaskCustomField} from 'shared/models/task/task';\n\nimport {GanttTask} from '../../types';\n\nexport function updateTaskCustomFieldValue(task: GanttTask, {field, value}: {field: string; value: string}): boolean {\n const taskCustomFields = task.custom_fields;\n const fieldIndex = taskCustomFields?.findIndex(({internal_field_name}) => internal_field_name === field) ?? -1;\n const oldFieldValue = fieldIndex !== -1 ? taskCustomFields[fieldIndex].value : null;\n\n if (oldFieldValue !== value) {\n const updatedModel = {internal_field_name: field, value: value};\n\n // for showing the new value after exiting from inline editor\n // before receiving a response from the API (task update)\n if (fieldIndex !== -1) {\n task.custom_fields[fieldIndex].value = value;\n } else {\n task.custom_fields.push(updatedModel);\n }\n\n const prev = (task.lastChangedFields?.customFields?.newValue as GanttTaskCustomField[]) ?? [];\n task.lastChangedFields.customFields = {\n newValue: prev.concat([updatedModel]),\n oldValue: taskCustomFields,\n };\n return true;\n }\n return false;\n}\n","import {TFunction} from 'i18next';\n\nimport {TaskObjectType} from 'shared/models/task/const';\nimport {TaskStatusType} from 'shared/models/task/taskStatus';\n\nexport enum GANTT_COLUMNS_NAMES {\n activityNames = 'activityNames',\n actualEnd = 'actual_end',\n actualStart = 'actual_start',\n assignmentCount = 'assignment_count',\n averageLaborAbbr = 'average_labor_abbr',\n baselineEnd = 'baseline_end',\n baselineStart = 'baseline_start',\n checkbox = 'custom_checkbox',\n comments = 'comments',\n costCode = 'cost_code',\n costImpact = 'costImpact',\n crew = 'crew',\n csiCode = 'csi_code',\n customAdd = 'custom_add',\n customCode = 'custom_code',\n customFields = 'customFields',\n description = 'description',\n doneDate = 'doneDate',\n duration = 'taskDuration',\n endDate = 'end_date',\n estimatedLaborAbbr = 'estimated_labor_abbr',\n estLaborHours = 'est_labor_hours',\n icons = 'icons',\n inprogressDate = 'inprogressDate',\n issueType = 'issue_type',\n location = 'location',\n name = 'name',\n ownership = 'culpable_org_id',\n phaseCode = 'phase_code',\n predecessor = 'predecessor',\n progress = 'progress',\n punchList = 'punchList',\n resolvingCompany = 'responsible_org_id',\n responsible = 'responsible',\n rownumber = 'rownumber',\n severity = 'impact',\n startDate = 'start_date',\n subcontractor = 'responsible_org_id',\n targetAmount = 'completion_target',\n targetUom = 'completion_unit',\n taskStatus = 'task_status',\n trackNumber = 'cost_tracking_number',\n type = 'taskType',\n uniqueId = 'unique_id',\n variance = 'variance',\n zone = 'zone',\n}\n\nexport enum GANTT_COLUMNS_NAMES_EXTRA {\n baselineStart = 'baseline_start',\n baselineEnd = 'baseline_end',\n variance = 'variance',\n}\n\nexport enum EditActionTypes {\n date = 'date',\n status = 'status',\n subcontractor = 'subcontractor',\n taskType = 'taskType',\n predecessor = 'predecessor',\n}\n\nexport const SAFE_STATUSES: TaskStatusType[] = [\n TaskStatusType.approved,\n TaskStatusType.done,\n TaskStatusType.verified,\n TaskStatusType.closed,\n];\n\nexport const BASELINE_EXTRA_COLUMNS_NAMES = [\n GANTT_COLUMNS_NAMES_EXTRA.baselineStart,\n GANTT_COLUMNS_NAMES_EXTRA.baselineEnd,\n GANTT_COLUMNS_NAMES_EXTRA.variance,\n];\n\nexport const getGanttColumnsLabels = (\n t: TFunction,\n): {\n [key in Exclude<\n GANTT_COLUMNS_NAMES | GANTT_COLUMNS_NAMES_EXTRA,\n GANTT_COLUMNS_NAMES.checkbox | GANTT_COLUMNS_NAMES.customAdd | GANTT_COLUMNS_NAMES.customFields\n >]: string;\n} => {\n return {\n [GANTT_COLUMNS_NAMES.activityNames]: t('gantt:columns.activity_names'),\n [GANTT_COLUMNS_NAMES.uniqueId]: t('gantt:columns.unique_id', 'Unique ID'),\n [GANTT_COLUMNS_NAMES.rownumber]: t('gantt:columns.row_number', '#'),\n [GANTT_COLUMNS_NAMES.icons]: t('gantt:columns.icons', 'Icons'),\n [GANTT_COLUMNS_NAMES.assignmentCount]: t('gantt:columns.assignees', 'Watchers'),\n [GANTT_COLUMNS_NAMES.punchList]: t('gantt:columns.punch_list', 'Punch list'),\n [GANTT_COLUMNS_NAMES.startDate]: t('gantt:columns.start', 'Start'),\n [GANTT_COLUMNS_NAMES.endDate]: t('gantt:columns.end', 'End'),\n [GANTT_COLUMNS_NAMES.taskStatus]: t('gantt:columns.status', 'Status'),\n [GANTT_COLUMNS_NAMES.name]: t('gantt:columns.gantt.activity', 'Activity'),\n [GANTT_COLUMNS_NAMES.subcontractor]: t('gantt:columns.gantt.subcontractor', 'Company'),\n [GANTT_COLUMNS_NAMES.description]: t('gantt:columns.description', 'Notes'),\n [GANTT_COLUMNS_NAMES.location]: t('gantt:columns.location', 'Location'),\n [GANTT_COLUMNS_NAMES.responsible]: t('gantt:columns.responsible', 'Responsible'),\n [GANTT_COLUMNS_NAMES.type]: t('gantt:columns.type', 'Type'),\n [GANTT_COLUMNS_NAMES.actualStart]: t('gantt:columns.actual_start', 'Actual Start'),\n [GANTT_COLUMNS_NAMES.actualEnd]: t('gantt:columns.actual_end', 'Actual End'),\n [GANTT_COLUMNS_NAMES.duration]: t('gantt:columns.duration', 'Duration'),\n [GANTT_COLUMNS_NAMES.predecessor]: t('gantt:columns.predecessor', 'Predecessor'),\n [GANTT_COLUMNS_NAMES_EXTRA.baselineStart]: t('gantt:columns.baseline_start', 'Baseline Start'),\n [GANTT_COLUMNS_NAMES_EXTRA.baselineEnd]: t('gantt:columns.baseline_end', 'Baseline End'),\n [GANTT_COLUMNS_NAMES_EXTRA.variance]: t('gantt:columns.variance', 'Variance'),\n [GANTT_COLUMNS_NAMES.comments]: t('gantt:columns.comments'),\n [GANTT_COLUMNS_NAMES.estimatedLaborAbbr]: t('gantt:columns.estimated_labor_abbr', 'Estimated Labor'),\n [GANTT_COLUMNS_NAMES.averageLaborAbbr]: t('gantt:columns.average_labor_abbr', 'Average Labor'),\n [GANTT_COLUMNS_NAMES.progress]: t('gantt:columns.progress', 'Progress'),\n [GANTT_COLUMNS_NAMES.csiCode]: t('gantt:columns.csi_code', 'CSI Code'),\n [GANTT_COLUMNS_NAMES.phaseCode]: t('gantt:columns.phase_code', 'Phase Code'),\n [GANTT_COLUMNS_NAMES.costCode]: t('gantt:columns.cost_code', 'Cost Code'),\n [GANTT_COLUMNS_NAMES.customCode]: t('gantt:columns.custom_code', 'Custom Code'),\n [GANTT_COLUMNS_NAMES.ownership]: t('gantt:columns.ownership', 'Liable Company'),\n [GANTT_COLUMNS_NAMES.severity]: t('gantt:columns.impact', 'Time Impact'),\n [GANTT_COLUMNS_NAMES.issueType]: t('gantt:columns.issue_type', 'Type'),\n [GANTT_COLUMNS_NAMES.trackNumber]: t('gantt:columns.cost_tracking_number', 'Cost Track Number'),\n [GANTT_COLUMNS_NAMES.costImpact]: t('gantt:columns.cost_impact', 'Cost Impact'),\n [GANTT_COLUMNS_NAMES.inprogressDate]: t('gantt:columns.in_progress_date', 'In-progress Date'),\n [GANTT_COLUMNS_NAMES.doneDate]: t('gantt:columns.done_date', 'Done Date'),\n [GANTT_COLUMNS_NAMES.estLaborHours]: t('gantt:columns.estimated_labor_hours'),\n [GANTT_COLUMNS_NAMES.zone]: t('gantt:columns.zone'),\n [GANTT_COLUMNS_NAMES.crew]: t('gantt:columns.crew'),\n [GANTT_COLUMNS_NAMES.targetAmount]: t('gantt:columns.target_amount'),\n [GANTT_COLUMNS_NAMES.targetUom]: t('gantt:columns.target_uom'),\n };\n};\n\nexport const SELECTED_GANTT_COLUMNS = 'selectedGanttColumns_v3';\nexport const GANTT_COLUMNS_SETTINGS = 'ganttColumnsSettings';\nexport const getActivityName = (t: TFunction) => t('gantt:activity.name', 'New Activity');\n\nexport enum DataProcessorAction {\n Inserted = 'inserted',\n Updated = 'updated',\n Deleted = 'deleted',\n Invalid = 'invalid',\n Error = 'error',\n}\n\nexport const NOT_EDITABLE_COLUMNS: {[key in TaskObjectType]?: GANTT_COLUMNS_NAMES[]} = {\n [TaskObjectType.summary]: [\n GANTT_COLUMNS_NAMES.actualStart,\n GANTT_COLUMNS_NAMES.actualEnd,\n GANTT_COLUMNS_NAMES.startDate,\n GANTT_COLUMNS_NAMES.endDate,\n GANTT_COLUMNS_NAMES.duration,\n GANTT_COLUMNS_NAMES.predecessor,\n GANTT_COLUMNS_NAMES.responsible,\n GANTT_COLUMNS_NAMES.subcontractor,\n GANTT_COLUMNS_NAMES.location,\n GANTT_COLUMNS_NAMES.type,\n GANTT_COLUMNS_NAMES.taskStatus,\n GANTT_COLUMNS_NAMES.inprogressDate,\n GANTT_COLUMNS_NAMES.doneDate,\n GANTT_COLUMNS_NAMES.estimatedLaborAbbr,\n GANTT_COLUMNS_NAMES.averageLaborAbbr,\n GANTT_COLUMNS_NAMES.progress,\n GANTT_COLUMNS_NAMES.comments,\n GANTT_COLUMNS_NAMES.zone,\n GANTT_COLUMNS_NAMES.crew,\n ],\n [TaskObjectType.milestone]: [GANTT_COLUMNS_NAMES.location, GANTT_COLUMNS_NAMES.subcontractor],\n};\n\nexport const NON_HIDING_COLUMNS = [\n GANTT_COLUMNS_NAMES.customAdd,\n GANTT_COLUMNS_NAMES.checkbox,\n GANTT_COLUMNS_NAMES.name,\n GANTT_COLUMNS_NAMES.rownumber,\n];\n\nexport const GANTT_LOCALE_MAP = {\n ja: 'jp',\n es: 'es',\n en: 'en',\n pt: 'pt',\n};\nexport const PERSONAL_PROJECT_NAME = 'Personal Project';\n\nexport enum GanttZoomLevels {\n DAY = 'day',\n WEEK = 'week',\n MONTH = 'month',\n QUARTER = 'quarter',\n YEAR = 'year',\n}\n","import {gantt, GanttStatic} from 'dhtmlx-gantt';\n\nimport {GanttApiResponse, GanttTask} from 'modules/Tasks/components/Gantt/types';\nimport {\n deselectAll,\n isPlaceholderTask,\n KeyNavigationEventName,\n OSKMap,\n prepareTaskGanttChangedFields,\n traverseTasks,\n} from 'modules/Tasks/components/Gantt/utils/gantt';\nimport {useTasksActions} from 'modules/Tasks/hooks/useTasksActions';\nimport {safeParseJSON} from 'modules/Tasks/utils/utils';\nimport {safeFormatDate, safeParseDate, subtract, toShortIso} from 'shared/helpers/dates';\nimport {getProjectCustomField} from 'shared/helpers/project';\nimport {parseUrlQuery} from 'shared/helpers/queryParams';\nimport {GanttTaskColors} from 'shared/helpers/task';\nimport {\n getPunchListCountModel,\n prepareAssignees,\n prepareDateForGantt,\n prepareEndDateForGantt,\n} from 'shared/mapping/task';\nimport {ProjectCustomFieldType, ProjectModel, WorkDaysEnum} from 'shared/models/project';\nimport {TaskObjectType, TaskObjectSubType} from 'shared/models/task/const';\nimport {\n TaskModelRawDTO,\n TaskDetailsModelDTO,\n TaskGanttModelDTO,\n TaskGanttModel,\n TaskHistoryRawType,\n FeedbackProjectModelDTO,\n} from 'shared/models/task/task';\nimport {TaskStatusType} from 'shared/models/task/taskStatus';\n\nimport {GANTT_COLUMNS_NAMES, NON_HIDING_COLUMNS} from './constants';\nimport {EventStore} from './eventStore';\n\ninterface TransformDataConfig {\n data: GanttApiResponse;\n projectId: string;\n colors?: GanttTaskColors;\n flatList?: boolean;\n inclusiveEndDate?: boolean;\n}\n\ntype TransformLookaheadDataConfig = Omit & {\n tasks: TaskModelRawDTO[];\n oskMap?: OSKMap;\n collapsed?: Set;\n};\n\nexport type GetOneDayFilterOptions = () => {filterDate: Date | null; enableOneDayFilter: boolean};\n\nexport const getOneDayFilterOptions: GetOneDayFilterOptions = () => {\n const {schedEndFirst, schedWeeks} = parseUrlQuery<{schedEndFirst?: Date; schedWeeks?: number}>(\n window.location.search,\n {\n schedEndFirst: 'date',\n schedWeeks: 'number',\n },\n );\n const enableOneDayFilter = schedEndFirst && schedWeeks === 0;\n\n return {filterDate: schedEndFirst, enableOneDayFilter};\n};\n\nexport const setProjectCalendarExceptions = (gantt: GanttStatic, project: ProjectModel) => {\n const calendar = gantt.getCalendar(project.id);\n const ganttDateConverter = gantt.date.str_to_date('%Y-%m-%d');\n project.calendar.exceptions.forEach((ex) => {\n calendar.setWorkTime({\n date: ganttDateConverter(ex.date),\n hours: ex.working ? [`${project.defaultTaskStart}-${project.defaultTaskEnd}`] : false,\n });\n });\n};\n\n// Gantt library return any type\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const setHolidays = (projectWorkDays: WorkDaysEnum[], calendar: any) => {\n const workDays = {\n sunday: 0,\n monday: 1,\n tuesday: 2,\n wednesday: 3,\n thursday: 4,\n friday: 5,\n saturday: 6,\n };\n projectWorkDays.forEach((day) => {\n if (workDays[day]) delete workDays[day];\n });\n for (const key of Object.keys(workDays)) {\n calendar.setWorkTime({day: workDays[key], hours: false});\n }\n};\n\nexport const transformLookaheadData = ({\n tasks,\n projectId,\n flatList,\n oskMap: initialOskMap,\n collapsed,\n}: TransformLookaheadDataConfig) => {\n const oskMap = traverseTasks(tasks, initialOskMap);\n\n return {\n tasks: tasks.map((taskModel: TaskModelRawDTO & {row_height?: number}) => {\n const children = oskMap.get(taskModel.outline_sort_key)?.children_count;\n const parentOSK = oskMap.get(taskModel.outline_sort_key)?.parent;\n const parent = parentOSK ? oskMap.get(parentOSK).id : '0';\n const model = mapTaskProjectionToTaskGanttModel({\n taskModel,\n projectId,\n flatList: flatList,\n inclusiveEndDate: true,\n });\n model.has_child = children;\n model.$has_child = Boolean(children);\n model.parent = parent;\n model.open = !collapsed?.has(taskModel.id);\n model.isPending = false;\n return model;\n }),\n links: [],\n };\n};\n\nexport const transformIssuesData = ({\n tasks,\n projectId,\n flatList,\n feedbackMap = new Map(),\n}: TransformLookaheadDataConfig & {\n feedbackMap: Map;\n}) => {\n return {\n tasks: tasks.map((taskModel: TaskModelRawDTO & {row_height?: number}) => {\n const model = mapTaskProjectionToTaskGanttModel({\n taskModel,\n projectId,\n flatList: flatList,\n inclusiveEndDate: true,\n });\n model.unscheduled = true;\n // Add additional safety check when accessing the map\n const feedback = feedbackMap.get(taskModel.id);\n // Inject comment count for display in gantt column\n model.comment_count = feedback ? feedback.length : 0;\n return model;\n }),\n links: [],\n };\n};\n\n/*\n * We transform dates to inclusive format after get them from server,\n * and convert them back to exclusive when save to server\n * be careful with this converting\n * */\nexport const transformData = ({data, projectId, flatList, inclusiveEndDate}: TransformDataConfig) => {\n return {\n tasks: data.tasks.map((taskModel) =>\n mapGanttProjectionToTaskGanttModel({\n taskModel: taskModel,\n projectId: projectId,\n flatList: flatList,\n inclusiveEndDate: inclusiveEndDate,\n }),\n ),\n links: data.links.map((link) => Object.assign({}, link, {type: gantt.config.links[link.type]})),\n };\n};\n\nexport const prepareTaskChangedFieldsForUpdate = (task: GanttTask): Partial => {\n const lastChangedFields = prepareTaskGanttChangedFields(task);\n const fieldsToSave = {} as Partial;\n const prepareDate = (date: string) => safeParseDate(date);\n const prepareInclusiveDate = (date: string) => subtract(prepareDate(date), 1).toDate();\n if (lastChangedFields?.actualStart) {\n fieldsToSave.actualStart = toShortIso(prepareDate(lastChangedFields?.actualStart as string));\n }\n\n if (lastChangedFields.hasOwnProperty('estLaborHours')) {\n if (lastChangedFields.estLaborHours === '' || lastChangedFields.estLaborHours === undefined) {\n fieldsToSave.estLaborHours = null;\n } else {\n fieldsToSave.estLaborHours = parseFloat(lastChangedFields.estLaborHours as string);\n }\n }\n\n if (lastChangedFields?.estimatedLaborAbbr) {\n fieldsToSave.projectedLabor = lastChangedFields.estimatedLaborAbbr as string;\n }\n\n if (lastChangedFields?.actualEnd) {\n fieldsToSave.actualEnd = toShortIso(prepareInclusiveDate(lastChangedFields?.actualEnd as string));\n }\n // sent startDate + duration if user changing either start_date or duration\n // otherwise if user changing end data sent pair of start and end dates\n if (lastChangedFields?.taskDuration || lastChangedFields?.startDate) {\n fieldsToSave.duration = Math.abs(parseInt(String(lastChangedFields.taskDuration || task.taskDuration)));\n delete lastChangedFields['taskDuration'];\n fieldsToSave.startDate = toShortIso(\n lastChangedFields?.startDate ? prepareDate(lastChangedFields?.startDate as string) : task.start_date,\n );\n } else if (lastChangedFields?.endDate) {\n fieldsToSave.endDate = toShortIso(prepareInclusiveDate(lastChangedFields.endDate as string));\n fieldsToSave.startDate = toShortIso(\n lastChangedFields?.startDate ? prepareDate(lastChangedFields?.startDate as string) : task.start_date,\n );\n }\n if (task.object_type === TaskObjectType.milestone && (lastChangedFields?.startDate || lastChangedFields?.endDate)) {\n const date = lastChangedFields?.startDate ? lastChangedFields?.startDate : lastChangedFields?.endDate;\n fieldsToSave.startDate = toShortIso(prepareInclusiveDate(date as string));\n fieldsToSave.endDate = undefined;\n fieldsToSave.duration = 0;\n }\n if ('taskType' in lastChangedFields) {\n fieldsToSave.type = lastChangedFields.taskType as string;\n delete lastChangedFields.taskType;\n }\n if ('costImpact' in lastChangedFields) {\n fieldsToSave.costImpact = lastChangedFields.costImpact as boolean;\n delete lastChangedFields.costImpact;\n }\n if ('location' in lastChangedFields && task.location === null) {\n fieldsToSave.location = '';\n delete lastChangedFields.location;\n }\n\n return {id: String(task.id), projectId: task.projectId, ...lastChangedFields, ...fieldsToSave};\n};\n\nexport const prepareTaskForCreate = (task: GanttTask): Partial => {\n const model: Partial & {parentId?: string} = {\n id: task.id,\n uniqueId: task?.unique_id,\n name: task?.name,\n projectId: task?.projectId,\n status: task?.taskStatus as TaskStatusType,\n completionAmount: task.completion_amount || '',\n completionTarget: task.completion_target,\n completionUnit: task.completion_unit,\n objectType: task.object_type,\n responsible: prepareAssignees(task.responsible),\n responsibleOrgId: task.responsible_org_id,\n type: task.taskType,\n location: task.location || '',\n startDate: toShortIso(task.start_date),\n actualEndDate: task.actual_start && toShortIso(task.actual_start),\n actualEnd: task.actual_end && toShortIso(subtract(task.end_date, 1)),\n };\n const hasDuration = Math.abs(parseInt(String(task?.taskDuration))) >= 0;\n const duration = Math.abs(parseInt(String(task?.taskDuration))) || undefined;\n if (hasDuration) {\n model.duration = duration;\n if (duration == 0) {\n model.startDate = toShortIso(task.end_date);\n }\n } else {\n model.endDate = toShortIso(subtract(task.end_date, 1));\n }\n\n if (task?.parent !== gantt.config.root_id) {\n model.parentId = String(task?.parent);\n }\n if (task?.lastChangedFields && Object.keys(task.lastChangedFields).length) {\n Object.assign(model, {...prepareTaskChangedFieldsForUpdate(task)});\n }\n if (task?.relativeToId) {\n Object.assign(model, {relativeToId: task.relativeToId, relativeDir: task.relativeDir});\n }\n return model;\n};\n\ninterface MapToTaskGanttModelParams {\n taskModel: T;\n projectId: string;\n flatList?: boolean;\n inclusiveEndDate?: boolean;\n}\n\nfunction mapGanttProjectionToTaskGanttModel({\n taskModel,\n flatList,\n inclusiveEndDate = true,\n}: MapToTaskGanttModelParams) {\n const prepareEndDateFn = inclusiveEndDate ? prepareEndDateForGantt : prepareDateForGantt;\n const result: TaskGanttModel = {\n ...taskModel,\n // converted to boolean after gantt v9 update\n $has_child: Boolean(taskModel.has_child),\n // converted to boolean after gantt v9 update\n open: Boolean(taskModel.open),\n activities: taskModel.activities,\n estimated_labor: taskModel.estimatedLabor,\n punchlist: taskModel.punchlist,\n issue_task_ids: taskModel.issue_task_ids,\n assignment_count: taskModel.assignment_count,\n projectId: taskModel.project_id,\n parent: taskModel.parent || (gantt.config.root_id as string),\n meta: {loading: false},\n responsible: taskModel.responsible,\n start_date: prepareDateForGantt(taskModel.start_date),\n end_date: prepareEndDateFn(taskModel.end_date),\n actual_start: prepareDateForGantt(taskModel.actual_start),\n actual_end: prepareEndDateFn(taskModel.actual_end),\n date_list: taskModel.date_list,\n taskStatus: taskModel.status,\n taskDuration: taskModel.duration,\n punchList: getPunchListCountModel(taskModel.punchlist),\n timeRemoved: taskModel.time_removed,\n lastChangedFields: {},\n feedback_by_date: taskModel.feedback_by_date,\n feedback_rollup: taskModel.feedback_rollup,\n est_labor_hours: taskModel.est_labor_hours,\n // injected to keep a tally of non-system generated comments\n comment_count: taskModel.comment_count,\n };\n\n if (flatList) {\n result.parent = gantt.config.root_id as string;\n }\n\n return result;\n}\n\nfunction getStatusDate(history: TaskHistoryRawType[], status: TaskStatusType): string | undefined {\n return history.find((statusChange) => statusChange.status === status)?.time_updated;\n}\n\nexport function mapTaskProjectionToTaskGanttModel({\n taskModel,\n flatList,\n inclusiveEndDate = true,\n}: MapToTaskGanttModelParams) {\n const prepareEndDateFn = inclusiveEndDate ? prepareEndDateForGantt : prepareDateForGantt;\n const startDate = prepareDateForGantt(taskModel.start_date);\n const endDate = prepareEndDateFn(taskModel.end_date);\n const result: TaskGanttModel = {\n ...taskModel,\n estimated_labor: taskModel.projected_labor,\n projectId: taskModel.project_id,\n parent: gantt.config.root_id as string,\n meta: {loading: false},\n issue_task_ids: taskModel.issue_task_ids,\n status_issue_task_ids_pairs: taskModel.status_issue_task_ids_pairs,\n actual_start: prepareDateForGantt(taskModel.actual_start),\n actual_end: prepareEndDateFn(taskModel.actual_end),\n start_date: startDate,\n start_date_real: startDate,\n end_date: endDate,\n end_date_real: endDate,\n date_list: taskModel.date_list,\n task_ids: taskModel.task_ids,\n taskStatus: taskModel.status,\n taskDuration: taskModel.duration,\n taskType: taskModel.type,\n punchList: getPunchListCountModel(taskModel.punchlist),\n timeRemoved: taskModel.time_removed,\n type: taskModel.object_type === TaskObjectType.milestone ? taskModel.object_type : undefined,\n lastChangedFields: {},\n has_child: 0, // need to be calculated\n $has_child: false, // need to be calculated\n subtask_count: 0, // need to be calculated\n comment_count: taskModel.comment_count,\n };\n\n if (taskModel.status_history) {\n // status history is provided newest to oldest, but looking for first in-progress\n result.inprogressDate = prepareDateForGantt(\n getStatusDate(taskModel.status_history.slice().reverse(), TaskStatusType.inProgress),\n );\n result.doneDate = prepareDateForGantt(getStatusDate(taskModel.status_history, TaskStatusType.done));\n }\n\n if (taskModel.object_type === TaskObjectType.milestone && taskModel.object_subtype === TaskObjectSubType.end) {\n result.start_date = result.end_date;\n }\n\n if (flatList) {\n result.parent = gantt.config.root_id as string;\n }\n\n return result;\n}\nexport function registerCustomKeyNavMapping(\n eventStore: EventStore,\n gantt: GanttStatic,\n tasksActions: ReturnType,\n) {\n const mapping = {\n init: function (inlineEditors) {\n eventStore.attach('onBeforeFocus', function (node) {\n if (\n document.activeElement &&\n ['input', 'textarea'].includes(document.activeElement.nodeName.toLowerCase()) &&\n !document.activeElement.closest('.gantt-container')\n ) {\n return false;\n }\n const activeCell = inlineEditors.locateCell(node);\n if (activeCell) {\n // TODO: need to investigate why inline editor closes after changing a row\n if (inlineEditors.isVisible()) {\n return false;\n }\n }\n\n return true;\n });\n eventStore.attach('onFocus', function (node) {\n const activeCell = inlineEditors.locateCell(node);\n const state = inlineEditors.getState();\n\n if (activeCell && !(activeCell.id == state.id && activeCell.columnName == state.columnName)) {\n if (inlineEditors.isVisible()) {\n inlineEditors.save();\n return false;\n }\n }\n\n return true;\n });\n eventStore.attach('onKeyDown', function (_command, e: KeyboardEvent) {\n if (e.target instanceof Element && !e.target.closest('#foxit-container')) {\n const activeCell = inlineEditors.locateCell(e.target);\n const hasEditor = activeCell ? inlineEditors.getEditorConfig(activeCell.columnName) : false;\n const state = inlineEditors.getState();\n const keyboard = gantt.constants.KEY_CODES;\n const keyCode = e.keyCode;\n let preventKeyNav = false;\n\n if (e.target instanceof Element && !e.target.closest('#foxit-container')) {\n const keyCode = e.code;\n\n const CustomKeyNavMapping = {\n BracketLeft: 'BracketLeft',\n BracketRight: 'BracketRight',\n } as const;\n\n if (keyCode === CustomKeyNavMapping.BracketLeft && e.ctrlKey) {\n tasksActions.outdentSelectedTasks();\n e.preventDefault();\n e.stopPropagation();\n preventKeyNav = true;\n return;\n } else if (keyCode === CustomKeyNavMapping.BracketRight && e.ctrlKey) {\n tasksActions.indentSelectedTasks();\n e.preventDefault();\n e.stopPropagation();\n preventKeyNav = true;\n return;\n }\n }\n\n switch (keyCode) {\n case keyboard.ENTER:\n if (inlineEditors.isVisible()) {\n const nextTaskId = gantt.getNext(state.id);\n inlineEditors.save();\n if (nextTaskId) {\n const nextTask = gantt.getTask(nextTaskId);\n inlineEditors.startEdit(\n nextTaskId,\n isPlaceholderTask(gantt, nextTask) ? GANTT_COLUMNS_NAMES.name : state.columnName,\n );\n } else {\n const placeholderTask = gantt.getTaskBy((task) => isPlaceholderTask(gantt, task))?.[0];\n if (placeholderTask) {\n inlineEditors.startEdit(placeholderTask.id, GANTT_COLUMNS_NAMES.name);\n }\n }\n e.preventDefault();\n e.stopPropagation();\n preventKeyNav = true;\n } else if (hasEditor && !(e.ctrlKey || e.metaKey || e.shiftKey)) {\n inlineEditors.startEdit(activeCell.id, activeCell.columnName);\n e.preventDefault();\n preventKeyNav = true;\n }\n break;\n\n case keyboard.ESC:\n if (inlineEditors.isVisible()) {\n inlineEditors.hide();\n e.preventDefault();\n preventKeyNav = true;\n } else {\n deselectAll(gantt);\n }\n\n break;\n\n case keyboard.UP:\n case keyboard.DOWN:\n if (inlineEditors.isVisible()) {\n preventKeyNav = true;\n }\n break;\n\n case keyboard.LEFT:\n case keyboard.RIGHT:\n if (hasEditor && inlineEditors.isVisible()) {\n preventKeyNav = true;\n }\n break;\n\n case keyboard.SPACE:\n if (inlineEditors.isVisible()) {\n preventKeyNav = true;\n }\n\n if ((hasEditor && !inlineEditors.isVisible()) || state.editorType === 'date') {\n inlineEditors.startEdit(activeCell.id, activeCell.columnName);\n e.preventDefault();\n preventKeyNav = true;\n }\n break;\n\n case keyboard.DELETE:\n preventKeyNav = true;\n break;\n\n case keyboard.TAB:\n if (inlineEditors.isVisible()) {\n e.preventDefault();\n preventKeyNav = true;\n\n const task = gantt.getTask(state.id);\n if (isPlaceholderTask(gantt, task)) {\n if (state.columnName === GANTT_COLUMNS_NAMES.name) {\n const value = state.editor.get_value(task.id, state.columnName, state.placeholder);\n if (e.shiftKey) {\n if (value) {\n inlineEditors.moveRow(-1);\n const cell = inlineEditors.getLastCell();\n if (cell) {\n task.focus = cell;\n }\n }\n inlineEditors.editPrevCell(true);\n break;\n } else if (!value) {\n inlineEditors.hide();\n break;\n }\n }\n\n const previous = gantt.getPrev(task.id);\n const nextColumnName = inlineEditors.getNextCell(e.shiftKey ? -1 : 1);\n if (nextColumnName) {\n task.focus = nextColumnName;\n inlineEditors.save();\n const nextTask = gantt.getNext(previous);\n inlineEditors.startEdit(nextTask, nextColumnName);\n }\n } else {\n if (e.shiftKey) {\n inlineEditors.editPrevCell(true);\n } else {\n inlineEditors.editNextCell(true);\n }\n }\n\n e.preventDefault();\n preventKeyNav = true;\n }\n break;\n\n default:\n if (inlineEditors.isVisible()) {\n preventKeyNav = true;\n }\n break;\n }\n\n return !preventKeyNav;\n }\n return false;\n });\n },\n\n onShow: function () {\n return;\n },\n onHide: function () {\n gantt.focus();\n },\n\n // required for gantt v9 update\n destroy: function () {\n console.warn('not implemented');\n },\n };\n gantt.ext.inlineEditors.setMapping(mapping);\n}\n\nexport function resetFrozenColumnsOffset() {\n document.documentElement.style.setProperty('--gantt-frozen-column-scroll-left', 0 + 'px');\n}\nexport function registerFrozenColumnsHandler(gantt: GanttStatic, columns: number): () => void {\n const frozenClass = `gantt_grid__frozen-${columns}`;\n let scrollContainer: HTMLElement;\n const events: string[] = [];\n const calcOffset = () =>\n document.documentElement.style.setProperty('--gantt-frozen-column-scroll-left', scrollContainer.scrollLeft + 'px');\n const onScrollHandler = () => {\n gantt.$grid.classList.add(frozenClass);\n gantt.$grid.dataset.frozenColumns = String(columns);\n calcOffset();\n };\n\n events.push(\n gantt.attachEvent(\n 'onGanttReady',\n () => {\n scrollContainer = document.querySelector('.gridScroll_cell .gantt_hor_scroll');\n if (scrollContainer) {\n scrollContainer.addEventListener('scroll', onScrollHandler);\n }\n },\n null,\n ),\n );\n\n events.push(\n gantt.attachEvent(\n 'onGridResizeEnd',\n () => {\n setTimeout(calcOffset);\n },\n null,\n ),\n );\n\n return () => {\n events.forEach((eventId) => gantt.detachEvent(eventId));\n gantt.$grid.classList.remove(frozenClass);\n delete gantt.$grid.dataset.frozenColumns;\n scrollContainer?.removeEventListener('scroll', onScrollHandler);\n };\n}\n\nexport function isNonHidingColumn(colName: string): boolean {\n return NON_HIDING_COLUMNS.includes(colName as GANTT_COLUMNS_NAMES);\n}\n\nexport function getCustomColumnCellTemplate(project: ProjectModel, task: GanttTask, columnName: string): string {\n if (isPlaceholderTask(gantt, task)) return '';\n const columnValue =\n // eslint-disable-next-line @typescript-eslint/naming-convention\n task.custom_fields?.find(({internal_field_name}) => internal_field_name === columnName)?.value ?? '';\n if (!columnValue) return '';\n const columnType = getProjectCustomField(project, columnName)?.fieldType;\n switch (columnType) {\n case ProjectCustomFieldType.date:\n return safeFormatDate(columnValue) ?? 'Not Parsed';\n case ProjectCustomFieldType.select:\n case ProjectCustomFieldType.multiselect: {\n if (!columnValue) return '';\n const parseResult = safeParseJSON(columnValue);\n if (!parseResult.success) {\n return columnValue;\n }\n return parseResult.data.join(', ');\n }\n default: {\n return columnValue;\n }\n }\n}\n\nexport function getCustomColumnWidthByFieldType(fieldType: ProjectCustomFieldType): number {\n return fieldType === ProjectCustomFieldType.date ? 125 : 100;\n}\n\nexport function getInlineEditorTypeForCustomColumn(fieldType: ProjectCustomFieldType): {\n type: string;\n map_to: GANTT_COLUMNS_NAMES;\n} {\n const mapTo = GANTT_COLUMNS_NAMES.customFields;\n const defaultEditor = {type: 'generalEditorForCustomField', map_to: mapTo};\n switch (fieldType) {\n case ProjectCustomFieldType.number:\n return {type: 'generalNumberEditor', map_to: mapTo};\n case ProjectCustomFieldType.date:\n return {type: 'customFieldDateEditor', map_to: mapTo};\n case ProjectCustomFieldType.select:\n case ProjectCustomFieldType.multiselect:\n return {type: 'customFieldDropdownEditor', map_to: mapTo};\n default: {\n return defaultEditor;\n }\n }\n}\n","import classnames from 'classnames';\nimport dayjs from 'dayjs';\nimport {GanttEventCallback, GanttStatic, Task} from 'dhtmlx-gantt';\nimport {camelize, camelizeKeys} from 'humps';\nimport {TFunction} from 'i18next';\n\nimport {CellLocation, GanttTask, InlineEditorState} from 'modules/Tasks/components/Gantt/types';\nimport {debounce} from 'shared/helpers/debounce';\nimport {useMixpanel} from 'shared/hooks/analytics/useMixpanel';\nimport {ProjectModel} from 'shared/models/project';\nimport {TaskObjectType, TaskObjectSubType} from 'shared/models/task/const';\nimport {RedoType} from 'shared/models/task/task';\nimport {TaskStatusType} from 'shared/models/task/taskStatus';\nimport {TaskDependencyTypeAbbr, TaskDependencyTypeByAbbr} from 'shared/models/TaskDependency';\n\nimport {updateTaskCustomFieldValue} from '../components/Editors/helpers';\n\nimport {GANTT_COLUMNS_NAMES, NOT_EDITABLE_COLUMNS, PERSONAL_PROJECT_NAME} from './constants';\nimport {EventStore} from './eventStore';\n\nexport type InlineEditorEventName =\n | 'onContextMenuCustom'\n | 'afterTasksImport'\n | 'onAfterManualUpdate'\n | 'onEditEnd'\n | 'onBeforeEditStart'\n | 'onBeforeSave'\n | 'onEditStart'\n | 'onBeforeAdd';\n\nexport type CustomGanttEvents =\n | 'onTaskOpen'\n | 'onContextMenuCustom'\n | 'afterTasksImport'\n | 'onAfterManualUpdate'\n | 'onCopy'\n | 'bulkDelete'\n | 'focusAnnot'\n | 'DataLoaded'\n | 'selectAll'\n | 'deselectAll'\n | 'toolbarAction';\n\nexport type GanttEventNameUnion = keyof GanttEventCallback | CustomGanttEvents;\n\nexport type GanttGridEventNames =\n | 'onAfterColumnReorder'\n | 'onBeforeColumnReorder'\n | 'onBeforeColumnDragStart'\n | 'onColumnDragMove';\n\nexport type KeyNavigationEventName = 'onKeyDown' | 'onEmptyClick' | 'onTaskClick' | 'onBeforeFocus' | 'onFocus';\n\ntype OptionalID = unknown & {value?: {id?: string | number}};\n\nexport const FOURTH_LEVEL = 3;\n\nexport type OSKMap = Map;\ninterface OSKMapTaskInfo {\n id: string;\n children_count: number;\n parent: string;\n}\n\nconst columnsForTrackingMixpanel = [\n GANTT_COLUMNS_NAMES.name,\n GANTT_COLUMNS_NAMES.description,\n GANTT_COLUMNS_NAMES.trackNumber,\n];\n\nexport function traverseTasks(tasks: {outline_sort_key?: string; id: string}[], map?: OSKMap): OSKMap {\n return tasks.reduce((acc, task) => {\n let parentKey: string;\n if (typeof task.outline_sort_key === 'string' && task.outline_sort_key.length > 10) {\n parentKey = task.outline_sort_key.slice(0, -11);\n if (acc.has(parentKey)) {\n const parent = acc.get(parentKey);\n parent.children_count += 1;\n } else {\n acc.set(parentKey, {id: undefined, children_count: 1, parent: undefined});\n }\n }\n if (acc.has(task.outline_sort_key)) {\n acc.get(task.outline_sort_key).id = task.id;\n } else {\n acc.set(task.outline_sort_key, {id: task.id, children_count: 0, parent: parentKey});\n }\n return acc;\n }, map || (new Map() as OSKMap));\n}\n\nexport const markWbsDatesDisabled = (task, node) => {\n if (task.object_type === TaskObjectType.summary) {\n node.classList.add('disabled');\n }\n};\n\nexport function checkEmptyPersonalProject(project: ProjectModel) {\n return project.name === PERSONAL_PROJECT_NAME && project.taskCount === 0;\n}\n\nexport const disableReadonlyAfterRedo = (actions: {commands: Array}, gantt: GanttStatic) => {\n actions?.commands.forEach((action) => {\n if (action.entity === 'task' && action.type === 'add') {\n if (gantt.isTaskExists((action as OptionalID)?.value?.id)) {\n const task = gantt.getTask((action as OptionalID)?.value?.id);\n task.readonly = false;\n }\n }\n });\n};\n\nexport function getBaselineDateRange(task: Task): [Date, Date] {\n return [\n dayjs(task.baseline_start).startOf('day').toDate(),\n dayjs(task.baseline_end).add(1, 'day').startOf('day').toDate(),\n ];\n}\n\nexport function getTaskDateRange(task: Task): [Date, Date] {\n let startDate = dayjs(task.start_date).startOf('day').toDate();\n let endDate = dayjs(task.end_date).startOf('day').toDate();\n\n if (task.date_list?.length && task.object_type !== 'summary') {\n startDate = dayjs(task.date_list[0])?.startOf('day').toDate();\n endDate = dayjs(task.date_list[task.date_list.length - 1])\n ?.add(1, 'day')\n .startOf('day')\n .toDate();\n }\n\n return [startDate, endDate];\n}\n\nexport function getVisibleDateRange(gantt: GanttStatic, dates: [Date, Date]): [Date, Date] {\n const [startDate, endDate] = dates;\n const timelineStart = new Date(gantt.config.start_date || gantt.getSubtaskDates()?.start_date);\n const timelineEnd = new Date(gantt.config.end_date || gantt.getSubtaskDates()?.end_date);\n return [startDate < timelineStart ? timelineStart : startDate, endDate > timelineEnd ? timelineEnd : endDate];\n}\n\nexport function formatTaskDependencies(gantt: GanttStatic, task: GanttTask): string {\n if (!task.sourceDeps?.length) return '';\n return (\n task.sourceDeps\n .reduce((res, {depType, lagDays, predTaskId}) => {\n const depRowNumber = gantt.rownumbersMap?.[predTaskId];\n if (!depRowNumber) return res;\n let mask = `${depRowNumber}`;\n if (depType !== 'finish_start') {\n mask += TaskDependencyTypeAbbr[depType];\n }\n if (lagDays !== 0) {\n mask += `${lagDays > 0 ? `+${lagDays}` : lagDays}d`;\n }\n res.push({mask, row: depRowNumber});\n return res;\n }, [])\n // row numbers in ASC order\n .sort(function (a, b) {\n if (a.row === b.row) return 0;\n return a > b ? 1 : -1;\n })\n .map(({mask}) => mask)\n .join(',')\n );\n}\n\ntype ParsedDependency = {\n rownum: number;\n depType: string;\n lagDays: number;\n};\n\nexport function parseTaskDependencies(gantt: GanttStatic, mask: string, t?: TFunction): ParsedDependency[] {\n const regExp = /(?\\d+)(?\\w+)?(?[+-]\\d+d?)?/gi;\n return mask\n .split(',')\n .map((part) => part.trim())\n .reduce((acc, part) => {\n const parsed = Array.from(part.matchAll(regExp)).pop();\n if (parsed) {\n const {row, depType = '', lag = ''} = parsed.groups;\n if (depType && !Object.values(TaskDependencyTypeAbbr).includes(depType.toUpperCase())) {\n // don't try to abstract out second argument of call to t() so later string\n // extractions won't blank translation.\n const errorMsg = t\n ? t('gantt:toast.error.predecessor.wrong_deptype', 'Invalid task dependency type. Use FS, SS, FF, SF')\n : 'Invalid task dependency type. Use FS, SS, FF, SF';\n throw new Error(errorMsg);\n }\n const rowLag = parseInt(lag);\n if (row) {\n acc.push({\n rownum: parseInt(row),\n depType: depType ? TaskDependencyTypeByAbbr[depType.toUpperCase()] : TaskDependencyTypeByAbbr['FS'],\n lagDays: isNaN(rowLag) ? 0 : rowLag,\n });\n }\n }\n return acc;\n }, [] as ParsedDependency[]);\n}\n\nexport function getDependenciesDiff(gantt: GanttStatic, task: GanttTask, newDependencies: ParsedDependency[]) {\n const prevDeps = task.sourceDeps || [];\n const toRemove = [];\n const toAdd = [];\n const toUpdate = [];\n\n if (prevDeps.length) {\n for (const {depType, rownum, lagDays} of newDependencies) {\n const existed = prevDeps.find((p) => p.rownum === rownum);\n const predTask = getTaskByRowNumber(gantt, rownum);\n if (existed) {\n if (existed.depType !== depType || existed.lagDays !== lagDays) {\n toUpdate.push({id: existed.id, depType, lagDays, predTaskId: predTask?.id});\n }\n } else if (predTask) {\n toAdd.push({predTaskId: predTask?.id, taskId: task.id, depType, lagDays});\n }\n }\n // find dependencies to remove\n for (const dep of prevDeps) {\n const found = newDependencies.find(({rownum}) => rownum === dep.rownum);\n if (!found && !toRemove.includes(dep.id)) {\n toRemove.push(dep.id);\n }\n }\n } else {\n for (const {depType, rownum, lagDays} of newDependencies) {\n const predTask = getTaskByRowNumber(gantt, rownum);\n toAdd.push({predTaskId: predTask?.id, taskId: task.id, depType, lagDays});\n }\n }\n\n return {\n add: toAdd,\n update: toUpdate,\n remove: toRemove,\n };\n}\n\n/*\n * Mark gantt in rendering process for cypress\n * */\nexport function trackRerenderingClassname(eventStore: EventStore, gantt: GanttStatic) {\n const CY_RERENDER_CLASSNAME = 're-render';\n if (window.Cypress) {\n eventStore.attach('onBeforeDataRender', () => {\n gantt.$root.classList.add(CY_RERENDER_CLASSNAME);\n });\n eventStore.attach(\n 'onDataRender',\n debounce(() => {\n gantt.$root.classList.remove(CY_RERENDER_CLASSNAME);\n }, 2000),\n );\n }\n}\n\nexport function getTaskByRowNumber(gantt: GanttStatic, row: number): Task {\n return gantt.getTaskBy('rownum', row)?.[0] as Task;\n}\n\nexport function prepareTaskGanttChangedFields(task: GanttTask): Record {\n const res = {};\n Object.entries(task.lastChangedFields).forEach(([key, {newValue}]) => {\n res[key] = newValue;\n });\n return camelizeKeys(res, (key, convert) => (key.includes('-') ? key : convert(key))) as Record;\n}\n\nexport function registerInlineEditorsListeners(\n gantt: GanttStatic,\n eventStore: EventStore,\n mixpanel: ReturnType,\n) {\n eventStore.attach('onBeforeEditStart', ({id, columnName}) => {\n if (gantt.isTaskExists(id)) {\n const task = gantt.getTask(id);\n if (isPlaceholderTask(gantt, task)) {\n gantt.refreshTask(task.id);\n mixpanel.track(mixpanel.events.tasks.creteNewTaskEmptyRow, {taskType: TaskObjectType.activity});\n return true;\n }\n if (task.type === TaskObjectType.milestone) {\n if (\n (task.object_subtype === TaskObjectSubType.end && columnName === GANTT_COLUMNS_NAMES.startDate) ||\n (task.object_subtype === TaskObjectSubType.start && columnName === GANTT_COLUMNS_NAMES.endDate)\n ) {\n return false;\n }\n }\n\n const notEditableColumn = NOT_EDITABLE_COLUMNS[task.object_type]?.includes(columnName);\n if (!(task.readonly || notEditableColumn)) {\n mixpanel.track(mixpanel.events.gantt.inlineEdit[camelize(columnName)], {taskType: task.object_type});\n return true;\n }\n }\n return false;\n });\n\n eventStore.attach('onBeforeSave', ({id, columnName, oldValue, newValue}) => {\n const columnConfig = gantt.getGridColumn(columnName);\n const task = gantt.getTask(id) as GanttTask;\n\n if (columnsForTrackingMixpanel.includes(columnName)) {\n mixpanel.track(mixpanel.events.gantt.inlineEdit[camelize(columnName)]);\n }\n\n if (columnConfig.editor.map_to === 'auto') {\n return true;\n }\n\n if (!task.lastChangedFields) {\n task.lastChangedFields = {};\n }\n\n const isProjectCustomField = columnConfig.editor.map_to === GANTT_COLUMNS_NAMES.customFields;\n if (isProjectCustomField) {\n return updateTaskCustomFieldValue(task, {field: columnName, value: newValue});\n }\n\n if (columnName === GANTT_COLUMNS_NAMES.duration && task.datesIsPristine && newValue) {\n task.datesIsPristine = false;\n gantt.refreshTask(id);\n }\n\n if (oldValue !== newValue && gantt.isTaskExists(id)) {\n task.lastChangedFields[columnName] = {oldValue, newValue};\n }\n return true;\n });\n eventStore.attach('onEditStart', function () {\n const inlineState = gantt.ext.inlineEditors.getState() as InlineEditorState;\n let targetEl = inlineState.placeholder;\n // so that cell borders don't overlap\n targetEl.style.height = targetEl.offsetHeight - 1 + 'px';\n targetEl.style.zIndex = '1';\n\n inlineState.editor.valueOnStartEdit = inlineState.editor.get_value(\n inlineState.id,\n inlineState.columnName,\n targetEl,\n );\n\n if (inlineState.editor?.get_input) {\n const input = inlineState.editor.get_input(inlineState.placeholder);\n if (input) {\n // sometimes input width is larger than the container (e.g. date inputs)\n if (input.clientWidth >= targetEl.clientWidth) {\n targetEl = input;\n }\n }\n }\n const resizer = document.querySelector('.gantt_layout_content.gantt_resizer_x');\n if (resizer) {\n const targetElRect = targetEl.getBoundingClientRect();\n const resizerRect = resizer.getBoundingClientRect();\n if (targetElRect.right > resizerRect.left) {\n const horizScroll = document.querySelector('.gantt_layout_cell.gantt_hor_scroll');\n setTimeout(() => {\n horizScroll.scrollLeft += targetElRect.right - resizerRect.left;\n }, 1);\n }\n }\n });\n}\n\nexport function isPlaceholderTask(gantt: GanttStatic, task: Task) {\n return gantt.config.types.placeholder === task?.type;\n}\n\nexport function deselectAll(gantt: GanttStatic) {\n gantt.eachSelectedTask(gantt.toggleTaskSelection);\n gantt.dRender();\n}\n\nexport function toggleOpen(gantt: GanttStatic, open = true) {\n gantt.batchUpdate(() => {\n gantt.eachTask((task) => {\n task.$open = open;\n });\n });\n}\n\nexport function isNotEditableTask(task: Task): boolean {\n return task.readonly || !!task?.time_removed || task.status === TaskStatusType.archived;\n}\n\nconst isIncludedInDateRange = (targetDate: Date, startDate: Date, endDate: Date | null) => {\n const target = dayjs(targetDate);\n const beforeToday = target.isBefore(new Date(), 'd') || target.isSame(new Date(), 'd');\n const beforeIssueEnd = target.isBefore(endDate, 'd') || !endDate;\n const afterIssueStart = target.isAfter(startDate, 'd');\n const sameStartOrEnd = target.isSame(startDate, 'd') || target.isSame(endDate, 'd');\n return (afterIssueStart && beforeIssueEnd && beforeToday) || (sameStartOrEnd && beforeToday);\n};\n\nexport const getQuantityIssuesInDay = (gantt: GanttStatic, openIssueIds: string[], taskDate: Date) => {\n return openIssueIds.reduce((acc, issueId) => {\n const issue = gantt?.issuesDictionary?.[issueId];\n if (issue && isIncludedInDateRange(taskDate, issue.startDate, issue.endDate)) {\n ++acc;\n }\n return acc;\n }, 0);\n};\n\nexport function startInlineEditing(gantt: GanttStatic, node: HTMLElement): boolean {\n const inlineEditors = gantt.ext.inlineEditors;\n const state = inlineEditors.getState() as InlineEditorState;\n const cell = inlineEditors.locateCell(node) as CellLocation | null;\n\n if (cell && inlineEditors.getEditorConfig(cell.columnName)) {\n if (inlineEditors.isVisible() && state.id === cell.id && state.columnName === cell.columnName) {\n // do nothing if editor is already active in this cell\n return false;\n }\n\n const task = gantt.getTask(cell.id);\n if (state.columnName === GANTT_COLUMNS_NAMES.duration && task.object_type === TaskObjectType.summary) {\n return false;\n }\n inlineEditors.startEdit(cell.id, cell.columnName);\n return true;\n }\n return false;\n}\n\nexport const getGridRowClass = (gantt: GanttStatic) => {\n return (_start: Date, _end: Date, task: GanttTask) => {\n return classnames({\n 'selected-task_custom': task.openedEditPanel,\n 'gantt__row_has-child': task.$has_child,\n 'gantt__row_is-child': task.parent !== gantt.config.root_id,\n [`wbs-level__${task.$level > FOURTH_LEVEL ? FOURTH_LEVEL : task.$level}`]:\n task.object_type === TaskObjectType.summary,\n ['gantt__row_is_pending']: task.isPending,\n });\n };\n};\n","import axios, {CancelToken} from 'axios';\nimport {Effect} from 'effect';\nimport {InterruptedException, UnknownException} from 'effect/Cause';\n\nimport TasksApi from 'api/tasks';\nimport {SortOrder} from 'shared/constants/common';\nimport {SortField, TaskProjection} from 'shared/models/task/const';\nimport {TaskFilterQuery, TaskStatusQuery} from 'shared/models/task/filter';\nimport {IssueModelRawDTO, TaskModelRawDTO} from 'shared/models/task/task';\n\nimport {ApiResponse} from '../BatchLoader';\nimport {BadGatewayError, EffectError, HttpError} from '../errors';\n\nexport const createFetchIssuesBatch = ({\n projectId,\n queryParams,\n dataRange,\n}: {\n projectId: string;\n queryParams: Partial;\n dataRange: Date[];\n}) => {\n return (\n offset: number,\n take: number,\n cancelToken: CancelToken,\n ): Effect.Effect, EffectError, never> =>\n Effect.tryPromise({\n try: () =>\n TasksApi.getTaskIssues(projectId, {\n offset,\n limit: take,\n sortParams: {\n sortField: 'description',\n sortOrder: SortOrder.DESC,\n },\n filterParams: {\n ...queryParams,\n schedIntersect: dataRange?.map((date) => date.toISOString()) as [string, string],\n },\n cancelToken,\n }),\n catch: (error): EffectError => {\n if (axios.isCancel(error)) {\n return new InterruptedException('Request cancelled');\n }\n return handleAxiosError(error);\n },\n }).pipe(\n Effect.map((response) => ({\n data: response.data,\n headers: response.headers,\n })),\n );\n};\n\nexport const createFetchDailiesIssuesBatch = ({\n projectId,\n queryParams,\n}: {\n projectId: string;\n queryParams: Partial;\n}) => {\n return (\n offset: number,\n take: number,\n cancelToken: CancelToken,\n ): Effect.Effect, EffectError, never> =>\n Effect.tryPromise({\n try: () =>\n TasksApi.getTaskIssues(projectId, {\n offset,\n limit: take,\n sortParams: {\n sortField: 'description',\n sortOrder: SortOrder.DESC,\n },\n filterParams: {\n ...queryParams,\n schedEndFirst: queryParams.schedEndFirst,\n },\n cancelToken,\n }),\n catch: (error): EffectError => {\n if (axios.isCancel(error)) {\n return new InterruptedException('Request cancelled');\n }\n return handleAxiosError(error);\n },\n }).pipe(\n Effect.map((response) => ({\n data: response.data,\n headers: response.headers,\n })),\n );\n};\n\nexport const createFetchTaskDetailsBatch = ({\n filterParams,\n}: {\n filterParams: Partial;\n}) => {\n return (\n offset: number,\n take: number,\n cancelToken: CancelToken,\n ): Effect.Effect, EffectError, never> => {\n const batchTaskIds = filterParams.ids.slice(offset, offset + take);\n\n return Effect.tryPromise({\n try: () =>\n TasksApi.getProjectTasks({\n projection: TaskProjection.taskSmall,\n offset,\n limit: take,\n sortField: SortField.outlineSortKey,\n sortOrder: SortOrder.ASC,\n params: {ids: batchTaskIds, ...filterParams},\n cancelToken,\n }),\n catch: (error): EffectError => {\n if (axios.isCancel(error)) {\n return new InterruptedException('Request cancelled');\n }\n return handleAxiosError(error);\n },\n }).pipe(\n Effect.map((response) => ({\n data: response.data as TaskModelRawDTO[],\n headers: response.headers,\n })),\n );\n };\n};\n\nexport const handleAxiosError = (error: unknown): EffectError => {\n if (axios.isAxiosError(error)) {\n switch (error.response?.status) {\n case 502:\n return new BadGatewayError({\n message: error.message,\n cause: error,\n });\n default:\n return new HttpError({\n statusCode: error.response?.status || 500,\n message: error.message,\n cause: error,\n });\n }\n }\n return new UnknownException({\n message: error instanceof Error ? error.message : 'Unknown error',\n cause: error instanceof Error ? error : undefined,\n });\n};\n","import axios, {CancelToken} from 'axios';\nimport {Effect} from 'effect';\nimport {InterruptedException} from 'effect/Cause';\n\nimport TasksApi from 'api/tasks';\nimport {LoadOptions} from 'modules/Tasks/components/Gantt/types';\nimport {SortOrder} from 'shared/constants/common';\nimport {addStatusToFilters} from 'shared/helpers/tasks';\nimport {TaskProjection, TaskObjectType} from 'shared/models/task/const';\nimport {TaskListMinimalModel} from 'shared/models/task/task';\n\nimport {ApiResponse} from '../BatchLoader';\nimport {EffectError} from '../errors';\n\nimport {handleAxiosError} from './createIssueEffect';\n\nexport interface FetchActivityIdsBatchFnDeps {\n queryParams: LoadOptions['queryParams'];\n projectId: string;\n dataRange: LoadOptions['dataRange'];\n requestProjectId: string;\n}\n\nexport interface FetchActivityIdsBatchParams {\n queryParams: LoadOptions['queryParams'];\n projectId: string;\n dataRange: LoadOptions['dataRange'];\n}\n\nexport const createActivityIdsFetcherEffect = ({queryParams, projectId, dataRange}: FetchActivityIdsBatchParams) => {\n return (\n offset: number,\n take: number,\n cancelToken: CancelToken,\n ): Effect.Effect, EffectError, never> =>\n Effect.tryPromise({\n try: () =>\n TasksApi.getProjectTasks({\n projection: TaskProjection.taskMinimal,\n offset,\n limit: take,\n sortField: 'outline_sort_key',\n sortOrder: SortOrder.ASC,\n includeSummaryTasks: true,\n params: addStatusToFilters(queryParams.state, {\n ...queryParams,\n objectTypeList: queryParams.milestonesOnly\n ? [TaskObjectType.milestone]\n : [TaskObjectType.task, TaskObjectType.summary, TaskObjectType.activity, TaskObjectType.milestone],\n projectId,\n schedIntersect: dataRange?.map((date) => date.toISOString()) as [string, string],\n }),\n cancelToken,\n }),\n catch: (error): EffectError => {\n if (axios.isCancel(error)) {\n return new InterruptedException('Request cancelled');\n }\n return handleAxiosError(error);\n },\n }).pipe(\n Effect.map((response) => ({\n data: response.data as TaskListMinimalModel[],\n headers: response.headers,\n })),\n );\n};\n","/* eslint-disable new-cap */\n/* eslint-disable @typescript-eslint/naming-convention */\nimport axios, {CancelToken, CancelTokenSource} from 'axios';\nimport {Effect, Queue, Schedule, Duration} from 'effect';\n\nimport {EffectError} from './errors';\nimport {calculateBatchParameters} from './helpers';\n\nexport type ApiResponse = {\n data: T[];\n headers?: {\n 'content-range'?: string;\n [key: string]: any;\n };\n};\n\ndeclare global {\n interface BatchLoadTracker {\n operationId: number;\n completed: Set;\n inProgress: boolean;\n startTime: number;\n fnName: string;\n cancelTokenSource: CancelTokenSource;\n projectId: string;\n }\n\n interface Window {\n _batchLoads: {\n [fnName: string]: BatchLoadTracker;\n };\n }\n}\n\nexport type BatchLoadConfig = {\n batchFn: (\n offset: number,\n take: number,\n cancelToken: CancelToken,\n ) => Effect.Effect, EffectError, never>;\n fnName: string;\n projectId: string;\n batchSize?: number;\n};\n\nconst effect = Effect.gen(function* () {\n const createBatchLoadEffect = (config: BatchLoadConfig): Effect.Effect => {\n const {batchFn, fnName, projectId, batchSize} = config;\n const batchLoadId = Date.now();\n // eslint-disable-next-line import/no-named-as-default-member\n const cancelTokenSource = axios.CancelToken.source();\n\n if (typeof window._batchLoads === 'undefined') {\n window._batchLoads = {};\n }\n\n const progressTracker: BatchLoadTracker = {\n operationId: batchLoadId,\n completed: new Set(),\n inProgress: true,\n startTime: performance.now(),\n fnName,\n cancelTokenSource,\n projectId,\n };\n\n const existingOperation = window._batchLoads[fnName];\n if (existingOperation?.projectId !== projectId && existingOperation?.inProgress) {\n existingOperation.cancelTokenSource?.cancel('Project changed');\n existingOperation.inProgress = false;\n }\n\n window._batchLoads[fnName] = progressTracker;\n\n return Effect.gen(function* (_) {\n try {\n const initialResponse = yield* _(batchFn(0, 1, cancelTokenSource.token));\n const contentRange = initialResponse.headers?.['content-range'];\n const total = contentRange\n ? parseInt(contentRange.match(/\\d+-\\d+\\/(\\d+)/)?.[1] ?? '0', 10)\n : initialResponse.data.length;\n\n if (total === 0) {\n return [];\n }\n\n const {\n batchSize: optimizedBatchSize,\n batchCount: numberOfBatches,\n concurrency: optimizedConcurrency,\n } = calculateBatchParameters(total, batchSize);\n\n const resultQueue = yield* _(Queue.unbounded>());\n\n const processBatch = (index: number) =>\n Effect.gen(function* (_) {\n const result = yield* _(\n batchFn(index * optimizedBatchSize, optimizedBatchSize, cancelTokenSource.token).pipe(\n Effect.retry(Schedule.exponential(Duration.seconds(2)).pipe(Schedule.compose(Schedule.recurs(3)))),\n ),\n );\n\n if (window._batchLoads[fnName]?.operationId === batchLoadId) {\n progressTracker.completed.add(index);\n }\n\n yield* _(Queue.offer(resultQueue, result));\n return result;\n });\n\n yield* _(\n Effect.forEach(\n Array.from({length: numberOfBatches}, (_, i) => i),\n processBatch,\n {concurrency: optimizedConcurrency},\n ),\n );\n\n const results = yield* _(\n Effect.forEach(Array.from({length: numberOfBatches}), () => Queue.take(resultQueue), {concurrency: 1}),\n );\n\n return results.flatMap((batch) => batch.data);\n } catch (error) {\n throw error;\n } finally {\n if (window._batchLoads[fnName]?.operationId === batchLoadId) {\n delete window._batchLoads[fnName];\n }\n }\n });\n };\n\n return {\n createBatchLoadEffect,\n };\n});\n\nexport class BatchLoader extends Effect.Service()('BatchLoader', {\n effect,\n}) {}\n","/* eslint-disable @typescript-eslint/naming-convention */\n/* eslint-disable new-cap */\nimport {Effect, Layer} from 'effect';\nimport {InterruptedException} from 'effect/Cause';\n\nimport {LoadOptions} from 'modules/Tasks/components/Gantt/types';\nimport {TaskListMinimalModel} from 'shared/models/task/task';\n\nimport {createActivityIdsFetcherEffect} from './api/createActivityIdsEffect';\nimport {BatchLoadConfig, BatchLoader} from './BatchLoader';\nimport {EffectError} from './errors';\nimport {createProjectLoader} from './helpers';\n\nconst effect = Effect.gen(function* () {\n const batchLoader = yield* BatchLoader;\n\n const loadActivityIds = ({\n queryParams,\n projectId,\n dataRange,\n done,\n setLoading,\n }: LoadOptions): Effect.Effect => {\n // Create the loading effect\n const loadingEffect = Effect.sync(() => {\n if (setLoading) {\n setLoading(true);\n }\n });\n\n // Create the cleanup effect\n const cleanupEffect = Effect.sync(() => {\n if (setLoading) {\n setLoading(false);\n }\n });\n\n const fetchActivityIdsBatch = createActivityIdsFetcherEffect({\n queryParams,\n projectId,\n dataRange,\n });\n\n const fetchAndTransformData = batchLoader\n .createBatchLoadEffect({\n batchFn: fetchActivityIdsBatch,\n fnName: 'activityIdsLoader',\n projectId,\n batchSize: 5_000,\n })\n .pipe(\n Effect.map((results) => {\n const activityIds = results.map((task) => task.id);\n done(activityIds);\n return results;\n }),\n );\n\n return loadingEffect.pipe(\n Effect.flatMap(() => createProjectLoader(projectId, fetchAndTransformData)),\n Effect.ensuring(cleanupEffect),\n );\n };\n\n return {loadActivityIds} as const;\n});\n\nexport class ConcurrentActivityIdsLoader extends Effect.Service()(\n 'ConcurrentActivityIdsLoader',\n {\n effect,\n dependencies: [BatchLoader.Default],\n },\n) {\n static Test = (mockData?: T[]) => {\n // For success cases with mock data\n if (Array.isArray(mockData)) {\n return this.DefaultWithoutDependencies.pipe(\n Layer.provide(\n Layer.succeed(BatchLoader, {\n createBatchLoadEffect: (_config: BatchLoadConfig): Effect.Effect =>\n Effect.succeed(mockData as unknown as U[]),\n _tag: 'BatchLoader' as const,\n }),\n ),\n );\n }\n\n // Default case for error testing\n const defaultBatchLayer = Layer.succeed(BatchLoader, {\n createBatchLoadEffect: (config: BatchLoadConfig): Effect.Effect => {\n return Effect.gen(function* () {\n const response = yield* config.batchFn(0, config.batchSize, null);\n return response.data;\n });\n },\n _tag: 'BatchLoader' as const,\n });\n\n return this.DefaultWithoutDependencies.pipe(Layer.provide(defaultBatchLayer));\n };\n}\n","/* eslint-disable new-cap */\n/* eslint-disable @typescript-eslint/naming-convention */\nimport {Effect, Layer} from 'effect';\nimport {InterruptedException} from 'effect/Cause';\n\nimport {LoadOptions, Activity} from 'modules/Tasks/components/Gantt/types';\nimport {transformIssuesData} from 'modules/Tasks/components/Gantt/utils/functions';\nimport {TaskFilterQuery} from 'shared/models/task/filter';\nimport {IssueModelRawDTO, TaskGanttModel, GanttLinkModelDTO} from 'shared/models/task/task';\n\nimport {\n createFetchDailiesIssuesBatch,\n createFetchIssuesBatch,\n createFetchTaskDetailsBatch,\n} from './api/createIssueEffect';\nimport {BatchLoadConfig, BatchLoader} from './BatchLoader';\nimport {EffectError} from './errors';\nimport {createProjectLoader} from './helpers';\n\nexport type IssuesLoaderResult = {\n allIssues: IssueModelRawDTO[];\n ganttData: {\n tasks: TaskGanttModel[];\n links: GanttLinkModelDTO[];\n };\n taskIdToNameMap: Map;\n};\n\nconst effect = Effect.gen(function* () {\n const batchLoader = yield* BatchLoader;\n\n const loadIssues = ({\n queryParams,\n projectId,\n dataRange,\n done,\n setLoading,\n }: LoadOptions): Effect.Effect => {\n // Create the loading effect\n const loadingEffect = Effect.sync(() => {\n if (setLoading) {\n setLoading(true);\n }\n });\n\n // Create the cleanup effect\n const cleanupEffect = Effect.sync(() => {\n if (setLoading) {\n setLoading(false);\n }\n });\n\n const fetchIssuesBatch = createFetchIssuesBatch({\n projectId,\n queryParams,\n dataRange,\n });\n\n const fetchAndTransformData = Effect.gen(function* (_) {\n const allIssues = yield* batchLoader.createBatchLoadEffect({\n batchFn: fetchIssuesBatch,\n fnName: 'loadIssues',\n projectId,\n });\n\n const ganttData = transformIssuesData({\n tasks: allIssues,\n projectId,\n flatList: false,\n feedbackMap: new Map(),\n });\n\n const allTaskIds = new Set();\n ganttData.tasks.forEach((issue) => issue.task_ids.forEach((taskId) => allTaskIds.add(taskId)));\n const taskIdsList = Array.from(allTaskIds);\n\n const fetchTaskDetailsBatch = createFetchTaskDetailsBatch({filterParams: {ids: taskIdsList, projectId}});\n\n const taskDetailsResults = yield* batchLoader.createBatchLoadEffect({\n batchFn: fetchTaskDetailsBatch,\n fnName: 'loadTaskDetails',\n projectId,\n });\n\n const taskIdToNameMap = new Map();\n taskDetailsResults?.forEach((task) => taskIdToNameMap.set(task.id, task.name));\n\n const tasks = ganttData.tasks.map((issue) => ({\n ...issue,\n activities: issue.task_ids.reduce((acc, taskId) => {\n const taskName = taskIdToNameMap.get(taskId);\n if (taskName) {\n acc.push({id: taskId, name: taskName});\n }\n return acc;\n }, [] as Activity[]),\n }));\n\n done({links: ganttData.links, tasks});\n return allIssues;\n });\n\n return loadingEffect.pipe(\n Effect.flatMap(() => createProjectLoader(projectId, fetchAndTransformData)),\n Effect.ensuring(cleanupEffect),\n );\n };\n\n const loadDailiesIssues = ({\n queryParams,\n projectId,\n setLoading,\n }: {\n queryParams: Partial;\n projectId: string;\n setLoading?: (loading: boolean) => void;\n }): Effect.Effect => {\n // Create the loading effect\n const loadingEffect = Effect.sync(() => {\n if (setLoading) {\n setLoading(true);\n }\n });\n\n // Create the cleanup effect\n const cleanupEffect = Effect.sync(() => {\n if (setLoading) {\n setLoading(false);\n }\n });\n\n const fetchIssuesBatch = createFetchDailiesIssuesBatch({\n projectId,\n queryParams,\n });\n\n const fetchData = Effect.gen(function* (_) {\n const allIssues = yield* batchLoader.createBatchLoadEffect({\n batchFn: fetchIssuesBatch,\n fnName: 'loadDailiesIssues',\n projectId,\n });\n\n return allIssues;\n });\n\n return loadingEffect.pipe(\n Effect.flatMap(() => createProjectLoader(projectId, fetchData)),\n Effect.ensuring(cleanupEffect),\n );\n };\n\n return {\n loadIssues,\n loadDailiesIssues,\n } as const;\n});\n\nexport class ConcurrentIssuesLoader extends Effect.Service()('ConcurrentIssuesLoader', {\n effect,\n dependencies: [BatchLoader.Default],\n}) {\n static Test = (mockData?: T[]) => {\n // For success cases with mock data\n if (Array.isArray(mockData) || (mockData && 'tasks' in mockData)) {\n return this.DefaultWithoutDependencies.pipe(\n Layer.provide(\n Layer.succeed(BatchLoader, {\n createBatchLoadEffect: (_config: BatchLoadConfig): Effect.Effect =>\n Effect.succeed(Array.isArray(mockData) ? (mockData as unknown as U[]) : ([mockData] as unknown as U[])),\n _tag: 'BatchLoader' as const,\n }),\n ),\n );\n }\n\n // Default case for error testing\n const defaultBatchLayer = Layer.succeed(BatchLoader, {\n createBatchLoadEffect: (config: BatchLoadConfig): Effect.Effect => {\n return Effect.gen(function* () {\n const response = yield* config.batchFn(0, config.batchSize, null);\n return response.data;\n });\n },\n _tag: 'BatchLoader' as const,\n });\n\n return this.DefaultWithoutDependencies.pipe(Layer.provide(defaultBatchLayer));\n };\n}\n","import axios, {CancelToken} from 'axios';\nimport {Effect} from 'effect';\nimport {InterruptedException, UnknownException} from 'effect/Cause';\n\nimport ProjectsApi from 'api/projects';\nimport {TaskDependencyDto} from 'shared/models/TaskDependency';\n\nimport {ApiResponse} from '../BatchLoader';\nimport {BadGatewayError, EffectError, HttpError} from '../errors';\n\nexport const createProjecDepsEffect = ({projectId, taskIds}: {projectId: string; taskIds: string[]}) => {\n return (\n offset: number,\n take: number,\n cancelToken: CancelToken,\n ): Effect.Effect, EffectError, never> =>\n Effect.tryPromise({\n try: () =>\n ProjectsApi.getTaskDependencies(projectId, taskIds, {\n offset,\n limit: take,\n cancelToken,\n }),\n catch: (error): EffectError => {\n if (axios.isCancel(error)) {\n return new InterruptedException('Request cancelled');\n }\n\n if (axios.isAxiosError(error)) {\n switch (error.response?.status) {\n case 502:\n return new BadGatewayError({\n message: error.message,\n cause: error,\n });\n default:\n return new HttpError({\n statusCode: error.response?.status || 500,\n message: error.message,\n cause: error,\n });\n }\n }\n\n return new UnknownException({\n message: error instanceof Error ? error.message : 'Unknown error',\n cause: error instanceof Error ? error : undefined,\n });\n },\n }).pipe(\n Effect.map((response) => ({\n data: response.data.dependencies,\n headers: response.headers,\n })),\n );\n};\n","/* eslint-disable @typescript-eslint/naming-convention */\n/* eslint-disable new-cap */\nimport {Effect, Layer} from 'effect';\nimport {InterruptedException} from 'effect/Cause';\n\nimport {LoadProjectOptions} from 'modules/Tasks/components/Gantt/types';\nimport {TaskDependencyDto} from 'shared/models/TaskDependency';\n\nimport {createProjecDepsEffect} from './api/createProjecDepsEffect';\nimport {BatchLoader, BatchLoadConfig} from './BatchLoader';\nimport {EffectError} from './errors';\nimport {createProjectLoader} from './helpers';\n\nconst effect = Effect.gen(function* () {\n const batchLoader = yield* BatchLoader;\n\n const loadDependencies = ({\n projectId,\n taskIds,\n }: LoadProjectOptions): Effect.Effect => {\n if (!projectId) {\n return Effect.fail(new Error('Project ID is required'));\n }\n\n const fetchProjectDepsBatch = createProjecDepsEffect({\n projectId,\n taskIds,\n });\n\n const batchEffect = batchLoader.createBatchLoadEffect({\n batchFn: fetchProjectDepsBatch,\n fnName: 'fetchProjectDepsBatch',\n projectId,\n batchSize: 6_000,\n });\n\n return createProjectLoader(projectId, batchEffect);\n };\n\n return {\n loadDependencies,\n };\n});\n\nexport class ConcurrentProjectLoader extends Effect.Service()('ConcurrentProjectLoader', {\n effect,\n dependencies: [BatchLoader.Default],\n}) {\n static Test = (mockData?: T[]) => {\n // For success cases with mock data\n if (Array.isArray(mockData) || (mockData && 'tasks' in mockData)) {\n return this.DefaultWithoutDependencies.pipe(\n Layer.provide(\n Layer.succeed(BatchLoader, {\n createBatchLoadEffect: (_config: BatchLoadConfig): Effect.Effect =>\n Effect.succeed(Array.isArray(mockData) ? (mockData as unknown as U[]) : ([mockData] as unknown as U[])),\n _tag: 'BatchLoader' as const,\n }),\n ),\n );\n }\n\n // Default case for error testing\n const defaultBatchLayer = Layer.succeed(BatchLoader, {\n createBatchLoadEffect: (config: BatchLoadConfig): Effect.Effect => {\n return Effect.gen(function* () {\n const response = yield* config.batchFn(0, config.batchSize, null);\n return response.data;\n });\n },\n _tag: 'BatchLoader' as const,\n });\n\n return this.DefaultWithoutDependencies.pipe(Layer.provide(defaultBatchLayer));\n };\n}\n","import axios, {CancelToken} from 'axios';\nimport {Effect, Schedule, Duration} from 'effect';\nimport {InterruptedException, UnknownException} from 'effect/Cause';\n\nimport TasksApi from 'api/tasks';\nimport {SortOrder} from 'shared/constants/common';\nimport {SortField, TaskProjection} from 'shared/models/task/const';\nimport {TaskFilterQuery, TaskStatusQuery} from 'shared/models/task/filter';\nimport {TaskDetailsModelDTO, TaskModelRawDTO} from 'shared/models/task/task';\n\nimport {ApiResponse} from '../BatchLoader';\nimport {EffectError, BadGatewayError, HttpError} from '../errors';\n\nexport const createFetchBatch = (\n params: Partial,\n): ((\n offset: number,\n take: number,\n cancelToken: CancelToken,\n) => Effect.Effect, EffectError, never>) => {\n return (offset: number, take: number, cancelToken: CancelToken) =>\n Effect.tryPromise({\n try: () =>\n TasksApi.getProjectTasks({\n projection: TaskProjection.task,\n offset,\n limit: take,\n sortField: 'outline_sort_key',\n sortOrder: SortOrder.ASC,\n includeSummaryTasks: true,\n params,\n cancelToken,\n }),\n catch: (error): EffectError => {\n if (axios.isCancel(error)) {\n return new InterruptedException('Request cancelled');\n }\n\n if (axios.isAxiosError(error)) {\n switch (error.response?.status) {\n case 502:\n return new BadGatewayError({\n message: error.message,\n cause: error,\n });\n default:\n return new HttpError({\n statusCode: error.response?.status || 500,\n message: error.message,\n cause: error,\n });\n }\n }\n return new UnknownException({\n message: error instanceof Error ? error.message : 'Unknown error',\n cause: error instanceof Error ? error : undefined,\n });\n },\n }).pipe(\n Effect.map((response) => ({\n data: response.data as unknown as TaskDetailsModelDTO[],\n headers: response.headers,\n })),\n Effect.retry(Schedule.exponential(Duration.seconds(2)).pipe(Schedule.compose(Schedule.recurs(3)))),\n );\n};\n\nexport const createAllTasksFetchBatch = ({\n filterParams,\n}: {\n filterParams: Partial;\n}) => {\n return (\n offset: number,\n take: number,\n cancelToken: CancelToken,\n ): Effect.Effect, EffectError, never> =>\n Effect.tryPromise({\n try: () =>\n TasksApi.getV2ProjectTasks({\n offset,\n limit: take,\n sortField: SortField.outlineSortKey,\n sortOrder: SortOrder.ASC,\n params: filterParams,\n cancelToken,\n }),\n catch: (error): EffectError => {\n if (axios.isCancel(error)) {\n return new InterruptedException('Request cancelled');\n }\n\n if (axios.isAxiosError(error)) {\n switch (error.response?.status) {\n case 502:\n return new BadGatewayError({\n message: error.message,\n cause: error,\n });\n default:\n return new HttpError({\n statusCode: error.response?.status || 500,\n message: error.message,\n cause: error,\n });\n }\n }\n\n return new UnknownException({\n message: error instanceof Error ? error.message : 'Unknown error',\n cause: error instanceof Error ? error : undefined,\n });\n },\n }).pipe(\n Effect.map((response) => {\n const allTasks = response.data.tasks;\n const summaryTasks = response?.data?.summary_tasks ?? [];\n allTasks.push(...summaryTasks);\n\n return {\n data: allTasks as TaskModelRawDTO[],\n headers: response.headers,\n };\n }),\n );\n};\n","/* eslint-disable @typescript-eslint/naming-convention */\nimport {Effect, Cause, Layer} from 'effect';\nimport {camelizeKeys} from 'humps';\n\nimport {toShortIso} from 'shared/helpers/dates';\nimport {toGanttTaskModel} from 'shared/mapping/task';\nimport {TaskObjectType} from 'shared/models/task/const';\nimport {TaskFilterQuery, TaskStatusQuery} from 'shared/models/task/filter';\nimport {TaskGanttModel, TaskModelRawDTO} from 'shared/models/task/task';\nimport {TaskStatusType} from 'shared/models/task/taskStatus';\n\nimport {createAllTasksFetchBatch, createFetchBatch} from './api/createTasksEffect';\nimport {BatchLoadConfig, BatchLoader} from './BatchLoader';\nimport {EffectError} from './errors';\nimport {createProjectLoader} from './helpers';\n\nconst effect = Effect.gen(function* () {\n const batchLoader = yield* BatchLoader; // 👈 Create dependency\n\n const loadTasksOnGantt = (\n params: Partial,\n setLoading?: (loading: boolean) => void,\n ): Effect.Effect => {\n const requestProjectId = params.projectId;\n\n if (!requestProjectId) {\n return Effect.fail(new Error('Project ID is required'));\n }\n\n // Create the loading effect\n const loadingEffect = Effect.sync(() => {\n if (setLoading) {\n setLoading(true);\n }\n });\n\n // Create the cleanup effect\n const cleanupEffect = Effect.sync(() => {\n if (setLoading) {\n setLoading(false);\n }\n });\n\n // Create the fetch batch\n const fetchBatch = createFetchBatch(params);\n\n // Create the batch effect\n const batchEffect = batchLoader.createBatchLoadEffect({\n batchFn: fetchBatch,\n fnName: 'loadTasks',\n projectId: requestProjectId,\n });\n\n // Transform the results\n const transformedEffect = batchEffect.pipe(\n Effect.map((results) => results.map((t) => toGanttTaskModel(camelizeKeys(t)))),\n Effect.catchAll((error) => (!Cause.isInterruptedException(error) ? Effect.fail(error) : Effect.succeed([]))),\n );\n\n // Combine all effects\n return loadingEffect.pipe(\n Effect.flatMap(() => createProjectLoader(requestProjectId, transformedEffect)),\n Effect.ensuring(cleanupEffect),\n );\n };\n\n const loadAllTasks = (\n projectId: string,\n loadDeleted = false,\n ): Effect.Effect => {\n const filterParams = {\n objectTypeList: [TaskObjectType.milestone, TaskObjectType.activity, TaskObjectType.task, TaskObjectType.summary],\n projectId,\n deleted: loadDeleted,\n };\n\n const fetchBatch = createAllTasksFetchBatch({\n filterParams,\n });\n\n const batchEffect = batchLoader.createBatchLoadEffect({\n batchFn: fetchBatch,\n fnName: 'loadAllTasks',\n projectId,\n });\n\n return createProjectLoader(projectId, batchEffect);\n };\n\n const fetchTasksByDate = (projectId: string, begin: Date, end: Date, setLoading?: (loading: boolean) => void) =>\n loadTasksOnGantt(\n {\n schedIntersect: [toShortIso(begin), toShortIso(end)],\n objectTypeList: ['task', 'activity'],\n projectId,\n },\n setLoading,\n );\n\n const fetchBlockedTasks = (projectId: string, setLoading?: (loading: boolean) => void) =>\n loadTasksOnGantt(\n {\n objectTypeList: ['task', 'activity'],\n status: TaskStatusType.blocked,\n projectId,\n },\n setLoading,\n );\n\n return {\n fetchBlockedTasks,\n fetchTasksByDate,\n loadAllTasks,\n } as const;\n});\n\n// eslint-disable-next-line new-cap\nexport class ConcurrentTaskLoader extends Effect.Service()('ConcurrentTaskLoader', {\n effect,\n dependencies: [BatchLoader.Default],\n}) {\n static Test = (mockData?: T[]) => {\n // For success cases with mock data\n if (Array.isArray(mockData)) {\n return this.DefaultWithoutDependencies.pipe(\n Layer.provide(\n Layer.succeed(BatchLoader, {\n createBatchLoadEffect: (_config: BatchLoadConfig): Effect.Effect =>\n Effect.succeed(mockData as unknown as U[]),\n _tag: 'BatchLoader' as const,\n }),\n ),\n );\n }\n\n // Default case for error testing\n const defaultBatchLayer = Layer.succeed(BatchLoader, {\n createBatchLoadEffect: (config: BatchLoadConfig): Effect.Effect => {\n return Effect.gen(function* () {\n const response = yield* config.batchFn(0, config.batchSize, null);\n return response.data;\n });\n },\n _tag: 'BatchLoader' as const,\n });\n\n return this.DefaultWithoutDependencies.pipe(Layer.provide(defaultBatchLayer));\n };\n}\n","/* eslint-disable @typescript-eslint/naming-convention */\nimport {Dayjs} from 'dayjs';\nimport {Effect} from 'effect';\nimport {InterruptedException} from 'effect/Cause';\n\nimport {ConcurrentActivityIdsLoader} from 'services/Effect/ActivityIdsLoader';\nimport {EffectError} from 'services/Effect/errors';\nimport {runLoaderEffect} from 'services/Effect/helpers';\nimport {ConcurrentIssuesLoader} from 'services/Effect/IssuesLoader';\nimport {ConcurrentProjectLoader} from 'services/Effect/ProjectLoader';\nimport {ConcurrentTaskLoader} from 'services/Effect/TasksLoader';\nimport {TaskFilterQuery} from 'shared/models/task/filter';\nimport {IssueModelRawDTO, TaskGanttModel, TaskListMinimalModel, TaskModelRawDTO} from 'shared/models/task/task';\nimport {TaskDependencyDto} from 'shared/models/TaskDependency';\n\nimport {LoadOptions} from '../types';\n\nexport type LoaderOptions = {\n name: string;\n projectId: string;\n extra?: Record;\n};\n\nexport async function loadActivityIds(options: LoadOptions) {\n const program = Effect.gen(function* () {\n const activityLoader = yield* ConcurrentActivityIdsLoader;\n const result = yield* activityLoader.loadActivityIds(options);\n return result as TaskListMinimalModel[];\n }).pipe(Effect.map((result) => result as TaskListMinimalModel[]));\n\n return runLoaderEffect(\n program,\n ConcurrentActivityIdsLoader.Default,\n {\n name: 'loadActivityIds',\n projectId: options.projectId,\n extra: {\n queryParams: options.queryParams,\n dataRange: options.dataRange,\n },\n },\n );\n}\n\nexport async function loadAllTasks(projectId: string, loadDeleted: boolean) {\n const program = Effect.gen(function* () {\n const taskLoader = yield* ConcurrentTaskLoader;\n const result = yield* taskLoader.loadAllTasks(projectId, loadDeleted);\n return result;\n }).pipe(Effect.map((result) => result));\n\n return runLoaderEffect(program, ConcurrentTaskLoader.Default, {\n name: 'loadAllTasks',\n projectId,\n });\n}\n\nexport async function loadIssues(options: LoadOptions) {\n const program = Effect.gen(function* () {\n const issuesLoader = yield* ConcurrentIssuesLoader;\n const result = yield* issuesLoader.loadIssues(options);\n return result;\n }).pipe(Effect.map((result) => result as IssueModelRawDTO[]));\n\n return runLoaderEffect(\n program,\n ConcurrentIssuesLoader.Default,\n {\n name: 'loadIssues',\n projectId: options.projectId,\n extra: {\n queryParams: options.queryParams,\n dataRange: options.dataRange,\n },\n },\n );\n}\n\nexport async function fetchTasksByDate(projectId: string, begin: Dayjs, end: Dayjs) {\n const program = Effect.gen(function* () {\n const taskLoader = yield* ConcurrentTaskLoader;\n return yield* taskLoader.fetchTasksByDate(projectId, begin.toDate(), end.toDate());\n });\n\n return runLoaderEffect(program, ConcurrentTaskLoader.Default, {\n name: 'fetchTasksByDate',\n projectId,\n });\n}\n\nexport async function fetchBlockedTasks(projectId: string) {\n const program = Effect.gen(function* () {\n const taskLoader = yield* ConcurrentTaskLoader;\n return yield* taskLoader.fetchBlockedTasks(projectId);\n });\n\n return runLoaderEffect(program, ConcurrentTaskLoader.Default, {\n name: 'fetchBlockedTasks',\n projectId,\n });\n}\n\nexport async function loadDailiesIssues(projectId: string, queryParams: Partial) {\n const program = Effect.gen(function* () {\n const issuesLoader = yield* ConcurrentIssuesLoader;\n return yield* issuesLoader.loadDailiesIssues({\n projectId,\n queryParams,\n });\n }).pipe(Effect.map((result) => result as IssueModelRawDTO[]));\n\n return runLoaderEffect(\n program,\n ConcurrentIssuesLoader.Default,\n {\n name: 'loadDailiesIssues',\n projectId,\n extra: {\n queryParams,\n },\n },\n );\n}\n\nexport async function loadProjectDependencies(projectId: string, taskIds: string[] = []) {\n const program = Effect.gen(function* () {\n const dependenciesLoader = yield* ConcurrentProjectLoader;\n const result = yield* dependenciesLoader.loadDependencies({\n projectId,\n taskIds,\n });\n\n if (result instanceof InterruptedException) {\n return [] as TaskDependencyDto[];\n }\n\n return result;\n }).pipe(Effect.map((result) => result));\n\n return runLoaderEffect(\n program,\n ConcurrentProjectLoader.Default,\n {\n name: 'loadProjectDependancies',\n projectId,\n },\n );\n}\n","import {GanttTask} from 'modules/Tasks/components/Gantt/types';\nimport {TaskStatusType} from 'shared/models/task/taskStatus';\n\nexport const statusColors: Record = {\n [TaskStatusType.tba]: '#ff7c43',\n [TaskStatusType.assigned]: '#bc5eaa',\n [TaskStatusType.inProgress]: '#4764a4',\n [TaskStatusType.rework]: '#ffd777',\n [TaskStatusType.blocked]: '#de425b',\n [TaskStatusType.done]: '#45cba3',\n [TaskStatusType.verified]: '#88b388',\n [TaskStatusType.approved]: '#0b991b',\n [TaskStatusType.archived]: '#818181',\n [TaskStatusType.closed]: '#000000',\n [TaskStatusType.unblocked]: '#cccccc', // TODO: need color\n [TaskStatusType.notDone]: '#cccccc', // TODO: need color\n};\n\nexport function getTaskColorByStatus(taskStatus: TaskStatusType, fallbackColor = '#A1A1A1'): string {\n const MAP_TASK_STATUS_TO_COLOR = {\n [TaskStatusType.tba]: '#A1A1A1',\n [TaskStatusType.assigned]: '#122D8B',\n [TaskStatusType.inProgress]: '#5779F2',\n [TaskStatusType.unblocked]: '#5779F2',\n [TaskStatusType.blocked]: '#FA380D',\n [TaskStatusType.done]: '#63E37F',\n [TaskStatusType.notDone]: '#DB9F06',\n [TaskStatusType.verified]: '#089326',\n [TaskStatusType.closed]: '#282828',\n };\n return MAP_TASK_STATUS_TO_COLOR[taskStatus] || fallbackColor;\n}\n\nexport function getLaborColorForDate(task: GanttTask, date: string, fallbackColor = '#A1A1A1'): string {\n const projectedLabor = task.projected_labor ? Number(task.projected_labor) : null;\n if (projectedLabor === null) {\n return fallbackColor;\n }\n\n const dailyLaborFeedback = task.feedback_by_date.find((fb) => fb.field === 'daily_labor');\n if (!dailyLaborFeedback || !dailyLaborFeedback.feedback_by_date) {\n return fallbackColor;\n }\n\n const laborEntry = dailyLaborFeedback.feedback_by_date.find((entry) => entry.date === date);\n if (!laborEntry) {\n return fallbackColor;\n }\n\n const actualLabor = Number(laborEntry.value);\n\n if (actualLabor < projectedLabor) {\n return '#FA380D'; // Under projected labor\n } else if (actualLabor === projectedLabor) {\n return '#0b991b'; // Exactly at projected labor\n } else {\n return '#FFA500'; // Over projected labor\n }\n}\n\nexport const orderedStatusList: TaskStatusType[] = [\n TaskStatusType.closed,\n TaskStatusType.archived,\n TaskStatusType.approved,\n TaskStatusType.verified,\n TaskStatusType.done,\n TaskStatusType.blocked,\n TaskStatusType.unblocked,\n TaskStatusType.notDone,\n TaskStatusType.rework,\n TaskStatusType.inProgress,\n TaskStatusType.assigned,\n TaskStatusType.tba,\n];\n","import * as Sentry from '@sentry/react';\nimport {GanttStatic} from 'dhtmlx-gantt';\n\nimport {reactQueryClient} from 'App';\nimport {GanttTask, InlineEditorState} from 'modules/Tasks/components/Gantt/types';\nimport {GANTT_PREFERENCES_KEY, TasksViewMode} from 'shared/constants/common';\nimport {toShortIso} from 'shared/helpers/dates';\nimport {getTaskChangedFieldsOnly} from 'shared/helpers/task';\nimport Gantt from 'shared/models/Gantt';\nimport {TaskObjectType} from 'shared/models/task/const';\nimport {TaskColorMode, IssueStatusTaskIDsPair} from 'shared/models/task/task';\nimport {TaskStatusType} from 'shared/models/task/taskStatus';\n\nimport {getLaborColorForDate, getTaskColorByStatus} from '../../Dashboard/meta';\n\nimport {getCachedOrg} from './utils';\n\nexport function getTaskFeedback(task: GanttTask, specificDate: string, field: 'daily_labor' | 'progress'): string {\n const formattedDate = toShortIso(specificDate);\n\n if (task.feedback_by_date) {\n const feedbackEntry = task.feedback_by_date.find((entry) => entry.field === field);\n\n if (feedbackEntry) {\n const feedbackItem = feedbackEntry.feedback_by_date.find((item) => item.date === formattedDate);\n\n if (feedbackItem) {\n return feedbackItem.value?.toString();\n }\n }\n }\n\n return '-';\n}\n\nexport function getFormattedTaskFeedback(task: GanttTask, date: string, field: 'daily_labor' | 'progress'): string {\n const feedback = getTaskFeedback(task, date, field);\n return feedback !== '-' ? `${feedback}` : '-';\n}\n\nexport function getColorTasksModeFromLocalStorage(projectId: string): string {\n const storageKey = GANTT_PREFERENCES_KEY;\n const storedPreferences = localStorage.getItem(storageKey);\n\n if (storedPreferences) {\n try {\n const preferences = JSON.parse(storedPreferences);\n\n const projectPreferences = preferences?.byProject?.[projectId];\n\n if (projectPreferences && 'colorTasksMode' in projectPreferences) {\n return projectPreferences.colorTasksMode;\n } else {\n return 'default';\n }\n } catch (error) {\n Sentry.captureException(error, {\n tags: {\n name: 'getColorTasksModeFromLocalStorage',\n },\n });\n }\n }\n return 'default';\n}\n\nexport const calculateRowHeight = (rowHeight) => Math.round((rowHeight * 0.92 + Number.EPSILON) * 10) / 10;\n\nexport function refreshTask(gantt: GanttStatic, id: string | number, updates: Partial) {\n const task = gantt.getTask(id) as GanttTask;\n const inlineEditors = gantt.ext.inlineEditors;\n if (task) {\n // don't overwrite task fields which is in queue to update\n if (task.lastChangedFields) {\n for (const field in task.lastChangedFields) {\n if (field in updates) {\n delete updates[field];\n }\n }\n }\n Object.assign(task, updates);\n task?.sourceDeps?.forEach(({id}) => {\n gantt.refreshLink(id);\n });\n task?.targetDeps?.forEach(({id}) => {\n gantt.refreshLink(id);\n });\n if (inlineEditors) {\n const editorState = inlineEditors.getState() as InlineEditorState;\n const columnName = editorState.columnName;\n const changedFields = Object.keys(getTaskChangedFieldsOnly(task, updates, ['id', 'projectId']) || []);\n if (gantt.ext.inlineEditors.isVisible() && changedFields.includes(columnName)) {\n inlineEditors.setValue();\n }\n }\n }\n}\n\nexport function updateCollapseIcon(gantt: GanttStatic, parentId: string, childrenChange = 0) {\n const parent = gantt.isTaskExists(parentId) && gantt.getTask(parentId);\n if (parent) {\n const hasChild = parent.has_child;\n const diff = hasChild + childrenChange || 0;\n parent.$has_child = diff;\n parent.has_child = diff;\n if (!diff) {\n parent.object_type = TaskObjectType.activity;\n parent.open = false;\n }\n gantt.refreshTask(parentId);\n }\n}\n\nexport function reloadProjectData() {\n Gantt.list().forEach((inst) => {\n inst.needReload = true;\n inst.callEvent('afterTasksImport', []);\n });\n}\n\nexport function getTaskColor(gantt: GanttStatic, task: GanttTask, specificDate = ''): string {\n const defaultColor = 'rgba(128, 128, 128)';\n let color = defaultColor;\n const org = getCachedOrg({\n id: task.responsible_org_id,\n projectId: task.projectId,\n queryClient: reactQueryClient,\n });\n\n if (specificDate && task.per_date_override[specificDate]?.lookahead_color) {\n color = gantt.subcontractorColors?.[task.per_date_override[specificDate]?.lookahead_color]?.fill ?? defaultColor;\n } else {\n switch (gantt.taskColorMode) {\n case TaskColorMode.COMPANY:\n color = task.lookahead_color\n ? gantt.subcontractorColors?.[task.lookahead_color]?.fill ?? defaultColor\n : gantt.subcontractorColors?.[org?.lookaheadColor]?.fill ?? defaultColor;\n break;\n case TaskColorMode.STATUS:\n color = getTaskColorByStatus(task.status);\n break;\n case TaskColorMode.LABOR:\n color = getLaborColorForDate(task, specificDate);\n break;\n default:\n color = defaultColor;\n }\n }\n\n return color;\n}\n\nexport function getTaskAbbrev(gantt: GanttStatic, task: GanttTask, specificDate: Date): string {\n const formattedDate = toShortIso(specificDate);\n const org = getCachedOrg({\n id: task.responsible_org_id,\n projectId: task.projectId,\n queryClient: reactQueryClient,\n });\n\n if (task.per_date_override?.[formattedDate]?.abbrev) {\n return task.per_date_override[formattedDate].abbrev;\n }\n if (task.abbrev) {\n return task.abbrev;\n }\n if (org?.abbrev) {\n return org?.abbrev;\n }\n return '';\n}\n\nexport function isValidViewMode(viewMode: string): boolean {\n return Object.values(TasksViewMode).includes(viewMode as unknown as TasksViewMode);\n}\n\nexport function getTaskOpenIssuesIds(taskIssues: IssueStatusTaskIDsPair[]): string[] {\n const openIssuesIds = taskIssues?.reduce((acc, pair) => {\n if (pair.issue_task_status !== TaskStatusType.closed && pair.issue_task_ids.length) {\n return acc.concat(pair.issue_task_ids);\n }\n return acc;\n }, []);\n\n return Array.from(new Set(openIssuesIds || []));\n}\n","import * as Sentry from '@sentry/react';\nimport {QueryClient} from '@tanstack/react-query';\nimport {GanttStatic} from 'dhtmlx-gantt';\n\nimport {SafeParseResult} from 'modules/Tasks/types/safeParse';\nimport {ObserverAction, ObserverActionSource} from 'services/TasksObserver/const';\nimport {TasksObserver} from 'services/TasksObserver/TasksObserver';\nimport {QUERY_CACHE_KEYS} from 'shared/constants/queryCache';\nimport {CompanyOrgs} from 'shared/models/company';\nimport {ProjectModel} from 'shared/models/project';\nimport {TaskProjection} from 'shared/models/task/const';\nimport {TaskDetailsModelDTO} from 'shared/models/task/task';\n\nexport const batchUpdateSelectedTasks = (\n gantt: GanttStatic,\n data: PromiseFulfilledResult[],\n project: ProjectModel,\n observer: TasksObserver,\n) => {\n gantt.batchUpdate(function () {\n gantt.eachSelectedTask(function (taskId: string) {\n const updatedTask = data.find((promise) => promise.value.id === taskId)?.value;\n if (updatedTask) {\n updateTasksCache(observer, updatedTask);\n }\n });\n });\n};\n\nconst updateTasksCache = (observer: TasksObserver, task: TaskDetailsModelDTO) => {\n observer.emit([{data: task}], {\n action: ObserverAction.update,\n projectId: task.projectId,\n projection: TaskProjection.taskDetail,\n source: ObserverActionSource.bulk,\n });\n};\n\nexport function safeParseJSON(json: string): SafeParseResult {\n try {\n const parsed = JSON.parse(json);\n return {\n success: true,\n data: parsed as T,\n };\n } catch (error) {\n Sentry.captureException(error);\n return {\n success: false,\n error: error instanceof Error ? error : new Error('Failed to parse JSON'),\n };\n }\n}\n\nexport function getCachedOrg({queryClient, projectId, id}: {queryClient: QueryClient; projectId: string; id: string}) {\n const orgs = queryClient.getQueryData(QUERY_CACHE_KEYS.projectSubcontractors(projectId));\n return (orgs || []).find((org) => org.id === id);\n}\n","/* eslint-disable @typescript-eslint/naming-convention */\n/* eslint-disable new-cap */\nimport * as Sentry from '@sentry/react';\nimport {AxiosError} from 'axios';\nimport {Effect, Schedule, Duration, Either} from 'effect';\nimport {sleep} from 'effect/Clock';\n\nimport {CompletePercentageFunc} from 'shared/helpers/api';\n\nimport {BadGatewayError, GatewayTimeoutError, HttpError, NetworkError, EffectError} from './errors';\n\nexport type PollingConfig = {\n importId: string;\n maxWaitSec: number;\n completePercentage?: CompletePercentageFunc;\n fetcher: () => Promise<{data: R}>;\n};\n\n// Helper function to determine if an error is retryable\nexport const isRetryableError = (error: EffectError): boolean => {\n if (error instanceof BadGatewayError || error instanceof GatewayTimeoutError) {\n return true;\n }\n if (error instanceof HttpError) {\n // Only retry specific HTTP status codes\n return error.statusCode === 502 || error.statusCode === 504;\n }\n if (error instanceof NetworkError) {\n return true;\n }\n\n // For AxiosError or other Error types\n const axiosError = error as AxiosError;\n return (\n !axiosError.response || // Network error\n axiosError.code === 'ECONNABORTED' || // Timeout\n axiosError.response?.status === 502 ||\n axiosError.response?.status === 504\n );\n};\n\nconst mapError = (error: unknown, context: string): EffectError => {\n const axiosError = error as AxiosError;\n\n if (axiosError.response) {\n const statusCode = axiosError.response.status;\n\n if (statusCode === 502) {\n return new BadGatewayError({\n message: `Bad Gateway error (502) in ${context}`,\n cause: error as Error,\n });\n }\n\n if (statusCode === 504) {\n return new GatewayTimeoutError({\n message: `Gateway Timeout error (504) in ${context}`,\n cause: error as Error,\n });\n }\n\n return new HttpError({\n statusCode,\n message: `HTTP error ${statusCode} in ${context}`,\n cause: error as Error,\n });\n }\n\n // Network errors or ECONNABORTED\n if (!axiosError.response || axiosError.code === 'ECONNABORTED') {\n return new NetworkError({\n message: `Network error in ${context}: ${axiosError.message}`,\n cause: error as Error,\n });\n }\n\n return new NetworkError({\n message: `Unknown error in ${context}: ${error instanceof Error ? error.message : String(error)}`,\n cause: error instanceof Error ? error : undefined,\n });\n};\n\n// Convert a Promise-based fetcher to an Effect\nconst createFetcherEffect = (\n fetcher: () => Promise<{data: R}>,\n) => {\n return Effect.flatMap(\n Effect.tryPromise({\n try: fetcher,\n catch: (error) => {\n const _error = mapError(error, 'PollingService.fetch');\n return _error;\n },\n }),\n (result) => Effect.succeed(result),\n );\n};\n\nconst effect = Effect.gen(function* () {\n // Poll function that exactly mimics the behavior of existing pollResults function\n // but adds retry logic for errors\n const poll = (\n config: PollingConfig,\n ): Effect.Effect => {\n const {maxWaitSec, completePercentage, fetcher} = config;\n\n return Effect.gen(function* (_) {\n const fetcherEffect = createFetcherEffect(fetcher);\n\n const maxRetries = 5;\n const retryPolicy = Schedule.exponential(Duration.seconds(1), 1.5)\n .pipe(Schedule.compose(Schedule.recurs(maxRetries)))\n .pipe(\n Schedule.whileInput((error: EffectError) => {\n const shouldRetry = isRetryableError(error);\n if (shouldRetry) {\n Sentry.captureMessage(`Polling retry attempt due to error`, {\n level: 'warning',\n tags: {\n context: 'PollingService.retry',\n importId: config.importId,\n },\n extra: {\n error,\n },\n });\n }\n return shouldRetry;\n }),\n );\n\n const retryableFetcher = fetcherEffect.pipe(\n Effect.retry(retryPolicy),\n Effect.catchAll((error) => Effect.fail(error)),\n );\n\n // Attempt to execute the retryableFetcher effect and capture the result as Either\n const respOrFailure = yield* _(Effect.either(retryableFetcher));\n // Check if the response is an error (Left variant of Either)\n const isError = Either.isLeft(respOrFailure);\n let data: R;\n if (!isError) {\n // If no error, extract the data from the Right variant\n data = respOrFailure.right.data;\n } else {\n // If an error occurred, extract it from the Left variant\n const error = respOrFailure.left;\n if (error) {\n // Propagate the error by failing the effect\n yield* _(Effect.fail(error));\n return;\n }\n }\n let iters = 1;\n\n // Report initial progress\n if (typeof completePercentage === 'function' && typeof data.progressPercent === 'number') {\n completePercentage(data.progressPercent);\n }\n\n // Poll until completion or max wait time\n while (data && (data.status === 'queued' || data.status === 'running') && iters < maxWaitSec) {\n // Wait between polls - use same delay as existing code\n const pollDelay = 5000;\n yield* _(sleep(pollDelay));\n\n // Fetch again with retry capability\n const response = yield* _(retryableFetcher);\n if (completePercentage && typeof response.data.progressPercent === 'number') {\n completePercentage(response.data.progressPercent);\n }\n data = response.data;\n iters += 1;\n }\n\n return data;\n });\n };\n\n // Helper to directly run the effect and return a Promise\n const runPoll = (config: PollingConfig): Promise => {\n return Effect.runPromise(poll(config));\n };\n\n return {poll, runPoll} as const;\n});\n\n// Create the service class\nexport class PollingService extends Effect.Service()('PollingService', {\n effect,\n}) {}\n","import {Effect} from 'effect';\n\nimport {PollingConfig, PollingService} from 'services/Effect/Polling';\n\nexport async function runPollingEffect(\n config: PollingConfig,\n): Promise {\n const pollingService = Effect.gen(function* () {\n const service = yield* PollingService;\n // Pass all original config properties along with empty callback handlers\n const result = yield* service.poll(config);\n return result;\n });\n\n return Effect.runPromise(Effect.provide(pollingService, PollingService.Default));\n}\n","/* eslint-disable new-cap */\nimport {Data} from 'effect';\nimport {InterruptedException, UnknownException} from 'effect/Cause';\n\nexport class BadGatewayError extends Data.TaggedError('BadGatewayError')<{\n message: string;\n cause?: Error;\n}> {}\n\nexport class HttpError extends Data.TaggedError('HttpError')<{\n statusCode: number;\n message: string;\n cause?: Error;\n}> {}\n\nexport class GatewayTimeoutError extends Data.TaggedError('GatewayTimeoutError')<{\n message: string;\n cause?: Error;\n}> {}\n\nexport class NetworkError extends Data.TaggedError('NetworkError')<{\n message: string;\n cause?: Error;\n}> {}\n\nexport type EffectError =\n | Error\n | InterruptedException\n | HttpError\n | BadGatewayError\n | UnknownException\n | GatewayTimeoutError\n | NetworkError;\n","/* eslint-disable no-console */\nimport {SerializedError} from '@reduxjs/toolkit';\nimport * as Sentry from '@sentry/browser';\nimport axios, {isAxiosError} from 'axios';\nimport {Duration, Effect, Layer, Schedule} from 'effect';\nimport {InterruptedException} from 'effect/Cause';\n\nimport {LoaderOptions} from 'modules/Tasks/components/Gantt/utils/load';\nimport {serializeError} from 'store/utils/serializeError';\n\nimport {EffectError} from '../errors';\n\nexport const calculateBatchParameters = (total: number, configuredBatchSize?: number) => {\n // Handle negative numbers and ensure total is non-negative\n const safeTotal = Math.max(0, total);\n\n // Handle invalid configuredBatchSize\n const safeBatchSize = configuredBatchSize && configuredBatchSize > 0 ? configuredBatchSize : 1_000;\n\n // For very small datasets, just load everything in one batch\n if (safeTotal <= 100) {\n return {\n batchSize: safeTotal,\n batchCount: safeTotal === 0 ? 1 : Math.ceil(safeTotal / safeTotal),\n concurrency: 1,\n };\n }\n\n // For small datasets (101-500 items), use 2 batches\n if (safeTotal <= 500) {\n const batchSize = Math.ceil(safeTotal / 2);\n return {\n batchSize,\n batchCount: Math.ceil(safeTotal / batchSize),\n concurrency: 2,\n };\n }\n\n // For medium datasets (501-750), use 3 batches\n if (safeTotal <= 750) {\n const batchSize = Math.ceil(safeTotal / 3);\n return {\n batchSize,\n batchCount: Math.ceil(safeTotal / batchSize),\n concurrency: 3,\n };\n }\n\n // For larger datasets (751-2500), use 5 batches\n if (safeTotal <= 2_500) {\n const batchSize = Math.ceil(safeTotal / 5);\n return {\n batchSize,\n batchCount: Math.ceil(safeTotal / batchSize),\n concurrency: 5,\n };\n }\n\n // For very large datasets (2500-5000), use 10 batches\n if (safeTotal <= 5_000) {\n const batchSize = Math.ceil(safeTotal / 10);\n return {\n batchSize,\n batchCount: Math.ceil(safeTotal / batchSize),\n concurrency: 10,\n };\n }\n\n const IDEAL_BATCH_SIZE = safeBatchSize;\n const MAX_CONCURRENT_REQUESTS = 10;\n // Calculate number of batches needed with ideal batch size\n const batchCount = Math.ceil(safeTotal / IDEAL_BATCH_SIZE);\n // Adjust concurrency based on batch count\n const concurrency = Math.min(batchCount, MAX_CONCURRENT_REQUESTS);\n\n return {\n batchSize: IDEAL_BATCH_SIZE,\n batchCount,\n concurrency,\n };\n};\n\nexport const formatTime = (ms: number) => {\n const MILLISECONDS_IN_SECOND = 1_000;\n const MILLISECONDS_IN_MINUTE = 60_000;\n const DEFAULT_TIME = '0ms';\n const DECIMAL_PLACES = 1;\n const INTEGER_PLACES = 0;\n\n if (!ms || Number.isNaN(ms)) {\n return DEFAULT_TIME;\n }\n\n // Less than a second\n if (ms < MILLISECONDS_IN_SECOND) {\n return `${ms.toFixed(INTEGER_PLACES)}ms`;\n }\n\n // Less than a minute\n if (ms < MILLISECONDS_IN_MINUTE) {\n return `${(ms / MILLISECONDS_IN_SECOND).toFixed(DECIMAL_PLACES)}s`;\n }\n\n // Minutes and seconds\n const minutes = Math.floor(ms / MILLISECONDS_IN_MINUTE);\n const seconds = ((ms % MILLISECONDS_IN_MINUTE) / MILLISECONDS_IN_SECOND).toFixed(DECIMAL_PLACES);\n return `${minutes}m ${seconds}s`;\n};\n\nexport async function runLoaderEffect(\n program: Effect.Effect,\n provider: Layer.Layer,\n options: LoaderOptions,\n): Promise {\n if (!options.name || !options.projectId) {\n throw new Error('Missing required options: name and projectId are required');\n }\n\n const runnable = program.pipe(\n Effect.provide(provider),\n Effect.catchAll((error: E) => {\n if (error instanceof InterruptedException) {\n return Effect.succeed(new InterruptedException('InterruptedException') as T);\n }\n return Effect.fail(error);\n }),\n );\n\n try {\n const result = await Effect.runPromise(runnable);\n return result;\n } catch (error) {\n Sentry.captureException(error, {\n tags: {\n projectId: options.projectId,\n name: options.name,\n },\n extra: options.extra,\n });\n }\n}\n\nexport const createProjectLoader = (\n projectId: string,\n loaderFn: Effect.Effect,\n): Effect.Effect => {\n return Effect.gen(function* (_) {\n // eslint-disable-next-line import/no-named-as-default-member\n const cancelTokenSource = axios.CancelToken.source();\n\n return yield* _(\n loaderFn.pipe(\n Effect.ensuring(\n Effect.sync(() => {\n cancelTokenSource.cancel('Project changed or operation completed');\n }),\n ),\n Effect.withSpan('projectLoader', {\n attributes: {\n projectId,\n cancelToken: cancelTokenSource.token,\n },\n }),\n ),\n );\n });\n};\n\nexport type ImportError = {\n type: 'network' | 'validation' | 'server';\n serialized: SerializedError;\n original?: unknown;\n};\n\ntype RetryConfig = {\n initialDelay?: number;\n maxAttempts?: number;\n backoffFactor?: number;\n /**\n * @property {string} context - Used to identify the source of the error in Sentry\n */\n context: string;\n timeout?: number;\n};\n\nconst isNetworkError = (error: unknown): boolean => {\n if (!isAxiosError(error)) return false;\n\n const networkErrorCodes = [\n 'ECONNABORTED',\n 'ERR_NETWORK',\n 'ERR_CONNECTION_REFUSED',\n 'ETIMEDOUT',\n 'ERR_NETWORK_ACCESS_DENIED',\n ];\n\n return Boolean(\n (error.code && networkErrorCodes.includes(error.code)) || !error.response, // no response typically means network error\n );\n};\n\nconst getErrorType = (error: unknown): ImportError['type'] => {\n // handle non-axios errors\n if (!isAxiosError(error)) {\n return 'server';\n }\n\n // handle network connectivity issues\n if (isNetworkError(error)) {\n return 'network';\n }\n\n // handle http status codes\n const status = error.response?.status;\n if (!status) {\n return 'server';\n }\n\n switch (true) {\n // validation errors\n case status === 422:\n case status === 400:\n return 'validation';\n\n // client errors (4xx) that aren't validation\n case status >= 401 && status <= 499:\n return 'server'; // or could be more specific if needed\n\n // server errors (5xx)\n case status >= 500:\n return 'server';\n\n // fallback for unexpected status codes\n default:\n return 'server';\n }\n};\n\nconst shouldRetryError = (error: ImportError): boolean => {\n // always retry network errors\n if (error.type === 'network') return true;\n\n // retry server errors only if they're > 5xx\n if (error.type === 'server' && isAxiosError(error.original)) {\n const statusCode = error.original.response?.status ?? 500;\n return statusCode > 500; // This is correct - only retry on 501+\n }\n\n return false;\n};\n\nexport const createRetryableEffect = (\n apiCall: () => Promise,\n {initialDelay = 1, maxAttempts = 3, backoffFactor = 1.5, context}: RetryConfig,\n) => {\n return Effect.retry(\n Effect.tryPromise({\n try: apiCall,\n catch: (error: unknown): ImportError => ({\n type: getErrorType(error),\n serialized: serializeError(error),\n original: error,\n }),\n }),\n Schedule.exponential(Duration.seconds(initialDelay), backoffFactor).pipe(\n Schedule.compose(Schedule.recurs(maxAttempts)),\n Schedule.whileInput(shouldRetryError),\n ),\n ).pipe(\n Effect.catchAll((error) => {\n Sentry.captureException(error.serialized, {\n tags: {context, errorType: error.type},\n });\n return Effect.fail(error);\n }),\n );\n};\n","/* eslint-disable import/no-duplicates, import/no-named-as-default, import/no-named-as-default-member*/\nimport {initializeApp} from 'firebase/app';\nimport {\n applyActionCode,\n Auth,\n browserLocalPersistence,\n inMemoryPersistence,\n AuthCredential,\n ConfirmationResult,\n EmailAuthProvider,\n getAuth,\n getMultiFactorResolver,\n linkWithCredential,\n multiFactor,\n MultiFactorInfo,\n PhoneAuthCredential,\n PhoneAuthProvider,\n PhoneMultiFactorGenerator,\n reauthenticateWithCredential,\n RecaptchaVerifier,\n sendEmailVerification,\n sendPasswordResetEmail,\n setPersistence,\n signInAnonymously,\n signInWithCredential,\n signInWithCustomToken,\n signInWithEmailAndPassword,\n signInWithPhoneNumber,\n} from 'firebase/auth';\n\nimport {splitPhoneByCountryCode} from 'shared/constants/common';\n\nimport {FirebaseTokenProvider} from './FirebaseTokenProvider';\n\nconst FirebaseConfig = {\n apiKey: process.env.REACT_APP_FIREBASE_API_KEY,\n authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,\n databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,\n projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,\n storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,\n messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,\n measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,\n};\n\nconst LS_WORKER_ID_KEY = 'workerId';\n\nclass Firebase implements FirebaseTokenProvider {\n public auth: Auth;\n private testPhone = process.env.REACT_APP_TEST_PHONE;\n constructor(config: typeof FirebaseConfig) {\n initializeApp(config);\n this.auth = getAuth();\n }\n get phoneMultiFactorGenerator() {\n return PhoneMultiFactorGenerator;\n }\n\n toggleRecapchaAutoVerificationForTesting(phone?: string) {\n const phoneWithoutFormatting = phone ? phone.replace(/[\\(\\)\\s-]/g, '') : phone;\n this.auth.settings.appVerificationDisabledForTesting =\n phoneWithoutFormatting && this.testPhone\n ? phoneWithoutFormatting === this.testPhone || `+1${phoneWithoutFormatting}` === this.testPhone\n : false;\n }\n\n initRecaptchaVerifier = (container: HTMLElement | string, recaptchaSize: 'normal' | 'compact' | 'invisible') => {\n return new RecaptchaVerifier(this.auth, container, {\n size: recaptchaSize,\n });\n };\n\n signInWithPhone = (phone: string, recaptchaVerifier: RecaptchaVerifier) => {\n return signInWithPhoneNumber(this.auth, phone, recaptchaVerifier);\n };\n\n signInWithCredential = async (credential: AuthCredential) => {\n return signInWithCredential(this.auth, credential);\n };\n\n signInWithCustomToken = async (token) => {\n await setPersistence(this.auth, inMemoryPersistence);\n return signInWithCustomToken(this.auth, token);\n };\n\n turnOnPersistence = async () => {\n await setPersistence(this.auth, browserLocalPersistence);\n };\n\n confirmSignInWithMobile = async (confirmation: string, confirmationResult: ConfirmationResult) => {\n return confirmationResult.confirm(confirmation);\n };\n\n signInAnonymously = async () => {\n return signInAnonymously(this.auth);\n };\n\n linkWithPhoneCredential = async (confirmResult: ConfirmationResult, verificationCode: string) => {\n const credential: PhoneAuthCredential = await PhoneAuthProvider.credential(\n confirmResult.verificationId,\n verificationCode,\n );\n\n return linkWithCredential(this.auth.currentUser, credential)\n .then((usercred) => usercred.user)\n .catch((error) => Promise.reject(error));\n };\n\n createUserWithEmailAndPassword = async (email: string, password: string) => {\n const credential = await EmailAuthProvider.credential(email, password);\n\n return linkWithCredential(this.auth.currentUser, credential)\n .then((usercred) => usercred.user)\n .catch((error) => Promise.reject(error));\n };\n\n signInWithEmailAndPassword = async (email: string, password: string) => {\n return signInWithEmailAndPassword(this.auth, email, password);\n };\n\n getUserIdToken = async () => {\n if (this.auth.currentUser) {\n return await this.auth.currentUser.getIdToken();\n }\n };\n\n getCurrentUser = async () => {\n return this.auth.currentUser;\n };\n\n signOut = async () => {\n localStorage.removeItem(LS_WORKER_ID_KEY);\n await this.auth.signOut();\n return true;\n };\n\n setWorkerIdToLS(workerId: string) {\n localStorage.setItem(LS_WORKER_ID_KEY, workerId);\n }\n\n getWorkerIdFromLS() {\n return localStorage.getItem(LS_WORKER_ID_KEY);\n }\n\n deleteUser = async () => {\n if (this.auth.currentUser) {\n return this.auth.currentUser.delete();\n }\n return null;\n };\n\n sendPasswordResetEmail = async (emailAddress: string) => {\n return sendPasswordResetEmail(this.auth, emailAddress);\n };\n\n sendVerificationEmailLink = (): Promise => {\n return sendEmailVerification(this.auth.currentUser);\n };\n\n applyActionCode = async (oobCode: string) => {\n return await applyActionCode(this.auth, oobCode);\n };\n\n reauthenticateWithCredential = async (credentials: AuthCredential) => {\n return reauthenticateWithCredential(this.auth.currentUser, credentials);\n };\n\n getPhoneAuthProvider = () => {\n return new PhoneAuthProvider(this.auth);\n };\n\n getMultiFactorResolverByError = (error) => {\n return getMultiFactorResolver(this.auth, error);\n };\n\n getPhoneMultiFactorResolver = (hints: MultiFactorInfo[]): MultiFactorInfo => {\n return hints.find(({factorId}) => factorId === PhoneMultiFactorGenerator.FACTOR_ID);\n };\n\n getPhoneNumberFromEnrolled2Fa = (splitByCode = true): string[] => {\n const enrolledFactor = multiFactor(this.auth.currentUser).enrolledFactors.find(\n ({factorId}) => factorId === PhoneMultiFactorGenerator.FACTOR_ID,\n );\n const phoneNumber = enrolledFactor?.['phoneNumber'] ?? '';\n if (phoneNumber) {\n return splitByCode ? splitPhoneByCountryCode(phoneNumber) : phoneNumber;\n }\n return enrolledFactor?.['phoneNumber'] ? splitPhoneByCountryCode(enrolledFactor['phoneNumber']) : null;\n };\n}\n\nconst service = new Firebase(FirebaseConfig);\n\nexport default service;\n","import {nanoid} from 'nanoid';\n\nimport TasksApi from 'api/tasks';\nimport {ObserverJobStatus} from 'services/TasksObserver/const';\nimport {\n isLoadEvent,\n ObserverEvent,\n ObserverLoadEvent,\n ObserverUpdateEvent,\n} from 'services/TasksObserver/TasksObserverEvent';\nimport {ObserverJob} from 'services/TasksObserver/TasksObserverJob';\nimport {ObserverUnsubscribe, Subscription, SubscriptionConfig} from 'services/TasksObserver/TasksObserverSubscription';\nimport {SortOrder} from 'shared/constants/common';\nimport {GanttNames} from 'shared/constants/gantt';\nimport {chunk} from 'shared/helpers/common';\nimport {debounce} from 'shared/helpers/debounce';\nimport {TaskProjection} from 'shared/models/task/const';\nimport {TaskDetailsModelDTO} from 'shared/models/task/task';\n\nconst REQUEST_LIMIT = 5;\n\nconst instances = new Map();\n\nexport class TasksObserver {\n private retry: 1;\n private subscribers = new Map();\n private queue: ObserverJob[] = [];\n private running: ObserverJob[] = [];\n private events: ObserverLoadEvent[] = [];\n\n static getInstance(name = GanttNames.gantt) {\n let inst = instances.get(name);\n if (!inst) {\n inst = new TasksObserver();\n instances.set(name, inst);\n }\n return inst;\n }\n\n private queueJobs = debounce(() => {\n const events = this.events.splice(0);\n const subscribers = Array.from(this.subscribers.values());\n /* TODO: handle project change\n if there is situation when load tasks will be ran to multiple projects at once\n we need to group that tasks in different jobs\n const projects = new Set();\n const projections = new Set();\n */\n const targetProjections = new Set(\n subscribers.reduce((acc, cur) => acc.concat(cur.config.projection), [] as TaskProjection[]),\n );\n\n targetProjections.forEach((projection) => {\n chunk(this.getIdsToLoad(events), 50).forEach((ids) => {\n const job: ObserverJob = {\n id: nanoid(),\n created: new Date(),\n started: null,\n status: ObserverJobStatus.queue,\n events: [...events],\n idsToLoad: ids,\n staleIds: [],\n projection,\n retryAttempts: 0,\n };\n this.queue.unshift(job);\n });\n });\n this.runJobs();\n }, 50).bind(this);\n\n private getIdsToLoad(events: ObserverLoadEvent[]) {\n return Array.from(new Set(events.reduce((acc, cur) => acc.concat(cur.ids), [])));\n }\n\n private runJobs() {\n while (this.running.length < REQUEST_LIMIT && this.queue.length) {\n this.runJob(this.queue.at(-1));\n }\n }\n\n private findStaleIds() {\n const alreadyLoading = new Set();\n [...this.running]\n .sort((jobA, jobB) => +jobB.started - +jobA.started)\n .forEach((job) => {\n job.idsToLoad.forEach((id) => {\n if (!alreadyLoading.has(id)) {\n alreadyLoading.add(id);\n } else {\n job.staleIds.push(id);\n }\n });\n });\n }\n\n private async runJob(job: ObserverJob) {\n this.running.push(this.queue.pop());\n job.started = new Date();\n job.status = ObserverJobStatus.running;\n try {\n job.status = ObserverJobStatus.success;\n // todo make generic base on projection\n job.result = (await this.processJob(job)) as TaskDetailsModelDTO[];\n this.findStaleIds();\n this.notifyOnJobComplete(job);\n } catch (e) {\n job.status = ObserverJobStatus.error;\n job.error = e as Error;\n if (job.retryAttempts < this.retry) {\n this.queue.push(job);\n }\n }\n this.running = this.running.filter((running) => running.id !== job.id);\n this.runJobs();\n }\n\n private async processJob(job: ObserverJob) {\n const events = job.events;\n return TasksApi.getProjectTasks({\n projection: job.projection,\n limit: job.idsToLoad.length,\n sortOrder: SortOrder.ASC,\n sortField: 'outline_sort_key',\n params: {\n projectId: events[0].projectId,\n ids: job.idsToLoad,\n },\n }).then((res) => res.data);\n }\n\n load(events: ObserverLoadEvent | ObserverLoadEvent[]) {\n this.events.push(...[].concat(events));\n this.queueJobs();\n }\n\n emit(events: Pick[], params: Omit) {\n this.notify(([] as ObserverUpdateEvent[]).concat(events.map((data) => Object.assign(data, params))));\n }\n\n subscribe(callback: Subscription['callback'], config: SubscriptionConfig, id?: string): ObserverUnsubscribe {\n const subscriptionId = id || nanoid();\n this.subscribers.set(subscriptionId, {callback, config, id: subscriptionId});\n const unsub = (() => this.unsubscribe(subscriptionId)) as ObserverUnsubscribe;\n unsub.id = subscriptionId;\n return unsub;\n }\n\n unsubscribe(id: string) {\n if (this.subscribers.has(id)) {\n this.subscribers.delete(id);\n } else {\n console.warn(`Attempt to unsubscribe with not exist id: ${id}`);\n }\n }\n\n private getEventsForSubscription(events: E[], subscription: Subscription) {\n return events.filter(\n (event) =>\n (!subscription.config.triggerSource || subscription.config.triggerSource.includes(event.source)) &&\n (!subscription.config.triggerType || subscription.config.triggerType.includes(event.action)) &&\n (isLoadEvent(event) ? true : subscription.config.projection.includes(event.projection)),\n );\n }\n\n private notifyOnJobComplete(job: ObserverJob) {\n if (job) {\n // need to optimize\n this.subscribers.forEach((s) => {\n if (s.config.projection.includes(job.projection)) {\n const eventsToEmit = this.getEventsForSubscription(job.events, s);\n const ids = this.getIdsToLoad(eventsToEmit).filter((id) => !job.staleIds.includes(id));\n // TODO: optimize\n const res = job.result\n .filter((res) => ids.includes(res.id))\n .map((res) => ({\n event: job.events.find((event) => event.ids.includes(res.id)),\n data: res,\n }));\n res.length &&\n s.callback({\n type: 'load',\n payload: res,\n });\n }\n });\n }\n }\n\n private notify(events: ObserverUpdateEvent | ObserverUpdateEvent[]) {\n const eventsArray = [].concat(events) as ObserverUpdateEvent[];\n this.subscribers.forEach((s) => {\n const eventsForSub = this.getEventsForSubscription(eventsArray, s);\n if (eventsForSub.length) {\n s.callback({\n type: 'cache',\n payload: eventsForSub,\n });\n }\n });\n }\n}\n","import {ObserverAction, ObserverActionSource} from 'services/TasksObserver/const';\nimport {TaskProjection} from 'shared/models/task/const';\nimport {TaskDetailsModelDTO} from 'shared/models/task/task';\n\nexport function isLoadEvent(e: unknown): e is ObserverLoadEvent {\n return e && typeof e === 'object' && 'ids' in e;\n}\n\nexport type ObserverLoadEvent = {\n ids: string[];\n} & ObserverBaseEvent;\n\nexport type ObserverData = TaskDetailsModelDTO[];\n\nexport type ObserverUpdateEvent = {\n projection: TaskProjection;\n data?: Partial;\n} & ObserverBaseEvent;\n\ntype ObserverBaseEvent = {\n action?: ObserverAction;\n projectId: string;\n source?: ObserverActionSource;\n sourceName?: string;\n refetchRowNumbers?: boolean;\n meta?: {\n create?: {\n isPristine: boolean;\n index: number;\n };\n move?: {\n parent: string;\n index: number;\n };\n };\n};\n\nexport type ObserverEvent = ObserverLoadEvent | ObserverUpdateEvent;\n","export enum ObserverAction {\n create = 'create',\n update = 'update',\n remove = 'remove',\n move = 'move',\n archive = 'archive',\n restore = 'restore',\n}\n\nexport enum ObserverJobStatus {\n queue,\n running,\n success,\n error,\n}\n\nexport enum ObserverActionSource {\n taskDetails,\n gantt,\n affected,\n sync,\n bulk,\n}\n","import {type StylesConfig, type GroupBase, type CSSObjectWithLabel} from 'react-select';\n\nimport {TaskOptionType} from 'modules/Tasks/components/SidebarPanel/components/TaskAsyncSelect';\nimport {BulkOption} from 'modules/Tasks/components/TasksActionsBar/bulkPopups/BulkWatcher/BulkWatcher';\nimport {CountryCodeOption} from 'shared/constants/common';\n\nimport {ProjectWorkerSelectOption} from './AsyncProjectWorkerSelect/AsyncProjectWorkerSelect';\nimport type {SelectOption} from './types';\n\nfunction createGenericStyles