Initial dev repository
[kcls-web.git] / opac / skin / phasefx / js / myopac.js
1 \r
2 //attachEvt("common", "run", myOPACInit );\r
3 // force init to run after opac_init();\r
4 dojo.addOnLoad(function(){setTimeout(myOPACInit, 0)});\r
5         \r
6 attachEvt('common','locationUpdated', myopacReload );\r
7 dojo.require('openils.Util');\r
8 \r
9 var FETCH_CONTAINER_DETAILS = ['open-ils.actor','open-ils.actor.container.flesh'];\r
10 var FETCH_CHECKED_DETAILS = ['open-ils.circ','open-ils.circ.actor.user.checked_out.atomic'];\r
11 var FETCH_CHECKED_HISTORY = ['open-ils.actor','open-ils.actor.history.circ.visible.atomic'];\r
12 var FETCH_FAV_SEARCHES = ['open-ils.actor','open-ils.actor.user.saved_search.retrieve'];\r
13 var FETCH_HOLD_DETAILS = ['open-ils.circ','open-ils.circ.hold.details.batch.retrieve.atomic'];\r
14 var FETCH_MODS_BY_COPY = ['open-ils.search','open-ils.search.biblio.mods_from_copy'];\r
15 var FETCH_CALL_NUMBER = ['open-ils.search','open-ils.search.callnumber.retrieve'];\r
16 var FETCH_MODS_SLIM = ['open-ils.search','open-ils.search.biblio.record.mods_slim.retrieve'];\r
17 var FETCH_FULL_USER = ['open-ils.actor','open-ils.actor.user.fleshed.retrieve'];\r
18 var FETCH_HOLD_IDS = ['open-ils.circ','open-ils.circ.holds.id_list.retrieve'];\r
19 var FETCH_COPY_OBJ = ['open-ils.search','open-ils.search.asset.copy.retrieve'];\r
20 var FETCH_OPT_INS = ['open-ils.actor','open-ils.actor.event_def.opt_in.settings.atomic'];\r
21 var FETCH_LISTS = ['open-ils.actor','open-ils.actor.container.flesh'];\r
22 var PASS_RESET = ['open-ils.actor','open-ils.actor.patron.password_reset.request'];\r
23 var PAY_BILLS = ['open-ils.circ','open-ils.circ.money.payment'];\r
24 // number of api calls to run before firing myOPACPostCollect() -- helps make all data available first (avoids having to make sync'd calls)\r
25 var TOTAL_CALLS = 6;\r
26 \r
27 var PREFS_PREDUE_3DAY = "notification.predue.email";\r
28 var PREFS_OVER_FIRST = "notification.overdue.first.email";\r
29 var PREFS_OVER_FIRST_P = "notification.overdue.first.phone";\r
30 var PREFS_HOLD_EXPIRE = "notification.hold.expire.email";\r
31 var PREFS_HOLD_CANCEL = "notification.hold.cancel.email";\r
32 var PREFS_CIRC_HIST_AGE = "history.circ.retention_age";\r
33 var PREFS_CIRC_HIST_START = "history.circ.retention_start";\r
34 \r
35 var listsCache = [];\r
36 var holdsCache = [];\r
37 var holdsCacheMap = [];\r
38 var itemsOutCache = [];\r
39 var callNumCache = [];\r
40 var favsCache = [];\r
41 var copyObjCache = [];\r
42 var mvrObjCache = [];\r
43 var itemsOutHistory = [];\r
44 var userOptIns = [];\r
45 var userOptInsMap = [];\r
46 var fleshedLists = [];\r
47 var imgFormatCache = [];\r
48 var fleshedContainers = {};\r
49 var subPageObjs = {};\r
50 \r
51 var CIRC_HIST_PAGE_LIMIT = 10;\r
52 var circHistPage = 0;\r
53 var showXUL = false;\r
54 var holdsList = null;\r
55 var fleshedUser = null;\r
56 var allowPendingAddr = false;\r
57 var currPage = "";\r
58 var templates = {};\r
59 var containerTemplate;\r
60 var containerTemplate2;\r
61 var myopacGenericTransTemplate;\r
62 var myopacCircTransTemplate;\r
63 var addrRowTemplate;\r
64 var notesTemplate;\r
65 \r
66 function myOPACInit() {\r
67         if(!(G.user && G.user.session)) {\r
68         initLogin();\r
69     } else {\r
70         allowPendingAddr = fetchOrgSettingDefault(G.user.home_ou(), 'opac.allow_pending_address');\r
71         if(allowPendingAddr) unHideMe($('myopac_pending_addr_td'));\r
72 \r
73                 unHideMe($('myopac_tabs'));\r
74                 currPage = "summary";\r
75                 holdsList = getCacheValue('saveAnonCache');\r
76                 if(holdsList) { currPage = "holds"; swapTabs($('acct_holds')); setCacheValue('saveAnonCache', null); TOTAL_CALLS -= 2; }\r
77                 var retUrl = getCacheValue('returnURL');\r
78                 if(retUrl) { setCacheValue('returnURL', null); setCacheValue('showHoldEditor', {record:retUrl.record, type:retUrl.type}); window.location=retUrl.href; }\r
79                 \r
80                 var sel = $('myopac_new_home');\r
81                 buildOrgSel(sel, globalOrgTree, 0);\r
82                 setSelector(sel, G.user.home_ou());\r
83                 \r
84                 switch(new CGI().param('acctpage')) {\r
85                         case "1": currPage = "summary";  break;\r
86                         case "2": currPage = "checked"; swapTabs($('acct_checked_out')); break;\r
87                         case "3": currPage = "holds"; swapTabs($('acct_holds')); break;\r
88                         case "4": currPage = "prefs"; swapTabs($('acct_prefs')); break;\r
89                         case "5": currPage = "fines"; swapTabs($('acct_favs')); break;\r
90                         case "6": currPage = "bookbag"; swapTabs($('acct_lists')); break;\r
91                 }\r
92                 \r
93                 if(!isXUL()) {\r
94                         unHideMe($('myopac_summary_email_change'));\r
95                         unHideMe($('myopac_summary_password_change'));\r
96                         unHideMe($('myopac_summary_username_change'));\r
97                 } else {\r
98                         unHideMe($('myopac_summary_phone1_change'));\r
99                         unHideMe($('myopac_summary_phone2_change'));\r
100                         unHideMe($('myopac_summary_phone3_change'));\r
101                 }\r
102 \r
103 \r
104         fieldmapper.standardRequest(FETCH_FULL_USER, {async:true, params:[G.user.session, G.user.id()],\r
105             oncomplete:function(r) {\r
106                                 showXUL = isXUL();\r
107                 fleshedUser = openils.Util.readResponse(r);\r
108                 myOPACShowUser(false);\r
109                         myOPACChangePage(currPage);\r
110                         myOPACInitTemplates();\r
111                         myOPACInitSubpages();\r
112                         //myOPACShowBookbags(true);\r
113                         if(holdsList) doBatchAnonHolds();\r
114                         showCanvas();\r
115             }\r
116         });\r
117         }\r
118 }\r
119 \r
120 function myopacReload() {\r
121         var a = {};\r
122         a[PARAM_LOCATION] = getNewSearchLocation();\r
123         a[PARAM_DEPTH] = getNewSearchDepth();\r
124         hideMe($('canvas_main'));\r
125         goTo(buildOPACLink(a, true));\r
126 }\r
127 \r
128 function myOPACChangePage( page ) {\r
129         var s = $("myopac_summary_td");\r
130         var c = $("myopac_checked_td");\r
131         var f = $("myopac_fines_td");\r
132         var h = $("myopac_holds_td");\r
133         var p = $("myopac_prefs_td");\r
134         var b = $('myopac_bookbag_td');\r
135 \r
136         var ss = $("myopac_summary_div");\r
137         var cc = $("myopac_checked_div");\r
138         var ff = $("myopac_fines_div");\r
139         var hh = $("myopac_holds_div");\r
140         var pp = $("myopac_prefs_div");\r
141         var bb = $('myopac_bookbag_div');\r
142 \r
143         hideMe(ss);\r
144         hideMe(cc); hideMe(ff);\r
145         hideMe(hh); hideMe(pp);\r
146         hideMe(bb);\r
147 \r
148     var oncomplete = null;\r
149 \r
150         switch( page ) {\r
151                 case "summary": unHideMe(ss);\r
152                         if($('show_fines_link').innerHTML=="Hide Overdue Materials") unHideMe(ff);\r
153             oncomplete = myOPACDrawSummary;\r
154                         break;\r
155 \r
156                 case "checked": \r
157             unHideMe(cc); \r
158             oncomplete = drawCheckedPage;\r
159             break;\r
160 \r
161                 case "holds": \r
162             unHideMe(hh); \r
163             oncomplete = drawHoldsPage;\r
164             break;\r
165 \r
166                 case "prefs": \r
167             unHideMe(pp); \r
168             oncomplete = myOPACShowPrefs;\r
169             break;\r
170 \r
171                 case 'bookbag': \r
172             unHideMe(bb); \r
173             break;\r
174         }\r
175         currPage = page;\r
176     myOPACGrabPageData(page, oncomplete);\r
177 }\r
178 \r
179 var fetchedPages={}\r
180 function myOPACGrabPageData(page, oncomplete) {\r
181     if(fetchedPages[page]) return;\r
182     fetchedPages[page] = true;\r
183 \r
184     switch(page) {\r
185 \r
186                 case "summary": \r
187             oncomplete();\r
188             break;\r
189 \r
190                 case "checked": \r
191 \r
192                 progressDialog.show(true);\r
193                 fieldmapper.standardRequest(FETCH_CHECKED_DETAILS, {async:true, params:[G.user.session, G.user.id()],\r
194                         oncomplete:function(r) {\r
195                         progressDialog.hide();\r
196                                 itemsOutCache = openils.Util.readResponse(r);\r
197                     oncomplete();\r
198                         }\r
199                 });\r
200 \r
201             break;\r
202 \r
203                 case "holds": \r
204 \r
205                 progressDialog.show(true);\r
206             fieldmapper.standardRequest(FETCH_HOLD_IDS, {async:true, params:[G.user.session, G.user.id()], \r
207                 oncomplete: function(r) { \r
208                     var holdids = openils.Util.readResponse(r);\r
209 \r
210                     fieldmapper.standardRequest(FETCH_HOLD_DETAILS, {async:true, params:[G.user.session, holdids], \r
211                         oncomplete: function(rr) {\r
212                                 progressDialog.hide();\r
213                             var holds = openils.Util.readResponse(rr);\r
214                             holdsCache = holds;\r
215                             setTimeout(function(){oncomplete()}, 150); // give the progress dialog a chance to clear out\r
216                         }\r
217                     });\r
218                 }\r
219             });\r
220 \r
221             break;\r
222 \r
223                 case "prefs": \r
224             fieldmapper.standardRequest(FETCH_OPT_INS, {async:true, params:[G.user.session],\r
225                 oncomplete:function(r) {\r
226                     userOptIns = openils.Util.readResponse(r);\r
227                     for(var i=0; i<userOptIns.length; i++) userOptInsMap[userOptIns[i].name()] = i;\r
228                     oncomplete();\r
229                 }\r
230             });\r
231 \r
232             break;\r
233 \r
234                 case 'bookbag': \r
235             myOPACShowBookbags(true);\r
236             break;\r
237     }\r
238 }\r
239 \r
240 \r
241 function myOPACDrawSummary() {\r
242     var stats = userVitalStats; // see misc.js\r
243         if(!stats) return;\r
244         $('myopac_sum_pickup').innerHTML = "("+stats.holds.ready+")";\r
245         $('myopac_sum_checked').innerHTML = "("+ (stats.checkouts.out+stats.checkouts.overdue) +")";\r
246         $('myopac_sum_holds').innerHTML = "("+stats.holds.total+")";\r
247     if(stats.fines.balance_owed > 0) {\r
248         var bal = $('myopac_sum_fines_bal');\r
249         bal.style.color = "red";\r
250         appendClear(bal, text("$" + Number(stats.fines.balance_owed).toFixed(2)));\r
251     }\r
252 }\r
253 \r
254 function myOPACInitTemplates() {\r
255         //holds page\r
256         if(!templates.holdsParent) templates.holdsParent = $('holds_temp_parent');\r
257         if(!templates.holdsTemp) templates.holdsTemp = templates.holdsParent.removeChild($('acct_holds_temp'));\r
258         //checked out page\r
259         if(!templates.checkedParent) templates.checkedParent = $('checked_temp_parent');\r
260         if(!templates.checkedTemp) templates.checkedTemp = templates.checkedParent.removeChild($('acct_checked_temp'));\r
261         //checked history page\r
262         if(!templates.circHistPar) templates.circHistPar = $('acct_checked_hist_parent');\r
263         if(!templates.circHistTemp) templates.circHistTemp = templates.circHistPar.removeChild($('acct_checked_hist_temp'));\r
264 }\r
265 \r
266 // link-up all the Account sub-pages for switchSubPage()\r
267 function myOPACInitSubpages() {\r
268         // create a primary object for each page...\r
269         subPageObjs.checked = {};\r
270         subPageObjs.holds = {};\r
271         subPageObjs.prefs = {};\r
272         \r
273         // ... then create an array for each sub-page\r
274         subPageObjs.checked.main = [];\r
275         subPageObjs.checked.hist = [];\r
276         subPageObjs.holds.main = [];\r
277         subPageObjs.holds.hist = [];\r
278         subPageObjs.prefs.info = [];\r
279         subPageObjs.prefs.notify = [];\r
280         subPageObjs.prefs.search = [];\r
281         \r
282         // add .header to each primary page object and link to the page's blue header bar.\r
283         // add ['header'] to each sub-page array and put the text to display\r
284         subPageObjs.checked.header = $('acct_checked_header');\r
285         subPageObjs.checked.main['header'] = "Current Items Checked Out";\r
286         subPageObjs.checked.hist['header'] = "Check Out History";\r
287         subPageObjs.checked.main.push($('checked_label'));\r
288         subPageObjs.checked.hist.push($('checked_link'));\r
289         subPageObjs.checked.main.push($('checked_hist_link'));\r
290         subPageObjs.checked.hist.push($('checked_hist_label'));\r
291         subPageObjs.checked.main.push($('checked_main'));\r
292         subPageObjs.checked.hist.push($('checked_hist'));\r
293         \r
294         subPageObjs.holds.header = $('acct_holds_header');\r
295         subPageObjs.holds.main['header'] = "Current Items on Hold";\r
296         subPageObjs.holds.hist['header'] = "Holds History";\r
297         subPageObjs.holds.main.push($('holds_label'));\r
298         subPageObjs.holds.hist.push($('holds_link'));\r
299         subPageObjs.holds.main.push($('holds_hist_link'));\r
300         subPageObjs.holds.hist.push($('holds_hist_label'));\r
301         subPageObjs.holds.main.push($('holds_main'));\r
302         subPageObjs.holds.hist.push($('holds_hist_table'));\r
303         \r
304         subPageObjs.prefs.header = $('acct_prefs_header');\r
305         subPageObjs.prefs.info['header'] = "Account Information and Preferences";\r
306         subPageObjs.prefs.notify['header'] = "Notification Preferences";\r
307         subPageObjs.prefs.search['header'] = "Search Preferences";\r
308         subPageObjs.prefs.info.push($('prefs_info_lbl'));\r
309         subPageObjs.prefs.notify.push($('prefs_info_link'));\r
310         subPageObjs.prefs.notify.push($('prefs_notify_lbl'));\r
311         subPageObjs.prefs.info.push($('prefs_notify_link'));\r
312         subPageObjs.prefs.search.push($('prefs_search_lbl'));\r
313         subPageObjs.prefs.info.push($('prefs_search_link'));\r
314         subPageObjs.prefs.notify.push($('prefs_search_link'));\r
315         subPageObjs.prefs.search.push($('prefs_notify_link'));\r
316         subPageObjs.prefs.search.push($('prefs_info_link'));\r
317         subPageObjs.prefs.info.push($('acct_info_main'));\r
318         subPageObjs.prefs.search.push($('acct_search_main'));\r
319         subPageObjs.prefs.notify.push($('acct_notify_main'));\r
320         subPageObjs.prefs.notify.push($('acct_prefs_save'));\r
321         subPageObjs.prefs.search.push($('acct_prefs_save'));\r
322 }\r
323 \r
324 var myopacForceHoldsRedraw = false;\r
325 function drawHoldsPage(sort) {\r
326         if(sort == undefined) sort = true;\r
327         if(!templates.holdsParent || !templates.holdsTemp) return;\r
328         var parent = templates.holdsParent;\r
329         var temp = templates.holdsTemp;\r
330         var ready = 0;\r
331         \r
332         if(myopacForceHoldsRedraw) {\r
333                 holdsCache = fieldmapper.standardRequest(FETCH_HOLD_DETAILS, {async:false, params:[G.user.session, \r
334                         fieldmapper.standardRequest(FETCH_HOLD_IDS, {async:false, params:[G.user.session, G.user.id()]})\r
335                 ]});\r
336         }\r
337 \r
338         if(sort) holdsCache = holdsCache.sort(function(a, b) {\r
339                 if(a.status==4) return -1;\r
340                 if(b.status==4) return 1;\r
341                 if(isTrue(a.hold.frozen())) return 1;\r
342                 if(isTrue(b.hold.frozen())) return -1;\r
343                 return dojo.date.stamp.fromISOString(a.hold.request_time()) > dojo.date.stamp.fromISOString(b.hold.request_time())?1:-1;\r
344         });\r
345         \r
346         holdsCacheMap=[];\r
347         for(var i=0; i<holdsCache.length; i++) holdsCacheMap[holdsCache[i].hold.id()] = i;\r
348         \r
349         removeChildren(parent); \r
350         var row = null;\r
351         var h = null;\r
352         var form = null;\r
353         var tree = null;\r
354         var activeSel = null;\r
355         var ress = "";\r
356         var imgTD = null;\r
357         var imgEl = null;\r
358         var d = null;\r
359         var exp_date;\r
360         var suffix = "";\r
361         for(var i in holdsCache) {\r
362                 row = temp.cloneNode(true);\r
363                 h = holdsCache[i];\r
364                 row.id = "myopac_holds_row_" + h.hold.id();\r
365                 form = $n(row, "myopac_holds_formats");\r
366                 form.id = "myopac_holds_form_" + h.hold.id();\r
367                 $n(row,'hold_pickup_lib_span').appendChild($('hold_pickup_lib_temp').cloneNode(true));\r
368                 \r
369                 tree = $n(row,'hold_pickup_lib_sel');\r
370                 buildOrgSelAlt(tree, globalOrgTree, 0);\r
371                 setSelector(tree, h.hold.pickup_lib());\r
372                 $n(row,'check_all_holds').holdid = h.hold.id();\r
373                 $n(row,'hold_edit_link').setAttribute('href','javascript:editHold('+h.hold.id()+');'); \r
374                 $n(row,'hold_cancel_link').setAttribute('href','javascript:cancelHold('+h.hold.id()+');');\r
375                 $n(row,'hold_save_link').setAttribute('href','javascript:saveHold('+h.hold.id()+');');\r
376                 activeSel = $n(row,'hold_active_sel');\r
377                 activeSel.selectedIndex = isTrue(h.hold.frozen())?1:0;\r
378                 \r
379                 //var djBox = $n(row,'activate_box').parentNode.parentNode.parentNode;\r
380                 //djBox.id=djBox.id+h.hold.id();\r
381                 //var blah = dojo.query('input',$n(row,'activate_box').parentNode)[0];\r
382                 //blah.id = djBox.getAttribute("widgetId")+h.hold.id();\r
383                 //$().id = djBox.id+h.hold.id();\r
384                 //djBox.setAttribute("widgetId", djBox.getAttribute("widgetId")+h.hold.id());\r
385                 \r
386                 $n(row,'hold_pickup_lib').innerHTML = findOrgUnit(h.hold.pickup_lib()).name();\r
387                 $n(row,'hold_active').innerHTML = isTrue(h.hold.frozen())?"Suspended":"Active";\r
388                 if(isTrue(h.hold.frozen())) row.style.background="#ebf9ff";\r
389                 \r
390                 if(h.hold.thaw_date()) {\r
391                         d = dojo.date.stamp.fromISOString(h.hold.thaw_date());\r
392                         $n(row, 'activate_date').innerHTML = dojo.date.locale.format(d, {selector: 'date', fullYear: true});\r
393                         unHideMe($n(row,'activate_label'));\r
394                         $n(row,'activate_box').value = dojo.date.locale.format(d, {selector:'date', fullYear: true});\r
395                 }\r
396                 \r
397                 if(h.hold.expire_time()) {\r
398                         exp_date = dojo.date.stamp.fromISOString(h.hold.expire_time().replace(/(T\d\d:\d\d:\d\d)([+-]\d\d)(\d)/, "$1$2:$3"))\r
399                         $n(row, 'hold_expires').innerHTML = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});\r
400                         unHideMe($n(row,'hold_expires_label'));\r
401                         $n(row,'hold_expires_box').value = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});\r
402                 }\r
403                 \r
404                 buildTitleDetailLink(h.mvr, $n(row,'myopac_holds_title_link'));\r
405                 $n(row,'myopac_holds_title_link').title = h.mvr.title();\r
406                 \r
407                 imgTD = $n(row, "myopac_holds_formats");\r
408                 imgEl = elem('img');\r
409                 imgEl.className = 'hide_me';\r
410                 imgEl.name = 'format_icon_'+h.hold.id();\r
411                 imgTD.appendChild(imgEl);\r
412                 if(imgFormatCache[h.hold.id()]==null) imgFormatCache[h.hold.id()] = getMarcData(h.mvr.doc_id(),"998","d");\r
413                 setFormatIcon(imgEl, imgFormatCache[h.hold.id()]);\r
414                 \r
415                 $n(row,'myopac_holds_author').innerHTML = h.mvr.author();\r
416                 \r
417                 if( h.status == 4) {\r
418                         ready++;\r
419                         $n(row,'acct_holds_status').innerHTML = "<span style='color:blue;font-weight:bold;'>Ready for Pickup</span>";\r
420                         hideMe($n(row,'holds_editor_row'));\r
421                         unHideMe($n(row,'holds_ready_row'));\r
422                         if(h.hold.shelf_expire_time()) $n(row,'hold_ready_expire').innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(h.hold.shelf_expire_time()), {selector:'date', fullYear: true});;\r
423                 } else {\r
424                         var num = h.queue_position+'';\r
425                         suffix = (num.charAt(num.length-1)=="1")?"st":(num.charAt(num.length-1)=="2")?"nd":(num.charAt(num.length-1)=="3")?"rd":"th";\r
426                         if(num=="11" || num=="12" || num=="13") suffix = "th";\r
427                         $n(row,'acct_holds_status').innerHTML = h.queue_position+suffix+" hold on "+h.potential_copies+" circulating cop"+(h.potential_copies==1?"y":"ies");\r
428                 }\r
429                 parent.appendChild(row);\r
430         }\r
431         $('myopac_sum_pickup').innerHTML = "("+ready+")";\r
432         if(!holdsCache.length) parent.appendChild(elem('div',{style:"font-weight:bold;font-size:14px;width:100%;text-align:center;",align:'center'},'No holds found.'));\r
433 }\r
434 \r
435 var checkedDrawn = true;\r
436 function drawCheckedPage(sort) {\r
437         if(sort==undefined) sort = true;\r
438         if(!templates.checkedParent || !templates.checkedTemp) return;\r
439         var parent = templates.checkedParent;\r
440         var temp = templates.checkedTemp;\r
441         \r
442         if(!checkedDrawn) itemsOutCache = fieldmapper.standardRequest(FETCH_CHECKED_DETAILS, {async:false, params:[G.user.session, G.user.id()]});\r
443         if(sort) itemsOutCache = itemsOutCache.sort(function(a, b) {\r
444                 if(dojo.date.stamp.fromISOString(a.circ.due_date()) > dojo.date.stamp.fromISOString(b.circ.due_date())) return 1;\r
445                 return -1;\r
446         });\r
447         checkedDrawn = true;\r
448         \r
449         removeChildren(parent);\r
450         for(var i in itemsOutCache) {\r
451                 var row = temp.cloneNode(true);\r
452                 var out = itemsOutCache[i];\r
453                 //row.id = "myopac_holds_row_" + out.hold.id();\r
454                 if(!mvrObjCache[out.circ.target_copy()]) mvrObjCache[out.circ.target_copy()] = out.record;\r
455                 if(!copyObjCache[out.copy.id()]) copyObjCache[out.copy.id()] = out.copy;\r
456                                 \r
457                 if(out.circ.due_date()) {\r
458                         var exp_date = dojo.date.stamp.fromISOString(out.circ.due_date());\r
459                         if(exp_date<(new Date())) $n(row,'due_date').style.color="red";\r
460                         $n(row, 'due_date').innerHTML = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});\r
461                 }\r
462                 \r
463                 $n(row, 'renewals').innerHTML = out.circ.renewal_remaining();\r
464                 buildTitleDetailLink(out.record, $n(row,'title'));\r
465                 if(out.record.author()) $n(row, 'author').appendChild(text(" / "+out.record.author()));\r
466                 dojo.attr($n(row, 'check_all_checked'), 'circid', out.circ.id())\r
467                 $n(row,'title').title = out.record.title();\r
468                 $n(row, 'barcode').innerHTML = out.copy.barcode();\r
469                 if(callNumCache[out.copy.call_number()]==null) callNumCache[out.copy.call_number()] = fieldmapper.standardRequest(FETCH_CALL_NUMBER, {async:false, params:[out.copy.call_number()]});\r
470                 $n(row, 'call_number').innerHTML = callNumCache[out.copy.call_number()].label();\r
471                 \r
472                 parent.appendChild(row);\r
473         }\r
474         \r
475         if(!itemsOutCache.length) parent.appendChild(elem('div',{style:"font-weight:bold;font-size:14px;width:100%;text-align:center;",align:'center'},'No items checked out.'));\r
476 }\r
477 \r
478 var circHistDrawn = true;\r
479 function drawCircHistory(sort, offset) {\r
480         if(sort==undefined) sort = true;\r
481         if(offset==undefined) offset = circHistPage; else circHistPage = offset;\r
482         if(!templates.circHistPar || !templates.circHistTemp) return;\r
483         var parent = templates.circHistPar;\r
484         var temp = templates.circHistTemp;\r
485         \r
486         if(!circHistDrawn) itemsOutHistory = fieldmapper.standardRequest(FETCH_CHECKED_HISTORY, {async:false, params:[G.user.session, G.user.id(), {'limit':CIRC_HIST_PAGE_LIMIT, 'offset':offset}]});\r
487         circHistDrawn = true;\r
488         \r
489         removeChildren(parent);\r
490         for(var i in itemsOutHistory) {\r
491                 var row = temp.cloneNode(true);\r
492                 var h = itemsOutHistory[i];\r
493                 if(mvrObjCache[h.circ.target_copy()]==null) mvrObjCache[h.circ.target_copy()] = fieldmapper.standardRequest(FETCH_MODS_BY_COPY, {async:false, params:[h.circ.target_copy()]});\r
494                 var mvr = mvrObjCache[h.circ.target_copy()];\r
495                 \r
496                 if(mvr && !mvr.desc) {\r
497                         buildTitleDetailLink(mvr, $n(row, 'title'));\r
498                         $n(row, 'title').title = mvr.title();\r
499                         $n(row, 'author').innerHTML = mvr.author();\r
500                         \r
501                         //dojo.date.locale.format(dojo.date.stamp.fromISOString(), {selector:'date', fullYear: true});\r
502                 }\r
503                 \r
504                 //date formatting and coloring\r
505                 var ret = $n(row, 'returned');\r
506                 var due = $n(row, 'due_date');\r
507                 $n(row, 'checkout').innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(h.circ.create_time()), {selector:'date', fullYear: true});\r
508                 due.innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(h.circ.due_date()), {selector:'date', fullYear: true});\r
509                 if(!h.circ.checkin_time() && new Date() > dojo.date.stamp.fromISOString(h.circ.due_date())) due.style.color="red";\r
510                 if(h.circ.checkin_time() && dojo.date.stamp.fromISOString(h.circ.checkin_time()) > dojo.date.stamp.fromISOString(h.circ.due_date())) ret.style.color="red";\r
511                 if(h.circ.checkin_time()) ret.innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(h.circ.checkin_time()), {selector:'date', fullYear: true});\r
512                 else ret.innerHTML = "Checked Out";\r
513                 \r
514                 if(copyObjCache[h.circ.target_copy()]==null) copyObjCache[h.circ.target_copy()] = fieldmapper.standardRequest(FETCH_COPY_OBJ, {async:false, params:[h.circ.target_copy()]});\r
515                 if(callNumCache[copyObjCache[h.circ.target_copy()].call_number()]==null)\r
516                         callNumCache[copyObjCache[h.circ.target_copy()].call_number()] = fieldmapper.standardRequest(FETCH_CALL_NUMBER, {async:false, params:[copyObjCache[h.circ.target_copy()].call_number()]});\r
517                 \r
518                 if(copyObjCache[h.circ.target_copy()] && callNumCache[copyObjCache[h.circ.target_copy()].call_number()])\r
519                         $n(row,'call_number').innerHTML = callNumCache[copyObjCache[h.circ.target_copy()].call_number()].label();\r
520                 parent.appendChild(row);\r
521         }\r
522         \r
523         if(!itemsOutHistory.length) {\r
524                 parent.appendChild(elem('tr').appendChild(elem('td',{style:"font-weight:bold;font-size:14px;width:100%;text-align:center;",align:'center'},'No items found.')));\r
525                 return;\r
526         }\r
527         \r
528         //build pagination\r
529         var pageTR = elem('tr');\r
530         var pageTD = elem('td', {'align':'center', 'colspan':'5'}, null);\r
531         \r
532         var offPrev = offset - CIRC_HIST_PAGE_LIMIT;\r
533         var offNext = offset + CIRC_HIST_PAGE_LIMIT;\r
534         if(offset==0) offPrev = 0;\r
535         \r
536         if(offset!=0) var prev = elem('a', {'href':'javascript: circHistDrawn = false; drawCircHistory(true,'+offPrev+');'}, '< Previous');\r
537         else var prev = elem('span', null, '< Previous');\r
538         if(itemsOutHistory.length<CIRC_HIST_PAGE_LIMIT) var next = elem('span', null, 'Next >');\r
539         else var next = elem('a', {'href':'javascript:  circHistDrawn = false; drawCircHistory(true,'+offNext+');'}, 'Next >');\r
540         \r
541         pageTD.appendChild(prev);\r
542         pageTD.appendChild(elem('span', null, '    '));\r
543         pageTD.appendChild(next);\r
544         pageTR.appendChild(pageTD);\r
545         parent.appendChild(pageTR);\r
546 }\r
547 \r
548 function myOPACShowPrefs() {\r
549         grabUserPrefs();\r
550         myOPACShowHitsPer();\r
551         myOPACShowDefFont();\r
552         myOPACShowDefLocation();\r
553         myOPACShowNotifyPrefs();\r
554         hideMe($('myopac_prefs_loading'));\r
555 }\r
556 \r
557 var defSearchLocationDrawn = false;\r
558 var defDepthIndex = 0;\r
559 function myOPACShowDefLocation() {\r
560 \r
561         var selector = $('prefs_def_location');\r
562         var rsel = $('prefs_def_range');\r
563 \r
564         if(!defSearchLocationDrawn) {\r
565                 defSearchLocationDrawn = true;\r
566                 var org = G.user.prefs[PREF_DEF_LOCATION];\r
567 \r
568                 if(!org) {\r
569                         $('myopac_pref_home_lib').checked = true;\r
570                         $('prefs_def_location').disabled = true;\r
571                         org = G.user.home_ou();\r
572                 }\r
573                 buildOrgSel(selector, globalOrgTree, 0);\r
574 \r
575                 globalOrgTypes = globalOrgTypes.sort(\r
576                         function(a, b) {\r
577                                 if( a.depth() < b.depth() ) return -1;\r
578                                 return 1;\r
579                         }\r
580                 );\r
581 \r
582                 iterate(globalOrgTypes,\r
583                         function(t) {\r
584                                 if( t.depth() <= findOrgDepth(org) ) {\r
585                                         setSelectorVal(rsel, defDepthIndex++, t.opac_label(), t.depth());\r
586                                         if( t.depth() == findOrgDepth(org)) \r
587                                                 setSelector(rsel, t.depth());\r
588                                 }\r
589                         }\r
590                 );\r
591         }\r
592 \r
593         setSelector(selector, org);\r
594 }\r
595 \r
596 function myOPACShowNotifyPrefs() {\r
597         var preEmail = $(PREFS_PREDUE_3DAY);\r
598         var overEmail = $(PREFS_OVER_FIRST);\r
599         var overPhone = $(PREFS_OVER_FIRST_P);\r
600         var holdsCancel = $(PREFS_HOLD_CANCEL);\r
601         var holdsExpire = $(PREFS_HOLD_EXPIRE);\r
602         var holdsEmail = $(PREF_HOLD_NOTIFY+".email");\r
603         var holdsPhone = $(PREF_HOLD_NOTIFY+".phone");\r
604         if(G.user.prefs[PREFS_CIRC_HIST_START]) { $('circHistStart').checked = true; }\r
605         \r
606         if(preEmail && typeof(G.user.prefs[PREFS_PREDUE_3DAY])   !="undefined") preEmail.checked  = G.user.prefs[PREFS_PREDUE_3DAY];\r
607         if(overEmail && typeof(G.user.prefs[PREFS_OVER_FIRST])   !="undefined") overEmail.checked = G.user.prefs[PREFS_OVER_FIRST];\r
608         if(overPhone && typeof(G.user.prefs[PREFS_OVER_FIRST_P]) !="undefined") overPhone.checked = G.user.prefs[PREFS_OVER_FIRST_P];\r
609         if(holdsCancel && typeof(G.user.prefs[PREFS_HOLD_CANCEL])!="undefined") holdsCancel.checked = G.user.prefs[PREFS_HOLD_CANCEL];\r
610         if(holdsExpire && typeof(G.user.prefs[PREFS_HOLD_EXPIRE])!="undefined") holdsExpire.checked = G.user.prefs[PREFS_HOLD_EXPIRE];\r
611         if(typeof(G.user.prefs[PREF_HOLD_NOTIFY])!="undefined") {\r
612                 var pref = G.user.prefs[PREF_HOLD_NOTIFY];\r
613                 if(pref.match(/email/)) holdsEmail.checked = true;\r
614                 if(pref.match(/phone/)) holdsPhone.checked = true;\r
615         }\r
616 }\r
617 \r
618 function myOPACShowHitsPer() {\r
619         var hits = 10;\r
620         if(G.user.prefs[PREF_HITS_PER])\r
621                 hits = G.user.prefs[PREF_HITS_PER];\r
622         var hitsSel = $('prefs_hits_per');\r
623         setSelector(hitsSel, hits);\r
624 }\r
625 \r
626 function myOPACShowDefFont() {\r
627         var font;\r
628         if(G.user.prefs[PREF_DEF_FONT])\r
629                 font = G.user.prefs[PREF_DEF_FONT];\r
630         else font = "regular";\r
631         setSelector($('prefs_def_font'), font);\r
632 }\r
633 \r
634 function myOPACShowUser(bool) {\r
635         if(bool) fleshedUser = fieldmapper.standardRequest(FETCH_FULL_USER, {async:false, params:[G.user.session, G.user.id()]});\r
636         var user = fleshedUser;\r
637         \r
638     var expireDate = dojo.date.stamp.fromISOString(user.expire_date());\r
639     if( expireDate < new Date() ) {\r
640         appendClear($('myopac.expired.date'), expireDate.iso8601Format('YMD'));\r
641         unHideMe($('myopac.expired.alert'));\r
642     }\r
643 \r
644         var iv1 = user.ident_value()+'';\r
645     if (iv1.length > 4 && iv1.match(/\d{4}/)) iv1 = iv1.substring(0,4) + '***********';\r
646 \r
647         appendClear($('myopac_sum_name'),text(user.first_given_name()+" "+(user.family_name()==null?"":user.family_name())));   \r
648         appendClear($('myopac_summary_prefix'),text(user.first_given_name()+" "+(user.family_name()==null?"":user.family_name())));\r
649         appendClear($('myopac_summary_homelib'),text(findOrgUnit(user.home_ou()).name()));\r
650 \r
651         appendClear($('myopac_summary_dayphone'),text(user.day_phone()));\r
652         appendClear($('myopac_summary_eveningphone'),text(user.evening_phone()));\r
653         appendClear($('myopac_summary_otherphone'),text(user.other_phone()));\r
654         appendClear($('myopac_summary_suffix'),text(user.suffix()));\r
655         appendClear($('myopac_summary_username'),text(user.usrname()));\r
656         appendClear($('myopac_summary_email'),text(user.email()));\r
657         appendClear($('myopac_summary_barcode'),text(user.card().barcode()));\r
658         appendClear($('myopac_summary_ident1'),text(iv1));\r
659         appendClear($('myopac_summary_create_date'),text(_trimTime(user.create_date())));\r
660 \r
661         var req = new Request( \r
662                 FETCH_USER_NOTES, G.user.session, {pub:1, patronid:G.user.id()});\r
663         req.callback(myopacDrawNotes);\r
664         req.send();\r
665 \r
666         var tbody = $('myopac_addr_tbody');\r
667         var template;\r
668 \r
669         if(addrRowTemplate) { \r
670                 template = addrRowTemplate;\r
671         } else {\r
672                 template = tbody.removeChild($('myopac_addr_row'));\r
673                 addrRowTemplate = template;\r
674         }\r
675         removeChildren(tbody);\r
676 \r
677     var addrs = user.addresses();\r
678         for( var a in addrs ) {\r
679         var addr = addrs[a];\r
680         if(!allowPendingAddr && isTrue(addr.pending()))\r
681             continue;\r
682         if(addr.replaces() != null) continue;\r
683                 var row = template.cloneNode(true);\r
684                 myOPACDrawAddr(row, addr, addrs);\r
685                 tbody.appendChild(row);\r
686         }\r
687 }\r
688 \r
689 function myopacDrawNotes(r) {\r
690         var notes = r.getResultObject();\r
691         var tbody = $('myopac.notes.tbody');\r
692         if(!notesTemplate)\r
693                 notesTemplate = tbody.removeChild($('myopac.notes.tr'));\r
694         removeChildren(tbody);\r
695 \r
696         iterate(notes, \r
697                 function(note) {\r
698                         unHideMe($('myopac.notes.div'));\r
699                         var row = notesTemplate.cloneNode(true);\r
700                         $n(row, 'title').appendChild(text(note.title()));\r
701                         $n(row, 'value').appendChild(text(note.value()));\r
702                         tbody.appendChild(row);\r
703                 }\r
704         );\r
705 }\r
706 \r
707 function myOPACDrawAddr(row, addr, addrs) {\r
708     appendClear($n(row, 'myopac_addr_type'),text(addr.address_type()));\r
709     appendClear($n(row, 'myopac_addr_street'),text(addr.street1()));\r
710     appendClear($n(row, 'myopac_addr_street2'),text(addr.street2()));\r
711     appendClear($n(row, 'myopac_addr_city'),text(addr.city()));\r
712     appendClear($n(row, 'myopac_addr_county'),text(addr.county()));\r
713     appendClear($n(row, 'myopac_addr_state'),text(addr.state()));\r
714     appendClear($n(row, 'myopac_addr_country'),text(addr.country()));\r
715     appendClear($n(row, 'myopac_addr_zip'),text(addr.post_code()));\r
716 \r
717     if(!allowPendingAddr) return;\r
718 \r
719     $n(row, 'myopac_addr_edit_link').onclick = function(){myopacEditAddress(addr)};\r
720     unHideMe($n(row, 'myopac_addr_edit_td'));\r
721 \r
722     /* if we have a replacement address, plop it into the table next to this addr */\r
723     var repl = grep(addrs, function(a) { return a.replaces() == addr.id(); });\r
724 \r
725     $n(row, 'myopac_pending_addr_td').id = 'myopac_pending_addr_td_' + addr.id();\r
726 \r
727     if(repl) {\r
728         hideMe($n(row, 'myopac_addr_edit_td')); // hide the edit link\r
729         repl = repl[0];\r
730         myopacSetAddrInputs(row, repl);\r
731     }\r
732 }\r
733 \r
734 function myopacEditAddress(addr) {\r
735     var td = $('myopac_pending_addr_td_' + addr.id());\r
736     var row = td.parentNode;\r
737     myopacSetAddrInputs(row, addr);\r
738 }\r
739 \r
740 function myopacSetAddrInputs(row, addr, prefix) {\r
741     unHideMe($n(row, 'myopac_pending_addr_td'));\r
742     $n(row, 'myopac_pending_addr_type').value = addr.address_type();\r
743     $n(row, 'myopac_pending_addr_street').value = addr.street1();\r
744     $n(row, 'myopac_pending_addr_street2').value = addr.street2();\r
745     $n(row, 'myopac_pending_addr_city').value = addr.city();\r
746     $n(row, 'myopac_pending_addr_county').value = addr.county();\r
747     $n(row, 'myopac_pending_addr_state').value = addr.state();\r
748     $n(row, 'myopac_pending_addr_country').value = addr.country();\r
749     $n(row, 'myopac_pending_addr_zip').value = addr.post_code();\r
750     $n(row, 'myopac_pending_addr_edit_link').onclick = function(){myopacSaveAddress(row, addr)};\r
751     $n(row, 'myopac_pending_addr_del_link').onclick = function(){myopacSaveAddress(row, addr, true)};\r
752 }\r
753 \r
754 function _trimTime(time) { \r
755         if(!time) return ""; \r
756     var d = dojo.date.stamp.fromISOString(time);\r
757     if(!d) return ""; /* date parse failed */\r
758     return d.iso8601Format('YMD');\r
759 }\r
760 \r
761 function _trimSeconds(time) { \r
762     if(!time) return ""; \r
763     var d = dojo.date.stamp.fromISOString(time);\r
764     if(!d) return ""; /* date parse failed */\r
765     return d.iso8601Format('YMDHM',null,true,true);\r
766 }\r
767 \r
768 function myopacSaveAddress(row, addr, deleteMe) {\r
769     if(addr.replaces() == null) {\r
770         var repl = new aua();\r
771         repl.usr(addr.usr());\r
772         repl.address_type(addr.address_type());\r
773         repl.within_city_limits(addr.within_city_limits());\r
774         repl.replaces(addr.id());\r
775         repl.pending('t');\r
776         repl.isnew(true);\r
777         repl.id(null);\r
778         addr = repl;\r
779     }\r
780 \r
781     if(deleteMe) {\r
782         if(addr.id() == null) {\r
783             hideMe($n(row, 'myopac_pending_addr_td'));\r
784             return;\r
785         }\r
786         addr.isdeleted(true);\r
787     } else {\r
788         addr.address_type($n(row, 'myopac_pending_addr_type').value);\r
789         addr.street1($n(row, 'myopac_pending_addr_street').value);\r
790         addr.street2($n(row, 'myopac_pending_addr_street2').value);\r
791         addr.city($n(row, 'myopac_pending_addr_city').value);\r
792         addr.county($n(row, 'myopac_pending_addr_county').value);\r
793         addr.state($n(row, 'myopac_pending_addr_state').value);\r
794         addr.country($n(row, 'myopac_pending_addr_country').value);\r
795         addr.post_code($n(row, 'myopac_pending_addr_zip').value);\r
796     }\r
797 \r
798         var req = new Request('open-ils.actor:open-ils.actor.user.address.pending.cud', G.user.session, addr);\r
799 \r
800     req.callback(\r
801         function(r) {\r
802             var resp = r.getResultObject(); \r
803 \r
804             if(addr.isnew()) {\r
805                 // new, add to list of addrs\r
806                 addr.id(resp);\r
807                 fleshedUser.addresses().push(addr);\r
808             } else {\r
809                 // deleted, remove from list of addrs\r
810                 if(addr.isdeleted()) {\r
811                     hideMe($n(row, 'myopac_pending_addr_td'));\r
812                     var addrs = [];\r
813                     for(var i in fleshedUser.addresses()) {\r
814                         var a = fleshedUser.addresses()[i];\r
815                         if(a.id() != addr.id()) addrs.push(a);\r
816                     }\r
817                     fleshedUser.addresses(addrs);\r
818                 }\r
819             }\r
820            alertId('myopac_addr_changes_saved');\r
821         }\r
822     );\r
823     req.send();\r
824 }\r
825 \r
826 function myOPACSavePrefs() {\r
827         G.user.prefs[PREF_HITS_PER] = getSelectorVal($('prefs_hits_per'));\r
828         G.user.prefs[PREF_DEF_FONT] = getSelectorVal($('prefs_def_font'));\r
829         //G.user.prefs[PREF_HOLD_NOTIFY] = getSelectorVal($('prefs_hold_notify'));\r
830         G.user.prefs[PREF_DEF_DEPTH] = getSelectorVal($('prefs_def_range'));\r
831         \r
832         var holdsPhone = $(PREF_HOLD_NOTIFY+".phone");\r
833         var holdsEmail = $(PREF_HOLD_NOTIFY+".email");\r
834         var circStartBox = $('circHistStart').checked;\r
835         var circStart = null;\r
836         circStart = (circStartBox && G.user.prefs[PREFS_CIRC_HIST_START])?G.user.prefs[PREFS_CIRC_HIST_START]:dojo.date.stamp.toISOString(new Date());\r
837         if(!circStartBox) circStart = null;\r
838         \r
839         G.user.prefs[PREF_HOLD_NOTIFY] = holdsPhone.checked?(holdsEmail.checked?"phone:email":"phone"):(holdsEmail.checked?"email":"");\r
840         G.user.prefs[PREFS_PREDUE_3DAY] = $(PREFS_PREDUE_3DAY).checked;\r
841         G.user.prefs[PREFS_OVER_FIRST] = $(PREFS_OVER_FIRST).checked;\r
842         G.user.prefs[PREFS_OVER_FIRST_P] = $(PREFS_OVER_FIRST_P).checked;\r
843         G.user.prefs[PREFS_HOLD_EXPIRE] = $(PREFS_HOLD_EXPIRE).checked;\r
844         G.user.prefs[PREFS_HOLD_CANCEL] = $(PREFS_HOLD_CANCEL).checked;\r
845         //G.user.prefs[PREFS_CIRC_HIST_AGE] = "2592000";\r
846         G.user.prefs[PREFS_CIRC_HIST_START] = circStart;\r
847 \r
848         if( $('myopac_pref_home_lib').checked == true )\r
849                 G.user.prefs[PREF_DEF_LOCATION] = null;\r
850         else\r
851                 G.user.prefs[PREF_DEF_LOCATION] = getSelectorVal($('prefs_def_location'));\r
852 \r
853   try {\r
854         if(commitUserPrefs())\r
855                 alert($('prefs_update_success').innerHTML);\r
856         else alert($('prefs_update_failure').innerHTML);\r
857   } catch(e) {\r
858         alert(e);  \r
859   }\r
860         fieldmapper.standardRequest(FETCH_CHECKED_HISTORY,{params:[G.user.session, G.user.id()],oncomplete:function(r){\r
861                 var resp = r.recv();\r
862                 if(resp) resp = resp.content();\r
863         }});\r
864 }\r
865 \r
866 function myOPACUpdateEmail() {\r
867         var email = $('myopac_new_email').value;\r
868         if(email == null || email == "") {\r
869                 alert($('myopac_email_error').innerHTML);\r
870                 return;\r
871         }\r
872 \r
873         var req = new Request(UPDATE_EMAIL, G.user.session, email );\r
874         req.send(true);\r
875         if(req.result()) {\r
876                 G.user.usrname(email);\r
877                 hideMe($('myopac_update_email_row'));\r
878                 userShown = false;\r
879                 alertId('myopac_email_success');\r
880                 myOPACShowUser(true);\r
881                 return;\r
882         }\r
883 \r
884         alert($('myopac_email_failure').innerHTML);\r
885 }\r
886 \r
887 function myOPACUpdatePassword() {\r
888         var curpassword = $('myopac_current_password').value;\r
889         var password = $('myopac_new_password').value;\r
890         var password2 = $('myopac_new_password2').value;\r
891 \r
892         if(     curpassword == null || curpassword == "" || \r
893                         password == null || password == "" || \r
894                         password2 == null || password2 == "" || password != password2 ) {\r
895                 alert($('myopac_password_error').innerHTML);\r
896                 return;\r
897         }\r
898 \r
899         if(!strongPassword(password, true)) return;\r
900 \r
901         var req = new Request(UPDATE_PASSWORD, G.user.session, password, curpassword );\r
902         req.send(true);\r
903         if(req.result()) {\r
904                 hideMe($('myopac_update_password_row'));\r
905                 userShown = false;\r
906                 alertId('myopac_password_success');\r
907                 myOPACShowUser(true);\r
908                 return;\r
909         }\r
910 \r
911         alert($('myopac_password_failure').innerHTML);\r
912 }\r
913 \r
914 function myOPACUpdatePhone(which) {\r
915         if(!which) return;\r
916         var tr = $('myopac_update_phone'+which+'_row');\r
917         var input = $('myopac_new_phone'+which);\r
918         if(!tr || !input) return;\r
919         var val = input.value;\r
920         if(!val.match(REGEX_PHONE)) {\r
921                 alert("Not a valid phone number. Should be in the form ###-###-####");\r
922                 input.focus();\r
923                 input.select();\r
924                 return;\r
925         }\r
926         \r
927         var newUser = fleshedUser.clone(true);\r
928         switch(which) {\r
929                 case "1": newUser.day_phone(val); break;\r
930                 case "2": newUser.evening_phone(val); break;\r
931                 case "3": newUser.other_phone(val); break;\r
932         }\r
933         \r
934         newUser.ischanged("t");\r
935         var resp = fieldmapper.standardRequest(['open-ils.actor', 'open-ils.actor.patron.update'], {async:false, params:[G.user.session, newUser]});\r
936         if(typeof(resp.desc)=="undefined") {\r
937                 hideMe(tr);\r
938                 userShown = false;\r
939                 fleshedUser = resp;\r
940                 alert("Phone number updated successfully.");\r
941                 myOPACShowUser(true);\r
942         } else {\r
943                 alert(resp.textcode+'\n'+resp.desc);\r
944                 input.focus();\r
945                 input.select();\r
946         }\r
947 }\r
948 \r
949 function myOPACUpdateUsername() {\r
950         var username = $('myopac_new_username').value;\r
951         if(username == null || username == "") {\r
952                 alert($('myopac_username_error').innerHTML);\r
953                 return;\r
954         }\r
955 \r
956         if( username.match(/.*\s.*/) ) {\r
957                 alert($('myopac_invalid_username').innerHTML);\r
958                 return;\r
959         }\r
960 \r
961     r = fetchOrgSettingDefault(globalOrgTree.id(), 'opac.barcode_regex');\r
962     if(r) REGEX_BARCODE = new RegExp(r);\r
963 \r
964     if(username.match(REGEX_BARCODE)) {\r
965         alert($('myopac_invalid_username').innerHTML);\r
966         return;\r
967     }\r
968 \r
969         /* first see if the requested username is taken */\r
970         var req = new Request(CHECK_USERNAME, G.user.session, username);\r
971         req.send(true);\r
972         var res = req.result();\r
973         if( res !== null && res != G.user.id() ) {\r
974                 alertId('myopac_username_dup');\r
975                 return;\r
976         }\r
977 \r
978         var req = new Request(UPDATE_USERNAME, G.user.session, username );\r
979         req.send(true);\r
980         if(req.result()) {\r
981 \r
982                 var evt;\r
983                 var res = req.result();\r
984                 if(evt = checkILSEvent(res)) {\r
985                         alertILSEvent(res);\r
986                         return;\r
987                 }\r
988 \r
989                 G.user.usrname(username);\r
990                 hideMe($('myopac_update_username_row'));\r
991                 userShown = false;\r
992                 alertId('myopac_username_success');\r
993                 myOPACShowUser(true);\r
994                 return;\r
995         }\r
996 \r
997         alert($('myopac_username_failure').innerHTML);\r
998 }\r
999 \r
1000 function iForgotMyPassword(un,email) {\r
1001         if(!un) return;\r
1002         //var type = un.match(/^\d+$/)?'barcode':'username';\r
1003         fieldmapper.standardRequest(PASS_RESET,{params:['barcode',un,email],oncomplete:function(rr){\r
1004                 var resp = rr.recv().content();\r
1005                 if(resp.textcode=="ACTOR_USER_NOT_FOUND") fieldmapper.standardRequest(PASS_RESET,{params:['username',un,email],oncomplete:function(r){\r
1006                         var resp2 = r.recv().content();\r
1007                         if(resp2.textcode) alert(resp2.textcode+'\n'+resp2.desc);\r
1008                         else { alert("Password reset request sent successfully."); unHideMe($('login_box'));hideMe($('forget_pw')); }\r
1009                 }}); else {\r
1010                         if(resp.textcode) alert(resp.textcode+'\n'+resp.desc);\r
1011                         else { alert("Password reset request sent successfully."); unHideMe($('login_box'));hideMe($('forget_pw')); }\r
1012                 }\r
1013         }});\r
1014 }\r
1015 \r
1016 function myOPACShowBookbags(force) {\r
1017         if(anonListCache.length) drawAnonLists(force); else hideMe($('acct_list_template2'));\r
1018         var wrapper = $('acct_lists_prime');\r
1019         if(!containerTemplate) containerTemplate = wrapper.removeChild($('acct_list_template')); else if(!force) return;\r
1020         if(!wrapper) return;\r
1021         \r
1022         var containers = containerFetchAll();\r
1023         \r
1024         var found = false;\r
1025         for(var i in containers) {\r
1026                 found = true;\r
1027                 var cont = containers[i];\r
1028                 fleshedContainers[cont.id()] = cont;\r
1029                 var temp = containerTemplate.cloneNode(true);\r
1030                 var title = $n(temp, 'list_name');\r
1031                 var share = $n(temp, 'share_list_link');\r
1032                 var rem = $n(temp, 'remove_list');\r
1033                 if(!title || !share || !rem) continue;\r
1034                 \r
1035                 title.appendChild(text(cont.name()));\r
1036                 share.onclick = myListAction;\r
1037                 share.listID = cont.id();\r
1038                 rem.value='delete';\r
1039                 rem.onclick = myListAction;\r
1040                 rem.listID = cont.id();\r
1041                 temp.setAttribute("id",temp.id + '_' + cont.id());\r
1042                 \r
1043                 if(containers.length>1) {\r
1044                         var sel = $n(temp, 'list_actions');\r
1045                         var optg = elem('optgroup', {label:'Move Items to'});\r
1046                         for(var n in containers) {\r
1047                                 var cont2 = containers[n];\r
1048                                 if(cont2.id()==cont.id()) continue;\r
1049                                 var opt = elem('option', {value:'move', container:cont2.id()}, cont2.name());\r
1050                                 optg.appendChild(opt);\r
1051                         }\r
1052                         sel.appendChild(optg);\r
1053                 }\r
1054                 \r
1055                 if(isTrue(cont.pub())) {\r
1056                         share.value='hide';\r
1057                         share.innerHTML = 'Un-share';\r
1058                         share.title='';\r
1059                         var link = $n(temp,'share_list_rss');\r
1060                         link.setAttribute('href', buildExtrasLink( 'feed/bookbag/rss2-full/'+cont.id(), false));\r
1061                         unHideMe(link);\r
1062                 } else {\r
1063                         share.value='share';\r
1064                         share.title = 'Sharing this bookbag will allow the contents of the bookbag to be seen by others.'\r
1065                         share.innerHTML = 'Share';\r
1066                 }\r
1067                 \r
1068                 wrapper.appendChild(temp);\r
1069                 // grab container items after adding each list to the page\r
1070                 fieldmapper.standardRequest(FETCH_CONTAINER_DETAILS,{params:[G.user.session, 'biblio', cont.id()],oncomplete:drawListItemRows});\r
1071         }\r
1072         \r
1073         if(!found) wrapper.appendChild(elem("div",{style:"font-weight:bold;text-align:center;font-size:14px;"},"You have not created any lists"));\r
1074         \r
1075         var anonSel = $('sel_all_list_anon');\r
1076         if(!anonSel) return;\r
1077         var optg2 = elem('optgroup', {label:'Move Items to', id:'anon_list_grp'});\r
1078         for(var t in containers) {\r
1079                 var cont3 = containers[t];\r
1080                 var opt2 = elem('option', {value:'move', container:cont3.id()}, cont3.name());\r
1081                 optg2.appendChild(opt2);\r
1082         }\r
1083         anonSel.appendChild(optg2);\r
1084 }\r
1085 \r
1086 function drawAnonLists() {\r
1087         var cont = $('acct_list_template2');\r
1088         var bibs = fieldmapper.standardRequest(FETCH_MODS_SLIM, {async:false, params:[anonListCache]});\r
1089         \r
1090         var tbody = $('anon_list_tbody');\r
1091         for(var i in bibs) {\r
1092                 var it = bibs[i];\r
1093                 var tr = elem('tr');\r
1094                 var td1 = elem('td',{style:'padding-right:5px;'},it.title());\r
1095                 var td2 = elem('td',{width:'1'});\r
1096                 var el = elem('input',{type:'checkbox', name:'list_action_chbx', recordid:it.doc_id()+'', doc_id:it.doc_id()+'', listID:'anon'});\r
1097                 el.className = "list_action_chbx";\r
1098                 el.name="list_action_chbx";\r
1099                 td2.appendChild(el);\r
1100                 tr.appendChild(td2);\r
1101                 tr.appendChild(td1);\r
1102                 tbody.appendChild(tr);\r
1103         }\r
1104         unHideMe(cont);\r
1105 }\r
1106 \r
1107 function drawListItemRows(r) {\r
1108         var fleshed = r.recv().content();\r
1109         if(!fleshed) return;\r
1110         var modsArr = [];\r
1111         \r
1112         var temp = $('acct_list_template_'+fleshed.id());\r
1113         if(!temp) return;\r
1114         var tbody = $n(temp,'list_tbody');\r
1115         if(!tbody) return;\r
1116         var items = fleshed.items();\r
1117 \r
1118         for(var i=0; i<items.length; i++) {\r
1119                 var it = items[i];\r
1120                 var tr = elem('tr');\r
1121                 var td1 = elem('td',{'class':'list_item_title_'+it.target_biblio_record_entry(), style:'padding-right:5px;'});\r
1122                 td1.className = 'list_item_title_'+it.target_biblio_record_entry();\r
1123                 var td2 = elem('td',{width:'1'});\r
1124                 \r
1125                 var el = elem('input',{type:'checkbox', name:'list_action_chbx','class':'list_action_chbx', recordid:it.target_biblio_record_entry()+'', itemID:it.id()+'',listID:fleshed.id()});\r
1126                 el.name="list_action_chbx";\r
1127                 el.className="list_action_chbx";\r
1128                 td2.appendChild(el);\r
1129                 tr.appendChild(td2);\r
1130                 tr.appendChild(td1);\r
1131                 tbody.appendChild(tr);\r
1132                 modsArr[i] = it.target_biblio_record_entry();\r
1133         }\r
1134         \r
1135         // yay for batching requests\r
1136         if(modsArr.length) {\r
1137                 fieldmapper.standardRequest(FETCH_MODS_SLIM,{params:[modsArr],oncomplete:drawListItemTitles});\r
1138         } else {\r
1139                 var tr = elem('tr');\r
1140                 var td = elem('td',{style:"font-weight:bold;font-size:14px;",align:'center'},'No items have been added to this list yet.');\r
1141                 td.style.fontWeight='bold';\r
1142                 td.style.fontSize='14px';\r
1143                 tr.appendChild(td);\r
1144                 tbody.appendChild(tr);\r
1145         }\r
1146 }\r
1147 \r
1148 function drawListItemTitles(r) {\r
1149         var rec = r.recv().content();\r
1150         if(!rec) return;\r
1151         for(var i in rec) {\r
1152                 var rows = dojo.query('.list_item_title_'+rec[i].doc_id()); //$c('list_item_title_'+rec[i].doc_id());\r
1153                 for(var n in rows) rows[n].innerHTML = rec[i].title();\r
1154         }\r
1155 }\r
1156 \r
1157 function addMyList() {\r
1158         var name = $('mylist_new').value;       \r
1159         if(!name) return false;\r
1160 \r
1161         var exists = false;\r
1162         for( var c in fleshedContainers ) { exists = true; break; }\r
1163 \r
1164         /* let them know what they are getting into... */\r
1165         if(!exists) if(!confirm($('bb_create_warning').innerHTML)) return false;\r
1166         var result = containerCreate( name, $('shareListYes').checked );\r
1167         var code = checkILSEvent(result);\r
1168         if(code) { alertILSEvent(result); return false; }\r
1169         //if(result) alert($('myopac_bb_update_success').innerHTML);\r
1170         $('mylist_new').value="";\r
1171         $('shareListYes').checked = false;\r
1172         $('shareListNo').checked = true;\r
1173         reloadMyLists();\r
1174         return true;\r
1175 }\r
1176 \r
1177 function myListAction() {\r
1178         if(!this.listID) return;\r
1179         switch(this.value) {\r
1180                 case "delete": myOPACDeleteBookbag(this.listID); break;\r
1181                 case  "share": myOPACMakeBBPublished(this.listID); break;\r
1182                 case   "hide": myOPACMakeBBPublished(this.listID, true); break;\r
1183         }\r
1184 }\r
1185 \r
1186 function myOPACMakeBBPublished(bbid, hideme) {\r
1187         var bb = fleshedContainers[bbid];\r
1188 \r
1189         if(hideme) {\r
1190                 if(!confirm($('myopac_make_unpublished_confirm').innerHTML)) return;\r
1191                 bb.pub('f');\r
1192         } else {\r
1193                 if(!confirm($('myopac_make_published_confirm').innerHTML)) return;\r
1194                 bb.pub('t');\r
1195         }\r
1196 \r
1197         var result = containerUpdate(bb);\r
1198         var code = checkILSEvent(result);\r
1199         if(code) { alertILSEvent(result); return; }\r
1200 \r
1201         //alert($('myopac_bb_update_success').innerHTML);\r
1202         reloadMyLists();\r
1203 }\r
1204 \r
1205 function myOPACDeleteBookbag(id) {\r
1206         if( confirm( $('myopac_delete_bookbag_warn').innerHTML ) ) {\r
1207                 var result = containerDelete(id);\r
1208                 var code = checkILSEvent(result);\r
1209                 if(code) { alertILSEvent(result); return; }\r
1210                 //alert($('myopac_bb_update_success').innerHTML);\r
1211                 //hideMe($('myopac_bookbag_items_table'));\r
1212                 //hideMe($('myopac_bookbag_items_name'));\r
1213                 //hideMe($('myopac_bookbag_no_items'));\r
1214                 reloadMyLists();\r
1215         }\r
1216 }\r
1217 \r
1218 function reloadMyLists() {\r
1219         var prime = $('acct_lists_prime');\r
1220         var anon = $('anon_list_tbody');\r
1221         $('sel_all_list_anon').removeChild($('anon_list_grp'));\r
1222         removeChildren(prime);\r
1223         removeChildren(anon);\r
1224         prime.innerHTML = "";\r
1225         myOPACShowBookbags(true);\r
1226 }\r
1227 \r
1228 function removeSelectedItems(parent) {\r
1229         if(!parent) parent = $('acct_lists_prime');\r
1230         var items = dojo.query('input[name=list_action_chbx]', parent);\r
1231         if(!items.length) items = dojo.query('.list_action_chbx', parent);\r
1232         items.filter(function(item, index, arr){return item.checked;},this);\r
1233         \r
1234         if(items.length) {\r
1235                 for(var i=0; i<items.length; i++) {\r
1236                         var box = items[i];\r
1237                         if(box.checked) {\r
1238                                 containerRemoveItem(box.getAttribute("itemID"));\r
1239                         }\r
1240                 }\r
1241         }\r
1242 }\r
1243 \r
1244 var finesShown = false;\r
1245 function myOPACShowFines(showing) {\r
1246         if(finesShown) return; finesShown = true;\r
1247         var req = new Request(FETCH_FINES_SUMMARY, G.user.session, G.user.id() );\r
1248     req.request.__showing = showing;\r
1249         req.callback(_myOPACShowFines);\r
1250         req.send();\r
1251 }\r
1252 \r
1253 function _myOPACShowFines(r) {\r
1254         hideMe($('myopac_fines_summary_loading'));\r
1255         unHideMe($('myopac_fines_summary_row'));\r
1256 \r
1257         var summary = r.getResultObject();\r
1258         var total       = "0.00";\r
1259         var paid        = "0.00";\r
1260         var balance = "0.00";\r
1261         var balance2 = "0.00";\r
1262         \r
1263         if( instanceOf(summary,mous) ) {\r
1264                 total           = _finesFormatNumber(summary.total_owed());\r
1265                 paid            = _finesFormatNumber(summary.total_paid());\r
1266                 balance = _finesFormatNumber(summary.balance_owed());\r
1267                 balance2 = _finesFormatNumber(summary.balance_owed());\r
1268 \r
1269                 var req = new Request(FETCH_TRANSACTIONS, G.user.session, G.user.id() );\r
1270                 req.callback(myOPACShowTransactions);\r
1271                 req.send();\r
1272         }\r
1273 \r
1274         if(parseFloat(balance2) > 0.00) {\r
1275                 var bal = $('myopac_sum_fines_bal');\r
1276                 bal.style.color = "red";\r
1277                 appendClear(bal,text("$"+balance2));\r
1278                 unHideMe($('myopac_sum_fines'));\r
1279                 unHideMe($('myopac_sum_fines_slim'));\r
1280                 unHideMe($('pay_fines_btn'));\r
1281         if(!r.__showing)\r
1282                     showFinesDiv($('show_fines_link'));\r
1283         }\r
1284 \r
1285         $('myopac_fines_summary_total').appendChild(text(total));\r
1286         $('myopac_fines_summary_paid').appendChild(text(paid));\r
1287         $('myopac_fines_summary_balance').appendChild(text(balance));\r
1288 }\r
1289 \r
1290 function _finesFormatNumber(num) {\r
1291         if(isNull(num)) num = 0;\r
1292         num = num + "";\r
1293         if(num.length < 2 || !num.match(/\./)) num += ".00";\r
1294         if(num.match(/\./) && num.charAt(num.length-2) == '.') num += "0";\r
1295         return num;\r
1296 }\r
1297 \r
1298 function _trimTime(time) { \r
1299         if(!time) return ""; \r
1300     var d = dojo.date.stamp.fromISOString(time);\r
1301     if(!d) return ""; /* date parse failed */\r
1302     return d.iso8601Format('YMD');\r
1303 }\r
1304 \r
1305 function _trimSeconds(time) { \r
1306     if(!time) return ""; \r
1307     var d = dojo.date.stamp.fromISOString(time);\r
1308     if(!d) return ""; /* date parse failed */\r
1309     return d.iso8601Format('YMDHM',null,true,true);\r
1310 }\r
1311 \r
1312 function myOPACShowTransactions(r) {\r
1313         if(myopacGenericTransTemplate || myopacCircTransTemplate) return;\r
1314         var transactions = r.getResultObject();\r
1315 \r
1316         for( var idx in transactions ) {\r
1317                 var trans       = transactions[idx].transaction;\r
1318                 var record      = transactions[idx].record;\r
1319                 var circ        = transactions[idx].circ;\r
1320 \r
1321                 if(trans.xact_type() == 'circulation') myOPACShowCircTransaction(trans, record, circ);\r
1322                 else if(trans.xact_type() == 'grocery') myopacShowGenericTransaction( trans );\r
1323         }\r
1324 }\r
1325 \r
1326 function myopacShowGenericTransaction( trans ) {\r
1327         var tbody = $('myopac_trans_tbody');\r
1328 \r
1329         if(!myopacGenericTransTemplate) {\r
1330                 myopacGenericTransTemplate = tbody.removeChild($('myopac_trans_row'));\r
1331                 removeChildren(tbody);\r
1332         }\r
1333 \r
1334         var row = myopacGenericTransTemplate.cloneNode(true);\r
1335         $n(row,'myopac_trans_start').appendChild(text(_trimSeconds(trans.xact_start())));\r
1336         $n(row,'myopac_trans_last_payment').appendChild(text(_trimSeconds(trans.last_payment_ts())));\r
1337         $n(row,'myopac_trans_init_amount').appendChild(text(_finesFormatNumber(trans.total_owed())));\r
1338         $n(row,'myopac_trans_total_paid').appendChild(text(_finesFormatNumber(trans.total_paid())));\r
1339         $n(row,'myopac_trans_balance').appendChild(text(_finesFormatNumber(trans.balance_owed())));\r
1340         $n(row,'selector').balance_owed = trans.balance_owed();\r
1341         $n(row,'selector').setAttribute("xact", trans.id());\r
1342 \r
1343         var req = new Request(FETCH_MONEY_BILLING, G.user.session, trans.id());\r
1344         req.send(true);\r
1345         var bills = req.result();\r
1346         if(bills && bills[0]) $n(row,'myopac_trans_bill_type').appendChild(text(bills[0].billing_type()));\r
1347 \r
1348         tbody.appendChild(row);\r
1349         unHideMe($('myopac_trans_div'));\r
1350 }\r
1351 \r
1352 function myOPACShowCircTransaction(trans, record, circ) {\r
1353         var tbody = $('myopac_circ_trans_tbody');\r
1354 \r
1355         if(!myopacCircTransTemplate) {\r
1356                 myopacCircTransTemplate = tbody.removeChild($('myopac_circ_trans_row'));\r
1357                 removeChildren(tbody);\r
1358         }\r
1359 \r
1360         var row = myopacCircTransTemplate.cloneNode(true);\r
1361         if(record) {\r
1362                 buildTitleDetailLink(record, $n(row,'myopac_circ_trans_title'));\r
1363                 $n(row,'myopac_circ_trans_author').appendChild(text(normalize(truncate(record.author(), 65))));\r
1364         } else {\r
1365                 var req = new Request( FETCH_COPY, circ.target_copy() );\r
1366                 req.alertEvents = false;\r
1367                 req.send(true);\r
1368                 var copy = req.result();\r
1369                 if( copy ) {\r
1370                         $n(row,'myopac_circ_trans_title').appendChild(text(copy.dummy_title()));\r
1371                         $n(row,'myopac_circ_trans_author').appendChild(text(copy.dummy_author()));\r
1372                 }\r
1373         }\r
1374         \r
1375         $n(row,'myopac_circ_trans_start').appendChild(text(_trimTime(trans.xact_start())));\r
1376 \r
1377     var due = _trimTime(circ.due_date());\r
1378         var checkin = _trimTime(circ.stop_fines_time());\r
1379 \r
1380         $n(row,'myopac_circ_trans_due').appendChild(text(due))\r
1381         if(checkin) appendClear($n(row,'myopac_circ_trans_finished'), text(checkin));\r
1382         if(circ.stop_fines() == 'LOST') appendClear($n(row,'myopac_circ_trans_finished'), text(circ.stop_fines()));\r
1383         if(circ.stop_fines() == 'CLAIMSRETURNED') appendClear($n(row,'myopac_circ_trans_finished'), text(""));\r
1384         $n(row,'myopac_circ_trans_balance').appendChild(text(_finesFormatNumber(trans.balance_owed())));\r
1385         $n(row,'selector').balance_owed = trans.balance_owed();\r
1386         $n(row,'selector').setAttribute("xact",trans.id()); \r
1387 \r
1388         tbody.appendChild(row);\r
1389         unHideMe($('myopac_circ_trans_div'));\r
1390 }\r
1391 \r
1392 function showFinesDiv(el) {\r
1393         if(!el) return;\r
1394         if($('myopac_fines_div').className.indexOf('hide_me')>=0) { \r
1395                 unHideMe($('myopac_fines_div'));\r
1396                 el.innerHTML="Hide Overdue Materials";\r
1397         if(!finesShown) {\r
1398             myOPACShowFines(true);\r
1399         }\r
1400         } else {\r
1401                 hideMe($('myopac_fines_div'));\r
1402                 el.innerHTML="Show Overdue Materials";\r
1403         }\r
1404 }\r
1405 \r
1406 function showPaymentForm() {\r
1407         unHideMe($('pay_fines_now'));\r
1408         hideMe($('acct_sum'));\r
1409         drawPayFinesPage(\r
1410                 G.user,\r
1411                 getSelectedFinesTotal(),\r
1412                 getSelectedFineTransactions(),\r
1413                 function(resp) {\r
1414                         if(resp.textcode) {\r
1415                                 var message = resp.textcode+'\n'+resp.desc + '';\r
1416                                 if(resp.textcode == 'CREDIT_PROCESSOR_DECLINED_TRANSACTION' && resp.payload)\r
1417                                         message += '\n' + resp.payload.error_message;\r
1418                                 alert(message);\r
1419                                 return;\r
1420                         }\r
1421                         G.user.last_xact_id(resp.last_xact_id); // update to match latest from server\r
1422                 }\r
1423         );\r
1424 }\r
1425 \r
1426 function getSelectedFinesTotal() {\r
1427     var total = 0;\r
1428     dojo.forEach(\r
1429         dojo.query("[name=selector]", $('myopac_circ_trans_tbody')),\r
1430         function(input) { if(input.checked && input.getAttribute("xact")) total += Number(input.balance_owed); }\r
1431     );\r
1432         \r
1433     dojo.forEach(\r
1434         dojo.query("[name=selector]", $('myopac_trans_tbody')),\r
1435         function(input) { if(input.checked && input.getAttribute("xact")) total += Number(input.balance_owed); }\r
1436     );\r
1437     return total.toFixed(2);\r
1438 }\r
1439 \r
1440 function getSelectedFineTransactions() {\r
1441         var set1 = dojo.query("[name=selector]", $('myopac_circ_trans_tbody')).\r
1442         filter(function (o) { return o.checked }).\r
1443                 map(function (o) {return [o.getAttribute("xact"), Number(o.balance_owed).toFixed(2)];}\r
1444         );\r
1445         var set2 = dojo.query("[name=selector]", $('myopac_trans_tbody')).\r
1446         filter(function (o) { return o.checked }).\r
1447                 map(function (o) {return [o.getAttribute("xact"), Number(o.balance_owed).toFixed(2)];}\r
1448         );\r
1449         var obj = set1.concat(set2);\r
1450         return obj.filter(function(el){return el[0]==null?false:true;});\r
1451 }\r
1452 \r
1453 function drawPayFinesPage(patron, total, xacts, onPaymentSubmit) {\r
1454     if (typeof(this.authtoken) == "undefined")\r
1455         this.authtoken = patron.session;\r
1456 \r
1457     dojo.query("span", "oils-selfck-cc-payment-summary")[0].innerHTML = total;\r
1458 \r
1459     oilsSelfckCCNumber.attr('value', '');\r
1460     oilsSelfckCCCVV.attr('value', '');\r
1461     oilsSelfckCCMonth.attr('value', '01');\r
1462     oilsSelfckCCYear.attr('value', new Date().getFullYear());\r
1463     oilsSelfckCCFName.attr('value', patron.first_given_name());\r
1464     oilsSelfckCCLName.attr('value', patron.family_name());\r
1465 \r
1466     var addr = patron.billing_address() || patron.mailing_address();\r
1467 \r
1468     if (typeof(addr) != "object") {\r
1469         /* still don't have usable address? try getting better user object. */\r
1470         fieldmapper.standardRequest(\r
1471             FETCH_FULL_USER, {\r
1472                 "params": [patron.session, patron.id(), ["billing_address", "mailing_address"]],\r
1473                 "async": false,\r
1474                 "oncomplete": function(r) {\r
1475                     var usr = r.recv().content();\r
1476                     if (usr) addr = usr.billing_address() || usr.mailing_address();\r
1477                 }\r
1478             }\r
1479         );\r
1480     }\r
1481 \r
1482     if (addr) {\r
1483         oilsSelfckCCStreet.attr('value', addr.street1()+' '+addr.street2());\r
1484         oilsSelfckCCCity.attr('value', addr.city());\r
1485         oilsSelfckCCState.attr('value', addr.state());\r
1486         oilsSelfckCCZip.attr('value', addr.post_code());\r
1487     }\r
1488 \r
1489     dojo.connect(oilsSelfckEditDetails, 'onChange',\r
1490         function(newVal) {\r
1491             dojo.forEach(\r
1492                 [oilsSelfckCCFName, oilsSelfckCCLName, oilsSelfckCCStreet, oilsSelfckCCCity, oilsSelfckCCState, oilsSelfckCCZip],\r
1493                 function(dij) { dij.attr('disabled', !newVal); }\r
1494             );\r
1495         }\r
1496     );\r
1497 \r
1498     dojo.connect(oilsSelfckCCSubmit, 'onClick',\r
1499         function() {\r
1500             if (typeof(progressDialog) != "undefined") progressDialog.show(true);\r
1501             sendCCPayment(patron, xacts, onPaymentSubmit);\r
1502         }\r
1503     );\r
1504 }\r
1505 \r
1506 function sendCCPayment(patron, xacts, onPaymentSubmit) {\r
1507     var args = {\r
1508         userid : patron.id(),\r
1509         payment_type : 'credit_card_payment',\r
1510         payments : xacts,\r
1511         cc_args : {\r
1512             where_process : 1,\r
1513             //type :  'MasterCard',//oilsSelfckCCType.attr('value'),\r
1514             number : oilsSelfckCCNumber.attr('value'),\r
1515             cvv2 : oilsSelfckCCCVV.attr('value'),\r
1516             expire_year : oilsSelfckCCYear.attr('value'),\r
1517             expire_month : oilsSelfckCCMonth.attr('value'),\r
1518             billing_first : oilsSelfckCCFName.attr('value'),\r
1519             billing_last : oilsSelfckCCLName.attr('value'),\r
1520             billing_address : oilsSelfckCCStreet.attr('value'),\r
1521             billing_city : oilsSelfckCCCity.attr('value'),\r
1522             billing_state : oilsSelfckCCState.attr('value'),\r
1523             billing_zip : oilsSelfckCCZip.attr('value')\r
1524         }\r
1525     }\r
1526 \r
1527     var resp = fieldmapper.standardRequest(PAY_BILLS,{params : [patron.session, args, patron.last_xact_id()]});\r
1528     if (typeof(progressDialog) != "undefined")\r
1529         progressDialog.hide();\r
1530 \r
1531     if (typeof(onPaymentSubmit) == "function") {\r
1532         onPaymentSubmit(resp);\r
1533     } else {\r
1534         var evt = openils.Event.parse(resp);\r
1535         if (evt) alert(evt);\r
1536     }\r
1537 }\r
1538 \r
1539 function myopacSelectedHoldsRows() {\r
1540     var r = [];\r
1541         var cb;\r
1542     var rows = dojo.query('[name=acct_holds_temp]',$("holds_temp_parent"));\r
1543     for(var i = 0; i < rows.length; i++) {\r
1544         cb = $n(rows[i], 'check_all_holds');\r
1545         if(cb && cb.checked)\r
1546             r.push(rows[i]);\r
1547     }\r
1548     return r;\r
1549 }\r
1550 \r
1551 var myopacProcessedHolds = 0;\r
1552 var myopacHoldsToProcess = 0;\r
1553 function myopacDoHoldAction() {\r
1554     var selectedRows = myopacSelectedHoldsRows();\r
1555     var action = getSelectorVal($('acct_holds_actions'));\r
1556     $('myopac_holds_actions_none').selected = true;\r
1557     if(selectedRows.length == 0) return;\r
1558 \r
1559     myopacProcessedHolds = 0;\r
1560 \r
1561     if(!confirmId('myopac.holds.'+action+'.confirm')) return;\r
1562     //myopacSelectNoneHolds(); /* clear the selection */\r
1563 \r
1564 \r
1565     /* first, let's collect the holds that actually need processing and\r
1566         collect the full process count while we're at it */\r
1567     var holds = [];\r
1568     for(var i = 0; i < selectedRows.length; i++) {\r
1569                 var ahold = $n(selectedRows[i],'check_all_holds');\r
1570         var hold = holdsCache[holdsCacheMap[ahold.holdid]];\r
1571         var qstats = hold.status;\r
1572         switch(action) {\r
1573             case 'cancel':\r
1574                 holds.push(hold.hold);\r
1575                 break;\r
1576             case 'thaw_date':\r
1577             case 'thaw':\r
1578                 if(isTrue(hold.hold.frozen()))\r
1579                     holds.push(hold.hold);\r
1580                 break;\r
1581             case 'freeze':\r
1582                 if(!isTrue(hold.hold.frozen()) && qstats < 3)\r
1583                     holds.push(hold.hold);\r
1584                 break;\r
1585         }\r
1586     }\r
1587 \r
1588     myopacHoldsToProcess = holds;\r
1589     if(myopacHoldsToProcess.length == 0) return;\r
1590 \r
1591     if(action == 'thaw_date' || action == 'freeze') \r
1592         myopacDrawHoldThawDateForm();\r
1593     else\r
1594     myopacProcessHolds(action);\r
1595 }\r
1596 \r
1597 function myopacDrawHoldThawDateForm() {\r
1598     hideMe($('myopac_holds_div'));\r
1599     unHideMe($('myopac_holds_thaw_date_form'));\r
1600     $('myopac_holds_thaw_date_input').focus();\r
1601 }\r
1602 \r
1603 function myopacApplyThawDate() {\r
1604     var dateString = dijit.byId('myopac_holds_thaw_date_input').getValue();\r
1605     if(dateString) {\r
1606         dateString = dojo.date.stamp.toISOString(dateString);\r
1607         if(dateString) {\r
1608             dateString = holdsVerifyThawDate(dateString);\r
1609             if(!dateString) return;\r
1610         } else {\r
1611             dateString = null;\r
1612         }\r
1613     }\r
1614         unHideMe($('myopac_holds_div'));\r
1615     hideMe($('myopac_holds_thaw_date_form'));\r
1616     myopacProcessHolds('freeze', dateString);\r
1617 }\r
1618 \r
1619 \r
1620 function myopacProcessHolds(action, thawDate) {\r
1621         progressDialog.show(true);\r
1622    // myopacShowHoldProcessing();\r
1623     /* now we process them */\r
1624     for(var i = 0; i < myopacHoldsToProcess.length; i++) {\r
1625         var hold = myopacHoldsToProcess[i];\r
1626         \r
1627         var req;\r
1628         switch(action) { \r
1629 \r
1630             case 'cancel':\r
1631                 req = new Request(CANCEL_HOLD, G.user.session, hold.id());\r
1632                 break;\r
1633     \r
1634             case 'thaw':\r
1635                 hold.frozen('f');\r
1636                 hold.thaw_date(null);\r
1637                 req = new Request(UPDATE_HOLD, G.user.session, hold);\r
1638                 break;\r
1639 \r
1640             case 'thaw_date':\r
1641             case 'freeze':\r
1642                 hold.frozen('t');\r
1643                 hold.thaw_date(thawDate); \r
1644                 req = new Request(UPDATE_HOLD, G.user.session, hold);\r
1645                 break;\r
1646                 //thawDate = prompt($('myopac.holds.freeze.select_thaw').innerHTML);\r
1647 \r
1648         }\r
1649 \r
1650         req.callback(myopacBatchHoldCallback);\r
1651         req.send();\r
1652         req = null;\r
1653     }\r
1654 }\r
1655 \r
1656 function myopacBatchHoldCallback(r) {\r
1657         var res = r.getResultObject();\r
1658         myopacHoldsToProcess = grep(myopacHoldsToProcess, function(i) { return (i.id() != res); }); \r
1659         if(!myopacHoldsToProcess || ++myopacProcessedHolds >= myopacHoldsToProcess.length) {\r
1660           //alert(res);\r
1661           progressDialog.hide();\r
1662           myopacForceHoldsRedraw = true;\r
1663           $('check_all_holds').checked = false;\r
1664           drawHoldsPage();\r
1665         }\r
1666 }\r
1667 \r
1668 function myOPACRenewSelected() {\r
1669    var rows = dojo.query('input[name=check_all_checked]',$('checked_temp_parent')).filter(function(n,i){ return n.checked; });\r
1670    __renew_circs = [];\r
1671         if(!rows.length || !confirm($('myopac_renew_confirm').innerHTML)) return;\r
1672    __success_count = 0;\r
1673    __fail_count = 0;\r
1674 \r
1675    for( var i = 0; i < rows.length; i++ ) {\r
1676       var row = rows[i];\r
1677       var circ_id = row.getAttribute('circid');\r
1678 \r
1679            var circ;\r
1680            for( var j = 0; j != itemsOutCache.length; j++ ) \r
1681                    if(itemsOutCache[j].circ.id() == circ_id)\r
1682                            circ = itemsOutCache[j].circ;\r
1683 \r
1684       __renew_circs.push(circ);\r
1685    }\r
1686 \r
1687     if( __renew_circs.length == 0 ) return;\r
1688 \r
1689     //unHideMe($('my_renewing'));\r
1690     //moClearCheckedTable();\r
1691 \r
1692     for( var i = 0; i < __renew_circs.length; i++ ) {\r
1693         var circ = __renew_circs[i];\r
1694         moRenewCirc( circ.target_copy(), G.user.id(), circ );\r
1695     }\r
1696 }\r
1697 \r
1698 var __renew_circs = [];\r
1699 var __rewnew_errors = [];\r
1700 var __success_count = 0;\r
1701 var __fail_count = 0;\r
1702 function moRenewCirc(copy_id, user_id, circ) {\r
1703 \r
1704    _debug('renewing circ ' + circ.id() + ' with copy ' + copy_id);\r
1705    var req = new Request(RENEW_CIRC, G.user.session, \r
1706       {  patron : user_id, \r
1707          copyid : copy_id, \r
1708          opac_renewal : 1\r
1709       } \r
1710    );\r
1711 \r
1712    req.request.alertEvent = false;\r
1713    req.callback(myHandleRenewResponse);\r
1714    req.request.circ = circ;\r
1715    req.send();\r
1716 }\r
1717 \r
1718 /* handles the circ renew results */\r
1719 \r
1720 function myHandleRenewResponse(r) {\r
1721    try{ var res = r.getResultObject(); } catch(e){ alert("Renew Error\n\n"+e); __renew_circs = []; __rewnew_errors = []; return; }\r
1722    var circ = r.circ;\r
1723 \r
1724    /* remove this circ from the list of circs to renew */\r
1725    if(checkILSEvent(res) || checkILSEvent(res[0])) {\r
1726            var str1 = truncate(mvrObjCache[circ.target_copy()].title(),65)+'\n';\r
1727            if(res.ilsevent) str1 += res.ilsevent+': '+res.desc+'\n'; else for(var i in res) str1 += res[i].ilsevent+': '+res[i].desc+'\n';\r
1728            __rewnew_errors[circ.id()] = str1;\r
1729    }\r
1730    __renew_circs = grep(__renew_circs, function(i) { return (i.id() != circ.id()); });\r
1731    _debug("handling renew result for " + circ.id());\r
1732 \r
1733    if(checkILSEvent(res) || checkILSEvent(res[0])) __fail_count++;\r
1734       //alertIdText('myopac_renew_fail', __circ_titles[circ.id()]);\r
1735    else __success_count++;\r
1736    \r
1737    if(__renew_circs) return; /* more to come */\r
1738    __renew_circs = [];\r
1739    \r
1740    var str = "";\r
1741    if(__success_count) str+= __success_count+" items renewed successfully";\r
1742    if(__fail_count) str+=__fail_count+" items did not renew.";\r
1743    str+='\n\n';\r
1744    for(var i in __rewnew_errors) str+=__rewnew_errors[i]+'\n';\r
1745    \r
1746    if(__success_count || __fail_count) alert(str);\r
1747    __rewnew_errors = [];\r
1748 \r
1749         //if( __success_count > 0 )\r
1750     //  alertIdText('myopac_renew_success', __success_count);\r
1751 \r
1752    hideMe($('my_renewing'));\r
1753    checkedDrawn = false;\r
1754     drawCheckedPage();\r
1755         $('check_all_checked').checked = false;\r
1756 }\r
1757 \r
1758 \r
1759 function moveToNewList(parent, dest) {\r
1760         if(!parent || !dest) return;\r
1761         \r
1762         var items = dojo.query('input[name=list_action_chbx]', parent);\r
1763         if(!items.length) items = dojo.query('.list_action_chbx', parent);\r
1764         items.filter(function(item, index, arr){return item.checked;},this);\r
1765         \r
1766         if(items.length) {\r
1767                 for(var i=0; i<items.length; i++) {\r
1768                         var box = items[i];\r
1769                         if(box.checked) {\r
1770                                 containerCreateItem(dest, box.getAttribute("recordid"));\r
1771                         }\r
1772                 }\r
1773         }\r
1774 }\r
1775 \r
1776 function listSaveAction() {\r
1777         var lists = dojo.query('select[name=list_actions]',$('temp_wrapper')).filter(function(n,i){\r
1778                 return n.options[n.selectedIndex].value!="0"\r
1779         });\r
1780         \r
1781         if(lists.length) { if(!confirm("Proceed with the selected action(s)?")) return; } else return;\r
1782         progressDialog.show(true);\r
1783         var updateHolds = false;\r
1784         var updateLists = false;\r
1785         \r
1786         lists.forEach(function(n,i){\r
1787                 var val = n.options[n.selectedIndex].value;\r
1788                 if(val=="0") return;\r
1789                 var p = n.parentNode.parentNode.parentNode.parentNode.parentNode;\r
1790                 switch(val) {\r
1791                         case "hold": batchHoldMyList(null, p); updateHolds = true; break;\r
1792                         case "move": if(n.id=='sel_all_list_anon') delSelCache(p, 'list_action_chbx');\r
1793                                                                 else removeSelectedItems(p); moveToNewList(p, n.options[n.selectedIndex].getAttribute("container"));\r
1794                                                   updateLists = true; break;\r
1795                         case "remove": if(n.id=='sel_all_list_anon') delSelCache(p, 'list_action_chbx');\r
1796                                                                 else removeSelectedItems(p);\r
1797                                                    updateLists = true; break;\r
1798                 }\r
1799                 setSelector(n, "0");\r
1800         });\r
1801         \r
1802         if(updateLists) reloadMyLists();\r
1803         if(updateHolds) { myopacForceHoldsRedraw = true; drawHoldsPage(); }\r
1804         progressDialog.hide();\r
1805 }\r
1806 \r
1807 var itemsOutHistoryInitialFetch = false;\r
1808 function switchSubPage(page, subpage) {\r
1809         if(!page || !subpage) return;\r
1810         \r
1811         var pg = subPageObjs[page]; if(!pg) return;\r
1812         var spg = subPageObjs[page][subpage]; if(!spg) return;\r
1813         \r
1814         for(var i in pg) { if(i!='header') for(var n in pg[i]){ if(pg[i][n] || n!='header') hideMe(pg[i][n]); } }\r
1815         for(var t in spg) { if(spg[t] || t!='header') unHideMe(spg[t]); }\r
1816         \r
1817         pg.header.innerHTML = spg.header;\r
1818 \r
1819     if(page == 'checked' && subpage == 'hist') {\r
1820         if(!itemsOutHistoryInitialFetch) {\r
1821             itemsOutHistoryInitialFetch = true;\r
1822             progressDialog.show(true);\r
1823                 fieldmapper.standardRequest(FETCH_CHECKED_HISTORY, {async:true, params:[G.user.session, G.user.id(), {'limit':CIRC_HIST_PAGE_LIMIT, 'offset':0}],\r
1824                         oncomplete:function(r) {\r
1825                     progressDialog.hide();\r
1826                     itemsOutHistory = openils.Util.readResponse(r);\r
1827                     drawCircHistory();\r
1828                         }\r
1829                 });\r
1830         }\r
1831     }\r
1832 }\r
1833 \r
1834 function doBatchAnonHolds() {\r
1835         var error = {err:""};\r
1836         var resp = placeBatchHold(holdsList, G.user.home_ou(), error);\r
1837         if(resp == -1) alert("Unable to place holds"); else {\r
1838           alert(resp+" hold"+(resp==1?"":"s")+" placed successfully\n\n"+error.err);\r
1839         }\r
1840         \r
1841         holdsList = null;\r
1842         myopacForceHoldsRedraw = true;\r
1843         drawHoldsPage();\r
1844 }\r
1845 \r
1846 function myOPACUpdateHomeOU() {\r
1847         var sel = $('myopac_new_home');\r
1848         \r
1849 }\r
1850 \r
1851 var sortOrder = true;\r
1852 function sortHolds(by) {\r
1853         if(!by) return;\r
1854         \r
1855         sortOrder = !sortOrder;\r
1856         switch(by.toLowerCase()) {\r
1857                 case "format":\r
1858                 holdsCache = holdsCache.sort(function(a, b) {\r
1859                         if(sortOrder) return get998dValue(imgFormatCache[a.hold.id()])<get998dValue(imgFormatCache[b.hold.id()])?-1:1;\r
1860                                 else      return get998dValue(imgFormatCache[a.hold.id()])>get998dValue(imgFormatCache[b.hold.id()])?-1:1;\r
1861                 });\r
1862                 break;\r
1863                 case "title":\r
1864                 holdsCache = holdsCache.sort(function(a, b) {\r
1865                         if(sortOrder) return a.mvr.title()<b.mvr.title()?-1:1;\r
1866                                 else      return a.mvr.title()>b.mvr.title()?-1:1;\r
1867                 });\r
1868                 break;\r
1869                 case "pickup":\r
1870                 holdsCache = holdsCache.sort(function(a, b) {\r
1871                         if(sortOrder) return findOrgUnit(a.hold.pickup_lib()).name()<findOrgUnit(b.hold.pickup_lib()).name()?-1:1;\r
1872                                 else      return findOrgUnit(a.hold.pickup_lib()).name()>findOrgUnit(b.hold.pickup_lib()).name()?-1:1;\r
1873                 });\r
1874                 break;\r
1875                 case "author":\r
1876                 holdsCache = holdsCache.sort(function(a, b) {\r
1877                         if(sortOrder) return a.mvr.author()<b.mvr.author()?-1:1;\r
1878                                 else      return a.mvr.author()>b.mvr.author()?-1:1;\r
1879                 });\r
1880                 break;\r
1881                 case "status":\r
1882                 if(sortOrder) {\r
1883                         drawHoldsPage(true);\r
1884                         return;\r
1885                 } else {\r
1886                         holdsCache = holdsCache.sort(function(a, b) {\r
1887                                 if(a.status==4) return 1;\r
1888                                 if(b.status==4) return -1;\r
1889                                 if(isTrue(a.hold.frozen())) return -1;\r
1890                                 if(isTrue(b.hold.frozen())) return 1;\r
1891                                 return dojo.date.stamp.fromISOString(a.hold.request_time()) > dojo.date.stamp.fromISOString(b.hold.request_time())?-1:1;\r
1892                         });                     \r
1893                 }\r
1894         }\r
1895         \r
1896         drawHoldsPage(false);\r
1897 }\r
1898 \r
1899 function sortChecked(by) {\r
1900         if(!by) return;\r
1901         \r
1902         sortOrder = !sortOrder;\r
1903         switch(by.toLowerCase()) {\r
1904                 case "title":\r
1905                 itemsOutCache = itemsOutCache.sort(function(a, b) {\r
1906                         if(sortOrder) return a.record.title()<b.record.title()?-1:1;\r
1907                                 else      return a.record.title()>b.record.title()?-1:1;\r
1908                 });\r
1909                 break;\r
1910                 case "author":\r
1911                 itemsOutCache = itemsOutCache.sort(function(a, b) {\r
1912                         if(sortOrder) return a.record.author()<b.record.author()?-1:1;\r
1913                                 else      return a.record.author()>b.record.author()?-1:1;\r
1914                 });\r
1915                 break;\r
1916                 case "due":\r
1917                 if(sortOrder) {\r
1918                         drawCheckedPage(); return;\r
1919                 } else itemsOutCache = itemsOutCache.sort(function(a, b) {\r
1920                         return dojo.date.stamp.fromISOString(a.circ.due_date()) < dojo.date.stamp.fromISOString(b.circ.due_date())?1:-1;\r
1921                 });\r
1922                 break;\r
1923                 case "barcode":\r
1924                 itemsOutCache = itemsOutCache.sort(function(a, b) {\r
1925                         if(sortOrder) return Number(a.copy.barcode())<Number(b.copy.barcode())?-1:1;\r
1926                                 else      return Number(a.copy.barcode())>Number(b.copy.barcode())?-1:1;\r
1927                 });\r
1928                 break;\r
1929                 case "cn":\r
1930                 itemsOutCache = itemsOutCache.sort(function(a, b) {\r
1931                         if(sortOrder) return callNumCache[a.copy.call_number()]<callNumCache[b.copy.call_number()] ?-1:1;\r
1932                                 else      return callNumCache[a.copy.call_number()]>callNumCache[b.copy.call_number()]?-1:1;\r
1933                 });\r
1934                 break;\r
1935                 case "renews":\r
1936                 itemsOutCache = itemsOutCache.sort(function(a, b) {\r
1937                         if(sortOrder) return Number(a.circ.renewal_remaining())<Number(b.circ.renewal_remaining())?-1:1;\r
1938                                 else      return Number(a.circ.renewal_remaining())>Number(b.circ.renewal_remaining())?-1:1;\r
1939                 });\r
1940                 break;\r
1941         }\r
1942         \r
1943         drawCheckedPage(false);\r
1944 }\r
1945 \r
1946 function sortCheckedHist(by) {\r
1947         if(!by) return;\r
1948         \r
1949         sortOrder = !sortOrder;\r
1950         switch(by.toLowerCase()) {\r
1951                 case "title":\r
1952                 itemsOutHistory = itemsOutHistory.sort(function(a, b) {\r
1953                         if(mvrObjCache[a.circ.target_copy()].title()==null) return 1;\r
1954                         if(mvrObjCache[b.circ.target_copy()].title()==null) return -1;\r
1955                         if(sortOrder) return mvrObjCache[a.circ.target_copy()].title().toLowerCase()<mvrObjCache[b.circ.target_copy()].title().toLowerCase()?-1:1;\r
1956                                 else      return mvrObjCache[a.circ.target_copy()].title().toLowerCase()>mvrObjCache[b.circ.target_copy()].title().toLowerCase()?-1:1;\r
1957                 });\r
1958                 break;\r
1959                 case "author":\r
1960                 itemsOutHistory = itemsOutHistory.sort(function(a, b) {\r
1961                         if(mvrObjCache[a.circ.target_copy()].author()==null) return 1;\r
1962                         if(mvrObjCache[b.circ.target_copy()].author()==null) return -1;\r
1963                         if(sortOrder) return mvrObjCache[a.circ.target_copy()].author().toLowerCase()<mvrObjCache[b.circ.target_copy()].author().toLowerCase()?1:-1;\r
1964                                 else      return mvrObjCache[a.circ.target_copy()].author().toLowerCase()>mvrObjCache[b.circ.target_copy()].author().toLowerCase()?1:-1;\r
1965                 });\r
1966                 break;\r
1967                 case "duedate":\r
1968                 if(sortOrder) {\r
1969                         drawCheckedPage(); return;\r
1970                 } else itemsOutHistory = itemsOutHistory.sort(function(a, b) {\r
1971                         return dojo.date.stamp.fromISOString(a.circ.due_date()) < dojo.date.stamp.fromISOString(b.circ.due_date())?1:-1;\r
1972                 });\r
1973                 break;\r
1974                 case "cn":\r
1975                 itemsOutHistory = itemsOutHistory.sort(function(a, b) {\r
1976                                                                                 // ya, i know, but it gets the job done.\r
1977                         if(sortOrder) return callNumCache[copyObjCache[a.circ.target_copy()].call_number()].label().toLowerCase()<callNumCache[copyObjCache[b.circ.target_copy()].call_number()].label().toLowerCase()?-1:1;\r
1978                                 else      return callNumCache[copyObjCache[a.circ.target_copy()].call_number()].label().toLowerCase()>callNumCache[copyObjCache[b.circ.target_copy()].call_number()].label().toLowerCase()?-1:1;\r
1979                 });\r
1980                 break;\r
1981         }\r
1982         \r
1983         drawCircHistory(false);\r
1984 }\r
1985 \r
1986 function buildOrgSelAlt(selector, org, offset, namecol) {\r
1987  if(!namecol) namecol = 'name';\r
1988  if(!showXUL && !isTrue(org.opac_visible())) return; // for some reason, isXUL() is rather slow when used in a decently sized loop.\r
1989  insertSelectorVal( selector, -1,\r
1990  org[namecol](), org.id(), null, findOrgDepth(org) - offset );\r
1991  var kids = org.children();\r
1992  if (kids) {\r
1993  for( var c = 0; c < kids.length; c++ )\r
1994  buildOrgSelAlt( selector, kids[c], offset, namecol);\r
1995  }\r
1996 }