Key: | ';
+ my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc");
if ($navmap->{LAST_CHECK}) {
$result .=
- ' '.&mt('New discussion since').' '.
+ ' '.&mt('New discussion since').' '.
strftime("%A, %b %e at %I:%M %P", localtime($navmap->{LAST_CHECK})).
' '.
- ' '.&mt('New message (click to open)').' '.
+ ' '.&mt('New message (click to open)').' '.
' | ';
} else {
$result .= ' '.
- ' '.&mt('Discussions').' | '.
- ' '.&mt('New message (click to open)').
+ ' '.&mt('Discussions').' | '.
+ ' '.&mt('New message (click to open)').
' | ';
}
@@ -1515,53 +1539,85 @@ sub render {
}
if ($printCloseAll && !$args->{'resource_no_folder_link'}) {
+ my ($link,$text);
if ($condition) {
- $result.="".&mt('Close All Folders')."";
+ $link='"navmaps?condition=0&filter=&'.$queryString.
+ '&here='.&Apache::lonnet::escape($here).'"';
+ $text='Close All Folders';
} else {
- $result.="".&mt('Open All Folders')."";
- }
+ $link='"navmaps?condition=1&filter=&'.$queryString.
+ '&here='.&Apache::lonnet::escape($here).'"';
+ $text='Open All Folders';
+ }
+ if ($args->{'caller'} eq 'navmapsdisplay') {
+ &add_linkitem($args->{'linkitems'},'changefolder',
+ 'location.href='.$link,$text);
+ } else {
+ $result.=''.&mt($text).'';
+ }
$result .= "\n";
}
# Check for any unread discussions in all resources.
- if (!$args->{'resource_no_folder_link'}) {
- my $totdisc = 0;
- my $haveDisc = '';
- my @allres=$navmap->retrieveResources();
- foreach my $resource (@allres) {
- if ($resource->hasDiscussion()) {
- my $ressymb;
- if ($resource->symb() =~ m-(___adm/\w+/\w+)/(\d+)/bulletinboard$-) {
- $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
- } else {
- $ressymb = $resource->symb();
+ if ($args->{'caller'} eq 'navmapsdisplay') {
+ &add_linkitem($args->{'linkitems'},'clearbubbles',
+ 'document.clearbubbles.submit()',
+ 'Mark all posts read');
+ my $time=time;
+ $result .= (<
+
+
+END
+ if ($args->{'sort'} eq 'discussion') {
+ my $totdisc = 0;
+ my $haveDisc = '';
+ my @allres=$navmap->retrieveResources();
+ foreach my $resource (@allres) {
+ if ($resource->hasDiscussion()) {
+ my $ressymb;
+ if ($resource->symb() =~ m-(___adm/\w+/\w+)/(\d+)/bulletinboard$-) {
+ $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
+ } else {
+ $ressymb = $resource->symb();
+ }
+ $haveDisc .= $ressymb.':';
+ $totdisc ++;
}
- $haveDisc .= $ressymb.':';
- $totdisc ++;
}
- }
- if ($totdisc > 0) {
- $haveDisc =~ s/:$//;
- my %lt = &Apache::lonlocal::texthash(
- 'mapr' => 'Mark all posts read',
- );
- $result .= (<$lt{'mapr'}
-
+ if ($totdisc > 0) {
+ $haveDisc =~ s/:$//;
+ $result .= (<
+
END
- } else {
- $result .= '
';
+ }
}
+ $result.='';
}
- if ($args->{'sort_html'}) { $result.=$args->{'sort_html'}; }
+ if ($args->{'caller'} eq 'navmapsdisplay') {
+ $result .= ''.
+ &Apache::loncommon::help_open_menu('','Navigation Screen','Navigation_Screen','',undef,'RAT').' | ';
+ if ($ENV{'environment.remotenavmap'} ne 'on') {
+ $result .= ' | ';
+ } else {
+ $result .= '
';
+ }
+ $result.=&show_linkitems($args->{'linkitems'});
+ if ($args->{'sort_html'}) {
+ if ($ENV{'environment.remotenavmap'} ne 'on') {
+ $result.=' | | | '.
+ ''.$args->{'sort_html'}.' |
';
+ } else {
+ $result.=' '.
+ $args->{'sort_html'}.' |
';
+ }
+ }
+ $result .= '
';
+ } elsif ($args->{'sort_html'}) {
+ $result.=$args->{'sort_html'};
+ }
$result .= "
\n";
if ($r) {
@@ -1585,7 +1641,9 @@ END
$args->{'indentLevel'} = 0;
$args->{'isNewBranch'} = 0;
$args->{'condensed'} = 0;
- $args->{'indentString'} = setDefault($args->{'indentString'}, "");
+ my $location=
+ &Apache::loncommon::lonhttpdurl("/adm/lonIcons/whitespace1.gif");
+ $args->{'indentString'} = setDefault($args->{'indentString'}, "");
$args->{'displayedHereMarker'} = 0;
# If we're suppressing empty sequences, look for them here. Use DFS for speed,
@@ -1646,18 +1704,35 @@ END
return &$oldFilterFunc($res);
};
@resources=$navmap->retrieveResources(undef,$filterFunc);
- @resources= sort {lc($a->compTitle) cmp lc($b->compTitle)} @resources;
+ @resources= sort { &cmp_title($a,$b) } @resources;
} elsif ($args->{'sort'} eq 'duedate') {
- @resources=$navmap->retrieveResources(undef,
- sub { shift->is_problem(); });
- @resources= sort
- {
+ my $oldFilterFunc = $filterFunc;
+ my $filterFunc=
+ sub {
+ my ($res)=@_;
+ if (!$res->is_problem()) { return 0;}
+ return &$oldFilterFunc($res);
+ };
+ @resources=$navmap->retrieveResources(undef,$filterFunc);
+ @resources= sort {
if ($a->duedate ne $b->duedate) {
return $a->duedate cmp $b->duedate;
- } else {
- lc($a->compTitle) cmp lc($b->compTitle)
}
+ my $value=&cmp_title($a,$b);
+ return $value;
} @resources;
+ } elsif ($args->{'sort'} eq 'discussion') {
+ my $oldFilterFunc = $filterFunc;
+ my $filterFunc=
+ sub {
+ my ($res)=@_;
+ if (!$res->hasDiscussion() &&
+ !$res->getFeedback() &&
+ !$res->getErrors()) { return 0;}
+ return &$oldFilterFunc($res);
+ };
+ @resources=$navmap->retrieveResources(undef,$filterFunc);
+ @resources= sort { &cmp_title($a,$b) } @resources;
} else {
#unknow sort mechanism or default
undef($args->{'sort'});
@@ -1774,7 +1849,26 @@ END
# Add part 0 so we display it correctly.
unshift @parts, '0';
}
-
+
+ {
+ my ($src,$symb,$anchor,$stack);
+ if ($args->{'sort'}) {
+ my $it = $navmap->getIterator(undef, undef, undef, 1);
+ while ( my $res=$it->next()) {
+ if (ref($res) &&
+ $res->symb() eq $curRes->symb()) { last; }
+ }
+ $stack=$it->getStack();
+ } else {
+ $stack=$it->getStack();
+ }
+ ($src,$symb,$anchor)=getLinkForResource($stack);
+ if (defined($anchor)) { $anchor='#'.$anchor; }
+ my $srcHasQuestion = $src =~ /\?/;
+ $args->{"resourceLink"} = $src.
+ ($srcHasQuestion?'&':'?') .
+ 'symb=' . &Apache::lonnet::escape($symb).$anchor;
+ }
# Now, we've decided what parts to show. Loop through them and
# show them.
foreach my $part (@parts) {
@@ -1785,22 +1879,6 @@ END
# Set up some data about the parts that the cols might want
my $filter = $it->{FILTER};
- my $src;
- if ($args->{'sort'}) {
- $src = $curRes->src(); # FIXME this is wrong for .pages
- } else {
- my $stack = $it->getStack();
- $src=getLinkForResource($stack);
- }
- my $anchor='';
- if ($src=~s/(\#.*)$//) {
- $anchor=$1;
- }
- my $srcHasQuestion = $src =~ /\?/;
- $args->{"resourceLink"} = $src.
- ($srcHasQuestion?'&':'?') .
- 'symb=' . &Apache::lonnet::escape($curRes->symb()).
- $anchor;
# Now, display each column.
foreach my $col (@$cols) {
@@ -1867,8 +1945,46 @@ if (location.href.indexOf('#curloc')==-1
$r->rflush();
}
- if ($mustCloseNavMap) { $navmap->untieHashes(); }
+ return $result;
+}
+
+sub add_linkitem {
+ my ($linkitems,$name,$cmd,$text)=@_;
+ $$linkitems{$name}{'cmd'}=$cmd;
+ $$linkitems{$name}{'text'}=&mt($text);
+}
+sub show_linkitems {
+ my ($linkitems)=@_;
+ my @linkorder = ("blank","launchnav","closenav","firsthomework",
+ "everything","uncompleted","changefolder","clearbubbles");
+
+ my $result .= (<
+
+ '."\n";
+
return $result;
}
@@ -1929,10 +2045,6 @@ successful, or B if not.
=back
-When you are done with the $navmap object, you I call
-$navmap->untieHashes(), or you'll prevent the current user from using that
-course until the web server is restarted. (!)
-
=head2 Methods
=over 4
@@ -2078,17 +2190,11 @@ sub generate_email_discuss_status {
foreach my $msgid (split(/\&/, $keys)) {
$msgid=&Apache::lonnet::unescape($msgid);
- my $plain=&Apache::lonnet::unescape(&Apache::lonnet::unescape($msgid));
- if ($plain=~/(Error|Feedback) \[([^\]]+)\]/) {
- my ($what,$url)=($1,$2);
- my %status=
- &Apache::lonnet::get('email_status',[$msgid]);
- if ($status{$msgid}=~/^error\:/) {
- $status{$msgid}='';
- }
-
- if (($status{$msgid} eq 'new') ||
- (!$status{$msgid})) {
+ if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) {
+ my $plain=
+ &Apache::lonnet::unescape(&Apache::lonnet::unescape($msgid));
+ if ($plain=~/(Error|Feedback) \[([^\]]+)\]/) {
+ my ($what,$url)=($1,$2);
if ($what eq 'Error') {
$error{$url}.=','.$msgid;
} else {
@@ -2098,8 +2204,10 @@ sub generate_email_discuss_status {
}
}
+ #url's of resources that have feedbacks
$self->{FEEDBACK} = \%feedback;
- $self->{ERROR_MSG} = \%error; # what is this? JB
+ #or errors
+ $self->{ERROR_MSG} = \%error;
$self->{DISCUSSION_TIME} = \%discussiontime;
$self->{EMAIL_STATUS} = \%emailstatus;
$self->{LAST_READ} = \%lastreadtime;
@@ -2153,13 +2261,6 @@ sub getIterator {
return $iterator;
}
-# unties the hash when done
-sub untieHashes {
- my $self = shift;
- untie %{$self->{NAV_HASH}};
- untie %{$self->{PARM_HASH}};
-}
-
# Private method: Does the given resource (as a symb string) have
# current discussion? Returns 0 if chat/mail data not extracted.
sub hasDiscussion {
@@ -2540,7 +2641,7 @@ sub hasResource {
1;
package Apache::lonnavmaps::iterator;
-
+use WeakRef;
=pod
=back
@@ -2680,7 +2781,7 @@ sub new {
my $class = ref($proto) || $proto;
my $self = {};
- $self->{NAV_MAP} = shift;
+ weaken($self->{NAV_MAP} = shift);
return undef unless ($self->{NAV_MAP});
# Handle the parameters
@@ -3016,7 +3117,7 @@ sub populateStack {
1;
package Apache::lonnavmaps::DFSiterator;
-
+use WeakRef;
# Not documented in the perldoc: This is a simple iterator that just walks
# through the nav map and presents the resources in a depth-first search
# fashion, ignorant of conditionals, randomized resources, etc. It presents
@@ -3044,7 +3145,7 @@ sub new {
my $class = ref($proto) || $proto;
my $self = {};
- $self->{NAV_MAP} = shift;
+ weaken($self->{NAV_MAP} = shift);
return undef unless ($self->{NAV_MAP});
$self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource();
@@ -3198,7 +3299,7 @@ sub populateStack {
1;
package Apache::lonnavmaps::resource;
-
+use WeakRef;
use Apache::lonnet;
=pod
@@ -3280,7 +3381,7 @@ sub new {
my $class = ref($proto) || $proto;
my $self = {};
- $self->{NAV_MAP} = shift;
+ weaken($self->{NAV_MAP} = shift);
$self->{ID} = shift;
# Store this new resource in the parent nav map's cache.
@@ -3368,6 +3469,7 @@ Returns the title of the resource.
# These info functions can be used directly, as they don't return
# resource information.
sub comesfrom { my $self=shift; return $self->navHash("comesfrom_", 1); }
+sub encrypted { my $self=shift; return $self->navHash("encrypted_", 1); }
sub ext { my $self=shift; return $self->navHash("ext_", 1) eq 'true:'; }
sub from { my $self=shift; return $self->navHash("from_", 1); }
# considered private and undocumented
@@ -3379,10 +3481,20 @@ sub randompick {
return $self->{NAV_MAP}->{PARM_HASH}->{$self->symb .
'.0.parameter_randompick'};
}
+sub link {
+ my $self=shift;
+ if ($self->encrypted()) { return &Apache::lonenc::encrypted($self->src); }
+ return $self->src;
+}
sub src {
my $self=shift;
return $self->navHash("src_", 1);
}
+sub shown_symb {
+ my $self=shift;
+ if ($self->encrypted()) {return &Apache::lonenc::encrypted($self->symb());}
+ return $self->symb();
+}
sub symb {
my $self=shift;
(my $first, my $second) = $self->{ID} =~ /(\d+).(\d+)/;
@@ -3401,6 +3513,16 @@ sub title {
return $self->navHash("title_", 1); }
# considered private and undocumented
sub to { my $self=shift; return $self->navHash("to_", 1); }
+sub condition {
+ my $self=shift;
+ my $undercond=$self->navHash("undercond_", 1);
+ if (!defined($undercond)) { return 1; };
+ my $condid=$self->navHash("condid_$undercond");
+ if (!defined($condid)) { return 1; };
+ my $condition=&Apache::lonnet::directcondval($condid);
+ return $condition;
+}
+
sub compTitle {
my $self = shift;
my $title = $self->title();
@@ -3822,6 +3944,16 @@ Returns the number of parts of the probl
for single part problems, returns 1. For multipart, it returns the
number of parts in the problem, not including psuedo-part 0.
+=item * B():
+
+Returns the total number of responses in the problem a student can answer.
+
+=item * B():
+
+Returns a hash whose keys are the response types. The values are the number
+of times each response type is used. This is for the I problem, not
+just a single part.
+
=item * B():
Returns true if the problem is multipart, false otherwise. Use this instead
@@ -3868,6 +4000,26 @@ sub countParts {
return scalar(@{$parts}); # + $delta;
}
+sub countResponses {
+ my $self = shift;
+ my $count;
+ foreach my $part (@{$self->parts()}) {
+ $count+= scalar($self->responseIds($part));
+ }
+ return $count;
+}
+
+sub responseTypes {
+ my $self = shift;
+ my %responses;
+ foreach my $part ($self->parts()) {
+ foreach my $responsetype ($self->responseType($part)) {
+ $responses{$responsetype}++ if (defined($responsetype));
+ }
+ }
+ return %responses;
+}
+
sub multipart {
my $self = shift;
return $self->countParts() > 1;
@@ -3955,6 +4107,7 @@ sub extractParts {
}
+ # These hashes probably do not need names that end with "Hash"....
my %responseIdHash;
my %responseTypeHash;
@@ -3990,17 +4143,27 @@ sub extractParts {
}
}
my $resorder = &Apache::lonnet::metadata($self->src(),'responseorder');
+ #
+ # Reorder the arrays in the %responseIdHash and %responseTypeHash
if ($resorder) {
my @resorder=split(/,/,$resorder);
foreach my $part (keys(%responseIdHash)) {
- my %resids = map { ($_,1) } @{ $responseIdHash{$part} };
+ my $i=0;
+ my %resids = map { ($_,$i++) } @{ $responseIdHash{$part} };
my @neworder;
foreach my $possibleid (@resorder) {
if (exists($resids{$possibleid})) {
- push(@neworder,$possibleid);
+ push(@neworder,$resids{$possibleid});
}
}
- $responseIdHash{$part}=\@neworder;
+ my @ids;
+ my @type;
+ foreach my $element (@neworder) {
+ push (@ids,$responseIdHash{$part}->[$element]);
+ push (@type,$responseTypeHash{$part}->[$element]);
+ }
+ $responseIdHash{$part}=\@ids;
+ $responseTypeHash{$part}=\@type;
}
}
$self->{RESPONSE_IDS} = \%responseIdHash;
@@ -4196,6 +4359,7 @@ sub getCompletionStatus {
# Left as separate if statements in case we ever do more with this
if ($status eq 'correct_by_student') {return $self->CORRECT;}
+ if ($status eq 'correct_by_scantron') {return $self->CORRECT;}
if ($status eq 'correct_by_override') {return $self->CORRECT_BY_OVERRIDE; }
if ($status eq 'incorrect_attempted') {return $self->INCORRECT; }
if ($status eq 'incorrect_by_override') {return $self->INCORRECT_BY_OVERRIDE; }
@@ -4532,6 +4696,7 @@ sub getNext {
my $to = $self->to();
foreach my $branch ( split(/,/, $to) ) {
my $choice = $self->{NAV_MAP}->getById($branch);
+ if (!$choice->condition()) { next; }
my $next = $choice->goesto();
$next = $self->{NAV_MAP}->getById($next);
@@ -4560,7 +4725,8 @@ sub browsePriv {
return $self->{BROWSE_PRIV};
}
- $self->{BROWSE_PRIV} = &Apache::lonnet::allowed('bre', $self->src());
+ $self->{BROWSE_PRIV} = &Apache::lonnet::allowed('bre',$self->src(),
+ $self->symb());
}
=pod