repair place-hold-takes-you-to-login feature that got mangled in one of the updates
[evergreen-equinox.git] / Open-ILS / web / opac / skin / kcls / js / holds.js
1 var holdsOrgSelectorBuilt = false;
2 var holdArgs;
3
4 /* 
5 note: metarecord holds have a holdable_formats field that contains
6 item_type(s)-item_forms(s)-language
7 item_form and language are optional - if language exist and no 
8 item_form is specified, use item_type(s)--language
9 */
10
11 var noEmailMessage;
12 var noEmailMessageXUL;
13
14 function hideResultsPage(bool) {
15         if(!bool) {
16                 unHideMe($('result_header'));
17                 unHideMe($('tehSideBar'));
18                 unHideMe($('facetSidebarContainer'));
19                 unHideMe($('sidebar_div'));
20                 unHideMe($('statusbar'));
21                 unHideMe($('tips'));
22                 unHideMe($('result_table_div'));
23                 unHideMe($('results_header_nav1'));
24                 unHideMe($('result_info_2'));
25                 unHideMe($('results_header_bar'));
26         } else {
27                 hideMe($('result_header'));
28                 hideMe($('tehSideBar'));
29                 hideMe($('facetSidebarContainer'));
30                 hideMe($('sidebar_div'));
31                 hideMe($('statusbar'));
32                 hideMe($('tips'));
33                 hideMe($('result_table_div'));
34                 hideMe($('anonListTable'));
35                 hideMe($('results_header_nav1'));
36                 hideMe($('result_info_2'));
37                 hideMe($('results_header_bar'));
38         }
39 }
40
41 function holdsHandleStaff() {
42
43     // if we know the recipient's barcode, use it
44     if(xulG.patron_barcode) return _holdsHandleStaff();
45
46         swapCanvas($('xulholds_box'));
47         $('xul_recipient_barcode').focus();
48         $('xul_recipient_barcode').onkeypress = function(evt) 
49                 {if(userPressedEnter(evt)) { _holdsHandleStaff(); } };
50         $('xul_recipient_barcode_submit').onclick = _holdsHandleStaff;
51         $('xul_recipient_me').onclick = _holdsHandleStaffMe;
52
53         $('xul_recipient_barcode').onkeyup = function(evt) {
54         if($('xul_recipient_barcode').value == '') 
55             $('xul_recipient_me').disabled = false;
56         else
57             $('xul_recipient_me').disabled = true;
58     };
59 }
60
61 attachEvt(
62     "common", "init", function() {
63         $('holds_frozen_thaw_input').onchange =
64             function(){holdsVerifyThawDateUI('holds_frozen_thaw_input');}
65         $('holds_frozen_thaw_input').onkeyup =
66             function(){holdsVerifyThawDateUI('holds_frozen_thaw_input');}
67     }
68 );
69
70 function _holdsHandleStaffMe() {
71         holdArgs.recipient = G.user;
72         holdsDrawEditor();
73 }
74
75 function _holdsHandleStaff() {
76         var barcode = xulG.patron_barcode || $('xul_recipient_barcode').value;
77         var user = grabUserByBarcode( G.user.session, barcode );
78
79         var evt;
80         if(evt = checkILSEvent(user)) {
81                 alertILSEvent(user);
82                 return;
83         }
84
85         if(!barcode || !user) {
86                 alertId('holds_invalid_recipient', barcode);
87                 return
88         }
89
90         grabUserPrefs(user);
91
92         holdArgs.recipient = user;
93         holdsDrawEditor();
94 }
95
96
97
98 /** args:
99   * record, volume, copy (ids)
100   * request, recipient, editHold (objects)
101   */
102
103 function holdsDrawEditor(args) {
104         holdArgs = (args) ? args : holdArgs;
105
106     if(!noEmailMessage) noEmailMessage = $('holds_email').removeChild($('holds.no_email'));
107     if(!noEmailMessageXUL) noEmailMessageXUL = $('holds_email').removeChild($('holds.no_email.xul'));
108
109         if(isXUL() && holdArgs.recipient == null && holdArgs.editHold == null) {
110                 holdsHandleStaff();
111                 return;
112         }
113
114         if(!holdArgs.recipient) holdArgs.recipient = G.user;
115         if(!holdArgs.requestor) holdArgs.requestor = G.user;
116
117         if(!(holdArgs.requestor && holdArgs.requestor.session)) {
118                 /*
119                 alert("Please login first before placing a hold");
120                 setCacheValue('returnURL',{href:window.location.href, record:holdArgs.record, type:holdArgs.type});
121                 goTo(buildOPACLink({page:MYOPAC}, false, true));
122                 return;
123                 */
124                 detachAllEvt('common','locationChanged');
125                 attachEvt('common','loggedIn', holdsDrawEditor);
126                 initLogin();
127                 return;
128         }
129 // flesh the args with the existing hold 
130         if(holdArgs.editHold) holdArgsFromHold(holdArgs.editHold, holdArgs);
131
132         hideResultsPage(true);
133         holdsDrawWindow();
134 }
135
136
137 // updates the edit window with the existing hold's data 
138 function _holdsUpdateEditHold() {
139
140         var hold = holdArgs.editHold;
141         var qstats = holdArgs.status;
142
143         var orgsel = $('holds_org_selector');
144     var frozenbox = $('holds_frozen_chkbox');
145
146         setSelector(orgsel, hold.pickup_lib());
147
148         if( hold.capture_time() || qstats.status > 2 ) {
149         frozenbox.disabled = true;
150         $('holds_frozen_thaw_input').disabled = true;
151         if(qstats.status == 3) {
152             // no pickup lib changes while in-transit
153                     orgsel.disabled = true;
154         } else {
155             var orgs = fetchPermOrgs('UPDATE_PICKUP_LIB_FROM_HOLDS_SHELF');
156             if(orgs[0] == -1)
157                         orgsel.disabled = true;
158         }
159     } else {
160                 orgsel.disabled = false;
161         frozenbox.disabled = false;
162     }
163
164
165         $('holds_submit').onclick = holdsEditHold;
166         $('holds_update').onclick = holdsEditHold;
167
168         if(hold.phone_notify()) {
169                 $('holds_enable_phone').checked = true;
170                 $('holds_phone').value = hold.phone_notify();
171
172         } else {
173                 $('holds_phone').disabled = true;
174                 $('holds_enable_phone').checked = false;
175         }
176
177         if(isTrue(hold.email_notify())) {
178                 $('holds_enable_email').checked = true;
179
180         } else {
181                 $('holds_enable_email').checked = false;
182         }
183
184     //$('holds_expire_time').setValue(dojo.date.stamp.fromISOString(hold.expire_time()));
185
186     /* populate the hold freezing info */
187     if(!frozenbox.disabled && isTrue(hold.frozen())) {
188         frozenbox.checked = true;
189         unHideMe($('hold_frozen_thaw_row'));
190         if(hold.thaw_date()) {
191             $('holds_frozen_thaw_input').value=dojo.date.stamp.fromISOString(hold.thaw_date());
192         } else {
193             $('holds_frozen_thaw_input').value='';
194         }
195     } else {
196         frozenbox.checked = false;
197         $('holds_frozen_thaw_input').value='';
198         hideMe($('hold_frozen_thaw_row'));
199     }
200 }
201
202 function holdsEditHold() {
203         var hold = holdsBuildHoldFromWindow();
204         if(!hold) return;
205         holdsUpdate(hold);
206         showCanvas();
207         if(holdArgs.onComplete)
208                 holdArgs.onComplete(hold);
209 }
210
211 function holdArgsFromHold(hold, oargs) {
212         var args = (oargs) ? oargs : {};
213         args.type = hold.hold_type();
214         var target = hold.target();
215
216         switch(args.type) {
217                 case 'M':
218                         args.metarecord = target;
219                         break;
220                 case 'T':
221                         args.record = target;
222                         break;
223                 case 'V':
224                         args.volume = target;
225                         break;
226                 case 'C':
227                         args.copy = target;
228                         break;
229         }
230         return args;
231 }
232
233 function holdFetchObjects(hold, doneCallback) {
234         var args = (hold) ? holdArgsFromHold(hold) : holdArgs;
235         var type = args.type;
236
237         if( type == 'C' ) {
238                 if( args.copyObject ) {
239
240                         args.copy = args.copyObject.id();
241                         args.volume = args.copyObject.call_number();
242                         _h_set_vol(args, doneCallback);
243
244                 } else {
245                         var creq = new Request(FETCH_COPY, args.copy);
246
247                         creq.callback(
248                                 function(r) {
249                                         var cp = r.getResultObject();
250                                         args.copyObject = cp;
251                                         args.volume = args.copyObject.call_number();
252                                         _h_set_vol(args, doneCallback);
253                                 }
254                         );
255                         creq.send();
256                 }
257         } else {
258                 if( type == 'V' ) {
259                         _h_set_vol(args, doneCallback);
260
261                 } else {
262                         if( type == 'T' ) {
263                                 _h_set_rec(args, doneCallback);
264                         } else {
265                                 _h_set_rec_descriptors(args, doneCallback);
266                         }
267                 }
268         }
269
270         return args;
271 }
272
273 function _h_set_vol(args, doneCallback) {
274
275         if( args.volumeObject ) {
276                 args.volume = args.volumeObject.id();
277                 args.record = args.volumeObject.record();
278                 _h_set_rec(args, doneCallback);
279
280         } else {
281
282                 var vreq = new Request(FETCH_VOLUME, args.volume);
283                 vreq.callback(
284                         function(r) {
285                                 var vol = r.getResultObject();
286                                 args.volumeObject = vol;
287                                 args.record = vol.record();
288                                 _h_set_rec(args, doneCallback);
289                         }
290                 );
291                 vreq.send();
292         }
293 }
294
295 function _h_set_rec(args, doneCallback) {
296
297         if(args.recordObject) 
298                 args.record = args.recordObject.doc_id();
299         else 
300                 args.recordObject = findRecord( args.record, 'T' );
301         
302         if( args.type == 'T' || args.type == 'M' ) 
303                 _h_set_rec_descriptors(args, doneCallback);
304         else 
305                 if(doneCallback) doneCallback(args);
306 }
307
308
309 function _h_set_rec_descriptors(args, doneCallback) {
310
311         // grab the list of record desciptors attached to this records metarecord 
312         if( ! args.recordDescriptors )  {
313                 var params = { record: args.record };
314
315                 if( ! args.record ) {
316                         if( args.metarecord )
317                                 params = { metarecord : args.metarecord };
318                         else 
319                                 params = { metarecord : args.metarecordObject.doc_id() };
320                 }
321
322                 var req = new Request(FETCH_MR_DESCRIPTORS, params );
323                 req.callback(
324                         function(r) {
325                                 var data = r.getResultObject();
326                                 args.recordDescriptors = data.descriptors;
327                                 args.metarecord = data.metarecord;
328                                 if( args.type == 'M' && ! args.metarecordObject) 
329                                         args.metarecordObject = findRecord(args.metarecord, 'M');       
330                                  
331                                 if(doneCallback) doneCallback(args);
332                         }
333                 );
334                 req.send();
335
336         } else {
337                 if(doneCallback) doneCallback(args);
338         }
339
340         return args;
341 }
342
343
344
345 function holdsDrawWindow(bool) {
346         swapCanvas($('holds_box'));
347         $('holds_cancel').onclick = function(){
348                 hideResultsPage(false);
349                 hideMe($('holds_box'));
350                 unHideMe($('canvas_main'));
351                 //runEvt('common', 'holdUpdateCanceled'), showCanvas() 
352                 runEvt('common', 'holdUpdateCanceled');
353         };
354         $('holds_submit').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};
355         $('holds_update').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};
356         holdFetchObjects(null, 
357                 function(){
358                         __holdsDrawWindow();
359
360                         if(holdArgs.editHold) {
361                                 //hideMe($('holds_submit'));
362                                 unHideMe($('holds_update'));
363                                 var req = new Request(FETCH_HOLD_STATUS, 
364                                         G.user.session, holdArgs.editHold.id());
365                                 req.send(true);
366                                 holdArgs.status = req.result();
367                                 _holdsUpdateEditHold();
368                         }  
369                 }
370         );
371 }
372
373 function selOrgChange(e) {
374         
375         $('holds_pickup_lib').innerHTML = this.options[this.selectedIndex].text;
376 }
377
378 function __holdsDrawWindow() {
379
380         var rec = holdArgs.recordObject;
381         var vol = holdArgs.volumeObject;
382         var copy = holdArgs.copyObject;
383         var mr = holdArgs.metarecordObject;
384
385         rec = (rec) ? rec : mr;
386
387         if(!holdsOrgSelectorBuilt) {
388                 holdsBuildOrgSelector(null,0);
389                 holdsOrgSelectorBuilt = true;
390                 var selector = $('holds_org_selector');
391
392                 /*
393                 var o_loc = findOrgUnit(getOrigLocation());
394                 var t = findOrgType(o_loc.ou_type());
395                 if( t.can_have_users() ) 
396                         setSelector(selector, o_loc.id());
397                 else 
398                 */
399                 selector.onchange = selOrgChange;
400                 setSelector(selector, holdArgs.recipient.home_ou());
401         }
402         
403         var obj = findOrgUnit(holdArgs.recipient.home_ou());
404         $('holds_pickup_lib').innerHTML = obj.name();
405
406         /*
407         if(isXUL()) {
408                 var dsel = $('holds_depth_selector');
409                 unHideMe($('holds_depth_selector_row'));
410                 if(dsel.getElementsByTagName('option').length == 0) {
411                         var types = globalOrgTypes;
412                         var depth = findOrgDepth(G.user.ws_ou());
413                         iterate(types, 
414                                 function(t) {
415                                         if(t.depth() > depth) return;
416                                         insertSelectorVal(dsel, -1, t.opac_label(), t.depth());
417                                 }
418                         );
419                 }
420         }
421         */
422
423         appendClear($('holds_recipient'), text(
424                 holdArgs.recipient.family_name() + ', ' +  
425                         holdArgs.recipient.first_given_name()));
426         appendClear($('holds_title'), text(rec.title()));
427         appendClear($('holds_author'), text(rec.author()));
428
429         if( holdArgs.type == 'V' || holdArgs.type == 'C' ) {
430
431                 unHideMe($('holds_type_row'));
432                 unHideMe($('holds_cn_row'));
433                 appendClear($('holds_cn'), text(holdArgs.volumeObject.label()));
434
435                 if( holdArgs.type == 'V'  ) {
436                         unHideMe($('holds_is_cn'));
437                         hideMe($('holds_is_copy'));
438
439                 } else {
440                         hideMe($('holds_is_cn'));
441                         unHideMe($('holds_is_copy'));
442                         unHideMe($('holds_copy_row'));
443                         appendClear($('holds_copy'), text(holdArgs.copyObject.barcode()));
444                 }
445
446         } else {
447                 hideMe($('holds_type_row'));
448                 hideMe($('holds_copy_row'));
449                 hideMe($('holds_cn_row'));
450         }
451
452         removeChildren($('holds_format'));
453
454         var mods_formats = rec.types_of_resource();
455         var formats;
456
457         if(holdArgs.recordDescriptors)
458                 formats = holdArgs.recordDescriptors[0].item_type();
459
460         if( holdArgs.type == 'T' ) {
461                 var desc = grep( holdArgs.recordDescriptors,
462                         function(i) {
463                                 return (i.record() == holdArgs.record); 
464                         }
465                 );
466                 formats = desc[0].item_type();
467         }
468
469         if( holdArgs.type == 'M' ) {
470                 var data = holdsParseMRFormats(holdArgs.editHold.holdable_formats());
471                 mods_formats = data.mods_formats;
472                 formats = data.formats;
473         }
474
475
476         for( var i in mods_formats ) {
477                 var res = mods_formats[i];
478                 var img = elem("img");
479                 setResourcePic(img, res);
480                 $('holds_format').appendChild(img);
481                 if(formats)
482                         $('holds_format').appendChild(text(' '+ MARCTypeToFriendly(formats[i]) +' '));
483                 else
484                         $('holds_format').appendChild(text(' '+ mods_formats[i] +' '));
485                 $('holds_format').appendChild(elem('br'));
486         }
487
488
489         $('holds_phone').value = (holdArgs.recipient.day_phone())?holdArgs.recipient.day_phone():"";
490         appendClear( $('holds_email'), text(holdArgs.recipient.email()));
491
492         var pref = holdArgs.recipient.prefs[PREF_HOLD_NOTIFY];
493
494         if(pref) {
495                 if( ! pref.match(/email/i) ) {
496                         $('holds_enable_email').checked = false;
497                 } else {
498                         $('holds_enable_email').checked = true;
499                 }
500
501                 if( ! pref.match(/phone/i) ) {
502                         $('holds_phone').disabled = true;
503                         $('holds_enable_phone').checked = false;
504                 } else {
505                         $('holds_phone').disabled = false;
506                         $('holds_enable_phone').checked = true;
507                 }
508         }
509
510     if(!holdArgs.recipient.email()) {
511                 $('holds_enable_email').checked = false;        
512                 $('holds_enable_email').disabled = true;
513         var message;
514         if(isXUL()) {
515             message = noEmailMessageXUL.cloneNode(true);
516                 appendClear($('holds_email'), message);
517         } else {
518             message = noEmailMessage.cloneNode(true);
519                 appendClear($('holds_email'), message);
520             $('holds.no_email.my_account').setAttribute('href', buildOPACLink({page:MYOPAC},null,true));
521         }
522         unHideMe(message);
523     }
524
525         if(!$('holds_phone').value) 
526                 $('holds_enable_phone').checked = false;        
527
528         appendClear($('holds_physical_desc'), text(rec.physical_description()));
529
530         if(holdArgs.type == 'M') hideMe($('hold_physical_desc_row'));
531
532         holdsSetFormatSelector();
533
534     $('holds_frozen_chkbox').checked = false;
535     hideMe($('hold_frozen_thaw_row'));
536
537     var interval = fetchOrgSettingDefault(holdArgs.recipient.home_ou(), 'circ.hold_expire_interval');
538     var secs = 0;
539     if(interval) {
540         secs = interval_to_seconds(interval);
541         var expire = new Date();
542         expire.setTime(expire.getTime() + Number(secs + '000'));
543         if(dijit.byId('holds_expire_time')) dijit.byId('holds_expire_time').setValue(expire);
544     }
545 }
546
547 function holdsParseMRFormats(str) {
548         var data = str.split(/-/);      
549
550         var formats = [];
551         var mods_formats = [];
552
553         for( var i = 0; i < data[0].length; i++ ) {
554                 formats.push( data[0].charAt(i) );
555                 mods_formats.push( MARCFormatToMods( formats[i] ) );
556         }
557         
558         formats = uniquify(formats);
559         mods_formats = uniquify(mods_formats);
560
561         return {
562                 formats                 : formats,
563                 mods_formats    : mods_formats,
564                 lang                            : data[2],
565                 largeprint              : data[1]
566         };
567 }
568
569
570 function holdsSetFormatSelector() {
571         var type = holdArgs.type;
572         if( type == 'C' || type == 'V' || holdArgs.editHold ) return;
573
574         var data                                = holdsGetFormats();
575         var avail_formats       = data.avail_formats;
576         var sel_formats = data.sel_formats;
577         holdArgs.language = data.lang;
578
579         unHideMe($('holds_alt_formats_row_extras'));
580         var selector = $('hold_alt_form_selector');
581
582         for( var i = 0; i < avail_formats.length; i++ ) {
583                 var form = avail_formats[i];
584                 unHideMe(findSelectorOptByValue(selector, form));
585         }
586 }
587
588
589 function holdsGetFormats() {
590
591         var lang;
592         var formats = [];
593         var sformats = []; // selected formats 
594
595         var type = holdArgs.type;
596         var desc = holdArgs.recordDescriptors;
597         var rec = holdArgs.record;
598         var mrec = holdArgs.metarecord;
599
600         if( type == 'T' ) {
601
602                 for( var i = 0; i < desc.length; i++ ) {
603                         var d = desc[i];
604                         if( d.record() == holdArgs.record ) {
605                                 lang = d.item_lang();
606                                 holdArgs.myFormat =  _t_f_2_format(d.item_type(), d.item_form());
607                                 sformats.push(holdArgs.myFormat);
608                                 break;
609                         }
610                 }
611         }
612
613         for( var i = 0; i < desc.length; i++ ) {
614                 var d = desc[i];
615                 if( d.item_lang() != lang ) continue;
616                 formats.push( _t_f_2_format(d.item_type(), d.item_form()));
617         }
618
619         formats = uniquify(formats);
620
621         return {
622                 lang : lang,
623                 avail_formats : formats, 
624                 sel_formats : sformats
625         };
626 }
627
628
629
630 function _t_f_2_format(type, form) {
631         if( form == 'd' ) return 'at-d';
632         return (type == 'a' || type == 't') ? 'at' : 
633                 ( type == 'i' || type == 'g' || type == 'j' ) ? type : null;
634 }
635
636 function holdsSetSelectedFormats() {
637
638         var cn = $('holds_alt_formats_row').className;
639         if( cn && cn.match(/hide_me/) ) return;
640
641         var selector = $('hold_alt_form_selector');
642         var vals = getSelectedList(selector);
643
644         if(vals.length == 0) return;
645
646         var fstring = "";
647
648         if( contains(vals, 'at-d') ) {
649                 if( contains(vals, 'at') )
650                         fstring = 'at';
651                 else 
652                         fstring = 'at-d';
653         } else {
654                 if( contains(vals, 'at') )
655                         fstring = 'at';
656         }
657
658         for( var i = 0; i < vals.length; i++ ) {
659                 var val = vals[i];
660                 if( !val.match(/at/) ) fstring = val + fstring;
661         }
662
663         if( holdArgs.language ) {
664                 if( fstring.match(/-/) )
665                         fstring = fstring + '-' + holdArgs.language;
666                 else
667                         fstring = fstring + '--' + holdArgs.language;
668         }
669         return fstring;
670 }
671
672
673 function holdsCheckPossibility(pickuplib, hold, recurse) {
674
675         var args = { 
676                 titleid : holdArgs.record,
677                 volume_id : holdArgs.volume,
678                 copy_id : holdArgs.copy,
679                 hold_type : holdArgs.type,
680                 patronid : holdArgs.recipient.id(),
681                 depth : 0, 
682                 pickup_lib : pickuplib 
683         };
684
685         if(recurse) {
686                 /* if we're calling create again (recursing), 
687                         we know that the hold possibility check already succeeded */
688                 holdHandleCreateResponse({_recurse:true, _hold:hold}, true );
689
690         } else {
691                 _debug("hold possible args = "+js2JSON(args));
692         
693                 var req = new Request(CHECK_HOLD_POSSIBLE, G.user.session, args );
694         
695                 req.request.alertEvent = false;
696                 req.request._hold = hold;
697                 req.request._recurse = recurse;
698                 req.callback(holdHandleCreateResponse);
699                 req.send();
700         }
701 }
702
703
704 function holdsBuildOrgSelector(node, sel) {
705
706         if(!node) node = globalOrgTree;
707     if(!isTrue(node.opac_visible())) return;
708
709         var selector = sel?sel:$('holds_org_selector');
710         var index = selector.options.length;
711
712         var type = findOrgType(node.ou_type());
713         var indent = type.depth() - 1;
714         var opt = setSelectorVal( selector, index, node.name(), node.id(), null, indent );
715         if(!type.can_have_users()) {
716                 opt.disabled = true;
717                 addCSSClass(opt, 'disabled_option');
718         }
719         
720         for( var i in node.children() ) {
721                 var child = node.children()[i];
722                 if(child) holdsBuildOrgSelector(child);
723         }
724 }
725
726 function holdsBuildHoldFromWindow() {
727
728         var org = getSelectorVal($('holds_org_selector'));
729         var node = findOrgUnit(org);
730         var ntype = findOrgType(node.ou_type());
731         if(!ntype.can_have_users()) {
732                 alertId('holds_pick_good_org');
733                 return;
734         }
735
736         var hold = new ahr();
737         if(holdArgs.editHold) {
738                 hold = holdArgs.editHold;
739                 holdArgs.editHold = null;
740         }
741
742         if( $('holds_enable_phone').checked ) {
743                 var phone = $('holds_phone').value;
744                 if( !phone || !phone.match(REGEX_PHONE) ) {
745                         alert($('holds_bad_phone').innerHTML);
746                         return null;
747                 }
748                 hold.phone_notify(phone);
749
750         } else {
751                 hold.phone_notify("");
752         }
753
754         if( $('holds_enable_email').checked ) 
755                 hold.email_notify(1);
756         else
757                 hold.email_notify(0);
758
759         var target;
760
761         switch(holdArgs.type) {
762                 case 'M':
763                         target = holdArgs.metarecord; break;
764                 case 'T':
765                         target = holdArgs.record; break;
766                 case 'V':
767                         target = holdArgs.volume; break;
768                 case 'C':
769                         target = holdArgs.copy; break;
770         }
771
772
773
774         hold.pickup_lib(org); 
775         //hold.request_lib(org); 
776         hold.requestor(holdArgs.requestor.id());
777         hold.usr(holdArgs.recipient.id());
778         hold.target(target);
779         hold.hold_type(holdArgs.type);
780
781     try{var expDate = dijit.byId('holds_expire_time').getValue();} catch(e){}
782     if(expDate) {
783         var expireDate = dojo.date.stamp.toISOString(expDate);
784         expireDate = holdsVerifyThawDate(expireDate); 
785         if(expireDate)
786             hold.expire_time(expireDate);
787         else 
788             return;
789     }
790
791     // see if this hold should be frozen and for how long
792     if($('holds_frozen_chkbox').checked) {
793         hold.frozen('t');
794         unHideMe($('hold_frozen_thaw_row'));
795         thawDate = dojo.date.stamp.toISOString(dijit.byId('holds_frozen_thaw_input').getValue());
796         if(thawDate) {
797             thawDate = holdsVerifyThawDate(thawDate); 
798             if(thawDate) 
799                 hold.thaw_date(thawDate);
800             else
801                 return;
802         } else {
803             hold.thaw_date(null);
804         }
805     } else {
806         hold.frozen('f');
807         hold.thaw_date(null);
808     }
809
810         //check for alternate hold formats 
811         var fstring = holdsSetSelectedFormats();
812         if(fstring) { 
813                 hold.hold_type('M'); 
814                 hold.holdable_formats(fstring);
815                 hold.target(holdArgs.metarecord);
816         }
817         return hold;
818 }
819         
820 function holdsPlaceHold(hold, recurse) {
821         if(!hold) return;
822         swapCanvas($('check_holds_box'));
823         holdsCheckPossibility(hold.pickup_lib(), hold, recurse);
824 }
825
826
827 function holdHandleCreateResponse(r, recurse) {
828
829         if(!recurse) {
830                 var res = r.getResultObject();
831                 if(checkILSEvent(res) || res.success != 1) {
832                         if(res.success != 1) {
833                                 alert($('hold_not_allowed').innerHTML+(!res.last_event.desc?"":"\n\nHold failure description:\n"+res.last_event.desc));
834                         } else {
835                                 if( res.textcode == 'PATRON_BARRED' ) {
836                                         alertId('hold_failed_patron_barred');
837                                 } else {
838                                         alert($('hold_not_allowed').innerHTML+(!res.last_event.desc?"":"\n\nHold failure description:\n"+res.last_event.desc));
839                                 }
840                         }
841                         swapCanvas($('holds_box'));
842                         return;
843                 }
844         r._hold.selection_depth(res.depth);
845         }       
846
847         holdCreateHold(r._recurse, r._hold);
848         hideResultsPage(false);
849 }
850
851
852 function holdCreateHold( recurse, hold ) {
853         var method = CREATE_HOLD;
854         if(recurse) method = CREATE_HOLD_OVERRIDE;
855         var req = new Request( method, holdArgs.requestor.session, hold );
856         req.request.alertEvent = false;
857         req.send(true);
858         var res = req.result();
859         holdProcessResult(hold, res, recurse);
860
861         showCanvas();
862
863         runEvt('common', 'holdUpdated');
864 }
865
866
867 function holdProcessResult( hold, res, recurse ) {
868
869         if( res && res > -1 ) {
870                 alert($('holds_success').innerHTML);
871                 holdArgs = null;
872         if(isXUL() && typeof xulG.opac_hold_placed == 'function')
873             xulG.opac_hold_placed(res);
874
875         } else {
876
877                 if( recurse ) {
878                         alert($('holds_failure').innerHTML);
879                         return;
880                 }
881
882                 if( grep(res, function(e) { return (e.textcode == 'HOLD_EXISTS'); }) ) {
883                         if( fetchPermOrgs('HOLD_EXISTS.override')[0] != -1 ) {
884                                 if( confirm($('hold_dup_exists_override').innerHTML) ) {
885                                         return holdsPlaceHold(hold, true);
886                                 }
887                 return;
888
889                         } else {
890                                 return alert($('hold_dup_exists').innerHTML);
891                         }
892                 }
893
894                 if( grep(res, function(e) { return (e.textcode == 'HOLD_ITEM_CHECKED_OUT'); }) ) {
895                         if( fetchPermOrgs('HOLD_ITEM_CHECKED_OUT.override')[0] != -1 ) {
896                                 if( confirm($('hold_checked_out_override').innerHTML) ) {
897                                         return holdsPlaceHold(hold, true);
898                                 }
899                 return;
900
901                         } else {
902                                 return alert($('hold_checked_out').innerHTML);
903                         }
904                 }
905
906
907                 alert($('holds_failure').innerHTML);
908         }
909 }
910
911
912 function holdsCancel(holdid, user) {
913         if(!user) user = G.user;
914         var req = new Request(CANCEL_HOLD, user.session, holdid, /* Patron via OPAC */ 6);
915         req.send(true);
916         return req.result();
917         runEvt('common', 'holdUpdated');
918 }
919
920 function holdsUpdate(hold, user) {
921         if(!user) user = G.user;
922         var req = new Request(UPDATE_HOLD, user.session, hold);
923         req.send(true);
924         var x = req.result(); // cause an exception if there is one 
925         runEvt('common', 'holdUpdated');
926 }
927
928 /* verify that the thaw date is valid and after today */
929 function holdsVerifyThawDate(dateString, isGreater) {
930     thawDate = dojo.date.stamp.fromISOString(dateString);
931     if(thawDate) {
932         if(isGreater) {
933             if(dojo.date.compare(thawDate) > 0) {
934                 return dojo.date.stamp.toISOString(thawDate);
935             }
936         } else {
937             return dojo.date.stamp.toISOString(thawDate);
938         }
939     }
940     return null;
941 }
942
943 function holdsVerifyThawDateUI(element) {
944     value = dojo.date.stamp.toISOString(dijit.byId(element).getValue());
945
946     if(!value) {
947         removeCSSClass($(element), 'invalid_field');
948         return;
949     }
950
951     if(!holdsVerifyThawDate(value, true)) {
952         addCSSClass($(element), 'invalid_field');
953     } else {
954         removeCSSClass($(element), 'invalid_field');
955     }
956 }
957
958
959 function editHold(h) {
960         var row = $('myopac_holds_row_'+h);
961         var objs = [];
962         
963         objs['hold_pickup_lib'] = $n(row,'hold_pickup_lib');
964         objs['hold_pickup_lib_sel'] = $n(row,'hold_pickup_lib_sel');
965         objs['hold_active'] = $n(row,'hold_active');
966         objs['activate_label'] = $n(row,'activate_label');
967         objs['activate_date'] = $n(row,'activate_date');
968         objs['activate_box'] = $n(row,'activate_box');
969         objs['hold_expires_label'] = $n(row,'hold_expires_label');
970         objs['hold_expires'] = $n(row,'hold_expires');
971         objs['hold_expires_box'] = $n(row,'hold_expires_box');
972         objs['hold_active_sel'] = $n(row,'hold_active_sel');
973         objs['hold_edit_link'] = $n(row,'hold_edit_link');
974         objs['hold_save_link'] = $n(row,'hold_save_link');
975         objs['hold_cancel_link'] = $n(row,'hold_cancel_link');
976                 
977         for(var i in objs) unHideMe(objs[i]);
978         
979         hideMe(objs['activate_date']);
980         hideMe(objs['hold_active']);
981         hideMe(objs['hold_expires']);
982         hideMe(objs['hold_pickup_lib']);
983         hideMe(objs['hold_edit_link']);
984         row.orig_bgcolor = row.style.background;
985         row.style.background= "#fcdf89";
986 }
987
988 function cancelHold(h) {
989         var row = $('myopac_holds_row_'+h);
990         var objs = [];
991         
992         objs['hold_pickup_lib'] = $n(row,'hold_pickup_lib');
993         objs['hold_pickup_lib_sel'] = $n(row,'hold_pickup_lib_sel');
994         objs['hold_active'] = $n(row,'hold_active');
995         objs['activate_label'] = $n(row,'activate_label');
996         objs['activate_date'] = $n(row,'activate_date');
997         objs['activate_box'] = $n(row,'activate_box');
998         objs['hold_expires_label'] = $n(row,'hold_expires_label');
999         objs['hold_expires'] = $n(row,'hold_expires');
1000         objs['hold_expires_box'] = $n(row,'hold_expires_box');
1001         objs['hold_active_sel'] = $n(row,'hold_active_sel');
1002         objs['hold_edit_link'] = $n(row,'hold_edit_link');
1003         objs['hold_save_link'] = $n(row,'hold_save_link');
1004         objs['hold_cancel_link'] = $n(row,'hold_cancel_link');
1005                 
1006         for(var i in objs) hideMe(objs[i]);
1007         
1008         unHideMe(objs['hold_edit_link']);
1009         unHideMe(objs['hold_pickup_lib']);
1010         unHideMe(objs['holds_active']);
1011         unHideMe(objs['hold_active']);
1012         unHideMe(objs['activate_date']);
1013         unHideMe(objs['hold_expires']);
1014         if(objs['hold_expires'].innerHTML) unHideMe(objs['hold_expires_label']);
1015         if(objs['activate_date'].innerHTML) unHideMe(objs['activate_label']);
1016         row.style.background=row.orig_bgcolor;
1017 }
1018
1019 function saveHold(h) {
1020         var row = $('myopac_holds_row_'+h);
1021         var hold = holdsCache[holdsCacheMap[h]].hold;
1022         
1023         var activateDataBox = $n(row,'activate_box');
1024         var expireDateBox = $n(row,'hold_expires_box');
1025         var pickupLibSel = $n(row,'hold_pickup_lib_sel');
1026         var activateSel = $n(row,'hold_active_sel');
1027         var expireTime = dojo.date.stamp.toISOString(new Date(Date.parse(expireDateBox.value)),null);
1028         var activateTime = dojo.date.stamp.toISOString(new Date(Date.parse(activateDataBox.value)),null);
1029         if(parseInt(expireTime)) hold.expire_time(expireTime);
1030         if(parseInt(activateTime)) hold.thaw_date(activateTime);
1031         hold.frozen(activateSel.options[activateSel.selectedIndex].value);
1032         hold.pickup_lib(pickupLibSel.options[pickupLibSel.selectedIndex].value)
1033         
1034         fieldmapper.standardRequest(['open-ils.circ','open-ils.circ.hold.update'],{params:[G.user.session,hold],oncomplete:refreshHold});
1035         row.style.background= isTrue(hold.frozen())?"#e5e5e5":"";
1036         row.orig_bgcolor=row.style.background;
1037 }
1038
1039 function updateHoldInfo(holdid,holdrow) {
1040         var h = holdsCache[holdsCacheMap[holdid]].hold;
1041         if(!h) return;
1042         var row = holdrow?holdrow:$('myopac_holds_row_'+holdid);
1043         if(!row) return;
1044         
1045         $n(row,'hold_pickup_lib').innerHTML = findOrgUnit(h.pickup_lib()).name();
1046         $n(row,'hold_active').innerHTML = isTrue(h.frozen())?"Suspended":"Active";
1047         
1048         if(h.thaw_date()) {
1049                 var d = dojo.date.stamp.fromISOString(h.thaw_date());
1050                 $n(row, 'activate_date').innerHTML = dojo.date.locale.format(d, {selector: 'date', fullYear: true});
1051                 unHideMe($n(row,'activate_label'));
1052                 $n(row,'activate_box').value = dojo.date.locale.format(d, {selector:'date', fullYear: true});
1053         }
1054         
1055         if(h.expire_time()) {
1056                 var exp_date = dojo.date.stamp.fromISOString(h.expire_time());
1057                 $n(row, 'hold_expires').innerHTML = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});
1058                 unHideMe($n(row,'hold_expires_label'));
1059                 $n(row,'hold_expires_box').value = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});
1060         }
1061 }
1062
1063 function refreshHold(r) {
1064         var hold = r.recv().content();
1065         if(!parseInt(hold)) return;
1066         updateHoldInfo(hold);
1067         cancelHold(hold);
1068 }