version 1.181, 2003/04/24 18:18:38
|
version 1.187, 2003/05/14 18:01:16
|
Line 71 my %statusIconMap =
|
Line 71 my %statusIconMap =
|
$resObj->TRIES_LEFT => 'navmap.open.gif', |
$resObj->TRIES_LEFT => 'navmap.open.gif', |
$resObj->INCORRECT => 'navmap.wrong.gif', |
$resObj->INCORRECT => 'navmap.wrong.gif', |
$resObj->OPEN => 'navmap.open.gif', |
$resObj->OPEN => 'navmap.open.gif', |
$resObj->ATTEMPTED => 'navmap.open.gif' ); |
$resObj->ATTEMPTED => 'navmap.open.gif', |
|
$resObj->ANSWER_SUBMITTED => '' ); |
|
|
my %iconAltTags = |
my %iconAltTags = |
( 'navmap.correct.gif' => 'Correct', |
( 'navmap.correct.gif' => 'Correct', |
Line 199 sub real_handler {
|
Line 200 sub real_handler {
|
} |
} |
} |
} |
|
|
|
# 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("<font size='+2'>All homework assignments have been completed.</font><br /><br />"); |
|
} |
|
} else { |
|
$r->print("<a href='navmaps?jumpToFirstHomework'>" . |
|
"Go To My First Homework Problem</a><br />"); |
|
} |
|
|
# renderer call |
# renderer call |
my $render = render({ 'cols' => [0,1,2,3], |
my $render = render({ 'cols' => [0,1,2,3], |
'url' => '/adm/navmaps', |
'url' => '/adm/navmaps', |
Line 271 sub getDescription {
|
Line 318 sub getDescription {
|
my $part = shift; |
my $part = shift; |
my $status = $res->status($part); |
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) { |
if ($status == $res->NOTHING_SET) { |
return "Not currently assigned."; |
return "Not currently assigned."; |
} |
} |
Line 317 sub getDescription {
|
Line 366 sub getDescription {
|
return "No due date $triesString"; |
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 |
# Convenience function, so others can use it: Is the problem due in less then |
Line 1472 sub init {
|
Line 1524 sub init {
|
unless ((time-$courserdatas{$cid.'.last_cache'})<240) { |
unless ((time-$courserdatas{$cid.'.last_cache'})<240) { |
my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum. |
my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum. |
':resourcedata',$chome); |
':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}=$reply; |
$courserdatas{$cid.'.last_cache'}=time; |
$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})) { |
foreach (split(/\&/,$courserdatas{$cid})) { |
my ($name,$value)=split(/\=/,$_); |
my ($name,$value)=split(/\=/,$_); |
Line 2753 sub is_sequence {
|
Line 2803 sub is_sequence {
|
sub parmval { |
sub parmval { |
my $self = shift; |
my $self = shift; |
my $what = 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()); |
return $self->{NAV_MAP}->parmval($part.'.'.$what, $self->symb()); |
} |
} |
|
|
Line 2927 sub opendate {
|
Line 2980 sub opendate {
|
} |
} |
return $self->parmval("opendate"); |
return $self->parmval("opendate"); |
} |
} |
|
sub problemstatus { |
|
(my $self, my $part) = @_; |
|
return $self->parmval("problemstatus", $part); |
|
} |
sub sig { |
sub sig { |
(my $self, my $part) = @_; |
(my $self, my $part) = @_; |
return $self->parmval("sig", $part); |
return $self->parmval("sig", $part); |
Line 3040 number of parts in the problem, not incl
|
Line 3097 number of parts in the problem, not incl
|
B<parts> may return an array with fewer parts in it then countParts |
B<parts> may return an array with fewer parts in it then countParts |
might lead you to believe. |
might lead you to believe. |
|
|
|
=item * B<responseType>($part): |
|
|
|
Returns the response type of the part, without the word "response" on the |
|
end. Example return values: 'string', 'essay', 'numeric', etc. |
|
|
|
=item * B<responseId>($part): |
|
|
|
Retreives the response ID for the given part, which may be an empty string. |
|
|
=back |
=back |
|
|
=cut |
=cut |
Line 3069 sub countParts {
|
Line 3135 sub countParts {
|
return scalar(@{$parts}) + $delta; |
return scalar(@{$parts}) + $delta; |
} |
} |
|
|
# Private function: Extracts the parts information and saves it |
sub responseType { |
|
my $self = shift; |
|
my $part = shift; |
|
|
|
$self->extractParts(); |
|
return $self->{RESPONSE_TYPE}->{$part}; |
|
} |
|
|
|
sub responseId { |
|
my $self = shift; |
|
my $part = shift; |
|
|
|
$self->extractParts(); |
|
return $self->{RESPONSE_IDS}->{$part}; |
|
} |
|
|
|
# Private function: Extracts the parts information, both part names and |
|
# part types, and saves it. |
sub extractParts { |
sub extractParts { |
my $self = shift; |
my $self = shift; |
|
|
Line 3083 sub extractParts {
|
Line 3166 sub extractParts {
|
# Retrieve part count, if this is a problem |
# Retrieve part count, if this is a problem |
if ($self->is_problem()) { |
if ($self->is_problem()) { |
my $metadata = &Apache::lonnet::metadata($self->src(), 'packages'); |
my $metadata = &Apache::lonnet::metadata($self->src(), 'packages'); |
|
print $metadata; |
if (!$metadata) { |
if (!$metadata) { |
$self->{RESOURCE_ERROR} = 1; |
$self->{RESOURCE_ERROR} = 1; |
$self->{PARTS} = []; |
$self->{PARTS} = []; |
|
$self->{PART_TYPE} = {}; |
return; |
return; |
} |
} |
foreach (split(/\,/,$metadata)) { |
foreach (split(/\,/,$metadata)) { |
if ($_ =~ /^part_(.*)$/) { |
if ($_ =~ /^part_(.*)$/) { |
my $part = $1; |
my $part = $1; |
# This floods the logs |
# This floods the logs if it blows up |
#if (defined($parts{$part})) { |
if (defined($parts{$part})) { |
# Apache::lonnet::logthis("$part multiply defined in metadata for " . $self->symb()); |
Apache::lonnet::logthis("$part multiply defined in metadata for " . $self->symb()); |
# } |
} |
|
|
# check to see if part is turned off. |
# check to see if part is turned off. |
|
|
Line 3107 sub extractParts {
|
Line 3192 sub extractParts {
|
|
|
my @sortedParts = sort keys %parts; |
my @sortedParts = sort keys %parts; |
$self->{PARTS} = \@sortedParts; |
$self->{PARTS} = \@sortedParts; |
|
|
|
my %responseIdHash; |
|
my %responseTypeHash; |
|
|
|
# Now, the unfortunate thing about this is that parts, part name, and |
|
# response if are delimited by underscores, but both the part |
|
# name and response id can themselves have underscores in them. |
|
# So we have to use our knowlege of part names to figure out |
|
# where the part names begin and end, and even then, it is possible |
|
# to construct ambiguous situations. |
|
foreach (split /,/, $metadata) { |
|
if ($_ =~ /^([a-zA-Z]+)response_(.*)/) { |
|
my $responseType = $1; |
|
my $partStuff = $2; |
|
my $partIdSoFar = ''; |
|
my @partChunks = split /_/, $partStuff; |
|
my $i = 0; |
|
|
|
for ($i = 0; $i < scalar(@partChunks); $i++) { |
|
if ($partIdSoFar) { $partIdSoFar .= '_'; } |
|
$partIdSoFar .= $partChunks[$i]; |
|
if ($parts{$partIdSoFar}) { |
|
my @otherChunks = @partChunks[$i+1..$#partChunks]; |
|
my $responseId = join('_', @otherChunks); |
|
$responseIdHash{$partIdSoFar} = $responseId; |
|
$responseTypeHash{$partIdSoFar} = $responseType; |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
|
|
$self->{RESPONSE_IDS} = \%responseIdHash; |
|
$self->{RESPONSE_TYPES} = \%responseTypeHash; |
} |
} |
|
|
return; |
return; |
Line 3310 sub queryRestoreHash {
|
Line 3429 sub queryRestoreHash {
|
my $self = shift; |
my $self = shift; |
my $hashentry = shift; |
my $hashentry = shift; |
my $part = 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}); |
return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE}); |
|
|
$self->getReturnHash(); |
$self->getReturnHash(); |
Line 3328 combine the two status tidbits into one
|
Line 3447 combine the two status tidbits into one
|
represent the status of the resource as a whole. The precise logic is |
represent the status of the resource as a whole. The precise logic is |
documented in the comments of the status method. The following results |
documented in the comments of the status method. The following results |
may be returned, all available as methods on the resource object |
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 |
=over 4 |
|
|
Line 3387 The item is open and not yet tried.
|
Line 3509 The item is open and not yet tried.
|
|
|
The problem has been attempted. |
The problem has been attempted. |
|
|
|
=item * B<ANSWER_SUBMITTED>: |
|
|
|
An answer has been submitted, but the student should not see it. |
|
|
=back |
=back |
|
|
=cut |
=cut |
|
|
sub TRIES_LEFT { return 10; } |
sub TRIES_LEFT { return 20; } |
|
sub ANSWER_SUBMITTED { return 21; } |
|
|
sub status { |
sub status { |
my $self = shift; |
my $self = shift; |
Line 3406 sub status {
|
Line 3533 sub status {
|
|
|
if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; } |
if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; } |
|
|
|
my $suppressFeedback = lc($self->parmval("problemstatus", $part)) eq 'no'; |
|
|
# 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 ) { |
return CORRECT; |
return $suppressFeedback? ANSWER_SUBMITTED : CORRECT; |
} |
} |
|
|
if ($completionStatus == ATTEMPTED) { |
if ($completionStatus == ATTEMPTED) { |
Line 3450 sub status {
|
Line 3579 sub status {
|
if ($self->tries($part) < $self->maxtries($part) || !$self->maxtries($part)) { |
if ($self->tries($part) < $self->maxtries($part) || !$self->maxtries($part)) { |
return TRIES_LEFT; |
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 |
# Otherwise, it's untried and open |