#ProjectManagerTMPL0002
<script type="text/javascript">
	var JScolresize= "1";
	var JScolmove= "1";
	var JScolhide= "1";
	var filtered = 0;
	var sortable = new Array (0,0,0,0,0,0);
	var filterable = new Array (0,0,0,0,0,0);

	function init(tableName) {
		sortableInit(tableName);
	}
</script>

<script type="text/javascript">
//<![CDATA[
	var dayMS = 86400000;

	var popTitle = "Add/Edit Task";

	var dunits = "<tmpl_var project.durationUnits>";
	var hoursPerDay = <tmpl_var project.hoursPerDay>;
	var taskLength=<tmpl_var project.task.length>;

	//---------------------------------------------------------------------
	function doCalendar (fieldId) {
		Calendar.setup({
			inputField : fieldId,
			ifFormat : "%Y-%m-%d",
			showsTime : false,
			step : 1,
			timeFormat : "12",
			firstDay : false
		});
	}

	//---------------------------------------------------------------------
	function buildMenuUrl (urltype,taskId) {
		if(urltype == "edit") {
			alert("edit task: "+taskId);
		} else if(urltype == "insertAbove") {
			alert("insert task above: "+taskId);
		} else if(urltype == "insertBelow") {
			alert("insert task below: "+taskId);
		} else if(urltype == "delete") {
			alert("delete task: "+taskId);
		}
	}

	//---------------------------------------------------------------------
	function closeImage() {
		return '<tmpl_var extras>/close.gif';
	}

	//---------------------------------------------------------------------
	function configureMilestone(box) {
		var form = box.form;
		if (box.checked==true) {
			form.end.value=form.start.value;
			form.duration.value=0;
			form.duration.disabled=true;
			form.end.disabled=true;
			form.dependants.disabled=true;
			form.resource.disabled=true;
			form.percentComplete.disabled=true;
			form.percentComplete.value=0;
		} else {
			form.end.disabled=false;
			form.duration.disabled=false;
			form.dependants.disabled=false;
			form.resource.disabled=false;
			form.percentComplete.disabled=false;
			form.duration.value = (dunits == "hrs")?hoursPerDay:1;
		}
	}

	//---------------------------------------------------------------------
	function checkEditTaskForm (form) {
		if (form.name.value == "") {
			alert("<tmpl_var form.name.error>");
			return;
		} else if(form.start.value == "") {
			alert("<tmpl_var form.start.error>");
			return;
		} else if(form.milestone.checked==false && form.end.value == "") {
			alert("<tmpl_var form.end.error>");
			return;
		}
		form.submit();
	}

	//---------------------------------------------------------------------
	function intlDate(dateObj) {
		return dateObj.getFullYear()+"-"+pad((dateObj.getMonth()+1))+"-"+pad(dateObj.getDate());
	}

	//---------------------------------------------------------------------
	function toDateObj(date) {
		var to = date.split("-");
		var dateObj = new Date(to[0],(to[1]-1),to[2],0,0,1,0);
		return dateObj;
	}

	//---------------------------------------------------------------------
	function adjustTaskTimeFromDuration(start, end, duration, isTaskForm, predecessor, origStart, origEnd, seqNum) {
		//set the form element
		var form = duration.form;

		//get today's date
		var today = new Date();
		var todayIntl = intlDate(today);
		//set start and end date if not already set
		if (start.value == "") start.value = todayIntl;
		if (end.value == "") end.value = todayIntl;

		//Convert predecessor hours to days
		var taskDuration = duration.value;
		if (dunits == "hrs") taskDuration = taskDuration / hoursPerDay;
		var durationFloor = Math.floor(taskDuration);

		//Handle task form and main form seperately due to differences in the forms
		if (isTaskForm && taskDuration <= 0) {
			//Convert to milestone if task is less or equal to zero
			if (confirm("Zero duration tasks are considered Milestones.  Do you wish to change this task to a milestone?")) {
				form.milestone.checked = true;
				configureMilestone(form.milestone);
			} else {
				duration.value = form.orig_duration.value;
			}
			return;
		} else if (taskDuration <= 0) {
			//Do not let users zero out tasks
			alert("Zero duration tasks are considered Milestones.  Please edit the task by clicking the link if you wish to change this task to a milestone");
			return;
		}

		//create the start date
		var aTo = start.value.split("-");
		var toDate = new Date(aTo[0],(aTo[1]-1),aTo[2],0,0,1,0);

		//add new duration days to the start date
		toDate.setDate(toDate.getDate() + durationFloor);

		//set end date to this date
		end.value = intlDate(toDate);

		//Set new duration in taskArray
		taskArray[seqNum]["duration"] = duration.value;
		//Adjust time based on new end date
		adjustTaskTimeFromDate(start, end, duration, end, isTaskForm, predecessor, origStart, origEnd, seqNum);
	}

	//---------------------------------------------------------------------
	function adjustTaskTimeFromDate (start, end, duration, element, isTaskForm, predecessor, origStart, origEnd, seqNum) {
		//set the form element
		var form = element.form;
		//set original duration from task form to determine whether or not to continue to set duration
		var orig_duration;

		if (isTaskForm) {
			if (form.milestone.checked == true) return;
			orig_duration = form.orig_duration.value;
		}

		//Handle case where both start and end are empty
		if (start.value == "" && end.value == "") {
			//get today's date
			var today = new Date();
			var todayIntl = intlDate(today);
			//set start and end date if not already set
			start.value = todayIntl;
			end.value = todayIntl;
		}

		//Handle case where one is set and the other isn't
		if (end.value == "") end.value = start.value;
		if (start.value == "") start.value = end.value;

		if (isTaskForm && orig_duration == "") {
			//Set duration if this is a new record
			//Check to make sure start date comes before end date
			var startcomp = start.value.replace(/-/g,"");
			var endcomp = end.value.replace(/-/g,"");
			if (startcomp > endcomp) {
				alert("<tmpl_var form.greaterthan.error>");
				if (element.name == "start") {
					end.value = element.value;
				} else {
					start.value = element.value;
				}
				duration.value = (dunits == "hrs")?hoursPerDay:1;
				return;
			}

			var d = getDaysInterval(start.value,end.value);
			if (d == 0) d = 1;
			if (dunits == "hrs") {
				d = d * hoursPerDay;
			}
			duration.value = d;
		} else {
			//Set start/end if duration has been saved
			var d = duration.value;
			if (dunits == "hrs") {
				//Convert to days
				d = d / hoursPerDay;
			}
			//Round off duration or set it to zero if less than 1;
			//alert("d = " + d + " floor = " + Math.floor(d));
			if (d < 1) d = 0;
			else d = Math.floor(d);

			if (element.name.indexOf("start") > -1) {
				//create the date
				var aTo = start.value.split("-");
				var toDate = new Date(aTo[0],(aTo[1]-1),aTo[2],0,0,1,0);
				//add duration days to the start date
				toDate.setDate(toDate.getDate() + d);
				//set end date to this date
				end.value = intlDate(toDate);
			} else if(element.name.indexOf("end") > -1) {
				//create the date
				var aFrom = end.value.split("-");
				var fromDate = new Date(aFrom[0],(aFrom[1]-1),aFrom[2],0,0,1,0);
				//subtract duration days from the end date
				fromDate.setDate(fromDate.getDate() - d);
				//set start date to this date
				start.value = intlDate(fromDate);
			}
		}

		//Check Predecessors before moving stuff
		var pred = predecessor.value;
		if(pred != "") {
			//Check to make sure that the dependency requirement for this task is still valid
			//Get the predecessor end date
			var taskStart = toDateObj(start.value);
			var predTaskEnd;
			if (isTaskForm) {
				predTaskEnd = toDateObj(taskArray[pred]["end"]);
			} else {
				var predTaskEndId = "end_"+taskArray[pred]["id"]+"_formId"
				predTaskEnd = toDateObj(document.getElementById(predTaskEndId).value);
			}

			if (taskStart.getTime() < predTaskEnd.getTime()) {
				alert("<tmpl_var form.invalidMove.error>");
				start.value = origStart.value;
				end.value = origEnd.value;
				return;
			}
		}

		//Check all tasks past this one and move them forward if necessary (this only needs to happen on the main form)
		if (!isTaskForm) {
			arrangePredecessors(element,seqNum);
		}
		//reset orig start and end values
		origStart.value = start.value;
		origEnd.value = end.value;

		if (!isTaskForm) {
			//Adjust task form for
			paintGanttChart();
		}
	}

	//---------------------------------------------------------------------
	function trim(str) {
		return str.replace(/^\s+|\s+$/, '');
	}

	//---------------------------------------------------------------------
	function arrangePredecessors (element,seqNum) {
		for (var i = 1; i <= taskLength; i++) {
			var seq = i;
			var task = taskArray[seq];
			var taskId = task["id"];
			//Calculate duration and duraiton floor
			var durationInDays = parseFloat(task["duration"]);
			if (dunits == "hrs") durationInDays = durationInDays / hoursPerDay;
			var durationFloor = Math.floor(durationInDays);
			//alert("Duration Floor is: "+durationFloor);
			//Get the current elements
			var currElementStart = document.getElementById("start_"+taskId+"_formId");
			var currElementEnd = document.getElementById("end_"+taskId+"_formId");
			//alert("Current Start Date: "+currElementStart.value+"   Current End Date: "+currElementEnd.value);
			//Skip the first record as it is the record that was changed
			if (seq > 1) {
				var predecessor = task["predecessor"];
				//alert("predecessor for "+i+" is "+predecessor);
				if (predecessor != "") {
					var pred = taskArray[predecessor];
					var predEndDate = toDateObj(pred["end"]);
					var startDate = toDateObj(task["start"]);
					//alert ("Pred End Date: "+intlDate(predEndDate));
					//Make sure start date of this task is greater than the end date of the predecessor
					if (startDate.getTime() <= predEndDate.getTime()) {
						//Change the start and end dates of the task
						//Get the day part of the predecessor
						var predDayPart = parseFloat(pred["dayPart"]);
						//alert("predDayPart: "+predDayPart);
						if (predDayPart > 0) {
							//The previous task took up part of a day.  Add the additional day part to the duration
							durationInDays += predDayPart;
							durationFloor = Math.floor(durationInDays);
						}
						//alert("Duration in Days: "+durationInDays+" Duration Floor: "+durationFloor);
						//Set the start date of this task to the end date of the predecessor
						currElementStart.value = pred["end"];
						//Adjust end date for change in start date and update the object - start date is actually predEndDate now, so use the existing date object
						predEndDate.setDate(predEndDate.getDate() + durationFloor);
						currElementEnd.value = intlDate(predEndDate);
						//alert("Set seq "+i+" to start: "+pred["end"]+" end: "+intlDate(predEndDate));
					}
				}
			}

			//Update task array with new start/end values
			taskArray[seq]["start"] = currElementStart.value;
			taskArray[seq]["end"] = currElementEnd.value;
			taskArray[seq]["dayPart"] = (durationInDays - Math.floor(durationInDays));
		}
	}

	//---------------------------------------------------------------------
	function getDaysInterval(from,to) {
		var aFrom = from.split("-");
		var aTo = to.split("-");
		var fromDate = new Date(aFrom[0],(aFrom[1]-1),aFrom[2],0,0,1,0);
		var toDate = new Date(aTo[0],(aTo[1]-1),aTo[2],0,0,1,0);
		var fromEpoch = fromDate.getTime();
		var toEpoch = toDate.getTime();

		var seconds = toEpoch - fromEpoch;
		if (seconds == 0) return 0;
		return (seconds/dayMS);
	}

	//---------------------------------------------------------------------
	function pad(date) {
		var str = ""+date;
		if (str.length == 1) {
			str = "0"+str;
		}
		return str;
	}

	//---------------------------------------------------------------------
	function paintGanttChart () {
		var status = AjaxRequest.submit(document.forms['editAll'],{
                                      'onSuccess':function(req){ document.getElementById('gantt').innerHTML = req.responseText; }
                                     });

		var mwidth = document.getElementById("projectTableWidth").name + "px";
		var swidth = document.getElementById("projectScrollPercentWidth").name + "%";
		document.getElementById("mastertable").style.width=mwidth;
		document.getElementById("scrolltd").style.width=swidth;
	}

	//---------------------------------------------------------------------
	function validateDependant(field,origField,seqNum,start,end,duration,isTaskForm,origStart,origEnd) {
		var pred = field.value;
		var newTask = false;
		if (pred != "") {
			if (seqNum == "") seqNum = taskLength+1;
			if (pred < 1) {
				alert("<tmpl_var form.noPredecessor.error>");
				field.value=origField.value;
				return;
			}
			if (pred == seqNum) {
				alert("<tmpl_var form.samePredecessor.error>");
				field.value=origField.value;
				return;
			}
			if (pred > seqNum) {
				alert("<tmpl_var form.previousPredecessor.error>");
				field.value = origField.value;
				return;
			}

			//Set defaults if it's a new record and one of the other options hasn't been checked.
			if (start.value == "" || end.value == "") {
				//get today's date
				newTask = true;
				duration.value = (dunits == "hrs") ? hoursPerDay : 1;
			}
			//Get the predecessor end date and decide where the new start date belongs
			var taskStart = start.value;
			var taskStartObj = toDateObj(taskStart);
			var predTaskEnd = taskArray[pred]["end"];
			var predTaskEndObj = toDateObj(predTaskEnd);

			//Change start date if it comes before predecessor end date
			if (newTask || (taskStartObj.getTime() < predTaskEndObj.getTime())) {
				//Convert predecessor hours to days
				var taskDuration = duration.value;
				if(dunits == "hrs") taskDuration = taskDuration / hoursPerDay;
				var durationFloor = Math.floor(taskDuration);

				//Get the predecessor dayPart
				var predDayPart = parseFloat(pred["dayPart"]);
				if (predDayPart > 0) {
					//The previous task took up part of a day.  Add the additional day part to the duration
					taskDuration += predDayPart;
					durationFloor = Math.floor(durationInDays);
				}

				//Set the start date of this task to the end date of the predecessor
				start.value = predTaskEnd;
				//Adjust end date for change in start date
				adjustTaskTimeFromDate(start,end,duration,start,isTaskForm,field,origStart,origEnd,seqNum);
				return;
			}
		}

		//Repaint
		if(!isTaskForm) {
			//Set new predecessor in taskArray
			taskArray[seqNum]["predecessor"] = pred;
			paintGanttChart();
			}
		}

		addEvent(window, "load", initPopUp);
//]]>
</script>
<tmpl_var form.header>
<table cellpadding="0" cellspacing="0" border="0" class="project" id="mastertable" style="width:<tmpl_var project.table.width>px;">
   <tbody>
      <tr>
         <td style="width:20px;height:20px;">&nbsp;</td>
	     <td style="width:300px;" align="center">Task Name</td>
	     <td style="width:70px;" align="center">Duration</td>
	     <td style="width:70px;" align="center">Start</td>
	     <td style="width:70px;" align="center">Finish</td>
	     <td style="width:30px;" align="center">Pred</td>
	     <td rowspan="<tmpl_var project.gantt.rowspan>" valign="top" id="scrolltd" style="border-style:none;width:<tmpl_var project.scroll.percentWidth>%;">
		<div class="scroller" id="gantt">
			<tmpl_var project.ganttChart>
		</div>
	     </td>
      </tr>
      <tr>
	     <td colspan="6">&nbsp;</td>
      </tr>
      <tmpl_loop task.loop>
      <tr id="<tmpl_var task.row.id>">
	     <td align="center" style="height:20px"><tmpl_var task.number></td>
	     <td align="left" style="height:20px">
	        <tmpl_if task.canAdd>
		       <a href="<tmpl_var task.edit.url>" class="submodal"><tmpl_var task.name></a>
		    <tmpl_else>
		       <tmpl_var task.name>
		    </tmpl_if>
	     </td>
	     <td align="center" style="height:20px"><tmpl_var task.duration> <tmpl_var task.duration.units></td>
	     <td align="center" style="height:20px"><tmpl_var task.start></td>
	     <td align="center" style="height:20px"><tmpl_var task.end></td>
	     <td align="center" style="height:20px"><tmpl_var task.dependants></td>
      </tr>
      </tmpl_loop>
      <tr><td colspan="6" style="border-style:none;">&nbsp;</td></tr>
      <tr><td colspan="6" style="border-style:none;">&nbsp;</td></tr>
   </tbody>
</table>
<tmpl_var form.footer>

<div id="links">
<!-- 	<tmpl_if project.canEdit><a href="<tmpl_var task.resources.url>"><tmpl_var task.resources.label></a>&nbsp;|&nbsp;</tmpl_if> -->
	<tmpl_if task.canAdd><a href="<tmpl_var task.add.url>" class="submodal"><tmpl_var task.add.label></a>&nbsp;|&nbsp;</tmpl_if>
	<a href="<tmpl_var task.back.url>"><tmpl_var task.back.label></a>
</div>
<script type="text/javascript">
	init("mastertable");
</script>
~~~
<style type="text/css">
body, html {
	margin:0px;
	padding:0px;
}
.project {
	position:relative;
	margin-top:5px;
	margin-left:5px;
}
.project td {
	border:solid silver 1px;
	border-bottom:solid gray 1px;
	font-size:9pt;
	font-family:arial;
}
.project a {
	color:#000000;
	font-weight: normal;
	font-size: 9pt;
	text-decoration: none;
}
.project a:hover {
	color:#7AB7E9;
	font-weight: normal;
	font-size: 9pt;
	text-decoration: none;
}
.taskname {
	font-family: verdana;
	font-size: 10px;
	font-weight: normal;
	color: black;
	width: 295px;
}
.taskduration {
	font-family: verdana;
	font-size: 10px;
	font-weight: normal;
	color: black;
	width: 25px;
}
.taskdate {
	font-family: verdana;
	font-size: 10px;
	font-weight: normal;
	color: black;
	width: 68px;
}
.taskdependant {
	font-family: verdana;
	font-size: 10px;
	font-weight: normal;
	color: black;
	width: 20px;
}
tr.monthNames td {
	text-align:center;
}
tr.dates td {
	width:16px;
}
div.scroller {
	overflow:scroll;
	position:relative;
	width:400px;
}
* html div.scroller {
	overflow-x:scroll;
}
td.empty {
	background-color:transparent;
	border-style:none;
	height:20px;
}
div.barPositions {
	position:relative;
}
div.projectBar {
	background-color:#7AB7E9;
	position:absolute;
	height:10px;
	z-index:2;
	padding:0px;
	margin:0px;
	font-size:1pt;
}
div.statusBar {
	background-color:#000;
	position:absolute;
	height:5px;
	z-index:3;
	padding:0px;
	top:2px;
	margin:0px;
	font-size:1pt;
}
div.projectLineH {
	background: url('images/dot.gif') top repeat-x;
	font-size:1pt;
	text-align:right;
	position:absolute;
}
div.projectLineV {
	width:1px;
	background-color:black;
	position:relative;
	font-size:1pt;
	height:100%;
	float:right;
}
div.projectLabel {
	position:absolute;
	margin-top:-3px;
	white-space:nowrap;
	font-family: verdana;
	font-size:8px;
}
div.milestone {
	color:#000000;
	position:absolute;
	z-index:4;
	margin:0px;
	padding:0px;
	margin-top:-3px;
	font-size: 10px;
	font-family: times;
}
#links {
	margin-top:7px;
	margin-left:5px;
	font-family:arial;
	font-size:9pt;
}
#links a {
	color:#7AB7E9;
}
</style>

<style type="text/css">
.popUp {
	width:100%;
	border:solid black 0px;
	background-color:#F5F5F5;
}
.popUp td {
	font-size:9pt;
	font-family:arial;
	border-top:solid #E0E0E0 1px;
}
.popUp tr.clear td {
	border-style:none;
	background-color:#F0F0F0;
}
.popUp tr.clearNoBG td {
	border-style:none;
}
.popUp td.header {
	font-weight:bold;
}
a.saveBtn {
	width:40px;
	height:15px;
	background-color:silver;
	padding:1px;
	padding-left:5px;
	padding-right:5px;
	color:white;
	border:solid gray 1px;
	text-decoration:none;
	font-weight:bold;
	display:block;
	float:right;
	text-align:center;
}
a.saveBtn:hover {
	background-color:#F0F0F0;
	color:gray;
}
</style>
