Bug 17602: OPAC integration of RecordedBooks
[koha.git] / koha-tmpl / opac-tmpl / bootstrap / js / recordedbooks.js
1 if ( typeof KOHA == "undefined" || !KOHA ) {
2     var KOHA = {};
3 }
4
5 KOHA.RecordedBooks = new function() {
6     var svc_url = '/cgi-bin/koha/svc/recordedbooks';
7
8     var error_div = $('<div class="recordedbooks-error">');
9     function display_error ( error ) {
10         error_div.text(error);
11     }
12
13     var details = null;
14
15     function is_identified() {
16         return details ? details.is_identified : false;
17     }
18
19     var checkout_popup = null;
20     $( document ).ready(function() {
21         checkout_popup = $("#recordedbooks-checkout");
22     });
23
24     function display_account (container, data) {
25         if (!data.is_identified) {
26             return;
27         }
28
29         if (data.checkouts) {
30             var checkouts_div = $('<div class="recordedbooks-div">').html('<h3>' + _("Checkouts") + '</h3>');
31             var items = data.checkouts.items;
32             var checkouts_list;
33             if (items.length == 0) {
34                 checkouts_list = _("No checkouts");
35             } else {
36                 checkouts_list = $('<ul class="recordedbooks-list">');
37                 data.checkouts.items.forEach(function(item) {
38                     item_line(checkouts_list, item);
39                 });
40             }
41             checkouts_div.append(checkouts_list);
42             $(container).append(checkouts_div);
43         }
44
45         if (data.holds) {
46             var holds_div = $('<div class="recordedbooks-div">').html('<h3>' + _("Holds") + '</h3>');
47             var items = data.holds.items;
48             var holds_list;
49             if (items.length == 0) {
50                 holds_list = _("No holds");
51             } else {
52                 holds_list = $('<ul class="recordedbooks-list">');
53                 data.holds.items.forEach(function(item) {
54                     item_line(holds_list, item);
55                 });
56             }
57             holds_div.append(holds_list);
58             $(container).append(holds_div);
59         }
60     }
61
62     function item_line(ul_el, item) {
63         var line = $('<li class="recordedbooks-item">');
64         if (item.images) {
65             var thumb_url = item.images.small;
66             if (thumb_url) {
67                 $('<img class="recordedbooks-item-thumbnail">')
68                     .attr("src", thumb_url)
69                     .appendTo(line);
70             }
71         }
72         $('<div class="recordedbooks-item-title">')
73             .text(item.title)
74             .appendTo(line);
75         $('<div class="recordedbooks-item-subtitle">')
76             .text(item.subtitle)
77             .appendTo(line);
78         $('<div class="recordedbooks-item-author">')
79             .text(item.author)
80             .appendTo(line);
81         if (item.files && item.files.length > 0) {
82             downloads = $('<div class="recordedbooks-item-author">')
83                 .text("Downloads")
84                 .appendTo(line);
85             render_downloads(downloads, item.files);
86         }
87         var actions = $('<span class="actions">');
88         display_actions(actions, item.isbn);
89         $('<div id="action_'+item.isbn+'" class="actions-menu">')
90             .append(actions)
91             .appendTo(line);
92
93         $(ul_el).append(line);
94     }
95
96     function render_downloads(el, files) {
97         if (files.length == 0) return;
98         var file_spec = files.shift();
99         if (/^https?:\/\/api\./.test(file_spec.url)) {
100             $.ajax({
101                 dataType: "json",
102                 url: file_spec.url,
103                 success: function (data) {
104                     append_download_link(el, data.url, data.id);
105                     render_downloads(el, files);
106                 },
107                 error: function(jqXHR, textStatus, errorThrown) {
108                     display_error(errorThrown);
109                 }
110             });
111         } else {
112             append_download_link(el, file_spec.url, file_spec.filename);
113             render_downloads(el, files);
114         }
115     }
116     function append_download_link(el, url, text) {
117         var p = $("<p>");
118         $( '<a href="' + url + '" target="recordedbooks">' )
119             .text(text)
120             .appendTo(p);
121         el.append(p);
122     }
123
124     function svc_ajax ( method, params, success_callback, callback_for_error_too ) {
125         // remove when jquery is upgraded
126         for (var key in params) {
127             if (params[key] === null) delete params[key];
128         }
129         return $.ajax({
130             method: method,
131             dataType: "json",
132             url: svc_url,
133             data: params,
134             success: function (data) {
135                 if (data.error && !callback_for_error_too) {
136                     display_error(data.error);
137                 }
138                 success_callback(data);
139             },
140             error: function(jqXHR, textStatus, errorThrown) {
141                 if (callback_for_error_too) {
142                     success_callback({error: errorThrown});
143                     return;
144                 }
145                 display_error(errorThrown);
146             }
147         });
148     }
149
150     function load_account_details ( callback ) {
151         svc_ajax('get', { action: "account" }, function(data) {
152             details = data;
153             callback(data);
154         });
155     }
156
157     function item_action (params, el) {
158         var isbn = params.isbn;
159         svc_ajax('post', params, function(data) {
160             if (data.checkouts) {
161                 details.checkouts = data.checkouts;
162             }
163             if (data.holds) {
164                 details.holds = data.holds;
165             }
166             display_actions(el, isbn);
167         });
168     }
169
170     function item_is_checked_out (isbn) {
171         if ( !(details && details.checkouts) ) {
172             return null;
173         }
174         var isbn_uc = isbn.toUpperCase();
175         var items = details.checkouts.items;
176         for (var i = 0; i < items.length; i++) {
177             if ( items[i].isbn.toUpperCase() == isbn_uc ) {
178                 return items[i];
179             }
180         }
181         return null;
182     }
183
184     function item_is_on_hold (isbn) {
185         if ( !(details && details.holds) ) {
186             return false;
187         }
188         var isbn_uc = isbn.toUpperCase();
189         var items = details.holds.items;
190         for (var i = 0; i < items.length; i++) {
191             if ( items[i].isbn.toUpperCase() == isbn_uc ) {
192                 return items[i];
193             }
194         }
195         return null;
196     }
197
198     function display_actions(el, isbn) {
199         $(el).empty();
200         if (is_identified()) {
201
202             var item = item_is_checked_out(isbn);
203             if (item) {
204                 var expires = new Date(item.expires);
205                 $('<span class="recordedbooks-item-status">')
206                     .text(_("Checked out until") + " " + expires.toLocaleString())
207                     .appendTo(el);
208                 $(el).append(" ");
209
210                 if (item.url) {
211                     var download = $('<a href="'+item.url+'">').appendTo(el);
212                     decorate_button(download, _("Download"));
213                     $(el).append(" ");
214                 }
215
216                 $(el).append( ajax_button(_("Check in"), function() {
217                     if( confirm(_("Are you sure you want to return this item?")) ) {
218                         item_action({action: "return", isbn: isbn}, el);
219                     }
220                 }) );
221
222                 return item;
223             }
224
225             item = item_is_on_hold(isbn);
226             if (item) {
227                 $('<span class="recordedbooks-status">')
228                     .text(_("On hold"))
229                     .appendTo(el);
230                 $(el).append(" ");
231             }
232
233             if(checkout_popup) {
234                 $(el).append( ajax_button(_("Check out"), function() {
235                     if( confirm(_("Are you sure you want to checkout this item?")) ) {
236                         svc_ajax('post', {action: "checkout", isbn: isbn}, function(data) {
237                             if (data.checkouts) {
238                                 details.checkouts = data.checkouts;
239                             }
240                             if (data.holds) {
241                                 details.holds = data.holds;
242                             }
243                             item = display_actions(el, isbn);
244                         });
245                     }
246                 }) );
247             }
248             if (!item) {
249                 $(el).append( ajax_button(_("Place hold"), function() {
250                     item_action({action: "place_hold", isbn: isbn}, el);
251                 }) );
252             }
253
254             if (item) {
255                 $(el).append( ajax_button(_("Cancel"), function() {
256                     if( confirm(_("Are you sure you want to cancel this hold?")) ) {
257                         item_action({action: "remove_hold", isbn: isbn}, el);
258                     }
259                 }) );
260             }
261             return item;
262         }
263     }
264
265     function ajax_button(label, on_click) {
266         var button = $('<a href="#">')
267             .click(function(e) {
268                 e.preventDefault();
269                 on_click();
270             });
271         decorate_button(button, label);
272         return button;
273     }
274
275     function decorate_button(button, label) {
276         $(button)
277             .addClass("btn btn-primary btn-mini")
278             .css("color","white")
279             .text(label);
280     }
281
282     this.with_account_details = function( el, callback ) {
283         $(el).append(error_div);
284         load_account_details( callback );
285     }
286
287     this.display_account_details = function( el ) {
288         $(el).empty().append(error_div);
289         load_account_details(function(data) {
290             display_account(el, data);
291         });
292     };
293
294     this.display_error = function( el, error ) {
295         $(el).empty().append(error_div);
296         display_error(error);
297     };
298
299     this.is_identified = is_identified;
300
301     this.add_actions = function(el, isbn) {
302         var actions = $('<span class="actions">');
303         display_actions(actions, isbn);
304         $('<div id="action_'+isbn+'" class="actions-menu">')
305             .append(actions)
306             .appendTo(el);
307     };
308
309     this.search = function( q, page_size, page, callback ) {
310         svc_ajax('get', { action: "search", q: q, page_size: page_size, page: page }, function (data) {
311             var results;
312             if (data.results) {
313                 results = data.results;
314                 if (!results.total) {
315                     var total = results.items.length;
316                     if ( total == results.page_size ) total = total + "+";
317                     results.total = total;
318                 }
319             }
320             else results = {};
321             results.error = data.error;
322             callback(results);
323         }, true);
324     };
325 }