Mercurial > pub > Impl
view Lib/IMPL/DOM/Navigator.pm @ 171:59e5fcb59d86
Исправления, изменена концепция веб-форм
author | sourcer |
---|---|
date | Mon, 06 Jun 2011 03:30:36 +0400 |
parents | 76515373dac0 |
children | d1676be8afcc |
line wrap: on
line source
package IMPL::DOM::Navigator; use strict; use warnings; use parent qw(IMPL::Object); use IMPL::Class::Property; use IMPL::Class::Property::Direct; BEGIN { private _direct property _path => prop_all; private _direct property _state => prop_all; private _direct property _savedstates => prop_all; public property Current => {get => \&_getCurrent}; } sub CTOR { my ($this,$CurrentNode) = @_; die IMPL::InvalidArgumentException("A starting node is a required paramater") unless $CurrentNode; $this->{$_state} = { alternatives => [ $CurrentNode ], current => 0 }; } sub _initNavigator { my ($this,$CurrentNode) = @_; die IMPL::InvalidArgumentException("A starting node is a required paramater") unless $CurrentNode; $this->{$_state} = { alternatives => [ $CurrentNode ], current => 0 }; delete $this->{$_path}; delete $this->{$_savedstates}; } sub _getCurrent { $_[0]->{$_state}{alternatives}[$_[0]->{$_state}{current}] } sub Navigate { my ($this,@path) = @_; return unless @path; my $node; foreach my $query (@path) { if (my $current = $this->Current) { my @alternatives = $current->selectNodes($query); unless (@alternatives) { $current = $this->advanceNavigator or return undef; @alternatives = $current->selectNodes($query); } push @{$this->{$_path}},$this->{$_state}; $this->{$_state} = { alternatives => \@alternatives, current => 0, query => $query }; $node = $alternatives[0]; } else { return undef; } } $node; } sub selectNodes { my ($this,@path) = @_; return $this->Current->selectNodes(@path); } sub internalNavigateNodeSet { my ($this,@nodeSet) = @_; push @{$this->{$_path}}, $this->{$_state}; $this->{$_state} = { alternatives => \@nodeSet, current => 0 }; $nodeSet[0]; } sub fetch { my ($this) = @_; my $result = $this->Current; $this->advanceNavigator; return $result; } sub advanceNavigator { my ($this) = @_; $this->{$_state}{current}++; if (@{$this->{$_state}{alternatives}} <= $this->{$_state}{current}) { if ( exists $this->{$_state}{query} ) { my $query = $this->{$_state}{query}; $this->Back or return undef; # that meams the end of the history undef while ( $this->advanceNavigator and not $this->Navigate($query)); return $this->Current; } return undef; } return $this->Current; } sub doeach { my ($this,$code) = @_; local $_; do { for (my $i = $this->{$_state}{current}; $i < @{$this->{$_state}{alternatives}}; $i++) { $_ = $this->{$_state}{alternatives}[$i]; $code->(); } $this->{$_state}{current} = @{$this->{$_state}{alternatives}}; } while ($this->advanceNavigator); } sub Back { my ($this,$steps) = @_; if ($this->{$_path} and @{$this->{$_path}}) { if ( (not $steps) || $steps == 1) { $this->{$_state} = pop @{$this->{$_path}}; } else { $steps ||= 1; $steps = @{$this->{$_path}} - 1 if $steps >= @{$this->{$_path}}; $this->{$_state} = (splice @{$this->{$_path}},-$steps)[0]; } $this->Current if defined wantarray; } else { return undef; } } sub PathToString { my ($this,$delim) = @_; $delim ||= '/'; join($delim,map $_->{alternatives}[$_->{current}]->nodeName, $this->{$_path} ? (@{$this->{$_path}}, $this->{$_state}) : $this->{$_state}); } sub pathLength { my ($this) = @_; $this->{$_path} ? scalar @{$this->{$_path}} : 0; } sub GetNodeFromHistory { my ($this,$index) = @_; if (my $state = $this->{$_path} ? $this->{$_path}->[$index] : undef ) { return $state->{alternatives}[$state->{current}] } else { return undef; } } sub clone { my ($this) = @_; my $newNavi = __PACKAGE__->surrogate; $newNavi->{$_path} = [ map { { %{ $_ } } } @{$this->{$_path}} ] if $this->{$_path}; $newNavi->{$_state} = { %{$this->{$_state}} }; return $newNavi; } sub saveState { my ($this) = @_; my %state; $state{path} = [ map { { %{ $_ } } } @{$this->{$_path}} ] if $this->{$_path}; $state{state} = { %{$this->{$_state}} }; push @{$this->{$_savedstates}}, \%state; } sub restoreState { my ($this) = @_; if ( my $state = pop @{$this->{$_savedstates}||[]} ) { $this->{$_path} = $state->{path}; $this->{$_state} = $state->{state}; } } sub applyState { my ($this) = @_; pop @{$this->{$_savedstates}||[]}; } sub dosafe { my ($this,$transaction) = @_; $this->saveState(); my $result; eval { $result = $transaction->(); }; if ($@) { $this->restoreState(); return undef; } else { $this->applyState(); return $result; } } 1; __END__ =pod =head1 DESCRIPTION DOM . (). , , . , . , , , . =head1 METHODS =over =item C<<$obj->new($nodeStart)>> . =item C<<$obj->Navigate([$query,...])>> C<$query>. . , . , C<undef>. =item C<<$obj->Back()>> , . , C<undef>. =item C<<$obj->advanceNavigator()>> , . =back =cut