--- loncom/interface/lonnavmaps.pm 2002/10/29 20:17:39 1.91 +++ loncom/interface/lonnavmaps.pm 2002/11/01 19:50:00 1.96 @@ -2,7 +2,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.91 2002/10/29 20:17:39 bowersj2 Exp $ +# $Id: lonnavmaps.pm,v 1.96 2002/11/01 19:50:00 bowersj2 Exp $ # # Copyright Michigan State University Board of Trustees # @@ -820,7 +820,7 @@ sub new_handle { &Apache::loncommon::no_cache($r); $r->send_http_header; - # Initialize the nav map + # Create the nav map the nav map my $navmap = Apache::lonnavmaps::navmap->new( $ENV{"request.course.fn"}.".db", $ENV{"request.course.fn"}."_parms.db", 1, 1); @@ -837,19 +837,40 @@ sub new_handle { '')); $r->print(''); my $desc=$ENV{'course.'.$ENV{'request.course.id'}.'.description'}; - if (defined($desc)) { $r->print("

$desc

\n"); } + $r->print(''); my $date=localtime; - $r->print("

$date

\n"); - $r->rflush(); + $r->print(''); if ($navmap->{LAST_CHECK}) { - $r->print(' New discussion since '. + $r->print(''); + } else { + $r->print(''); + } + $r->print('
Key:    '. + ' New discussion since '. strftime("%A, %b %e at %I:%M %P", localtime($navmap->{LAST_CHECK})). - '
New message (click to open)

'); + '

  '. + ' New message (click to open)

'. + '

  '. + ' Discussions'. + '   New message (click to open)'. + '
'); + my $condition = 0; + if ($ENV{'form.condition'}) { + $condition = 1; + } + + if ($condition) { + $r->print('Close All Folders'); } else { - $r->print(' Discussions'. - '
New message (click to open)

'); + $r->print('Open All Folders'); } + $r->print('
 '); + $r->rflush(); + + # Now that we've displayed some stuff to the user, init the navmap + $navmap->init(); + # Check that it's defined if (!($navmap->courseMapDefined())) { $r->print('Coursemap undefined.' . @@ -926,17 +947,6 @@ sub new_handle { my $queryAdd = "postdata=" . &Apache::lonnet::escape($currenturl) . "&alreadyHere=1"; - my $condition = 0; - if ($ENV{'form.condition'}) { - $condition = 1; - } - - if ($condition) { - $r->print('Close All Folders

'); - } else { - $r->print('Open All Folders

'); - } - # Begin the HTML table # four cols: resource + indent, chat+feedback, icon, text string $r->print('' ."\n"); @@ -947,6 +957,10 @@ sub new_handle { # Here's a simple example of the iterator. # Preprocess the map: Look for current URL, force inlined maps to display + # This currently does very little... + my $mapEventualIterator = Apache::lonnavmaps::iterator->new($navmap, undef, undef, {}, + undef, $condition); + my $mapIterator = $navmap->getIterator(undef, undef, {}, 1); my $found = 0; my $depth = 1; @@ -958,12 +972,8 @@ sub new_handle { my $counter = 0; while ($depth > 0) { - if ($curRes == $mapIterator->BEGIN_MAP()) { - $depth++; - } - if ($curRes == $mapIterator->END_MAP()) { - $depth--; - } + if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; } + if ($curRes == $mapIterator->END_MAP()) { $depth--; } if (ref($curRes)) { $counter++; } @@ -1048,12 +1058,8 @@ sub new_handle { if ($curRes == $mapIterator->BEGIN_BRANCH()) { $isNewBranch = 1; } - if ($curRes == $mapIterator->BEGIN_MAP()) { - $depth++; - } - if ($curRes == $mapIterator->END_MAP()) { - $depth--; - } + if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; } + if ($curRes == $mapIterator->END_MAP()) { $depth--; } if (ref($curRes)) { $counter++; } @@ -1640,6 +1646,14 @@ sub new { $self->{PARM_HASH} = \%parmhash; $self->{HASH_TIED} = 1; + bless($self); + + return $self; +} + +sub init { + my $self = shift; + # If the course opt hash and the user opt hash should be generated, # generate them if ($self->{GENERATE_COURSE_USER_OPT}) { @@ -1744,10 +1758,6 @@ sub new { } $self->{PARM_CACHE} = {}; - - bless($self); - - return $self; } # Checks to see if coursemap is defined, matching test in old lonnavmaps @@ -1762,7 +1772,7 @@ sub courseMapDefined { sub getIterator { my $self = shift; - my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift, + my $iterator = Apache::lonnavmaps::DFSiterator->new($self, shift, shift, shift, undef, shift, $ENV{'form.direction'}); return $iterator; @@ -2021,6 +2031,100 @@ sub END_BRANCH { return 4; } # end of sub FORWARD { return 1; } # go forward sub BACKWARD { return 2; } +sub min { + (my $a, my $b) = @_; + if ($a < $b) { return $a; } else { return $b; } +} + +sub new { + # magic invocation to create a class instance + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = {}; + + $self->{NAV_MAP} = shift; + return undef unless ($self->{NAV_MAP}); + + # Handle the parameters + $self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource(); + $self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource(); + + # If the given resources are just the ID of the resource, get the + # objects + if (!ref($self->{FIRST_RESOURCE})) { $self->{FIRST_RESOURCE} = + $self->{NAV_MAP}->getById($self->{FIRST_RESOURCE}); } + if (!ref($self->{FINISH_RESOURCE})) { $self->{FINISH_RESOURCE} = + $self->{NAV_MAP}->getById($self->{FINISH_RESOURCE}); } + + $self->{FILTER} = shift; + + # A hash, used as a set, of resource already seen + $self->{ALREADY_SEEN} = shift; + if (!defined($self->{ALREADY_SEEN})) { $self->{ALREADY_SEEN} = {} }; + $self->{CONDITION} = shift; + + # Now, we need to pre-process the map, by walking forward and backward + # over the parts of the map we're going to look at. + + my $forwardIterator = Apache::lonnavmaps::DFSiterator->new($self->{NAV_MAP}, + $self->{FIRST_RESOURCE}, + $self->{FINISH_RESOURCE}, + $self->{FILTER}, + undef, $self->{CONDITION}, + FORWARD()); + + # prime the recursion + $self->{FIRST_RESOURCE}->{DATA}->{TOP_DOWN_VAL} = 0; + my $depth = 1; + $forwardIterator->next(); + my $curRes = $forwardIterator->next(); + while ($depth > 0) { + if ($curRes == $forwardIterator->BEGIN_MAP()) { $depth++; } + if ($curRes == $forwardIterator->END_MAP()) { $depth--; } + + if (ref($curRes)) { + my $topDownVal = $curRes->{DATA}->{TOP_DOWN_VAL}; + my $nextResources = $curRes->getNext(); + my $resourceCount = scalar(@{$nextResources}); + + if ($resourceCount == 1) { + my $current = $nextResources->[0]->{DATA}->{TOP_DOWN_VAL} || 999999999; + $nextResources->[0]->{DATA}->{TOP_DOWN_VAL} = min($topDownVal, $current); + } + + if ($resourceCount > 1) { + foreach my $res (@{$nextResources}) { + my $current = $res->{DATA}->{TOP_DOWN_VAL} || 999999999; + $res->{DATA}->{TOP_DOWN_VAL} = min($current, $topDownVal + 1); + } + } + } + $curRes = $forwardIterator->next(); + } + + # Now we're ready to start iterating. +} + +1; + +package Apache::lonnavmaps::DFSiterator; + +# UNDOCUMENTED: This is a private library, it should not generally be used +# by the outside world. What it does is walk through the nav map in a +# depth-first fashion. This is not appropriate for most uses, but it is +# used by the main iterator for pre-processing. It also is able to isolate +# much of the complexity of the main iterator, so the main iterator is much +# simpler. + +# Here are the tokens for the iterator, replicated from iterator for convenience: + +sub BEGIN_MAP { return 1; } # begining of a new map +sub END_MAP { return 2; } # end of the map +sub BEGIN_BRANCH { return 3; } # beginning of a branch +sub END_BRANCH { return 4; } # end of a branch +sub FORWARD { return 1; } # go forward +sub BACKWARD { return 2; } + # Params: nav map, start resource, end resource, filter, condition, # already seen hash ref @@ -2229,7 +2333,7 @@ sub next { my $finishResource = $self->{HERE}->map_finish(); $self->{RECURSIVE_ITERATOR} = - Apache::lonnavmaps::iterator->new ($self->{NAV_MAP}, $firstResource, + Apache::lonnavmaps::DFSiterator->new ($self->{NAV_MAP}, $firstResource, $finishResource, $self->{FILTER}, $self->{ALREADY_SEEN}, $self->{CONDITION}, $self->{DIRECTION}); }