Bug 18589: (follow-up) Fix merge problem
[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     };
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
158     // Strip the expand prefix if it exists, we do this for display
159     var stripPrefix = function(value) {
160         expand.forEach(function(thisExpand) {
161             var regex = new RegExp(thisExpand + '_', 'g');
162             value = value.replace(regex, '');
163         });
164         return value;
165     };
166
167     // Our 'render' function for borrowerlink
168     var createPatronLink = function(data, type, row) {
169         var patronLink = '<a title="' + ill_borrower_details + '" ' +
170             'href="/cgi-bin/koha/members/moremember.pl?' +
171             'borrowernumber='+row.borrowernumber+'">';
172         if ( row.patron_firstname ) {
173             patronLink = patronLink + row.patron_firstname + ' ';
174         }
175         patronLink = patronLink + row.patron_surname +
176             ' (' + row.patron_cardnumber + ')' + '</a>';
177         return patronLink;
178     };
179
180     // Our 'render' function for biblio_id
181     var createBiblioLink = function(data, type, row) {
182         return (row.biblio_id) ?
183             '<a title="' + ill_biblio_details + '" ' +
184             'href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' +
185             row.biblio_id + '">' +
186             row.biblio_id +
187             '</a>' : '';
188     };
189
190     // Our 'render' function for title
191     var createTitle = function(data, type, row) {
192         return (
193             row.hasOwnProperty('metadata_container_title') &&
194             row.metadata_container_title
195         ) ? row.metadata_container_title : row.metadata_title;
196     };
197
198     // Render function for request ID
199     var createRequestId = function(data, type, row) {
200         return row.id_prefix + row.illrequest_id;
201     };
202
203     // Render function for type
204     var createType = function(data, type, row) {
205         if (!row.hasOwnProperty('metadata_Type') || !row.metadata_Type) {
206             if (row.hasOwnProperty('medium') && row.medium) {
207                 row.metadata_Type = row.medium;
208             } else {
209                 row.metadata_Type = null;
210             }
211         }
212         return row.metadata_Type;
213     };
214
215     // Render function for request status
216     var createStatus = function(data, type, row, meta) {
217         if (row.status_alias) {
218             return row.status_alias.lib
219                 ? row.status_alias.lib
220                 : row.status_alias.authorised_value;
221         } else {
222             var origData = meta.settings.oInit.originalData;
223             if (origData.length > 0) {
224                 var status_name = meta.settings.oInit.originalData[0].capabilities[
225                     row.status
226                 ].name;
227                 return getStatusName(status_name, row);
228             } else {
229                 return '';
230             }
231         }
232     };
233
234     var getStatusName = function(origName, row) {
235         switch( origName ) {
236             case "New request":
237                 return ill_statuses.new;
238             case "Requested":
239                 return ill_statuses.req;
240             case "Requested from partners":
241                 var statStr = ill_statuses.genreq;
242                 if (
243                     row.hasOwnProperty('requested_partners') &&
244                     row.requested_partners &&
245                     row.requested_partners.length > 0
246                 ) {
247                     statStr += ' (' + row.requested_partners + ')';
248                 }
249                 return statStr;
250             case "Request reverted":
251                 return ill_statuses.rev;
252             case "Queued request":
253                 return ill_statuses.que;
254             case "Cancellation requested":
255                 return ill_statuses.canc;
256             case "Completed":
257                 return ill_statuses.comp;
258             case "Delete request":
259                 return ill_statuses.del;
260             default:
261                 return origName;
262         }
263     };
264
265     // Render function for creating a row's action link
266     var createActionLink = function(data, type, row) {
267         return '<a class="btn btn-default btn-sm" ' +
268             'href="/cgi-bin/koha/ill/ill-requests.pl?' +
269             'method=illview&amp;illrequest_id=' +
270             row.illrequest_id +
271             '">' + ill_manage + '</a>';
272     };
273
274     // Columns that require special treatment
275     var specialCols = {
276         action: {
277             func: createActionLink,
278             skipSanitize: true
279         },
280         illrequest_id: {
281             func: createRequestId
282         },
283         status: {
284             func: createStatus
285         },
286         biblio_id: {
287             name: ill_columns.biblio_id,
288             func: createBiblioLink,
289             skipSanitize: true
290         },
291         metadata_title: {
292             func: createTitle
293         },
294         metadata_Type: {
295             func: createType
296         },
297         updated: {
298             name: ill_columns.updated
299         },
300         patron: {
301             skipSanitize: true,
302             func: createPatronLink
303         }
304     };
305
306     // Display the modal containing request supplier metadata
307     $('#ill-request-display-log').on('click', function(e) {
308         e.preventDefault();
309         $('#requestLog').modal({show:true});
310     });
311
312     // Toggle request attributes in Illview
313     $('#toggle_requestattributes').on('click', function(e) {
314         e.preventDefault();
315         $('#requestattributes').toggleClass('content_hidden');
316     });
317
318     // Toggle new comment form in Illview
319     $('#toggle_addcomment').on('click', function(e) {
320         e.preventDefault();
321         $('#addcomment').toggleClass('content_hidden');
322     });
323
324     // Filter partner list
325     $('#partner_filter').keyup(function() {
326         var needle = $('#partner_filter').val();
327         $('#partners > option').each(function() {
328             var regex = new RegExp(needle, 'i');
329             if (
330                 needle.length == 0 ||
331                 $(this).is(':selected') ||
332                 $(this).text().match(regex)
333             ) {
334                 $(this).show();
335             } else {
336                 $(this).hide();
337             }
338         });
339     });
340
341     // Display the modal containing request supplier metadata
342     $('#ill-request-display-metadata').on('click', function(e) {
343         e.preventDefault();
344         $('#dataPreview').modal({show:true});
345     });
346
347     // Allow us to chain Datatable render helpers together, so we
348     // can use our custom functions and render.text(), which
349     // provides us with data sanitization
350     $.fn.dataTable.render.multi = function(renderArray) {
351         return function(d, type, row, meta) {
352             for(var r = 0; r < renderArray.length; r++) {
353                 var toCall = renderArray[r].hasOwnProperty('display') ?
354                     renderArray[r].display :
355                     renderArray[r];
356                 d = toCall(d, type, row, meta);
357             }
358             return d;
359         }
360     }
361
362     // Get our data from the API and process it prior to passing
363     // it to datatables
364     var filterParam = prefilters ? '&' + prefilters : '';
365     var ajax = $.ajax(
366         '/api/v1/illrequests?embed=metadata,patron,capabilities,library,status_alias,comments,requested_partners'
367         + filterParam
368         ).done(function() {
369             var data = JSON.parse(ajax.responseText);
370             // Make a copy, we'll be removing columns next and need
371             // to be able to refer to data that has been removed
372             var dataCopy = $.extend(true, [], data);
373             // Expand columns that need it and create an array
374             // of all column names
375             $.each(dataCopy, function(k, row) {
376                 expandExpand(row);
377             });
378
379             // Assemble an array of column definitions for passing
380             // to datatables
381             var colData = [];
382             columns_settings.forEach(function(thisCol) {
383                 var colName = thisCol.columnname;
384                 // Create the base column object
385                 var colObj = $.extend({}, thisCol);
386                 colObj.name = colName;
387                 colObj.className = colName;
388                 colObj.defaultContent = '';
389
390                 // We may need to process the data going in this
391                 // column, so do it if necessary
392                 if (
393                     specialCols.hasOwnProperty(colName) &&
394                     specialCols[colName].hasOwnProperty('func')
395                 ) {
396                     var renderArray = [
397                         specialCols[colName].func
398                     ];
399                     if (!specialCols[colName].skipSanitize) {
400                         renderArray.push(
401                             $.fn.dataTable.render.text()
402                         );
403                     }
404
405                     colObj.render = $.fn.dataTable.render.multi(
406                         renderArray
407                     );
408                 } else {
409                     colObj.data = colName;
410                     colObj.render = $.fn.dataTable.render.text()
411                 }
412                 // Make sure properties that aren't present in the API
413                 // response are populated with null to avoid Datatables
414                 // choking on their absence
415                 dataCopy.forEach(function(thisData) {
416                     if (!thisData.hasOwnProperty(colName)) {
417                         thisData[colName] = null;
418                     }
419                 });
420                 colData.push(colObj);
421             });
422
423             // Initialise the datatable
424             table = KohaTable("ill-requests", {
425                 'aoColumnDefs': [
426                     { // Last column shouldn't be sortable or searchable
427                         'aTargets': [ 'actions' ],
428                         'bSortable': false,
429                         'bSearchable': false
430                     },
431                     { // When sorting 'placed', we want to use the
432                         // unformatted column
433                         'aTargets': [ 'placed_formatted'],
434                         'iDataSort': 14
435                     },
436                     { // When sorting 'updated', we want to use the
437                         // unformatted column
438                         'aTargets': [ 'updated_formatted'],
439                         'iDataSort': 16
440                     },
441                     { // When sorting 'completed', we want to use the
442                         // unformatted column
443                         'aTargets': [ 'completed_formatted'],
444                         'iDataSort': 19
445                     }
446                 ],
447                 'aaSorting': [[ 16, 'desc' ]], // Default sort, updated descending
448                 'processing': true, // Display a message when manipulating
449                 'sPaginationType': "full_numbers", // Pagination display
450                 'deferRender': true, // Improve performance on big datasets
451                 'data': dataCopy,
452                 'columns': colData,
453                 'originalData': data, // Enable render functions to access
454                                         // our original data
455                 'initComplete': function() {
456
457                     // Prepare any filter elements that need it
458                     for (var el in filterable) {
459                         if (filterable.hasOwnProperty(el)) {
460                             if (filterable[el].hasOwnProperty('prep')) {
461                                 filterable[el].prep(dataCopy, data);
462                             }
463                             if (filterable[el].hasOwnProperty('listener')) {
464                                 filterable[el].listener();
465                             }
466                         }
467                     }
468
469                 }
470             }, columns_settings);
471
472             // Custom date range filtering
473             $.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
474                 var placedStart = $('#illfilter_dateplaced_start').datepicker('getDate');
475                 var placedEnd = $('#illfilter_dateplaced_end').datepicker('getDate');
476                 var modifiedStart = $('#illfilter_datemodified_start').datepicker('getDate');
477                 var modifiedEnd = $('#illfilter_datemodified_end').datepicker('getDate');
478                 var rowPlaced = data[14] ? new Date(data[14]) : null;
479                 var rowModified = data[16] ? new Date(data[16]) : null;
480                 var placedPassed = true;
481                 var modifiedPassed = true;
482                 if (placedStart && rowPlaced && rowPlaced < placedStart) {
483                     placedPassed = false
484                 };
485                 if (placedEnd && rowPlaced && rowPlaced > placedEnd) {
486                     placedPassed = false;
487                 }
488                 if (modifiedStart && rowModified && rowModified < modifiedStart) {
489                     modifiedPassed = false
490                 };
491                 if (modifiedEnd && rowModified && rowModified > modifiedEnd) {
492                     modifiedPassed = false;
493                 }
494
495                 return placedPassed && modifiedPassed;
496
497             });
498
499         }
500     );
501
502     var clearSearch = function() {
503         table.api().search('').columns().search('');
504         activeFilters = {};
505         for (var filter in filterable) {
506             if (
507                 filterable.hasOwnProperty(filter) &&
508                 filterable[filter].hasOwnProperty('clear')
509             ) {
510                 filterable[filter].clear();
511             }
512         }
513         table.api().draw();
514     };
515
516     // Apply any search filters, or clear any previous
517     // ones
518     $('#illfilter_form').submit(function(event) {
519         event.preventDefault();
520         table.api().search('').columns().search('');
521         for (var active in activeFilters) {
522             if (activeFilters.hasOwnProperty(active)) {
523                 activeFilters[active]();
524             }
525         }
526         table.api().draw();
527     });
528
529     // Clear all filters
530     $('#clear_search').click(function() {
531         clearSearch();
532     });
533
534 });