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