@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,389 lines (1,085 loc) • 103 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__(1199);
/***/ }),
/***/ 3:
/***/ (function(module, exports) {
module.exports = function() { throw new Error("define cannot be used indirect"); };
/***/ }),
/***/ 1003:
/***/ (function(module, exports) {
module.exports = require("./kendo.dom");
/***/ }),
/***/ 1061:
/***/ (function(module, exports) {
module.exports = require("./kendo.draganddrop");
/***/ }),
/***/ 1195:
/***/ (function(module, exports) {
module.exports = require("./kendo.touch");
/***/ }),
/***/ 1199:
/***/ (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__(1003), __webpack_require__(1195), __webpack_require__(1061) ], __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.timeline",
name: "Gantt Timeline",
category: "web",
description: "The Gantt Timeline",
depends: [ "dom", "touch", "draganddrop" ],
hidden: true
};
(function($) {
var Widget = kendo.ui.Widget;
var kendoDomElement = kendo.dom.element;
var kendoTextElement = kendo.dom.text;
var kendoHtmlElement = kendo.dom.html;
var isPlainObject = $.isPlainObject;
var outerWidth = kendo._outerWidth;
var outerHeight = kendo._outerHeight;
var extend = $.extend;
var proxy = $.proxy;
var browser = kendo.support.browser;
var isRtl = false;
var keys = kendo.keys;
var Query = kendo.data.Query;
var STRING = "string";
var NS = ".kendoGanttTimeline";
var CLICK = "click";
var DBLCLICK = "dblclick";
var MOUSEMOVE = "mousemove";
var MOUSEENTER = "mouseenter";
var MOUSELEAVE = "mouseleave";
var KEYDOWN = "keydown";
var DOT = ".";
var TIME_HEADER_TEMPLATE = kendo.template("#=kendo.toString(start, 't')#");
var DAY_HEADER_TEMPLATE = kendo.template("#=kendo.toString(start, 'ddd M/dd')#");
var WEEK_HEADER_TEMPLATE = kendo.template("#=kendo.toString(start, 'ddd M/dd')# - #=kendo.toString(kendo.date.addDays(end, -1), 'ddd M/dd')#");
var MONTH_HEADER_TEMPLATE = kendo.template("#=kendo.toString(start, 'MMM')#");
var YEAR_HEADER_TEMPLATE = kendo.template("#=kendo.toString(start, 'yyyy')#");
var RESIZE_HINT = kendo.template('<div class="#=styles.marquee#">' +
'<div class="#=styles.marqueeColor#"></div>' +
'</div>');
var RESIZE_TOOLTIP_TEMPLATE = kendo.template('<div style="z-index: 100002;" class="#=styles.tooltipWrapper#">' +
'<div class="#=styles.tooltipContent#">' +
'<div>#=messages.start#: #=kendo.toString(start, format)#</div>' +
'<div>#=messages.end#: #=kendo.toString(end, format)#</div>' +
'</div>' +
'</div>');
var PERCENT_RESIZE_TOOLTIP_TEMPLATE = kendo.template('<div style="z-index: 100002;" class="#=styles.tooltipWrapper#" >' +
'<div class="#=styles.tooltipContent#">#=text#%</div>' +
'<div class="#=styles.tooltipCallout#" style="left:13px;"></div>' +
'</div>');
var TASK_TOOLTIP_TEMPLATE = kendo.template('<div class="#=kendo.htmlEncode(styles.taskDetails)#">' +
'<strong>#=kendo.htmlEncode(task.title)#</strong>' +
'<div class="#=styles.taskDetailsPercent#">#=kendo.toString(task.percentComplete, "p0")#</div>' +
'<ul class="#=styles.reset#">' +
'<li>#=messages.start#: #=kendo.toString(task.start, "h:mm tt ddd, MMM d")#</li>' +
'<li>#=messages.end#: #=kendo.toString(task.end, "h:mm tt ddd, MMM d")#</li>' +
'</ul>' +
'</div>');
var SIZE_CALCULATION_TEMPLATE = "<table style='visibility: hidden;'>" +
"<tbody>" +
"<tr style='height:{0}'>" +
"<td> </td>" +
"</tr>" +
"</tbody>" +
"</table>";
var defaultViews = {
day: {
type: "kendo.ui.GanttDayView"
},
week: {
type: "kendo.ui.GanttWeekView"
},
month: {
type: "kendo.ui.GanttMonthView"
},
year: {
type: "kendo.ui.GanttYearView"
}
};
function trimOptions(options) {
delete options.name;
delete options.prefix;
delete options.views;
return options;
}
function getWorkDays(options) {
var workDays = [];
var dayIndex = options.workWeekStart;
workDays.push(dayIndex);
while (options.workWeekEnd != dayIndex) {
if (dayIndex > 6) {
dayIndex -= 7;
} else {
dayIndex++;
}
workDays.push(dayIndex);
}
return workDays;
}
function blurActiveElement() {
var activeElement = kendo._activeElement();
if (activeElement && activeElement.nodeName.toLowerCase() !== "body") {
$(activeElement).blur();
}
}
var viewStyles = {
alt: "k-alt",
reset: "k-reset",
nonWorking: "k-nonwork-hour",
header: "k-header",
gridHeader: "k-grid-header",
gridHeaderWrap: "k-grid-header-wrap",
gridContent: "k-grid-content",
tasksWrapper: "k-gantt-tables",
rowsTable: "k-gantt-rows",
columnsTable: "k-gantt-columns",
tasksTable: "k-gantt-tasks",
dependenciesWrapper: "k-gantt-dependencies",
resource: "k-resource",
resourceAlt: "k-resource k-alt",
task: "k-task",
taskSingle: "k-task-single",
taskMilestone: "k-task-milestone",
taskSummary: "k-task-summary",
taskWrap: "k-task-wrap",
taskMilestoneWrap: "k-milestone-wrap",
resourcesWrap: "k-resources-wrap",
taskDot: "k-task-dot",
taskDotStart: "k-task-start",
taskDotEnd: "k-task-end",
taskDragHandle: "k-task-draghandle",
taskContent: "k-task-content",
taskTemplate: "k-task-template",
taskActions: "k-task-actions",
taskDelete: "k-task-delete",
taskComplete: "k-task-complete",
taskDetails: "k-task-details",
taskDetailsPercent: "k-task-pct",
link: "k-link",
icon: "k-icon",
iconDelete: "k-i-close",
taskResizeHandle: "k-resize-handle",
taskResizeHandleWest: "k-resize-w",
taskResizeHandleEast: "k-resize-e",
taskSummaryProgress: "k-task-summary-progress",
taskSummaryComplete: "k-task-summary-complete",
line: "k-line",
lineHorizontal: "k-line-h",
lineVertical: "k-line-v",
arrowWest: "k-arrow-w",
arrowEast: "k-arrow-e",
dragHint: "k-drag-hint",
dependencyHint: "k-dependency-hint",
tooltipWrapper: "k-widget k-tooltip k-popup k-group k-reset",
tooltipContent: "k-tooltip-content",
tooltipCallout: "k-callout k-callout-s",
callout: "k-callout",
marquee: "k-marquee k-gantt-marquee",
marqueeColor: "k-marquee-color"
};
var GanttView = kendo.ui.GanttView = Widget.extend({
init: function(element, options) {
Widget.fn.init.call(this, element, options);
this.title = this.options.title || this.options.name;
this.header = this.element.find(DOT + GanttView.styles.gridHeader);
this.content = this.element.find(DOT + GanttView.styles.gridContent);
this.contentWidth = this.content.width();
this._workDays = getWorkDays(this.options);
this._headerTree = options.headerTree;
this._taskTree = options.taskTree;
this._taskTemplate = options.taskTemplate ?
kendo.template(options.taskTemplate, extend({}, kendo.Template, options.templateSettings)) :
null;
this._dependencyTree = options.dependencyTree;
this._taskCoordinates = {};
this._currentTime();
},
destroy: function() {
Widget.fn.destroy.call(this);
clearTimeout(this._tooltipTimeout);
this.headerRow = null;
this.header = null;
this.content = null;
this._dragHint = null;
this._resizeHint = null;
this._resizeTooltip = null;
this._taskTooltip = null;
this._percentCompleteResizeTooltip = null;
this._headerTree = null;
this._taskTree = null;
this._dependencyTree = null;
},
options: {
showWorkHours: false,
showWorkDays: false,
workDayStart: new Date(1980, 1, 1, 8, 0, 0),
workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
workWeekStart: 1,
workWeekEnd: 5,
hourSpan: 1,
slotSize: 100,
currentTimeMarker: {
updateInterval: 10000
}
},
renderLayout: function() {
this._slots = this._createSlots();
this._tableWidth = this._calculateTableWidth();
this.createLayout(this._layout());
this._slotDimensions();
this._adjustHeight();
this.content.find(DOT + GanttView.styles.dependenciesWrapper).width(this._tableWidth);
},
_adjustHeight: function() {
if(this.content){
this.content.height(this.element.height() - outerHeight(this.header));
}
},
createLayout: function(rows) {
var headers = this._headers(rows);
var colgroup = this._colgroup();
var tree = this._headerTree;
var header = kendoDomElement("thead", null, headers);
var table = kendoDomElement("table", { style: { width: this._tableWidth + "px"} }, [colgroup, header]);
tree.render([table]);
this.headerRow = this.header.find("table:first tr").last();
},
_slotDimensions: function() {
var headers = this.headerRow[0].children;
var slots = this._timeSlots();
var slot;
var header;
for (var i = 0, length = headers.length; i < length; i++) {
header = headers[i];
slot = slots[i];
slot.offsetLeft = header.offsetLeft;
slot.offsetWidth = header.offsetWidth;
}
},
render: function(tasks) {
var taskCount = tasks.length;
var styles = GanttView.styles;
var contentTable;
var rowsTable = this._rowsTable(taskCount);
var columnsTable = this._columnsTable(taskCount);
var tasksTable = this._tasksTable(tasks);
var currentTimeMarker = this.options.currentTimeMarker;
var calculatedSize = this.options.calculatedSize;
var totalHeight;
this._taskTree.render([rowsTable, columnsTable, tasksTable]);
contentTable = this.content.find(DOT + styles.rowsTable);
if (calculatedSize) {
totalHeight = calculatedSize.row * tasks.length;
this.content.find(DOT + styles.tasksTable).height(totalHeight);
contentTable.height(totalHeight);
}
this._contentHeight = contentTable.height();
this._rowHeight = calculatedSize ? calculatedSize.row : this._contentHeight / contentTable.find("tr").length;
this.content.find(DOT + styles.columnsTable).height(this._contentHeight);
if (currentTimeMarker !== false && currentTimeMarker.updateInterval !== undefined) {
this._renderCurrentTime();
}
},
_rowsTable: function(rowCount) {
var rows = [];
var row;
var styles = GanttView.styles;
var attributes = [null, { className: styles.alt }];
for (var i = 0; i < rowCount; i++) {
row = kendoDomElement("tr", attributes[i % 2], [
kendoDomElement("td", null, [
kendoTextElement("\u00a0")
])
]);
rows.push(row);
}
return this._createTable(1, rows, { className: styles.rowsTable });
},
_columnsTable: function() {
var cells = [];
var row;
var styles = GanttView.styles;
var slots = this._timeSlots();
var slotsCount = slots.length;
var slot;
var slotSpan;
var totalSpan = 0;
var attributes;
for (var i = 0; i < slotsCount; i++) {
slot = slots[i];
attributes = {};
slotSpan = slot.span;
totalSpan += slotSpan;
if (slotSpan !== 1) {
attributes.colspan = slotSpan;
}
if (slot.isNonWorking) {
attributes.className = styles.nonWorking;
}
cells.push(kendoDomElement("td", attributes, [
kendoTextElement("\u00a0")
]));
}
row = kendoDomElement("tr", null, cells);
return this._createTable(totalSpan, [row], { className: styles.columnsTable});
},
_tasksTable: function(tasks) {
var rows = [];
var row;
var cell;
var position;
var task;
var styles = GanttView.styles;
var coordinates = this._taskCoordinates = {};
var size = this._calculateMilestoneWidth();
var milestoneWidth = Math.round(size.width);
var resourcesField = this.options.resourcesField;
var className = [styles.resource, styles.resourceAlt];
var calculatedSize = this.options.calculatedSize;
var resourcesPosition;
var resourcesMargin = this._calculateResourcesMargin();
var taskBorderWidth = this._calculateTaskBorderWidth();
var resourceStyle;
var addCoordinates = function(rowIndex) {
var taskLeft;
var taskRight;
taskLeft = position.left;
taskRight = taskLeft + position.width;
if (task.isMilestone()) {
taskLeft -= milestoneWidth / 2;
taskRight = taskLeft + milestoneWidth;
}
coordinates[task.id] = {
start: taskLeft,
end: taskRight,
rowIndex: rowIndex
};
};
for (var i = 0, l = tasks.length; i < l; i++) {
task = tasks[i];
position = this._taskPosition(task);
position.borderWidth = taskBorderWidth;
row = kendoDomElement("tr", null);
cell = kendoDomElement("td");
if (task.start <= this.end && task.end >= this.start) {
cell.children.push(this._renderTask(tasks[i], position));
if (task[resourcesField] && task[resourcesField].length) {
if (isRtl) {
resourcesPosition = this._tableWidth - position.left;
} else {
resourcesPosition = Math.max((position.width || size.clientWidth), 0) + position.left;
}
resourceStyle = {
width: (this._tableWidth - (resourcesPosition + resourcesMargin)) + "px"
};
resourceStyle[isRtl ? "right" : "left"] = resourcesPosition + "px";
if (calculatedSize) {
resourceStyle.height = calculatedSize.cell + "px";
}
cell.children.push(kendoDomElement("div",
{
className: styles.resourcesWrap,
style: resourceStyle
},
this._renderResources(task[resourcesField], className[i % 2]))
);
}
addCoordinates(i);
}
row.children.push(cell);
rows.push(row);
}
return this._createTable(1, rows, { className: GanttView.styles.tasksTable });
},
_createTable: function(colspan, rows, styles) {
var cols = [];
var colgroup;
var tbody;
for (var i = 0; i < colspan; i++) {
cols.push(kendoDomElement("col"));
}
colgroup = kendoDomElement("colgroup", null, cols);
tbody = kendoDomElement("tbody", null, rows);
if (!styles.style) {
styles.style = {};
}
styles.style.width = this._tableWidth + "px";
return kendoDomElement("table", styles, [colgroup, tbody]);
},
_calculateTableWidth: function() {
var slots = this._timeSlots();
var maxSpan = 0;
var totalSpan = 0;
var currentSpan;
var tableWidth;
for (var i = 0, length = slots.length; i < length; i++) {
currentSpan = slots[i].span;
totalSpan += currentSpan;
if (currentSpan > maxSpan) {
maxSpan = currentSpan;
}
}
tableWidth = Math.round((totalSpan * this.options.slotSize) / maxSpan);
return tableWidth;
},
_calculateMilestoneWidth: function() {
var size;
var className = GanttView.styles.task + " " + GanttView.styles.taskMilestone;
var milestone = $("<div class='" + className + "' style='visibility: hidden; position: absolute'>");
var boundingClientRect;
this.content.append(milestone);
boundingClientRect = milestone[0].getBoundingClientRect();
size = {
"width": boundingClientRect.right - boundingClientRect.left,
"clientWidth": milestone[0].clientWidth
};
milestone.remove();
return size;
},
_calculateResourcesMargin: function() {
var margin;
var wrapper = $("<div class='" + GanttView.styles.resourcesWrap + "' style='visibility: hidden; position: absolute'>");
this.content.append(wrapper);
margin = parseInt(wrapper.css(isRtl ? "margin-right" : "margin-left"), 10);
wrapper.remove();
return margin;
},
_calculateTaskBorderWidth: function() {
var width;
var className = GanttView.styles.task + " " + GanttView.styles.taskSingle;
var task = $("<div class='" + className + "' style='visibility: hidden; position: absolute'>");
var computedStyle;
this.content.append(task);
computedStyle = kendo.getComputedStyles(task[0], ["border-left-width"]);
width = parseFloat(computedStyle["border-left-width"], 10);
task.remove();
return width;
},
_renderTask: function(task, position) {
var taskWrapper;
var taskElement;
var editable = this.options.editable;
var progressHandleOffset;
var taskLeft = position.left;
var styles = GanttView.styles;
var wrapClassName = styles.taskWrap;
var calculatedSize = this.options.calculatedSize;
var dragHandleStyle = {};
var taskWrapAttr = {
className: wrapClassName,
style: { left: taskLeft + "px" }
};
if (calculatedSize) {
taskWrapAttr.style.height = calculatedSize.cell + "px";
}
if (task.summary) {
taskElement = this._renderSummary(task, position);
} else if (task.isMilestone()) {
taskElement = this._renderMilestone(task, position);
taskWrapAttr.className += " " + styles.taskMilestoneWrap;
} else {
taskElement = this._renderSingleTask(task, position);
}
taskWrapper = kendoDomElement("div", taskWrapAttr, [
taskElement
]);
if (editable && editable.dependencyCreate !== false) {
taskWrapper.children.push(kendoDomElement("div", { className: styles.taskDot + " " + styles.taskDotStart }));
taskWrapper.children.push(kendoDomElement("div", { className: styles.taskDot + " " + styles.taskDotEnd }));
}
if (!task.summary && !task.isMilestone() && editable && editable.dragPercentComplete !== false && editable.update !== false && this._taskTemplate === null) {
progressHandleOffset = Math.round(position.width * task.percentComplete);
dragHandleStyle[isRtl ? "right" : "left"] = progressHandleOffset + "px";
taskWrapper.children.push(kendoDomElement("div", { className: styles.taskDragHandle, style: dragHandleStyle }));
}
return taskWrapper;
},
_renderSingleTask: function(task, position) {
var styles = GanttView.styles;
var progressWidth = Math.round(position.width * task.percentComplete);
var taskChildren = [];
var taskContent;
var editable = this.options.editable;
if (this._taskTemplate !== null) {
taskContent = kendoHtmlElement(this._taskTemplate(task));
} else {
taskContent = kendoTextElement(task.title);
taskChildren.push(kendoDomElement("div", { className: styles.taskComplete, style: { width: progressWidth + "px" } }));
}
var content = kendoDomElement("div", { className: styles.taskContent }, [
kendoDomElement("div", { className: styles.taskTemplate }, [
taskContent
])
]);
taskChildren.push(content);
if (editable) {
if (editable.destroy !== false) {
content.children.push(kendoDomElement("span", { className: styles.taskActions }, [
kendoDomElement("a", { className: styles.link + " " + styles.taskDelete, href: "#", "aria-label": "Delete" }, [
kendoDomElement("span", { className: styles.icon + " " + styles.iconDelete })
])
]));
}
if (editable.resize !== false && editable.update !== false) {
content.children.push(kendoDomElement("span", { className: styles.taskResizeHandle + " " + styles.taskResizeHandleWest }));
content.children.push(kendoDomElement("span", { className: styles.taskResizeHandle + " " + styles.taskResizeHandleEast }));
}
}
var element = kendoDomElement("div", {
className: styles.task + " " + styles.taskSingle, "data-uid": task.uid, style:
{ width: Math.max((position.width - position.borderWidth * 2), 0) + "px" }
}, taskChildren);
return element;
},
_renderMilestone: function(task) {
var styles = GanttView.styles;
var element = kendoDomElement("div", { className: styles.task + " " + styles.taskMilestone, "data-uid": task.uid });
return element;
},
_renderSummary: function(task, position) {
var styles = GanttView.styles;
var progressWidth = Math.round(position.width * task.percentComplete);
var element = kendoDomElement("div", { className: styles.task + " " + styles.taskSummary, "data-uid": task.uid, style: { width: position.width + "px" } }, [
kendoDomElement("div", { className: styles.taskSummaryProgress, style: { width: progressWidth + "px" } }, [
kendoDomElement("div", { className: styles.taskSummaryComplete, style: { width: position.width + "px" } })
])
]);
return element;
},
_renderResources: function(resources, className) {
var children = [];
var resource;
for (var i = 0, length = resources.length; i < length; i++) {
resource = resources[i];
children.push(kendoDomElement("span", {
className: className,
style: {
"color": resource.get("color")
}
}, [kendoTextElement(resource.get("name"))]));
}
if (isRtl) {
children.reverse();
}
return children;
},
_taskPosition: function(task) {
var round = Math.round;
var startLeft = round(this._offset(isRtl ? task.end : task.start));
var endLeft = round(this._offset(isRtl ? task.start : task.end));
return { left: startLeft, width: endLeft - startLeft };
},
_offset: function(date) {
var slots = this._timeSlots();
var slot;
var startOffset;
var slotDuration;
var slotOffset = 0;
var startIndex;
if (!slots.length) {
return 0;
}
startIndex = this._slotIndex("start", date);
slot = slots[startIndex];
if (slot.end < date) {
slotOffset = slot.offsetWidth;
} else if (slot.start <= date) {
startOffset = date - slot.start;
slotDuration = slot.end - slot.start;
slotOffset = (startOffset / slotDuration) * slot.offsetWidth;
}
if (isRtl) {
slotOffset = (slot.offsetWidth + 1) - slotOffset; // Add one pixel for border
}
return slot.offsetLeft + slotOffset;
},
_slotIndex: function(field, value, reverse) {
var slots = this._timeSlots();
var startIdx = 0;
var endIdx = slots.length - 1;
var middle;
if (reverse) {
slots = [].slice.call(slots).reverse();
}
do {
middle = Math.ceil((endIdx + startIdx) / 2);
if (slots[middle][field] < value) {
startIdx = middle;
} else {
if (middle === endIdx) {
middle--;
}
endIdx = middle;
}
} while (startIdx !== endIdx);
if (reverse) {
startIdx = (slots.length - 1) - startIdx;
}
return startIdx;
},
_timeByPosition: function(x, snap, snapToEnd) {
var slot = this._slotByPosition(x);
if (snap) {
return snapToEnd ? slot.end : slot.start;
}
var offsetLeft = x - $(DOT + GanttView.styles.tasksTable).offset().left;
var duration = slot.end - slot.start;
var slotOffset = offsetLeft - slot.offsetLeft;
if (isRtl) {
slotOffset = slot.offsetWidth - slotOffset;
}
return new Date(slot.start.getTime() + (duration * (slotOffset / slot.offsetWidth)));
},
_slotByPosition: function(x) {
var offsetLeft = x - $(DOT + GanttView.styles.tasksTable).offset().left;
var slotIndex = this._slotIndex("offsetLeft", offsetLeft, isRtl);
return this._timeSlots()[slotIndex];
},
_renderDependencies: function(dependencies) {
var elements = [];
var tree = this._dependencyTree;
for (var i = 0, l = dependencies.length; i < l; i++) {
elements.push.apply(elements, this._renderDependency(dependencies[i]));
}
tree.render(elements);
},
_renderDependency: function(dependency) {
var predecessor = this._taskCoordinates[dependency.predecessorId];
var successor = this._taskCoordinates[dependency.successorId];
var elements;
var method;
if (!predecessor || !successor) {
return [];
}
method = "_render" + ["FF", "FS", "SF", "SS"][isRtl ? 3 - dependency.type : dependency.type];
elements = this[method](predecessor, successor);
for (var i = 0, length = elements.length; i < length; i++) {
elements[i].attr["data-uid"] = dependency.uid;
}
return elements;
},
_renderFF: function(from, to) {
var lines = this._dependencyFF(from, to, false);
lines[lines.length - 1].children[0] = this._arrow(true);
return lines;
},
_renderSS: function(from, to) {
var lines = this._dependencyFF(to, from, true);
lines[0].children[0] = this._arrow(false);
return lines.reverse();
},
_renderFS: function(from, to) {
var lines = this._dependencyFS(from, to, false);
lines[lines.length - 1].children[0] = this._arrow(false);
return lines;
},
_renderSF: function(from, to) {
var lines = this._dependencyFS(to, from, true);
lines[0].children[0] = this._arrow(true);
return lines.reverse();
},
_dependencyFF: function(from, to, reverse) {
var that = this;
var lines = [];
var left = 0;
var top = 0;
var width = 0;
var height = 0;
var dir = reverse ? "start" : "end";
var delta;
var overlap = 2;
var arrowOverlap = 1;
var rowHeight = this._rowHeight;
var minLineWidth = 10;
var fromTop = from.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
var toTop = to.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
var styles = GanttView.styles;
var addHorizontal = function() {
lines.push(that._line(styles.line + " " + styles.lineHorizontal, { left: left + "px", top: top + "px", width: width + "px" }));
};
var addVertical = function() {
lines.push(that._line(styles.line + " " + styles.lineVertical, { left: left + "px", top: top + "px", height: height + "px" }));
};
left = from[dir];
top = fromTop;
width = minLineWidth;
delta = to[dir] - from[dir];
if ((delta) > 0 !== reverse) {
width = Math.abs(delta) + minLineWidth;
}
if (reverse) {
left -= width;
width -= arrowOverlap;
addHorizontal();
} else {
addHorizontal();
left += width - overlap;
}
if (toTop < top) {
height = top - toTop;
height += overlap;
top = toTop;
addVertical();
} else {
height = toTop - top;
height += overlap;
addVertical();
top += (height - overlap);
}
width = Math.abs(left - to[dir]);
if (!reverse) {
width -= arrowOverlap;
left -= width;
}
addHorizontal();
return lines;
},
_dependencyFS: function(from, to, reverse) {
var that = this;
var lines = [];
var left = 0;
var top = 0;
var width = 0;
var height = 0;
var rowHeight = this._rowHeight;
var minLineHeight = Math.floor(rowHeight / 2);
var minLineWidth = 10;
var minDistance = 2 * minLineWidth;
var delta = to.start - from.end;
var overlap = 2;
var arrowOverlap = 1;
var fromTop = from.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
var toTop = to.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
var styles = GanttView.styles;
var addHorizontal = function() {
lines.push(that._line(styles.line + " " + styles.lineHorizontal, { left: left + "px", top: top + "px", width: width + "px" }));
};
var addVertical = function() {
lines.push(that._line(styles.line + " " + styles.lineVertical, { left: left + "px", top: top + "px", height: height + "px" }));
};
left = from.end;
top = fromTop;
width = minLineWidth;
if (reverse) {
left += arrowOverlap;
if (delta > minDistance) {
width = delta - (minLineWidth - overlap);
}
width -= arrowOverlap;
}
addHorizontal();
left += width - overlap;
if ((delta) <= minDistance) {
height = reverse ? Math.abs(toTop - fromTop) - minLineHeight : minLineHeight;
if (toTop < fromTop) {
top -= height;
height += overlap;
addVertical();
} else {
addVertical();
top += height;
}
width = (from.end - to.start) + minDistance;
if (width < minLineWidth) {
width = minLineWidth;
}
left -= width - overlap;
addHorizontal();
}
if (toTop < fromTop) {
height = top - toTop;
top = toTop;
height += overlap;
addVertical();
} else {
height = toTop - top;
addVertical();
top += height;
}
width = to.start - left;
if (!reverse) {
width -= arrowOverlap;
}
addHorizontal();
return lines;
},
_line: function(className, styles) {
return kendoDomElement("div", { className: className, style: styles });
},
_arrow: function(direction) {
return kendoDomElement("span", { className: direction ? GanttView.styles.arrowWest : GanttView.styles.arrowEast });
},
_colgroup: function() {
var slots = this._timeSlots();
var count = slots.length;
var cols = [];
for (var i = 0; i < count; i++) {
for (var j = 0, length = slots[i].span; j < length; j++) {
cols.push(kendoDomElement("col"));
}
}
return kendoDomElement("colgroup", null, cols);
},
_createDragHint: function(element) {
this._dragHint = element
.clone()
.addClass(GanttView.styles.dragHint)
.css("cursor", "move");
element
.parent()
.append(this._dragHint);
},
_updateDragHint: function(start) {
var left = this._offset(start);
this._dragHint
.css({
"left": left
});
},
_removeDragHint: function() {
this._dragHint.remove();
this._dragHint = null;
},
_createResizeHint: function(task) {
var styles = GanttView.styles;
var taskTop = this._taskCoordinates[task.id].rowIndex * this._rowHeight;
var tooltipHeight;
var tooltipTop;
var options = this.options;
var messages = options.messages;
this._resizeHint = $(RESIZE_HINT({ styles: styles })).css({
"top": 0,
"height": this._contentHeight
});
this.content.append(this._resizeHint);
this._resizeTooltip = $(RESIZE_TOOLTIP_TEMPLATE({
styles: styles,
start: task.start,
end: task.end,
messages: messages.views,
format: options.resizeTooltipFormat
}))
.css({
"top": 0,
"left": 0
});
this.content.append(this._resizeTooltip);
this._resizeTooltipWidth = outerWidth(this._resizeTooltip);
tooltipHeight = outerHeight(this._resizeTooltip);
tooltipTop = taskTop - tooltipHeight;
if (tooltipTop < 0) {
tooltipTop = taskTop + this._rowHeight;
}
this._resizeTooltipTop = tooltipTop;
},
_updateResizeHint: function(start, end, resizeStart) {
var left = this._offset(isRtl ? end : start);
var right = this._offset(isRtl ? start : end);
var width = right - left;
var tooltipLeft = (resizeStart !== isRtl) ? left : right;
var tablesWidth = this._tableWidth - kendo.support.scrollbar();
var tooltipWidth = this._resizeTooltipWidth;
var options = this.options;
var messages = options.messages;
var tableOffset = $(DOT + GanttView.styles.tasksTable).offset().left - $(DOT + GanttView.styles.tasksWrapper).offset().left;
if (isRtl) {
left += tableOffset;
}
this._resizeHint
.css({
"left": left,
"width": width
});
if (this._resizeTooltip) {
this._resizeTooltip.remove();
}
tooltipLeft -= Math.round(tooltipWidth / 2);
if (tooltipLeft < 0) {
tooltipLeft = 0;
} else if (tooltipLeft + tooltipWidth > tablesWidth) {
tooltipLeft = tablesWidth - tooltipWidth;
}
if (isRtl) {
tooltipLeft += tableOffset;
}
this._resizeTooltip = $(RESIZE_TOOLTIP_TEMPLATE({
styles: GanttView.styles,
start: start,
end: end,
messages: messages.views,
format: options.resizeTooltipFormat
}))
.css({
"top": this._resizeTooltipTop,
"left": tooltipLeft,
"min-width": tooltipWidth
})
.appendTo(this.content);
},
_removeResizeHint: function() {
this._resizeHint.remove();
this._resizeHint = null;
this._resizeTooltip.remove();
this._resizeTooltip = null;
},
_updatePercentCompleteTooltip: function(top, left, text) {
this._removePercentCompleteTooltip();
var tooltip = this._percentCompleteResizeTooltip = $(PERCENT_RESIZE_TOOLTIP_TEMPLATE({ styles: GanttView.styles, text: text }))
.appendTo(this.element);
var tooltipMiddle = Math.round(outerWidth(tooltip) / 2);
var arrow = tooltip.find(DOT + GanttView.styles.callout);
var arrowHeight = Math.round(outerWidth(arrow) / 2);
tooltip.css({
"top": top - (outerHeight(tooltip) + arrowHeight),
"left": left - tooltipMiddle
});
arrow.css("left", tooltipMiddle - arrowHeight);
},
_removePercentCompleteTooltip: function() {
if (this._percentCompleteResizeTooltip) {
this._percentCompleteResizeTooltip.remove();
}
this._percentCompleteResizeTooltip = null;
},
_updateDependencyDragHint: function(from, to, useVML) {
this._removeDependencyDragHint();
if (useVML) {
this._creteVmlDependencyDragHint(from, to);
} else {
this._creteDependencyDragHint(from, to);
}
},
_creteDependencyDragHint: function(from, to) {
var styles = GanttView.styles;
var deltaX = to.x - from.x;
var deltaY = to.y - from.y;
var width = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var angle = Math.atan(deltaY / deltaX);
if (deltaX < 0) {
angle += Math.PI;
}
$("<div class='" + styles.line + " " + styles.lineHorizontal + " " + styles.dependencyHint + "'></div>")
.css({
"top": from.y,
"left": from.x,
"width": width,
"transform-origin": "0% 0",
"-ms-transform-origin": "0% 0",
"-webkit-transform-origin": "0% 0",
"transform": "rotate(" + angle + "rad)",
"-ms-transform": "rotate(" + angle + "rad)",
"-webkit-transform": "rotate(" + angle + "rad)"
})
.appendTo(this.content);
},
_creteVmlDependencyDragHint: function(from, to) {
var hint = $("<kvml:line class='" + GanttView.styles.dependencyHint + "' style='position:absolute; top: 0px; left: 0px;' strokecolor='black' strokeweight='2px' from='" +
from.x + "px," + from.y + "px' to='" + to.x + "px," + to.y + "px'" + "></kvml:line>")
.appendTo(this.content);
// IE8 Bug
hint[0].outerHTML = hint[0].outerHTML;
},
_removeDependencyDragHint: function() {
this.content.find(DOT + GanttView.styles.dependencyHint).remove();
},
_createTaskTooltip: function(task, element, mouseLeft) {
var styles = GanttView.styles;
var options = this.options;
var content = this.content;
var contentOffset = content.offset();
var contentWidth = content.width();
var contentScrollLeft = kendo.scrollLeft(content);
var row = $(element).parents("tr").first();
var rowOffset = row.offset();
var template = (options.tooltip && options.tooltip.template) ? kendo.template(options.tooltip.template) : TASK_TOOLTIP_TEMPLATE;
var left = isRtl ? mouseLeft - (contentOffset.left + contentScrollLeft + kendo.support.scrollbar())
: mouseLeft - (contentOffset.left - contentScrollLeft);
var top = (rowOffset.top + outerHeight(row) - contentOffset.top) + content.scrollTop();
var tooltip = this._taskTooltip = $('<div style="z-index: 100002;" class="' +styles.tooltipWrapper + '" >' +
'<div class="' + styles.taskContent + '"></div></div>');
var tooltipWidth;
tooltip
.css({
"left": left,
"top": top
})
.appendTo(content)
.find(DOT + styles.taskContent)
.append(template({
styles: styles,
task: task,
messages: options.messages.views
}));
if (outerHeight(tooltip) < rowOffset.top - contentOffset.top) {
tooltip.css("top", ((rowOffset.top - contentOffset.top) - outerHeight(tooltip)) + content.scrollTop());
}
tooltipWidth = outerWidth(tooltip);
if ((tooltipWidth + left) - contentScrollLeft > contentWidth) {
left -= tooltipWidth;
if (left < contentScrollLeft) {
left = (contentScrollLeft + contentWidth) - (tooltipWidth + 17);
}
tooltip.css("left", left);
}
},
_removeTaskTooltip: function() {
if (this._taskTooltip) {
this._taskTooltip.remove();
}
this._taskTooltip = null;
},
_scrollTo: function(element) {
var elementLeft = element.offset().left;
var elementWidth = element.width();
var elementRight = elementLeft + elementWidth;
var row = element.closest("tr");
var rowTop = row.offset().top;
var rowHeight = row.height();
var rowBottom = rowTop + rowHeight;
var content = this.content;
var contentOffset = content.offset();
var contentTop = contentOffset.top;
var contentHeight = content.height();
var contentBottom = contentTop + contentHeight;
var contentLeft = contentOffset.left;
var contentWidth = content.width();
var contentRight = contentLeft + contentWidth;
var scrollbarWidth = kend