--- loncom/interface/lonnavmaps.pm 2003/09/10 19:29:33 1.227
+++ loncom/interface/lonnavmaps.pm 2004/03/05 21:51:50 1.250
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Navigate Maps Handler
#
-# $Id: lonnavmaps.pm,v 1.227 2003/09/10 19:29:33 bowersj2 Exp $
+# $Id: lonnavmaps.pm,v 1.250 2004/03/05 21:51:50 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -25,20 +25,7 @@
#
# http://www.lon-capa.org/
#
-# (Page Handler
-#
-# (TeX Content Handler
-#
-# 05/29/00,05/30 Gerd Kortemeyer)
-# 08/30,08/31,09/06,09/14,09/15,09/16,09/19,09/20,09/21,09/23,
-# 10/02,10/10,10/14,10/16,10/18,10/19,10/31,11/6,11/14,11/16 Gerd Kortemeyer)
-#
-# 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
-# YEAR=2003
-# Jeremy Bowers ... lots of days
+###
package Apache::lonnavmaps;
@@ -46,6 +33,7 @@ use strict;
use Apache::Constants qw(:common :http);
use Apache::loncommon();
use Apache::lonmenu();
+use Apache::lonlocal;
use POSIX qw (floor strftime);
use Data::Dumper; # for debugging, not always used
@@ -106,9 +94,9 @@ sub real_handler {
# Handle header-only request
if ($r->header_only) {
if ($ENV{'browser.mathml'}) {
- $r->content_type('text/xml');
+ &Apache::loncommon::content_type($r,'text/xml');
} else {
- $r->content_type('text/html');
+ &Apache::loncommon::content_type($r,'text/html');
}
$r->send_http_header;
return OK;
@@ -116,9 +104,9 @@ sub real_handler {
# Send header, don't cache this page
if ($ENV{'browser.mathml'}) {
- $r->content_type('text/xml');
+ &Apache::loncommon::content_type($r,'text/xml');
} else {
- $r->content_type('text/html');
+ &Apache::loncommon::content_type($r,'text/html');
}
&Apache::loncommon::no_cache($r);
$r->send_http_header;
@@ -126,7 +114,6 @@ sub real_handler {
# Create the nav map
my $navmap = Apache::lonnavmaps::navmap->new();
-
if (!defined($navmap)) {
my $requrl = $r->uri;
$ENV{'user.error.msg'} = "$requrl:bre:0:0:Course not initialized";
@@ -134,7 +121,7 @@ sub real_handler {
}
$r->print("
\n");
- $r->print("Navigate Course Contents");
+ $r->print("".&mt('Navigate Course Contents')."");
# ------------------------------------------------------------ Get query string
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['register']);
@@ -221,7 +208,7 @@ sub real_handler {
}
} else {
$r->print("" .
- "Go To My First Homework Problem ");
+ &mt("Go To My First Homework Problem")." ");
}
my $suppressEmptySequences = 0;
@@ -236,13 +223,13 @@ sub real_handler {
$filterFunc = sub { my $res = shift;
return $res->completable() || $res->is_map();
};
- $r->print("Uncompleted Homework
");
+ $r->print("".&mt("Uncompleted Homework")."
");
$ENV{'form.filter'} = '';
$ENV{'form.condition'} = 1;
$resource_no_folder_link = 1;
} else {
$r->print("" .
- "Show Only Uncompleted Homework ");
+ &mt("Show Only Uncompleted Homework")." ");
}
# renderer call
@@ -261,7 +248,7 @@ sub real_handler {
# user knows there was no error.
if ($renderArgs->{'counter'} == 0) {
if ($showOnlyHomework) {
- $r->print("All homework is currently completed.
");
+ $r->print("".&mt("All homework is currently completed").".
");
} else { # both jumpToFirstHomework and normal use the same: course must be empty
$r->print("This course is empty.
");
}
@@ -303,8 +290,16 @@ sub getLinkForResource {
# Check to see if there are any pages in the stack
foreach $res (@$stack) {
- if (defined($res) && $res->is_page()) {
- return $res->src();
+ if (defined($res)) {
+ if ($res->is_page()) {
+ return $res->src();
+ }
+ # in case folder was skipped over as "only sequence"
+ my ($map,$id,$src)=&Apache::lonnet::decode_symb($res->symb());
+ if ($map=~/\.page$/) {
+ return &Apache::lonnet::clutter($map).'#'.
+ &Apache::lonnet::escape(&Apache::lonnet::declutter($src));
+ }
}
}
@@ -331,35 +326,35 @@ sub getDescription {
my $status = $res->status($part);
if ($status == $res->NETWORK_FAILURE) {
- return "Having technical difficulties; please check status later";
+ return &mt("Having technical difficulties; please check status later");
}
if ($status == $res->NOTHING_SET) {
- return "Not currently assigned.";
+ return &mt("Not currently assigned.");
}
if ($status == $res->OPEN_LATER) {
return "Open " . timeToHumanString($res->opendate($part));
}
if ($status == $res->OPEN) {
if ($res->duedate($part)) {
- return "Due " . timeToHumanString($res->duedate($part));
+ return &mt("Due")." " .timeToHumanString($res->duedate($part));
} else {
- return "Open, no due date";
+ return &mt("Open, no due date");
}
}
if ($status == $res->PAST_DUE_ANSWER_LATER) {
- return "Answer open " . timeToHumanString($res->answerdate($part));
+ return &mt("Answer open")." " . timeToHumanString($res->answerdate($part));
}
if ($status == $res->PAST_DUE_NO_ANSWER) {
- return "Was due " . timeToHumanString($res->duedate($part));
+ return &mt("Was due")." " . timeToHumanString($res->duedate($part));
}
if ($status == $res->ANSWER_OPEN) {
- return "Answer available";
+ return &mt("Answer available");
}
if ($status == $res->EXCUSED) {
- return "Excused by instructor";
+ return &mt("Excused by instructor");
}
if ($status == $res->ATTEMPTED) {
- return "Answer submitted, not yet graded.";
+ return &mt("Answer submitted, not yet graded");
}
if ($status == $res->TRIES_LEFT) {
my $tries = $res->tries($part);
@@ -371,15 +366,15 @@ sub getDescription {
$triesString = "$triesString";
}
}
- if ($res->duedate()) {
- return "Due " . timeToHumanString($res->duedate($part)) .
+ if ($res->duedate($part)) {
+ return &mt("Due")." " . timeToHumanString($res->duedate($part)) .
" $triesString";
} else {
- return "No due date $triesString";
+ return &mt("No due date")." $triesString";
}
}
if ($status == $res->ANSWER_SUBMITTED) {
- return 'Answer submitted';
+ return &mt('Answer submitted');
}
}
@@ -393,8 +388,8 @@ sub dueInLessThen24Hours {
return ($status == $res->OPEN() ||
$status == $res->TRIES_LEFT()) &&
- $res->duedate() && $res->duedate() < time()+(24*60*60) &&
- $res->duedate() > time();
+ $res->duedate($part) && $res->duedate($part) < time()+(24*60*60) &&
+ $res->duedate($part) > time();
}
# Convenience function, so others can use it: Is there only one try remaining for the
@@ -406,8 +401,8 @@ sub lastTry {
my $tries = $res->tries($part);
my $maxtries = $res->maxtries($part);
return $tries && $maxtries && $maxtries > 1 &&
- $maxtries - $tries == 1 && $res->duedate() &&
- $res->duedate() > time();
+ $maxtries - $tries == 1 && $res->duedate($part) &&
+ $res->duedate($part) > time();
}
# This puts a human-readable name on the ENV variable.
@@ -429,9 +424,11 @@ sub timeToHumanString {
my ($time) = @_;
# zero, '0' and blank are bad times
if (!$time) {
- return 'never';
+ return &mt('never');
}
-
+ unless (&Apache::lonlocal::current_language()=~/^en/) {
+ return &Apache::lonlocal::locallocaltime($time);
+ }
my $now = time();
my @time = localtime($time);
@@ -499,7 +496,7 @@ sub timeToHumanString {
# HH:MM
if ( $delta < $day * 5 ) {
my $timeStr = strftime("%A, %b %e at %I:%M %P", localtime($time));
- $timeStr =~ s/12:00 am/midnight/;
+ $timeStr =~ s/12:00 am/00:00/;
$timeStr =~ s/12:00 pm/noon/;
return ($inPast ? "last " : "next ") .
$timeStr;
@@ -509,14 +506,14 @@ sub timeToHumanString {
if ( $time[5] == $now[5]) {
# Return on Month Day, HH:MM meridian
my $timeStr = strftime("on %A, %b %e at %I:%M %P", localtime($time));
- $timeStr =~ s/12:00 am/midnight/;
+ $timeStr =~ s/12:00 am/00:00/;
$timeStr =~ s/12:00 pm/noon/;
return $timeStr;
}
# Not this year, so show the year
my $timeStr = strftime("on %A, %b %e %G at %I:%M %P", localtime($time));
- $timeStr =~ s/12:00 am/midnight/;
+ $timeStr =~ s/12:00 am/00:00/;
$timeStr =~ s/12:00 pm/noon/;
return $timeStr;
}
@@ -893,12 +890,8 @@ sub render_resource {
$icon = $params->{'indentString'};
}
} else {
- my $curfext= (split (/\./,$resource->src))[-1];
- my $embstyle = &Apache::loncommon::fileembstyle($curfext);
- # The unless conditional that follows is a bit of overkill
- if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
- $icon = "
";
- }
+ $icon = "
";
}
# Display the correct map icon to open or shut map
@@ -968,7 +961,11 @@ sub render_resource {
if ($resource->is_problem() && $part ne '0' &&
!$params->{'condensed'}) {
- $partLabel = " (Part $part)";
+ my $displaypart=&Apache::lonnet::EXT('resource.'.$part.'.display',
+ $resource->symb());
+ unless ($displaypart) { $displaypart=$part; }
+ $partLabel = " (Part: $displaypart)";
+ $link.='#'.&Apache::lonnet::escape($part);
$title = "";
}
@@ -1328,15 +1325,15 @@ sub render {
$result.='Key: | ';
if ($navmap->{LAST_CHECK}) {
$result .=
- '
New discussion since '.
+ '
'.&mt('New discussion since').' '.
strftime("%A, %b %e at %I:%M %P", localtime($navmap->{LAST_CHECK})).
' '.
- ' New message (click to open)'.
+ ' '.&mt('New message (click to open)').' '.
' | ';
} else {
$result .= ' '.
- ' Discussions | '.
- ' New message (click to open)'.
+ ' '.&mt('Discussions').' | '.
+ ' '.&mt('New message (click to open)').
' | ';
}
@@ -1347,11 +1344,11 @@ sub render {
if ($condition) {
$result.="Close All Folders";
+ "\">".&mt('Close All Folders')."";
} else {
$result.="Open All Folders";
+ "\">".&mt('Open All Folders')."";
}
$result .= "
\n";
}
@@ -1543,11 +1540,15 @@ sub render {
my $filter = $it->{FILTER};
my $stack = $it->getStack();
my $src = getLinkForResource($stack);
-
+ my $anchor='';
+ if ($src=~s/(\#.*$)//) {
+ $anchor=$1;
+ }
my $srcHasQuestion = $src =~ /\?/;
$args->{"resourceLink"} = $src.
($srcHasQuestion?'&':'?') .
- 'symb=' . &Apache::lonnet::escape($curRes->symb());
+ 'symb=' . &Apache::lonnet::escape($curRes->symb()).
+ $anchor;
# Now, display each column.
foreach my $col (@$cols) {
@@ -1584,7 +1585,6 @@ sub render {
# If we have the connection, make sure the user is still connected
my $c = $r->connection;
if ($c->aborted()) {
- Apache::lonnet::logthis("navmaps aborted");
# Who cares what we do, nobody will see it anyhow.
return '';
}
@@ -1599,7 +1599,12 @@ sub render {
# it's quite likely this might fix other browsers, too, and
# certainly won't hurt anything.
if ($displayedJumpMarker) {
- $result .= "\n";
+ $result .= "
+";
}
$result .= "";
@@ -1975,7 +1980,7 @@ sub getById {
sub getBySymb {
my $self = shift;
my $symb = shift;
- my ($mapUrl, $id, $filename) = split (/___/, $symb);
+ my ($mapUrl, $id, $filename) = &Apache::lonnet::decode_symb($symb);
my $map = $self->getResourceByUrl($mapUrl);
return $self->getById($map->map_pc() . '.' . $id);
}
@@ -2101,7 +2106,11 @@ sub parmval_real {
# ----------------------------------------------------- fourth , check default
- my $default=&Apache::lonnet::metadata($fn,$rwhat.'.default');
+ my $meta_rwhat=$rwhat;
+ $meta_rwhat=~s/\./_/g;
+ my $default=&Apache::lonnet::metadata($fn,$meta_rwhat);
+ if (defined($default)) { return $default}
+ $default=&Apache::lonnet::metadata($fn,'parameter_'.$meta_rwhat);
if (defined($default)) { return $default}
# --------------------------------------------------- fifth , cascade up parts
@@ -2344,6 +2353,8 @@ consisting entirely of empty resources e
ending resource, will cause a lot of BRANCH_STARTs and BRANCH_ENDs,
but only one resource will be returned.
+=back
+
=head2 Normal Usage
Normal usage of the iterator object is to do the following:
@@ -2364,8 +2375,6 @@ the depth of the iterator to see when it
code. It is difficult to get right and harder to understand then
this. They should be migrated to this new style.
-=back
-
=cut
# Here are the tokens for the iterator:
@@ -3166,7 +3175,7 @@ sub is_page {
sub is_problem {
my $self=shift;
my $src = $self->src();
- return ($src =~ /problem$/);
+ return ($src =~ /\.(problem|exam|quiz|assess|survey|form|library)$/);
}
sub is_sequence {
my $self=shift;
@@ -3366,7 +3375,7 @@ sub opendate {
}
sub problemstatus {
(my $self, my $part) = @_;
- return $self->parmval("problemstatus", $part);
+ return lc $self->parmval("problemstatus", $part);
}
sub sig {
(my $self, my $part) = @_;
@@ -3544,7 +3553,11 @@ sub responseType {
my $part = shift;
$self->extractParts();
- return $self->{RESPONSE_TYPES}->{$part};
+ if (defined($self->{RESPONSE_TYPES}->{$part})) {
+ return @{$self->{RESPONSE_TYPES}->{$part}};
+ } else {
+ return undef;
+ }
}
sub responseIds {
@@ -3552,7 +3565,11 @@ sub responseIds {
my $part = shift;
$self->extractParts();
- return $self->{RESPONSE_IDS}->{$part};
+ if (defined($self->{RESPONSE_IDS}->{$part})) {
+ return @{$self->{RESPONSE_IDS}->{$part}};
+ } else {
+ return undef;
+ }
}
# Private function: Extracts the parts information, both part names and
@@ -3569,32 +3586,44 @@ sub extractParts {
# Retrieve part count, if this is a problem
if ($self->is_problem()) {
+ my $partorder = &Apache::lonnet::metadata($self->src(), 'partorder');
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())) {
- $parts{$part} = 1;
- }
- }
+ if ($partorder) {
+ my @parts;
+ for my $part (split (/,/,$partorder)) {
+ if (!Apache::loncommon::check_if_partid_hidden($part, $self->symb())) {
+ push @parts, $part;
+ $parts{$part} = 1;
+ }
+ }
+ $self->{PARTS} = \@parts;
+ } else {
+ 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())) {
+ $parts{$part} = 1;
+ }
+ }
+ }
+ my @sortedParts = sort keys %parts;
+ $self->{PARTS} = \@sortedParts;
}
-
- my @sortedParts = sort keys %parts;
- $self->{PARTS} = \@sortedParts;
my %responseIdHash;
my %responseTypeHash;
@@ -3606,7 +3635,7 @@ sub extractParts {
}
# Now, the unfortunate thing about this is that parts, part name, and
- # response if are delimited by underscores, but both the part
+ # response id 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
@@ -3618,7 +3647,6 @@ sub extractParts {
my $partIdSoFar = '';
my @partChunks = split /_/, $partStuff;
my $i = 0;
-
for ($i = 0; $i < scalar(@partChunks); $i++) {
if ($partIdSoFar) { $partIdSoFar .= '_'; }
$partIdSoFar .= $partChunks[$i];
@@ -3626,13 +3654,11 @@ sub extractParts {
my @otherChunks = @partChunks[$i+1..$#partChunks];
my $responseId = join('_', @otherChunks);
push @{$responseIdHash{$partIdSoFar}}, $responseId;
- $responseTypeHash{$partIdSoFar} = $responseType;
- last;
+ push @{$responseTypeHash{$partIdSoFar}}, $responseType;
}
}
}
}
-
$self->{RESPONSE_IDS} = \%responseIdHash;
$self->{RESPONSE_TYPES} = \%responseTypeHash;
}
@@ -3945,7 +3971,12 @@ sub status {
#if ($self->{RESOURCE_ERROR}) { return NETWORK_FAILURE; }
if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; }
- my $suppressFeedback = lc($self->parmval("problemstatus", $part)) eq 'no';
+ my $suppressFeedback = $self->problemstatus($part) eq 'no';
+ # If there's an answer date and we're past it, don't
+ # suppress the feedback; student should know
+ if ($self->answerdate($part) && $self->answerdate($part) < time()) {
+ $suppressFeedback = 0;
+ }
# There are a few whole rows we can dispose of:
if ($completionStatus == CORRECT ||