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
7 # Copyright 2000-2002 Katipo Communications
9 # This file is part of Koha.
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
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.
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.
25 # NOTE: I'm pretty sure this module is deprecated in favor of
29 #use warnings; FIXME - Bug 2505
32 use C4::Languages qw(getTranslatedLanguages get_bidi regex_lang_subtags language_get_description accept_language );
33 use C4::Dates qw(format_date);
34 use C4::Budgets qw(GetCurrency);
36 use HTML::Template::Pro;
37 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
40 # set the version for version checking
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_html_with_http_headers)],
47 ajax =>[qw(&output_with_http_headers is_ajax)],
48 html =>[qw(&output_with_http_headers &output_html_with_http_headers)]
51 &themelanguage &gettemplate setlanguagecookie getlanguagecookie pagination_bar
54 &output_html_with_http_headers &output_with_http_headers FormatData FormatNumber
60 C4::Output - Functions for managing templates
68 #FIXME: this is a quick fix to stop rc1 installing broken
69 #Still trying to figure out the correct fix.
70 my $path = C4::Context->config('intrahtdocs') . "/prog/en/includes/";
72 #---------------------------------------------------------------------------------------------------------
75 sub _get_template_file {
76 my ( $tmplbase, $interface, $query ) = @_;
77 my $htdocs = C4::Context->config( $interface ne 'intranet' ? 'opachtdocs' : 'intrahtdocs' );
78 my ( $theme, $lang ) = themelanguage( $htdocs, $tmplbase, $interface, $query );
79 my $opacstylesheet = C4::Context->preference('opacstylesheet');
81 # if the template doesn't exist, load the English one as a last resort
82 my $filename = "$htdocs/$theme/$lang/modules/$tmplbase";
83 unless (-f $filename) {
85 $filename = "$htdocs/$theme/$lang/modules/$tmplbase";
88 return ( $htdocs, $theme, $lang, $filename );
92 my ( $tmplbase, $interface, $query ) = @_;
93 ($query) or warn "no query in gettemplate";
94 my $path = C4::Context->preference('intranet_includes') || 'includes';
95 my $opacstylesheet = C4::Context->preference('opacstylesheet');
96 my ( $htdocs, $theme, $lang, $filename ) = _get_template_file( $tmplbase, $interface, $query );
98 my $template = HTML::Template::Pro->new(
99 filename => $filename,
100 die_on_bad_params => 1,
103 loop_context_vars => 1, # enable: __first__, __last__, __inner__, __odd__, __counter__
104 path => ["$htdocs/$theme/$lang/$path"]
106 my $themelang=( $interface ne 'intranet' ? '/opac-tmpl' : '/intranet-tmpl' )
109 themelang => $themelang,
110 yuipath => (C4::Context->preference("yuipath") eq "local"?"$themelang/lib/yui":C4::Context->preference("yuipath")),
111 interface => ( $interface ne 'intranet' ? '/opac-tmpl' : '/intranet-tmpl' ),
117 my $current_lang = regex_lang_subtags($lang);
119 $bidi = get_bidi($current_lang->{script}) if $current_lang->{script};
121 my $languages_loop = getTranslatedLanguages($interface,$theme,$lang);
122 my $num_languages_enabled = 0;
123 foreach my $lang (@$languages_loop) {
124 foreach my $sublang (@{ $lang->{'sublanguages_loop'} }) {
125 $num_languages_enabled++ if $sublang->{enabled};
129 languages_loop => $languages_loop,
131 one_language_enabled => ($num_languages_enabled <= 1) ? 1 : 0, # deal with zero enabled langs as well
132 ) unless @$languages_loop<2;
137 #---------------------------------------------------------------------------------------------------------
140 my ( $htdocs, $tmpl, $interface, $query ) = @_;
141 ($query) or warn "no query in themelanguage";
143 # Set some defaults for language and theme
144 # First, check the user's preferences
146 my $http_accept_language = $ENV{ HTTP_ACCEPT_LANGUAGE };
147 $lang = accept_language( $http_accept_language,
148 getTranslatedLanguages($interface,'prog') )
149 if $http_accept_language;
150 # But, if there's a cookie set, obey it
151 $lang = $query->cookie('KohaOpacLanguage') if (defined $query and $query->cookie('KohaOpacLanguage'));
152 # Fall back to English
154 if ($interface eq 'intranet') {
155 @languages = split ",", C4::Context->preference("language");
157 @languages = split ",", C4::Context->preference("opaclanguages");
160 @languages=($lang,@languages);
162 $lang = $languages[0];
164 my $theme = 'prog'; # in the event of theme failure default to 'prog' -fbcit
165 my $dbh = C4::Context->dbh;
167 if ( $interface eq "intranet" ) {
168 @themes = split " ", C4::Context->preference("template");
171 # we are in the opac here, what im trying to do is let the individual user
172 # set the theme they want to use.
173 # and perhaps the them as well.
174 #my $lang = $query->cookie('KohaOpacLanguage');
175 @themes = split " ", C4::Context->preference("opacthemes");
178 # searches through the themes and languages. First template it find it returns.
179 # Priority is for getting the theme right.
181 foreach my $th (@themes) {
182 foreach my $la (@languages) {
183 #for ( my $pass = 1 ; $pass <= 2 ; $pass += 1 ) {
184 # warn "$htdocs/$th/$la/modules/$interface-"."tmpl";
185 #$la =~ s/([-_])/ $1 eq '-'? '_': '-' /eg if $pass == 2;
186 if ( -e "$htdocs/$th/$la/modules/$tmpl") {
187 #".($interface eq 'intranet'?"modules":"")."/$tmpl" ) {
192 last unless $la =~ /[-_]/;
196 return ( $theme, $lang );
199 sub setlanguagecookie {
200 my ( $query, $language, $uri ) = @_;
201 my $cookie = $query->cookie(
202 -name => 'KohaOpacLanguage',
206 print $query->redirect(
212 sub getlanguagecookie {
215 if ($query->cookie('KohaOpacLanguage')){
216 $lang = $query->cookie('KohaOpacLanguage') ;
218 $lang = $ENV{HTTP_ACCEPT_LANGUAGE};
221 $lang = substr($lang, 0, 2);
229 my $cur = GetCurrency;
230 my $cur_format = C4::Context->preference("CurrencyFormat");
233 if ( $cur_format eq 'FR' ) {
234 $num = new Number::Format(
235 'decimal_fill' => '2',
236 'decimal_point' => ',',
237 'int_curr_symbol' => $cur->{symbol},
238 'mon_thousands_sep' => ' ',
239 'thousands_sep' => ' ',
240 'mon_decimal_point' => ','
242 } else { # US by default..
243 $num = new Number::Format(
244 'int_curr_symbol' => '',
245 'mon_thousands_sep' => ',',
246 'mon_decimal_point' => '.'
254 FormatData($data_hashref)
255 C<$data_hashref> is a ref to data to format
257 Format dates of data those dates are assumed to contain date in their noun
258 Could be used in order to centralize all the formatting for HTML output
262 my $data_hashref=shift;
263 $$data_hashref{$_} = format_date( $$data_hashref{$_} ) for grep{/date/} keys (%$data_hashref);
268 pagination_bar($base_url, $nb_pages, $current_page, $startfrom_name)
270 Build an HTML pagination bar based on the number of page to display, the
271 current page and the url to give to each page link.
273 C<$base_url> is the URL for each page link. The
274 C<$startfrom_name>=page_number is added at the end of the each URL.
276 C<$nb_pages> is the total number of pages available.
278 C<$current_page> is the current page number. This page number won't become a
281 This function returns HTML, without any language dependency.
286 my $base_url = (@_ ? shift : $ENV{SCRIPT_NAME} . $ENV{QUERY_STRING}) or return undef;
287 my $nb_pages = (@_) ? shift : 1;
288 my $current_page = (@_) ? shift : undef; # delay default until later
289 my $startfrom_name = (@_) ? shift : 'page';
291 # how many pages to show before and after the current page?
292 my $pages_around = 2;
294 my $delim = qr/\&(?:amp;)?|;/; # "non memory" cluster: no backreference
295 $base_url =~ s/$delim*\b$startfrom_name=(\d+)//g; # remove previous pagination var
296 unless (defined $current_page and $current_page > 0 and $current_page <= $nb_pages) {
297 $current_page = ($1) ? $1 : 1; # pull current page from param in URL, else default to 1
298 # $debug and # FIXME: use C4::Debug;
299 # warn "with QUERY_STRING:" .$ENV{QUERY_STRING}. "\ncurrent_page:$current_page\n1:$1 2:$2 3:$3";
301 $base_url =~ s/($delim)+/$1/g; # compress duplicate delims
302 $base_url =~ s/$delim;//g; # remove empties
303 $base_url =~ s/$delim$//; # remove trailing delim
305 my $url = $base_url . (($base_url =~ m/$delim/ or $base_url =~ m/\?/) ? '&' : '?' ) . $startfrom_name . '=';
306 my $pagination_bar = '';
308 # navigation bar useful only if more than one page to display !
309 if ( $nb_pages > 1 ) {
311 # link to first page?
312 if ( $current_page > 1 ) {
318 . '<<' . '</a>';
322 "\n" . ' <span class="inactive"><<</span>';
325 # link on previous page ?
326 if ( $current_page > 1 ) {
327 my $previous = $current_page - 1;
334 . '" rel="prev">' . '<' . '</a>';
338 "\n" . ' <span class="inactive"><</span>';
341 my $min_to_display = $current_page - $pages_around;
342 my $max_to_display = $current_page + $pages_around;
343 my $last_displayed_page = undef;
345 for my $page_number ( 1 .. $nb_pages ) {
348 or $page_number == $nb_pages
349 or ( $page_number >= $min_to_display
350 and $page_number <= $max_to_display )
353 if ( defined $last_displayed_page
354 and $last_displayed_page != $page_number - 1 )
357 "\n" . ' <span class="inactive">...</span>';
360 if ( $page_number == $current_page ) {
363 . '<span class="currentPage">'
372 . $page_number . '">'
373 . $page_number . '</a>';
375 $last_displayed_page = $page_number;
380 if ( $current_page < $nb_pages ) {
381 my $next = $current_page + 1;
383 $pagination_bar .= "\n"
387 . '" rel="next">' . '>' . '</a>';
391 "\n" . ' <span class="inactive">></span>';
395 if ( $current_page != $nb_pages ) {
396 $pagination_bar .= "\n"
401 . '>>' . '</a>';
405 "\n" . ' <span class="inactive">>></span>';
409 return $pagination_bar;
412 =item output_with_http_headers
414 &output_with_http_headers($query, $cookie, $data, $content_type[, $status])
416 Outputs $data with the appropriate HTTP headers,
417 the authentication cookie $cookie and a Content-Type specified in
420 If applicable, $cookie can be undef, and it will not be sent.
422 $content_type is one of the following: 'html', 'js', 'json', 'xml', 'rss', or 'atom'.
424 $status is an HTTP status message, like '403 Authentication Required'. It defaults to '200 OK'.
428 sub output_with_http_headers($$$$;$) {
429 my ( $query, $cookie, $data, $content_type, $status ) = @_;
430 $status ||= '200 OK';
432 my %content_type_map = (
433 'html' => 'text/html',
434 'js' => 'text/javascript',
435 'json' => 'application/json',
437 # NOTE: not using application/atom+xml or application/rss+xml because of
438 # Internet Explorer 6; see bug 2078.
443 die "Unknown content type '$content_type'" if ( !defined( $content_type_map{$content_type} ) );
445 type => $content_type_map{$content_type},
448 Pragma => 'no-cache',
449 'Cache-Control' => 'no-cache',
451 $options->{cookie} = $cookie if $cookie;
452 if ($content_type eq 'html') { # guaranteed to be one of the content_type_map keys, else we'd have died
453 $options->{'Content-Style-Type' } = 'text/css';
454 $options->{'Content-Script-Type'} = 'text/javascript';
456 # remove SUDOC specific NSB NSE
457 $data =~ s/\x{C2}\x{98}|\x{C2}\x{9C}/ /g;
458 $data =~ s/\x{C2}\x{88}|\x{C2}\x{89}/ /g;
459 print $query->header($options), $data;
462 sub output_html_with_http_headers ($$$;$) {
463 my ( $query, $cookie, $data, $status ) = @_;
464 $data =~ s/\&\;amp\; /\&\; /;
465 output_with_http_headers( $query, $cookie, $data, 'html', $status );
469 my $x_req = $ENV{HTTP_X_REQUESTED_WITH};
470 return ( $x_req and $x_req =~ /XMLHttpRequest/i ) ? 1 : 0;
473 END { } # module clean-up code here (global destructor)
482 Koha Developement team <info@koha.org>