Diff for /loncom/interface/lonnavmaps.pm between versions 1.175 and 1.185

version 1.175, 2003/04/11 20:13:25 version 1.185, 2003/05/12 18:22:38
Line 71  my %statusIconMap = Line 71  my %statusIconMap =
       $resObj->TRIES_LEFT         => 'navmap.open.gif',        $resObj->TRIES_LEFT         => 'navmap.open.gif',
       $resObj->INCORRECT          => 'navmap.wrong.gif',        $resObj->INCORRECT          => 'navmap.wrong.gif',
       $resObj->OPEN               => 'navmap.open.gif',        $resObj->OPEN               => 'navmap.open.gif',
       $resObj->ATTEMPTED          => 'navmap.open.gif' );        $resObj->ATTEMPTED          => 'navmap.open.gif',
         $resObj->ANSWER_SUBMITTED   => '' );
   
 my %iconAltTags =   my %iconAltTags = 
     ( 'navmap.correct.gif' => 'Correct',      ( 'navmap.correct.gif' => 'Correct',
Line 169  sub real_handler { Line 170  sub real_handler {
         return OK;          return OK;
     }      }
   
     # See if there's only one map in the top-level... if so,      # See if there's only one map in the top-level, if we don't
     # automatically display it      # already have a filter... if so, automatically display it
     my $iterator = $navmap->getIterator(undef, undef, undef, 0);      if ($ENV{QUERY_STRING} !~ /filter/) {
     my $depth = 1;          my $iterator = $navmap->getIterator(undef, undef, undef, 0);
     $iterator->next();          my $depth = 1;
     my $curRes = $iterator->next();          $iterator->next();
     my $sequenceCount = 0;          my $curRes = $iterator->next();
     my $sequenceId;          my $sequenceCount = 0;
     while ($depth > 0) {          my $sequenceId;
         if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }          while ($depth > 0) {
         if ($curRes == $iterator->END_MAP()) { $depth--; }              if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }
               if ($curRes == $iterator->END_MAP()) { $depth--; }
         if (ref($curRes) && $curRes->is_sequence()) {              
             $sequenceCount++;              if (ref($curRes) && $curRes->is_sequence()) {
             $sequenceId = $curRes->map_pc();                  $sequenceCount++;
                   $sequenceId = $curRes->map_pc();
               }
               
               $curRes = $iterator->next();
           }
           
           if ($sequenceCount == 1) {
               # The automatic iterator creation in the render call 
               # will pick this up. We know the condition because
               # the defined($ENV{'form.filter'}) also ensures this
               # is a fresh call.
               $ENV{'form.filter'} = "$sequenceId";
         }          }
   
         $curRes = $iterator->next();  
     }      }
   
     if ($sequenceCount == 1) {      # Check to see if the student is jumping to next open, do-able problem
         # The automatic iterator creation in the render call       if ($ENV{QUERY_STRING} eq 'jumpToFirstHomework') {
         # will pick this up.          # Find the next homework problem that they can do.
         $ENV{'form.filter'} = "$sequenceId";          my $iterator = $navmap->getIterator(undef, undef, undef, 1);
           my $depth = 1;
           $iterator->next();
           my $curRes = $iterator->next();
           my $foundDoableProblem = 0;
           my $problemRes;
           
           while ($depth > 0 && !$foundDoableProblem) {
               if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }
               if ($curRes == $iterator->END_MAP()) { $depth--; }
   
               if (ref($curRes) && $curRes->is_problem()) {
                   my $status = $curRes->status();
                   if (($status == $curRes->OPEN || 
                        $status == $curRes->TRIES_LEFT()) &&
                       $curRes->getCompletionStatus() != $curRes->ATTEMPTED()) {
                       $problemRes = $curRes;
                       $foundDoableProblem = 1;
   
                       # Pop open all previous maps
                       my $stack = $iterator->getStack();
                       pop @$stack; # last resource in the stack is the problem
                                    # itself, which we don't need in the map stack
                       my @mapPcs = map {$_->map_pc()} @$stack;
                       $ENV{'form.filter'} = join(',', @mapPcs);
   
                       # Mark as both "here" and "jump"
                       $ENV{'form.postsymb'} = $curRes->symb();
                   }
               }
           } continue {
               $curRes = $iterator->next();
           }
   
           # If we found no problems, print a note to that effect.
           if (!$foundDoableProblem) {
               $r->print("<font size='+2'>All homework assignments have been completed.</font><br /><br />");
           }
       } else {
           $r->print("<a href='navmaps?jumpToFirstHomework'>" .
                     "Go To My First Homework Problem</a><br />");
     }      }
   
     # renderer call      # renderer call
Line 267  sub getDescription { Line 318  sub getDescription {
     my $part = shift;      my $part = shift;
     my $status = $res->status($part);      my $status = $res->status($part);
   
     if ($status == $res->NETWORK_FAILURE) { return ""; }      if ($status == $res->NETWORK_FAILURE) { 
           return "Having technical difficulties; please check status later"; 
       }
     if ($status == $res->NOTHING_SET) {      if ($status == $res->NOTHING_SET) {
         return "Not currently assigned.";          return "Not currently assigned.";
     }      }
Line 313  sub getDescription { Line 366  sub getDescription {
             return "No due date $triesString";              return "No due date $triesString";
         }          }
     }      }
       if ($status == $res->ANSWER_SUBMITTED) {
           return 'Answer submitted';
       }
 }  }
   
 # Convenience function, so others can use it: Is the problem due in less then  # Convenience function, so others can use it: Is the problem due in less then
Line 343  sub lastTry { Line 399  sub lastTry {
 }  }
   
 # This puts a human-readable name on the ENV variable.  # This puts a human-readable name on the ENV variable.
 # FIXME: This needs better logic: Who gets the advanced view of navmaps?  
 #   As of 3-13-03, it's an open question. Guy doesn't want to check  
 #   roles directly because it should be a check of capabilities for future  
 #   role compatibity. There is no capability that matches this one for  
 #   now, so this is done. (A hack for 1.0 might be to simply check roles  
 #   anyhow.)  
 sub advancedUser {  sub advancedUser {
     return $ENV{'user.adv'};      return $ENV{'request.role.adv'};
 }  }
   
   
Line 1473  sub init { Line 1524  sub init {
             unless ((time-$courserdatas{$cid.'.last_cache'})<240) {              unless ((time-$courserdatas{$cid.'.last_cache'})<240) {
                 my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.                  my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.
                                                  ':resourcedata',$chome);                                                   ':resourcedata',$chome);
                 if ($reply!~/^error\:/) {                  # Check for network failure
                   if ( $reply =~ /no.such.host/i || $reply =~ /con_lost/i) {
                       $self->{NETWORK_FAILURE} = 1;
                   } elsif ($reply!~/^error\:/) {
                     $courserdatas{$cid}=$reply;                      $courserdatas{$cid}=$reply;
                     $courserdatas{$cid.'.last_cache'}=time;                      $courserdatas{$cid.'.last_cache'}=time;
                 }                  }
                 # check to see if network failed  
                 elsif ( $reply=~/no.such.host/i || $reply=~/con.*lost/i )  
                 {  
                     $self->{NETWORK_FAILURE} = 1;  
                 }  
             }              }
             foreach (split(/\&/,$courserdatas{$cid})) {              foreach (split(/\&/,$courserdatas{$cid})) {
                 my ($name,$value)=split(/\=/,$_);                  my ($name,$value)=split(/\=/,$_);
Line 2690  sub to { my $self=shift; return $self->n Line 2739  sub to { my $self=shift; return $self->n
 sub compTitle {  sub compTitle {
     my $self = shift;      my $self = shift;
     my $title = $self->title();      my $title = $self->title();
       $title=~s/\&colon\;/\:/gs;
     if (!$title) {      if (!$title) {
         $title = $self->src();          $title = $self->src();
         $title = substr($title, rindex($title, '/') + 1);          $title = substr($title, rindex($title, '/') + 1);
Line 2753  sub is_sequence { Line 2803  sub is_sequence {
 sub parmval {  sub parmval {
     my $self = shift;      my $self = shift;
     my $what = shift;      my $what = shift;
     my $part = shift || "0";      my $part = shift;
       if (!defined($part)) { 
           $part = '0'; 
       }
     return $self->{NAV_MAP}->parmval($part.'.'.$what, $self->symb());      return $self->{NAV_MAP}->parmval($part.'.'.$what, $self->symb());
 }  }
   
Line 2927  sub opendate { Line 2980  sub opendate {
     }      }
     return $self->parmval("opendate");      return $self->parmval("opendate");
 }  }
   sub problemstatus {
       (my $self, my $part) = @_;
       return $self->parmval("problemstatus", $part);
   }
 sub sig {  sub sig {
     (my $self, my $part) = @_;      (my $self, my $part) = @_;
     return $self->parmval("sig", $part);      return $self->parmval("sig", $part);
Line 3069  sub countParts { Line 3126  sub countParts {
     return scalar(@{$parts}) + $delta;      return scalar(@{$parts}) + $delta;
 }  }
   
 # Private function: Extracts the parts information and saves it  sub partType {
       my $self = shift;
       my $part = shift;
   
       $self->extractParts();
       return $self->{PART_TYPE}->{$part};
   }
   
   # Private function: Extracts the parts information, both part names and
   # part types, and saves it
 sub extractParts {   sub extractParts { 
     my $self = shift;      my $self = shift;
           
Line 3078  sub extractParts { Line 3144  sub extractParts {
   
     $self->{PARTS} = [];      $self->{PARTS} = [];
   
       my %parts;
   
     # Retrieve part count, if this is a problem      # Retrieve part count, if this is a problem
     if ($self->is_problem()) {      if ($self->is_problem()) {
         my $metadata = &Apache::lonnet::metadata($self->src(), 'packages');          my $metadata = &Apache::lonnet::metadata($self->src(), 'packages');
         if (!$metadata) {          if (!$metadata) {
             $self->{RESOURCE_ERROR} = 1;              $self->{RESOURCE_ERROR} = 1;
             $self->{PARTS} = [];              $self->{PARTS} = [];
               $self->{PART_TYPE} = {};
             return;              return;
         }          }
         foreach (split(/\,/,$metadata)) {          foreach (split(/\,/,$metadata)) {
             if ($_ =~ /^part_(.*)$/) {              if ($_ =~ /^part_(.*)$/) {
                 my $part = $1;                  my $part = $1;
                   # This floods the logs if it blows up
                   if (defined($parts{$part})) {
                       Apache::lonnet::logthis("$part multiply defined in metadata for " . $self->symb());
                     }
   
                 # check to see if part is turned off.                  # check to see if part is turned off.
                 if (! Apache::loncommon::check_if_partid_hidden($part, $self->symb())) {  
                     push @{$self->{PARTS}}, $1;                  if (!Apache::loncommon::check_if_partid_hidden($part, $self->symb())) {
                       $parts{$part} = 1;
                 }                  }
             }              }
         }          }
                   
                   
         my @sortedParts = sort @{$self->{PARTS}};          my @sortedParts = sort keys %parts;
         $self->{PARTS} = \@sortedParts;          $self->{PARTS} = \@sortedParts;
     }      }
   
Line 3302  sub queryRestoreHash { Line 3377  sub queryRestoreHash {
     my $self = shift;      my $self = shift;
     my $hashentry = shift;      my $hashentry = shift;
     my $part = shift;      my $part = shift;
     $part = "0" if (!defined($part));      $part = "0" if (!defined($part) || $part eq '');
     return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE});      return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE});
   
     $self->getReturnHash();      $self->getReturnHash();
Line 3320  combine the two status tidbits into one Line 3395  combine the two status tidbits into one
 represent the status of the resource as a whole. The precise logic is  represent the status of the resource as a whole. The precise logic is
 documented in the comments of the status method. The following results  documented in the comments of the status method. The following results
 may be returned, all available as methods on the resource object  may be returned, all available as methods on the resource object
 ($res->NETWORK_FAILURE):  ($res->NETWORK_FAILURE): In addition to the return values that match
   the date or completion status, this function can return "ANSWER_SUBMITTED"
   if that problemstatus parameter value is set to No, suppressing the
   incorrect/correct feedback.
   
 =over 4  =over 4
   
Line 3379  The item is open and not yet tried. Line 3457  The item is open and not yet tried.
   
 The problem has been attempted.  The problem has been attempted.
   
   =item * B<ANSWER_SUBMITTED>:
   
   An answer has been submitted, but the student should not see it.
   
 =back  =back
   
 =cut  =cut
   
 sub TRIES_LEFT { return 10; }  sub TRIES_LEFT       { return 20; }
   sub ANSWER_SUBMITTED { return 21; }
   
 sub status {  sub status {
     my $self = shift;      my $self = shift;
Line 3398  sub status { Line 3481  sub status {
   
     if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; }      if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; }
   
       my $suppressFeedback = $self->parmval("problemstatus", $part) eq 'No';
   
     # There are a few whole rows we can dispose of:      # There are a few whole rows we can dispose of:
     if ($completionStatus == CORRECT ||      if ($completionStatus == CORRECT ||
         $completionStatus == CORRECT_BY_OVERRIDE ) {          $completionStatus == CORRECT_BY_OVERRIDE ) {
         return CORRECT;           return $suppressFeedback? ANSWER_SUBMITTED : CORRECT; 
     }      }
   
     if ($completionStatus == ATTEMPTED) {      if ($completionStatus == ATTEMPTED) {
Line 3442  sub status { Line 3527  sub status {
         if ($self->tries($part) < $self->maxtries($part) || !$self->maxtries($part)) {          if ($self->tries($part) < $self->maxtries($part) || !$self->maxtries($part)) {
             return TRIES_LEFT;              return TRIES_LEFT;
         }          }
         return INCORRECT; # otherwise, return orange; student can't fix this          return $suppressFeedback ? ANSWER_SUBMITTED : INCORRECT; # otherwise, return orange; student can't fix this
     }      }
   
     # Otherwise, it's untried and open      # Otherwise, it's untried and open

Removed from v.1.175  
changed lines
  Added in v.1.185


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