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