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;