.resEdit {
padding: 15px;
}
.resLine {
width: 95%;
padding: 3px;
margin: 5px;
border: 1px solid #d0d0d0;
}
body {
overflow: hidden;
}
.ganttButtonBar h1{
color: #000000;
font-weight: bold;
font-size: 28px;
margin-left: 10px;
}
var ge;
$(function() {
var canWrite=true; //this is the default for test purposes
// here starts gantt initialization
ge = new GanttMaster();
ge.set100OnClose=true;
ge.shrinkParent=true;
ge.init($("#workSpace"));
loadI18n(); //overwrite with localized ones
//in order to force compute the best-fitting zoom level
delete ge.gantt.zoom;
var project=loadFromLocalStorage();
if (!project.canWrite)
$(".ganttButtonBar button.requireWrite").attr("disabled","true");
ge.loadProject(project);
ge.checkpoint(); //empty the undo stack
initializeHistoryManagement(ge.tasks[0].id);
});
function getDemoProject(){
//console.debug("getDemoProject")
ret= {"tasks": [
{"id": -1, "name": "Gantt editor", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 0, "status": "STATUS_ACTIVE", "depends": "", "canWrite": true, "start": 1396994400000, "duration": 20, "end": 1399586399999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": true},
{"id": -2, "name": "coding", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 1, "status": "STATUS_ACTIVE", "depends": "", "canWrite": true, "start": 1396994400000, "duration": 10, "end": 1398203999999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": true},
{"id": -3, "name": "gantt part", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_ACTIVE", "depends": "", "canWrite": true, "start": 1396994400000, "duration": 2, "end": 1397167199999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false},
{"id": -4, "name": "editor part", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_SUSPENDED", "depends": "3", "canWrite": true, "start": 1397167200000, "duration": 4, "end": 1397685599999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false},
{"id": -5, "name": "testing", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 1, "status": "STATUS_SUSPENDED", "depends": "2:5", "canWrite": true, "start": 1398981600000, "duration": 5, "end": 1399586399999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": true},
{"id": -6, "name": "test on safari", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_SUSPENDED", "depends": "", "canWrite": true, "start": 1398981600000, "duration": 2, "end": 1399327199999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false},
{"id": -7, "name": "test on ie", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_SUSPENDED", "depends": "6", "canWrite": true, "start": 1399327200000, "duration": 3, "end": 1399586399999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false},
{"id": -8, "name": "test on chrome", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_SUSPENDED", "depends": "6", "canWrite": true, "start": 1399327200000, "duration": 2, "end": 1399499999999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false}
], "selectedRow": 2, "deletedTaskIds": [],
"resources": [
{"id": "tmp_1", "name": "Resource 1"},
{"id": "tmp_2", "name": "Resource 2"},
{"id": "tmp_3", "name": "Resource 3"},
{"id": "tmp_4", "name": "Resource 4"}
],
"roles": [
{"id": "tmp_1", "name": "Project Manager"},
{"id": "tmp_2", "name": "Worker"},
{"id": "tmp_3", "name": "Stakeholder"},
{"id": "tmp_4", "name": "Customer"}
], "canWrite": true, "canDelete":true, "canWriteOnParent": true, canAdd:true}
//actualize data
var offset=new Date().getTime()-ret.tasks[0].start;
for (var i=0;i
ret.tasks[i].start = ret.tasks[i].start + offset;
}
return ret;
}
function loadGanttFromServer(taskId, callback) {
//this is a simulation: load data from the local storage if you have already played with the demo or a textarea with starting demo data
var ret=loadFromLocalStorage();
//this is the real implementation
/*
//var taskId = $("#taskSelector").val();
var prof = new Profiler("loadServerSide");
prof.reset();
$.getJSON("ganttAjaxController.jsp", {CM:"LOADPROJECT",taskId:taskId}, function(response) {
//console.debug(response);
if (response.ok) {
prof.stop();
ge.loadProject(response.project);
ge.checkpoint(); //empty the undo stack
if (typeof(callback)=="function") {
callback(response);
}
} else {
jsonErrorHandling(response);
}
});
*/
return ret;
}
function upload(uploadedFile) {
var fileread = new FileReader();
fileread.onload = function(e) {
var content = e.target.result;
var intern = JSON.parse(content); // Array of Objects.
//console.log(intern); // You can index every object
ge.loadProject(intern);
ge.checkpoint(); //empty the undo stack
};
fileread.readAsText(uploadedFile);
}
function saveGanttOnServer() {
//this is a simulation: save data to the local storage or to the textarea
//saveInLocalStorage();
var prj = ge.saveProject();
download(JSON.stringify(prj, null, '\t'), "MyProject.json", "application/json");
/*
delete prj.resources;
delete prj.roles;
var prof = new Profiler("saveServerSide");
prof.reset();
if (ge.deletedTaskIds.length>0) {
if (!confirm("TASK_THAT_WILL_BE_REMOVED\n"+ge.deletedTaskIds.length)) {
return;
}
}
$.ajax("ganttAjaxController.jsp", {
dataType:"json",
data: {CM:"SVPROJECT",prj:JSON.stringify(prj)},
type:"POST",
success: function(response) {
if (response.ok) {
prof.stop();
if (response.project) {
ge.loadProject(response.project); //must reload as "tmp_" ids are now the good ones
} else {
ge.reset();
}
} else {
var errMsg="Errors saving project\n";
if (response.message) {
errMsg=errMsg+response.message+"\n";
}
if (response.errorMessages.length) {
errMsg += response.errorMessages.join("\n");
}
alert(errMsg);
}
}
});
*/
}
// Function to download data to a file
function download(data, filename, type) {
var file = new Blob([data], {type: type});
if (window.navigator.msSaveOrOpenBlob) // IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
else { // Others
var a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
}
function newProject(){
clearGantt();
}
function clearGantt() {
ge.reset();
}
//------------------------------------------- Get project file as JSON (used for migrate project from gantt to Teamwork) ------------------------------------------------------
function getFile() {
$("#gimBaPrj").val(JSON.stringify(ge.saveProject()));
$("#gimmeBack").submit();
$("#gimBaPrj").val("");
/* var uriContent = "data:text/html;charset=utf-8," + encodeURIComponent(JSON.stringify(prj));
neww=window.open(uriContent,"dl");*/
}
function loadFromLocalStorage() {
var ret;
if (localStorage) {
if (localStorage.getObject("teamworkGantDemo")) {
ret = localStorage.getObject("teamworkGantDemo");
}
}
//if not found create a new example task
if (!ret || !ret.tasks || ret.tasks.length == 0){
ret=getDemoProject();
}
return ret;
}
function saveInLocalStorage() {
var prj = ge.saveProject();
if (localStorage) {
localStorage.setObject("teamworkGantDemo", prj);
}
}
//------------------------------------------- Open a black popup for managing resources. This is only an axample of implementation (usually resources come from server) ------------------------------------------------------
function editResources(){
//make resource editor
var resourceEditor = $.JST.createFromTemplate({}, "RESOURCE_EDITOR");
var resTbl=resourceEditor.find("#resourcesTable");
for (var i=0;i
var res=ge.resources[i];
resTbl.append($.JST.createFromTemplate(res, "RESOURCE_ROW"))
}
//bind add resource
resourceEditor.find("#addResource").click(function(){
resTbl.append($.JST.createFromTemplate({id:"new",name:"resource"}, "RESOURCE_ROW"))
});
//bind save event
resourceEditor.find("#resSaveButton").click(function(){
var newRes=[];
//find for deleted res
for (var i=0;i
var res=ge.resources[i];
var row = resourceEditor.find("[resId="+res.id+"]");
if (row.length>0){
//if still there save it
var name = row.find("input[name]").val();
if (name && name!="")
res.name=name;
newRes.push(res);
} else {
//remove assignments
for (var j=0;j
var task=ge.tasks[j];
var newAss=[];
for (var k=0;k
var ass=task.assigs[k];
if (ass.resourceId!=res.id)
newAss.push(ass);
}
task.assigs=newAss;
}
}
}
//loop on new rows
var cnt=0
resourceEditor.find("[resId=new]").each(function(){
cnt++;
var row = $(this);
var name = row.find("input[name]").val();
if (name && name!="")
newRes.push (new Resource("tmp_"+new Date().getTime()+"_"+cnt,name));
});
ge.resources=newRes;
closeBlackPopup();
ge.redraw();
});
var ndo = createModalPopup(400, 500).append(resourceEditor);
}
function initializeHistoryManagement(taskId){
//retrieve from server the list of history points in millisecond that represent the instant when the data has been recorded
//response: {ok:true, historyPoints: [1498168800000, 1498600800000, 1498687200000, 1501538400000, …]}
$.getJSON(contextPath+"/applications/teamwork/task/taskAjaxController.jsp", {CM: "GETGANTTHISTPOINTS", OBJID:taskId}, function (response) {
//if there are history points
if (response.ok == true && response.historyPoints && response.historyPoints.length>0) {
//add show slider button on button bar
var histBtn = $("").addClass("button textual icon lreq30 lreqLabel").attr("title", "SHOW_HISTORY").append("`");
//clicking it
histBtn .click(function () {
var el = $(this);
var ganttButtons = $(".ganttButtonBar .buttons");
//is it already on?
if (!ge.element.is(".historyOn")) {
ge.element.addClass("historyOn");
ganttButtons.find(".requireCanWrite").hide();
//load the history points from server again
showSavingMessage();
$.getJSON(contextPath + "/applications/teamwork/task/taskAjaxController.jsp", {CM: "GETGANTTHISTPOINTS", OBJID: ge.tasks[0].id}, function (response) {
jsonResponseHandling(response);
hideSavingMessage();
if (response.ok == true) {
var dh = response.historyPoints;
if (dh && dh.length > 0) {
//si crea il div per lo slider
var sliderDiv = $("
ganttButtons.append(sliderDiv);
var minVal = 0;
var maxVal = dh.length-1 ;
$("#slider").show().mbSlider({
rangeColor : '#2f97c6',
minVal : minVal,
maxVal : maxVal,
startAt : maxVal,
showVal : false,
grid :1,
formatValue: function (val) {
return new Date(dh[val]).format();
},
onSlideLoad: function (obj) {
this.onStop(obj);
},
onStart : function (obj) {},
onStop : function (obj) {
var val = $(obj).mbgetVal();
showSavingMessage();
/**
* load the data history for that milliseconf from server
* response in this format {ok: true, baselines: {...}}
*
* baselines: {61707: {duration:1,endDate:1550271599998,id:61707,progress:40,startDate:1550185200000,status:"STATUS_WAITING",taskId:"3055"},
* {taskId:{duration:in days,endDate:in millis,id:history record id,progress:in percent,startDate:in millis,status:task status,taskId:"3055"}....}} */
$.getJSON(contextPath + "/applications/teamwork/task/taskAjaxController.jsp", {CM: "GETGANTTHISTORYAT", OBJID: ge.tasks[0].id, millis:dh[val]}, function (response) {
jsonResponseHandling(response);
hideSavingMessage();
if (response.ok ) {
ge.baselines=response.baselines;
ge.showBaselines=true;
ge.baselineMillis=dh[val];
ge.redraw();
}
})
},
onSlide : function (obj) {
clearTimeout(obj.renderHistory);
var self = this;
obj.renderHistory = setTimeout(function(){
self.onStop(obj);
}, 200)
}
});
}
}
});
// closing the history
} else {
//remove the slider
$("#slider").remove();
ge.element.removeClass("historyOn");
if (ge.permissions.canWrite)
ganttButtons.find(".requireCanWrite").show();
ge.showBaselines=false;
ge.baselineMillis=undefined;
ge.redraw();
}
});
$("#saveGanttButton").before(histBtn);
}
})
}
function showBaselineInfo (event,element){
//alert(element.attr("data-label"));
$(element).showBalloon(event, $(element).attr("data-label"));
ge.splitter.secondBox.one("scroll",function(){
$(element).hideBalloon();
})
}
$.JST.loadDecorator("RESOURCE_ROW", function(resTr, res){
resTr.find(".delRes").click(function(){$(this).closest("tr").remove()});
});
$.JST.loadDecorator("ASSIGNMENT_ROW", function(assigTr, taskAssig){
var resEl = assigTr.find("[name=resourceId]");
var opt = $("");
resEl.append(opt);
for(var i=0; i< taskAssig.task.master.resources.length;i++){
var res = taskAssig.task.master.resources[i];
opt = $("");
opt.val(res.id).html(res.name);
if(taskAssig.assig.resourceId == res.id)
opt.attr("selected", "true");
resEl.append(opt);
}
var roleEl = assigTr.find("[name=roleId]");
for(var i=0; i< taskAssig.task.master.roles.length;i++){
var role = taskAssig.task.master.roles[i];
var optr = $("");
optr.val(role.id).html(role.name);
if(taskAssig.assig.roleId == role.id)
optr.attr("selected", "true");
roleEl.append(optr);
}
if(taskAssig.task.master.permissions.canWrite && taskAssig.task.canWrite){
assigTr.find(".delAssig").click(function(){
var tr = $(this).closest("[assId]").fadeOut(200, function(){$(this).remove()});
});
}
});
function loadI18n(){
GanttMaster.messages = {
"CANNOT_WRITE":"No permission to change the following task:",
"CHANGE_OUT_OF_SCOPE":"Project update not possible as you lack rights for updating a parent project.",
"START_IS_MILESTONE":"Start date is a milestone.",
"END_IS_MILESTONE":"End date is a milestone.",
"TASK_HAS_CONSTRAINTS":"Task has constraints.",
"GANTT_ERROR_DEPENDS_ON_OPEN_TASK":"Error: there is a dependency on an open task.",
"GANTT_ERROR_DESCENDANT_OF_CLOSED_TASK":"Error: due to a descendant of a closed task.",
"TASK_HAS_EXTERNAL_DEPS":"This task has external dependencies.",
"GANNT_ERROR_LOADING_DATA_TASK_REMOVED":"GANNT_ERROR_LOADING_DATA_TASK_REMOVED",
"CIRCULAR_REFERENCE":"Circular reference.",
"CANNOT_DEPENDS_ON_ANCESTORS":"Cannot depend on ancestors.",
"INVALID_DATE_FORMAT":"The data inserted are invalid for the field format.",
"GANTT_ERROR_LOADING_DATA_TASK_REMOVED":"An error has occurred while loading the data. A task has been trashed.",
"CANNOT_CLOSE_TASK_IF_OPEN_ISSUE":"Cannot close a task with open issues",
"TASK_MOVE_INCONSISTENT_LEVEL":"You cannot exchange tasks of different depth.",
"CANNOT_MOVE_TASK":"CANNOT_MOVE_TASK",
"PLEASE_SAVE_PROJECT":"PLEASE_SAVE_PROJECT",
"GANTT_SEMESTER":"Semester",
"GANTT_SEMESTER_SHORT":"s.",
"GANTT_QUARTER":"Quarter",
"GANTT_QUARTER_SHORT":"q.",
"GANTT_WEEK":"Week",
"GANTT_WEEK_SHORT":"w."
};
}
function createNewResource(el) {
var row = el.closest("tr[taskid]");
var name = row.find("[name=resourceId_txt]").val();
var url = contextPath + "/applications/teamwork/resource/resourceNew.jsp?CM=ADD&name=" + encodeURI(name);
openBlackPopup(url, 700, 320, function (response) {
//fillare lo smart combo
if (response && response.resId && response.resName) {
//fillare lo smart combo e chiudere l'editor
row.find("[name=resourceId]").val(response.resId);
row.find("[name=resourceId_txt]").val(response.resName).focus().blur();
}
});
}
$(document).on("change", "#load-file", function() {
var uploadedFile = $("#load-file").prop("files")[0];
upload(uploadedFile);
});