Bug 32185: Fix template typo in opac-reserve.pl
[koha.git] / koha-tmpl / opac-tmpl / bootstrap / js / global.js
1 /* global enquire readCookie updateBasket delCookie __ */
2 (function( w ){
3     // if the class is already set, the font has already been loaded
4     if( w.document.documentElement.className.indexOf( "fonts-loaded" ) > -1 ){
5         return;
6     }
7     var PrimaryFont = new w.FontFaceObserver( "NotoSans", {
8         weight: 400
9     });
10
11     PrimaryFont.load(null, 5000).then(function(){
12         w.document.documentElement.className += " fonts-loaded";
13     }, function(){
14         console.log("Failed");
15     });
16 }( this ));
17
18 // http://stackoverflow.com/questions/1038746/equivalent-of-string-format-in-jquery/5341855#5341855
19 String.prototype.format = function() { return formatstr(this, arguments) }
20 function formatstr(str, col) {
21     col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1);
22     var idx = 0;
23     return str.replace(/%%|%s|%(\d+)\$s/g, function (m, n) {
24         if (m == "%%") { return "%"; }
25         if (m == "%s") { return col[idx++]; }
26         return col[n];
27     });
28 };
29
30 function confirmDelete(message) {
31     return (confirm(message) ? true : false);
32 }
33
34 function Dopop(link) {
35     newin=window.open(link,'popup','width=500,height=400,toolbar=false,scrollbars=yes,resizable=yes');
36 }
37
38 jQuery.fn.preventDoubleFormSubmit = function() {
39     jQuery(this).submit(function() {
40         if (this.beenSubmitted)
41             return false;
42         else
43             this.beenSubmitted = true;
44     });
45 };
46
47 function prefixOf (s, tok) {
48     var index = s.indexOf(tok);
49     return s.substring(0, index);
50 }
51 function suffixOf (s, tok) {
52     var index = s.indexOf(tok);
53     return s.substring(index + 1);
54 }
55
56 $("body").on("keypress", ".noEnterSubmit", function(e){
57     return checkEnter(e);
58 });
59
60 // http://jennifermadden.com/javascript/stringEnterKeyDetector.html
61 function checkEnter(e){ //e is event object passed from function invocation
62     var characterCode; // literal character code will be stored in this variable
63     if(e && e.which){ //if which property of event object is supported (NN4)
64         characterCode = e.which; //character code is contained in NN4's which property
65     } else {
66         characterCode = e.keyCode; //character code is contained in IE's keyCode property
67     }
68     if( characterCode == 13 //if generated character code is equal to ascii 13 (if enter key)
69         && e.target.nodeName == "INPUT"
70         && e.target.type != "submit" // Allow enter to submit using the submit button
71     ){
72         return false;
73     } else {
74         return true;
75     }
76 }
77
78 // Adapted from https://gist.github.com/jnormore/7418776
79 function confirmModal(message, title, yes_label, no_label, callback) {
80     $("#bootstrap-confirm-box-modal").data('confirm-yes', false);
81     if($("#bootstrap-confirm-box-modal").length == 0) {
82         $("body").append('<div id="bootstrap-confirm-box-modal" tabindex="-1" role="dialog" aria-hidden="true" class="modal">\
83             <div class="modal-dialog">\
84                 <div class="modal-content">\
85                     <div class="modal-header" style="min-height:40px;">\
86                         <h4 class="modal-title"></h4>\
87                         <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close">\
88                         <span aria-hidden="true">&times;</span>\
89                     </button>\
90                     </div>\
91                     <div class="modal-body"><p></p></div>\
92                     <div class="modal-footer">\
93                         <a href="#" id="bootstrap-confirm-box-modal-submit" class="btn btn-danger"><i class="fa fa-check" aria-hidden="true"></i></a>\
94                         <a href="#" id="bootstrap-confirm-box-modal-cancel" data-dismiss="modal" class="btn btn-secondary"><i class="fa fa-remove" aria-hidden="true"></i></a>\
95                     </div>\
96                 </div>\
97             </div>\
98         </div>');
99         $("#bootstrap-confirm-box-modal-submit").on('click', function () {
100             $("#bootstrap-confirm-box-modal").data('confirm-yes', true);
101             $("#bootstrap-confirm-box-modal").modal('hide');
102             return false;
103         });
104         $("#bootstrap-confirm-box-modal").on('hide.bs.modal', function () {
105             if(callback) callback($("#bootstrap-confirm-box-modal").data('confirm-yes'));
106         });
107     }
108
109     $("#bootstrap-confirm-box-modal .modal-header h4").text( title || "" );
110     if( message && message != "" ){
111         $("#bootstrap-confirm-box-modal .modal-body").html( message || "" );
112     } else {
113         $("#bootstrap-confirm-box-modal .modal-body").remove();
114     }
115     $("#bootstrap-confirm-box-modal-submit").text( yes_label || 'Confirm' );
116     $("#bootstrap-confirm-box-modal-cancel").text( no_label || 'Cancel' );
117     $("#bootstrap-confirm-box-modal").modal('show');
118 }
119
120
121 // Function to check errors from AJAX requests
122 const checkError = function(response) {
123     if (response.status >= 200 && response.status <= 299) {
124         return response.json();
125     } else {
126         console.log("Server returned an error:");
127         console.log(response);
128         alert("%s (%s)".format(response.statusText, response.status));
129     }
130 };
131
132 //Add jQuery :focusable selector
133 (function($) {
134     function visible(element) {
135         return $.expr.filters.visible(element) && !$(element).parents().addBack().filter(function() {
136             return $.css(this, 'visibility') === 'hidden';
137         }).length;
138     }
139
140     function focusable(element, isTabIndexNotNaN) {
141         var map, mapName, img, nodeName = element.nodeName.toLowerCase();
142         if ('area' === nodeName) {
143             map = element.parentNode;
144             mapName = map.name;
145             if (!element.href || !mapName || map.nodeName.toLowerCase() !== 'map') {
146                 return false;
147             }
148             img = $('img[usemap=#' + mapName + ']')[0];
149             return !!img && visible(img);
150         }
151         return (/input|select|textarea|button|object/.test(nodeName) ?
152                 !element.disabled :
153                 'a' === nodeName ?
154                 element.href || isTabIndexNotNaN :
155                 isTabIndexNotNaN) &&
156             // the element and all of its ancestors must be visible
157             visible(element);
158     }
159
160     $.extend($.expr[':'], {
161         focusable: function(element) {
162             return focusable(element, !isNaN($.attr(element, 'tabindex')));
163         }
164     });
165 })(jQuery);
166
167 enquire.register("screen and (max-width:608px)", {
168     match : function() {
169         if($("body.scrollto").length > 0){
170             window.scrollTo( 0, $(".maincontent").offset().top );
171         }
172     }
173 });
174
175 enquire.register("screen and (min-width:992px)", {
176     match : function() {
177         facetMenu( "show" );
178     },
179     unmatch : function() {
180         facetMenu( "hide" );
181     }
182 });
183
184 function facetMenu( action ){
185     if( action == "show" ){
186         $(".menu-collapse-toggle").off("click", facetHandler );
187         $(".menu-collapse").show();
188     } else {
189         $(".menu-collapse-toggle").on("click", facetHandler ).removeClass("menu-open");
190         $(".menu-collapse").hide();
191     }
192 }
193
194 var facetHandler = function(e){
195     e.preventDefault();
196     $(this).toggleClass("menu-open");
197     $(".menu-collapse").toggle();
198 };
199
200 $(document).ready(function(){
201     $("html").removeClass("no-js").addClass("js");
202     $(".close").click(function(){
203         window.close();
204     });
205     $(".focus").focus();
206     $(".js-show").show();
207     $(".js-hide").hide();
208
209     if( $(window).width() < 991 ){
210         facetMenu("hide");
211     }
212
213     // clear the basket when user logs out
214     $("#logout").click(function(){
215         var nameCookie = "bib_list";
216         var valCookie = readCookie(nameCookie);
217         if (valCookie) { // basket has contents
218             updateBasket(0,null);
219             delCookie(nameCookie);
220             return true;
221         } else {
222             return true;
223         }
224     });
225
226     $(".loginModal-trigger").on("click",function(e){
227         e.preventDefault();
228         $("#loginModal").modal("show");
229     });
230     $("#loginModal").on("shown.bs.modal", function(){
231         $("#muserid").focus();
232     });
233
234     $("#scrolltocontent").click(function() {
235         var content = $(".maincontent");
236         if (content.length > 0) {
237             $('html,body').animate({
238                 scrollTop: content.first().offset().top
239             },
240             'slow');
241             content.first().find(':focusable').eq(0).focus();
242         }
243     });
244
245     $('[data-toggle="tooltip"]').tooltip();
246
247     /* Scroll back to top button */
248     $("body").append('<button id="backtotop" class="btn btn-primary" aria-label="' + __("Back to top") + '"><i class="fa fa-arrow-up" aria-hidden="true" title="' + __("Scroll to the top of the page") + '"></i></button>');
249     $("#backtotop").hide();
250     $(window).on("scroll", function(){
251         if ( $(window).scrollTop() < 300 ) {
252             $("#backtotop").fadeOut();
253         } else {
254             $("#backtotop").fadeIn();
255         }
256     });
257     $("#backtotop").on("click", function(e) {
258         e.preventDefault();
259         $("html,body").animate({scrollTop: 0}, "slow");
260     });
261 });