Bug 30063: Fix address format
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / includes / patron-search.inc
1 [% USE Koha %]
2 [% USE I18N %]
3 [% USE Branches %]
4 [% USE raw %]
5 [% USE Asset %]
6 [% USE To %]
7
8 [% BLOCK patron_search_filters_simple  %]
9     <form id="patron_search_form">
10         <div class="hint">Enter patron card number or partial name:</div>
11         <input type="text" size="40" id="search_patron_filter" class="focus" autocomplete="off" />
12         <input type="submit" value="Search" />
13     </form>
14 [% END %]
15
16 [% BLOCK patron_search_filters %]
17     <form id="patron_search_form">
18         <fieldset class="brief">
19             <h3>Search for patron</h3>
20             <ol>
21                 <li>
22                     <label for="search_patron_filter">Search:</label>
23                     <input type="text" id="search_patron_filter" value="[% search_filter | html %]" class="focus" />
24                 </li>
25
26                 [% FOR f IN filters %]
27                     [% SWITCH f %]
28                     [% CASE 'branch' %]
29                         <li>
30                             <label for="branchcode_filter">Library:</label>
31                             <select id="branchcode_filter">
32                                 [% SET libraries = Branches.all( only_from_group => 1 ) %]
33                                 [% IF libraries.size != 1 %]
34                                     <option value="">Any</option>
35                                 [% END %]
36                                 [% FOREACH l IN libraries %]
37                                     <option value="[% l.branchcode | html %]">[% l.branchname | html %]</option>
38                                 [% END %]
39                             </select>
40                         </li>
41                     [% CASE 'category' %]
42                         <li>
43                             <label for="categorycode_filter">Category:</label>
44                             <select id="categorycode_filter">
45                                 <option value="">Any</option>
46                                 [% FOREACH category IN categories %]
47                                     <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
48                                 [% END %]
49                             </select>
50                         </li>
51                     [% CASE 'search_field' %]
52                         <li>
53                             <label for="searchfieldstype_filter">Search field:</label>
54                             <select name="searchfieldstype" id="searchfieldstype_filter">
55                                 [% pref_fields = Koha.Preference('DefaultPatronSearchFields').split(',') %]
56                                 [% default_fields = [ 'surname,firstname,othernames,cardnumber,userid', 'surname', 'cardnumber', 'email', 'borrowernumber', 'userid', 'phone', 'address', 'dateofbirth', 'sort1', 'sort2' ] %]
57                                 [% search_options = default_fields.merge(pref_fields).unique %]
58                                 [% FOREACH s_o IN search_options %]
59                                     [% display_name = PROCESS patron_fields name=s_o %]
60                                     [% NEXT IF !display_name %]
61                                     [% IF searchfieldstype == s_o %]
62                                         <option selected="selected" value=[% s_o | html %]>[% display_name | $raw %]</option>
63                                     [% ELSE %]
64                                         <option value=[% s_o | html %]>[% display_name | $raw %]</option>
65                                     [% END %]
66                                 [% END %]
67                             </select>
68                         </li>
69                     [% CASE 'search_type' %]
70                         <li>
71                             <label for="searchtype_filter">Search type:</label>
72                             <select name="searchtype" id="searchtype_filter">
73                               [% IF searchtype == "start_with" %]
74                                 <option value='start_with' selected="selected">Starts with</option>
75                                 <option value="contain">Contains</option>
76                               [% ELSE %]
77                                 <option value='start_with'>Starts with</option>
78                                 <option value="contain" selected="selected">Contains</option>
79                               [% END %]
80                             </select>
81                         </li>
82                     [% END %]
83                 [% END %]
84             </ol>
85             <fieldset class="action">
86                 <input type="submit" value="Search" />
87                 <input type="button" value="Clear" id="clear_search" />
88             </fieldset>
89         </fieldset>
90     </form>
91 [% END %]
92
93 [% BLOCK patron_search_table %]
94
95     [% IF filter == 'suggestions_managers' %]
96         <div class="hint">Only staff with superlibrarian or suggestions_manage permissions are returned in the search results</div>
97     [% ELSIF filter == 'orders_managers' %]
98         <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>
99     [% ELSIF filter == 'funds_owners' OR filter == 'funds_users' %]
100         <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>
101     [% END %]
102
103     <div class="browse">
104         Browse by last name:
105         [% SET alphabet = Koha.Preference('alphabet').split(' ') %]
106         [% UNLESS alphabet.size %]
107             [% alphabet = ['A' .. 'Z'] %]
108         [% END %]
109         [% FOREACH letter IN alphabet %]
110             <a href="#" class="filterByLetter">[% letter | html %]</a>
111         [% END %]
112     </div>
113
114
115     <h3 style="display: none;">Patrons found for: <span id="searchpattern"></span></h3>
116
117     <div id="[% table_id | html %]_search_results" style="display:none;">
118
119         <div id="info" class="dialog message" style="display: none;"></div>
120         <div id="error" class="dialog alert" style="display: none;"></div>
121
122         <input type="hidden" id="firstletter_filter" value="" />
123         [% IF open_on_row_click %]
124         <table id="[% table_id | html %]" class="selections-table">
125         [% ELSE %]
126         <table id="[% table_id | html %]">
127         [% END %]
128             <thead>
129                 <tr>
130                     [% FOR column IN columns %]
131                         [% SWITCH column %]
132                             [% CASE 'checkbox' %]<th class="noExport"></th>
133                             [% CASE 'cardnumber' %]<th>Card</th>
134                             [% CASE 'dateofbirth' %]<th>Date of birth</th>
135                             [% CASE 'name' %]<th>Name</th>
136                             [% CASE 'name-address' %]<th>Name</th>
137                             [% CASE 'address' %]<th>Address</th>
138                             [% CASE 'address-library' %]<th>Address</th>
139                             [% CASE 'branch' %]<th data-filter="libraries">Library</th>
140                             [% CASE 'category' %]<th data-filter="categories">Category</th>
141                             [% CASE 'dateexpiry' %]<th>Expires on</td>
142                             [% CASE 'borrowernotes' %]<th>Notes</th>
143                             [% CASE 'phone' %]<th>Phone</th>
144                             [% CASE 'checkouts' %]<th>Checkouts</th>
145                             [% CASE 'account_balance' %]<th>Fines</th>
146                             [% CASE 'action' %]<th>&nbsp;</th>
147                         [% END %]
148                     [% END %]
149                 </tr>
150               </thead>
151             <tbody></tbody>
152         </table>
153     </div>
154
155 <!-- Patron preview modal -->
156 <div class="modal" id="patronPreview" tabindex="-1" role="dialog" aria-labelledby="patronPreviewLabel">
157     <div class="modal-dialog" role="document">
158         <div class="modal-content">
159             <div class="modal-header">
160                 <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
161                 <h4 class="modal-title" id="patronPreviewLabel"></h4>
162             </div>
163             <div class="modal-body">
164                 <div id="loading">
165                     <img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading
166                 </div>
167             </div>
168             <div class="modal-footer">
169                 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
170             </div>
171         </div>
172     </div>
173 </div>
174
175 [% END %]
176
177 [% BLOCK patron_search_js %]
178
179     [% IF redirect_if_one_result && !redirect_url %]
180         <script>console.log("Wrong call of patron_searh_js - missing redirect_url");</script>
181     [% END %]
182     <script>
183         let categories = [% To.json(categories) | $raw %];
184         let categories_map = categories.reduce((map, c) => {
185             map[c.categorycode] = c;
186             return map;
187         }, {});
188         let libraries  = [% To.json(libraries) | $raw %];
189         let libraries_map = libraries.reduce((map, l) => {
190             map[l.branchcode] = l;
191             return map;
192         }, {});
193
194         [% IF Koha.Preference('ExtendedPatronAttributes') && extended_attribute_types %]
195             let extended_attribute_types = [% To.json(extended_attribute_types || []) | $raw %];
196         [% END %]
197
198     </script>
199
200     [% INCLUDE 'datatables.inc' %]
201     [% INCLUDE 'js-date-format.inc' %]
202     [% INCLUDE 'js-patron-get-age.inc' %]
203     [% INCLUDE 'js-patron-format.inc' %]
204     [% INCLUDE 'js-patron-format-address.inc' %]
205     [% IF sticky_header %]
206         [% Asset.js("lib/hc-sticky.js") | $raw %]
207     [% END %]
208
209     <script>
210         var first_draw = 0;
211         let patrons_table;
212         var Sticky;
213         var singleBranchMode = '[% singleBranchMode | html %]';
214         let logged_in_library_id = "[% Branches.GetLoggedInBranchcode | html %]";
215
216         /* popstate event triggered by forward and back button. Need to refresh search */
217         window.addEventListener('popstate', (event) => {
218             getSearchByLocation( false );
219         });
220
221         $(document).ready(function(){
222
223             $("#info").hide();
224             $("#error").hide();
225
226             // Build the aLengthMenu
227             var aLengthMenu = [
228                 [% Koha.Preference('PatronsPerPage') | html %], 10, 20, 50, 100, -1
229             ];
230             jQuery.unique(aLengthMenu);
231             aLengthMenu.sort(function( a, b ){
232                 // Put "All" at the end
233                 if ( a == -1 ) {
234                     return 1;
235                 } else if ( b == -1 ) {
236                     return -1;
237                 }
238                 return parseInt(a) < parseInt(b) ? -1 : 1;}
239             );
240             var aLengthMenuLabel = [];
241             $(aLengthMenu).each(function(){
242                 if ( this == -1 ) {
243                     // Label for -1 is "All"
244                     aLengthMenuLabel.push(_("All"));
245                 } else {
246                     aLengthMenuLabel.push(this);
247                 }
248             });
249
250             let additional_filters = {
251                 surname: function(){
252                     let start_with = $("#firstletter_filter").val()
253                     if (!start_with) return "";
254                     return { "like": start_with + "%" }
255                 },
256                 "-and": function(){
257                     let filter = $("#search_patron_filter").val();
258                     if (!filter) return "";
259
260                     let filters = [];
261                     let search_type = $("#searchtype_filter").val() || "contain";
262                     let search_fields = $("#searchfieldstype_filter").val();
263                     if ( !search_fields ) {
264                         search_fields = "[% Koha.Preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid' | html %]";
265                     }
266                     search_fields.split(',').forEach(function(e,i){
267                         filters.push({["me."+e]:{"like":"%"+filter+(search_type == "contain" ? "%" : "" )}});
268                     });
269                     [% IF Koha.Preference('ExtendedPatronAttributes') && extended_attribute_types %]
270                         filters.push({
271                             "extended_attributes.value": { "like": "%" + filter + (search_type == "contain" ? "%" : "" )},
272                             "extended_attributes.code": extended_attribute_types
273                         });
274                     [% END %]
275                     return filters;
276                 }
277             };
278             [% UNLESS default_sort_column %]
279                 [% default_sort_column = "name" %]
280             [% END %]
281             [% SET order_column_index = 0 %]
282             [% SET embed = ['extended_attributes'] %]
283             patrons_table = $("#[% table_id | html %]").kohaTable({
284                 "ajax": {
285                     [% SWITCH filter %]
286                     [% CASE 'suggestions_managers' %]
287                         "url": '/api/v1/suggestions/managers',
288                     [% CASE 'baskets_managers' %]
289                         "url": '/api/v1/acquisitions/baskets/managers',
290                     [% CASE 'funds_owners' %]
291                         "url": '/api/v1/acquisitions/funds/owners',
292                     [% CASE 'funds_users' %]
293                         "url": '/api/v1/acquisitions/funds/users',
294                     [% CASE %]
295                         "url": '/api/v1/patrons',
296                     [% END %]
297                     "dataSrc": function ( json ) {
298                         [% IF redirect_if_one_result %]
299                             // redirect if there is only 1 result.
300                             if ( first_draw && json.recordsFiltered == 1 ) {
301                                 let url = '[% redirect_url | url %]'.indexOf("?") != -1
302                                     ? '[% redirect_url | url %]&borrowernumber=' + json.data[0].patron_id
303                                     : '[% redirect_url | url %]?borrowernumber=' + json.data[0].patron_id;
304                                 document.location.href = url;
305                                 return false;
306                             }
307                             first_draw = 0;
308                         [% END %]
309                         return json.data;
310                     }
311                 },
312                 [% IF open_on_row_click OR preview_on_name_click %]
313                 "drawCallback": function( settings ) {
314                     var api = this.api();
315                     var data = api.data();
316                     if ( data.length == 0 ) return;
317
318                     [% IF open_on_row_click %]
319                     $.each($(this).find("tbody tr"), function(index, tr) {
320                         let url = "[% on_click_url | url %]&borrowernumber=" + data[index].patron_id;
321                         $(tr).off('click').on('click', function() {
322                             document.location.href = url;
323                         }).addClass('clickable');
324                         $(tr).find("a.patron_name").attr('href', url);
325                     });
326                     [% END %]
327                     [% IF preview_on_name_click %]
328                     $.each($(this).find("tbody tr"), function(index, tr) {
329                         $(tr).find("a.patron_name").addClass("patron_preview");
330                     });
331                     [% END %]
332                 },
333                 [% END %]
334                 "iDeferLoading": 0,
335                 "columns": [
336                     [% FOR column IN columns %]
337                         [% IF default_sort_column == column %]
338                             [% order_column_index = loop.count - 1%]
339                         [% END %]
340                         [% SWITCH column %]
341                             [% CASE 'checkbox' %]
342                             {
343                                 "data": "patron_id",
344                                 "searchable": false,
345                                 "orderable": false,
346                                 "render": function( data, type, row, meta ) {
347                                     return "<label for='check" + data + "' class='content_hidden'>" + _("Select patron") + "</label><input type='checkbox' id='check" + data + "' class='selection' name='borrowernumber' value='" + data + "' />";
348                                 }
349                             }
350                             [% CASE 'cardnumber' %]
351                             {
352                                 "data": "cardnumber",
353                                 "searchable": true,
354                                 "orderable": true,
355                                 "render": function( data, type, row, meta ) {
356                                     let patron_id = encodeURIComponent(row.patron_id);
357                                     [% IF !open_on_row_click AND CAN_user_circulate_circulate_remaining_permissions %]
358                                         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>";
359                                     [% ELSE %]
360                                         return escape_str(data);
361                                     [% END %]
362                                 }
363
364                             }
365                             [% CASE 'dateofbirth' %]
366                             {
367                                 "data": "date_of_birth",
368                                 "searchable": true,
369                                 "orderable": true,
370                                 "render": function( data, type, row, meta ) {
371                                     return data ? escape_str($date(data) + " (" + _("%s years").format($get_age(data)) + ")") : "";
372                                 }
373                             }
374                             [% CASE 'address' %]
375                             {
376                                 "data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
377                                 "searchable": true,
378                                 "orderable": true,
379                                  "render": function( data, type, row, meta ) {
380                                     let r = '<div class="address"><ul>';
381                                     r += $format_address(row, { no_line_break: 1 });
382                                     r += '</div></ul>';
383                                     return r;
384                                 }
385                             }
386                             [% CASE 'address-library' %]
387                             {
388                                 "data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
389                                 "searchable": true,
390                                 "orderable": true,
391                                 "render": function( data, type, row, meta ) {
392                                     let r = '<div class="address"><ul>';
393                                     r += $format_address(row, { no_line_break: 1 });
394                                     r += '</div></ul>';
395                                     r += " " + escape_str(libraries_map[row.library_id].branchname);
396                                     return r;
397                                 }
398                             }
399                             [% CASE 'name-address' %]
400                             {
401                                 "data": "me.firstname:me.surname:me.othernames:me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
402                                 "searchable": true,
403                                 "orderable": true,
404                                 "render": function( data, type, row, meta ) {
405                                     let patron_id = encodeURIComponent(row.patron_id);
406                                     let r = '';
407                                     [% IF ! open_on_row_click %]
408                                     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>";
409                                     [% ELSE %]
410                                     r += $patron_to_html(row, { invert_name: 1 });
411                                     [% END %]
412                                     r += '<br/>';
413                                     r += '<div class="address"><ul>';
414                                     r += $format_address(row, { no_line_break: 1 });
415
416                                     if ( row.email ) {
417                                         r += "<li>" + _("Email: ") + "<a href='mailto:" + encodeURIComponent(row.email) + "'>" + escape_str(row.email) + "</a></li>";
418                                     }
419                                     r += '</ul></div>'
420
421                                     return r;
422                                 }
423                             }
424                             [% CASE 'name-address' %]
425                             {
426                                 "data": "me.firstname:me.surname:me.othernames:me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
427                                 "searchable": true,
428                                 "orderable": true,
429                                 "render": function( data, type, row, meta ) {
430                                     let patron_id = encodeURIComponent(row.patron_id);
431                                     let r = '';
432                                     [% IF ! open_on_row_click %]
433                                     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>";
434                                     [% ELSE %]
435                                     r += $patron_to_html(row, { invert_name: 1 });
436                                     [% END %]
437                                     r += '<br/>';
438                                     r += '<div class="address"><ul>';
439                                     r += $format_address(row, { no_line_break: 1 });
440
441                                     if ( row.email ) {
442                                         r += "<li>" + _("Email: ") + "<a href='mailto:" + encodeURIComponent(row.email) + "'>" + escape_str(row.email) + "</a></li>";
443                                     }
444                                     r += '</ul></div>'
445
446                                     return r;
447                                 }
448                             }
449                             [% CASE 'name' %]
450                             {
451                                 "data": "me.firstname:me.surname:me.othernames",
452                                 "searchable": true,
453                                 "orderable": true,
454                                 "render": function( data, type, row, meta ) {
455                                     let patron_id = encodeURIComponent(row.patron_id);
456                                     [% IF ! open_on_row_click %]
457                                     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>";
458                                     [% ELSE %]
459                                     return $patron_to_html(row, { invert_name: 1 });
460                                     [% END %]
461                                 }
462                             }
463                             [% CASE 'branch' %]
464                             {
465                                 "data": "library_id",
466                                 "searchable": true,
467                                 "orderable": true,
468                                 "render": function( data, type, row, meta ) {
469                                     let library_name = libraries_map[data].branchname
470                                     if( !singleBranchMode && data == logged_in_library_id ) {
471                                         return "<span class=\"currentlibrary\">" + escape_str(library_name) + "</span>";
472                                     } else {
473                                         return escape_str(library_name);
474                                     }
475                                 }
476                             }
477                             [% CASE 'category' %]
478                             {
479                                 "data": "category_id",
480                                 "searchable": true,
481                                 "orderable": true,
482                                 "render": function( data, type, row, meta ) {
483                                     return escape_str(categories_map[data].description);
484                                 }
485                             }
486                             [% CASE 'dateexpiry' %]
487                             {
488                                 "data": "expiry_date",
489                                 "searchable": true,
490                                 "orderable": true,
491                                 "render": function( data, type, row, meta ) {
492                                     return data ? escape_str($date(data)) : "";
493                                 }
494                             }
495                             [% CASE 'borrowernotes' %]
496                             {
497                                 "data": "staff_notes",
498                                 "searchable": true,
499                                 "orderable": true,
500                                 [%# We don't escape here, we allow html tag in staff notes %]
501                             }
502                             [% CASE 'phone' %]
503                             {
504                                 "data": "phone",
505                                 "searchable": true,
506                                 "orderable": true,
507                                 "render": function( data, type, row, meta ) {
508                                     return escape_str(data);
509                                 }
510                             }
511                             [% CASE 'checkouts' %][% embed.push('checkouts+count', 'overdues+count') %]
512                             {
513                                 "data": "",
514                                 "searchable": false,
515                                 "orderable": false,
516                                 "render": function( data, type, row, meta ) {
517                                     if ( row.overdues_count ) {
518                                         return "<span class='overdue'><strong>"+row.overdues_count + "</strong></span>";
519                                     } else {
520                                         return "0 / " + row.checkouts_count;
521                                     }
522                                 }
523                             }
524                             [% CASE 'account_balance' %][% embed.push('account_balance') %]
525                             {
526                                 "data": "",
527                                 "searchable": false,
528                                 "orderable": false,
529                                 "render": function( data, type, row, meta ) {
530                                     let r = "<span style='text-align: right; display: block;'><a href=\"/cgi-bin/koha/members/boraccount.pl?borrowernumber="+row.patron_id+"\">";
531                                     let balance_str = row.account_balance || 0;
532                                     balance_str = balance_str.escapeHtml().format_price();
533                                     if ( row.account_balance < 0 ) {
534                                         // FIXME Format price here
535                                         r += "<span class='credit'>" + balance_str + "</span>";
536                                     } else if ( row.account_balance > 0 ) {
537                                         r += "<span class='debit'><strong>" + balance_str  + "</strong></span>"
538                                     } else {
539                                         r += balance_str;
540                                     }
541                                     r += "</a></span>";
542                                     return r;
543                                 }
544                             }
545
546                             [% CASE 'action' %]
547                             {
548                                 "data": function( row, type, val, meta ) {
549
550                                     let patron_id = encodeURIComponent(row.patron_id);
551                                     let action_node = "";
552                                     [% FOR action IN actions %]
553                                     [% SWITCH action %]
554                                     [% CASE 'select' %]
555                                         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)+'\' />';
556                                     [% CASE 'add' %]
557                                         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 + '" />';
558                                     [% CASE 'edit' %]
559                                         action_node += '<a href="/cgi-bin/koha/members/memberentry.pl?op=modify&amp;destination=circ&amp;borrowernumber=' + patron_id + '" class="btn btn-default btn-xs"><i class="fa fa-pencil"></i> Edit</a>';
560                                     [% CASE 'checkout' %]
561                                         [% IF CAN_user_circulate_circulate_remaining_permissions %]
562                                             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>';
563                                         [% END %]
564                                     [% END %]
565                                     [% END %]
566                                     return action_node;
567                                 },
568                                 "searchable": false,
569                                 "orderable": false
570                             }
571                         [% END %]
572                         [% UNLESS loop.last %],[% END %]
573                     [% END %]
574                 ],
575                 'embed': [% To.json(embed) | $raw %],
576                 "order": [[ [% order_column_index | html %], "asc" ]],
577                 'bAutoWidth': false,
578                 'lengthMenu': [aLengthMenu, aLengthMenuLabel],
579                 'sPaginationType': 'full_numbers',
580                 "pageLength": [% Koha.Preference('PatronsPerPage') | html %],
581                 [% IF sticky_header %]
582                 "initComplete": function(settings, json) {
583                     Sticky = $("#[% sticky_header | html %]");
584                     Sticky.hcSticky({
585                         stickTo: "#[% sticky_to | html %]",
586                         stickyClass: "floating"
587                     });
588                 },
589                 [% END %]
590             }, typeof table_settings !== 'undefined' ? table_settings : null, 1, additional_filters);
591
592             $("#patron_search_form").on('submit', filter);
593             $(".filterByLetter").on("click",function(e){
594                 e.preventDefault();
595                 filterByFirstLetterSurname($(this).text(), true);
596             });
597             $("body").on("click",".add_user",function(e){
598                 e.preventDefault();
599                 var borrowernumber = $(this).data("borrowernumber");
600                 var firstname = $(this).data("firstname");
601                 var surname = $(this).data("surname");
602                 add_user( borrowernumber, firstname + " " + surname );
603             });
604
605             $("body").on("click",".select_user",function(e){
606                 e.preventDefault();
607                 var borrowernumber = $(this).data("borrowernumber");
608                 var borrower_data = $("#borrower_data"+borrowernumber).val();
609                 select_user( borrowernumber, JSON.parse(borrower_data) );
610             });
611
612             $("body").on("click",".patron_preview", function( e ){
613                 e.preventDefault();
614                 var borrowernumber = $(this).data("borrowernumber");
615                 var page = "/cgi-bin/koha/members/moremember.pl?print=brief&borrowernumber=" + borrowernumber;
616                 $("#patronPreview .modal-body").load( page + " div.container-fluid" );
617                 $('#patronPreview').modal({show:true});
618             });
619
620             $("#patronPreview").on('hidden.bs.modal', function (e) {
621                 $("#patronPreview .modal-body").html("<img src=\"[% interface | html %]/[% theme | html %]/img/spinner-small.gif\" alt=\"\" /> Loading");
622             });
623
624             $("#clear_search").on("click",function(e){
625                 e.preventDefault();
626                 clearFilters();
627                 $("#searchpattern").parent().hide();
628             });
629
630             if ( $("#search_patron_filter").val().length > 0 ) {
631                 $("#patron_search_form").submit();
632             }
633
634             /* Initial page load does not trigger the popstate event, so we explicitly call this */
635             getSearchByLocation( false );
636
637         });
638
639         function getSearchByLocation( setstate ){
640             /* Check to see if the URL contains a search parameter */
641             if( location.search != ""){
642                 var params = new URLSearchParams( location.search );
643                 var firstletter = params.get("firstletter");
644                 /* Check to see if search is a first letter param */
645                 if( firstletter ){
646                     /* Trigger function to return search results by letter */
647                     filterByFirstLetterSurname( firstletter, setstate );
648                 }
649             }
650         }
651
652         function update_search_description(){
653             var searched = $("#searchfieldstype_filter").find("option:selected").text();
654             if ( $("#search_patron_filter").val() ) {
655                 if ( $("#searchtype_filter").val() == 'start_with' ) {
656                     searched += _(" starting with ");
657                 } else {
658                     searched += _(" containing ");
659                 }
660                 searched += "'" + $("#search_patron_filter").val() + "'";
661             }
662             if ( $("#firstletter_filter").val() ) {
663                 searched += _(" begins with ") + "'" + $("#firstletter_filter").val() +"'";
664             }
665             if ( $("#categorycode_filter").val() ) {
666                 searched += _(" with category ") + "'" + $("#categorycode_filter").find("option:selected").text() + "'";
667             }
668             if ( $("#branchcode_filter").val() ) {
669                 searched += _(" in library ") + $("#branchcode_filter").find("option:selected").text();
670             }
671             $("#searchpattern").text(searched);
672             $("#searchpattern").parent().show();
673         }
674
675         function filter() {
676             $("#firstletter_filter").val('');
677             $("#[% table_id | html %]_search_results").show();
678
679             let table_dt = patrons_table.DataTable();
680             [% FOR c IN columns %]
681                 [% SWITCH c %]
682                 [% CASE 'branch' %]
683                     library_id = $("#branchcode_filter").val() || "";
684                     patrons_table.find('thead tr:eq(1) th[data-filter="libraries"] select').val(library_id);
685                     table_dt.column([% loop.count - 1 %]).search(library_id ? '^'+library_id+'$' : '');
686                 [% CASE 'category' %]
687                     let category_id = $("#categorycode_filter").val() || "";
688                     patrons_table.find('thead tr:eq(1) th[data-filter="categories"] select').val(category_id);
689                     table_dt.column([% loop.count - 1 %]).search(category_id ? '^'+category_id+'$' : '');
690                 [% END %]
691             [% END %]
692             table_dt.search("");
693             first_draw = 1; // Only redirect if we are coming from here
694             table_dt.draw();
695             update_search_description();
696             return false;
697         }
698
699         function clearFilters() {
700             $("#searchfieldstype_filter option:first").prop("selected", true);
701             $("#searchtype_filter option[value='contain']").prop("selected", true);
702             $("#categorycode_filter option:first").prop("selected", true);
703             $("#branchcode_filter option:first").prop("selected", true);
704             $("#firstletter_filter").val('');
705             $("#search_patron_filter").val('');
706             /* remove any search string added by firstletter search */
707             history.pushState( {}, null, window.location.href.split("?" )[0]);
708             $("#[% table_id | html %]_search_results").hide();
709             update_search_description();
710         }
711
712         // User has clicked on a letter
713         function filterByFirstLetterSurname(letter, setstate ) {
714             $("#firstletter_filter").val(letter);
715
716             $("#[% table_id | html %]_search_results").show();
717
718             if ( setstate ) {
719                 history.pushState( null, null, "?firstletter=" + letter );
720             }
721
722             patrons_table.DataTable().draw();
723             update_search_description();
724         }
725
726         // modify parent window owner element
727         function add_user(borrowernumber, borrowername) {
728             var p = window.opener;
729             // In one place (serials/routing.tt), the page is reload on every add
730             // We have to wait for the page to be there
731             function wait_for_opener () {
732                 if ( ! $(opener.document).find('body').size() ) {
733                     setTimeout(wait_for_opener, 500);
734                 } else {
735                     [%# Note that add_user could sent data instead of borrowername too %]
736                     $("#info").hide();
737                     $("#error").hide();
738                     if ( p.add_user(borrowernumber, borrowername) < 0 ) {
739                         $("#error").html(_("Patron '%s' is already in the list.").format(borrowername));
740                         $("#error").show();
741                     } else {
742                         $("#info").html(_("Patron '%s' added.").format(borrowername));
743                         $("#info").show();
744                     }
745                 }
746             }
747             wait_for_opener();
748         }
749         function select_user(borrowernumber, data) {
750             var p = window.opener;
751             [%  IF callback %]
752                 p.[% callback | html %](borrowernumber, data);
753             [%  ELSE %]
754                 p.select_user(borrowernumber, data);
755             [%  END %]
756             window.close();
757         }
758     </script>
759 [% END %]