1 package SL::Template::Plugin::MultiColumnIterator;
4 use base 'Template::Plugin';
5 use Template::Constants;
6 use Template::Exception;
7 use Template::Iterator;
14 $main::lxdebug->enter_sub();
17 my $data = shift || [ ];
23 push @ISA, "Template::Iterator";
25 if (ref $data eq 'HASH') {
26 # map a hash into a list of { key => ???, value => ??? } hashes,
27 # one for each key, sorted by keys
28 $data = [ map { { key => $_, value => $data->{ $_ } } }
31 elsif (UNIVERSAL::can($data, 'as_list')) {
32 $data = $data->as_list();
34 elsif (ref $data ne 'ARRAY') {
35 # coerce any non-list data into an array reference
39 $main::lxdebug->leave_sub();
50 $main::lxdebug->enter_sub();
52 my $data = $self->{ _DATA };
53 my $dim = $self->{ _DIM };
55 $self->{ _DATASET } = $self->{ _DATA };
56 my $size = int ((scalar @$data - 1) / $dim) + 1;
59 return (undef, Template::Constants::STATUS_DONE) unless $size;
61 # initialise various counters, flags, etc.
62 @$self{ qw( SIZE MAX INDEX COUNT FIRST LAST ) } = ( $size, $size - 1, $index, 1, 1, $size > 1 ? 0 : 1, undef );
63 @$self{ qw( PREV ) } = ( undef );
64 $$self{ qw( NEXT ) } = [ @{ $self->{ _DATASET } }[ map { $index + 1 + $_ * $size } 0 .. ($dim - 1) ] ];
66 $main::lxdebug->leave_sub();
67 return [ @{ $self->{ _DATASET } }[ map { $index + $_ * $size } 0 .. ($dim - 1) ] ];
71 $main::lxdebug->enter_sub();
73 my ($max, $index) = @$self{ qw( MAX INDEX ) };
74 my $data = $self->{ _DATASET };
75 my $dim = $self->{ _DIM };
76 my $size = $self->{ SIZE };
78 # warn about incorrect usage
79 unless (defined $index) {
80 my ($pack, $file, $line) = caller();
81 warn("iterator get_next() called before get_first() at $file line $line\n");
82 return (undef, Template::Constants::STATUS_DONE); ## RETURN ##
85 # if there's still some data to go...
87 # update counters and flags
89 @$self{ qw( INDEX COUNT FIRST LAST ) } = ( $index, $index + 1, 0, $index == $max ? 1 : 0 );
90 $$self{ qw( PREV ) } = [ @{ $self->{ _DATASET } }[ map { $index - 1 + $_ * $size } 0 .. ($dim - 1) ] ];
91 $$self{ qw( NEXT ) } = [ @{ $self->{ _DATASET } }[ map { $index + 1 + $_ * $size } 0 .. ($dim - 1) ] ];
92 $main::lxdebug->leave_sub();
93 return [ @{ $self->{ _DATASET } }[ map { $index + $_ * $size } 0 .. ($dim - 1) ] ];
96 $main::lxdebug->leave_sub();
97 return (undef, Template::Constants::STATUS_DONE); ## RETURN ##
103 my ($max, $index, $dim, $size) = @$self{ qw( MAX INDEX _DIM SIZE) };
106 # if there's still some data to go...
109 @data = map do{ !($i = $_) || +[ @{ $self->{ _DATASET } }[ map { $i + $_ * $size } 0 .. ($dim - 1) ] ] }, $index .. $max;
110 # update counters and flags
111 @$self{ qw( INDEX COUNT FIRST LAST ) } = ( $max, $max + 1, 0, 1 );
112 $main::lxdebug->leave_sub();
113 return \@data; ## RETURN ##
116 $main::lxdebug->leave_sub();
117 return (undef, Template::Constants::STATUS_DONE); ## RETURN ##
123 my $item = $AUTOLOAD;
125 return if $item eq 'DESTROY';
127 # alias NUMBER to COUNT for backwards compatability
128 $item = 'COUNT' if $item =~ /NUMBER/i;
130 return $self->{ uc $item };
134 $main::lxdebug->enter_sub();
136 $main::lxdebug->leave_sub();
139 " Data: ", Dumper($self->{ _DATA }), "\n",
140 " Index: ", $self->{ INDEX }, "\n",
141 "Number: ", $self->{ NUMBER }, "\n",
142 " Max: ", $self->{ MAX }, "\n",
143 " Size: ", $self->{ SIZE }, "\n",
144 " First: ", $self->{ FIRST }, "\n",
145 " Last: ", $self->{ LAST }, "\n",
152 $main::lxdebug->enter_sub();
154 $main::lxdebug->leave_sub();
155 return $self->{ INDEX };
159 $main::lxdebug->enter_sub();
161 $main::lxdebug->leave_sub();
162 return $self->{ NUMBER };
166 $main::lxdebug->enter_sub();
168 $main::lxdebug->leave_sub();
169 return $self->{ COUNT };
172 $main::lxdebug->enter_sub();
174 $main::lxdebug->leave_sub();
175 return $self->{ MAX };
179 $main::lxdebug->enter_sub();
181 $main::lxdebug->leave_sub();
182 return $self->{ SIZE };
186 $main::lxdebug->enter_sub();
188 $main::lxdebug->leave_sub();
189 return $self->{ FIRST };
193 $main::lxdebug->enter_sub();
195 $main::lxdebug->leave_sub();
196 return $self->{ LAST};