--- loncom/interface/lonnavmaps.pm 2003/02/06 21:26:21 1.138 +++ loncom/interface/lonnavmaps.pm 2003/02/06 22:58:12 1.139 @@ -2,7 +2,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.138 2003/02/06 21:26:21 bowersj2 Exp $ +# $Id: lonnavmaps.pm,v 1.139 2003/02/06 22:58:12 bowersj2 Exp $ # # Copyright Michigan State University Board of Trustees # @@ -252,17 +252,7 @@ sub real_handler { return OK; } - # Grab a resource object so we have access to the constants; this - # 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. - - my %condenseStatuses = - ( $res->NETWORK_FAILURE => 1, - $res->NOTHING_SET => 1, - $res->CORRECT => 1 ); + my $res = "Apache::lonnavmaps::resource"; my %filterHash; # Figure out what we're not displaying @@ -272,10 +262,6 @@ sub real_handler { } } - # 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"); @@ -284,7 +270,7 @@ sub real_handler { # instead of uris. The changes to this and the main rendering # loop should be obvious. # Here's a simple example of the iterator. - # Preprocess the map: Look for current URL, force inlined maps to display + # Preprocess the map: Look for current URL, open necessary maps my $mapIterator = $navmap->getIterator(undef, undef, undef, 1); my $found = 0; @@ -354,359 +340,13 @@ sub real_handler { $curRes = $mapIterator->next(); } - undef $res; # so we don't accidentally use it later - my $indentLevel = 0; - my $indentString = ""; - - my $isNewBranch = 0; - my $now = time(); - my $in24Hours = $now + 24 * 60 * 60; - my $displayedHereMarker = 0; - my $displayedJumpMarker = 0; - - # We know the first thing is a BEGIN_MAP (see "$self->{STARTED}" - # code in iterator->next), so ignore the first one - $mapIterator = $navmap->getIterator(undef, undef, \%filterHash, - $condition); - $mapIterator->next(); - $curRes = $mapIterator->next(); - $depth = 1; - - my @backgroundColors = ("#FFFFFF", "#F6F6F6"); - my $rowNum = 0; - - $counter = 0; - - while ($depth > 0) { - if ($curRes == $mapIterator->BEGIN_MAP() || - $curRes == $mapIterator->BEGIN_BRANCH()) { - $indentLevel++; - } - if ($curRes == $mapIterator->END_MAP() || - $curRes == $mapIterator->END_BRANCH()) { - $indentLevel--; - } - if ($curRes == $mapIterator->BEGIN_BRANCH()) { - $isNewBranch = 1; - } - if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; } - if ($curRes == $mapIterator->END_MAP()) { $depth--; } - - if (ref($curRes)) { $counter++; } - - if (ref($curRes)) { - - my $deltalevel = $isNewBranch? 1 : 0; # reserves space for branch icon - - if ($indentLevel - $deltalevel < 0) { - # If this would be at a negative depth (top-level maps in - # new-style courses, we want to suppress their title display) - # then ignore it. - $curRes = $mapIterator->next(); - next; - } - - # Step one: Decide which parts to show - my @parts = @{$curRes->parts()}; - my $multipart = scalar(@parts) > 1; - my $condensed = 0; - - if ($curRes->is_problem()) { - - # Is it multipart? - if ($multipart) { - # If it's multipart, see if part 0 is "open" - # if it is, display all parts, if it isn't, - # just display first - if (!$curRes->opendate("0")) { - # no parts are open, display as one part - @parts = ("0"); - $condensed = 1; - } else { - # Otherwise, only display part 0 if we want to - # attach feedback or email information to it - if ($curRes->hasDiscussion() || $curRes->getFeedback()) { - # Is this right? I think this will toss it - # if it DOES have discussion, not if it doesn't? - # - Jeremy (yes, commenting on his own code) - shift @parts; - } else { - # Now, we decide whether to condense the - # parts due to similarity - my $status = $curRes->status($parts[1]); - my $due = $curRes->duedate($parts[1]); - my $open = $curRes->opendate($parts[1]); - my $statusAllSame = 1; - my $dueAllSame = 1; - my $openAllSame = 1; - for (my $i = 2; $i < scalar(@parts); $i++) { - if ($curRes->status($parts[$i]) != $status){ - $statusAllSame = 0; - } - if ($curRes->duedate($parts[$i]) != $due ) { - $dueAllSame = 0; - } - if ($curRes->opendate($parts[$i]) != $open) { - $openAllSame = 0; - } - } - - # $*allSame is true if all the statuses were - # the same. Now, if they are all the same and - # match one of the statuses to condense, or they - # are all open with the same due date, or they are - # all OPEN_LATER with the same open date, display the - # status of the first non-zero part (to get the 'correct' - # status right, since 0 is never 'correct' or 'open'). - if (($statusAllSame && defined($condenseStatuses{$status})) || - ($dueAllSame && $status == $curRes->OPEN && $statusAllSame)|| - ($openAllSame && $status == $curRes->OPEN_LATER && $statusAllSame) ){ - @parts = ($parts[1]); - $condensed = 1; - } - } - } - } - - } else { - $parts[0] = "0"; # this is to get past foreach loop below - # you can consider a non-problem resource as a resource - # with only one part without loss, and it simplifies the looping - } - - # Is it a multipart problem with a single part, now in - # @parts with "0" filtered out? If so, 'forget' it's a multi-part - # problem and treat it like a single-part problem. - if ( scalar(@parts) == 1 ) { - $multipart = 0; - } - - # Display one part, in event of network error. - # If this is a single part, we can at least show the correct - # status, but if it's multipart, we're lost, since we can't - # retreive the metadata to count the parts - if ($curRes->{RESOURCE_ERROR}) { - @parts = ("0"); - } - - # Step Two: Print the actual data. - - # For each part we intend to display... - foreach my $part (@parts) { - - my $nonLinkedText = ""; # unlinked stuff after title - - my $stack = $mapIterator->getStack(); - my $src = getLinkForResource($stack); - - # Pass the correct symb on the querystring, so the - # remote will figure out where we are if we click a link - my $srcHasQuestion = $src =~ /\?/; - my $link = $src. - ($srcHasQuestion?'&':'?') . - 'symb='.&Apache::lonnet::escape($curRes->symb()). - '"'; - - my $title = $curRes->compTitle(); - if ($src=~/^\/uploaded\//) { - $nonLinkedText=$title; - $title=''; - } - my $partLabel = ""; - my $newBranchText = ""; - - # If this is a new branch, label it so - if ($isNewBranch) { - $newBranchText = ""; - $isNewBranch = 0; - } - - # links to open and close the folders - my $linkopen = ""; - my $linkclose = ""; - - my $icon = "\"\""; - if ($curRes->is_problem()) { - if ($part eq "0" || $condensed) { - $icon = ''; - } else { - $icon = $indentString; - } - } - - # Display the correct icon, link to open or shut map - if ($curRes->is_map()) { - my $mapId = $curRes->map_pc(); - my $nowOpen = (!defined($filterHash{$mapId})); - if ($condition) {$nowOpen = !$nowOpen;} - $icon = $nowOpen ? - "navmap.folder.closed.gif" : "navmap.folder.open.gif"; - $icon = "\"\""; - $linkopen = ""; - $linkclose = ""; - - } - - my $color; - if ($curRes->is_problem()) { - $color = $colormap{$curRes->status}; - - if (dueInLessThen24Hours($curRes, $part) || - lastTry($curRes, $part)) { - $color = $hurryUpColor; - } - } - - if ($curRes->randomout()) { - $nonLinkedText .= ' (hidden) '; - } - - $rowNum++; - my $backgroundColor = $backgroundColors[$rowNum % scalar(@backgroundColors)]; - - # FIRST COL: The resource indentation, branch icon, name, and anchor - $r->print(" \n"); - - # SECOND COL: Is there text, feedback, errors?? - my $discussionHTML = ""; my $feedbackHTML = ""; my $errorHTML = ""; - - if ($curRes->hasDiscussion()) { - $discussionHTML = $linkopen . - '' . - $linkclose; - } - - if ($curRes->getFeedback()) { - my $feedback = $curRes->getFeedback(); - foreach (split(/\,/, $feedback)) { - if ($_) { - $feedbackHTML .= ' ' - . ''; - } - } - } - - if ($curRes->getErrors()) { - my $errors = $curRes->getErrors(); - foreach (split(/,/, $errors)) { - if ($_) { - $errorHTML .= ' ' - . ''; - } - } - } - - $r->print(""); - - # Is this the first displayed part of a multi-part problem - # that has not been condensed, so we should suppress these two - # columns so we don't display useless status info about part - # "0"? - my $firstDisplayed = !$condensed && $multipart && $part eq "0"; - - # THIRD COL: Problem status icon - if ($curRes->is_problem() && - !$firstDisplayed) { - my $icon = $statusIconMap{$curRes->status($part)}; - my $alt = $iconAltTags{$icon}; - if ($icon) { - $r->print("\n"); - } else { - $r->print("\n"); - } - } else { # not problem, no icon - $r->print("\n"); - } - - # FOURTH COL: Text description - $r->print("\n"); - - if (!($counter % 20)) { $r->rflush(); } - if ($counter == 2) { $r->rflush(); } - } - } - $curRes = $mapIterator->next(); - } - - $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++) { - $r->print($indentString); - } - - $r->print(" ${newBranchText}${linkopen}$icon${linkclose}\n"); - - 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 "0" && !$condensed) { - $partLabel = " (Part $part)"; - $title = ""; - } - if ($multipart && $condensed) { - $nonLinkedText .= ' (' . $curRes->countParts() . ' parts)'; - } - - $r->print(" $curMarkerBegin$title$partLabel $curMarkerEnd $nonLinkedText"); - - #if ($curRes->{RESOURCE_ERROR}) { - # $r->print(&Apache::loncommon::help_open_topic ("Navmap_Host_Down", - # 'Host down')); - # } - - $r->print("$discussionHTML$feedbackHTML$errorHTML $linkopen\"$alt\"$linkclose  \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(" 
"); - - # Print out the part that jumps to #curloc if it exists - if ($displayedJumpMarker) { - $r->print(''); - } - # renderer call $mapIterator = $navmap->getIterator(undef, undef, \%filterHash, 0); my $render = render({ 'cols' => [0,1,2,3], 'iterator' => $mapIterator, 'url' => '/adm/navmaps', - 'queryString' => 'alreadyHere=1' }); - $r->print('|' . $render . '|'); + 'queryString' => 'alreadyHere=1', + 'currentJumpIndex' => $currentJumpIndex}); + $r->print($render); $navmap->untieHashes(); @@ -1036,6 +676,10 @@ Note these functions are responsible for =item * B: The url the folders will link to, which should be the current page. Required if the resource info column is shown. +=item * B: Describes the currently-open row number to cause the browser to jump to, because the user just opened that folder. + +=item * B: The standard Apache response object. If you pass this to the render, it will use it to flush the table every 20 rows and handle the rendering itself. + =back =head2 Additional Info @@ -1113,7 +757,7 @@ sub render_resource { . $params->{'hereType'} . '&here=' . &Apache::lonnet::escape($params->{'here'}) . '&jumpType=' . SYMB() . '&jump=' . - &Apache::lonnet::escape($params->{$resource->symb()}) . "'>"; + &Apache::lonnet::escape($resource->symb()) . "'>"; } if ($resource->randomout()) { @@ -1288,9 +932,15 @@ sub render { my $jumpToSymb = $args->{'jumpToSymb'}; my $hereURL = $args->{'hereURL'}; my $hereSymb = $args->{'hereSymb'}; + # keeps track of when the current resource is found, + # so we can back up a few and put the anchor above the + # current resource + my $currentJumpIndex = setDefault($args->{'currentJumpIndex'}, 0); + my $currentJumpDelta = 2; # change this to change how many resources are displayed + # before the current resource when using #current + my $r = $args->{'r'}; + - #if (defined($jumpToURL)) { - # $args->{'jumpType'} = # End parameter setting @@ -1302,11 +952,6 @@ sub render { $res->NOTHING_SET => 1, $res->CORRECT => 1 ); my @backgroundColors = ("#FFFFFF", "#F6F6F6"); - my $currentJumpIndex = 0; # keeps track of when the current resource is found, - # so we can back up a few and put the anchor above the - # current resource - my $currentJumpDelta = 2; # change this to change how many resources are displayed - # before the current resource when using #current # Shared variables $args->{'counter'} = 0; # counts the rows @@ -1449,35 +1094,40 @@ sub render { # Now, display each column. foreach my $col (@$cols) { + my $colHTML = ''; + if (ref($col)) { + $colHTML .= &$col($curRes, $part, $args); + } else { + $colHTML .= &{$preparedColumns[$col]}($curRes, $part, $args); + } # If this is the first column and it's time to print # the anchor, do so if ($col == $cols->[0] && $args->{'counter'} == $args->{'currentJumpIndex'} - - $args->{'currentJumpDelta'}) { - $result .= ''; + $currentJumpDelta) { + # Jam the anchor after the tag; + # necessary for valid HTML (which Mozilla requires) + $colHTML =~ s/\>/\>\/; $displayedJumpMarker = 1; } - - - if (ref($col)) { - $result .= &$col($curRes, $part, $args); - } else { - $result .= &{$preparedColumns[$col]}($curRes, $part, $args); - } - + $result .= $colHTML . "\n"; } - - $result .= " \n"; + $result .= " \n"; + } + + if ($r && $rownum % 20 == 0) { + $r->print($result); + $result = ""; + $r->rflush(); } - $curRes = $it->next(); } # Print out the part that jumps to #curloc if it exists - if ($args->{"displayedJumpMarker"}) { - $result .= "\n"; + if ($displayedJumpMarker) { + $result .= "\n"; } $result .= "";