--- loncom/interface/lonnavmaps.pm 2007/05/23 20:46:29 1.399
+++ loncom/interface/lonnavmaps.pm 2008/01/20 01:52:47 1.410
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Navigate Maps Handler
#
-# $Id: lonnavmaps.pm,v 1.399 2007/05/23 20:46:29 albertel Exp $
+# $Id: lonnavmaps.pm,v 1.410 2008/01/20 01:52:47 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -36,9 +36,9 @@ use Apache::lonenc();
use Apache::lonlocal;
use Apache::lonnet;
use POSIX qw (floor strftime);
-use Data::Dumper; # for debugging, not always
use Time::HiRes qw( gettimeofday tv_interval );
use LONCAPA;
+use DateTime();
# symbolic constants
sub SYMB { return 1; }
@@ -170,7 +170,10 @@ sub getLinkForResource {
if (defined($item)) { $res = $item; }
}
- return ($res->link(),$res->shown_symb());
+ if ($res) {
+ return ($res->link(),$res->shown_symb());
+ }
+ return;
}
# Convenience function: This separates the logic of how to create
@@ -184,6 +187,10 @@ sub getDescription {
my $part = shift;
my $status = $res->status($part);
+ my $open = $res->opendate($part);
+ my $due = $res->duedate($part);
+ my $answer = $res->answerdate($part);
+
if ($status == $res->NETWORK_FAILURE) {
return &mt("Having technical difficulties; please check status later");
}
@@ -191,20 +198,28 @@ sub getDescription {
return &mt("Not currently assigned.");
}
if ($status == $res->OPEN_LATER) {
- return "Open " . timeToHumanString($res->opendate($part),'start');
+ return "Open " .timeToHumanString($open,'start');
}
if ($status == $res->OPEN) {
- if ($res->duedate($part)) {
- return &mt("Due")." " .timeToHumanString($res->duedate($part),'end');
+ if ($due) {
+ if ($res->is_practice()) {
+ return &mt("Closes ")." " .timeToHumanString($due,'start');
+ } else {
+ return &mt("Due")." " .timeToHumanString($due,'end');
+ }
} else {
return &mt("Open, no due date");
}
}
if ($status == $res->PAST_DUE_ANSWER_LATER) {
- return &mt("Answer open")." " . timeToHumanString($res->answerdate($part),'start');
+ return &mt("Answer open")." " .timeToHumanString($answer,'start');
}
if ($status == $res->PAST_DUE_NO_ANSWER) {
- return &mt("Was due")." " . timeToHumanString($res->duedate($part),'end');
+ if ($res->is_practice()) {
+ return &mt("Closed")." " . timeToHumanString($due,'start');
+ } else {
+ return &mt("Was due")." " . timeToHumanString($due,'end');
+ }
}
if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT)
&& $res->handgrade($part) ne 'yes') {
@@ -226,8 +241,8 @@ sub getDescription {
$triesString = "$triesString";
}
}
- if ($res->duedate($part)) {
- return &mt("Due")." " . timeToHumanString($res->duedate($part),'end') .
+ if ($due) {
+ return &mt("Due")." " . timeToHumanString($due,'end') .
" $triesString";
} else {
return &mt("No due date")." $triesString";
@@ -294,9 +309,6 @@ sub timeToHumanString {
}
my $now = time();
- my @time = localtime($time);
- my @now = localtime($now);
-
# Positive = future
my $delta = $time - $now;
@@ -355,22 +367,25 @@ sub timeToHumanString {
return "$prefix$hourString$minuteString$tense";
}
+ my $dt = DateTime->from_epoch(epoch => $time)
+ ->set_time_zone(&Apache::lonlocal::gettimezone());
+
# If there's a caller supplied format, use it.
- if($format ne '') {
- my $timeStr = strftime($format, localtime($time));
- return $timeStr.&Apache::lonlocal::gettimezone($time);
+ if ($format ne '') {
+ my $timeStr = $dt->strftime($format);
+ return $timeStr.' ('.$dt->time_zone_short_name().')';
}
# Less than 5 days away, display day of the week and
# HH:MM
if ( $delta < $day * 5 ) {
- my $timeStr = strftime("%A, %b %e at %I:%M %P", localtime($time));
+ my $timeStr = $dt->strftime("%A, %b %e at %I:%M %P (%Z)");
$timeStr =~ s/12:00 am/00:00/;
$timeStr =~ s/12:00 pm/noon/;
return ($inPast ? "last " : "this ") .
- $timeStr.&Apache::lonlocal::gettimezone($time);
+ $timeStr;
}
my $conjunction='on';
@@ -380,19 +395,22 @@ sub timeToHumanString {
$conjunction='by';
}
# Is it this year?
- if ( $time[5] == $now[5]) {
+ my $dt_now = DateTime->from_epoch(epoch => $now)
+ ->set_time_zone(&Apache::lonlocal::gettimezone());
+ if ( $dt->year() == $dt_now->year()) {
# Return on Month Day, HH:MM meridian
- my $timeStr = strftime("$conjunction %A, %b %e at %I:%M %P", localtime($time));
+ my $timeStr = $dt->strftime("$conjunction %A, %b %e at %I:%M %P (%Z)");
$timeStr =~ s/12:00 am/00:00/;
$timeStr =~ s/12:00 pm/noon/;
- return $timeStr.&Apache::lonlocal::gettimezone($time);
+ return $timeStr;
}
# Not this year, so show the year
- my $timeStr = strftime("$conjunction %A, %b %e %Y at %I:%M %P", localtime($time));
+ my $timeStr =
+ $dt->strftime("$conjunction %A, %b %e %Y at %I:%M %P (%Z)");
$timeStr =~ s/12:00 am/00:00/;
$timeStr =~ s/12:00 pm/noon/;
- return $timeStr.&Apache::lonlocal::gettimezone($time);
+ return $timeStr;
}
}
@@ -604,6 +622,11 @@ instruct the renderer to render only a p
the source of the map you want to process, like
'/res/103/jerf/navmap.course.sequence'.
+=item * B: default: false
+
+If you need to include the top level map (meaning the course) in the
+rendered output set this to true
+
=item * B: default: constructs one from %env
A reference to a navmap, used only if an iterator is not passed in. If
@@ -974,7 +997,7 @@ sub render_long_status {
$params->{'multipart'} && $part eq "0";
my $color;
- if ($resource->is_problem()) {
+ if ($resource->is_problem() || $resource->is_practice()) {
$color = $colormap{$resource->status};
if (dueInLessThan24Hours($resource, $part) ||
@@ -984,14 +1007,17 @@ sub render_long_status {
}
if ($resource->kind() eq "res" &&
- $resource->is_problem() &&
+ ($resource->is_problem() || $resource->is_practice()) &&
!$firstDisplayed) {
if ($color) {$result .= ""; }
$result .= getDescription($resource, $part);
if ($color) {$result .= ""; }
}
- if ($resource->is_map() && advancedUser() && $resource->randompick()) {
- $result .= '(randomly select ' . $resource->randompick() .')';
+ if ($resource->is_map() && &advancedUser() && $resource->randompick()) {
+ $result .= &mt('(randomly select [_1])', $resource->randompick());
+ }
+ if ($resource->is_map() && &advancedUser() && $resource->randomorder()) {
+ $result .= &mt('(randomly ordered)');
}
# Debugging code
@@ -1026,7 +1052,6 @@ my %statusStrings =
);
my @statuses = ($resObj->CORRECT, $resObj->ATTEMPTED, $resObj->INCORRECT, $resObj->OPEN, $resObj->CLOSED, $resObj->ERROR);
-use Data::Dumper;
sub render_parts_summary_status {
my ($resource, $part, $params) = @_;
if (!$resource->is_problem() && !$resource->contains_problem) { return ' | '; }
@@ -1233,7 +1258,7 @@ sub render {
$args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition);
} else {
- $args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition);
+ $args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition,undef,$args->{'include_top_level_map'});
}
}
@@ -1270,7 +1295,6 @@ sub render {
# Print key?
if ($printKey) {
$result .= '';
- my $date=localtime;
$result.='Key: | ';
my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc");
if ($navmap->{LAST_CHECK}) {
@@ -2275,12 +2299,19 @@ sub parmval {
my $hashkey = $what."|||".$symb;
if (defined($self->{PARM_CACHE}->{$hashkey})) {
- return $self->{PARM_CACHE}->{$hashkey};
+ if (wantarray) {
+ return @{$self->{PARM_CACHE}->{$hashkey}};
+ } else {
+ return $self->{PARM_CACHE}->{$hashkey}->[0];
+ }
}
my $result = $self->parmval_real($what, $symb, $recurse);
$self->{PARM_CACHE}->{$hashkey} = $result;
- return $result;
+ if (wantarray) {
+ return @{$result};
+ }
+ return $result->[0];
}
sub parmval_real {
@@ -2301,7 +2332,7 @@ sub parmval_real {
my $uname=$env{'user.name'};
my $udom=$env{'user.domain'};
- unless ($symb) { return ''; }
+ unless ($symb) { return ['']; }
my $result='';
my ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb);
@@ -2333,48 +2364,49 @@ sub parmval_real {
# ---------------------------------------------------------- first, check user
if ($uname and defined($useropt)) {
- if (defined($$useropt{$courselevelr})) { return $$useropt{$courselevelr}; }
- if (defined($$useropt{$courselevelm})) { return $$useropt{$courselevelm}; }
- if (defined($$useropt{$courselevel})) { return $$useropt{$courselevel}; }
+ if (defined($$useropt{$courselevelr})) { return [$$useropt{$courselevelr},'resource']; }
+ if (defined($$useropt{$courselevelm})) { return [$$useropt{$courselevelm},'map']; }
+ if (defined($$useropt{$courselevel})) { return [$$useropt{$courselevel},'course']; }
}
# ------------------------------------------------------- second, check course
if ($cgroup ne '' and defined($courseopt)) {
- if (defined($$courseopt{$grplevelr})) { return $$courseopt{$grplevelr}; }
- if (defined($$courseopt{$grplevelm})) { return $$courseopt{$grplevelm}; }
- if (defined($$courseopt{$grplevel})) { return $$courseopt{$grplevel}; }
+ if (defined($$courseopt{$grplevelr})) { return [$$courseopt{$grplevelr},'resource']; }
+ if (defined($$courseopt{$grplevelm})) { return [$$courseopt{$grplevelm},'map']; }
+ if (defined($$courseopt{$grplevel})) { return [$$courseopt{$grplevel},'course']; }
}
if ($csec and defined($courseopt)) {
- if (defined($$courseopt{$seclevelr})) { return $$courseopt{$seclevelr}; }
- if (defined($$courseopt{$seclevelm})) { return $$courseopt{$seclevelm}; }
- if (defined($$courseopt{$seclevel})) { return $$courseopt{$seclevel}; }
+ if (defined($$courseopt{$seclevelr})) { return [$$courseopt{$seclevelr},'resource']; }
+ if (defined($$courseopt{$seclevelm})) { return [$$courseopt{$seclevelm},'map']; }
+ if (defined($$courseopt{$seclevel})) { return [$$courseopt{$seclevel},'course']; }
}
if (defined($courseopt)) {
- if (defined($$courseopt{$courselevelr})) { return $$courseopt{$courselevelr}; }
+ if (defined($$courseopt{$courselevelr})) { return [$$courseopt{$courselevelr},'resource']; }
}
# ----------------------------------------------------- third, check map parms
my $thisparm=$$parmhash{$symbparm};
- if (defined($thisparm)) { return $thisparm; }
+ if (defined($thisparm)) { return [$thisparm,'map']; }
# ----------------------------------------------------- fourth , check default
my $meta_rwhat=$rwhat;
$meta_rwhat=~s/\./_/g;
my $default=&Apache::lonnet::metadata($fn,$meta_rwhat);
- if (defined($default)) { return $default}
+ if (defined($default)) { return [$default,'resource']}
$default=&Apache::lonnet::metadata($fn,'parameter_'.$meta_rwhat);
- if (defined($default)) { return $default}
-
+ if (defined($default)) { return [$default,'resource']}
# --------------------------------------------------- fifth, check more course
if (defined($courseopt)) {
- if (defined($$courseopt{$courselevelm})) { return $$courseopt{$courselevelm}; }
- if (defined($$courseopt{$courselevel})) { return $$courseopt{$courselevel}; }
+ if (defined($$courseopt{$courselevelm})) { return [$$courseopt{$courselevelm},'map']; }
+ if (defined($$courseopt{$courselevel})) {
+ my $ret = [$$courseopt{$courselevel},'course'];
+ return $ret;
+ }
}
-
# --------------------------------------------------- sixth , cascade up parts
my ($space,@qualifier)=split(/\./,$rwhat);
@@ -2384,13 +2416,13 @@ sub parmval_real {
my $id=pop(@parts);
my $part=join('_',@parts);
if ($part eq '') { $part='0'; }
- my $partgeneral=$self->parmval($part.".$qualifier",$symb,1);
- if (defined($partgeneral)) { return $partgeneral; }
+ my @partgeneral=$self->parmval($part.".$qualifier",$symb,1);
+ if (defined($partgeneral[0])) { return \@partgeneral; }
}
- if ($recurse) { return undef; }
+ if ($recurse) { return []; }
my $pack_def=&Apache::lonnet::packages_tab_default($fn,'resource.'.$rwhat);
- if (defined($pack_def)) { return $pack_def; }
- return '';
+ if (defined($pack_def)) { return [$pack_def,'resource']; }
+ return [''];
}
=pod
@@ -2511,6 +2543,10 @@ sub retrieveResources {
my @resources = ();
+ if (&$filterFunc($map)) {
+ push(@resources, $map);
+ }
+
# Run down the iterator and collect the resources.
my $curRes;
@@ -2520,7 +2556,7 @@ sub retrieveResources {
next;
}
- push @resources, $curRes;
+ push(@resources, $curRes);
if ($bailout) {
return @resources;
@@ -2851,6 +2887,10 @@ sub next {
$self->{HAVE_RETURNED_0} = 1;
return $self->{NAV_MAP}->getById('0.0');
}
+ if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0_BEGIN_MAP}) {
+ $self->{HAVE_RETURNED_0_BEGIN_MAP} = 1;
+ return $self->BEGIN_MAP();
+ }
if ($self->{RECURSIVE_ITERATOR_FLAG}) {
# grab the next from the recursive iterator
@@ -3364,8 +3404,13 @@ false.
=item * B:
-Returns true for a map if the randompick feature is being used on the
-map. (?)
+Returns the number of randomly picked items for a map if the randompick
+feature is being used on the map.
+
+=item * B:
+
+Returns true for a map if the randomorder feature is being used on the
+map.
=item * B:
@@ -3395,7 +3440,13 @@ sub kind { my $self=shift; return $self-
sub randomout { my $self=shift; return $self->navHash("randomout_", 1); }
sub randompick {
my $self = shift;
- return $self->parmval('randompick');
+ my $randompick = $self->parmval('randompick');
+ return $randompick;
+}
+sub randomorder {
+ my $self = shift;
+ my $randomorder = $self->parmval('randomorder');
+ return ($randomorder =~ /^yes$/i);
}
sub link {
my $self=shift;
@@ -3516,7 +3567,8 @@ sub retrieveResources {
sub is_exam {
my ($self,$part) = @_;
- if ($self->parmval('type',$part) eq 'exam') {
+ my $type = $self->parmval('type',$part);
+ if ($type eq 'exam') {
return 1;
}
if ($self->src() =~ /\.(exam)$/) {
@@ -3539,7 +3591,8 @@ sub is_page {
sub is_practice {
my $self=shift;
my ($part) = @_;
- if ($self->parmval('type',$part) eq 'practice') {
+ my $type = $self->parmval('type',$part);
+ if ($type eq 'practice') {
return 1;
}
return 0;
@@ -3560,6 +3613,15 @@ sub contains_problem {
}
return 0;
}
+sub map_contains_problem {
+ my $self=shift;
+ if ($self->is_map()) {
+ my $has_problem=
+ $self->hasResource($self,sub { $_[0]->is_problem() },1);
+ return $has_problem;
+ }
+ return 0;
+}
sub is_sequence {
my $self=shift;
return $self->navHash("is_map_", 1) &&
@@ -3568,7 +3630,8 @@ sub is_sequence {
sub is_survey {
my $self = shift();
my $part = shift();
- if ($self->parmval('type',$part) eq 'survey') {
+ my $type = $self->parmval('type',$part);
+ if ($type eq 'survey') {
return 1;
}
if ($self->src() =~ /\.(survey)$/) {
@@ -3744,16 +3807,19 @@ Get the weight for the problem.
sub acc {
(my $self, my $part) = @_;
- return $self->parmval("acc", $part);
+ my $acc = $self->parmval("acc", $part);
+ return $acc;
}
sub answerdate {
(my $self, my $part) = @_;
# Handle intervals
- if ($self->parmval("answerdate.type", $part) eq 'date_interval') {
- return $self->duedate($part) +
- $self->parmval("answerdate", $part);
+ my $answerdatetype = $self->parmval("answerdate.type", $part);
+ my $answerdate = $self->parmval("answerdate", $part);
+ my $duedate = $self->parmval("duedate", $part);
+ if ($answerdatetype eq 'date_interval') {
+ $answerdate = $duedate + $answerdate;
}
- return $self->parmval("answerdate", $part);
+ return $answerdate;
}
sub awarded {
my $self = shift; my $part = shift;
@@ -3765,13 +3831,15 @@ sub awarded {
sub duedate {
(my $self, my $part) = @_;
my $date;
- my $interval=$self->parmval("interval", $part);
+ my @interval=$self->parmval("interval", $part);
my $due_date=$self->parmval("duedate", $part);
- if ($interval =~ /\d+/) {
- my $first_access=&Apache::lonnet::get_first_access('map',$self->symb);
+ if ($interval[0] =~ /\d+/) {
+ my $first_access=&Apache::lonnet::get_first_access($interval[1],
+ $self->symb);
if (defined($first_access)) {
- $interval = $first_access+$interval;
- $date = ($interval < $due_date)? $interval : $due_date;
+ my $interval = $first_access+$interval[0];
+ $date = (!$due_date || $interval < $due_date) ? $interval
+ : $due_date;
} else {
$date = $due_date;
}
@@ -3785,39 +3853,46 @@ sub handgrade {
my @response_ids = $self->responseIds($part);
if (@response_ids) {
foreach my $response_id (@response_ids) {
- if (lc($self->parmval("handgrade",$part.'_'.$response_id))
- eq 'yes') {
+ my $handgrade = $self->parmval("handgrade",$part.'_'.$response_id);
+ if (lc($handgrade) eq 'yes') {
return 'yes';
}
}
}
- return $self->parmval("handgrade", $part);
+ my $handgrade = $self->parmval("handgrade", $part);
+ return $handgrade;
}
sub maxtries {
(my $self, my $part) = @_;
- return $self->parmval("maxtries", $part);
+ my $maxtries = $self->parmval("maxtries", $part);
+ return $maxtries;
}
sub opendate {
(my $self, my $part) = @_;
- if ($self->parmval("opendate.type", $part) eq 'date_interval') {
- return $self->duedate($part) -
- $self->parmval("opendate", $part);
+ my $opendatetype = $self->parmval("opendate.type", $part);
+ my $opendate = $self->parmval("opendate", $part);
+ if ($opendatetype eq 'date_interval') {
+ my $duedate = $self->duedate($part);
+ $opendate = $duedate - $opendate;
}
- return $self->parmval("opendate");
+ return $opendate;
}
sub problemstatus {
(my $self, my $part) = @_;
- return lc $self->parmval("problemstatus", $part);
+ my $problemstatus = $self->parmval("problemstatus", $part);
+ return lc($problemstatus);
}
sub sig {
(my $self, my $part) = @_;
- return $self->parmval("sig", $part);
+ my $sig = $self->parmval("sig", $part);
+ return $sig;
}
sub tol {
(my $self, my $part) = @_;
- return $self->parmval("tol", $part);
+ my $tol = $self->parmval("tol", $part);
+ return $tol;
}
-sub tries {
+sub tries {
my $self = shift;
my $tries = $self->queryRestoreHash('tries', shift);
if (!defined($tries)) { return '0';}
@@ -3825,15 +3900,17 @@ sub tries {
}
sub type {
(my $self, my $part) = @_;
- return $self->parmval("type", $part);
+ my $type = $self->parmval("type", $part);
+ return $type;
}
sub weight {
my $self = shift; my $part = shift;
if (!defined($part)) { $part = '0'; }
- return &Apache::lonnet::EXT('resource.'.$part.'.weight',
- $self->symb(), $env{'user.domain'},
- $env{'user.name'},
- $env{'request.course.sec'});
+ my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
+ $self->symb(), $env{'user.domain'},
+ $env{'user.name'},
+ $env{'request.course.sec'});
+ return $weight;
}
sub part_display {
my $self= shift(); my $partID = shift();
@@ -4507,7 +4584,11 @@ sub status {
#if ($self->{RESOURCE_ERROR}) { return NETWORK_FAILURE; }
if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; }
- my $suppressFeedback = $self->problemstatus($part) eq 'no';
+ my $suppressFeedback = 0;
+ if (($self->problemstatus($part) eq 'no') ||
+ ($self->problemstatus($part) eq 'no_feedback_ever')) {
+ $suppressFeedback = 1;
+ }
# If there's an answer date and we're past it, don't
# suppress the feedback; student should know
if ($self->duedate($part) && $self->duedate($part) < time() &&