Bug 33945: Add ability to delay the loading of the current checkouts table on the...
[koha.git] / koha-tmpl / intranet-tmpl / prog / js / staff-global.js
1 /* global shortcut delBasket Sticky AUDIO_ALERT_PATH Cookies */
2 /* exported addBibToContext delBibToContext escape_str escape_price openWindow _ removeFocus toUC confirmDelete confirmClone playSound */
3 if ( KOHA === undefined ) var KOHA = {};
4
5 function _(s) { return s; } // dummy function for gettext
6
7 // http://stackoverflow.com/questions/1038746/equivalent-of-string-format-in-jquery/5341855#5341855
8 String.prototype.format = function() { return formatstr(this, arguments); };
9 function formatstr(str, col) {
10     col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1);
11     var idx = 0;
12     return str.replace(/%%|%s|%(\d+)\$s/g, function (m, n) {
13         if (m == "%%") { return "%"; }
14         if (m == "%s") { return col[idx++]; }
15         return col[n];
16     });
17 }
18
19 var HtmlCharsToEscape = {
20     '&': '&',
21     '<': '&lt;',
22     '>': '&gt;'
23 };
24 String.prototype.escapeHtml = function() {
25     return this.replace(/[&<>]/g, function(c) {
26         return HtmlCharsToEscape[c] || c;
27     });
28 };
29 function escape_str(s){
30     return s != null ? s.escapeHtml() : "";
31 }
32
33 /*
34  * Void method for numbers, for consistency
35  */
36 Number.prototype.escapeHtml = function() {
37     return this;
38 };
39 function escape_price(p){
40     return p != null ? p.escapeHtml().format_price() : "";
41 }
42
43 // http://stackoverflow.com/questions/14859281/select-tab-by-name-in-jquery-ui-1-10-0/16550804#16550804
44 $.fn.tabIndex = function () {
45     return $(this).parent().children('div').index(this);
46 };
47 $.fn.selectTabByID = function (tabID) {
48     $("a[href='" + tabID + "']", $(this) ).tab("show");
49 };
50
51 $(document).ready(function() {
52
53     //check for a hash before setting focus
54     let hash = window.location.hash;
55     if ( ! hash ) {
56         $(".tab-pane.active input:text:first").focus();
57     }
58     $("#header_search a[data-toggle='tab']").on("shown.bs.tab", function (e) {
59         $( e.target.hash ).find("input:text:first").focus();
60     });
61
62     $(".close").click(function(){ window.close(); });
63
64     $("#checkin_search form").preventDoubleFormSubmit();
65
66     if($("#header_search #checkin_search").length > 0){
67         shortcut.add('Alt+r',function (){
68             $("#header_search").selectTabByID("#checkin_search");
69             $("#ret_barcode").focus();
70         });
71     } else {
72         shortcut.add('Alt+r',function (){
73             location.href="/cgi-bin/koha/circ/returns.pl"; });
74     }
75     if($("#header_search #circ_search").length > 0){
76         shortcut.add('Alt+u',function (){
77             $("#header_search").selectTabByID("#circ_search");
78             $("#findborrower").focus();
79         });
80     } else {
81         shortcut.add('Alt+u',function(){ location.href="/cgi-bin/koha/circ/circulation.pl"; });
82     }
83     if($("#header_search #catalog_search").length > 0){
84         shortcut.add('Alt+q',function (){
85             $("#header_search").selectTabByID("#catalog_search");
86             $("#search-form").focus();
87         });
88     } else {
89         shortcut.add('Alt+q',function(){ location.href="/cgi-bin/koha/catalogue/search.pl"; });
90     }
91     if($("#header_search #renew_search").length > 0){
92         shortcut.add('Alt+w',function (){
93             $("#header_search").selectTabByID("#renew_search");
94             $("#ren_barcode").focus();
95         });
96     } else {
97         shortcut.add('Alt+w',function(){ location.href="/cgi-bin/koha/circ/renew.pl"; });
98     }
99
100     $('#header_search .form-extra-content-toggle').on('click', function () {
101         const extraContent = $(this).closest('form').find('.form-extra-content');
102         if (extraContent.is(':visible')) {
103             extraContent.hide();
104         } else {
105             extraContent.show();
106         }
107     });
108
109     $(".focus").focus();
110     $(".validated").each(function() {
111         $(this).validate();
112     });
113
114     $("#logout").on("click",function(){
115         logOut();
116     });
117     $("#helper").on("click",function(){
118         openHelp();
119         return false;
120     });
121
122     $("body").on("keypress", ".noEnterSubmit", function(e){
123         return checkEnter(e);
124     });
125
126     $(".keep_text").on("click",function(){
127         var field_index = $(this).parent().index();
128         keep_text( field_index );
129     });
130
131     $(".toggle_element").on("click",function(e){
132         e.preventDefault();
133         $( $(this).data("element") ).toggle();
134         if (typeof Sticky !== "undefined" && typeof hcSticky === "function") {
135             Sticky.hcSticky('update');
136         }
137     });
138
139     var navmenulist = $("#navmenulist");
140     if( navmenulist.length > 0 ){
141         var path = location.pathname.substring(1);
142         var url = window.location.toString();
143         var params = '';
144         if ( url.match(/\?(.+)$/) ) {
145             params = "?" + RegExp.$1;
146         }
147         $("a[href$=\"/" + path + params + "\"]", navmenulist).addClass("current");
148     }
149
150     $("#catalog-search-link a").on("mouseenter mouseleave", function(){
151         $("#catalog-search-dropdown a").toggleClass("catalog-search-dropdown-hover");
152     });
153
154     if ( localStorage.getItem("lastborrowernumber") ){
155         if( $("#hiddenborrowernumber").val() != localStorage.getItem("lastborrowernumber") ) {
156             $("#lastborrowerlink").show();
157             $("#lastborrowerlink").prop("title", localStorage.getItem("lastborrowername") + " (" + localStorage.getItem("lastborrowercard") + ")");
158             $("#lastborrowerlink").prop("href", "/cgi-bin/koha/circ/circulation.pl?borrowernumber=" + localStorage.getItem("lastborrowernumber"));
159             $("#lastborrower-window").css("display", "inline-flex");
160         }
161     }
162
163     if( !localStorage.getItem("lastborrowernumber") || ( $("#hiddenborrowernumber").val() != localStorage.getItem("lastborrowernumber") && localStorage.getItem("currentborrowernumber") != $("#hiddenborrowernumber").val())) {
164         if( $("#hiddenborrowernumber").val() ){
165             localStorage.setItem("lastborrowernumber", $("#hiddenborrowernumber").val() );
166             localStorage.setItem("lastborrowername", $("#hiddenborrowername").val() );
167             localStorage.setItem("lastborrowercard", $("#hiddenborrowercard").val() );
168         }
169     }
170
171     if( $("#hiddenborrowernumber").val() ){
172         localStorage.setItem("currentborrowernumber", $("#hiddenborrowernumber").val() );
173     }
174
175     $("#lastborrower-remove").click(function() {
176         removeLastBorrower();
177         $("#lastborrower-window").hide();
178     });
179
180     /* Search results browsing */
181     /* forms with action leading to search */
182     $("form[action*='search.pl']").submit(function(){
183         $('[name^="limit"]').each(function(){
184             if( $(this).val() == '' ){
185                 $(this).prop("disabled","disabled");
186             }
187         });
188         var disabledPrior = false;
189         $(".search-term-row").each(function(){
190             if( disabledPrior ){
191                 $(this).find('select[name="op"]').prop("disabled","disabled");
192                 disabledPrior = false;
193             }
194             if( $(this).find('input[name="q"]').val() == "" ){
195                 $(this).find('input').prop("disabled","disabled");
196                 $(this).find('select').prop("disabled","disabled");
197                 disabledPrior = true;
198             }
199         });
200         resetSearchContext();
201         saveOrClearSimpleSearchParams();
202     });
203     /* any link to launch a search except navigation links */
204     $("[href*='search.pl?']").not(".nav").not('.searchwithcontext').click(function(){
205         resetSearchContext();
206     });
207     /* any link to a detail page from the results page. */
208     $("#bookbag_form a[href*='detail.pl?']").click(function(){
209         resetSearchContext();
210     });
211
212 });
213
214 function removeLastBorrower(){
215     localStorage.removeItem("lastborrowernumber");
216     localStorage.removeItem("lastborrowername");
217     localStorage.removeItem("lastborrowercard");
218     localStorage.removeItem("currentborrowernumber");
219 }
220
221 // http://jennifermadden.com/javascript/stringEnterKeyDetector.html
222 function checkEnter(e){ //e is event object passed from function invocation
223     var characterCode; // literal character code will be stored in this variable
224     if(e && e.which){ //if which property of event object is supported (NN4)
225         characterCode = e.which; //character code is contained in NN4's which property
226     } else {
227         characterCode = e.keyCode; //character code is contained in IE's keyCode property
228     }
229     if( characterCode == 13 //if generated character code is equal to ascii 13 (if enter key)
230         && e.target.nodeName == "INPUT"
231         && e.target.type != "submit" // Allow enter to submit using the submit button
232     ){
233         return false;
234     } else {
235         return true;
236     }
237 }
238
239 function clearHoldFor(){
240     Cookies.remove("holdfor", { path: '/', SameSite: 'Lax' });
241 }
242
243 function logOut(){
244     if( typeof delBasket == 'function' ){
245         delBasket('main', true);
246     }
247     clearHoldFor();
248     removeLastBorrower();
249     localStorage.removeItem("sql_reports_activetab");
250     localStorage.removeItem("searches");
251     localStorage.removeItem("bibs_selected");
252     localStorage.removeItem("patron_search_selections");
253 }
254
255 function openHelp(){
256     window.open( "/cgi-bin/koha/help.pl", "_blank");
257 }
258
259 jQuery.fn.preventDoubleFormSubmit = function() {
260     jQuery(this).submit(function() {
261         $("body, form input[type='submit'], form button[type='submit'], form a").addClass('waiting');
262         if (this.beenSubmitted)
263             return false;
264         else
265             this.beenSubmitted = true;
266     });
267 };
268
269 function openWindow(link,name,width,height) {
270     name = (typeof name == "undefined")?'popup':name;
271     width = (typeof width == "undefined")?'600':width;
272     height = (typeof height == "undefined")?'400':height;
273     //IE <= 9 can't handle a "name" with whitespace
274     try {
275         window.open(link,name,'width='+width+',height='+height+',resizable=yes,toolbar=false,scrollbars=yes,top');
276     } catch(e) {
277         window.open(link,null,'width='+width+',height='+height+',resizable=yes,toolbar=false,scrollbars=yes,top');
278     }
279 }
280
281 // Use this function to remove the focus from any element for
282 // repeated scanning actions on errors so the librarian doesn't
283 // continue scanning and miss the error.
284 function removeFocus() {
285     $(':focus').blur();
286 }
287
288 function toUC(f) {
289     var x=f.value.toUpperCase();
290     f.value=x;
291     return true;
292 }
293
294 function confirmDelete(message) {
295     return (confirm(message) ? true : false);
296 }
297
298 function confirmClone(message) {
299     return (confirm(message) ? true : false);
300 }
301
302 function playSound( sound ) {
303     if ( ! ( sound.indexOf('http://') === 0 || sound.indexOf('https://') === 0  ) ) {
304         sound = AUDIO_ALERT_PATH + sound;
305     }
306     document.getElementById("audio-alert").innerHTML = '<audio src="' + sound + '" autoplay="autoplay" autobuffer="autobuffer"></audio>';
307 }
308
309 // For keeping the text when navigating the search tabs
310 function keep_text(clicked_index) {
311     var searchboxes = document.getElementsByClassName("head-searchbox");
312     var persist = searchboxes[0].value;
313
314     for (var i = 0; i < searchboxes.length - 1; i++) {
315         if (searchboxes[i].value != searchboxes[i+1].value) {
316             if (i === searchboxes.length-2) {
317                 if (searchboxes[i].value != searchboxes[0].value) {
318                     persist = searchboxes[i].value;
319                 } else if (searchboxes.length === 2) {
320                     if (clicked_index === 0) {
321                         persist = searchboxes[1].value;
322                     }
323                 } else {
324                     persist = searchboxes[i+1].value;
325                 }
326             } else if (searchboxes[i+1].value != searchboxes[i+2].value) {
327                 persist = searchboxes[i+1].value;
328             }
329         }
330     }
331
332     for (i = 0; i < searchboxes.length; i++) {
333         searchboxes[i].value = persist;
334     }
335 }
336
337 // Extends jQuery API
338 jQuery.extend({uniqueArray:function(array){
339     return $.grep(array, function(el, index) {
340         return index === $.inArray(el, array);
341     });
342 }});
343
344 function removeByValue(arr, val) {
345     for(var i=0; i<arr.length; i++) {
346         if(arr[i] == val) {
347             arr.splice(i, 1);
348             break;
349         }
350     }
351 }
352
353 function addBibToContext( bibnum ) {
354     bibnum = parseInt(bibnum, 10);
355     var bibnums = getContextBiblioNumbers();
356     bibnums.push(bibnum);
357     setContextBiblioNumbers( bibnums );
358     setContextBiblioNumbers( $.uniqueArray( bibnums ) );
359 }
360
361 function delBibToContext( bibnum ) {
362     var bibnums = getContextBiblioNumbers();
363     removeByValue( bibnums, bibnum );
364     setContextBiblioNumbers( $.uniqueArray( bibnums ) );
365 }
366
367 function setContextBiblioNumbers( bibnums ) {
368     localStorage.setItem('bibs_selected', JSON.stringify( bibnums ) );
369 }
370
371 function getContextBiblioNumbers() {
372     var r = localStorage.getItem('bibs_selected');
373     if ( r ) {
374         return JSON.parse(r);
375     }
376     r = new Array();
377     return r;
378 }
379
380 function resetSearchContext() {
381     setContextBiblioNumbers( new Array() );
382 }
383
384 function saveOrClearSimpleSearchParams() {
385     // Simple masthead search - pass value for display on details page
386     var pulldown_selection;
387     var searchbox_value;
388     if( $("#cat-search-block select.advsearch").length ){
389         pulldown_selection = $("#cat-search-block select.advsearch").val();
390     } else {
391         pulldown_selection ="";
392     }
393     if( $("#cat-search-block #search-form").length ){
394         searchbox_value = $("#cat-search-block #search-form").val();
395     } else {
396         searchbox_value ="";
397     }
398     localStorage.setItem('cat_search_pulldown_selection', pulldown_selection );
399     localStorage.setItem('searchbox_value', searchbox_value );
400 }