]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/opac/skin/default/js/myopac.js
Incorporate CC payment interface into OPAC fines page (rough)
[Evergreen.git] / Open-ILS / web / opac / skin / default / js / myopac.js
1
2 attachEvt("common", "run", myOPACInit );
3 //attachEvt("common", "loggedIn", myOPACInit );
4 attachEvt('common','locationUpdated', myopacReload );
5
6 var fleshedUser = null;
7 var fleshedContainers = {};
8 var holdCache = {};
9 var holdStatusCache = {};
10 var allowPendingAddr = false;
11 var myopacEnableRefWorks = false;
12 var myopacRefWorksHost = 'http://www.refworks.com';
13 var paymentForm = new PaymentForm();
14
15
16 function clearNodes( node, keepArray ) {
17         if(!node) return;
18         for( var n in keepArray ) node.removeChild(keepArray[n]);
19         removeChildren(node);
20         for( var n in keepArray ) node.appendChild(keepArray[n]);
21 }
22
23 function myOPACInit() {
24
25         if(!(G.user && G.user.session)) {
26         initLogin();
27
28     } else {
29
30         allowPendingAddr = fetchOrgSettingDefault(G.user.home_ou(), 'opac.allow_pending_address');
31         if(allowPendingAddr)
32             unHideMe($('myopac_pending_addr_td'));
33             myOPACChangePage( "summary" );
34     }
35
36     $('myopac_holds_thaw_date_input').onkeyup = 
37         function(){holdsVerifyThawDateUI('myopac_holds_thaw_date_input'); }
38     $('myopac_holds_thaw_date_input').onchange = 
39         function(){holdsVerifyThawDateUI('myopac_holds_thaw_date_input'); }
40
41 }
42
43 function myopacReload() {
44         //swapCanvas($('myopac_reloading'));
45         var a = {};
46         a[PARAM_LOCATION] = getNewSearchLocation();
47         a[PARAM_DEPTH] = getNewSearchDepth();
48         hideMe($('canvas_main'));
49         goTo(buildOPACLink(a, true));
50 }
51
52
53 function myOPACChangePage( page ) {
54         showCanvas();
55
56         var s = $("myopac_summary_td");
57         var c = $("myopac_checked_td");
58         var f = $("myopac_fines_td");
59         var h = $("myopac_holds_td");
60         var p = $("myopac_prefs_td");
61         var b = $('myopac_bookbag_td');
62
63         var ss = $("myopac_summary_div");
64         var cc = $("myopac_checked_div");
65         var ff = $("myopac_fines_div");
66         var hh = $("myopac_holds_div");
67         var pp = $("myopac_prefs_div");
68         var bb = $('myopac_bookbag_div');
69
70         var cls = "myopac_link";
71         var acls = "myopac_link_active";
72
73         hideMe(ss);
74         hideMe(cc); hideMe(ff);
75         hideMe(hh); hideMe(pp);
76         hideMe(bb);
77
78         removeCSSClass(s, acls );
79         removeCSSClass(c, acls );
80         removeCSSClass(f, acls );
81         removeCSSClass(h, acls );
82         removeCSSClass(p, acls );
83         removeCSSClass(b, acls );
84
85         switch( page ) {
86
87                 case "summary": 
88                         unHideMe(ss);
89                         addCSSClass(s, acls );
90                         myOPACShowSummary();
91                         break;
92
93                 case "checked": 
94                         unHideMe(cc);
95                         addCSSClass(c, acls );
96                         myOPACShowChecked();
97                         break;
98
99                 case "holds": 
100                         unHideMe(hh);
101                         addCSSClass(h, acls );
102                         myOPACShowHolds();
103                         break;
104
105                 case "fines": 
106                         unHideMe(ff);
107                         addCSSClass(f, acls );
108                         myOPACShowFines();
109                         break;
110
111                 case "prefs": 
112                         unHideMe(pp);
113                         addCSSClass(p, acls );
114                         myOPACShowPrefs();
115                         break;
116
117                 case 'bookbag':
118                         unHideMe(bb);
119                         addCSSClass(b, acls);
120                         myOPACShowBookbags();
121                         break;
122         }
123 }
124
125 function myOPACShowChecked() {
126         if(checkedDrawn) return;
127         var req = new Request(FETCH_CHECKED_OUT_SUM, G.user.session, G.user.id());      
128         req.callback(myOPACDrawCheckedOutSlim);
129         req.send();
130
131         var nreq = new Request(FETCH_NON_CAT_CIRCS, G.user.session);
132         nreq.callback(myOPACDrawNonCatCircs);
133         nreq.send();
134 }
135
136
137 var checkedRowTemplate;
138 var circsCache = new Array();
139 var checkedDrawn = false;
140
141 function moClearCheckedTable() {
142         var tbody                       = $("myopac_checked_tbody");
143         var loading                     = $("myopac_checked_loading");
144         var none                                = $("myopac_checked_none");
145         clearNodes( tbody, [ loading, none ] );
146 }
147
148 var __can_renew_one = false;
149
150 function myOPACDrawCheckedOutSlim(r) {
151
152         var checked                     = r.getResultObject();
153         var tbody                       = $("myopac_checked_tbody");
154         var loading                     = $("myopac_checked_loading");
155         var none                                = $("myopac_checked_none");
156
157    __can_renew_one = false;
158
159         if(checkedDrawn) return;
160         checkedDrawn = true;
161         if(!checkedRowTemplate) 
162                 checkedRowTemplate = tbody.removeChild($("myopac_checked_row"));
163
164    moClearCheckedTable();
165
166         hideMe(loading); /* remove all children and start over */
167         if(!(checked && (checked.out || checked.overdue))) {
168                 unHideMe(none);
169                 return;
170         }
171
172     var totalAsync = checked.overdue.length + checked.out.length;
173     var fetchedCircs = [];
174     var collectCircs = function(r) {
175         var circ = r.getResultObject();
176         circ._od = r.od;
177         fetchedCircs.push(circ);
178         if(fetchedCircs.length < totalAsync) return;
179
180         // sort by due date, oldest to newest
181         fetchedCircs = fetchedCircs.sort(
182             function(a, b) {
183                 if(a.due_date() > b.due_date()) return 1;
184                 return -1;
185             }
186         )
187
188         dojo.forEach(fetchedCircs, 
189             function(circ) { 
190                 myOPACDrawCheckedItem(circ, tbody);
191             }
192         );
193     }
194
195         for( var i = 0; i < checked.overdue.length; i++ ) {
196                 var req = new Request(FETCH_CIRC_BY_ID, G.user.session, checked.overdue[i]);
197                 //req.request.tbody = tbody;
198                 req.request.od = true;
199                 req.callback(collectCircs);
200                 req.send();
201         }
202
203
204         for( var i = 0; i < checked.out.length; i++ ) {
205                 var req = new Request(FETCH_CIRC_BY_ID, G.user.session, checked.out[i]);
206                 //req.request.tbody = tbody;
207                 req.callback(collectCircs);
208                 req.send();
209         }
210
211    appendClear($('mo_items_out_count'), 
212       text(new String( parseInt(checked.overdue.length) + parseInt(checked.out.length) )) );
213
214    if( checked.overdue.length > 0 ) {
215       addCSSClass($('mo_items_overdue_count'), 'overdue');
216       appendClear($('mo_items_overdue_count'),
217          text(new String( parseInt(checked.overdue.length) )) );
218    }
219
220 }
221
222
223 //function myOPACDrawCheckedItem(r) {
224 function myOPACDrawCheckedItem(circ, tbody) {
225
226         //var circ = r.getResultObject();
227         //var tbody = r.tbody;
228         var row = checkedRowTemplate.cloneNode(true);
229         row.id = 'myopac_checked_row_ ' + circ.id();
230     row.setAttribute('circid', circ.id());
231
232         var due = _trimTime(circ.due_date());
233
234         var dlink = $n( row, "myopac_checked_due" );
235         var rlink = $n( row, "myopac_checked_renewals" );
236         //var rnlink = $n( row, "myopac_checked_renew_link" );
237
238         //if( r.od ) due = elem('b', {style:'color:red;font-size:110%'},due);
239         if( circ._od ) {
240       due = elem('b', null, due);
241       addCSSClass(due, 'overdue');
242    } else {
243       due = text(due);
244    }
245
246         dlink.appendChild(due);
247         rlink.appendChild(text(circ.renewal_remaining()));
248         unHideMe(row);
249         //rnlink.setAttribute('href', 'javascript:myOPACRenewCirc("'+circ.id()+'");');
250         circsCache.push(circ);
251
252    if( circ.renewal_remaining() < 1 ) {
253       $n(row, 'selectme').disabled = true;
254       if(!__can_renew_one)
255          $('mo_renew_button').disabled = true;
256    } else {
257       __can_renew_one = true;
258       $('mo_renew_button').disabled = false;
259       $n(row, 'selectme').disabled = false;
260    }
261
262         tbody.appendChild(row);
263
264         var req = new Request(FETCH_MODS_FROM_COPY, circ.target_copy() );
265         req.request.alertEvent = false;
266         req.request.circ = circ.id();
267         req.request.copy = circ.target_copy();
268         req.callback(myOPACDrawCheckedTitle);
269         req.send();
270 }
271
272 var __circ_titles = {};
273
274 function myOPACDrawCheckedTitle(r) {
275         var record = r.getResultObject();
276         var circid = r.circ;
277
278         if(!record || checkILSEvent(record)) {
279                 var req = new Request( FETCH_COPY, r.copy );
280                 req.request.circ = circid
281                 req.callback(myOPACDrawNonCatalogedItem);
282                 req.send();
283                 return;
284         }
285
286         var row = $('myopac_checked_row_ ' + circid);
287         var tlink = $n( row, "myopac_checked_title_link" );
288         var alink = $n( row, "myopac_checked_author_link" );
289         buildTitleDetailLink(record, tlink);
290         buildSearchLink(STYPE_AUTHOR, record.author(), alink);
291    __circ_titles[circid] = record.title();
292 }
293
294 function myOPACDrawNonCatalogedItem(r) {
295         var copy = r.getResultObject();
296         var circid = r.circ;
297
298         var row = $('myopac_checked_row_ ' + circid);
299         var tlink = $n( row, "myopac_checked_title_link" );
300         var alink = $n( row, "myopac_checked_author_link" );
301
302         tlink.parentNode.appendChild(text(copy.dummy_title()));
303         alink.parentNode.appendChild(text(copy.dummy_author()));
304    __circ_titles[circid] = copy.dummy_title();
305 }
306
307
308 /*
309 function myOPACRenewCirc(circid) {
310
311         var circ;
312         for( var i = 0; i != circsCache.length; i++ ) 
313                 if(circsCache[i].id() == circid)
314                         circ = circsCache[i];
315
316         if(!confirm($('myopac_renew_confirm').innerHTML)) return;
317
318         var req = new Request(RENEW_CIRC, G.user.session, 
319                 { patron : G.user.id(), copyid : circ.target_copy(), opac_renewal : 1 } );
320         req.request.alertEvent = false;
321         req.send(true);
322         var res = req.result();
323
324         if(checkILSEvent(res) || checkILSEvent(res[0])) {
325                 alertId('myopac_renew_fail');
326                 return;
327         }
328
329         alert($('myopac_renew_success').innerHTML);     
330         checkedDrawn = false;
331         myOPACShowChecked();
332 }
333 */
334
335
336
337 function myOPACShowHolds() {
338         var req = new Request(FETCH_HOLDS, G.user.session, G.user.id());        
339         req.callback(myOPACDrawHolds);
340         req.send();
341     $('myopac_holds_actions_none').selected = true;
342 }
343
344 var holdsTemplateRowOrig;
345 var holdsTemplateRow;
346 var myopacForceHoldsRedraw = false;
347 function myOPACDrawHolds(r) {
348
349         var tbody = $("myopac_holds_tbody");
350         if(holdsTemplateRow && !myopacForceHoldsRedraw) return;
351     myopacForceHoldsRedraw = false;
352
353         if(holdsTemplateRowOrig) {
354                 holdsTemplateRow = holdsTemplateRowOrig;
355                 removeChildren(tbody);
356         } else {
357                 holdsTemplateRow = tbody.removeChild($("myopac_holds_row"));
358                 holdsTemplateRowOrig = holdsTemplateRow;
359         }
360
361         hideMe($('myopac_holds_loading'));
362
363         var holds = r.getResultObject();
364
365         if(!holds || holds.length < 1) unHideMe($('myopac_holds_none'));
366         for( var i = 0; i != holds.length; i++ ) {
367
368                 var h = holds[i];
369                 holdCache[h.id()] = h;
370
371                 var row = holdsTemplateRow.cloneNode(true);
372                 row.id = "myopac_holds_row_" + h.id();
373
374                 var form = $n(row, "myopac_holds_formats");
375                 form.id = "myopac_holds_form_" + h.id();
376
377                 var orglink = $n(row, "myopac_holds_location");
378                 orglink.appendChild(text(findOrgUnit(h.pickup_lib()).name()));
379
380                 tbody.appendChild(row);
381
382                 $n(row,'myopac_holds_edit_link').setAttribute(
383                         'href','javascript:myOPACEditHold("'+ h.id()+'");'); 
384
385         if(isTrue(h.frozen())) {
386             hideMe($n(row, 'myopac_hold_unfrozen_true'))
387             unHideMe($n(row, 'myopac_hold_unfrozen_false'))
388             if(h.thaw_date()) {
389                 var d = dojo.date.stamp.fromISOString(h.thaw_date());
390                 $n(row, 'myopac_holds_frozen_until').appendChild(text(dojo.date.locale.format(d, {selector: 'date', fullYear: true})));
391             }
392         } else {
393             unHideMe($n(row, 'myopac_hold_unfrozen_true'))
394             hideMe($n(row, 'myopac_hold_unfrozen_false'))
395         }
396
397         $n(row, 'myopac_holds_selected_chkbx').checked = false;
398
399         var exp_date;
400         if(h.expire_time()) {
401             exp_date = dojo.date.stamp.fromISOString(h.expire_time().replace(/(T\d\d:\d\d:\d\d)([+-]\d\d)(\d)/, "$1$2:$3"));
402             $n(row, 'myopac_hold_expire_time').appendChild(
403                 text(dojo.date.locale.format(exp_date, {selector:'date'})));
404         }
405
406                 unHideMe(row);
407
408         var interval = fetchOrgSettingDefault(G.user.home_ou(), 'circ.hold_expire_alert_interval');
409         if(interval && exp_date) {
410             secs = interval_to_seconds(interval) * 1000;
411             var diff = exp_date.getTime() - new Date().getTime();
412             if(diff < secs)
413                 addCSSClass($n(row, 'myopac_hold_expire_time'), 'hold_expire_warning');
414         }
415
416         myOPACDrawHoldTitle(h);
417         myOPACDrawHoldStatus(h);
418     }
419 }
420
421 function myOPACEditHold(holdid) {
422         var hold = holdCache[holdid];
423
424         holdsDrawEditor( 
425                 { 
426                         editHold : hold,
427                         onComplete : function(){ 
428                                 holdsTemplateRow = null;
429                                 myOPACShowHolds(); 
430                         }
431                 }
432         );
433 }
434
435
436 function myOPACDrawHoldStatus(hold) {
437         var req = new Request(FETCH_HOLD_STATUS, G.user.session, hold.id() );
438         req.callback(myOShowHoldStatus);
439         req.request.hold = hold;
440         req.send();
441 }
442
443 var myopacShowHoldEstimate = false;
444 function myOShowHoldStatus(r) {
445
446         var hold = r.hold;
447         var qstats = r.getResultObject();
448     holdStatusCache[hold.id()] = qstats;
449
450         var row = $("myopac_holds_row_" + r.hold.id());
451
452     if(qstats.estimated_wait || myopacShowHoldEstimate) {
453         myopacShowHoldEstimate = true;
454         if(qstats.estimated_wait)
455             $n(row, 'myopac_holds_estimated_wait').appendChild(text(qstats.estimated_wait));
456         unHideMe($('myopac_holds_estimated_wait_column'));
457         unHideMe($n(row, 'myopac_holds_estimated_wait'));
458     } 
459
460         if( qstats.status == 4 ) {
461                 unHideMe($n(row, 'hold_status_available'));
462                 hideMe($n(row, 'myopac_holds_cancel_link'));
463         }
464
465     if(false) {
466         var node = $n(row, 'hold_qstats');
467         // XXX best way to display this info + dojo i18n
468         node.appendChild(text('hold #' + qstats.queue_position+' of '+qstats.queue_position+' and '+qstats.potential_copies+' item(s)'));
469         unHideMe(node);
470
471     } else {
472             if( qstats.status < 3 )
473                     unHideMe($n(row, 'hold_status_waiting'));
474     
475             if( qstats.status == 3 )
476                     unHideMe($n(row, 'hold_status_transit'));
477     }
478 }
479
480
481 function myOPACDrawHoldTitle(hold) {
482         var method;
483
484         if( hold.hold_type() == 'T' || hold.hold_type() == 'M' ) {
485                 if(hold.hold_type() == "M") method = FETCH_MRMODS;
486                 if(hold.hold_type() == "T") method = FETCH_RMODS;
487                 var req = new Request(method, hold.target());
488                 req.callback(myOPACFleshHoldTitle);
489                 req.request.hold = hold;
490                 req.request.alertEvent = false;
491                 req.send();
492
493         } else {
494                 holdFetchObjects(hold, 
495                         function(a) { _myOPACFleshHoldTitle(hold, a);});
496         }
497 }
498
499 function myOPACFleshHoldTitle(r) {
500         var rec = r.getResultObject();
501         _myOPACFleshHoldTitle(r.hold, {recordObject: rec});
502 }
503
504 function _myOPACFleshHoldTitle(hold, holdObjects) {
505
506         var record = holdObjects.recordObject;
507         var volume      = holdObjects.volumeObject;
508         var copy        = holdObjects.copyObject;
509
510         var row = $("myopac_holds_row_" + hold.id());
511         var title_link = $n(row, "myopac_holds_title_link");
512         var author_link = $n(row, "myopac_holds_author_link");
513
514         if(!record || checkILSEvent(record) ) {
515                 addCSSClass(row, 'invalid_hold');
516                 $n(row, 'myopac_holds_edit_link').setAttribute('href', 'javascript:void(0);');
517                 $n(row, 'myopac_holds_edit_link').onclick = function(){alertId('invalid_hold');};
518                 return;
519         }
520
521         buildTitleDetailLink(record, title_link);
522         buildSearchLink(STYPE_AUTHOR, record.author(), author_link);
523
524         if( volume ) {
525                 $n(row, 'volume').appendChild(text(volume.label()));
526                 unHideMe($n(row, 'vol_copy'));
527                 if(copy) $n(row, 'copy').appendChild(text(copy.barcode()));
528         }
529
530         var form = $("myopac_holds_form_" + hold.id());
531
532         if(form) {
533                 var mods_formats = record.types_of_resource();
534
535                 if( hold.hold_type() == 'M' ) {
536                         var data = holdsParseMRFormats(hold.holdable_formats());
537                         mods_formats = data.mods_formats;
538                 }
539
540                 for( var i = 0; i < mods_formats.length; i++ ) {
541                         var img = elem("img");
542                         setResourcePic(img, mods_formats[i]);
543                         form.appendChild(img);
544                 }
545         }
546 }
547
548 var finesShown = false;
549 function myOPACShowFines() {
550         if(finesShown) return; finesShown = true;
551         var req = new Request(FETCH_FINES_SUMMARY, G.user.session, G.user.id() );
552         req.callback(_myOPACShowFines);
553         req.send();
554 }
555
556 function _myOPACShowFines(r) {
557         hideMe($('myopac_fines_summary_loading'));
558         unHideMe($('myopac_fines_summary_row'));
559
560         var summary = r.getResultObject();
561         var total       = "0.00"; /* localization? */
562         var paid                = "0.00";
563         var balance = "0.00";
564         if( instanceOf(summary,mous) ) {
565
566                 total           = _finesFormatNumber(summary.total_owed());
567                 paid            = _finesFormatNumber(summary.total_paid());
568                 balance = _finesFormatNumber(summary.balance_owed());
569
570                 var req = new Request(FETCH_TRANSACTIONS, G.user.session, G.user.id() );
571                 req.callback(function(r) { myOPACShowTransactions(r, balance); });
572                 req.send();
573         }
574
575         $('myopac_fines_summary_total').appendChild(text(total));
576         $('myopac_fines_summary_paid').appendChild(text(paid));
577         $("myopac_fines_summary_balance").appendChild(text(balance));
578
579 }
580
581 function preparePaymentForm(balance, transactions) {
582         if (Number(balance) > 0) {
583                 var cxl_link = $("myopac_fines_payment_cancel_link");
584                 var pay_link = $("myopac_fines_payment_link");
585
586                 cxl_link.onclick = function() {
587                         hideMe(cxl_link);
588                         unHideMe(pay_link);
589                         unHideMe($("myopac_circ_trans_div"));
590                         $("myopac_payment_div").innerHTML = "";
591                 };
592                 pay_link.onclick = function() {
593                         dojo.xhrGet({
594                                 "url": "/eg/circ/selfcheck/payment",
595                                 "load": function(resp) {
596                                         hideMe($("myopac_circ_trans_div"));
597                                         $("myopac_payment_div").innerHTML = resp;
598                                         dojo.parser.parse($("myopac_payment_div"));
599                                         paymentForm.drawPayFinesPage(
600                                                 G.user, balance, dojo.map(
601                                                         transactions, function(t) {
602                                                                 return [t.id(), Number(t.balance_owed()).toFixed(2)];
603                                                         }
604                                                 ),
605                                                 function() { alert("Payment registered"); /* LFW XXX */ }
606                                         );
607                                         hideMe(pay_link);
608                                         unHideMe(cxl_link);
609                                 },
610                                 "error": function(e) {
611                                         alert("Error preparing payment form: " + e); // XXX i18n; user-friendliness
612                                 }
613                         });
614                 };
615                 unHideMe($("myopac_fines_payment"));
616         }
617 }
618
619 function _finesFormatNumber(num) {
620         if(isNull(num)) num = 0;
621         num = num + "";
622         if(num.length < 2 || !num.match(/\./)) num += ".00";
623         if(num.match(/\./) && num.charAt(num.length-2) == '.') num += "0";
624         return num;
625 }          
626
627 //function _trimTime(time) { if(!time) return ""; return time.replace(/\ .*/,""); }
628 function _trimTime(time) { 
629         if(!time) return ""; 
630     time = time.replace(/(T\d\d:\d\d:\d\d)([+-]\d\d)(\d)/, "$1$2:$3");
631     var d = dojo.date.stamp.fromISOString(time);
632     if(!d) return ""; /* date parse failed */
633     return d.iso8601Format('YMD');
634 }
635
636 function _trimSeconds(time) { 
637     if(!time) return ""; 
638     var d = dojo.date.stamp.fromISOString(time.replace(/(T\d\d:\d\d:\d\d)([+-]\d\d)(\d)/, "$1$2:$3"));
639     if(!d) return ""; /* date parse failed */
640     return d.iso8601Format('YMDHM',null,true,true);
641 }
642
643 function myOPACShowTransactions(r, balance) {
644
645         if(myopacGenericTransTemplate || myopacCircTransTemplate) return;
646
647         var transactions = r.getResultObject();
648         var payment_xacts = [];
649
650         for( var idx in transactions ) {
651
652                 var trans       = transactions[idx].transaction;
653                 var record      = transactions[idx].record;
654                 var circ                = transactions[idx].circ;
655
656                 if(trans.xact_type() == 'circulation') 
657                         myOPACShowCircTransaction(trans, record, circ);
658
659                 else if(trans.xact_type() == 'grocery' ) 
660                         myopacShowGenericTransaction( trans );
661
662                 payment_xacts.push(trans);
663
664 /*      XXX need to copy circulation output function here
665                 else if(trans.xact_type() == 'reservation' ) 
666                         myopacShowReservationTransaction( trans );
667 */
668
669         }
670
671         preparePaymentForm(balance, payment_xacts);
672 }
673
674 var myopacGenericTransTemplate;
675 function myopacShowGenericTransaction( trans ) {
676         var tbody = $('myopac_trans_tbody');
677
678         if(!myopacGenericTransTemplate) {
679                 myopacGenericTransTemplate = 
680                         tbody.removeChild($('myopac_trans_row'));
681                 removeChildren(tbody);
682         }
683
684         var row = myopacGenericTransTemplate.cloneNode(true);
685
686         $n(row,'myopac_trans_start').appendChild(
687                         text(_trimSeconds(trans.xact_start())));
688
689         $n(row,'myopac_trans_last_payment').appendChild(
690                         text(_trimSeconds(trans.last_payment_ts())));
691
692         $n(row,'myopac_trans_init_amount').appendChild(
693                         text(_finesFormatNumber(trans.total_owed())));
694
695         $n(row,'myopac_trans_total_paid').appendChild(
696                         text(_finesFormatNumber(trans.total_paid())));
697
698         $n(row,'myopac_trans_balance').appendChild(
699                         text(_finesFormatNumber(trans.balance_owed())));
700
701         var req = new Request(FETCH_MONEY_BILLING, G.user.session, trans.id());
702         req.send(true);
703         var bills = req.result();
704         if(bills && bills[0])
705                 $n(row,'myopac_trans_bill_type').appendChild(
706                                 text(bills[0].billing_type()));
707
708         tbody.appendChild(row);
709         unHideMe($('myopac_trans_div'));
710 }
711
712
713
714 /* draws a circulation transaction summary */
715 var myopacCircTransTemplate;
716 function myOPACShowCircTransaction(trans, record, circ) {
717         var tbody = $('myopac_circ_trans_tbody');
718
719         if(!myopacCircTransTemplate) {
720                 myopacCircTransTemplate = tbody.removeChild($('myopac_circ_trans_row'));
721                 removeChildren(tbody);
722         }
723
724         var row = myopacCircTransTemplate.cloneNode(true);
725
726         if(record) {
727                 buildTitleDetailLink(record, $n(row,'myopac_circ_trans_title'));
728
729                 $n(row,'myopac_circ_trans_author').appendChild(text(
730                         normalize(truncate(record.author(), 65))));
731
732         } else {
733
734                 var req = new Request( FETCH_COPY, circ.target_copy() );
735                 req.alertEvents = false;
736                 req.send(true);
737                 var copy = req.result();
738                 if( copy ) {
739                         $n(row,'myopac_circ_trans_title').appendChild(text(copy.dummy_title()));
740                         $n(row,'myopac_circ_trans_author').appendChild(text(copy.dummy_author()));
741                 }
742         }
743
744
745         $n(row,'myopac_circ_trans_start').
746                 appendChild(text(_trimTime(trans.xact_start())));
747         var due = _trimTime(circ.due_date());
748         var checkin = _trimTime(circ.stop_fines_time());
749
750         $n(row,'myopac_circ_trans_due').appendChild(text(due))
751         if(checkin)
752                 appendClear($n(row,'myopac_circ_trans_finished'), text(checkin));
753         if(circ.stop_fines() == 'LOST')
754                 appendClear($n(row,'myopac_circ_trans_finished'), text(circ.stop_fines()));
755         if(circ.stop_fines() == 'CLAIMSRETURNED')
756                 appendClear($n(row,'myopac_circ_trans_finished'), text(""));
757
758
759         $n(row,'myopac_circ_trans_balance').
760                 appendChild(text(_finesFormatNumber(trans.balance_owed())));
761
762         tbody.appendChild(row);
763         unHideMe($('myopac_circ_trans_div'));
764 }
765
766
767 function myOPACSavePrefs() {
768         G.user.prefs[PREF_HITS_PER] = getSelectorVal($('prefs_hits_per'));
769         G.user.prefs[PREF_DEF_FONT] = getSelectorVal($('prefs_def_font'));
770         G.user.prefs[PREF_HOLD_NOTIFY] = getSelectorVal($('prefs_hold_notify'));
771         G.user.prefs[PREF_DEF_DEPTH] = getSelectorVal($('prefs_def_range'));
772
773         if( $('myopac_pref_home_lib').checked == true )
774                 G.user.prefs[PREF_DEF_LOCATION] = null;
775         else
776                 G.user.prefs[PREF_DEF_LOCATION] = getSelectorVal($('prefs_def_location'));
777
778         if(commitUserPrefs())
779                 alert($('prefs_update_success').innerHTML);
780         else alert($('prefs_update_failure').innerHTML);
781 }
782
783
784 function myOPACShowDefFont() {
785         var font;
786         if(G.user.prefs[PREF_DEF_FONT])
787                 font = G.user.prefs[PREF_DEF_FONT];
788         else font = "regular";
789         setSelector($('prefs_def_font'), font);
790 }
791
792 function myOPACShowHoldNotify() {
793         var pref = G.user.prefs[PREF_HOLD_NOTIFY];
794
795         if(pref) {
796                 if(pref.match(/email/i) && pref.match(/phone/i)) {
797                         setSelector($('prefs_hold_notify'), 'phone:email');
798                 } else if( pref.match(/email/i) ) {
799                         setSelector($('prefs_hold_notify'), 'email');
800                 } else if( pref.match(/phone/i) ) {
801                         setSelector($('prefs_hold_notify'), 'phone');
802                 }
803
804         } else {
805                 setSelector($('prefs_hold_notify'), 'phone:email');
806         }
807 }
808
809 function myOPACShowPrefs() {
810         grabUserPrefs();
811         myOPACShowHitsPer();
812         myOPACShowDefFont();
813         myOPACShowHoldNotify();
814         myOPACShowDefLocation();
815         hideMe($('myopac_prefs_loading'));
816 }
817
818 var defSearchLocationDrawn = false;
819 var defDepthIndex = 0;
820 function myOPACShowDefLocation() {
821
822         var selector = $('prefs_def_location');
823         var rsel = $('prefs_def_range');
824
825         if(!defSearchLocationDrawn) {
826
827                 defSearchLocationDrawn = true;
828
829                 var org = G.user.prefs[PREF_DEF_LOCATION];
830
831                 if(!org) {
832                         $('myopac_pref_home_lib').checked = true;
833                         $('prefs_def_location').disabled = true;
834                         org = G.user.home_ou();
835                 }
836
837                 buildOrgSel(selector, globalOrgTree, 0);
838
839                 globalOrgTypes = globalOrgTypes.sort(
840                         function(a, b) {
841                                 if( a.depth() < b.depth() ) return -1;
842                                 return 1;
843                         }
844                 );
845
846                 iterate(globalOrgTypes,
847                         function(t) {
848                                 if( t.depth() <= findOrgDepth(org) ) {
849                                         setSelectorVal(rsel, defDepthIndex++, t.opac_label(), t.depth());
850                                         if( t.depth() == findOrgDepth(org) ) 
851                                                 setSelector(rsel, t.depth());
852                                 }
853                         }
854                 );
855         }
856
857         setSelector(selector, org);
858 }
859
860 function myOPACShowHitsPer() {
861         var hits = 10;
862         if(G.user.prefs[PREF_HITS_PER])
863                 hits = G.user.prefs[PREF_HITS_PER];
864         var hitsSel = $('prefs_hits_per');
865         setSelector(hitsSel, hits);
866 }
867
868 var userShown = false;
869 function myOPACShowSummary() {
870         if(userShown) return; userShown = true;
871         var req = new Request(FETCH_FLESHED_USER,G.user.session, G.user.id());
872         req.callback(_myOPACSummaryShowUer);
873         req.send();
874 }
875
876 var addrRowTemplate;
877 var notesTemplate;
878 function _myOPACSummaryShowUer(r) {
879
880         var user = r.getResultObject();
881         fleshedUser = user;
882         if(!user) return;
883
884     var expireDate = dojo.date.stamp.fromISOString(user.expire_date());
885     if( expireDate < new Date() ) {
886         appendClear($('myopac.expired.date'), expireDate.iso8601Format('YMD'));
887         unHideMe($('myopac.expired.alert'));
888     }
889
890         var iv1 = user.ident_value()+'';
891     if (iv1.length > 4 && iv1.match(/\d{4}/)) iv1 = iv1.substring(0,4) + '***********';
892
893
894         appendClear($('myopac_summary_prefix'),text(user.prefix()));
895         appendClear($('myopac_summary_first'),text(user.first_given_name()));
896         appendClear($('myopac_summary_middle'),text(user.second_given_name()));
897         appendClear($('myopac_summary_dayphone'),text(user.day_phone()));
898         appendClear($('myopac_summary_eveningphone'),text(user.evening_phone()));
899         appendClear($('myopac_summary_otherphone'),text(user.other_phone()));
900         appendClear($('myopac_summary_last'),text(user.family_name()));
901         appendClear($('myopac_summary_suffix'),text(user.suffix()));
902         appendClear($('myopac_summary_username'),text(user.usrname()));
903         appendClear($('myopac_summary_email'),text(user.email()));
904         appendClear($('myopac_summary_barcode'),text(user.card().barcode()));
905         appendClear($('myopac_summary_ident1'),text(iv1));
906         appendClear($('myopac_summary_homelib'),text(findOrgUnit(user.home_ou()).name()));
907         appendClear($('myopac_summary_create_date'),text(_trimTime(user.create_date())));
908
909         var req = new Request( 
910                 FETCH_USER_NOTES, G.user.session, {pub:1, patronid:G.user.id()});
911         req.callback(myopacDrawNotes);
912         req.send();
913
914
915         var tbody = $('myopac_addr_tbody');
916         var template;
917
918         if(addrRowTemplate) { 
919                 template = addrRowTemplate;
920         } else {
921                 template = tbody.removeChild($('myopac_addr_row'));
922                 addrRowTemplate = template;
923         }
924         removeChildren(tbody);
925
926     var addrs = user.addresses();
927         for( var a in addrs ) {
928         var addr = addrs[a];
929         if(!allowPendingAddr && isTrue(addr.pending()))
930             continue;
931         if(addr.replaces() != null) continue;
932                 var row = template.cloneNode(true);
933                 myOPACDrawAddr(row, addr, addrs);
934                 tbody.appendChild(row);
935         }
936 }
937
938
939 function myopacDrawNotes(r) {
940         var notes = r.getResultObject();
941         var tbody = $('myopac.notes.tbody');
942         if(!notesTemplate)
943                 notesTemplate = tbody.removeChild($('myopac.notes.tr'));
944         removeChildren(tbody);
945
946         iterate(notes, 
947                 function(note) {
948                         unHideMe($('myopac.notes.div'));
949                         var row = notesTemplate.cloneNode(true);
950                         $n(row, 'title').appendChild(text(note.title()));
951                         $n(row, 'value').appendChild(text(note.value()));
952                         tbody.appendChild(row);
953                 }
954         );
955 }
956
957
958
959 function myOPACDrawAddr(row, addr, addrs) {
960     appendClear($n(row, 'myopac_addr_type'),text(addr.address_type()));
961     appendClear($n(row, 'myopac_addr_street'),text(addr.street1()));
962     appendClear($n(row, 'myopac_addr_street2'),text(addr.street2()));
963     appendClear($n(row, 'myopac_addr_city'),text(addr.city()));
964     appendClear($n(row, 'myopac_addr_county'),text(addr.county()));
965     appendClear($n(row, 'myopac_addr_state'),text(addr.state()));
966     appendClear($n(row, 'myopac_addr_country'),text(addr.country()));
967     appendClear($n(row, 'myopac_addr_zip'),text(addr.post_code()));
968
969     if(!isTrue(addr.valid()))
970         unHideMe($n(row, 'myopac_invalid_addr_row'));
971
972     if(!allowPendingAddr) return;
973
974     $n(row, 'myopac_addr_edit_link').onclick = function(){myopacEditAddress(addr)};
975     unHideMe($n(row, 'myopac_addr_edit_td'));
976
977     /* if we have a replacement address, plop it into the table next to this addr */
978     var repl = grep(addrs,
979         function(a) { 
980             return a.replaces() == addr.id(); 
981         } 
982     );
983
984     $n(row, 'myopac_pending_addr_td').id = 'myopac_pending_addr_td_' + addr.id();
985
986     if(repl) {
987         hideMe($n(row, 'myopac_addr_edit_td')); // hide the edit link
988         repl = repl[0];
989         myopacSetAddrInputs(row, repl);
990     }
991 }
992
993 function myopacEditAddress(addr) {
994     var td = $('myopac_pending_addr_td_' + addr.id());
995     var row = td.parentNode;
996     myopacSetAddrInputs(row, addr);
997 }
998
999 function myopacSetAddrInputs(row, addr, prefix) {
1000     unHideMe($n(row, 'myopac_pending_addr_td'));
1001     $n(row, 'myopac_pending_addr_type').value = addr.address_type();
1002     $n(row, 'myopac_pending_addr_street').value = addr.street1();
1003     $n(row, 'myopac_pending_addr_street2').value = addr.street2();
1004     $n(row, 'myopac_pending_addr_city').value = addr.city();
1005     $n(row, 'myopac_pending_addr_county').value = addr.county();
1006     $n(row, 'myopac_pending_addr_state').value = addr.state();
1007     $n(row, 'myopac_pending_addr_country').value = addr.country();
1008     $n(row, 'myopac_pending_addr_zip').value = addr.post_code();
1009     $n(row, 'myopac_pending_addr_edit_link').onclick = function(){myopacSaveAddress(row, addr)};
1010     $n(row, 'myopac_pending_addr_del_link').onclick = function(){myopacSaveAddress(row, addr, true)};
1011 }
1012
1013 // if no pending addr exists, this is called with the original address
1014 function myopacSaveAddress(row, addr, deleteMe) {
1015
1016     if(addr.replaces() == null) {
1017         // we are editing a non-pending address.  create a pending address to manage that
1018         var repl = new aua();
1019         repl.usr(addr.usr());
1020         repl.address_type(addr.address_type());
1021         repl.within_city_limits(addr.within_city_limits());
1022         repl.replaces(addr.id());
1023         repl.pending('t');
1024         repl.isnew(true);
1025         repl.id(null);
1026         addr = repl;
1027     }
1028
1029     if(deleteMe) {
1030         if(addr.id() == null) {
1031             hideMe($n(row, 'myopac_pending_addr_td'));
1032             return;
1033         }
1034         addr.isdeleted(true);
1035     } else {
1036         addr.address_type($n(row, 'myopac_pending_addr_type').value);
1037         addr.street1($n(row, 'myopac_pending_addr_street').value);
1038         addr.street2($n(row, 'myopac_pending_addr_street2').value);
1039         addr.city($n(row, 'myopac_pending_addr_city').value);
1040         addr.county($n(row, 'myopac_pending_addr_county').value);
1041         addr.state($n(row, 'myopac_pending_addr_state').value);
1042         addr.country($n(row, 'myopac_pending_addr_country').value);
1043         addr.post_code($n(row, 'myopac_pending_addr_zip').value);
1044     }
1045
1046         var req = new Request(
1047         'open-ils.actor:open-ils.actor.user.address.pending.cud', 
1048         G.user.session, addr);
1049
1050     req.callback(
1051         function(r) {
1052             var resp = r.getResultObject(); 
1053
1054             if(addr.isnew()) {
1055                 // new, add to list of addrs
1056                 addr.id(resp);
1057                 fleshedUser.addresses().push(addr);
1058
1059             } else {
1060                 // deleted, remove from list of addrs
1061                 if(addr.isdeleted()) {
1062                     hideMe($n(row, 'myopac_pending_addr_td'));
1063                     var addrs = [];
1064                     for(var i in fleshedUser.addresses()) {
1065                         var a = fleshedUser.addresses()[i];
1066                         if(a.id() != addr.id())
1067                             addrs.push(a);
1068                     }
1069                     fleshedUser.addresses(addrs);
1070                 }
1071             }
1072            alertId('myopac_addr_changes_saved');
1073         }
1074     );
1075     req.send();
1076 };
1077
1078
1079 function myOPACUpdateUsername() {
1080         var username = $('myopac_new_username').value;
1081         if(username == null || username == "") {
1082                 alert($('myopac_username_error').innerHTML);
1083                 return;
1084         }
1085
1086         if( username.match(/.*\s.*/) ) {
1087                 alert($('myopac_invalid_username').innerHTML);
1088                 return;
1089         }
1090
1091     r = fetchOrgSettingDefault(globalOrgTree.id(), 'opac.barcode_regex');
1092     if(r) REGEX_BARCODE = new RegExp(r);
1093
1094     if(username.match(REGEX_BARCODE)) {
1095         alert($('myopac_invalid_username').innerHTML);
1096         return;
1097     }
1098
1099         /* first see if the requested username is taken */
1100         var req = new Request(CHECK_USERNAME, G.user.session, username);
1101         req.send(true);
1102         var res = req.result();
1103         /* If the username does not already exist, res will be null;
1104          * we can move on to updating the username.
1105          * 
1106          * If the username does exist, then res will be the user ID.
1107          * G.user.id() gives us the currently authenticated user ID.
1108          * If res == G.user.id(), we try to update the username anyways.
1109          */
1110         if( res !== null && res != G.user.id() ) {
1111                 alertId('myopac_username_dup');
1112                 return;
1113         }
1114
1115         var req = new Request(UPDATE_USERNAME, G.user.session, username );
1116         req.send(true);
1117         if(req.result()) {
1118
1119                 var evt;
1120                 var res = req.result();
1121                 if(evt = checkILSEvent(res)) {
1122                         alertILSEvent(res);
1123                         return;
1124                 }
1125
1126                 G.user.usrname(username);
1127                 hideMe($('myopac_update_username_row'));
1128                 userShown = false;
1129                 alertId('myopac_username_success');
1130                 myOPACShowSummary();
1131                 return;
1132         }
1133
1134         alert($('myopac_username_failure').innerHTML);
1135 }
1136
1137 function myOPACUpdateEmail() {
1138         var email = $('myopac_new_email').value;
1139         if(email == null || email == "") {
1140                 alert($('myopac_email_error').innerHTML);
1141                 return;
1142         }
1143
1144         var req = new Request(UPDATE_EMAIL, G.user.session, email );
1145         req.send(true);
1146         if(req.result()) {
1147                 G.user.email(email);
1148                 hideMe($('myopac_update_email_row'));
1149                 userShown = false;
1150                 alertId('myopac_email_success');
1151                 myOPACShowSummary();
1152                 return;
1153         }
1154
1155         alert($('myopac_email_failure').innerHTML);
1156 }
1157
1158
1159 function myOPACUpdatePassword() {
1160         var curpassword = $('myopac_current_password').value;
1161         var password = $('myopac_new_password').value;
1162         var password2 = $('myopac_new_password2').value;
1163
1164         if(     curpassword == null || curpassword == "" || 
1165                         password == null || password == "" || 
1166                         password2 == null || password2 == "" || password != password2 ) {
1167                 alert($('myopac_password_error').innerHTML);
1168                 return;
1169         }
1170
1171         if(!strongPassword(password, true)) return;
1172
1173         var req = new Request(UPDATE_PASSWORD, G.user.session, password, curpassword );
1174         req.send(true);
1175         if(req.result()) {
1176                 hideMe($('myopac_update_password_row'));
1177                 userShown = false;
1178                 alertId('myopac_password_success');
1179                 myOPACShowSummary();
1180                 return;
1181         }
1182
1183         alert($('myopac_password_failure').innerHTML);
1184 }
1185
1186
1187
1188
1189 var containerTemplate;
1190 function myOPACShowBookbags(force) {
1191
1192         var tbody =$('myopac_bookbag_tbody') ;
1193
1194         if(!containerTemplate) 
1195                 containerTemplate = tbody.removeChild($('myopac_bookbag_tr'));
1196         else if(!force) return;
1197
1198         removeChildren(tbody);
1199
1200         var containers = containerFetchAll();
1201
1202         var found = false;
1203         for( var i in containers ) {
1204                 found = true;
1205                 var cont = containers[i];
1206                 var row = containerTemplate.cloneNode(true);
1207                 row.id = 'myopac_bookbag_row_' + cont.id();
1208                 var link = $n(row, 'myopac_expand_bookbag');
1209                 var dlink = $n(row, 'myopac_container_delete');
1210                 link.appendChild( text(cont.name()) );
1211                 link.setAttribute('href', 
1212                         'javascript:myOPACExpandBookbag("' + cont.id() + '","' + cont.name() + '");');
1213                 myOPACFetchBBItems( cont.id(), row );
1214                 dlink.setAttribute('href', 'javascript:myOPACDeleteBookbag("'+cont.id()+'");');
1215
1216                 if( isTrue(cont.pub()) ) {
1217                         unHideMe($n(row, 'myopac_bb_published_yes'));
1218                         var link = $n(row, 'myopac_bb_published_view');
1219                         link.setAttribute('href', buildExtrasLink( 'feed/bookbag/html-full/'+cont.id(), false));  
1220                         link.setAttribute('target', '_blank' );
1221                         unHideMe(link);
1222
1223                         link = $n(row, 'myopac_bb_published_atom');
1224                         link.setAttribute('href', buildExtrasLink( 'feed/bookbag/rss2-full/'+cont.id(), false));  
1225                         link.setAttribute('target', '_blank' );
1226                         unHideMe(link);
1227
1228                         link = $n(row, 'myopac_bb_make_unpublished');
1229                         link.setAttribute('href', 'javascript:myOPACMakeBBPublished("'+cont.id()+'", true);');
1230                         unHideMe(link);
1231                         
1232                         var RW = $n(row, 'myopac_bb_exp_refworks');
1233                         if (RW && myopacEnableRefWorks) {
1234                                 var here = (findOrgUnit(getLocation())).name();
1235                                 var org_name = here.replace(" ", "+");
1236                                 var cgi = new CGI();
1237
1238                                 RW.setAttribute('href',
1239                                 myopacRefWorksHost + '/express/expressimport.asp?vendor='
1240                                         + org_name
1241                                         + '&filter=MARC+Format&database=All+MARC+Formats&encoding=65001&url=http%3A%2F%2F'
1242                                         + cgi.server_name + '/opac/extras/feed/bookbag/marctxt-full/'
1243                                         + cont.id()
1244                                 );
1245                                 RW.setAttribute('target', 'RefWorksMain');
1246                                 unHideMe($n(row, 'myopac_bb_exp_refworks'));
1247                         }
1248                 } else { 
1249                         unHideMe($n(row, 'myopac_bb_published_no')); 
1250                         var link = $n(row, 'myopac_bb_make_published');
1251                         link.setAttribute('href', 'javascript:myOPACMakeBBPublished("'+cont.id()+'");');
1252                         unHideMe(link);
1253                 }
1254
1255                 tbody.appendChild(row); 
1256         }
1257
1258         if(!found) unHideMe($('myopac_bookbags_none'));
1259         else unHideMe($('myopac_bookbag_table'));       
1260 }
1261
1262 function myOPACMakeBBPublished(bbid, hideme) {
1263
1264         var bb = fleshedContainers[bbid];
1265
1266         if(hideme) {
1267                 if(!confirm($('myopac_make_unpublished_confirm').innerHTML)) return;
1268                 bb.pub('f');
1269         } else {
1270                 if(!confirm($('myopac_make_published_confirm').innerHTML)) return;
1271                 bb.pub('t');
1272         }
1273
1274         var result = containerUpdate(bb);
1275
1276         var code = checkILSEvent(result);
1277         if(code) { alertILSEvent(result); return; }
1278
1279         alert($('myopac_bb_update_success').innerHTML);
1280         myOPACShowBookbags(true);
1281 }
1282
1283
1284
1285 function myOPACDeleteBookbag(id) {
1286         if( confirm( $('myopac_delete_bookbag_warn').innerHTML ) ) {
1287                 var result = containerDelete(id);
1288                 var code = checkILSEvent(result);
1289                 if(code) { alertILSEvent(result); return; }
1290                 alert($('myopac_bb_update_success').innerHTML);
1291                 hideMe($('myopac_bookbag_items_table'));
1292                 hideMe($('myopac_bookbag_items_name'));
1293                 hideMe($('myopac_bookbag_no_items'));
1294                 myOPACShowBookbags(true);
1295         }
1296 }
1297
1298 function myOPACFetchBBItems( id, row, block ) {
1299         if(!block) {
1300                 containerFlesh( id, _myOPACSetBBItems, { row: row }  );
1301         } else {
1302                 var cont = containerFlesh(id);
1303                 myOPACSetBBItems( cont, row );
1304         }
1305 }
1306
1307 function _myOPACSetBBItems(r) { myOPACSetBBItems( r.getResultObject(), r.args.row ); }
1308
1309 function myOPACSetBBItems( container, row ) {
1310         fleshedContainers[container.id()] = container;
1311         var node = $n(row, 'myopac_bookbag_item_count');
1312         removeChildren(node);
1313         node.appendChild( text(container.items().length) );
1314 }
1315
1316 var BBItemsRow;
1317 function myOPACExpandBookbag( id, name ) {
1318         
1319         var tbody = $('myopac_bookbag_items_tbody');
1320         if(!BBItemsRow) BBItemsRow = tbody.removeChild($('myopac_bookbag_items_row'));
1321         removeChildren(tbody);
1322         removeChildren($('myopac_bookbag_items_name'));
1323
1324         $('myopac_bookbag_items_name').appendChild(text(name));
1325
1326         if( fleshedContainers[id] ) {
1327                 var len = fleshedContainers[id].items().length;
1328
1329                 if( len == 0 ) {
1330                         unHideMe($('myopac_bookbag_no_items'));
1331                         hideMe($('myopac_bookbag_items_table'));
1332                         return;
1333                 }
1334
1335                 hideMe($('myopac_bookbag_no_items'));
1336                 unHideMe($('myopac_bookbag_items_table'));
1337
1338                 for( var i = 0; i != len; i++ ) {
1339                         var row = BBItemsRow.cloneNode(true);
1340                         found = true;
1341
1342                         var item = fleshedContainers[id].items()[i];
1343                         var tlink = $n(row,'myopac_bookbag_items_title');
1344                         var alink = $n(row,'myopac_bookbag_items_author');
1345
1346                         var req = new Request( FETCH_RMODS, item.target_biblio_record_entry() );
1347                         req.request.tlink = tlink;
1348                         req.request.alink = alink;
1349                         req.callback(myOPACShowBBItem);
1350                         req.send();
1351
1352                         var clink = $n(row, 'myopac_bookbag_items_remove');
1353                         clink.setAttribute('href', 'javascript:myOPACRemoveBBItem("'+item.id()+'","'+id+'","'+name+'");');
1354
1355                         tbody.appendChild(row);
1356                 }
1357         }
1358 }
1359
1360 function myOPACRemoveBBItem( id, containerid, container_name ) {
1361         if(!confirm($('myopac_remove_bb_item_confirm').innerHTML)) return;
1362         var stat = containerRemoveItem( id );
1363         if(stat) alert($('myopac_bb_update_success').innerHTML);
1364         myOPACFetchBBItems( containerid, $('myopac_bookbag_row_' + containerid), true);
1365         myOPACExpandBookbag( containerid, container_name );
1366 }
1367
1368 function myOPACShowBBItem(r) {
1369         var record = r.getResultObject();
1370         buildTitleDetailLink(record, r.tlink);
1371         buildSearchLink(STYPE_AUTHOR, record.author(), r.alink);
1372 }
1373
1374 function myOPACCreateBookbag() {
1375         var name = $('myopac_bookbag_new_name').value;  
1376         if(!name) return;
1377
1378         var exists = false;
1379         for( var c in fleshedContainers ) { exists = true; break; }
1380
1381         /* let them know what they are getting into... */
1382         if(!exists) if(!confirm($('bb_create_warning').innerHTML)) return;
1383
1384         var result = containerCreate( name, $('bb_public_yes').checked );
1385         var code = checkILSEvent(result);
1386         if(code) { alertILSEvent(result); return; }
1387         if(result) alert($('myopac_bb_update_success').innerHTML);
1388         myOPACShowBookbags(true);
1389 }
1390
1391
1392 /* ---------------------------------------------------------------------- */
1393 /* Non cat circs */
1394 /* ---------------------------------------------------------------------- */
1395
1396 var nonCatCircIds;
1397 var nonCatTypes;
1398 /* if we have some circs, grab the non-cat types */
1399 function myOPACDrawNonCatCircs(r) {
1400         var ids = r.getResultObject();
1401         if(ids.length == 0) return;
1402         nonCatCircIds = ids;
1403         unHideMe($('non_cat_circs_div'));
1404         var req = new Request(FETCH_NON_CAT_TYPES, G.user.home_ou());
1405         req.callback(myOPACDrawNonCatCircs2);
1406         req.send();
1407 }
1408
1409
1410 /* now we have circs and the types.. draw each one */
1411 var nonCatTbody;
1412 var nonCatRow;
1413 function myOPACDrawNonCatCircs2(r) {
1414         nonCatTypes = r.getResultObject();
1415         nonCatTbody = $('non_cat_circs_tbody');
1416         if(!nonCatRow) nonCatRow = 
1417                 nonCatTbody.removeChild($('non_cat_circs_row'));
1418         removeChildren(nonCatTbody);
1419         for( var i in nonCatCircIds ) {
1420                 var req = new Request(FETCH_NON_CAT_CIRC, G.user.session, nonCatCircIds[i]);
1421                 req.callback(myOPACDrawNonCatCirc);
1422                 req.send();
1423         }
1424 }
1425
1426
1427 /* draw a single circ */
1428 function myOPACDrawNonCatCirc(r) {
1429         var circ = r.getResultObject();
1430
1431
1432         var type = grep(nonCatTypes, 
1433                 function(i){
1434                         return (i.id() == circ.item_type());
1435                 }
1436         )[0];
1437
1438
1439         var row = nonCatTbody.appendChild(nonCatRow.cloneNode(true));
1440         appendClear($n(row, 'circ_lib'), text(findOrgUnit(circ.circ_lib()).name()));
1441         appendClear($n(row, 'item_type'), text(type.name()));
1442
1443         appendClear(
1444         $n(row, 'circ_time'), 
1445         text(dojo.date.locale.format(
1446             dojo.date.stamp.fromISOString(circ.duedate()),
1447             {format : 'short'}
1448         ))
1449     );
1450 }
1451
1452
1453
1454
1455 function myopacSelectAllChecked() {
1456    __myopacSelectChecked(true);
1457 }
1458
1459 function myopacSelectNoneChecked() {
1460    __myopacSelectChecked(false);
1461 }
1462
1463 function __myopacSelectChecked(value) {
1464    var rows = myopacGetCheckedOutRows();
1465    for( var i = 0; i < rows.length; i++ ) {
1466       var row = rows[i];
1467       var box = $n(row, 'selectme');
1468       if( box && ! box.disabled )
1469       box.checked = value;
1470    }
1471 }
1472
1473 function myopacGetCheckedOutRows() {
1474    var rows = [];
1475    var tbody = $('myopac_checked_tbody');
1476    var children = tbody.childNodes;
1477    for( var i = 0; i < children.length; i++ ) {
1478       var child = children[i];
1479       if( child.nodeName.match(/^tr$/i) ) 
1480          if( $n(child, 'selectme') ) 
1481             rows.push(child);
1482    }
1483    return rows;
1484 }
1485
1486 var __renew_circs = [];
1487
1488 /* true if 1 renewal succeeded */
1489 var __success_count = 0;
1490
1491 /* renews all selected circulations */
1492 function myOPACRenewSelected() {
1493    var rows = myopacGetCheckedOutRows();
1494         if(!confirm($('myopac_renew_confirm').innerHTML)) return;
1495    __success_count = 0;
1496
1497    for( var i = 0; i < rows.length; i++ ) {
1498
1499       var row = rows[i];
1500       if( ! $n(row, 'selectme').checked ) continue;
1501       var circ_id = row.getAttribute('circid');
1502
1503            var circ;
1504            for( var j = 0; j != circsCache.length; j++ ) 
1505                    if(circsCache[j].id() == circ_id)
1506                            circ = circsCache[j];
1507
1508       __renew_circs.push(circ);
1509    }
1510
1511     if( __renew_circs.length == 0 ) return;
1512
1513     unHideMe($('my_renewing'));
1514     moClearCheckedTable();
1515
1516     for( var i = 0; i < __renew_circs.length; i++ ) {
1517         var circ = __renew_circs[i];
1518         moRenewCirc( circ.target_copy(), G.user.id(), circ );
1519     }
1520 }
1521
1522
1523 /* renews a single circulation */
1524 function moRenewCirc(copy_id, user_id, circ) {
1525
1526    _debug('renewing circ ' + circ.id() + ' with copy ' + copy_id);
1527    var req = new Request(RENEW_CIRC, G.user.session, 
1528       {  patron : user_id, 
1529          copyid : copy_id, 
1530          opac_renewal : 1 
1531       } 
1532    );
1533
1534    req.request.alertEvent = false;
1535    req.callback(myHandleRenewResponse);
1536    req.request.circ = circ;
1537    req.send();
1538 }
1539
1540
1541
1542 /* handles the circ renew results */
1543 function myHandleRenewResponse(r) {
1544    var res = r.getResultObject();
1545    var circ = r.circ;
1546
1547    /* remove this circ from the list of circs to renew */
1548    __renew_circs = grep(__renew_circs, function(i) { return (i.id() != circ.id()); });
1549
1550    _debug("handling renew result for " + circ.id());
1551
1552    if(checkILSEvent(res) || checkILSEvent(res[0])) 
1553       alertIdText('myopac_renew_fail', __circ_titles[circ.id()]);
1554    else __success_count++;
1555
1556    if(__renew_circs) return; /* more to come */
1557
1558    __renew_circs = [];
1559
1560         if( __success_count > 0 )
1561       alertIdText('myopac_renew_success', __success_count);
1562
1563    hideMe($('my_renewing'));
1564    checkedDrawn = false;
1565     myOPACShowChecked();
1566 }
1567
1568 /** ---- batch hold processing ------------ */
1569
1570
1571 /* myopac_holds_checkbx */
1572 function myopacSelectAllHolds() {
1573     var rows = getTableRows($("myopac_holds_tbody"));
1574     for(var i = 0; i < rows.length; i++) {
1575         cb = $n(rows[i], 'myopac_holds_selected_chkbx');
1576         if(cb) cb.checked = true;
1577     }
1578 }
1579
1580 function myopacSelectNoneHolds() {
1581     var rows = getTableRows($("myopac_holds_tbody"));
1582     for(var i = 0; i < rows.length; i++) {
1583         cb = $n(rows[i], 'myopac_holds_selected_chkbx');
1584         if(cb) cb.checked = false;
1585     }
1586 }
1587
1588 function myopacSelectedHoldsRows() {
1589     var r = [];
1590     var rows = getTableRows($("myopac_holds_tbody"));
1591     for(var i = 0; i < rows.length; i++) {
1592         cb = $n(rows[i], 'myopac_holds_selected_chkbx');
1593         if(cb && cb.checked)
1594             r.push(rows[i]);
1595     }
1596     return r;
1597 }
1598
1599 var myopacProcessedHolds = 0;
1600 var myopacHoldsToProcess = 0;
1601 function myopacDoHoldAction() {
1602
1603     var selectedRows = myopacSelectedHoldsRows();
1604     action = getSelectorVal($('myopac_holds_actions'));
1605     $('myopac_holds_actions_none').selected = true;
1606     if(selectedRows.length == 0) return;
1607
1608     myopacProcessedHolds = 0;
1609
1610     if(!confirmId('myopac.holds.'+action+'.confirm')) return;
1611     myopacSelectNoneHolds(); /* clear the selection */
1612
1613
1614     /* first, let's collect the holds that actually need processing and
1615         collect the full process count while we're at it */
1616     var holds = [];
1617     for(var i = 0; i < selectedRows.length; i++) {
1618         hold = holdCache[myopacHoldIDFromRow(selectedRows[i])];
1619         var qstats = holdStatusCache[hold.id()];
1620         switch(action) {
1621             case 'cancel':
1622                 holds.push(hold);
1623                 break;
1624             case 'thaw_date':
1625             case 'thaw':
1626                 if(isTrue(hold.frozen()))
1627                     holds.push(hold);
1628                 break;
1629             case 'freeze':
1630                 if(!isTrue(hold.frozen()) && qstats.status < 3)
1631                     holds.push(hold);
1632                 break;
1633         }
1634     }
1635     myopacHoldsToProcess = holds;
1636     if(myopacHoldsToProcess.length == 0) return;
1637
1638     if(action == 'thaw_date' || action == 'freeze') 
1639         myopacDrawHoldThawDateForm();
1640     else
1641     myopacProcessHolds(action);
1642 }
1643
1644
1645 function myopacProcessHolds(action, thawDate) {
1646
1647     myopacShowHoldProcessing();
1648     /* now we process them */
1649     for(var i = 0; i < myopacHoldsToProcess.length; i++) {
1650
1651         hold = myopacHoldsToProcess[i];
1652         
1653         var req;
1654         switch(action) { 
1655
1656             case 'cancel':
1657                 req = new Request(CANCEL_HOLD, G.user.session, hold.id());
1658                 break;
1659     
1660             case 'thaw':
1661                 hold.frozen('f');
1662                 hold.thaw_date(null);
1663                 req = new Request(UPDATE_HOLD, G.user.session, hold);
1664                 break;
1665
1666             case 'thaw_date':
1667             case 'freeze':
1668                 hold.frozen('t');
1669                 hold.thaw_date(thawDate); 
1670                 req = new Request(UPDATE_HOLD, G.user.session, hold);
1671                 break;
1672                 //thawDate = prompt($('myopac.holds.freeze.select_thaw').innerHTML);
1673
1674         }
1675
1676         req.callback(myopacBatchHoldCallback);
1677         req.send();
1678         req = null;
1679     }
1680 }
1681
1682 function myopacDrawHoldThawDateForm() {
1683     hideMe($('myopac_holds_main_table'));
1684     unHideMe($('myopac_holds_thaw_date_form'));
1685     $('myopac_holds_thaw_date_input').focus();
1686 }
1687
1688 function myopacApplyThawDate() {
1689     var dateString = dijit.byId('myopac_holds_thaw_date_input').getValue();
1690     if(dateString) {
1691         dateString = dojo.date.stamp.toISOString(dateString);
1692         if(dateString) {
1693             dateString = holdsVerifyThawDate(dateString);
1694             if(!dateString) return;
1695         } else {
1696             dateString = null;
1697         }
1698     }
1699     myopacProcessHolds('freeze', dateString);
1700 }
1701
1702 function myopacHoldIDFromRow(row) {
1703     return row.id.replace(/.*_(\d+)$/, '$1');
1704 }
1705
1706 function myopacShowHoldProcessing() {
1707     unHideMe($('myopac_holds_processing'));
1708     hideMe($('myopac_holds_main_table'));
1709 }
1710
1711 function myopacHideHoldProcessing() {
1712     hideMe($('myopac_holds_processing'));
1713     unHideMe($('myopac_holds_main_table'));
1714     hideMe($('myopac_holds_thaw_date_form'));
1715 }
1716
1717 function myopacBatchHoldCallback(r) {
1718     if(r) /* force load any exceptions */
1719         r.getResultObject();
1720     if(++myopacProcessedHolds >= myopacHoldsToProcess.length) {
1721         myopacHideHoldProcessing();
1722         holdCache = {};
1723         holdStatusCache = {};
1724         myopacForceHoldsRedraw = true;
1725         myOPACShowHolds();
1726     }
1727 }
1728