You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
778 lines
27 KiB
778 lines
27 KiB
/* |
|
Copyright (c) 2012-2018 Open Lab |
|
Written by Roberto Bicchierai and Silvia Chelazzi http://roberto.open-lab.com |
|
Permission is hereby granted, free of charge, to any person obtaining |
|
a copy of this software and associated documentation files (the |
|
"Software"), to deal in the Software without restriction, including |
|
without limitation the rights to use, copy, modify, merge, publish, |
|
distribute, sublicense, and/or sell copies of the Software, and to |
|
permit persons to whom the Software is furnished to do so, subject to |
|
the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be |
|
included in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
*/ |
|
function GridEditor(master) { |
|
this.master = master; // is the a GantEditor instance |
|
|
|
var editorTabel = $.JST.createFromTemplate({}, "TASKSEDITHEAD"); |
|
if (!master.permissions.canSeeDep) |
|
editorTabel.find(".requireCanSeeDep").hide(); |
|
|
|
this.gridified = $.gridify(editorTabel); |
|
this.element = this.gridified.find(".gdfTable").eq(1); |
|
|
|
this.minAllowedDate=new Date(new Date().getTime()-3600000*24*365*20).format(); |
|
this.maxAllowedDate=new Date(new Date().getTime()+3600000*24*365*30).format(); |
|
} |
|
|
|
|
|
GridEditor.prototype.fillEmptyLines = function () { |
|
//console.debug("fillEmptyLines") |
|
var factory = new TaskFactory(); |
|
var master = this.master; |
|
|
|
//console.debug("GridEditor.fillEmptyLines"); |
|
var rowsToAdd = master.minRowsInEditor - this.element.find(".taskEditRow").length; |
|
var empty=this.element.find(".emptyRow").length; |
|
rowsToAdd=Math.max(rowsToAdd,empty>5?0:5-empty); |
|
|
|
//fill with empty lines |
|
for (var i = 0; i < rowsToAdd; i++) { |
|
var emptyRow = $.JST.createFromTemplate({}, "TASKEMPTYROW"); |
|
if (!master.permissions.canSeeDep) |
|
emptyRow.find(".requireCanSeeDep").hide(); |
|
|
|
//click on empty row create a task and fill above |
|
emptyRow.click(function (ev) { |
|
//console.debug("emptyRow.click") |
|
var emptyRow = $(this); |
|
//add on the first empty row only |
|
if (!master.permissions.canAdd || emptyRow.prevAll(".emptyRow").length > 0) |
|
return; |
|
|
|
master.beginTransaction(); |
|
var lastTask; |
|
var start = new Date().getTime(); |
|
var level = 0; |
|
if (master.tasks[0]) { |
|
start = master.tasks[0].start; |
|
level = master.tasks[0].level + 1; |
|
} |
|
|
|
//fill all empty previouses |
|
var cnt=0; |
|
emptyRow.prevAll(".emptyRow").addBack().each(function () { |
|
cnt++; |
|
var ch = factory.build("tmp_fk" + new Date().getTime()+"_"+cnt, "", "", level, start, Date.workingPeriodResolution); |
|
var task = master.addTask(ch); |
|
lastTask = ch; |
|
}); |
|
master.endTransaction(); |
|
if (lastTask.rowElement) { |
|
lastTask.rowElement.find("[name=name]").focus();//focus to "name" input |
|
} |
|
}); |
|
this.element.append(emptyRow); |
|
} |
|
}; |
|
|
|
|
|
GridEditor.prototype.addTask = function (task, row, hideIfParentCollapsed) { |
|
// console.debug("GridEditor.addTask",task,row); |
|
// console.log('addtask row', task); |
|
//var prof = new Profiler("ganttGridEditor.addTask"); |
|
|
|
//remove extisting row |
|
this.element.find("#tid_" + task.id).remove(); |
|
|
|
var taskRow = $.JST.createFromTemplate(task, "TASKROW"); |
|
|
|
if (!this.master.permissions.canSeeDep) |
|
taskRow.find(".requireCanSeeDep").hide(); |
|
|
|
if (!this.master.permissions.canSeePopEdit) |
|
taskRow.find(".edit .teamworkIcon").hide(); |
|
|
|
// if (task.level === 0) { |
|
// taskRow.find(".edit").append('<span class="teamworkIcon" style="font-size:12px;" title="Show Network Diagram" onclick="showNetworkDiagram('+task.id+')" >|</span>'); |
|
// } |
|
// else if(task.level > 0) { |
|
// taskRow.find(".edit").append(`<span>${' '}</span>`); |
|
// } |
|
|
|
//save row element on task |
|
task.rowElement = taskRow; |
|
|
|
this.bindRowEvents(task, taskRow); |
|
|
|
if (typeof(row) != "number") { |
|
var emptyRow = this.element.find(".emptyRow:first"); //tries to fill an empty row |
|
if (emptyRow.length > 0) |
|
emptyRow.replaceWith(taskRow); |
|
else |
|
this.element.append(taskRow); |
|
} else { |
|
var tr = this.element.find("tr.taskEditRow").eq(row); |
|
if (tr.length > 0) { |
|
tr.before(taskRow); |
|
} else { |
|
this.element.append(taskRow); |
|
} |
|
|
|
} |
|
|
|
//[expand] |
|
if (hideIfParentCollapsed) { |
|
if (task.collapsed) taskRow.addClass('collapsed'); |
|
var collapsedDescendant = this.master.getCollapsedDescendant(); |
|
if (collapsedDescendant.indexOf(task) >= 0) taskRow.hide(); |
|
} |
|
//prof.stop(); |
|
return taskRow; |
|
}; |
|
|
|
GridEditor.prototype.refreshExpandStatus = function (task) { |
|
//console.debug("refreshExpandStatus",task); |
|
if (!task) return; |
|
if (task.isParent()) { |
|
task.rowElement.addClass("isParent"); |
|
} else { |
|
task.rowElement.removeClass("isParent"); |
|
} |
|
|
|
|
|
var par = task.getParent(); |
|
if (par && !par.rowElement.is("isParent")) { |
|
par.rowElement.addClass("isParent"); |
|
} |
|
|
|
}; |
|
|
|
GridEditor.prototype.refreshTaskRow = function (task) { |
|
//console.debug("refreshTaskRow") |
|
//var profiler = new Profiler("editorRefreshTaskRow"); |
|
|
|
var canWrite=this.master.permissions.canWrite || task.canWrite; |
|
|
|
var row = task.rowElement; |
|
|
|
row.find(".taskRowIndex").html(task.getRow() + 1); |
|
row.find(".indentCell").css("padding-left", task.level * 10 + 18); |
|
row.find("[name=name]").val(task.name); |
|
row.find("[name=code]").val(task.code); |
|
row.find("[status]").attr("status", task.status); |
|
|
|
row.find("[name=duration]").val(durationToString(task.duration)).prop("readonly",!canWrite || task.isParent() && task.master.shrinkParent); |
|
row.find("[name=progress]").val(task.progress).prop("readonly",!canWrite || task.progressByWorklog==true); |
|
row.find("[name=startIsMilestone]").prop("checked", task.startIsMilestone); |
|
row.find("[name=start]").val(new Date(task.start).format()).updateOldValue().prop("readonly",!canWrite || task.depends || !(task.canWrite || this.master.permissions.canWrite) ); // called on dates only because for other field is called on focus event |
|
row.find("[name=endIsMilestone]").prop("checked", task.endIsMilestone); |
|
row.find("[name=end]").val(new Date(task.end).format()).prop("readonly",!canWrite || task.isParent() && task.master.shrinkParent).updateOldValue(); |
|
row.find("[name=depends]").val(task.depends); |
|
row.find(".taskAssigs").html(task.getAssigsString()); |
|
row.find(".materialAssigs").html(task.getMaterialString()); |
|
row.find(".toolsAssigs").html(task.getToolsString()); |
|
|
|
//manage collapsed |
|
if (task.collapsed) |
|
row.addClass("collapsed"); |
|
else |
|
row.removeClass("collapsed"); |
|
|
|
|
|
//Enhancing the function to perform own operations |
|
this.master.element.trigger('gantt.task.afterupdate.event', task); |
|
//profiler.stop(); |
|
}; |
|
|
|
GridEditor.prototype.redraw = function () { |
|
//console.debug("GridEditor.prototype.redraw") |
|
//var prof = new Profiler("gantt.GridEditor.redraw"); |
|
for (var i = 0; i < this.master.tasks.length; i++) { |
|
this.refreshTaskRow(this.master.tasks[i]); |
|
} |
|
// check if new empty rows are needed |
|
if (this.master.fillWithEmptyLines) |
|
this.fillEmptyLines(); |
|
|
|
//prof.stop() |
|
|
|
}; |
|
|
|
GridEditor.prototype.reset = function () { |
|
this.element.find("[taskid]").remove(); |
|
}; |
|
|
|
|
|
GridEditor.prototype.bindRowEvents = function (task, taskRow) { |
|
var self = this; |
|
//console.debug("bindRowEvents",this,this.master,this.master.permissions.canWrite, task.canWrite); |
|
|
|
//bind row selection |
|
taskRow.click(function (event) { |
|
var row = $(this); |
|
//console.debug("taskRow.click",row.attr("taskid"),event.target) |
|
//var isSel = row.hasClass("rowSelected"); |
|
row.closest("table").find(".rowSelected").removeClass("rowSelected"); |
|
row.addClass("rowSelected"); |
|
|
|
//set current task |
|
self.master.currentTask = self.master.getTask(row.attr("taskId")); |
|
|
|
//move highlighter |
|
self.master.gantt.synchHighlight(); |
|
|
|
//if offscreen scroll to element |
|
var top = row.position().top; |
|
if (top > self.element.parent().height()) { |
|
row.offsetParent().scrollTop(top - self.element.parent().height() + 100); |
|
} else if (top <= 40) { |
|
row.offsetParent().scrollTop(row.offsetParent().scrollTop() - 40 + top); |
|
} |
|
}); |
|
|
|
|
|
if (this.master.permissions.canWrite || task.canWrite) { |
|
self.bindRowInputEvents(task, taskRow); |
|
|
|
} else { //cannot write: disable input |
|
taskRow.find("input").prop("readonly", true); |
|
taskRow.find("input:checkbox,select").prop("disabled", true); |
|
} |
|
|
|
if (!this.master.permissions.canSeeDep) |
|
taskRow.find("[name=depends]").attr("readonly", true); |
|
|
|
self.bindRowExpandEvents(task, taskRow); |
|
|
|
if (this.master.permissions.canSeePopEdit) { |
|
taskRow.find(".edit-icon").click(function () {self.openFullEditor(task, false, false, false)}); |
|
|
|
taskRow.dblclick(function (ev) { //open editor only if no text has been selected |
|
if (window.getSelection().toString().trim()=="") |
|
self.openFullEditor(task, $(ev.target).closest(".taskAssigs").size()>0, $(ev.target).closest(".materialAssigs").size()>0, $(ev.target).closest(".toolsAssigs").size()>0) |
|
}); |
|
} |
|
//prof.stop(); |
|
}; |
|
|
|
|
|
GridEditor.prototype.bindRowExpandEvents = function (task, taskRow) { |
|
var self = this; |
|
//expand collapse |
|
taskRow.find(".exp-controller").click(function () { |
|
var el = $(this); |
|
var taskId = el.closest("[taskid]").attr("taskid"); |
|
var task = self.master.getTask(taskId); |
|
if (task.collapsed) { |
|
self.master.expand(task,false); |
|
} else { |
|
self.master.collapse(task,false); |
|
} |
|
}); |
|
}; |
|
|
|
GridEditor.prototype.bindRowInputEvents = function (task, taskRow) { |
|
var self = this; |
|
|
|
//bind dateField on dates |
|
taskRow.find(".date").each(function () { |
|
var el = $(this); |
|
el.click(function () { |
|
var inp = $(this); |
|
inp.dateField({ |
|
inputField: el, |
|
minDate:self.minAllowedDate, |
|
maxDate:self.maxAllowedDate, |
|
callback: function (d) { |
|
$(this).blur(); |
|
} |
|
}); |
|
}); |
|
|
|
el.blur(function (date) { |
|
var inp = $(this); |
|
if (inp.isValueChanged()) { |
|
if (!Date.isValid(inp.val())) { |
|
alert(GanttMaster.messages["INVALID_DATE_FORMAT"]); |
|
inp.val(inp.getOldValue()); |
|
|
|
} else { |
|
var row = inp.closest("tr"); |
|
var taskId = row.attr("taskId"); |
|
var task = self.master.getTask(taskId); |
|
|
|
var leavingField = inp.prop("name"); |
|
var dates = resynchDates(inp, row.find("[name=start]"), row.find("[name=startIsMilestone]"), row.find("[name=duration]"), row.find("[name=end]"), row.find("[name=endIsMilestone]")); |
|
//console.debug("resynchDates",new Date(dates.start), new Date(dates.end),dates.duration) |
|
//update task from editor |
|
self.master.beginTransaction(); |
|
self.master.changeTaskDates(task, dates.start, dates.end); |
|
self.master.endTransaction(); |
|
inp.updateOldValue(); //in order to avoid multiple call if nothing changed |
|
} |
|
} |
|
}); |
|
}); |
|
|
|
|
|
//milestones checkbox |
|
taskRow.find(":checkbox").click(function () { |
|
var el = $(this); |
|
var row = el.closest("tr"); |
|
var taskId = row.attr("taskId"); |
|
|
|
var task = self.master.getTask(taskId); |
|
|
|
//update task from editor |
|
var field = el.prop("name"); |
|
|
|
if (field == "startIsMilestone" || field == "endIsMilestone") { |
|
self.master.beginTransaction(); |
|
//milestones |
|
task[field] = el.prop("checked"); |
|
resynchDates(el, row.find("[name=start]"), row.find("[name=startIsMilestone]"), row.find("[name=duration]"), row.find("[name=end]"), row.find("[name=endIsMilestone]")); |
|
self.master.endTransaction(); |
|
} |
|
|
|
}); |
|
|
|
|
|
//binding on blur for task update (date exluded as click on calendar blur and then focus, so will always return false, its called refreshing the task row) |
|
taskRow.find("input:text:not(.date)").focus(function () { |
|
$(this).updateOldValue(); |
|
|
|
}).blur(function (event) { |
|
var el = $(this); |
|
var row = el.closest("tr"); |
|
var taskId = row.attr("taskId"); |
|
var task = self.master.getTask(taskId); |
|
//update task from editor |
|
var field = el.prop("name"); |
|
|
|
if (el.isValueChanged()) { |
|
self.master.beginTransaction(); |
|
|
|
if (field == "depends") { |
|
var oldDeps = task.depends; |
|
task.depends = el.val(); |
|
|
|
// update links |
|
var linkOK = self.master.updateLinks(task); |
|
if (linkOK) { |
|
//synchronize status from superiors states |
|
var sups = task.getSuperiors(); |
|
|
|
var oneFailed=false; |
|
var oneUndefined=false; |
|
var oneActive=false; |
|
var oneSuspended=false; |
|
var oneWaiting=false; |
|
for (var i = 0; i < sups.length; i++) { |
|
oneFailed=oneFailed|| sups[i].from.status=="STATUS_FAILED"; |
|
oneUndefined=oneUndefined|| sups[i].from.status=="STATUS_UNDEFINED"; |
|
oneActive=oneActive|| sups[i].from.status=="STATUS_ACTIVE"; |
|
oneSuspended=oneSuspended|| sups[i].from.status=="STATUS_SUSPENDED"; |
|
oneWaiting=oneWaiting|| sups[i].from.status=="STATUS_WAITING"; |
|
} |
|
|
|
if (oneFailed){ |
|
task.changeStatus("STATUS_FAILED") |
|
} else if (oneUndefined){ |
|
task.changeStatus("STATUS_UNDEFINED") |
|
} else if (oneActive){ |
|
//task.changeStatus("STATUS_SUSPENDED") |
|
task.changeStatus("STATUS_WAITING") |
|
} else if (oneSuspended){ |
|
task.changeStatus("STATUS_SUSPENDED") |
|
} else if (oneWaiting){ |
|
task.changeStatus("STATUS_WAITING") |
|
} else { |
|
task.changeStatus("STATUS_ACTIVE") |
|
} |
|
|
|
self.master.changeTaskDeps(task); //dates recomputation from dependencies |
|
} |
|
|
|
} else if (field == "duration") { |
|
var dates = resynchDates(el, row.find("[name=start]"), row.find("[name=startIsMilestone]"), row.find("[name=duration]"), row.find("[name=end]"), row.find("[name=endIsMilestone]")); |
|
self.master.changeTaskDates(task, dates.start, dates.end); |
|
|
|
} else if (field == "name" && el.val() == "") { // remove unfilled task |
|
self.master.deleteCurrentTask(taskId); |
|
|
|
|
|
} else if (field == "progress" ) { |
|
task[field]=parseFloat(el.val())||0; |
|
el.val(task[field]); |
|
|
|
} else { |
|
task[field] = el.val(); |
|
} |
|
self.master.endTransaction(); |
|
|
|
} else if (field == "name" && el.val() == "") { // remove unfilled task even if not changed |
|
if (task.getRow()!=0) { |
|
self.master.deleteCurrentTask(taskId); |
|
|
|
}else { |
|
el.oneTime(1,"foc",function(){$(this).focus()}); // |
|
event.preventDefault(); |
|
//return false; |
|
} |
|
|
|
} |
|
}); |
|
|
|
//cursor key movement |
|
taskRow.find("input").keydown(function (event) { |
|
var theCell = $(this); |
|
var theTd = theCell.parent(); |
|
var theRow = theTd.parent(); |
|
var col = theTd.prevAll("td").length; |
|
|
|
var ret = true; |
|
if (!event.ctrlKey) { |
|
switch (event.keyCode) { |
|
case 13: |
|
if (theCell.is(":text")) |
|
theCell.blur(); |
|
break; |
|
|
|
case 37: //left arrow |
|
if (!theCell.is(":text") || (!this.selectionEnd || this.selectionEnd == 0)) |
|
theTd.prev().find("input").focus(); |
|
break; |
|
case 39: //right arrow |
|
if (!theCell.is(":text") || (!this.selectionEnd || this.selectionEnd == this.value.length)) |
|
theTd.next().find("input").focus(); |
|
break; |
|
|
|
case 38: //up arrow |
|
//var prevRow = theRow.prev(); |
|
var prevRow = theRow.prevAll(":visible:first"); |
|
var td = prevRow.find("td").eq(col); |
|
var inp = td.find("input"); |
|
|
|
if (inp.length > 0) |
|
inp.focus(); |
|
break; |
|
case 40: //down arrow |
|
//var nextRow = theRow.next(); |
|
var nextRow = theRow.nextAll(":visible:first"); |
|
var td = nextRow.find("td").eq(col); |
|
var inp = td.find("input"); |
|
if (inp.length > 0) |
|
inp.focus(); |
|
else |
|
nextRow.click(); //create a new row |
|
break; |
|
case 36: //home |
|
break; |
|
case 35: //end |
|
break; |
|
|
|
case 9: //tab |
|
case 13: //enter |
|
break; |
|
} |
|
} |
|
return ret; |
|
|
|
}).focus(function () { |
|
$(this).closest("tr").click(); |
|
}); |
|
|
|
|
|
//change status |
|
taskRow.find(".taskStatus").click(function () { |
|
var el = $(this); |
|
var tr = el.closest("[taskid]"); |
|
var taskId = tr.attr("taskid"); |
|
var task = self.master.getTask(taskId); |
|
|
|
var changer = $.JST.createFromTemplate({}, "CHANGE_STATUS"); |
|
changer.find("[status=" + task.status + "]").addClass("selected"); |
|
changer.find(".taskStatus").click(function (e) { |
|
e.stopPropagation(); |
|
var newStatus = $(this).attr("status"); |
|
changer.remove(); |
|
self.master.beginTransaction(); |
|
task.changeStatus(newStatus); |
|
self.master.endTransaction(); |
|
el.attr("status", task.status); |
|
}); |
|
el.oneTime(3000, "hideChanger", function () { |
|
changer.remove(); |
|
}); |
|
el.after(changer); |
|
}); |
|
|
|
}; |
|
|
|
GridEditor.prototype.openFullEditor = function (task, editOnlyAssig, editOnlyMaterial, editOnlyTools) { |
|
var self = this; |
|
|
|
if (!self.master.permissions.canSeePopEdit) |
|
return; |
|
|
|
var taskRow=task.rowElement; |
|
|
|
//task editor in popup |
|
var taskId = taskRow.attr("taskId"); |
|
|
|
//make task editor |
|
var taskEditor = $.JST.createFromTemplate(task, "TASK_EDITOR"); |
|
|
|
//hide task data if editing assig only |
|
if (editOnlyAssig) { |
|
taskEditor.find(".taskData").hide(); |
|
taskEditor.find(".materialData").hide(); |
|
taskEditor.find(".toolsData").hide(); |
|
taskEditor.find(".geofenceData").hide(); |
|
taskEditor.find("#mapgantt").hide(); |
|
taskEditor.find(".assigsTableWrapper").height(455); |
|
taskEditor.prepend("<h1>\""+task.name+"\"</h1>"); |
|
} |
|
|
|
if (editOnlyMaterial) { |
|
taskEditor.find(".taskData").hide(); |
|
taskEditor.find(".assignmentsData").hide(); |
|
taskEditor.find(".toolsData").hide(); |
|
taskEditor.find(".geofenceData").hide(); |
|
taskEditor.find("#mapgantt").hide(); |
|
taskEditor.find(".assigsTableWrapper").height(455); |
|
taskEditor.prepend("<h1>\""+task.name+"\"</h1>"); |
|
} |
|
|
|
if (editOnlyTools) { |
|
taskEditor.find(".taskData").hide(); |
|
taskEditor.find(".assignmentsData").hide(); |
|
taskEditor.find(".materialData").hide(); |
|
taskEditor.find(".geofenceData").hide(); |
|
taskEditor.find("#mapgantt").hide(); |
|
taskEditor.find(".assigsTableWrapper").height(455); |
|
taskEditor.prepend("<h1>\""+task.name+"\"</h1>"); |
|
} |
|
|
|
//got to extended editor |
|
if (task.isNew()|| !self.master.permissions.canSeeFullEdit){ |
|
taskEditor.find("#taskFullEditor").remove(); |
|
} else { |
|
taskEditor.bind("openFullEditor.gantt",function () { |
|
window.location.href=contextPath+"/applications/teamwork/task/taskEditor.jsp?CM=ED&OBJID="+task.id; |
|
}); |
|
} |
|
|
|
|
|
taskEditor.find("#name").val(task.name); |
|
taskEditor.find("#description").val(task.description); |
|
taskEditor.find("#code").val(task.code); |
|
taskEditor.find("#progress").val(task.progress ? parseFloat(task.progress) : 0).prop("readonly",task.progressByWorklog==true); |
|
taskEditor.find("#progressByWorklog").prop("checked",task.progressByWorklog); |
|
taskEditor.find("#status").val(task.status); |
|
taskEditor.find("#type").val(task.typeId); |
|
taskEditor.find("#type_txt").val(task.type); |
|
taskEditor.find("#relevance").val(task.relevance); |
|
//cvc_redraw(taskEditor.find(".cvcComponent")); |
|
|
|
|
|
if (task.startIsMilestone) |
|
taskEditor.find("#startIsMilestone").prop("checked", true); |
|
if (task.endIsMilestone) |
|
taskEditor.find("#endIsMilestone").prop("checked", true); |
|
|
|
taskEditor.find("#duration").val(durationToString(task.duration)); |
|
var startDate = taskEditor.find("#start"); |
|
startDate.val(new Date(task.start).format()); |
|
//start is readonly in case of deps |
|
if (task.depends || !(this.master.permissions.canWrite ||task.canWrite)) { |
|
startDate.attr("readonly", "true"); |
|
} else { |
|
startDate.removeAttr("readonly"); |
|
} |
|
|
|
taskEditor.find("#end").val(new Date(task.end).format()); |
|
|
|
//make assignments table |
|
var assigsTable = taskEditor.find("#assigsTable"); |
|
assigsTable.find("[assId]").remove(); |
|
// loop on assignments |
|
for (var i = 0; i < task.assigs.length; i++) { |
|
var assig = task.assigs[i]; |
|
var assigRow = $.JST.createFromTemplate({task: task, assig: assig}, "ASSIGNMENT_ROW"); |
|
assigsTable.append(assigRow); |
|
} |
|
|
|
taskEditor.find(":input").updateOldValue(); |
|
|
|
if (!(self.master.permissions.canWrite || task.canWrite)) { |
|
taskEditor.find("input,textarea").prop("readOnly", true); |
|
taskEditor.find("input:checkbox,select").prop("disabled", true); |
|
taskEditor.find("#saveButton").remove(); |
|
taskEditor.find(".button").addClass("disabled"); |
|
|
|
} else { |
|
|
|
//bind dateField on dates, duration |
|
taskEditor.find("#start,#end,#duration").click(function () { |
|
var input = $(this); |
|
if (input.is("[entrytype=DATE]")) { |
|
input.dateField({ |
|
inputField: input, |
|
minDate:self.minAllowedDate, |
|
maxDate:self.maxAllowedDate, |
|
callback: function (d) {$(this).blur();} |
|
}); |
|
} |
|
}).blur(function () { |
|
var inp = $(this); |
|
if (inp.validateField()) { |
|
resynchDates(inp, taskEditor.find("[name=start]"), taskEditor.find("[name=startIsMilestone]"), taskEditor.find("[name=duration]"), taskEditor.find("[name=end]"), taskEditor.find("[name=endIsMilestone]")); |
|
//workload computation |
|
if (typeof(workloadDatesChanged)=="function") |
|
workloadDatesChanged(); |
|
} |
|
}); |
|
|
|
taskEditor.find("#startIsMilestone,#endIsMilestone").click(function () { |
|
var inp = $(this); |
|
resynchDates(inp, taskEditor.find("[name=start]"), taskEditor.find("[name=startIsMilestone]"), taskEditor.find("[name=duration]"), taskEditor.find("[name=end]"), taskEditor.find("[name=endIsMilestone]")); |
|
}); |
|
|
|
//bind add assignment |
|
var cnt=0; |
|
taskEditor.find("#addAssig").click(function () { |
|
cnt++; |
|
var assigsTable = taskEditor.find("#assigsTable"); |
|
var assigRow = $.JST.createFromTemplate({task: task, assig: {id: "tmp_" + new Date().getTime()+"_"+cnt}}, "ASSIGNMENT_ROW"); |
|
assigsTable.append(assigRow); |
|
$("#bwinPopupd").scrollTop(10000); |
|
}).click(); |
|
|
|
//bind add material |
|
var cnt=0; |
|
taskEditor.find("#addMaterial").click(function () { |
|
cnt++; |
|
var materialTable = taskEditor.find("#materialTable"); |
|
var materialRow = $.JST.createFromTemplate({task: task, material: {id: "tmp_" + new Date().getTime()+"_"+cnt}}, "MATERIAL_ROW"); |
|
materialTable.append(materialRow); |
|
$("#bwinPopupd").scrollTop(10000); |
|
}).click(); |
|
|
|
//bind add tools |
|
var cnt=0; |
|
taskEditor.find("#addTools").click(function () { |
|
cnt++; |
|
var toolsTable = taskEditor.find("#toolsTable"); |
|
var toolsRow = $.JST.createFromTemplate({task: task, tools: {id: "tmp_" + new Date().getTime()+"_"+cnt}}, "TOOLS_ROW"); |
|
toolsTable.append(toolsRow); |
|
$("#bwinPopupd").scrollTop(10000); |
|
}).click(); |
|
|
|
//save task |
|
taskEditor.bind("saveFullEditor.gantt",function () { |
|
//console.debug("saveFullEditor"); |
|
var task = self.master.getTask(taskId); // get task again because in case of rollback old task is lost |
|
|
|
self.master.beginTransaction(); |
|
task.name = taskEditor.find("#name").val(); |
|
task.description = taskEditor.find("#description").val(); |
|
task.code = taskEditor.find("#code").val(); |
|
task.progress = parseFloat(taskEditor.find("#progress").val()); |
|
//task.duration = parseInt(taskEditor.find("#duration").val()); //bicch rimosso perchè devono essere ricalcolata dalla start end, altrimenti sbaglia |
|
task.startIsMilestone = taskEditor.find("#startIsMilestone").is(":checked"); |
|
task.endIsMilestone = taskEditor.find("#endIsMilestone").is(":checked"); |
|
|
|
task.type = taskEditor.find("#type_txt").val(); |
|
task.typeId = taskEditor.find("#type").val(); |
|
task.relevance = taskEditor.find("#relevance").val(); |
|
task.progressByWorklog= taskEditor.find("#progressByWorklog").is(":checked"); |
|
|
|
//set assignments |
|
var cnt=0; |
|
taskEditor.find("tr[assId]").each(function () { |
|
var trAss = $(this); |
|
var assId = trAss.attr("assId"); |
|
var resId = trAss.find("[name=resourceId]").val(); |
|
var resName = trAss.find("[name=resourceId_txt]").val(); // from smartcombo text input part |
|
var roleId = trAss.find("[name=roleId]").val(); |
|
var effort = millisFromString(trAss.find("[name=effort]").val(),true); |
|
|
|
//check if the selected resource exists in ganttMaster.resources |
|
var res= self.master.getOrCreateResource(resId,resName); |
|
|
|
//if resource is not found nor created |
|
if (!res) |
|
return; |
|
|
|
//check if an existing assig has been deleted and re-created with the same values |
|
var found = false; |
|
for (var i = 0; i < task.assigs.length; i++) { |
|
var ass = task.assigs[i]; |
|
|
|
if (assId == ass.id) { |
|
ass.effort = effort; |
|
ass.roleId = roleId; |
|
ass.resourceId = res.id; |
|
ass.touched = true; |
|
found = true; |
|
break; |
|
|
|
} else if (roleId == ass.roleId && res.id == ass.resourceId) { |
|
ass.effort = effort; |
|
ass.touched = true; |
|
found = true; |
|
break; |
|
|
|
} |
|
} |
|
|
|
if (!found && resId && roleId) { //insert |
|
cnt++; |
|
var ass = task.createAssignment("tmp_" + new Date().getTime()+"_"+cnt, resId, roleId, effort); |
|
ass.touched = true; |
|
} |
|
|
|
}); |
|
|
|
//remove untouched assigs |
|
task.assigs = task.assigs.filter(function (ass) { |
|
var ret = ass.touched; |
|
delete ass.touched; |
|
return ret; |
|
}); |
|
|
|
//change dates |
|
task.setPeriod(Date.parseString(taskEditor.find("#start").val()).getTime(), Date.parseString(taskEditor.find("#end").val()).getTime() + (3600000 * 22)); |
|
|
|
//change status |
|
task.changeStatus(taskEditor.find("#status").val()); |
|
|
|
if (self.master.endTransaction()) { |
|
taskEditor.find(":input").updateOldValue(); |
|
closeBlackPopup(); |
|
} |
|
|
|
}); |
|
} |
|
|
|
taskEditor.attr("alertonchange","true"); |
|
var ndo = createModalPopup(800, 450).append(taskEditor);//.append("<div style='height:800px; background-color:red;'></div>") |
|
|
|
//workload computation |
|
if (typeof(workloadDatesChanged)=="function") |
|
workloadDatesChanged(); |
|
|
|
|
|
|
|
};
|
|
|