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