Diff for /loncom/interface/lonnavmaps.pm between versions 1.115 and 1.129.2.1

version 1.115, 2002/11/26 14:45:24 version 1.129.2.1, 2003/02/01 19:55:00
Line 48  use POSIX qw (floor strftime); Line 48  use POSIX qw (floor strftime);
   
 sub handler {  sub handler {
     my $r = shift;      my $r = shift;
       real_handler($r);
   }
   
   sub real_handler {
       my $r = shift;
   
     &Apache::loncommon::get_unprocessed_cgi($ENV{QUERY_STRING});      &Apache::loncommon::get_unprocessed_cgi($ENV{QUERY_STRING});
   
Line 84  sub handler { Line 89  sub handler {
     }      }
   
     $r->print("<html><head>\n");      $r->print("<html><head>\n");
     $r->print("<title>Navigate Course Contents</title>");      $r->print("<title>Navigate Course Contents</title></head>");
   
     # Header      # Header
     $r->print(&Apache::loncommon::bodytag('Navigate Course Contents','',      $r->print(&Apache::loncommon::bodytag('Navigate Course Contents','',
                                           ''));                                            ''));
     $r->print('<script>window.focus();</script>');      $r->print('<script>window.focus();</script>');
   
       $r->rflush();
   
       # Now that we've displayed some stuff to the user, init the navmap
       $navmap->init();
   
     $r->print('<table border="0" cellpadding="2" cellspacing="0">');      $r->print('<table border="0" cellpadding="2" cellspacing="0">');
     my $date=localtime;      my $date=localtime;
     $r->print('<tr><td align="right" valign="bottom">Key:&nbsp;&nbsp;</td>');      $r->print('<tr><td align="right" valign="bottom">Key:&nbsp;&nbsp;</td>');
Line 116  sub handler { Line 126  sub handler {
         $condition = 1;          $condition = 1;
     }      }
   
     my $currenturl = $ENV{'form.postdata'};      # Determine where the "here" marker is and where the screen jumps to.
     $currenturl=~s/^http\:\/\///;      my $SYMB = 1; my $URL = 2; my $NOTHING = 3; # symbolic constants
     $currenturl=~s/^[^\/]+//;      my $hereType; # the type of marker, $SYMB, $URL, or $NOTHING
       my $here; # the actual URL or SYMB for the here marker
       my $jumpType; # The type of the thing we have a jump for, $SYMB or $URL
       my $jump; # the SYMB/URL of the resource we need to jump to
   
       if ( $ENV{'form.alreadyHere'} ) { # we came from a user's manipulation of the nav page
           # If this is a click on a folder or something, we want to preserve the "here"
           # from the querystring, and get the new "jump" marker
           $hereType = $ENV{'form.hereType'};
           $here = $ENV{'form.here'};
           $jumpType = $ENV{'form.jumpType'} || $NOTHING;
           $jump = $ENV{'form.jump'};
       } else { # the user is visiting the nav map from the remote
           # We're coming from the remote. We have either a url, a symb, or nothing,
           # and we need to figure out what.
           # Preference: Symb
           
           if ($ENV{'form.symb'}) {
               $hereType = $jumpType = $SYMB;
               $here = $jump = $ENV{'form.symb'};
           } elsif ($ENV{'form.postdata'}) {
               # couldn't find a symb, is there a URL?
               my $currenturl = $ENV{'form.postdata'};
               $currenturl=~s/^http\:\/\///;
               $currenturl=~s/^[^\/]+//;
   
               $hereType = $jumpType = $URL;
               $here = $jump = $currenturl;
           } else {
               # Nothing
               $hereType = $jumpType = $NOTHING;
           }
       }
   
       
     # alreadyHere allows us to only open the maps necessary to view      # alreadyHere allows us to only open the maps necessary to view
     # the current location once, while at the same time remembering      # the current location once, while at the same time remembering
     # the current location. Without that check, the user would never      # the current location. Without that check, the user would never
     # be able to close those maps; the user would close it, and the      # be able to close those maps; the user would close it, and the
     # currenturl scan would re-open it.      # currenturl scan would re-open it.
     my $queryAdd = "postdata=" . &Apache::lonnet::escape($currenturl) .      my $queryAdd = "&alreadyHere=1";
         "&alreadyHere=1";  
   
     if ($condition) {      if ($condition) {
         $r->print("<a href=\"navmaps?condition=0&filter=&$queryAdd\">Close All Folders</a>");          $r->print("<a href=\"navmaps?condition=0&filter=&$queryAdd" .
                     "&hereType=$hereType&here=" . Apache::lonnet::escape($here) .
                     "\">Close All Folders</a>");
     } else {      } else {
         $r->print("<a href=\"navmaps?condition=1&filter=&$queryAdd\">Open All Folders</a>");          $r->print("<a href=\"navmaps?condition=1&filter=&$queryAdd" .
                     "&hereType=$hereType&here=" . Apache::lonnet::escape($here) . 
                     "\">Open All Folders</a>");
     }      }
   
     $r->print('<br>&nbsp;');      $r->print('<br>&nbsp;');
     $r->rflush();      $r->rflush();
   
     # Now that we've displayed some stuff to the user, init the navmap  
     $navmap->init();  
   
     # Check that it's defined      # Check that it's defined
     if (!($navmap->courseMapDefined())) {      if (!($navmap->courseMapDefined())) {
         $r->print('<font size="+2" color="red">Coursemap undefined.</font>' .          $r->print('<font size="+2" color="red">Coursemap undefined.</font>' .
Line 208  sub handler { Line 251  sub handler {
     # Is this a new-style course? If so, we want to suppress showing the top-level      # Is this a new-style course? If so, we want to suppress showing the top-level
     # maps in their own folders, in favor of "inlining" them.      # maps in their own folders, in favor of "inlining" them.
     my $topResource = $navmap->getById("0.0");      my $topResource = $navmap->getById("0.0");
     my $inlineTopLevelMaps = $topResource->src() =~ m|^/uploaded/.*default\.sequence$|;  
     my $inlinedelta = $inlineTopLevelMaps? -1 : 0;  
   
     # Begin the HTML table      # Begin the HTML table
     # four cols: resource + indent, chat+feedback, icon, text string      # four cols: resource + indent, chat+feedback, icon, text string
Line 221  sub handler { Line 262  sub handler {
     # Here's a simple example of the iterator.      # Here's a simple example of the iterator.
     # Preprocess the map: Look for current URL, force inlined maps to display      # Preprocess the map: Look for current URL, force inlined maps to display
   
     my $mapIterator = $navmap->getIterator(undef, undef, \%filterHash, 1);      my $mapIterator = $navmap->getIterator(undef, undef, undef, 1);
     my $found = 0;      my $found = 0;
     my $depth = 1;      my $depth = 1;
     my $currentUrlIndex = 0; # keeps track of when the current resource is found,      my $currentJumpIndex = 0; # keeps track of when the current resource is found,
                              # so we can back up a few and put the anchor above the                               # so we can back up a few and put the anchor above the
                              # current resource                               # current resource
     my $currentUrlDelta = 5; # change this to change how many resources are displayed      my $currentJumpDelta = 2; # change this to change how many resources are displayed
                              # before the current resource when using #current                               # before the current resource when using #current
     $mapIterator->next(); # discard the first BEGIN_MAP      $mapIterator->next(); # discard the first BEGIN_MAP
     my $curRes = $mapIterator->next();      my $curRes = $mapIterator->next();
     my $counter = 0;      my $counter = 0;
           my $foundJump = ($jumpType == $NOTHING); # look for jump point if we have one
     while ($depth > 0) {      my $looped = 0; 
   
       # We only need to do this if we need to open the maps to show the
       # current position. This will change the counter so we can't count
       # for the jump marker with this loop.
       while ($depth > 0 && !$ENV{'form.alreadyHere'}) {
         if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; }          if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; }
         if ($curRes == $mapIterator->END_MAP()) { $depth--; }          if ($curRes == $mapIterator->END_MAP()) { $depth--; }
   
         if (ref($curRes)) { $counter++; }          if (ref($curRes) && !$ENV{'form.alreadyHere'} && 
               ($hereType == $SYMB && $curRes->symb() eq $here) ||
         my $mapStack = $mapIterator->getStack();              (ref($curRes) && $hereType == $URL && $curRes->src() eq $here)) {
         if ($currenturl && !$ENV{'form.alreadyHere'} && ref($curRes) &&               my $mapStack = $mapIterator->getStack();
             $curRes->src() eq $currenturl) {  
             # If this is the correct resource, be sure to   
             # show it by making sure the containing maps  
             # are open.  
   
             # This is why we have to use the main iterator instead of the  
             # potentially faster DFS: The count has to be the same, so  
             # the order has to be the same, which DFS won't give us.  
             $currentUrlIndex = $counter;  
                           
             # Ensure the parent maps are open              # Ensure the parent maps are open
             for my $map (@{$mapStack}) {              for my $map (@{$mapStack}) {
Line 261  sub handler { Line 298  sub handler {
             }              }
             $ENV{'form.alreadyHere'} = 1;              $ENV{'form.alreadyHere'} = 1;
         }          }
                       $looped = 1;
         # Preprocessing: If we're inlining nav maps into the top-level display,  
         # make sure we show this map!          $curRes = $mapIterator->next();
         if ($inlineTopLevelMaps && ref($curRes) && $curRes->is_map &&       }            
             scalar(@{$mapStack}) == 1) {      
             if ($condition) {      $mapIterator = $navmap->getIterator(undef, undef, \%filterHash, 0);
                 undef $filterHash{$curRes->map_pc()};      $depth = 1;
             } else {      $mapIterator->next();
                 $filterHash{$curRes->map_pc()} = 1;      $curRes = $mapIterator->next();
             }  
       while ($depth > 0 && !$foundJump) {
           if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; }
           if ($curRes == $mapIterator->END_MAP()) { $depth--; }
           if (ref($curRes)) { $counter++; }
   
           if (ref($curRes) && 
               (($jumpType == $SYMB && $curRes->symb() eq $jump) ||
               ($jumpType == $URL && $curRes->src() eq $jump))) {
               # If this is the correct resource, be sure to 
               # show it by making sure the containing maps
               # are open.
   
               # This is why we have to use the main iterator instead of the
               # potentially faster DFS: The count has to be the same, so
               # the order has to be the same, which DFS won't give us.
               $currentJumpIndex = $counter;
               $foundJump = 1;
         }          }
   
         $curRes = $mapIterator->next();          $curRes = $mapIterator->next();
Line 284  sub handler { Line 338  sub handler {
     my $now = time();      my $now = time();
     my $in24Hours = $now + 24 * 60 * 60;      my $in24Hours = $now + 24 * 60 * 60;
     my $displayedHereMarker = 0;      my $displayedHereMarker = 0;
       my $displayedJumpMarker = 0;
           
     # We know the first thing is a BEGIN_MAP (see "$self->{STARTED}"      # We know the first thing is a BEGIN_MAP (see "$self->{STARTED}"
     # code in iterator->next), so ignore the first one      # code in iterator->next), so ignore the first one
Line 298  sub handler { Line 353  sub handler {
   
     $counter = 0;      $counter = 0;
   
     # Print the 'current' anchor here if it would fall off the top  
     if ($currentUrlIndex - $currentUrlDelta < 0) {  
         $r->print('<a name="current" />');  
     }  
   
     while ($depth > 0) {      while ($depth > 0) {
         if ($curRes == $mapIterator->BEGIN_MAP() ||          if ($curRes == $mapIterator->BEGIN_MAP() ||
             $curRes == $mapIterator->BEGIN_BRANCH()) {              $curRes == $mapIterator->BEGIN_BRANCH()) {
Line 327  sub handler { Line 377  sub handler {
             next; # if yes, then just ignore this resource              next; # if yes, then just ignore this resource
         }          }
   
         if (ref($curRes) && $curRes->src()) {          if (ref($curRes)) {
   
             my $deltalevel = $isNewBranch? 1 : 0; # reserves space for branch icon              my $deltalevel = $isNewBranch? 1 : 0; # reserves space for branch icon
   
             if ($indentLevel - $deltalevel + $inlinedelta < 0) {              if ($indentLevel - $deltalevel < 0) {
                 # If this would be at a negative depth (top-level maps in                  # If this would be at a negative depth (top-level maps in
                 # new-style courses, we want to suppress their title display)                  # new-style courses, we want to suppress their title display)
                 # then ignore it.                  # then ignore it.
Line 438  sub handler { Line 488  sub handler {
                     '"';                      '"';
   
                 my $title = $curRes->compTitle();                  my $title = $curRes->compTitle();
                   if ($src=~/^\/uploaded\//) {
       $nonLinkedText=$title;
                       $title='';
                   }
                 my $partLabel = "";                  my $partLabel = "";
                 my $newBranchText = "";                  my $newBranchText = "";
   
Line 472  sub handler { Line 526  sub handler {
                     $linkopen .= ($nowOpen xor $condition) ?                       $linkopen .= ($nowOpen xor $condition) ? 
                         addToFilter(\%filterHash, $mapId) :                          addToFilter(\%filterHash, $mapId) :
                         removeFromFilter(\%filterHash, $mapId);                          removeFromFilter(\%filterHash, $mapId);
                     $linkopen .= "&condition=$condition&$queryAdd\">";                      $linkopen .= "&condition=$condition&$queryAdd" . 
                           "&hereType=$hereType&here=" . 
                           Apache::lonnet::escape($here) . "&jumpType=$SYMB&" .
                           "jump=" . Apache::lonnet::escape($curRes->symb()) ."\">";
                     $linkclose = "</a>";                      $linkclose = "</a>";
   
                 }                  }
Line 500  sub handler { Line 557  sub handler {
                 my $backgroundColor = $backgroundColors[$rowNum % scalar(@backgroundColors)];                  my $backgroundColor = $backgroundColors[$rowNum % scalar(@backgroundColors)];
   
                 # FIRST COL: The resource indentation, branch icon, name, and anchor                  # FIRST COL: The resource indentation, branch icon, name, and anchor
                 $r->print("  <tr bgcolor=\"$backgroundColor\"><td align=\"left\" valign=\"center\" width=\"60%\">\n");                  $r->print("  <tr bgcolor=\"$backgroundColor\"><td align=\"left\" valign=\"center\">\n");
   
                 # Print the anchor if necessary                  # Print the anchor if necessary
                 if ($counter == $currentUrlIndex - $currentUrlDelta) {                  if ($counter == $currentJumpIndex - $currentJumpDelta ) {
                     $r->print('<a name="current" />');                      $r->print('<a name="curloc" />');
                       $displayedJumpMarker = 1;
                 }                  }
   
                 # print indentation                  # print indentation
                 for (my $i = 0; $i < $indentLevel - $deltalevel + $inlinedelta; $i++) {                  for (my $i = 0; $i < $indentLevel - $deltalevel; $i++) {
                     $r->print($indentString);                      $r->print($indentString);
                 }                  }
   
Line 518  sub handler { Line 576  sub handler {
                 my $curMarkerEnd = "";                  my $curMarkerEnd = "";
   
                 # Is this the current resource?                  # Is this the current resource?
                 if ($curRes->src() eq $currenturl && !$displayedHereMarker) {                  if (!$displayedHereMarker && 
                     $curMarkerBegin = '<a name="curloc" /><font color="red" size="+2">&gt; </font>';                      (($hereType == $SYMB && $curRes->symb eq $here) ||
                       ($hereType == $URL && $curRes->src eq $here))) {
                       $curMarkerBegin = '<font color="red" size="+2">&gt; </font>';
                     $curMarkerEnd = '<font color="red" size="+2"> &lt;</font>';                      $curMarkerEnd = '<font color="red" size="+2"> &lt;</font>';
                     $displayedHereMarker = 1;                      $displayedHereMarker = 1;
                 }                  }
Line 534  sub handler { Line 594  sub handler {
   
                 $r->print("  $curMarkerBegin<a href=\"$link\">$title$partLabel</a> $curMarkerEnd $nonLinkedText");                  $r->print("  $curMarkerBegin<a href=\"$link\">$title$partLabel</a> $curMarkerEnd $nonLinkedText");
   
                 if ($curRes->{RESOURCE_ERROR}) {                  #if ($curRes->{RESOURCE_ERROR}) {
                     $r->print(&Apache::loncommon::help_open_topic ("Navmap_Host_Down",                  #    $r->print(&Apache::loncommon::help_open_topic ("Navmap_Host_Down",
                                               '<font size="-1">Host down</font>'));                  #                              '<font size="-1">Host down</font>'));
                     }                  #    }
   
                 $r->print("</td>\n");                  $r->print("</td>\n");
   
                 # SECOND COL: Is there text, feedback, errors??                  # SECOND COL: Is there text, feedback, errors??
                 my $discussionHTML = ""; my $feedbackHTML = "";                  my $discussionHTML = ""; my $feedbackHTML = ""; my $errorHTML = "";
   
                 if ($curRes->hasDiscussion()) {                  if ($curRes->hasDiscussion()) {
                     $discussionHTML = $linkopen .                      $discussionHTML = $linkopen .
Line 562  sub handler { Line 622  sub handler {
                     }                      }
                 }                  }
   
                 $r->print("<td width=\"75\" align=\"left\" valign=\"center\">$discussionHTML$feedbackHTML&nbsp;</td>");                  if ($curRes->getErrors()) {
                       my $errors = $curRes->getErrors();
                       foreach (split(/,/, $errors)) {
                           if ($_) {
                               $errorHTML .= '&nbsp;<a href="/adm/email?display='
                                   . &Apache::lonnet::escape($_) . '">'
                                   . '<img src="/adm/lonMisc/bomb.gif" '
                                   . 'border="0" /></a>';
                           }
                       }
                   }
   
                   $r->print("<td width=\"75\" align=\"left\" valign=\"center\">$discussionHTML$feedbackHTML$errorHTML&nbsp;</td>");
   
                 # Is this the first displayed part of a multi-part problem                  # Is this the first displayed part of a multi-part problem
                 # that has not been condensed, so we should suppress these two                  # that has not been condensed, so we should suppress these two
Line 607  sub handler { Line 679  sub handler {
         $curRes = $mapIterator->next();          $curRes = $mapIterator->next();
     }      }
   
     $r->print("</table></body></html>");      $r->print("</table>");
   
       # Print out the part that jumps to #curloc if it exists
       if ($displayedJumpMarker) {
           $r->print('<script>location += "#curloc";</script>');
       }
   
     $navmap->untieHashes();      $navmap->untieHashes();
   
       $r->print("</body></html>");
   
     return OK;      return OK;
 }  }
   
Line 920  sub new { Line 999  sub new {
         return undef;          return undef;
     }      }
   
     # Now copy the hashes for speed (?)      $self->{HASH_TIED} = 1;
     my %realnav; my %realparm;      $self->{NAV_HASH} = \%navmaphash;
     foreach (%navmaphash) { $realnav{$_} = $navmaphash{$_}; }      $self->{PARM_HASH} = \%parmhash;
     foreach (%parmhash) { $realparm{$_} = $navmaphash{$_}; }  
     $self->{NAV_HASH} = \%realnav;  
     $self->{PARM_HASH} = \%realparm;  
   
     bless($self);      bless($self);
     $self->untieHashes();  
                   
     return $self;      return $self;
 }  }
Line 999  sub init { Line 1074  sub init {
         my %emailstatus = &Apache::lonnet::dump('email_status');          my %emailstatus = &Apache::lonnet::dump('email_status');
         my $logoutTime = $emailstatus{'logout'};          my $logoutTime = $emailstatus{'logout'};
         my $courseLeaveTime = $emailstatus{'logout_'.$ENV{'request.course.id'}};          my $courseLeaveTime = $emailstatus{'logout_'.$ENV{'request.course.id'}};
         $self->{LAST_CHECK} = ($courseLeaveTime > $logoutTime ?          $self->{LAST_CHECK} = ($courseLeaveTime < $logoutTime ?
                                $courseLeaveTime : $logoutTime);                                 $courseLeaveTime : $logoutTime);
         my %discussiontime = &Apache::lonnet::dump('discussiontimes',           my %discussiontime = &Apache::lonnet::dump('discussiontimes', 
                                                    $cdom, $cnum);                                                     $cdom, $cnum);
Line 1080  sub DESTROY { Line 1155  sub DESTROY {
     $self->untieHashes();      $self->untieHashes();
 }  }
   
 # Private function: Does the given resource (as a symb string) have  # Private method: Does the given resource (as a symb string) have
 # current discussion? Returns 0 if chat/mail data not extracted.  # current discussion? Returns 0 if chat/mail data not extracted.
 sub hasDiscussion {  sub hasDiscussion {
     my $self = shift;      my $self = shift;
     my $symb = shift;      my $symb = shift;
     if (!defined($self->{DISCUSSION_TIME})) { return 0; }      if (!defined($self->{DISCUSSION_TIME})) { return 0; }
   
       #return defined($self->{DISCUSSION_TIME}->{$symb});
     return $self->{DISCUSSION_TIME}->{$symb} >      return $self->{DISCUSSION_TIME}->{$symb} >
            $self->{LAST_CHECK};             $self->{LAST_CHECK};
 }  }
   
 # Private function: Does the given resource (as a symb string) have  # Private method: Does the given resource (as a symb string) have
 # current feedback? Returns the string in the feedback hash, which  # current feedback? Returns the string in the feedback hash, which
 # will be false if it does not exist.  # will be false if it does not exist.
 sub getFeedback {   sub getFeedback { 
Line 1103  sub getFeedback { Line 1179  sub getFeedback {
     return $self->{FEEDBACK}->{$symb};      return $self->{FEEDBACK}->{$symb};
 }  }
   
   # Private method: Get the errors for that resource (by source).
   sub getErrors { 
       my $self = shift;
       my $src = shift;
       
       if (!defined($self->{ERROR_MSG})) { return ""; }
       return $self->{ERROR_MSG}->{$src};
   }
   
 =pod  =pod
   
 =item * B<getById>(id): Based on the ID of the resource (1.1, 3.2, etc.), get a resource object for that resource. This method, or other methods that use it (as in the resource object) is the only proper way to obtain a resource object.  =item * B<getById>(id): Based on the ID of the resource (1.1, 3.2, etc.), get a resource object for that resource. This method, or other methods that use it (as in the resource object) is the only proper way to obtain a resource object.
Line 1276  getIterator behaves as follows: Line 1361  getIterator behaves as follows:
   
 =over 4  =over 4
   
 =item * B<getIterator>(firstResource, finishResource, filterHash, condition): All parameters are optional. firstResource is a resource reference corresponding to where the iterator should start. It defaults to navmap->firstResource() for the corresponding nav map. finishResource corresponds to where you want the iterator to end, defaulting to navmap->finishResource(). filterHash is a hash used as a set containing strings representing the resource IDs, defaulting to empty. Condition is a 1 or 0 that sets what to do with the filter hash: If a 0, then only resource that exist IN the filterHash will be recursed on. If it is a 1, only resources NOT in the filterHash will be recursed on. Defaults to 0.  =item * B<getIterator>(firstResource, finishResource, filterHash, condition, forceTop): All parameters are optional. firstResource is a resource reference corresponding to where the iterator should start. It defaults to navmap->firstResource() for the corresponding nav map. finishResource corresponds to where you want the iterator to end, defaulting to navmap->finishResource(). filterHash is a hash used as a set containing strings representing the resource IDs, defaulting to empty. Condition is a 1 or 0 that sets what to do with the filter hash: If a 0, then only resource that exist IN the filterHash will be recursed on. If it is a 1, only resources NOT in the filterHash will be recursed on. Defaults to 0. forceTop is a boolean value. If it is false (default), the iterator will only return the first level of map that is not just a single, 'redirecting' map. If true, the iterator will return all information, starting with the top-level map, regardless of content.
   
 Thus, by default, only top-level resources will be shown. Change the condition to a 1 without changing the hash, and all resources will be shown. Changing the condition to 1 and including some values in the hash will allow you to selectively suppress parts of the navmap, while leaving it on 0 and adding things to the hash will allow you to selectively add parts of the nav map. See the handler code for examples.  Thus, by default, only top-level resources will be shown. Change the condition to a 1 without changing the hash, and all resources will be shown. Changing the condition to 1 and including some values in the hash will allow you to selectively suppress parts of the navmap, while leaving it on 0 and adding things to the hash will allow you to selectively add parts of the nav map. See the handler code for examples.
   
Line 1296  The iterator will return either a refere Line 1381  The iterator will return either a refere
   
 The tokens are retreivable via methods on the iterator object, i.e., $iterator->END_MAP.  The tokens are retreivable via methods on the iterator object, i.e., $iterator->END_MAP.
   
   Maps can contain empty resources. The iterator will automatically skip over such resources, but will still treat the structure correctly. Thus, a complicated map with several branches, but consisting entirely of empty resources except for one beginning or ending resource, will cause a lot of BRANCH_STARTs and BRANCH_ENDs, but only one resource will be returned.
   
 =back  =back
   
 =cut  =cut
Line 1346  sub new { Line 1433  sub new {
     if (!defined($self->{ALREADY_SEEN})) { $self->{ALREADY_SEEN} = {} };      if (!defined($self->{ALREADY_SEEN})) { $self->{ALREADY_SEEN} = {} };
     $self->{CONDITION} = shift;      $self->{CONDITION} = shift;
   
       # Do we want to automatically follow "redirection" maps?
       $self->{FORCE_TOP} = shift;
   
     # Now, we need to pre-process the map, by walking forward and backward      # 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.      # over the parts of the map we're going to look at.
   
Line 1361  sub new { Line 1451  sub new {
   
     my $maxDepth = 0; # tracks max depth      my $maxDepth = 0; # tracks max depth
   
       # If there is only one resource in this map, and it's a map, we
       # want to remember that, so the user can ask for the first map
       # that isn't just a redirector.
       my $resource; my $resourceCount = 0;
   
     # **1**      # **1**
   
     foreach my $pass (@iterations) {      foreach my $pass (@iterations) {
Line 1384  sub new { Line 1479  sub new {
             if ($curRes == $iterator->END_MAP()) { $depth--; }              if ($curRes == $iterator->END_MAP()) { $depth--; }
                   
             if (ref($curRes)) {              if (ref($curRes)) {
                   # If there's only one resource, this will save it
                   # we have to filter empty resources from consideration here,
                   # or even "empty", redirecting maps have two (start & finish)
                   # or three (start, finish, plus redirector)
                   if($direction == FORWARD && $curRes->src()) { 
                       $resource = $curRes; $resourceCount++; 
                   }
                 my $resultingVal = $curRes->{DATA}->{$valName};                  my $resultingVal = $curRes->{DATA}->{$valName};
                 my $nextResources = $curRes->$nextResourceMethod();                  my $nextResources = $curRes->$nextResourceMethod();
                 my $resourceCount = scalar(@{$nextResources});                  my $nextCount = scalar(@{$nextResources});
   
                 if ($resourceCount == 1) { # **3**                  if ($nextCount == 1) { # **3**
                     my $current = $nextResources->[0]->{DATA}->{$valName} || 999999999;                      my $current = $nextResources->[0]->{DATA}->{$valName} || 999999999;
                     $nextResources->[0]->{DATA}->{$valName} = min($resultingVal, $current);                      $nextResources->[0]->{DATA}->{$valName} = min($resultingVal, $current);
                 }                  }
                                   
                 if ($resourceCount > 1) { # **4**                  if ($nextCount > 1) { # **4**
                     foreach my $res (@{$nextResources}) {                      foreach my $res (@{$nextResources}) {
                         my $current = $res->{DATA}->{$valName} || 999999999;                          my $current = $res->{DATA}->{$valName} || 999999999;
                         $res->{DATA}->{$valName} = min($current, $resultingVal + 1);                          $res->{DATA}->{$valName} = min($current, $resultingVal + 1);
Line 1413  sub new { Line 1515  sub new {
         }          }
     }      }
   
       # Check: Was this only one resource, a map?
       if ($resourceCount == 1 && $resource->is_map() && !$self->{FORCE_TOP}) { 
           my $firstResource = $resource->map_start();
           my $finishResource = $resource->map_finish();
           return 
               Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
                                                 $finishResource, $self->{FILTER},
                                                 $self->{ALREADY_SEEN}, 
                                                 $self->{CONDITION}, 0);
           
       }
   
     # Set up some bookkeeping information.      # Set up some bookkeeping information.
     $self->{CURRENT_DEPTH} = 0;      $self->{CURRENT_DEPTH} = 0;
     $self->{MAX_DEPTH} = $maxDepth;      $self->{MAX_DEPTH} = $maxDepth;
Line 1562  sub next { Line 1676  sub next {
                                               $self->{ALREADY_SEEN}, $self->{CONDITION});                                                $self->{ALREADY_SEEN}, $self->{CONDITION});
     }      }
   
       # If this is a blank resource, don't actually return it.
       # Should you ever find you need it, make sure to add an option to the code
       #  that you can use; other things depend on this behavior.
       if (!$self->{HERE}->src() || !$self->{HERE}->browsePriv()) {
           return $self->next();
       }
   
     return $self->{HERE};      return $self->{HERE};
   
 }  }
Line 1608  package Apache::lonnavmaps::DFSiterator; Line 1729  package Apache::lonnavmaps::DFSiterator;
 #  but this might as well be left seperate, since it is possible some other  #  but this might as well be left seperate, since it is possible some other
 #  use might be found for it. - Jeremy  #  use might be found for it. - Jeremy
   
   # Unlike the main iterator, this DOES return all resources, even blank ones.
   #  The main iterator needs them to correctly preprocess the map.
   
 sub BEGIN_MAP { return 1; }    # begining of a new map  sub BEGIN_MAP { return 1; }    # begining of a new map
 sub END_MAP { return 2; }      # end of the map  sub END_MAP { return 2; }      # end of the map
 sub FORWARD { return 1; }      # go forward  sub FORWARD { return 1; }      # go forward
Line 2129  sub hasDiscussion { Line 2253  sub hasDiscussion {
   
 sub getFeedback {  sub getFeedback {
     my $self = shift;      my $self = shift;
     return $self->{NAV_MAP}->getFeedback($self->src());      my $source = $self->src();
       if ($source =~ /^\/res\//) { $source = substr $source, 5; }
       return $self->{NAV_MAP}->getFeedback($source);
   }
   
   sub getErrors {
       my $self = shift;
       my $source = $self->src();
       if ($source =~ /^\/res\//) { $source = substr $source, 5; }
       return $self->{NAV_MAP}->getErrors($source);
 }  }
   
 =pod  =pod
Line 2485  sub getNext { Line 2618  sub getNext {
         my $next = $choice->goesto();          my $next = $choice->goesto();
         $next = $self->{NAV_MAP}->getById($next);          $next = $self->{NAV_MAP}->getById($next);
   
         # Don't remember it if the student doesn't have browse priviledges          push @branches, $next;
         # future note: this may properly belong in the client of the resource  
         my $browsePriv = $self->{BROWSE_PRIV};  
         if (!defined($browsePriv)) {  
             $browsePriv = &Apache::lonnet::allowed('bre', $self->src);  
             $self->{BROWSE_PRIV} = $browsePriv;  
         }  
         if (!($browsePriv ne '2' && $browsePriv ne 'F')) {  
             push @branches, $next;  
         }  
     }      }
     return \@branches;      return \@branches;
 }  }
Line 2508  sub getPrevious { Line 2632  sub getPrevious {
         my $prev = $choice->comesfrom();          my $prev = $choice->comesfrom();
         $prev = $self->{NAV_MAP}->getById($prev);          $prev = $self->{NAV_MAP}->getById($prev);
   
         # Don't remember it if the student doesn't have browse priviledges          push @branches, $prev;
         # future note: this may properly belong in the client of the resource  
         my $browsePriv = $self->{BROWSE_PRIV};  
         if (!defined($browsePriv)) {  
             $browsePriv = &Apache::lonnet::allowed('bre', $self->src);  
             $self->{BROWSE_PRIV} = $browsePriv;  
         }  
         if (!($browsePriv ne '2' && $browsePriv ne 'F')) {  
             push @branches, $prev;  
         }  
     }      }
     return \@branches;      return \@branches;
 }  }
   
   sub browsePriv {
       my $self = shift;
       if (defined($self->{BROWSE_PRIV})) {
           return $self->{BROWSE_PRIV};
       }
   
       $self->{BROWSE_PRIV} = &Apache::lonnet::allowed('bre', $self->src());
   }
   
 =pod  =pod
   
 =back  =back

Removed from v.1.115  
changed lines
  Added in v.1.129.2.1


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>