UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

1,419 lines (1,187 loc) 95.3 kB
import './kendo.data.js'; import './kendo.resizable.js'; import './kendo.switch.js'; import './kendo.gantt.data.js'; import './kendo.gantt.editors.js'; import './kendo.gantt.list.js'; import './kendo.gantt.timeline.js'; import './kendo.pdf.js'; import './kendo.toolbar.js'; import './kendo.html.button.js'; var __meta__ = { id: "gantt", name: "Gantt", category: "web", description: "The Gantt component.", depends: [ "data", "resizable", "switch", "gantt.data", "gantt.editors", "gantt.list", "gantt.timeline", "pdf", "toolbar", "html.button" ] }; (function($, undefined$1) { var kendo = window.kendo, keys = kendo.keys, supportsMedia = "matchMedia" in window, mobileOS = kendo.support.mobileOS, Widget = kendo.ui.Widget, ObservableObject = kendo.data.ObservableObject, ObservableArray = kendo.data.ObservableArray, Query = kendo.data.Query, isArray = Array.isArray, isFunction = kendo.isFunction, extend = $.extend, isPlainObject = $.isPlainObject, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, defaultIndicatorWidth = 3, NS = ".kendoGantt", PERCENTAGE_FORMAT = "p0", TABINDEX = "tabIndex", STRING = "string", ARIA_DESCENDANT = "aria-activedescendant", ACTIVE_CELL = "gantt_active_cell", DOT = ".", TASK_DELETE_CONFIRM = "Are you sure you want to delete this task?", DEPENDENCY_DELETE_CONFIRM = "Are you sure you want to delete this dependency?", VIEWS_DROPDOWN_TEMPLATE = ({ label, styles, views }) => `<select aria-label="${label}" class="k-dropdown k-picker k-dropdown-list ${styles.viewsDropdown}">` + `${Object.keys(views).map(view => '<option value="' + view + '">' + views[view].title + '</option>').join("")}` + '</select>', MIN_SCREEN = "(max-width: 480px)", ADD_ACTIONS = [{ data: "add", text: "addChild" }, { data: "insert-before", text: "insertBefore" }, { data: "insert-after", text: "insertAfter" }]; var ganttStyles = { wrapper: "k-gantt", plannedTasks: "k-gantt-planned", rowHeight: "k-gantt-rowheight", content: "k-gantt-content", listWrapper: "k-gantt-treelist", list: "k-gantt-treelist", timelineWrapper: "k-gantt-timeline", timeline: "k-gantt-timeline", splitBarWrapper: "k-splitbar k-splitbar-horizontal k-splitbar-draggable-horizontal", splitBar: "k-splitbar", splitBarHover: "k-splitbar-horizontal-hover", popupWrapper: "k-list-container", popupList: "k-list k-reset", resizeHandle: "k-resize-handle", icon: "k-icon", item: "k-item", line: "k-gantt-line", buttonDelete: "k-gantt-delete", buttonCancel: "k-gantt-cancel", buttonSave: "k-gantt-update", buttonToggle: "k-gantt-toggle", buttonDefaults: "k-button-md k-rounded-md k-button-solid", primary: "k-button-solid-primary", hovered: "k-hover", selected: "k-selected", focused: "k-focus", focusedCell: "k-focus", gridHeader: "k-grid-header", gridHeaderWrap: "k-grid-header-wrap", gridContent: "k-grid-content", tasks: "k-gantt-tasks", popup: { form: "k-popup-edit-form", editForm: "k-gantt-edit-form", formContainer: "k-edit-form-container", resourcesFormContainer: "k-resources-form-container", message: "k-popup-message", buttonsContainer: "k-edit-buttons", button: "k-button", editField: "k-edit-field", editLabel: "k-edit-label", resourcesField: "k-gantt-resources" }, toolbar: { headerWrapper: "k-gantt-header k-gantt-toolbar", footerWrapper: "k-gantt-footer k-gantt-toolbar", toolbar: "k-gantt-toolbar", views: "k-gantt-views", viewsWrapper: "k-gantt-views-wrapper", viewsDropdown: "k-views-dropdown", button: "k-button", buttonToggle: "k-gantt-toggle", buttonDefaults: "k-button-md k-rounded-md k-button-solid", iconPlus: "plus", iconPdf: "file-pdf", iconToggle: "layout-1-by-4", viewButton: "k-view", link: "k-link", pdfButton: "k-gantt-pdf", appendButton: "k-gantt-create" } }; function selector(uid) { return "[" + kendo.attr("uid") + (uid ? "='" + uid + "']" : "]"); } function trimOptions(options) { delete options.name; delete options.prefix; delete options.remove; delete options.edit; delete options.add; delete options.navigate; return options; } function focusTable(table, direct) { var wrapper = table.parents('[' + kendo.attr("role") + '="gantt"]'); var scrollPositions = []; var parents = scrollableParents(wrapper); table.attr(TABINDEX, 0); if (direct) { parents.each(function(index, parent) { scrollPositions[index] = $(parent).scrollTop(); }); } try { //The setActive method does not cause the document to scroll to the active object in the current page table[0].setActive(); } catch (e) { table[0].focus(); } if (direct) { parents.each(function(index, parent) { $(parent).scrollTop(scrollPositions[index]); }); } } function scrollableParents(element) { return $(element).parentsUntil("body") .filter(function(index, element) { var computedStyle = kendo.getComputedStyles(element, ["overflow"]); return computedStyle.overflow != "visible"; }) .add(window); } var Gantt = Widget.extend({ init: function(element, options, events) { if (isArray(options)) { options = { dataSource: options }; } Widget.fn.init.call(this, element, options); if (events) { this._events = events; } this._wrapper(); this._resources(); if (!this.options.views || !this.options.views.length) { this.options.views = ["day", "week", "month"]; } this._timeline(); this._processDefaults(); this._toolbar(); this._footer(); this._adjustDimensions(); // Prevent extra refresh from setting the view this._preventRefresh = true; this.view(this.timeline._selectedViewName); this._preventRefresh = false; this._dataSource(); this._assignments(); this._list(); this._dependencies(); this._resizable(); this._scrollable(); this._dataBind(); this._attachEvents(); this._createEditor(); kendo.notify(this); }, events: [ "dataBinding", "dataBound", "add", "edit", "remove", "cancel", "save", "change", "navigate", "moveStart", "move", "moveEnd", "resizeStart", "resize", "resizeEnd", "columnHide", "columnReorder", "columnResize", "columnShow", "togglePlannedTasks" ], options: { name: "Gantt", autoBind: true, navigatable: false, selectable: true, editable: true, resizable: false, columnResizeHandleWidth: defaultIndicatorWidth, columns: [], views: [], dataSource: {}, dependencies: {}, resources: {}, assignments: {}, taskTemplate: null, messages: { save: "Save", cancel: "Cancel", destroy: "Delete", deleteTaskConfirmation: TASK_DELETE_CONFIRM, deleteDependencyConfirmation: DEPENDENCY_DELETE_CONFIRM, deleteTaskWindowTitle: "Delete task", deleteDependencyWindowTitle: "Delete dependency", selectView: "Select view", views: { day: "Day", week: "Week", month: "Month", year: "Year", start: "Start", end: "End" }, actions: { append: "Add Task", addChild: "Add Child", insertBefore: "Add Above", insertAfter: "Add Below", pdf: "Export to PDF", toggle: "Toggle pane" }, editor: { editorTitle: "Task", resourcesEditorTitle: "Resources", title: "Title", start: "Start", end: "End", plannedStart: "Planned Start", plannedEnd: "Planned End", percentComplete: "Complete", resources: "Resources", assignButton: "Assign", resourcesHeader: "Resources", unitsHeader: "Units", parent: "Parent", addNew: "Add", name: "Name", percentCompleteHint: "value from 0 to 1", remove: "Remove", actualStart: "Actual Start", actualEnd: "Actual End", parentOptionLabel: "-None-", general: "General", predecessors: "Predecessors", successors: "Successors", other: "Other", dependencyType: "Type" }, plannedTasks: { switchText: "Planned Tasks", offsetTooltipAdvanced: "Met deadline earlier", offsetTooltipDelay: "Delay", seconds: "seconds", minutes: "minutes", hours: "hours", days: "days" } }, showWorkHours: true, showWorkDays: true, toolbar: null, workDayStart: new Date(1980, 1, 1, 8, 0, 0), workDayEnd: new Date(1980, 1, 1, 17, 0, 0), workWeekStart: 1, workWeekEnd: 5, hourSpan: 1, snap: true, height: 600, listWidth: "30%", rowHeight: null, showPlannedTasks: false }, select: function(value) { var list = this.list; if (!value) { return list.select(); } if (typeof value === STRING) { value = list.content.find(value); } list.select(value); this._selectionUpdate(); this.list.element.find("table[role=treegrid]").trigger("focus"); return; }, clearSelection: function() { this.list.clearSelection(); this._selectionUpdate(); }, destroy: function() { Widget.fn.destroy.call(this); if (this.dataSource) { this.dataSource.unbind("change", this._refreshHandler); this.dataSource.unbind("progress", this._progressHandler); this.dataSource.unbind("error", this._errorHandler); } if (this.dependencies) { this.dependencies.unbind("change", this._dependencyRefreshHandler); this.dependencies.unbind("error", this._dependencyErrorHandler); } if (this.timeline) { this.timeline.unbind(); this.timeline.destroy(); } if (this.list) { this.list.unbind(); this.list.destroy(); } if (this.toolbar && this.toolbar.getKendoToolBar()) { this.toolbar.getKendoToolBar().destroy(); } if (this.footer && this.footer.getKendoToolBar()) { this.footer.getKendoToolBar().destroy(); } if (this._editor) { this._editor.destroy(); } if (this._resourceEditorWindow) { this._resourceEditorWindow.destroy(); } if (this._resizeDraggable) { this._resizeDraggable.destroy(); } this.toolbar.off(NS); if (supportsMedia) { this._mediaQuery.removeListener(this._mediaQueryHandler); this._mediaQuery = null; } $(window).off("resize" + NS, this._resizeHandler); $(this.wrapper).off(NS); this.toolbar = null; this.footer = null; kendo.destroy(this.element); }, setOptions: function(options) { var newOptions = kendo.deepExtend({}, this.options, options); var events = this._events; if (!options.views) { var selectedView = this.view().name; newOptions.views = $.map(this.options.views, function(view) { var isSettings = isPlainObject(view); var name = isSettings ? ((typeof view.type !== "string") ? view.title : view.type) : view; if (selectedView === name) { if (isSettings) { view.selected = true; } else { view = { type: name, selected: true }; } } else if (isSettings) { view.selected = false; } return view; }); } if (!options.dataSource) { newOptions.dataSource = this.dataSource; } if (!options.dependencies) { newOptions.dependencies = this.dependencies; } if (!options.resources) { newOptions.resources = this.resources; } if (!options.assignments) { newOptions.assignments = this.assignments; } this.destroy(); this.element.empty(); this.options = null; this.init(this.element, newOptions, events); Widget.fn._setEvents.call(this, newOptions); }, _attachEvents: function() { this._resizeHandler = this.resize.bind(this, false); $(window).on("resize" + NS, this._resizeHandler); if (supportsMedia) { this._mediaQueryHandler({ matches: this._mediaQuery.matches }); } }, _wrapper: function() { var ganttStyles = Gantt.styles; var splitBarHandleClassName = [ganttStyles.icon, ganttStyles.resizeHandle].join(" "); var options = this.options; var height = options.height; var width = options.width; this.wrapper = this.element.addClass(ganttStyles.wrapper).attr("role", "application"); this.layout = $("<div class='" + ganttStyles.content + "' />").appendTo(this.wrapper) .append("<div class='" + ganttStyles.listWrapper + "'><div></div></div>") .append("<div class='" + ganttStyles.splitBarWrapper + "'><div class='" + splitBarHandleClassName + "'></div></div>") .append("<div class='" + ganttStyles.timelineWrapper + "'><div></div></div>"); if (options.showPlannedTasks) { this.wrapper.addClass(ganttStyles.plannedTasks); } if (height) { this.wrapper.css("height", height); } if (width) { this.wrapper.css("width", width); } if (options.rowHeight) { this.wrapper.addClass(ganttStyles.rowHeight); } this.treelistWrapper = this.wrapper.find(DOT + ganttStyles.list); this.splitbar = this.wrapper.find(DOT + ganttStyles.splitBar); this.timelineWrapper = this.wrapper.find(DOT + ganttStyles.timeline); this.treelistWrapper.css("width", options.listWidth); this.timelineWrapper.css("width", this.wrapper.width() - this.treelistWrapper.outerWidth() - this.splitbar.outerWidth() ); }, _viewClickHandler: function(e) { var list = this.list; var name = e.target.attr(kendo.attr("name")); if (list.editor && !list.editor.end()) { return; } if (!this.trigger("navigate", { view: name })) { this.view(name); } else { e.preventDefault(); } }, _togglePane: function(e) { var that = this, treelist = that.treelistWrapper, timeline = that.timelineWrapper, contentSelector = DOT + ganttStyles.gridContent; e.preventDefault(); if (treelist.is(":visible")) { treelist.addClass("k-hidden"); timeline.removeClass("k-hidden"); that.refresh(); timeline .find(contentSelector) .scrollTop(that.scrollTop); } else { treelist.removeClass("k-hidden"); timeline.addClass("k-hidden"); treelist .find(contentSelector) .scrollTop(that.scrollTop); } that._resize(); }, _processDefaults: function() { var that = this, views = that.timeline.views, ns = kendo.ns, viewsButtons = [], toolbarStyles = Gantt.styles.toolbar, actionsMessages = this.options.messages.actions, items = ADD_ACTIONS.map((m) => ({ text: actionsMessages[m.text], attributes: { "data-type": m.data } })), defaults = { append: { name: "append", type: "dropDownButton", menuButtons: items, icon: toolbarStyles.iconPlus, attributes: { class: toolbarStyles.appendButton }, click: that._addClickHandler.bind(that), open: that._openAddClickHandler.bind(that) }, pdf: { name: "pdf", type: "button", attributes: { class: toolbarStyles.pdfButton }, icon: toolbarStyles.iconPdf, click: that.saveAsPDF.bind(that) }, toggle: { name: "toggle", type: "button", showText: "overflow", attributes: { class: "k-gantt-toggle" }, icon: toolbarStyles.iconToggle, click: that._togglePane.bind(that) }, switchLabel: { template: "<label for=planned-switch>" + that.options.messages.plannedTasks.switchText + "</label>" }, plannedTasks: { type: "component", component: "Switch", element: "<input id='planned-switch' class='k-gantt-planned-switch'>", componentOptions: { checked: that.options.showPlannedTasks, change: that._togglePlannedTasks.bind(that), messages: { checked: "", unchecked: "" } } }, viewsDdl: { template: VIEWS_DROPDOWN_TEMPLATE({ views: that.timeline.views, styles: toolbarStyles, label: that.options.messages.selectView }) }, view: { name: "view", type: "button", togglable: true, group: "views" }, viewsGroup: { type: "buttonGroup", attributes: { class: toolbarStyles.views } } }; Object.keys(views).map(name => { var current = $.extend(true, {}, defaults.view); current.text = views[name].title; current.attributes = { class: "k-view-" + name.toLowerCase() }; current.attributes["data" + ns + "-name"] = name; defaults[name] = current; viewsButtons.push(name); }); Object.values(defaults).map(t => { if (t.name === "view") { t.click = that._viewClickHandler.bind(that); } }); defaults.viewsGroup.buttons = viewsButtons; that._viewsButtons = viewsButtons; that.defaultCommands = defaults; }, _processTools: function(items) { var editable = this.options.editable, commands = [], tools = ["toggle"], spacerPresent = false, defaults = this.defaultCommands; if (!Array.isArray(items)) { if (editable && editable.create !== false) { tools.push("append"); } } else { commands = items; } commands.map(c => { if (c === "plannedTasks" || c.name === "plannedTasks") { spacerPresent = true; tools.push({ type: "spacer" }); tools.push("switchLabel"); } if (!defaults[c] && !defaults[c.name] && !c.template) { if (typeof c === STRING) { c = { name: c, type: "button", text: c, attributes: { class: "k-gantt-" + c } }; } else { c = $.extend({}, { type: "button", text: c.name, attributes: { class: "k-gantt-" + c.name } }, c); } } tools.push(c); }); if (!spacerPresent) { tools.push({ type: "spacer" }); } if (this._viewsButtons && this._viewsButtons.length > 0) { if (this._viewsButtons.length > 1) { tools.push("viewsDdl"); } tools.push("viewsGroup"); } return tools; }, _mediaQueryHandler: function(e) { var that = this; var splitbar = that.splitbar; var treelist = that.treelistWrapper; var timeline = that.timelineWrapper; var contentSelector = DOT + ganttStyles.gridContent; var toolbarEl = that.toolbar; var toolbar = toolbarEl.getKendoToolBar(); if (e.matches) { treelist.addClass("k-hidden"); splitbar.addClass("k-hidden"); toolbar.hide(toolbarEl.find(".k-gantt-views")); toolbar.show(toolbarEl.find(".k-views-dropdown")); treelist.width("100%"); } else { treelist.removeClass("k-hidden"); splitbar.removeClass("k-hidden"); timeline.removeClass("k-hidden"); toolbar.show(toolbarEl.find(".k-gantt-views")); toolbar.hide(toolbarEl.find(".k-views-dropdown")); treelist.width(treelist.outerWidth()); timeline .find(contentSelector) .scrollTop(that.scrollTop); } that._resize(); }, _toolbar: function() { var that = this; var ganttStyles = Gantt.styles; var viewsDropdownSelector = DOT + ganttStyles.toolbar.viewsDropdown; var toolsOptions = this.options.toolbar; var tools; var toolbar; if (typeof toolsOptions === STRING) { toolsOptions = kendo.template(toolsOptions).bind(this); } if (isFunction(toolsOptions)) { tools = this._processTools([{ template: toolsOptions({}) }]); } else { tools = this._processTools(toolsOptions); } toolbar = $("<div class='" + ganttStyles.toolbar.headerWrapper + "'>"); this.wrapper.prepend(toolbar); this.toolbar = toolbar; toolbar.kendoToolBar({ resizable: false, tools: tools, size: "medium", defaultTools: this.defaultCommands, parentMessages: this.options.messages.actions }); if (supportsMedia) { this._mediaQuery = window.matchMedia(MIN_SCREEN); this._mediaQuery.addListener(this._mediaQueryHandler.bind(this)); } toolbar.on("change" + NS, viewsDropdownSelector, function() { var list = that.list; var name = $(this).val(); if (list.editable && list.editable.trigger("validate")) { return; } if (!that.trigger("navigate", { view: name })) { that.view(name); } }); this.toggleSwitch = toolbar.find('input.k-gantt-planned-switch').data("kendoSwitch"); }, _footer: function() { var editable = this.options.editable; if (!editable || editable.create === false) { return; } var ganttStyles = Gantt.styles.toolbar; var messages = this.options.messages.actions; var footer = $("<div class='" + ganttStyles.footerWrapper + "'>"); this.wrapper.append(footer); this.footer = footer; footer.kendoToolBar({ resizable: false, size: "medium", tools: ["append"], defaultTools: { append: extend(true, {}, this.defaultCommands.append, { direction: "up", animation: { open: { effects: "slideIn:up" } } }) }, parentMessages: messages }); }, _adjustDimensions: function() { var element = this.element; var toolbarHeight = outerHeight(this.toolbar); var footerHeight = this.footer ? outerHeight(this.footer) : 0; var totalHeight = element.height(); var totalWidth = element.width(); var splitBarWidth = this.splitbar.is(":visible") ? outerWidth(this.splitbar) : 0; var treeListWidth = this.treelistWrapper.is(":visible") ? outerWidth(this.treelistWrapper) : 0; var timelineWidth = totalWidth - ( treeListWidth + splitBarWidth ); this.layout.children().height(totalHeight - (toolbarHeight + footerHeight)); this.timelineWrapper.width(timelineWidth); if (totalWidth < (treeListWidth + splitBarWidth)) { this.treelistWrapper.width(totalWidth - splitBarWidth); } }, _scrollTo: function(value) { var view = this.timeline.view(); var list = this.list; var attr = kendo.attr("uid"); var id = typeof value === "string" ? value : value.closest("tr" + selector()).attr(attr); var action; var scrollTarget; var scrollIntoView = function() { if (scrollTarget.length !== 0) { action(); } }; if (view.content.is(":visible")) { scrollTarget = view.content.find(selector(id)); action = function() { view._scrollTo(scrollTarget); }; } else { scrollTarget = list.element.find(selector(id)); action = function() { scrollTarget.get(0).scrollIntoView(); }; } scrollIntoView(); }, _addTask: function(selected, parent, type) { var dataSource = this.dataSource, task = dataSource._createNewModel({}), timeline = this.timeline, firstSlot = timeline.view()._timeSlots()[0], editable = this.list.editor, orderId; if (editable && editable.trigger("validate")) { return; } task.set("title", "New task"); if (parent) { task.set("parentId", parent.get("id")); task.set("start", parent.get("start")); task.set("end", parent.get("end")); task.set("plannedStart", parent.get("plannedStart")); task.set("plannedEnd", parent.get("plannedEnd")); } else { task.set("start", firstSlot.start); task.set("end", firstSlot.end); } if (type && type !== "add") { orderId = selected.get("orderId"); orderId = type === "insert-before" ? orderId : orderId + 1; } this._createTask(task, orderId); }, _addClickHandler: function(e) { var type = e.target.data("type"); var dataSource = this.dataSource; var selected = this.dataItem(this.select()); var parent = dataSource.taskParent(selected); var target = type === "add" ? selected : parent; this._addTask(selected, target, type); }, _openAddClickHandler: function(e) { var selected = this.select(); if (!selected || selected.length === 0) { e.preventDefault(); this._addTask(); } }, _getListEditable: function() { var editable = false, options = this.options; if (options.editable !== false) { editable = "incell"; if (options.editable && options.editable.update === false) { editable = false; } else { if (!options.editable || options.editable.reorder !== false) { editable = { mode: "incell", move: { reorderable: true } }; } } } return editable; }, _getListOptions: function() { var options = this.options, editable = this._getListEditable(), listWrapper = this.wrapper.find(DOT + ganttStyles.list), ganttListOptions = { columns: options.columns || [], dataSource: this.dataSource, selectable: options.selectable, reorderable: options.reorderable, editable: editable, resizable: options.resizable, filterable: options.filterable, columnMenu: options.columnMenu, columnResizeHandleWidth: this.options.columnResizeHandleWidth, listWidth: outerWidth(listWrapper), resourcesField: this.resources.field, rowHeight: this.options.rowHeight }; return ganttListOptions; }, _attachResourceEditor: function(columns) { var column; for (var i = 0; i < columns.length; i++) { column = columns[i]; if (column.field === this.resources.field && typeof column.editor !== "function") { column.editor = this._resourcePopupEditor.bind(this); } } }, _attachListEvents: function() { var that = this, navigatable = that.options.navigatable, restoreFocus = function() { var element; if (navigatable && that._cachedCurrent) { element = that.list.content.find("tr").eq(that._cachedCurrent.rowIndex).find("td").eq(that._cachedCurrent.columnIndex); that._current(element); focusTable(that.list.content.find("table"), true); } delete that._cachedCurrent; }; that.list .bind("columnShow", function(e) { that.trigger("columnShow", { column: e.column }); }) .bind("columnHide", function(e) { that.trigger("columnHide", { column: e.column }); }) .bind("columnReorder", function(e) { that.trigger("columnReorder", { column: e.column, oldIndex: e.oldIndex, newIndex: e.newIndex }); }) .bind("columnResize", function(e) { that.trigger("columnResize", { column: e.column, oldWidth: e.oldWidth, newWidth: e.newWidth }); }) .bind("render", function() { that._navigatable(); }, true) .bind("beforeEdit", function(e) { that._cachedCurrent = { rowIndex: e.container.closest("tr").index(), columnIndex: e.container.index() }; if (that.trigger("edit", { task: e.model, container: e.container })) { e.preventDefault(); } }) .bind("cancel", function(e) { if (that.trigger("cancel", { task: e.model, container: e.cell })) { e.preventDefault(); return; } that._preventItemChange = true; that.list.closeCell(true); restoreFocus(); }) .bind("save", function(e) { var updatedValues = e.values, key; that.previousTask = {}; that._preventRefresh = true; if (that.updateDuration === null || that.updateDuration === undefined$1) { that.updateDuration = e.model.duration(); } if (that.updatePlannedDuration === null || that.updatePlannedDuration === undefined$1) { that.updatePlannedDuration = e.model.plannedDuration(); } if (updatedValues.hasOwnProperty("start")) { updatedValues.end = new Date(updatedValues.start.getTime() + that.updateDuration); } if (updatedValues.hasOwnProperty("plannedStart") && updatedValues.plannedStart) { updatedValues.plannedEnd = new Date(updatedValues.plannedStart.getTime() + that.updatePlannedDuration); } for (key in updatedValues) { if (updatedValues.hasOwnProperty(key)) { that.previousTask[key] = e.model.get(key); } } that.updatedValues = updatedValues; }) .bind("itemChange", function(e) { var updateInfo = that.updatedValues, task = e.data, resourcesField = that.resources.field, previousTask = that.previousTask, key; if (that._preventItemChange) { that._preventItemChange = false; return; } for (key in previousTask) { if (previousTask.hasOwnProperty(key)) { task.set(key, previousTask[key]); } } that.previousTask = {}; if (!that.trigger("save", { task: task, values: updateInfo })) { if (updateInfo) { that._preventRefresh = true; that.dataSource.update(task, updateInfo); if (updateInfo[resourcesField]) { that._updateAssignments(task.get("id"), updateInfo[resourcesField]); } } that._preventRefresh = false; that._requestStart(); that.dataSource.sync().then(function() { restoreFocus(); }); } else if (that.dataSource.hasChanges()) { that.dataSource.cancelChanges(task); that._preventRefresh = false; that.refresh(); } that.updatedValues = null; that.updateDuration = null; }) .bind("change", function() { that.trigger("change"); that._selectionUpdate(); }) .bind("collapse", function(e) { e.preventDefault(); var row = that.list.element.find("tr[data-uid='" + e.model.uid + "']"); e.model.set("expanded", false); that._cachedCurrent = { rowIndex: row.index(), columnIndex: row.find(".k-focus").index() }; restoreFocus(); }) .bind("expand", function(e) { e.preventDefault(); var row = that.list.element.find("tr[data-uid='" + e.model.uid + "']"); e.model.set("expanded", true); that._cachedCurrent = { rowIndex: row.index(), columnIndex: row.find(".k-focus").index() }; restoreFocus(); }) .bind("dragend", function(e) { var dataSource = that.dataSource, task, updateInfo; if (e.position === "over") { dataSource.cancelChanges(); updateInfo = { parentId: e.source.parentId }; task = dataSource.get(e.source.id); if (!that.trigger("save", { task: task, values: updateInfo })) { dataSource.update(task, updateInfo); } dataSource.sync(); } }) .bind("dataBound", function() { if (that.dataSource.sort().length === 0) { that.dataSource.sort([{ field: "orderId", dir: "asc" }]); } }) .bind("reorder", function(e) { that._updateTask(e.task, e.updateInfo); restoreFocus(); }); }, _selectionUpdate: function() { var that = this, selection = that.list.select(); if (selection.length) { that.timeline.select("[data-uid='" + selection.attr("data-uid") + "']"); } else { that.timeline.clearSelection(); } }, _list: function() { var ganttStyles = Gantt.styles, listWrapper = this.wrapper.find(DOT + ganttStyles.list), listElement = listWrapper.find("> div"), listOptions = this._getListOptions(); this._attachResourceEditor(listOptions.columns); this.list = new kendo.ui.GanttList(listElement, listOptions); this._attachListEvents(); }, _timeline: function() { var that = this; var ganttStyles = Gantt.styles; var options = trimOptions(extend(true, { resourcesField: this.resources.field }, this.options)); var element = this.wrapper.find(DOT + ganttStyles.timeline + " > div"); this.timeline = new kendo.ui.GanttTimeline(element, options); this.timeline .bind("navigate", function(e) { var viewName = e.view.replace(/\./g, "\\.").toLowerCase(); var viewsEl = that.toolbar.find(DOT + ganttStyles.toolbar.views); var viewsGroup = viewsEl.getKendoButtonGroup(); if (viewsGroup) { viewsGroup.select(viewsEl.find(DOT + ganttStyles.toolbar.viewButton + "-" + viewName)); } that.toolbar .find(DOT + ganttStyles.toolbar.viewsDropdown) .val(e.view); that.refresh(); }) .bind("moveStart", function(e) { var editable = that.list.editor; if (editable && !editable.end()) { e.preventDefault(); return; } if (that.trigger("moveStart", { task: e.task })) { e.preventDefault(); } }) .bind("move", function(e) { var task = e.task; var start = e.start; var end = new Date(start.getTime() + task.duration()); if (that.trigger("move", { task: task, start: start, end: end })) { e.preventDefault(); } }) .bind("moveEnd", function(e) { var task = e.task; var start = e.start; var end = new Date(start.getTime() + task.duration()); if (!that.trigger("moveEnd", { task: task, start: start, end: end })) { that._updateTask(that.dataSource.getByUid(task.uid), { start: start, end: end }); } }) .bind("resizeStart", function(e) { var editable = that.list.editor; if (editable && !editable.end()) { e.preventDefault(); return; } if (that.trigger("resizeStart", { task: e.task })) { e.preventDefault(); } }) .bind("resize", function(e) { if (that.trigger("resize", { task: e.task, start: e.start, end: e.end })) { e.preventDefault(); } }) .bind("resizeEnd", function(e) { var task = e.task; var updateInfo = {}; if (e.resizeStart) { updateInfo.start = e.start; } else { updateInfo.end = e.end; } if (!that.trigger("resizeEnd", { task: task, start: e.start, end: e.end })) { that._updateTask(that.dataSource.getByUid(task.uid), updateInfo); } }) .bind("percentResizeStart", function(e) { var editable = that.list.editor; if (editable && !editable.end()) { e.preventDefault(); } }) .bind("percentResizeEnd", function(e) { that._updateTask(that.dataSource.getByUid(e.task.uid), { percentComplete: e.percentComplete }); }) .bind("dependencyDragStart", function(e) { var editable = that.list.editor; if (editable && !editable.end()) { e.preventDefault(); } }) .bind("dependencyDragEnd", function(e) { var dependency = that.dependencies._createNewModel({ type: e.type, predecessorId: e.predecessor.id, successorId: e.successor.id }); that._createDependency(dependency); }) .bind("select", function(e) { var editable = that.list.editor, current = that.select(), currentUid; if (editable) { editable.end(); } if (current && current.length) { currentUid = current.data("uid"); } if (currentUid !== e.uid) { that.select("[data-uid='" + e.uid + "']"); that.trigger("change"); } }) .bind("editTask", function(e) { var editable = that.list.editor; if (editable && !editable.end()) { return; } that.editTask(e.uid); }) .bind("clear", function() { that.clearSelection(); that.trigger("change"); }) .bind("removeTask", function(e) { var editable = that.list.editor; if (editable && !editable.end()) { return; } that.removeTask(that.dataSource.getByUid(e.uid)); }) .bind("removeDependency", function(e) { var editable = that.list.editor; if (editable && !editable.end()) { return; } that.removeDependency(that.dependencies.getByUid(e.uid)); }); }, _dataSource: function() { var options = this.options; var dataSource = options.dataSource; dataSource = isArray(dataSource) ? { data: dataSource } : dataSource; if (this.dataSource && this._refreshHandler) { this.dataSource .unbind("change", this._refreshHandler) .unbind("progress", this._progressHandler) .unbind("error", this._errorHandler); } else { this._refreshHandler = this.refresh.bind(this); this._progressHandler = this._requestStart.bind(this); this._errorHandler = this._error.bind(this); } this.dataSource = kendo.data.GanttDataSource.create(dataSource) .bind("change", this._refreshHandler) .bind("progress", this._progressHandler) .bind("error", this._errorHandler); }, _dependencies: function() {