--- loncom/interface/lonnavmaps.pm 2003/06/16 15:08:22 1.205
+++ loncom/interface/lonnavmaps.pm 2004/07/27 23:35:34 1.273
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Navigate Maps Handler
#
-# $Id: lonnavmaps.pm,v 1.205 2003/06/16 15:08:22 bowersj2 Exp $
+# $Id: lonnavmaps.pm,v 1.273 2004/07/27 23:35:34 www 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
@@ -61,19 +49,14 @@ my $resObj = "Apache::lonnavmaps::resour
# Keep these mappings in sync with lonquickgrades, which uses the colors
# instead of the icons.
my %statusIconMap =
- ( $resObj->NETWORK_FAILURE => '',
- $resObj->NOTHING_SET => '',
- $resObj->CORRECT => 'navmap.correct.gif',
- $resObj->EXCUSED => 'navmap.correct.gif',
- $resObj->PAST_DUE_NO_ANSWER => 'navmap.wrong.gif',
- $resObj->PAST_DUE_ANSWER_LATER => 'navmap.wrong.gif',
- $resObj->ANSWER_OPEN => 'navmap.wrong.gif',
- $resObj->OPEN_LATER => '',
- $resObj->TRIES_LEFT => 'navmap.open.gif',
- $resObj->INCORRECT => 'navmap.wrong.gif',
- $resObj->OPEN => 'navmap.open.gif',
- $resObj->ATTEMPTED => 'navmap.ellipsis.gif',
- $resObj->ANSWER_SUBMITTED => '' );
+ (
+ $resObj->CLOSED => '',
+ $resObj->OPEN => 'navmap.open.gif',
+ $resObj->CORRECT => 'navmap.correct.gif',
+ $resObj->INCORRECT => 'navmap.wrong.gif',
+ $resObj->ATTEMPTED => 'navmap.ellipsis.gif',
+ $resObj->ERROR => ''
+ );
my %iconAltTags =
( 'navmap.correct.gif' => 'Correct',
@@ -92,11 +75,64 @@ my %colormap =
$resObj->TRIES_LEFT => '',
$resObj->INCORRECT => '',
$resObj->OPEN => '',
- $resObj->NOTHING_SET => '' );
+ $resObj->NOTHING_SET => '',
+ $resObj->ATTEMPTED => '',
+ $resObj->ANSWER_SUBMITTED => ''
+ );
# And a special case in the nav map; what to do when the assignment
# is not yet done and due in less then 24 hours
my $hurryUpColor = "#FF0000";
+sub launch_win {
+ my ($mode,$script)=@_;
+ my $result;
+ if ($script ne 'no') {
+ $result.='';
+ }
+ if ($mode eq 'link') {
+ $result.=''
+ .&mt("Launch navigation in separate window")." ";
+ }
+ return $result;
+}
+
+sub close {
+ if ($ENV{'environment.remotenavmap'} ne 'on') { return ''; }
+ return(<
+window.status='Accessing Nav Control';
+menu=window.open("/adm/rat/empty.html","loncapanav",
+ "height=600,width=400,scrollbars=1");
+window.status='Closing Nav Control';
+menu.close();
+window.status='Done.';
+
+ENDCLOSE
+}
+
+sub update {
+ if ($ENV{'environment.remotenavmap'} ne 'on') { return ''; }
+ if (!$ENV{'request.course.id'}) { return ''; }
+ if ($ENV{'REQUEST_URI'}=~m|^/adm/navmaps|) { return ''; }
+ return(<
+
+ENDUPDATE
+}
+
sub handler {
my $r = shift;
real_handler($r);
@@ -108,9 +144,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;
@@ -118,18 +154,37 @@ 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;
- # Create the nav map
- my $navmap = Apache::lonnavmaps::navmap->new(
- $ENV{"request.course.fn"}.".db",
- $ENV{"request.course.fn"}."_parms.db", 1, 1);
+ if ($ENV{QUERY_STRING} eq 'collapseExternal') {
+ &Apache::lonnet::put('environment',{'remotenavmap' => 'off'});
+ &Apache::lonnet::appenv('environment.remotenavmap' => 'off');
+ $r->print(<<"ENDSUBM");
+
+
+
+
+
+
+ENDSUBM
+ return;
+ }
+ if ($ENV{QUERY_STRING} eq 'launchExternal') {
+ &Apache::lonnet::put('environment',{'remotenavmap' => 'on'});
+ &Apache::lonnet::appenv('environment.remotenavmap' => 'on');
+ }
+ # Create the nav map
+ my $navmap = Apache::lonnavmaps::navmap->new();
if (!defined($navmap)) {
my $requrl = $r->uri;
@@ -138,30 +193,38 @@ 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']);
+ &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['register','sort']);
# ----------------------------------------------------- Force menu registration
my $addentries='';
+ my $more_unload;
+ if ($ENV{'environment.remotenavmap'} eq 'on') {
+ $r->print('');
+# FIXME need to be smarter to only catch window close events
+# $more_unload="collapse()"
+ }
if ($ENV{'form.register'}) {
- $addentries=' onLoad="'.&Apache::lonmenu::loadevents().
- '" onUnload="'.&Apache::lonmenu::unloadevents().'"';
- $r->print(&Apache::lonmenu::registerurl(1));
+ $addentries=' onLoad="'.&Apache::lonmenu::loadevents().
+ '" onUnload="'.&Apache::lonmenu::unloadevents().';'.
+ $more_unload.'"';
+ $r->print(&Apache::lonmenu::registerurl(1));
+ } else {
+ $addentries=' onUnload="'.$more_unload.'"';
}
# Header
$r->print(''.
&Apache::loncommon::bodytag('Navigate Course Contents','',
$addentries,'','',$ENV{'form.register'}));
- $r->print('');
-
- $r->rflush();
-
- # Now that we've displayed some stuff to the user, init the navmap
- $navmap->init();
-
- $r->print(' ');
+ $r->print(''.
+ &Apache::loncommon::help_open_menu('','Navigation Screen','Navigation_Screen','',undef,'RAT'));
+
$r->rflush();
# Check that it's defined
@@ -173,23 +236,17 @@ sub real_handler {
# See if there's only one map in the top-level, if we don't
# already have a filter... if so, automatically display it
+ # (older code; should use retrieveResources)
if ($ENV{QUERY_STRING} !~ /filter/) {
my $iterator = $navmap->getIterator(undef, undef, undef, 0);
- my $depth = 1;
- $iterator->next();
- my $curRes = $iterator->next();
+ my $curRes;
my $sequenceCount = 0;
my $sequenceId;
- while ($depth > 0) {
- if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }
- if ($curRes == $iterator->END_MAP()) { $depth--; }
-
+ while ($curRes = $iterator->next()) {
if (ref($curRes) && $curRes->is_sequence()) {
$sequenceCount++;
$sequenceId = $curRes->map_pc();
}
-
- $curRes = $iterator->next();
}
if ($sequenceCount == 1) {
@@ -201,22 +258,38 @@ sub real_handler {
}
}
+ if ($ENV{QUERY_STRING} eq 'launchExternal') {
+ $r->print('
+ ');
+ $r->print('
+ ');
+ }
+
+ if ($ENV{'environment.remotenavmap'} ne 'on') {
+ $r->print(&launch_win('link','yes'));
+ }
+ if ($ENV{'environment.remotenavmap'} eq 'on') {
+# $r->print("" .
+ $r->print("" .
+ &mt("Close separate navigation window").
+ " ");
+ }
+
my $jumpToFirstHomework = 0;
# Check to see if the student is jumping to next open, do-able problem
if ($ENV{QUERY_STRING} eq 'jumpToFirstHomework') {
$jumpToFirstHomework = 1;
# 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 $curRes;
my $foundDoableProblem = 0;
my $problemRes;
- while ($depth > 0 && !$foundDoableProblem) {
- if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }
- if ($curRes == $iterator->END_MAP()) { $depth--; }
-
+ while (($curRes = $iterator->next()) && !$foundDoableProblem) {
if (ref($curRes) && $curRes->is_problem()) {
my $status = $curRes->status();
if ($curRes->completable()) {
@@ -234,8 +307,6 @@ sub real_handler {
$ENV{'form.postsymb'} = $curRes->symb();
}
}
- } continue {
- $curRes = $iterator->next();
}
# If we found no problems, print a note to that effect.
@@ -244,7 +315,7 @@ sub real_handler {
}
} else {
$r->print("" .
- "Go To My First Homework Problem ");
+ &mt("Go To My First Homework Problem")." ");
}
my $suppressEmptySequences = 0;
@@ -259,17 +330,29 @@ 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")." ");
}
+ $r->print("");
# renderer call
- my $renderArgs = { 'cols' => [0,1,2,3],
+ my $renderArgs = { 'cols' => [0,2,3],
+ 'sort' => $ENV{'form.sort'},
'url' => '/adm/navmaps',
'navmap' => $navmap,
'suppressNavmap' => 1,
@@ -284,7 +367,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.
");
}
@@ -326,8 +409,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));
+ }
}
}
@@ -342,9 +433,9 @@ sub getLinkForResource {
return $res->src();
}
-# Convenience function: This seperates the logic of how to create
+# Convenience function: This separates the logic of how to create
# the problem text strings ("Due: DATE", "Open: DATE", "Not yet assigned",
-# etc.) into a seperate function. It takes a resource object as the
+# etc.) into a separate function. It takes a resource object as the
# first parameter, and the part number of the resource as the second.
# It's basically a big switch statement on the status of the resource.
@@ -354,35 +445,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);
@@ -394,30 +485,30 @@ 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');
}
}
# Convenience function, so others can use it: Is the problem due in less then
# 24 hours, and still can be done?
-sub dueInLessThen24Hours {
+sub dueInLessThan24Hours {
my $res = shift;
my $part = shift;
my $status = $res->status($part);
- return ($status == $res->OPEN() || $status == $res->ATTEMPTED() ||
+ 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
@@ -429,8 +520,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.
@@ -452,9 +543,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);
@@ -522,7 +615,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;
@@ -532,14 +625,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;
}
@@ -550,7 +643,8 @@ sub timeToHumanString {
=head1 NAME
-Apache::lonnavmap - Subroutines to handle and render the navigation maps
+Apache::lonnavmap - Subroutines to handle and render the navigation
+ maps
=head1 SYNOPSIS
@@ -558,18 +652,62 @@ The main handler generates the navigatio
the other objects export this information in a usable fashion for
other modules.
+=head1 OVERVIEW
+
+X When a user enters a course, LON-CAPA examines the
+course structure and caches it in what is often referred to as the
+"big hash" X. You can see it if you are logged into
+LON-CAPA, in a course, by going to /adm/test. (You may need to
+tweak the /home/httpd/lonTabs/htpasswd file to view it.) The
+content of the hash will be under the heading "Big Hash".
+
+Big Hash contains, among other things, how resources are related
+to each other (next/previous), what resources are maps, which
+resources are being chosen to not show to the student (for random
+selection), and a lot of other things that can take a lot of time
+to compute due to the amount of data that needs to be collected and
+processed.
+
+Apache::lonnavmaps provides an object model for manipulating this
+information in a higher-level fashion then directly manipulating
+the hash. It also provides access to several auxilary functions
+that aren't necessarily stored in the Big Hash, but are a per-
+resource sort of value, like whether there is any feedback on
+a given resource.
+
+Apache::lonnavmaps also abstracts away branching, and someday,
+conditions, for the times where you don't really care about those
+things.
+
+Apache::lonnavmaps also provides fairly powerful routines for
+rendering navmaps, and last but not least, provides the navmaps
+view for when the user clicks the NAV button.
+
+B: Apache::lonnavmaps I works for the "currently
+logged in user"; if you want things like "due dates for another
+student" lonnavmaps can not directly retrieve information like
+that. You need the EXT function. This module can still help,
+because many things, such as the course structure, are constant
+between users, and Apache::lonnavmaps can help by providing
+symbs for the EXT call.
+
+The rest of this file will cover the provided rendering routines,
+which can often be used without fiddling with the navmap object at
+all, then documents the Apache::lonnavmaps::navmap object, which
+is the key to accessing the Big Hash information, covers the use
+of the Iterator (which provides the logic for traversing the
+somewhat-complicated Big Hash data structure), documents the
+Apache::lonnavmaps::Resource objects that are returned by
+
=head1 Subroutine: render
The navmap renderer package provides a sophisticated rendering of the
standard navigation maps interface into HTML. The provided nav map
handler is actually just a glorified call to this.
-Because of the large number of parameters this function presents,
+Because of the large number of parameters this function accepts,
instead of passing it arguments as is normal, pass it in an anonymous
-hash with the given options. This is because there is no obvious order
-you may wish to override these in and a hash is easier to read and
-understand then "undef, undef, undef, 1, undef, undef, renderButton,
-undef, 0" when you mostly want default behaviors.
+hash with the desired options.
The package provides a function called 'render', called as
Apache::lonnavmaps::render({}).
@@ -597,29 +735,33 @@ that takes a resource reference, a part
argument hash passed to the renderer, and returns a string that will
be inserted into the HTML representation as it.
+All other parameters are ways of either changing how the columns
+are printing, or which rows are shown.
+
The pre-packaged column names are refered to by constants in the
Apache::lonnavmaps namespace. The following currently exist:
=over 4
-=item * B:
+=item * B:
The general info about the resource: Link, icon for the type, etc. The
-first column in the standard nav map display. This column also accepts
+first column in the standard nav map display. This column provides the
+indentation effect seen in the B