Bug 13133: Fix mangled titles on pay fines page
[koha.git] / C4 / Output.pm
1 package C4::Output;
2
3 #package to deal with marking up output
4 #You will need to edit parts of this pm
5 #set the value of path to be where your html lives
6
7 # Copyright 2000-2002 Katipo Communications
8 #
9 # This file is part of Koha.
10 #
11 # Koha is free software; you can redistribute it and/or modify it under the
12 # terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
14 # version.
15 #
16 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
17 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License along
21 # with Koha; if not, write to the Free Software Foundation, Inc.,
22 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
24
25 # NOTE: I'm pretty sure this module is deprecated in favor of
26 # templates.
27
28 use strict;
29 #use warnings; FIXME - Bug 2505
30
31 use URI::Escape;
32
33 use C4::Context;
34 use C4::Dates qw(format_date);
35 use C4::Budgets qw(GetCurrency);
36 use C4::Templates;
37
38 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
39
40 BEGIN {
41     # set the version for version checking
42     $VERSION = 3.07.00.049;
43     require Exporter;
44
45  @ISA    = qw(Exporter);
46     @EXPORT_OK = qw(&is_ajax ajax_fail); # More stuff should go here instead
47     %EXPORT_TAGS = ( all =>[qw(setlanguagecookie pagination_bar parametrized_url
48                                 &output_with_http_headers &output_ajax_with_http_headers &output_html_with_http_headers)],
49                     ajax =>[qw(&output_with_http_headers &output_ajax_with_http_headers is_ajax)],
50                     html =>[qw(&output_with_http_headers &output_html_with_http_headers)]
51                 );
52     push @EXPORT, qw(
53         setlanguagecookie getlanguagecookie pagination_bar parametrized_url
54     );
55     push @EXPORT, qw(
56         &output_html_with_http_headers &output_ajax_with_http_headers &output_with_http_headers FormatData
57     );
58
59 }
60
61 =head1 NAME
62
63 C4::Output - Functions for managing output, is slowly being deprecated
64
65 =head1 FUNCTIONS
66
67 =over 2
68 =cut
69
70 =item FormatData
71
72 FormatData($data_hashref)
73 C<$data_hashref> is a ref to data to format
74
75 Format dates of data those dates are assumed to contain date in their noun
76 Could be used in order to centralize all the formatting for HTML output
77 =cut
78
79 sub FormatData{
80                 my $data_hashref=shift;
81         $$data_hashref{$_} = format_date( $$data_hashref{$_} ) for grep{/date/} keys (%$data_hashref);
82 }
83
84 =item pagination_bar
85
86    pagination_bar($base_url, $nb_pages, $current_page, $startfrom_name)
87
88 Build an HTML pagination bar based on the number of page to display, the
89 current page and the url to give to each page link.
90
91 C<$base_url> is the URL for each page link. The
92 C<$startfrom_name>=page_number is added at the end of the each URL.
93
94 C<$nb_pages> is the total number of pages available.
95
96 C<$current_page> is the current page number. This page number won't become a
97 link.
98
99 This function returns HTML, without any language dependency.
100
101 =cut
102
103 sub pagination_bar {
104         my $base_url = (@_ ? shift : $ENV{SCRIPT_NAME} . $ENV{QUERY_STRING}) or return;
105     my $nb_pages       = (@_) ? shift : 1;
106     my $current_page   = (@_) ? shift : undef;  # delay default until later
107     my $startfrom_name = (@_) ? shift : 'page';
108
109     # how many pages to show before and after the current page?
110     my $pages_around = 2;
111
112         my $delim = qr/\&(?:amp;)?|;/;          # "non memory" cluster: no backreference
113         $base_url =~ s/$delim*\b$startfrom_name=(\d+)//g; # remove previous pagination var
114     unless (defined $current_page and $current_page > 0 and $current_page <= $nb_pages) {
115         $current_page = ($1) ? $1 : 1;  # pull current page from param in URL, else default to 1
116                 # $debug and    # FIXME: use C4::Debug;
117                 # warn "with QUERY_STRING:" .$ENV{QUERY_STRING}. "\ncurrent_page:$current_page\n1:$1  2:$2  3:$3";
118     }
119         $base_url =~ s/($delim)+/$1/g;  # compress duplicate delims
120         $base_url =~ s/$delim;//g;              # remove empties
121         $base_url =~ s/$delim$//;               # remove trailing delim
122
123     my $url = $base_url . (($base_url =~ m/$delim/ or $base_url =~ m/\?/) ? '&amp;' : '?' ) . $startfrom_name . '=';
124     my $pagination_bar = '';
125
126     # navigation bar useful only if more than one page to display !
127     if ( $nb_pages > 1 ) {
128
129         # link to first page?
130         if ( $current_page > 1 ) {
131             $pagination_bar .=
132                 "\n" . '&nbsp;'
133               . '<a href="'
134               . $url
135               . '1" rel="start">'
136               . '&lt;&lt;' . '</a>';
137         }
138         else {
139             $pagination_bar .=
140               "\n" . '&nbsp;<span class="inactive">&lt;&lt;</span>';
141         }
142
143         # link on previous page ?
144         if ( $current_page > 1 ) {
145             my $previous = $current_page - 1;
146
147             $pagination_bar .=
148                 "\n" . '&nbsp;'
149               . '<a href="'
150               . $url
151               . $previous
152               . '" rel="prev">' . '&lt;' . '</a>';
153         }
154         else {
155             $pagination_bar .=
156               "\n" . '&nbsp;<span class="inactive">&lt;</span>';
157         }
158
159         my $min_to_display      = $current_page - $pages_around;
160         my $max_to_display      = $current_page + $pages_around;
161         my $last_displayed_page = undef;
162
163         for my $page_number ( 1 .. $nb_pages ) {
164             if (
165                    $page_number == 1
166                 or $page_number == $nb_pages
167                 or (    $page_number >= $min_to_display
168                     and $page_number <= $max_to_display )
169               )
170             {
171                 if ( defined $last_displayed_page
172                     and $last_displayed_page != $page_number - 1 )
173                 {
174                     $pagination_bar .=
175                       "\n" . '&nbsp;<span class="inactive">...</span>';
176                 }
177
178                 if ( $page_number == $current_page ) {
179                     $pagination_bar .=
180                         "\n" . '&nbsp;'
181                       . '<span class="currentPage">'
182                       . $page_number
183                       . '</span>';
184                 }
185                 else {
186                     $pagination_bar .=
187                         "\n" . '&nbsp;'
188                       . '<a href="'
189                       . $url
190                       . $page_number . '">'
191                       . $page_number . '</a>';
192                 }
193                 $last_displayed_page = $page_number;
194             }
195         }
196
197         # link on next page?
198         if ( $current_page < $nb_pages ) {
199             my $next = $current_page + 1;
200
201             $pagination_bar .= "\n"
202               . '&nbsp;<a href="'
203               . $url
204               . $next
205               . '" rel="next">' . '&gt;' . '</a>';
206         }
207         else {
208             $pagination_bar .=
209               "\n" . '&nbsp;<span class="inactive">&gt;</span>';
210         }
211
212         # link to last page?
213         if ( $current_page != $nb_pages ) {
214             $pagination_bar .= "\n"
215               . '&nbsp;<a href="'
216               . $url
217               . $nb_pages
218               . '" rel="last">'
219               . '&gt;&gt;' . '</a>';
220         }
221         else {
222             $pagination_bar .=
223               "\n" . '&nbsp;<span class="inactive">&gt;&gt;</span>';
224         }
225     }
226
227     return $pagination_bar;
228 }
229
230 =item output_with_http_headers
231
232    &output_with_http_headers($query, $cookie, $data, $content_type[, $status[, $extra_options]])
233
234 Outputs $data with the appropriate HTTP headers,
235 the authentication cookie $cookie and a Content-Type specified in
236 $content_type.
237
238 If applicable, $cookie can be undef, and it will not be sent.
239
240 $content_type is one of the following: 'html', 'js', 'json', 'xml', 'rss', or 'atom'.
241
242 $status is an HTTP status message, like '403 Authentication Required'. It defaults to '200 OK'.
243
244 $extra_options is hashref.  If the key 'force_no_caching' is present and has
245 a true value, the HTTP headers include directives to force there to be no
246 caching whatsoever.
247
248 =cut
249
250 sub output_with_http_headers {
251     my ( $query, $cookie, $data, $content_type, $status, $extra_options ) = @_;
252     $status ||= '200 OK';
253
254     $extra_options //= {};
255
256     my %content_type_map = (
257         'html' => 'text/html',
258         'js'   => 'text/javascript',
259         'json' => 'application/json',
260         'xml'  => 'text/xml',
261         # NOTE: not using application/atom+xml or application/rss+xml because of
262         # Internet Explorer 6; see bug 2078.
263         'rss'  => 'text/xml',
264         'atom' => 'text/xml'
265     );
266
267     die "Unknown content type '$content_type'" if ( !defined( $content_type_map{$content_type} ) );
268     my $cache_policy = 'no-cache';
269     $cache_policy .= ', no-store, max-age=0' if $extra_options->{force_no_caching};
270     my $options = {
271         type    => $content_type_map{$content_type},
272         status  => $status,
273         charset => 'UTF-8',
274         Pragma          => 'no-cache',
275         'Cache-Control' => $cache_policy,
276     };
277     $options->{expires} = 'now' if $extra_options->{force_no_caching};
278
279     $options->{cookie} = $cookie if $cookie;
280     if ($content_type eq 'html') {  # guaranteed to be one of the content_type_map keys, else we'd have died
281         $options->{'Content-Style-Type' } = 'text/css';
282         $options->{'Content-Script-Type'} = 'text/javascript';
283     }
284
285 # We can't encode here, that will double encode our templates, and xslt
286 # We need to fix the encoding as it comes out of the database, or when we pass the variables to templates
287  
288 #    utf8::encode($data) if utf8::is_utf8($data);
289
290     $data =~ s/\&amp\;amp\; /\&amp\; /g;
291     print $query->header($options), $data;
292 }
293
294 sub output_html_with_http_headers {
295     my ( $query, $cookie, $data, $status, $extra_options ) = @_;
296     output_with_http_headers( $query, $cookie, $data, 'html', $status, $extra_options );
297 }
298
299
300 sub output_ajax_with_http_headers {
301     my ( $query, $js ) = @_;
302     print $query->header(
303         -type            => 'text/javascript',
304         -charset         => 'UTF-8',
305         -Pragma          => 'no-cache',
306         -'Cache-Control' => 'no-cache',
307         -expires         => '-1d',
308     ), $js;
309 }
310
311 sub is_ajax {
312     my $x_req = $ENV{HTTP_X_REQUESTED_WITH};
313     return ( $x_req and $x_req =~ /XMLHttpRequest/i ) ? 1 : 0;
314 }
315
316 sub parametrized_url {
317     my $url = shift || ''; # ie page.pl?ln={LANG}
318     my $vars = shift || {}; # ie { LANG => en }
319     my $ret = $url;
320     while ( my ($key,$val) = each %$vars) {
321         my $val_url = URI::Escape::uri_escape_utf8($val);
322         $ret =~ s/\{$key\}/$val_url/g;
323     }
324     $ret =~ s/\{[^\{]*\}//g; # remove not defined vars
325     return $ret;
326 }
327
328 END { }    # module clean-up code here (global destructor)
329
330 1;
331 __END__
332
333 =back
334
335 =head1 AUTHOR
336
337 Koha Development Team <http://koha-community.org/>
338
339 =cut