changed return object key names for consistency
[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 function holdsParseMRFormats(str) {
493         var data = str.split(/-/);      
494
495         var formats = [];
496         var mods_formats = [];
497
498         for( var i = 0; i < data[0].length; i++ ) {
499                 formats.push( data[0].charAt(i) );
500                 mods_formats.push( MARCFormatToMods( formats[i] ) );
501         }
502         
503         formats = uniquify(formats);
504         mods_formats = uniquify(mods_formats);
505
506         return {
507                 formats                 : formats,
508                 mods_formats    : mods_formats,
509                 lang                            : data[2],
510                 largeprint              : data[1]
511         };
512 }
513
514
515 function holdsSetFormatSelector() {
516         var type = holdArgs.type;
517         if( type == 'C' || type == 'V' || holdArgs.editHold ) return;
518
519         var data                                = holdsGetFormats();
520         var avail_formats       = data.avail_formats;
521         var sel_formats = data.sel_formats;
522         holdArgs.language = data.lang;
523
524         unHideMe($('holds_alt_formats_row_extras'));
525         var selector = $('hold_alt_form_selector');
526
527         for( var i = 0; i < avail_formats.length; i++ ) {
528                 var form = avail_formats[i];
529                 unHideMe(findSelectorOptByValue(selector, form));
530         }
531 }
532
533
534 function holdsGetFormats() {
535
536         var lang;
537         var formats = [];
538         var sformats = []; // selected formats 
539
540         var type = holdArgs.type;
541         var desc = holdArgs.recordDescriptors;
542         var rec = holdArgs.record;
543         var mrec = holdArgs.metarecord;
544
545         if( type == 'T' ) {
546
547                 for( var i = 0; i < desc.length; i++ ) {
548                         var d = desc[i];
549                         if( d.record() == holdArgs.record ) {
550                                 lang = d.item_lang();
551                                 holdArgs.myFormat =  _t_f_2_format(d.item_type(), d.item_form());
552                                 sformats.push(holdArgs.myFormat);
553                                 break;
554                         }
555                 }
556         }
557
558         for( var i = 0; i < desc.length; i++ ) {
559                 var d = desc[i];
560                 if( d.item_lang() != lang ) continue;
561                 formats.push( _t_f_2_format(d.item_type(), d.item_form()));
562         }
563
564         formats = uniquify(formats);
565
566         return {
567                 lang : lang,
568                 avail_formats : formats, 
569                 sel_formats : sformats
570         };
571 }
572
573
574
575 function _t_f_2_format(type, form) {
576         if( form == 'd' ) return 'at-d';
577         return (type == 'a' || type == 't') ? 'at' : 
578                 ( type == 'i' || type == 'g' || type == 'j' ) ? type : null;
579 }
580
581 function holdsSetSelectedFormats() {
582
583         var cn = $('holds_alt_formats_row').className;
584         if( cn && cn.match(/hide_me/) ) return;
585
586         var selector = $('hold_alt_form_selector');
587         var vals = getSelectedList(selector);
588
589         if(vals.length == 0) return;
590
591         var fstring = "";
592
593         if( contains(vals, 'at-d') ) {
594                 if( contains(vals, 'at') )
595                         fstring = 'at';
596                 else 
597                         fstring = 'at-d';
598         } else {
599                 if( contains(vals, 'at') )
600                         fstring = 'at';
601         }
602
603         for( var i = 0; i < vals.length; i++ ) {
604                 var val = vals[i];
605                 if( !val.match(/at/) ) fstring = val + fstring;
606         }
607
608         if( holdArgs.language ) {
609                 if( fstring.match(/-/) )
610                         fstring = fstring + '-' + holdArgs.language;
611                 else
612                         fstring = fstring + '--' + holdArgs.language;
613         }
614
615
616         return fstring;
617 }
618
619
620 function holdsCheckPossibility(pickuplib, hold, recurse) {
621
622         var args = { 
623                 titleid : holdArgs.record,
624                 volume_id : holdArgs.volume,
625                 copy_id : holdArgs.copy,
626                 hold_type : holdArgs.type,
627                 patronid : holdArgs.recipient.id(),
628                 depth : 0, 
629                 pickup_lib : pickuplib 
630         };
631
632         if(recurse) {
633                 /* if we're calling create again (recursing), 
634                         we know that the hold possibility check already succeeded */
635                 holdHandleCreateResponse({_recurse:true, _hold:hold}, true );
636
637         } else {
638                 _debug("hold possible args = "+js2JSON(args));
639         
640                 var req = new Request(CHECK_HOLD_POSSIBLE, G.user.session, args );
641         
642                 req.request.alertEvent = false;
643                 req.request._hold = hold;
644                 req.request._recurse = recurse;
645                 req.callback(holdHandleCreateResponse);
646                 req.send();
647         }
648 }
649
650
651 function holdsBuildOrgSelector(node) {
652
653         if(!node) node = globalOrgTree;
654     if(!isTrue(node.opac_visible())) return;
655
656         var selector = $('holds_org_selector');
657         var index = selector.options.length;
658
659         var type = findOrgType(node.ou_type());
660         var indent = type.depth() - 1;
661         var opt = setSelectorVal( selector, index, node.name(), node.id(), null, indent );
662         if(!type.can_have_users()) {
663                 opt.disabled = true;
664                 addCSSClass(opt, 'disabled_option');
665         }
666         
667         for( var i in node.children() ) {
668                 var child = node.children()[i];
669                 if(child) holdsBuildOrgSelector(child);
670         }
671 }
672
673 function holdsBuildHoldFromWindow() {
674
675         var org = getSelectorVal($('holds_org_selector'));
676         var node = findOrgUnit(org);
677         var ntype = findOrgType(node.ou_type());
678         if(!ntype.can_have_users()) {
679                 alertId('holds_pick_good_org');
680                 return;
681         }
682
683         var hold = new ahr();
684         if(holdArgs.editHold) {
685                 hold = holdArgs.editHold;
686                 holdArgs.editHold = null;
687         }
688
689         if( $('holds_enable_phone').checked ) {
690                 var phone = $('holds_phone').value;
691                 if( !phone || !phone.match(REGEX_PHONE) ) {
692                         alert($('holds_bad_phone').innerHTML);
693                         return null;
694                 }
695                 hold.phone_notify(phone);
696
697         } else {
698                 hold.phone_notify("");
699         }
700
701         if( $('holds_enable_email').checked ) 
702                 hold.email_notify(1);
703         else
704                 hold.email_notify(0);
705
706         var target;
707
708         switch(holdArgs.type) {
709                 case 'M':
710                         target = holdArgs.metarecord; break;
711                 case 'T':
712                         target = holdArgs.record; break;
713                 case 'V':
714                         target = holdArgs.volume; break;
715                 case 'C':
716                         target = holdArgs.copy; break;
717         }
718
719
720
721         hold.pickup_lib(org); 
722         //hold.request_lib(org); 
723         hold.requestor(holdArgs.requestor.id());
724         hold.usr(holdArgs.recipient.id());
725         hold.target(target);
726         hold.hold_type(holdArgs.type);
727
728     var expireDate = dojo.date.stamp.toISOString(dijit.byId('holds_expire_time').getValue())
729     expireDate = holdsVerifyThawDate(expireDate); 
730     if(expireDate)
731         hold.expire_time(expireDate);
732     else 
733         return;
734
735     // see if this hold should be frozen and for how long
736     if($('holds_frozen_chkbox').checked) {
737         hold.frozen('t');
738         unHideMe($('hold_frozen_thaw_row'));
739         thawDate = dojo.date.stamp.toISOString(dijit.byId('holds_frozen_thaw_input').getValue());
740         if(thawDate) {
741             thawDate = holdsVerifyThawDate(thawDate); 
742             if(thawDate) 
743                 hold.thaw_date(thawDate);
744             else
745                 return;
746         } else {
747             hold.thaw_date(null);
748         }
749     } else {
750         hold.frozen('f');
751         hold.thaw_date(null);
752     }
753
754         //check for alternate hold formats 
755         var fstring = holdsSetSelectedFormats();
756         if(fstring) { 
757                 hold.hold_type('M'); 
758                 hold.holdable_formats(fstring);
759                 hold.target(holdArgs.metarecord);
760         }
761         return hold;
762 }
763         
764 function holdsPlaceHold(hold, recurse) {
765         if(!hold) return;
766         swapCanvas($('check_holds_box'));
767         holdsCheckPossibility(hold.pickup_lib(), hold, recurse);
768 }
769
770
771 function holdHandleCreateResponse(r, recurse) {
772
773         if(!recurse) {
774                 var res = r.getResultObject();
775                 if(checkILSEvent(res) || res.success != 1) {
776                         if(res.success != 1) {
777                                 alert($('hold_not_allowed').innerHTML);
778                         } else {
779                                 if( res.textcode == 'PATRON_BARRED' ) {
780                                         alertId('hold_failed_patron_barred');
781                         } else {
782                                         alert($('hold_not_allowed').innerHTML);
783                                 }
784                         }
785                         swapCanvas($('holds_box'));
786                         return;
787                 }
788         r._hold.selection_depth(res.depth);
789         }       
790
791         holdCreateHold(r._recurse, r._hold);
792 }
793
794
795 function holdCreateHold( recurse, hold ) {
796         var method = CREATE_HOLD;
797         if(recurse) method = CREATE_HOLD_OVERRIDE;
798         var req = new Request( method, holdArgs.requestor.session, hold );
799         req.request.alertEvent = false;
800         req.send(true);
801         var res = req.result();
802         holdProcessResult(hold, res, recurse);
803         
804         showCanvas();
805
806         runEvt('common', 'holdUpdated');
807 }
808
809
810 function holdProcessResult( hold, res, recurse ) {
811
812         if( res == '1' ) {
813                 alert($('holds_success').innerHTML);
814                 holdArgs = null;
815
816         } else {
817
818                 if( recurse ) {
819                         alert($('holds_failure').innerHTML);
820                         return;
821                 }
822
823                 if( grep(res, function(e) { return (e.textcode == 'HOLD_EXISTS'); }) ) {
824                         if( fetchPermOrgs('HOLD_EXISTS.override')[0] != -1 ) {
825                                 if( confirm($('hold_dup_exists_override').innerHTML) ) {
826                                         return holdsPlaceHold(hold, true);
827                                 }
828
829                         } else {
830                                 return alert($('hold_dup_exists').innerHTML);
831                         }
832                 }
833
834                 alert($('holds_failure').innerHTML);
835         }
836 }
837
838
839 function holdsCancel(holdid, user) {
840         if(!user) user = G.user;
841         var req = new Request(CANCEL_HOLD, user.session, holdid);
842         req.send(true);
843         return req.result();
844         runEvt('common', 'holdUpdated');
845 }
846
847 function holdsUpdate(hold, user) {
848         if(!user) user = G.user;
849         var req = new Request(UPDATE_HOLD, user.session, hold);
850         req.send(true);
851         var x = req.result(); // cause an exception if there is one 
852         runEvt('common', 'holdUpdated');
853 }
854
855 /* verify that the thaw date is valid and after today */
856 function holdsVerifyThawDate(dateString) {
857     thawDate = dojo.date.stamp.fromISOString(dateString);
858     if(thawDate && (dojo.date.compare(thawDate) > 0))
859         return dojo.date.stamp.toISOString(thawDate);
860     return null;
861 }
862
863 function holdsVerifyThawDateUI(element) {
864     value = dojo.date.stamp.toISOString(dijit.byId(element).getValue());
865
866     if(!value) {
867         removeCSSClass($(element), 'invalid_field');
868         return;
869     }
870
871     if(!holdsVerifyThawDate(value)) {
872         addCSSClass($(element), 'invalid_field');
873     } else {
874         removeCSSClass($(element), 'invalid_field');
875     }
876 }
877