loop — iterate through a list
Attribute | Pos. | Req. | Default | Description |
---|---|---|---|---|
list | Yes | list of items to iterate through | ||
prefix |
loop
|
|||
list_prefix |
list
|
changes subtag for list | ||
label | ||||
object | ||||
more | No |
enable paginating with [more_list]
|
||
ml | 50 | number of items to display | ||
more_template |
template for [more_list]
|
|||
form | form parameters embedded into more links | |||
more_routine |
custom routine for [more_list]
|
|||
mv_first_match | ||||
search | ||||
file | file to read the list from | |||
lr | ||||
quoted | ||||
extended | ||||
table | ||||
extended_only | ||||
fn | ||||
mv_field_names | ||||
delimiter | ||||
record_delim | ||||
acclist | ||||
ranges | list consists of ranges like 1..4 | |||
head_skip | ||||
interpolate | 0 | interpolate input? | ||
reparse | 1 | interpolate output? | ||
hide | 0 | Hide the tag return value? |
[loop]
belongs to the so-called looping tags, see
glossary
for a complete discussion of this class of tags.
Example: Loop through expiration years
<select name="mv_credit_card_exp_year"> [loop ranges=1 list="2008..2022"] <option>[loop-code] [/loop] </select>
Interchange 5.9.0:
Source: code/SystemTag/loop.coretag
Lines: 17
# Copyright 2002-2007 Interchange Development Group and others # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. See the LICENSE file for details. # # $Id: loop.coretag,v 1.4 2007-03-30 23:40:49 pajamian Exp $ UserTag loop Order list UserTag loop addAttr UserTag loop attrAlias args list UserTag loop attrAlias arg list UserTag loop hasEndTag UserTag loop PosNumber 1 UserTag loop Version $Revision: 1.4 $ UserTag loop MapRoutine Vend::Interpolate::tag_loop_list
Source: lib/Vend/Interpolate.pm
Lines: 5018
sub tag_loop_list { my ($list, $opt, $text) = @_; my $fn; my @rows; $opt->{prefix} ||= 'loop'; $opt->{label} ||= "loop" . ++$::Instance->{List_it} . $Global::Variable->{MV_PAGE}; #::logDebug("list is: " . uneval($list) ); ## Thanks to Kaare Rasmussen for this suggestion ## about passing embedded Perl objects to a list # Can pass object.mv_results=$ary object.mv_field_names=$ary if ($opt->{object}) { my $obj = $opt->{object}; # ensure that number of matches is always set # so [on-match] / [no-match] works $obj->{matches} = scalar(@{$obj->{mv_results}}); return region($opt, $text); } # Here we can take the direct results of an op like # @set = $db->query() && return \@set; # Called with # [loop list=`$Scratch->{ary}`] [loop-code] # [/loop] if (ref $list) { #::logDebug("opt->list in: " . uneval($list) ); unless (ref $list eq 'ARRAY' and ref $list->[0] eq 'ARRAY') { logError("loop was passed invalid list=`...` argument"); return; } my ($ary, $fh, $fa) = @$list; my $obj = $opt->{object} ||= {}; $obj->{mv_results} = $ary; $obj->{matches} = scalar @$ary; $obj->{mv_field_names} = $fa if $fa; $obj->{mv_field_hash} = $fh if $fh; if($opt->{ml}) { $obj->{mv_matchlimit} = $opt->{ml}; $obj->{mv_no_more} = ! $opt->{more}; $obj->{mv_first_match} = $opt->{mv_first_match} || 0; $obj->{mv_next_pointer} = $opt->{mv_first_match} + $opt->{ml}; } return region($opt, $text); } my $delim; if($opt->{search}) { #::logDebug("loop resolve search"); if($opt->{more} and $Vend::More_in_progress) { undef $Vend::More_in_progress; return region($opt, $text); } else { return region($opt, $text); } } elsif ($opt->{file}) { #::logDebug("loop resolve file"); $list = Vend::Util::readfile($opt->{file}); $opt->{lr} = 1 unless defined $opt->{lr} or $opt->{quoted}; } elsif ($opt->{extended}) { ### ### This returns ### my ($view, $tab, $key) = split /:+/, $opt->{extended}, 3; if(! $key) { $key = $tab; $tab = $view; undef $view; } my $id = $tab; $id .= "::$key" if $key; my $meta = Vend::Table::Editor::meta_record( $id, $view, $opt->{table}, $opt->{extended_only}, ); if(! $meta) { $opt->{object} = { matches => 1, mv_results => [], mv_field_names => [], }; } else { $opt->{object} = { matches => 1, mv_results => [ $meta ], }; } return region($opt, $text); } if ($fn = $opt->{fn} || $opt->{mv_field_names}) { $fn = [ grep /\S/, split /[\s,]+/, $fn ]; } if ($opt->{lr}) { #::logDebug("loop resolve line"); $list =~ s/^\s+//; $list =~ s/\s+$//; if ($list) { $delim = $opt->{delimiter} || "\t"; my $splittor = $opt->{record_delim} || "\n"; if ($splittor eq "\n") { $list =~ s/\r\n/\n/g; } eval { @rows = map { [ split /\Q$delim/, $_ ] } split /\Q$splittor/, $list; }; } } elsif($opt->{acclist}) { #::logDebug("loop resolve acclist"); $fn = [ qw/option label/ ] unless $fn; eval { my @items = split /\s*,\s*/, $list; for(@items) { my ($o, $l) = split /=/, $_; $l = $o unless defined $l && $l =~ /\S/; push @rows, [ $o, $l ]; } }; #::logDebug("rows:" . uneval(\@rows)); } elsif($opt->{quoted}) { #::logDebug("loop resolve quoted"); my @l = Text::ParseWords::shellwords($list); produce_range(\@l) if $opt->{ranges}; eval { @rows = map { [$_] } @l; }; } else { #::logDebug("loop resolve default"); $delim = $opt->{delimiter} || '[,\s]+'; my @l = split /$delim/, $list; produce_range(\@l) if $opt->{ranges}; eval { @rows = map { [$_] } @l; }; } if($@) { logError("bad split delimiter in loop list: $@"); #::logDebug("loop resolve error $@"); } # head_skip pulls rows off the top, and uses the last row to # set the field names if mv_field_names/fn option was not set if ($opt->{head_skip}) { my $i = 0; my $last_row; $last_row = shift(@rows) while $i++ < $opt->{head_skip}; $fn ||= $last_row; } $opt->{object} = { matches => scalar(@rows), mv_results => \@rows, mv_field_names => $fn, }; #::logDebug("loop object: " . uneval($opt)); return region($opt, $text); }