--- loncom/interface/lonnavmaps.pm 2002/09/24 02:41:21 1.52 +++ loncom/interface/lonnavmaps.pm 2002/09/24 20:01:05 1.54 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.52 2002/09/24 02:41:21 bowersj2 Exp $ +# $Id: lonnavmaps.pm,v 1.54 2002/09/24 20:01:05 bowersj2 Exp $ # # Copyright Michigan State University Board of Trustees # @@ -833,15 +833,17 @@ sub new_handle { # Defines a status->color mapping, null string means don't color my %colormap = - ( $res->NETWORK_FAILURE => '', - $res->CORRECT => '#BBFFBB', - $res->EXCUSED => '#BBBBFF', - $res->PAST_DUE => '#FFAA00', - $res->ANSWER_OPEN => '#FF00AA', - $res->OPEN_LATER => '', - $res->TRIES_LEFT => '#FFFF00', - $res->INCORRECT => '#FFAA00', - $res->OPEN => '#FFFF88' ); + ( $res->NETWORK_FAILURE => '', + $res->CORRECT => '#BBFFBB', + $res->EXCUSED => '#BBBBFF', + $res->PAST_DUE_ANSWER_LATER => '#FFAA00', + $res->PAST_DUE_NO_ANSWER => '#FFAA00', + $res->ANSWER_OPEN => '#FF00AA', + $res->OPEN_LATER => '', + $res->TRIES_LEFT => '#FFFF00', + $res->INCORRECT => '#FFAA00', + $res->OPEN => '#FFFF88', + $res->NOTHING_SET => '' ); if (!defined($navmap)) { my $requrl = $r->uri; @@ -863,6 +865,7 @@ sub new_handle { my $mapIterator = $navmap->getIterator(undef, undef, \%filterHash); my $curRes = $mapIterator->next(); + undef $res; # so we don't accidentally use it later my $indentLevel = -1; my $indentString = "        "; @@ -966,7 +969,7 @@ sub new_handle { if ($curRes->kind() eq "res" and $curRes->is_problem() ) { - $r->print (" Due: " . localtime($curRes->duedate())); + $r->print (getDescription($curRes, $part)); } } } @@ -1024,6 +1027,45 @@ sub getLinkForResource { return $res->src(); } +# Convenience function: This seperates the logic of how to create +# the problem text strings ("Due: DATE", "Open: DATE", "Not yet assigned", +# etc.) into a seperate function. It takes a resource object as the +# first parameter, and the part number of the resource as the second. +# It's basically a big switch statement on the status of the resource. + +sub getDescription { + my $res = shift; + my $part = shift; + my $status = $res->getDateStatus(); + + if ($status == $res->NETWORK_FAILURE) { return ""; } + if ($status == $res->NOTHING_SET) { + return "Not currently assigned."; + } + if ($status == $res->OPEN_LATER) { + return "Opens: " . timeToHumanString($res->opendate($part)); + } + if ($status == $res->OPEN) { + return "Due: $status " . timeToHumanString($res->duedate($part)); + } + if ($status == $res->PAST_DUE_ANSWER_LATER) { + return "Answer: " . timeToHumanString($res->answerdate($part)); + } + if ($status == $res->PAST_DUE_NO_ANSWER) { + return "Was Due: " . timeToHumanString($res->duedate($part)); + } + if ($status == $res->ANSWER_OPEN) { + return "Answer available"; + } +} + +# I want to change this into something more human-friendly. For +# now, this is a simple call to localtime. The final function +# probably belongs in loncommon. +sub timeToHumanString { + return localtime(shift); +} + 1; package Apache::lonnavmaps::navmap; @@ -1985,7 +2027,9 @@ B =item * B: Open and not yet due. -=item * B: The due date has passed, but the answer date has not yet arrived. +=item * B: The due date has passed, but the answer date has not yet arrived. + +=item * B: The due date has passed and there is no answer opening date set. =item * B: The answer date is here. @@ -1996,28 +2040,45 @@ B =cut # Apparently the compiler optimizes these into constants automatically -sub OPEN_LATER { return 0; } -sub OPEN { return 1; } -sub PAST_DUE { return 2; } -sub ANSWER_OPEN { return 3; } -sub NETWORK_FAILURE { return 100; } +sub OPEN_LATER { return 0; } +sub OPEN { return 1; } +sub PAST_DUE_NO_ANSWER { return 2; } +sub PAST_DUE_ANSWER_LATER { return 3; } +sub ANSWER_OPEN { return 4; } +sub NOTHING_SET { return 5; } +sub NETWORK_FAILURE { return 100; } + +# getDateStatus gets the date status for a given problem part. +# Because answer date, due date, and open date are fully independent +# (i.e., it is perfectly possible to *only* have an answer date), +# we have to completely cover the 3x3 maxtrix of (answer, due, open) x +# (past, future, none given). This function handles this with a decision +# tree. Read the comments to follow the decision tree. sub getDateStatus { my $self = shift; my $part = shift; $part = "0" if (!defined($part)); + + # Always return network failure if there was one. return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE}); my $now = time(); - my $o = $now - $self->opendate($part); - my $d = $now - $self->duedate($part); - my $a = $now - $self->answerdate($part); - - if ($o < 0) {return $self->OPEN_LATER}; - if ($d < 0) {return $self->OPEN}; - if ($a < 0) {return $self->PAST_DUE}; - return $self->ANSWER_OPEN; + my $open = $self->opendate($part); + my $due = $self->duedate($part); + my $answer = $self->answerdate($part); + + if (!$open && !$due && !$answer) { + # no data on the problem at all + # should this be the same as "open later"? think multipart. + return $self->NOTHING_SET; + } + if (!$open || $now < $open) {return $self->OPEN_LATER}; + if (!$due || $now < $due) {return $self->OPEN}; + if ($answer && $now < $answer) {return $self->PAST_DUE_ANSWER_LATER}; + if ($answer) { return $self->ANSWER_OPEN; }; + return PAST_DUE_NO_ANSWER; } =pod @@ -2052,12 +2113,12 @@ B =cut -sub NOT_ATTEMPTED { return 0; } -sub INCORRECT { return 1; } -sub INCORRECT_BY_OVERRIDE { return 2; } -sub CORRECT { return 3; } -sub CORRECT_BY_OVERRIDE { return 4; } -sub EXCUSED { return 5; } +sub NOT_ATTEMPTED { return 10; } +sub INCORRECT { return 11; } +sub INCORRECT_BY_OVERRIDE { return 12; } +sub CORRECT { return 13; } +sub CORRECT_BY_OVERRIDE { return 14; } +sub EXCUSED { return 15; } sub getCompletionStatus { my $self = shift; @@ -2089,11 +2150,15 @@ Along with directly returning the date o =item * NETWORK_FAILURE: The network has failed and the information is not available. +=item * NOTHING_SET: No dates have been set for this problem (part) at all. (Because only certain parts of a multi-part problem may be assigned, this can not be collapsed into "open later", as we don't know a given part will EVER be opened.) + =item * CORRECT: For any reason at all, the part is considered correct. =item * EXCUSED: For any reason at all, the problem is excused. -=item * PAST_DUE: The problem is past due, and not considered correct. +=item * PAST_DUE_NO_ANSWER: The problem is past due, not considered correct, and no answer date is set. + +=item * PAST_DUE_ANSWER_LATER: The problem is past due, not considered correct, and an answer date in the future is set. =item * ANSWER_OPEN: The problem is past due, not correct, and the answer is now available. @@ -2120,56 +2185,55 @@ sub status { # What we have is a two-dimensional matrix with 4 entries on one # dimension and 5 entries on the other, which we want to colorize, - # plus network failure. + # plus network failure and "no date data at all". - # Don't colorize on network failure. - if ($completionStatus == NETWORK_FAILURE()) { return $self->NETWORK_FAILURE(); } + if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; } # There are a few whole rows we can dispose of: - # If the problem is CORRECT, color it green no matter what - if ($completionStatus == CORRECT() || - $completionStatus == CORRECT_BY_OVERRIDE() ) { - return $self->CORRECT(); # Return a nice green. + if ($completionStatus == CORRECT || + $completionStatus == CORRECT_BY_OVERRIDE ) { + return CORRECT(); + } + + # If it's EXCUSED, then return that no matter what + if ($completionStatus == EXCUSED) { + return EXCUSED; } - # If it's EXCUSED, then return something no matter what - if ($completionStatus == EXCUSED()) { - return $self->EXCUSED(); # return a nice blue + if ($dateStatus == NOTHING_SET) { + return NOTHING_SET; } # Now we're down to a 3 (incorrect, incorrect_override, not_attempted) # by 4 matrix (date status). - # If it's Past Due and we didn't bail earlier because it's correct, - # color it orange. (Red is sort inappropriate; too drastic a color - # for something the student can't fix. - if ($dateStatus == PAST_DUE()) { - return $self->PAST_DUE(); # return orange + if ($dateStatus == PAST_DUE_ANSWER_LATER || + $dateStatus == PAST_DUE_NO_ANSWER) { + return $dateStatus; } - if ($dateStatus == ANSWER_OPEN()) { - return $self->ANSWER_OPEN(); + if ($dateStatus == ANSWER_OPEN) { + return ANSWER_OPEN; } # Now: (incorrect, incorrect_override, not_attempted) x # (open_later), (open) - # If it's open later, then don't colorize - if ($dateStatus == OPEN_LATER()) { - return $self->OPEN_LATER(); + if ($dateStatus == OPEN_LATER) { + return OPEN_LATER; } # If it's WRONG... - if ($completionStatus == INCORRECT() || $completionStatus == INCORRECT_BY_OVERRIDE()) { + if ($completionStatus == INCORRECT || $completionStatus == INCORRECT_BY_OVERRIDE) { # and there are TRIES LEFT: if ($self->tries() < $self->maxtries()) { - return $self->TRIES_LEFT(); # return red: The student can fix this + return TRIES_LEFT; } - return $self->INCORRECT(); # otherwise, return orange; student can't fix this + return INCORRECT; # otherwise, return orange; student can't fix this } # Otherwise, it's untried and open - return $self->OPEN(); # Light yellow + return OPEN; } =pod