]> sipb.mit.edu Git - ikiwiki.git/blob - doc/todo/allow_TMPL__95__LOOP_in_template_directives.mdwn
mirrorlist: new mirrorlist_use_cgi boolean setting.
[ikiwiki.git] / doc / todo / allow_TMPL__95__LOOP_in_template_directives.mdwn
1 [[!tag patch todo]]
2
3 [[!template id="note" text="""
4 Simply copied this from my website
5 [[http://www.camco.ie/code/ikiwiki,3.20120202,20120313a/]]
6 feel free to reformat / delete"""]]
7
8 The following re-write allows for multiple definitions of the
9 same tag value in a [[plugins/template]] definition.  This, in turn, allows
10 us to use TMPL_LOOPS in our [[ikiwiki/directive/template]] directives; all-be-it in a
11 rather limited way.
12
13 > I'm willing to consider such a feature, but it needs to be presented in
14 > the form of a patch that is reviewable, not a gratuitous rewrite.
15 > --[[Joey]] 
16
17 I would, personally, only use this feature for very basic loops
18 and, although nested loops *might* be possible (with a little
19 more tinkering) it think any attempt would be better served by
20 [[Kathyrn Anderson's|http://www.katspace.org/]] [[field et
21 al.|http://ikiwiki.info/plugins/contrib/field/]] plugin.
22
23 It *is* (primarily) intended to allow insertion of organised CSS
24 blocks (i.e. `<div>`) through template directives (since i can't
25 seem to get HTML and Markup to mix the way I want).
26
27 [[!template id="note" text="""
28 Apologies for the re-write.  I struggle reading perl code that
29 I didn't write and (probably too often) re-format to reduce my
30 head-aches.  Anyway it didn't make sense to post the patch since
31 everything's changed now.
32 """]]
33
34 NB: this *should* be 100% backwards compatible.
35
36 # `lib/perl5/IkiWiki/Plugin/template.pm`
37
38 [[!format perl """
39
40         #!/usr/bin/perl
41         # Structured template plugin.
42         package IkiWiki::Plugin::template ;
43
44         use warnings ;
45         use strict ;
46         use IkiWiki 3.00 ;
47         use Encode ;
48
49         sub mktmpl_hash( $ ; $ ; @ ) ;
50                                 # declare to supress warning in recursive call
51         sub mktmpl_hash( $ ; $ ; @ )
52                                 # make hash for the template, filling
53                                 # values from the supplied params
54         {
55                 my $template = shift( @_ )
56                                 || error( "mktmpl_hash: no template provided" ) ;
57                 my $param_src = shift( @_ )
58                                 || error( "mktmpl_hash: no parameters" ) ;
59
60                 my $path ;
61                 if( $#_ > 0 )
62                 {
63                         $path = [ @_ ] ;
64                 } else {
65                         $path = shift(@_) || [] ;
66                 } ;
67
68                 my %params ;
69
70                 my @path_vars ;
71                 if( $#{$path} < 0 )
72                 {
73                         @path_vars = $template->query() ;
74                 } else {
75                         @path_vars = $template->query( loop => $path ) ;
76                 } ;
77
78                 foreach my $var ( @path_vars )
79                 {
80                         push( @{$path}, $var ) ;
81                         my $param_type = $template->query( name => $path ) ;
82                         if( $param_type eq 'VAR' )
83                         {
84                                 my @var_path = split( /_/, $var ) ;
85                                 if( $var_path[0] ne '' )
86                                 {
87                                         $path->[-1] = join( '_', @var_path[1..$#var_path] )
88                                                 if( $var_path[0] eq 'raw' ) ;
89                                         $params{$var} = shift( @{$param_src->{$path->[-1]}} )
90                                                         || return(undef) ;
91                                 } ;
92                         } elsif( $param_type eq 'LOOP' )
93                         {
94                                 $params{$var} = [] ;
95                                 push( @{$params{$var}}, $_ )
96                                         while( $_ = mktmpl_hash($template,$param_src,$path) ) ;
97                         } ;
98                         pop( @{$path} ) ;
99                 } ; 
100                 return( \%params ) ;
101         } ;
102
103         sub proc_tmpl_hash( $ ; $ ; $ ; $ ) ;
104                                 # declare to supress warning in recursive call
105         sub proc_tmpl_hash( $ ; $ ; $ ; $ )
106                                 # walk the hash, preprocess and
107                                 # convert to html
108         {
109                 my $tmpl_hash = shift( @_ ) ;
110                 my $page = shift( @_ ) ;
111                 my $destpage = shift( @_ ) ;
112                 my $scan = shift( @_ ) ;
113                 foreach my $key ( keys(%{$tmpl_hash}) )
114                 {
115                         unless( ref($tmpl_hash->{$key}) )
116                                                 # here we assume that
117                                                 # any reference is an
118                                                 # array and allow it to
119                                                 # fail if that's false
120                         {
121                                 $tmpl_hash->{$key} =
122                                                 IkiWiki::preprocess(
123                                                                 $page,
124                                                                 $destpage,
125                                                                 $tmpl_hash->{$key},
126                                                                 $scan ) ;
127                                 my @key_path = split( /_/, $key ) ;
128                                 $tmpl_hash->{$key} =
129                                                 IkiWiki::htmlize(
130                                                                 $page,
131                                                                 $destpage,
132                                                                 pagetype($pagesources{$page}),
133                                                                 $tmpl_hash->{$key}, )
134                                         unless( $key_path[0] eq 'raw' ) ;
135                         } else {
136                                 proc_tmpl_hash( $_, $page, $destpage, $scan )
137                                         foreach( @{$tmpl_hash->{$key}} ) ;
138                         } ;
139                 } ;
140         } ;
141
142         # "standard" ikiwiki definitions / hooks
143
144         sub import
145         {
146                 hook( type => "getsetup",
147                                 id => "template",
148                                 call => \&getsetup ) ;
149                 hook( type => "preprocess",
150                                 id => "template",
151                                 call => \&preprocess,
152                                 scan => 1 ) ;
153         } ;
154
155         sub getsetup()
156         {
157                 return(
158                                 plugin => {
159                                         safe => 1,
160                                         rebuild => undef,
161                                         section => "widget",
162                                 }, ) ;
163         } ;
164
165         sub preprocess( @ )
166         {
167         # first process arguments into arrays of values
168                 my %params ;
169
170                 my( $key, $value ) ;
171                 while( ($key,$value)=splice(@_,0,2) )
172                 {
173                         if( exists($params{$key}) )
174                         {
175                                 push( @{$params{$key}}, $value ) ;
176                         } else {
177                                 $params{$key} = [ $value ] ;
178                         } ;
179                 } ;
180
181         # set context
182                 my $scan = ! defined( wantarray() ) ;
183                                         # This needs to run even in scan
184                                         # mode, in order to process links
185                                         # and other metadata included via
186                                         # the template.
187
188         # check for critical values
189                 if( ! exists($params{id}) )
190                 {
191                         error( gettext("missing id parameter") ) ;
192                 } ;
193
194         # set some convenience variables
195                 my $id = $params{id}->[$#{$params{id}}] ;
196                 my $page = $params{page}->[$#{$params{page}}] ;
197                 my $destpage = $params{destpage}->[$#{$params{destpage}}] ;
198         # ... and an essential one for the production pass
199                 $params{basename} = [ IkiWiki::basename($page) ] ;
200
201         # load the template
202                 my $template ;
203                 eval {
204                         $template =
205                                         template_depends( $id, $page,
206                                                         blind_cache=>1 ) ;
207                                                 # The bare id is used, so
208                                                 # a page templates/$id can
209                                                 # be used as the template.
210                 } ;
211                 if( $@ )
212                 {
213                         error(
214                                         sprintf(
215                                                         gettext("failed to process template %s"),
216                                                         htmllink(
217                                                                         $page,
218                                                                         $destpage,
219                                                                         "/templates/$id")
220                                                         )." $@"
221                                         ) ;
222                 } ;
223
224         # create and process the parameters
225                 my $tmpl_hash = mktmpl_hash( $template, \%params ) ;
226                 proc_tmpl_hash( $tmpl_hash, $page, $destpage, $scan ) ;
227         # ... and load the template with the values
228                 $template->param( $tmpl_hash ) ;
229
230         # return the processed page chunk
231                 return( IkiWiki::preprocess($page,
232                                                 $destpage,
233                                                 $template->output(),$scan)
234                                 ) ;
235         } ;
236
237         1 ;
238
239 """]]
240
241 ## sample template
242
243         # <TMPL_VAR HEADER0>
244
245         <table>
246         <TMPL_LOOP TEST0>
247         <tr>
248                 <td><TMPL_VAR DATA0></td>
249                 <td><TMPL_VAR DATA1></td>
250         </tr>
251         </TMPL_LOOP>
252         </table>
253
254 ## sample iki page
255
256         \[[!meta title="this is my loops page"]]
257
258         \[[!template id="loops"
259         header0="this is a table"
260         data0="cell0:0"
261         data1="cell0:1"
262         data0="cell1:0"
263         data1="cell1:1"
264         ]]