version 1.101, 2002/11/08 20:58:13
|
version 1.110, 2002/11/15 20:12:11
|
Line 37
|
Line 37
|
# 3/1/1,6/1,17/1,29/1,30/1,2/8,9/21,9/24,9/25 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 |
# YEAR=2002 |
# 1/1 Gerd Kortemeyer |
# 1/1 Gerd Kortemeyer |
# |
# Oct-Nov Jeremy Bowers |
|
|
package Apache::lonnavmaps; |
package Apache::lonnavmaps; |
|
|
use strict; |
use strict; |
use Apache::Constants qw(:common :http); |
use Apache::Constants qw(:common :http); |
use Apache::lonnet(); |
|
use Apache::loncommon(); |
use Apache::loncommon(); |
use GDBM_File; |
|
use POSIX qw (floor strftime); |
use POSIX qw (floor strftime); |
|
|
sub handler { |
sub handler { |
Line 73 sub handler {
|
Line 71 sub handler {
|
&Apache::loncommon::no_cache($r); |
&Apache::loncommon::no_cache($r); |
$r->send_http_header; |
$r->send_http_header; |
|
|
# Create the nav map the nav map |
# Create the nav map |
my $navmap = Apache::lonnavmaps::navmap->new( |
my $navmap = Apache::lonnavmaps::navmap->new( |
$ENV{"request.course.fn"}.".db", |
$ENV{"request.course.fn"}.".db", |
$ENV{"request.course.fn"}."_parms.db", 1, 1); |
$ENV{"request.course.fn"}."_parms.db", 1, 1); |
Line 115 sub handler {
|
Line 113 sub handler {
|
$condition = 1; |
$condition = 1; |
} |
} |
|
|
|
my $currenturl = $ENV{'form.postdata'}; |
|
$currenturl=~s/^http\:\/\///; |
|
$currenturl=~s/^[^\/]+//; |
|
|
|
# alreadyHere allows us to only open the maps necessary to view |
|
# the current location once, while at the same time remembering |
|
# the current location. Without that check, the user would never |
|
# be able to close those maps; the user would close it, and the |
|
# currenturl scan would re-open it. |
|
my $queryAdd = "postdata=" . &Apache::lonnet::escape($currenturl) . |
|
"&alreadyHere=1"; |
|
|
if ($condition) { |
if ($condition) { |
$r->print('<a href="navmaps?condition=0&filter=">Close All Folders</a>'); |
$r->print("<a href=\"navmaps?condition=0&filter=&$queryAdd\">Close All Folders</a>"); |
} else { |
} else { |
$r->print('<a href="navmaps?condition=1&filter=">Open All Folders</a>'); |
$r->print("<a href=\"navmaps?condition=1&filter=&$queryAdd\">Open All Folders</a>"); |
} |
} |
|
|
$r->print('<br> '); |
$r->print('<br> '); |
Line 195 sub handler {
|
Line 205 sub handler {
|
my $topResource = $navmap->getById("0.0"); |
my $topResource = $navmap->getById("0.0"); |
my $inlineTopLevelMaps = $topResource->src() =~ m|^/uploaded/.*default\.sequence$|; |
my $inlineTopLevelMaps = $topResource->src() =~ m|^/uploaded/.*default\.sequence$|; |
|
|
my $currenturl = $ENV{'form.postdata'}; |
|
$currenturl=~s/^http\:\/\///; |
|
$currenturl=~s/^[^\/]+//; |
|
|
|
# alreadyHere allows us to only open the maps necessary to view |
|
# the current location once, while at the same time remembering |
|
# the current location. Without that check, the user would never |
|
# be able to close those maps; the user would close it, and the |
|
# currenturl scan would re-open it. |
|
my $queryAdd = "postdata=" . &Apache::lonnet::escape($currenturl) . |
|
"&alreadyHere=1"; |
|
|
|
# Begin the HTML table |
# Begin the HTML table |
# four cols: resource + indent, chat+feedback, icon, text string |
# four cols: resource + indent, chat+feedback, icon, text string |
$r->print('<table cellspacing="0" cellpadding="3" border="0" bgcolor="#FFFFFF">' ."\n"); |
$r->print('<table cellspacing="0" cellpadding="3" border="0" bgcolor="#FFFFFF">' ."\n"); |
Line 437 sub handler {
|
Line 435 sub handler {
|
'symb='.&Apache::lonnet::escape($curRes->symb()). |
'symb='.&Apache::lonnet::escape($curRes->symb()). |
'"'; |
'"'; |
|
|
my $title = $curRes->title(); |
my $title = $curRes->compTitle(); |
if (!$title) { |
|
$title = $curRes->src(); |
|
$title = substr ($title, rindex($title, "/") + 1); |
|
} |
|
my $partLabel = ""; |
my $partLabel = ""; |
my $newBranchText = ""; |
my $newBranchText = ""; |
|
|
Line 1289 sub min {
|
Line 1283 sub min {
|
if ($a < $b) { return $a; } else { return $b; } |
if ($a < $b) { return $a; } else { return $b; } |
} |
} |
|
|
|
# In the CVS repository, documentation of this algorithm is included |
|
# in /doc/lonnavdocs, as a PDF and .tex source. Markers like **1** |
|
# will reference the same location in the text as the part of the |
|
# algorithm is running through. |
|
|
sub new { |
sub new { |
# magic invocation to create a class instance |
# magic invocation to create a class instance |
my $proto = shift; |
my $proto = shift; |
Line 1331 sub new {
|
Line 1330 sub new {
|
|
|
my $maxDepth = 0; # tracks max depth |
my $maxDepth = 0; # tracks max depth |
|
|
|
# **1** |
|
|
foreach my $pass (@iterations) { |
foreach my $pass (@iterations) { |
my $direction = $pass->[0]; |
my $direction = $pass->[0]; |
my $valName = $pass->[1]; |
my $valName = $pass->[1]; |
Line 1355 sub new {
|
Line 1356 sub new {
|
my $resultingVal = $curRes->{DATA}->{$valName}; |
my $resultingVal = $curRes->{DATA}->{$valName}; |
my $nextResources = $curRes->$nextResourceMethod(); |
my $nextResources = $curRes->$nextResourceMethod(); |
my $resourceCount = scalar(@{$nextResources}); |
my $resourceCount = scalar(@{$nextResources}); |
|
|
if ($resourceCount == 1) { |
if ($resourceCount == 1) { # **3** |
my $current = $nextResources->[0]->{DATA}->{$valName} || 999999999; |
my $current = $nextResources->[0]->{DATA}->{$valName} || 999999999; |
$nextResources->[0]->{DATA}->{$valName} = min($resultingVal, $current); |
$nextResources->[0]->{DATA}->{$valName} = min($resultingVal, $current); |
} |
} |
|
|
if ($resourceCount > 1) { |
if ($resourceCount > 1) { # **4** |
foreach my $res (@{$nextResources}) { |
foreach my $res (@{$nextResources}) { |
my $current = $res->{DATA}->{$valName} || 999999999; |
my $current = $res->{DATA}->{$valName} || 999999999; |
$res->{DATA}->{$valName} = min($current, $resultingVal + 1); |
$res->{DATA}->{$valName} = min($current, $resultingVal + 1); |
Line 1369 sub new {
|
Line 1370 sub new {
|
} |
} |
} |
} |
|
|
# Assign the final val |
# Assign the final val (**2**) |
if (ref($curRes) && $direction == BACKWARD()) { |
if (ref($curRes) && $direction == BACKWARD()) { |
my $finalDepth = min($curRes->{DATA}->{TOP_DOWN_VAL}, |
my $finalDepth = min($curRes->{DATA}->{TOP_DOWN_VAL}, |
$curRes->{DATA}->{BOT_UP_VAL}); |
$curRes->{DATA}->{BOT_UP_VAL}); |
Line 1391 sub new {
|
Line 1392 sub new {
|
push @{$self->{STACK}}, []; |
push @{$self->{STACK}}, []; |
} |
} |
|
|
# Prime the recursion w/ the first resource |
# Prime the recursion w/ the first resource **5** |
push @{$self->{STACK}->[0]}, $self->{FIRST_RESOURCE}; |
push @{$self->{STACK}->[0]}, $self->{FIRST_RESOURCE}; |
$self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1; |
$self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1; |
|
|
Line 1440 sub next {
|
Line 1441 sub next {
|
my $newDepth; |
my $newDepth; |
my $here; |
my $here; |
while ( $i >= 0 && !$found ) { |
while ( $i >= 0 && !$found ) { |
if ( scalar(@{$self->{STACK}->[$i]}) > 0 ) { |
if ( scalar(@{$self->{STACK}->[$i]}) > 0 ) { # **6** |
$here = $self->{HERE} = shift @{$self->{STACK}->[$i]}; |
$here = pop @{$self->{STACK}->[$i]}; # **7** |
$found = 1; |
$found = 1; |
$newDepth = $i; |
$newDepth = $i; |
} |
} |
Line 1459 sub next {
|
Line 1460 sub next {
|
} |
} |
} |
} |
|
|
|
# If this is not a resource, it must be an END_BRANCH marker we want |
|
# to return directly. |
|
if (!ref($here)) { # **8** |
|
if ($here == END_BRANCH()) { # paranoia, in case of later extension |
|
$self->{CURRENT_DEPTH}--; |
|
return $here; |
|
} |
|
} |
|
|
|
# Otherwise, it is a resource and it's safe to store in $self->{HERE} |
|
$self->{HERE} = $here; |
|
|
# Get to the right level |
# Get to the right level |
if ( $self->{CURRENT_DEPTH} > $newDepth ) { |
if ( $self->{CURRENT_DEPTH} > $newDepth ) { |
push @{$self->{STACK}->[$newDepth]}, $here; |
push @{$self->{STACK}->[$newDepth]}, $here; |
Line 1478 sub next {
|
Line 1491 sub next {
|
# So we need to look at all the resources we can get to from here, |
# So we need to look at all the resources we can get to from here, |
# categorize them if we haven't seen them, remember if we have a new |
# categorize them if we haven't seen them, remember if we have a new |
my $nextUnfiltered = $here->getNext(); |
my $nextUnfiltered = $here->getNext(); |
|
my $maxDepthAdded = -1; |
|
|
for (@$nextUnfiltered) { |
for (@$nextUnfiltered) { |
if (!defined($self->{ALREADY_SEEN}->{$_->{ID}})) { |
if (!defined($self->{ALREADY_SEEN}->{$_->{ID}})) { |
push @{$self->{STACK}->[$_->{DATA}->{DISPLAY_DEPTH}]}, $_; |
my $depth = $_->{DATA}->{DISPLAY_DEPTH}; |
|
push @{$self->{STACK}->[$depth]}, $_; |
$self->{ALREADY_SEEN}->{$_->{ID}} = 1; |
$self->{ALREADY_SEEN}->{$_->{ID}} = 1; |
|
if ($maxDepthAdded < $depth) { $maxDepthAdded = $depth; } |
} |
} |
} |
} |
|
|
|
# Is this the end of a branch? If so, all of the resources examined above |
|
# led to lower levels then the one we are currently at, so we push a END_BRANCH |
|
# marker onto the stack so we don't forget. |
|
# Example: For the usual A(BC)(DE)F case, when the iterator goes down the |
|
# BC branch and gets to C, it will see F as the only next resource, but it's |
|
# one level lower. Thus, this is the end of the branch, since there are no |
|
# more resources added to this level or above. |
|
my $isEndOfBranch = $maxDepthAdded < $self->{CURRENT_DEPTH}; |
|
if ($isEndOfBranch) { # **9** |
|
push @{$self->{STACK}->[$self->{CURRENT_DEPTH}]}, END_BRANCH(); |
|
} |
|
|
# That ends the main iterator logic. Now, do we want to recurse |
# That ends the main iterator logic. Now, do we want to recurse |
# down this map (if this resource is a map)? |
# down this map (if this resource is a map)? |
if ($self->{HERE}->is_map() && |
if ($self->{HERE}->is_map() && |
Line 1757 These are methods that help you retrieve
|
Line 1785 These are methods that help you retrieve
|
|
|
=over 4 |
=over 4 |
|
|
|
=item * B<compTitle>: Returns a "composite title", that is equal to $res->title() if the resource has a title, and is otherwise the last part of the URL (e.g., "problem.problem"). |
|
|
=item * B<ext>: Returns true if the resource is external. |
=item * B<ext>: Returns true if the resource is external. |
|
|
=item * B<goesto>: Returns the "goesto" value from the compiled nav map. (It is likely you want to use B<getNext> instead.) |
=item * B<goesto>: Returns the "goesto" value from the compiled nav map. (It is likely you want to use B<getNext> instead.) |
Line 1806 sub symb {
|
Line 1836 sub symb {
|
} |
} |
sub title { my $self=shift; return $self->navHash("title_", 1); } |
sub title { my $self=shift; return $self->navHash("title_", 1); } |
sub to { my $self=shift; return $self->navHash("to_", 1); } |
sub to { my $self=shift; return $self->navHash("to_", 1); } |
|
sub compTitle { |
|
my $self = shift; |
|
my $title = $self->title(); |
|
if (!$title) { |
|
$title = $self->src(); |
|
$title = substr($title, rindex($title, '/') + 1); |
|
} |
|
return $title; |
|
} |
=pod |
=pod |
|
|
B<Predicate Testing the Resource> |
B<Predicate Testing the Resource> |
Line 1966 sub answerdate {
|
Line 2004 sub answerdate {
|
} |
} |
return $self->parmval("answerdate", $part); |
return $self->parmval("answerdate", $part); |
} |
} |
|
sub awarded { my $self = shift; return $self->queryRestoreHash('awarded', shift); } |
sub duedate { |
sub duedate { |
(my $self, my $part) = @_; |
(my $self, my $part) = @_; |
return $self->parmval("duedate", $part); |
return $self->parmval("duedate", $part); |
Line 1990 sub tol {
|
Line 2029 sub tol {
|
(my $self, my $part) = @_; |
(my $self, my $part) = @_; |
return $self->parmval("tol", $part); |
return $self->parmval("tol", $part); |
} |
} |
sub tries { |
sub tries { |
my $self = shift; |
my $self = shift; |
my $part = shift; |
my $tries = $self->queryRestoreHash('tries', shift); |
$part = '0' if (!defined($part)); |
if (!defined($tries)) { return '0';} |
|
|
# Make sure return hash is loaded, should error check |
|
$self->getReturnHash(); |
|
|
|
my $tries = $self->{RETURN_HASH}->{'resource.'.$part.'.tries'}; |
|
if (!defined($tries)) {return '0';} |
|
return $tries; |
return $tries; |
} |
} |
sub type { |
sub type { |
(my $self, my $part) = @_; |
(my $self, my $part) = @_; |
return $self->parmval("type", $part); |
return $self->parmval("type", $part); |
} |
} |
sub weight { |
sub weight { |
(my $self, my $part) = @_; |
my $self = shift; my $part = shift; |
return $self->parmval("weight", $part); |
return $self->parmval("weight", $part); |
} |
} |
|
|
Line 2269 sub ATTEMPTED { return 16; }
|
Line 2302 sub ATTEMPTED { return 16; }
|
|
|
sub getCompletionStatus { |
sub getCompletionStatus { |
my $self = shift; |
my $self = shift; |
my $part = shift; |
|
$part = "0" if (!defined($part)); |
|
return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE}); |
return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE}); |
|
|
# Make sure return hash exists |
my $status = $self->queryRestoreHash('solved', shift); |
$self->getReturnHash(); |
|
|
|
my $status = $self->{RETURN_HASH}->{'resource.'.$part.'.solved'}; |
|
|
|
# Left as seperate if statements in case we ever do more with this |
# Left as seperate if statements in case we ever do more with this |
if ($status eq 'correct_by_student') {return $self->CORRECT;} |
if ($status eq 'correct_by_student') {return $self->CORRECT;} |
Line 2288 sub getCompletionStatus {
|
Line 2316 sub getCompletionStatus {
|
return $self->NOT_ATTEMPTED; |
return $self->NOT_ATTEMPTED; |
} |
} |
|
|
|
sub queryRestoreHash { |
|
my $self = shift; |
|
my $hashentry = shift; |
|
my $part = shift; |
|
$part = "0" if (!defined($part)); |
|
return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE}); |
|
|
|
$self->getReturnHash(); |
|
|
|
return $self->{RETURN_HASH}->{'resource.'.$part.'.'.$hashentry}; |
|
} |
|
|
=pod |
=pod |
|
|
B<Composite Status> |
B<Composite Status> |
Line 2414 sub getNext {
|
Line 2454 sub getNext {
|
# Don't remember it if the student doesn't have browse priviledges |
# Don't remember it if the student doesn't have browse priviledges |
# future note: this may properly belong in the client of the resource |
# future note: this may properly belong in the client of the resource |
my $browsePriv = &Apache::lonnet::allowed('bre', $self->src); |
my $browsePriv = &Apache::lonnet::allowed('bre', $self->src); |
if ($browsePriv ne '2' && $browsePriv ne 'F') { |
if (!($browsePriv ne '2' && $browsePriv ne 'F')) { |
push @branches, $next; |
push @branches, $next; |
} |
} |
} |
} |
Line 2433 sub getPrevious {
|
Line 2473 sub getPrevious {
|
# Don't remember it if the student doesn't have browse priviledges |
# Don't remember it if the student doesn't have browse priviledges |
# future note: this may properly belong in the client of the resource |
# future note: this may properly belong in the client of the resource |
my $browsePriv = &Apache::lonnet::allowed('bre', $self->src); |
my $browsePriv = &Apache::lonnet::allowed('bre', $self->src); |
if ($browsePriv ne '2' && $browsePriv ne 'F') { |
if (!($browsePriv ne '2' && $browsePriv ne 'F')) { |
push @branches, $prev; |
push @branches, $prev; |
} |
} |
} |
} |