package HTML::Widgets::NavMenu::Tree::Iterator;
use strict;
use warnings;
use base qw(HTML::Widgets::NavMenu::Object);
use base 'Class::Accessor';
use HTML::Widgets::NavMenu::Tree::Iterator::Stack;
use HTML::Widgets::NavMenu::Tree::Iterator::Item;
__PACKAGE__->mk_accessors(qw(
coords
stack
));
=head1 NAME
HTML::Widgets::NavMenu::Tree::Iterator - an iterator for HTML.
=head1 SYNOPSIS
For internal use only.
=head1 METHODS
=cut
sub _init
{
my $self = shift;
$self->stack(HTML::Widgets::NavMenu::Tree::Iterator::Stack->new());
return 0;
}
=head2 $self->top()
Retrieves the stack top item.
=cut
sub top
{
my $self = shift;
return $self->stack()->top();
}
sub _construct_new_item
{
my $self = shift;
return HTML::Widgets::NavMenu::Tree::Iterator::Item->new(
@_
);
}
=head2 $self->get_new_item('node' => $node, 'parent_item' => $parent)
Gets the new item.
=cut
sub get_new_item
{
my $self = shift;
my %args = (@_);
my $node = $args{'node'};
my $parent_item = $args{'parent_item'};
return
$self->_construct_new_item(
'node' => $node,
'subs' => $self->get_node_subs('node' => $node),
'accum_state' =>
$self->get_new_accum_state(
'item' => $parent_item,
'node' => $node,
),
);
}
sub _push_into_stack
{
my $self = shift;
my %args = (@_);
my $node = $args{'node'};
$self->stack()->push(
$self->get_new_item(
'node' => $node,
'parent_item' => $self->top(),
),
);
}
=head2 $self->traverse()
Traverses the tree.
=cut
sub traverse
{
my $self = shift;
$self->_push_into_stack('node' => $self->get_initial_node());
$self->coords([]);
my $top_item;
MAIN_LOOP: while ($top_item = $self->top())
{
my $visited = $top_item->_is_visited();
if (!$visited)
{
$self->node_start();
}
my $sub_item =
($self->node_should_recurse() ?
$top_item->_visit() :
undef);
if (defined($sub_item))
{
push @{$self->coords()}, $top_item->_visited_index();
$self->_push_into_stack(
'node' =>
$self->get_node_from_sub(
'item' => $top_item,
'sub' => $sub_item,
),
);
next MAIN_LOOP;
}
else
{
$self->node_end();
$self->stack->pop();
pop(@{$self->coords()})
}
}
return 0;
}
=head2 $self->get_node_from_sub()
This function can be overriden to generate a node from the sub-nodes
returned by get_node_subs() in a different way than the default.
=cut
sub get_node_from_sub
{
my $self = shift;
my %args = (@_);
return $args{'sub'};
}
=head2 $self->find_node_by_coords($coords, $callback)
Finds a node by its coordinations.
=cut
sub find_node_by_coords
{
my $self = shift;
my $coords = shift;
my $callback = shift || (sub { });
my $idx = 0;
my $item =
$self->get_new_item(
'node' => $self->get_initial_node(),
);
my $internal_callback =
sub {
$callback->(
'idx' => $idx,
'item' => $item,
'self' => $self,
);
};
$internal_callback->();
foreach my $c (@$coords)
{
$item =
$self->get_new_item(
'node' =>
$self->get_node_from_sub(
'item' => $item,
'sub' => $item->_get_sub($c),
),
'parent_item' => $item,
);
$idx++;
$internal_callback->();
}
return +{ 'item' => $item, };
}
=head2 $self->get_coords()
Returns the current coordinates of the object.
=cut
sub get_coords
{
my $self = shift;
return $self->coords();
}
=head1 COPYRIGHT & LICENSE
Copyright 2006 Shlomi Fish, all rights reserved.
This program is released under the following license: MIT X11.
=cut
1;