\n");
+ # anchor for current resource... - 5 is deliberate: If it's that
+ # high on the screen, don't bother focusing on it. Also this will
+ # print multiple anchors if this is an expanded multi-part problem...
+ # who cares?
+ if ($counter == $currentUrlIndex - 5) {
+ $r->print('');
+ }
+
# print indentation
for (my $i = 0; $i < $indentLevel - $deltalevel + $deltadepth; $i++) {
$r->print($indentString);
@@ -1615,6 +1646,14 @@ sub new {
$self->{PARM_HASH} = \%parmhash;
$self->{HASH_TIED} = 1;
+ bless($self);
+
+ return $self;
+}
+
+sub init {
+ my $self = shift;
+
# If the course opt hash and the user opt hash should be generated,
# generate them
if ($self->{GENERATE_COURSE_USER_OPT}) {
@@ -1719,10 +1758,6 @@ sub new {
}
$self->{PARM_CACHE} = {};
-
- bless($self);
-
- return $self;
}
# Checks to see if coursemap is defined, matching test in old lonnavmaps
@@ -1737,7 +1772,7 @@ sub courseMapDefined {
sub getIterator {
my $self = shift;
- my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift,
+ my $iterator = Apache::lonnavmaps::DFSiterator->new($self, shift, shift,
shift, undef, shift,
$ENV{'form.direction'});
return $iterator;
@@ -1996,6 +2031,100 @@ sub END_BRANCH { return 4; } # end of
sub FORWARD { return 1; } # go forward
sub BACKWARD { return 2; }
+sub min {
+ (my $a, my $b) = @_;
+ if ($a < $b) { return $a; } else { return $b; }
+}
+
+sub new {
+ # magic invocation to create a class instance
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = {};
+
+ $self->{NAV_MAP} = shift;
+ return undef unless ($self->{NAV_MAP});
+
+ # Handle the parameters
+ $self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource();
+ $self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource();
+
+ # If the given resources are just the ID of the resource, get the
+ # objects
+ if (!ref($self->{FIRST_RESOURCE})) { $self->{FIRST_RESOURCE} =
+ $self->{NAV_MAP}->getById($self->{FIRST_RESOURCE}); }
+ if (!ref($self->{FINISH_RESOURCE})) { $self->{FINISH_RESOURCE} =
+ $self->{NAV_MAP}->getById($self->{FINISH_RESOURCE}); }
+
+ $self->{FILTER} = shift;
+
+ # A hash, used as a set, of resource already seen
+ $self->{ALREADY_SEEN} = shift;
+ if (!defined($self->{ALREADY_SEEN})) { $self->{ALREADY_SEEN} = {} };
+ $self->{CONDITION} = shift;
+
+ # 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.
+
+ my $forwardIterator = Apache::lonnavmaps::DFSiterator->new($self->{NAV_MAP},
+ $self->{FIRST_RESOURCE},
+ $self->{FINISH_RESOURCE},
+ $self->{FILTER},
+ undef, $self->{CONDITION},
+ FORWARD());
+
+ # prime the recursion
+ $self->{FIRST_RESOURCE}->{DATA}->{TOP_DOWN_VAL} = 0;
+ my $depth = 1;
+ $forwardIterator->next();
+ my $curRes = $forwardIterator->next();
+ while ($depth > 0) {
+ if ($curRes == $forwardIterator->BEGIN_MAP()) { $depth++; }
+ if ($curRes == $forwardIterator->END_MAP()) { $depth--; }
+
+ if (ref($curRes)) {
+ my $topDownVal = $curRes->{DATA}->{TOP_DOWN_VAL};
+ my $nextResources = $curRes->getNext();
+ my $resourceCount = scalar(@{$nextResources});
+
+ if ($resourceCount == 1) {
+ my $current = $nextResources->[0]->{DATA}->{TOP_DOWN_VAL} || 999999999;
+ $nextResources->[0]->{DATA}->{TOP_DOWN_VAL} = min($topDownVal, $current);
+ }
+
+ if ($resourceCount > 1) {
+ foreach my $res (@{$nextResources}) {
+ my $current = $res->{DATA}->{TOP_DOWN_VAL} || 999999999;
+ $res->{DATA}->{TOP_DOWN_VAL} = min($current, $topDownVal + 1);
+ }
+ }
+ }
+ $curRes = $forwardIterator->next();
+ }
+
+ # Now we're ready to start iterating.
+}
+
+1;
+
+package Apache::lonnavmaps::DFSiterator;
+
+# UNDOCUMENTED: This is a private library, it should not generally be used
+# by the outside world. What it does is walk through the nav map in a
+# depth-first fashion. This is not appropriate for most uses, but it is
+# 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
+# simpler.
+
+# Here are the tokens for the iterator, replicated from iterator for convenience:
+
+sub BEGIN_MAP { return 1; } # begining of a new map
+sub END_MAP { return 2; } # end of the map
+sub BEGIN_BRANCH { return 3; } # beginning of a branch
+sub END_BRANCH { return 4; } # end of a branch
+sub FORWARD { return 1; } # go forward
+sub BACKWARD { return 2; }
+
# Params: nav map, start resource, end resource, filter, condition,
# already seen hash ref
@@ -2053,7 +2182,7 @@ sub new {
if ($self->{DIRECTION} == FORWARD) {
push @{$self->{BRANCH_STACK}}, $self->{FIRST_RESOURCE};
} else {
- push @{$self->{BRANCH_STACK}), $self->{FINISH_RESOURCE};
+ push @{$self->{BRANCH_STACK}}, $self->{FINISH_RESOURCE};
}
$self->{BRANCH_STACK_SIZE} = 1;
@@ -2151,10 +2280,11 @@ sub next {
$self->{ALREADY_SEEN}->{$self->{HERE}->{ID}} = 1;
# Get the next possible resources
+ my $nextUnfiltered;
if ($self->{DIRECTION} == FORWARD()) {
- my $nextUnfiltered = $self->{HERE}->getNext();
+ $nextUnfiltered = $self->{HERE}->getNext();
} else {
- my $nextUnfiltered = $self->{HERE}->getPrevious();
+ $nextUnfiltered = $self->{HERE}->getPrevious();
}
my $next = [];
@@ -2203,9 +2333,9 @@ sub next {
my $finishResource = $self->{HERE}->map_finish();
$self->{RECURSIVE_ITERATOR} =
- Apache::lonnavmaps::iterator->new ($self->{NAV_MAP}, $firstResource,
+ Apache::lonnavmaps::DFSiterator->new ($self->{NAV_MAP}, $firstResource,
$finishResource, $self->{FILTER}, $self->{ALREADY_SEEN},
- $self->{CONDITION});
+ $self->{CONDITION}, $self->{DIRECTION});
}
return $self->{HERE};
|