Koha/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt
Owen Leonard aa49b1bed9
Bug 31566: 'Patrons selected' counter doubles on 'Select all'
This patch refines the JavaScript which is run when the "Select all"
or "Clear all" controls are clicked. The script now checks to see
whether the checkbox is checked before triggering the change function.

To test, apply the patch and perform a patron search in the staff
interface which will return multiple results.

- After the patron search results are displayed, test the "Select
  all" control. The visible search results should all be checked,
  and the "Patrons selected" counter at the top should be
  incremented correctly.
- Clicking the "Select all" control again should have no effect.
  The "Patrons selected" counter should not increment again.
- Test the "Clear all" control to confirm that checkboxes are
  unchecked and the counter updates correctly.
- Test with multiple pages of patron search results to confirm
  that the controls work correctly on any page of results..

Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
2022-10-03 13:36:45 -03:00

373 lines
18 KiB
Text

[% USE raw %]
[% USE Asset %]
[% USE Koha %]
[% USE TablesSettings %]
[% USE Branches %]
[% USE Categories %]
[% SET footerjs = 1 %]
[% PROCESS 'patronfields.inc' %]
[% SET libraries = Branches.all %]
[% SET categories = Categories.all.unblessed %]
[% SET columns = ['cardnumber', 'name-address', 'dateofbirth', 'branch', 'category', 'dateexpiry', 'checkouts', 'account_balance', 'borrowernotes', 'action'] %]
[% PROCESS 'patron-search.inc' %]
[% INCLUDE 'doc-head-open.inc' %]
<title>Patrons[% IF ( searching ) %] &rsaquo; Search results[% END %] &rsaquo; Koha</title>
[% INCLUDE 'doc-head-close.inc' %]
</head>
<body id="pat_member" class="pat">
[% INCLUDE 'header.inc' %]
[% INCLUDE 'patron-search-header.inc' %]
<nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="/cgi-bin/koha/mainpage.pl">Home</a>
</li>
[% IF ( searching ) %]
<li>
<a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>
</li>
<li>
<a href="#" aria-current="page">
Search results
</a>
</li>
[% ELSE %]
<li>
<a href="#" aria-current="page">
Patrons
</a>
</li>
[% END %]
</ol>
</nav>
<div class="main container-fluid">
<div class="row">
<div class="col-sm-10 col-sm-push-2">
<main>
[% IF CAN_user_tools_manage_patron_lists %]
<div id="patron_list_dialog" class="dialog message">
Added <span class="patrons-length"></span> patrons to <a></a>.
</div>
[% END %]
[% INCLUDE 'patron-toolbar.inc' %]
[% INCLUDE 'noadd-warnings.inc' %]
[% 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>:
<span class="number_box"><a href="/cgi-bin/koha/members/members-update.pl">[% pending_borrower_modifications | html %]</a></span>
</div>
[% END %]
<div id="searchresults">
[% IF CAN_user_tools_manage_patron_lists || CAN_user_borrowers_edit_borrowers %]
<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>
|
<a href="#" class="btn btn-link" id="clear_all"><i class="fa fa-remove"></i> Clear all</a>
[% IF CAN_user_tools_manage_patron_lists %]
[% END %]
[% IF CAN_user_tools_manage_patron_lists %]
<div id="patronlist-dropdown" class="btn-group">
<button id="patronlist-menu" type="button" class="btn btn-sm btn-default dropdown-toggle patron-edits disabled" disabled="disabled" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Add to patron list <span class="caret"></span>
</button>
<ul class="dropdown-menu">
[% IF patron_lists %]
[% FOREACH pl IN patron_lists %]
<li><a href="#" class="patron-list-add" data-listid="[% pl.patron_list_id | html %]">[% pl.name | html %]</a></li>
[% END %]
[% END %]
<li role="separator" class="divider"></li>
<li><a href="#" class="patron-list-add" data-listid="new">New list</a></li>
</ul>
</div>
[% END %]
[% IF CAN_user_borrowers_edit_borrowers %]
<button id="merge-patrons" class="btn btn-sm btn-default disabled" disabled="disabled" type="submit"><i class="fa fa-compress" aria-hidden="true"></i> Merge selected patrons</button>
[% END %]
<div id="patron_search_selected" class="btn-group" style="display:none;">
<span></span>
<a href="#" id="clear-patron-selection"><i class="fa fa-remove"></i> Clear</a>
</div>
</div>
</div>
[% END %]
[% 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>
</div> <!-- /.col-sm-10.col-sm-push-2 -->
<div class="col-sm-2 col-sm-pull-10">
<aside>
[% 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 -->
<!-- New Patron List Modal -->
<div class="modal" id="new-patron-list" tabindex="-1" role="dialog" aria-labelledby="new-patron-listLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="new-patron-listLabel">Add patrons to a new patron list</h4>
</div>
<form id="new-patron-list_form">
<div class="modal-body">
<div class="form-group">
<label for="new_patron_list" class="required">Patron list name: </label>
<input class="form-control required" type="text" name="new_patron_list" id="new_patron_list" required="required" />
<input type="hidden" name="add_to_patron_list" id="add_to_patron_list" />
<span class="required">Required</span>
</div>
</div> <!-- /.modal-body -->
<div class="modal-footer">
<button type="submit" id="add_to_patron_list_submit" class="btn btn-default approve">Submit</button>
<button type="button" class="btn btn-default deny" data-dismiss="modal">Cancel</button>
</div> <!-- /.modal-footer -->
</form> <!-- /#new-patron-list_form -->
</div> <!-- /.modal-content -->
</div> <!-- /.modal-dialog -->
</div> <!-- /#new-patron-list -->
[% MACRO jsinclude BLOCK %]
[% INCLUDE 'datatables.inc' %]
[% INCLUDE 'columns_settings.inc' %]
[% INCLUDE 'str/members-menu.inc' %]
[% Asset.js("js/members-menu.js") | $raw %]
<script>
function showPatronSelections( number ){
$("#patron_search_selected").show().find("span").text(_("Patrons selected: " + number ) );
}
$(document).ready(function() {
$('#merge-patrons').prop('disabled', true);
$('#memberresultst').on('change', 'input.selection', function() {
var patron_search_selections = JSON.parse( localStorage.getItem("patron_search_selections") ) || [];
var borrowernumber = $(this).val();
if( $(this).prop("checked") ){
patron_search_selections.push( $(this).val() );
localStorage.setItem('patron_search_selections', JSON.stringify( patron_search_selections ));
showPatronSelections( patron_search_selections.length );
} else {
var filtered = patron_search_selections.filter(function( value ){
return value !== borrowernumber;
});
if( filtered.length > 0 ){
localStorage.setItem('patron_search_selections', JSON.stringify( filtered ));
patron_search_selections = filtered;
showPatronSelections( filtered.length );
} else {
patron_search_selections = [];
localStorage.removeItem('patron_search_selections');
$("#patron_search_selected").hide();
}
}
if ( patron_search_selections.length > 1 ) {
/* More than one checkbox has been checked */
$('#merge-patrons').prop('disabled', false).removeClass("disabled");
$("#patronlist-menu").removeClass("disabled").prop("disabled", false);
} else if ( patron_search_selections.length == 1 ) {
/* At least one checkbox has been checked */
$('#merge-patrons').prop('disabled', true).addClass("disabled");
$("#patronlist-menu").removeClass("disabled").prop("disabled", false);
} else {
/* No checkbox has been checked */
$('#merge-patrons').prop('disabled', true).addClass("disabled");
$("#patronlist-menu").addClass("disabled").prop("disabled", true);
}
});
$('#merge-patrons').on('click', function() {
var patron_search_selections = JSON.parse( localStorage.getItem("patron_search_selections") ) || [];
var merge_patrons_url = 'merge-patrons.pl?id=' + patron_search_selections.join("&id=");
window.location.href = merge_patrons_url;
});
$("#clear-patron-selection").on("click", function(e){
e.preventDefault();
$(".selection").prop("checked", false).change();
localStorage.removeItem("patron_search_selections");
$("#patron_search_selected").hide();
$('#merge-patrons').prop('disabled', true).addClass("disabled");
$("#patronlist-menu").addClass("disabled").prop("disabled", true);
});
$("#patronlist-dropdown").on("click", ".patron-list-add", function(e){
e.preventDefault();
var patron_search_selections = JSON.parse( localStorage.getItem("patron_search_selections") ) || [];
if ( patron_search_selections.length == 0 ) {
alert( _("You have not selected any patrons to add to a list!") );
$(".btn-group").removeClass("open"); /* Close button menu */
return false;
}
var listid = $(this).data("listid");
$("#add_to_patron_list").val( listid );
if( listid == "new" ){
/* #add_to_patron_list value "new" in the modal form will tell API to create a new list */
$("#new-patron-list").modal("show");
} else {
/* Ajax submit the patrons to list */
patronListAdd();
}
})
/* Submit selected patrons to a list via AJAX */
$("#new-patron-list_form").on('submit', function(e){
e.preventDefault();
/* Upon submitting modal patron list add form... */
if ( $('#new_patron_list').val() ) {
$(".patron-list-add").each(function() {
/* Check each list name in the menu of patron lists */
/* If submitted list name matches... */
if ( $(this).text() == $('#new_patron_list').val() ) {
alert( _("You already have a list with that name!") );
return false;
}
});
} else {
alert( _("You must give your new patron list a name!") );
return false;
}
$("#new-patron-list").modal("hide");
patronListAdd();
});
$("#select_all").on("click",function(e){
e.preventDefault();
$(".selection").each(function(){
if( $(this).prop("checked") == false ){
$(this).prop( "checked", true ).change();
}
});
});
$("#clear_all").on("click",function(e){
e.preventDefault();
$(".selection").each(function(){
if( $(this).prop("checked") ){
$(this).prop("checked", false ).change();
}
});
});
[% IF searchmember %]
$("#searchmember_filter").val("[% searchmember | html %]");
[% END %]
[% IF searchfieldstype %]
$("searchfieldstype_filter").val("[% searchfieldstype | html %]");
[% END %]
[% IF searchtype %]
$("#searchtype_filter").val("[% searchtype | html %]");
[% END %]
[% IF categorycode %]
$("#categorycode_filter").val("[% categorycode_filter | html %]");
[% END %]
[% IF branchcode %]
$("#branchcode_filter").val("[% branchcode_filter | html %]");
[% END %]
$("#searchheader").hide();
$("#patron_search_form").on('submit', function(){$("#searchheader").show();});
$("#clear_search").on("click",function(e){$("#searchheader").hide();});
});
function patronListAdd(){
var borrowernumbers = JSON.parse( localStorage.getItem("patron_search_selections") ) || [];
if ( borrowernumbers.length > 0 ){
var data = {
add_to_patron_list: $("#add_to_patron_list").val(),
new_patron_list: $("#new_patron_list").val(),
borrowernumbers: borrowernumbers
};
$.ajax({
data: data,
type: 'POST',
url: '/cgi-bin/koha/svc/members/add_to_list',
success: function(data) {
$("#patron_list_dialog").show();
$("#patron_list_dialog > span.patrons-length").html(data.patrons_added_to_list);
$("#patron_list_dialog > a").attr("href", "/cgi-bin/koha/patron_lists/list.pl?patron_list_id=" + data.patron_list.patron_list_id);
$("#patron_list_dialog > a").html(data.patron_list.name);
if ( $('#add_to_patron_list').val() == 'new' ) {
/* Add a new entry to the menu */
$("#patronlist-dropdown .divider").before('<li><a class="patron-list-add" href="#" data-listid="' + data.patron_list.patron_list_id + '">' + data.patron_list.name + '</li>');
}
},
error: function() {
alert( _("An error occurred. Patron list could not be updated.") );
}
});
return true;
} else {
alert( _("You have not selected any patrons to add to a list!") );
return false;
}
}
function prepSelections(){
var selected_patrons = JSON.parse( localStorage.getItem("patron_search_selections") );
if( selected_patrons && selected_patrons.length > 0 ){
showPatronSelections( selected_patrons.length );
$('#merge-patrons').prop('disabled', true);
$("input.selection").each(function(){
var cardnumber = $(this).val();
if( selected_patrons.indexOf( cardnumber ) >= 0 ){
$(this).prop("checked", true );
}
});
if( selected_patrons.length > 1 ){
$('#merge-patrons').removeClass("disabled").prop('disabled', false);
$('#patronlist-menu').removeClass("disabled").prop('disabled', false);
}
}
}
$('#memberresultst tbody').on('click','td',function(e){
var $checkbox = $(this).find("input[type=checkbox]");
if (e.target.type != "checkbox") {
$checkbox.prop('checked', !$checkbox.prop("checked"));
$checkbox.change();
}
});
</script>
<script>
// Apply DataTables on the results table
var table_settings = [% TablesSettings.GetTableSettings( '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 %]
table_settings['columns'].splice(0, 1);
[% END %]
</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 => "searchresults", default_sort_column => 'name-address', display_search_description => 1, remember_selections => 1 %]
[% END %]
[% INCLUDE 'intranet-bottom.inc' %]