--- loncom/interface/lonnavmaps.pm 2002/11/08 20:58:13 1.101
+++ loncom/interface/lonnavmaps.pm 2002/11/26 16:25:36 1.116
@@ -2,7 +2,7 @@
# The LearningOnline Network with CAPA
# Navigate Maps Handler
#
-# $Id: lonnavmaps.pm,v 1.101 2002/11/08 20:58:13 bowersj2 Exp $
+# $Id: lonnavmaps.pm,v 1.116 2002/11/26 16:25:36 bowersj2 Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -37,15 +37,13 @@
# 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);
sub handler {
@@ -73,7 +71,7 @@ sub handler {
&Apache::loncommon::no_cache($r);
$r->send_http_header;
- # Create the nav map the nav map
+ # Create the nav map
my $navmap = Apache::lonnavmaps::navmap->new(
$ENV{"request.course.fn"}.".db",
$ENV{"request.course.fn"}."_parms.db", 1, 1);
@@ -85,8 +83,11 @@ sub handler {
return HTTP_NOT_ACCEPTABLE;
}
+ $r->print("
\n");
+ $r->print("Navigate Course Contents");
+
# Header
- $r->print(&Apache::loncommon::bodytag('Navigate Course Map','',
+ $r->print(&Apache::loncommon::bodytag('Navigate Course Contents','',
''));
$r->print('');
@@ -115,10 +116,22 @@ sub handler {
$condition = 1;
}
+ my $currenturl = $ENV{'form.postdata'};
+ $currenturl=~s/^http\:\/\///;
+ $currenturl=~s/^[^\/]+//;
+
+ # alreadyHere allows us to only open the maps necessary to view
+ # the current location once, while at the same time remembering
+ # the current location. Without that check, the user would never
+ # be able to close those maps; the user would close it, and the
+ # currenturl scan would re-open it.
+ my $queryAdd = "postdata=" . &Apache::lonnet::escape($currenturl) .
+ "&alreadyHere=1";
+
if ($condition) {
- $r->print('Close All Folders');
+ $r->print("Close All Folders");
} else {
- $r->print('Open All Folders');
+ $r->print("Open All Folders");
}
$r->print('
');
@@ -145,10 +158,10 @@ sub handler {
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 => '',
@@ -158,6 +171,8 @@ sub handler {
# is not yet done and due in less then 24 hours
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 => '',
@@ -193,19 +208,6 @@ sub 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");
- my $inlineTopLevelMaps = $topResource->src() =~ m|^/uploaded/.*default\.sequence$|;
-
- my $currenturl = $ENV{'form.postdata'};
- $currenturl=~s/^http\:\/\///;
- $currenturl=~s/^[^\/]+//;
-
- # alreadyHere allows us to only open the maps necessary to view
- # the current location once, while at the same time remembering
- # the current location. Without that check, the user would never
- # be able to close those maps; the user would close it, and the
- # currenturl scan would re-open it.
- my $queryAdd = "postdata=" . &Apache::lonnet::escape($currenturl) .
- "&alreadyHere=1";
# Begin the HTML table
# four cols: resource + indent, chat+feedback, icon, text string
@@ -228,8 +230,10 @@ sub handler {
$mapIterator->next(); # discard the first BEGIN_MAP
my $curRes = $mapIterator->next();
my $counter = 0;
-
- while ($depth > 0) {
+
+ # We only need to do this if we need to open the maps to show the
+ # current position
+ while ($depth > 0 && !$ENV{'form.alreadyHere'}) {
if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; }
if ($curRes == $mapIterator->END_MAP()) { $depth--; }
@@ -258,17 +262,6 @@ sub handler {
$ENV{'form.alreadyHere'} = 1;
}
- # Preprocessing: If we're inlining nav maps into the top-level display,
- # make sure we show this map!
- if ($inlineTopLevelMaps && ref($curRes) && $curRes->is_map &&
- scalar(@{$mapStack}) == 1) {
- if ($condition) {
- undef $filterHash{$curRes->map_pc()};
- } else {
- $filterHash{$curRes->map_pc()} = 1;
- }
- }
-
$curRes = $mapIterator->next();
}
@@ -287,7 +280,6 @@ sub handler {
$condition);
$mapIterator->next();
$curRes = $mapIterator->next();
- my $deltadepth = 0;
$depth = 1;
my @backgroundColors = ("#FFFFFF", "#F6F6F6");
@@ -301,15 +293,6 @@ sub handler {
}
while ($depth > 0) {
- # If this is an inlined map, cancel the shift to the right,
- # which has the effect of making the map look inlined
- if ($inlineTopLevelMaps && scalar(@{$mapIterator->getStack()}) == 1 &&
- ref($curRes) && $curRes->is_map()) {
- $deltadepth = -1;
- $curRes = $mapIterator->next();
- next;
- }
-
if ($curRes == $mapIterator->BEGIN_MAP() ||
$curRes == $mapIterator->BEGIN_BRANCH()) {
$indentLevel++;
@@ -326,9 +309,6 @@ sub handler {
if (ref($curRes)) { $counter++; }
- if ($depth == 1) { $deltadepth = 0; } # we're done shifting, because we're
- # out of the inlined map
-
# Is this resource being ignored because it is in a random-out
# map and it was not selected?
if (ref($curRes) && !advancedUser() && $curRes->randomout()) {
@@ -336,7 +316,17 @@ sub handler {
next; # if yes, then just ignore this resource
}
- if (ref($curRes) && $curRes->src()) {
+ if (ref($curRes)) {
+
+ my $deltalevel = $isNewBranch? 1 : 0; # reserves space for branch icon
+
+ 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()};
@@ -423,7 +413,6 @@ sub handler {
# For each part we intend to display...
foreach my $part (@parts) {
- my $deltalevel = 0; # for inserting the branch icon
my $nonLinkedText = ""; # unlinked stuff after title
my $stack = $mapIterator->getStack();
@@ -437,11 +426,7 @@ sub handler {
'symb='.&Apache::lonnet::escape($curRes->symb()).
'"';
- my $title = $curRes->title();
- if (!$title) {
- $title = $curRes->src();
- $title = substr ($title, rindex($title, "/") + 1);
- }
+ my $title = $curRes->compTitle();
my $partLabel = "";
my $newBranchText = "";
@@ -449,7 +434,6 @@ sub handler {
if ($isNewBranch) {
$newBranchText = "
";
$isNewBranch = 0;
- $deltalevel = 1; # reserves space for the branch icon
}
# links to open and close the folders
@@ -485,27 +469,13 @@ sub handler {
my $colorizer = "";
my $color;
if ($curRes->is_problem()) {
- my $status = $curRes->status($part);
- $color = $colormap{$status};
+ $color = $colormap{$curRes->status};
- # Special case in the navmaps: If in less then
- # 24 hours, give it a bit of urgency
- if (($status == $curRes->OPEN() || $status == $curRes->ATTEMPTED() ||
- $status == $curRes->TRIES_LEFT())
- && $curRes->duedate() &&
- $curRes->duedate() < time()+(24*60*60) &&
- $curRes->duedate() > time()) {
- $color = $hurryUpColor;
- }
- # Special case: If this is the last try, and there is
- # more then one available, and it's not due yet, give a bit of urgency
- my $tries = $curRes->tries($part);
- my $maxtries = $curRes->maxtries($part);
- if ($tries && $maxtries && $maxtries > 1 &&
- $maxtries - $tries == 1 && $curRes->duedate() &&
- $curRes->duedate() > time()) {
+ if (dueInLessThen24Hours($curRes, $part) ||
+ lastTry($curRes, $part)) {
$color = $hurryUpColor;
}
+
if ($color ne "") {
$colorizer = "bgcolor=\"$color\"";
}
@@ -519,7 +489,7 @@ sub handler {
my $backgroundColor = $backgroundColors[$rowNum % scalar(@backgroundColors)];
# FIRST COL: The resource indentation, branch icon, name, and anchor
- $r->print(" \n");
+ $r->print(" |
\n");
# Print the anchor if necessary
if ($counter == $currentUrlIndex - $currentUrlDelta) {
@@ -527,7 +497,7 @@ sub handler {
}
# print indentation
- for (my $i = 0; $i < $indentLevel - $deltalevel + $deltadepth; $i++) {
+ for (my $i = 0; $i < $indentLevel - $deltalevel; $i++) {
$r->print($indentString);
}
@@ -558,6 +528,8 @@ sub handler {
'Host down'));
}
+ $r->print(" | \n");
+
# SECOND COL: Is there text, feedback, errors??
my $discussionHTML = ""; my $feedbackHTML = "";
@@ -616,6 +588,9 @@ sub handler {
}
$r->print("
\n");
+
+ if (!($counter % 20)) { $r->rflush(); }
+ if ($counter == 2) { $r->rflush(); }
}
}
$curRes = $mapIterator->next();
@@ -733,6 +708,33 @@ sub getDescription {
}
}
+# Convenience function, so others can use it: Is the problem due in less then
+# 24 hours, and still can be done?
+
+sub dueInLessThen24Hours {
+ my $res = shift;
+ my $part = shift;
+ my $status = $res->status($part);
+
+ return ($status == $res->OPEN() || $status == $res->ATTEMPTED() ||
+ $status == $res->TRIES_LEFT()) &&
+ $res->duedate() && $res->duedate() < time()+(24*60*60) &&
+ $res->duedate() > time();
+}
+
+# Convenience function, so others can use it: Is there only one try remaining for the
+# part, with more then one try to begin with, not due yet and still can be done?
+sub lastTry {
+ my $res = shift;
+ my $part = shift;
+
+ my $tries = $res->tries($part);
+ my $maxtries = $res->maxtries($part);
+ return $tries && $maxtries && $maxtries > 1 &&
+ $maxtries - $tries == 1 && $res->duedate() &&
+ $res->duedate() > time();
+}
+
# This puts a human-readable name on the ENV variable.
sub advancedUser {
return $ENV{'user.adv'};
@@ -898,7 +900,6 @@ sub new {
&GDBM_READER(), 0640))) {
return undef;
}
- $self->{NAV_HASH} = \%navmaphash;
my %parmhash;
if (!(tie(%parmhash, 'GDBM_File', $self->{PARM_HASH_FILE},
@@ -907,10 +908,16 @@ sub new {
untie $self->{PARM_HASH};
return undef;
}
- $self->{PARM_HASH} = \%parmhash;
- $self->{HASH_TIED} = 1;
+
+ # Now copy the hashes for speed (?)
+ my %realnav; my %realparm;
+ foreach (%navmaphash) { $realnav{$_} = $navmaphash{$_}; }
+ foreach (%parmhash) { $realparm{$_} = $navmaphash{$_}; }
+ $self->{NAV_HASH} = \%realnav;
+ $self->{PARM_HASH} = \%realparm;
bless($self);
+ $self->untieHashes();
return $self;
}
@@ -1024,13 +1031,20 @@ sub init {
$self->{PARM_CACHE} = {};
}
+# Internal function: Takes a key to look up in the nav hash and implements internal
+# memory caching of that key.
+sub navhash {
+ my $self = shift; my $key = shift;
+ return $self->{NAV_HASH}->{$key};
+}
+
# Checks to see if coursemap is defined, matching test in old lonnavmaps
sub courseMapDefined {
my $self = shift;
my $uri = &Apache::lonnet::clutter($ENV{'request.course.uri'});
- my $firstres = $self->{NAV_HASH}->{"map_start_$uri"};
- my $lastres = $self->{NAV_HASH}->{"map_finish_$uri"};
+ my $firstres = $self->navhash("map_start_$uri");
+ my $lastres = $self->navhash("map_finish_$uri");
return $firstres && $lastres;
}
@@ -1110,8 +1124,8 @@ sub getById {
sub firstResource {
my $self = shift;
- my $firstResource = $self->{NAV_HASH}->{'map_start_' .
- &Apache::lonnet::clutter($ENV{'request.course.uri'})};
+ my $firstResource = $self->navhash('map_start_' .
+ &Apache::lonnet::clutter($ENV{'request.course.uri'}));
return $self->getById($firstResource);
}
@@ -1123,8 +1137,8 @@ sub firstResource {
sub finishResource {
my $self = shift;
- my $firstResource = $self->{NAV_HASH}->{'map_finish_' .
- &Apache::lonnet::clutter($ENV{'request.course.uri'})};
+ my $firstResource = $self->navhash('map_finish_' .
+ &Apache::lonnet::clutter($ENV{'request.course.uri'}));
return $self->getById($firstResource);
}
@@ -1251,7 +1265,7 @@ getIterator behaves as follows:
=over 4
-=item * B(firstResource, finishResource, filterHash, condition): All parameters are optional. firstResource is a resource reference corresponding to where the iterator should start. It defaults to navmap->firstResource() for the corresponding nav map. finishResource corresponds to where you want the iterator to end, defaulting to navmap->finishResource(). filterHash is a hash used as a set containing strings representing the resource IDs, defaulting to empty. Condition is a 1 or 0 that sets what to do with the filter hash: If a 0, then only resource that exist IN the filterHash will be recursed on. If it is a 1, only resources NOT in the filterHash will be recursed on. Defaults to 0.
+=item * B(firstResource, finishResource, filterHash, condition, forceTop): All parameters are optional. firstResource is a resource reference corresponding to where the iterator should start. It defaults to navmap->firstResource() for the corresponding nav map. finishResource corresponds to where you want the iterator to end, defaulting to navmap->finishResource(). filterHash is a hash used as a set containing strings representing the resource IDs, defaulting to empty. Condition is a 1 or 0 that sets what to do with the filter hash: If a 0, then only resource that exist IN the filterHash will be recursed on. If it is a 1, only resources NOT in the filterHash will be recursed on. Defaults to 0. forceTop is a boolean value. If it is false (default), the iterator will only return the first level of map that is not just a single, 'redirecting' map. If true, the iterator will return all information, starting with the top-level map, regardless of content.
Thus, by default, only top-level resources will be shown. Change the condition to a 1 without changing the hash, and all resources will be shown. Changing the condition to 1 and including some values in the hash will allow you to selectively suppress parts of the navmap, while leaving it on 0 and adding things to the hash will allow you to selectively add parts of the nav map. See the handler code for examples.
@@ -1271,6 +1285,8 @@ The iterator will return either a refere
The tokens are retreivable via methods on the iterator object, i.e., $iterator->END_MAP.
+Maps can contain empty resources. The iterator will automatically skip over such resources, but will still treat the structure correctly. Thus, a complicated map with several branches, but consisting entirely of empty resources except for one beginning or ending resource, will cause a lot of BRANCH_STARTs and BRANCH_ENDs, but only one resource will be returned.
+
=back
=cut
@@ -1289,6 +1305,11 @@ sub min {
if ($a < $b) { return $a; } else { return $b; }
}
+# In the CVS repository, documentation of this algorithm is included
+# in /doc/lonnavdocs, as a PDF and .tex source. Markers like **1**
+# will reference the same location in the text as the part of the
+# algorithm is running through.
+
sub new {
# magic invocation to create a class instance
my $proto = shift;
@@ -1316,6 +1337,9 @@ sub new {
if (!defined($self->{ALREADY_SEEN})) { $self->{ALREADY_SEEN} = {} };
$self->{CONDITION} = shift;
+ # Do we want to automatically follow "redirection" maps?
+ $self->{FORCE_TOP} = shift;
+
# Now, we need to pre-process the map, by walking forward and backward
# over the parts of the map we're going to look at.
@@ -1331,6 +1355,13 @@ sub new {
my $maxDepth = 0; # tracks max depth
+ # If there is only one resource in this map, and it's a map, we
+ # want to remember that, so the user can ask for the first map
+ # that isn't just a redirector.
+ my $resource; my $resourceCount = 0;
+
+ # **1**
+
foreach my $pass (@iterations) {
my $direction = $pass->[0];
my $valName = $pass->[1];
@@ -1352,16 +1383,18 @@ sub new {
if ($curRes == $iterator->END_MAP()) { $depth--; }
if (ref($curRes)) {
+ # If there's only one resource, this will save it
+ if($direction == FORWARD) { $resource = $curRes; $resourceCount++; }
my $resultingVal = $curRes->{DATA}->{$valName};
my $nextResources = $curRes->$nextResourceMethod();
- my $resourceCount = scalar(@{$nextResources});
-
- if ($resourceCount == 1) {
+ my $nextCount = scalar(@{$nextResources});
+
+ if ($nextCount == 1) { # **3**
my $current = $nextResources->[0]->{DATA}->{$valName} || 999999999;
$nextResources->[0]->{DATA}->{$valName} = min($resultingVal, $current);
}
- if ($resourceCount > 1) {
+ if ($nextCount > 1) { # **4**
foreach my $res (@{$nextResources}) {
my $current = $res->{DATA}->{$valName} || 999999999;
$res->{DATA}->{$valName} = min($current, $resultingVal + 1);
@@ -1369,7 +1402,7 @@ sub new {
}
}
- # Assign the final val
+ # Assign the final val (**2**)
if (ref($curRes) && $direction == BACKWARD()) {
my $finalDepth = min($curRes->{DATA}->{TOP_DOWN_VAL},
$curRes->{DATA}->{BOT_UP_VAL});
@@ -1381,6 +1414,18 @@ sub new {
}
}
+ # Check: Was this only one resource, a map?
+ if ($resourceCount == 1 && $resource->is_map() && !$self->{FORCE_TOP}) {
+ my $firstResource = $resource->map_start();
+ my $finishResource = $resource->map_finish();
+ return
+ Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
+ $finishResource, $self->{FILTER},
+ $self->{ALREADY_SEEN},
+ $self->{CONDITION}, 0);
+
+ }
+
# Set up some bookkeeping information.
$self->{CURRENT_DEPTH} = 0;
$self->{MAX_DEPTH} = $maxDepth;
@@ -1391,7 +1436,7 @@ sub new {
push @{$self->{STACK}}, [];
}
- # Prime the recursion w/ the first resource
+ # Prime the recursion w/ the first resource **5**
push @{$self->{STACK}->[0]}, $self->{FIRST_RESOURCE};
$self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1;
@@ -1440,8 +1485,8 @@ sub next {
my $newDepth;
my $here;
while ( $i >= 0 && !$found ) {
- if ( scalar(@{$self->{STACK}->[$i]}) > 0 ) {
- $here = $self->{HERE} = shift @{$self->{STACK}->[$i]};
+ if ( scalar(@{$self->{STACK}->[$i]}) > 0 ) { # **6**
+ $here = pop @{$self->{STACK}->[$i]}; # **7**
$found = 1;
$newDepth = $i;
}
@@ -1459,6 +1504,18 @@ sub next {
}
}
+ # If this is not a resource, it must be an END_BRANCH marker we want
+ # to return directly.
+ if (!ref($here)) { # **8**
+ if ($here == END_BRANCH()) { # paranoia, in case of later extension
+ $self->{CURRENT_DEPTH}--;
+ return $here;
+ }
+ }
+
+ # Otherwise, it is a resource and it's safe to store in $self->{HERE}
+ $self->{HERE} = $here;
+
# Get to the right level
if ( $self->{CURRENT_DEPTH} > $newDepth ) {
push @{$self->{STACK}->[$newDepth]}, $here;
@@ -1478,14 +1535,32 @@ sub next {
# So we need to look at all the resources we can get to from here,
# categorize them if we haven't seen them, remember if we have a new
my $nextUnfiltered = $here->getNext();
-
+ my $maxDepthAdded = -1;
+
for (@$nextUnfiltered) {
if (!defined($self->{ALREADY_SEEN}->{$_->{ID}})) {
- push @{$self->{STACK}->[$_->{DATA}->{DISPLAY_DEPTH}]}, $_;
+ my $depth = $_->{DATA}->{DISPLAY_DEPTH};
+ push @{$self->{STACK}->[$depth]}, $_;
$self->{ALREADY_SEEN}->{$_->{ID}} = 1;
+ if ($maxDepthAdded < $depth) { $maxDepthAdded = $depth; }
}
}
-
+
+ # Is this the end of a branch? If so, all of the resources examined above
+ # led to lower levels then the one we are currently at, so we push a END_BRANCH
+ # marker onto the stack so we don't forget.
+ # Example: For the usual A(BC)(DE)F case, when the iterator goes down the
+ # BC branch and gets to C, it will see F as the only next resource, but it's
+ # one level lower. Thus, this is the end of the branch, since there are no
+ # more resources added to this level or above.
+ # We don't do this if the examined resource is the finish resource,
+ # because the condition given above is true, but the "END_MAP" will
+ # take care of things and we should already be at depth 0.
+ my $isEndOfBranch = $maxDepthAdded < $self->{CURRENT_DEPTH};
+ if ($isEndOfBranch && $here != $self->{FINISH_RESOURCE}) { # **9**
+ push @{$self->{STACK}->[$self->{CURRENT_DEPTH}]}, END_BRANCH();
+ }
+
# That ends the main iterator logic. Now, do we want to recurse
# down this map (if this resource is a map)?
if ($self->{HERE}->is_map() &&
@@ -1500,6 +1575,11 @@ sub next {
$self->{ALREADY_SEEN}, $self->{CONDITION});
}
+ # If this is a blank resource, don't actually return it.
+ if (!$self->{HERE}->src()) {
+ return $self->next();
+ }
+
return $self->{HERE};
}
@@ -1683,6 +1763,11 @@ sub next {
$self->{CONDITION}, $self->{DIRECTION});
}
+ # If this is a blank resource, ignore it.
+ if (!$self->{HERE}->src()) {
+ return $self->next();
+ }
+
return $self->{HERE};
}
@@ -1746,7 +1831,7 @@ sub navHash {
my $self = shift;
my $param = shift;
my $id = shift;
- return $self->{NAV_MAP}->{NAV_HASH}->{$param . ($id?$self->{ID}:"")};
+ return $self->{NAV_MAP}->navhash($param . ($id?$self->{ID}:""));
}
=pod
@@ -1757,6 +1842,8 @@ These are methods that help you retrieve
=over 4
+=item * B: Returns a "composite title", that is equal to $res->title() if the resource has a title, and is otherwise the last part of the URL (e.g., "problem.problem").
+
=item * B: Returns true if the resource is external.
=item * B: Returns the "goesto" value from the compiled nav map. (It is likely you want to use B instead.)
@@ -1806,7 +1893,15 @@ sub symb {
}
sub title { my $self=shift; return $self->navHash("title_", 1); }
sub to { my $self=shift; return $self->navHash("to_", 1); }
-
+sub compTitle {
+ my $self = shift;
+ my $title = $self->title();
+ if (!$title) {
+ $title = $self->src();
+ $title = substr($title, rindex($title, '/') + 1);
+ }
+ return $title;
+}
=pod
B
@@ -1966,6 +2061,7 @@ sub answerdate {
}
return $self->parmval("answerdate", $part);
}
+sub awarded { my $self = shift; return $self->queryRestoreHash('awarded', shift); }
sub duedate {
(my $self, my $part) = @_;
return $self->parmval("duedate", $part);
@@ -1990,24 +2086,18 @@ sub tol {
(my $self, my $part) = @_;
return $self->parmval("tol", $part);
}
-sub tries {
- my $self = shift;
- my $part = shift;
- $part = '0' if (!defined($part));
-
- # Make sure return hash is loaded, should error check
- $self->getReturnHash();
-
- my $tries = $self->{RETURN_HASH}->{'resource.'.$part.'.tries'};
- if (!defined($tries)) {return '0';}
+sub tries {
+ my $self = shift;
+ my $tries = $self->queryRestoreHash('tries', shift);
+ if (!defined($tries)) { return '0';}
return $tries;
}
sub type {
(my $self, my $part) = @_;
return $self->parmval("type", $part);
}
-sub weight {
- (my $self, my $part) = @_;
+sub weight {
+ my $self = shift; my $part = shift;
return $self->parmval("weight", $part);
}
@@ -2269,14 +2359,9 @@ sub ATTEMPTED { return 16; }
sub getCompletionStatus {
my $self = shift;
- my $part = shift;
- $part = "0" if (!defined($part));
return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE});
- # Make sure return hash exists
- $self->getReturnHash();
-
- my $status = $self->{RETURN_HASH}->{'resource.'.$part.'.solved'};
+ my $status = $self->queryRestoreHash('solved', shift);
# Left as seperate if statements in case we ever do more with this
if ($status eq 'correct_by_student') {return $self->CORRECT;}
@@ -2288,6 +2373,18 @@ sub getCompletionStatus {
return $self->NOT_ATTEMPTED;
}
+sub queryRestoreHash {
+ my $self = shift;
+ my $hashentry = shift;
+ my $part = shift;
+ $part = "0" if (!defined($part));
+ return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE});
+
+ $self->getReturnHash();
+
+ return $self->{RETURN_HASH}->{'resource.'.$part.'.'.$hashentry};
+}
+
=pod
B
@@ -2413,8 +2510,12 @@ sub getNext {
# Don't remember it if the student doesn't have browse priviledges
# future note: this may properly belong in the client of the resource
- my $browsePriv = &Apache::lonnet::allowed('bre', $self->src);
- if ($browsePriv ne '2' && $browsePriv ne 'F') {
+ my $browsePriv = $self->{BROWSE_PRIV};
+ if (!defined($browsePriv)) {
+ $browsePriv = &Apache::lonnet::allowed('bre', $self->src);
+ $self->{BROWSE_PRIV} = $browsePriv;
+ }
+ if (!($browsePriv ne '2' && $browsePriv ne 'F')) {
push @branches, $next;
}
}
@@ -2432,8 +2533,12 @@ sub getPrevious {
# Don't remember it if the student doesn't have browse priviledges
# future note: this may properly belong in the client of the resource
- my $browsePriv = &Apache::lonnet::allowed('bre', $self->src);
- if ($browsePriv ne '2' && $browsePriv ne 'F') {
+ my $browsePriv = $self->{BROWSE_PRIV};
+ if (!defined($browsePriv)) {
+ $browsePriv = &Apache::lonnet::allowed('bre', $self->src);
+ $self->{BROWSE_PRIV} = $browsePriv;
+ }
+ if (!($browsePriv ne '2' && $browsePriv ne 'F')) {
push @branches, $prev;
}
}