Initial dev repository
[kcls-web.git] / opac / skin / css_alt / js / holds.js
diff --git a/opac/skin/css_alt/js/holds.js b/opac/skin/css_alt/js/holds.js
new file mode 100644 (file)
index 0000000..4f2cc55
--- /dev/null
@@ -0,0 +1,1051 @@
+var holdsOrgSelectorBuilt = false;\r
+var holdArgs;\r
+\r
+/* \r
+note: metarecord holds have a holdable_formats field that contains\r
+item_type(s)-item_forms(s)-language\r
+item_form and language are optional - if language exist and no \r
+item_form is specified, use item_type(s)--language\r
+*/\r
+\r
+var noEmailMessage;\r
+var noEmailMessageXUL;\r
+\r
+function hideResultsPage(bool) {\r
+       if(!bool) {\r
+               unHideMe($('result_header'));\r
+               unHideMe($('tehSideBar'));\r
+               //unHideMe($('facetSidebarContainer'));\r
+               unHideMe($('sidebar_div'));\r
+               unHideMe($('statusbar'));\r
+               unHideMe($('tips'));\r
+               unHideMe($('result_table_div'));\r
+               if($('rresults_page')) $('rresults_page').style.width="500px";\r
+       } else {\r
+               hideMe($('result_header'));\r
+               hideMe($('tehSideBar'));\r
+               hideMe($('facetSidebarContainer'));\r
+               hideMe($('sidebar_div'));\r
+               hideMe($('statusbar'));\r
+               hideMe($('tips'));\r
+               hideMe($('result_table_div'));\r
+               hideMe($('anonListTable'));\r
+               if($('rresults_page')) $('rresults_page').style.width="690px";\r
+       }\r
+}\r
+\r
+function holdsHandleStaff() {\r
+\r
+    // if we know the recipient's barcode, use it\r
+    if(xulG.patron_barcode) return _holdsHandleStaff();\r
+\r
+       swapCanvas($('xulholds_box'));\r
+       $('xul_recipient_barcode').focus();\r
+       $('xul_recipient_barcode').onkeypress = function(evt) \r
+               {if(userPressedEnter(evt)) { _holdsHandleStaff(); } };\r
+       $('xul_recipient_barcode_submit').onclick = _holdsHandleStaff;\r
+       $('xul_recipient_me').onclick = _holdsHandleStaffMe;\r
+\r
+       $('xul_recipient_barcode').onkeyup = function(evt) {\r
+        if($('xul_recipient_barcode').value == '') \r
+            $('xul_recipient_me').disabled = false;\r
+        else\r
+            $('xul_recipient_me').disabled = true;\r
+    };\r
+}\r
+\r
+$('holds_frozen_thaw_input').onchange = function(){holdsVerifyThawDateUI('holds_frozen_thaw_input');}\r
+$('holds_frozen_thaw_input').onkeyup = function(){holdsVerifyThawDateUI('holds_frozen_thaw_input');}\r
+\r
+function _holdsHandleStaffMe() {\r
+       holdArgs.recipient = G.user;\r
+       holdsDrawEditor();\r
+}\r
+\r
+function _holdsHandleStaff() {\r
+       var barcode = xulG.patron_barcode || $('xul_recipient_barcode').value;\r
+       var user = grabUserByBarcode( G.user.session, barcode );\r
+\r
+       var evt;\r
+       if(evt = checkILSEvent(user)) {\r
+               alertILSEvent(user);\r
+               return;\r
+       }\r
+\r
+       if(!barcode || !user) {\r
+               alertId('holds_invalid_recipient', barcode);\r
+               return\r
+       }\r
+\r
+       grabUserPrefs(user);\r
+\r
+       holdArgs.recipient = user;\r
+       holdsDrawEditor();\r
+}\r
+\r
+\r
+\r
+/** args:\r
+  * record, volume, copy (ids)\r
+  * request, recipient, editHold (objects)\r
+  */\r
+\r
+function holdsDrawEditor(args) {\r
+       holdArgs = (args) ? args : holdArgs;\r
+\r
+    if(!noEmailMessage) noEmailMessage = $('holds_email').removeChild($('holds.no_email'));\r
+    if(!noEmailMessageXUL) noEmailMessageXUL = $('holds_email').removeChild($('holds.no_email.xul'));\r
+\r
+       if(isXUL() && holdArgs.recipient == null && holdArgs.editHold == null) {\r
+               holdsHandleStaff();\r
+               return;\r
+       }\r
+\r
+       if(!holdArgs.recipient) holdArgs.recipient = G.user;\r
+       if(!holdArgs.requestor) holdArgs.requestor = G.user;\r
+\r
+       if(!(holdArgs.requestor && holdArgs.requestor.session)) {\r
+               alert("Please login first before placing a hold");\r
+               setCacheValue('returnURL',{href:window.location.href, record:holdArgs.record, type:holdArgs.type});\r
+               goTo(buildOPACLink({page:MYOPAC}, false, true));\r
+               return;\r
+               //detachAllEvt('common','locationChanged');\r
+               //attachEvt('common','loggedIn', holdsDrawEditor);\r
+               //initLogin();\r
+               //return;\r
+       }\r
+// flesh the args with the existing hold \r
+       if(holdArgs.editHold) holdArgsFromHold(holdArgs.editHold, holdArgs);\r
+\r
+       hideResultsPage(true);\r
+       holdsDrawWindow();\r
+}\r
+\r
+\r
+// updates the edit window with the existing hold's data \r
+function _holdsUpdateEditHold() {\r
+\r
+       var hold = holdArgs.editHold;\r
+       var qstats = holdArgs.status;\r
+\r
+       var orgsel = $('holds_org_selector');\r
+    var frozenbox = $('holds_frozen_chkbox');\r
+\r
+       setSelector(orgsel, hold.pickup_lib());\r
+\r
+       if( hold.capture_time() || qstats.status > 2 ) {\r
+        frozenbox.disabled = true;\r
+        $('holds_frozen_thaw_input').disabled = true;\r
+        if(qstats.status == 3) {\r
+            // no pickup lib changes while in-transit\r
+                   orgsel.disabled = true;\r
+        } else {\r
+            var orgs = fetchPermOrgs('UPDATE_PICKUP_LIB_FROM_HOLDS_SHELF');\r
+            if(orgs[0] == -1)\r
+                       orgsel.disabled = true;\r
+        }\r
+    } else {\r
+               orgsel.disabled = false;\r
+        frozenbox.disabled = false;\r
+    }\r
+\r
+\r
+       $('holds_submit').onclick = holdsEditHold;\r
+       $('holds_update').onclick = holdsEditHold;\r
+\r
+       if(hold.phone_notify()) {\r
+               $('holds_enable_phone').checked = true;\r
+               $('holds_phone').value = hold.phone_notify();\r
+\r
+       } else {\r
+               $('holds_phone').disabled = true;\r
+               $('holds_enable_phone').checked = false;\r
+       }\r
+\r
+       if(isTrue(hold.email_notify())) {\r
+               $('holds_enable_email').checked = true;\r
+\r
+       } else {\r
+               $('holds_enable_email').checked = false;\r
+       }\r
+\r
+    //$('holds_expire_time').setValue(dojo.date.stamp.fromISOString(hold.expire_time()));\r
+\r
+    /* populate the hold freezing info */\r
+    if(!frozenbox.disabled && isTrue(hold.frozen())) {\r
+        frozenbox.checked = true;\r
+        unHideMe($('hold_frozen_thaw_row'));\r
+        if(hold.thaw_date()) {\r
+            $('holds_frozen_thaw_input').value=dojo.date.stamp.fromISOString(hold.thaw_date());\r
+        } else {\r
+            $('holds_frozen_thaw_input').value='';\r
+        }\r
+    } else {\r
+        frozenbox.checked = false;\r
+        $('holds_frozen_thaw_input').value='';\r
+        hideMe($('hold_frozen_thaw_row'));\r
+    }\r
+}\r
+\r
+function holdsEditHold() {\r
+       var hold = holdsBuildHoldFromWindow();\r
+       if(!hold) return;\r
+       holdsUpdate(hold);\r
+       showCanvas();\r
+       if(holdArgs.onComplete)\r
+               holdArgs.onComplete(hold);\r
+}\r
+\r
+function holdArgsFromHold(hold, oargs) {\r
+       var args = (oargs) ? oargs : {};\r
+       args.type = hold.hold_type();\r
+       var target = hold.target();\r
+\r
+       switch(args.type) {\r
+               case 'M':\r
+                       args.metarecord = target;\r
+                       break;\r
+               case 'T':\r
+                       args.record = target;\r
+                       break;\r
+               case 'V':\r
+                       args.volume = target;\r
+                       break;\r
+               case 'C':\r
+                       args.copy = target;\r
+                       break;\r
+       }\r
+       return args;\r
+}\r
+\r
+function holdFetchObjects(hold, doneCallback) {\r
+       var args = (hold) ? holdArgsFromHold(hold) : holdArgs;\r
+       var type = args.type;\r
+\r
+       if( type == 'C' ) {\r
+               if( args.copyObject ) {\r
+\r
+                       args.copy = args.copyObject.id();\r
+                       args.volume = args.copyObject.call_number();\r
+                       _h_set_vol(args, doneCallback);\r
+\r
+               } else {\r
+                       var creq = new Request(FETCH_COPY, args.copy);\r
+\r
+                       creq.callback(\r
+                               function(r) {\r
+                                       var cp = r.getResultObject();\r
+                                       args.copyObject = cp;\r
+                                       args.volume = args.copyObject.call_number();\r
+                                       _h_set_vol(args, doneCallback);\r
+                               }\r
+                       );\r
+                       creq.send();\r
+               }\r
+       } else {\r
+               if( type == 'V' ) {\r
+                       _h_set_vol(args, doneCallback);\r
+\r
+               } else {\r
+                       if( type == 'T' ) {\r
+                               _h_set_rec(args, doneCallback);\r
+                       } else {\r
+                               _h_set_rec_descriptors(args, doneCallback);\r
+                       }\r
+               }\r
+       }\r
+\r
+       return args;\r
+}\r
+\r
+function _h_set_vol(args, doneCallback) {\r
+\r
+       if( args.volumeObject ) {\r
+               args.volume = args.volumeObject.id();\r
+               args.record = args.volumeObject.record();\r
+               _h_set_rec(args, doneCallback);\r
+\r
+       } else {\r
+\r
+               var vreq = new Request(FETCH_VOLUME, args.volume);\r
+               vreq.callback(\r
+                       function(r) {\r
+                               var vol = r.getResultObject();\r
+                               args.volumeObject = vol;\r
+                               args.record = vol.record();\r
+                               _h_set_rec(args, doneCallback);\r
+                       }\r
+               );\r
+               vreq.send();\r
+       }\r
+}\r
+\r
+function _h_set_rec(args, doneCallback) {\r
+\r
+       if(args.recordObject) \r
+               args.record = args.recordObject.doc_id();\r
+       else \r
+               args.recordObject = findRecord( args.record, 'T' );\r
+       \r
+       if( args.type == 'T' || args.type == 'M' ) \r
+               _h_set_rec_descriptors(args, doneCallback);\r
+       else \r
+               if(doneCallback) doneCallback(args);\r
+}\r
+\r
+\r
+function _h_set_rec_descriptors(args, doneCallback) {\r
+\r
+       // grab the list of record desciptors attached to this records metarecord \r
+       if( ! args.recordDescriptors )  {\r
+               var params = { record: args.record };\r
+\r
+               if( ! args.record ) {\r
+                       if( args.metarecord )\r
+                               params = { metarecord : args.metarecord };\r
+                       else \r
+                               params = { metarecord : args.metarecordObject.doc_id() };\r
+               }\r
+\r
+               var req = new Request(FETCH_MR_DESCRIPTORS, params );\r
+               req.callback(\r
+                       function(r) {\r
+                               var data = r.getResultObject();\r
+                               args.recordDescriptors = data.descriptors;\r
+                               args.metarecord = data.metarecord;\r
+                               if( args.type == 'M' && ! args.metarecordObject) \r
+                                       args.metarecordObject = findRecord(args.metarecord, 'M');       \r
+                                \r
+                               if(doneCallback) doneCallback(args);\r
+                       }\r
+               );\r
+               req.send();\r
+\r
+       } else {\r
+               if(doneCallback) doneCallback(args);\r
+       }\r
+\r
+       return args;\r
+}\r
+\r
+\r
+\r
+function holdsDrawWindow(bool) {\r
+       swapCanvas($('holds_box'));\r
+       $('holds_cancel').onclick = function(){\r
+               hideResultsPage(false);\r
+               hideMe($('holds_box'));\r
+               unHideMe($('canvas_main'));\r
+               //runEvt('common', 'holdUpdateCanceled'), showCanvas() \r
+       };\r
+       $('holds_submit').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};\r
+       $('holds_update').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};\r
+       holdFetchObjects(null, \r
+               function(){\r
+                       __holdsDrawWindow();\r
+\r
+                       if(holdArgs.editHold) {\r
+                               //hideMe($('holds_submit'));\r
+                               unHideMe($('holds_update'));\r
+                               var req = new Request(FETCH_HOLD_STATUS, \r
+                                       G.user.session, holdArgs.editHold.id());\r
+                               req.send(true);\r
+                               holdArgs.status = req.result();\r
+                               _holdsUpdateEditHold();\r
+                       }  \r
+               }\r
+       );\r
+}\r
+\r
+function selOrgChange(e) {\r
+       \r
+       $('holds_pickup_lib').innerHTML = this.options[this.selectedIndex].text;\r
+}\r
+\r
+function __holdsDrawWindow() {\r
+\r
+       var rec = holdArgs.recordObject;\r
+       var vol = holdArgs.volumeObject;\r
+       var copy = holdArgs.copyObject;\r
+       var mr = holdArgs.metarecordObject;\r
+\r
+       rec = (rec) ? rec : mr;\r
+\r
+       if(!holdsOrgSelectorBuilt) {\r
+               holdsBuildOrgSelector(null,0);\r
+               holdsOrgSelectorBuilt = true;\r
+               var selector = $('holds_org_selector');\r
+\r
+               /*\r
+               var o_loc = findOrgUnit(getOrigLocation());\r
+               var t = findOrgType(o_loc.ou_type());\r
+               if( t.can_have_users() ) \r
+                       setSelector(selector, o_loc.id());\r
+               else \r
+               */\r
+               selector.onchange = selOrgChange;\r
+               setSelector(selector, holdArgs.recipient.home_ou());\r
+       }\r
+       \r
+       var obj = findOrgUnit(holdArgs.recipient.home_ou());\r
+       $('holds_pickup_lib').innerHTML = obj.name();\r
+\r
+       /*\r
+       if(isXUL()) {\r
+               var dsel = $('holds_depth_selector');\r
+               unHideMe($('holds_depth_selector_row'));\r
+               if(dsel.getElementsByTagName('option').length == 0) {\r
+                       var types = globalOrgTypes;\r
+                       var depth = findOrgDepth(G.user.ws_ou());\r
+                       iterate(types, \r
+                               function(t) {\r
+                                       if(t.depth() > depth) return;\r
+                                       insertSelectorVal(dsel, -1, t.opac_label(), t.depth());\r
+                               }\r
+                       );\r
+               }\r
+       }\r
+       */\r
+\r
+       appendClear($('holds_recipient'), text(\r
+               holdArgs.recipient.family_name() + ', ' +  \r
+                       holdArgs.recipient.first_given_name()));\r
+       appendClear($('holds_title'), text(rec.title()));\r
+       appendClear($('holds_author'), text(rec.author()));\r
+\r
+       if( holdArgs.type == 'V' || holdArgs.type == 'C' ) {\r
+\r
+               unHideMe($('holds_type_row'));\r
+               unHideMe($('holds_cn_row'));\r
+               appendClear($('holds_cn'), text(holdArgs.volumeObject.label()));\r
+\r
+               if( holdArgs.type == 'V'  ) {\r
+                       unHideMe($('holds_is_cn'));\r
+                       hideMe($('holds_is_copy'));\r
+\r
+               } else {\r
+                       hideMe($('holds_is_cn'));\r
+                       unHideMe($('holds_is_copy'));\r
+                       unHideMe($('holds_copy_row'));\r
+                       appendClear($('holds_copy'), text(holdArgs.copyObject.barcode()));\r
+               }\r
+\r
+       } else {\r
+               hideMe($('holds_type_row'));\r
+               hideMe($('holds_copy_row'));\r
+               hideMe($('holds_cn_row'));\r
+       }\r
+\r
+       removeChildren($('holds_format'));\r
+\r
+       var mods_formats = rec.types_of_resource();\r
+       var formats;\r
+\r
+       if(holdArgs.recordDescriptors)\r
+               formats = holdArgs.recordDescriptors[0].item_type();\r
+\r
+       if( holdArgs.type == 'T' ) {\r
+               var desc = grep( holdArgs.recordDescriptors,\r
+                       function(i) {\r
+                               return (i.record() == holdArgs.record); \r
+                       }\r
+               );\r
+               formats = desc[0].item_type();\r
+       }\r
+\r
+       if( holdArgs.type == 'M' ) {\r
+               var data = holdsParseMRFormats(holdArgs.editHold.holdable_formats());\r
+               mods_formats = data.mods_formats;\r
+               formats = data.formats;\r
+       }\r
+\r
+\r
+       for( var i in mods_formats ) {\r
+               var res = mods_formats[i];\r
+               var img = elem("img");\r
+               setResourcePic(img, res);\r
+               $('holds_format').appendChild(img);\r
+               if(formats)\r
+                       $('holds_format').appendChild(text(' '+ MARCTypeToFriendly(formats[i]) +' '));\r
+               else\r
+                       $('holds_format').appendChild(text(' '+ mods_formats[i] +' '));\r
+               $('holds_format').appendChild(elem('br'));\r
+       }\r
+\r
+\r
+       $('holds_phone').value = (holdArgs.recipient.day_phone())?holdArgs.recipient.day_phone():"";\r
+       appendClear( $('holds_email'), text(holdArgs.recipient.email()));\r
+\r
+       var pref = holdArgs.recipient.prefs[PREF_HOLD_NOTIFY];\r
+\r
+       if(pref) {\r
+               if( ! pref.match(/email/i) ) {\r
+                       $('holds_enable_email').checked = false;\r
+               } else {\r
+                       $('holds_enable_email').checked = true;\r
+               }\r
+\r
+               if( ! pref.match(/phone/i) ) {\r
+                       $('holds_phone').disabled = true;\r
+                       $('holds_enable_phone').checked = false;\r
+               } else {\r
+                       $('holds_phone').disabled = false;\r
+                       $('holds_enable_phone').checked = true;\r
+               }\r
+       }\r
+\r
+    if(!holdArgs.recipient.email()) {\r
+               $('holds_enable_email').checked = false;        \r
+               $('holds_enable_email').disabled = true;\r
+        var message;\r
+        if(isXUL()) {\r
+            message = noEmailMessageXUL.cloneNode(true);\r
+               appendClear($('holds_email'), message);\r
+        } else {\r
+            message = noEmailMessage.cloneNode(true);\r
+               appendClear($('holds_email'), message);\r
+            $('holds.no_email.my_account').setAttribute('href', buildOPACLink({page:MYOPAC},null,true));\r
+        }\r
+        unHideMe(message);\r
+    }\r
+\r
+       if(!$('holds_phone').value) \r
+               $('holds_enable_phone').checked = false;        \r
+\r
+       appendClear($('holds_physical_desc'), text(rec.physical_description()));\r
+\r
+       if(holdArgs.type == 'M') hideMe($('hold_physical_desc_row'));\r
+\r
+       holdsSetFormatSelector();\r
+\r
+    $('holds_frozen_chkbox').checked = false;\r
+    hideMe($('hold_frozen_thaw_row'));\r
+\r
+    var interval = fetchOrgSettingDefault(holdArgs.recipient.home_ou(), 'circ.hold_expire_interval');\r
+    var secs = 0;\r
+    if(interval) {\r
+        secs = interval_to_seconds(interval);\r
+        var expire = new Date();\r
+        expire.setTime(expire.getTime() + Number(secs + '000'));\r
+        if(dijit.byId('holds_expire_time')) dijit.byId('holds_expire_time').setValue(expire);\r
+    }\r
+}\r
+\r
+function holdsParseMRFormats(str) {\r
+       var data = str.split(/-/);      \r
+\r
+       var formats = [];\r
+       var mods_formats = [];\r
+\r
+       for( var i = 0; i < data[0].length; i++ ) {\r
+               formats.push( data[0].charAt(i) );\r
+               mods_formats.push( MARCFormatToMods( formats[i] ) );\r
+       }\r
+       \r
+       formats = uniquify(formats);\r
+       mods_formats = uniquify(mods_formats);\r
+\r
+       return {\r
+               formats                 : formats,\r
+               mods_formats    : mods_formats,\r
+               lang                            : data[2],\r
+               largeprint              : data[1]\r
+       };\r
+}\r
+\r
+\r
+function holdsSetFormatSelector() {\r
+       var type = holdArgs.type;\r
+       if( type == 'C' || type == 'V' || holdArgs.editHold ) return;\r
+\r
+       var data                                = holdsGetFormats();\r
+       var avail_formats       = data.avail_formats;\r
+       var sel_formats = data.sel_formats;\r
+       holdArgs.language = data.lang;\r
+\r
+       unHideMe($('holds_alt_formats_row_extras'));\r
+       var selector = $('hold_alt_form_selector');\r
+\r
+       for( var i = 0; i < avail_formats.length; i++ ) {\r
+               var form = avail_formats[i];\r
+               unHideMe(findSelectorOptByValue(selector, form));\r
+       }\r
+}\r
+\r
+\r
+function holdsGetFormats() {\r
+\r
+       var lang;\r
+       var formats = [];\r
+       var sformats = []; // selected formats \r
+\r
+       var type = holdArgs.type;\r
+       var desc = holdArgs.recordDescriptors;\r
+       var rec = holdArgs.record;\r
+       var mrec = holdArgs.metarecord;\r
+\r
+       if( type == 'T' ) {\r
+\r
+               for( var i = 0; i < desc.length; i++ ) {\r
+                       var d = desc[i];\r
+                       if( d.record() == holdArgs.record ) {\r
+                               lang = d.item_lang();\r
+                               holdArgs.myFormat =  _t_f_2_format(d.item_type(), d.item_form());\r
+                               sformats.push(holdArgs.myFormat);\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       for( var i = 0; i < desc.length; i++ ) {\r
+               var d = desc[i];\r
+               if( d.item_lang() != lang ) continue;\r
+               formats.push( _t_f_2_format(d.item_type(), d.item_form()));\r
+       }\r
+\r
+       formats = uniquify(formats);\r
+\r
+       return {\r
+               lang : lang,\r
+               avail_formats : formats, \r
+               sel_formats : sformats\r
+       };\r
+}\r
+\r
+\r
+\r
+function _t_f_2_format(type, form) {\r
+       if( form == 'd' ) return 'at-d';\r
+       return (type == 'a' || type == 't') ? 'at' : \r
+               ( type == 'i' || type == 'g' || type == 'j' ) ? type : null;\r
+}\r
+\r
+function holdsSetSelectedFormats() {\r
+\r
+       var cn = $('holds_alt_formats_row').className;\r
+       if( cn && cn.match(/hide_me/) ) return;\r
+\r
+       var selector = $('hold_alt_form_selector');\r
+       var vals = getSelectedList(selector);\r
+\r
+       if(vals.length == 0) return;\r
+\r
+       var fstring = "";\r
+\r
+       if( contains(vals, 'at-d') ) {\r
+               if( contains(vals, 'at') )\r
+                       fstring = 'at';\r
+               else \r
+                       fstring = 'at-d';\r
+       } else {\r
+               if( contains(vals, 'at') )\r
+                       fstring = 'at';\r
+       }\r
+\r
+       for( var i = 0; i < vals.length; i++ ) {\r
+               var val = vals[i];\r
+               if( !val.match(/at/) ) fstring = val + fstring;\r
+       }\r
+\r
+       if( holdArgs.language ) {\r
+               if( fstring.match(/-/) )\r
+                       fstring = fstring + '-' + holdArgs.language;\r
+               else\r
+                       fstring = fstring + '--' + holdArgs.language;\r
+       }\r
+       return fstring;\r
+}\r
+\r
+\r
+function holdsCheckPossibility(pickuplib, hold, recurse) {\r
+\r
+       var args = { \r
+               titleid : holdArgs.record,\r
+               volume_id : holdArgs.volume,\r
+               copy_id : holdArgs.copy,\r
+               hold_type : holdArgs.type,\r
+               patronid : holdArgs.recipient.id(),\r
+               depth : 0, \r
+               pickup_lib : pickuplib \r
+       };\r
+\r
+       if(recurse) {\r
+               /* if we're calling create again (recursing), \r
+                       we know that the hold possibility check already succeeded */\r
+               holdHandleCreateResponse({_recurse:true, _hold:hold}, true );\r
+\r
+       } else {\r
+               _debug("hold possible args = "+js2JSON(args));\r
+       \r
+               var req = new Request(CHECK_HOLD_POSSIBLE, G.user.session, args );\r
+       \r
+               req.request.alertEvent = false;\r
+               req.request._hold = hold;\r
+               req.request._recurse = recurse;\r
+               req.callback(holdHandleCreateResponse);\r
+               req.send();\r
+       }\r
+}\r
+\r
+\r
+function holdsBuildOrgSelector(node, sel) {\r
+\r
+       if(!node) node = globalOrgTree;\r
+    if(!isTrue(node.opac_visible())) return;\r
+\r
+       var selector = sel?sel:$('holds_org_selector');\r
+       var index = selector.options.length;\r
+\r
+       var type = findOrgType(node.ou_type());\r
+       var indent = type.depth() - 1;\r
+       var opt = setSelectorVal( selector, index, node.name(), node.id(), null, indent );\r
+       if(!type.can_have_users()) {\r
+               opt.disabled = true;\r
+               addCSSClass(opt, 'disabled_option');\r
+       }\r
+       \r
+       for( var i in node.children() ) {\r
+               var child = node.children()[i];\r
+               if(child) holdsBuildOrgSelector(child);\r
+       }\r
+}\r
+\r
+function holdsBuildHoldFromWindow() {\r
+\r
+       var org = getSelectorVal($('holds_org_selector'));\r
+       var node = findOrgUnit(org);\r
+       var ntype = findOrgType(node.ou_type());\r
+       if(!ntype.can_have_users()) {\r
+               alertId('holds_pick_good_org');\r
+               return;\r
+       }\r
+\r
+       var hold = new ahr();\r
+       if(holdArgs.editHold) {\r
+               hold = holdArgs.editHold;\r
+               holdArgs.editHold = null;\r
+       }\r
+\r
+       if( $('holds_enable_phone').checked ) {\r
+               var phone = $('holds_phone').value;\r
+               if( !phone || !phone.match(REGEX_PHONE) ) {\r
+                       alert($('holds_bad_phone').innerHTML);\r
+                       return null;\r
+               }\r
+               hold.phone_notify(phone);\r
+\r
+       } else {\r
+               hold.phone_notify("");\r
+       }\r
+\r
+       if( $('holds_enable_email').checked ) \r
+               hold.email_notify(1);\r
+       else\r
+               hold.email_notify(0);\r
+\r
+       var target;\r
+\r
+       switch(holdArgs.type) {\r
+               case 'M':\r
+                       target = holdArgs.metarecord; break;\r
+               case 'T':\r
+                       target = holdArgs.record; break;\r
+               case 'V':\r
+                       target = holdArgs.volume; break;\r
+               case 'C':\r
+                       target = holdArgs.copy; break;\r
+       }\r
+\r
+\r
+\r
+       hold.pickup_lib(org); \r
+       //hold.request_lib(org); \r
+       hold.requestor(holdArgs.requestor.id());\r
+       hold.usr(holdArgs.recipient.id());\r
+       hold.target(target);\r
+       hold.hold_type(holdArgs.type);\r
+\r
+    try{var expDate = dijit.byId('holds_expire_time').getValue();} catch(e){}\r
+    if(expDate) {\r
+        var expireDate = dojo.date.stamp.toISOString(expDate);\r
+        expireDate = holdsVerifyThawDate(expireDate); \r
+        if(expireDate)\r
+            hold.expire_time(expireDate);\r
+        else \r
+            return;\r
+    }\r
+\r
+    // see if this hold should be frozen and for how long\r
+    if($('holds_frozen_chkbox').checked) {\r
+        hold.frozen('t');\r
+        unHideMe($('hold_frozen_thaw_row'));\r
+        thawDate = dojo.date.stamp.toISOString(dijit.byId('holds_frozen_thaw_input').getValue());\r
+        if(thawDate) {\r
+            thawDate = holdsVerifyThawDate(thawDate); \r
+            if(thawDate) \r
+                hold.thaw_date(thawDate);\r
+            else\r
+                return;\r
+        } else {\r
+            hold.thaw_date(null);\r
+        }\r
+    } else {\r
+        hold.frozen('f');\r
+        hold.thaw_date(null);\r
+    }\r
+\r
+       //check for alternate hold formats \r
+       var fstring = holdsSetSelectedFormats();\r
+       if(fstring) { \r
+               hold.hold_type('M'); \r
+               hold.holdable_formats(fstring);\r
+               hold.target(holdArgs.metarecord);\r
+       }\r
+       return hold;\r
+}\r
+       \r
+function holdsPlaceHold(hold, recurse) {\r
+       if(!hold) return;\r
+       swapCanvas($('check_holds_box'));\r
+       holdsCheckPossibility(hold.pickup_lib(), hold, recurse);\r
+}\r
+\r
+\r
+function holdHandleCreateResponse(r, recurse) {\r
+\r
+       if(!recurse) {\r
+               var res = r.getResultObject();\r
+               if(checkILSEvent(res) || res.success != 1) {\r
+                       if(res.success != 1) {\r
+                               alert($('hold_not_allowed').innerHTML+(!res.last_event.desc?"":"\n\nHold failure description:\n"+res.last_event.desc));\r
+                       } else {\r
+                               if( res.textcode == 'PATRON_BARRED' ) {\r
+                                       alertId('hold_failed_patron_barred');\r
+                               } else {\r
+                                       alert($('hold_not_allowed').innerHTML+(!res.last_event.desc?"":"\n\nHold failure description:\n"+res.last_event.desc));\r
+                               }\r
+                       }\r
+                       swapCanvas($('holds_box'));\r
+                       return;\r
+               }\r
+        r._hold.selection_depth(res.depth);\r
+       }       \r
+\r
+       holdCreateHold(r._recurse, r._hold);\r
+       hideResultsPage(false);\r
+}\r
+\r
+\r
+function holdCreateHold( recurse, hold ) {\r
+       var method = CREATE_HOLD;\r
+       if(recurse) method = CREATE_HOLD_OVERRIDE;\r
+       var req = new Request( method, holdArgs.requestor.session, hold );\r
+       req.request.alertEvent = false;\r
+       req.send(true);\r
+       var res = req.result();\r
+       holdProcessResult(hold, res, recurse);\r
+\r
+       showCanvas();\r
+\r
+       runEvt('common', 'holdUpdated');\r
+}\r
+\r
+\r
+function holdProcessResult( hold, res, recurse ) {\r
+\r
+       if( res && res > -1 ) {\r
+               alert($('holds_success').innerHTML);\r
+               holdArgs = null;\r
+        if(isXUL() && typeof xulG.opac_hold_placed == 'function')\r
+            xulG.opac_hold_placed(res);\r
+\r
+       } else {\r
+\r
+               if( recurse ) {\r
+                       alert($('holds_failure').innerHTML);\r
+                       return;\r
+               }\r
+\r
+               if( grep(res, function(e) { return (e.textcode == 'HOLD_EXISTS'); }) ) {\r
+                       if( fetchPermOrgs('HOLD_EXISTS.override')[0] != -1 ) {\r
+                               if( confirm($('hold_dup_exists_override').innerHTML) ) {\r
+                                       return holdsPlaceHold(hold, true);\r
+                               }\r
+                return;\r
+\r
+                       } else {\r
+                               return alert($('hold_dup_exists').innerHTML);\r
+                       }\r
+               }\r
+\r
+               if( grep(res, function(e) { return (e.textcode == 'HOLD_ITEM_CHECKED_OUT'); }) ) {\r
+                       if( fetchPermOrgs('HOLD_ITEM_CHECKED_OUT.override')[0] != -1 ) {\r
+                               if( confirm($('hold_checked_out_override').innerHTML) ) {\r
+                                       return holdsPlaceHold(hold, true);\r
+                               }\r
+                return;\r
+\r
+                       } else {\r
+                               return alert($('hold_checked_out').innerHTML);\r
+                       }\r
+               }\r
+\r
+\r
+               alert($('holds_failure').innerHTML);\r
+       }\r
+}\r
+\r
+\r
+function holdsCancel(holdid, user) {\r
+       if(!user) user = G.user;\r
+       var req = new Request(CANCEL_HOLD, user.session, holdid, /* Patron via OPAC */ 6);\r
+       req.send(true);\r
+       return req.result();\r
+       runEvt('common', 'holdUpdated');\r
+}\r
+\r
+function holdsUpdate(hold, user) {\r
+       if(!user) user = G.user;\r
+       var req = new Request(UPDATE_HOLD, user.session, hold);\r
+       req.send(true);\r
+       var x = req.result(); // cause an exception if there is one \r
+       runEvt('common', 'holdUpdated');\r
+}\r
+\r
+/* verify that the thaw date is valid and after today */\r
+function holdsVerifyThawDate(dateString, isGreater) {\r
+    thawDate = dojo.date.stamp.fromISOString(dateString);\r
+    if(thawDate) {\r
+        if(isGreater) {\r
+            if(dojo.date.compare(thawDate) > 0) {\r
+                return dojo.date.stamp.toISOString(thawDate);\r
+            }\r
+        } else {\r
+            return dojo.date.stamp.toISOString(thawDate);\r
+        }\r
+    }\r
+    return null;\r
+}\r
+\r
+function holdsVerifyThawDateUI(element) {\r
+    value = dojo.date.stamp.toISOString(dijit.byId(element).getValue());\r
+\r
+    if(!value) {\r
+        removeCSSClass($(element), 'invalid_field');\r
+        return;\r
+    }\r
+\r
+    if(!holdsVerifyThawDate(value, true)) {\r
+        addCSSClass($(element), 'invalid_field');\r
+    } else {\r
+        removeCSSClass($(element), 'invalid_field');\r
+    }\r
+}\r
+\r
+\r
+function editHold(h) {\r
+       var row = $('myopac_holds_row_'+h);\r
+       var objs = [];\r
+       \r
+       objs['hold_pickup_lib'] = $n(row,'hold_pickup_lib');\r
+       objs['hold_pickup_lib_sel'] = $n(row,'hold_pickup_lib_sel');\r
+       objs['hold_active'] = $n(row,'hold_active');\r
+       objs['activate_label'] = $n(row,'activate_label');\r
+       objs['activate_date'] = $n(row,'activate_date');\r
+       objs['activate_box'] = $n(row,'activate_box');\r
+       objs['hold_expires_label'] = $n(row,'hold_expires_label');\r
+       objs['hold_expires'] = $n(row,'hold_expires');\r
+       objs['hold_expires_box'] = $n(row,'hold_expires_box');\r
+       objs['hold_active_sel'] = $n(row,'hold_active_sel');\r
+       objs['hold_edit_link'] = $n(row,'hold_edit_link');\r
+       objs['hold_save_link'] = $n(row,'hold_save_link');\r
+       objs['hold_cancel_link'] = $n(row,'hold_cancel_link');\r
+               \r
+       for(var i in objs) unHideMe(objs[i]);\r
+       \r
+       hideMe(objs['activate_date']);\r
+       hideMe(objs['hold_active']);\r
+       hideMe(objs['hold_expires']);\r
+       hideMe(objs['hold_pickup_lib']);\r
+       hideMe(objs['hold_edit_link']);\r
+}\r
+\r
+function cancelHold(h) {\r
+       var row = $('myopac_holds_row_'+h);\r
+       var objs = [];\r
+       \r
+       objs['hold_pickup_lib'] = $n(row,'hold_pickup_lib');\r
+       objs['hold_pickup_lib_sel'] = $n(row,'hold_pickup_lib_sel');\r
+       objs['hold_active'] = $n(row,'hold_active');\r
+       objs['activate_label'] = $n(row,'activate_label');\r
+       objs['activate_date'] = $n(row,'activate_date');\r
+       objs['activate_box'] = $n(row,'activate_box');\r
+       objs['hold_expires_label'] = $n(row,'hold_expires_label');\r
+       objs['hold_expires'] = $n(row,'hold_expires');\r
+       objs['hold_expires_box'] = $n(row,'hold_expires_box');\r
+       objs['hold_active_sel'] = $n(row,'hold_active_sel');\r
+       objs['hold_edit_link'] = $n(row,'hold_edit_link');\r
+       objs['hold_save_link'] = $n(row,'hold_save_link');\r
+       objs['hold_cancel_link'] = $n(row,'hold_cancel_link');\r
+               \r
+       for(var i in objs) hideMe(objs[i]);\r
+       \r
+       unHideMe(objs['hold_edit_link']);\r
+       unHideMe(objs['hold_pickup_lib']);\r
+       unHideMe(objs['holds_active']);\r
+       unHideMe(objs['hold_active']);\r
+       unHideMe(objs['activate_date']);\r
+       unHideMe(objs['hold_expires']);\r
+       if(objs['hold_expires'].innerHTML) unHideMe(objs['hold_expires_label']);\r
+       if(objs['activate_date'].innerHTML) unHideMe(objs['activate_label']);\r
+}\r
+\r
+function saveHold(h) {\r
+       var row = $('myopac_holds_row_'+h);\r
+       var hold = holdsCache[holdsCacheMap[h]].hold;\r
+       \r
+       var activateDataBox = $n(row,'activate_box');\r
+       var expireDateBox = $n(row,'hold_expires_box');\r
+       var pickupLibSel = $n(row,'hold_pickup_lib_sel');\r
+       var activateSel = $n(row,'hold_active_sel');\r
+       var expireTime = dojo.date.stamp.toISOString(new Date(Date.parse(expireDateBox.value)),null);\r
+       var activateTime = dojo.date.stamp.toISOString(new Date(Date.parse(activateDataBox.value)),null);\r
+       if(parseInt(expireTime)) hold.expire_time(expireTime);\r
+       if(parseInt(activateTime)) hold.thaw_date(activateTime);\r
+       hold.frozen(activateSel.options[activateSel.selectedIndex].value);\r
+       hold.pickup_lib(pickupLibSel.options[pickupLibSel.selectedIndex].value);\r
+       row.style.background= isTrue(hold.frozen())?"#ebf9ff":"";\r
+       \r
+       fieldmapper.standardRequest(['open-ils.circ','open-ils.circ.hold.update'],{params:[G.user.session,hold],oncomplete:refreshHold});\r
+}\r
+\r
+function updateHoldInfo(holdid,holdrow) {\r
+       var h = holdsCache[holdsCacheMap[holdid]].hold;\r
+       if(!h) return;\r
+       var row = holdrow?holdrow:$('myopac_holds_row_'+holdid);\r
+       if(!row) return;\r
+       \r
+       $n(row,'hold_pickup_lib').innerHTML = findOrgUnit(h.pickup_lib()).name();\r
+       $n(row,'hold_active').innerHTML = isTrue(h.frozen())?"Suspended":"Active";\r
+       \r
+       if(h.thaw_date()) {\r
+               var d = dojo.date.stamp.fromISOString(h.thaw_date());\r
+               $n(row, 'activate_date').innerHTML = dojo.date.locale.format(d, {selector: 'date', fullYear: true});\r
+               unHideMe($n(row,'activate_label'));\r
+               $n(row,'activate_box').value = dojo.date.locale.format(d, {selector:'date', fullYear: true});\r
+       }\r
+       \r
+       if(h.expire_time()) {\r
+               var exp_date = dojo.date.stamp.fromISOString(h.expire_time());\r
+               $n(row, 'hold_expires').innerHTML = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});\r
+               unHideMe($n(row,'hold_expires_label'));\r
+               $n(row,'hold_expires_box').value = dojo.date.locale.format(exp_date, {selector:'date', fullYear: true});\r
+       }\r
+}\r
+\r
+function refreshHold(r) {\r
+       var hold = r.recv().content();\r
+       if(!parseInt(hold)) return;\r
+       updateHoldInfo(hold);\r
+       cancelHold(hold);\r
+}\r