--- loncom/interface/lonnavmaps.pm 2004/09/09 09:49:03 1.286
+++ loncom/interface/lonnavmaps.pm 2004/10/07 22:12:47 1.300
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Navigate Maps Handler
#
-# $Id: lonnavmaps.pm,v 1.286 2004/09/09 09:49:03 albertel Exp $
+# $Id: lonnavmaps.pm,v 1.300 2004/10/07 22:12:47 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -35,7 +35,7 @@ use Apache::loncommon();
use Apache::lonmenu();
use Apache::lonlocal;
use POSIX qw (floor strftime);
-use Data::Dumper; # for debugging, not always used
+use Data::Dumper; # for debugging, not always
# symbolic constants
sub SYMB { return 1; }
@@ -127,7 +127,7 @@ sub nav_control_js {
function gonav(url) {
if (w_loncapanav_flag != 1) {
- go(url);
+ gopost(url,'');
} else {
navwindow=window.open(url,
"loncapanav","height=600,width=400,scrollbars=1");
@@ -354,7 +354,7 @@ ENDSUBM
} else {
&add_linkitem(\%toplinkitems,'firsthomework',
'location.href="navmaps?jumpToFirstHomework"',
- "Go To My First Homework Problem");
+ "Show Me My First Homework Problem");
}
my $suppressEmptySequences = 0;
@@ -370,7 +370,7 @@ ENDSUBM
return $res->completable() || $res->is_map();
};
&add_linkitem(\%toplinkitems,'everything',
- 'location.href="locatnavmaps?sort='.$ENV{'form.sort'}.'"',
+ 'location.href="navmaps?sort='.$ENV{'form.sort'}.'"',
"Show Everything");
$r->print("
".&mt("Uncompleted Homework")."
");
$ENV{'form.filter'} = '';
@@ -392,6 +392,7 @@ ENDSUBM
+
");
@@ -409,7 +410,6 @@ ENDSUBM
'caller' => 'navmapsdisplay',
'linkitems' => \%toplinkitems};
my $render = render($renderArgs);
- $navmap->untieHashes();
# If no resources were printed, print a reassuring message so the
# user knows there was no error.
@@ -1034,10 +1034,10 @@ sub render_resource {
my $partLabel = "";
my $newBranchText = "";
-
+ my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons");
# If this is a new branch, label it so
if ($params->{'isNewBranch'}) {
- $newBranchText = "";
+ $newBranchText = "";
}
# links to open and close the folder
@@ -1045,17 +1045,16 @@ sub render_resource {
my $linkclose = "";
# Default icon: unknown page
- my $icon = "";
+ my $icon = "";
if ($resource->is_problem()) {
if ($part eq '0' || $params->{'condensed'}) {
- $icon = '';
+ $icon ='';
} else {
$icon = $params->{'indentString'};
}
} else {
- $icon = "";
+ $icon = "";
}
# Display the correct map icon to open or shut map
@@ -1070,7 +1069,7 @@ sub render_resource {
if (!$params->{'resource_no_folder_link'}) {
$icon = "navmap.$folderType." . ($nowOpen ? 'closed' : 'open') . '.gif';
- $icon = "";
+ $icon = "";
$linkopen = "{'queryString'} . '&filter=';
@@ -1087,7 +1086,7 @@ sub render_resource {
# Don't allow users to manipulate folder
$icon = "navmap.$folderType." . ($nowOpen ? 'closed' : 'open') .
'.nomanip.gif';
- $icon = "";
+ $icon = "";
$linkopen = "";
$linkclose = "";
@@ -1155,10 +1154,10 @@ sub render_communication_status {
my $link = $params->{"resourceLink"};
my $linkopen = "";
my $linkclose = "";
-
+ my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc");
if ($resource->hasDiscussion()) {
$discussionHTML = $linkopen .
- '' .
+ '' .
$linkclose;
}
@@ -1168,7 +1167,7 @@ sub render_communication_status {
if ($_) {
$feedbackHTML .= ' '
- . '';
}
}
@@ -1183,7 +1182,7 @@ sub render_communication_status {
$errorcount++;
$errorHTML .= ' '
- . '';
}
}
@@ -1212,7 +1211,9 @@ sub render_quick_status {
my $icon = $statusIconMap{$resource->simpleStatus($part)};
my $alt = $iconAltTags{$icon};
if ($icon) {
- $result .= "
$linkopen$linkclose
\n";
+ my $location=
+ &Apache::loncommon::lonhttpdurl("/adm/lonIcons/$icon");
+ $result .= "
$linkopen$linkclose
\n";
} else {
$result .= "
\n";
}
@@ -1343,11 +1344,17 @@ sub setDefault {
return $val;
}
+sub cmp_title {
+ my ($atitle,$btitle) = (lc($_[0]->compTitle),lc($_[1]->compTitle));
+ $atitle=~s/^\s*//;
+ $btitle=~s/^\s*//;
+ return $atitle cmp $btitle;
+}
+
sub render {
my $args = shift;
&Apache::loncommon::get_unprocessed_cgi($ENV{QUERY_STRING});
my $result = '';
-
# Configure the renderer.
my $cols = $args->{'cols'};
if (!defined($cols)) {
@@ -1428,7 +1435,7 @@ sub render {
# We only need to do this if we need to open the maps to show the
# current position. This will change the counter so we can't count
# for the jump marker with this loop.
- while (($curRes = $mapIterator->next()) && !$found) {
+ while ($here && ($curRes = $mapIterator->next()) && !$found) {
if (ref($curRes) && $curRes->symb() eq $here) {
my $mapStack = $mapIterator->getStack();
@@ -1504,23 +1511,24 @@ sub render {
my $printKey = $args->{'printKey'};
my $printCloseAll = $args->{'printCloseAll'};
if (!defined($printCloseAll)) { $printCloseAll = 1; }
-
+
# Print key?
if ($printKey) {
$result .= '
';
my $date=localtime;
$result.='
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})).
'
';
}
@@ -1549,34 +1557,40 @@ sub render {
# Check for any unread discussions in all resources.
if ($args->{'caller'} eq 'navmapsdisplay') {
- 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();
+ &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 $navurl = $ENV{'QUERY_STRING'};
- &add_linkitem($args->{'linkitems'},'clearbubbles',
- 'document.clearbubbles.submit()',
- 'Mark all posts read');
- $result .= (<
-
-
-
+ if ($totdisc > 0) {
+ $haveDisc =~ s/:$//;
+ $result .= (<
+
END
+ }
}
+ $result.='';
}
if ($args->{'caller'} eq 'navmapsdisplay') {
@@ -1624,7 +1638,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,
@@ -1685,18 +1701,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'});
@@ -1906,8 +1939,6 @@ if (location.href.indexOf('#curloc')==-1
$r->rflush();
}
- if ($mustCloseNavMap) { $navmap->untieHashes(); }
-
return $result;
}
@@ -1947,6 +1978,7 @@ ENDBLOCK
$result .= '
'."\n";
+
return $result;
}
@@ -2007,10 +2039,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
@@ -2156,17 +2184,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 {
@@ -2176,8 +2198,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;
@@ -2231,13 +2255,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 {
@@ -2618,7 +2635,7 @@ sub hasResource {
1;
package Apache::lonnavmaps::iterator;
-
+use WeakRef;
=pod
=back
@@ -2758,7 +2775,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
@@ -3094,7 +3111,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
@@ -3122,7 +3139,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();
@@ -3276,7 +3293,7 @@ sub populateStack {
1;
package Apache::lonnavmaps::resource;
-
+use WeakRef;
use Apache::lonnet;
=pod
@@ -3358,7 +3375,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.
@@ -3900,6 +3917,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
@@ -3946,6 +3973,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;
@@ -4285,6 +4332,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; }