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