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