tagging: Allow using titles in for related stories.
[matthijs/upstream/blosxom-plugins.git] / gavinc / mason_blocks
1 # Blosxom Plugin: mason_blocks
2 # Author(s): Gavin Carr <gavin@openfusion.com.au>
3 # Version: 0.002001
4
5 package mason_blocks;
6
7 use strict;
8
9 #use Blosxom::Debug debug_level => 1;
10
11 # --- Configurable variables -----
12
13 # None
14
15 # --------------------------------
16
17 sub start { 1 };
18
19 sub head {
20   my($pkg, $currentdir, $head_ref) = @_;
21   munge_blocks($head_ref);
22   return 1;
23 }
24
25 sub story {
26   my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
27   munge_blocks($story_ref);
28   return 1;
29 }
30
31 sub foot {
32   my($pkg, $currentdir, $foot_ref) = @_;
33   munge_blocks($foot_ref);
34   return 1;
35 }
36
37 sub munge_blocks {
38   my ($flavour_ref) = @_;
39
40   my @flavour = ();
41   my ($doc, @if, @else, @if_blocks, @else_blocks);
42   @if = @else = @if_blocks = @else_blocks = ();
43   for (split /\n/, $$flavour_ref) {
44     # Ignore lines beginning with '%#'
45     next if m/^%\s*#/;
46
47     # Ignore if in doc block <%doc> .... </%doc> (at beginning of lines)
48     if (m!^</%doc>! && $doc) {
49       $doc = 0;
50       next;
51     } elsif ($doc) {
52       next;
53     } elsif (m!^<%doc>!) {
54       $doc = 1;
55       next;
56     }
57
58     # Minimalist version - if, } else {, } only, nesting supported
59     if (m/^%\s*if\b/) {
60       my $if = $_;
61       $if =~ s/^%\s*if\s*//;
62       $if =~ s/\s*{\s*$//;
63       # New block, record condition, and add new entries to other arrays
64       push @if, $if;
65       push @else, 0;
66       push @if_blocks,   [];
67       push @else_blocks, [];
68       next;
69     }
70     elsif (m/^%\s*\}\s*else\s*\{/) {
71       # Else at same level - set current else flag to true
72       $else[$#else] = 1;
73       next;
74     }
75     elsif (m/^%\s*\}/) {
76       # End of block - pull latest entries from all arrays
77       my $if = pop @if;
78       my $else = pop @else;
79       my $if_block = pop @if_blocks;
80       my $else_block = pop @else_blocks;
81       # debug(1, "end_block: if '$if', if block " .  scalar(@$if_block) . " lines, else block " .  scalar(@$else_block) . " lines\n");
82       # Check condition, and replace current line with appropriate flattened block
83       if (eval "$if") {
84         $_ = join "\n", @$if_block;
85       } else {
86         $_ = join "\n", @$else_block;
87       }
88     }
89     
90     # Regular line - add to @else_blocks, @if_blocks, or @flavour
91     if (@else && $else[$#else]) {
92       push @{$else_blocks[$#else_blocks]}, $_;
93     }
94     elsif (@if) {
95       push @{$if_blocks[$#if_blocks]}, $_;
96     }
97     else {
98       push @flavour, $_;
99     }
100   }
101
102   # Join flavour lines and update $$flavour_ref
103   $$flavour_ref = join "\n", @flavour;
104
105   # Support mason-style end-of-line newline escapes
106   $$flavour_ref =~ s/\\\r?\n//g;
107 }
108
109 1;
110
111 __END__
112
113 =head1 NAME
114
115 mason_blocks - blosxom plugin to support simple mason-style if-blocks
116 in blosxom flavours/templates
117
118 =head1 SYNOPSIS
119
120     # In a flavour or template file ...
121
122     # Mason-style conditionals
123     % if ($pagetype::pagetype ne 'story') {
124     <a href="$permalink::story#comments">Comments ($feedback::count) &raquo;</a>
125     % } else {
126     <a href="$permalink::story#leave_comment">Leave a comment &raquo;</a>
127     % }
128
129     # Mason-style comments
130     %# Only show a comments section if there are comments
131     % if ($feedback::count > 0) {
132     $feedback::comments
133     % }
134
135     # Mason-style block comments
136     <%doc>
137     This is a great big
138     multi-line, extremely important
139     comment.
140     </%doc>
141
142
143 =head1 DESCRIPTION
144
145 mason_blocks is a blosxom plugin implementing simple conditional and
146 commment blocks using mason-style syntax (as in the HTML::Mason perl
147 templating system), for use in blosxom flavour and template files.
148
149 =head2 CONDITIONALS
150
151 mason_blocks supports simple if and if-else blocks using lines beginning
152 with the '%' character (which must be the first character on the line)
153 e.g.
154
155     % if ($pagetype::pagetype eq 'story') {
156     <a href="$permalink::story#leave_comment">Leave a comment &raquo;</a>
157     % }
158
159 and
160
161     % if ($pagetype::pagetype ne 'story') {
162     <a href="$permalink::story#comments">Comments ($feedback::count) &raquo;</a>
163     % } else {
164     <a href="$permalink::story#leave_comment">Leave a comment &raquo;</a>
165     % }
166
167 Whitespace is not significant, but braces are required and should match, 
168 just as in perl. The if-conditions can comprise any valid perl condition.
169
170 =head2 COMMENTS
171
172 Two comment styles are also supported. Single line comments must begin with
173 a '%' character, followed by optional whitespace, follwed by a '#' character,
174 and continue only to the end of the line e.g.
175
176     %# This is a completely profound and illuminating comment
177     % # As is this
178
179 Block comments must begin with a <%doc> token (at the beginning of a line)
180 and end with a </%doc> token (also at the beginning of a line). All text
181 between these two tokens is treated as a comment and not included in output.
182 For example:
183
184     <%doc>
185     More enlightening profundities from your template author
186     Explaining why this stuff is as ugly as it is ...
187     </%doc>
188
189 Block comments cannot be nested.
190
191 =head2 VS. INTERPOLATE_FANCY
192
193 mason_blocks was initially born out of my frustration with older versions 
194 of interpolate_fancy not supporting nested constructs properly (though I'd
195 also been frustrated with the syntax and the limits on the conditionals
196 available). 
197
198 I thought for an experiment I'd see how hard simple non-nested 
199 conditionals using a mason-style syntax would be, and it turned out to be
200 not very difficult at all. I no longer use interpolate_fancy at all - my
201 limited use cases seem better met using mason_blocks.
202
203 As I see it, mason_blocks has the following advantages over 
204 interpolate_fancy:
205
206 =over 4
207
208 =item Nesting support
209
210 Earlier versions of interpolate_fancy had problems with nested 
211 constructs. I believe that this has been fixed in the later versions
212 updated by Matthijs Kooijman (>= version 20060111). 
213
214 mason_blocks fully supports nested conditionals.
215
216 =item If-Else Constructs
217
218 mason_blocks supports simple if-else blocks, instead of making you
219 use 'if x eq 1; if x ne 1' pairs. It does not currently support 
220 elsif, however.
221
222 =item Full perl conditions
223
224 mason_blocks allows you to use full perl conditions (including composite
225 conditions) instead of being limited to simple conditions using only the
226 most common operators. For instance, all of the following require hoop
227 jumping with interpolate_fancy:
228
229 =over 4
230
231 =item if ($foo >= 3)
232
233 =item if (substr($foo, 3, 1) eq 'X')
234
235 =item if ($pagetype::pagetype eq 'story' && $feedback::comments > 0)
236
237 =back
238
239 =back
240
241 mason_blocks does not provide any of interpolate_fancy's interpolation 
242 or action functionality, however.
243
244
245 =head1 USAGE
246
247 mason_blocks should probably be loaded relatively late, since you'll
248 often want to use various plugin package variables in your conditionals.
249
250 It uses the 'head', 'story', and 'footer' hooks, rather than 'interpolate',
251 so it should be able to be used alongside any of the interpolate plugins
252 if you wish.
253
254
255 =head1 SEE ALSO
256
257 HTML::Mason, for the block syntax (the module is not used or required by 
258 this plugin, however).
259
260 Blosxom: http://blosxom.sourceforge.net/
261
262
263 =head1 BUGS
264
265 Please report bugs either directly to the author or to the blosxom 
266 development mailing list: <blosxom-devel@lists.sourceforge.net>.
267
268
269 =head1 TODO
270
271 - add elsif support
272
273
274 =head1 AUTHOR
275
276 Gavin Carr <gavin@openfusion.com.au>, http://www.openfusion.net/
277
278 =head1 LICENSE
279
280 Copyright 2007, Gavin Carr.
281
282 This plugin is licensed under the same terms as blosxom itself i.e.
283
284 Permission is hereby granted, free of charge, to any person obtaining a
285 copy of this software and associated documentation files (the "Software"),
286 to deal in the Software without restriction, including without limitation
287 the rights to use, copy, modify, merge, publish, distribute, sublicense,
288 and/or sell copies of the Software, and to permit persons to whom the
289 Software is furnished to do so, subject to the following conditions:
290
291 The above copyright notice and this permission notice shall be included
292 in all copies or substantial portions of the Software.
293
294 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
295 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
296 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
297 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
298 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
299 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
300 OTHER DEALINGS IN THE SOFTWARE.
301
302 =cut
303
304 # vim:ft=perl