Bug 23529: (follow-up) Fix syntax error
[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     // Only fire the request if we're on the ILL list page
366     if (window.location.search.length == 0) {}
367         var ajax = $.ajax(
368             '/api/v1/illrequests?embed=metadata,patron,capabilities,library,status_alias,comments,requested_partners'
369             + filterParam
370         ).done(function() {
371             var data = JSON.parse(ajax.responseText);
372             // Make a copy, we'll be removing columns next and need
373             // to be able to refer to data that has been removed
374             var dataCopy = $.extend(true, [], data);
375             // Expand columns that need it and create an array
376             // of all column names
377             $.each(dataCopy, function(k, row) {
378                 expandExpand(row);
379             });
380
381             // Assemble an array of column definitions for passing
382             // to datatables
383             var colData = [];
384             columns_settings.forEach(function(thisCol) {
385                 var colName = thisCol.columnname;
386                 // Create the base column object
387                 var colObj = $.extend({}, thisCol);
388                 colObj.name = colName;
389                 colObj.className = colName;
390                 colObj.defaultContent = '';
391
392                 // We may need to process the data going in this
393                 // column, so do it if necessary
394                 if (
395                     specialCols.hasOwnProperty(colName) &&
396                     specialCols[colName].hasOwnProperty('func')
397                 ) {
398                     var renderArray = [
399                         specialCols[colName].func
400                     ];
401                     if (!specialCols[colName].skipSanitize) {
402                         renderArray.push(
403                             $.fn.dataTable.render.text()
404                         );
405                     }
406
407                     colObj.render = $.fn.dataTable.render.multi(
408                         renderArray
409                     );
410                 } else {
411                     colObj.data = colName;
412                     colObj.render = $.fn.dataTable.render.text()
413                 }
414                 // Make sure properties that aren't present in the API
415                 // response are populated with null to avoid Datatables
416                 // choking on their absence
417                 dataCopy.forEach(function(thisData) {
418                     if (!thisData.hasOwnProperty(colName)) {
419                         thisData[colName] = null;
420                     }
421                 });
422                 colData.push(colObj);
423             });
424
425             // Initialise the datatable
426             table = KohaTable("ill-requests", {
427                 'aoColumnDefs': [
428                     { // Last column shouldn't be sortable or searchable
429                         'aTargets': [ 'actions' ],
430                         'bSortable': false,
431                         'bSearchable': false
432                     },
433                     { // When sorting 'placed', we want to use the
434                         // unformatted column
435                         'aTargets': [ 'placed_formatted'],
436                         'iDataSort': 14
437                     },
438                     { // When sorting 'updated', we want to use the
439                         // unformatted column
440                         'aTargets': [ 'updated_formatted'],
441                         'iDataSort': 16
442                     },
443                     { // When sorting 'completed', we want to use the
444                         // unformatted column
445                         'aTargets': [ 'completed_formatted'],
446                         'iDataSort': 19
447                     }
448                 ],
449                 'aaSorting': [[ 16, 'desc' ]], // Default sort, updated descending
450                 'processing': true, // Display a message when manipulating
451                 'sPaginationType': "full_numbers", // Pagination display
452                 'deferRender': true, // Improve performance on big datasets
453                 'data': dataCopy,
454                 'columns': colData,
455                 'originalData': data, // Enable render functions to access
456                                         // our original data
457                 'initComplete': function() {
458
459                     // Prepare any filter elements that need it
460                     for (var el in filterable) {
461                         if (filterable.hasOwnProperty(el)) {
462                             if (filterable[el].hasOwnProperty('prep')) {
463                                 filterable[el].prep(dataCopy, data);
464                             }
465                             if (filterable[el].hasOwnProperty('listener')) {
466                                 filterable[el].listener();
467                             }
468                         }
469                     }
470
471                 }
472             }, columns_settings);
473
474             // Custom date range filtering
475             $.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
476                 var placedStart = $('#illfilter_dateplaced_start').datepicker('getDate');
477                 var placedEnd = $('#illfilter_dateplaced_end').datepicker('getDate');
478                 var modifiedStart = $('#illfilter_datemodified_start').datepicker('getDate');
479                 var modifiedEnd = $('#illfilter_datemodified_end').datepicker('getDate');
480                 var rowPlaced = data[14] ? new Date(data[14]) : null;
481                 var rowModified = data[16] ? new Date(data[16]) : null;
482                 var placedPassed = true;
483                 var modifiedPassed = true;
484                 if (placedStart && rowPlaced && rowPlaced < placedStart) {
485                     placedPassed = false
486                 };
487                 if (placedEnd && rowPlaced && rowPlaced > placedEnd) {
488                     placedPassed = false;
489                 }
490                 if (modifiedStart && rowModified && rowModified < modifiedStart) {
491                     modifiedPassed = false
492                 };
493                 if (modifiedEnd && rowModified && rowModified > modifiedEnd) {
494                     modifiedPassed = false;
495                 }
496
497                 return placedPassed && modifiedPassed;
498
499             });
500
501         });
502     }
503
504     var clearSearch = function() {
505         table.api().search('').columns().search('');
506         activeFilters = {};
507         for (var filter in filterable) {
508             if (
509                 filterable.hasOwnProperty(filter) &&
510                 filterable[filter].hasOwnProperty('clear')
511             ) {
512                 filterable[filter].clear();
513             }
514         }
515         table.api().draw();
516     };
517
518     // Apply any search filters, or clear any previous
519     // ones
520     $('#illfilter_form').submit(function(event) {
521         event.preventDefault();
522         table.api().search('').columns().search('');
523         for (var active in activeFilters) {
524             if (activeFilters.hasOwnProperty(active)) {
525                 activeFilters[active]();
526             }
527         }
528         table.api().draw();
529     });
530
531     // Clear all filters
532     $('#clear_search').click(function() {
533         clearSearch();
534     });
535
536 });