source: trunk/lib/OpenGuides/Template.pm @ 683

Last change on this file since 683 was 683, checked in by Earle Martin, 16 years ago

new "summary" metadata field

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.0 KB
Line 
1package OpenGuides::Template;
2
3use strict;
4use vars qw( $VERSION );
5$VERSION = '0.12';
6
7use Carp qw( croak );
8use CGI; # want to get rid of this and put the burden on the templates
9use Geography::NationalGrid;
10use Geography::NationalGrid::GB;
11use OpenGuides; # for $VERSION for template variable
12use OpenGuides::CGI;
13use Template;
14use URI::Escape;
15
16=head1 NAME
17
18OpenGuides::Template - Do Template Toolkit related stuff for OpenGuides applications.
19
20=head1 DESCRIPTION
21
22Does all the Template Toolkit stuff for OpenGuides.  Distributed and
23installed as part of the OpenGuides project, not intended for
24independent installation.  This documentation is probably only useful
25to OpenGuides developers.
26
27=head1 SYNOPSIS
28
29  use OpenGuides::Config;
30  use OpenGuides::Utils;
31  use OpenGuides::Template;
32
33  my $config = OpenGuides::Config->new( file => "wiki.conf" );
34  my $wiki = OpenGuides::Utils->make_wiki_object( config => $config );
35
36  print OpenGuides::Template->output( wiki     => $wiki,
37                                      config   => $config,
38                                      template => "node.tt",
39                                      vars     => { foo => "bar" }
40  );
41
42=head1 METHODS
43
44=over 4
45
46=item B<output>
47
48  print OpenGuides::Template->output( wiki         => $wiki,
49                                      config       => $config,
50                                      template     => "node.tt",
51                                      content_type => "text/html",
52                                      cookies      => $cookie,
53                                      vars         => {foo => "bar"}
54  );
55
56Returns everything you need to send to STDOUT, including the
57Content-Type: header. Croaks unless C<template> is supplied.
58
59The variables supplied in C<vars> are passed through to the template
60specified.  Additional Template Toolkit variables are automatically
61set and passed through as well, as described below.  B<Note:>
62variables set in C<vars> will over-ride any variables of the same name
63in the config object or the user cookies.
64
65=over
66
67=item * C<openguides_version>
68
69=item * C<site_name>
70
71=item * C<cgi_url>
72
73=item * C<full_cgi_url>
74
75=item * C<enable_page_deletion> (gets set to true or false - defaults to false)
76
77=item * C<contact_email>
78
79=item * C<stylesheet>
80
81=item * C<home_link>
82
83=item * C<formatting_rules_link> (unless C<omit_formatting_link> is set in user cookie)
84
85=item * C<navbar_on_home_page>
86
87=item * C<home_name>
88
89=back
90
91=over
92
93If C<node> is supplied:
94
95=item * C<node_name>
96
97=item * C<node_param> (the node name escaped for use in URLs)
98
99=back
100
101Content-Type: defaults to C<text/html> and is omitted if the
102C<content_type> arg is explicitly set to the blank string.
103
104=cut
105
106sub output {
107    my ($class, %args) = @_;
108    croak "No template supplied" unless $args{template};
109    my $config = $args{config} or croak "No config supplied";
110    my $template_path = $config->template_path;
111    my $custom_template_path = $config->custom_template_path || "";
112    my $tt = Template->new( { INCLUDE_PATH => "$custom_template_path:$template_path" } );
113
114    my $script_name  = $config->script_name;
115    my $script_url   = $config->script_url;
116    my $default_city = $config->default_city;
117   
118    # Check cookie to see if we need to set the formatting_rules_link.
119    my ($formatting_rules_link, $omit_help_links);
120    my $formatting_rules_node = $config->formatting_rules_node;
121    $formatting_rules_link = $config->formatting_rules_link;
122    my %cookie_data = OpenGuides::CGI->get_prefs_from_cookie(config=>$config);
123    if ( $cookie_data{omit_help_links} ) {
124        $omit_help_links = 1;
125    } else {
126        if (( $formatting_rules_node ) and !( $formatting_rules_link )){
127            $formatting_rules_link = $script_url . $script_name . "?"
128                                   . uri_escape($args{wiki}->formatter->node_name_to_node_param($formatting_rules_node));
129        }
130    }
131
132    my $enable_page_deletion = 0;
133    if ( $config->enable_page_deletion
134         and ( lc($config->enable_page_deletion) eq "y"
135               or $config->enable_page_deletion eq "1" )
136       ) {
137        $enable_page_deletion = 1;
138    }
139
140    my $tt_vars = {
141        site_name             => $config->site_name,
142        cgi_url               => $script_name,
143        full_cgi_url          => $script_url . $script_name,
144        contact_email         => $config->contact_email,
145        stylesheet            => $config->stylesheet_url,
146        home_link             => $script_url . $script_name,
147        home_name             => $config->home_name,
148        navbar_on_home_page   => $config->navbar_on_home_page,
149        omit_help_links       => $omit_help_links,
150        formatting_rules_link => $formatting_rules_link,
151        formatting_rules_node => $formatting_rules_node,
152        openguides_version    => $OpenGuides::VERSION,
153        enable_page_deletion  => $enable_page_deletion,
154        language              => $config->default_language,
155        default_city          => $default_city,
156    };
157
158    if ($args{node}) {
159        $tt_vars->{node_name} = CGI->escapeHTML($args{node});
160        $tt_vars->{node_param} = CGI->escape($args{wiki}->formatter->node_name_to_node_param($args{node}));
161    }
162
163    # Now set further TT variables if explicitly supplied - do this last
164    # as these override auto-set ones.
165    $tt_vars = { %$tt_vars, %{ $args{vars} || {} } };
166
167    my $header = "";
168    unless ( defined $args{content_type} and $args{content_type} eq "" ) {
169        $header = CGI::header( -cookie => $args{cookies} );
170    }
171
172    # vile hack
173    my %field_vars = OpenGuides::Template->extract_metadata_vars(
174                         wiki                 => $args{wiki},
175                         config               => $config,
176                         set_coord_field_vars => 1,
177                         metadata => {},
178                     );
179                     
180    $tt_vars = { %field_vars, %$tt_vars };
181
182    my $output;
183    $tt->process( $args{template}, $tt_vars, \$output );
184
185    $output ||= qq(<html><head><title>ERROR</title></head><body><p>
186                   Failed to process template: )
187              . $tt->error
188              . qq(</p></body></html>);
189
190    return $header . $output;
191}
192
193=item B<extract_metadata_vars>
194
195  my %node_data = $wiki->retrieve_node( "Home Page" );
196
197  my %metadata_vars = OpenGuides::Template->extract_metadata_vars(
198                          wiki     => $wiki,
199                          config   => $config,
200                          metadata => $node_data{metadata}
201                      );
202
203  # -- or --
204
205  my %metadata_vars = OpenGuides::Template->extract_metadata_vars(
206                          wiki     => $wiki,
207                          config   => $config,
208                          cgi_obj  => $q
209                      );
210
211  # -- then --
212
213  print OpenGuides::Template->output(
214            wiki     => $wiki,
215            config   => $config,
216            template => "node.tt",
217            vars     => { foo => "bar",
218                          %metadata_vars }
219        );
220
221Picks out things like categories, locales, phone number etc from
222EITHER the metadata hash returned by L<CGI::Wiki> OR the query
223parameters in a L<CGI> object, and packages them nicely for passing to
224templates or storing in L<CGI::Wiki> datastore.  If you supply both
225C<metadata> and C<cgi_obj> then C<metadata> will take precedence, but
226don't do that.
227
228The variables C<dist_field>, C<coord_field_1>, C<coord_field_1_name>,
229C<coord_field_1_value>, C<coord_field_2>, C<coord_field_2_name>, and
230C<coord_field_2_value>, which are used to create various forms, will
231only be set if I<either> C<metadata> is supplied I<or>
232C<set_coord_field_vars> is true, to prevent these values from being
233stored in the database on a node commit.
234
235=cut
236
237sub extract_metadata_vars {
238    my ($class, %args) = @_;
239    my %metadata = %{$args{metadata} || {} };
240    my $q = $args{cgi_obj};
241    my $formatter = $args{wiki}->formatter;
242    my $config = $args{config};
243    my $script_name = $config->script_name;
244
245    # Categories and locales are displayed as links in the page footer.
246    # We return these twice, as eg 'category' being a simple array of
247    # category names, but 'categories' being an array of hashrefs including
248    # a URL too.  This is ick.
249    my (@catlist, @loclist);
250    if ( $args{metadata} ) {
251        @catlist = @{ $metadata{category} || [] };
252        @loclist = @{ $metadata{locale}   || [] };
253    } else {
254        my $categories_text = $q->param('categories');
255        my $locales_text    = $q->param('locales');
256        @catlist = sort map { s/^\s+//; s/\s+$//; $_; } # trim lead/trail space
257                        split("\r\n", $categories_text);
258        @loclist = sort map { s/^\s+//; s/\s+$//; $_; } # trim lead/trail space
259                        split("\r\n", $locales_text);
260    }
261
262    my @categories = map { { name => $_,
263                             url  => "$script_name?Category_"
264            . uri_escape($formatter->node_name_to_node_param($_)) } } @catlist;
265
266    my @locales    = map { { name => $_,
267                             url  => "$script_name?Locale_"
268            . uri_escape($formatter->node_name_to_node_param($_)) } } @loclist;
269
270    # The 'website' attribute might contain a URL so we wiki-format it here
271    # rather than just CGI::escapeHTMLing it all in the template.
272    my $website = $args{metadata} ? $metadata{website}[0]
273                                  : $q->param("website");
274    my $formatted_website_text = "";
275    if ( $website ) {
276        $formatted_website_text = $class->format_website_text(
277            formatter => $formatter,
278            text      => $website
279        );
280    }
281
282    my $hours_text = $args{metadata} ? $metadata{opening_hours_text}[0]
283                                    : $q->param("hours_text");
284
285    my $summary = $args{metadata} ? $metadata{summary}[0]
286                                  : $q->param("summary");
287                                 
288    my %vars = (
289        categories             => \@categories,
290        locales                => \@locales,
291        category               => \@catlist,
292        locale                 => \@loclist,
293        formatted_website_text => $formatted_website_text,
294        hours_text             => $hours_text,
295        summary                => $summary,
296    );
297
298    if ( $args{metadata} ) {
299        foreach my $var ( qw( phone fax address postcode os_x os_y osie_x
300                              osie_y latitude longitude map_link website
301                              summary) ) {
302            $vars{$var} = $metadata{$var}[0];
303        }
304        # Data for the distance search forms on the node display.
305        my $geo_handler = $config->geo_handler;
306        if ( $geo_handler == 1 ) {
307            %vars = (
308                        %vars,
309                        coord_field_1       => "os_x",
310                        coord_field_2       => "os_y",
311                        dist_field          => "os_dist",
312                        coord_field_1_name  => "OS X coordinate",
313                        coord_field_2_name  => "OS Y coordinate",
314                        coord_field_1_value => $metadata{os_x}[0],
315                        coord_field_2_value => $metadata{os_y}[0],
316                    );
317        } elsif ( $geo_handler == 2 ) {
318            %vars = (
319                        %vars,
320                        coord_field_1       => "osie_x",
321                        coord_field_2       => "osie_y",
322                        dist_field          => "osie_dist",
323                        coord_field_1_name  =>"Irish National Grid X coordinate",
324                        coord_field_2_name  =>"Irish National Grid Y coordinate",
325                        coord_field_1_value => $metadata{osie_x}[0],
326                        coord_field_2_value => $metadata{osie_y}[0],
327                    );
328        } else {
329            %vars = (
330                        %vars,
331                        coord_field_1       => "latitude",
332                        coord_field_2       => "longitude",
333                        dist_field          => "latlong_dist",
334                        coord_field_1_name  => "Latitude (decimal)",
335                        coord_field_2_name  => "Longitude (decimal)",
336                        coord_field_1_value => $metadata{latitude}[0],
337                        coord_field_2_value => $metadata{longitude}[0],
338                    );
339        }
340    } else {
341        foreach my $var ( qw( phone fax address postcode map_link website summary) ) {
342            $vars{$var} = $q->param($var);
343        }
344
345        my $geo_handler = $config->geo_handler;
346        if ( $geo_handler == 1 ) {
347            require Geography::NationalGrid::GB;
348            my $os_x   = $q->param("os_x");
349            my $os_y   = $q->param("os_y");
350            my $lat    = $q->param("latitude");
351            my $long   = $q->param("longitude");
352
353            # Trim whitespace - trailing whitespace buggers up the
354            # integerification by postgres and it's an easy mistake to
355            # make when typing into a form.
356            $os_x =~ s/\s+//g;
357            $os_y =~ s/\s+//g;
358
359            # If we were sent x and y, work out lat/long; and vice versa.
360            if ( $os_x && $os_y ) {
361                my $point = Geography::NationalGrid::GB->new( Easting =>$os_x,
362                                     Northing=>$os_y);
363                $lat  = sprintf("%.6f", $point->latitude);
364                $long = sprintf("%.6f", $point->longitude);
365            } elsif ( $lat && $long ) {
366                my $point = Geography::NationalGrid::GB->new(Latitude  => $lat,
367                                                             Longitude => $long);
368                $os_x = $point->easting;
369                $os_y = $point->northing;
370            }
371           
372            if ( $os_x && $os_y ) {
373                %vars = (
374                            %vars,
375                            latitude  => $lat,
376                            longitude => $long,
377                            os_x      => $os_x,
378                            os_y      => $os_y,
379                        );
380            }
381            if ( $args{set_coord_field_vars} ) {
382                %vars = (
383                            %vars,
384                            coord_field_1       => "os_x",
385                            coord_field_2       => "os_y",
386                            dist_field          => "os_dist",
387                            coord_field_1_name  => "OS X coordinate",
388                            coord_field_2_name  => "OS Y coordinate",
389                            coord_field_1_value => $os_x,
390                            coord_field_2_value => $os_y,
391                        );
392            }
393        } elsif ( $geo_handler == 2 ) {
394            require Geography::NationalGrid::IE;
395            my $osie_x = $q->param("osie_x");
396            my $osie_y = $q->param("osie_y");
397            my $lat    = $q->param("latitude");
398            my $long   = $q->param("longitude");
399
400            # Trim whitespace.
401            $osie_x =~ s/\s+//g;
402            $osie_y =~ s/\s+//g;
403
404            # If we were sent x and y, work out lat/long; and vice versa.
405            if ( $osie_x && $osie_y ) {
406                my $point = Geography::NationalGrid::IE->new(Easting=>$osie_x,
407                                   Northing=>$osie_y);
408                $lat = sprintf("%.6f", $point->latitude);
409                $long = sprintf("%.6f", $point->longitude);
410            } elsif ( $lat && $long ) {
411                my $point = Geography::NationalGrid::GB->new(Latitude  => $lat,
412                                                             Longitude => $long);
413                $osie_x = $point->easting;
414                $osie_y = $point->northing;
415            }
416            if ( $osie_x && $osie_y ) {
417                %vars = (
418                            %vars,
419                            latitude  => $lat,
420                            longitude => $long,
421                            osie_x    => $osie_x,
422                            osie_y    => $osie_y,
423                        );
424            }
425            if ( $args{set_coord_field_vars} ) {
426                %vars = (
427                            %vars,
428                            coord_field_1       => "osie_x",
429                            coord_field_2       => "osie_y",
430                            dist_field          => "osie_dist",
431                            coord_field_1_name  => "Irish National Grid X coordinate",
432                            coord_field_2_name  => "Irish National Grid Y coordinate",
433                            coord_field_1_value => $osie_x,
434                            coord_field_2_value => $osie_y,
435                        );
436            }
437        } elsif ( $geo_handler == 3 ) {
438            require Geo::Coordinates::UTM;
439            my $lat    = $q->param("latitude");
440            my $long   = $q->param("longitude");
441           
442            if ( $lat && $long ) {
443                # Trim whitespace.
444                $lat =~ s/\s+//g;
445                $long =~ s/\s+//g;
446                my ($zone, $easting, $northing) =
447                 Geo::Coordinates::UTM::latlon_to_utm( $config->ellipsoid,
448                                                       $lat, $long );
449                $easting  =~ s/\..*//; # chop off decimal places
450                $northing =~ s/\..*//; # - metre accuracy enough
451                %vars = (
452                            %vars,
453                            latitude  => $lat,
454                            longitude => $long,
455                            easting   => $easting,
456                            northing  => $northing,
457                        );
458             }
459             if ( $args{set_coord_field_vars} ) {
460                %vars = (
461                            %vars,
462                            coord_field_1       => "latitude",
463                            coord_field_2       => "longitude",
464                            dist_field          => "latlong_dist",
465                            coord_field_1_name  => "Latitude (decimal)",
466                            coord_field_2_name  => "Longitude (decimal)",
467                            coord_field_1_value => $lat,
468                            coord_field_2_value => $long,
469                        );
470             }
471        }
472    }
473
474    # Check whether we need to munge lat and long.
475    # Store them unmunged as well so commit_node can get hold of them.
476    my %prefs = OpenGuides::CGI->get_prefs_from_cookie( config => $config );
477    if ( $prefs{latlong_traditional} ) {
478        foreach my $var ( qw( latitude longitude ) ) {
479            next unless defined $vars{$var};
480            $vars{$var."_unmunged"} = $vars{$var};
481            $vars{$var} = Geography::NationalGrid->deg2string($vars{$var});
482        }
483    }
484
485    return %vars;
486}
487
488sub format_website_text {
489    my ($class, %args) = @_;
490    my ($formatter, $text) = @args{ qw( formatter text ) };
491    my $formatted = $formatter->format($text);
492
493    # Strip out paragraph markers put in by formatter since we want this
494    # to be a single string to put in a <ul>.
495    $formatted =~ s/<p>//g;
496    $formatted =~ s/<\/p>//g;
497
498    return $formatted;
499}
500
501
502=back
503
504=head1 AUTHOR
505
506The OpenGuides Project (openguides-dev@openguides.org)
507
508=head1 COPYRIGHT
509
510  Copyright (C) 2003-2005 The OpenGuides Project.  All Rights Reserved.
511
512This module is free software; you can redistribute it and/or modify it
513under the same terms as Perl itself.
514
515=cut
516
5171;
Note: See TracBrowser for help on using the repository browser.