version 1.96, 2002/11/01 19:50:00
|
version 1.98, 2002/11/08 18:35:37
|
Line 958 sub new_handle {
|
Line 958 sub new_handle {
|
# Preprocess the map: Look for current URL, force inlined maps to display |
# Preprocess the map: Look for current URL, force inlined maps to display |
|
|
# This currently does very little... |
# This currently does very little... |
my $mapEventualIterator = Apache::lonnavmaps::iterator->new($navmap, undef, undef, {}, |
#my $mapEventualIterator = Apache::lonnavmaps::iterator->new($navmap, undef, undef, {}, |
undef, $condition); |
#undef, $condition); |
|
|
my $mapIterator = $navmap->getIterator(undef, undef, {}, 1); |
my $mapIterator = $navmap->getIterator(undef, undef, {}, 1); |
my $found = 0; |
my $found = 0; |
Line 1290 sub new_handle {
|
Line 1290 sub new_handle {
|
} |
} |
|
|
$r->print(" $curMarkerBegin<a href=\"$link\">$title$partLabel</a> $curMarkerEnd $nonLinkedText"); |
$r->print(" $curMarkerBegin<a href=\"$link\">$title$partLabel</a> $curMarkerEnd $nonLinkedText"); |
|
#$r->print(" TDV:" . $curRes->{DATA}->{TOP_DOWN_VAL}); # temp |
|
#$r->print(" BUV:" . $curRes->{DATA}->{BOT_UP_VAL}); # temp |
|
#$r->print(" DD:" . $curRes->{DATA}->{DISPLAY_DEPTH}); # temp |
|
|
if ($curRes->{RESOURCE_ERROR}) { |
if ($curRes->{RESOURCE_ERROR}) { |
$r->print(&Apache::loncommon::help_open_topic ("Navmap_Host_Down", |
$r->print(&Apache::loncommon::help_open_topic ("Navmap_Host_Down", |
Line 1772 sub courseMapDefined {
|
Line 1775 sub courseMapDefined {
|
|
|
sub getIterator { |
sub getIterator { |
my $self = shift; |
my $self = shift; |
my $iterator = Apache::lonnavmaps::DFSiterator->new($self, shift, shift, |
my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift, |
shift, undef, shift, |
shift, undef, shift, |
$ENV{'form.direction'}); |
$ENV{'form.direction'}); |
return $iterator; |
return $iterator; |
Line 2066 sub new {
|
Line 2069 sub new {
|
# Now, we need to pre-process the map, by walking forward and backward |
# Now, we need to pre-process the map, by walking forward and backward |
# over the parts of the map we're going to look at. |
# over the parts of the map we're going to look at. |
|
|
my $forwardIterator = Apache::lonnavmaps::DFSiterator->new($self->{NAV_MAP}, |
# The processing steps are exactly the same, except for a few small |
$self->{FIRST_RESOURCE}, |
# changes, so I bundle those up in the following list of two elements: |
$self->{FINISH_RESOURCE}, |
# (direction_to_iterate, VAL_name, next_resource_method_to_call, |
$self->{FILTER}, |
# first_resource). |
undef, $self->{CONDITION}, |
# This prevents writing nearly-identical code twice. |
FORWARD()); |
my @iterations = ( [FORWARD(), 'TOP_DOWN_VAL', 'getNext', |
|
'FIRST_RESOURCE'], |
|
[BACKWARD(), 'BOT_UP_VAL', 'getPrevious', |
|
'FINISH_RESOURCE'] ); |
|
|
|
my $maxDepth = 0; # tracks max depth |
|
|
|
foreach my $pass (@iterations) { |
|
my $direction = $pass->[0]; |
|
my $valName = $pass->[1]; |
|
my $nextResourceMethod = $pass->[2]; |
|
my $firstResourceName = $pass->[3]; |
|
|
|
my $iterator = Apache::lonnavmaps::DFSiterator->new($self->{NAV_MAP}, |
|
$self->{FIRST_RESOURCE}, |
|
$self->{FINISH_RESOURCE}, |
|
{}, undef, 0, $direction); |
|
|
# prime the recursion |
# prime the recursion |
$self->{FIRST_RESOURCE}->{DATA}->{TOP_DOWN_VAL} = 0; |
$self->{$firstResourceName}->{DATA}->{$valName} = 0; |
my $depth = 1; |
my $depth = 0; |
$forwardIterator->next(); |
$iterator->next(); |
my $curRes = $forwardIterator->next(); |
my $curRes = $iterator->next(); |
while ($depth > 0) { |
while ($depth > -1) { |
if ($curRes == $forwardIterator->BEGIN_MAP()) { $depth++; } |
if ($curRes == $iterator->BEGIN_MAP()) { $depth++; } |
if ($curRes == $forwardIterator->END_MAP()) { $depth--; } |
if ($curRes == $iterator->END_MAP()) { $depth--; } |
|
|
if (ref($curRes)) { |
if (ref($curRes)) { |
my $topDownVal = $curRes->{DATA}->{TOP_DOWN_VAL}; |
my $resultingVal = $curRes->{DATA}->{$valName}; |
my $nextResources = $curRes->getNext(); |
my $nextResources = $curRes->$nextResourceMethod(); |
my $resourceCount = scalar(@{$nextResources}); |
my $resourceCount = scalar(@{$nextResources}); |
|
|
if ($resourceCount == 1) { |
if ($resourceCount == 1) { |
my $current = $nextResources->[0]->{DATA}->{TOP_DOWN_VAL} || 999999999; |
my $current = $nextResources->[0]->{DATA}->{$valName} || 999999999; |
$nextResources->[0]->{DATA}->{TOP_DOWN_VAL} = min($topDownVal, $current); |
$nextResources->[0]->{DATA}->{$valName} = min($resultingVal, $current); |
|
} |
|
|
|
if ($resourceCount > 1) { |
|
foreach my $res (@{$nextResources}) { |
|
my $current = $res->{DATA}->{$valName} || 999999999; |
|
$res->{DATA}->{$valName} = min($current, $resultingVal + 1); |
|
} |
|
} |
|
} |
|
if (ref($curRes) && $curRes->is_map() && $direction == FORWARD()) { |
|
my $firstResource = $curRes->map_start(); |
|
my $finishResource = $curRes->map_finish(); |
|
my $newIterator = Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, |
|
$firstResource, |
|
$finishResource, |
|
$self->{FILTER}, |
|
$self->{ALREADY_SEEN}, |
|
$self->{CONDITION}); |
} |
} |
|
|
if ($resourceCount > 1) { |
# Assign the final val |
foreach my $res (@{$nextResources}) { |
if (ref($curRes) && $direction == BACKWARD()) { |
my $current = $res->{DATA}->{TOP_DOWN_VAL} || 999999999; |
my $finalDepth = min($curRes->{DATA}->{TOP_DOWN_VAL}, |
$res->{DATA}->{TOP_DOWN_VAL} = min($current, $topDownVal + 1); |
$curRes->{DATA}->{BOT_UP_VAL}); |
|
|
|
$curRes->{DATA}->{DISPLAY_DEPTH} = $finalDepth; |
|
if ($finalDepth > $maxDepth) {$maxDepth = $finalDepth;} |
} |
} |
} |
$curRes = $iterator->next(); |
|
} |
|
} |
|
|
|
# Set up some bookkeeping information. |
|
$self->{CURRENT_DEPTH} = 0; |
|
$self->{MAX_DEPTH} = $maxDepth; |
|
$self->{STACK} = []; |
|
$self->{RECURSIVE_ITERATOR_FLAG} = 0; |
|
|
|
for (my $i = 0; $i <= $self->{MAX_DEPTH}; $i++) { |
|
push @{$self->{STACK}}, []; |
|
} |
|
|
|
# Prime the recursion w/ the first resource |
|
push @{$self->{STACK}->[0]}, $self->{FIRST_RESOURCE}; |
|
$self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1; |
|
|
|
bless ($self); |
|
|
|
return $self; |
|
} |
|
|
|
sub next { |
|
my $self = shift; |
|
|
|
if ($self->{RECURSIVE_ITERATOR_FLAG}) { |
|
# grab the next from the recursive iterator |
|
my $next = $self->{RECURSIVE_ITERATOR}->next(); |
|
|
|
# is it a begin or end map? If so, update the depth |
|
if ($next == BEGIN_MAP() ) { $self->{RECURSIVE_DEPTH}++; } |
|
if ($next == END_MAP() ) { $self->{RECURSIVE_DEPTH}--; } |
|
|
|
# Are we back at depth 0? If so, stop recursing |
|
if ($self->{RECURSIVE_DEPTH} == 0) { |
|
$self->{RECURSIVE_ITERATOR_FLAG} = 0; |
|
} |
|
|
|
return $next; |
|
} |
|
|
|
if (defined($self->{FORCE_NEXT})) { |
|
my $tmp = $self->{FORCE_NEXT}; |
|
$self->{FORCE_NEXT} = undef; |
|
return $tmp; |
|
} |
|
|
|
# Have we not yet begun? If not, return BEGIN_MAP and |
|
# remember we've started. |
|
if ( !$self->{STARTED} ) { |
|
$self->{STARTED} = 1; |
|
return $self->BEGIN_MAP(); |
|
} |
|
|
|
# Here's the guts of the iterator. |
|
|
|
# Find the next resource, if any. |
|
my $found = 0; |
|
my $i = $self->{MAX_DEPTH}; |
|
my $newDepth; |
|
my $here; |
|
while ( $i >= 0 && !$found ) { |
|
if ( scalar(@{$self->{STACK}->[$i]}) > 0 ) { |
|
$here = $self->{HERE} = shift @{$self->{STACK}->[$i]}; |
|
$found = 1; |
|
$newDepth = $i; |
|
} |
|
$i--; |
|
} |
|
|
|
# If we still didn't find anything, we're done. |
|
if ( !$found ) { |
|
# We need to get back down to the correct branch depth |
|
if ( $self->{CURRENT_DEPTH} > 0 ) { |
|
$self->{CURRENT_DEPTH}--; |
|
return END_BRANCH(); |
|
} else { |
|
return END_MAP(); |
|
} |
|
} |
|
|
|
# Get to the right level |
|
if ( $self->{CURRENT_DEPTH} > $newDepth ) { |
|
push @{$self->{STACK}->[$newDepth]}, $here; |
|
$self->{CURRENT_DEPTH}--; |
|
return END_BRANCH(); |
|
} |
|
if ( $self->{CURRENT_DEPTH} < $newDepth) { |
|
push @{$self->{STACK}->[$newDepth]}, $here; |
|
$self->{CURRENT_DEPTH}++; |
|
return BEGIN_BRANCH(); |
|
} |
|
|
|
# If we made it here, we have the next resource, and we're at the |
|
# right branch level. So let's examine the resource for where |
|
# 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 |
|
my $nextUnfiltered = $here->getNext(); |
|
|
|
for (@$nextUnfiltered) { |
|
if (!defined($self->{ALREADY_SEEN}->{$_->{ID}})) { |
|
push @{$self->{STACK}->[$_->{DATA}->{DISPLAY_DEPTH}]}, $_; |
|
$self->{ALREADY_SEEN}->{$_->{ID}} = 1; |
} |
} |
$curRes = $forwardIterator->next(); |
|
} |
} |
|
|
|
# That ends the main iterator logic. Now, do we want to recurse |
|
# down this map (if this resource is a map)? |
|
if ($self->{HERE}->is_map() && |
|
(defined($self->{FILTER}->{$self->{HERE}->map_pc()}) xor $self->{CONDITION})) { |
|
$self->{RECURSIVE_ITERATOR_FLAG} = 1; |
|
my $firstResource = $self->{HERE}->map_start(); |
|
my $finishResource = $self->{HERE}->map_finish(); |
|
|
|
$self->{RECURSIVE_ITERATOR} = |
|
Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource, |
|
$finishResource, $self->{FILTER}, |
|
$self->{ALREADY_SEEN}, $self->{CONDITION}); |
|
} |
|
|
|
return $self->{HERE}; |
|
|
|
} |
|
|
|
=pod |
|
|
# Now we're ready to start iterating. |
The other method available on the iterator is B<getStack>, which returns an array populated with the current 'stack' of maps, as references to the resource objects. Example: This is useful when making the navigation map, as we need to check whether we are under a page map to see if we need to link directly to the resource, or to the page. The first elements in the array will correspond to the top of the stack (most inclusive map). |
|
|
|
=cut |
|
|
|
sub getStack { |
|
my $self=shift; |
|
|
|
my @stack; |
|
|
|
$self->populateStack(\@stack); |
|
|
|
return \@stack; |
|
} |
|
|
|
# Private method: Calls the iterators recursively to populate the stack. |
|
sub populateStack { |
|
my $self=shift; |
|
my $stack = shift; |
|
|
|
push @$stack, $self->{HERE} if ($self->{HERE}); |
|
|
|
if ($self->{RECURSIVE_ITERATOR_FLAG}) { |
|
$self->{RECURSIVE_ITERATOR}->populateStack($stack); |
|
} |
} |
} |
|
|
1; |
1; |
Line 2115 package Apache::lonnavmaps::DFSiterator;
|
Line 2302 package Apache::lonnavmaps::DFSiterator;
|
# used by the main iterator for pre-processing. It also is able to isolate |
# used by the main iterator for pre-processing. It also is able to isolate |
# much of the complexity of the main iterator, so the main iterator is much |
# much of the complexity of the main iterator, so the main iterator is much |
# simpler. |
# simpler. |
|
# There is no real benefit in merging the main iterator and this one into one class... |
|
# all the logic in DFSiterator would need to be replicated, you gain no performance, |
|
# at best, you just make one massively complicated iterator in place of two |
|
# somewhat complicated ones. ;-) - Jeremy |
|
|
# Here are the tokens for the iterator, replicated from iterator for convenience: |
# Here are the tokens for the iterator, replicated from iterator for convenience: |
|
|
Line 2200 sub next {
|
Line 2391 sub next {
|
|
|
# Are we using a recursive iterator? If so, pull from that and |
# Are we using a recursive iterator? If so, pull from that and |
# watch the depth; we want to resume our level at the correct time. |
# watch the depth; we want to resume our level at the correct time. |
if ($self->{RECURSIVE_ITERATOR_FLAG}) |
if ($self->{RECURSIVE_ITERATOR_FLAG}) { |
{ |
|
# grab the next from the recursive iterator |
# grab the next from the recursive iterator |
my $next = $self->{RECURSIVE_ITERATOR}->next(); |
my $next = $self->{RECURSIVE_ITERATOR}->next(); |
|
|
Line 2265 sub next {
|
Line 2455 sub next {
|
|
|
# Are we at the right depth? If not, close a branch and return |
# Are we at the right depth? If not, close a branch and return |
# the current resource onto the branch stack |
# the current resource onto the branch stack |
|
# Note: There seems to be some bugs here, so don't rely |
|
# on this, use the real iterator instead. |
if (defined($self->{HERE}->{DATA}->{ITERATOR_DEPTH}) |
if (defined($self->{HERE}->{DATA}->{ITERATOR_DEPTH}) |
&& $self->{HERE}->{DATA}->{ITERATOR_DEPTH} < |
&& $self->{HERE}->{DATA}->{ITERATOR_DEPTH} < |
$self->{BRANCH_DEPTH} ) { |
$self->{BRANCH_DEPTH} ) { |
Line 2341 sub next {
|
Line 2533 sub next {
|
return $self->{HERE}; |
return $self->{HERE}; |
} |
} |
|
|
=pod |
|
|
|
The other method available on the iterator is B<getStack>, which returns an array populated with the current 'stack' of maps, as references to the resource objects. Example: This is useful when making the navigation map, as we need to check whether we are under a page map to see if we need to link directly to the resource, or to the page. The first elements in the array will correspond to the top of the stack (most inclusive map). |
|
|
|
=cut |
|
|
|
sub getStack { |
sub getStack { |
my $self=shift; |
my $self=shift; |
|
|