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