Merge remote-tracking branch 'origin/new/bug_8062'
[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 C4::Context;
32 use C4::Dates qw(format_date);
33 use C4::Budgets qw(GetCurrency);
34 use C4::Templates;
35
36 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
37
38 BEGIN {
39     # set the version for version checking
40     $VERSION = 3.07.00.049;
41     require Exporter;
42
43  @ISA    = qw(Exporter);
44     @EXPORT_OK = qw(&is_ajax ajax_fail); # More stuff should go here instead
45     %EXPORT_TAGS = ( all =>[qw(&themelanguage &gettemplate setlanguagecookie pagination_bar
46                                 &output_with_http_headers &output_ajax_with_http_headers &output_html_with_http_headers)],
47                     ajax =>[qw(&output_with_http_headers &output_ajax_with_http_headers is_ajax)],
48                     html =>[qw(&output_with_http_headers &output_html_with_http_headers)]
49                 );
50     push @EXPORT, qw(
51         &themelanguage &gettemplate setlanguagecookie getlanguagecookie pagination_bar
52     );
53     push @EXPORT, qw(
54         &output_html_with_http_headers &output_ajax_with_http_headers &output_with_http_headers FormatData FormatNumber
55     );
56
57 }
58
59 =head1 NAME
60
61 C4::Output - Functions for managing output, is slowly being deprecated
62
63 =head1 FUNCTIONS
64
65 =over 2
66 =cut
67
68 =item FormatNumber
69 =cut
70 sub FormatNumber{
71 my $cur  =  GetCurrency;
72 my $cur_format = C4::Context->preference("CurrencyFormat");
73 my $num;
74
75 if ( $cur_format eq 'FR' ) {
76     $num = new Number::Format(
77         'decimal_fill'      => '2',
78         'decimal_point'     => ',',
79         'int_curr_symbol'   => $cur->{symbol},
80         'mon_thousands_sep' => ' ',
81         'thousands_sep'     => ' ',
82         'mon_decimal_point' => ','
83     );
84 } else {  # US by default..
85     $num = new Number::Format(
86         'int_curr_symbol'   => '',
87         'mon_thousands_sep' => ',',
88         'mon_decimal_point' => '.'
89     );
90 }
91 return $num;
92 }
93
94 =item FormatData
95
96 FormatData($data_hashref)
97 C<$data_hashref> is a ref to data to format
98
99 Format dates of data those dates are assumed to contain date in their noun
100 Could be used in order to centralize all the formatting for HTML output
101 =cut
102
103 sub FormatData{
104                 my $data_hashref=shift;
105         $$data_hashref{$_} = format_date( $$data_hashref{$_} ) for grep{/date/} keys (%$data_hashref);
106 }
107
108 =item pagination_bar
109
110    pagination_bar($base_url, $nb_pages, $current_page, $startfrom_name)
111
112 Build an HTML pagination bar based on the number of page to display, the
113 current page and the url to give to each page link.
114
115 C<$base_url> is the URL for each page link. The
116 C<$startfrom_name>=page_number is added at the end of the each URL.
117
118 C<$nb_pages> is the total number of pages available.
119
120 C<$current_page> is the current page number. This page number won't become a
121 link.
122
123 This function returns HTML, without any language dependency.
124
125 =cut
126
127 sub pagination_bar {
128         my $base_url = (@_ ? shift : $ENV{SCRIPT_NAME} . $ENV{QUERY_STRING}) or return undef;
129     my $nb_pages       = (@_) ? shift : 1;
130     my $current_page   = (@_) ? shift : undef;  # delay default until later
131     my $startfrom_name = (@_) ? shift : 'page';
132
133     # how many pages to show before and after the current page?
134     my $pages_around = 2;
135
136         my $delim = qr/\&(?:amp;)?|;/;          # "non memory" cluster: no backreference
137         $base_url =~ s/$delim*\b$startfrom_name=(\d+)//g; # remove previous pagination var
138     unless (defined $current_page and $current_page > 0 and $current_page <= $nb_pages) {
139         $current_page = ($1) ? $1 : 1;  # pull current page from param in URL, else default to 1
140                 # $debug and    # FIXME: use C4::Debug;
141                 # warn "with QUERY_STRING:" .$ENV{QUERY_STRING}. "\ncurrent_page:$current_page\n1:$1  2:$2  3:$3";
142     }
143         $base_url =~ s/($delim)+/$1/g;  # compress duplicate delims
144         $base_url =~ s/$delim;//g;              # remove empties
145         $base_url =~ s/$delim$//;               # remove trailing delim
146
147     my $url = $base_url . (($base_url =~ m/$delim/ or $base_url =~ m/\?/) ? '&amp;' : '?' ) . $startfrom_name . '=';
148     my $pagination_bar = '';
149
150     # navigation bar useful only if more than one page to display !
151     if ( $nb_pages > 1 ) {
152
153         # link to first page?
154         if ( $current_page > 1 ) {
155             $pagination_bar .=
156                 "\n" . '&nbsp;'
157               . '<a href="'
158               . $url
159               . '1" rel="start">'
160               . '&lt;&lt;' . '</a>';
161         }
162         else {
163             $pagination_bar .=
164               "\n" . '&nbsp;<span class="inactive">&lt;&lt;</span>';
165         }
166
167         # link on previous page ?
168         if ( $current_page > 1 ) {
169             my $previous = $current_page - 1;
170
171             $pagination_bar .=
172                 "\n" . '&nbsp;'
173               . '<a href="'
174               . $url
175               . $previous
176               . '" rel="prev">' . '&lt;' . '</a>';
177         }
178         else {
179             $pagination_bar .=
180               "\n" . '&nbsp;<span class="inactive">&lt;</span>';
181         }
182
183         my $min_to_display      = $current_page - $pages_around;
184         my $max_to_display      = $current_page + $pages_around;
185         my $last_displayed_page = undef;
186
187         for my $page_number ( 1 .. $nb_pages ) {
188             if (
189                    $page_number == 1
190                 or $page_number == $nb_pages
191                 or (    $page_number >= $min_to_display
192                     and $page_number <= $max_to_display )
193               )
194             {
195                 if ( defined $last_displayed_page
196                     and $last_displayed_page != $page_number - 1 )
197                 {
198                     $pagination_bar .=
199                       "\n" . '&nbsp;<span class="inactive">...</span>';
200                 }
201
202                 if ( $page_number == $current_page ) {
203                     $pagination_bar .=
204                         "\n" . '&nbsp;'
205                       . '<span class="currentPage">'
206                       . $page_number
207                       . '</span>';
208                 }
209                 else {
210                     $pagination_bar .=
211                         "\n" . '&nbsp;'
212                       . '<a href="'
213                       . $url
214                       . $page_number . '">'
215                       . $page_number . '</a>';
216                 }
217                 $last_displayed_page = $page_number;
218             }
219         }
220
221         # link on next page?
222         if ( $current_page < $nb_pages ) {
223             my $next = $current_page + 1;
224
225             $pagination_bar .= "\n"
226               . '&nbsp;<a href="'
227               . $url
228               . $next
229               . '" rel="next">' . '&gt;' . '</a>';
230         }
231         else {
232             $pagination_bar .=
233               "\n" . '&nbsp;<span class="inactive">&gt;</span>';
234         }
235
236         # link to last page?
237         if ( $current_page != $nb_pages ) {
238             $pagination_bar .= "\n"
239               . '&nbsp;<a href="'
240               . $url
241               . $nb_pages
242               . '" rel="last">'
243               . '&gt;&gt;' . '</a>';
244         }
245         else {
246             $pagination_bar .=
247               "\n" . '&nbsp;<span class="inactive">&gt;&gt;</span>';
248         }
249     }
250
251     return $pagination_bar;
252 }
253
254 =item output_with_http_headers
255
256    &output_with_http_headers($query, $cookie, $data, $content_type[, $status])
257
258 Outputs $data with the appropriate HTTP headers,
259 the authentication cookie $cookie and a Content-Type specified in
260 $content_type.
261
262 If applicable, $cookie can be undef, and it will not be sent.
263
264 $content_type is one of the following: 'html', 'js', 'json', 'xml', 'rss', or 'atom'.
265
266 $status is an HTTP status message, like '403 Authentication Required'. It defaults to '200 OK'.
267
268 =cut
269
270 sub output_with_http_headers($$$$;$) {
271     my ( $query, $cookie, $data, $content_type, $status ) = @_;
272     $status ||= '200 OK';
273
274     my %content_type_map = (
275         'html' => 'text/html',
276         'js'   => 'text/javascript',
277         'json' => 'application/json',
278         'xml'  => 'text/xml',
279         # NOTE: not using application/atom+xml or application/rss+xml because of
280         # Internet Explorer 6; see bug 2078.
281         'rss'  => 'text/xml',
282         'atom' => 'text/xml'
283     );
284
285     die "Unknown content type '$content_type'" if ( !defined( $content_type_map{$content_type} ) );
286     my $options = {
287         type    => $content_type_map{$content_type},
288         status  => $status,
289         charset => 'UTF-8',
290         Pragma          => 'no-cache',
291         'Cache-Control' => 'no-cache',
292     };
293     $options->{cookie} = $cookie if $cookie;
294     if ($content_type eq 'html') {  # guaranteed to be one of the content_type_map keys, else we'd have died
295         $options->{'Content-Style-Type' } = 'text/css';
296         $options->{'Content-Script-Type'} = 'text/javascript';
297     }
298
299 # We can't encode here, that will double encode our templates, and xslt
300 # We need to fix the encoding as it comes out of the database, or when we pass the variables to templates
301  
302 #    utf8::encode($data) if utf8::is_utf8($data);
303
304     $data =~ s/\&amp\;amp\; /\&amp\; /g;
305     print $query->header($options), $data;
306 }
307
308 sub output_html_with_http_headers ($$$;$) {
309     my ( $query, $cookie, $data, $status ) = @_;
310     output_with_http_headers( $query, $cookie, $data, 'html', $status );
311 }
312
313
314 sub output_ajax_with_http_headers {
315     my ( $query, $js ) = @_;
316     print $query->header(
317         -type            => 'text/javascript',
318         -charset         => 'UTF-8',
319         -Pragma          => 'no-cache',
320         -'Cache-Control' => 'no-cache',
321         -expires         => '-1d',
322     ), $js;
323 }
324
325 sub is_ajax {
326     my $x_req = $ENV{HTTP_X_REQUESTED_WITH};
327     return ( $x_req and $x_req =~ /XMLHttpRequest/i ) ? 1 : 0;
328 }
329
330 END { }    # module clean-up code here (global destructor)
331
332 1;
333 __END__
334
335 =back
336
337 =head1 AUTHOR
338
339 Koha Development Team <http://koha-community.org/>
340
341 =cut