@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
3,600 lines • 134 kB
JavaScript
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ({
/***/ 0:
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1189);
/***/ }),
/***/ 3:
/***/ (function(module, exports) {
module.exports = function() { throw new Error("define cannot be used indirect"); };
/***/ }),
/***/ 1015:
/***/ (function(module, exports) {
module.exports = require("./kendo.data");
/***/ }),
/***/ 1038:
/***/ (function(module, exports) {
module.exports = require("./kendo.popup");
/***/ }),
/***/ 1142:
/***/ (function(module, exports) {
module.exports = require("./kendo.resizable");
/***/ }),
/***/ 1143:
/***/ (function(module, exports) {
module.exports = require("./kendo.window");
/***/ }),
/***/ 1189:
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function(f, define){
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(1015), __webpack_require__(1038), __webpack_require__(1143), __webpack_require__(1142), __webpack_require__(1190), __webpack_require__(1191), __webpack_require__(1192), __webpack_require__(1193)], __WEBPACK_AMD_DEFINE_FACTORY__ = (f), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
})(function(){
var __meta__ = { // jshint ignore:line
id: "gantt",
name: "Gantt",
category: "web",
description: "The Gantt component.",
depends: [ "data", "popup", "resizable", "window", "gantt.list", "gantt.timeline", "grid" ]
};
(function($, undefined) {
var kendo = window.kendo;
var keys = $.extend({F10: 121}, kendo.keys);
var supportsMedia = "matchMedia" in window;
var browser = kendo.support.browser;
var mobileOS = kendo.support.mobileOS;
var Observable = kendo.Observable;
var Widget = kendo.ui.Widget;
var DataSource = kendo.data.DataSource;
var ObservableObject = kendo.data.ObservableObject;
var ObservableArray = kendo.data.ObservableArray;
var Query = kendo.data.Query;
var isArray = $.isArray;
var inArray = $.inArray;
var isFunction = kendo.isFunction;
var proxy = $.proxy;
var extend = $.extend;
var isPlainObject = $.isPlainObject;
var map = $.map;
var outerWidth = kendo._outerWidth;
var outerHeight = kendo._outerHeight;
var defaultIndicatorWidth = 3;
var NS = ".kendoGantt";
var PERCENTAGE_FORMAT = "p0";
var TABINDEX = "tabIndex";
var CLICK = "click";
var WIDTH = "width";
var STRING = "string";
var DIRECTIONS = {
"down": {
origin: "bottom left",
position: "top left"
},
"up": {
origin: "top left",
position: "bottom left"
}
};
var ARIA_DESCENDANT = "aria-activedescendant";
var ARIA_LABEL = "aria-label";
var ACTIVE_CELL = "gantt_active_cell";
var ACTIVE_OPTION = "action-option-focused";
var DOT = ".";
var TASK_DELETE_CONFIRM = "Are you sure you want to delete this task?";
var DEPENDENCY_DELETE_CONFIRM = "Are you sure you want to delete this dependency?";
var TOGGLE_BUTTON_TEMPLATE = kendo.template('<button class="#=styles.buttonToggle#" type="button" '+ ARIA_LABEL + '="Toggle"><span class="#=styles.iconToggle#"></span></button>');
var BUTTON_TEMPLATE = '<button class="#=styles.button# #=className#" type="button" '+
'#if (action) {#' +
'data-action="#=action#"' +
'#}#' +
'><span class="#=iconClass#"></span><span>#=text#</span></button>';
var COMMAND_BUTTON_TEMPLATE = '<a class="#=className#" #=attr# href="\\#">#=text#</a>';
var VIEWBUTTONTEMPLATE = kendo.template('<li class="#=styles.currentView# #=styles.viewButtonDefault#"><a href="\\#" class="#=styles.link#">&nbps;</a></li>');
var HEADER_VIEWS_TEMPLATE = kendo.template('<ul class="#=styles.viewsWrapper#">' +
'#for(var view in views){#' +
'<li class="#=styles.viewButtonDefault# #=styles.viewButton#-#= view.toLowerCase() #" data-#=ns#name="#=view#"><a href="\\#" class="#=styles.link#">#=views[view].title#</a></li>' +
'#}#' +
'</ul>');
var TASK_DROPDOWN_TEMPLATE = kendo.template('<div class="#=styles.popupWrapper#">' +
'<ul class="#=styles.popupList#" role="listbox">' +
'#for(var i = 0, l = actions.length; i < l; i++){#' +
'<li class="#=styles.item#" data-action="#=actions[i].data#" role="option">#=actions[i].text#</span>' +
'#}#' +
'</ul>' +
'</div>');
var DATERANGEEDITOR = function(container, options) {
var attr = { name: options.field, title: options.title };
var validationRules = options.model.fields[options.field].validation;
if (validationRules && isPlainObject(validationRules) && validationRules.message) {
attr[kendo.attr("dateCompare-msg")] = validationRules.message;
}
$('<input type="text" required ' +
kendo.attr("type") + '="date" ' +
kendo.attr("role") + '="datetimepicker" ' +
kendo.attr("bind") + '="value:' +
options.field +'" ' +
kendo.attr("validate") + "='true' />")
.attr(attr)
.appendTo(container);
$('<span ' + kendo.attr("for") + '="' + options.field + '" class="k-invalid-msg"/>')
.hide()
.appendTo(container);
};
var RESOURCESEDITOR = function(container, options) {
$('<a href="#" class="' + options.styles.button + '">' + options.messages.assignButton + '</a>').click(options.click).appendTo(container);
};
var ganttStyles = {
wrapper: "k-widget k-gantt",
rowHeight: "k-gantt-rowheight",
listWrapper: "k-gantt-layout k-gantt-treelist",
list: "k-gantt-treelist",
timelineWrapper: "k-gantt-layout k-gantt-timeline",
timeline: "k-gantt-timeline",
splitBarWrapper: "k-splitbar k-state-default k-splitbar-horizontal k-splitbar-draggable-horizontal k-gantt-layout",
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-line",
buttonDelete: "k-gantt-delete",
buttonCancel: "k-gantt-cancel",
buttonSave: "k-gantt-update",
buttonToggle: "k-gantt-toggle",
primary: "k-primary",
hovered: "k-state-hover",
selected: "k-state-selected",
focused: "k-state-focused",
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 k-state-default",
button: "k-button",
editField: "k-edit-field",
editLabel: "k-edit-label",
resourcesField: "k-gantt-resources"
},
toolbar: {
headerWrapper: "k-floatwrap k-header k-gantt-toolbar",
footerWrapper: "k-floatwrap k-header k-gantt-toolbar",
toolbar: "k-gantt-toolbar",
expanded: "k-state-expanded",
views: "k-gantt-views",
viewsWrapper: "k-reset k-header k-gantt-views",
actions: "k-gantt-actions",
button: "k-button k-button-icontext",
buttonToggle: "k-button k-button-icon k-gantt-toggle",
iconPlus: "k-icon k-i-plus",
iconPdf: "k-icon k-i-file-pdf",
iconToggle: "k-icon k-i-layout-1-by-4",
viewButtonDefault: "k-state-default",
viewButton: "k-view",
currentView: "k-current-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 dateCompareValidator(input) {
if (input.filter("[name=end], [name=start]").length) {
var field = input.attr("name");
var picker = kendo.widgetInstance(input, kendo.ui);
var dates = {};
var container = input;
var editable;
var model;
while (container !== window && !editable) {
container = container.parent();
editable = container.data("kendoEditable");
}
model = editable ? editable.options.model : null;
if (!model) {
return true;
}
dates.start = model.start;
dates.end = model.end;
dates[field] = picker ? picker.value() : kendo.parseDate(input.val());
return dates.start <= dates.end;
}
return true;
}
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 defaultCommands;
var TaskDropDown = Observable.extend({
init: function(element, options) {
Observable.fn.init.call(this);
this.element = element;
this.options = extend(true, {}, this.options, options);
this._popup();
},
options: {
direction: "down",
navigatable: false
},
_current: function(method) {
var ganttStyles = Gantt.styles;
var current = this.list
.find(DOT + ganttStyles.focused);
var sibling = current[method]();
if (sibling.length) {
current
.removeClass(ganttStyles.focused)
.removeAttr("id");
sibling
.addClass(ganttStyles.focused)
.attr("id", ACTIVE_OPTION);
this.list.find("ul")
.removeAttr(ARIA_DESCENDANT)
.attr(ARIA_DESCENDANT, ACTIVE_OPTION);
}
},
_popup: function() {
var that = this;
var ganttStyles = Gantt.styles;
var itemSelector = "li" + DOT + ganttStyles.item;
var appendButtonSelector = DOT + ganttStyles.toolbar.appendButton;
var actions = this.options.messages.actions;
var navigatable = this.options.navigatable;
this.list = $(TASK_DROPDOWN_TEMPLATE({
styles: ganttStyles,
actions: [
{
data: "add",
text: actions.addChild
},
{
data: "insert-before",
text: actions.insertBefore
},
{
data: "insert-after",
text: actions.insertAfter
}
]
}));
this.element.append(this.list);
this.popup = new kendo.ui.Popup(this.list,
extend({
anchor: this.element.find(appendButtonSelector),
open: function() {
that._adjustListWidth();
},
animation: this.options.animation
}, DIRECTIONS[this.options.direction])
);
this.element
.on(CLICK + NS, appendButtonSelector, function(e) {
var target = $(this);
var action = target.attr(kendo.attr("action"));
e.preventDefault();
if (action) {
that.trigger("command", { type: action });
} else {
that.popup.open();
if (navigatable) {
that.list
.find("li:first")
.addClass(ganttStyles.focused)
.attr("id", ACTIVE_OPTION)
.end()
.find("ul")
.attr({
TABINDEX: 0,
"aria-activedescendant": ACTIVE_OPTION
})
.focus();
}
}
});
this.list
.find(itemSelector)
.hover(function() {
$(this).addClass(ganttStyles.hovered);
}, function() {
$(this).removeClass(ganttStyles.hovered);
})
.end()
.on(CLICK + NS, itemSelector, function() {
that.trigger("command", { type: $(this).attr(kendo.attr("action")) });
that.popup.close();
});
if (navigatable) {
this.popup
.bind("close", function() {
that.list
.find(itemSelector)
.removeClass(ganttStyles.focused)
.end()
.find("ul")
.attr(TABINDEX, 0);
that.element
.parents('[' + kendo.attr("role") + '="gantt"]')
.find(DOT + ganttStyles.gridContent + " > table:first")
.focus();
});
this.list
.find("ul")
.on("keydown" + NS, function(e) {
var key = e.keyCode;
switch (key) {
case keys.UP:
e.preventDefault();
that._current("prev");
break;
case keys.DOWN:
e.preventDefault();
that._current("next");
break;
case keys.ENTER:
that.list
.find(DOT + ganttStyles.focused)
.click();
break;
case keys.ESC:
e.preventDefault();
that.popup.close();
break;
}
});
}
},
_adjustListWidth: function() {
var list = this.list;
var ganttStyles = Gantt.styles;
var width = list[0].style.width;
var wrapper = this.element.find(DOT + ganttStyles.toolbar.appendButton);
var listOuterWidth = outerWidth(list);
var computedStyle;
var computedWidth;
if (!list.data(WIDTH) && width) {
return;
}
computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
computedWidth = computedStyle ? parseFloat(computedStyle.width) : outerWidth(wrapper);
if (computedStyle && (browser.mozilla || browser.msie)) { // getComputedStyle returns different box in FF and IE.
computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
}
if (list.css("box-sizing") !== "border-box") {
width = computedWidth - (outerWidth(list) - list.width());
} else {
width = computedWidth;
}
if (listOuterWidth > width) {
width = listOuterWidth;
}
list.css({
fontFamily: wrapper.css("font-family"),
width: width
})
.data(WIDTH, width);
},
destroy: function() {
clearTimeout(this._focusTimeout);
this.popup.destroy();
this.element.off(NS);
this.list.off(NS);
this.unbind();
}
});
var createDataSource = function(type, name) {
return function(options) {
options = isArray(options) ? { data: options } : options;
var dataSource = options || {};
var data = dataSource.data;
dataSource.data = data;
if (!(dataSource instanceof type) && dataSource instanceof DataSource) {
throw new Error("Incorrect DataSource type. Only " + name + " instances are supported");
}
return dataSource instanceof type ? dataSource : new type(dataSource);
};
};
var GanttDependency = kendo.data.Model.define({
id: "id",
fields: {
id: { type: "number" },
predecessorId: { type: "number" },
successorId: { type: "number" },
type: { type: "number" }
}
});
var GanttDependencyDataSource = DataSource.extend({
init: function(options) {
DataSource.fn.init.call(this, extend(true, {}, {
schema: {
modelBase: GanttDependency,
model: GanttDependency
}
}, options));
},
successors: function(id) {
return this._dependencies("predecessorId", id);
},
predecessors: function(id) {
return this._dependencies("successorId", id);
},
dependencies: function(id) {
var predecessors = this.predecessors(id);
var successors = this.successors(id);
predecessors.push.apply(predecessors, successors);
return predecessors;
},
_dependencies: function(field, id) {
var data = this.view();
var filter = {
field: field,
operator: "eq",
value: id
};
data = new Query(data).filter(filter).toArray();
return data;
}
});
GanttDependencyDataSource.create = createDataSource(GanttDependencyDataSource, "GanttDependencyDataSource");
var GanttTask = kendo.data.Model.define({
duration: function() {
var end = this.end;
var start = this.start;
return end - start;
},
isMilestone: function() {
return this.duration() === 0;
},
_offset: function(value) {
var field = ["start", "end"];
var newValue;
for (var i = 0; i < field.length; i++) {
newValue = new Date(this.get(field[i]).getTime() + value);
this.set(field[i], newValue);
}
},
id: "id",
fields: {
id: { type: "number" },
parentId: { type: "number", defaultValue: null, validation: { required: true } },
orderId: { type: "number", validation: { required: true } },
title: { type: "string", defaultValue: "New task" },
start: { type: "date", validation: { required: true } },
end: {
type: "date", validation: {
required: true,
dateCompare: dateCompareValidator,
message: "End date should be after or equal to the start date"
}
},
percentComplete: { type: "number", validation: { required: true, min:0, max: 1, step: 0.01 } },
summary: { type: "boolean" },
expanded: { type: "boolean", defaultValue: true }
}
});
var GanttDataSource = DataSource.extend({
init: function(options) {
DataSource.fn.init.call(this, extend(true, {}, {
schema: {
modelBase: GanttTask,
model: GanttTask
}
}, options));
},
remove: function(task) {
var parentId = task.get("parentId");
var children = this.taskAllChildren(task);
this._removeItems(children);
task = DataSource.fn.remove.call(this, task);
this._childRemoved(parentId, task.get("orderId"));
return task;
},
add: function(task) {
if (!task) {
return;
}
task = this._toGanttTask(task);
return this.insert(this.taskSiblings(task).length, task);
},
insert: function(index, task) {
if (!task) {
return;
}
task = this._toGanttTask(task);
task.set("orderId", index);
task = DataSource.fn.insert.call(this, index, task);
this._reorderSiblings(task, this.taskSiblings(task).length - 1);
this._resolveSummaryFields(this.taskParent(task));
return task;
},
taskChildren: function(task) {
var data = this.view();
var filter = {
field: "parentId",
operator: "eq",
value: null
};
var order = (this._sort && this._sort.length) ? this._sort : {
field: "orderId",
dir: "asc"
};
var taskId;
if (!!task) {
taskId = task.get("id");
if (taskId === undefined || taskId === null || taskId === "") {
return [];
}
filter.value = taskId;
}
data = new Query(data).filter(filter).sort(order).toArray();
return data;
},
taskAllChildren: function(task) {
var data = [];
var that = this;
var callback = function(task) {
var tasks = that.taskChildren(task);
data.push.apply(data, tasks);
map(tasks, callback);
};
if (!!task) {
callback(task);
} else {
data = this.view();
}
return data;
},
taskSiblings: function(task) {
if (!task) {
return null;
}
var parent = this.taskParent(task);
return this.taskChildren(parent);
},
taskParent: function(task) {
if (!task || task.get("parentId") === null) {
return null;
}
return this.get(task.parentId);
},
taskLevel: function(task) {
var level = 0;
var parent = this.taskParent(task);
while (parent !== null) {
level += 1;
parent = this.taskParent(parent);
}
return level;
},
taskTree: function(task) {
var data = [];
var current;
var tasks = this.taskChildren(task);
for (var i = 0, l = tasks.length; i < l; i++) {
current = tasks[i];
data.push(current);
if (current.get("expanded")) {
var children = this.taskTree(current);
data.push.apply(data, children);
}
}
return data;
},
update: function(task, taskInfo) {
var that = this;
var oldValue;
var offsetChildren = function(parentTask, offset) {
var children = that.taskAllChildren(parentTask);
for (var i = 0, l = children.length; i < l; i++) {
children[i]._offset(offset);
}
};
var modelChangeHandler = function(e) {
var field = e.field;
var model = e.sender;
switch (field) {
case "start":
that._resolveSummaryStart(that.taskParent(model));
offsetChildren(model, model.get(field).getTime() - oldValue.getTime());
break;
case "end":
that._resolveSummaryEnd(that.taskParent(model));
break;
case "percentComplete":
that._resolveSummaryPercentComplete(that.taskParent(model));
break;
case "orderId":
that._reorderSiblings(model, oldValue);
break;
}
};
if (taskInfo.parentId !== undefined) {
oldValue = task.get("parentId");
if (oldValue !== taskInfo.parentId) {
task.set("parentId", taskInfo.parentId);
that._childRemoved(oldValue, task.get("orderId"));
task.set("orderId", that.taskSiblings(task).length - 1);
that._resolveSummaryFields(that.taskParent(task));
}
delete taskInfo.parentId;
}
task.bind("change", modelChangeHandler);
for (var field in taskInfo) {
oldValue = task.get(field);
task.set(field, taskInfo[field]);
}
task.unbind("change", modelChangeHandler);
},
_resolveSummaryFields: function(summary) {
if (!summary) {
return;
}
this._updateSummary(summary);
if (!this.taskChildren(summary).length) {
return;
}
this._resolveSummaryStart(summary);
this._resolveSummaryEnd(summary);
this._resolveSummaryPercentComplete(summary);
},
_resolveSummaryStart: function(summary) {
var that = this;
var getSummaryStart = function(parentTask) {
var children = that.taskChildren(parentTask);
var min = children[0].start.getTime();
var currentMin;
for (var i = 1, l = children.length; i < l; i++) {
currentMin = children[i].start.getTime();
if (currentMin < min) {
min = currentMin;
}
}
return new Date(min);
};
this._updateSummaryRecursive(summary, "start", getSummaryStart);
},
_resolveSummaryEnd: function(summary) {
var that = this;
var getSummaryEnd = function(parentTask) {
var children = that.taskChildren(parentTask);
var max = children[0].end.getTime();
var currentMax;
for (var i = 1, l = children.length; i < l; i++) {
currentMax = children[i].end.getTime();
if (currentMax > max) {
max = currentMax;
}
}
return new Date(max);
};
this._updateSummaryRecursive(summary, "end", getSummaryEnd);
},
_resolveSummaryPercentComplete: function(summary) {
var that = this;
var getSummaryPercentComplete = function(parentTask) {
var children = that.taskChildren(parentTask);
var percentComplete = new Query(children).aggregate([{
field: "percentComplete",
aggregate: "average"
}]);
return percentComplete.percentComplete.average;
};
this._updateSummaryRecursive(summary, "percentComplete", getSummaryPercentComplete);
},
_updateSummaryRecursive: function(summary, field, callback) {
if (!summary) {
return;
}
var value = callback(summary);
summary.set(field, value);
var parent = this.taskParent(summary);
if (parent) {
this._updateSummaryRecursive(parent, field, callback);
}
},
_childRemoved: function(parentId, index) {
var parent = parentId === null ? null : this.get(parentId);
var children = this.taskChildren(parent);
for (var i = index, l = children.length; i < l; i++) {
children[i].set("orderId", i);
}
this._resolveSummaryFields(parent);
},
_reorderSiblings: function(task, oldOrderId) {
var orderId = task.get("orderId");
var direction = orderId > oldOrderId;
var startIndex = direction ? oldOrderId : orderId;
var endIndex = direction ? orderId : oldOrderId;
var newIndex = direction ? startIndex : startIndex + 1;
var siblings = this.taskSiblings(task);
endIndex = Math.min(endIndex, siblings.length - 1);
for (var i = startIndex; i <= endIndex; i++) {
if (siblings[i] === task) {
continue;
}
siblings[i].set("orderId", newIndex);
newIndex += 1;
}
},
_updateSummary: function(task) {
if (task !== null) {
var childCount = this.taskChildren(task).length;
task.set("summary", childCount > 0);
}
},
_toGanttTask: function(task) {
if (!(task instanceof GanttTask)) {
var taskInfo = task;
task = this._createNewModel();
task.accept(taskInfo);
}
return task;
}
});
GanttDataSource.create = createDataSource(GanttDataSource, "GanttDataSource");
extend(true, kendo.data, {
GanttDataSource: GanttDataSource,
GanttTask: GanttTask,
GanttDependencyDataSource: GanttDependencyDataSource,
GanttDependency: GanttDependency
});
var editors = {
desktop: {
dateRange: DATERANGEEDITOR,
resources: RESOURCESEDITOR
}
};
var Editor = kendo.Observable.extend({
init: function(element, options) {
kendo.Observable.fn.init.call(this);
this.element = element;
this.options = extend(true, {}, this.options, options);
this.createButton = this.options.createButton;
},
fields: function(editors, model) {
var that = this;
var options = this.options;
var messages = options.messages.editor;
var resources = options.resources;
var fields;
var click = function(e) {
e.preventDefault();
resources.editor(that.container.find(DOT + Gantt.styles.popup.resourcesField), model);
};
if (options.editable.template) {
fields = $.map(model.fields, function(value, key) {
return { field: key };
});
} else {
fields = [
{ field: "title", title: messages.title },
{ field: "start", title: messages.start, editor: editors.dateRange },
{ field: "end", title: messages.end, editor: editors.dateRange },
{ field: "percentComplete", title: messages.percentComplete, format: PERCENTAGE_FORMAT }
];
if (model.get(resources.field)) {
fields.push({ field: resources.field, title: messages.resources, messages: messages, editor: editors.resources, click: click, styles: Gantt.styles.popup });
}
}
return fields;
},
_buildEditTemplate: function(model, fields, editableFields) {
var resources = this.options.resources;
var template = this.options.editable.template;
var settings = extend({}, kendo.Template, this.options.templateSettings);
var paramName = settings.paramName;
var popupStyles = Gantt.styles.popup;
var html = "";
if (template) {
if (typeof template === STRING) {
template = window.unescape(template);
}
html += (kendo.template(template, settings))(model);
} else {
for (var i = 0, length = fields.length; i < length; i++) {
var field = fields[i];
html += '<div class="' + popupStyles.editLabel + '"><label for="' + field.field + '">' + (field.title || field.field || "") + '</label></div>';
if (field.field === resources.field) {
html += '<div class="' + popupStyles.resourcesField + '" style="display:none"></div>';
}
if ((!model.editable || model.editable(field.field))) {
editableFields.push(field);
html += '<div ' + kendo.attr("container-for") + '="' + field.field + '" class="' + popupStyles.editField + '"></div>';
} else {
var tmpl = "#:";
if (field.field) {
field = kendo.expr(field.field, paramName);
tmpl += field + "==null?'':" + field;
} else {
tmpl += "''";
}
tmpl += "#";
tmpl = kendo.template(tmpl, settings);
html += '<div class="' + popupStyles.editField + '">' + tmpl(model) + '</div>';
}
}
}
return html;
}
});
var PopupEditor = Editor.extend({
destroy: function() {
this.close();
this.unbind();
},
editTask: function(task) {
this.editable = this._createPopupEditor(task);
},
close: function() {
var that = this;
var destroy = function() {
if (that.editable) {
that.editable.destroy();
that.editable = null;
that.container = null;
}
if (that.popup) {
that.popup.destroy();
that.popup = null;
}
};
if (this.editable && this.container.is(":visible")) {
that.trigger("close", { window: that.container });
this.container.data("kendoWindow").bind("deactivate", destroy).close();
} else {
destroy();
}
},
showDialog: function(options) {
var buttons = options.buttons;
var popupStyles = Gantt.styles.popup;
var html = kendo.format('<div class="{0}"><div class="{1}"><p class="{2}">{3}</p><div class="{4}">',
popupStyles.form, popupStyles.formContainer, popupStyles.message, options.text, popupStyles.buttonsContainer);
for (var i = 0, length = buttons.length; i < length; i++) {
html += this.createButton(buttons[i]);
}
html += '</div></div></div>';
var wrapper = this.element;
if (this.popup) {
this.popup.destroy();
}
var popup = this.popup = $(html).appendTo(wrapper)
.eq(0)
.on("click", DOT + popupStyles.button, function(e) {
e.preventDefault();
popup.close();
var buttonIndex = $(e.currentTarget).index();
buttons[buttonIndex].click();
})
.kendoWindow({
modal: true,
autoFocus: false,
resizable: false,
draggable: false,
title: options.title,
visible: false,
deactivate: function() {
this.destroy();
wrapper.focus();
}
})
.getKendoWindow();
popup.center().open();
popup.element.find(".k-primary").focus();
},
_createPopupEditor: function(task) {
var that = this;
var options = {};
var messages = this.options.messages;
var ganttStyles = Gantt.styles;
var popupStyles = ganttStyles.popup;
var html = kendo.format('<div {0}="{1}" class="{2} {3}"><div class="{4}">',
kendo.attr("uid"), task.uid, popupStyles.form, popupStyles.editForm, popupStyles.formContainer);
var fields = this.fields(editors.desktop, task);
var editableFields = [];
html += this._buildEditTemplate(task, fields, editableFields);
html += '<div class="' + popupStyles.buttonsContainer + '">';
html += this.createButton({ name: "update", text: messages.save, className: Gantt.styles.primary });
html += this.createButton({ name: "cancel", text: messages.cancel });
if (that.options.editable.destroy !== false) {
html += this.createButton({ name: "delete", text: messages.destroy });
}
html += '</div></div></div>';
var container = this.container = $(html).appendTo(this.element)
.eq(0)
.kendoWindow(extend({
modal: true,
resizable: false,
draggable: true,
title: messages.editor.editorTitle,
visible: false,
close: function(e) {
if (e.userTriggered) {
if (that.trigger("cancel", { container: container, model: task })) {
e.preventDefault();
}
}
}
}, options));
var editableWidget = container
.kendoEditable({
fields: editableFields,
model: task,
clearContainer: false,
validateOnBlur: true,
target: that.options.target
})
.data("kendoEditable");
kendo.cycleForm(container);
if (!this.trigger("edit", { container: container, model: task })) {
container.data("kendoWindow").center().open();
container.on(CLICK + NS, DOT + ganttStyles.buttonCancel, function(e) {
e.preventDefault();
e.stopPropagation();
that.trigger("cancel", { container: container, model: task });
});
container.on(CLICK + NS, DOT + ganttStyles.buttonSave, function(e) {
e.preventDefault();
e.stopPropagation();
var fields = that.fields(editors.desktop, task);
var updateInfo = {};
var field;
for (var i = 0, length = fields.length; i < length; i++) {
field = fields[i].field;
updateInfo[field] = task.get(field);
}
that.trigger("save", { container: container, model: task, updateInfo: updateInfo });
});
container.on(CLICK + NS, DOT + ganttStyles.buttonDelete, function(e) {
e.preventDefault();
e.stopPropagation();
that.trigger("remove", { container: container, model: task });
});
} else {
that.trigger("cancel", { container: container, model: task });
}
return editableWidget;
}
});
var ResourceEditor = Widget.extend({
init: function(element, options) {
Widget.fn.init.call(this, element, options);
this.wrapper = this.element;
this.model = this.options.model;
this.resourcesField = this.options.resourcesField;
this.createButton = this.options.createButton;
this._initContainer();
this._attachHandlers();
},
events: [
"save"
],
open: function() {
this.window.center().open();
},
close: function() {
this.window.bind("deactivate", proxy(this.destroy, this)).close();
},
destroy: function() {
this._dettachHandlers();
this.grid.destroy();
this.grid = null;
this.window.destroy();
this.window = null;
Widget.fn.destroy.call(this);
kendo.destroy(this.wrapper);
this.element = this.wrapper = null;
},
_attachHandlers: function() {
var ganttStyles = Gantt.styles;
var grid = this.grid;
var closeHandler = this._cancelProxy = proxy(this._cancel, this);
this.container.on(CLICK + NS, DOT + ganttStyles.buttonCancel, this._cancelProxy);
this._saveProxy = proxy(this._save, this);
this.container.on(CLICK + NS, DOT + ganttStyles.buttonSave, this._saveProxy);
this.window.bind("close", function(e) {
if (e.userTriggered) {
closeHandler(e);
}
});
grid.wrapper.on(CLICK + NS, "input[type='checkbox']", function() {
var element = $(this);
var row = $(element).closest("tr");
var model = grid.dataSource.getByUid(row.attr(kendo.attr("uid")));
var value = $(element).is(":checked") ? 1 : "";
model.set("value", value);
});
},
_dettachHandlers: function() {
this._cancelProxy = null;
this._saveProxy = null;
this.container.off(NS);
this.grid.wrapper.off();
},
_cancel: function(e) {
e.preventDefault();
this.close();
},
_save: function(e) {
e.preventDefault();
this._updateModel();
if (!this.wrapper.is(DOT + Gantt.styles.popup.resourcesField)) {
this.trigger("save", { container: this.wrapper, model: this.model });
}
this.close();
},
_initContainer: function() {
var that = this;
var popupStyles = Gantt.styles.popup;
var dom = kendo.format('<div class="{0} {1}"><div class="{2} {3}"/></div>"',
popupStyles.form, popupStyles.editForm, popupStyles.formContainer, popupStyles.resourcesFormContainer);
dom = $(dom);
this.container = dom.find(DOT + popupStyles.resourcesFormContainer);
this.window = dom.kendoWindow({
modal: true,
resizable: false,
draggable: true,
visible: false,
title: this.options.messages.resourcesEditorTitle,
open: function() {
that.grid.resize(true);
}
}).data("kendoWindow");
this._resourceGrid();
this._createButtons();
},
_resourceGrid: function() {
var that = this;
var messages = this.options.messages;
var element = $('<div id="resources-grid"/>').appendTo(this.container);
this.grid = new kendo.ui.Grid(element, {
columns: [
{
field: "name",
title: messages.resourcesHeader,
template:
"<label><input type='checkbox' value='#=name#'" +
"# if (value > 0 && value !== null) {#" +
"checked='checked'" +
"# } #" +
"/>#=name#</labe>"
},
{
field: "value",
title: messages.unitsHeader,
template: function(dataItem) {
var valueFormat = dataItem.format;
var value = dataItem.value !== null ? dataItem.value : "";
return valueFormat ? kendo.toString(value, valueFormat) : value;
}
}
],
height: 280,
sortable: true,
editable: true,
filterable: true,
dataSource: {
data: that.options.data,
schema: {
model: {
id: "id",
fields: {
id: { from: "id" },
name: { from: "name", type: "string", editable: false},
value: { from: "value", type: "number", validation: this.options.unitsValidation },
format: { from: "format", type: "string" }
}
}
}
},
save: function(e) {
var value = !!e.values.value;
e.container.parent().find("input[type='checkbox']").prop("checked", value);
}
});
},
_createButtons: function() {
var buttons = this.options.buttons;
var html = '<div class="' + Gantt.styles.popup.buttonsContainer + '">';
for (var i = 0, length = buttons.length; i < length; i++) {
html += this.createButton(buttons[i]);
}
html += "</div>";
this.container.append(html);
},
_updateModel: function() {
var resources = [];
var value;
var data = this.grid.dataSource.data();
for (var i = 0, length = data.length; i < length; i++) {
value = data[i].get("value");
if (value !== null && value > 0) {
resources.push(data[i]);
}
}
this.model[this.resourcesField] = resources;
}
});
var Gantt = Widget.extend({
init: function(element, options, events) {
if (isArray(options)) {
options = { dataSource: options };
}
defaultCommands = {
append: {
text: "Add Task",
action: "add",
className: Gantt.styles.toolbar.appendButton,
iconClass: Gantt.styles.toolbar.iconPlus
},
pdf: {
text: "Export to PDF",
className: Gantt.styles.toolbar.pdfButton,
iconClass: Gantt.styles.toolbar.iconPdf
}
};
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._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._dropDowns();
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",
"columnResize"
],
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",
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"
},
editor: {
editorTitle: "Task",
resourcesEditorTitle: "Resources",
title: "Title",
start: "Start",
end: "End",
percentComplete: "Complete",
resources: "Resources",
assignButton: "Assign",
resourcesHeader: "Resources",
unitsHeader: "Units"
}
},
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
},
select: function(value) {
var list = this.list;
if (!value) {
return list.select();
}
list.select(value);
this.list.element.find("table[role=treegrid]").focus();
return;
},
clearSelection: function() {
this.list.clearSelection();
},
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.footerDropDown) {
this.footerDropDown.destroy();
}
if (this.headerDropDown) {
this.headerDropDown.destroy();
}
if (this._editor) {
this._editor.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;
},
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 = proxy(this.resize, this, false);
$(window).on("resize" + NS, this._resizeHandler);
},
_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)
.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>");
this.wrapper.find(DOT + ganttStyles.list).width(options.listWidth);
if (height) {
this.wrapper.height(height);
}
if (width) {
this.wrapper.width(width);
}
if (options.rowHeight) {
this.wrapper.addClass(ganttStyles.rowHeight);
}
},
_toolbar: function() {
var that = this;
var ganttStyles = Gantt.styles;
var viewsSelector = DOT + ganttStyles.toolbar.views + " > li";
var pdfSelector = DOT + ganttStyles.toolbar.pdfButton;
var toggleSelector = DOT + ganttStyles.buttonToggle;
var contentSelector = DOT + ganttStyles.gridContent;
var treelist = $(DOT + ganttStyles.list);
var timeline = $(DOT + ganttStyles.timeline);
var hoveredClassName = ganttStyles.hovered;
var actions = this.options.toolbar;
var actionsWrap = $("<div class='" + ganttStyles.toolbar.actions + "'>");
var toolbar;
var views;
var toggleButton;
var handler = function(e) {
if (e.matches) {
treelist.css({
"display": "none",
"max-width": 0
});
} else {
treelist.css({
"display": "inline-block",
"width": "30%",
"max-width": "none"
});
timeline.css("display", "inline-block");
that.refresh();
timeline
.find(contentSelector)
.scrollTop(that.scrollTop);
}
that._resize();
};
if (!isFunction(actions)) {
actions = (typeof actions === STRING ? actions : this._actions(actions));
actions = proxy(kendo.template(actions), this);
}
toggleButton = $(TOGGLE_BUTTON_TEMPLATE({ styles: ganttStyles.toolbar }));
views = $(HEADER_VIEWS_TEMPLATE({
ns: kendo.ns,
views: this.timeline.views,
styles: ganttStyles.toolbar
}));
actionsWrap.append(actions({}));
toolbar = $("<div class='" + ganttStyles.toolbar.headerWrapper + "'>")
.append(toggleButton)
.append(views)
.append(actionsWrap);
if (views.find("li").length > 1) {
views.prepend(VIEWBUTTONTEMPLATE({ styles: ganttStyles.toolbar }));
}
this.wrapper.prepend(toolbar);
this.toolbar = toolbar;
if (supportsMedia) {
this._mediaQueryHandler = proxy(handler, this);
this._mediaQuery = window.matchMedia("(max-width: 480px)");
this._mediaQuery.addListener(this._mediaQueryHandler);
}
toolbar
.on(CLICK + NS, viewsSelector, function(e) {
e.preventDefault();
var list = that.list;
var name = $(this).attr(kendo.attr("name"));
var currentView = views.find(DOT + ganttStyles.toolbar.currentView);
if (currentView.is(":visible")) {
currentView.parent().toggleClass(ganttStyles.toolbar.expanded);
}
if (list.editable && list.editable.trigger("validate")) {
return;
}
if (!that.trigger("navigate", { view: name })) {
that.view(name);
}
that.toolbar.find(DOT + ganttStyles.focused).removeClass(ganttStyles.focused);
})
.on("keydown" + NS, viewsSelector, function(e) {
var views = $(DOT + ganttStyles.toolbar.views).children(":not(.k-current-view)");
var focusedViewIndex = views.index((that._focusedView && that._focusedView[0]) || views.closest(DOT + ganttStyles.selected)[0]);
if (e.keyCode === keys.RIGHT) {
$(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
that._focusedView = focusedViewIndex + 1 === views.length ? $(views[0]) : $(views[focusedViewIndex + 1]);
that._focusedView.focus().addClass(ganttStyles.focused);
e.preventDefault();
} else if (e.keyCode === keys.LEFT) {
$(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
that._focusedView = focusedViewIndex === 0 ? $(views[views.length - 1]) : $(views[focusedViewIndex - 1]);
that._focusedView.focus().addClass(ganttStyles.focused);
e.preventDefault();
} else if (e.keyCode === keys.DOWN && that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().hasClass(ganttStyles.toolbar.expanded)) {
$(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
that._focusedView = focusedViewIndex + 1 === views.length ? $(views[0]) : $(views[focusedViewIndex + 1]);
that._focusedView.focus().addClass(ganttStyles.focused);
e.preventDefault();
} else if (e.keyCode === keys.UP && that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().hasClass(ganttStyles.toolbar.expanded)) {
$(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
that._focusedView = focusedViewIndex === 0 ? $(views[views.length - 1]) : $(views[focusedViewIndex - 1]);
that._focusedView.focus().addClass(ganttStyles.focused);
e.preventDefault();
} else if ((e.keyCode === keys.ENTER || e.keyCode === keys.SPACEBAR) && that._focusedView) {
that.view(that._focusedView.text().toLowerCase());
e.preventDefault();
} else if ((e.keyCode === keys.SPACEBAR || e.keyCode === keys.ENTER || (e.keyCode === keys.DOWN && e.altKey)) && that.toolbar.find(DOT + ganttStyles.toolbar.currentView + " > a").hasClass(ganttStyles.focused)) {
that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().toggleClass(ganttStyles.toolbar.expanded);
e.preventDefault();
} else if (e.keyCode === keys.ESC && that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().hasClass(ganttStyles.toolbar.expanded)) {
that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().toggleClass(ganttStyles.toolbar.expanded).blur();
that._focusedView = null;
that.toolbar.find(DOT + ganttStyles.toolbar.currentView + " > a").addClass(ganttStyles.focused).focus();
e.preventDefault();
} else if (e.keyCode >= 49 && e.keyCode <= 57) {
that.view(that.timeline._viewByIndex(e.keyCode - 49));
}
})
.on(CLICK + NS, pdfSelector, function(e) {
e.preventDefault();
that.saveAsPDF();
})
.on(CLICK + NS, toggleSelector, function(e) {
e.preventDefault();
if (treelist.is(":visible")) {
treelist.css({
"display": "none",
"width": "0"
});
timeline.css({
"display": "inline-block",
"width": "100%"
});
that.refresh();
timeline
.find(contentSelector)
.scrollTop(that.scrollTop);
} else {
timeline.css({
"display": "none",
"width": 0
});
treelist
.css({
"display": "inline-block",
"width": "100%",
"max-width": "none"
})
.find(contentSelector)
.scrollTop(that.scrollTop);
}
that._resize();
});
this.wrapper
.on("focusout" + NS, function(e) {
if (!$(e.relatedTarget).closest(DOT + ganttStyles.toolbar.toolbar).length) {
that.toolbar.find(DOT + ganttStyles.focused).removeClass(ganttStyles.focused);
}
if (!$(e.relatedTarget).closest(DOT + ganttStyles.toolbar.views).length) {
that.toolbar.find(DOT + ganttStyles.toolbar.views).removeClass(ganttStyles.toolbar.expanded);
}
})
.find(DOT + ganttStyles.toolbar.toolbar + " li")
.hover(function() {
$(this).addClass(hoveredClassName);
}, function() {
$(this).removeClass(hoveredClassName);
});
},
_actions: function() {
var options = this.options;
var editable = options.editable;
var actions = options.toolbar;
var html = "";
if (!isArray(actions)) {
if (editable && editable.create !== false) {
actions = ["append"];
} else {
return html;
}
}
for (var i = 0, length = actions.length; i < length; i++) {
html += this._createButton(actions[i]);
}
return html;
},
_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 button = $(kendo.template(BUTTON_TEMPLATE)(extend(true, { styles: ganttStyles }, defaultCommands.append, { text: messages.append })));
var actionsWrap = $("<div class='" + ganttStyles.actions + "'>").append(button);
var footer = $("<div class='" + ganttStyles.footerWrapper + "'>").append(actionsWrap);
this.wrapper.append(footer);
this.footer = footer;
},
_createButton: function(command) {
var template = command.template || BUTTON_TEMPLATE;
var messages = this.options.messages.actions;
var commandName = typeof command === STRING ? command : command.name || command.text;
var className = defaultCommands[commandName] ? defaultCommands[commandName].className : "k-gantt-" + (commandName || "").replace(/\s/g, "");
var options = {
iconClass: "",
action: "",
text: commandName,
className: className,
styles: Gantt.styles.toolbar
};
if (!commandName && !(isPlainObject(command) && command.template)) {
throw new Error("Custom commands should have name specified");
}
options = extend(true, options, defaultCommands[commandName], { text: messages[commandName] });
if (isPlainObject(command)) {
if (command.className && inArray(options.className, command.className.split(" ")) < 0) {
command.className += " " + options.className;
}
options = extend(true, options, command);
}
return kendo.template(template)(options);
},
_adjustDimensions: function() {
var element = this.element;
var ganttStyles = Gantt.styles;
var listSelector = DOT + ganttStyles.list;
var timelineSelector = DOT + ganttStyles.timeline;
var splitBarSelector = DOT + ganttStyles.splitBar;
var toolbarHeight = outerHeight(this.toolbar);
var footerHeight = this.footer ? outerHeight(this.footer) : 0;
var totalHeight = element.height();
var totalWidth = element.width();
var splitBarWidth = outerWidth(element.find(splitBarSelector));
var treeListWidth = outerWidth(element.find(listSelector));
element
.children([listSelector, timelineSelector, splitBarSelector].join(","))
.height(totalHeight - (toolbarHeight + footerHeight))
.end()
.children(timelineSelector)
.width(totalWidth - (splitBarWidth + treeListWidth));
if (totalWidth < (treeListWidth + splitBarWidth)) {
element.find(listSelector).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.content.find(selector(id));
action = function() {
scrollTarget.get(0).scrollIntoView();
};
}
scrollIntoView();
},
_dropDowns: function() {
var that = this;
var actionsSelector = DOT + Gantt.styles.toolbar.actions;
var actionMessages = this.options.messages.actions;
var timeline = this.timeline;
var editable = this.options.editable;
var handler = function(e) {
var type = e.type;
var orderId;
var dataSource = that.dataSource;
var task = dataSource._createNewModel();
var selected = that.dataItem(that.select());
var parent = dataSource.taskParent(selected);
var firstSlot = timeline.view()._timeSlots()[0];
var target = type === "add" ? selected : parent;
var editable = that.list.editable;
if (editable && editable.trigger("validate")) {
return;
}
task.set("title", "New task");
if (target) {
task.set("parentId", target.get("id"));
task.set("start", target.get("start"));
task.set("end", target.get("end"));
} else {
task.set("start", firstSlot.start);
task.set("end", firstSlot.end);
}
if (type !== "add") {
orderId = selected.get("orderId");
orderId = type === "insert-before" ? orderId : orderId + 1;
}
that._createTask(task, orderId);
};
if (!editable || editable.create === false) {
return;
}
this.footerDropDown = new TaskDropDown(this.footer.children(actionsSelector).eq(0), {
messages: {
actions: actionMessages
},
direction: "up",
animation: {
open: {
effects: "slideIn:up"
}
},
navigatable: that.options.navigatable
});
this.headerDropDown = new TaskDropDown(this.toolbar.children(actionsSelector).eq(0), {
messages: {
actions: actionMessages
},
navigatable: that.options.navigatable
});
this.footerDropDown.bind("command", handler);
this.headerDropDown.bind("command", handler);
},
_list: function() {
var that = this;
var navigatable = that.options.navigatable;
var ganttStyles = Gantt.styles;
var listWrapper = this.wrapper.find(DOT + ganttStyles.list);
var element = listWrapper.find("> div");
var toggleButtons = this.wrapper.find(DOT + ganttStyles.toolbar.actions + " > button");
var options = {
columns: this.options.columns || [],
dataSource: this.dataSource,
selectable: this.options.selectable,
editable: this.options.editable,
resizable: this.options.resizable,
columnResizeHandleWidth: this.options.columnResizeHandleWidth,
listWidth: outerWidth(listWrapper),
resourcesField: this.resources.field,
rowHeight: this.options.rowHeight
};
var columns = options.columns;
var column;
var restoreFocus = function() {
if (navigatable) {
that._current(that._cachedCurrent);
focusTable(that.list.content.find("table"), true);
}
delete that._cachedCurrent;
};
for (var i = 0; i < columns.length; i++) {
column = columns[i];
if (column.field === this.resources.field && typeof column.editor !== "function") {
column.editor = proxy(this._createResourceEditor, this);
}
}
this.list = new kendo.ui.GanttList(element, options);
this.list
.bind("render", function() {
that._navigatable();
}, true)
.bind("edit", function(e) {
that._cachedCurrent = e.cell;
if (that.trigger("edit", { task: e.model, container: e.cell })) {
e.preventDefault();
}
})
.bind("cancel", function(e) {
if (that.trigger("cancel", { task: e.model, container: e.cell })) {
e.preventDefault();
}
restoreFocus();
})
.bind("update", function(e) {
that._updateTask(e.task, e.updateInfo);
restoreFocus();
})
.bind("change", function() {
that.trigger("change");
var selection = that.list.select();
if (selection.length) {
toggleButtons.removeAttr("data-action", "add");
that.timeline.select("[data-uid='" + selection.attr("data-uid") + "']");
} else {
toggleButtons.attr("data-action", "add");
that.timeline.clearSelection();
}
})
.bind("columnResize", function(e) {
that.trigger("columnResize", { column: e.column, oldWidth: e.oldWidth, newWidth: e.newWidth });
});
},
_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");
var currentViewSelector = DOT + ganttStyles.toolbar.currentView + " > " + DOT + ganttStyles.toolbar.link;
this.timeline = new kendo.ui.GanttTimeline(element, options);
this.timeline
.bind("navigate", function(e) {
var viewName = e.view.replace(/\./g, "\\.").toLowerCase();
var text = that.toolbar
.find(DOT + ganttStyles.toolbar.views +" > li")
.removeClass(ganttStyles.selected)
.end()
.find(DOT + ganttStyles.toolbar.viewButton + "-" + viewName)
.addClass(ganttStyles.selected)
.find(DOT + ganttStyles.toolbar.link)
.text();
that.toolbar
.find(currentViewSelector)
.text(text);
that.refresh();
})
.bind("moveStart", function(e) {
var editable = that.list.editable;
if (editable && editable.trigger("validate")) {
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.editable;
if (editable && editable.trigger("validate")) {
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.editable;
if (editable && editable.trigger("validate")) {
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.editable;
if (editable && editable.trigger("validate")) {
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.editable;
if (editable) {
editable.trigger("validate");
}
that.select("[data-uid='" + e.uid + "']");
})
.bind("editTask", function(e) {
var editable = that.list.editable;
if (editable && editable.trigger("validate")) {
return;
}
that.editTask(e.uid);
})
.bind("clear", function() {
that.clearSelection();
})
.bind("removeTask", function(e) {
var editable = that.list.editable;
if (editable && editable.trigger("validate")) {
return;
}
that.removeTask(that.dataSource.getByUid(e.uid));
})
.bind("removeDependency", function(e) {
var editable = that.list.editable;
if (editable && editable.trigger("validate")) {
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 = proxy(this.refresh, this);
this._progressHandler = proxy(this._requestStart, this);
this._errorHandler = proxy(this._error, this);
}
this.dataSource = kendo.data.GanttDataSource.create(dataSource)
.bind("change", this._refreshHandler)
.bind("progress", this._progressHandler)
.bind("error", this._errorHandler);
},
_dependencies: function() {
var dependencies = this.options.dependencies || {};
var dataSource = isArray(dependencies) ? { data: dependencies } : dependencies;
if (this.dependencies && this._dependencyRefreshHandler) {
this.dependencies
.unbind("change", this._dependencyRefreshHandler)
.unbind("error", this._dependencyErrorHandler);
} else {
this._dependencyRefreshHandler = proxy(this.refreshDependencies, this);
this._dependencyErrorHandler = proxy(this._error, this);
}
this.dependencies = kendo.data.GanttDependencyDataSource.create(dataSource)
.bind("change", this._dependencyRefreshHandler)
.bind("error", this._dependencyErrorHandler);
},
_resources: function() {
var resources = this.options.resources;
var dataSource = resources.dataSource || {};
this.resources = {
field: "resources",
dataTextField: "name",
dataColorField: "color",
dataFormatField: "format"
};
extend(this.resources, resources);
this.resources.dataSource = kendo.data.DataSource.create(dataSource);
},
_assignments: function() {
var assignments = this.options.assignments;
var dataSource = assignments.dataSource || { };
if (this.assignments) {
this.assignments.dataSource
.unbind("change", this._assignmentsRefreshHandler);
} else {
this._assignmentsRefreshHandler = proxy(this.refresh, this);
}
this.assignments = {
dataTaskIdField: "taskId",
dataResourceIdField: "resourceId",
dataValueField: "value"
};
extend(this.assignments, assignments);
this.assignments.dataSource = kendo.data.DataSource.create(dataSource);
this.assignments.dataSource.
bind("change", this._assignmentsRefreshHandler);
},
_createEditor: function() {
var that = this;
var editor = this._editor = new PopupEditor(this.wrapper, extend({}, this.options, {
target: this,
resources: {
field: this.resources.field,
editor: proxy(this._createResourceEditor, this)
},
createButton: proxy(this._createPopupButton, this)
}));
editor
.bind("cancel", function(e) {
var task = that.dataSource.getByUid(e.model.uid);
if (that.trigger("cancel", { container: e.container, task: task })) {
e.preventDefault();
return;
}
that.cancelTask();
})
.bind("edit", function(e) {
var task = that.dataSource.getByUid(e.model.uid);
if (that.trigger("edit", { container: e.container, task: task })) {
e.preventDefault();
}
})
.bind("save", function(e) {
var task = that.dataSource.getByUid(e.model.uid);
that.saveTask(task, e.updateInfo);
})
.bind("remove", function(e) {
that.removeTask(e.model.uid);
})
.bind("close", that._onDialogClose);
},
_onDialogClose: function() {},
_createResourceEditor: function(container, options) {
var that = this;
var model = options instanceof ObservableObject ? options : options.model;
var id = model.get("id");
var messages = this.options.messages;
var resourcesField = this.resources.field;
var unitsValidation = { step: 0.01 };
var assignmentsModel = this.assignments.dataSource.options.schema.model;
if (assignmentsModel && assignmentsModel.fields.Units && assignmentsModel.fields.Units.validation) {
extend(true, unitsValidation, assignmentsModel.fields.Units.validation);
}
var editor = this._resourceEditor = new ResourceEditor(container, {
resourcesField: resourcesField,
unitsValidation: unitsValidation,
data: this._wrapResourceData(id),
model: model,
messages: extend({}, messages.editor),
buttons: [
{ name: "update", text: messages.save, className: Gantt.styles.primary },
{ name: "cancel", text: messages.cancel }
],
createButton: proxy(this._createPopupButton, this),
save: function(e) {
that._updateAssignments(e.model.get("id"), e.model.get(resourcesField));
}
});
editor.open();
},
_createPopupButton: function(command) {
var commandName = command.name || command.text;
var options = {
className: Gantt.styles.popup.button + " k-gantt-" + (commandName || "").replace(/\s/g, ""),
text: commandName,
attr: ""
};
if (!commandName && !(isPlainObject(command) && command.template)) {
throw new Error("Custom commands should have name specified");
}
if (isPlainObject(command)) {
if (command.className) {
command.className += " " + options.className;
}
options = extend(true, options, command);
}
return kendo.template(COMMAND_BUTTON_TEMPLATE)(options);
},
view: function(type) {
return this.timeline.view(type);
},
range: function (range) {
var dataSource = this.dataSource;
var view = this.view();
var timeline = this.timeline;
if (range) {
view.options.range = {
start: range.start,
end: range.end
};
timeline._render(dataSource.taskTree());
timeline._renderDependencies(this.dependencies.view());
}
return {
start: view.start,
end: view.end
};
},
date: function (date) {
var view = this.view();
if (date) {
view.options.date = date;
view._scrollToDate(date);
}
return view.options.date;
},
dataItem: function(value) {
if (!value) {
return null;
}
var list = this.list;
var element = list.content.find(value);
return list._modelFromElement(element);
},
setDataSource: function(dataSource) {
this.options.dataSource = dataSource;
this._dataSource();
this.list._setDataSource(this.dataSource);
if (this.options.autoBind) {
dataSource.fetch();
}
},
setDependenciesDataSource: function(dependencies) {
this.options.dependencies = dependencies;
this._dependencies();
if (this.options.autoBind) {
dependencies.fetch();
}
},
items: function() {
return this.wrapper.children(".k-task");
},
_updateAssignments: function(id, resources) {
var dataSource = this.assignments.dataSource;
var taskId = this.assignments.dataTaskIdField;
var resourceId = this.assignments.dataResourceIdField;
var hasMatch = false;
var assignments = new Query(dataSource.view())
.filter({
field: taskId,
operator: "eq",
value: id
}).toArray();
var assignment;
var resource;
var value;
while (assignments.length) {
assignment = assignments[0];
for (var i = 0, length = resources.length; i < length; i++) {
resource = resources[i];
if (assignment.get(resourceId) === resource.get("id")) {
value = resources[i].get("value");
this._updateAssignment(assignment, value);
resources.splice(i, 1);
hasMatch = true;
break;
}
}
if (!hasMatch) {
this._removeAssignment(assignment);
}
hasMatch = false;
assignments.shift();
}
for (var j = 0, newLength = resources.length; j < newLength; j++) {
resource = resources[j];
this._createAssignment(resource, id);
}
dataSource.sync();
},
cancelTask: function() {
var editor = this._editor;
var container = editor.container;
if (container) {
editor.close();
}
},
editTask: function(uid) {
var task = typeof uid === "string" ? this.dataSource.getByUid(uid) : uid;
if (!task) {
return;
}
var taskCopy = this.dataSource._createNewModel(task.toJSON());
taskCopy.uid = task.uid;
this.cancelTask();
this._editTask(taskCopy);
},
_editTask: function(task) {
this._editor.editTask(task);
},
saveTask: function(task, updateInfo) {
var editor = this._editor;
var container = editor.container;
var editable = editor.editable;
if (container && editable && editable.end()) {
this._updateTask(task, updateInfo);
}
},
_updateTask: function(task, updateInfo) {
var resourcesField = this.resources.field;
if (!this.trigger("save", { task: task, values: updateInfo })) {
this._preventRefresh = true;
this.dataSource.update(task, updateInfo);
if (updateInfo[resourcesField]) {
this._updateAssignments(task.get("id"), updateInfo[resourcesField]);
}
this._syncDataSource();
}
},
_updateAssignment: function(assignment, value) {
var resourceValueField = this.assignments.dataValueField;
assignment.set(resourceValueField, value);
},
removeTask: function(uid) {
var that = this;
var task = typeof uid === "string" ? this.dataSource.getByUid(uid) : uid;
if (!task) {
return;
}
this._taskConfirm(function(cancel) {
if (!cancel) {
that._removeTask(task);
}
}, task);
},
_createTask: function(task, index) {
if (!this.trigger("add", {
task: task,
dependency: null
})) {
var dataSource = this.dataSource;
this._preventRefresh = true;
if (index === undefined) {
dataSource.add(task);
} else {
dataSource.insert(index, task);
}
this._scrollToUid = task.uid;
this._syncDataSource();
}
},
_createDependency: function(dependency) {
if (!this.trigger("add", {
task: null,
dependency: dependency
})) {
this._preventDependencyRefresh = true;
this.dependencies.add(dependency);
this._preventDependencyRefresh = false;
this.dependencies.sync();
}
},
_createAssignment: function(resource, id) {
var assignments = this.assignments;
var dataSource = assignments.dataSource;
var taskId = assignments.dataTaskIdField;
var resourceId = assignments.dataResourceIdField;
var resourceValue = assignments.dataValueField;
var assignment = dataSource._createNewModel();
assignment[taskId] = id;
assignment[resourceId] = resource.get("id");
assignment[resourceValue] = resource.get("value");
dataSource.add(assignment);
},
removeDependency: function(uid) {
var that = this;
var dependency = typeof uid === "string" ? this.dependencies.getByUid(uid) : uid;
if (!dependency) {
return;
}
this._dependencyConfirm(function(cancel) {
if (!cancel) {
that._removeDependency(dependency);
}
}, dependency);
},
_removeTaskDependencies: function(task, dependencies) {
this._preventDependencyRefresh = true;
for (var i = 0, length = dependencies.length; i < length; i++) {
this.dependencies.remove(dependencies[i]);
}
this._preventDependencyRefresh = false;
this.dependencies.sync();
},
_removeTaskAssignments: function(task) {
var dataSource = this.assignments.dataSource;
var assignments = dataSource.view();
var filter = {
field: this.assignments.dataTaskIdField,
operator: "eq",
value: task.get("id")
};
assignments = new Query(assignments).filter(filter).toArray();
this._preventRefresh = true;
for (var i = 0, length = assignments.length; i < length; i++) {
dataSource.remove(assignments[i]);
}
this._preventRefresh = false;
dataSource.sync();
},
_removeTask: function(task) {
var dependencies = this.dependencies.dependencies(task.id);
if (!this.trigger("remove", {
task: task,
dependencies: dependencies
})) {
this._removeTaskDependencies(task, dependencies);
this._removeTaskAssignments(task);
this._preventRefresh = true;
if (this.dataSource.remove(task)) {
this._syncDataSource();
}
this._preventRefresh = false;
}
},
_removeDependency: function(dependency) {
if (!this.trigger("remove", {
task: null,
dependencies: [dependency]
})) {
if (this.dependencies.remove(dependency)) {
this.dependencies.sync();
}
}
},
_removeAssignment: function(assignment) {
this.assignments.dataSource.remove(assignment);
},
_taskConfirm: function(callback, task) {
var messages = this.options.messages;
this._confirm(callback, {
model: task,
text: messages.deleteTaskConfirmation,
title: messages.deleteTaskWindowTitle
});
},
_dependencyConfirm: function(callback, dependency) {
var messages = this.options.messages;
this._confirm(callback, {
model: dependency,
text: messages.deleteDependencyConfirmation,
title: messages.deleteDependencyWindowTitle
});
},
_confirm: function(callback, options) {
var editable = this.options.editable;
var messages;
var buttons;
if (editable === true || editable.confirmation !== false) {
messages = this.options.messages;
buttons = [
{ name: "delete", text: messages.destroy, className: Gantt.styles.primary, click: function() { callback(); } },
{ name: "cancel", text: messages.cancel, click: function() { callback(true); } }
];
this.showDialog(extend(true, {}, options, { buttons: buttons }));
} else {
callback();
}
},
showDialog: function(options) {
this._editor.showDialog(options);
},
refresh: function() {
if (this._preventRefresh || this.list.editable) {
return;
}
this._progress(false);
var dataSource = this.dataSource;
var taskTree = dataSource.taskTree();
var scrollToUid = this._scrollToUid;
var current;
var cachedUid;
var cachedIndex = -1;
if (this.current) {
cachedUid = this.current.closest("tr").attr(kendo.attr("uid"));
cachedIndex = this.current.index();
}
if (this.trigger("dataBinding")) {
return;
}
if (this.resources.dataSource.data().length !== 0) {
this._assignResources(taskTree);
}
if (this._editor) {
this._editor.close();
}
this.clearSelection();
this.list._render(taskTree);
this.timeline._render(taskTree);
this.timeline._renderDependencies(this.dependencies.view());
if (scrollToUid) {
this._scrollTo(scrollToUid);
this.select(selector(scrollToUid));
}
if ((scrollToUid || cachedUid) && cachedIndex >= 0) {
current = this.list.content
.find("tr" + selector((scrollToUid || cachedUid)) + " > td:eq(" + cachedIndex + ")");
this._current(current);
}
this._scrollToUid = null;
this.trigger("dataBound");
},
refreshDependencies: function() {
if (this._preventDependencyRefresh) {
return;
}
if (this.trigger("dataBinding")) {
return;
}
this.timeline._renderDependencies(this.dependencies.view());
this.trigger("dataBound");
},
_assignResources: function(taskTree) {
var resources = this.resources;
var assignments = this.assignments;
var groupAssigments = function() {
var data = assignments.dataSource.view();
var group = {
field: assignments.dataTaskIdField
};
data = new Query(data).group(group).toArray();
return data;
};
var assigments = groupAssigments();
var applyTaskResource = function(task, action) {
var taskId = task.get("id");
kendo.setter(resources.field)(task, new ObservableArray([]));
for (var i = 0, length = assigments.length; i < length; i++) {
if (assigments[i].value === taskId) {
action(task, assigments[i].items);
}
}
};
var wrapTask = function(task, items) {
for (var j = 0, length = items.length; j < length; j++) {
var item = items[j];
var resource = resources.dataSource.get(item.get(assignments.dataResourceIdField));
var resourceValue = item.get(assignments.dataValueField);
var resourcedId = item.get(assignments.dataResourceIdField);
var valueFormat = resource.get(resources.dataFormatField) || PERCENTAGE_FORMAT;
var formatedValue = kendo.toString(resourceValue, valueFormat);
task[resources.field].push(new ObservableObject({
id: resourcedId,
name: resource.get(resources.dataTextField),
color: resource.get(resources.dataColorField),
value: resourceValue,
formatedValue: formatedValue
}));
}
};
for (var i = 0, length = taskTree.length; i < length; i++) {
applyTaskResource(taskTree[i], wrapTask);
}
},
_wrapResourceData: function(id) {
var that = this;
var result = [];
var resource;
var resources = this.resources.dataSource.view();
var assignments = this.assignments.dataSource.view();
var taskAssignments = new Query(assignments).filter({
field: that.assignments.dataTaskIdField,
operator: "eq",
value: id
}).toArray();
var valuePerResource = function(id) {
var resourceValue = null;
new Query(taskAssignments).filter({
field: that.assignments.dataResourceIdField,
operator: "eq",
value: id
}).select(function(assignment) {
resourceValue += assignment.get(that.assignments.dataValueField);
});
return resourceValue;
};
for (var i = 0, length = resources.length; i < length; i++) {
resource = resources[i];
result.push({
id: resource.get("id"),
name: resource.get(that.resources.dataTextField),
format: resource.get(that.resources.dataFormatField) || PERCENTAGE_FORMAT,
value: valuePerResource(resource.id)
});
}
return result;
},
_syncDataSource: function() {
this._preventRefresh = false;
this._requestStart();
this.dataSource.sync();
},
_requestStart: function() {
this._progress(true);
},
_error: function() {
this._progress(false);
},
_progress: function(toggle) {
kendo.ui.progress(this.element, toggle);
},
_resizable: function() {
var that = this;
var wrapper = this.wrapper;
var ganttStyles = Gantt.styles;
var contentSelector = DOT + ganttStyles.gridContent;
var treeListWrapper = wrapper.find(DOT + ganttStyles.list);
var timelineWrapper = wrapper.find(DOT + ganttStyles.timeline);
var treeListWidth;
var timelineWidth;
var timelineScroll;
this._resizeDraggable = wrapper
.find(DOT + ganttStyles.splitBar)
.height(treeListWrapper.height())
.hover(function () {
$(this).addClass(ganttStyles.splitBarHover);
}, function () {
$(this).removeClass(ganttStyles.splitBarHover);
})
.end()
.kendoResizable({
orientation: "horizontal",
handle: DOT + ganttStyles.splitBar,
"start": function () {
treeListWidth = treeListWrapper.width();
timelineWidth = timelineWrapper.width();
timelineScroll = timelineWrapper.find(contentSelector).scrollLeft();
},
"resize": function(e) {
var delta = e.x.initialDelta;
if (kendo.support.isRtl(wrapper)) {
delta *= -1;
}
if (treeListWidth + delta < 0 || timelineWidth - delta < 0) {
return;
}
treeListWrapper.width(treeListWidth + delta);
timelineWrapper.width(timelineWidth - delta);
timelineWrapper.find(contentSelector).scrollLeft(timelineScroll + delta);
that.timeline.view()._renderCurrentTime();
}
}).data("kendoResizable");
},
_scrollable: function() {
var that = this;
var ganttStyles = Gantt.styles;
var contentSelector = DOT + ganttStyles.gridContent;
var headerSelector = DOT + ganttStyles.gridHeaderWrap;
var timelineHeader = this.timeline.element.find(headerSelector);
var timelineContent = this.timeline.element.find(contentSelector);
var treeListHeader = this.list.element.find(headerSelector);
var treeListContent = this.list.element.find(contentSelector);
if (mobileOS) {
treeListContent.css("overflow-y", "auto");
}
timelineContent.on("scroll", function() {
that.scrollTop = this.scrollTop;
timelineHeader.scrollLeft(this.scrollLeft);
treeListContent.scrollTop(this.scrollTop);
});
treeListContent
.on("scroll", function() {
treeListHeader.scrollLeft(this.scrollLeft);
})
.on("DOMMouseScroll" + NS + " mousewheel" + NS, function(e) {
var scrollTop = timelineContent.scrollTop();
var delta = kendo.wheelDeltaY(e);
if (delta) {
e.preventDefault();
//In Firefox DOMMouseScroll event cannot be canceled
$(e.currentTarget).one("wheel" + NS, false);
timelineContent.scrollTop(scrollTop + (-delta));
}
});
},
_navigatable: function() {
var that = this;
var navigatable = this.options.navigatable;
var editable = this.options.editable;
var headerTable = this.list.header.find("table");
var contentTable = this.list.content.find("table");
var ganttStyles = Gantt.styles;
var isRtl = kendo.support.isRtl(this.wrapper);
var timelineContent = this.timeline.element.find(DOT + ganttStyles.gridContent);
var tables = headerTable.add(contentTable);
var attr = selector();
var cellIndex;
var expandState = {
collapse: false,
expand: true
};
var scroll = function(reverse) {
var width = that.timeline.view()._timeSlots()[0].offsetWidth;
timelineContent.scrollLeft(timelineContent.scrollLeft() + (reverse ? -width : width));
};
var scrollVertical = function(reverse) {
var height = that.timeline.view()._rowHeight;
timelineContent.scrollTop(timelineContent.scrollTop() + (reverse ? -height : height));
};
var moveVertical = function(method) {
var parent = that.current.parent("tr" + selector());
var index = that.current.index();
var subling = parent[method]();
if (that.select().length !== 0) {
that.clearSelection();
}
if (subling.length !== 0) {
that._current(subling.children("td:eq(" + index + ")"));
that._scrollTo(that.current);
} else {
if (that.current.is("td") && method == "prev") {
focusTable(headerTable);
} else if (that.current.is("th") && method == "next") {
focusTable(contentTable);
}
}
};
var moveHorizontal = function(method) {
var subling = that.current[method]();
if (subling.length !== 0) {
that._current(subling);
cellIndex = that.current.index();
}
};
var toggleExpandedState = function(value) {
var model = that.dataItem(that.current);
if (model.summary && model.expanded !== value) {
model.set("expanded", value);
}
};
var deleteAction = function() {
var editable = that.options.editable;
if (!editable || editable.destroy === false || that.list.editable) {
return;
}
var selectedTask = that.select();
var uid = kendo.attr("uid");
if (selectedTask.length) {
that.removeTask(selectedTask.attr(uid));
}
};
$(this.wrapper)
.on("mousedown" + NS, "tr" + attr + ", div" + attr + ":not(" + DOT + ganttStyles.line + ")", function(e) {
var currentTarget = $(e.currentTarget);
var isInput = $(e.target).is(":button,a,:input,a>.k-icon,textarea,span.k-icon,span.k-link,.k-input,.k-multiselect-wrap");
var current;
if (e.ctrlKey) {
return;
}
if (navigatable) {
if (currentTarget.is("tr")) {
current = $(e.target).closest("td");
} else {
current = that.list
.content.find("tr" + selector(currentTarget.attr(kendo.attr("uid"))) + " > td:first");
}
that._current(current);
}
if ((navigatable || editable) && !isInput) {
that._focusTimeout = setTimeout(function() {
focusTable(that.list.content.find("table"), true);
}, 2);
}
})
.on("keydown" + NS, function (e) {
var key = e.keyCode;
var that = this;
var focusableItems = $(that._getToolbarItems());
var idx = focusableItems.index(that.toolbar.find(DOT + ganttStyles.focused)[0]);
if (idx === -1 && $(e.target).closest(DOT + ganttStyles.toolbar.views).length) {
idx = focusableItems.index(that.toolbar.find(".k-gantt-views > .k-state-selected:visible > a, .k-current-view:visible > a")[0]);
}
var itemToFocus = e.shiftKey ? focusableItems[idx - 1] : focusableItems[idx + 1];
if (key === keys.F10) {
that.toolbar.find(".k-button:visible:first").addClass(ganttStyles.focused).focus();
e.preventDefault();
} else if (key == keys.TAB && $(e.target).closest(DOT + ganttStyles.toolbar.toolbar).length) {
that.toolbar.find(DOT + ganttStyles.focused).removeClass(ganttStyles.focused).blur();
if (itemToFocus) {
$(itemToFocus).addClass(ganttStyles.focused).focus();
e.preventDefault();
return;
}
if (this.list.element.is(":visible")) {
this.list.element.find("table[role=treegrid]").focus();
} else {
this.element.find(DOT + ganttStyles.tasks)[0].focus();
}
e.preventDefault();
}
}.bind(this));
if (navigatable !== true) {
contentTable
.on("keydown" + NS, function(e) {
if (e.keyCode == keys.DELETE) {
deleteAction();
}
});
return;
}
tables
.on("focus" + NS, function() {
var selector = this === contentTable.get(0) ? "td" : "th";
var selection = that.select();
var current = that.current || $((selection.length ? selection : this))
.find(selector + ":eq(" + (cellIndex || 0) + ")");
that._current(current);
$(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
$(that.toolbar.find(DOT + ganttStyles.toolbar.currentView)).parent().removeClass(ganttStyles.toolbar.expanded);
})
.on("blur" + NS, function() {
that._current();
if (this == headerTable) {
$(this).attr(TABINDEX, -1);
}
})
.on("keydown" + NS, function(e) {
var key = e.keyCode;
var isCell;
if (!that.current) {
return;
}
isCell = that.current.is("td");
switch (key) {
case keys.RIGHT:
e.preventDefault();
if (e.altKey) {
scroll();
} else if (e.ctrlKey) {
toggleExpandedState(isRtl ? expandState.collapse : expandState.expand);
} else {
moveHorizontal(isRtl ? "prev" : "next");
}
break;
case keys.LEFT:
e.preventDefault();
if (e.altKey) {
scroll(true);
} else if (e.ctrlKey) {
toggleExpandedState(isRtl ? expandState.expand : expandState.collapse);
} else {
moveHorizontal(isRtl ? "next" : "prev");
}
break;
case keys.UP:
e.preventDefault();
if (e.altKey) {
scrollVertical(true);
} else {
moveVertical("prev");
}
break;
case keys.DOWN:
e.preventDefault();
if (e.altKey) {
scrollVertical();
} else {
moveVertical("next");
}
break;
case keys.SPACEBAR:
e.preventDefault();
if (isCell) {
that.select(that.current.closest("tr"));
}
break;
case keys.ENTER:
e.preventDefault();
if (isCell) {
if (that.options.editable && that.options.editable.update !== false) {
that._cachedCurrent = that.current;
that.list._startEditHandler(that.current);
$(this).one("keyup", function(e) {
/* Stop the event propagation so that the list widget won't close its editor immediately */
e.stopPropagation();
});
}
} else {
/* Sort */
that.current
.children("a.k-link")
.click();
}
break;
case keys.ESC:
// e.stopPropagation();
break;
case keys.DELETE:
if (isCell) {
deleteAction();
}
break;
default:
if (key >= 49 && key <= 57 && e.target.tagName.toLowerCase() !== "input") {
that.view(that.timeline._viewByIndex(key - 49));
}
break;
}
});
},
_getToolbarItems: function () {
return this.toolbar.find(".k-gantt-toggle:visible").toArray().concat(
this.toolbar.find(".k-gantt-actions > .k-button:visible").toArray(),
this.toolbar.find(".k-gantt-views > .k-state-selected:visible > a, .k-current-view:visible > a").toArray()
);
},
_current: function(element) {
var ganttStyles = Gantt.styles;
var activeElement;
if (this.current && this.current.length) {
this.current
.removeClass(ganttStyles.focused)
.removeAttr("id");
}
if (element && element.length) {
this.current = element
.addClass(ganttStyles.focused)
.attr("id", ACTIVE_CELL);
activeElement = $(kendo._activeElement());
if (activeElement.is("table") && this.wrapper.find(activeElement).length > 0) {
activeElement
.removeAttr(ARIA_DESCENDANT)
.attr(ARIA_DESCENDANT, ACTIVE_CELL);
}
} else {
this.current = null;
}
},
_dataBind: function() {
var that = this;
if (that.options.autoBind) {
this._preventRefresh = true;
this._preventDependencyRefresh = true;
var promises = $.map([
this.dataSource,
this.dependencies,
this.resources.dataSource,
this.assignments.dataSource
],
function(dataSource) {
return dataSource.fetch();
});
$.when.apply(null, promises)
.done(function() {
that._preventRefresh = false;
that._preventDependencyRefresh = false;
that.refresh();
});
}
},
_resize: function() {
this._adjustDimensions();
this.timeline.view()._adjustHeight();
this.timeline.view()._renderCurrentTime();
this.list._adjustHeight();
}
});
if (kendo.PDFMixin) {
kendo.PDFMixin.extend(Gantt.fn);
Gantt.fn._drawPDF = function() {
var ganttStyles = Gantt.styles;
var listClass = "." + ganttStyles.list;
var listWidth = this.wrapper.find(listClass).width();
var content = this.wrapper.clone();
content.find(listClass).css("width", listWidth);
return this._drawPDFShadow({
content: content
}, {
avoidLinks: this.options.pdf.avoidLinks
});
};
}
kendo.ui.plugin(Gantt);
extend(true, Gantt, { styles: ganttStyles });
})(window.kendo.jQuery);
return window.kendo;
}, __webpack_require__(3));
/***/ }),
/***/ 1190:
/***/ (function(module, exports) {
module.exports = require("./kendo.gantt.list");
/***/ }),
/***/ 1191:
/***/ (function(module, exports) {
module.exports = require("./kendo.gantt.timeline");
/***/ }),
/***/ 1192:
/***/ (function(module, exports) {
module.exports = require("./kendo.grid");
/***/ }),
/***/ 1193:
/***/ (function(module, exports) {
module.exports = require("./kendo.pdf");
/***/ })
/******/ });