@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,420 lines (1,132 loc) • 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) {#" +
"c