Bug 32185: Fix template typo in opac-reserve.pl
[koha.git] / koha-tmpl / opac-tmpl / bootstrap / js / overdrive.js
1 /* global OD_password_required __ */
2
3 if ( typeof KOHA == "undefined" || !KOHA ) {
4     var KOHA = {};
5 }
6
7 KOHA.OverDrive = ( function() {
8     var proxy_base_url = '/cgi-bin/koha/svc/overdrive_proxy';
9     var library_base_url = 'http://api.overdrive.com/v1/libraries/';
10     return {
11         Get: function( url, params, callback ) {
12             $.ajax( {
13                 type: 'GET',
14                 url: url.replace( /https?:\/\/api.overdrive.com\/v[1|2]/, proxy_base_url ),
15                 dataType: 'json',
16                 data: params,
17                 error: function( xhr, error ) {
18                     try {
19                         callback( JSON.parse( xhr.responseText ));
20                     } catch ( e ) {
21                         callback( {error: xhr.responseText || true} );
22                     }
23                 },
24                 success: callback
25             } );
26         },
27         GetCollectionURL: function( library_id, callback ) {
28             if ( KOHA.OverDrive.collection_url ) {
29                 callback( KOHA.OverDrive.collection_url );
30                 return;
31             }
32
33             KOHA.OverDrive.Get(
34                 library_base_url + library_id,
35                 {},
36                 function ( data ) {
37                     if ( data.error ) {
38                         callback( data );
39                         return;
40                     }
41
42                     KOHA.OverDrive.collection_url = data.links.products.href;
43
44                     callback( data.links.products.href );
45                 }
46             );
47         },
48         Search: function( library_id, q, limit, offset, callback ) {
49             KOHA.OverDrive.GetCollectionURL( library_id, function( data ) {
50                 if ( data.error ) {
51                     callback( data );
52                     return;
53                 }
54
55                 KOHA.OverDrive.Get(
56                     data,
57                     {q: q, limit: limit, offset: offset},
58                     callback
59                 );
60             } );
61         }
62     };
63 } )();
64
65 KOHA.OverDriveCirculation = new function() {
66     var svc_url = '/cgi-bin/koha/svc/overdrive';
67
68     var error_div = $('<div class="overdrive-error">');
69     function display_error ( error ) {
70         error_div.text(error);
71     }
72
73     var login_link = $('<a class="btn btn-primary" href="#">')
74         .click(function(e) {
75             e.preventDefault();
76             if( OD_password_required ) { $("#overdrive-login").modal('show'); }
77             else { login(""); }
78         })
79         .text( __("Log in to your OverDrive account") );
80
81     var login_div = $('<div class="overdrive-login">').append(login_link);
82
83     var details = null;
84
85     function is_logged_in() {
86         return details ? details.is_logged_in : false;
87     }
88
89     var checkout_popup = null;
90     $( document ).ready(function() {
91         checkout_popup = $("#overdrive-checkout");
92         $("#overdrive-login-form").submit(function(e){
93             e.preventDefault();
94             $("#overdrive-login").modal('hide');
95             var ODpassword = $("input[name='ODpassword']").val();
96             login( ODpassword );
97         });
98
99         $("#overdrive-login").on("shown.bs.modal", function(){
100             $("#ODpassword").focus();
101         });
102
103         var p = window.opener;
104         var cb;
105         if (p) {
106             try { cb = p.refresh_overdrive_account_details;}
107             catch(err){ return; } //Catch error if opener is not accessible
108             if (cb) {
109                 cb();
110             } else {
111                 p.location.reload();
112             }
113             window.close();
114         }
115     });
116
117     function display_account (container, data) {
118         if (!data.is_logged_in) {
119             $(container).append(login_div);
120             return;
121         }
122
123         var button_toolbar = $("<div/>").addClass("btn-toolbar").attr("role","toolbar");
124
125         var overdrive_link = $("<div/>").addClass("btn-group mr-2").attr("role", "group")
126             .append( $('<a href="https://www.overdrive.com/account/" target="overdrive-account" class="btn btn-sm btn-primary overdrive-link">')
127                 .text( __( "OverDrive account page" ) ) );
128         button_toolbar.append(overdrive_link);
129
130         var logout_link = $("<div/>").addClass("btn-group mr-2").attr("role", "group")
131             .append( $('<a href="#logout" class="btn btn-sm btn-primary overdrive-logout">')
132                 .click(function(e) {
133                     e.preventDefault();
134                     $(container).empty().append(error_div);
135                     logout(function(data) {
136                         display_account(container, data);
137                     });
138                 }).text( __("Log out of your OverDrive account") ) );
139
140         button_toolbar.append(logout_link);
141
142         $(container).append( button_toolbar );
143
144         if (data.checkouts) {
145             var checkouts_div = $('<div class="overdrive-div">').html('<h3>' + __("Checkouts") + '</h3>');
146             var checkouts_list = $('<div class="overdrive-list">');
147             data.checkouts.items.forEach(function(item) {
148                 item_line(checkouts_list, item);
149             });
150             checkouts_div.append(checkouts_list);
151             $(container).append(checkouts_div);
152         }
153
154         if (data.holds) {
155             var holds_div = $('<div class="overdrive-div">').html('<h3>' + __("Holds") + '</h3>');
156             var holds_list = $('<div class="overdrive-list">');
157             data.holds.items.forEach(function(item) {
158                 item_line(holds_list, item);
159             });
160             holds_div.append(holds_list);
161             $(container).append(holds_div);
162         }
163     }
164
165     function item_line(ul_el, item) {
166         var line = $('<div class="overdrive-item">');
167         var image_container = $('<div class="overdrive-item-thumbnail">');
168         if (item.images) {
169             var thumb_url = item.images.thumbnail;
170             if (thumb_url) {
171                 $('<img class="overdrive-thumbnail">')
172                     .attr("src", thumb_url)
173                     .appendTo( image_container );
174             }
175         }
176         image_container.appendTo( line );
177         var item_details = $('<div class="overdrive-item-details">')
178             .append(
179                 $('<h4 class="overdrive-item-title">')
180                     .text(item.title) )
181             .append( $('<div class="overdrive-item-author">')
182                 .text(item.author) )
183             .append(
184                 $('<div class="overdrive-item-subtitle">')
185                     .html(item.subtitle) )
186             .appendTo(line);
187         var actions = $('<div class="actions">');
188         display_actions(actions, item.id);
189         item_details.append( $('<div id="action_' + item.id + '" class="actions-menu">')
190             .append(actions) )
191             .appendTo(line);
192         $(ul_el).append(line);
193     }
194
195     function svc_ajax ( method, params, success_callback ) {
196         return $.ajax({
197             method: method,
198             dataType: "json",
199             url: svc_url,
200             data: params,
201             success: function (data) {
202                 if (data.error) {
203                     display_error(data.error);
204                 }
205                 success_callback(data);
206             },
207             error: function(jqXHR, textStatus, errorThrown) {
208                 display_error(errorThrown);
209             }
210         });
211     }
212
213     function load_account_details ( callback ) {
214         svc_ajax('get', { action: "account" }, function(data) {
215             details = data;
216             callback(data);
217         });
218     }
219
220     function login(p) {
221         svc_ajax('get', { action: "login", password: p }, function(data) {
222             details = null;
223             if( data.login_success ){
224                 $(login_div).detach();
225                 if( $("#overdrive-results-page").length > 0 ){
226                     location.reload();
227                 } else {
228                     KOHA.OverDriveCirculation.display_account_details( $("#opac-user-overdrive") );
229                 }
230             }
231         });
232     }
233
234     function logout (callback) {
235         svc_ajax('post', { action: "logout" }, function(data) {
236             details = null;
237             callback(data);
238         });
239     }
240
241     function item_action (params, el, copies_available) {
242         var id = params.id;
243         svc_ajax('post', params, function(data) {
244             if (data.checkouts) {
245                 details.checkouts = data.checkouts;
246             }
247             if (data.holds) {
248                 details.holds = data.holds;
249             }
250             display_actions(el, id, copies_available);
251         });
252     }
253
254     function item_is_checked_out (id) {
255         if ( !(details && details.checkouts) ) {
256             return null;
257         }
258         var id_uc = id.toUpperCase();
259         var items = details.checkouts.items;
260         for (var i = 0; i < items.length; i++) {
261             if ( items[i].id.toUpperCase() == id_uc ) {
262                 return items[i];
263             }
264         }
265         return null;
266     }
267
268     function item_is_on_hold (id) {
269         if ( !(details && details.holds) ) {
270             return false;
271         }
272         var id_uc = id.toUpperCase();
273         var items = details.holds.items;
274         for (var i = 0; i < items.length; i++) {
275             if ( items[i].id.toUpperCase() == id_uc ) {
276                 return items[i];
277             }
278         }
279         return null;
280     }
281
282     function display_actions(el, id, copies_available) {
283         $(el).empty();
284         if (is_logged_in()) {
285
286             var item = item_is_checked_out(id);
287             if (item) {
288                 var expires = new Date(item.expires);
289                 $('<div class="overdrive-item-status">')
290                     .text( __( "Checked out until: " )  + " " + expires.toLocaleString())
291                     .appendTo(el);
292                 $(el).append(" ");
293
294                 var access = $('<a target="_blank">').appendTo(el);
295                 decorate_button(access, __("Get item") );
296                 svc_ajax('get', {action: "download-url", id: id}, function(data) {
297                     access.attr("href", data.action.redirect);
298                 });
299                 $(el).append(" ");
300
301                 $(el).append( ajax_button( __("Check in"), function() {
302                     if( confirm( __("Are you sure you want to return this item?") ) ) {
303                         item_action({action: "return", id: id}, el, copies_available + 1);
304                     }
305                 }, "checkin") );
306
307                 return item;
308             }
309
310             item = item_is_on_hold(id);
311             if (item) {
312                 $('<span class="overdrive-item-status">')
313                     .text(__("On hold"))
314                     .appendTo(el);
315                 $(el).append(" ");
316             }
317
318             if(copies_available && checkout_popup) {
319                 $(el).append( ajax_button( __("Check out") , function() {
320                     if( confirm( __("Are you sure you want to check out this item?") ) ) {
321                         svc_ajax('post', {action: "checkout", id: id}, function(data) {
322                             if (data.checkouts) {
323                                 details.checkouts = data.checkouts;
324                             }
325                             if (data.holds) {
326                                 details.holds = data.holds;
327                             }
328                             item = display_actions(el, id, copies_available - 1);
329                             if (item && item.formats && !item.format) {
330                                 var has_available_formats = false;
331                                 var lockable_formats = [];
332                                 for (var f in item.formats) {
333                                     if (item.formats[f]) {
334                                         has_available_formats = true;
335                                         break;
336                                     }
337                                     lockable_formats.push(f);
338                                 }
339
340                                 if (!has_available_formats) {
341                                     checkout_format(el, id, lockable_formats, copies_available - 1);
342                                 }
343                             }
344                         });
345                     }
346                 }, "checkout") );
347             }
348             else if (!item) {
349                 $(el).append( ajax_button( __("Place hold"), function() {
350                     item_action({action: "place-hold", id: id}, el, copies_available);
351                 }, "placehold") );
352             }
353
354             if (item) {
355                 $(el).append( ajax_button( __("Cancel hold"), function() {
356                     if( confirm( __("Are you sure you want to cancel this hold?") ) ) {
357                         item_action({action: "remove-hold", id: id}, el, copies_available);
358                     }
359                 }, "cancelhold") );
360             }
361             return item;
362         }
363     }
364
365     function ajax_button(label, on_click, uniqueName) {
366         var button = $('<a href="#">')
367             .click(function(e) {
368                 e.preventDefault();
369                 on_click();
370             });
371         decorate_button(button, label, uniqueName);
372         return button;
373     }
374
375     function decorate_button(button, label, uniqueName) {
376         $(button)
377             .addClass("btn btn-primary btn-sm")
378             .css("color","white")
379             .text(label)
380             .addClass(uniqueName);
381     }
382
383     function checkout_format(el, id, formats, copies_available) {
384         if (formats.length == 0) {
385             alert( __("Item cannot be checked out. There are no available formats") );
386             return false;
387         }
388
389         var checkout_format_list = checkout_popup.find("#overdrive-format-list").empty();
390         formats.forEach(function (item) {
391             var line = $("<div/>").addClass("form-check");
392             var input = '<input id="' + item + '" class="form-check-input" value="' + item + '" name="checkout-format" type="radio" /> ';
393             var label = '<label for="' + item + '">' + item + '</label>"';
394             $(input).appendTo( line );
395             $(label).appendTo( line );
396             line.appendTo( checkout_format_list );
397         });
398         checkout_popup.modal("show");
399         checkout_popup.find(".overdrive-checkout-submit").click(function(e) {
400             e.preventDefault();
401             var format = checkout_format_list.find("input[type='radio'][name='checkout-format']:checked").val();
402             item_action({action: "checkout-format", id: id, format: format}, el, copies_available);
403             $(this).unbind( e );
404             checkout_popup.modal("hide");
405         });
406     }
407
408     this.with_account_details = function( el, callback ) {
409         $(el).append(error_div);
410         load_account_details(function(data) {
411             if (!data.is_logged_in) {
412                 $(el).append(login_div);
413             }
414             callback(data);
415         });
416     };
417
418     this.display_account_details = function( el ) {
419         window.refresh_overdrive_account_details = function () {
420             KOHA.OverDriveCirculation.display_account_details( el );
421         };
422         $(el).empty().append(error_div);
423         load_account_details(function(data) {
424             display_account(el, data);
425         });
426     };
427
428     this.display_error = function( el, error ) {
429         $(el).empty().append(error_div);
430         display_error(error);
431     };
432
433     this.is_logged_in = is_logged_in;
434
435     this.add_actions = function(el, id, copies_available) {
436         var actions = $('<span class="actions">');
437         display_actions(actions, id, copies_available);
438         $('<div id="action_'+id+'" class="actions-menu">')
439             .append(actions)
440             .appendTo(el);
441     };
442 };