--- loncom/interface/lonnavmaps.pm 2002/10/11 18:39:55 1.73 +++ loncom/interface/lonnavmaps.pm 2003/03/20 20:40:42 1.129.2.2 @@ -2,7 +2,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.73 2002/10/11 18:39:55 bowersj2 Exp $ +# $Id: lonnavmaps.pm,v 1.129.2.2 2003/03/20 20:40:42 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -37,381 +37,26 @@ # 3/1/1,6/1,17/1,29/1,30/1,2/8,9/21,9/24,9/25 Gerd Kortemeyer # YEAR=2002 # 1/1 Gerd Kortemeyer -# +# Oct-Nov Jeremy Bowers package Apache::lonnavmaps; use strict; use Apache::Constants qw(:common :http); -use Apache::lonnet(); use Apache::loncommon(); -use GDBM_File; use POSIX qw (floor strftime); -# -------------------------------------------------------------- Module Globals -my %hash; -my @rows; - -# -# These cache hashes need to be independent of user, resource and course -# (user and course can/should be in the keys) -# - -my %courserdatas; -my %userrdatas; - -# -# These global hashes are dependent on user, course and resource, -# and need to be initialized every time when a sheet is calculated -# -my %courseopt; -my %useropt; -my %parmhash; - -# This parameter keeps track of whether obtaining the user's information -# failed, which the colorizer in astatus can use -my $networkFailedFlag = 0; - -# ------------------------------------------------------------------ Euclid gcd - -sub euclid { - my ($e,$f)=@_; - my $a; my $b; my $r; - if ($e>$f) { $b=$e; $r=$f; } else { $r=$e; $b=$f; } - while ($r!=0) { - $a=$b; $b=$r; - $r=$a%$b; - } - return $b; -} - -# --------------------------------------------------------------------- Parmval - -# -------------------------------------------- Figure out a cascading parameter -# -# For this function to work -# -# * parmhash needs to be tied -# * courseopt and useropt need to be initialized for this user and course -# - -sub parmval { - my ($what,$symb)=@_; - my $cid=$ENV{'request.course.id'}; - my $csec=$ENV{'request.course.sec'}; - my $uname=$ENV{'user.name'}; - my $udom=$ENV{'user.domain'}; - - unless ($symb) { return ''; } - my $result=''; - - my ($mapname,$id,$fn)=split(/\_\_\_/,$symb); - -# ----------------------------------------------------- Cascading lookup scheme - my $rwhat=$what; - $what=~s/^parameter\_//; - $what=~s/\_/\./; - - my $symbparm=$symb.'.'.$what; - my $mapparm=$mapname.'___(all).'.$what; - my $usercourseprefix=$uname.'_'.$udom.'_'.$cid; - - my $seclevel= $usercourseprefix.'.['.$csec.'].'.$what; - my $seclevelr=$usercourseprefix.'.['.$csec.'].'.$symbparm; - my $seclevelm=$usercourseprefix.'.['.$csec.'].'.$mapparm; - - my $courselevel= $usercourseprefix.'.'.$what; - my $courselevelr=$usercourseprefix.'.'.$symbparm; - my $courselevelm=$usercourseprefix.'.'.$mapparm; - -# ---------------------------------------------------------- first, check user - if (defined($uname)) { - if (defined($useropt{$courselevelr})) { return $useropt{$courselevelr}; } - if (defined($useropt{$courselevelm})) { return $useropt{$courselevelm}; } - if (defined($useropt{$courselevel})) { return $useropt{$courselevel}; } - } - -# ------------------------------------------------------- second, check course - if (defined($csec)) { - if (defined($courseopt{$seclevelr})) { return $courseopt{$seclevelr}; } - if (defined($courseopt{$seclevelm})) { return $courseopt{$seclevelm}; } - if (defined($courseopt{$seclevel})) { return $courseopt{$seclevel}; } - } - - if (defined($courseopt{$courselevelr})) { return $courseopt{$courselevelr}; } - if (defined($courseopt{$courselevelm})) { return $courseopt{$courselevelm}; } - if (defined($courseopt{$courselevel})) { return $courseopt{$courselevel}; } - -# ----------------------------------------------------- third, check map parms - - my $thisparm=$parmhash{$symbparm}; - if (defined($thisparm)) { return $thisparm; } - -# ----------------------------------------------------- fourth , check default - - my $default=&Apache::lonnet::metadata($fn,$rwhat.'.default'); - if (defined($default)) { return $default} - -# --------------------------------------------------- fifth , cascade up parts - - my ($space,@qualifier)=split(/\./,$rwhat); - my $qualifier=join('.',@qualifier); - unless ($space eq '0') { - my ($part,$id)=split(/\_/,$space); - if ($id) { - my $partgeneral=&parmval($part.".$qualifier",$symb); - if (defined($partgeneral)) { return $partgeneral; } - } else { - my $resourcegeneral=&parmval("0.$qualifier",$symb); - if (defined($resourcegeneral)) { return $resourcegeneral; } - } - } - return ''; -} - - - -# ------------------------------------------------------------- Find out status -# return codes -# tcode (timecode) -# 1: will open later -# 2: is open and not past due yet -# 3: is past due date -# 4: due in the next 24 hours -# -# code (curent solved status) -# 1: not attempted -# 2: attempted but wrong, or incorrect by instructor -# 3: solved or correct by instructor -# 4: partially correct (one or more parts correct) -# "excused" needs to be supported, but is not yet. -sub astatus { - my $rid=shift; - my $code=0; - my $ctext=''; - $rid=~/(\d+)\.(\d+)/; - my $symb=&Apache::lonnet::declutter($hash{'map_id_'.$1}).'___'.$2.'___'. - &Apache::lonnet::declutter($hash{'src_'.$rid}); - my %duedate=(); - my %opendate=(); - my %answerdate=(); - # need to always check part 0's open/due/answer status - foreach (sort(split(/\,/,&Apache::lonnet::metadata($hash{'src_'.$rid},'allpo\ssiblekeys')))) { - if ($_=~/^parameter\_(.*)\_opendate$/) { - my $part=$1; - $duedate{$part}=&parmval($part.'.duedate',$symb); - $opendate{$part}=&parmval($part.'.opendate',$symb); - $answerdate{$part}=&parmval($part.'.answerdate',$symb); - if (&parmval($part.'.opendate.type',$symb) eq 'date_interval') { - $opendate{$part}=$duedate{$part}-$opendate{$part}; - } - if (&parmval($part.'.answerdate.type',$symb) eq 'date_interval') { - $answerdate{$part}=$duedate{$part}+$answerdate{$part}; - } - } - } - my $now=time; - my $tcode=0; - - my %returnhash=&Apache::lonnet::restore($symb); - - foreach (sort(keys(%opendate))) { - my $duedate=$duedate{$_}; - my $opendate=$opendate{$_}; - my $answerdate=$answerdate{$_}; - my $preface=''; - unless ($_ eq '0') { $preface=' Part: '.$_.' '; } - if ($opendate) { - if ($now<$duedate || (!$duedate)) { - unless ($tcode==4) { $tcode=2; } - if ($duedate) { - $ctext.=$preface.'Due: '.localtime($duedate); - } else { - $ctext.=$preface.'No Due Date'; - } - if ($now<$opendate) { - unless ($tcode) { $tcode=1; } - $ctext.=$preface.'Open: '.localtime($opendate); - } - if ($duedate && $duedate-$now<86400) { - $tcode=4; - $ctext.=$preface.'Due: '.localtime($duedate); - } - } else { - unless (($tcode==4) || ($tcode eq 2)) { $tcode=3; } - if ($now<$answerdate) { - $ctext.='Answer: '.localtime($duedate); - } - } - } else { - unless (($tcode==2) || ($tcode==4)) { $tcode=1; } - } - - my $status=$returnhash{'resource.'.$_.'.solved'}; - - if ($status eq 'correct_by_student') { - if ($code==0||$code==3) { $code=3; } else { $code=4; } - $ctext.=' solved'; - } elsif ($status eq 'correct_by_override') { - if ($code==0||$code==3) { $code=3; } else { $code=4; } - $ctext.=' override'; - } elsif ($status eq 'incorrect_attempted') { - if ($code!=4 && $code!=3) { $code=2; } - if ($code==3) { $code=4; } - $ctext.=' ('. - ($returnhash{'resource.'.$_.'.tries'}? - $returnhash{'resource.'.$_.'.tries'}:'0'); - my $numtries = &parmval($_.'.maxtries',$symb); - if ($numtries) { $ctext.='/'.$numtries.' tries'; } - $ctext.=')'; - } elsif ($status eq 'incorrect_by_override') { - if ($code!=4 && $code!=3) { $code=2; } - if ($code==3) { $code=4; } - $ctext.=' override'; - } elsif ($status eq 'excused') { - if ($code==0||$code==3) { $code=3; } else { $code=4; } - $ctext.=' excused'; - } else { - if ($code==0) { $code=1; } - } - } - - return 'p'.$code.$tcode.'"'.$ctext.'"'; -} - - -sub addresource { - my ($resource,$sofar,$rid,$showtypes,$indent,$linkid)=@_; - if ($showtypes eq 'problems') { - if ($resource!~/\.(problem|exam|quiz|assess|survey|form)$/) { - return; - } - } - my $brepriv=&Apache::lonnet::allowed('bre',$resource); - if ($hash{'src_'.$rid}) { - if (($brepriv eq '2') || ($brepriv eq 'F')) { - my $pprefix=''; - if ($resource=~/\.(problem|exam|quiz|assess|survey|form)$/) { - $pprefix=&astatus($rid); - } - $$sofar++; - if ($indent) { $pprefix='i'.$indent.','.$pprefix; } - if ($linkid) { $pprefix='l'.$linkid.','.$pprefix; } - if (defined($rows[$$sofar])) { - $rows[$$sofar].='&'.$pprefix.$rid; - } else { - $rows[$$sofar]=$pprefix.$rid; - } - } - } -} - -sub followlinks () { - my ($rid,$sofar,$beenhere,$further,$showtypes,$indent,$linkid)=@_; - my $mincond=1; - my $next=''; - foreach (split(/\,/,$hash{'to_'.$rid})) { - my $thiscond= - &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$_}}); - if ($thiscond>=$mincond) { - if ($next) { - $next.=','.$_.':'.$thiscond; - } else { - $next=$_.':'.$thiscond; - } - if ($thiscond>$mincond) { $mincond=$thiscond; } - } - } - my $col=0; - &Apache::lonxml::debug("following links -$next-"); - foreach (split(/\,/,$next)) { - my ($nextlinkid,$condval)=split(/\:/,$_); - if ($condval>=$mincond) { - my $now=&tracetable($sofar,$hash{'goesto_'.$nextlinkid}, - $beenhere,$showtypes,$indent,$linkid); - if ($now>$further) { - if ($col>0) { - my $string; - for(my $i=0;$i<$col;$i++) { $string.='&'; } - for(my $i=$further+1;$now-1>$i;$i++) { - $rows[$i]=$string.$rows[$i]; - } - } - $further=$now; - } - } - $col++; - } - return $further; -} -# ------------------------------------------------------------ Build page table - -sub tracetable { - my ($sofar,$rid,$beenhere,$showtypes,$indent,$linkid)=@_; - my $newshowtypes=$showtypes; - my $further=$sofar; -# $Apache::lonxml::debug=1; - &Apache::lonxml::debug("$rid ; $linkid ; $sofar ; $beenhere ; ".$hash{'src_'.$rid}); - if ($beenhere=~/\&$rid\&/) { return $further; } - $beenhere.=$rid.'&'; - - if (defined($hash{'is_map_'.$rid})) { - $sofar++; - my $tprefix=''; - if ($hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}} - eq 'sequence') { - $tprefix='h'; - } elsif ($hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}} - eq 'page') { - $tprefix='j'; - if ($indent) { $tprefix='i'.$indent.','.$tprefix; } - if ($linkid) { $tprefix='l'.$linkid.','.$tprefix; } - $newshowtypes='problems'; - $indent++; - #if in a .page continue to link the encompising .page - if (!$linkid) { $linkid=$rid; } - } - if (defined($rows[$sofar])) { - $rows[$sofar].='&'.$tprefix.$rid; - } else { - $rows[$sofar]=$tprefix.$rid; - } - if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) && - (defined($hash{'map_finish_'.$hash{'src_'.$rid}}))) { - my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}}; - $sofar=&tracetable($sofar,$hash{'map_start_'.$hash{'src_'.$rid}}, - '&'.$frid.'&',$newshowtypes,$indent,$linkid); - &addresource($hash{'src_'.$frid},\$sofar,$frid,$newshowtypes, - $indent,$linkid); - if ($tprefix =~ /j$/) { $indent--; $linkid=''; } - } - } else { - &addresource($hash{'src_'.$rid},\$sofar,$rid,$showtypes, - $indent,$linkid); - } - - if (defined($hash{'to_'.$rid})) { - $further=&followlinks($rid,$sofar,$beenhere,$further,$showtypes, - $indent,$linkid); - } - - return $further; +sub handler { + my $r = shift; + real_handler($r); } -# ================================================================ Main Handler - -sub handler { - my $r=shift; +sub real_handler { + my $r = shift; &Apache::loncommon::get_unprocessed_cgi($ENV{QUERY_STRING}); - if ($ENV{'form.jtest'} ne "1") - { - return new_handle($r); - } - -# ------------------------------------------- Set document type for header only - + # Handle header-only request if ($r->header_only) { if ($ENV{'browser.mathml'}) { $r->content_type('text/xml'); @@ -421,28 +66,8 @@ sub handler { $r->send_http_header; return OK; } - my $requrl=$r->uri; - my $hashtied; -# ----------------------------------------------------------------- Tie db file - my $fn; - if ($ENV{'request.course.fn'}) { - $fn=$ENV{'request.course.fn'}; - if (-e "$fn.db") { - if ((tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER(),0640)) && - (tie(%parmhash,'GDBM_File', - $ENV{'request.course.fn'}.'_parms.db', - &GDBM_READER(),0640))) { - $hashtied=1; - } - } - } - if (!$hashtied) { - $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized"; - return HTTP_NOT_ACCEPTABLE; - } - -# ------------------------------------------------------------------- Hash tied + # Send header, don't cache this page if ($ENV{'browser.mathml'}) { $r->content_type('text/xml'); } else { @@ -451,408 +76,112 @@ sub handler { &Apache::loncommon::no_cache($r); $r->send_http_header; - my $firstres=$hash{'map_start_'. - &Apache::lonnet::clutter($ENV{'request.course.uri'})}; - my $lastres=$hash{'map_finish_'. - &Apache::lonnet::clutter($ENV{'request.course.uri'})}; - if (!(($firstres) && ($lastres))) { - $r->print('
Coursemap undefined.'); - } else { - -# ----------------------------------------------------------------- Render page -# -------------------------------------------------------------- Set parameters - - -# ---------------------------- initialize coursedata and userdata for this user - undef %courseopt; - undef %useropt; - - my $uname=$ENV{'user.name'}; - my $udom=$ENV{'user.domain'}; - my $uhome=$ENV{'user.home'}; - my $cid=$ENV{'request.course.id'}; - my $chome=$ENV{'course.'.$cid.'.home'}; - my ($cdom,$cnum)=split(/\_/,$cid); - - my $userprefix=$uname.'_'.$udom.'_'; - - unless ($uhome eq 'no_host') { -# ------------------------------------------------- Get coursedata (if present) - unless ((time-$courserdatas{$cid.'.last_cache'})<240) { - my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum. - ':resourcedata',$chome); - if ($reply!~/^error\:/) { - $courserdatas{$cid}=$reply; - $courserdatas{$cid.'.last_cache'}=time; - } - # check to see if network failed - elsif ( $reply=~/no.such.host/i || $reply=~/con.*lost/i ) - { - $networkFailedFlag = 1; - } - } - foreach (split(/\&/,$courserdatas{$cid})) { - my ($name,$value)=split(/\=/,$_); - $courseopt{$userprefix.&Apache::lonnet::unescape($name)}= - &Apache::lonnet::unescape($value); - } -# --------------------------------------------------- Get userdata (if present) - unless ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) { - my $reply=&Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome); - if ($reply!~/^error\:/) { - $userrdatas{$uname.'___'.$udom}=$reply; - $userrdatas{$uname.'___'.$udom.'.last_cache'}=time; - } - } - foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) { - my ($name,$value)=split(/\=/,$_); - $useropt{$userprefix.&Apache::lonnet::unescape($name)}= - &Apache::lonnet::unescape($value); - } - } + # Create the nav map + my $navmap = Apache::lonnavmaps::navmap->new( + $ENV{"request.course.fn"}.".db", + $ENV{"request.course.fn"}."_parms.db", 1, 1); - @rows=(); - &tracetable(0,$firstres,'&','',0); + if (!defined($navmap)) { + my $requrl = $r->uri; + $ENV{'user.error.msg'} = "$requrl:bre:0:0:Course not initialized"; + return HTTP_NOT_ACCEPTABLE; + } -# ------------------------------------------------------------------ Page parms + $r->print("\n"); + $r->print("Key: | '); - unless ($contents) { - $r->print('Empty Map.'); - } else { + # Print discussions and feedback header + if ($navmap->{LAST_CHECK}) { + $r->print(''. + ' New discussion since '. + strftime("%A, %b %e at %I:%M %P", localtime($navmap->{LAST_CHECK})). + ' | '.
+ ' New message (click to open) '. + ' | ');
+ } else {
+ $r->print(''. + ' Discussions | '. + ' New message (click to open)'. + ' | '); + } + $r->print('
'); - if (($currenturl=~/^\/res/) && - ($currenturl!~/^\/res\/adm/)) { - $r->print('Current Location
'); - } - - # Handle a network error - - if ($networkFailedFlag) - { - $r->print('
LON-CAPA's network is having difficulties, some problem" .
- " information, such as due dates, will not be available.");
- }
-# ----------------------------------------------------- The little content list
- for ($i=0;$i<=$#rows;$i++) {
- if ($rows[$i]) {
- my @colcont=split(/\&/,$rows[$i]);
- my $avespan=$lcm/($#colcont+1);
- for ($j=0;$j<=$#colcont;$j++) {
- my $rid=$colcont[$j];
- if ($rid=~/^h(.+)/) {
- $rid=$1;
- $r->print(' '.$hash{'title_'.$rid}.
- '
');
- }
- }
- }
- }
-# ----------------------------------------------------------------- Start table
- $r->print('
'; - my $adde=' | '; - my $hwk=''; - my $hwke=''; - if ($rid=~/^l(\d+\.\d+),(.+)/) { $linkid=$1; $rid=$2; } - if ($rid=~/^i(\d+),(.+)/) { $indent=$1; $rid=$2; } - if ($rid=~/^h(.+)/) { - $rid=$1; - $add=''; - $adde=' | '; - if (($ENV{'user.adv'}) && - ($parmhash{$symb.'.0.parameter_randompick'})) { - $adde=' (randomly select '. - $parmhash{$symb.'.0.parameter_randompick'}. - ')'; - } - } - if ($rid=~/^j(.+)/) { $rid=$1; } - if ($rid=~/^p(\d)(\d)\"([\w\: \(\)\/\,]*)\"(.+)/) { - # sub astatus describes what code/tcode mean - my $code=$1; - my $tcode=$2; - my $ctext=$3; - $rid=$4; - - # will open later - if ($tcode eq '1') { - $add=''; - } - - # solved/correct - if ($code eq '3') { - $add=' | '; - } elsif ($code eq '4') { # partially correct - $add=' | '; - } else { - # not attempted - - # we end up here on network failure, so pick a neutral - # color if the network failed instead of bright red. - if ( $networkFailedFlag ) - { - $add = ' | '; - } - else - { - $add=' | '; - } - - if ($tcode eq '2') { # open, not past due - $add=' | '; - } - - if ($tcode eq '4') { # due in next 24 hours - $add=' | '; - $adde=' | '; - } - } - $hwk=''; - $hwke=''; - if ($code eq '1') { - $hwke=' ('.$ctext.')'; - } - if ($code eq '2' || $code eq '4') { - $hwk=''; - $hwke=' ('.$ctext.')'; - } - if ($code eq '3') { - $hwk=''; - $hwke=' ('.$ctext.')'; - } - if ($networkFailedFlag) - { - $hwke=' (status unavailable)'; - } - } - if ($rid && $hash{'src_'.$rid} eq $currenturl) { - $add=$add.''. - '> '; - $adde= - ' <'.$adde; - } - if ($discussiontimes{$symb}>$lastcheck) { - $adde= - ''. - $adde; - } - if ($error{$src}) { - foreach (split(/\,/,$error{$src})) { - if ($_) { - $adde= - ' ' - .$adde; - } - } - } - if ($feedback{$src}) { - foreach (split(/\,/,$feedback{$src})) { - if ($_) { - $adde= - ' ' - .$adde; - } - } - } - if ($indent) { - my $is=" "; - for(my $i=-1;$i<$indent;$i++) { $indentstr.=$is; } - } - if (!$linkid) { $linkid=$rid; } - if ($hash{'randomout_'.$rid}) { - $adde=' (hidden)'.$adde; - } - $r->print($add.$indentstr); - if ($rid) { - $r->print(''. - $hwk.$hash{'title_'.$rid}.$hwke.''); - } - $r->print($adde); - } - $r->print('
---|
');
- } else {
- $r->print(' Discussions'.
- '
New message (click to open)
'); - } - #if (($currenturl=~/^\/res/) && - # ($currenturl!~/^\/res\/adm/)) { - # $r->print('Current Location
');
- #}
# Check that it's defined
if (!($navmap->courseMapDefined())) {
@@ -865,14 +194,17 @@ sub new_handle {
# is technically not proper, but should be harmless
my $res = $navmap->firstResource();
+ # These are some data tables, which make it easy to change some of
+ # of the specific visualization parameters if desired.
+
# Defines a status->color mapping, null string means don't color
my %colormap =
( $res->NETWORK_FAILURE => '',
$res->CORRECT => '',
- $res->EXCUSED => '#BBBBFF',
+ $res->EXCUSED => '#3333FF',
$res->PAST_DUE_ANSWER_LATER => '',
$res->PAST_DUE_NO_ANSWER => '',
- $res->ANSWER_OPEN => '#CCFFCC',
+ $res->ANSWER_OPEN => '#006600',
$res->OPEN_LATER => '',
$res->TRIES_LEFT => '',
$res->INCORRECT => '',
@@ -880,8 +212,10 @@ sub new_handle {
$res->NOTHING_SET => '' );
# And a special case in the nav map; what to do when the assignment
# is not yet done and due in less then 24 hours
- my $hurryUpColor = "#FFCCCC";
+ my $hurryUpColor = "#FF0000";
+ # Keep these mappings in sync with lonquickgrades, which uses the colors
+ # instead of the icons.
my %statusIconMap =
( $res->NETWORK_FAILURE => '',
$res->NOTHING_SET => '',
@@ -894,7 +228,7 @@ sub new_handle {
$res->TRIES_LEFT => 'navmap.open.gif',
$res->INCORRECT => 'navmap.wrong.gif',
$res->OPEN => 'navmap.open.gif',
- $res->ATTEMPTED => '' );
+ $res->ATTEMPTED => 'navmap.open.gif' );
my %iconAltTags =
( 'navmap.correct.gif' => 'Correct',
@@ -914,23 +248,88 @@ sub new_handle {
}
}
- my $currenturl = $ENV{'form.postdata'};
- $currenturl=~s/^http\:\/\///;
- $currenturl=~s/^[^\/]+//;
- my $queryAdd = "postdata=" . &Apache::lonnet::escape($currenturl);
-
- $r->print('Show All Resources
');
+ # 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.
+ my $topResource = $navmap->getById("0.0");
# Begin the HTML table
# four cols: resource + indent, chat+feedback, icon, text string
- $r->print('
\n"); + $rowNum++; + my $backgroundColor = $backgroundColors[$rowNum % scalar(@backgroundColors)]; + + # FIRST COL: The resource indentation, branch icon, name, and anchor + $r->print(" | ||||||||||
\n"); + + # Print the anchor if necessary + if ($counter == $currentJumpIndex - $currentJumpDelta ) { + $r->print(''); + $displayedJumpMarker = 1; + } # print indentation for (my $i = 0; $i < $indentLevel - $deltalevel; $i++) { @@ -1126,24 +571,38 @@ sub new_handle { $r->print(" ${newBranchText}${linkopen}$icon${linkclose}\n"); - if ($curRes->is_problem() && $part ne "0" && !$condensed) { + my $curMarkerBegin = ""; + my $curMarkerEnd = ""; + + # Is this the current resource? + if (!$displayedHereMarker && + (($hereType == $SYMB && $curRes->symb eq $here) || + ($hereType == $URL && $curRes->src eq $here))) { + $curMarkerBegin = '> '; + $curMarkerEnd = ' <'; + $displayedHereMarker = 1; + } + + if ($curRes->is_problem() && $part ne "" && !$condensed) { $partLabel = " (Part $part)"; $title = ""; } - if ($multipart && $condensed) { + if ($condensed && $curRes->countParts() > 1) { $nonLinkedText .= ' (' . $curRes->countParts() . ' parts)'; } - $r->print(" $title$partLabel $nonLinkedText"); + $r->print(" $curMarkerBegin$title$partLabel $curMarkerEnd $nonLinkedText"); - if ($curRes->{RESOURCE_ERROR}) { - $r->print(&Apache::loncommon::help_open_topic ("Navmap_Host_Down", - 'Host down')); - } + #if ($curRes->{RESOURCE_ERROR}) { + # $r->print(&Apache::loncommon::help_open_topic ("Navmap_Host_Down", + # 'Host down')); + # } + + $r->print(" | \n"); - my $discussionHTML = ""; my $feedbackHTML = ""; + # SECOND COL: Is there text, feedback, errors?? + my $discussionHTML = ""; my $feedbackHTML = ""; my $errorHTML = ""; - # SECOND COL: Is there text or feedback? if ($curRes->hasDiscussion()) { $discussionHTML = $linkopen . '' . @@ -1162,11 +621,24 @@ sub new_handle { } } - $r->print("$discussionHTML$feedbackHTML | "); + if ($curRes->getErrors()) { + my $errors = $curRes->getErrors(); + foreach (split(/,/, $errors)) { + if ($_) { + $errorHTML .= ' ' + . ''; + } + } + } + + $r->print("$discussionHTML$feedbackHTML$errorHTML | "); # Is this the first displayed part of a multi-part problem # that has not been condensed, so we should suppress these two - # columns? + # columns so we don't display useless status info about part + # "0"? my $firstDisplayed = !$condensed && $multipart && $part eq "0"; # THIRD COL: Problem status icon @@ -1175,36 +647,48 @@ sub new_handle { my $icon = $statusIconMap{$curRes->status($part)}; my $alt = $iconAltTags{$icon}; if ($icon) { - $r->print("$linkopen$linkclose | \n"); + $r->print("$linkopen$linkclose | \n"); } else { - $r->print("\n"); + $r->print(" | \n"); } } else { # not problem, no icon - $r->print(" | \n"); + $r->print(" | \n"); } # FOURTH COL: Text description - $r->print(" | \n"); + $r->print(" | \n"); if ($curRes->kind() eq "res" && $curRes->is_problem() && !$firstDisplayed) { + $r->print ("") if ($color); $r->print (getDescription($curRes, $part)); + $r->print ("") if ($color); } if ($curRes->is_map() && advancedUser() && $curRes->randompick()) { $r->print('(randomly select ' . $curRes->randompick() .')'); } - $r->print(" |