Bugzilla – Attachment 130610 Details for
Bug 30063
Make the main patron search use the /patrons REST API route
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 30063: Make the main patron search use the REST API
Bug-30063-Make-the-main-patron-search-use-the-REST.patch (text/plain), 50.02 KB, created by
Jonathan Druart
on 2022-02-15 10:31:19 UTC
(
hide
)
Description:
Bug 30063: Make the main patron search use the REST API
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2022-02-15 10:31:19 UTC
Size:
50.02 KB
patch
obsolete
>From 8ae97b5c36b6baaee772b8ec051ad5021794ec91 Mon Sep 17 00:00:00 2001 >From: Jonathan Druart <jonathan.druart@bugs.koha-community.org> >Date: Fri, 11 Feb 2022 14:03:36 +0100 >Subject: [PATCH] Bug 30063: Make the main patron search use the REST API > >To test: >* Length menu (PatronsPerPage) >* Query description >* Highlight of the current library > >* sticky header - Does not work (?) > >If the table does not show when you submit the filter form, make sure >you regenerated the compiled CSS. >--- > .../prog/en/includes/patron-search.inc | 315 ++++++++++++--- > .../prog/en/includes/patronfields.inc | 2 +- > .../prog/en/modules/members/member.tt | 376 ++---------------- > .../prog/en/modules/members/search.tt | 5 +- > members/member.pl | 4 + > 5 files changed, 294 insertions(+), 408 deletions(-) > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc >index 8efb1e2a290..d6c8acb0a4c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc >@@ -1,6 +1,8 @@ > [% USE Koha %] >+[% USE I18N %] > [% USE Branches %] > [% USE raw %] >+[% USE Asset %] > [% USE To %] > > [% BLOCK patron_search_filters_simple %] >@@ -18,12 +20,11 @@ > <ol> > <li> > <label for="search_patron_filter">Search:</label> >- <div class="hint">Enter patron card number or partial name:</div> > <input type="text" id="search_patron_filter" value="[% search_filter | html %]" class="focus" /> > </li> > >- [% FOR column IN columns %] >- [% SWITCH column %] >+ [% FOR filter IN filters %] >+ [% SWITCH filter %] > [% CASE 'branch' %] > <li> > <label for="branchcode_filter">Library:</label> >@@ -47,11 +48,43 @@ > [% END %] > </select> > </li> >+ [% CASE 'search_field' %] >+ <li> >+ <label for="searchfieldstype_filter">Search field:</label> >+ <select name="searchfieldstype" id="searchfieldstype_filter"> >+ [% pref_fields = Koha.Preference('DefaultPatronSearchFields').split(',') %] >+ [% default_fields = [ 'surname,firstname,othernames,cardnumber,userid', 'surname', 'cardnumber', 'email', 'borrowernumber', 'userid', 'phone', 'address', 'dateofbirth', 'sort1', 'sort2' ] %] >+ [% search_options = default_fields.merge(pref_fields).unique %] >+ [% FOREACH s_o IN search_options %] >+ [% display_name = PROCESS patron_fields name=s_o %] >+ [% NEXT IF !display_name %] >+ [% IF searchfieldstype == s_o %] >+ <option selected="selected" value=[% s_o | html %]>[% display_name | $raw %]</option> >+ [% ELSE %] >+ <option value=[% s_o | html %]>[% display_name | $raw %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ [% CASE 'search_type' %] >+ <li> >+ <label for="searchtype_filter">Search type:</label> >+ <select name="searchtype" id="searchtype_filter"> >+ [% IF searchtype == "start_with" %] >+ <option value='start_with' selected="selected">Starts with</option> >+ <option value="contain">Contains</option> >+ [% ELSE %] >+ <option value='start_with'>Starts with</option> >+ <option value="contain" selected="selected">Contains</option> >+ [% END %] >+ </select> >+ </li> > [% END %] > [% END %] > </ol> > <fieldset class="action"> > <input type="submit" value="Search" /> >+ <input type="button" value="Clear" id="clear_search" /> > </fieldset> > </fieldset> > </form> >@@ -78,11 +111,13 @@ > [% END %] > </div> > >+ >+ <h3 style="display: none;">Patrons found for: <span id="searchpattern"></span></h3> >+ > <div id="[% table_id | html %]_search_results" style="display:none;"> > > <div id="info" class="dialog message" style="display: none;"></div> >- <div id="error" class="dialog alert" style="dispay: none;"></div> >- >+ <div id="error" class="dialog alert" style="display: none;"></div> > > <input type="hidden" id="firstletter_filter" value="" /> > [% IF open_on_row_click %] >@@ -94,6 +129,7 @@ > <tr> > [% FOR column IN columns %] > [% SWITCH column %] >+ [% CASE 'checkbox' %]<th></th> > [% CASE 'cardnumber' %]<th>Card</th> > [% CASE 'dateofbirth' %]<th>Date of birth</th> > [% CASE 'name' %]<th>Name</th> >@@ -166,17 +202,51 @@ > [% INCLUDE 'js-patron-get-age.inc' %] > [% INCLUDE 'js-patron-format.inc' %] > [% INCLUDE 'js-patron-format-address.inc' %] >+ [% IF sticky_header %] >+ [% Asset.js("lib/hc-sticky.js") | $raw %] >+ [% END %] > > <script> > var first_draw = 0; > let patrons_table; >+ var Sticky; >+ var singleBranchMode = '[% singleBranchMode | html %]'; >+ let logged_in_library_id = "[% Branches.GetLoggedInBranchcode | html %]"; > >- $(document).ready(function(){ >+ /* popstate event triggered by forward and back button. Need to refresh search */ >+ window.addEventListener('popstate', (event) => { >+ getSearchByLocation( false ); >+ }); > >+ $(document).ready(function(){ > > $("#info").hide(); > $("#error").hide(); > >+ // Build the aLengthMenu >+ var aLengthMenu = [ >+ [% Koha.Preference('PatronsPerPage') | html %], 10, 20, 50, 100, -1 >+ ]; >+ jQuery.unique(aLengthMenu); >+ aLengthMenu.sort(function( a, b ){ >+ // Put "All" at the end >+ if ( a == -1 ) { >+ return 1; >+ } else if ( b == -1 ) { >+ return -1; >+ } >+ return parseInt(a) < parseInt(b) ? -1 : 1;} >+ ); >+ var aLengthMenuLabel = []; >+ $(aLengthMenu).each(function(){ >+ if ( this == -1 ) { >+ // Label for -1 is "All" >+ aLengthMenuLabel.push(_("All")); >+ } else { >+ aLengthMenuLabel.push(this); >+ } >+ }); >+ > let additional_filters = { > surname: function(){ > let start_with = $("#firstletter_filter").val() >@@ -184,20 +254,25 @@ > return { "like": start_with + "%" } > }, > "-and": function(){ >- let filter = $("#searchmember_filter").val(); >+ let filter = $("#search_patron_filter").val(); > if (!filter) return ""; >- [% SET search_fields = Koha.Preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid' %] >- return [ >- [% FOR search_field IN search_fields.split(',') %] >- {"me.[% search_field | html %]":{"like":"%"+filter+"%"}}, >- [% END %] >- [% IF Koha.Preference('ExtendedPatronAttributes') && extended_attribute_types %] >- { >- "extended_attributes.value": { "like": "%" + filter + "%" }, >+ >+ let filters = []; >+ let search_type = $("#searchtype_filter").val() || "contain"; >+ let search_fields = $("#searchfieldstype_filter").val(); >+ if ( !search_fields ) { >+ search_fields = "[% Koha.Preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid' | html %]"; >+ } >+ search_fields.split(',').forEach(function(e,i){ >+ filters.push({["me."+e]:{"like":"%"+filter+(search_type == "contain" ? "%" : "" )}}); >+ }); >+ [% IF Koha.Preference('ExtendedPatronAttributes') && extended_attribute_types %] >+ filters.push({ >+ "extended_attributes.value": { "like": "%" + filter + (search_type == "contain" ? "%" : "" )}, > "extended_attributes.code": extended_attribute_types >- } >- [% END %] >- ]; >+ }); >+ [% END %] >+ return filters; > } > }; > patrons_table = $("#[% table_id | html %]").kohaTable({ >@@ -218,7 +293,10 @@ > [% IF redirect_if_one_result %] > // redirect if there is only 1 result. > if ( first_draw && json.recordsFiltered == 1 ) { >- document.location.href = '[% redirect_url | html %]&borrowernumber=' + json.data[0].patron_id; >+ let url = '[% redirect_url | html %]'.indexOf("?") != -1 >+ ? '[% redirect_url | html %]&borrowernumber=' + json.data[0].patron_id >+ : '[% redirect_url | html %]?borrowernumber=' + json.data[0].patron_id; >+ document.location.href = url; > return false; > } > first_draw = 0; >@@ -227,6 +305,7 @@ > } > }, > embed: ['extended_attributes', 'checkouts+count', 'overdues+count', 'account_balance'], >+ [% IF open_on_row_click OR preview_on_name_click %] > "drawCallback": function( settings ) { > var api = this.api(); > var data = api.data(); >@@ -240,12 +319,14 @@ > }).addClass('clickable'); > $(tr).find("a.patron_name").attr('href', url); > }); >- [% ELSE %] >+ [% END %] >+ [% IF preview_on_name_click %] > $.each($(this).find("tbody tr"), function(index, tr) { > $(tr).find("a.patron_name").addClass("patron_preview"); > }); > [% END %] > }, >+ [% END %] > "order": [[ 1, "asc" ]], > "iDeferLoading": 0, > "columns": [ >@@ -253,20 +334,27 @@ > [% SWITCH column %] > [% CASE 'checkbox' %] > { >- "data": "borrowernumber", >- "searchable": true, >- "orderable": true, >+ "data": "patron_id", >+ "searchable": false, >+ "orderable": false, > "render": function( data, type, row, meta ) { >- return "<input type=\"checkbox\" name="data ? escape_str($date(data) + " (" + _("%s years").format($get_age(data)) + ")") : ""; >- >- return "<label for='check" + data + "' class='content_hidden'>" + _("Select patron") + "</label><input type='checkbox' id='check" + data + "' class='selection' name='borrowernumber' value='" + data + "' />", >+ return "<label for='check" + data + "' class='content_hidden'>" + _("Select patron") + "</label><input type='checkbox' id='check" + data + "' class='selection' name='borrowernumber' value='" + data + "' />"; > } > } > [% CASE 'cardnumber' %] > { > "data": "cardnumber", > "searchable": true, >- "orderable": true >+ "orderable": true, >+ "render": function( data, type, row, meta ) { >+ let patron_id = encodeURIComponent(row.patron_id); >+ [% IF !open_on_row_click AND CAN_user_circulate_circulate_remaining_permissions %] >+ return "<a href=\"/cgi-bin/koha/circ/circulation.pl?borrowernumber=" + patron_id + "\" title=\"[% I18N.t("Check out") | html %]\" class=\"patron_name\" data-borrowernumber=\"" + patron_id + "\" style=\"white-space:nowrap\">" + escape_str(data) + "</a>"; >+ [% ELSE %] >+ return escape_str(data); >+ [% END %] >+ } >+ > } > [% CASE 'dateofbirth' %] > { >@@ -334,7 +422,11 @@ > "orderable": true, > "render": function( data, type, row, meta ) { > let patron_id = encodeURIComponent(row.patron_id); >+ [% IF ! open_on_row_click %] > return "<a href=\"/cgi-bin/koha/members/moremember.pl?borrowernumber=" + patron_id + "\" class=\"patron_name\" data-borrowernumber=\"" + patron_id + "\" style=\"white-space:nowrap\">" + $patron_to_html(row, { invert_name: 1 }) + "</a>"; >+ [% ELSE %] >+ return $patron_to_html(row, { invert_name: 1 }); >+ [% END %] > } > } > [% CASE 'branch' %] >@@ -343,7 +435,12 @@ > "searchable": true, > "orderable": true, > "render": function( data, type, row, meta ) { >- return escape_str(libraries_map[data].branchname); >+ let library_name = libraries_map[data].branchname >+ if( !singleBranchMode && data == logged_in_library_id ) { >+ return "<span class=\"currentlibrary\">" + escape_str(library_name) + "</span>"; >+ } else { >+ return escape_str(library_name); >+ } > } > } > [% CASE 'category' %] >@@ -420,11 +517,22 @@ > "data": function( row, type, val, meta ) { > > let patron_id = encodeURIComponent(row.patron_id); >- [% IF selection_type == 'select' %] >- return '<a href="#" class="btn btn-default btn-xs select_user" data-borrowernumber="' + patron_id + '">Select</a><input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '" value=\''+JSON.stringify(row)+'\' />'; >- [% ELSE %] >- return '<a href="#" class="btn btn-default btn-xs add_user" data-borrowernumber="' + patron_id + '" data-firstname="' + encodeURIComponent(row.firstname) + '" data-surname="' + encodeURIComponent(row.surname) + '">Add</a><input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '" />'; >+ let action_node = ""; >+ [% FOR action IN actions %] >+ [% SWITCH action %] >+ [% CASE 'select' %] >+ action_node += '<a href="#" class="btn btn-default btn-xs select_user" data-borrowernumber="' + patron_id + '">Select</a><input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '" value=\''+JSON.stringify(row)+'\' />'; >+ [% CASE 'add' %] >+ action_node += '<a href="#" class="btn btn-default btn-xs add_user" data-borrowernumber="' + patron_id + '" data-firstname="' + encodeURIComponent(row.firstname) + '" data-surname="' + encodeURIComponent(row.surname) + '">Add</a><input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '" />'; >+ [% CASE 'edit' %] >+ action_node += '<a href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=' + patron_id + '" class="btn btn-default btn-xs"><i class="fa fa-pencil"></i> Edit</a>'; >+ [% CASE 'checkout' %] >+ [% IF CAN_user_circulate_circulate_remaining_permissions %] >+ action_node += '<a class="btn btn-default btn-xs" href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=' + patron_id + '"><i class="fa fa-barcode"></i> ' + _("Check out") + '</a>'; >+ [% END %] >+ [% END %] > [% END %] >+ return action_node; > }, > "searchable": false, > "orderable": false >@@ -434,14 +542,24 @@ > [% END %] > ], > 'bAutoWidth': false, >+ 'lengthMenu': [aLengthMenu, aLengthMenuLabel], > 'sPaginationType': 'full_numbers', >- "iDisplayLength": [% Koha.Preference('PatronsPerPage') | html %], >+ "pageLength": [% Koha.Preference('PatronsPerPage') | html %], >+ [% IF sticky_header %] >+ "initComplete": function(settings, json) { >+ Sticky = $("#[% sticky_header | html %]x"); >+ Sticky.hcSticky({ >+ stickTo: "#[% sticky_to | html %]", >+ stickyClass: "floating" >+ }); >+ }, >+ [% END %] > }, typeof table_settings !== 'undefined' ? table_settings : null, 1, additional_filters); > > $("#patron_search_form").on('submit', filter); > $(".filterByLetter").on("click",function(e){ > e.preventDefault(); >- filterByFirstLetterSurname($(this).text()); >+ filterByFirstLetterSurname($(this).text(), true); > }); > $("body").on("click",".add_user",function(e){ > e.preventDefault(); >@@ -470,8 +588,57 @@ > $("#patronPreview .modal-body").html("<img src=\"[% interface | html %]/[% theme | html %]/img/spinner-small.gif\" alt=\"\" /> Loading"); > }); > >+ $("#clear_search").on("click",function(e){ >+ e.preventDefault(); >+ clearFilters(); >+ $("#searchpattern").parent().hide(); >+ }); >+ >+ if ( $("#search_patron_filter").val().length > 0 ) { >+ $("#patron_search_form").submit(); >+ } >+ >+ /* Initial page load does not trigger the popstate event, so we explicitly call this */ >+ getSearchByLocation( false ); >+ > }); > >+ function getSearchByLocation( setstate ){ >+ /* Check to see if the URL contains a search parameter */ >+ if( location.search != ""){ >+ var params = new URLSearchParams( location.search ); >+ var firstletter = params.get("firstletter"); >+ /* Check to see if search is a first letter param */ >+ if( firstletter ){ >+ /* Trigger function to return search results by letter */ >+ filterByFirstLetterSurname( firstletter, setstate ); >+ } >+ } >+ } >+ >+ function update_search_description(){ >+ var searched = $("#searchfieldstype_filter").find("option:selected").text(); >+ if ( $("#search_patron_filter").val() ) { >+ if ( $("#searchtype_filter").val() == 'start_with' ) { >+ searched += _(" starting with "); >+ } else { >+ searched += _(" containing "); >+ } >+ searched += "'" + $("#search_patron_filter").val() + "'"; >+ } >+ if ( $("#firstletter_filter").val() ) { >+ searched += _(" begins with ") + "'" + $("#firstletter_filter").val() +"'"; >+ } >+ if ( $("#categorycode_filter").val() ) { >+ searched += _(" with category ") + "'" + $("#categorycode_filter").find("option:selected").text() + "'"; >+ } >+ if ( $("#branchcode_filter").val() ) { >+ searched += _(" in library ") + $("#branchcode_filter").find("option:selected").text(); >+ } >+ $("#searchpattern").text(searched); >+ $("#searchpattern").parent().show(); >+ } >+ > function filter() { > $("#firstletter_filter").val(''); > $("#[% table_id | html %]_search_results").show(); >@@ -492,50 +659,68 @@ > table_dt.search(""); > first_draw = 1; // Only redirect if we are coming from here > table_dt.draw(); >+ update_search_description(); > return false; > } > >+ function clearFilters() { >+ $("#searchfieldstype_filter option:first").prop("selected", true); >+ $("#searchtype_filter option[value='contain']").prop("selected", true); >+ $("#categorycode_filter option:first").prop("selected", true); >+ $("#branchcode_filter option:first").prop("selected", true); >+ $("#firstletter_filter").val(''); >+ $("#search_patron_filter").val(''); >+ /* remove any search string added by firstletter search */ >+ history.pushState( {}, null, window.location.href.split("?" )[0]); >+ $("#[% table_id | html %]_search_results").hide(); >+ update_search_description(); >+ } >+ > // User has clicked on a letter >- function filterByFirstLetterSurname(letter) { >+ function filterByFirstLetterSurname(letter, setstate ) { > $("#firstletter_filter").val(letter); >+ > $("#[% table_id | html %]_search_results").show(); >+ >+ if ( setstate ) { >+ history.pushState( null, null, "?firstletter=" + letter ); >+ } >+ > patrons_table.DataTable().draw(); >+ update_search_description(); > } > > // modify parent window owner element >- [% IF selection_type == 'add' %] >- function add_user(borrowernumber, borrowername) { >- var p = window.opener; >- // In one place (serials/routing.tt), the page is reload on every add >- // We have to wait for the page to be there >- function wait_for_opener () { >- if ( ! $(opener.document).find('body').size() ) { >- setTimeout(wait_for_opener, 500); >+ function add_user(borrowernumber, borrowername) { >+ var p = window.opener; >+ // In one place (serials/routing.tt), the page is reload on every add >+ // We have to wait for the page to be there >+ function wait_for_opener () { >+ if ( ! $(opener.document).find('body').size() ) { >+ setTimeout(wait_for_opener, 500); >+ } else { >+ [%# Note that add_user could sent data instead of borrowername too %] >+ $("#info").hide(); >+ $("#error").hide(); >+ if ( p.add_user(borrowernumber, borrowername) < 0 ) { >+ $("#error").html(_("Patron '%s' is already in the list.").format(borrowername)); >+ $("#error").show(); > } else { >- [%# Note that add_user could sent data instead of borrowername too %] >- $("#info").hide(); >- $("#error").hide(); >- if ( p.add_user(borrowernumber, borrowername) < 0 ) { >- $("#error").html(_("Patron '%s' is already in the list.").format(borrowername)); >- $("#error").show(); >- } else { >- $("#info").html(_("Patron '%s' added.").format(borrowername)); >- $("#info").show(); >- } >+ $("#info").html(_("Patron '%s' added.").format(borrowername)); >+ $("#info").show(); > } > } >- wait_for_opener(); > } >- [% ELSIF selection_type == 'select' %] >- function select_user(borrowernumber, data) { >- var p = window.opener; >- [% IF callback %] >- p.[% callback | html %](borrowernumber, data); >- [% ELSE %] >- p.select_user(borrowernumber, data); >- [% END %] >- window.close(); >- } >- [% END %] >+ wait_for_opener(); >+ } >+ function select_user(borrowernumber, data) { >+ var p = window.opener; >+ [% IF callback %] >+ p.[% callback | html %](borrowernumber, data); >+ [% ELSE %] >+ p.select_user(borrowernumber, data); >+ [% END %] >+ window.close(); >+ } > </script> > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patronfields.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patronfields.inc >index 7edc5c90827..6380e78ecd7 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/patronfields.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patronfields.inc >@@ -1,6 +1,6 @@ > [%- BLOCK patron_fields -%] > [%- SWITCH name -%] >- [%- CASE 'standard' -%]<span>Standard</span> >+ [%- CASE 'surname,firstname,othernames,cardnumber,userid' -%]<span>Standard</span> > [%- CASE 'borrowernumber' -%]<span>Borrowernumber</span> > [%- CASE 'cardnumber' -%]<span>Card number</span> > [%- CASE 'surname' -%]<span>Surname</span> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt >index d1d2641e7c9..016060065da 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt >@@ -6,6 +6,10 @@ > [% USE Categories %] > [% SET footerjs = 1 %] > [% PROCESS 'patronfields.inc' %] >+[% SET libraries = Branches.all %] >+[% SET categories = Categories.all.unblessed %] >+[% SET columns = ['cardnumber', 'name', 'dateofbirth', 'branch', 'category', 'dateexpiry', 'checkouts', 'account_balance', 'borrowernotes', 'action'] %] >+[% PROCESS 'patron-search.inc' %] > [% INCLUDE 'doc-head-open.inc' %] > <title>Patrons[% IF ( searching ) %] › Search results[% END %] › Koha</title> > [% INCLUDE 'doc-head-close.inc' %] >@@ -53,13 +57,6 @@ > [% INCLUDE 'patron-toolbar.inc' %] > [% INCLUDE 'noadd-warnings.inc' %] > >- <div class="browse"> >- Browse by last name: >- [% FOREACH letter IN alphabet.split(' ') %] >- <a href="#" class="filterByLetter">[% letter | html %]</a> >- [% END %] >- </div> >- > [% IF CAN_user_borrowers_edit_borrowers && pending_borrower_modifications %] > <div class="pending-info" id="patron_updates_pending"> > <a href="/cgi-bin/koha/members/members-update.pl">Patrons requesting modifications</a>: >@@ -67,10 +64,9 @@ > </div> > [% END %] > >- <div id="searchresults"> >- <h3>Patrons found for: <span id="searchpattern">[% IF searchmember %] for '[% searchmember | html %]'[% END %]</span></h3> >+ <div id="patron_search_results"> > [% IF CAN_user_tools_manage_patron_lists || CAN_user_borrowers_edit_borrowers %] >- <div class="searchheader fh-fixedHeader" id="searchheader"> >+ <div class="searchheader fh-fixedHeader" id="searchheader" style="display:none;"> > <div> > <a href="#" class="btn btn-link" id="select_all"><i class="fa fa-check"></i> Select all</a> > | >@@ -103,26 +99,10 @@ > </div> > [% END %] > >- <table id="memberresultst"> >- <thead> >- <tr> >- [% IF CAN_user_borrowers_edit_borrowers || CAN_user_tools_manage_patron_lists %] >- <th> </th> >- [% END %] >- <th>Card</th> >- <th>Name</th> >- <th>Date of birth</th> >- <th>Category</th> >- <th>Library</th> >- <th>Expires on</th> >- <th>OD/Checkouts</th> >- <th>Fines</th> >- <th>Circ note</th> >- <th> </th> >- </tr> >- </thead> >- <tbody></tbody> >- </table> >+ [% IF CAN_user_borrowers_edit_borrowers || CAN_user_tools_manage_patron_lists %] >+ [% columns.unshift('checkbox') | html %] >+ [% END %] >+ [% PROCESS patron_search_table table_id => 'memberresultst' columns => columns %] > </div> > > </main> >@@ -130,76 +110,7 @@ > > <div class="col-sm-2 col-sm-pull-10"> > <aside> >- <form method="get" id="searchform"> >- <input type="hidden" id="firstletter_filter" value="" /> >- <fieldset class="brief"> >- <h3>Search patrons</h3> >- <ol> >- <li> >- <label for="searchmember_filter">Search for:</label> >- <input type="text" id="searchmember_filter" value="[% searchmember | html %]"/> >- </li> >- <li> >- <label for="searchfieldstype_filter">Search field:</label> >- <select name="searchfieldstype" id="searchfieldstype_filter"> >- [% pref_fields = Koha.Preference('DefaultPatronSearchFields').split(',') %] >- [% default_fields = [ 'standard', 'surname', 'cardnumber', 'email', 'borrowernumber', 'userid', 'phone', 'address', 'dateofbirth', 'sort1', 'sort2' ] %] >- [% search_options = default_fields.merge(pref_fields).unique %] >- [% FOREACH s_o IN search_options %] >- [% display_name = PROCESS patron_fields name=s_o %] >- [% NEXT IF !display_name %] >- [% IF searchfieldstype == s_o %] >- <option selected="selected" value=[% s_o | html %]>[% display_name | $raw %]</option> >- [% ELSE %] >- <option value=[% s_o | html %]>[% display_name | $raw %]</option> >- [% END %] >- [% END %] >- </select> >- </li> >- <li> >- <label for="searchtype_filter">Search type:</label> >- <select name="searchtype" id="searchtype_filter"> >- [% IF searchtype == "start_with" %] >- <option value='start_with' selected="selected">Starts with</option> >- <option value="contain">Contains</option> >- [% ELSE %] >- <option value='start_with'>Starts with</option> >- <option value="contain" selected="selected">Contains</option> >- [% END %] >- </select> >- </li> >- <li> >- <label for="categorycode_filter">Patron category:</label> >- [% SET categories = Categories.all() %] >- <select id="categorycode_filter"> >- <option value="">Any</option> >- [% FOREACH cat IN categories %] >- [% IF cat.categorycode == categorycode_filter %] >- <option selected="selected" value="[% cat.categorycode | html %]">[% cat.description | html %]</option> >- [% ELSE %] >- <option value="[% cat.categorycode | html %]">[% cat.description | html %]</option> >- >- [% END %] >- [% END %] >- </select> >- </li> >- <li> >- <label for="branchcode_filter">Library:</label> >- [% SET branches = Branches.all( selected => branchcode_filter, only_from_group => 1 ) %] >- <select id="branchcode_filter"> >- [% IF branches.size != 1 %] >- <option value="">Any</option> >- [% END %] >- [% PROCESS options_for_libraries libraries => branches %] >- </select> >- </li> >- </ol> >- <fieldset class="action"> >- <input type="submit" value="Search" /> >- <input type="button" value="Clear" id="clear_search" /> >- </fieldset> >- </fieldset> >- </form> >+ [% PROCESS patron_search_filters categories => categories, libraries => libraries, filters => ['search_field', 'search_type', 'category', 'branch'], search_filter => searchmember %] > </aside> > </div> <!-- /.col-sm-2.col-sm-pull-10 --> > </div> <!-- /.row --> >@@ -234,16 +145,8 @@ > [% INCLUDE 'datatables.inc' %] > [% INCLUDE 'columns_settings.inc' %] > [% INCLUDE 'str/members-menu.inc' %] >- [% Asset.js("lib/hc-sticky.js") | $raw %] > [% Asset.js("js/members-menu.js") | $raw %] > <script> >- var singleBranchMode = '[% singleBranchMode | html %]'; >- var dtMemberResults; >- var search = 1; >- /* popstate event triggered by forward and back button. Need to refresh search */ >- window.addEventListener('popstate', (event) => { >- getSearchByLocation( false ); >- }); > > $(document).ready(function() { > $('#merge-patrons').prop('disabled', true); >@@ -313,10 +216,6 @@ > patronListAdd(); > }); > >- $(".filterByLetter").on("click",function(e){ >- e.preventDefault(); >- filterByFirstLetterSurname( $(this).text(), true ); >- }); > $("#select_all").on("click",function(e){ > e.preventDefault(); > $(".selection").prop("checked", true).change(); >@@ -325,11 +224,6 @@ > e.preventDefault(); > $(".selection").prop("checked", false).change(); > }); >- $("#clear_search").on("click",function(e){ >- e.preventDefault(); >- clearFilters(true); >- }); >- $("#searchform").on("submit", filter); > > [% IF searchmember %] > $("#searchmember_filter").val("[% searchmember | html %]"); >@@ -347,161 +241,16 @@ > $("#branchcode_filter").val("[% branchcode_filter | html %]"); > [% END %] > >- [% IF view != "show_results" %] >- search = 0; >- [% ELSE %] >- $("#searchresults").show(); >- [% END %] >- >- // Build the aLengthMenu >- var aLengthMenu = [ >- [% PatronsPerPage | html %], 10, 20, 50, 100, -1 >- ]; >- jQuery.unique(aLengthMenu); >- aLengthMenu.sort(function( a, b ){ >- // Put "All" at the end >- if ( a == -1 ) { >- return 1; >- } else if ( b == -1 ) { >- return -1; >- } >- return parseInt(a) < parseInt(b) ? -1 : 1;} >- ); >- var aLengthMenuLabel = []; >- $(aLengthMenu).each(function(){ >- if ( this == -1 ) { >- // Label for -1 is "All" >- aLengthMenuLabel.push(_("All")); >- } else { >- aLengthMenuLabel.push(this); >- } >- }); >+ $("#searchheader").hide(); >+ $("#patron_search_form").on('submit', function(){$("#searchheader").show();}); >+ $("#clear_search").on("click",function(e){$("#searchheader").hide();}); > > // Apply DataTables on the results table >- var columns_settings = [% TablesSettings.GetColumns( 'members', 'member', 'memberresultst', 'json' ) | $raw %]; >+ var table_settings = [% TablesSettings.GetColumns( 'members', 'member', 'memberresultst', 'json' ) | $raw %]; > [% UNLESS CAN_user_borrowers_edit_borrowers OR CAN_user_tools_manage_patron_lists %] > [%# Remove the first column if we do not display the checkbox %] >- columns_settings.splice(0, 1); >+ table_settings.splice(0, 1); > [% END %] >- dtMemberResults = KohaTable("memberresultst", { >- 'bServerSide': true, >- 'sAjaxSource': "/cgi-bin/koha/svc/members/search", >- 'fnServerData': function(sSource, aoData, fnCallback) { >- if ( ! search ) { >- return; >- } >- aoData.push({ >- 'name': 'searchmember', >- 'value': $("#searchmember_filter").val() >- },{ >- 'name': 'firstletter', >- 'value': $("#firstletter_filter").val() >- },{ >- 'name': 'searchfieldstype', >- 'value': $("#searchfieldstype_filter").val() >- },{ >- 'name': 'searchtype', >- 'value': $("#searchtype_filter").val() >- },{ >- 'name': 'categorycode', >- 'value': $("#categorycode_filter").val() >- },{ >- 'name': 'branchcode', >- 'value': $("#branchcode_filter").val() >- },{ >- 'name': 'name_sorton', >- 'value': 'borrowers.surname borrowers.firstname' >- },{ >- 'name': 'cardnumber_sorton', >- 'value': 'borrowers.cardnumber', >- },{ >- 'name': 'dateofbirth_sorton', >- 'value': 'borrowers.dateofbirth', >- },{ >- 'name': 'dateexpiry_sorton', >- 'value': 'borrowers.dateexpiry', >- },{ >- 'name': 'category_sorton', >- 'value': 'categories.description', >- },{ >- 'name': 'branch_sorton', >- 'value': 'branches.branchname' >- },{ >- 'name': 'borrowernotes_sorton', >- 'value': 'borrowers.borrowernotes' >- },{ >- 'name': 'template_path', >- 'value': 'members/tables/members_results.tt', >- }); >- $.ajax({ >- 'dataType': 'json', >- 'type': 'POST', >- 'url': sSource, >- 'data': aoData, >- 'success': function(json){ >- // redirect if there is only 1 result. >- if ( json.aaData.length == 1 ) { >- var borrowernumber = json.aaData[0].borrowernumber; >- /* Overwrite history state of firstletter search since only one result was returned; This prevents a loop upon clicking back */ >- history.replaceState( {}, null, window.location.href.split("?" )[0]); >- [% IF circsearch == 1 %] >- [% SET redirect = "circ/circulation" %] >- [% ELSE %] >- [% SET redirect = "members/moremember" %] >- [% END %] >- document.location.href="/cgi-bin/koha/[% redirect | $raw %].pl?borrowernumber="+borrowernumber; >- return false; >- } >- fnCallback(json); >- } >- }); >- }, >- 'aoColumns':[ >- [% IF CAN_user_borrowers_edit_borrowers || CAN_user_tools_manage_patron_lists %] >- { 'mDataProp': 'dt_borrowernumber', 'bSortable': false }, >- [% END %] >- { 'mDataProp': 'dt_cardnumber' }, >- { 'mDataProp': 'dt_name' }, >- { 'mDataProp': 'dt_dateofbirth' }, >- { 'mDataProp': 'dt_category' }, >- { >- 'mDataProp': function ( oObj ) { >- if( !singleBranchMode && oObj.dt_branch == "[% Branches.GetLoggedInBranchname | html %]" ){ >- return "<span class=\"currentlibrary\">" + oObj.dt_branch + "</span>"; >- } else { >- return oObj.dt_branch; >- } >- } >- }, >- { 'mDataProp': 'dt_dateexpiry' }, >- { 'mDataProp': 'dt_od_checkouts', 'bSortable': false }, >- { 'mDataProp': 'dt_fines', 'bSortable': false }, >- { 'mDataProp': 'dt_borrowernotes' }, >- { 'mDataProp': 'dt_action', 'bSortable': false, 'sClass': 'actions' } >- ], >- 'bFilter': false, >- 'bAutoWidth': false, >- [% IF CAN_user_borrowers_edit_borrowers || CAN_user_tools_manage_patron_lists %] >- 'aaSorting': [[2, 'asc']], >- [% ELSE %] >- 'aaSorting': [[1, 'asc']], >- [% END %] >- "aLengthMenu": [aLengthMenu, aLengthMenuLabel], >- 'sPaginationType': 'full_numbers', >- "iDisplayLength": [% PatronsPerPage | html %], >- "bProcessing": true, >- "initComplete": function(settings, json) { >- Sticky = $("#searchheader"); >- Sticky.hcSticky({ >- stickTo: "#searchresults", >- stickyClass: "floating" >- }); >- } >- }, columns_settings); >- update_searched(); >- /* Initial page load doesn't trigger the popstate event, so we explicitly call this */ >- getSearchByLocation( false ); >- > }); > > function patronListAdd(){ >@@ -536,52 +285,6 @@ > return true; > } > >- function getSearchByLocation( setstate ){ >- /* Check to see if the URL contains a search parameter */ >- if( location.search != ""){ >- var params = new URLSearchParams( location.search ); >- var firstletter = params.get("firstletter"); >- /* Check to see if search is a first letter param */ >- if( firstletter ){ >- /* Trigger function to return search results by letter */ >- filterByFirstLetterSurname( firstletter, setstate ); >- } >- } >- } >- >- // Update the string "Results found ..." >- function update_searched(){ >- var searched = $("#searchfieldstype_filter").find("option:selected").text(); >- if ( $("#searchmember_filter").val() ) { >- if ( $("#searchtype_filter").val() == 'start_with' ) { >- searched += _(" starting with "); >- } else { >- searched += _(" containing "); >- } >- searched += "'" + $("#searchmember_filter").val() + "'"; >- } >- if ( $("#firstletter_filter").val() ) { >- searched += _(" begins with ") + "'" + $("#firstletter_filter").val() +"'"; >- } >- if ( $("#categorycode_filter").val() ) { >- searched += _(" with category ") + "'" + $("#categorycode_filter").find("option:selected").text() + "'"; >- } >- if ( $("#branchcode_filter").val() ) { >- searched += _(" in library ") + $("#branchcode_filter").find("option:selected").text(); >- } >- $("#searchpattern").text(searched); >- } >- >- // Redraw the table >- function filter() { >- $("#firstletter_filter").val(''); >- update_searched(); >- search = 1; >- $("#searchresults").show(); >- dtMemberResults.fnDraw(); >- return false; >- } >- > $('#memberresultst tbody').on('click','td',function(e){ > var $checkbox = $(this).find("input[type=checkbox]"); > if (e.target.type != "checkbox") { >@@ -590,34 +293,27 @@ > } > }); > >- // User has clicked on the Clear button >- function clearFilters(redraw) { >- $("#searchform select").val(''); >- $("#firstletter_filter").val(''); >- $("#searchmember_filter").val(''); >- if(redraw) { >- /* remove any search string added by firstletter search */ >- history.pushState( {}, null, window.location.href.split("?" )[0]); >- update_searched(); >- search = 0; >- $("#searchresults").hide(); >- dtMemberResults.fnDraw(); >- } >- } >- >- // User has clicked on a letter >- function filterByFirstLetterSurname( letter, setstate ) { >- clearFilters(false); >- $("#firstletter_filter").val(letter); >- if( setstate ){ >- history.pushState( null, null, "?firstletter=" + letter ); >- } >- update_searched(); >- search = 1; >- $("#searchresults").show(); >- dtMemberResults.fnDraw(); >- } > </script> >+ >+ [% IF circsearch == 1 %] >+ [% SET redirect_url = '/cgi-bin/koha/circ/circulation.pl' %] >+ [% ELSE %] >+ [% SET redirect_url = '/cgi-bin/koha/members/moremember.pl' %] >+ [% END %] >+ [% PROCESS patron_search_js >+ table_id => 'memberresultst', >+ categories => categories, >+ libraries => libraries, >+ extended_attribute_types => attribute_type_codes, >+ columns => columns, >+ actions => ['edit', 'checkout'], >+ redirect_if_one_result => 1, >+ redirect_url => redirect_url, >+ sticky_header => "searchheader", >+ sticky_to => "patron_search_results", >+ %] >+ >+ > [% END %] > > [% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/search.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/search.tt >index 9e404c9efbb..ec5b390e0b7 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/search.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/search.tt >@@ -17,7 +17,7 @@ > <div id="patron_search" class="yui-t7"> > <div class="container-fluid"> > >- [% PROCESS patron_search_filters categories => categories, libraries => libraries, columns => columns, search_filter => searchmember %] >+ [% PROCESS patron_search_filters categories => categories, libraries => libraries, filters => ['branch', 'category'], search_filter => searchmember %] > </form> > > [% PROCESS patron_search_table table_id => 'memberresultst' columns => columns %] >@@ -35,7 +35,8 @@ > extended_attribute_types => attribute_type_codes, > columns => columns, > filter => filter, >- selection_type => selection_type, >+ actions => [selection_type], >+ preview_on_name_click => 1, > callback => callback > %] > [% END %] >diff --git a/members/member.pl b/members/member.pl >index b6ce83fb7a6..bd85a3b613c 100755 >--- a/members/member.pl >+++ b/members/member.pl >@@ -29,6 +29,7 @@ use C4::Output qw( output_html_with_http_headers ); > use CGI qw( -utf8 ); > use Koha::List::Patron qw( GetPatronLists ); > use Koha::Patrons; >+use Koha::Patron::Attribute::Types; > > my $input = CGI->new; > >@@ -79,6 +80,9 @@ $template->param( > PatronsPerPage => C4::Context->preference("PatronsPerPage") || 20, > view => $view, > circsearch => $circsearch, >+ attribute_type_codes => ( C4::Context->preference('ExtendedPatronAttributes') >+ ? [ Koha::Patron::Attribute::Types->search( { staff_searchable => 1 } )->get_column('code') ] >+ : [] ), > ); > > output_html_with_http_headers $input, $cookie, $template->output; >-- >2.25.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 30063
:
130608
|
130609
|
130610
|
130611
|
130612
|
130613
|
130614
|
130615
|
132387
|
132552
|
132731
|
132732
|
132733
|
132734
|
132735
|
132736
|
132737
|
132738
|
132739
|
132740
|
132741
|
132742
|
132743
|
132744
|
132745
|
132746
|
132747
|
132748
|
132749
|
132759
|
132760
|
132761
|
132762
|
132763
|
132764
|
132765
|
132766
|
132767
|
132768
|
132769
|
132770
|
132771
|
132772
|
132773
|
132774
|
132775
|
132776
|
132777
|
132958