Bug 25314: Make OPAC facets collapse

This patch implements collapsing facets using the Bootstrap Collapse
component.

To test, apply the patch and rebuild the OPAC CSS.

1. Clear your browser cache if necessary.
2. Using the sample data, go to Advanced Search in the OPAC. Check the
   "Books" checkbox under the "Item types" tab and submit.
3. In the left-hand sidebar you should see the facets you normally see,
   but now each one has an arrow icon to show whether the facet is
   expanded or collapsed.
4. All facets should be expanded by default. Adding expanded/collapsed
   settings to system preferences is out of scope for this bug.
5. Test expanding and collapsing facets, as well as the "Show more" link
   under each one.
6. Click the "Fiction" link under the "Collections" facet. When the
   refined search results load you clicked should now have a red "X"
   link next to "Fiction," which should no longer be a link.
   - Because "Fiction" is the only uption under the "Collections" facet,
     the facet is not collapsible. I reasoned that it would be important
     not to let a facet limitation disappear behind hidden facets.
   * The only way I know to do this in the template is to check for
     facets with only one option this has the possibly-unwanted side
     effect of making facets which haven't been selected but still only
     have one option not collapsible. In this example search "Holding
     libraries" and "Topics" show this. I'm open to suggestions on this!
7. Test with the displayFacetCount preference both enabled and disabled.

Sponsored-by: Athens County Public Libraries
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 2546c08688)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
This commit is contained in:
Owen Leonard 2026-01-29 12:38:39 +00:00 committed by Jacob O'Mara
parent 1c0c0b3d17
commit 1cea1fc4ea
No known key found for this signature in database
3 changed files with 211 additions and 141 deletions

View File

@ -176,6 +176,15 @@ caption {
}
}
.badge {
&.bg-info-subtle,
&.bg-secondary-subtle {
color: #000 !important;
margin-left: .3em;
text-indent: 0;
}
}
.btn-primary {
background-color: $base-theme-color;
border: 1px solid darken( $base-theme-color, 10% );

View File

@ -1840,18 +1840,9 @@ nav {
}
li {
font-size: 90%;
font-weight: bold;
font-size: 95%;
list-style-type: none;
li {
font-size: 95%;
font-weight: normal;
line-height: 125%;
margin-bottom: 2px;
padding: .1em .2em;
}
&.showmore {
a {
font-weight: bold;
@ -1864,8 +1855,59 @@ nav {
font-weight: normal;
}
.facet-count {
display: inline-block;
.facet-label-selected {
font-weight: bold;
}
.facet-toggle,
.facet-toggle:hover,
.facet-static {
color: #6F6F6F;
cursor: pointer;
display: inline-flex;
font-weight: bold;
padding: 0.3em 0;
text-decoration: none;
}
.facet-toggle::before {
color: #5A5A5A;
content: "\f0da";
font-family: "Font Awesome 6 Free";
font-size: 90%;
line-height: 1.5em;
padding: 0 0.35em 0 0;
transition: transform 0.2s ease;
}
.facet-toggle[aria-expanded="true"]::before {
content: "\f0d7";
padding-top: 0;
padding-bottom: 0;
}
.facet-static::before {
color: #5A5A5A;
content: "\f0c8";
cursor: default;
font-family: "Font Awesome 6 Free";
font-size: 50%;
line-height: 1.5em;
padding: .7em 1em 0 0;
}
.facet-collapse li {
padding: 0.1em 0 0.1em 1.6em;
text-indent: -1em;
}
.facet-remove {
background:#FFF none !important;
color:red !important;
padding:.2em .4em;
border:1px solid rgb(255, 0, 0);
text-indent:0;
}
.facet-remove:hover {
background: rgba(255, 0, 0, 0.1) none !important;
}
}

View File

@ -10,161 +10,180 @@
<ul class="menu-collapse">
[% IF Koha.Preference("SavedSearchFilters") && search_filters.size > 0 %]
<li id="search-filters">
<h3 id="filter_facets">Custom search filters</h3>
<ul>
[% SET base_url = "/cgi-bin/koha/opac-search.pl?" _ query_cgi _ limit_cgi %]
[% FOREACH search_filter IN search_filters %]
[% SET search_filter_id = search_filter.id | uri %]
<li>
[% IF active_filters.${search_filter.id} %]
<span class="filter_label">[% search_filter.name | html %]<a href="[% base_url _ '&nolimit=search_filter:' _ search_filter_id | $raw %]">[x]</a></span>
[% ELSE %]
<span class="filter_label"><a href="[% base_url _ '&limit=search_filter:' _ search_filter_id | $raw %]">[% search_filter.name | html %]</a></span>
[% END %]
</li>
[% END %]
</ul>
<a class="facet-toggle" aria-expanded="true" data-bs-toggle="collapse" data-bs-target="#custom_search_collapse" id="filter_facets">Custom search filters</a>
<div class="facet-collapse collapse show" id="custom_search_collapse">
<ul>
[% SET base_url = "/cgi-bin/koha/opac-search.pl?" _ query_cgi _ limit_cgi %]
[% FOREACH search_filter IN search_filters %]
[% SET search_filter_id = search_filter.id | uri %]
<li>
[% IF active_filters.${search_filter.id} %]
<span class="filter_label">[% search_filter.name | html %]<a href="[% base_url _ '&nolimit=search_filter:' _ search_filter_id | $raw %]">[x]</a></span>
[% ELSE %]
<span class="filter_label"><a href="[% base_url _ '&limit=search_filter:' _ search_filter_id | $raw %]">[% search_filter.name | html %]</a></span>
[% END %]
</li>
[% END %]
</ul>
</div>
</li>
[% END %]
<li id="availability_facet"
><h3 id="facet-availability">Availability</h3>
<ul>
[% IF ( available ) %]
<li><strong>Showing only records with available items</strong></li
><li><a href="/cgi-bin/koha/opac-search.pl?[% query_cgi | $raw %][% limit_cgi_not_availablity | $raw %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by |uri %][% END %]">Show all records</a> </li>
[% ELSE %]
<li><a href="/cgi-bin/koha/opac-search.pl?[% query_cgi | $raw %][% limit_cgi | $raw %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by |uri %][% END %]&amp;limit=available">Limit to records with available items</a></li>
[% END %]
</ul>
[% IF ( related ) %]<li>(related searches: [% FOREACH relate IN related %][% relate.related_search | html %][% END %])</li>[% END %]
<li id="availability_facet">
<a class="facet-toggle" aria-expanded="true" data-bs-toggle="collapse" data-bs-target="#availability_collapse" id="filter_facets">Availability</a>
<div class="facet-collapse collapse show" id="availability_collapse">
<ul>
[% IF ( available ) %]
<li><strong>Showing only records with available items</strong></li
><li><a href="/cgi-bin/koha/opac-search.pl?[% query_cgi | $raw %][% limit_cgi_not_availablity | $raw %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by |uri %][% END %]">Show all records</a> </li>
[% ELSE %]
<li
><a href="/cgi-bin/koha/opac-search.pl?[% query_cgi | $raw %][% limit_cgi | $raw %][% IF ( sort_by ) %]&amp;sort_by=[% sort_by |uri %][% END %]&amp;limit=available"
>Limit to records with available items</a
></li
>
[% END %]
[% IF ( related ) %]<li>(related searches: [% FOREACH relate IN related %][% relate.related_search | html %][% END %])</li>[% END %]
</ul>
</div>
</li>
[% FOREACH facets_loo IN facets_loop %]
[% IF facets_loo.facets.size > 0 %]
<li id="[% facets_loo.type_id | html %]">
[% IF ( facets_loo.facets.size == 1 ) %]
[% attrs = "class='facet-static'" %]
[% ELSE %]
[% attrs = "class='facet-toggle' aria-expanded='true' data-bs-toggle='collapse' data-bs-target='#" _ facets_loo.type_id _ "_collapse'" %]
[% END %]
[% SWITCH facets_loo.label %]
[% CASE 'Authors' %]
<h3 id="facet-authors">Authors</h3>
<a [% attrs | $raw %] id="facet-authors">Authors</a>
[% CASE 'Titles' %]
<h3 id="facet-titles">Titles</h3>
<a [% attrs | $raw %] id="facet-titles">Titles</a>
[% CASE 'Topics' %]
<h3 id="facet-topics">Topics</h3>
<a [% attrs | $raw %] id="facet-topics">Topics</a>
[% CASE 'Places' %]
<h3 id="facet-places">Places</h3>
<a [% attrs | $raw %] id="facet-places">Places</a>
[% CASE 'Series' %]
<h3 id="facet-series">Series</h3>
<a [% attrs | $raw %] id="facet-series">Series</a>
[% CASE 'Item types' %]
<h3 id="facet-itemtypes">Item types</h3>
<a [% attrs | $raw %] id="facet-itemtypes">Item types</a>
[% CASE 'Home libraries' %]
<h3 id="facet-home-libraries">Home libraries</h3>
<a [% attrs | $raw %] id="facet-home-libraries">Home libraries</a>
[% CASE 'Holding libraries' %]
<h3 id="facet-holding-libraries">Holding libraries</h3>
<a [% attrs | $raw %] id="facet-holding-libraries">Holding libraries</a>
[% CASE 'Location' %]
<h3 id="facet-locations">Locations</h3>
<a [% attrs | $raw %] id="facet-locations">Locations</a>
[% CASE 'Collections' %]
<h3 id="facet-collections">Collections</h3>
<a [% attrs | $raw %] id="facet-collections">Collections</a>
[% CASE 'Languages' %]
<h3 id="facet-languages">Languages</h3>
<a [% attrs | $raw %] id="facet-languages">Languages</a>
[% CASE %]
<h3 id="facet-[% facets_loo.type_link_value | html %]">[% facets_loo.label | html %]</h3>
<a [% attrs | $raw %] id="facet-[% facets_loo.type_link_value | html %]">[% facets_loo.type_id | html %]</a>
[% END %]
<ul>
[% SET url = "/cgi-bin/koha/opac-search.pl?" _ query_cgi _ limit_cgi %]
[% IF ( sort_by ) %]
[% url = BLOCK %][% url | $raw %][% "&amp;sort_by=" _ sort_by | url %][% END %]
[% END %]
[% IF ( results_per_page ) %]
[% url = BLOCK %][% url | $raw %][% "&amp;count=" _ results_per_page | url %][% END %]
[% END %]
[% FOREACH facet IN facets_loo.facets %]
[% IF facets_loo.label == 'Collections' %][% SET facet.facet_label_value = AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => facet.facet_label_value, opac =>1 ) || facet.facet_label_value %][% END %]
[% IF facets_loo.label == 'Languages' %][% SET facet.facet_label_value = Languages.GetByISOCode(lang,facet.facet_label_value) || facet.facet_label_value %][% END %]
[% SET li_class = '' %]
[% SET li_style = '' %]
[% IF loop.count > 5 && !facet.active %]
[% li_class = "collapsible-facet" %]
[% li_style = "display:none" %]
<div class="facet-collapse collapse show" id="[% facets_loo.type_id | html %]_collapse">
<ul>
[% SET url = "/cgi-bin/koha/opac-search.pl?" _ query_cgi _ limit_cgi %]
[% IF ( sort_by ) %]
[% url = BLOCK %][% url | $raw %][% "&amp;sort_by=" _ sort_by | url %][% END %]
[% END %]
<li class="[% li_class | html %]" style="[% li_style | html %]">
[% IF facet.active %]
[% local_url = BLOCK %][% url | $raw %][% "&nolimit=" _ facet.type_link_value _ ":" _ facet.facet_link_value | url %][% END %]
<span class="facet-label">[% facet.facet_label_value | html %]</span>
[% IF ( displayFacetCount ) %]
<span class="facet-count-selected">([% facet.facet_count | html %])</span>
[% IF ( results_per_page ) %]
[% url = BLOCK %][% url | $raw %][% "&amp;count=" _ results_per_page | url %][% END %]
[% END %]
[% FOREACH facet IN facets_loo.facets %]
[% IF facets_loo.label == 'Collections' %][% SET facet.facet_label_value = AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => facet.facet_label_value, opac =>1 ) || facet.facet_label_value %][% END %]
[% IF facets_loo.label == 'Languages' %][% SET facet.facet_label_value = Languages.GetByISOCode(lang,facet.facet_label_value) || facet.facet_label_value %][% END %]
[% SET li_class = '' %]
[% SET li_style = '' %]
[% IF loop.count > 5 && !facet.active %]
[% li_class = "collapsible-facet" %]
[% li_style = "display:none" %]
[% END %]
<li class="[% li_class | html %]" style="[% li_style | html %]">
[% IF facet.active %]
[% local_url = BLOCK %][% url | $raw %][% "&nolimit=" _ facet.type_link_value _ ":" _ facet.facet_link_value | url %][% END %]
[% FILTER collapse %]
<span class="facet-label facet-label-selected">
[% facet.facet_label_value | html %]
[% IF ( displayFacetCount ) %]
&nbsp;<span class="badge bg-info-subtle facet-count-selected">[% facet.facet_count | html %]</span>
[% END %]
&nbsp;<a href="[% local_url | $raw %]" title="Remove facet [% facet.facet_label_value | html %]"><span class="badge facet-remove">x</span></a>
</span>
[% END %]
[% ELSE %]
[% local_url = BLOCK %][% url | $raw %][% "&limit=" _ facet.type_link_value _ ":" _ facet.facet_link_value | url %][% END %]
<span class="facet-label"><a href="[% local_url | $raw %]" title="[% facet.facet_title_value | html %]">[% facet.facet_label_value | html %]</a></span>
[% IF ( displayFacetCount ) %]
<span class="badge bg-info-subtle facet-count"> [% facet.facet_count | html %]</span>
[% END %]
[% END %]
[<a href="[% local_url | $raw %]" title="Remove facet [% facet.facet_label_value | html %]">x</a>]
[% ELSE %]
[% local_url = BLOCK %][% url | $raw %][% "&limit=" _ facet.type_link_value _ ":" _ facet.facet_link_value | url %][% END %]
<span class="facet-label"><a href="[% local_url | $raw %]" title="[% facet.facet_title_value | html %]">[% facet.facet_label_value | html %]</a></span>
[% IF ( displayFacetCount ) %]
<span class="facet-count"> ([% facet.facet_count | html %])</span>
</li>
[% END %]
[% IF facets_loo.facets.size > 5 %]
<li class="moretoggle">
[% SET aria_label = t("Show more") %]
[% SWITCH facets_loo.label %]
[% CASE 'Authors' %]
[% aria_label = t("Show more authors") %]
[% CASE 'Titles' %]
[% aria_label = t("Show more titles") %]
[% CASE 'Topics' %]
[% aria_label = t("Show more topics") %]
[% CASE 'Places' %]
[% aria_label = t("Show more places") %]
[% CASE 'Series' %]
[% aria_label = t("Show more series") %]
[% CASE 'Item types' %]
[% aria_label = t("Show more item types") %]
[% CASE 'Home libraries' %]
[% aria_label = t("Show more home libraries") %]
[% CASE 'Holding libraries' %]
[% aria_label = t("Show more holding libraries") %]
[% CASE 'Location' %]
[% aria_label = t("Show more locations") %]
[% CASE 'Collections' %]
[% aria_label = t("Show more collections") %]
[% CASE 'Languages' %]
[% aria_label = t("Show more languages") %]
[% END %]
[% END %]
</li>
[% END %]
[% IF facets_loo.facets.size > 5 %]
<li class="moretoggle">
[% SET aria_label = t("Show more") %]
[% SWITCH facets_loo.label %]
[% CASE 'Authors' %]
[% aria_label = t("Show more authors") %]
[% CASE 'Titles' %]
[% aria_label = t("Show more titles") %]
[% CASE 'Topics' %]
[% aria_label = t("Show more topics") %]
[% CASE 'Places' %]
[% aria_label = t("Show more places") %]
[% CASE 'Series' %]
[% aria_label = t("Show more series") %]
[% CASE 'Item types' %]
[% aria_label = t("Show more item types") %]
[% CASE 'Home libraries' %]
[% aria_label = t("Show more home libraries") %]
[% CASE 'Holding libraries' %]
[% aria_label = t("Show more holding libraries") %]
[% CASE 'Location' %]
[% aria_label = t("Show more locations") %]
[% CASE 'Collections' %]
[% aria_label = t("Show more collections") %]
[% CASE 'Languages' %]
[% aria_label = t("Show more languages") %]
[% END %]
<a href="#" aria-label="[% aria_label | html | trim %]"><strong>Show more</strong></a>
</li>
<li class="moretoggle" style="display:none">
[% SET aria_label = t("Show more") %]
[% SWITCH facets_loo.label %]
[% CASE 'Authors' %]
[% aria_label = t("Show fewer authors") %]
[% CASE 'Titles' %]
[% aria_label = t("Show fewer titles") %]
[% CASE 'Topics' %]
[% aria_label = t("Show fewer topics") %]
[% CASE 'Places' %]
[% aria_label = t("Show fewer places") %]
[% CASE 'Series' %]
[% aria_label = t("Show fewer series") %]
[% CASE 'Item types' %]
[% aria_label = t("Show fewer item types") %]
[% CASE 'Home libraries' %]
[% aria_label = t("Show fewer home libraries") %]
[% CASE 'Holding libraries' %]
[% aria_label = t("Show fewer holding libraries") %]
[% CASE 'Location' %]
[% aria_label = t("Show fewer locations") %]
[% CASE 'Collections' %]
[% aria_label = t("Show fewer collections") %]
[% CASE 'Languages' %]
[% aria_label = t("Show fewer languages") %]
[% END %]
<a href="#" aria-label="[% aria_label | html | trim %]"><strong>Show more</strong></a>
</li>
<li class="moretoggle" style="display:none">
[% SET aria_label = t("Show more") %]
[% SWITCH facets_loo.label %]
[% CASE 'Authors' %]
[% aria_label = t("Show fewer authors") %]
[% CASE 'Titles' %]
[% aria_label = t("Show fewer titles") %]
[% CASE 'Topics' %]
[% aria_label = t("Show fewer topics") %]
[% CASE 'Places' %]
[% aria_label = t("Show fewer places") %]
[% CASE 'Series' %]
[% aria_label = t("Show fewer series") %]
[% CASE 'Item types' %]
[% aria_label = t("Show fewer item types") %]
[% CASE 'Home libraries' %]
[% aria_label = t("Show fewer home libraries") %]
[% CASE 'Holding libraries' %]
[% aria_label = t("Show fewer holding libraries") %]
[% CASE 'Location' %]
[% aria_label = t("Show fewer locations") %]
[% CASE 'Collections' %]
[% aria_label = t("Show fewer collections") %]
[% CASE 'Languages' %]
[% aria_label = t("Show fewer languages") %]
[% END %]
[% IF aria_label %]
<a href="#" aria-label="[% aria_label | html | trim %]"><strong>Show less</strong></a>
[% END %]
</li>
[% END %]
</ul>
[% IF aria_label %]
<a href="#" aria-label="[% aria_label | html | trim %]"><strong>Show less</strong></a>
[% END %]
</li>
[% END %]
</ul>
</div>
</li>
[% END # / IF facets_loo.facets.size > 0 %]
[% END # / FOREACH facets_loo %]