Enh 7031: More options for Advanced Search
authorIan Walls <ian.walls@bywatersolutions.com>
Wed, 27 Jul 2011 18:08:23 +0000 (14:08 -0400)
committerPaul Poulain <paul.poulain@biblibre.com>
Wed, 14 Mar 2012 13:35:27 +0000 (14:35 +0100)
Adds the ability to perform advanced searches in both the OPAC and staff client on more than
a single AdvancedSearchType at a time.  Support included for Itemtype, Collection Code and Shelving Location.

AdvancedSearchTypes syspref preference is repurposed; no longer a single value, it can now take
multiple item code fields separated by "|".  The order of these fields will determine the order
of the tabs in the OPAC and staff client advanced search screens.  Values within the search type
are OR'ed together, while each different search type is AND'ed together in the query limits.  The
current stored values are supported without any required modification.

Each set of advanced search fields are displayed in tabs in both the OPAC and staff client.  The
first value in the AdvancedSearchTypes syspref is the selected tab; if no values are present, "itemtypes"
is used.  For non-itemtype values, the value in AdvancedSearchTypes must match the Authorised Value name, and
must be indexed with 'mc-' prefixing that name.

<li> elements in tab are assigned unique IDs, so the text of the tab can be altered to match the
library's needs (using JQuery)

The logic to handle the 5 element row limit has been moved from the Perl to the templates, since Template::Toolkit
has a simple method for extracting the count of an element in a loop and performing 'modulus' on it.

2011-12-21: Incorporated changes recommend by Owen Leonard on bug report.
Signed-off-by: Owen Leonard <oleonard@myacpl.org>

C4/Search.pm
catalogue/search.pl
koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref
koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/advsearch.tt
koha-tmpl/opac-tmpl/prog/en/css/opac.css
koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt
opac/opac-search.pl

index 05a860c..f994e9a 100644 (file)
@@ -1296,7 +1296,7 @@ sub buildQuery {
     warn "QUERY BEFORE LIMITS: >$query<" if $DEBUG;
 
     # add limits
-    my $group_OR_limits;
+    my %group_OR_limits;
     my $availability_limit;
     foreach my $this_limit (@limits) {
         if ( $this_limit =~ /available/ ) {
@@ -1313,17 +1313,16 @@ sub buildQuery {
         # group_OR_limits, prefixed by mc-
         # OR every member of the group
         elsif ( $this_limit =~ /mc/ ) {
-        
-            if ( $this_limit =~ /mc-ccode:/ ) {
+            my ($k,$v) = split(/:/, $this_limit,2);
+            if ( $k !~ /mc-i(tem)?type/ ) {
                 # in case the mc-ccode value has complicating chars like ()'s inside it we wrap in quotes
                 $this_limit =~ tr/"//d;
-                my ($k,$v) = split(/:/, $this_limit,2);
                 $this_limit = $k.":\"".$v."\"";
             }
 
-            $group_OR_limits .= " or " if $group_OR_limits;
-            $limit_desc      .= " or " if $group_OR_limits;
-            $group_OR_limits .= "$this_limit";
+            $group_OR_limits{$k} .= " or " if $group_OR_limits{$k};
+            $limit_desc      .= " or " if $group_OR_limits{$k};
+            $group_OR_limits{$k} .= "$this_limit";
             $limit_cgi       .= "&limit=$this_limit";
             $limit_desc      .= " $this_limit";
         }
@@ -1346,9 +1345,9 @@ sub buildQuery {
             }
         }
     }
-    if ($group_OR_limits) {
+    foreach my $k (keys (%group_OR_limits)) {
         $limit .= " and " if ( $query || $limit );
-        $limit .= "($group_OR_limits)";
+        $limit .= "($group_OR_limits{$k})";
     }
     if ($availability_limit) {
         $limit .= " and " if ( $query || $limit );
index 49e63bc..20d21f1 100755 (executable)
@@ -239,44 +239,50 @@ my $categories = GetBranchCategories(undef,'searchdomain');
 $template->param(branchloop => \@branch_loop, searchdomainloop => $categories);
 
 # load the Type stuff
-# load the Type stuff
 my $itemtypes = GetItemTypes;
 # the index parameter is different for item-level itemtypes
 my $itype_or_itemtype = (C4::Context->preference("item-level_itypes"))?'itype':'itemtype';
-my @itemtypesloop;
-my $selected=1;
+my @advancedsearchesloop;
 my $cnt;
-my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
-
-if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {                                                                 foreach my $thisitemtype ( sort {$itemtypes->{$a}->{'description'} cmp $itemtypes->{$b}->{'description'} } keys %$itemtypes ) {
-    my %row =(  number=>$cnt++,
-                ccl => qq($itype_or_itemtype,phr),
+my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes") || "itemtypes";
+my @advanced_search_types = split(/\|/, $advanced_search_types);
+
+foreach my $advanced_srch_type (@advanced_search_types) {
+   if ($advanced_srch_type eq 'itemtypes') {
+   # itemtype is a special case, since it's not defined in authorized values
+        my @itypesloop;
+       foreach my $thisitemtype ( sort {$itemtypes->{$a}->{'description'} cmp $itemtypes->{$b}->{'description'} } keys %$itemtypes ) {
+           my %row =(  number=>$cnt++,
+               ccl => "$itype_or_itemtype,phr",
                 code => $thisitemtype,
-                selected => $selected,
                 description => $itemtypes->{$thisitemtype}->{'description'},
-                count5 => $cnt % 4,
-                imageurl=> getitemtypeimagelocation( 'intranet', $itemtypes->{$thisitemtype}->{'imageurl'} ),
+                imageurl=> getitemtypeimagelocation( 'opac', $itemtypes->{$thisitemtype}->{'imageurl'} ),
             );
-        $selected = 0 if ($selected) ;
-        push @itemtypesloop, \%row;
-    }
-    $template->param(itemtypeloop => \@itemtypesloop);
-} else {
-    my $advsearchtypes = GetAuthorisedValues($advanced_search_types);
-    for my $thisitemtype (sort {$a->{'lib'} cmp $b->{'lib'}} @$advsearchtypes) {
-        my %row =(
-                number=>$cnt++,
-                ccl => $advanced_search_types,
+           push @itypesloop, \%row;
+       }
+        my %search_code = (  advanced_search_type => $advanced_srch_type,
+                             code_loop => \@itypesloop );
+        push @advancedsearchesloop, \%search_code;
+    } else {
+    # covers all the other cases: non-itemtype authorized values
+       my $advsearchtypes = GetAuthorisedValues($advanced_srch_type, '', 'opac');
+        my @authvalueloop;
+       for my $thisitemtype (@$advsearchtypes) {
+               my %row =(
+                               number=>$cnt++,
+                               ccl => $advanced_srch_type,
                 code => $thisitemtype->{authorised_value},
-                selected => $selected,
                 description => $thisitemtype->{'lib'},
-                count5 => $cnt % 4,
-                imageurl=> getitemtypeimagelocation( 'intranet', $thisitemtype->{'imageurl'} ),
-            );
-        push @itemtypesloop, \%row;
+                imageurl => getitemtypeimagelocation( 'intranet', $thisitemtype->{'imageurl'} ),
+                );
+               push @authvalueloop, \%row;
+       }
+        my %search_code = (  advanced_search_type => $advanced_srch_type,
+                             code_loop => \@authvalueloop );
+        push @advancedsearchesloop, \%search_code;
     }
-    $template->param(itemtypeloop => \@itemtypesloop);
 }
+$template->param(advancedsearchesloop => \@advancedsearchesloop);
 
 # The following should only be loaded if we're bringing up the advanced search template
 if ( $template_type eq 'advsearch' ) {
index fec66d6..010399b 100644 (file)
@@ -2054,32 +2054,36 @@ fieldset.rows+h3 {clear:both;padding-top:.5em;}
     padding-left:20px
 }
 
-#advanced-search fieldset {
+.adsearch {
+    margin: 0;
+}
+
+.advsearch fieldset {
        border : 1px solid #EEE;
        -moz-border-radius : 3px;
        border-radius : 3px;
 }
 
-#advanced-search fieldset.action {
+.advsearch fieldset.action {
        border : 0;
 }
 
-#advanced-search fieldset fieldset {
+.advsearch fieldset fieldset {
        border : 1px solid #EEE;
        margin : 0;
        padding : .3em .5em;
        -moz-border-radius : 0;
        border-radius : 0;
 }
-#advanced-search fieldset fieldset+fieldset {
+.advsearch fieldset fieldset+fieldset {
        border-top : 0;
 }
-#advanced-search table {
+.advsearch table {
        border-spacing : 5px;
        border-collapse : separate;
        border-width : 0;
 }
-#advanced-search td {
+.advsearch td {
        border : 1px solid #EEE;
        padding : 0.3em 0.4em;
 }
index 12075ec..f4b02cc 100644 (file)
@@ -71,12 +71,11 @@ Searching:
             - subdivisions for searches generated by clicking on subject tracings.
     Search Form:
         -
-            - Show checkboxes to search by
+            - Show tabs in OPAC and staff-side advanced search for limiting searches on the
             - pref: AdvancedSearchTypes
-              choices:
-                  itemtypes: itemtype
-                  ccode: collection code
-            - on the OPAC and staff advanced search pages.
+              class: long
+            - "fields (separate values with |). Tabs appear in the order listed.<br/>"
+            - "<em>Currently supported values</em>: Item types (<strong>itemtypes</strong>), Collection Codes (<strong>ccode</strong>) and Shelving Location (<strong>loc</strong>)."
         -
             - By default,
             - pref: expandedSearchOption
index 7e6b5ad..acf133d 100644 (file)
@@ -15,6 +15,7 @@
        }
        $(document).ready(function() {
                $("input[name=q]:eq(0)").focus();
+                $('#advsearches > ul').tabs();
        });
 </script>
 </head>
             <a href="/cgi-bin/koha/catalogue/search.pl?do=Clear">[New search]</a>
             </fieldset>
 <!-- /SEARCH BUTTONS -->
-
-<!-- ITEMTYPE LIMITS -->
-       <fieldset id="itemtypelist">
-     <legend>Limit to any of the following</legend>
+</div>
+<!-- MC-TYPE LIMITS -->
+    <div class="yui-g">
+      <div id="advsearches" class="toptabs">
+      <ul>
+      [% FOREACH advsearchloo IN advancedsearchesloop %]
+        <li id="advsearch-tab-[% advsearchloo.advanced_search_type %]">
+           <a href="/cgi-bin/koha/opac-search.pl#advsearch-[% advsearchloo.advanced_search_type %]">
+           [% IF ( advsearchloo.advanced_search_type == 'itemtypes' ) %]Item Type
+           [% ELSIF ( advsearchloo.advanced_search_type == 'ccode' ) %]Collection
+           [% ELSIF ( advsearchloo.advanced_search_type == 'loc' ) %]Shelving Location
+           [% ELSE %]Something Else
+           [% END %]
+           </a>
+        </li>
+      [% END %]
+      </ul>
+    [% FOREACH advsearchloo IN advancedsearchesloop %]
+    <div id="advsearch-[% advsearchloo.advanced_search_type %]" class="advsearch">
+    <fieldset>
+    <legend>Limit to any of the following:</legend>
     <table>
         <tr>
-      [% FOREACH itemtypeloo IN itemtypeloop %]
-        <td>
-        [% UNLESS ( noItemTypeImages ) %]
-        [% IF ( itemtypeloo.imageurl ) %]<img border="0" src="[% itemtypeloo.imageurl %]" alt="[% itemtypeloo.description %]" />[% END %]
-        [% END %]
-               <input type="checkbox" id="[% itemtypeloo.ccl %]-[% itemtypeloo.number %]" name="limit" value="mc-[% itemtypeloo.ccl %]:[% itemtypeloo.code %]" />&nbsp;
-        <label for="[% itemtypeloo.ccl %]-[% itemtypeloo.number %]">[% itemtypeloo.description %]</label></td>
-        [% UNLESS ( itemtypeloo.count5 ) %]</tr><tr>[% END %]
-      [% END %]
-         <!-- FIXME: for validation, avoid generating empty row -->
-      </tr>
+    [% FOREACH itemtypeloo IN advsearchloo.code_loop %]
+        <td><input type="checkbox" id="[% itemtypeloo.ccl %]-[% itemtypeloo.number %]" name="limit" value="mc-[% itemtypeloo.ccl %]:[% itemtypeloo.code %]"/><label for="[% itemtypeloo.ccl %]-[% itemtypeloo.number %]">[% UNLESS ( noItemTypeImages ) %][% IF ( itemtypeloo.imageurl ) %]<img border="0" src="[% itemtypeloo.imageurl %]" alt="[% itemtypeloo.description %]" />[% END %]&nbsp;[% END %]
+        [% itemtypeloo.description %]</label></td>
+        [% UNLESS ( loop.count % 5 ) %]</tr><tr>[% END %]
+    [% END %]
+        </tr>
     </table>
-       </fieldset>
-<!-- /ITEMTYPE LIMITS -->
-
+    </fieldset>
+    </div>
+    [% END %]
+<!-- /MC-TYPE LIMIT -->
 [% IF ( expanded_options ) %]
 <!-- BASIC LIMITS -->
  <fieldset id="basiclimits">
index 3e4fb00..88d18b0 100644 (file)
@@ -672,7 +672,7 @@ input.deleteshelf:active {
 }
 
 /* the itemtype list in advanced search */
-#advsearch-itemtype table {
+.advsearch table {
        border-collapse : separate;
        border-spacing : 3px;
        border : 0px;
@@ -681,14 +681,14 @@ input.deleteshelf:active {
        border : 0px solid #D8DEB8;
 }
 
-#advsearch-itemtype table tr td {
+.advsearch table tr td {
        background-color : #F8F8EB;
        border : 0px;
        margin : 0px;
        width : 700px;
 }
 
-#advsearch-itemtype td {
+.advsearch td {
        font-size : 0.8em;
        background-color : #F8F8EB;
 }
@@ -2258,6 +2258,7 @@ a.localimage img {
        margin : 0 .5em;
        padding : .3em;
 }
+
 p.patronimage {
        border:1px solid #EEE;
        border-bottom-color:#000;
@@ -2268,4 +2269,4 @@ p.patronimage {
 p.patronimage.edit {
        border-color:#E8E8E8;
        margin: 1em 1em 1em 0;
-}
\ No newline at end of file
+}
index 216ce8e..4847ae3 100644 (file)
@@ -2,6 +2,12 @@
 [% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha Online[% END %]
     Catalog &rsaquo; Advanced Search
 [% INCLUDE 'doc-head-close.inc' %]
+<script type="text/javascript" language="javascript">//<![CDATA[
+            $(document).ready(function() {
+            $('#advsearches > ul').tabs();
+});
+    //]]>
+</script>
 </head>
 <body id="advsearch"><div id="doc3" class="yui-t7">
 <div id="bd">
 </div>
 </div>
     <div class="yui-g">
+      <div id="advsearches" class="toptabs">
+      <ul>
+      [% FOREACH advsearchloo IN advancedsearchesloop %]
+        <li id="advsearch-tab-[% advsearchloo.advanced_search_type %]">
+           <a href="/cgi-bin/koha/opac-search.pl#advsearch-[% advsearchloo.advanced_search_type %]">
+           [% IF ( advsearchloo.advanced_search_type == 'itemtypes' ) %]Item Type
+           [% ELSIF ( advsearchloo.advanced_search_type == 'ccode' ) %]Collection
+           [% ELSIF ( advsearchloo.advanced_search_type == 'loc' ) %]Shelving Location
+           [% ELSE %]Something Else
+           [% END %]
+           </a>
+        </li>
+      [% END %]
+      </ul>
 <!-- /BOOLEAN SEARCH OPTIONS -->
-    <div id="advsearch-itemtype" class="container">
+    [% FOREACH advsearchloo IN advancedsearchesloop %]
+    <div id="advsearch-[% advsearchloo.advanced_search_type %]" class="container advsearch">
     <fieldset>
     <legend>Limit to any of the following:</legend>
     <table>
         <tr>
-    [% FOREACH itemtypeloo IN itemtypeloop %]
+    [% FOREACH itemtypeloo IN advsearchloo.code_loop %]
         <td><input type="checkbox" id="[% itemtypeloo.ccl %]-[% itemtypeloo.number %]" name="limit" value="mc-[% itemtypeloo.ccl %]:[% itemtypeloo.code %]"/><label for="[% itemtypeloo.ccl %]-[% itemtypeloo.number %]">[% UNLESS ( noItemTypeImages ) %][% IF ( itemtypeloo.imageurl ) %]<img border="0" src="[% itemtypeloo.imageurl %]" alt="[% itemtypeloo.description %]" />[% END %]&nbsp;[% END %]
         [% itemtypeloo.description %]</label></td>
-        [% UNLESS ( itemtypeloo.count5 ) %][% UNLESS ( loop.last ) %]</tr><tr>[% END %][% END %]
+        [% UNLESS ( loop.count % 5 ) %]</tr><tr>[% END %]
     [% END %]
         </tr>
     </table>
     </fieldset>
     </div>
+    [% END %]
+    </div>
     <div id="langfilter">
     <fieldset><legend>Language</legend>
     <!-- LANGUAGE LIMIT -->
index a70b152..eb9ee51 100755 (executable)
@@ -165,40 +165,47 @@ $template->param(search_languages_loop => $languages_limit_loop,);
 my $itemtypes = GetItemTypes;
 # the index parameter is different for item-level itemtypes
 my $itype_or_itemtype = (C4::Context->preference("item-level_itypes"))?'itype':'itemtype';
-my @itemtypesloop;
-my $selected=1;
+my @advancedsearchesloop;
 my $cnt;
-my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
-
-if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
-    foreach my $thisitemtype ( sort {$itemtypes->{$a}->{'description'} cmp $itemtypes->{$b}->{'description'} } keys %$itemtypes ) {
-        my %row =(  number=>$cnt++,
-        ccl => "$itype_or_itemtype,phr",
+my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes") || "itemtypes";
+my @advanced_search_types = split(/\|/, $advanced_search_types);
+
+foreach my $advanced_srch_type (@advanced_search_types) {
+   if ($advanced_srch_type eq 'itemtypes') {
+   # itemtype is a special case, since it's not defined in authorized values
+        my @itypesloop;
+       foreach my $thisitemtype ( sort {$itemtypes->{$a}->{'description'} cmp $itemtypes->{$b}->{'description'} } keys %$itemtypes ) {
+           my %row =(  number=>$cnt++,
+               ccl => "$itype_or_itemtype,phr",
                 code => $thisitemtype,
-                selected => $selected,
                 description => $itemtypes->{$thisitemtype}->{'description'},
-                count5 => $cnt % 4,
                 imageurl=> getitemtypeimagelocation( 'opac', $itemtypes->{$thisitemtype}->{'imageurl'} ),
             );
-        $selected = 0; # set to zero after first pass through
-        push @itemtypesloop, \%row;
-    }
-} else {
-    my $advsearchtypes = GetAuthorisedValues($advanced_search_types, '', 'opac');
-    for my $thisitemtype (@$advsearchtypes) {
-        my %row =(
-                number=>$cnt++,
-                ccl => $advanced_search_types,
+           push @itypesloop, \%row;
+       }
+        my %search_code = (  advanced_search_type => $advanced_srch_type,
+                             code_loop => \@itypesloop );
+        push @advancedsearchesloop, \%search_code;
+    } else {
+    # covers all the other cases: non-itemtype authorized values
+       my $advsearchtypes = GetAuthorisedValues($advanced_srch_type, '', 'opac');
+        my @authvalueloop;
+       for my $thisitemtype (@$advsearchtypes) {
+               my %row =(
+                               number=>$cnt++,
+                               ccl => $advanced_srch_type,
                 code => $thisitemtype->{authorised_value},
-                selected => $selected,
-                description => $thisitemtype->{'lib'},
-                count5 => $cnt % 4,
-                imageurl=> getitemtypeimagelocation( 'opac', $thisitemtype->{'imageurl'} ),
-            );
-        push @itemtypesloop, \%row;
+                description => $thisitemtype->{'lib_opac'} || $thisitemtype->{'lib'},
+                imageurl => getitemtypeimagelocation( 'opac', $thisitemtype->{'imageurl'} ),
+                );
+               push @authvalueloop, \%row;
+       }
+        my %search_code = (  advanced_search_type => $advanced_srch_type,
+                             code_loop => \@authvalueloop );
+        push @advancedsearchesloop, \%search_code;
     }
 }
-$template->param(itemtypeloop => \@itemtypesloop);
+$template->param(advancedsearchesloop => \@advancedsearchesloop);
 
 # # load the itypes (Called item types in the template -- just authorized values for searching)
 # my ($itypecount,@itype_loop) = GetCcodes();