Koha/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js
Owen Leonard b70a9a29d7 Bug 28983: Use Flatpickr on various pages
This patch replaces the use of jQueryUI's datepicker on various
unrelated pages.

To test, apply the patch and test the following pages to confirm
that datepickers work correctly. "Linked" date fields should prevent a
"to" selection which preceeds the selected "from" date.

- Tools -> Patron clubs -> New club: Linked "start date" and "end date"
  fields.
- ILL requests: Two linked pairs of date fields in the sidebar, "Date
  placed between" and "Updated between." Each pair should work correctly
  and table filtering by date should work correctly.
- Tools -> Label creator -> Manage -> Layout batches -> Edit a batch ->
  Add items. This should trigger a popup window with a linked pair of
  date fields, "Added on or after date," and "Added on or before date."
- Point of sale -> Transaction history: "From" and "To" linked date
  field in the "Older transactions" section.
- Acquisitions -> Suggestions -> Add a suggestion: "Created by,"
  "Accepted on," and "Managed by" fields.
- Tools -> Tags -> Filter tags by date.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
2021-10-05 10:58:14 +02:00

587 lines
21 KiB
JavaScript

$(document).ready(function() {
// Illview Datatable setup
var table;
// Filters that are active
var activeFilters = {};
// Get any prefilters
var prefilters = $('table#ill-requests').data('prefilters');
// Fields we need to expand (flatten)
var expand = [
'metadata',
'patron',
'library'
];
// Expanded fields
// This is auto populated
var expanded = {};
// Filterable columns
var filterable = {
status: {
prep: function(tableData, oData) {
var uniques = {};
tableData.forEach(function(row) {
var resolvedName;
if (row.status_alias) {
resolvedName = row.status_alias.lib;
} else {
resolvedName = getStatusName(
row.capabilities[row.status].name,
row
);
}
uniques[resolvedName] = 1
});
Object.keys(uniques).sort().forEach(function(unique) {
$('#illfilter_status').append(
'<option value="' + unique +
'">' + unique + '</option>'
);
});
},
listener: function() {
var me = 'status';
$('#illfilter_status').change(function() {
var sel = $('#illfilter_status option:selected').val();
if (sel && sel.length > 0) {
activeFilters[me] = function() {
table.api().column(13).search(sel);
}
} else {
if (activeFilters.hasOwnProperty(me)) {
delete activeFilters[me];
}
}
});
},
clear: function() {
$('#illfilter_status').val('');
}
},
pickupBranch: {
prep: function(tableData, oData) {
var uniques = {};
tableData.forEach(function(row) {
uniques[row.library_branchname] = 1
});
Object.keys(uniques).sort().forEach(function(unique) {
$('#illfilter_branchname').append(
'<option value="' + unique +
'">' + unique + '</option>'
);
});
},
listener: function() {
var me = 'pickupBranch';
$('#illfilter_branchname').change(function() {
var sel = $('#illfilter_branchname option:selected').val();
if (sel && sel.length > 0) {
activeFilters[me] = function() {
table.api().column(12).search(sel);
}
} else {
if (activeFilters.hasOwnProperty(me)) {
delete activeFilters[me];
}
}
});
},
clear: function() {
$('#illfilter_branchname').val('');
}
},
patron: {
listener: function() {
var me = 'patron';
$('#illfilter_patron').change(function() {
var val = $('#illfilter_patron').val();
if (val && val.length > 0) {
activeFilters[me] = function() {
table.api().column(10).search(val);
}
} else {
if (activeFilters.hasOwnProperty(me)) {
delete activeFilters[me];
}
}
});
},
clear: function() {
$('#illfilter_patron').val('');
}
},
keyword: {
listener: function () {
var me = 'keyword';
$('#illfilter_keyword').change(function () {
var val = $('#illfilter_keyword').val();
if (val && val.length > 0) {
activeFilters[me] = function () {
table.api().search(val);
}
} else {
if (activeFilters.hasOwnProperty(me)) {
delete activeFilters[me];
}
}
});
},
clear: function () {
$('#illfilter_keyword').val('');
}
},
dateModified: {
clear: function() {
$('#illfilter_datemodified_start, #illfilter_datemodified_end').val('');
}
},
datePlaced: {
clear: function() {
$('#illfilter_dateplaced_start, #illfilter_dateplaced_end').val('');
}
}
}; //END Filterable columns
// Expand any fields we're expanding
var expandExpand = function(row) {
expand.forEach(function(thisExpand) {
if (row.hasOwnProperty(thisExpand)) {
if (!expanded.hasOwnProperty(thisExpand)) {
expanded[thisExpand] = [];
}
var expandObj = row[thisExpand];
Object.keys(expandObj).forEach(
function(thisExpandCol) {
var expColName = thisExpand + '_' + thisExpandCol.replace(/\s/g,'_');
// Keep a list of fields that have been expanded
// so we can create toggle links for them
if (expanded[thisExpand].indexOf(expColName) == -1) {
expanded[thisExpand].push(expColName);
}
expandObj[expColName] =
expandObj[thisExpandCol];
delete expandObj[thisExpandCol];
}
);
$.extend(true, row, expandObj);
delete row[thisExpand];
}
});
};
//END Expand
// Strip the expand prefix if it exists, we do this for display
var stripPrefix = function(value) {
expand.forEach(function(thisExpand) {
var regex = new RegExp(thisExpand + '_', 'g');
value = value.replace(regex, '');
});
return value;
};
// Our 'render' function for borrowerlink
var createPatronLink = function(data, type, row) {
var patronLink = '<a title="' + ill_borrower_details + '" ' +
'href="/cgi-bin/koha/members/moremember.pl?' +
'borrowernumber='+row.borrowernumber+'">';
if ( row.patron_firstname ) {
patronLink = patronLink + row.patron_firstname + ' ';
}
patronLink = patronLink + row.patron_surname +
' (' + row.patron_cardnumber + ')' + '</a>';
return patronLink;
};
// Our 'render' function for biblio_id
var createBiblioLink = function(data, type, row) {
return (row.biblio_id) ?
'<a title="' + ill_biblio_details + '" ' +
'href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' +
row.biblio_id + '">' +
row.biblio_id +
'</a>' : '';
};
// Our 'render' function for title
var createTitle = function(data, type, row) {
return (
row.hasOwnProperty('metadata_container_title') &&
row.metadata_container_title
) ? row.metadata_container_title : row.metadata_title;
};
// Render function for request ID
var createRequestId = function(data, type, row) {
return row.id_prefix + row.illrequest_id;
};
// Render function for type
var createType = function(data, type, row) {
if (!row.hasOwnProperty('metadata_Type') || !row.metadata_Type) {
if (row.hasOwnProperty('medium') && row.medium) {
row.metadata_Type = row.medium;
} else {
row.metadata_Type = null;
}
}
return row.metadata_Type;
};
// Render function for request status
var createStatus = function(data, type, row, meta) {
if (row.status_alias) {
return row.status_alias.lib
? row.status_alias.lib
: row.status_alias.authorised_value;
} else {
var status_name = row.capabilities[row.status].name;
return getStatusName(status_name, row);
}
};
var getStatusName = function(origName, row) {
switch( origName ) {
case "New request":
return ill_statuses.new;
case "Requested":
return ill_statuses.req;
case "Requested from partners":
var statStr = ill_statuses.genreq;
if (
row.hasOwnProperty('requested_partners') &&
row.requested_partners &&
row.requested_partners.length > 0
) {
statStr += ' (' + row.requested_partners + ')';
}
return statStr;
case "Request reverted":
return ill_statuses.rev;
case "Queued request":
return ill_statuses.que;
case "Cancellation requested":
return ill_statuses.canc;
case "Completed":
return ill_statuses.comp;
case "Delete request":
return ill_statuses.del;
default:
return origName;
}
};
// Render function for creating a row's action link
var createActionLink = function(data, type, row) {
return '<a class="btn btn-default btn-sm" ' +
'href="/cgi-bin/koha/ill/ill-requests.pl?' +
'method=illview&amp;illrequest_id=' +
row.illrequest_id +
'">' + ill_manage + '</a>';
};
// Columns that require special treatment
var specialCols = {
action: {
func: createActionLink,
skipSanitize: true
},
illrequest_id: {
func: createRequestId
},
status: {
func: createStatus
},
biblio_id: {
name: ill_columns.biblio_id,
func: createBiblioLink,
skipSanitize: true
},
metadata_title: {
func: createTitle
},
metadata_Type: {
func: createType
},
updated: {
name: ill_columns.updated
},
patron: {
skipSanitize: true,
func: createPatronLink
}
};
// Display the modal containing request supplier metadata
$('#ill-request-display-log').on('click', function(e) {
e.preventDefault();
$('#requestLog').modal({show:true});
});
// Toggle request attributes in Illview
$('#toggle_requestattributes').on('click', function(e) {
e.preventDefault();
$('#requestattributes').toggleClass('content_hidden');
});
// Toggle new comment form in Illview
$('#toggle_addcomment').on('click', function(e) {
e.preventDefault();
$('#addcomment').toggleClass('content_hidden');
});
var illfilter_dateplaced_start = $("#illfilter_dateplaced_start").flatpickr({
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
illfilter_dateplaced_end.set('minDate', selectedDates[0]);
}
});
var illfilter_dateplaced_end = $("#illfilter_dateplaced_end").flatpickr({
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
},
});
var illfilter_datemodified_start = $("#illfilter_datemodified_start").flatpickr({
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
illfilter_datemodified_end.set('minDate', selectedDates[0]);
}
});
var illfilter_datemodified_end = $("#illfilter_datemodified_end").flatpickr({
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
},
});
// Filter partner list
// Record the list of all options
var ill_partner_options = $('#partners > option');
$('#partner_filter').keyup(function() {
var needle = $('#partner_filter').val();
var regex = new RegExp(needle, 'i');
var filtered = [];
ill_partner_options.each(function() {
if (
needle.length == 0 ||
$(this).is(':selected') ||
$(this).text().match(regex)
) {
filtered.push($(this));
}
});
$('#partners').empty().append(filtered);
});
// Display the modal containing request supplier metadata
$('#ill-request-display-metadata').on('click', function(e) {
e.preventDefault();
$('#dataPreview').modal({show:true});
});
// Allow us to chain Datatable render helpers together, so we
// can use our custom functions and render.text(), which
// provides us with data sanitization
$.fn.dataTable.render.multi = function(renderArray) {
return function(d, type, row, meta) {
for(var r = 0; r < renderArray.length; r++) {
var toCall = renderArray[r].hasOwnProperty('display') ?
renderArray[r].display :
renderArray[r];
d = toCall(d, type, row, meta);
}
return d;
}
}
// Get our data from the API and process it prior to passing
// it to datatables
var filterParam = prefilters ? '&' + prefilters : '';
// Only fire the request if we're on an appropriate page
if (
(
// ILL list requests page
window.location.href.match(/ill\/ill-requests\.pl/) &&
window.location.search.length == 0
) ||
// Patron profile page
window.location.href.match(/members\/ill-requests\.pl/)
) {
var ajax = $.ajax(
'/api/v1/illrequests?embed=metadata,patron,capabilities,library,status_alias,comments,requested_partners'
+ filterParam
).done(function() {
var data = JSON.parse(ajax.responseText);
// Make a copy, we'll be removing columns next and need
// to be able to refer to data that has been removed
var dataCopy = $.extend(true, [], data);
// Expand columns that need it and create an array
// of all column names
$.each(dataCopy, function(k, row) {
expandExpand(row);
});
// Assemble an array of column definitions for passing
// to datatables
var colData = [];
columns_settings.forEach(function(thisCol) {
var colName = thisCol.columnname;
// Create the base column object
var colObj = $.extend({}, thisCol);
colObj.name = colName;
colObj.className = colName;
colObj.defaultContent = '';
// We may need to process the data going in this
// column, so do it if necessary
if (
specialCols.hasOwnProperty(colName) &&
specialCols[colName].hasOwnProperty('func')
) {
var renderArray = [
specialCols[colName].func
];
if (!specialCols[colName].skipSanitize) {
renderArray.push(
$.fn.dataTable.render.text()
);
}
colObj.render = $.fn.dataTable.render.multi(
renderArray
);
} else {
colObj.data = colName;
colObj.render = $.fn.dataTable.render.text()
}
// Make sure properties that aren't present in the API
// response are populated with null to avoid Datatables
// choking on their absence
dataCopy.forEach(function(thisData) {
if (!thisData.hasOwnProperty(colName)) {
thisData[colName] = null;
}
});
colData.push(colObj);
});
// Initialise the datatable
table = KohaTable("ill-requests", {
'aoColumnDefs': [
{ // Last column shouldn't be sortable or searchable
'aTargets': [ 'actions' ],
'bSortable': false,
'bSearchable': false
},
{ // When sorting 'placed', we want to use the
// unformatted column
'aTargets': [ 'placed_formatted'],
'iDataSort': 14
},
{ // When sorting 'updated', we want to use the
// unformatted column
'aTargets': [ 'updated_formatted'],
'iDataSort': 16
},
{ // When sorting 'completed', we want to use the
// unformatted column
'aTargets': [ 'completed_formatted'],
'iDataSort': 19
}
],
'aaSorting': [[ 16, 'desc' ]], // Default sort, updated descending
'processing': true, // Display a message when manipulating
'sPaginationType': "full_numbers", // Pagination display
'deferRender': true, // Improve performance on big datasets
'data': dataCopy,
"dom": '<"top pager"<"table_entries"ilp><"table_controls"B>>tr<"bottom pager"ip>',
'columns': colData,
'originalData': data, // Enable render functions to access
// our original data
'initComplete': function() {
// Prepare any filter elements that need it
for (var el in filterable) {
if (filterable.hasOwnProperty(el)) {
if (filterable[el].hasOwnProperty('prep')) {
filterable[el].prep(dataCopy, data);
}
if (filterable[el].hasOwnProperty('listener')) {
filterable[el].listener();
}
}
}
}
}, columns_settings);
// Custom date range filtering
$.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
var placedStart = illfilter_dateplaced_start.selectedDates[0];
var placedEnd = illfilter_dateplaced_end.selectedDates[0];
var modifiedStart = illfilter_datemodified_start.selectedDates[0];
var modifiedEnd = illfilter_datemodified_end.selectedDates[0];
var rowPlaced = data[14] ? new Date(data[14]) : null;
var rowModified = data[16] ? new Date(data[16]) : null;
var placedPassed = true;
var modifiedPassed = true;
if (placedStart && rowPlaced && rowPlaced < placedStart) {
placedPassed = false
};
if (placedEnd && rowPlaced && rowPlaced > placedEnd) {
placedPassed = false;
}
if (modifiedStart && rowModified && rowModified < modifiedStart) {
modifiedPassed = false
};
if (modifiedEnd && rowModified && rowModified > modifiedEnd) {
modifiedPassed = false;
}
return placedPassed && modifiedPassed;
});
});
} //END if window.location.search.length == 0
var clearSearch = function() {
table.api().search('').columns().search('');
activeFilters = {};
for (var filter in filterable) {
if (
filterable.hasOwnProperty(filter) &&
filterable[filter].hasOwnProperty('clear')
) {
filterable[filter].clear();
}
}
table.api().draw();
};
// Apply any search filters, or clear any previous
// ones
$('#illfilter_form').submit(function(event) {
event.preventDefault();
table.api().search('').columns().search('');
for (var active in activeFilters) {
if (activeFilters.hasOwnProperty(active)) {
activeFilters[active]();
}
}
table.api().draw();
});
// Clear all filters
$('#clear_search').click(function() {
clearSearch();
});
});