diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 06fb0de90..c96b29f8b 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -3,7 +3,8 @@ - fix: adding Matrix listings committing the current version tag - fix: user searches in task resource additions in PM not displaying right without both last name and first name present - fix: task editor in PM not actually receiving start/end date information at first -- fix: Error Displaying Multiple TimeTracking Wobjects (ekennedy) + - fix: Error Displaying Multiple TimeTracking Wobjects (ekennedy) + - refactoring of PM JavaScript stuff 7.0.9 - Removed the need for DateTime::Cron::Simple, which also added the ability diff --git a/docs/upgrades/templates-7.0.10/default-pm-edit-task.tmpl b/docs/upgrades/templates-7.0.10/default-pm-edit-task.tmpl new file mode 100644 index 000000000..dda6384a6 --- /dev/null +++ b/docs/upgrades/templates-7.0.10/default-pm-edit-task.tmpl @@ -0,0 +1,91 @@ +#ProjectManagerTMPL0004 + + + + + + + + + + + + + + + + + + + + + + + + + + + +~~~ + + diff --git a/docs/upgrades/templates-7.0.10/default-pm-project-display.tmpl b/docs/upgrades/templates-7.0.10/default-pm-project-display.tmpl new file mode 100644 index 000000000..a6ca6c50c --- /dev/null +++ b/docs/upgrades/templates-7.0.10/default-pm-project-display.tmpl @@ -0,0 +1,275 @@ +#ProjectManagerTMPL0002 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 Task NameDurationStartFinishPred +
+ +
+
 
+ + + + + + +
 
 
+ + + + +~~~ + + + diff --git a/lib/WebGUI/Asset/Wobject/ProjectManager.pm b/lib/WebGUI/Asset/Wobject/ProjectManager.pm index 5fe69f6b2..9e43b3316 100644 --- a/lib/WebGUI/Asset/Wobject/ProjectManager.pm +++ b/lib/WebGUI/Asset/Wobject/ProjectManager.pm @@ -537,7 +537,7 @@ sub www_editProject { - + |; $f->raw($html); @@ -855,12 +855,15 @@ sub www_editTask { -value=>$form->get("insertAt") }); - my $duration = $task->{duration}; my ($startEpoch, $endEpoch) = $db->quickArray('SELECT startDate, startDate FROM PM_task WHERE projectId = ? ORDER BY sequenceNumber LIMIT 1', [$projectId]); + my $dependant = $task->{dependants}; + my $duration = $task->{duration} || ($taskType eq 'timed')? (($project->{durationUnits} eq 'hours')? $project->{hoursPerDay} : 1) : 0; + + $startEpoch = $endEpoch = time unless defined $startEpoch and defined $endEpoch; $startEpoch = $task->{startDate} if $task->{startDate}; $endEpoch = $task->{endDate} if $task->{endDate}; + $endEpoch += 86400 if $taskType eq 'timed' and !$task->{duration} and !$task->{endDate}; my ($start, $end) = ($dt->epochToSet($startEpoch), $dt->epochToSet($endEpoch)); - my $dependant = $task->{dependants}; # Set some hidden variables to make it easy to reset data in javascript $var->{'form.header'} .= WebGUI::Form::hidden($session, { @@ -884,19 +887,27 @@ sub www_editTask { -value=>$task->{taskName}, -extras=>q|style="width:95%;"| }); - + + $var->{'form.seqNum'} = WebGUI::Form::hidden($session, { + -name => "seqNum", + -value => $seq, + }); + my $durationEvents = qq|onchange="durationChanged(this.form, '', true)" onblur="if (this.value == 0) durationChanged(this.form, '', true)"|; + my $startDateEvents = qq|onfocus="doCalendar(this.id)" onblur="startDateChanged(this.form, '', true)"|; + my $endDateEvents = qq|onfocus="doCalendar(this.id)" onblur="endDateChanged(this.form, '', true)"|; + $var->{'form.duration'} = WebGUI::Form::float($session,{ -name => "duration", - -value => (($taskType ne 'milestone')? $task->{duration} : 'N/A'), - -extras => qq|style="width:70%;" onchange="adjustTaskTimeFromDuration(this.form.start,this.form.end,this,this.form.lagTime,true,this.form.dependants,this.form.orig_start,this.form.orig_end,'$seq')" onblur="if(this.value == 0){ adjustTaskTimeFromDuration(this.form.start,this.form.end,this,this.form.lagTime,true,this.form.dependants,this.form.orig_start,this.form.orig_end,'$seq') }" $disabledIfMilestone| + -value => $duration, + -extras => qq|style="width:70%;" $durationEvents $disabledIfMilestone| }); $var->{'form.duration.units'} = $self->_getDurationUnitHashAbbrev->{$project->{durationUnits}}; $var->{'form.lagTime'} = WebGUI::Form::float($session,{ -name => "lagTime", -value => (($taskType eq 'timed')? $task->{lagTime} : 'N/A'), - -extras => qq|style="width:70%;" onchange="adjustTaskTimeFromDuration(this.form.start,this.form.end,this.form.duration,this,true,this.form.dependants,this.form.orig_start,this.form.orig_end,'$seq')" onblur="if(this.value == 0){ adjustTaskTimeFromDuration(this.form.start,this.form.end,this.form.duration,this,true,this.form.dependants,this.form.orig_start,this.form.orig_end,'$seq') }" $disabledIfUntimed| + -extras => qq|style="width:70%;" $durationEvents $disabledIfUntimed| }); $var->{'form.lagTime.units'} = $self->_getDurationUnitHashAbbrev->{$project->{durationUnits}}; @@ -905,15 +916,15 @@ sub www_editTask { -value=>$start, -size=>"10", -maxlength=>"10", - -extras=>qq|onfocus="doCalendar(this.id);" onblur="if(getTaskType(this.form) == 'milestone') this.form.end.value=this.value; adjustTaskTimeFromDate(this.form.start,this.form.end,this.form.duration,this.form.lagTime,this,true,this.form.dependants,this.form.orig_start,this.form.orig_end,'$seq');" style="width:88%;"| + -extras=>qq|style="width:88%;" $startDateEvents| }); - + $var->{'form.end'} = WebGUI::Form::text($session,{ -name=>"end", -value=>$end, -size=>"10", -maxlength=>"10", - -extras=>qq|onfocus="doCalendar(this.id);" style="width:88%;" onblur="adjustTaskTimeFromDate(this.form.start,this.form.end,this.form.duration,this.form.lagTime,this,true,this.form.dependants,this.form.orig_start,this.form.orig_end,'$seq');" $disabledIfUntimed| + -extras=>qq|style="width:88%;" $endDateEvents $disabledIfUntimed| }); $var->{'form.dependants'} = WebGUI::Form::integer($session,{ @@ -921,8 +932,8 @@ sub www_editTask { -value=>$dependant || "", -defaultValue=>"", -size=>4, - -maxlength=>10, - -extras=>qq|style="width:50%;" onchange="validateDependant(this,this.form.orig_dependant,'$seq',this.form.start,this.form.end,this.form.duration,this.form.lagTime,true,true,this.form.orig_start,this.form.orig_end);"| + -maxlength=>10, + -extras=>qq|style="width:50%;" onchange="predecessorChanged(this.form, '', true)"| }); tie my %users, "Tie::IxHash"; @@ -969,12 +980,12 @@ sub www_editTask { $var->{'form.save'} = WebGUI::Form::submit($session, { -value=>"Save", -extras=>q|name="subbutton"| - }); -$var->{'form.footer'} = WebGUI::Form::formFooter($session); + }); + $var->{'form.footer'} = WebGUI::Form::formFooter($session); -$var->{'extras'} = $config->get("extrasURL"); -$var->{'assetExtras'} = $config->get("extrasURL").'/wobject/ProjectManager'; -return $self->processTemplate($var,$self->getValue("editTaskTemplateId")) + $var->{'extras'} = $config->get("extrasURL"); + $var->{'assetExtras'} = $config->get("extrasURL").'/wobject/ProjectManager'; + return $self->processTemplate($var,$self->getValue("editTaskTemplateId")) } #------------------------------------------------------------------- @@ -1171,22 +1182,21 @@ sub www_saveExistingTasks { $self->_updateProject($projectId); $self->_updateDependantDates($projectId); return $self->www_drawGanttChart(); - } #------------------------------------------------------------------- sub www_viewProject { my $self = shift; my $var = {}; - #Set Method Helpers - my ($session,$privilege,$form,$db,$dt,$i18n,$user) = $self->setSessionVars; - my $config = $session->config; + #Set Method Helpers + my ($session,$privilege,$form,$db,$dt,$i18n,$user) = $self->setSessionVars; + my $config = $session->config; my $style = $session->style; my $eh = $session->errorHandler; my $projectId = $_[0] || $form->get("projectId"); #Check Privileges - return $privilege->insufficient unless $self->_userCanObserveProject($user, $projectId); + return $privilege->insufficient unless $self->_userCanObserveProject($user, $projectId); my $extras = $config->get("extrasURL"); my $assetExtras = $config->get("extrasURL")."/wobject/ProjectManager"; @@ -1194,7 +1204,7 @@ sub www_viewProject { $var->{'extras'} = $assetExtras; $var->{'extras.base'} = $extras; - #Set Some Style stuff + #Set Some Style stuff $style->setLink($assetExtras."/subModal.css",{rel=>"stylesheet",type=>"text/css"}); $style->setLink($assetExtras."/taskEdit.css",{rel=>"stylesheet",type=>"text/css"}); $style->setLink($extras."/calendar/calendar-win2k-1.css",{rel=>"stylesheet",type=>"text/css"}); @@ -1245,7 +1255,8 @@ sub www_viewProject { my $hash = {}; my $seq = $row->{sequenceNumber}; my $id = $row->{taskId}; - my $isUntimed = ($row->{taskType} ne 'timed'); + my $taskType = $row->{taskType}; + my $isUntimed = ($taskType ne 'timed'); my $startDate = $dt->epochToSet($row->{startDate}); my $endDate = $dt->epochToSet($row->{endDate}); my $duration = $row->{duration}; @@ -1256,78 +1267,71 @@ sub www_viewProject { $hash->{'task.name'} = $row->{taskName}; if($canEditTasks) { - my $startId = "start_".$id."_formId"; - my $endId = "end_".$id."_formId"; - my $durId = "duration_".$id."_formId"; - my $lagId = "lagTime_".$id."_formId"; - my $predId = "dependants_".$id."_formId"; - my $origStartField = "orig_start_$id"; - my $origStartFieldId = $origStartField."_formId"; - my $origDepField = "orig_dependants_$id"; - my $origDepFieldId = $origDepField."_formId"; - my $origEndField = "orig_end_$id"; - my $origEndFieldId = $origEndField."_formId"; + my $suffix = '_'.$id; $hash->{'task.start'} = WebGUI::Form::text($session,{ - -name=>"start_$id", + -name=>'start'.$suffix, -value=>$startDate, -size=>"10", -maxlength=>"10", - -extras=>qq + -extras=>qq }); $hash->{'task.start'} .= WebGUI::Form::hidden($session,{ - -name=>$origStartField, + -name=>'orig_start'.$suffix, -value=>$startDate, - -extras=>qq|id="$origStartFieldId"| }); $hash->{'task.dependants'} = WebGUI::Form::integer($session,{ - -name=>"dependants_$id", + -name=>'dependants'.$suffix, -value=>$row->{dependants} || "", -defaultValue=>"", - -extras=>qq|class="taskdependant" onchange="validateDependant(this,document.getElementById('$origDepFieldId'),'$seq',document.getElementById('$startId'),document.getElementById('$endId'),document.getElementById('$durId'),document.getElementById('$lagId'),false,document.getElementById('$origStartFieldId'),document.getElementById('$origEndFieldId'));"| + -extras=>qq|class="taskdependant" onchange="predecessorChanged(this.form, '$suffix', false);"| }); $hash->{'task.dependants'} .= WebGUI::Form::hidden($session,{ - -name=>$origDepField, + -name=>'orig_dependants'.$suffix, -value=>$row->{dependants}, - -extras=>qq|id="$origDepFieldId"| }); $hash->{'task.end'} = WebGUI::Form::text($session,{ - -name=>"end_$id", + -name=>'end'.$suffix, -value=>$endDate, -size=>"10", -maxlength=>"10", - -extras=>qq|class="taskdate" onfocus="doCalendar(this.id);" onblur="adjustTaskTimeFromDate(document.getElementById('$startId'),this,document.getElementById('$durId'),document.getElementById('$lagId'),this,false,document.getElementById('$predId'),document.getElementById('$origStartFieldId'),document.getElementById('$origEndFieldId'),'$seq');"| + -extras=>qq|class="taskdate" onfocus="doCalendar(this.id);" onblur="endDateChanged(this.form, '$suffix', false);"| }); $hash->{'task.end'} .= WebGUI::Form::hidden($session,{ - -name=>$origEndField, + -name=>'orig_end'.$suffix, -value=>$endDate, - -extras=>qq|id="$origEndFieldId"| }); + # Don't display duration for untimed tasks. if ($isUntimed) { $hash->{'task.duration'} = $row->{duration}; $hash->{'task.duration'} .= WebGUI::Form::hidden($session,{ - -name=>"duration_$id", + -name=>'duration'.$suffix, -value=>$duration, - -extras=>qq|id="$durId"| }); } else { $hash->{'task.duration'} = WebGUI::Form::float($session,{ - -name=>"duration_$id", + -name=>'duration'.$suffix, -value=>$duration, - -extras=>qq|class="taskduration" onchange="adjustTaskTimeFromDuration(document.getElementById('$startId'),document.getElementById('$endId'),this,document.getElementById('$lagId'),false,document.getElementById('$predId'),document.getElementById('$origStartFieldId'),document.getElementById('$origEndFieldId'),'$seq');" | + -extras=>qq|class="taskduration" onchange="durationChanged(this.form, '$suffix', false);" | }); } $hash->{'task.lagTime'} = WebGUI::Form::hidden($session,{ - -name => "lagTime_$id", + -name => 'lagTime'.$suffix, -value => $lagTime, - -extras=>qq|id="$lagId"| }); - + $hash->{'task.taskType'} = WebGUI::Form::hidden($session, { + -name => 'taskType'.$suffix, + -value => $taskType, + }); + $hash->{'task.seqNum'} = WebGUI::Form::hidden($session, { + -name => 'seqNum'.$suffix, + -value => $seq + }); } else { $hash->{'task.duration'} = $duration; $hash->{'task.start'} = $startDate; @@ -1335,7 +1339,6 @@ sub www_viewProject { $hash->{'task.dependants'} = $row->{dependants} || " "; } $hash->{'task.duration.units'} = $dunits; - $hash->{'task.taskType'} = $row->{taskType}; if($canEditTasks) { $hash->{'task.edit.url'} = $self->getUrl("func=editTask;projectId=$projectId;taskId=".$row->{taskId}); $hash->{'task.edit.label'} = $i18n->get("edit task label"); diff --git a/www/extras/wobject/ProjectManager/projectDisplay.js b/www/extras/wobject/ProjectManager/projectDisplay.js index 3c7f0b7e9..0017cf532 100644 --- a/www/extras/wobject/ProjectManager/projectDisplay.js +++ b/www/extras/wobject/ProjectManager/projectDisplay.js @@ -42,6 +42,8 @@ function closeImage() { //-------------------------------------------------------------------------------------- function configureForTaskType(form) { + var te = getTaskElements(form, ''); + switch (getTaskType(form)) { case 'timed': form.end.disabled = false; @@ -71,7 +73,6 @@ function configureForTaskType(form) { break; case 'milestone': - form.end.value = form.start.value; form.duration.value = 0; form.duration.disabled = true; form.lagTime.value = 'N/A'; @@ -82,6 +83,8 @@ function configureForTaskType(form) { form.percentComplete.disabled = true; break; } + + setEndFromStartDate(te); } //-------------------------------------------------------------------------------------- @@ -99,10 +102,107 @@ function setCheckedOfNodeList(list, value) { return value; } -function getTaskType(form) { return getCheckedOfNodeList(form.taskType); } -function setTaskType(form, value) { setCheckedOfNodeList(form.taskType, value); } -function isTimed(form) { return getTaskType(form) == 'timed'; } -function isUntimed(form) { return !isTimed(form); } +// TODO: convert this whole bunch of stuff to do with task element groups +// to an actual prototype/class? + +function getTaskElements(form, suffix) { + var te = new Object(); + var keys = ['start', 'end', 'duration', 'lagTime', 'dependants', 'origStart', 'origEnd', + 'seqNum', 'taskType', 'orig_start', 'orig_duration', 'orig_dependant', 'orig_end']; + for (var i = 0; i < keys.length; i++) + te[keys[i]] = form[keys[i]+suffix]; + return te; +} + +function getTaskType(te) { + var taskTypeElt = te.taskType; + if (taskTypeElt.type == 'hidden') return taskTypeElt.value; + else return getCheckedOfNodeList(taskTypeElt); +} + +function setTaskType(te, value) { + var taskTypeElt = te.taskType; + if (taskTypeElt.type == 'hidden') taskTypeElt.value = value; + else setCheckedOfNodeList(taskTypeElt, value); +} + +function isTimed(te) { return getTaskType(te) == 'timed'; } +function isUntimed(te) { return !isTimed(te); } + +function fracDaysOfDuration(dur) { + if (dunits == 'hrs') return dur / hoursPerDay; + else return dur; +} + +function durationOfFracDays(days) { + if (dunits == 'hrs') return days * hoursPerDay; + else return days; +} + +function getDuration(te) { return fracDaysOfDuration(parseFloat(te.duration.value)); } +function setDuration(te, days) { te.duration.value = durationOfFracDays(days); } + +function getDateByKey(te, key) { + var split = te[key].value.split('-'); + return new Date(split[0], split[1]-1, split[2], 0, 0, 1, 0); +} +function getStartDate(te) { return getDateByKey(te, 'start'); } +function getEndDate(te) { return getDateByKey(te, 'end'); } + +function setDateByKey(te, key, date) { te[key].value = intlDate(date); } +function setStartDate(te, date) { setDateByKey(te, 'start', date); } +function setEndDate(te, date) { setDateByKey(te, 'end', date); } + +function setStartFromEndDate(te) { setStartDate(te, datePlusDays(getEndDate(te), -Math.floor(getTotalDuration(te)))); } +function setEndFromStartDate(te) { setEndDate(te, datePlusDays(getStartDate(te), Math.floor(getTotalDuration(te)))); } + +function setOrigDates(te) { + te.orig_start.value = te.start.value; + te.orig_end.value = te.end.value; +} + +function datePlusDays(date, days) { + var ret = new Date(); + ret.setTime(date.getTime() + days * dayMS); + return ret; +} + +function getTotalDuration(te) { + return fracDaysOfDuration(parseFloat(te.duration.value) + + parseFloatOrNA(te.lagTime.value)); +} + +function maybeDefaultTaskValues(te) { + var todayString = intlDate(new Date()); + var tomorrowString = intlDate(datePlusDays(new Date(), 1)); + var timed = isTimed(te); + + if (te.duration.value == "") te.duration.value = timed? durationOfFracDays(1) : 0; + if (te.lagTime.value == "") te.lagTime.value = 0; + + if (te.start.value == "" && te.end.value == "") { + te.start.value = todayString; + te.end.value = tomorrowString; + } else if (te.start.value == "") { + setEndFromStartDate(te); + } else if (te.end.value == "") { + setStartFromEndDate(te); + } + + updateTaskArray(te); +} + +function updateTaskArray(te) { + var seqNum = te.seqNum.value; + if (seqNum == "") return; + var assoc = taskArray[seqNum]; + assoc.start = te.start.value; + assoc.end = te.end.value; + assoc.duration = te.duration.value; + assoc.lagTime = ''+parseInt(te.lagTime.value); + assoc.predecessor = te.dependants.value; + assoc.type = getTaskType(te); +} //-------------------------------------------------------------------------------------- function checkEditTaskForm (form) { @@ -131,173 +231,115 @@ function toDateObj(date) { return dateObj; } -//-------------------------------------------------------------------------------------- -function adjustTaskTimeFromDuration(start, end, duration, lagTime, isTaskForm, predecessor, origStart, origEnd, seqNum) { - //set the form element - var form = duration.form; - - var today = new Date(); - var todayIntl = intlDate(today); +//--------------------------------------------------------------------------------------x +function durationChanged(form, suffix, isTaskForm, gotDelay) { + if (!isTaskForm && !gotDelay) + return window.setTimeout(function() { + durationChanged(form, suffix, isTaskForm, true); }, 1); - // Set values if not already set. - if (start.value == "") start.value = todayIntl; - if (end.value == "") end.value = todayIntl; - if (duration.value == "") duration.value = hoursPerDay; - - // Convert hours to days. - var taskDuration = parseFloat(duration.value); - var taskTotalDuration = taskDuration + parseFloatOrNA(lagTime.value); - if(dunits == "hrs") taskTotalDuration = taskTotalDuration / hoursPerDay; - var totalDurationFloor = Math.floor(taskTotalDuration); + var te = getTaskElements(form, suffix); + maybeDefaultTaskValues(te); + + // Get the new duration. + var duration = getDuration(te); + var totalDuration = getTotalDuration(te); // We can't have timed tasks with duration zero. Those are called "milestones". - if (taskDuration <= 0 && getTaskType(form) == 'timed') { + if (duration <= 0 && getTaskType(te) == 'timed') { if (isTaskForm) { // Convert to milestone if desired. if (confirm("Zero duration tasks are considered milestones. Do you wish to change this task to a milestone?")) { - setTaskType(form, 'milestone'); + setTaskType(te, 'milestone'); configureForTaskType(form); } else { - duration.value = form.orig_duration.value; - if (parseFloat(duration.value) <= 0) - duration.value = hoursPerDay; + form.duration.value = form.orig_duration.value; + if (getDuration(te) <= 0) + setDuration(te, 1); } } else { // Do not let users zero out tasks from the quick view. 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() + totalDurationFloor); - - //set end date to this date - end.value = intlDate(toDate); - - //Set new duration in taskArray - taskArray[seqNum]["duration"] = taskDuration; - //Adjust time based on new end date - adjustTaskTimeFromDate(start, end, duration, lagTime, end, isTaskForm, predecessor, origStart, origEnd, seqNum); + + switch (getTaskType(te)) { + case 'timed': + case 'progressive': + setEndDate(te, datePlusDays(getStartDate(te), Math.floor(totalDuration))); + break; + + case 'milestone': + setEndDate(te, getStartDate(te)); + break; + } + + te.orig_duration.value = te.duration.value; + updateTaskArray(te); + + if (!isTaskForm) { + updateDependantDates(); + paintGanttChart(); + } } -//-------------------------------------------------------------------------------------- -function adjustTaskTimeFromDate(start, end, duration, lagTime, 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 (isUntimed(form)) return; - orig_duration = form.orig_duration.value; +function checkPredecessorCollision(te, isTaskForm) { + var predecessor = te.dependants.value; + if (predecessor == "") return; + var predAssoc = taskArray[predecessor]; + var predEnd = toDateObj(predAssoc.end); + if (predEnd.getTime() >= getStartDate(te).getTime()) { + setStartDate(te, predEnd); + setEndFromStartDate(te); } - - //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; +} + +function dateChanged(form, suffix, isTaskForm, setWhichWay, gotDelay) { + if (!isTaskForm && !gotDelay) + return window.setTimeout(function() { + dateChanged(form, suffix, isTaskForm, setWhichWay, true); }, 1); + + var te = getTaskElements(form, suffix); + maybeDefaultTaskValues(te); + setWhichWay(te); + checkPredecessorCollision(te, isTaskForm); + setOrigDates(te); + updateTaskArray(te); + + if (!isTaskForm) { + updateDependantDates(); + paintGanttChart(); } - - //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(errorMsgs.greaterthan); - if(element.name == "start") { - end.value = element.value; - } else { - start.value = element.value; - } - duration.value = (dunits == "hrs")?hoursPerDay:1; - lagTime.value = 0; - return; - } - - var d = getDaysInterval(start.value,end.value); - if(d == 0) d = 1; - if(dunits == "hrs") { - d = d * hoursPerDay; - } - duration.value = d - lagTime.value; - } else { - //Set start/end if duration has been saved - var d = parseFloat(duration.value) + parseFloatOrNA(lagTime.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); +} + +function startDateChanged(form, suffix, isTaskForm) { dateChanged(form, suffix, isTaskForm, setEndFromStartDate); } +function endDateChanged(form, suffix, isTaskForm) { dateChanged(form, suffix, isTaskForm, setStartFromEndDate); } + +function predecessorChanged(form, suffix, isTaskForm, gotDelay) { + if (!isTaskForm && !gotDelay) + return window.setTimeout(function() { + predecessorChanged(form, suffix, isTaskForm, true); }, 1); + + var te = getTaskElements(form, suffix); + var seqNum = te.seqNum.value, predecessor = te.dependants.value; + + if (predecessor != "") { + var assoc = taskArray[predecessor]; + var revert = function() { te.dependants.value = te.orig_dependant.value; return; } + + if (predecessor < 1) { alert(errorMsgs.noPredecessor); return revert(); } + if (seqNum != "") { + if (predecessor == seqNum) { alert(errorMsgs.samePredecessor); return revert(); } + if (predecessor > seqNum) { alert(errorMsgs.previousPredecessor); return revert(); } } + if (assoc["type"] != 'timed') { alert(errorMsgs.untimedPredecessor); return revert(); } } - - //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(errorMsgs.invalidMove); - 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 + + te.orig_dependant.value = te.dependants.value; + checkPredecessorCollision(te, isTaskForm); + updateTaskArray(te); + + if (!isTaskForm) { + updateDependantDates(); paintGanttChart(); } } @@ -308,7 +350,7 @@ function trim(str) { } //-------------------------------------------------------------------------------------- -function arrangePredecessors (element,seqNum) { +function updateDependantDates() { for (var i = 1; i <= taskLength; i++) { var seq = i; var task = taskArray[seq]; @@ -394,78 +436,3 @@ function paintGanttChart () { document.getElementById("mastertable").style.width=mwidth; document.getElementById("scrolltd").style.width=swidth; } - -//-------------------------------------------------------------------------------------- -function validateDependant(field,origField,seqNum,start,end,duration,lagTime,isTaskForm,origStart,origEnd) { - var pred = field.value; - var newTask = false; - if(pred != "") { - if (seqNum == "") seqNum = taskLength+1; - - if (pred < 1) { - alert(errorMsgs.noPredecessor); - field.value = origField.value; - return; - } - - if (pred == seqNum) { - alert(errorMsgs.samePredecessor); - field.value = origField.value; - return; - } - - if (pred > seqNum) { - alert(errorMsgs.previousPredecessor); - field.value = origField.value; - return; - } - - if (taskArray[pred]["type"] != 'timed') { - alert(errorMsgs.untimedPredecessor); - 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 taskTotalDuration = parseFloat(duration.value) + parseFloatOrNA(lagTime.value); - if(dunits == "hrs") taskTotalDuration = taskTotalDuration / hoursPerDay; - var totalDurationFloor = Math.floor(taskTotalDuration); - - //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 - taskTotalDuration += predDayPart; - totalDurationFloor = Math.floor(totalDurationInDays); - } - - //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,lagTime,start,isTaskForm,field,origStart,origEnd,seqNum); - return; - } - } - - //Repaint - if(!isTaskForm) { - //Set new predecessor in taskArray - taskArray[seqNum]["predecessor"] = pred; - paintGanttChart(); - } -}