Diff for /loncom/interface/lonnavmaps.pm between versions 1.509.2.17 and 1.510

version 1.509.2.17, 2024/07/03 03:07:58 version 1.510, 2015/10/05 01:52:10
Line 2 Line 2
 # Navigate Maps Handler  # Navigate Maps Handler
 #  #
 # $Id$  # $Id$
   
 #  #
 # Copyright Michigan State University Board of Trustees  # Copyright Michigan State University Board of Trustees
 #  #
Line 342  user into thinking that if the sequence Line 341  user into thinking that if the sequence
 under it; for example, see the "Show Uncompleted Homework" view on the  under it; for example, see the "Show Uncompleted Homework" view on the
 B<NAV> screen.  B<NAV> screen.
   
 =item * B<suppressNavmap>: default: false  =item * B<suppressNavmaps>: default: false
   
 If true, will not display Navigate Content resources.   If true, will not display Navigate Content resources. 
   
Line 486  use Apache::lonlocal; Line 485  use Apache::lonlocal;
 use Apache::lonnet;  use Apache::lonnet;
 use Apache::lonmap;  use Apache::lonmap;
   
 use POSIX qw (ceil floor strftime);  use POSIX qw (floor strftime);
 use Time::HiRes qw( gettimeofday tv_interval );  use Time::HiRes qw( gettimeofday tv_interval );
 use LONCAPA;  use LONCAPA;
 use DateTime();  use DateTime();
Line 534  my %colormap = Line 533  my %colormap =
       $resObj->EXCUSED                => '#3333FF',        $resObj->EXCUSED                => '#3333FF',
       $resObj->PAST_DUE_ANSWER_LATER  => '',        $resObj->PAST_DUE_ANSWER_LATER  => '',
       $resObj->PAST_DUE_NO_ANSWER     => '',        $resObj->PAST_DUE_NO_ANSWER     => '',
       $resObj->PAST_DUE_ATMPT_ANS     => '',  
       $resObj->PAST_DUE_ATMPT_NOANS   => '',  
       $resObj->PAST_DUE_NO_ATMT_ANS   => '',  
       $resObj->PAST_DUE_NO_ATMT_NOANS => '',  
       $resObj->ANSWER_OPEN            => '#006600',        $resObj->ANSWER_OPEN            => '#006600',
       $resObj->OPEN_LATER             => '',        $resObj->OPEN_LATER             => '',
       $resObj->TRIES_LEFT             => '',        $resObj->TRIES_LEFT             => '',
Line 581  sub getLinkForResource { Line 576  sub getLinkForResource {
     my $anchor;      my $anchor;
     if ($res->is_page()) {      if ($res->is_page()) {
  foreach my $item (@$stack) { if (defined($item)) { $anchor = $item; }  }   foreach my $item (@$stack) { if (defined($item)) { $anchor = $item; }  }
  if ($anchor->encrypted() && !&advancedUser()) {   $anchor=&escape($anchor->shown_symb());
     $anchor='LC_'.$anchor->id();  
  } else {  
     $anchor=&escape($anchor->shown_symb());  
  }  
  return ($res->link(),$res->shown_symb(),$anchor);   return ($res->link(),$res->shown_symb(),$anchor);
     }      }
             # in case folder was skipped over as "only sequence"              # in case folder was skipped over as "only sequence"
Line 651  sub getDescription { Line 642  sub getDescription {
             } elsif ($slot_status == $res->RESERVABLE) {              } elsif ($slot_status == $res->RESERVABLE) {
                 $slotmsg = &mt('Reservable, reservations close [_1]',                  $slotmsg = &mt('Reservable, reservations close [_1]',
                            timeToHumanString($slot_time,'end'));                             timeToHumanString($slot_time,'end'));
             } elsif ($slot_status == $res->NEEDS_CHECKIN) {  
                 $slotmsg = &mt('Reserved, check-in needed - ends [_1]',  
                            timeToHumanString($slot_time,'end'));  
             } elsif ($slot_status == $res->RESERVABLE_LATER) {              } elsif ($slot_status == $res->RESERVABLE_LATER) {
                 $slotmsg = &mt('Reservable, reservations open [_1]',                  $slotmsg = &mt('Reservable, reservations open [_1]',
                            timeToHumanString($slot_time,'start'));                             timeToHumanString($slot_time,'start'));
Line 683  sub getDescription { Line 671  sub getDescription {
             return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part).$slotinfo;              return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part).$slotinfo;
         }          }
     }      }
     if (($status == $res->PAST_DUE_ANSWER_LATER) || ($status == $res->PAST_DUE_ATMPT_ANS) || ($status == $res->PAST_DUE_NO_ATMT_ANS)) {      if ($status == $res->PAST_DUE_ANSWER_LATER) {
         return &mt("Answer open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($answer,'start'),$res->symb(),'answerdate',$part));          return &mt("Answer open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($answer,'start'),$res->symb(),'answerdate',$part));
     }      }
     if (($status == $res->PAST_DUE_NO_ANSWER) || ($status == $res->PAST_DUE_ATMPT_NOANS) || ($status == $res->PAST_DUE_NO_ATMT_NOANS)) {      if ($status == $res->PAST_DUE_NO_ANSWER) {
  if ($res->is_practice()) {   if ($res->is_practice()) {
     return &mt("Closed [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'answerdate,duedate',$part));      return &mt("Closed [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'answerdate,duedate',$part));
  } else {   } else {
Line 926  sub render_resource { Line 914  sub render_resource {
     my $nonLinkedText = ''; # stuff after resource title not in link      my $nonLinkedText = ''; # stuff after resource title not in link
   
     my $link = $params->{"resourceLink"};      my $link = $params->{"resourceLink"};
     if ($resource->ext()) {  
         $link =~ s/\#.+(\?)/$1/g;  
     }  
   
     #  The URL part is not escaped at this point, but the symb is...       #  The URL part is not escaped at this point, but the symb is... 
   
Line 949  sub render_resource { Line 934  sub render_resource {
     # links to open and close the folder      # links to open and close the folder
   
     my $whitespace = $location.'/whitespace_21.gif';      my $whitespace = $location.'/whitespace_21.gif';
     my $linkopen = "<img src='$whitespace' alt='' />";      my $linkopen = "<img src='$whitespace' alt='' />"."<a href=\"$link\">";
     my $nomodal;  
     if (($params->{'modalLink'}) && (!$resource->is_sequence())) {  
         if ($link =~m{^(?:|/adm/wrapper)/ext/([^#]+)}) {  
             my $exturl = $1;  
             if (($ENV{'SERVER_PORT'} == 443) && ($exturl !~ /^https:/)) {  
                 $nomodal = 1;  
             }  
         } elsif (($link eq "/public/$LONCAPA::match_domain/$LONCAPA::match_courseid/syllabus") &&  
                  ($env{'request.course.id'}) && ($ENV{'SERVER_PORT'} == 443) &&  
                  ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) {  
              $nomodal = 1;  
         }  
         my $esclink = &js_escape($link);  
         if ($nomodal) {  
             $linkopen .= "<a href=\"#\" onclick=\"javascript:window.open('$esclink','resourcepreview','height=400,width=500,scrollbars=1,resizable=1,menubar=0,location=1'); return false;\" />";  
         } else {  
             $linkopen .= "<a href=\"$link\" onclick=\"javascript:openMyModal('$esclink',600,500,'yes','true'); return false;\">";  
         }  
     } else {  
         $linkopen .= "<a href=\"$link\">";  
     }  
     my $linkclose = "</a>";      my $linkclose = "</a>";
   
     # Default icon: unknown page      # Default icon: unknown page
Line 999  sub render_resource { Line 963  sub render_resource {
         if ($it->{CONDITION}) {          if ($it->{CONDITION}) {
             $nowOpen = !$nowOpen;              $nowOpen = !$nowOpen;
         }          }
  my $folderType;  
  if (&advancedUser() && $resource->is_missing_map()) {   my $folderType = $resource->is_sequence() ? 'folder' : 'page';
     $folderType = 'none';  
  } else {  
     $folderType = $resource->is_sequence() ? 'folder' : 'page';  
  }  
         my $title=$resource->title;          my $title=$resource->title;
  $title=~s/\"/\&qout;/g;   $title=~s/\"/\&qout;/g;
         if (!$params->{'resource_no_folder_link'}) {          if (!$params->{'resource_no_folder_link'}) {
Line 1028  sub render_resource { Line 988  sub render_resource {
             # Don't allow users to manipulate folder              # Don't allow users to manipulate folder
             $icon = "navmap.$folderType." . ($nowOpen ? 'closed' : 'open') . '.gif';              $icon = "navmap.$folderType." . ($nowOpen ? 'closed' : 'open') . '.gif';
             $icon = "<img class=\"LC_space\" src='$whitespace' alt='' />"."<img class=\"LC_contentImage\" src='$location/$icon' alt=\"".($nowOpen ? &mt('Open Folder') : &mt('Close Folder')).' '.$title."\" />";              $icon = "<img class=\"LC_space\" src='$whitespace' alt='' />"."<img class=\"LC_contentImage\" src='$location/$icon' alt=\"".($nowOpen ? &mt('Open Folder') : &mt('Close Folder')).' '.$title."\" />";
             if ($params->{'caller'} eq 'sequence') {  
                 $linkopen = "<a href=\"$link\">";              $linkopen = "";
             } else {              $linkclose = "";
                 $linkopen = "";  
                 $linkclose = "";  
             }  
         }          }
         if (((&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) ||          if ((&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) &&
              (&Apache::lonnet::allowed('cev',$env{'request.course.id'}))) &&  
             ($resource->symb=~/\_\_\_[^\_]+\_\_\_uploaded/)) {              ($resource->symb=~/\_\_\_[^\_]+\_\_\_uploaded/)) {
             if (!$params->{'map_no_edit_link'}) {              if (!$params->{'map_no_edit_link'}) {
                 my $icon = &Apache::loncommon::lonhttpdurl('/res/adm/pages').'/editmap.png';                  my $icon = &Apache::loncommon::lonhttpdurl('/res/adm/pages').'/editmap.png';
Line 1046  sub render_resource { Line 1002  sub render_resource {
                          '</a>';                           '</a>';
             }              }
         }          }
         if ($params->{'mapHidden'} || $resource->randomout()) {      }
             $nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> ';  
         }      if ($resource->randomout()) {
     } else {          $nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> ';
         if ($resource->randomout()) {  
             $nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> ';  
         }  
     }      }
     if (!$resource->condval()) {      if (!$resource->condval()) {
         $nonLinkedText .= ' <span class="LC_info">('.&mt('conditionally hidden').')</span> ';          $nonLinkedText .= ' <span class="LC_info">('.&mt('conditionally hidden').')</span> ';
Line 1102  sub render_resource { Line 1055  sub render_resource {
     }      }
   
     if (!$params->{'resource_nolink'} && !$resource->is_sequence() && !$resource->is_empty_sequence) {      if (!$params->{'resource_nolink'} && !$resource->is_sequence() && !$resource->is_empty_sequence) {
         $linkclose = '</a>';          $result .= "$curMarkerBegin<a href=\"$link\">$title$partLabel</a>$curMarkerEnd$editmapLink$nonLinkedText</td>";
         if ($params->{'modalLink'}) {      } else {
             my $esclink = &js_escape($link);          $result .= "$curMarkerBegin$linkopen$title$partLabel</a>$curMarkerEnd$editmapLink$nonLinkedText</td>";
             if ($nomodal) {  
                 $linkopen = "<a href=\"#\" onclick=\"javascript:window.open('$esclink','resourcepreview','height=400,width=500,scrollbars=1,resizable=1,menubar=0,location=1'); return false;\" />";  
             } else {  
                 $linkopen = "<a href=\"$link\" onclick=\"javascript:openMyModal('$esclink',600,500,'yes','true'); return false;\">";  
             }  
         } else {  
             $linkopen = "<a href=\"$link\">";  
         }  
     }      }
     $result .= "$curMarkerBegin$linkopen$title$partLabel$linkclose$curMarkerEnd$editmapLink$nonLinkedText</td>";  
   
     return $result;      return $result;
 }  }
Line 1405  sub render { Line 1349  sub render {
             my $currenturl = $env{'form.postdata'};              my $currenturl = $env{'form.postdata'};
             #$currenturl=~s/^http\:\/\///;              #$currenturl=~s/^http\:\/\///;
             #$currenturl=~s/^[^\/]+//;              #$currenturl=~s/^[^\/]+//;
             unless ($args->{'caller'} eq 'sequence') {               
                 $here = $jump = &Apache::lonnet::symbread($currenturl);              $here = $jump = &Apache::lonnet::symbread($currenturl);
             }  
  }   }
  if (($here eq '') && ($args->{'caller'} ne 'sequence')) {    if ($here eq '') {
     my $last;      my $last;
     if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',      if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
                     &GDBM_READER(),0640)) {                      &GDBM_READER(),0640)) {
Line 1423  sub render { Line 1366  sub render {
         my $mapIterator = $navmap->getIterator(undef, undef, undef, 1);          my $mapIterator = $navmap->getIterator(undef, undef, undef, 1);
         my $curRes;          my $curRes;
         my $found = 0;          my $found = 0;
         my $here_is_navmaps = 0;  
         if ($here =~ m{___\d+___adm/navmaps$}) {  
             $here_is_navmaps = 1;  
         }  
                   
         # We only need to do this if we need to open the maps to show the          # 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          # current position. This will change the counter so we can't count
         # for the jump marker with this loop.          # for the jump marker with this loop.
         while ($here && ($curRes = $mapIterator->next()) && !$found && !$here_is_navmaps) {          while ($here && ($curRes = $mapIterator->next()) && !$found) {
             if (ref($curRes) && $curRes->symb() eq $here) {              if (ref($curRes) && $curRes->symb() eq $here) {
                 my $mapStack = $mapIterator->getStack();                  my $mapStack = $mapIterator->getStack();
                                   
Line 1473  sub render { Line 1412  sub render {
         if ($args->{'iterator_map'}) {          if ($args->{'iterator_map'}) {
             my $map = $args->{'iterator_map'};              my $map = $args->{'iterator_map'};
             $map = $navmap->getResourceByUrl($map);              $map = $navmap->getResourceByUrl($map);
             if (ref($map)) {              my $firstResource = $map->map_start();
                 my $firstResource = $map->map_start();              my $finishResource = $map->map_finish();
                 my $finishResource = $map->map_finish();  
                 $args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition);              $args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition);
             } else {  
                 return;  
             }  
         } else {          } else {
             $args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition,undef,$args->{'include_top_level_map'});              $args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition,undef,$args->{'include_top_level_map'});
         }          }
Line 1548  sub render { Line 1484  sub render {
  '&amp;here='.&escape($here);   '&amp;here='.&escape($here);
     $text='Open all folders';      $text='Open all folders';
         }          }
           if ($env{'form.register'}) {
               $link .= '&amp;register='.$env{'form.register'};
           }
  if ($args->{'caller'} eq 'navmapsdisplay') {   if ($args->{'caller'} eq 'navmapsdisplay') {
             unless ($args->{'notools'}) {              unless ($args->{'notools'}) {
                 &add_linkitem($args->{'linkitems'},'changefolder',                  &add_linkitem($args->{'linkitems'},'changefolder',
Line 1571  sub render { Line 1510  sub render {
  <input type="hidden" name="navurl" value="$querystr" />   <input type="hidden" name="navurl" value="$querystr" />
  <input type="hidden" name="navtime" value="$time" />   <input type="hidden" name="navtime" value="$time" />
 END  END
           if ($env{'form.register'}) {
               $result .= '<input type="hidden" name="register" value="'.$env{'form.register'}.'" />';
           }
         if ($args->{'sort'} eq 'discussion') {           if ($args->{'sort'} eq 'discussion') { 
     my $totdisc = 0;      my $totdisc = 0;
     my $haveDisc = '';      my $haveDisc = '';
Line 1592  END Line 1534  END
  $result.='</form>';   $result.='</form>';
     }      }
     if (($args->{'caller'} eq 'navmapsdisplay') &&      if (($args->{'caller'} eq 'navmapsdisplay') &&
         ((&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) ||          (&Apache::lonnet::allowed('mdc',$env{'request.course.id'}))) {
          (&Apache::lonnet::allowed('cev',$env{'request.course.id'})))) {  
         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};          my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};          my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
         if ($env{'course.'.$env{'request.course.id'}.'.url'} eq           if ($env{'course.'.$env{'request.course.id'}.'.url'} eq 
Line 1639  END Line 1580  END
     $args->{'indentString'} = setDefault($args->{'indentString'}, "<img src='$location' alt='' />");      $args->{'indentString'} = setDefault($args->{'indentString'}, "<img src='$location' alt='' />");
     $args->{'displayedHereMarker'} = 0;      $args->{'displayedHereMarker'} = 0;
   
     # If we're suppressing empty sequences, look for them here.      # If we're suppressing empty sequences, look for them here. Use DFS for speed,
     # We also do this even if $args->{'suppressEmptySequences'}      # since structure actually doesn't matter, except what map has what resources.
     # is not true, so we can hide empty sequences for which the      if ($args->{'suppressEmptySequences'}) {
     # hiddenresource parameter is set to yes (at map level), or          my $dfsit = Apache::lonnavmaps::DFSiterator->new($navmap,
     # mark as hidden for users who have $userCanSeeHidden.                                                           $it->{FIRST_RESOURCE},
     # Use DFS for speed, since structure actually doesn't matter,                                                           $it->{FINISH_RESOURCE},
     # except what map has what resources.                                                           {}, undef, 1);
           my $depth = 0;
     my $dfsit = Apache::lonnavmaps::DFSiterator->new($navmap,          $dfsit->next();
                                                      $it->{FIRST_RESOURCE},          my $curRes = $dfsit->next();
                                                      $it->{FINISH_RESOURCE},          while ($depth > -1) {
                                                      {}, undef, 1);              if ($curRes == $dfsit->BEGIN_MAP()) { $depth++; }
               if ($curRes == $dfsit->END_MAP()) { $depth--; }
     my $depth = 0;  
     $dfsit->next();              if (ref($curRes)) { 
     my $curRes = $dfsit->next();                  # Parallel pre-processing: Do sequences have non-filtered-out children?
     while ($depth > -1) {                  if ($curRes->is_map()) {
         if ($curRes == $dfsit->BEGIN_MAP()) { $depth++; }                      $curRes->{DATA}->{HAS_VISIBLE_CHILDREN} = 0;
         if ($curRes == $dfsit->END_MAP()) { $depth--; }                      # Sequences themselves do not count as visible children,
                       # unless those sequences also have visible children.
         if (ref($curRes)) {                      # This means if a sequence appears, there's a "promise"
             # Parallel pre-processing: Do sequences have non-filtered-out children?                      # that there's something under it if you open it, somewhere.
             if ($curRes->is_map()) {                  } else {
                 $curRes->{DATA}->{HAS_VISIBLE_CHILDREN} = 0;                      # Not a sequence: if it's filtered, ignore it, otherwise
                 # Sequences themselves do not count as visible children,                      # rise up the stack and mark the sequences as having children
                 # unless those sequences also have visible children.                      if (&$filterFunc($curRes)) {
                 # This means if a sequence appears, there's a "promise"                          for my $sequence (@{$dfsit->getStack()}) {
                 # that there's something under it if you open it, somewhere.                              $sequence->{DATA}->{HAS_VISIBLE_CHILDREN} = 1;
             } elsif ($curRes->src()) {                          }
                 # Not a sequence: if it's filtered, ignore it, otherwise  
                 # rise up the stack and mark the sequences as having children  
                 if (&$filterFunc($curRes)) {  
                     for my $sequence (@{$dfsit->getStack()}) {  
                         $sequence->{DATA}->{HAS_VISIBLE_CHILDREN} = 1;  
                     }                      }
                 }                  }
             }              }
           } continue {
               $curRes = $dfsit->next();
         }          }
     } continue {  
         $curRes = $dfsit->next();  
     }      }
   
     my $displayedJumpMarker = 0;      my $displayedJumpMarker = 0;
Line 1736  END Line 1672  END
  undef($args->{'sort'});   undef($args->{'sort'});
     }      }
   
     # Determine if page will be served with https in case  
     # it contains a syllabus which uses an external URL  
     # which points at an http site.  
   
     my ($is_ssl,$cdom,$cnum,$hostname);  
     if ($ENV{'SERVER_PORT'} == 443) {  
         $is_ssl = 1;  
         if ($r) {  
             $hostname = $r->hostname();  
         } else {  
             $hostname = $ENV{'SERVER_NAME'};  
         }  
     }  
     if ($env{'request.course.id'}) {  
         $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
         $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};  
     }  
   
     my $inhibitmenu;  
     if ($args->{'modalLink'}) {  
         $inhibitmenu = '&amp;inhibitmenu=yes';  
     }  
   
     while (1) {      while (1) {
  if ($args->{'sort'}) {   if ($args->{'sort'}) {
Line 1793  END Line 1707  END
         }           } 
   
         # If this is an empty sequence and we're filtering them, continue on          # If this is an empty sequence and we're filtering them, continue on
         $args->{'mapHidden'} = 0;          if ($curRes->is_map() && $args->{'suppressEmptySequences'} &&
         if (($curRes->is_map()) && (!$curRes->{DATA}->{HAS_VISIBLE_CHILDREN})) {              !$curRes->{DATA}->{HAS_VISIBLE_CHILDREN}) {
             if ($args->{'suppressEmptySequences'}) {              next;
                 next;  
             } else {  
                 my $mapname = &Apache::lonnet::declutter($curRes->src());  
                 $mapname = &Apache::lonnet::deversion($mapname);  
                 if (lc($navmap->get_mapparam(undef,$mapname,"0.hiddenresource")) eq 'yes') {  
                     if ($userCanSeeHidden) {  
                         $args->{'mapHidden'} = 1;  
                     } else {  
                         next;  
                     }  
                 }  
             }  
         }          }
   
         # If we're suppressing navmaps and this is a navmap, continue on          # If we're suppressing navmaps and this is a navmap, continue on
Line 1891  END Line 1793  END
  $stack=$it->getStack();   $stack=$it->getStack();
     }      }
     ($src,$symb,$anchor)=getLinkForResource($stack);      ($src,$symb,$anchor)=getLinkForResource($stack);
             my $srcHasQuestion = $src =~ /\?/;  
             if ($env{'request.course.id'}) {  
                 if (($is_ssl) && ($src =~ m{^\Q/public/$cdom/$cnum/syllabus\E($|\?)}) &&  
                     ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) {  
                     unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {  
                         if ($hostname ne '') {  
                             $src = 'http://'.$hostname.$src;  
                         }  
                         $src .= ($srcHasQuestion? '&amp;' : '?') . 'usehttp=1';  
                         $srcHasQuestion = 1;  
                     }  
                 } elsif (($is_ssl) && ($src =~ m{^\Q/adm/wrapper/ext/\E(?!https:)})) {  
                     unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {  
                         if ($hostname ne '') {  
                             $src = 'http://'.$hostname.$src;  
                         }  
                         $src .= ($srcHasQuestion? '&amp;' : '?') . 'usehttp=1';  
                         $srcHasQuestion = 1;  
                     }  
                 }  
             }  
     if (defined($anchor)) { $anchor='#'.$anchor; }      if (defined($anchor)) { $anchor='#'.$anchor; }
             if (($args->{'caller'} eq 'sequence') && ($curRes->is_map())) {      my $srcHasQuestion = $src =~ /\?/;
                 $args->{"resourceLink"} = $src.($srcHasQuestion?'&amp;':'?') .'navmap=1';      $args->{"resourceLink"} = $src.
             } else {   ($srcHasQuestion?'&amp;':'?') .
         $args->{"resourceLink"} = $src.   'symb=' . &escape($symb).$anchor;
     ($srcHasQuestion?'&amp;':'?') .  
     'symb=' . &escape($symb).$inhibitmenu.$anchor;  
             }  
  }   }
         # Now, we've decided what parts to show. Loop through them and          # Now, we've decided what parts to show. Loop through them and
         # show them.          # show them.
Line 1947  END Line 1825  END
                     $currentJumpDelta) {                      $currentJumpDelta) {
                     # Jam the anchor after the <td> tag;                      # Jam the anchor after the <td> tag;
                     # necessary for valid HTML (which Mozilla requires)                      # necessary for valid HTML (which Mozilla requires)
                     $colHTML =~ s/\>/\>\<a name="curloc" \>\<\/a\>/;                      $colHTML =~ s/\>/\>\<a name="curloc" \/\>/;
                     $displayedJumpMarker = 1;                      $displayedJumpMarker = 1;
                 }                  }
                 $result .= $colHTML . "\n";                  $result .= $colHTML . "\n";
Line 2333  sub generate_email_discuss_status { Line 2211  sub generate_email_discuss_status {
     foreach my $msgid (@keys) {      foreach my $msgid (@keys) {
  if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) {   if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) {
             my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid,              my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid,
                 $symb,$error) = &Apache::lonmsg::unpackmsgid(&LONCAPA::escape($msgid));                  $symb,$error) = &Apache::lonmsg::unpackmsgid($msgid);
             &Apache::lonenc::check_decrypt(\$symb);               &Apache::lonenc::check_decrypt(\$symb); 
             if (($fromcid ne '') && ($fromcid ne $cid)) {              if (($fromcid ne '') && ($fromcid ne $cid)) {
                 next;                  next;
Line 2830  sub parmval_real { Line 2708  sub parmval_real {
     if (defined($pack_def)) { return [$pack_def,'resource']; }      if (defined($pack_def)) { return [$pack_def,'resource']; }
     return [''];      return [''];
 }  }
   
 sub recurseup_maps {  
     my ($self,$mapname) = @_;  
     my @recurseup;  
     if ($mapname) {  
         my $res = $self->getResourceByUrl($mapname);  
         if (ref($res)) {  
             my @pcs = split(/,/,$res->map_hierarchy());  
             shift(@pcs);  
             if (@pcs) {  
                 @recurseup = map { &Apache::lonnet::declutter($self->getByMapPc($_)->src()); } reverse(@pcs);  
             }  
         }  
     }  
     return @recurseup;  
 }  
   
 sub recursed_crumbs {  
     my ($self,$mapurl,$restitle) = @_;  
     my (@revmapinfo,@revmapres);  
     my $mapres = $self->getResourceByUrl($mapurl);  
     if (ref($mapres)) {  
         @revmapres = map { $self->getByMapPc($_); } split(/,/,$mapres->map_breadcrumbs());  
         shift(@revmapres);  
     }  
     my $allowedlength = 60;  
     my $minlength = 5;  
     my $allowedtitle = 30;  
     if (($env{'environment.icons'} eq 'iconsonly') && (!$env{'browser.mobile'})) {  
         $allowedlength = 100;  
         $allowedtitle = 70;  
     }  
     if (length($restitle) > $allowedtitle) {  
         $restitle = &truncate_crumb_text($restitle,$allowedtitle);  
     }  
     my $totallength = length($restitle);  
     my @links;  
   
     foreach my $map (@revmapres) {  
         my $pc = $map->map_pc();  
         next if ((!$pc) || ($pc == 1));  
         push(@links,$map);  
         my $text = $map->title();  
         if ($text eq '') {  
             $text = '...';  
         }  
         push(@revmapinfo,{'href' => $env{'request.use_absolute'}.$map->link().'?navmap=1','text' => $text,'no_mt' => 1,});  
         $totallength += length($text);  
     }  
     my $numlinks = scalar(@links);  
     if ($numlinks) {  
         if ($totallength - $allowedlength > 0) {  
             my $available = $allowedlength - length($restitle);  
             my $avg = POSIX::ceil($available/$numlinks);  
             if ($avg < $minlength) {  
                 $avg = $minlength;  
             }  
             @revmapinfo = ();  
             foreach my $map (@links) {  
                 my $title = $map->title();  
                 if ($title eq '') {  
                     $title = '...';  
                 }  
                 my $showntitle = &truncate_crumb_text($title,$avg);  
                 if ($showntitle ne '') {  
                     push(@revmapinfo,{'href' => $env{'request.use_absolute'}.$map->link().'?navmap=1','text' => $showntitle,'no_mt' => 1,});  
                 }  
             }  
         }  
     }  
     if ($restitle ne '') {  
         push(@revmapinfo,{'text' => $restitle, 'no_mt' => 1});  
     }  
     return @revmapinfo;  
 }  
   
 sub truncate_crumb_text {  
     my ($title,$limit) = @_;  
     my $showntitle = '';  
     if (length($title) > $limit) {  
         my @words = split(/\b\s*/,$title);  
         if (@words == 1) {  
             $showntitle = substr($title,0,$limit).' ...';  
         } else {  
             my $linklength = 0;  
             my $num = 0;  
             foreach my $word (@words) {  
                 $linklength += 1+length($word);  
                 if ($word eq '-') {  
                     $showntitle =~ s/ $//;  
                     $showntitle .= $word;  
                 } elsif ($linklength > $limit) {  
                     if ($num < @words) {  
                         $showntitle .= $word.' ...';  
                         last;  
                     } else {  
                         $showntitle .= $word;  
                     }  
                 } else {  
                     $showntitle .= $word.' ';  
                 }  
             }  
             $showntitle =~ s/ $//;  
         }  
         return $showntitle;  
     } else {  
         return $title;  
     }  
 }  
   
 #  #
 #  Determines the open/close dates for printing a map that  #  Determines the open/close dates for printing a map that
 #  encloses a resource.  #  encloses a resource.
Line 2951  sub map_printdates { Line 2719  sub map_printdates {
   
   
   
     my $opendate = $self->get_mapparam($res->symb(),'',"$part.printstartdate");      my $opendate = $self->get_mapparam($res->symb(), "$part.printstartdate");
     my $closedate= $self->get_mapparam($res->symb(),'', "$part.printenddate");      my $closedate= $self->get_mapparam($res->symb(), "$part.printenddate");
   
   
     return ($opendate, $closedate);      return ($opendate, $closedate);
 }  }
   
 sub get_mapparam {  sub get_mapparam {
     my ($self, $symb, $mapname, $what) = @_;      my ($self, $symb, $what) = @_;
   
     # Ensure the course option hash is populated:      # Ensure the course option hash is populated:
   
Line 2978  sub get_mapparam { Line 2746  sub get_mapparam {
     my $uname=$self->{USERNAME};      my $uname=$self->{USERNAME};
     my $udom=$self->{DOMAIN};      my $udom=$self->{DOMAIN};
   
     unless ($symb || $mapname) { return; }      unless ($symb) { return ['']; }
     my $result='';      my $result='';
     my ($recursed,@recurseup);  
   
     # Figure out which map we are in.      # Figure out which map we are in.
   
     if ($symb && !$mapname) {      my ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb);
         my ($id,$fn);      $mapname = &Apache::lonnet::deversion($mapname);
         ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb);  
         $mapname = &Apache::lonnet::deversion($mapname);  
     }  
   
     my $rwhat=$what;      my $rwhat=$what;
     $what=~s/^parameter\_//;      $what=~s/^parameter\_//;
Line 3020  sub get_mapparam { Line 2786  sub get_mapparam {
  if (defined($$useropt{$courselevel})) {   if (defined($$useropt{$courselevel})) {
     return $$useropt{$courselevel};      return $$useropt{$courselevel};
  }   }
         if ($what =~ /\.(encrypturl|hiddenresource)$/) {  
             unless ($recursed) {  
                 @recurseup = $self->recurseup_maps($mapname);  
                 $recursed = 1;  
             }  
             foreach my $item (@recurseup) {  
                 my $norecursechk=$usercourseprefix.'.'.$item.'___(all).'.$what;  
                 if (defined($$useropt{$norecursechk})) {  
                     if ($what =~ /\.(encrypturl|hiddenresource)$/) {  
                         return $$useropt{$norecursechk};  
                     }  
                 }  
             }  
         }  
     }      }
   
     # Check course -- group      # Check course -- group
Line 3044  sub get_mapparam { Line 2796  sub get_mapparam {
  if (defined($$courseopt{$grplevel})) {   if (defined($$courseopt{$grplevel})) {
     return $$courseopt{$grplevel};      return $$courseopt{$grplevel};
  }   }
         if ($what =~ /\.(encrypturl|hiddenresource)$/) {  
             unless ($recursed) {  
                 @recurseup = $self->recurseup_maps($mapname);  
                 $recursed = 1;  
             }  
             foreach my $item (@recurseup) {  
                 my $norecursechk=$usercourseprefix.'.['.$cgroup.'].'.$item.'___(all).'.$what;  
                 if (defined($$courseopt{$norecursechk})) {  
                     if ($what =~ /\.(encrypturl|hiddenresource)$/) {  
                         return $$courseopt{$norecursechk};  
                     }  
                 }  
             }  
         }  
     }      }
   
     # Check course -- section      # Check course -- section
Line 3070  sub get_mapparam { Line 2808  sub get_mapparam {
  if (defined($$courseopt{$seclevel})) {   if (defined($$courseopt{$seclevel})) {
     return $$courseopt{$seclevel};      return $$courseopt{$seclevel};
  }   }
         if ($what =~ /\.(encrypturl|hiddenresource)$/) {  
             unless ($recursed) {  
                 @recurseup = $self->recurseup_maps($mapname);  
                 $recursed = 1;  
             }  
             foreach my $item (@recurseup) {  
                 my $norecursechk=$usercourseprefix.'.['.$csec.'].'.$item.'___(all).'.$what;  
                 if (defined($$courseopt{$norecursechk})) {  
                     if ($what =~ /\.(encrypturl|hiddenresource)$/) {  
                         return $$courseopt{$norecursechk};  
                     }  
                 }  
             }  
         }  
     }      }
     # Check the map parameters themselves:      # Check the map parameters themselves:
   
     if ($symb) {      my $thisparm = $$parmhash{$symbparm};
         my $symbparm=$symb.'.'.$what;      if (defined($thisparm)) {
         my $thisparm = $$parmhash{$symbparm};   return $thisparm;
         if (defined($thisparm)) {  
             return $thisparm;  
         }  
     }      }
   
   
Line 3102  sub get_mapparam { Line 2823  sub get_mapparam {
  if (defined($$courseopt{$courselevel})) {   if (defined($$courseopt{$courselevel})) {
     return $$courseopt{$courselevel};      return $$courseopt{$courselevel};
  }   }
         if ($what =~ /\.(encrypturl|hiddenresource)$/) {  
             unless ($recursed) {  
                 @recurseup = $self->recurseup_maps($mapname);  
                 $recursed = 1;  
             }  
             foreach my $item (@recurseup) {  
                 my $norecursechk=$usercourseprefix.'.'.$item.'___(all).'.$what;  
                 if (defined($$courseopt{$norecursechk})) {  
                     if ($what =~ /\.(encrypturl|hiddenresource)$/) {  
                         return $$courseopt{$norecursechk};  
                     }  
                 }  
             }  
         }  
     }      }
     return undef; # Unefined if we got here.      return undef; # Unefined if we got here.
 }  }
Line 3171  sub getcourseparam { Line 2878  sub getcourseparam {
     #       # 
     # We want the course level stuff from the way      # We want the course level stuff from the way
     # parmval_real operates       # parmval_real operates 
     # TODO: Factor some of this stuff out of      # TODO: Fator some of this stuff out of
     # both parmval_real and here      # both parmval_real and here
     #      #
     my $courselevel = $cid . '.' .  $what;      my $courselevel = $cid . '.' .  $what;
Line 3188  sub getcourseparam { Line 2895  sub getcourseparam {
     }      }
     # Try for the group's course level option:      # Try for the group's course level option:
   
     if ($cgroup ne '' and defined($courseopt)) {      if ($uname ne '' and defined($courseopt)) {
  if (defined($$courseopt{$grplevel})) {   if (defined($$courseopt{$grplevel})) {
     return $$courseopt{$grplevel};      return $$courseopt{$grplevel};
  }   }
Line 3196  sub getcourseparam { Line 2903  sub getcourseparam {
   
     #  Try for section level parameters:      #  Try for section level parameters:
   
     if ($csec ne '' and defined($courseopt)) {      if ($csec and defined($courseopt)) {
  if (defined($$courseopt{$seclevel})) {   if (defined($$courseopt{$seclevel})) {
     return $$courseopt{$seclevel};      return $$courseopt{$seclevel};
  }   }
     }      }
     # Try for 'additional' course parameters:      # Try for 'additional' course parameterse:
   
     if (defined($courseopt)) {      if (defined($courseopt)) {
  if (defined($$courseopt{$courselevel})) {   if (defined($$courseopt{$courselevel})) {
Line 3813  sub next { Line 3520  sub next {
     # That ends the main iterator logic. Now, do we want to recurse      # That ends the main iterator logic. Now, do we want to recurse
     # down this map (if this resource is a map)?      # down this map (if this resource is a map)?
     if ( ($self->{HERE}->is_sequence() || (!$closeAllPages && $self->{HERE}->is_page())) &&      if ( ($self->{HERE}->is_sequence() || (!$closeAllPages && $self->{HERE}->is_page())) &&
         (defined($self->{FILTER}->{$self->{HERE}->map_pc()}) xor $self->{CONDITION}) &&          (defined($self->{FILTER}->{$self->{HERE}->map_pc()}) xor $self->{CONDITION})) {
         ($env{'request.role.adv'} || !$self->{HERE}->randomout())) {  
         $self->{RECURSIVE_ITERATOR_FLAG} = 1;          $self->{RECURSIVE_ITERATOR_FLAG} = 1;
         my $firstResource = $self->{HERE}->map_start();          my $firstResource = $self->{HERE}->map_start();
         my $finishResource = $self->{HERE}->map_finish();          my $finishResource = $self->{HERE}->map_finish();
Line 4292  sub enclosing_map_src { Line 3998  sub enclosing_map_src {
 }  }
 sub symb {  sub symb {
     my $self=shift;      my $self=shift;
     if (defined($self->{SYMB})) { return $self->{SYMB}; }  
     (my $first, my $second) = $self->{ID} =~ /(\d+).(\d+)/;      (my $first, my $second) = $self->{ID} =~ /(\d+).(\d+)/;
     my $symbSrc = &Apache::lonnet::declutter($self->src());      my $symbSrc = &Apache::lonnet::declutter($self->src());
     my $symb = &Apache::lonnet::declutter($self->navHash('map_id_'.$first))       my $symb = &Apache::lonnet::declutter($self->navHash('map_id_'.$first)) 
Line 4483  sub is_sequence { Line 4188  sub is_sequence {
     return $self->navHash("is_map_", 1) &&       return $self->navHash("is_map_", 1) && 
     $self->navHash("map_type_" . $self->map_pc()) eq 'sequence';      $self->navHash("map_type_" . $self->map_pc()) eq 'sequence';
 }  }
 sub is_missing_map {  
     my $self=shift;  
     return $self->navHash("is_map_", 1) &&  
     $self->navHash("map_type_" . $self->map_pc()) eq 'none';  
 }  
 sub is_survey {  sub is_survey {
     my $self = shift();      my $self = shift();
     my $part = shift();      my $part = shift();
Line 4568  Returns a string with a comma-separated Line 4268  Returns a string with a comma-separated
 for the hierarchy of maps containing a map, with the top level  for the hierarchy of maps containing a map, with the top level
 map first, then descending to deeper levels, with the enclosing map last.  map first, then descending to deeper levels, with the enclosing map last.
   
 =item * B<map_breadcrumbs>:  
   
 Same as map_hierarchy, except maps containing only a single itemm if  
 it's a map, or containing no items are omitted, unless it's the top  
 level map (map_pc = 1), which is always included.  
   
 =back  =back
   
 =cut  =cut
Line 4609  sub map_hierarchy { Line 4303  sub map_hierarchy {
     my $pc = $self->map_pc();      my $pc = $self->map_pc();
     return $self->navHash("map_hierarchy_$pc", 0);      return $self->navHash("map_hierarchy_$pc", 0);
 }  }
 sub map_breadcrumbs {  
     my $self = shift;  
     my $pc = $self->map_pc();  
     return $self->navHash("map_breadcrumbs_$pc", 0);  
 }  
   
 #####  #####
 # Property queries  # Property queries
Line 4840  sub duedate { Line 4529  sub duedate {
     my $due_date=$self->parmval("duedate", $part);      my $due_date=$self->parmval("duedate", $part);
     if ($interval[0] =~ /\d+/) {      if ($interval[0] =~ /\d+/) {
        my $first_access=&Apache::lonnet::get_first_access($interval[1],         my $first_access=&Apache::lonnet::get_first_access($interval[1],
                                                           $self->{SYMB});                                                            $self->symb);
  if (defined($first_access)) {   if (defined($first_access)) {
            my $interval = $first_access+$interval[0];             my $interval = $first_access+$interval[0];
     $date = (!$due_date || $interval < $due_date) ? $interval       $date = (!$due_date || $interval < $due_date) ? $interval 
Line 4922  sub part_display { Line 4611  sub part_display {
     my $self= shift(); my $partID = shift();      my $self= shift(); my $partID = shift();
     if (! defined($partID)) { $partID = '0'; }      if (! defined($partID)) { $partID = '0'; }
     my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display',      my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display',
                                      $self->{SYMB});                                       $self->symb);
     if (! defined($display) || $display eq '') {      if (! defined($display) || $display eq '') {
         $display = $partID;          $display = $partID;
     }      }
Line 5341  The problem will be opened later. Line 5030  The problem will be opened later.
   
 Open and not yet due.  Open and not yet due.
   
   
 =item * B<PAST_DUE_ANSWER_LATER>:  =item * B<PAST_DUE_ANSWER_LATER>:
   
 The due date has passed, but the answer date has not yet arrived.  The due date has passed, but the answer date has not yet arrived.
Line 5353  The due date has passed and there is no Line 5043  The due date has passed and there is no
   
 The answer date is here.  The answer date is here.
   
 =item * B<NOTHING_SET>:  
   
 No dates have been set for this problem at all.  
   
 =item * B<PAST_DUE_ATMPT_ANS>:  
   
 The due date has passed, feedback is suppressed, the problem was attempted, and the answer date has not yet arrived.  
   
 =item * B<PAST_DUE_ATMPT_NOANS>:  
   
 The due date has passed, feedback is suppressed, the problem was attempted, and there is no answer opening date set.  
   
 =item * B<PAST_DUE_NO_ATMT_ANS>:  
   
 The due date has passed, feedback is suppressed, the problem was not attempted, and the answer date has not yet arrived.  
   
 =item * B<PAST_DUE_NO_ATMT_NOANS>:  
   
 The due date has passed, feedback is suppressed, the problem was not attempted, and there is no answer opening date set.  
   
 =item * B<NETWORK_FAILURE>:  =item * B<NETWORK_FAILURE>:
   
 The information is unknown due to network failure.  The information is unknown due to network failure.
Line 5388  sub PAST_DUE_NO_ANSWER     { return 2; } Line 5058  sub PAST_DUE_NO_ANSWER     { return 2; }
 sub PAST_DUE_ANSWER_LATER  { return 3; }  sub PAST_DUE_ANSWER_LATER  { return 3; }
 sub ANSWER_OPEN            { return 4; }  sub ANSWER_OPEN            { return 4; }
 sub NOTHING_SET            { return 5; }  sub NOTHING_SET            { return 5; }
 sub PAST_DUE_ATMPT_ANS     { return 6; }  
 sub PAST_DUE_ATMPT_NOANS   { return 7; }  
 sub PAST_DUE_NO_ATMT_ANS   { return 8; }  
 sub PAST_DUE_NO_ATMT_NOANS { return 9; }  
 sub NETWORK_FAILURE        { return 100; }  sub NETWORK_FAILURE        { return 100; }
   
 # getDateStatus gets the date status for a given problem part.   # getDateStatus gets the date status for a given problem part. 
Line 5581  set. Line 5247  set.
 The problem is past due, not considered correct, and an answer date in  The problem is past due, not considered correct, and an answer date in
 the future is set.  the future is set.
   
 =item * B<PAST_DUE_ATMPT_ANS>:  
   
 The problem is past due, feedback is suppressed, the problem was  
 attempted and an answer date in the future is set.  
   
 =item * B<PAST_DUE_ATMPT_NOANS>:  
   
 The problem is past due, feedback is suppressed, the problem was  
 attempted and no answer date is set.  
   
 =item * B<PAST_DUE_NO_ATMT_ANS>:  
   
 The problem is past due, feedback is suppressed, the problem was  
 not attempted and an answer date in the future is set.  
   
 =item * B<PAST_DUE_NO_ATMT_NOANS>:  
   
 The problem is past due, feedback is suppressed, the problem was  
 not attempted and no answer date is set.  
   
 =item * B<ANSWER_OPEN>:  =item * B<ANSWER_OPEN>:
   
 The problem is past due, not correct, and the answer is now available.  The problem is past due, not correct, and the answer is now available.
Line 5683  sub status { Line 5329  sub status {
     # 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 ) {
  if ( $suppressFeedback ) {   if ( $suppressFeedback ) { return ANSWER_SUBMITTED }
             if ($dateStatus == PAST_DUE_ANSWER_LATER ||  
                 $dateStatus == PAST_DUE_NO_ANSWER ) {  
                 if ($dateStatus == PAST_DUE_ANSWER_LATER) {  
                     return PAST_DUE_ATMPT_ANS;  
                 } else {  
                     return PAST_DUE_ATMPT_NOANS;  
                 }  
             } else {  
                 return ANSWER_SUBMITTED;  
             }  
         }  
  my $awarded=$self->awarded($part);   my $awarded=$self->awarded($part);
  if ($awarded < 1 && $awarded > 0) {   if ($awarded < 1 && $awarded > 0) {
             return PARTIALLY_CORRECT;              return PARTIALLY_CORRECT;
Line 5733  sub status { Line 5368  sub status {
   
     if ($dateStatus == PAST_DUE_ANSWER_LATER ||      if ($dateStatus == PAST_DUE_ANSWER_LATER ||
         $dateStatus == PAST_DUE_NO_ANSWER ) {          $dateStatus == PAST_DUE_NO_ANSWER ) {
         if ($suppressFeedback) {          return $suppressFeedback ? ANSWER_SUBMITTED : $dateStatus; 
             if ($completionStatus == NOT_ATTEMPTED) {  
                 if ($dateStatus == PAST_DUE_ANSWER_LATER) {  
                     return PAST_DUE_NO_ATMT_ANS;  
                 } else {  
                     return PAST_DUE_NO_ATMT_NOANS;  
                 }  
             } else {  
                 if ($dateStatus == PAST_DUE_ANSWER_LATER) {  
                     return PAST_DUE_ATMPT_ANS;  
                 } else {  
                     return PAST_DUE_ATMPT_NOANS;  
                 }  
             }  
         } else {  
             return $dateStatus;  
         }  
     }      }
   
     if ($dateStatus == ANSWER_OPEN) {      if ($dateStatus == ANSWER_OPEN) {
Line 5788  sub check_for_slot { Line 5407  sub check_for_slot {
         my $cnum=$env{'course.'.$cid.'.num'};          my $cnum=$env{'course.'.$cid.'.num'};
         my $now = time;          my $now = time;
         my $num_usable_slots = 0;          my $num_usable_slots = 0;
         my ($checkedin,$checkedinslot,%consumed_uniq,%slots);  
         if (@slots > 0) {          if (@slots > 0) {
             %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum);              my %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum);
             if (&Apache::lonnet::error(%slots)) {              if (&Apache::lonnet::error(%slots)) {
                 return (UNKNOWN);                  return (UNKNOWN);
             }              }
             my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime');              my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime');
               my ($checkedin,$checkedinslot);
               my ($map) = &Apache::lonnet::decode_symb($symb);
             foreach my $slot_name (@sorted_slots) {              foreach my $slot_name (@sorted_slots) {
                 next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name}));                  next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name}));
                 my $end = $slots{$slot_name}->{'endtime'};                  my $end = $slots{$slot_name}->{'endtime'};
Line 5818  sub check_for_slot { Line 5438  sub check_for_slot {
                                 ($checkedin,$checkedinslot) = $self->checkedin();                                  ($checkedin,$checkedinslot) = $self->checkedin();
                                 unless ((grep(/^\Q$checkedin\E/,@proctors)) &&                                  unless ((grep(/^\Q$checkedin\E/,@proctors)) &&
                                         ($checkedinslot eq $slot_name)) {                                          ($checkedinslot eq $slot_name)) {
                                     return (NEEDS_CHECKIN,$end,$slot_name);                                       return (NEEDS_CHECKIN,undef,$slot_name); 
                                 }                                  }
                             }                              }
                             return (RESERVED,$end,$slot_name);                              return (RESERVED,$end,$slot_name);
Line 5828  sub check_for_slot { Line 5448  sub check_for_slot {
                     $num_usable_slots ++;                      $num_usable_slots ++;
                 }                  }
             }              }
             my ($is_correct,$wait_for_grade);              my ($is_correct,$got_grade);
             if ($self->is_task()) {              if ($self->is_task()) {
                 my $taskstatus = $self->taskstatus();                  my $taskstatus = $self->taskstatus();
                 $is_correct = (($taskstatus eq 'pass') ||                   $is_correct = (($taskstatus eq 'pass') || 
                                ($self->solved() =~ /^correct_/));                                 ($self->solved() =~ /^correct_/));
                 unless ($taskstatus =~ /^(?:pass|fail)$/) {                  $got_grade = ($taskstatus =~ /^(?:pass|fail)$/);
                     $wait_for_grade = 1;  
                 }  
             } else {              } else {
                 unless ($self->completable()) {                  $got_grade = 1;
                     $wait_for_grade = 1;                  $is_correct = ($self->solved() =~ /^correct_/);   
                 }  
                 unless (($self->problemstatus($part) eq 'no') ||  
                         ($self->problemstatus($part) eq 'no_feedback_ever')) {  
                     $is_correct = ($self->solved($part) =~ /^correct_/);  
                     $wait_for_grade = 0;  
                 }  
             }              }
             ($checkedin,$checkedinslot) = $self->checkedin();              ($checkedin,$checkedinslot) = $self->checkedin();
             if ($checkedin) {              if ($checkedin) {
                 if (ref($slots{$checkedinslot}) eq 'HASH') {                  if (!$got_grade) {
                     $consumed_uniq{$checkedinslot} = $slots{$checkedinslot}{'uniqueperiod'};  
                 }  
                 if ($wait_for_grade) {  
                     return (WAITING_FOR_GRADE);                      return (WAITING_FOR_GRADE);
                 } elsif ($is_correct) {                  } elsif ($is_correct) {
                     return (CORRECT);                       return (CORRECT); 
Line 5867  sub check_for_slot { Line 5476  sub check_for_slot {
             if ((ref($reservable->{'now_order'}) eq 'ARRAY') && (ref($reservable->{'now'}) eq 'HASH')) {              if ((ref($reservable->{'now_order'}) eq 'ARRAY') && (ref($reservable->{'now'}) eq 'HASH')) {
                 foreach my $slot (reverse (@{$reservable->{'now_order'}})) {                  foreach my $slot (reverse (@{$reservable->{'now_order'}})) {
                     my $canuse;                      my $canuse;
                     if (($reservable->{'now'}{$slot}{'symb'} eq '') ||                      if ($reservable->{'now'}{$slot}{'symb'} eq '') {
                         ($reservable->{'now'}{$slot}{'symb'} eq $symb)) {  
                         $canuse = 1;                          $canuse = 1;
                     }                      } else {
                     if ($canuse) {                          my %oksymbs;
                         if ($checkedin) {                          my @slotsymbs = split(/\s*,\s*/,$reservable->{'now'}{$slot}{'symb'});
                             if (ref($consumed_uniq{$checkedinslot}) eq 'ARRAY') {                          map { $oksymbs{$_} = 1; } @slotsymbs;
                                 my ($uniqstart,$uniqend)=@{$consumed_uniq{$checkedinslot}};                          if ($oksymbs{$symb}) {
                                 if ($reservable->{'now'}{$slot}{'uniqueperiod'} =~ /^(\d+),(\d+)$/) {                              $canuse = 1;
                                     my ($new_uniq_start,$new_uniq_end) = ($1,$2);                          } else {
                                     next if (!                              foreach my $item (@slotsymbs) {
                                         ($uniqstart < $new_uniq_start && $uniqend < $new_uniq_start) ||                                  if ($item =~ /\.(page|sequence)$/) {
                                         ($uniqstart > $new_uniq_end   &&  $uniqend > $new_uniq_end  ));                                      (undef,undef, my $sloturl) = &Apache::lonnet::decode_symb($item);
                                       if (($map ne '') && ($map eq $sloturl)) {
                                           $canuse = 1;
                                           last;
                                       }
                                 }                                  }
                             }                              }
                         }                          }
                       }
                       if ($canuse) {
                         return(RESERVABLE,$reservable->{'now'}{$slot}{'endreserve'});                          return(RESERVABLE,$reservable->{'now'}{$slot}{'endreserve'});
                     }                      }
                 }                  }
Line 5890  sub check_for_slot { Line 5504  sub check_for_slot {
             if ((ref($reservable->{'future_order'}) eq 'ARRAY') && (ref($reservable->{'future'}) eq 'HASH')) {              if ((ref($reservable->{'future_order'}) eq 'ARRAY') && (ref($reservable->{'future'}) eq 'HASH')) {
                 foreach my $slot (@{$reservable->{'future_order'}}) {                  foreach my $slot (@{$reservable->{'future_order'}}) {
                     my $canuse;                      my $canuse;
                     if (($reservable->{'future'}{$slot}{'symb'} eq '') ||                      if ($reservable->{'future'}{$slot}{'symb'} eq '') {
                         ($reservable->{'future'}{$slot}{'symb'} eq $symb)) {  
                         $canuse = 1;                          $canuse = 1;
                     }                      } elsif ($reservable->{'future'}{$slot}{'symb'} =~ /,/) {
                     if ($canuse) {                          my %oksymbs;
                         if ($checkedin) {                          my @slotsymbs = split(/\s*,\s*/,$reservable->{'future'}{$slot}{'symb'});
                             if (ref($consumed_uniq{$checkedinslot}) eq 'ARRAY') {                          map { $oksymbs{$_} = 1; } @slotsymbs;
                                 my ($uniqstart,$uniqend)=@{$consumed_uniq{$checkedinslot}};                          if ($oksymbs{$symb}) {
                                 if ($reservable->{'future'}{$slot}{'uniqueperiod'} =~ /^(\d+),(\d+)$/) {                              $canuse = 1;
                                     my ($new_uniq_start,$new_uniq_end) = ($1,$2);                          } else {
                                     next if (!                              foreach my $item (@slotsymbs) {
                                         ($uniqstart < $new_uniq_start && $uniqend < $new_uniq_start) ||                                  if ($item =~ /\.(page|sequence)$/) {
                                         ($uniqstart > $new_uniq_end   &&  $uniqend > $new_uniq_end  ));                                      (undef,undef, my $sloturl) = &Apache::lonnet::decode_symb($item);
                                       if (($map ne '') && ($map eq $sloturl)) {
                                           $canuse = 1;
                                           last;
                                       }
                                 }                                  }
                             }                              }
                         }                          }
                       } elsif ($reservable->{'future'}{$slot}{'symb'} eq $symb) {
                           $canuse = 1;
                       }
                       if ($canuse) {
                         return(RESERVABLE_LATER,$reservable->{'future'}{$slot}{'startreserve'});                          return(RESERVABLE_LATER,$reservable->{'future'}{$slot}{'startreserve'});
                     }                      }
                 }                  }
Line 5959  my %compositeToSimple = Line 5580  my %compositeToSimple =
       EXCUSED()               => CORRECT,        EXCUSED()               => CORRECT,
       PAST_DUE_NO_ANSWER()    => INCORRECT,        PAST_DUE_NO_ANSWER()    => INCORRECT,
       PAST_DUE_ANSWER_LATER() => INCORRECT,        PAST_DUE_ANSWER_LATER() => INCORRECT,
       PAST_DUE_ATMPT_ANS()    => ATTEMPTED,  
       PAST_DUE_ATMPT_NOANS()  => ATTEMPTED,  
       PAST_DUE_NO_ATMT_ANS()  => CLOSED,  
       PAST_DUE_NO_ATMT_NOANS() => CLOSED,  
       ANSWER_OPEN()           => INCORRECT,        ANSWER_OPEN()           => INCORRECT,
       OPEN_LATER()            => CLOSED,        OPEN_LATER()            => CLOSED,
       TRIES_LEFT()            => OPEN,        TRIES_LEFT()            => OPEN,

Removed from v.1.509.2.17  
changed lines
  Added in v.1.510


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