68cc2d5de76b4af2f1d6b283a005160a806e918f
[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         };
353         $('holds_submit').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};
354         $('holds_update').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};
355         holdFetchObjects(null, 
356                 function(){
357                         __holdsDrawWindow();
358
359                         if(holdArgs.editHold) {
360                                 //hideMe($('holds_submit'));
361                                 unHideMe($('holds_update'));
362                                 var req = new Request(FETCH_HOLD_STATUS, 
363                                         G.user.session, holdArgs.editHold.id());
364                                 req.send(true);
365                                 holdArgs.status = req.result();
366                                 _holdsUpdateEditHold();
367                         }  
368                 }
369         );
370 }
371
372 function selOrgChange(e) {
373         
374         $('holds_pickup_lib').innerHTML = this.options[this.selectedIndex].text;
375 }
376
377 function __holdsDrawWindow() {
378
379         var rec = holdArgs.recordObject;
380         var vol = holdArgs.volumeObject;
381         var copy = holdArgs.copyObject;
382         var mr = holdArgs.metarecordObject;
383
384         rec = (rec) ? rec : mr;
385
386         if(!holdsOrgSelectorBuilt) {
387                 holdsBuildOrgSelector(null,0);
388                 holdsOrgSelectorBuilt = true;
389                 var selector = $('holds_org_selector');
390
391                 /*
392                 var o_loc = findOrgUnit(getOrigLocation());
393                 var t = findOrgType(o_loc.ou_type());
394                 if( t.can_have_users() ) 
395                         setSelector(selector, o_loc.id());
396                 else 
397                 */
398                 selector.onchange = selOrgChange;
399                 setSelector(selector, holdArgs.recipient.home_ou());
400         }
401         
402         var obj = findOrgUnit(holdArgs.recipient.home_ou());
403         $('holds_pickup_lib').innerHTML = obj.name();
404
405         /*
406         if(isXUL()) {
407                 var dsel = $('holds_depth_selector');
408                 unHideMe($('holds_depth_selector_row'));
409                 if(dsel.getElementsByTagName('option').length == 0) {
410                         var types = globalOrgTypes;
411                         var depth = findOrgDepth(G.user.ws_ou());
412                         iterate(types, 
413                                 function(t) {
414                                         if(t.depth() > depth) return;
415                                         insertSelectorVal(dsel, -1, t.opac_label(), t.depth());
416                                 }
417                         );
418                 }
419         }
420         */
421
422         appendClear($('holds_recipient'), text(
423                 holdArgs.recipient.family_name() + ', ' +  
424                         holdArgs.recipient.first_given_name()));
425         appendClear($('holds_title'), text(rec.title()));
426         appendClear($('holds_author'), text(rec.author()));
427
428         if( holdArgs.type == 'V' || holdArgs.type == 'C' ) {
429
430                 unHideMe($('holds_type_row'));
431                 unHideMe($('holds_cn_row'));
432                 appendClear($('holds_cn'), text(holdArgs.volumeObject.label()));
433
434                 if( holdArgs.type == 'V'  ) {
435                         unHideMe($('holds_is_cn'));
436                         hideMe($('holds_is_copy'));
437
438                 } else {
439                         hideMe($('holds_is_cn'));
440                         unHideMe($('holds_is_copy'));
441                         unHideMe($('holds_copy_row'));
442                         appendClear($('holds_copy'), text(holdArgs.copyObject.barcode()));
443                 }
444
445         } else {
446                 hideMe($('holds_type_row'));
447                 hideMe($('holds_copy_row'));
448                 hideMe($('holds_cn_row'));
449         }
450
451         removeChildren($('holds_format'));
452
453         var mods_formats = rec.types_of_resource();
454         var formats;
455
456         if(holdArgs.recordDescriptors)
457                 formats = holdArgs.recordDescriptors[0].item_type();
458
459         if( holdArgs.type == 'T' ) {
460                 var desc = grep( holdArgs.recordDescriptors,
461                         function(i) {
462                                 return (i.record() == holdArgs.record); 
463                         }
464                 );
465                 formats = desc[0].item_type();
466         }
467
468         if( holdArgs.type == 'M' ) {
469                 var data = holdsParseMRFormats(holdArgs.editHold.holdable_formats());
470                 mods_formats = data.mods_formats;
471                 formats = data.formats;
472         }
473
474
475         for( var i in mods_formats ) {
476                 var res = mods_formats[i];
477                 var img = elem("img");
478                 setResourcePic(img, res);
479                 $('holds_format').appendChild(img);
480                 if(formats)
481                         $('holds_format').appendChild(text(' '+ MARCTypeToFriendly(formats[i]) +' '));
482                 else
483                         $('holds_format').appendChild(text(' '+ mods_formats[i] +' '));
484                 $('holds_format').appendChild(elem('br'));
485         }
486
487
488         $('holds_phone').value = (holdArgs.recipient.day_phone())?holdArgs.recipient.day_phone():"";
489         appendClear( $('holds_email'), text(holdArgs.recipient.email()));
490
491         var pref = holdArgs.recipient.prefs[PREF_HOLD_NOTIFY];
492
493         if(pref) {
494                 if( ! pref.match(/email/i) ) {
495                         $('holds_enable_email').checked = false;
496                 } else {
497                         $('holds_enable_email').checked = true;
498                 }
499
500                 if( ! pref.match(/phone/i) ) {
501                         $('holds_phone').disabled = true;
502                         $('holds_enable_phone').checked = false;
503                 } else {
504                         $('holds_phone').disabled = false;
505                         $('holds_enable_phone').checked = true;
506                 }
507         }
508
509     if(!holdArgs.recipient.email()) {
510                 $('holds_enable_email').checked = false;        
511                 $('holds_enable_email').disabled = true;
512         var message;
513         if(isXUL()) {
514             message = noEmailMessageXUL.cloneNode(true);
515                 appendClear($('holds_email'), message);
516         } else {
517             message = noEmailMessage.cloneNode(true);
518                 appendClear($('holds_email'), message);
519             $('holds.no_email.my_account').setAttribute('href', buildOPACLink({page:MYOPAC},null,true));
520         }
521         unHideMe(message);
522     }
523
524         if(!$('holds_phone').value) 
525                 $('holds_enable_phone').checked = false;        
526
527         appendClear($('holds_physical_desc'), text(rec.physical_description()));
528
529         if(holdArgs.type == 'M') hideMe($('hold_physical_desc_row'));
530
531         holdsSetFormatSelector();
532
533     $('holds_frozen_chkbox').checked = false;
534     hideMe($('hold_frozen_thaw_row'));
535
536     var interval = fetchOrgSettingDefault(holdArgs.recipient.home_ou(), 'circ.hold_expire_interval');
537     var secs = 0;
538     if(interval) {
539         secs = interval_to_seconds(interval);
540         var expire = new Date();
541         expire.setTime(expire.getTime() + Number(secs + '000'));
542         if(dijit.byId('holds_expire_time')) dijit.byId('holds_expire_time').setValue(expire);
543     }
544 }
545
546 function holdsParseMRFormats(str) {
547         var data = str.split(/-/);      
548
549         var formats = [];
550         var mods_formats = [];
551
552         for( var i = 0; i < data[0].length; i++ ) {
553                 formats.push( data[0].charAt(i) );
554                 mods_formats.push( MARCFormatToMods( formats[i] ) );
555         }
556         
557         formats = uniquify(formats);
558         mods_formats = uniquify(mods_formats);
559
560         return {
561                 formats                 : formats,
562                 mods_formats    : mods_formats,
563                 lang                            : data[2],
564                 largeprint              : data[1]
565         };
566 }
567
568
569 function holdsSetFormatSelector() {
570         var type = holdArgs.type;
571         if( type == 'C' || type == 'V' || holdArgs.editHold ) return;
572
573         var data                                = holdsGetFormats();
574         var avail_formats       = data.avail_formats;
575         var sel_formats = data.sel_formats;
576         holdArgs.language = data.lang;
577
578         unHideMe($('holds_alt_formats_row_extras'));
579         var selector = $('hold_alt_form_selector');
580
581         for( var i = 0; i < avail_formats.length; i++ ) {
582                 var form = avail_formats[i];
583                 unHideMe(findSelectorOptByValue(selector, form));
584         }
585 }
586
587
588 function holdsGetFormats() {
589
590         var lang;
591         var formats = [];
592         var sformats = []; // selected formats 
593
594         var type = holdArgs.type;
595         var desc = holdArgs.recordDescriptors;
596         var rec = holdArgs.record;
597         var mrec = holdArgs.metarecord;
598
599         if( type == 'T' ) {
600
601                 for( var i = 0; i < desc.length; i++ ) {
602                         var d = desc[i];
603                         if( d.record() == holdArgs.record ) {
604                                 lang = d.item_lang();
605                                 holdArgs.myFormat =  _t_f_2_format(d.item_type(), d.item_form());
606                                 sformats.push(holdArgs.myFormat);
607                                 break;
608                         }
609                 }
610         }
611
612         for( var i = 0; i < desc.length; i++ ) {
613                 var d = desc[i];
614                 if( d.item_lang() != lang ) continue;
615                 formats.push( _t_f_2_format(d.item_type(), d.item_form()));
616         }
617
618         formats = uniquify(formats);
619
620         return {
621                 lang : lang,
622                 avail_formats : formats, 
623                 sel_formats : sformats
624         };
625 }
626
627
628
629 function _t_f_2_format(type, form) {
630         if( form == 'd' ) return 'at-d';
631         return (type == 'a' || type == 't') ? 'at' : 
632                 ( type == 'i' || type == 'g' || type == 'j' ) ? type : null;
633 }
634
635 function holdsSetSelectedFormats() {
636
637         var cn = $('holds_alt_formats_row').className;
638         if( cn && cn.match(/hide_me/) ) return;
639
640         var selector = $('hold_alt_form_selector');
641         var vals = getSelectedList(selector);
642
643         if(vals.length == 0) return;
644
645         var fstring = "";
646
647         if( contains(vals, 'at-d') ) {
648                 if( contains(vals, 'at') )
649                         fstring = 'at';
650                 else 
651                         fstring = 'at-d';
652         } else {
653                 if( contains(vals, 'at') )
654                         fstring = 'at';
655         }
656
657         for( var i = 0; i < vals.length; i++ ) {
658                 var val = vals[i];
659                 if( !val.match(/at/) ) fstring = val + fstring;
660         }
661
662         if( holdArgs.language ) {
663                 if( fstring.match(/-/) )
664                         fstring = fstring + '-' + holdArgs.language;
665                 else
666                         fstring = fstring + '--' + holdArgs.language;
667         }
668         return fstring;
669 }
670
671
672 function holdsCheckPossibility(pickuplib, hold, recurse) {
673
674         var args = { 
675                 titleid : holdArgs.record,
676                 volume_id : holdArgs.volume,
677                 copy_id : holdArgs.copy,
678                 hold_type : holdArgs.type,
679                 patronid : holdArgs.recipient.id(),
680                 depth : 0, 
681                 pickup_lib : pickuplib 
682         };
683
684         if(recurse) {
685                 /* if we're calling create again (recursing), 
686                         we know that the hold possibility check already succeeded */
687                 holdHandleCreateResponse({_recurse:true, _hold:hold}, true );
688
689         } else {
690                 _debug("hold possible args = "+js2JSON(args));
691         
692                 var req = new Request(CHECK_HOLD_POSSIBLE, G.user.session, args );
693         
694                 req.request.alertEvent = false;
695                 req.request._hold = hold;
696                 req.request._recurse = recurse;
697                 req.callback(holdHandleCreateResponse);
698                 req.send();
699         }
700 }
701
702
703 function holdsBuildOrgSelector(node, sel) {
704
705         if(!node) node = globalOrgTree;
706     if(!isTrue(node.opac_visible())) return;
707
708         var selector = sel?sel:$('holds_org_selector');
709         var index = selector.options.length;
710
711         var type = findOrgType(node.ou_type());
712         var indent = type.depth() - 1;
713         var opt = setSelectorVal( selector, index, node.name(), node.id(), null, indent );
714         if(!type.can_have_users()) {
715                 opt.disabled = true;
716                 addCSSClass(opt, 'disabled_option');
717         }
718         
719         for( var i in node.children() ) {
720                 var child = node.children()[i];
721                 if(child) holdsBuildOrgSelector(child);
722         }
723 }
724
725 function holdsBuildHoldFromWindow() {
726
727         var org = getSelectorVal($('holds_org_selector'));
728         var node = findOrgUnit(org);
729         var ntype = findOrgType(node.ou_type());
730         if(!ntype.can_have_users()) {
731                 alertId('holds_pick_good_org');
732                 return;
733         }
734
735         var hold = new ahr();
736         if(holdArgs.editHold) {
737                 hold = holdArgs.editHold;
738                 holdArgs.editHold = null;
739         }
740
741         if( $('holds_enable_phone').checked ) {
742                 var phone = $('holds_phone').value;
743                 if( !phone || !phone.match(REGEX_PHONE) ) {
744                         alert($('holds_bad_phone').innerHTML);
745                         return null;
746                 }
747                 hold.phone_notify(phone);
748
749         } else {
750                 hold.phone_notify("");
751         }
752
753         if( $('holds_enable_email').checked ) 
754                 hold.email_notify(1);
755         else
756                 hold.email_notify(0);
757
758         var target;
759
760         switch(holdArgs.type) {
761                 case 'M':
762                         target = holdArgs.metarecord; break;
763                 case 'T':
764                         target = holdArgs.record; break;
765                 case 'V':
766                         target = holdArgs.volume; break;
767                 case 'C':
768                         target = holdArgs.copy; break;
769         }
770
771
772
773         hold.pickup_lib(org); 
774         //hold.request_lib(org); 
775         hold.requestor(holdArgs.requestor.id());
776         hold.usr(holdArgs.recipient.id());
777         hold.target(target);
778         hold.hold_type(holdArgs.type);
779
780     try{var expDate = dijit.byId('holds_expire_time').getValue();} catch(e){}
781     if(expDate) {
782         var expireDate = dojo.date.stamp.toISOString(expDate);
783         expireDate = holdsVerifyThawDate(expireDate); 
784         if(expireDate)
785             hold.expire_time(expireDate);
786         else 
787             return;
788     }
789
790     // see if this hold should be frozen and for how long
791     if($('holds_frozen_chkbox').checked) {
792         hold.frozen('t');
793         unHideMe($('hold_frozen_thaw_row'));
794         thawDate = dojo.date.stamp.toISOString(dijit.byId('holds_frozen_thaw_input').getValue());
795         if(thawDate) {
796             thawDate = holdsVerifyThawDate(thawDate); 
797             if(thawDate) 
798                 hold.thaw_date(thawDate);
799             else
800                 return;
801         } else {
802             hold.thaw_date(null);
803         }
804     } else {
805         hold.frozen('f');
806         hold.thaw_date(null);
807     }
808
809         //check for alternate hold formats 
810         var fstring = holdsSetSelectedFormats();
811         if(fstring) { 
812                 hold.hold_type('M'); 
813                 hold.holdable_formats(fstring);
814                 hold.target(holdArgs.metarecord);
815         }
816         return hold;
817 }
818         
819 function holdsPlaceHold(hold, recurse) {
820         if(!hold) return;
821         swapCanvas($('check_holds_box'));
822         holdsCheckPossibility(hold.pickup_lib(), hold, recurse);
823 }
824
825
826 function holdHandleCreateResponse(r, recurse) {
827
828         if(!recurse) {
829                 var res = r.getResultObject();
830                 if(checkILSEvent(res) || res.success != 1) {
831                         if(res.success != 1) {
832                                 alert($('hold_not_allowed').innerHTML+(!res.last_event.desc?"":"\n\nHold failure description:\n"+res.last_event.desc));
833                         } else {
834                                 if( res.textcode == 'PATRON_BARRED' ) {
835                                         alertId('hold_failed_patron_barred');
836                                 } else {
837                                         alert($('hold_not_allowed').innerHTML+(!res.last_event.desc?"":"\n\nHold failure description:\n"+res.last_event.desc));
838                                 }
839                         }
840                         swapCanvas($('holds_box'));
841                         return;
842                 }
843         r._hold.selection_depth(res.depth);
844         }       
845
846         holdCreateHold(r._recurse, r._hold);
847         hideResultsPage(false);
848 }
849
850
851 function holdCreateHold( recurse, hold ) {
852         var method = CREATE_HOLD;
853         if(recurse) method = CREATE_HOLD_OVERRIDE;
854         var req = new Request( method, holdArgs.requestor.session, hold );
855         req.request.alertEvent = false;
856         req.send(true);
857         var res = req.result();
858         holdProcessResult(hold, res, recurse);
859
860         showCanvas();
861
862         runEvt('common', 'holdUpdated');
863 }
864
865
866 function holdProcessResult( hold, res, recurse ) {
867
868         if( res && res > -1 ) {
869                 alert($('holds_success').innerHTML);
870                 holdArgs = null;
871         if(isXUL() && typeof xulG.opac_hold_placed == 'function')
872             xulG.opac_hold_placed(res);
873
874         } else {
875
876                 if( recurse ) {
877                         alert($('holds_failure').innerHTML);
878                         return;
879                 }
880
881                 if( grep(res, function(e) { return (e.textcode == 'HOLD_EXISTS'); }) ) {
882                         if( fetchPermOrgs('HOLD_EXISTS.override')[0] != -1 ) {
883                                 if( confirm($('hold_dup_exists_override').innerHTML) ) {
884                                         return holdsPlaceHold(hold, true);
885                                 }
886                 return;
887
888                         } else {
889                                 return alert($('hold_dup_exists').innerHTML);
890                         }
891                 }
892
893                 if( grep(res, function(e) { return (e.textcode == 'HOLD_ITEM_CHECKED_OUT'); }) ) {
894                         if( fetchPermOrgs('HOLD_ITEM_CHECKED_OUT.override')[0] != -1 ) {
895                                 if( confirm($('hold_checked_out_override').innerHTML) ) {
896                                         return holdsPlaceHold(hold, true);
897                                 }
898                 return;
899
900                         } else {
901                                 return alert($('hold_checked_out').innerHTML);
902                         }
903                 }
904
905
906                 alert($('holds_failure').innerHTML);
907         }
908 }
909
910
911 function holdsCancel(holdid, user) {
912         if(!user) user = G.user;
913         var req = new Request(CANCEL_HOLD, user.session, holdid, /* Patron via OPAC */ 6);
914         req.send(true);
915         return req.result();
916         runEvt('common', 'holdUpdated');
917 }
918
919 function holdsUpdate(hold, user) {
920         if(!user) user = G.user;
921         var req = new Request(UPDATE_HOLD, user.session, hold);
922         req.send(true);
923         var x = req.result(); // cause an exception if there is one 
924         runEvt('common', 'holdUpdated');
925 }
926
927 /* verify that the thaw date is valid and after today */
928 function holdsVerifyThawDate(dateString, isGreater) {
929     thawDate = dojo.date.stamp.fromISOString(dateString);
930     if(thawDate) {
931         if(isGreater) {
932             if(dojo.date.compare(thawDate) > 0) {
933                 return dojo.date.stamp.toISOString(thawDate);
934             }
935         } else {
936             return dojo.date.stamp.toISOString(thawDate);
937         }
938     }
939     return null;
940 }
941
942 function holdsVerifyThawDateUI(element) {
943     value = dojo.date.stamp.toISOString(dijit.byId(element).getValue());
944
945     if(!value) {
946         removeCSSClass($(element), 'invalid_field');
947         return;
948     }
949
950     if(!holdsVerifyThawDate(value, true)) {
951         addCSSClass($(element), 'invalid_field');
952     } else {
953         removeCSSClass($(element), 'invalid_field');
954     }
955 }
956
957
958 function editHold(h) {
959         var row = $('myopac_holds_row_'+h);
960         var objs = [];
961         
962         objs['hold_pickup_lib'] = $n(row,'hold_pickup_lib');
963         objs['hold_pickup_lib_sel'] = $n(row,'hold_pickup_lib_sel');
964         objs['hold_active'] = $n(row,'hold_active');
965         objs['activate_label'] = $n(row,'activate_label');
966         objs['activate_date'] = $n(row,'activate_date');
967         objs['activate_box'] = $n(row,'activate_box');
968         objs['hold_expires_label'] = $n(row,'hold_expires_label');
969         objs['hold_expires'] = $n(row,'hold_expires');
970         objs['hold_expires_box'] = $n(row,'hold_expires_box');
971         objs['hold_active_sel'] = $n(row,'hold_active_sel');
972         objs['hold_edit_link'] = $n(row,'hold_edit_link');
973         objs['hold_save_link'] = $n(row,'hold_save_link');
974         objs['hold_cancel_link'] = $n(row,'hold_cancel_link');
975                 
976         for(var i in objs) unHideMe(objs[i]);
977         
978         hideMe(objs['activate_date']);
979         hideMe(objs['hold_active']);
980         hideMe(objs['hold_expires']);
981         hideMe(objs['hold_pickup_lib']);
982         hideMe(objs['hold_edit_link']);
983         row.orig_bgcolor = row.style.background;
984         row.style.background= "#fcdf89";
985 }
986
987 function cancelHold(h) {
988         var row = $('myopac_holds_row_'+h);
989         var objs = [];
990         
991         objs['hold_pickup_lib'] = $n(row,'hold_pickup_lib');
992         objs['hold_pickup_lib_sel'] = $n(row,'hold_pickup_lib_sel');
993         objs['hold_active'] = $n(row,'hold_active');
994         objs['activate_label'] = $n(row,'activate_label');
995         objs['activate_date'] = $n(row,'activate_date');
996         objs['activate_box'] = $n(row,'activate_box');
997         objs['hold_expires_label'] = $n(row,'hold_expires_label');
998         objs['hold_expires'] = $n(row,'hold_expires');
999         objs['hold_expires_box'] = $n(row,'hold_expires_box');
1000         objs['hold_active_sel'] = $n(row,'hold_active_sel');
1001         objs['hold_edit_link'] = $n(row,'hold_edit_link');
1002         objs['hold_save_link'] = $n(row,'hold_save_link');
1003         objs['hold_cancel_link'] = $n(row,'hold_cancel_link');
1004                 
1005         for(var i in objs) hideMe(objs[i]);
1006         
1007         unHideMe(objs['hold_edit_link']);
1008         unHideMe(objs['hold_pickup_lib']);
1009         unHideMe(objs['holds_active']);
1010         unHideMe(objs['hold_active']);
1011         unHideMe(objs['activate_date']);
1012         unHideMe(objs['hold_expires']);
1013         if(objs['hold_expires'].innerHTML) unHideMe(objs['hold_expires_label']);
1014         if(objs['activate_date'].innerHTML) unHideMe(objs['activate_label']);
1015         row.style.background=row.orig_bgcolor;
1016 }
1017
1018 function saveHold(h) {
1019         var row = $('myopac_holds_row_'+h);
1020         var hold = holdsCache[holdsCacheMap[h]].hold;
1021         
1022         var activateDataBox = $n(row,'activate_box');
1023         var expireDateBox = $n(row,'hold_expires_box');
1024         var pickupLibSel = $n(row,'hold_pickup_lib_sel');
1025         var activateSel = $n(row,'hold_active_sel');
1026         var expireTime = dojo.date.stamp.toISOString(new Date(Date.parse(expireDateBox.value)),null);
1027         var activateTime = dojo.date.stamp.toISOString(new Date(Date.parse(activateDataBox.value)),null);
1028         if(parseInt(expireTime)) hold.expire_time(expireTime);
1029         if(parseInt(activateTime)) hold.thaw_date(activateTime);
1030         hold.frozen(activateSel.options[activateSel.selectedIndex].value);
1031         hold.pickup_lib(pickupLibSel.options[pickupLibSel.selectedIndex].value)
1032         
1033         fieldmapper.standardRequest(['open-ils.circ','open-ils.circ.hold.update'],{params:[G.user.session,hold],oncomplete:refreshHold});
1034         row.style.background= isTrue(hold.frozen())?"#e5e5e5":"";
1035         row.orig_bgcolor=row.style.background;
1036 }
1037
1038 function updateHoldInfo(holdid,holdrow) {
1039         var h = holdsCache[holdsCacheMap[holdid]].hold;
1040         if(!h) return;
1041         var row = holdrow?holdrow:$('myopac_holds_row_'+holdid);
1042         if(!row) return;
1043         
1044         $n(row,'hold_pickup_lib').innerHTML = findOrgUnit(h.pickup_lib()).name();
1045         $n(row,'hold_active').innerHTML = isTrue(h.frozen())?"Suspended":"Active";
1046         
1047         if(h.thaw_date()) {
1048                 var d = dojo.date.stamp.fromISOString(h.thaw_date());
1049                 $n(row, 'activate_date').innerHTML = dojo.date.locale.format(d, {selector: 'date', fullYear: true});
1050                 unHideMe($n(row,'activate_label'));
1051                 $n(row,'activate_box').value = dojo.date.locale.format(d, {selector:'date', fullYear: true});
1052         }
1053         
1054         if(h.expire_time()) {
1055                 var exp_date = dojo.date.stamp.fromISOString(h.expire_time());
1056                 $n(row, 'hold_expires').innerHTML = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});
1057                 unHideMe($n(row,'hold_expires_label'));
1058                 $n(row,'hold_expires_box').value = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});
1059         }
1060 }
1061
1062 function refreshHold(r) {
1063         var hold = r.recv().content();
1064         if(!parseInt(hold)) return;
1065         updateHoldInfo(hold);
1066         cancelHold(hold);
1067 }