Author: hansbak
Date: Mon Oct 13 01:47:05 2008 New Revision: 703969 URL: http://svn.apache.org/viewvc?rev=703969&view=rev Log: new ganntchart for project manager Added: ofbiz/trunk/framework/images/webapp/images/jsgantt.css (with props) ofbiz/trunk/framework/images/webapp/images/jsgantt.js (with props) Modified: ofbiz/trunk/LICENSE ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/WEB-INF/actions/GanttChart.groovy ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/project/gantChart.ftl ofbiz/trunk/specialpurpose/projectmgr/widget/ProjectScreens.xml Modified: ofbiz/trunk/LICENSE URL: http://svn.apache.org/viewvc/ofbiz/trunk/LICENSE?rev=703969&r1=703968&r2=703969&view=diff ============================================================================== --- ofbiz/trunk/LICENSE (original) +++ ofbiz/trunk/LICENSE Mon Oct 13 01:47:05 2008 @@ -432,6 +432,9 @@ ofbiz/trunk/framework/base/lib/javolution-5.2.3.jar ofbiz/trunk/framework/images/webapp/images/dojo/* ofbiz/trunk/specialpurpose/ldap/lib/cas-server-core-3.3.jar +ofbiz/trunk/framework/images/webapp/images/jsgantt.css +ofbiz/trunk/framework/images/webapp/images/jsgantt.js + ========================================================================= The BSD License Added: ofbiz/trunk/framework/images/webapp/images/jsgantt.css URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/jsgantt.css?rev=703969&view=auto ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/jsgantt.css (added) +++ ofbiz/trunk/framework/images/webapp/images/jsgantt.css Mon Oct 13 01:47:05 2008 @@ -0,0 +1,53 @@ + +// These are the class/styles used by various objects in GanttChart. However, Firefox has problems deciphering class style when DIVs are embedded in other DIVs. + +// GanttChart makes heavy use of embedded DIVS, thus the style are often embedded directly in the objects html. If this could be resolved with Firefox, it would + +// make alot of the code look simpleer/cleaner without all the embedded styles + + + +..gantt { font-family:tahoma, arial, verdana; font-size:10px;} + +..gdatehead { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; HEIGHT: 18px } + +..ghead { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 24px; HEIGHT: 20px } + +..gname { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; WIDTH: 18px; HEIGHT: 18px } + +..ghead A { FONT-SIZE: 10px; COLOR: #000000; TEXT-DECORATION: none } + +..gheadwkend A { FONT-SIZE: 10px; COLOR: #000000; TEXT-DECORATION: none } + +..gheadwkend { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 24px; HEIGHT: 20px; background-color: #cfcfcf } + +..gfiller { BORDER-TOP: #efefef 1px solid; BORDER-LEFT: #efefef 1px solid; WIDTH: 18px; HEIGHT: 18px } + +..gfillerwkend { BORDER-LEFT: #efefef 1px solid; WIDTH: 18px; HEIGHT: 18px; BACKGROUND-COLOR: #cfcfcf } + +..gitem { BORDER-TOP: #cccccc 1px solid; WIDTH: 18px; HEIGHT: 18px } + +..gitemwkend { BORDER-TOP: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; WIDTH: 18px; HEIGHT: 18px } + +..gmilestone { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 14px; OVERFLOW: hidden; BORDER-LEFT: #efefef 1px solid; WIDTH: 18px; HEIGHT: 18px} + +..gmilestonewkend { BORDER-TOP: #efefef 1px solid; BORDER-LEFT: #cccccc 1px solid; WIDTH: 18px; HEIGHT: 18px} + +..btn { BORDER-RIGHT: #ffffff; BORDER-TOP: #ffffff; FONT-WEIGHT: bold; FONT-SIZE: 10px; BORDER-LEFT: #ffffff; WIDTH: 12px; COLOR: #cccccc; BORDER-BOTTOM: #ffffff; BACKGROUND-COLOR: #ffffff } + +..hrcomplete { BORDER-RIGHT: #000000 2px solid; PADDING-RIGHT: 0px; BORDER-TOP: #000000 2px solid; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; BORDER-LEFT: #000000 2px solid; WIDTH: 20px; COLOR: #000000; PADDING-TOP: 0px; BORDER-BOTTOM: #000000 2px solid; HEIGHT: 4px } + +..hrhalfcomplete { BORDER-RIGHT: #000000 2px solid; BORDER-TOP: #000000 2px solid; BORDER-LEFT: #000000 2px solid; WIDTH: 9px; COLOR: #000000; BORDER-BOTTOM: #000000 2px solid; HEIGHT: 4px } + +..gweekend { font-family:tahoma, arial, verdana; font-size:11px; background-color:#EEEEEE; text-align:center; } + +..gtask { font-family:tahoma, arial, verdana; font-size:11px; background-color:#00FF00; text-align:center; } + +..gday { font-family:tahoma, arial, verdana; font-size:11px; text-align:center; } + +..gcomplete { background-color:black; height:5px; overflow: auto; margin-top:4px; } + +DIV.scroll { BORDER-RIGHT: #efefef 1px solid; PADDING-RIGHT: 0px; BORDER-TOP: #efefef 1px solid; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; OVERFLOW: hidden; BORDER-LEFT: #efefef 1px solid; WIDTH: 420px; PADDING-TOP: 0px; BORDER-BOTTOM: #efefef 1px solid; BACKGROUND-COLOR: #ffffff } + +DIV.scroll2 { position:relative; PADDING-RIGHT: 0px; overflow:auto ;overflow-x:scroll;overflow-y:hidden; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; WIDTH: 482px; PADDING-TOP: 0px; BACKGROUND-COLOR: #ffffff } + Propchange: ofbiz/trunk/framework/images/webapp/images/jsgantt.css ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/images/webapp/images/jsgantt.css ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/images/webapp/images/jsgantt.css ------------------------------------------------------------------------------ svn:mime-type = text/css Added: ofbiz/trunk/framework/images/webapp/images/jsgantt.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/jsgantt.js?rev=703969&view=auto ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/jsgantt.js (added) +++ ofbiz/trunk/framework/images/webapp/images/jsgantt.js Mon Oct 13 01:47:05 2008 @@ -0,0 +1,2173 @@ +/* Copyright (c) 2008, Shlomy Gantz/BlueBrick Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Shlomy Gantz or BlueBrick Inc. nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY SHLOMY GANTZ/BLUEBRICK INC. ''AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL SHLOMY GANTZ/BLUEBRICK INC. BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + // function that loads each Task Item and fills TaskList array with each task attributes. + + // You should be able to add items to the chart in realtime via javascript and issuing "g.Draw()" command. + + // Parameters: + + // pID: (required) is a unique ID used to identify each row for parent functions and for setting dom id for hiding/showing + + // pName: (required) is the task Label + + // pStart: (required) the task start date, can enter empty date ('') for groups + + // pEnd: (required) the task end date, can enter empty date ('') for groups + + // pColor: (required) the html color for this task; e.g. '00ff00' + + // pLink: (optional) any http link navigated to when task bar is clicked. + + // pMile: UNUSED - in future will represent a milestone + + // pRes: (optional) resource name + + // pComp: (required) completion percent + + // pGroup: (optional) indicates whether this is a group(parent) - 0=NOT Parent; 1=IS Parent + + // pParent: (required) identifies a parent pID, this causes this task to be a child of identified task + + // pOpen: UNUSED - in future can be initially set to close folder when chart is first drawn + + + +var JSGantt; if (!JSGantt) JSGantt = {}; + +var vTimeout = 0; + +//function JSGantt() {} + +JSGantt.isIE = function () { + + if(typeof document.all != 'undefined') + return true; + else + return false; + } + +function Graphics(canvas) + +{ + + this.canvas = canvas; + + this.cache = new Array; + + this.shapes = new Object; + + this.nObject = 0; + + + + // defaults + + this.penColor = "black"; + + this.zIndex = 0; + +} + + +Graphics.prototype.createPlotElement = function(x,y,w,h) { + // detect canvas +// if ( !this.oCanvas ) +// { + if ( (this.canvas == undefined) || (this.canvas == "") ) + this.oCanvas = document.body; + else + this.oCanvas = document.getElementById(this.canvas); +// } + + // retrieve DIV + var oDiv; +// if ( this.cache.length ) { +// oDiv = this.cache.pop(); +// } else { + oDiv = document.createElement('div'); + this.oCanvas.appendChild(oDiv); + + oDiv.style.position = "absolute"; + oDiv.style.margin = "0px"; + oDiv.style.padding = "0px"; + oDiv.style.overflow = "hidden"; + oDiv.style.border = "0px"; +// } + + // set attributes + oDiv.style.zIndex = this.zIndex; + oDiv.style.backgroundColor = this.penColor; + + oDiv.style.left = x; + oDiv.style.top = y; + oDiv.style.width = w + "px"; + oDiv.style.height = h + "px"; + + oDiv.style.visibility = "visible"; + + return oDiv; +} + + +Graphics.prototype.releasePlotElement = function(oDiv) + +{ + + oDiv.style.visibility = "hidden"; + + this.cache.push(oDiv); + +} + + + +Graphics.prototype.addShape = function(shape) + +{ + + shape.oGraphics = this; + + shape.graphicsID = this.nObject; + + this.shapes[this.nObject] = shape; + + this.nObject++; + + shape.draw(); + + return shape; + +} + + + +Graphics.prototype.removeShape = function(shape) + +{ + + if ( (shape instanceof Object) && + + (shape.oGraphics == this) && + + (this.shapes[shape.graphicsID] == shape) ) + + { + + shape.undraw(); + + this.shapes[shape.graphicsID] = undefined; + + shape.oGraphics = undefined; + + } + +} + +Graphics.prototype.clear = function() + +{ + + for ( var i in this.shapes ) + + this.removeShape(this.shapes[i]); + +} + + + + + +//============================================================================= + +// Point + +Graphics.prototype.drawPoint = function(x,y) + +{ + + return this.addShape(new Point(x,y)) + +} + + + +function Point(x,y) + +{ + + this.x = x; + + this.y = y; + +} + +Point.prototype.draw = function() + +{ + + this.oDiv = this.oGraphics.createPlotElement(this.x,this.y,1,1); + +} + +Point.prototype.undraw = function() + +{ + + this.oGraphics.releasePlotElement(this.oDiv); + + this.oDiv = undefined; + +} + + + +//============================================================================= + +// Line + +Graphics.prototype.drawLine = function(x1,y1,x2,y2) + +{ + + return this.addShape(new Line(x1,y1,x2,y2)) + +} + + + +function Line(x1,y1,x2,y2) + +{ + + this.x1 = x1; + + this.y1 = y1; + + this.x2 = x2; + + this.y2 = y2; + +} + + + +Line.prototype.draw = function() + +{ + + this.plots = new Array; + + + + var dx = this.x2 - this.x1; + + var dy = this.y2 - this.y1; + + var x = this.x1; + + var y = this.y1; + + + + var n = Math.max(Math.abs(dx),Math.abs(dy)); + + dx = dx / n; + + dy = dy / n; + + for ( i = 0; i <= n; i++ ) + + { + + this.plots.push(this.oGraphics.createPlotElement(Math.round(x),Math.round(y),1,1)); + + + + x += dx; + + y += dy; + + } + +} + +Line.prototype.undraw = function() + +{ + + while ( this.plots.length ) + + this.oGraphics.releasePlotElement(this.plots.pop()); + + this.plots = undefined; + +} + + + + + +JSGantt.TaskItem = function(pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend) + + { + + + + var vID = pID; + + var vName = pName; + + var vStart = new Date(); + + var vEnd = new Date(); + + var vColor = pColor; + + var vLink = pLink; + + var vMile = pMile; + + var vRes = pRes; + + var vComp = pComp; + + var vGroup = pGroup; + + var vParent = pParent; + + var vOpen = pOpen; + + var vDepend = pDepend; + + var vLevel = 0; + + var vNumKid = 0; + + var vVisible = 1; + + var x1, y1, x2, y2; + + + + + + if (vGroup != 1) + + { + + var vDateParts = pStart.split('/'); + + vStart.setFullYear(parseInt(vDateParts[2], 10), parseInt(vDateParts[0], 10) - 1, parseInt(vDateParts[1], 10)); + + vDateParts = pEnd.split('/'); + + vEnd.setFullYear(parseInt(vDateParts[2], 10), parseInt(vDateParts[0], 10) - 1, parseInt(vDateParts[1], 10)); + + } + + + + this.getID = function(){ return vID }; + + this.getName = function(){ return vName }; + + this.getStart = function(){ return vStart}; + + this.getEnd = function(){ return vEnd }; + + this.getColor = function(){ return vColor}; + + this.getLink = function(){ return vLink }; + + this.getMile = function(){ return vMile }; + + this.getDepend = function(){ return vDepend }; + + this.getResource = function(){ if(vRes) return vRes; else return ' '; }; + + this.getCompVal = function(){ if(vComp) return vComp; else return 0; }; + + this.getCompStr = function(){ if(vComp) return vComp+'%'; else return ''; }; + + this.getDuration = function(vFormat){ + + if (vMile) return '-'; + + + + if(vFormat == 'day') { + + tmpDays = Math.ceil((this.getEnd() - this.getStart()) / (24 * 60 * 60 * 1000) + 1); + + if(tmpDays == 1) return (tmpDays + ' Day'); else return(tmpDays + ' Days'); + + } + + if(vFormat == 'week') { + + tmpWeeks = ((this.getEnd() - this.getStart()) / (24 * 60 * 60 * 1000) + 1)/7; + + if(tmpWeeks == 1) return ('1 Week'); else return(tmpWeeks.toFixed(1) + ' Weeks'); + + } + + if(vFormat == 'month') { + + tmpMonths = ((this.getEnd() - this.getStart()) / (24 * 60 * 60 * 1000) + 1)/30; + + if(tmpMonths == 1) return ('1 Month'); else return(tmpMonths.toFixed(1) + ' Months'); + + } + + }; + + this.getParent = function(){ return vParent }; + + this.getGroup = function(){ return vGroup }; + + this.getOpen = function(){ return vOpen }; + + this.getLevel = function(){ return vLevel }; + + this.getNumKids = function(){ return vNumKid }; + + this.getStartX = function(){ return x1 }; + + this.getStartY = function(){ return y1 }; + + this.getEndX = function(){ return x2 }; + + this.getEndY = function(){ return y2 }; + + this.getVisible = function(){ return vVisible }; + + + + this.setDepend = function(pDepend){ vDepend = pDepend;}; + + this.setStart = function(pStart){ vStart = pStart;}; + + this.setEnd = function(pEnd) { vEnd = pEnd; }; + + this.setLevel = function(pLevel){ vLevel = pLevel;}; + + this.setNumKid = function(pNumKid){ vNumKid = pNumKid;}; + + this.setCompVal = function(pCompVal){ vComp = pCompVal;}; + + this.setStartX = function(pX) {x1 = pX; }; + + this.setStartY = function(pY) {y1 = pY; }; + + this.setEndX = function(pX) {x2 = pX; }; + + this.setEndY = function(pY) {y2 = pY; }; + + this.setOpen = function(pOpen) {vOpen = pOpen; }; + + this.setVisible = function(pVisible) {vVisible = pVisible; }; + + } + + + + + + // function that loads the main gantt chart properties and functions + + // pDiv: (required) this is a DIV object created in HTML + + // pStart: UNUSED - future use to force minimum chart date + + // pEnd: UNUSED - future use to force maximum chart date + + // pWidth: UNUSED - future use to force chart width and cause objects to scale to fit within that width + + // pShowRes: UNUSED - future use to turn on/off display of resource names + + // pShowDur: UNUSED - future use to turn on/off display of task durations + + // pFormat: (required) - used to indicate whether chart should be drawn in "day", "week", or "month" format + +JSGantt.GanttChart = function(pGanttVar, pDiv, pFormat) + + { + + var vGanttVar = pGanttVar; + + var vDiv = pDiv; + + var vFormat = pFormat; + + var vShowRes = 1; + + var vShowDur = 1; + + var vShowComp = 1; + + var vNumUnits = 0; + + + + var gr = new Graphics('rightside'); + + var vTaskList = new Array(); + + + var month=new Array(12); + + month[0]="January"; + + month[1]="February"; + + month[2]="March"; + + month[3]="April"; + + month[4]="May"; + + month[5]="June"; + + month[6]="July"; + + month[7]="August"; + + month[8]="September"; + + month[9]="October"; + + month[10]="November"; + + month[11]="December"; + + + this.setShowRes = function(pShow) { vShowRes = pShow; }; + + this.setShowDur = function(pShow) { vShowDur = pShow; }; + + this.setShowComp = function(pShow) { vShowComp = pShow; }; + + this.setFormat = function(pFormat){ + vFormat = pFormat; + + this.Draw(); + }; + + + + this.getShowRes = function(){ return vShowRes }; + + this.getShowDur = function(){ return vShowDur }; + + this.getShowComp = function(){ return vShowComp }; + + + this.CalcTaskXY = function () + + { + + var vList = this.getList(); + + var vTaskDiv; + + var vParDiv; + + var vLeft, vTop, vHeight, vWidth; + + + + for(i = 0; i < vList.length; i++) + + { + + vID = vList[i].getID(); + + + + vTaskDiv = document.getElementById("taskbar_"+vID); + + vBarDiv = document.getElementById("bardiv_"+vID); + + vParDiv = document.getElementById("childgrid_"+vID); + + + + if(vBarDiv) { + + vList[i].setStartX( vBarDiv.offsetLeft ); + + vList[i].setStartY( vParDiv.offsetTop+vBarDiv.offsetTop+6 ); + + vList[i].setEndX( vBarDiv.offsetLeft + vBarDiv.offsetWidth ); + + vList[i].setEndY( vParDiv.offsetTop+vBarDiv.offsetTop+6 ); + + } + + } + + } + + + + this.AddTaskItem = function(value) + + { + + vTaskList.push(value); + + } + + + + this.getList = function() { return vTaskList }; + + this.getGraphics = function() {return gr;}; + + + + this.drawDependency =function(x1,y1,x2,y2) + + { + + var gr = this.getGraphics(); + + gr.penColor = "red"; + + if(x1 < x2) + + { + + gr.drawLine(x1,y1,x1+5,y1); + + gr.drawLine(x1+5,y1,x1+5,y2); + + gr.drawLine(x1+5,y2,x2,y2); + + } + + else + + { + + var Xpoints = new Array(x1,x1+5, x1+5, x2-5, x2-5,x2); + + var Ypoints = new Array(y1,y1, y2-5, y2-5, y2,y2); + + gr.drawLine(x1,y1,x1+5,y1); + + gr.drawLine(x1+5,y1,x1+5,y2-10); + + gr.drawLine(x1+5,y2-10,x2-5,y2-10); + + gr.drawLine(x2-5,y2-10,x2-5,y2); + + gr.drawLine(x2-5,y2,x2,y2); + + } + + } + + + + + + this.DrawDependencies = function () + { + + //First recalculate the x,y + + this.CalcTaskXY(); + + + + var gr = this.getGraphics(); + + gr.clear(); + + + + var vList = this.getList(); + + + + for(var i = 0; i < vList.length; i++) + + { + + //if(!isNaN(vList[i].getDepend()) && document.getElementById("childgrid_"+vList[i].getID()).style.display=='') + if(!isNaN(vList[i].getDepend()) && vList[i].getVisible()==1) + + { + + var ii = this.getArrayLocationByID(vList[i].getDepend()); + + //if(document.getElementById("childgrid_"+vList[ii].getID()).style.display=='') + if(vList[ii].getVisible()==1) + + { + + this.drawDependency(vList[ii].getEndX(),vList[ii].getEndY(),vList[i].getStartX(),vList[i].getStartY()) + + } + + } + + } + + } + + + + this.getArrayLocationByID = function(pId) { + + + + var vList = this.getList(); + + for(var i = 0; i < vList.length; i++) + + { + + if(vList[i].getID()==pId) + + return i; + + } + + + + } + + + + this.Draw = function() + + { + + var vCurrDate = new Date(); + + var vMaxDate = new Date(); + + var vMinDate = new Date(); + + var vTmpDate = new Date(); + + var vNxtDate = new Date(); + + var vTaskLeft = 0; + + var vTaskRight = 0; + + var vNumCols = 0; + + var vID = 0; + + var vMainTable = ""; + + var vLeftTable = ""; + + var vRightTable = ""; + + var vDateRowStr = ""; + + var vItemRowStr = ""; + + var vSpanSet = 0; + + var vColWidth = 0; + + var vColUnit = 0; + + var vChartWidth = 0; + + var vNumDays = 0; + + var vDayWidth = 0; + + var vStr = ""; + + var vNameWidth = 220; + + var vStatusWidth = 70; + + var vLeftWidth = 15 + 220 + 70 + 70 + 70; + + if(vTaskList.length > 0) + + { + + + vCurrDate.setFullYear(vCurrDate.getFullYear(), vCurrDate.getMonth(), vCurrDate.getDate()); + + + + // Process all tasks preset parent date and completion % + + JSGantt.processRows(vTaskList, 0, -1, 1); + + + + // get overall min/max dates plus padding + + vMinDate = JSGantt.getMinDate(vTaskList, vFormat); + + vMaxDate = JSGantt.getMaxDate(vTaskList, vFormat); + + + + // Calculate chart width variables. vColWidth can be altered manually to change each column width + + // May be smart to make this a parameter of GanttChart or set it based on existing pWidth parameter + + if(vFormat == 'day') { + + vColWidth = 18; + + vColUnit = 1; + + } + + if(vFormat == 'week') { + + vColWidth = 37; + + vColUnit = 7; + + } + + if(vFormat == 'month') { + + vColWidth = 37; + + vColUnit = 30; + + } + + + + + + vNumDays = Math.ceil((Date.parse(vMaxDate) - Date.parse(vMinDate)) / ( 24 * 60 * 60 * 1000)); + + vNumUnits = vNumDays / vColUnit; + + vChartWidth = vNumUnits * vColWidth + 1; + + vDayWidth = (vColWidth / vColUnit) + (1/vColUnit); + + + + vMainTable = + + "<TABLE id=theTable cellSpacing=0 cellPadding=0 border=0><TBODY><TR>" + + + "<TD vAlign=top bgColor=#ffffff>"; + + + + if(vShowRes !=1) vNameWidth+=vStatusWidth; + if(vShowDur !=1) vNameWidth+=vStatusWidth; + if(vShowComp!=1) vNameWidth+=vStatusWidth; + + // DRAW the Left-side of the chart (names, resources, comp%) + + vLeftTable = + + '<DIV class=scroll id=leftside style="width:' + vLeftWidth + 'px"><TABLE cellSpacing=0 cellPadding=0 border=0><TBODY>' + + + '<TR style="HEIGHT: 17px">' + + + ' <TD style="WIDTH: 15px; HEIGHT: 17px"></TD>' + + + ' <TD style="WIDTH: ' + vNameWidth + 'px; HEIGHT: 17px"><NOBR></NOBR></TD>'; + + if(vShowRes ==1) vLeftTable += ' <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>' ; + if(vShowDur ==1) vLeftTable += ' <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>' ; + if(vShowComp==1) vLeftTable += ' <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>' ; + + vLeftTable += + '<TR style="HEIGHT: 20px">' + + + ' <TD style="BORDER-TOP: #efefef 1px solid; WIDTH: 15px; HEIGHT: 20px"></TD>' + + + ' <TD style="BORDER-TOP: #efefef 1px solid; WIDTH: ' + vNameWidth + 'px; HEIGHT: 20px"><NOBR></NOBR></TD>' ; + + if(vShowRes ==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=middle nowrap>Resource</TD>' ; + if(vShowDur ==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=middle nowrap>Duration</TD>' ; + if(vShowComp==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=middle nowrap>% Comp.</TD>' ; + + vLeftTable += '</TR>'; + + + for(i = 0; i < vTaskList.length; i++) + + { + + vID = vTaskList[i].getID(); + + if(vTaskList[i].getVisible() == 0) + + vLeftTable += '<TR id=child_' + vID + ' style="display:none">' ; + + else + + vLeftTable += '<TR id=child_' + vID + '>' ; + + + vLeftTable += + + ' <TD class=gdatehead style="WIDTH: 15px; HEIGHT: 20px; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;"> </TD>' + + + ' <TD class=gname style="WIDTH: ' + vNameWidth + 'px; HEIGHT: 20px; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px;" nowrap><NOBR><span style="color: #aaaaaa">'; + + + for(j=1; j<vTaskList[i].getLevel(); j++) { + + vLeftTable += '    '; + + } + + + vLeftTable += '</span>'; + + + if( vTaskList[i].getGroup()) { + + if( vTaskList[i].getOpen() == 1) + vLeftTable += '<SPAN id="group_' + vID + '" style="color:#000000; cursor:pointer; font:bold; FONT-SIZE: 12px;" onclick="JSGantt.folder(' + vID + ','+vGanttVar+');'+vGanttVar+'.DrawDependencies();">–</span><span style="color:#000000"> </SPAN>' ; + else + vLeftTable += '<SPAN id="group_' + vID + '" style="color:#000000; cursor:pointer; font:bold; FONT-SIZE: 12px;" onclick="JSGantt.folder(' + vID + ','+vGanttVar+');'+vGanttVar+'.DrawDependencies();">+</span><span style="color:#000000"> </SPAN>' ; + + } else { + + vLeftTable += '<span style="color: #000000; font:bold; FONT-SIZE: 12px;">   </span>'; + } + + + + vLeftTable += + + '<span onclick=JSGantt.taskLink("' + vTaskList[i].getLink() + '",300,200); style="cursor:pointer"> ' + vTaskList[i].getName() + '</span></NOBR></TD>' ; + + if(vShowRes ==1) vLeftTable += ' <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=middle><NOBR>' + vTaskList[i].getResource() + '</NOBR></TD>' ; + + if(vShowDur ==1) vLeftTable += ' <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=middle><NOBR>' + vTaskList[i].getDuration(vFormat) + '</NOBR></TD>' ; + + if(vShowComp==1) vLeftTable += ' <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=middle><NOBR>' + vTaskList[i].getCompStr() + '</NOBR></TD>' ; + + vLeftTable += '</TR>'; + + + + } + + + + + + // DRAW the date format selector at bottom left. Another potential GanttChart parameter to hide/show this selector + + vLeftTable += '</TD></TR>' + + + '<TR><TD border=1 colspan=5 align=left style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 11px; BORDER-LEFT: #efefef 1px solid; height=18px"> Powered by <a href=http://www.jsgantt.com>jsGantt</a> Format:'; + + + + if (vFormat=='day') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="day" checked>Day'; + + else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("day",'+vGanttVar+'); VALUE="day">Day'; + + + + if (vFormat=='week') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="week" checked>Week'; + + else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("week",'+vGanttVar+') VALUE="week">Week'; + + + + if (vFormat=='month') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" checked>Month'; + + else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("month",'+vGanttVar+') VALUE="month">Month'; + + + + vLeftTable += '</TD></TR></TBODY></TABLE></TD>'; + + + + vMainTable += vLeftTable; + + + + + + // Draw the Chart Rows + + vRightTable = + + '<TD style="width: ' + vChartWidth + 'px;" vAlign=top bgColor=#ffffff>' + + + '<DIV class=scroll2 id=rightside>' + + + '<TABLE style="width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>' + + + '<TBODY><TR style="HEIGHT: 18px">'; + + + + vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate()); + + + + // Major Date Header + + while(Date.parse(vTmpDate) <= Date.parse(vMaxDate)) + + { + + + + vStr = vTmpDate.getFullYear() + ''; + + vStr = vStr.substring(2,4); + + + + if(vFormat == 'day') + + { + + vRightTable += '<td class=gdatehead style="FONT-SIZE: 12px; HEIGHT: 19px;" align=center colspan=7>' + (vTmpDate.getMonth()+1) + '/' + vTmpDate.getDate() + ' - '; + + vTmpDate.setDate(vTmpDate.getDate()+6); + + vRightTable += (vTmpDate.getMonth()+1) + '/' + vTmpDate.getDate() + '/' + vStr + '</td>'; + + vTmpDate.setDate(vTmpDate.getDate()+1); + + + + } + + if(vFormat == 'week') + + { + + vRightTable += '<td class=gdatehead align=center style="FONT-SIZE: 12px; HEIGHT: 19px;" width='+vColWidth+'>`'+ vStr + '</td>'; + + vTmpDate.setDate(vTmpDate.getDate()+7); + + } + + if(vFormat == 'month') + + { + + vRightTable += '<td class=gdatehead align=center style="FONT-SIZE: 12px; HEIGHT: 19px;" width='+vColWidth+'>`'+ vStr + '</td>'; + + vTmpDate.setDate(vTmpDate.getDate() + 1); + + while(vTmpDate.getDate() > 1) + + { + + vTmpDate.setDate(vTmpDate.getDate() + 1); + + } + + } + + + + } + + + + + + vRightTable += '</TR><TR>'; + + + + // Minor Date header and Cell Rows + + vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate()); + + vNxtDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate()); + + vNumCols = 0; + + + + while(Date.parse(vTmpDate) <= Date.parse(vMaxDate)) + + { + + + + if(vFormat == 'day') + + { + + + + if(vTmpDate.getDay() % 6 == 0) { + + vDateRowStr += '<td class="gheadwkend" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#cfcfcf align=middle><div style="width: '+vColWidth+'">' + vTmpDate.getDate() + '</div></td>'; + + vItemRowStr += '<td class="gheadwkend" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;" bgcolor=#cfcfcf align=middle><div style="width: '+vColWidth+'"> </div></td>'; + + } + + else { + + vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" align=middle><div style="width: '+vColWidth+'">' + vTmpDate.getDate() + '</div></td>'; + + vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;" align=middle><div style="width: '+vColWidth+'">  </div></td>'; + + } + + + + vTmpDate.setDate(vTmpDate.getDate() + 1); + + + + } + + + + if(vFormat == 'week') + + { + + + + vNxtDate.setDate(vNxtDate.getDate() + 7); + + if(vNxtDate <= vMaxDate) { + + vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" align=middle width:'+vColWidth+'><div style="width: '+vColWidth+'">' + (vTmpDate.getMonth()+1) + '/' + vTmpDate.getDate() + '</div></td>'; + + vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=middle><div style="width: '+vColWidth+'">  </div></td>'; + + } else { + + vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=middle width:'+vColWidth+'><div style="width: '+vColWidth+'">' + (vTmpDate.getMonth()+1) + '/' + vTmpDate.getDate() + '</div></td>'; + + vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=middle><div style="width: '+vColWidth+'">  </div></td>'; + + } + + + + vTmpDate.setDate(vTmpDate.getDate() + 7); + + + + } + + + + if(vFormat == 'month') + + { + + + + vNxtDate.setDate(vNxtDate.getDate() + 31); + + if(vNxtDate <= vMaxDate) { + + vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" align=middle width:'+vColWidth+'><div style="width: '+vColWidth+'">' + month[vTmpDate.getMonth()].substr(0,3) + '</div></td>'; + + vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=middle><div style="width: '+vColWidth+'">  </div></td>'; + + } else { + + vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=middle width:'+vColWidth+'><div style="width: '+vColWidth+'">' + month[vTmpDate.getMonth()].substr(0,3) + '</div></td>'; + + vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=middle><div style="width: '+vColWidth+'">  </div></td>'; + + } + + + + vTmpDate.setDate(vTmpDate.getDate() + 1); + + while(vTmpDate.getDate() > 1) + + { + + vTmpDate.setDate(vTmpDate.getDate() + 1); + + } + + + + } + + + + } + + + + + + + + vRightTable += vDateRowStr + '</TR>'; + + vRightTable += '</TBODY></TABLE>'; + + + + + + // Draw each row + + for(i = 0; i < vTaskList.length; i++) + + { + + vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate()); + + vTaskStart = vTaskList[i].getStart(); + + vTaskEnd = vTaskList[i].getEnd(); + + + + vNumCols = 0; + + vID = vTaskList[i].getID(); + + + + vNumUnits = Math.ceil((vTaskList[i].getEnd() - vTaskList[i].getStart()) / (24 * 60 * 60 * 1000)) + 1; + + + + vSpanSet = 0; + + + + if(vTaskList[i].getVisible() == 0) + + vRightTable += '<DIV id=childgrid_' + vID + ' style="position:relative; display:none;">'; + + else + + vRightTable += '<DIV id=childgrid_' + vID + ' style="position:relative">'; + + + + vRightTable += '<DIV><TABLE style="position:relative; top:0px; width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0><TR class=yesdisplay style="HEIGHT: 20px">' + vItemRowStr + '</TR></TABLE></DIV>'; + + + + if( vTaskList[i].getMile()) { + + + + // Build date string for Title + + vStr = vTaskStart.getFullYear() + ''; + + vStr = vStr.substring(2,4); + + vDateRowStr = vTaskStart.getMonth() + '/' + vTaskStart.getDate() + '/' + vStr; + + + + vTaskLeft = (Date.parse(vTaskList[i].getStart()) - Date.parse(vMinDate)) / (24 * 60 * 60 * 1000); + + vTaskRight = 1 + + + + vRightTable += + + '<div id=bardiv_' + vID + ' style="position:absolute; top:0px; left:' + Math.ceil((vTaskLeft * (vDayWidth) + 1)) + 'px; height: 16px; width:12px; overflow:hidden;">' + + + '<div id=taskbar_' + vID + ' title="' + vTaskList[i].getName() + ': ' + vDateRowStr + '" style="height: 16px; width:12px; overflow:hidden; cursor: pointer;" onclick=JSGantt.taskLink("' + vTaskList[i].getLink() + '",300,200);>'; + + + + if(vTaskList[i].getCompVal() < 100) + + vRightTable += '◊</div></div>' ; + + else + + vRightTable += '♦</div></div>' ; + + + + } else { + + + + // Build date string for Title + + vStr = vTaskStart.getFullYear() + ''; + + vStr = vStr.substring(2,4); + + vDateRowStr = vTaskStart.getMonth() + '/' + vTaskStart.getDate() + '/' + vStr; + + vStr = vTaskEnd.getFullYear() + ''; + + vStr = vStr.substring(2,4); + + + vDateRowStr += ' - ' + vTaskEnd.getMonth() + '/' + vTaskEnd.getDate() + '/' + vStr; + + + + vTaskLeft = (Date.parse(vTaskList[i].getStart()) - Date.parse(vMinDate)) / (24 * 60 * 60 * 1000); + + vTaskRight = (Date.parse(vTaskList[i].getEnd()) - Date.parse(vTaskList[i].getStart())) / (24 * 60 * 60 * 1000) + 1/vColUnit; + + + + // Draw Group Bar which has outer div with inner group div and several small divs to left and right to create angled-end indicators + + if( vTaskList[i].getGroup()) { + + vRightTable += + + '<div id=bardiv_' + vID + ' style="position:absolute; top:5px; left:' + Math.ceil(vTaskLeft * (vDayWidth) + 1) + 'px; height: 7px; width:' + Math.ceil((vTaskRight) * (vDayWidth) - 1) + 'px">' + + + '<div id=taskbar_' + vID + ' title="' + vTaskList[i].getName() + ': ' + vDateRowStr + '" class=gtask style="background-color:#000000; height: 7px; width:' + Math.ceil((vTaskRight) * (vDayWidth) -1) + 'px; cursor: pointer;">' + + + '<div style="Z-INDEX: -4; float:left; background-color:#666666; height:3px; overflow: hidden; margin-top:1px; ' + + + 'margin-left:1px; margin-right:1px; filter: alpha(opacity=80); opacity:0.8; width:' + vTaskList[i].getCompStr() + '; ' + + + 'cursor: pointer;" onclick=JSGantt.taskLink("' + vTaskList[i].getLink() + '",300,200);></div></div>' + + + '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:4px; overflow: hidden; width:1px;"></div>' + + + '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:4px; overflow: hidden; width:1px;"></div>' + + + '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:3px; overflow: hidden; width:1px;"></div>' + + + '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:3px; overflow: hidden; width:1px;"></div>' + + + '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:2px; overflow: hidden; width:1px;"></div>' + + + '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:2px; overflow: hidden; width:1px;"></div>' + + + '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:1px; overflow: hidden; width:1px;"></div>' + + + '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:1px; overflow: hidden; width:1px;"></div>' + + + '</div>' ; + + + + } else { + + // Draw Task Bar which has outer DIV with enclosed colored bar div, and opaque completion div + + vRightTable += + + '<div id=bardiv_' + vID + ' style="position:absolute; top:4px; left:' + Math.ceil(vTaskLeft * (vDayWidth) + 1) + 'px; width:' + Math.ceil((vTaskRight) * (vDayWidth) - 1) + 'px">' + + + '<div id=taskbar_' + vID + ' title="' + vTaskList[i].getName() + ': ' + vDateRowStr + '" class=gtask style="background-color:' + vTaskList[i].getColor() +'; height: 13px; width:' + Math.ceil((vTaskRight) * (vDayWidth) - 1) + 'px; cursor: pointer;" ' + + + 'onclick=JSGantt.taskLink("' + vTaskList[i].getLink() + '",300,200);>' + + + '<div class=gcomplete style="Z-INDEX: -4; float:left; background-color:black; height:5px; overflow: auto; margin-top:4px; filter: alpha(opacity=40); opacity:0.4; width:' + vTaskList[i].getCompStr() + '; overflow:hidden"></div></div></div>' ; + + + + } + + + + } + + + + vRightTable += '</DIV>'; + + } + + vMainTable += vRightTable + '</DIV></TD></TR></TBODY></TABLE></BODY></HTML>'; + + + vDiv.innerHTML = vMainTable; + + } + + } + + + } + + + + + + + + // Recursively process task tree ... set min, max dates of parent tasks and identfy task level. + +JSGantt.processRows = function(pList, pID, pRow, pLevel) + + { + + + + var vMinDate = new Date(); + + var vMaxDate = new Date(); + + var vMinSet = 0; + + var vMaxSet = 0; + + var vList = pList; + + var vLevel = pLevel; + + var i = 0; + + var vNumKid = 0; + + var vCompSum = 0; + + + + for(i = 0; i < pList.length; i++) + + { + + + + if(pList[i].getParent() == pID) { + + + + pList[i].setLevel(vLevel); + + vNumKid++; + + + + if(pList[i].getGroup() == 1) { + + JSGantt.processRows(vList, pList[i].getID(), i, vLevel+1); + + } + + + + if( vMinSet==0 || pList[i].getStart() < vMinDate) { + + vMinDate = pList[i].getStart(); + + vMinSet = 1; + + } + + + + if( vMaxSet==0 || pList[i].getEnd() > vMaxDate) { + + vMaxDate = pList[i].getEnd(); + + vMaxSet = 1; + + } + + + + vCompSum += pList[i].getCompVal(); + + + + } + + + + } + + + + if(pRow >= 0) { + + pList[pRow].setStart(vMinDate); + + pList[pRow].setEnd(vMaxDate); + + pList[pRow].setNumKid(vNumKid); + + pList[pRow].setCompVal(Math.ceil(vCompSum/vNumKid)); + + } + + + + } + + + + + + + + // Used to determine the minimum date of all tasks and set lower bound based on format + +JSGantt.getMinDate = function getMinDate(pList, pFormat) + + { + + var vDate = new Date(); + + vDate.setFullYear(pList[0].getStart().getFullYear(), pList[0].getStart().getMonth(), pList[0].getStart().getDate()); + + + + // Parse all Task End dates to find min + + for(i = 0; i < pList.length; i++) + + { + + if(Date.parse(pList[i].getStart()) < Date.parse(vDate)) + + vDate.setFullYear(pList[i].getStart().getFullYear(), pList[i].getStart().getMonth(), pList[i].getStart().getDate()); + + } + + + + + + // Adjust min date to specific format boundaries (first of week or first of month) + + if (pFormat=='day') + + { + + vDate.setDate(vDate.getDate() - 1); + + while(vDate.getDay() % 7 > 0) + + { + + vDate.setDate(vDate.getDate() - 1); + + } + + } + + + + if (pFormat=='week') + + { + + vDate.setDate(vDate.getDate() - 7); + + while(vDate.getDay() % 7 > 0) + + { + + vDate.setDate(vDate.getDate() - 1); + + } + + } + + + + if (pFormat=='month') + + { + + while(vDate.getDate() > 1) + + { + + vDate.setDate(vDate.getDate() - 1); + + } + + } + + + + return(vDate); + + } + + + + + + + + // Used to determine the minimum date of all tasks and set lower bound based on format + +JSGantt.getMaxDate= function (pList, pFormat) + + { + + var vDate = new Date(); + + vDate.setFullYear(pList[0].getEnd().getFullYear(), pList[0].getEnd().getMonth(), pList[0].getEnd().getDate()); + + + + // Parse all Task End dates to find max + + for(i = 0; i < pList.length; i++) + + { + + if(Date.parse(pList[i].getEnd()) > Date.parse(vDate)) + + vDate.setFullYear(pList[i].getEnd().getFullYear(), pList[i].getEnd().getMonth(), pList[i].getEnd().getDate()); + + } + + + + // Adjust max date to specific format boundaries (end of week or end of month) + + if (pFormat=='day') + + { + + vDate.setDate(vDate.getDate() + 1); + + while(vDate.getDay() % 6 > 0) + + { + + vDate.setDate(vDate.getDate() + 1); + + } + + } + + + + if (pFormat=='week') + + { + + //For weeks, what is the last logical boundary? + + vDate.setDate(vDate.getDate() + 11); + + while(vDate.getDay() % 6 > 0) + + { + + vDate.setDate(vDate.getDate() + 1); + + } + + } + + + + // Set to last day of current Month + + if (pFormat=='month') + + { + + while(vDate.getDay() > 1) + + { + + vDate.setDate(vDate.getDate() + 1); + + } + + vDate.setDate(vDate.getDate() - 1); + + } + + + + return(vDate); + + } + + + + + + + + // This function finds the document id of the specified object + +JSGantt.findObj = function (theObj, theDoc) + + { + + var p, i, foundObj; + + if(!theDoc) theDoc = document; + + if( (p = theObj.indexOf("?")) > 0 && parent.frames.length){ + + theDoc = parent.frames[theObj.substring(p+1)].document; + + theObj = theObj.substring(0,p); + + } + + if(!(foundObj = theDoc[theObj]) && theDoc.all) + + foundObj = theDoc.all[theObj]; + + + + for (i=0; !foundObj && i < theDoc.forms.length; i++) + + foundObj = theDoc.forms[i][theObj]; + + + + for(i=0; !foundObj && theDoc.layers && i < theDoc.layers.length; i++) + + foundObj = JSGantt.findObj(theObj,theDoc.layers[i].document); + + + + if(!foundObj && document.getElementById) + + foundObj = document.getElementById(theObj); + + + + return foundObj; + + } + + + + + +JSGantt.changeFormat = function(pFormat,ganttObj) { + + + + if(ganttObj) + + { + + ganttObj.setFormat(pFormat); + + ganttObj.DrawDependencies(); + + } + + else + + alert('Chart undefined'); + + + + } + + + + + + // Function to open/close and hide/show children of specified task + + JSGantt.folder= function (pID,ganttObj) { + + + var vList = ganttObj.getList(); + + for(i = 0; i < vList.length; i++) + + { + + if(vList[i].getID() == pID) { + + if( vList[i].getOpen() == 1 ) { + + vList[i].setOpen(0); + + JSGantt.hide(pID,ganttObj); + + if (JSGantt.isIE()) + JSGantt.findObj('group_'+pID).innerText = '+'; + else + JSGantt.findObj('group_'+pID).textContent = '+'; + + } else { + + vList[i].setOpen(1); + + JSGantt.show(pID, 1, ganttObj); + + if (JSGantt.isIE()) + JSGantt.findObj('group_'+pID).innerText = ''; + else + JSGantt.findObj('group_'+pID).textContent = ''; + + } + + } + + } + + } + + + + + + JSGantt.hide= function (pID,ganttObj) { + + var vList = ganttObj.getList(); + + var vID = 0; + + for(var i = 0; i < vList.length; i++) + + { + + if(vList[i].getParent() == pID) { + + vID = vList[i].getID(); + + JSGantt.findObj('child_' + vID).style.display = "none"; + + JSGantt.findObj('childgrid_' + vID).style.display = "none"; + + vList[i].setVisible(0); + + if(vList[i].getGroup() == 1) + + JSGantt.hide(vID,ganttObj); + + } + + } + + } + + + + + + // Function to show children of specified task + + JSGantt.show = function (pID, pTop, ganttObj) { + + var vList = ganttObj.getList(); + + var vID = 0; + + for(var i = 0; i < vList.length; i++) + + { + + if(vList[i].getParent() == pID) { + + vID = vList[i].getID(); + + if(pTop == 1) { + + if (JSGantt.isIE()) { // IE; + + + + if( JSGantt.findObj('group_'+pID).innerText == '+') { + + JSGantt.findObj('child_'+vID).style.display = ""; + + JSGantt.findObj('childgrid_'+vID).style.display = ""; + + vList[i].setVisible(1); + + } + + + + } else { + + + + if( JSGantt.findObj('group_'+pID).textContent == '+') { + + JSGantt.findObj('child_'+vID).style.display = ""; + + JSGantt.findObj('childgrid_'+vID).style.display = ""; + + vList[i].setVisible(1); + + } + + } + + } else { + + if (JSGantt.isIE()) { // IE; + + + + if( JSGantt.findObj('group_'+pID).innerText == '') { + + JSGantt.findObj('child_'+vID).style.display = ""; + + JSGantt.findObj('childgrid_'+vID).style.display = ""; + + vList[i].setVisible(1); + + } + + + + } else { + + + + if( JSGantt.findObj('group_'+pID).textContent == '') { + + JSGantt.findObj('child_'+vID).style.display = ""; + + JSGantt.findObj('childgrid_'+vID).style.display = ""; + + vList[i].setVisible(1); + + } + + } + + } + + + if(vList[i].getGroup() == 1) + + JSGantt.show(vID, 0,ganttObj); + + + + } + + } + + } + + + + + + // function to open window to display task link + +JSGantt.taskLink = function(pRef,pWidth,pHeight) + + { + + if(pWidth) vWidth =pWidth; else vWidth =400; + if(pHeight) vHeight=pHeight; else vHeight=400; + + var OpenWindow=window.open(pRef, "newwin", "height="+vHeight+",width="+vWidth); + + } + + +JSGantt.parseXML = function(ThisFile,pGanttVar){ + var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; // Is this Chrome + + try { //Internet Explorer + xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); + } + catch(e) { + try { //Firefox, Mozilla, Opera, Chrome etc. + if (is_chrome==false) { xmlDoc=document.implementation.createDocument("","",null); } + } + catch(e) { + alert(e.message); + return; + } + } + + if (is_chrome==false) { // can't use xmlDoc.load in chrome at the moment + xmlDoc.async=false; + xmlDoc.load(ThisFile); // we can use loadxml + JSGantt.AddXMLTask(pGanttVar) + xmlDoc=null; // a little tidying + Task = null; + } + else { + JSGantt.ChromeLoadXML(ThisFile,pGanttVar); + ta=null; // a little tidying + } +} + +JSGantt.AddXMLTask = function(pGanttVar){ + + Task=xmlDoc.getElementsByTagName("task"); + + var n = xmlDoc.documentElement.childNodes.length; // the number of tasks. IE gets this right, but mozilla add extra ones (Whitespace) + + for(var i=0;i<n;i++) { + + // optional parameters may not have an entry (Whitespace from mozilla also returns an error ) + // Task ID must NOT be zero other wise it will be skipped + try { pID = Task[i].getElementsByTagName("pID")[0].childNodes[0].nodeValue; + } catch (error) {pID =0;} + pID *= 1; // make sure that these are numbers rather than strings in order to make jsgantt.js behave as expected. + + if(pID!=0){ + try { pName = Task[i].getElementsByTagName("pName")[0].childNodes[0].nodeValue; + } catch (error) {pName ="No Task Name";} // If there is no corresponding entry in the XML file the set a default. + + try { pColor = Task[i].getElementsByTagName("pColor")[0].childNodes[0].nodeValue; + } catch (error) {pColor ="0000ff";} + + try { pParent = Task[i].getElementsByTagName("pParent")[0].childNodes[0].nodeValue; + } catch (error) {pParent =0;} + pParent *= 1; + + try { pStart = Task[i].getElementsByTagName("pStart")[0].childNodes[0].nodeValue; + } catch (error) {pStart ="";} + + try { pEnd = Task[i].getElementsByTagName("pEnd")[0].childNodes[0].nodeValue; + } catch (error) { pEnd ="";} + + try { pLink = Task[i].getElementsByTagName("pLink")[0].childNodes[0].nodeValue; + } catch (error) { pLink ="";} + + try { pMile = Task[i].getElementsByTagName("pMile")[0].childNodes[0].nodeValue; + } catch (error) { pMile=0;} + pMile *= 1; + + try { pRes = Task[i].getElementsByTagName("pRes")[0].childNodes[0].nodeValue; + } catch (error) { pRes ="";} + + try { pComp = Task[i].getElementsByTagName("pComp")[0].childNodes[0].nodeValue; + } catch (error) {pComp =0;} + pComp *= 1; + + try { pGroup = Task[i].getElementsByTagName("pGroup")[0].childNodes[0].nodeValue; + } catch (error) {pGroup =0;} + pGroup *= 1; + + try { pOpen = Task[i].getElementsByTagName("pOpen")[0].childNodes[0].nodeValue; + } catch (error) { pOpen =1;} + pOpen *= 1; + + try { pDepend = Task[i].getElementsByTagName("pDepend")[0].childNodes[0].nodeValue; + } catch (error) { pDepend =0;} + pDepend *= 1; + if (pDepend==0){pDepend='x'} // need this to draw the dependency lines + + // Finally add the task + pGanttVar.AddTaskItem(new JSGantt.TaskItem(pID , pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend)); + } + } +} + +JSGantt.ChromeLoadXML = function(ThisFile,pGanttVar){ +// Thanks to vodobas at mindlence,com for the initial pointers here. + XMLLoader = new XMLHttpRequest(); + XMLLoader.onreadystatechange= function(){ + JSGantt.ChromeXMLParse(pGanttVar); + }; + XMLLoader.open("GET", ThisFile, false); + XMLLoader.send(null); +} + +JSGantt.ChromeXMLParse = function (pGanttVar){ +// Manually parse the file as it is loads quicker + if (XMLLoader.readyState == 4) { + var ta=XMLLoader.responseText.split(/<task>/gi); + + var n = ta.length; // the number of tasks. + for(var i=1;i<n;i++) { + Task = ta[i].replace(/<[/]p/g, '<p'); + var te = Task.split(/<pid>/i) + + if(te.length> 2){var pID=te[1];} else {var pID = 0;} + pID *= 1; + + var te = Task.split(/<pName>/i) + if(te.length> 2){var pName=te[1];} else {var pName = "No Task Name";} + + var te = Task.split(/<pstart>/i) + if(te.length> 2){var pStart=te[1];} else {var pStart = "";} + + var te = Task.split(/<pEnd>/i) + if(te.length> 2){var pEnd=te[1];} else {var pEnd = "";} + + var te = Task.split(/<pColor>/i) + if(te.length> 2){var pColor=te[1];} else {var pColor = '0000ff';} + + var te = Task.split(/<pLink>/i) + if(te.length> 2){var pLink=te[1];} else {var pLink = "";} + + var te = Task.split(/<pMile>/i) + if(te.length> 2){var pMile=te[1];} else {var pMile = 0;} + pMile *= 1; + + var te = Task.split(/<pRes>/i) + if(te.length> 2){var pRes=te[1];} else {var pRes = "";} + + var te = Task.split(/<pComp>/i) + if(te.length> 2){var pComp=te[1];} else {var pComp = 0;} + pComp *= 1; + + var te = Task.split(/<pGroup>/i) + if(te.length> 2){var pGroup=te[1];} else {var pGroup = 0;} + pGroup *= 1; + + var te = Task.split(/<pParent>/i) + if(te.length> 2){var pParent=te[1];} else {var pParent = 0;} + pParent *= 1; + + var te = Task.split(/<pOpen>/i) + if(te.length> 2){var pOpen=te[1];} else {var pOpen = 1;} + pOpen *= 1; + + var te = Task.split(/<pDepend>/i) + if(te.length> 2){var pDepend=te[1];} else {var pDepend = "x";} + pDepend *= 1; + if (pDepend==0){pDepend='x'} // need this to draw the dependency lines + + + // Finally add the task + pGanttVar.AddTaskItem(new JSGantt.TaskItem(pID , pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend)); + } + } +} Propchange: ofbiz/trunk/framework/images/webapp/images/jsgantt.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/images/webapp/images/jsgantt.js ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/images/webapp/images/jsgantt.js ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/WEB-INF/actions/GanttChart.groovy URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/WEB-INF/actions/GanttChart.groovy?rev=703969&r1=703968&r2=703969&view=diff ============================================================================== --- ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/WEB-INF/actions/GanttChart.groovy (original) +++ ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/WEB-INF/actions/GanttChart.groovy Mon Oct 13 01:47:05 2008 @@ -44,8 +44,11 @@ result = dispatcher.runSync("getProjectPhaseList", [userLogin : userLogin , projectId : projectId]); phases = result.phaseList; if (phases){ + phaseNr = 1; + taskNr = 10000; phases.each { phase -> newPhase = phase; + newPhase.phaseNr = phaseNr; if (!newPhase.estimatedStartDate && newPhase.actualStartDate) { newPhase.estimatedStartDate = newPhase.actualStartDate; } @@ -59,17 +62,14 @@ newPhase.estimatedCompletionDate = UtilDateTime.addDaysToTimestamp(newPhase.estimatedStartDate, 3); } newPhase.workEffortTypeId = "PHASE"; - Debug.log("===start: " + newPhase.estimatedStartDate + "===end: " + newPhase.estimatedCompletionDate); ganttList.add(newPhase); - Debug.log("=======" + phase.phaseName + "======" + phase.workEffortTypeId + " phaseId" + phase.phaseId); tasks = delegator.findByAnd("WorkEffort", ["workEffortParentId" : phase.phaseId]); if (tasks){ tasks.each { task -> - Debug.log("===name====" + task.workEffortName + "===type===" + task.workEffortTypeId + "===id===" + task.workEffortId); resultTaskInfo = dispatcher.runSync("getProjectTask", [userLogin : userLogin , taskId : task.workEffortId]); - Debug.log("===restaskinfo " + resultTaskInfo); taskInfo = resultTaskInfo.taskInfo; - Debug.log("===taskinfo " + taskInfo); + taskInfo.taskNr = taskNr++; + taskInfo.phaseNr = phaseNr; if (!taskInfo.estimatedStartDate && taskInfo.actualStartDate) { taskInfo.estimatedStartDate = taskInfo.actualStartDate; } @@ -81,11 +81,14 @@ } if (!taskInfo.estimatedCompletionDate) { taskInfo.estimatedCompletionDate = UtilDateTime.addDaysToTimestamp(newPhase.estimatedStartDate, 3); - } + } + taskInfo.estimatedStartDate = UtilDateTime.toDateString(taskInfo.estimatedStartDate, "MM/dd/yyyy"); + taskInfo.estimatedCompletionDate = UtilDateTime.toDateString(taskInfo.estimatedCompletionDate, "MM/dd/yyyy"); taskInfo.workEffortTypeId = "TASK"; ganttList.add(taskInfo); } } + phaseNr++; } } context.phaseTaskList = ganttList; Modified: ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/project/gantChart.ftl URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/project/gantChart.ftl?rev=703969&r1=703968&r2=703969&view=diff ============================================================================== --- ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/project/gantChart.ftl (original) +++ ofbiz/trunk/specialpurpose/projectmgr/webapp/projectmgr/project/gantChart.ftl Mon Oct 13 01:47:05 2008 @@ -1,107 +1,60 @@ -<div align="center"> -<table border="0" cellspacing="0" width="882px;"> - <tr> - <td style="width: 150px; vertical-align: bottom;" align="center"><h2>Name</h2></td> - <td style="width: 732px; vertical-align: bottom;" colspan="12" align="center"><h2>Time Line</h2></td> - </tr> - <tr> - <td style="width: 150px; vertical-align: bottom;"> </td> - <td style="width: 61px;" align="center" bgcolor="#D3D3D3">January</td> - <td style="width: 61px;" align="center" bgcolor="#BEBEBE">February</td> - <td style="width: 61px;" align="center" bgcolor="#D3D3D3">March</td> - <td style="width: 61px;" align="center" bgcolor="#BEBEBE">April</td> - <td style="width: 61px;" align="center" bgcolor="#D3D3D3">May</td> - <td style="width: 61px;" align="center" bgcolor="#BEBEBE">June</td> - <td style="width: 61px;" align="center" bgcolor="#D3D3D3">July</td> - <td style="width: 61px;" align="center" bgcolor="#BEBEBE">August</td> - <td style="width: 61px;" align="center" bgcolor="#D3D3D3">September</td> - <td style="width: 61px;" align="center" bgcolor="#BEBEBE">October</td> - <td style="width: 61px;" align="center" bgcolor="#D3D3D3">November</td> - <td style="width: 61px;" align="center" bgcolor="#BEBEBE">December</td> - </tr> -<#assign phasesummary2 = 0/> -<#assign summary2 = 0/> -<#assign day = 24 * 60 * 60 * 1000/> -<#if phaseTaskList?has_content> -<#list phaseTaskList as phases> -<#if phases.workEffortTypeId == "PHASE"> - <#assign phaseId = phases.phaseId/> - <#assign phasesStart = Static["org.ofbiz.base.util.UtilDateTime"].toCalendar(phases.estimatedStartDate)/> - <#assign phasesEnd = Static["org.ofbiz.base.util.UtilDateTime"].toCalendar(phases.estimatedCompletionDate)/> - <#assign t1 = phasesStart.getTime().getTime()/> - <#assign t2 = phasesEnd.getTime().getTime()/> - <#assign phasesMonth = phases.estimatedStartDate?substring(5,7)?number/> - <#assign phasesDay = phases.estimatedStartDate?substring(8,10)?number/> - <#assign phasespacer = ((phasesMonth-1)*60.8)+(phasesDay*2)/> - <#assign phasesummary = ((t2-t1)/day)*2/> - <#if (732<(phasespacer+phasesummary))> - <#assign phasesummary1 = 732-phasespacer/> - <#assign phasesummary2 = phasesummary-phasesummary1/> - <#assign phasesummary = phasesummary1/> - </#if> - <#assign lastSpacer = 732 - (phasespacer + phasesummary)/> - - <tr> - <td style="width: 150px; vertical-align: bottom;"> - ${phases.phaseName?if_exists} - </td> - <td colspan="12"> - <img src="/images/spacer.gif" height="15px;" width="${phasespacer}px;"><img src="/images/busy.gif" height="15px;" width="${phasesummary}px;"><img src="/images/spacer.gif" height="15px;" width="${lastSpacer}px;"> - </td> - </tr> - <#if (phasesummary2 != 0)> - <tr> - <td style="width: 150px; vertical-align: bottom;"> - - </td> - <td colspan="12"> - <img src="/images/busy.gif" height="15px;" width="${phasesummary2}px;"> - </td> - </tr> - </#if> -</#if> -<#if phases.workEffortTypeId == "TASK"> - <#assign tasks = phases/> - <#assign phasesId = tasks.workEffortParentId/> - <#assign taskId = tasks.taskId/> - <#assign taskStart = Static["org.ofbiz.base.util.UtilDateTime"].toCalendar(tasks.estimatedStartDate?if_exists)/> - <#assign taskEnd = Static["org.ofbiz.base.util.UtilDateTime"].toCalendar(tasks.estimatedCompletionDate?if_exists)/> - <#assign t3 = taskStart.getTime().getTime()/> - <#assign t4 = taskEnd.getTime().getTime()/> - <#assign startMonth = tasks.estimatedStartDate?substring(5,7)?number/> - <#assign startDay = tasks.estimatedStartDate?substring(8,10)?number/> - <#assign spacer = ((startMonth-1)*60.8)+(startDay*2)/> - <#if phasesId==phaseId> - <#assign summary = ((t4-t3)/day)*2/> - <#if (732<(spacer+summary))> - <#assign summary1 = 732-spacer/> - <#assign summary2 = summary-summary1/> - <#assign summary = summary1/> - </#if> - <#assign spacer2 = 732 - (spacer + summary)/> - <tr> - <td style="width: 150px; vertical-align: bottom;" > - <a href="/projectmgr/control/taskView?workEffortId=${tasks.taskId}">${tasks.taskName?if_exists}</a> - </td> - <td colspan="12"> - <img src="/images/spacer.gif" height="15px;" width="${spacer}px;"><img src="/images/bluebar.gif" height="15px;" width="${summary}px;"><img src="/images/spacer.gif" height="15px;" width="${spacer2}px;"> - </td> - </tr> - <#if (summary2 != 0)> - <tr> - <td style="width: 150px; vertical-align: bottom;" > - - </td> - <td colspan="12"> - <img src="/images/bluebar.gif" height="15px;" width="${summary2}px;"> - </td> - </tr> - </#if> - </#if> -</#if> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<#-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<div style="position:relative" class="gantt" id="GanttChartDIV"></div> +<script language="javascript"> +var g = new JSGantt.GanttChart('g',document.getElementById('GanttChartDIV'), 'day'); + +g.setShowRes(0); // Show/Hide Responsible (0/1) +g.setShowDur(1); // Show/Hide Duration (0/1) +g.setShowComp(0); // Show/Hide % Complete(0/1) + +// Parameters (pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen) + +<#list phaseTaskList as t> + <#if t.workEffortTypeId == "PHASE"> + g.AddTaskItem(new JSGantt.TaskItem(${t.phaseNr}, '${t.phaseName}', '', '', '#00ff00', ' ', 0, ' ', 0, 1, 0, 1)); + </#if> + <#if t.workEffortTypeId == "TASK"> + g.AddTaskItem(new JSGantt.TaskItem(${t.taskNr},'${t.taskName}','${t.estimatedStartDate}', '${t.estimatedCompletionDate}','#009900', ' ', 0, ' ', 0, 0, ${t.phaseNr}, 1)); + </#if> </#list> -</#if> -</table> -</div><br> -<img src="/images/busy.gif" height="15px;" width="30px;"><b> : Phase</b><br> -<img src="/images/bluebar.gif" height="15px;" width="30px;"><b> : Task</b> +<#-- + +TaskItem(pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend) +pID: (required) is a unique ID used to identify each row for parent functions and for setting dom id for hiding/showing +pName: (required) is the task Label +pStart: (required) the task start date, can enter empty date ('') for groups +pEnd: (required) the task end date, can enter empty date ('') for groups +pColor: (required) the html color for this task; e.g. '00ff00' +pLink: (optional) any http link navigated to when task bar is clicked. +pMile:(optional) represent a milestone +pRes: (optional) resource name +pComp: (required) completion percent +pGroup: (optional) indicates whether this is a group(parent) - 0=NOT Parent; 1=IS Parent +pParent: (required) identifies a parent pID, this causes this task to be a child of identified task +pOpen: UNUSED - in future can be initially set to close folder when chart is first drawn + +--> +g.Draw(); +g.DrawDependencies(); +</script> + + \ No newline at end of file Modified: ofbiz/trunk/specialpurpose/projectmgr/widget/ProjectScreens.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/projectmgr/widget/ProjectScreens.xml?rev=703969&r1=703968&r2=703969&view=diff ============================================================================== --- ofbiz/trunk/specialpurpose/projectmgr/widget/ProjectScreens.xml (original) +++ ofbiz/trunk/specialpurpose/projectmgr/widget/ProjectScreens.xml Mon Oct 13 01:47:05 2008 @@ -501,6 +501,8 @@ <actions> <set field="titleProperty" value="ProjectMgrGanttChart"/> <set field="tabButtonItem" value="ganttchart"/> + <set field="layoutSettings.javaScripts[]" value="/images/jsgantt.js" global="true"/> + <set field="layoutSettings.styleSheets[]" value="/images/jsgantt.css" global="true"/> <script location="component://projectmgr/webapp/projectmgr/WEB-INF/actions/GanttChart.groovy"/> </actions> <widgets> |
Free forum by Nabble | Edit this page |