From f938a52e47c9870e3c236bad1fbd9cb40ef8230f Mon Sep 17 00:00:00 2001
From: Fridolyn SOMERS <fridolyn.somers@biblibre.com>
Date: Wed, 27 Mar 2013 16:37:36 +0100
Subject: [PATCH] Bug 9579 - Incorrect display in truncated facets
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When a facet label is truncated and ends with a non-ASCII character, this label shows a <?> (broken character).

This patch moves facet label truncation from C4 to templates.
It adds a new template filter TruncateByWord, see http://search.cpan.org/~kawabata/Template-Plugin-TruncateByWord-0.11/
Note that existing TT filter "truncate()" has the problem with unicode.

Test plan :
- Perform a search
- Look for a facet label with a diacritic. For example "Médiathèque"
- Set syspref  FacetLabelTruncationLength so that facet label ends on a diacritic, in our example '8'
- Look at facettes in intranet and opac
=> Facet label is correct. In our example : "Médiathè..."
---
 C4/Search.pm                                       |   10 --
 Koha/Template/Plugin/TruncateByWord.pm             |  100 ++++++++++++++++++++
 catalogue/search.pl                                |    1 +
 .../intranet-tmpl/prog/en/includes/facets.inc      |    4 +-
 .../opac-tmpl/prog/en/includes/opac-facets.inc     |    4 +-
 opac/opac-search.pl                                |    1 +
 6 files changed, 108 insertions(+), 12 deletions(-)
 create mode 100644 Koha/Template/Plugin/TruncateByWord.pm

diff --git a/C4/Search.pm b/C4/Search.pm
index d3d3ce1..370ff1e 100644
--- a/C4/Search.pm
+++ b/C4/Search.pm
@@ -573,17 +573,7 @@ sub getRecords {
                                 my $facet_link_value = $one_facet;
                                 $facet_link_value =~ s/[()!?¡¿؟]/ /g;
 
-                                # fix the length that will display in the label,
                                 my $facet_label_value = $one_facet;
-                                my $facet_max_length  = C4::Context->preference(
-                                    'FacetLabelTruncationLength')
-                                  || 20;
-                                $facet_label_value =
-                                  substr( $one_facet, 0, $facet_max_length )
-                                  . "..."
-                                  if length($facet_label_value) >
-                                      $facet_max_length;
-
                             # if it's a branch, label by the name, not the code,
                                 if ( $link_value =~ /branch/ ) {
                                     if (   defined $branches
diff --git a/Koha/Template/Plugin/TruncateByWord.pm b/Koha/Template/Plugin/TruncateByWord.pm
new file mode 100644
index 0000000..5799260
--- /dev/null
+++ b/Koha/Template/Plugin/TruncateByWord.pm
@@ -0,0 +1,100 @@
+#
+# $Id: TruncateByWord.pm,v 1.3 2008/06/20 06:17:12 oneroad Exp $
+#
+package Koha::Template::Plugin::TruncateByWord;
+
+use strict;
+use warnings;
+
+our $VERSION = '0.11';
+
+use Template::Plugin::Filter;
+use base 'Template::Plugin::Filter';
+
+use Encode;
+
+our $FILTER_NAME_DEFAULT = 'truncate_by_word';
+our $ORG_ENC_DEFAULT = 'utf8';
+
+sub init {
+    my $self = shift;
+    $self->{_DYNAMIC} = 1;
+    $self->install_filter($self->{_CONFIG}->{name}||$FILTER_NAME_DEFAULT);
+    $self->{_CONFIG}->{enc} ||= $self->{_ARGS}->[0] || $ORG_ENC_DEFAULT;
+    return $self;
+}
+
+sub filter {
+    my($self, $string, $args, $conf) = @_;
+
+    return '' unless $string;
+
+    # decode
+    my $org_enc;
+    unless ( utf8::is_utf8($string) ) {
+        $org_enc = $self->{_CONFIG}->{enc};
+        $string = Encode::decode($org_enc, $string);
+    }
+
+    my $org_length = CORE::length($string);
+    my $length = $args->[0] || $org_length;
+    return if $length =~ /\D/;
+    $string = CORE::substr($string, 0, $length);
+
+    my $suffix = $args->[1]||'';
+    # revive encode
+    $string = Encode::encode($org_enc, $string) if $org_enc;
+    return $org_length > $length ? $string.$suffix : $string ;
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Template::Plugin::TruncateByWord - A Template Toolkit filter to truncate not the number of bytes but characters
+
+=head1 SYNOPSIS
+
+  # result is 'ab'
+  [% USE TruncateByWord %]
+  [% 'abcdefg' | truncate_by_word(2) %]
+
+  # result is 'abc....'
+  [% USE TruncateByWord %]
+  [% FILTER truncate_by_word(3,'....') %]
+  abcdefg
+  [% END %]
+
+  # default charset = 'utf8'. you can change this.
+  # result is 'abcd'
+  [% USE TruncateByWord 'euc-jp' %]
+  [% FILTER truncate_by_word(4) %]
+  abcdefg
+  [% END %]
+
+=head1 DESCRIPTION
+
+Template::Plugin::TruncateByWord is a filter plugin for Template Toolkit which truncate text not the number of bytes but the number of characters.
+
+=head1 BUGS
+
+If found, please Email me. I tested utf8, euc-jp, shiftjis, 7bit-jis, big5, and euc-kr. Please send me more test cases.
+
+=head1 SEE ALSO
+
+L<Template>, L<Template::Plugin::Filter>, and t/*.t
+
+=head1 AUTHOR
+
+User & KAWABATA Kazumichi (Higemaru) E<lt>kawabata@cpan.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2008- KAWABATA Kazumichi
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+
+=cut
diff --git a/catalogue/search.pl b/catalogue/search.pl
index 8624b3b..4f17ae5 100755
--- a/catalogue/search.pl
+++ b/catalogue/search.pl
@@ -679,6 +679,7 @@ $template->param(
             opacfacets => 1,
             facets_loop => $facets,
             displayFacetCount=> C4::Context->preference('displayFacetCount')||0,
+            FacetLabelTruncationLength => C4::Context->preference('FacetLabelTruncationLength') || 20,
             scan => $scan,
             search_error => $error,
 );
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/facets.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/facets.inc
index fd2302a..f6e2bf3 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/facets.inc
+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/facets.inc
@@ -1,3 +1,5 @@
+[% USE TruncateByWord %]
+
 [% IF ( opacfacets ) %]
 [% IF ( facets_loop ) %]
 <div id="search-facets">
@@ -19,7 +21,7 @@
 [% IF ( facets_loo.type_label_Libraries ) %]Libraries[% END %]
 [% IF ( facets_loo.type_label_Location ) %]Locations[% END %]
 <ul>
-        [% FOREACH facet IN facets_loo.facets %]<li><a href="/cgi-bin/koha/catalogue/search.pl?[% query_cgi |html %][% limit_cgi |html %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by %][% END %]&amp;limit=[% facet.type_link_value %]:[% facet.facet_link_value %]" title="[% facet.facet_title_value %]">[% facet.facet_label_value %]</a> [% IF ( displayFacetCount ) %]([% facet.facet_count %])[% END %]</li>[% END %][% IF ( facets_loo.expandable ) %]
+        [% FOREACH facet IN facets_loo.facets %]<li><a href="/cgi-bin/koha/catalogue/search.pl?[% query_cgi |html %][% limit_cgi |html %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by %][% END %]&amp;limit=[% facet.type_link_value %]:[% facet.facet_link_value %]" title="[% facet.facet_title_value %]">[% facet.facet_label_value |truncate_by_word(FacetLabelTruncationLength, '&hellip;') %]</a> [% IF ( displayFacetCount ) %]([% facet.facet_count %])[% END %]</li>[% END %][% IF ( facets_loo.expandable ) %]
         <li class="showmore"><a href="/cgi-bin/koha/catalogue/search.pl?[% query_cgi |html %][% limit_cgi |html %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by %][% END %][% IF ( offset ) %]&amp;offset=[% offset %][% END %]&amp;expand=[% facets_loo.expand %]#[% facets_loo.type_id %]">Show more</a></li>
 [% END %]
 </ul></li>
diff --git a/koha-tmpl/opac-tmpl/prog/en/includes/opac-facets.inc b/koha-tmpl/opac-tmpl/prog/en/includes/opac-facets.inc
index fbb7c55..e0b9062 100644
--- a/koha-tmpl/opac-tmpl/prog/en/includes/opac-facets.inc
+++ b/koha-tmpl/opac-tmpl/prog/en/includes/opac-facets.inc
@@ -1,3 +1,5 @@
+[% USE TruncateByWord %]
+
 [% IF ( opacfacets ) %]
 [% IF ( facets_loop ) %]
 <div id="search-facets">
@@ -20,7 +22,7 @@
 [% END %]
 [% IF ( facets_loo.type_label_Location ) %]Locations[% END %]
 <ul>
-        [% FOREACH facet IN facets_loo.facets %]<li><a href="/cgi-bin/koha/opac-search.pl?[% query_cgi |html %][% limit_cgi |html %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by |html %][% END %]&amp;limit=[% facet.type_link_value %]:[% facet.facet_link_value %]" title="[% facet.facet_title_value |html %]">[% facet.facet_label_value %]</a> [% IF ( displayFacetCount ) %]([% facet.facet_count %])[% END %]</li>[% END %][% IF ( facets_loo.expandable ) %]
+        [% FOREACH facet IN facets_loo.facets %]<li><a href="/cgi-bin/koha/opac-search.pl?[% query_cgi |html %][% limit_cgi |html %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by |html %][% END %]&amp;limit=[% facet.type_link_value %]:[% facet.facet_link_value %]" title="[% facet.facet_title_value |html %]">[% facet.facet_label_value |truncate_by_word(FacetLabelTruncationLength, '&hellip;') %]</a> [% IF ( displayFacetCount ) %]([% facet.facet_count %])[% END %]</li>[% END %][% IF ( facets_loo.expandable ) %]
         <li class="showmore"><a href="/cgi-bin/koha/opac-search.pl?[% query_cgi |html %][% limit_cgi |html %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by |html %][% END %][% IF ( offset ) %]&amp;offset=[% offset %][% END %]&amp;expand=[% facets_loo.expand %]#[% facets_loo.type_id %]">Show more</a></li>
 [% END %]
 </ul></li>
diff --git a/opac/opac-search.pl b/opac/opac-search.pl
index 9a58bcc..36c4a9a 100755
--- a/opac/opac-search.pl
+++ b/opac/opac-search.pl
@@ -862,6 +862,7 @@ $template->param(
             opacfacets => 1,
             facets_loop => $facets,
             displayFacetCount=> C4::Context->preference('displayFacetCount')||0,
+            FacetLabelTruncationLength => C4::Context->preference('FacetLabelTruncationLength') || 20,
             scan => $scan,
             search_error => $error,
 );
-- 
1.7.10.4