tagging: Allow using titles in for related stories.
[matthijs/upstream/blosxom-plugins.git] / gavinc / uf_hcalendar_meta
1 # Blosxom Plugin: uf_hcalendar_meta
2 # Author(s): Gavin Carr <gavin@openfusion.com.au>
3 # Version: 0.001000
4 # Documentation: 'perldoc uf_hcalendar_meta'
5
6 package uf_hcalendar_meta;
7
8 use strict;
9
10 # Uncomment next line to enable debug output (don't uncomment debug() lines)
11 #use Blosxom::Debug debug_level => 1;
12
13 # --- Configurable variables -----
14
15 my %config = ();
16
17 # Extra CSS classes to add to the microformat container e.g. to turn display off
18 $config{class} = '';
19 #$config{class} = 'nodisplay';
20
21 # Whether to automatically add microformat to story bodies. If not set, 
22 # you must explicitly add $uf_adr_meta::adr to a template somewhere.
23 $config{auto_append_to_body} = 1;
24
25 # What markup style to use for your adr, if auto-appending. 
26 # 3 styles are currently defined: 
27 # 'div-span' uses a 'div' elt for the container, and 'span' elements for the fields
28 # 'ul' uses a 'ul' list for the container, and 'li' elements for the fields
29 # 'dl' uses a 'dl' list for the container, 'dt' elements for field names, and 
30 #    'dd' elements for the fields themselves
31 #$config{style} = 'div-span';
32 #$config{style} = 'ul';
33 $config{style} = 'dl';
34
35 # --------------------------------
36 # __END_CONFIG__
37
38 use vars qw($hcalendar);
39
40 my @required = qw(summary dtstart);
41 my @optional = qw(dtend duration description location url uid);
42 my %label = (
43   dtstart   => 'DtStart',
44   dtend     => 'DtEnd',
45   uid       => 'UID',
46   url       => 'URL',
47 );
48
49 $config{style} = 'div-span' unless $config{style} eq 'ul' or $config{style} eq 'dl';
50
51 sub start { 1 }
52
53 # Return the first existing metadata item key and value given a list of keys
54 sub _get_meta {
55     for my $attr ( @_ ) {
56         my $meta_attr = $attr;
57         $meta_attr =~ s/-/_/g;
58         my $value = $blosxom::meta{$meta_attr};
59         $value = eval "\$meta::$attr" unless defined $value;
60         return wantarray ? ( $attr, $value ) : $value if defined $value;
61     }
62     return wantarray ? () : undef;
63 }
64
65 sub _format_date {
66     my ($date) = @_;
67     my $iso_date = $date;
68     $iso_date =~ s/^(\d{4}-\d{2}-\d{2})(\s+)/$1T/;
69     return $iso_date;  
70 }
71
72 sub _format_duration {
73     my ($duration) = @_;
74     my $iso_duration = uc $duration;
75
76     # Trim
77     $iso_duration =~ s/^\s+//;
78     $iso_duration =~ s/\s+$//;
79
80     # If $iso_duration begins with an H, M, or S element, and no P, insert PT
81     $iso_duration =~ s/^(\d+)([HMS])/PT$1$2/;
82
83     # Otherwise, if $iso_duration begins without a P, insert one
84     $iso_duration =~ s/^(\d)/P$1/;
85
86     # Replace date-time whitespace with 'T'
87     $iso_duration =~ s/([PYMD])\s+/$1T/;
88
89     return $iso_duration;
90 }
91
92 sub story {
93     my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
94
95     my %meta = ();
96     for (@required, @optional) {
97       $meta{$_} = _get_meta($_);
98     }
99     my @req_count = map { $meta{$_} ? 1 : () } @required;
100     return 1 unless @req_count == @required;
101
102     my $story_style = _get_meta( 'hcal_style' ) || $config{style};
103     my $ctag = $story_style eq 'div-span' ? 'div' : $story_style;
104     my $etag = $story_style eq 'div-span' ? 'span' :
105                $story_style eq 'ul' ? 'li' : 'dd';
106
107     $hcalendar = '';
108     my $container_classes = 'vevent';
109     if (my $meta_class = _get_meta('hcal_class')) {
110       $container_classes .= " $meta_class";
111     }
112     else {
113       $container_classes .= " $config{class}" if $config{class};
114     }
115     $hcalendar .= qq(<$ctag class="$container_classes">\n);
116     for (@required, @optional) {
117         next unless defined $meta{$_};
118         $hcalendar .= sprintf qq(<dt>%s</dt>), $label{$_} || ucfirst $_ 
119             if $story_style eq 'dl';
120         if ($_ eq 'dtstart' || $_ eq 'dtend') {
121             my $iso_date = _format_date($meta{$_});
122             $hcalendar .= qq(<$etag><abbr class="$_" title="$iso_date">$meta{$_}</abbr></$etag>\n);
123         }
124         elsif ($_ eq 'duration') {
125             my $iso_duration = _format_duration($meta{$_});
126             $hcalendar .= qq(<$etag><abbr class="$_" title="$iso_duration">$meta{$_}</abbr></$etag>\n);
127         }
128         elsif ($_ eq 'url') {
129             $hcalendar .= qq(<$etag><a class="$_" href="$meta{url}">$meta{url}</a></$etag>\n);
130         }
131         else {
132             $hcalendar .= qq(<$etag class="$_">$meta{$_}</$etag>\n);
133         }
134     }
135     $hcalendar .= qq(</$ctag>\n);
136     # debug(1, "uf_hcalendar_meta: $hcalendar\n");
137
138     my $autoappend = _get_meta( 'hcal_autoappend' );
139     $autoappend = $config{auto_append_to_body} unless defined $autoappend;
140     return 1 unless $autoappend;
141
142     $$body_ref .= "\n\n$hcalendar\n\n";
143
144     return 1;
145 }
146
147 1;
148
149 __END__
150
151 =head1 NAME
152
153 uf_hcalendar_meta - plugin to create an 'hcalendar' microformat tag from 
154 post metadata
155
156 =head1 DESCRIPTION
157
158 uf_hcalendar_meta is a plugin to create an 'hcalendar' microformat tag 
159 from metadata in your post. The microformat tag is created in the 
160 $uf_hcalendar_meta::hcalendar variable for use in templates or by other 
161 plugins, or if the $auto_append_to_body flag is set (it is by default), 
162 uf_hcalendar_meta will append the tag to your story body automatically.
163
164 =head2 REQUIRED METADATA ITEMS
165
166 (If using the 'metamail/metadir/metafile' plugins, metadata items
167 are matched case insensitively.)
168
169 =over 4
170
171 =item summary
172
173 The summary or title of the event.
174
175 =item dtstart
176
177 The start date/time of the event. 
178
179 Must be given as an ISO 8601 calendar date, in the form 
180 YYYY-MM-DDTHH:MM:SS or YYYYMMDDTHHMMSS, with an optional trailing 
181 timezone of the form /[+-]HH(:?MM)?/. Any number of rightmost time 
182 elements may be omitted. Hours must be given in 24-hour time.
183
184 For convenience, this plugin allows the 'T' marker to be replaced by 
185 whitespace.
186
187 The following are all valid dtstart values, for example:
188
189 =over 4
190
191 =item 2007-09-01T19:30:00+10:00
192
193 =item 20070901T193000-10
194
195 =item 2007-09-01
196
197 =item 2007-09-01 17:45
198
199 =back
200
201 =back
202
203 And one of:
204
205 =over 4
206
207 =item dtend
208
209 The end date/time of the event. Must be an ISO 8601 calendar date 
210 as defined for dtstart above.
211
212 =item duration
213
214 The duration of the event. This may be an ISO 8601 duration, of the
215 form PnnYnnMnnDTnnHnnMnnS e.g. "P3Y6M4DT12H30M0S". Elements may be
216 omitted if their duration is zero. The smallest value used may also 
217 have a decimal fraction, as in "P0.5Y" to indicate half a year.
218
219 For convenience, this plugin interprets the units case-insensitively,
220 allows the 'P' and 'T' markers to be omitted, and also accepts 
221 whitespace in the place of the 'T' time marker. 
222
223 Note that because months and minutes use the same signifier, there is
224 ambiguity about the meaning of 'P1M' and '1M'. This plugin interprets
225 'M' values as follows:
226
227 =over 4
228
229 =item 1M
230
231 Interpreted as minutes, since this is the most common use case, and 
232 since ISO 8601 really requires a leading 'P' signifier.
233
234 =item P1M
235
236 Interpreted as months, following ISO 8601.
237
238 =item PT1M
239
240 Interpreted as minutes, following ISO 8601.
241
242 =back
243
244 =back
245
246
247 =head2 OPTIONAL METADATA ITEMS
248
249 =over 4
250
251 =item description
252
253 A description of the event, sometimes longer than the summary.
254
255 =item dtend
256
257 The end date/time of the event, as discussed above.
258
259 =item duration
260
261 The duration of the event, as discussed above.
262
263 =item location
264
265 A string describing the location of the event.
266
267 =item url
268
269 A canonical URL for the event.
270
271 =item uid
272
273 A unique identifier for this event. Apparently required by some
274 versions of Microsoft Outlook.
275
276 =back
277
278 =head2 Config Elements
279
280 uf_hcalendar_meta also supports a couple of config elements that can be used to
281 override plugin config data on a per-story basis:
282
283 =over 4
284
285 =item HCal-Class (metamail) / hcal_class (meta)
286
287 This class (or list of classes) is appended to the class list applied to the
288 top-level hcalendar element in the rendered hcalendar i.e. it overrides the 
289 'class' config variable. 
290
291 =item HCal-Autoappend (metamail) / hcal_autoappend (meta)
292
293 This is a flag (0 or 1) indicating whether the rendered hcalendar should be 
294 automatically appended to the story body. It overrides the 'auto_append_to_body'
295 config variable.
296
297 =item HCal-Style (metamail) / hcal_style (meta)
298
299 One of the following styles: 'div-span', 'ul', 'dl', used to render the hcalendar. 
300 It overrides the 'style' config variable.
301
302 =back
303
304 =head1 USAGE
305
306 uf_hcalendar_meta should be loaded after the meta plugins (meta
307 itself, or the metaclear/metamail/metadir/metafile family).
308
309 =head1 SEE ALSO
310
311 Microformats.org: http://www.microformats.org/,
312 http://microformats.org/wiki/hcalendar.
313
314 Blosxom: http://blosxom.sourceforge.net/
315
316 =head1 BUGS
317
318 Only the most common hcalendar attributes have been implemented
319 so far. Please let me know if you'd like something not available 
320 yet.
321
322 =head1 AUTHOR
323
324 Gavin Carr <gavin@openfusion.com.au>, http://www.openfusion.net/
325
326 =head1 LICENSE
327
328 Copyright 2007, Gavin Carr.
329
330 This plugin is licensed under the same terms as blosxom itself i.e.
331
332 Permission is hereby granted, free of charge, to any person obtaining a
333 copy of this software and associated documentation files (the "Software"),
334 to deal in the Software without restriction, including without limitation
335 the rights to use, copy, modify, merge, publish, distribute, sublicense,
336 and/or sell copies of the Software, and to permit persons to whom the
337 Software is furnished to do so, subject to the following conditions:
338
339 The above copyright notice and this permission notice shall be included
340 in all copies or substantial portions of the Software.
341
342 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
343 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
344 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
345 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
346 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
347 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
348 OTHER DEALINGS IN THE SOFTWARE.
349
350 =cut
351
352 # vim:ft=perl