make-html: add hackerfunk color
[lugs.git] / make-html / make-html.pl
1 #!/usr/bin/perl
2 #
3 # Konvertiert die LUGS-Terminliste (im ASCII Format) in ein HTML-File
4 #
5 # (c) 1996-1998 Roland Alder
6 # (c) 2007-2008, 2011-2014 Steven Schubiger
7
8 use strict;
9 use warnings;
10 use lib qw(lib);
11
12 my $VERSION = '0.04';
13
14 #-----------------------
15 # Start of configuration
16 #-----------------------
17
18 #
19 # If you're looking for the template,
20 # it is contained below __DATA__ at the end
21 # of this script.
22 #
23
24 my $Config = {
25 data_source => './termine.txt',
26 html_file => './index.phtml',
27 colors => {
28 fremd => 'a2eeff', # blau/gruen
29 treff => '99ccff', # ex http://www.zuerich.ch/
30 seeland => 'ffffbb', # gelb
31 aargau => 'ffbbff', # violett
32 bern => 'a5f6bb', # gruen
33 spec => 'ff8a80', # rot
34 winti => 'd6d6ce', # ex http://www.stadt-winterthur.ch/
35 innerschweiz => '8abed7', # ex http://www.luzern.ch/
36 kreuzlingen => 'f9f9f9', # ehemals aargau (ex http://www.ag.ch/)
37 stgallen => 'e2b1a5', # wie heisst diese Farbe? :)
38 gnupingu => 'ffd133', # von http://www.gnupingu.ch/
39 debian => 'ffa500', # orange
40 hackerfunk => '99b2cd', # blau/grau
41 },
42 ical_dir => 'ical',
43 };
44
45 #---------------------
46 # End of configuration
47 #---------------------
48
49 #-------------------
50 # Start of internals
51 #-------------------
52
53 {
54 my $termine = LUGS::Termine::Liste->new;
55
56 $termine->init;
57
58 my ($html_before, $html_after) = $termine->extract_html;
59 $termine->parse_template;
60
61 my $fh = $termine->{fh}{out};
62
63 print {$fh} $html_before;
64 $termine->process_events;
65 print {$fh} $html_after;
66
67 $termine->cleanup;
68
69 $termine->finalize;
70 }
71
72 package LUGS::Termine::Liste;
73
74 use constant true => 1;
75
76 use File::Copy qw(copy);
77 use File::Temp qw(tempfile);
78 use LUGS::Events::Parser ();
79
80 # Return a new instance of our class.
81 sub new
82 {
83 my $class = shift;
84
85 return bless {};
86 }
87
88 # Open files and retrieve the modification time.
89 sub init
90 {
91 my $self = shift;
92
93 $self->{mtime} = scalar localtime +(stat($Config->{data_source}))[9];
94
95 open($self->{fh}{in}, '<', $Config->{html_file}) or die "Cannot open $Config->{html_file}: $!\n";
96 ($self->{fh}{out}, $self->{tmp_file}) = tempfile(UNLINK => true);
97 }
98
99 # Close file handles.
100 sub cleanup
101 {
102 my $self = shift;
103
104 foreach my $handle (qw(in out)) {
105 close($self->{fh}{$handle});
106 }
107 }
108
109 # Copy the temporary file to the HTML file's location.
110 sub finalize
111 {
112 my $self = shift;
113
114 copy($self->{tmp_file}, $Config->{html_file})
115 or die "Cannot copy $self->{tmp_file} to $Config->{html_file}: $!\n";
116 }
117
118 # Extract chunks before and after where the events get populated in.
119 sub extract_html
120 {
121 my $self = shift;
122
123 my $fh = $self->{fh}{in};
124 my $html = do { local $/; <$fh> };
125
126 my @regexes = (
127 qr/^ (.+? \n<!-- \s*? TERMINE_BEGIN \s*? --> \s*? \n)/sx,
128 qr/ \n(<!-- \s*? TERMINE_ENDE \s*? --> .*) $/sx,
129 );
130
131 my @chunks;
132 foreach my $regex (@regexes) {
133 push @chunks, $1 if $html =~ $regex;
134 }
135
136 return @chunks;
137 }
138
139 # Dump regular events formatted to the output handle.
140 sub process_events
141 {
142 my $self = shift;
143
144 my $parser = LUGS::Events::Parser->new($Config->{data_source});
145
146 my $i;
147 my %month_names = map { sprintf("%02d", ++$i) => $_ }
148 qw(Januar Februar M&auml;rz April Mai Juni Juli
149 August September Oktober November Dezember);
150
151 my $seen ||= '';
152 my $print_month = sub
153 {
154 my ($event) = @_;
155
156 my $year = $event->get_event_year;
157 my $month = $event->get_event_month;
158 my $day = $event->get_event_day;
159
160 if ($month ne $seen) {
161 $seen = $month;
162 $self->print_template('jahreszeit',
163 {
164 MONAT => $month_names{$month},
165 JAHR => $year,
166 });
167 }
168 };
169
170 $self->print_template('tabellenstart');
171 $self->print_template('kopfdaten');
172
173 while (my $event = $parser->next_event) {
174 $print_month->($event);
175
176 my $anchor = $event->get_event_anchor;
177
178 $self->print_template('farbe',
179 {
180 FARBE => $Config->{colors}->{$event->get_event_color}
181 });
182
183 $self->print_template('anker/wann',
184 {
185 ANKER => $anchor,
186 WOCHENTAG => $event->get_event_weekday,
187 TAG => $event->get_event_day,
188 });
189
190 $event->get_event_time
191 ? $self->print_template('zeit',
192 {
193 UHRZEIT => $event->get_event_time,
194 })
195 : $self->print_template('blank');
196
197 $event->get_event_responsible
198 ? $self->print_template('verantwortlich',
199 {
200 WER => $event->get_event_responsible,
201 })
202 : $self->print_template('blank');
203
204 $self->print_template('titel',
205 {
206 BEZEICHNUNG => $event->get_event_title,
207 });
208
209 $event->get_event_location
210 ? $self->print_template('standort',
211 {
212 STANDORT => $event->get_event_location,
213 })
214 : ();
215
216 $event->get_event_more
217 ? $self->print_template('infos',
218 {
219 INFORMATIONEN => $event->get_event_more,
220 })
221 : ();
222
223 my $ics_file = "$anchor.ics";
224 my $ics_link = join '/', ($Config->{ical_dir}, $ics_file);
225
226 $self->print_template('ical',
227 {
228 LINK => $ics_link,
229 });
230
231 $self->print_raw_html('</td></tr>');
232 }
233
234 $self->print_template('tabellenende');
235 $self->print_template('fussnoten',
236 {
237 AENDERUNG => $self->{mtime},
238 });
239 }
240
241 # Parse the template as outlined below __DATA__ and create
242 # a lookup map.
243 sub parse_template
244 {
245 my $self = shift;
246
247 my $template = do { local $/; <DATA> };
248
249 $self->{template} = [ map { s/\n{2,}$/\n/; $_ } # # description
250 grep /\S/, # -
251 split /\# \s+? .+? \s+? -\n/x,
252 $template ];
253 my @descriptions;
254 push @descriptions, $1 while $template =~ /\# \s+? (.+?) \s+? -\n/gx;
255
256 my $i;
257 $self->{lookup} = { map { $_ => $i++ } @descriptions };
258 }
259
260 # Look up the template item, substitute it with the data
261 # given and print it to the output handle.
262 sub print_template
263 {
264 my $self = shift;
265 my ($keyword, $data) = @_;
266
267 return unless exists $self->{lookup}->{$keyword};
268
269 my $item = $self->{template}->[$self->{lookup}->{$keyword}];
270
271 my %markers = (
272 begin => '[%',
273 end => '%]',
274 );
275 foreach my $marker ($markers{begin}, $markers{end}) {
276 $marker = qr/\Q$marker\E/;
277 }
278
279 foreach my $name (keys %$data) {
280 $item =~ s/$markers{begin}
281 \s*?
282 $name
283 \s*?
284 $markers{end}
285 /$data->{$name}/gx;
286 }
287
288 my $fh = $self->{fh}{out};
289 print {$fh} $item;
290 }
291
292 # Print raw HTML to the output handle.
293 sub print_raw_html
294 {
295 my $self = shift;
296 my ($html) = @_;
297
298 my $fh = $self->{fh}{out};
299 print {$fh} $html, "\n";
300 }
301
302 #-----------------
303 # End of internals
304 #-----------------
305
306 #
307 # Do not change the data descriptions within '# <name>' without
308 # adjusting the code accordingly; furthermore, the hyphen '-'
309 # is required and two trailing newlines at the end of the
310 # template item, too.
311 #
312
313 __DATA__
314
315 # tabellenstart
316 -
317 <table border=0 cellpadding=1 cellspacing=2>
318
319 # kopfdaten
320 -
321 <tr><td>&nbsp;</td></tr>
322 <tr><td colspan=4 align=left><h2>Definitive Daten</h2></td></tr>
323 <tr><th align=left>Tag</th><th align=left>Zeit</th><th align=left>Verantwortlich</th><th align=left>Anlass, Thema</th></tr>
324
325 # jahreszeit
326 -
327 <tr><th align=left colspan=3><br><font size="+1">[% MONAT %] [% JAHR %]</font></th></tr>
328
329 # anker
330 -
331 <a name="[% WERT %]"></a>
332
333 # farbe
334 -
335 <tr bgcolor="#[% FARBE %]">
336
337 # anker/wann
338 -
339 <td valign=top><a name="[% ANKER %]"></a>[% WOCHENTAG %], [% TAG %].</td>
340
341 # zeit
342 -
343 <td valign=top>[% UHRZEIT %]</td>
344
345 # verantwortlich
346 -
347 <td valign=top>[% WER %]</td>
348
349 # titel
350 -
351 <td valign=top><b>[% BEZEICHNUNG %]</b>
352
353 # standort
354 -
355 <br><font size=-1>[% STANDORT %]</font>
356
357 # infos
358 -
359 <br>[% INFORMATIONEN %]
360
361 # ical
362 -
363 <td valign=top><a href="[% LINK %]">iCal</a></td>
364
365 # tabellenende
366 -
367 </table>
368
369 # fussnoten
370 -
371 <p>
372 <font size="-1">Alle Angaben ohne Gew&auml;hr, letzte &Auml;nderung der Terminliste: [% AENDERUNG %]</font>
373
374 # blank
375 -
376 <td>&nbsp;</td>