8 [%# Display a simple form %]
9 [% BLOCK patron_search_filters_simple %]
10 <form id="patron_search_form">
11 <div class="hint">Enter patron card number or partial name:</div>
12 <input type="text" size="40" id="search_patron_filter" class="focus" autocomplete="off" />
13 <input type="submit" class="btn btn-primary" value="Search" />
17 [%# Display a complex patron search form %]
18 [%# - Search: input %]
19 [%# You can then pass a list of filters %]
20 [%# - branch: select library list %]
21 [%# - category: select patron category list %]
22 [%# - search_field: select patron field list %]
23 [%# - search_type: select 'contain' or 'start with' %]
24 [% BLOCK patron_search_filters %]
25 <form id="patron_search_form">
26 <fieldset class="brief">
27 <h3>Search for patron</h3>
30 <label for="search_patron_filter">Search:</label>
31 <input type="text" id="search_patron_filter" value="[% search_filter | html %]" class="focus" />
34 [% FOR f IN filters %]
38 <label for="branchcode_filter">Library:</label>
39 <select id="branchcode_filter">
40 [% SET libraries = Branches.all( only_from_group => 1 ) %]
41 [% IF libraries.size != 1 %]
42 <option value="">Any</option>
44 [% FOREACH l IN libraries %]
45 <option value="[% l.branchcode | html %]">[% l.branchname | html %]</option>
51 <label for="categorycode_filter">Category:</label>
52 <select id="categorycode_filter">
53 <option value="">Any</option>
54 [% FOREACH category IN categories %]
55 <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
61 <label for="sort1_filter">Sort1:</label>
62 [% PROCESS 'av-build-dropbox.inc' name="sort1_filter", category="Bsort1", empty=1, size = 20 %]
66 <label for="sort2_filter">Sort2:</label>
67 [% PROCESS 'av-build-dropbox.inc' name="sort2_filter", category="Bsort2", empty=1, size = 20 %]
69 [% CASE 'search_field' %]
71 [% INCLUDE patron_fields_dropdown %]
73 [% CASE 'search_type' %]
75 <label for="searchtype_filter">Search type:</label>
76 <select name="searchtype" id="searchtype_filter">
77 [% IF searchtype == "start_with" %]
78 <option value='start_with' selected="selected">Starts with</option>
79 <option value="contain">Contains</option>
81 <option value='start_with'>Starts with</option>
82 <option value="contain" selected="selected">Contains</option>
89 <fieldset class="action">
90 <input type="submit" class="btn btn-primary" value="Search" />
91 <input type="button" value="Clear" id="clear_search" />
97 [%# Display the table with: %]
98 [%# - At the top a hint about a possible filter %]
99 [%# - Browse by last name %]
101 [%# Get the following parameters: %]
102 [%# - filter: can be 'suggestions_managers', 'orders_managers', 'funds_owners', 'funds_users' or 'erm_users' to filter patrons on their permissions %]
103 [%# - table_id: the ID of the table %]
104 [%# open_on_row_click: See patron_search_js %]
105 [%# columns: See patron_search_js %]
106 [% BLOCK patron_search_table %]
108 [% IF filter == 'suggestions_managers' %]
109 <div class="hint">Only staff with superlibrarian or suggestions_manage permissions are returned in the search results</div>
110 [% ELSIF filter == 'orders_managers' %]
111 <div class="hint">Only staff with superlibrarian or acquisitions permissions (or order_manage permission if granular permissions are enabled) are returned in the search results</div>
112 [% ELSIF filter == 'funds_owners' OR filter == 'funds_users' %]
113 <div class="hint">Only staff with superlibrarian or acquisitions permissions (or budget_modify permission if granular permissions are enabled) are returned in the search results</div>
114 [% ELSIF filter == 'erm_users' %]
115 <div class="hint">Only staff with superlibrarian or ERM permissions are returned in the search results</div>
120 [% SET alphabet = Koha.Preference('alphabet').split(' ') %]
121 [% UNLESS alphabet.size %]
122 [% alphabet = ['A' .. 'Z'] %]
124 [% FOREACH letter IN alphabet %]
125 <a href="#" class="filterByLetter">[% letter | html %]</a>
130 <h3 style="display: none;">Patrons found for: <span id="searchpattern"></span></h3>
132 <div id="[% table_id | html %]_search_results" style="display:none;">
134 <div id="info" class="dialog message" style="display: none;"></div>
135 <div id="error" class="dialog alert" style="display: none;"></div>
137 <input type="hidden" id="firstletter_filter" value="" />
138 [% IF open_on_row_click %]
139 <table id="[% table_id | html %]" class="selections-table">
141 <table id="[% table_id | html %]">
145 [% FOR column IN columns %]
147 [% CASE 'checkbox' %]<th class="noExport"></th>
148 [% CASE 'cardnumber' %]<th>Card</th>
149 [% CASE 'dateofbirth' %]<th>Date of birth</th>
150 [% CASE 'name' %]<th>Name</th>
151 [% CASE 'name-address' %]<th>Name</th>
152 [% CASE 'address' %]<th>Address</th>
153 [% CASE 'address-library' %]<th>Address</th>
154 [% CASE 'branch' %]<th data-filter="libraries">Library</th>
155 [% CASE 'category' %]<th data-filter="categories">Category</th>
156 [% CASE 'dateexpiry' %]<th>Expires on</td>
157 [% CASE 'borrowernotes' %]<th>Notes</th>
158 [% CASE 'phone' %]<th>Phone</th>
159 [% CASE 'checkouts' %]<th>Checkouts</th>
160 [% CASE 'account_balance' %]<th>Fines</th>
161 [% CASE 'action' %]<th> </th>
170 <!-- Patron preview modal -->
171 <div class="modal" id="patronPreview" tabindex="-1" role="dialog" aria-labelledby="patronPreviewLabel">
172 <div class="modal-dialog" role="document">
173 <div class="modal-content">
174 <div class="modal-header">
175 <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
176 <h4 class="modal-title" id="patronPreviewLabel"></h4>
178 <div class="modal-body">
180 <img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading
183 <div class="modal-footer">
184 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
192 [%# Integrate all the JS code, outside of a script tag %]
193 [%# Get the following parameters: %]
194 [%# - redirect_if_one_result: Redirect to the patron if the search returns only one result, note that it will not redirect if filters of the DT are used (this is a feature) %]
195 [%# - redirect_url: The URL to use, the borrowernumber parameter will be added %]
196 [%# - redirect_if_attribute_equal: Name of the attribute to use for the redirect. Query using this attribute, before the normal search %]
197 [%# filter: Same as patron_search_table %]
198 [%# open_on_row_click: boolean, default off. Will allow to select a patron by clicking on the whole tr element %]
199 [%# columns: list of columns that will be displayed. Possible values are: 'checkbox', 'cardnumber', 'dateofbirth', 'address', 'name', 'name-address', 'branch', 'category', 'dateexpiry', 'borrowernotes, 'phone', 'checkouts', 'account_balance', 'action' %]
200 [%# preview_on_name_click: Open a modal window with patron's info when the name is clicked %]
201 [%# actions: list of buttons to display in the action column. Possible values are: 'select', 'add', 'edit', 'checkout' %]
202 [%# sticky_header and sticky_to: If we need a sticky header %]
203 [%# callback: name of the JS function that will be called when a patron is selected. Only work with action=select %]
204 [%# display_search_description: boolean, default off. Display the description of the search %]
205 [% BLOCK patron_search_js %]
207 [% IF redirect_if_one_result && !redirect_url %]
208 <script>console.log("Wrong call of patron_searh_js - missing redirect_url");</script>
211 [% INCLUDE 'select2.inc' %]
213 let categories = [% To.json(categories) | $raw %].map(e => {
214 e['_id'] = e.categorycode.toLowerCase();
215 e['_str'] = e.description;
218 let categories_map = categories.reduce((map, e) => {
222 let libraries = [% To.json(libraries) | $raw %].map(e => {
223 e['_id'] = e.branchcode;
224 e['_str'] = e.branchname;
227 let libraries_map = libraries.reduce((map, e) => {
232 [% IF Koha.Preference('ExtendedPatronAttributes') && extended_attribute_types %]
233 let extended_attribute_types = [% To.json(extended_attribute_types || []) | $raw %];
236 $(document).ready(function() {
237 $('select#sort1_filter').select2({allowClear:true});
238 $('select#sort2_filter').select2({allowClear:true});
242 [% INCLUDE 'datatables.inc' %]
243 [% INCLUDE 'js-patron-get-age.inc' %]
244 [% INCLUDE 'js-patron-format.inc' %]
245 [% INCLUDE 'js-patron-format-address.inc' %]
246 [% IF sticky_header %]
247 [% Asset.js("lib/hc-sticky.js") | $raw %]
254 var singleBranchMode = '[% singleBranchMode | html %]';
255 let logged_in_library_id = "[% Branches.GetLoggedInBranchcode | html %]";
256 [% IF do_not_defer_loading %]
257 let defer_loading = 0;
259 let defer_loading = 1;
262 /* popstate event triggered by forward and back button. Need to refresh search */
263 window.addEventListener('popstate', (event) => {
264 getSearchByLocation( false );
268 [% CASE 'suggestions_managers' %]
269 let patron_search_url = '/api/v1/suggestions/managers';
270 [% CASE 'baskets_managers' %]
271 let patron_search_url = '/api/v1/acquisitions/baskets/managers';
272 [% CASE 'funds_owners' %]
273 let patron_search_url = '/api/v1/acquisitions/funds/owners';
274 [% CASE 'funds_users' %]
275 let patron_search_url = '/api/v1/acquisitions/funds/users';
276 [% CASE 'erm_users' %]
277 let patron_search_url = '/api/v1/erm/users';
279 let patron_search_url = '/api/v1/patrons';
281 $(document).ready(function(){
286 // Build the aLengthMenu
288 [% Koha.Preference('PatronsPerPage') | html %], 10, 20, 50, 100, -1
290 jQuery.unique(aLengthMenu);
291 aLengthMenu.sort(function( a, b ){
292 // Put "All" at the end
295 } else if ( b == -1 ) {
298 return parseInt(a) < parseInt(b) ? -1 : 1;}
300 var aLengthMenuLabel = [];
301 $(aLengthMenu).each(function(){
303 // Label for -1 is "All"
304 aLengthMenuLabel.push(_("All"));
306 aLengthMenuLabel.push(this);
310 let additional_filters = {
312 let start_with = $("#firstletter_filter").val()
313 if (!start_with) return "";
314 return { "like": start_with + "%" }
318 let f_sort1 = $("#sort1_filter").val();
324 let f_sort2 = $("#sort2_filter").val();
331 let pattern = $("#search_patron_filter").val();
333 if ( filters.length == 0 ) {
340 let patterns = pattern.split(/[\s,]+/).filter(function(s){ return s.length });
342 let search_type = $("#searchtype_filter").val() || "contain";
343 let search_fields = $("#searchfieldstype_filter").val();
344 if ( !search_fields ) {
345 search_fields = "[% Koha.Preference('DefaultPatronSearchFields') || 'firstname,middle_name,surname,othernames,cardnumber,userid' | html %]";
348 let subquery_and = [];
349 patterns.forEach(function(pattern,i){
351 search_fields.split(',').forEach(function(attr,ii){
352 sub_or.push({["me."+attr]:{"like":(search_type == "contain" ? "%" : "" ) + pattern + "%"}});
353 if ( attr == 'dateofbirth' ) {
355 let d = $date_to_rfc3339(pattern);
356 sub_or.push({["me."+attr]:d});
358 // Hide the warning if the date is not correct
362 subquery_and.push(sub_or);
364 filters.push({"-and": subquery_and});
366 [% IF Koha.Preference('ExtendedPatronAttributes') && extended_attribute_types %]
368 patterns.forEach(function(pattern,i){
371 "extended_attributes.value": { "like": "%" + pattern + (search_type == "contain" ? "%" : "" )},
372 "extended_attributes.code": extended_attribute_types
374 subquery_and.push(sub_or);
376 filters.push({"-and": subquery_and});
382 [% UNLESS default_sort_column %]
383 [% default_sort_column = "name" %]
385 [% SET order_column_index = 0 %]
386 [% SET embed = ['extended_attributes'] %]
387 patrons_table = $("#[% table_id | html %]").kohaTable({
389 "url": patron_search_url,
390 "dataSrc": function ( json ) {
391 [% IF redirect_if_one_result %]
392 // redirect if there is only 1 result.
393 if ( first_draw && json.recordsFiltered == 1 ) {
394 let url = '[% redirect_url | url %]'.indexOf("?") != -1
395 ? '[% redirect_url | url %]&borrowernumber=' + json.data[0].patron_id
396 : '[% redirect_url | url %]?borrowernumber=' + json.data[0].patron_id;
397 document.location.href = url;
405 [% IF open_on_row_click OR preview_on_name_click OR remember_selections %]
406 "drawCallback": function( settings ) {
407 var api = this.api();
408 var data = api.data();
409 if ( data.length == 0 ) return;
411 [% IF open_on_row_click %]
412 $.each($(this).find("tbody tr"), function(index, tr) {
413 let url = "[% on_click_url | url %]&borrowernumber=" + data[index].patron_id;
414 $(tr).off('click').on('click', function() {
415 document.location.href = url;
416 }).addClass('clickable');
417 $(tr).find("a.patron_name").attr('href', url);
420 [% IF preview_on_name_click %]
421 $.each($(this).find("tbody tr"), function(index, tr) {
422 $(tr).find("a.patron_name").addClass("patron_preview");
425 [% IF remember_selections %]
430 "iDeferLoading": defer_loading,
432 [% FOR column IN columns %]
433 [% IF default_sort_column == column %]
434 [% order_column_index = loop.count - 1%]
437 [% CASE 'checkbox' %]
442 "render": function( data, type, row, meta ) {
443 return "<label for='check" + data + "' class='content_hidden'>" + _("Select patron") + "</label><input type='checkbox' id='check" + data + "' class='selection' name='borrowernumber' value='" + data + "' />";
446 [% CASE 'cardnumber' %]
448 "data": "cardnumber",
451 "render": function( data, type, row, meta ) {
452 let patron_id = encodeURIComponent(row.patron_id);
453 [% IF !open_on_row_click AND CAN_user_circulate_circulate_remaining_permissions %]
454 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>";
456 return escape_str(data);
461 [% CASE 'dateofbirth' %]
463 "data": "date_of_birth",
466 "render": function( data, type, row, meta ) {
467 return data ? "<span class=\"dateofbirth\">" + escape_str($date(data)) + "<span class=\"agehint\"> (" + _("%s years").format($get_age(data)) + ")</span></span>" : "";
472 "data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
475 "render": function( data, type, row, meta ) {
476 let r = '<div class="address"><ul>';
477 r += $format_address(row, { no_line_break: true, include_li: true });
482 [% CASE 'address-library' %]
484 "data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
487 "render": function( data, type, row, meta ) {
488 let r = '<div class="address"><ul>';
489 r += $format_address(row, { no_line_break: true, include_li: true });
491 r += " " + escape_str(libraries_map[row.library_id].branchname);
495 [% CASE 'name-address' %]
497 "data": "me.surname:me.firstname:me.middle_name:me.othernames:me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
500 "render": function( data, type, row, meta ) {
501 let patron_id = encodeURIComponent(row.patron_id);
503 [% IF ! open_on_row_click %]
504 r += "<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>";
506 r += $patron_to_html(row, { invert_name: 1 });
509 r += '<div class="address"><ul>';
510 r += $format_address(row, { no_line_break: true, include_li: true });
513 r += "<li>" + _("Email: ") + "<a href='mailto:" + encodeURIComponent(row.email) + "'>" + escape_str(row.email) + "</a></li>";
520 [% CASE 'name-address' %]
522 "data": "me.surname:me.firstname:me.othernames:me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
525 "render": function( data, type, row, meta ) {
526 let patron_id = encodeURIComponent(row.patron_id);
528 [% IF ! open_on_row_click %]
529 r += "<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>";
531 r += $patron_to_html(row, { invert_name: 1 });
534 r += '<div class="address"><ul>';
535 r += $format_address(row, { no_line_break: true, include_li: true });
538 r += "<li>" + _("Email: ") + "<a href='mailto:" + encodeURIComponent(row.email) + "'>" + escape_str(row.email) + "</a></li>";
547 "data": "me.surname:me.firstname:me.middle_name:me.othernames",
550 "render": function( data, type, row, meta ) {
551 let patron_id = encodeURIComponent(row.patron_id);
552 [% IF ! open_on_row_click %]
553 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>";
555 return $patron_to_html(row, { invert_name: 1 });
561 "data": "library_id",
564 "render": function( data, type, row, meta ) {
565 let library_name = libraries_map[data].branchname
566 if( !singleBranchMode && data == logged_in_library_id ) {
567 return "<span class=\"currentlibrary\">" + escape_str(library_name) + "</span>";
569 return escape_str(library_name);
573 [% CASE 'category' %]
575 "data": "category_id",
578 "render": function( data, type, row, meta ) {
579 return escape_str(categories_map[data.toLowerCase()].description);
582 [% CASE 'dateexpiry' %]
584 "data": "expiry_date",
587 "render": function( data, type, row, meta ) {
588 return data ? escape_str($date(data)) : "";
591 [% CASE 'borrowernotes' %]
593 "data": "staff_notes",
596 [%# We don't escape here, we allow html tag in staff notes %]
603 "render": function( data, type, row, meta ) {
604 return escape_str(data);
607 [% CASE 'checkouts' %][% embed.push('checkouts+count', 'overdues+count') %]
612 "render": function( data, type, row, meta ) {
613 if ( row.overdues_count ) {
614 return "<span class='overdue'><strong>"+row.overdues_count + "</strong></span>";
616 return "0 / " + row.checkouts_count;
620 [% CASE 'account_balance' %][% embed.push('account_balance') %]
625 "render": function( data, type, row, meta ) {
626 let r = "<span style='text-align: right; display: block;'><a href=\"/cgi-bin/koha/members/boraccount.pl?borrowernumber="+row.patron_id+"\">";
627 let balance_str = row.account_balance || 0;
628 balance_str = balance_str.escapeHtml().format_price();
629 if ( row.account_balance < 0 ) {
630 // FIXME Format price here
631 r += "<span class='credit'>" + balance_str + "</span>";
632 } else if ( row.account_balance > 0 ) {
633 r += "<span class='debit'><strong>" + balance_str + "</strong></span>"
644 "data": function( row, type, val, meta ) {
646 let patron_id = encodeURIComponent(row.patron_id);
647 let action_node = "";
648 [% FOR action IN actions %]
651 let patron_str = JSON.stringify(row);
652 action_node += '<a href="#" class="btn btn-default btn-xs select_user" data-borrowernumber="' + patron_id + '">' + _("Select") + '</a>';
653 let input_node = $('<input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '"/>');
654 $(input_node).val(patron_str);
655 action_node += $(input_node).prop('outerHTML');
657 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 + '" />';
659 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>';
660 [% CASE 'checkout' %]
661 [% IF CAN_user_circulate_circulate_remaining_permissions %]
662 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>';
672 [% UNLESS loop.last %],[% END %]
675 'embed': [% To.json(embed) | $raw %],
676 "order": [[ [% order_column_index | html %], "asc" ]],
678 'lengthMenu': [aLengthMenu, aLengthMenuLabel],
679 'sPaginationType': 'full_numbers',
680 "pageLength": [% Koha.Preference('PatronsPerPage') | html %],
681 [% IF sticky_header %]
682 "initComplete": function(settings, json) {
683 $("#[% sticky_header | html %]").show();
684 Sticky = $("#[% sticky_header | html %]");
686 stickTo: "#[% sticky_to | html %]",
687 stickyClass: "floating"
691 }, typeof table_settings !== 'undefined' ? table_settings : null, 1, additional_filters);
693 $("#patron_search_form").on('submit', filter);
694 $("#patron_search_form").on('submit', update_search_type);
695 $(".filterByLetter").on("click",function(e){
697 filterByFirstLetterSurname($(this).text(), true);
699 $("body").on("click",".add_user",function(e){
701 var borrowernumber = $(this).data("borrowernumber");
702 var firstname = $(this).data("firstname");
703 var surname = $(this).data("surname");
704 add_user( borrowernumber, firstname + " " + surname );
707 $("body").on("click",".select_user",function(e){
709 var borrowernumber = $(this).data("borrowernumber");
710 var borrower_data = $("#borrower_data"+borrowernumber).val();
711 select_user( borrowernumber, JSON.parse(borrower_data) );
714 $("body").on("click",".patron_preview", function( e ){
716 var borrowernumber = $(this).data("borrowernumber");
717 var page = "/cgi-bin/koha/members/moremember.pl?print=brief&borrowernumber=" + borrowernumber;
718 $("#patronPreview .modal-body").load( page + " div.container-fluid" );
719 $('#patronPreview').modal({show:true});
722 $("#patronPreview").on('hidden.bs.modal', function (e) {
723 $("#patronPreview .modal-body").html("<img src=\"[% interface | html %]/[% theme | html %]/img/spinner-small.gif\" alt=\"\" /> Loading");
726 $("#clear_search").on("click",function(e){
729 $("#searchpattern").parent().hide();
732 if ( !defer_loading ) {
733 $("#patron_search_form").submit();
736 /* Initial page load does not trigger the popstate event, so we explicitly call this */
737 getSearchByLocation( false );
741 function getSearchByLocation( setstate ){
742 /* Check to see if the URL contains a search parameter */
743 if( location.search != ""){
744 var params = new URLSearchParams( location.search );
745 var firstletter = params.get("firstletter");
746 /* Check to see if search is a first letter param */
748 /* Trigger function to return search results by letter */
749 filterByFirstLetterSurname( firstletter, setstate );
754 function update_search_type(){
755 $("#searchtype").val($("#searchtype_filter").val());
758 function update_search_description(){
759 var searched = $("#searchfieldstype_filter").find("option:selected").text();
760 if ( $("#search_patron_filter").val() ) {
761 if ( $("#searchtype_filter").val() == 'start_with' ) {
762 searched += _(" starting with ");
764 searched += _(" containing ");
766 searched += "'" + $("#search_patron_filter").val() + "'";
768 if ( $("#firstletter_filter").val() ) {
769 searched += _(" begins with ") + "'" + $("#firstletter_filter").val() +"'";
771 if ( $("#categorycode_filter").val() ) {
772 searched += _(" with category ") + "'" + $("#categorycode_filter").find("option:selected").text() + "'";
774 if ( $("#branchcode_filter").val() ) {
775 searched += _(" in library ") + $("#branchcode_filter").find("option:selected").text();
777 if ( $("#sort1_filter").val() ) {
778 searched += _(" with sort1 ")
779 if ( $("select#sort1_filter") ) {
780 searched += $("select#sort1_filter").find("option:selected").text();
783 searched += $("#sort1_filter").val();
786 if ( $("#sort2_filter").val() ) {
787 searched += _(" with sort2 ");
788 if ( $("select#sort2_filter") ) {
789 searched += $("select#sort2_filter").find("option:selected").text();
792 searched += $("#sort2_filter").val();
795 $("#searchpattern").text(searched);
796 $("#searchpattern").parent().show();
800 [% IF redirect_if_attribute_equal %]
801 let filter = $("#search_patron_filter").val();
804 data: { cardnumber: filter, _match: 'exact' },
806 url: patron_search_url,
807 success: function(data) {
808 if ( data.length == 1 ) {
809 let url = '[% redirect_url | url %]'.indexOf("?") != -1
810 ? '[% redirect_url | url %]&borrowernumber=' + data[0].patron_id
811 : '[% redirect_url | url %]?borrowernumber=' + data[0].patron_id;
812 document.location.href = url;
817 alert( _("An error occurred. Check the logs") );
822 $("#firstletter_filter").val('');
823 $("#[% table_id | html %]_search_results").show();
825 let table_dt = patrons_table.DataTable();
826 [% FOR c IN columns %]
829 library_id = $("#branchcode_filter").val() || "";
830 patrons_table.find('thead tr:eq(1) th[data-filter="libraries"] select').val(library_id);
831 table_dt.column([% loop.count - 1 %]).search(library_id ? '^'+library_id+'$' : '');
832 [% CASE 'category' %]
833 let category_id = $("#categorycode_filter").val() || "";
834 patrons_table.find('thead tr:eq(1) th[data-filter="categories"] select').val(category_id);
835 table_dt.column([% loop.count - 1 %]).search(category_id ? '^'+category_id+'$' : '');
839 first_draw = 1; // Only redirect if we are coming from here
841 [% IF display_search_description %]
842 update_search_description();
847 function clearFilters() {
848 $("#searchfieldstype_filter option:first").prop("selected", true);
849 $("#searchtype_filter option[value='contain']").prop("selected", true);
850 $("#categorycode_filter option:first").prop("selected", true);
851 $("#branchcode_filter option:first").prop("selected", true);
852 $("#sort1_filter").val('').trigger("change");
853 $("#sort2_filter").val('').trigger("change");
854 $("#firstletter_filter").val('');
855 $("#search_patron_filter").val('');
856 /* remove any search string added by firstletter search */
857 history.pushState( {}, null, window.location.href.split("?" )[0]);
858 $("#[% table_id | html %]_search_results").hide();
859 [% IF display_search_description %]
860 update_search_description();
864 // User has clicked on a letter
865 function filterByFirstLetterSurname(letter, setstate ) {
866 $("#firstletter_filter").val(letter);
868 $("#[% table_id | html %]_search_results").show();
871 history.pushState( null, null, "?firstletter=" + letter );
874 patrons_table.DataTable().draw();
875 [% IF display_search_description %]
876 update_search_description();
880 // modify parent window owner element
881 function add_user(borrowernumber, borrowername) {
882 var p = window.opener;
883 // In one place (serials/routing.tt), the page is reload on every add
884 // We have to wait for the page to be there
885 function wait_for_opener () {
886 if ( ! $(opener.document).find('body').size() ) {
887 setTimeout(wait_for_opener, 500);
889 [%# Note that add_user could sent data instead of borrowername too %]
892 if ( p.add_user(borrowernumber, borrowername) < 0 ) {
893 $("#error").html(_("Patron '%s' is already in the list.").format(borrowername));
896 $("#info").html(_("Patron '%s' added.").format(borrowername));
903 function select_user(borrowernumber, data) {
904 var p = window.opener;
905 if ( p.document.getElementById("selected_patron_id") ) {
906 p.document.getElementById("selected_patron_id").value = borrowernumber;
909 p.[% callback | html %](borrowernumber, data);
911 p.select_user(borrowernumber, data);