[[!tag patch todo]] [[!template id="note" text=""" Simply copied this from my website [[http://www.camco.ie/code/ikiwiki,3.20120202,20120313a/]] feel free to reformat / delete"""]] The following re-write allows for multiple definitions of the same tag value in a [[plugins/template]] definition. This, in turn, allows us to use TMPL_LOOPS in our [[ikiwiki/directive/template]] directives; all-be-it in a rather limited way. > I'm willing to consider such a feature, but it needs to be presented in > the form of a patch that is reviewable, not a gratuitous rewrite. > --[[Joey]] >> Yes, my apologies for that. The two worker functions `mktmpl_hash` and `proc_tmpl_hash` are new. The `preprocess` function then starts by arranging the parameters into an array. This array is passed to the `mktmpl_hash` and it creates a hash, suitable for passing into the HTML::Template directly. The `proc_tmpl_hash` then walks the hash structure and processes the parameters. >> I know ... you weren't looking for an explanation, just a patch ... totally understand. Point I'm trying to make, it's a 90% re-write anyway (and my `style(8)` will probably piss most people off). >> Anyway, would love to contribute so will try to get to doing this "correctly" and post as a patch. I would, personally, only use this feature for very basic loops and, although nested loops *might* be possible (with a little more tinkering) it think any attempt would be better served by [[Kathyrn Anderson's|http://www.katspace.org/]] [[field et al.|http://ikiwiki.info/plugins/contrib/field/]] plugin. It *is* (primarily) intended to allow insertion of organised CSS blocks (i.e. `
`) through template directives (since i can't seem to get HTML and Markup to mix the way I want). [[!template id="note" text=""" Apologies for the re-write. I struggle reading perl code that I didn't write and (probably too often) re-format to reduce my head-aches. Anyway it didn't make sense to post the patch since everything's changed now. """]] NB: this *should* be 100% backwards compatible. # `lib/perl5/IkiWiki/Plugin/template.pm` [[!format perl """ #!/usr/bin/perl # Structured template plugin. package IkiWiki::Plugin::template ; use warnings ; use strict ; use IkiWiki 3.00 ; use Encode ; sub mktmpl_hash( $ ; $ ; @ ) ; # declare to supress warning in recursive call sub mktmpl_hash( $ ; $ ; @ ) # make hash for the template, filling # values from the supplied params { my $template = shift( @_ ) || error( "mktmpl_hash: no template provided" ) ; my $param_src = shift( @_ ) || error( "mktmpl_hash: no parameters" ) ; my $path ; if( $#_ > 0 ) { $path = [ @_ ] ; } else { $path = shift(@_) || [] ; } ; my %params ; my @path_vars ; if( $#{$path} < 0 ) { @path_vars = $template->query() ; } else { @path_vars = $template->query( loop => $path ) ; } ; foreach my $var ( @path_vars ) { push( @{$path}, $var ) ; my $param_type = $template->query( name => $path ) ; if( $param_type eq 'VAR' ) { my @var_path = split( /_/, $var ) ; if( $var_path[0] ne '' ) { $path->[-1] = join( '_', @var_path[1..$#var_path] ) if( $var_path[0] eq 'raw' ) ; $params{$var} = shift( @{$param_src->{$path->[-1]}} ) || return(undef) ; } ; } elsif( $param_type eq 'LOOP' ) { $params{$var} = [] ; push( @{$params{$var}}, $_ ) while( $_ = mktmpl_hash($template,$param_src,$path) ) ; } ; pop( @{$path} ) ; } ; return( \%params ) ; } ; sub proc_tmpl_hash( $ ; $ ; $ ; $ ) ; # declare to supress warning in recursive call sub proc_tmpl_hash( $ ; $ ; $ ; $ ) # walk the hash, preprocess and # convert to html { my $tmpl_hash = shift( @_ ) ; my $page = shift( @_ ) ; my $destpage = shift( @_ ) ; my $scan = shift( @_ ) ; foreach my $key ( keys(%{$tmpl_hash}) ) { unless( ref($tmpl_hash->{$key}) ) # here we assume that # any reference is an # array and allow it to # fail if that's false { $tmpl_hash->{$key} = IkiWiki::preprocess( $page, $destpage, $tmpl_hash->{$key}, $scan ) ; my @key_path = split( /_/, $key ) ; $tmpl_hash->{$key} = IkiWiki::htmlize( $page, $destpage, pagetype($pagesources{$page}), $tmpl_hash->{$key}, ) unless( $key_path[0] eq 'raw' ) ; } else { proc_tmpl_hash( $_, $page, $destpage, $scan ) foreach( @{$tmpl_hash->{$key}} ) ; } ; } ; } ; # "standard" ikiwiki definitions / hooks sub import { hook( type => "getsetup", id => "template", call => \&getsetup ) ; hook( type => "preprocess", id => "template", call => \&preprocess, scan => 1 ) ; } ; sub getsetup() { return( plugin => { safe => 1, rebuild => undef, section => "widget", }, ) ; } ; sub preprocess( @ ) { # first process arguments into arrays of values my %params ; my( $key, $value ) ; while( ($key,$value)=splice(@_,0,2) ) { if( exists($params{$key}) ) { push( @{$params{$key}}, $value ) ; } else { $params{$key} = [ $value ] ; } ; } ; # set context my $scan = ! defined( wantarray() ) ; # This needs to run even in scan # mode, in order to process links # and other metadata included via # the template. # check for critical values if( ! exists($params{id}) ) { error( gettext("missing id parameter") ) ; } ; # set some convenience variables my $id = $params{id}->[$#{$params{id}}] ; my $page = $params{page}->[$#{$params{page}}] ; my $destpage = $params{destpage}->[$#{$params{destpage}}] ; # ... and an essential one for the production pass $params{basename} = [ IkiWiki::basename($page) ] ; # load the template my $template ; eval { $template = template_depends( $id, $page, blind_cache=>1 ) ; # The bare id is used, so # a page templates/$id can # be used as the template. } ; if( $@ ) { error( sprintf( gettext("failed to process template %s"), htmllink( $page, $destpage, "/templates/$id") )." $@" ) ; } ; # create and process the parameters my $tmpl_hash = mktmpl_hash( $template, \%params ) ; proc_tmpl_hash( $tmpl_hash, $page, $destpage, $scan ) ; # ... and load the template with the values $template->param( $tmpl_hash ) ; # return the processed page chunk return( IkiWiki::preprocess($page, $destpage, $template->output(),$scan) ) ; } ; 1 ; """]] ## sample template #
## sample iki page \[[!meta title="this is my loops page"]] \[[!template id="loops" header0="this is a table" data0="cell0:0" data1="cell0:1" data0="cell1:0" data1="cell1:1" ]]