Bug 24043: Fix retrieval of of status name
[koha.git] / koha-tmpl / intranet-tmpl / prog / js / ill-list-table.js
1 $(document).ready(function() {
2
3     // Illview Datatable setup
4
5     var table;
6
7     // Filters that are active
8     var activeFilters = {};
9
10     // Get any prefilters
11     var prefilters = $('table#ill-requests').data('prefilters');
12
13     // Fields we need to expand (flatten)
14     var expand = [
15         'metadata',
16         'patron',
17         'library'
18     ];
19
20     // Expanded fields
21     // This is auto populated
22     var expanded = {};
23
24     // Filterable columns
25     var filterable = {
26         status: {
27             prep: function(tableData, oData) {
28                 var uniques = {};
29                 tableData.forEach(function(row) {
30                     var resolvedName;
31                     if (row.status_alias) {
32                         resolvedName = row.status_alias.lib;
33                     } else {
34                         resolvedName = getStatusName(
35                             oData[0].capabilities[row.status].name,
36                             row
37                         );
38                     }
39                     uniques[resolvedName] = 1
40                 });
41                 Object.keys(uniques).sort().forEach(function(unique) {
42                     $('#illfilter_status').append(
43                         '<option value="' + unique  +
44                         '">' + unique +  '</option>'
45                     );
46                 });
47             },
48             listener: function() {
49                 var me = 'status';
50                 $('#illfilter_status').change(function() {
51                     var sel = $('#illfilter_status option:selected').val();
52                     if (sel && sel.length > 0) {
53                         activeFilters[me] = function() {
54                             table.api().column(13).search(sel);
55                         }
56                     } else {
57                         if (activeFilters.hasOwnProperty(me)) {
58                             delete activeFilters[me];
59                         }
60                     }
61                 });
62             },
63             clear: function() {
64                 $('#illfilter_status').val('');
65             }
66         },
67         pickupBranch: {
68             prep: function(tableData, oData) {
69                 var uniques = {};
70                 tableData.forEach(function(row) {
71                     uniques[row.library_branchname] = 1
72                 });
73                 Object.keys(uniques).sort().forEach(function(unique) {
74                     $('#illfilter_branchname').append(
75                         '<option value="' + unique  +
76                         '">' + unique +  '</option>'
77                     );
78                 });
79             },
80             listener: function() {
81                 var me = 'pickupBranch';
82                 $('#illfilter_branchname').change(function() {
83                     var sel = $('#illfilter_branchname option:selected').val();
84                     if (sel && sel.length > 0) {
85                         activeFilters[me] = function() {
86                             table.api().column(12).search(sel);
87                         }
88                     } else {
89                         if (activeFilters.hasOwnProperty(me)) {
90                             delete activeFilters[me];
91                         }
92                     }
93                 });
94             },
95             clear: function() {
96                 $('#illfilter_branchname').val('');
97             }
98         },
99         patron: {
100             listener: function() {
101                 var me = 'patron';
102                 $('#illfilter_patron').change(function() {
103                     var val = $('#illfilter_patron').val();
104                     if (val && val.length > 0) {
105                         activeFilters[me] = function() {
106                             table.api().column(10).search(val);
107                         }
108                     } else {
109                         if (activeFilters.hasOwnProperty(me)) {
110                             delete activeFilters[me];
111                         }
112                     }
113                 });
114             },
115             clear: function() {
116                 $('#illfilter_patron').val('');
117             }
118         },
119         dateModified: {
120             clear: function() {
121                 $('#illfilter_datemodified_start, #illfilter_datemodified_end').val('');
122             }
123         },
124         datePlaced: {
125             clear: function() {
126                 $('#illfilter_dateplaced_start, #illfilter_dateplaced_end').val('');
127             }
128         }
129     }; //END Filterable columns
130
131     // Expand any fields we're expanding
132     var expandExpand = function(row) {
133         expand.forEach(function(thisExpand) {
134             if (row.hasOwnProperty(thisExpand)) {
135                 if (!expanded.hasOwnProperty(thisExpand)) {
136                     expanded[thisExpand] = [];
137                 }
138                 var expandObj = row[thisExpand];
139                 Object.keys(expandObj).forEach(
140                     function(thisExpandCol) {
141                         var expColName = thisExpand + '_' + thisExpandCol.replace(/\s/g,'_');
142                         // Keep a list of fields that have been expanded
143                         // so we can create toggle links for them
144                         if (expanded[thisExpand].indexOf(expColName) == -1) {
145                             expanded[thisExpand].push(expColName);
146                         }
147                         expandObj[expColName] =
148                             expandObj[thisExpandCol];
149                         delete expandObj[thisExpandCol];
150                     }
151                 );
152                 $.extend(true, row, expandObj);
153                 delete row[thisExpand];
154             }
155         });
156     };
157     //END Expand
158
159     // Strip the expand prefix if it exists, we do this for display
160     var stripPrefix = function(value) {
161         expand.forEach(function(thisExpand) {
162             var regex = new RegExp(thisExpand + '_', 'g');
163             value = value.replace(regex, '');
164         });
165         return value;
166     };
167
168     // Our 'render' function for borrowerlink
169     var createPatronLink = function(data, type, row) {
170         var patronLink = '<a title="' + ill_borrower_details + '" ' +
171             'href="/cgi-bin/koha/members/moremember.pl?' +
172             'borrowernumber='+row.borrowernumber+'">';
173         if ( row.patron_firstname ) {
174             patronLink = patronLink + row.patron_firstname + ' ';
175         }
176         patronLink = patronLink + row.patron_surname +
177             ' (' + row.patron_cardnumber + ')' + '</a>';
178         return patronLink;
179     };
180
181     // Our 'render' function for biblio_id
182     var createBiblioLink = function(data, type, row) {
183         return (row.biblio_id) ?
184             '<a title="' + ill_biblio_details + '" ' +
185             'href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' +
186             row.biblio_id + '">' +
187             row.biblio_id +
188             '</a>' : '';
189     };
190
191     // Our 'render' function for title
192     var createTitle = function(data, type, row) {
193         return (
194             row.hasOwnProperty('metadata_container_title') &&
195             row.metadata_container_title
196         ) ? row.metadata_container_title : row.metadata_title;
197     };
198
199     // Render function for request ID
200     var createRequestId = function(data, type, row) {
201         return row.id_prefix + row.illrequest_id;
202     };
203
204     // Render function for type
205     var createType = function(data, type, row) {
206         if (!row.hasOwnProperty('metadata_Type') || !row.metadata_Type) {
207             if (row.hasOwnProperty('medium') && row.medium) {
208                 row.metadata_Type = row.medium;
209             } else {
210                 row.metadata_Type = null;
211             }
212         }
213         return row.metadata_Type;
214     };
215
216     // Render function for request status
217     var createStatus = function(data, type, row, meta) {
218         if (row.status_alias) {
219             return row.status_alias.lib
220                 ? row.status_alias.lib
221                 : row.status_alias.authorised_value;
222         } else {
223             var status_name = row.capabilities[row.status].name;
224             return getStatusName(status_name, row);
225         }
226     };
227
228     var getStatusName = function(origName, row) {
229         switch( origName ) {
230             case "New request":
231                 return ill_statuses.new;
232             case "Requested":
233                 return ill_statuses.req;
234             case "Requested from partners":
235                 var statStr = ill_statuses.genreq;
236                 if (
237                     row.hasOwnProperty('requested_partners') &&
238                     row.requested_partners &&
239                     row.requested_partners.length > 0
240                 ) {
241                     statStr += ' (' + row.requested_partners + ')';
242                 }
243                 return statStr;
244             case "Request reverted":
245                 return ill_statuses.rev;
246             case "Queued request":
247                 return ill_statuses.que;
248             case "Cancellation requested":
249                 return ill_statuses.canc;
250             case "Completed":
251                 return ill_statuses.comp;
252             case "Delete request":
253                 return ill_statuses.del;
254             default:
255                 return origName;
256         }
257     };
258
259     // Render function for creating a row's action link
260     var createActionLink = function(data, type, row) {
261         return '<a class="btn btn-default btn-sm" ' +
262             'href="/cgi-bin/koha/ill/ill-requests.pl?' +
263             'method=illview&amp;illrequest_id=' +
264             row.illrequest_id +
265             '">' + ill_manage + '</a>';
266     };
267
268     // Columns that require special treatment
269     var specialCols = {
270         action: {
271             func: createActionLink,
272             skipSanitize: true
273         },
274         illrequest_id: {
275             func: createRequestId
276         },
277         status: {
278             func: createStatus
279         },
280         biblio_id: {
281             name: ill_columns.biblio_id,
282             func: createBiblioLink,
283             skipSanitize: true
284         },
285         metadata_title: {
286             func: createTitle
287         },
288         metadata_Type: {
289             func: createType
290         },
291         updated: {
292             name: ill_columns.updated
293         },
294         patron: {
295             skipSanitize: true,
296             func: createPatronLink
297         }
298     };
299
300     // Display the modal containing request supplier metadata
301     $('#ill-request-display-log').on('click', function(e) {
302         e.preventDefault();
303         $('#requestLog').modal({show:true});
304     });
305
306     // Toggle request attributes in Illview
307     $('#toggle_requestattributes').on('click', function(e) {
308         e.preventDefault();
309         $('#requestattributes').toggleClass('content_hidden');
310     });
311
312     // Toggle new comment form in Illview
313     $('#toggle_addcomment').on('click', function(e) {
314         e.preventDefault();
315         $('#addcomment').toggleClass('content_hidden');
316     });
317
318     // Filter partner list
319     // Record the list of all options
320     var ill_partner_options = $('#partners > option');
321     $('#partner_filter').keyup(function() {
322         var needle = $('#partner_filter').val();
323         var regex = new RegExp(needle, 'i');
324         var filtered = [];
325         ill_partner_options.each(function() {
326             if (
327                 needle.length == 0 ||
328                 $(this).is(':selected') ||
329                 $(this).text().match(regex)
330             ) {
331                 filtered.push($(this));
332             }
333         });
334         $('#partners').empty().append(filtered);
335     });
336
337     // Display the modal containing request supplier metadata
338     $('#ill-request-display-metadata').on('click', function(e) {
339         e.preventDefault();
340         $('#dataPreview').modal({show:true});
341     });
342
343     // Allow us to chain Datatable render helpers together, so we
344     // can use our custom functions and render.text(), which
345     // provides us with data sanitization
346     $.fn.dataTable.render.multi = function(renderArray) {
347         return function(d, type, row, meta) {
348             for(var r = 0; r < renderArray.length; r++) {
349                 var toCall = renderArray[r].hasOwnProperty('display') ?
350                     renderArray[r].display :
351                     renderArray[r];
352                 d = toCall(d, type, row, meta);
353             }
354             return d;
355         }
356     }
357
358     // Get our data from the API and process it prior to passing
359     // it to datatables
360     var filterParam = prefilters ? '&' + prefilters : '';
361     // Only fire the request if we're on an appropriate page
362     if (
363         (
364             // ILL list requests page
365             window.location.href.match(/ill\/ill-requests\.pl/) &&
366             window.location.search.length == 0
367         ) ||
368         // Patron profile page
369         window.location.href.match(/members\/ill-requests\.pl/)
370     ) {
371         var ajax = $.ajax(
372             '/api/v1/illrequests?embed=metadata,patron,capabilities,library,status_alias,comments,requested_partners'
373             + filterParam
374         ).done(function() {
375             var data = JSON.parse(ajax.responseText);
376             // Make a copy, we'll be removing columns next and need
377             // to be able to refer to data that has been removed
378             var dataCopy = $.extend(true, [], data);
379             // Expand columns that need it and create an array
380             // of all column names
381             $.each(dataCopy, function(k, row) {
382                 expandExpand(row);
383             });
384
385             // Assemble an array of column definitions for passing
386             // to datatables
387             var colData = [];
388             columns_settings.forEach(function(thisCol) {
389                 var colName = thisCol.columnname;
390                 // Create the base column object
391                 var colObj = $.extend({}, thisCol);
392                 colObj.name = colName;
393                 colObj.className = colName;
394                 colObj.defaultContent = '';
395
396                 // We may need to process the data going in this
397                 // column, so do it if necessary
398                 if (
399                     specialCols.hasOwnProperty(colName) &&
400                     specialCols[colName].hasOwnProperty('func')
401                 ) {
402                     var renderArray = [
403                         specialCols[colName].func
404                     ];
405                     if (!specialCols[colName].skipSanitize) {
406                         renderArray.push(
407                             $.fn.dataTable.render.text()
408                         );
409                     }
410
411                     colObj.render = $.fn.dataTable.render.multi(
412                         renderArray
413                     );
414                 } else {
415                     colObj.data = colName;
416                     colObj.render = $.fn.dataTable.render.text()
417                 }
418                 // Make sure properties that aren't present in the API
419                 // response are populated with null to avoid Datatables
420                 // choking on their absence
421                 dataCopy.forEach(function(thisData) {
422                     if (!thisData.hasOwnProperty(colName)) {
423                         thisData[colName] = null;
424                     }
425                 });
426                 colData.push(colObj);
427             });
428
429             // Initialise the datatable
430             table = KohaTable("ill-requests", {
431                 'aoColumnDefs': [
432                     { // Last column shouldn't be sortable or searchable
433                         'aTargets': [ 'actions' ],
434                         'bSortable': false,
435                         'bSearchable': false
436                     },
437                     { // When sorting 'placed', we want to use the
438                         // unformatted column
439                         'aTargets': [ 'placed_formatted'],
440                         'iDataSort': 14
441                     },
442                     { // When sorting 'updated', we want to use the
443                         // unformatted column
444                         'aTargets': [ 'updated_formatted'],
445                         'iDataSort': 16
446                     },
447                     { // When sorting 'completed', we want to use the
448                         // unformatted column
449                         'aTargets': [ 'completed_formatted'],
450                         'iDataSort': 19
451                     }
452                 ],
453                 'aaSorting': [[ 16, 'desc' ]], // Default sort, updated descending
454                 'processing': true, // Display a message when manipulating
455                 'sPaginationType': "full_numbers", // Pagination display
456                 'deferRender': true, // Improve performance on big datasets
457                 'data': dataCopy,
458                 'columns': colData,
459                 'originalData': data, // Enable render functions to access
460                                         // our original data
461                 'initComplete': function() {
462
463                     // Prepare any filter elements that need it
464                     for (var el in filterable) {
465                         if (filterable.hasOwnProperty(el)) {
466                             if (filterable[el].hasOwnProperty('prep')) {
467                                 filterable[el].prep(dataCopy, data);
468                             }
469                             if (filterable[el].hasOwnProperty('listener')) {
470                                 filterable[el].listener();
471                             }
472                         }
473                     }
474
475                 }
476             }, columns_settings);
477
478             // Custom date range filtering
479             $.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
480                 var placedStart = $('#illfilter_dateplaced_start').datepicker('getDate');
481                 var placedEnd = $('#illfilter_dateplaced_end').datepicker('getDate');
482                 var modifiedStart = $('#illfilter_datemodified_start').datepicker('getDate');
483                 var modifiedEnd = $('#illfilter_datemodified_end').datepicker('getDate');
484                 var rowPlaced = data[14] ? new Date(data[14]) : null;
485                 var rowModified = data[16] ? new Date(data[16]) : null;
486                 var placedPassed = true;
487                 var modifiedPassed = true;
488                 if (placedStart && rowPlaced && rowPlaced < placedStart) {
489                     placedPassed = false
490                 };
491                 if (placedEnd && rowPlaced && rowPlaced > placedEnd) {
492                     placedPassed = false;
493                 }
494                 if (modifiedStart && rowModified && rowModified < modifiedStart) {
495                     modifiedPassed = false
496                 };
497                 if (modifiedEnd && rowModified && rowModified > modifiedEnd) {
498                     modifiedPassed = false;
499                 }
500
501                 return placedPassed && modifiedPassed;
502
503             });
504
505         });
506     } //END if window.location.search.length == 0
507
508     var clearSearch = function() {
509         table.api().search('').columns().search('');
510         activeFilters = {};
511         for (var filter in filterable) {
512             if (
513                 filterable.hasOwnProperty(filter) &&
514                 filterable[filter].hasOwnProperty('clear')
515             ) {
516                 filterable[filter].clear();
517             }
518         }
519         table.api().draw();
520     };
521
522     // Apply any search filters, or clear any previous
523     // ones
524     $('#illfilter_form').submit(function(event) {
525         event.preventDefault();
526         table.api().search('').columns().search('');
527         for (var active in activeFilters) {
528             if (activeFilters.hasOwnProperty(active)) {
529                 activeFilters[active]();
530             }
531         }
532         table.api().draw();
533     });
534
535     // Clear all filters
536     $('#clear_search').click(function() {
537         clearSearch();
538     });
539
540 });