Fix handling of errors for downloading Overdrive Read format
[sitka/overdrive-evergreen-opac.git] / src / od_pages_myopac.coffee
CommitLineData
8ebc3fff
SC
1# Define custom jQuery extensions to rewrite content of existing pages
2# None of the extensions directly use the API, but they depend on od_action which does.
3
4define [
5 'jquery'
6 'lodash'
8ebc3fff
SC
7 'jquery-ui'
8 'od_action'
9 'od_pages_opac'
508513a1 10], ($, _) ->
8ebc3fff
SC
11
12 $.fn.extend
13
14 # Given a map between classnames and numeric values,
15 # eg, { class1: 1, class2: -1 },
16 # increment the existing values of the containers with the classnames.
17 _counters: (x) ->
18 for n, v of x
19 $x = @find ".#{n}"
20 $x.text +($x.text()) + v
21 return @
22
23 _dashboard: (x) ->
24
25 if arguments.length is 0
26
27 # Add a new dashboard for to show counts of e-items; start with
28 # zero counts
29 base = '/eg/opac/myopac'
30 @append """
31 <div id="dashboard">
32 <span class="dash-align">
33 <a class="dash-link" href="#{base}/circs?e_items"><span class="ncheckouts" id="dash_checked">0</span> E-items Checked Out</a>
34 </span>
35 <span class="dash_divider">|</span>
36 <span class="dash-align">
37 <a class="dash-link" href="#{base}/holds?e_items"><span class="nholds" id="dash_holds">0</span> E-items on Hold</a>
38 </span>
39 <span class="dash_divider">|</span>
40 <span class="dash-align">
41 <a class="dash-link" href="#{base}/holds?e_items&available=1"><span class="nholdsready" id="dash_pickup">0</span> E-items Ready for Checkout</a>
42 </span>
43 </div>
44 """
45
46 # The following sequence is necessary to align the new dashboard
47 # with the existing ones, but do not know why it needs to be done
48 @find 'div'
49 .css float: 'none'
50 .end()
51
52 else
53 @_counters x # Change the values of the counters
54 return @
55
56 # Replace account summary area with one that shows links to go to
57 # e-items lists
58 _account_summary: (x) ->
59
60 if arguments.length is 0
61 # Parse a list of totals of physical items from the account summary table
62 totals = ( +(v.textContent.match(/\d+?/)[0]) for v in @find('td').not '[align="right"]' )
63
64 tpl = """
65 <tbody>
66 <tr>
67 <td>
68 <a href="/eg/opac/myopac/circs">
69 <span><span class="ncheckouts" /> Items Currently Checked out</span>
70 </a>
71 </td>
72 <td align="right">
73 <a href="/eg/opac/myopac/circs?e_items"><span class="n_checkouts" /> E-items Currently Checked out</a>
74 </td>
75 </tr>
76 <tr>
77 <td>
78 <a href="/eg/opac/myopac/holds"><span class="nholds" /> Items Currently on Hold</a>
79 </td>
80 <td align="right">
81 <a href="/eg/opac/myopac/holds?e_items"><span class="n_holds" /> E-items Currently on Hold</a>
82 </td>
83 </tr>
84 <tr>
85 <td>
86 <a href="/eg/opac/myopac/holds?available=1"><span class="nready" /> Items ready for pickup</a>
87 </td>
88 <td align="right">
89 <a href="/eg/opac/myopac/holds?e_items&available=1"><span class="n_ready" /> E-items ready for pickup</a>
90 </td>
91 </tr>
92 </tbody>
93 """
94 @empty().append tpl
95 return totals
96
97 else
98 @_counters x # Change the values of the counters
99
100 # Relabel a history tab
101 _tab_history: ->
102 $x = $('a', @)
103 $x.text "#{ $x.text() } (Physical Items)"
104 return @
105
106 # Add a new tab for e-items and select a tab relevant for the current page name.
107 # If page name contains 'history' then select any tabs with 'history' in its ID
108 # otherwise, if search parameters has 'e_items' property then select any tabs with 'eitems' in its ID
109 #$('#acct_holds_tabs, #acct_checked_tabs')._etabs()
110 _etabs: (page_name, e_items) ->
111
112 # Tab replacement is identified by container's id
113 new_tabs =
114 acct_holds_tabs: """
115 <div id="acct_holds_tabs">
116 <div class="align" id='tab_holds'>
117 <a href="holds#">Items on Hold</a>
118 </div>
119 <div class="align" id='tab_holds_eitems'>
120 <a href="holds?e_items">E-items on Hold</a>
121 </div>
122 <div class="align" id='tab_holds_history'>
123 <a href="hold_history">Holds History</a>
124 </div>
125 </div>
126 """
127 acct_checked_tabs: """
128 <div id="acct_checked_tabs">
129 <div class="align" id='tab_circs'>
130 <a href="circs#">Current Items Checked Out</a>
131 </div>
132 <div class="align" id='tab_circs_eitems'>
133 <a href="circs?e_items">E-items Checked Out</a>
134 </div>
135 <div class="align" id='tab_circs_history'>
136 <a href="circ_history">Check Out History</a>
137 </div>
138 </div>
139 """
140 @replaceWith new_tabs[@prop 'id']
141
142 # Compute the selected tab of the current page name
143 $selected =
144 # if page name ends with '_history', select the tab with id
145 # that ends with '_history'
146 if /_history$/.test page_name
147 $('[id$=_history]')
148 # else if search parameters has 'e_items' property, select the
149 # tab with id that ends with '_eitems'
150 else if e_items
151 $('[id$=_eitems]')
152 # else select the remaining tab
153 else
154 $('[id^=tab_]').not '[id$=_history],[id$=_eitems]'
155
156 $selected.addClass 'selected'
157
158 return @
159
160
161 # Resize columns of a table, either to fixed widths, or to be equal
162 # widths, ie, 100% divided by number of columns.
163 # Also, force width of table to 100%; don't know why this is necessary.
164 _resizeCols: ->
165
166 $table = @find 'table'
167 .css 'width', '100%'
168
169 # Resize to percentage widths given in the argument list
170 if arguments.length > 0
171 $th = $table.find 'th'
172 $td = $table.find 'td'
173 for width, n in arguments
174 $th.eq(n).css 'width', width
175 $td.eq(n).css 'width', width
176
177 # Otherwise, resize to equal widths
178 else
179 ncols = @find('th').length or 1
180 width = "#{100 / ncols}%"
181
182 $table
183 .find 'th'
184 .css 'width', width
185 .end()
186 .find 'td'
187 .css 'width', width
188 .end()
189
190 return @
191
192 # Show a container having a class name from a list of candidate, and hide the rest
193 _show_from: (which, candidates...) ->
194
195 @find(x).hide() for x in candidates
196 @find candidates[which]
197 .show()
198 .end()
199
200 # Replace a title of table with new text
201 _replace_title: (x) ->
202
203 @find '.header_middle span'
204 .eq 0
205 .text x
206 .end()
207
208 # Build an empty table for showing a list of holds
209 _holds_main: ->
210
211 table = """
212 <table cellpadding="0" cellspacing="0" border="0">
213 <thead id="acct_holds_main_header"><tr>
214 <th></th>
215 <th>Title/Author</th>
216 <th>Availability</th>
217 <th>Formats</th>
218 <th>Actions</th>
219 </tr></thead>
220 <tbody id="holds_temp_parent"></tbody>
221 </table>
222 <div class="warning_box">No holds found.</div>
223 """
224 @empty().append table
225 ._resizeCols '15%', '20%', '30%', '20%', '15%'
226
227 # Build <tr> elements for showing a list of holds
228 _holds_rows: (holds) ->
229 return [] unless holds
230
231 tpl = _.template """
232 <tr id="<%= id %>" name="acct_holds_temp" class="acct_holds_temp inactive-hold">
233 <td class="thumbnail"></td>
234 <td>
235 <div class="title" /> by <div class="author" />
236 </td>
237 <td class="availability"></td>
238 <td class="formats"></td>
239 <td class="actions"></td>
240 </tr>
241 """
242
243 ids = []
244 $rows = for hold in holds
245
246 ids.push hold.reserveId
247
248 # Build an empty row element that is uniquely identified by a
249 # product ID
250 $row = $ tpl id: hold.reserveId
251
252 # Fill the row with hold values and proxy the rest of the row
253 # with progress bars
254 $row
255 ._holds_row hold # hold values
256 ._row_meta() # progress bar
257 ._holds_row_avail() # progress bar
258
259 # Add hold rows to <tbody> and remove the warning box.
260 if $rows.length > 0
261 @find 'tbody'
262 .empty().append $rows
263 .end()
264 .find '.warning_box'
265 .remove()
266 .end()
267
268 return ids
269
270 _holds_row: (hold) ->
271
272 @find 'td.availability'
273 ._holds_row_avail1 hold
274 .end()
275 .find 'td.actions'
e2ef6d2a 276 ._actions hold.actions, hold.reserveId
8ebc3fff
SC
277 .end()
278
279 # Show a title, author, or format by using the given metadata object
280 _row_meta: (meta, classnames...) ->
281
282 status = if arguments.length is 0 then value: false else 'destroy'
e07737bf 283 try @find(".#{n}").progressbar(status) for n in ['title', 'author', 'formats']
8ebc3fff
SC
284
285 return @ unless meta
286
287 $title = $ """
288 <a href="/eg/opac/results?query=#{meta.title};locg=10;qtype=title">#{meta.title}</a>
289 """
290 $thumbnail = $ """
508513a1 291 <img src="#{meta.images?.thumbnail?.href}" alt="#{meta.title}" />
8ebc3fff
SC
292 """
293 $author = $ """
294 <a href="/eg/opac/results?query=#{meta.author};locg=10;qtype=author">#{meta.author}</a>
295 """
296 for n in classnames
297 $n = @find ".#{n}"
298 switch n
299 when 'thumbnail' then $n.empty().append $thumbnail
300 when 'title' then $n.empty().append $title
301 when 'author' then $n.empty().append $author
e07737bf 302 when 'formats' then $n._show_formats meta?.formats
8ebc3fff
SC
303 return @
304
305 _holds_row_avail1: (hold) ->
306
307 hold_status = if hold.holdSuspension then 0 else if hold.actions.checkout then 1 else 2
308
309 x = if hold.holdSuspension?.suspensionType is 'limited' then 'show' else 'hide'
310
311 tpl = _.template """
312 <div class="suspended">
313 <div style="color: red">Suspended <span class="limited">until <%= activates %></span></div>
314 <ul style="padding-left: 20px">
315 <li name="acct_holds_status"><%= position %> / <%= nHolds %> holds <span class="copies" /></li>
316 <li>Email notification will be sent to <%= email %></li>
317 <li>Hold was placed <%= placed %></li>
318 </ul>
319 </div>
320 <div class="unavailable">
321 <div>Waiting for copy</div>
322 <ul style="padding-left: 20px">
323 <li name="acct_holds_status"><%= position %> / <%= nHolds %> holds <span class="copies" /></li>
324 <li>Email notification will be sent to <%= email %></li>
325 <li>Hold was placed <%= placed %></li>
326 </ul>
327 </div>
328 <div class="available">
329 <div style="color: green">Ready for checkout</div>
330 <ul style="padding-left: 20px">
331 <li name="acct_holds_status"><%= position %> / <%= nHolds %> holds <span class="copies" /></li>
332 <li>Hold will expire <%= expires %></li>
333 </ul>
334 </div>
2e685799 335 <a href="http://downloads.bclibrary.ca/ContentDetails.htm?ID=<%= id %>">Link to Overdrive Account to change preferences</a>
8ebc3fff
SC
336 """
337 @empty().append tpl
338 position: hold.holdListPosition
339 nHolds: hold.numberOfHolds
340 email: hold.emailAddress
341 expires: hold.holdExpires.fromNow()
342 placed: hold.holdPlacedDate.fromNow()
343 activates: hold.holdSuspension?.numberOfDays.calendar()
6a1128e6 344 id: hold.reserveId
8ebc3fff
SC
345
346 # Illuminate areas of this row according to the hold status
347 ._show_from hold_status, '.suspended', '.available', '.unavailable'
348 # Show the hold suspension date only if suspension type is limited
349 .find('.limited')[x]()
350 .end()
351
352 # Complete building a <tr> element for showing a hold by using the
353 # given availability object
354 _holds_row_avail: (avail) ->
355
356 status = if arguments.length is 0 then value: false else 'destroy'
357 @find '.copies'
358 .progressbar status
359 .end()
360
361 return @ unless avail
362
363 text = """
364 on #{avail.copiesOwned} copies
365 """
366 @find '.copies'
367 .text text
368 .end()
369
370 # Build an empty table for showing a list of checkouts
371 _checkouts_main: ->
372
373 table = """
374 <table cellpadding="0" cellspacing="0" border="0">
375 <thead id="acct_checked_main_header"><tr>
376 <th></th>
377 <th>Title/Author</th>
378 <th>Availability</th>
379 <th>Formats</th>
380 <th>Actions</th>
381 </tr></thead>
382 <tbody id="holds_temp_parent"></tbody>
383 </table>
384 <div class="warning_box">No checkouts found.</div>
385 """
386 @empty().append table
387 ._resizeCols()
388
389 # Build <tr> elements for showing a list of checkouts
390 _checkouts_rows: (circs) ->
391 return [] unless circs
392
393 tpl = _.template """
394 <tr id="<%= id %>" name="acct_checked_temp" class="acct_checked_temp inactive-hold">
395 <td class="thumbnail"></td>
396 <td>
397 <div class="title" /> by <div class="author" />
398 </td>
399 <td class="availability"></td>
400 <td class="formats"></td>
401 <td class="actions"></td>
402 </tr>
403 """
404
405 ids = []
406 $rows = for circ in circs
407
408 ids.push circ.reserveId
409
410 # Build an empty row element that is uniquely identified by a
411 # product ID
412 $row = $ tpl id: circ.reserveId
413
414 # Fill the row with circ values and proxy the rest of the row
415 # with progress bars
416 $row
417 ._row_checkout circ # circ values
418 ._row_meta() # progress bars
419
420 # Add checkout rows to <tbody> and remove the warning box.
603dd210 421 if $rows.length > 0
8ebc3fff
SC
422 @find 'tbody'
423 .empty().append $rows
8ebc3fff
SC
424 .end()
425 .find '.warning_box'
426 .remove()
427 .end()
428
429 return ids
430
431 _row_checkout: (circ) ->
432
433 @find 'td.availability'
434 ._checkouts_row_avail circ
435 .end()
436 .find 'td.actions'
e2ef6d2a 437 ._actions circ.actions, circ.reserveId
8ebc3fff
SC
438 .end()
439 .find 'td.formats'
e2ef6d2a 440 ._formats circ.formats, circ.reserveId
8ebc3fff
SC
441 .end()
442
443 _checkouts_row_avail: (circ) ->
444
445 tpl = _.template """
446 <div>Expires <%= expires_relatively %></div>
447 <div><%= expires_exactly %></div>
6a1128e6 448 <a href="http://downloads.bclibrary.ca/ContentDetails.htm?ID=<%= id %>">Click to access online (library card required)</a>
8ebc3fff
SC
449 """
450 @empty().append tpl
451 expires_relatively: circ.expires.fromNow()
452 expires_exactly: circ.expires.format 'YYYY MMM D, h:mm:ss a'
6a1128e6 453 id: circ.reserveId
8ebc3fff
SC
454
455 # Build a <tr> element to show the available actions of an item.
456 # If the item is available, the check out action should be possible,
457 # and if unavailable, the place hold action should be possible.
458 _holdings_row: (id) ->
459
460 tpl = _.template """
461 <tr id="<%= id %>" name="acct_holds_temp" class="acct_holds_temp inactive-hold">
462 <td class="thumbnail"></td>
463 <td>
464 <div class="title" /> by <div class="author" />
465 </td>
466 <td class="availability"></td>
467 <td class="formats"><ul></ul></td>
468 <td class="actions"></td>
469 </tr>
470 """
471 $row = $(tpl id: id)
472 ._row_meta() # progress bar
473 ._holdings_row_avail() # progress bar
474
475 @find 'tbody'
476 .empty().append $row
477 .end()
478 .find '.warning_box'
479 .remove()
480 .end()
481
482 # Complete building a <tr> element for a holding using the given availability object
483 _holdings_row_avail: (avail) ->
484
485 # Create or destroy progress bars
486 status = if arguments.length is 0 then value: false else 'destroy'
487 @find 'td.availability'
488 .progressbar status
489 .end()
490 .find 'td.actions'
491 .progressbar status
492 .end()
493
494 return @ unless avail
495
496 tpl = _.template """
497 <div class="unavailable">No copies are available for checkout</div>
498 <div class="available" style="color: green">A copy is available for checkout</div>
499 <div><%= n_avail %> of <%= n_owned %> available, <%= n_holds %> holds</div>
500 """
501 @find 'td.availability'
502 .append tpl
503 n_owned: avail.copiesOwned
504 n_avail: avail.copiesAvailable
505 n_holds: avail.numberOfHolds
506 .end()
507
508 # Build action buttons
509 .find 'td.actions'
e2ef6d2a 510 ._actions avail.actions, avail.id
8ebc3fff
SC
511 .end()
512
513 # Illuminate areas of this row according to the holdings status
514 ._show_from (if avail.available then 0 else 1), '.available', '.unavailable'
515