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