--- loncom/interface/lonnavmaps.pm 2002/09/24 01:18:50 1.51 +++ loncom/interface/lonnavmaps.pm 2002/09/24 03:48:18 1.53 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.51 2002/09/24 01:18:50 bowersj2 Exp $ +# $Id: lonnavmaps.pm,v 1.53 2002/09/24 03:48:18 bowersj2 Exp $ # # Copyright Michigan State University Board of Trustees # @@ -841,7 +841,8 @@ sub new_handle { $res->OPEN_LATER => '', $res->TRIES_LEFT => '#FFFF00', $res->INCORRECT => '#FFAA00', - $res->OPEN => '#FFFF88' ); + $res->OPEN => '#FFFF88', + $res->NOTHING_SET => '' ); if (!defined($navmap)) { my $requrl = $r->uri; @@ -863,6 +864,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 = "        "; @@ -870,19 +872,15 @@ sub new_handle { while ($curRes != $mapIterator->END_NAV_MAP) { if ($curRes == $mapIterator->BEGIN_MAP() || - $curRes == $mapIterator->BEGIN_BRANCH()) { + $curRes == $mapIterator->BEGIN_BRANCH()) { $indentLevel++; } if ($curRes == $mapIterator->END_MAP() || - $curRes == $mapIterator->END_BRANCH()) { + $curRes == $mapIterator->END_BRANCH()) { $indentLevel--; } - - if ($curRes == $mapIterator->BEGIN_BRANCH()) { - $r->print("Begin branch
"); - } - if ($curRes == $mapIterator->END_BRANCH()) { - $r->print("End branch
"); + if ($curRes == $mapIterator->BEGIN_BRANCH()) { + $isNewBranch = 1; } if (ref($curRes) && $curRes->src()) { @@ -911,6 +909,14 @@ sub new_handle { '"'; my $title = $curRes->title(); my $partLabel = ""; + my $newBranchText = ""; + + # If this is a new branch, label it so + # (temporary, this should be an icon w/ alt text) + if ($isNewBranch) { + $newBranchText = "NB -> "; + $isNewBranch = 0; + } # links to open and close the folders my $linkopen = ""; @@ -927,7 +933,7 @@ sub new_handle { my $nowOpen = !defined($filterHash{$mapId}); $icon = $nowOpen ? "folder_opened.gif" : "folder_closed.gif"; - $linkopen = "print(" ${newBranchText}${linkopen}\"\"${linkclose}\n"); if ($curRes->is_problem() && $part != "0") { $partLabel = " (Part $part)"; } @@ -962,7 +968,7 @@ sub new_handle { if ($curRes->kind() eq "res" and $curRes->is_problem() ) { - $r->print (" Due: " . localtime($curRes->duedate())); + $r->print (getDescription($curRes, $part)); } } } @@ -1020,6 +1026,43 @@ 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: " . timeToHumanString($res->duedate($part)); + } + if ($status == $res->PAST_DUE) { + return "Answer: " . 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; @@ -1460,7 +1503,7 @@ sub next { if (scalar(@{$self->{BRANCH_STACK}}) == 0) { if ($self->{BRANCH_DEPTH} > 0) { $self->{FORCE_NEXT} = $self->END_MAP(); - $self->{BRANCH_DEPTH}--; + $self->{BRANCH_DEPTH}--; return $self->END_BRANCH(); } else { return $self->END_MAP(); @@ -1479,13 +1522,32 @@ sub next { # to start a new one. (We know because we already checked to see # if the stack was empty.) if ( scalar (@{$self->{BRANCH_STACK}}) < $self->{BRANCH_STACK_SIZE}) { - $self->{BRANCH_STACK_SIZE} = scalar(@{$self->{BRANCH_STACK}}); - $self->{BRANCH_DEPTH}++; - return $self->BEGIN_BRANCH(); + $self->{BRANCH_STACK_SIZE} = scalar(@{$self->{BRANCH_STACK}}); + $self->{BRANCH_DEPTH}++; + return $self->BEGIN_BRANCH(); } + # Remember the size for comparision next time. + $self->{BRANCH_STACK_SIZE} = scalar(@{$self->{BRANCH_STACK}}); + + # If the next resource we mean to return is going to need + # a lower branch level, terminate branches until we get + # there. + # Get the next resource in the branch $self->{HERE} = pop @{$self->{BRANCH_STACK}}; + + # Are we at the right depth? If not, close a branch and return + # the current resource onto the branch stack + if (defined($self->{HERE}->{DATA}->{ITERATOR_DEPTH}) + && $self->{HERE}->{DATA}->{ITERATOR_DEPTH} < + $self->{BRANCH_DEPTH} ) { + $self->{BRANCH_DEPTH}--; + # return it so we can pick it up eventually + push @{$self->{BRANCH_STACK}}, $self->{HERE}; + return $self->END_BRANCH(); + } + # We always return it after this point and never before # (proof: look at just the return statements), so we # remember that we've seen this. @@ -1493,23 +1555,23 @@ sub next { # Are we at the utter end? If so, return the END_NAV_MAP marker. if ($self->{HERE} == $self->{NAV_MAP}->finishResource() ) { - $self->{FORCE_NEXT} = $self->END_NAV_MAP; + $self->{FORCE_NEXT} = $self->END_NAV_MAP; return $self->{HERE}; } - # Remember the size for comparision next time. - $self->{BRANCH_STACK_SIZE} = scalar(@{$self->{BRANCH_STACK}}); - # Get the next possible resources my $nextUnfiltered = $self->{HERE}->getNext(); my $next = []; # filter the next possibilities to remove things we've - # already seen + # already seen. Also, remember what branch depth they should + # be displayed at, since there's no other reliable way to tell. foreach (@$nextUnfiltered) { - if (!defined($self->{ALREADY_SEEN}->{$_->{ID}})) { - push @$next, $_; - } + if (!defined($self->{ALREADY_SEEN}->{$_->{ID}})) { + push @$next, $_; + $_->{DATA}->{ITERATOR_DEPTH} = + $self->{BRANCH_DEPTH} + 1; + } } # Handle branch cases: @@ -1518,24 +1580,24 @@ sub next { # 2+ things next: have some branches my $nextCount = scalar(@$next); if ($nextCount == 0) { - # Return this and on the next run, close the branch up if we're - # in a branch - if ($self->{BRANCH_DEPTH} > 0 ) { - $self->{FORCE_NEXT} = $self->END_BRANCH(); - $self->{BRANCH_DEPTH}--; - } + # Return this and on the next run, close the branch up if we're + # in a branch + if ($self->{BRANCH_DEPTH} > 0 ) { + $self->{FORCE_NEXT} = $self->END_BRANCH(); + $self->{BRANCH_DEPTH}--; + } return $self->{HERE}; } while (@$next) { # copy the next possibilities over to the branch stack # in the right order - push @{$self->{BRANCH_STACK}}, shift @$next; + push @{$self->{BRANCH_STACK}}, shift @$next; } if ($nextCount >= 2) { - $self->{FORCE_NEXT} = $self->BEGIN_BRANCH(); - $self->{BRANCH_DEPTH}++; + $self->{FORCE_NEXT} = $self->BEGIN_BRANCH(); + $self->{BRANCH_DEPTH}++; return $self->{HERE}; } @@ -1552,8 +1614,8 @@ sub next { $self->{RECURSIVE_ITERATOR} = Apache::lonnavmaps::iterator->new ($self->{NAV_MAP}, $firstResource, $finishResource, $self->{FILTER}, $self->{ALREADY_SEEN}); - # prime the new iterator with the first resource - #push @{$self->{RECURSIVE_ITERATOR}->{BRANCH_STACK}}, $firstResource; + # prime the new iterator with the first resource + #push @{$self->{RECURSIVE_ITERATOR}->{BRANCH_STACK}}, $firstResource; } return $self->{HERE}; @@ -1977,6 +2039,7 @@ sub OPEN_LATER { return 0; } sub OPEN { return 1; } sub PAST_DUE { return 2; } sub ANSWER_OPEN { return 3; } +sub NOTHING_SET { return 4; } sub NETWORK_FAILURE { return 100; } sub getDateStatus { @@ -1987,13 +2050,18 @@ sub getDateStatus { 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}; + my $open = $self->opendate($part); + my $due = $self->duedate($part); + my $answer = $self->answerdate($part); + + if ($open && $now < $open) {return $self->OPEN_LATER}; + if ($due && $now < $due) {return $self->OPEN}; + if ($answer && $now < $answer) {return $self->PAST_DUE}; + 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; + } return $self->ANSWER_OPEN; } @@ -2029,12 +2097,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; @@ -2066,6 +2134,8 @@ 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. @@ -2097,56 +2167,54 @@ 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". - # 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) { + return PAST_DUE; } - 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