81f5b20693f9f35b383646d7afeb2817f332dc58
[Evergreen.git] / Open-ILS / xul / staff_client / server / patron / holds.js
1 dump('entering patron.holds.js\n');
2
3 function $(id) { return document.getElementById(id); }
4
5 if (typeof patron == 'undefined') patron = {};
6 patron.holds = function (params) {
7
8     JSAN.use('util.error'); this.error = new util.error();
9     JSAN.use('util.network'); this.network = new util.network();
10     JSAN.use('OpenILS.data'); this.data = new OpenILS.data(); this.data.init({'via':'stash'});
11 }
12
13 patron.holds.prototype = {
14
15     'hold_interface_type' : null,
16
17     'pull_from_shelf_interface' : {
18         '_default' : { 'limit' : 100, 'offset' : 0 },
19         'current' : { 'limit' : 100, 'offset' : 0 }
20     },
21
22     'filter_lib' : null,
23
24     'hold_subscription_map' : {},
25
26     'expired' : false,
27     'post_clear_shelf_hold_action_map' : {},
28
29     'retrieve_ids' : [],
30
31     'holds_map' : {},
32
33     'flatten_copy' : function(hold) {
34         try { if ( hold.current_copy() && typeof hold.current_copy() == 'object') hold.current_copy( hold.current_copy().id() ); } catch(E) { alert('FIXME: Error flattening hold before hold update: ' + E); }
35         return hold;
36     },
37
38     'init' : function( params ) {
39
40         var obj = this;
41
42         dojo.require("openils.Util");
43
44         obj.patron_id = params['patron_id'];
45         obj.patron_barcode = params['patron_barcode'];
46         obj.docid = params['docid'];
47         obj.shelf = params['shelf'];
48         obj.tree_id = params['tree_id'];
49
50         var progressmeter = document.getElementById('progress');
51
52         JSAN.use('circ.util');
53         var columns = circ.util.hold_columns(
54             {
55                 'title' : { 'hidden' : false, 'flex' : '3' },
56                 'request_time' : { 'hidden' : false },
57                 'pickup_lib_shortname' : { 'hidden' : false },
58                 'hold_type' : { 'hidden' : false },
59                 'current_copy' : { 'hidden' : false },
60                 'capture_time' : { 'hidden' : false },
61                 'notify_time' : { 'hidden' : false },
62                 'notify_count' : { 'hidden' : false },
63                 'cancel_cause' : { 'hidden' : ! ( obj.data.hash.aous['circ.holds.canceled.display_count'] || obj.data.hash.aous['circ.holds.canceled.display_age'] ) },
64                 'cancel_note' : { 'hidden' :  ! ( obj.data.hash.aous['circ.holds.canceled.display_count'] || obj.data.hash.aous['circ.holds.canceled.display_age'] ) },
65                 'cancel_time' : { 'hidden' :  ! ( obj.data.hash.aous['circ.holds.canceled.display_count'] || obj.data.hash.aous['circ.holds.canceled.display_age'] ) },
66                 'post_clear_shelf_action' : { 'hidden' : obj.shelf ? false : true }
67             }
68         );
69
70         JSAN.use('util.list'); obj.list = new util.list( obj.tree_id || 'holds_list');
71         obj.list.init(
72             {
73                 'columns' : columns.concat(
74                     obj.list.fm_columns('acp', {
75                         '*' : { 'expanded_label' : true, 'hidden' : true },
76                         // example of unhiding some columns by default
77                         // 'acp_circ_modifier' : { 'hidden' : false }
78                     })
79                 ),
80                 'retrieve_row' : function(params) {
81                     var row = params.row;
82                     try {
83                         obj.network.simple_request('FM_AHR_BLOB_RETRIEVE.authoritative', [ ses(), row.my.hold_id ],
84                             function(blob_req) {
85                                 try {
86                                     var blob = blob_req.getResultObject();
87                                     if (typeof blob.ilsevent != 'undefined') throw(blob);
88                                     row.my.ahr = blob.hold;
89                                     row.my.status = blob.status;
90                                     row.my.ahr.status( blob.status );
91                                     row.my.acp = blob.copy;
92                                     row.my.acn = blob.volume;
93                                     row.my.mvr = blob.mvr;
94                                     row.my.part = blob.part;
95                                     row.my.issuance = blob.issuance;
96                                     if (blob.issuance) {
97                                         row.my.subscription = blob.issuance.subscription();
98                                         obj.hold_subscription_map[ row.my.hold_id ] = row.my.subscription;
99                                     }
100                                     row.my.patron_family_name = blob.patron_last;
101                                     row.my.patron_first_given_name = blob.patron_first;
102                                     row.my.patron_barcode = blob.patron_barcode;
103                                     row.my.patron_alias = blob.patron_alias;
104                                     row.my.total_holds = blob.total_holds;
105                                     row.my.queue_position = blob.queue_position;
106                                     row.my.potential_copies = blob.potential_copies;
107                                     row.my.estimated_wait = blob.estimated_wait;
108                                     row.my.ahrn_count = blob.hold.notes().length;
109
110                                     var copy_id = row.my.ahr.current_copy();
111                                     if (typeof copy_id == 'object') {
112                                         if (copy_id == null) {
113                                             if (typeof row.my.acp == 'object' && row.my.acp != null) copy_id = row.my.acp.id();
114                                         } else {
115                                             copy_id = copy_id.id();
116                                         }
117                                     } else {
118                                         copy_id = row.my.acp.id();
119                                     }
120
121                                     obj.holds_map[ row.my.ahr.id() ] = blob;
122                                     params.row_node.setAttribute('retrieve_id',
123                                         js2JSON({
124                                             'copy_id':copy_id,
125                                             'barcode':row.my.acp ? row.my.acp.barcode() : null,
126                                             'id':row.my.ahr.id(),
127                                             'type':row.my.ahr.hold_type(),
128                                             'target':row.my.ahr.target(),
129                                             'usr':row.my.ahr.usr()
130                                         })
131                                     );
132                                     if (typeof params.on_retrieve == 'function') { params.on_retrieve(row); }
133
134                                 } catch(E) {
135                                     obj.error.standard_unexpected_error_alert($("patronStrings").getFormattedString('staff.patron.holds.init.hold_num_error', [row.my.hold_id]), E);
136                                 }
137                             }
138                         );
139                     } catch(E) {
140                         obj.error.sdump('D_ERROR','retrieve_row: ' + E );
141                     }
142                     return row;
143                 },
144                 'on_select' : function(ev) {
145                     JSAN.use('util.functional');
146                     var sel = obj.list.retrieve_selection();
147                     obj.controller.view.sel_clip.setAttribute('disabled',sel.length < 1);
148                     obj.retrieve_ids = util.functional.map_list(
149                         sel,
150                         function(o) { return JSON2js( o.getAttribute('retrieve_id') ); }
151                     );
152                     if (obj.retrieve_ids.length > 0) {
153                         obj.controller.view.sel_mark_items_damaged.setAttribute('disabled','false');
154                         obj.controller.view.sel_mark_items_missing.setAttribute('disabled','false');
155                         obj.controller.view.sel_copy_details.setAttribute('disabled','false');
156                         obj.controller.view.sel_patron.setAttribute('disabled','false');
157                         obj.controller.view.cmd_retrieve_patron.setAttribute('disabled','false');
158                         obj.controller.view.cmd_holds_edit_pickup_lib.setAttribute('disabled','false');
159                         obj.controller.view.cmd_holds_edit_desire_mint_condition.setAttribute('disabled','false');
160                         obj.controller.view.cmd_holds_edit_phone_notify.setAttribute('disabled','false');
161                         obj.controller.view.cmd_holds_edit_email_notify.setAttribute('disabled','false');
162                         obj.controller.view.cmd_holds_edit_selection_depth.setAttribute('disabled','false');
163                         obj.controller.view.cmd_holds_edit_expire_time.setAttribute('disabled','false');
164                         obj.controller.view.cmd_holds_edit_shelf_expire_time.setAttribute('disabled','false');
165                         obj.controller.view.cmd_holds_edit_thaw_date.setAttribute('disabled','false');
166                         obj.controller.view.cmd_holds_edit_request_date.setAttribute('disabled','false');
167                         obj.controller.view.cmd_holds_activate.setAttribute('disabled','false');
168                         obj.controller.view.cmd_holds_suspend.setAttribute('disabled','false');
169                         obj.controller.view.cmd_alt_view.setAttribute('rendering_rows','false');
170                         if (obj.controller.view.cmd_alt_view.getAttribute('ready')=='true') {
171                             obj.controller.view.cmd_alt_view.setAttribute('disabled','false');
172                         }
173                         obj.controller.view.cmd_holds_retarget.setAttribute('disabled','false');
174                         obj.controller.view.cmd_holds_cancel.setAttribute('disabled','false');
175                         obj.controller.view.cmd_holds_uncancel.setAttribute('disabled','false');
176                         obj.controller.view.cmd_show_catalog.setAttribute('disabled','false');
177                     } else {
178                         obj.controller.view.sel_mark_items_damaged.setAttribute('disabled','true');
179                         obj.controller.view.sel_mark_items_missing.setAttribute('disabled','true');
180                         obj.controller.view.sel_copy_details.setAttribute('disabled','true');
181                         obj.controller.view.sel_patron.setAttribute('disabled','true');
182                         obj.controller.view.cmd_retrieve_patron.setAttribute('disabled','true');
183                         obj.controller.view.cmd_holds_edit_pickup_lib.setAttribute('disabled','true');
184                         obj.controller.view.cmd_holds_edit_desire_mint_condition.setAttribute('disabled','true');
185                         obj.controller.view.cmd_holds_edit_phone_notify.setAttribute('disabled','true');
186                         obj.controller.view.cmd_holds_edit_email_notify.setAttribute('disabled','true');
187                         obj.controller.view.cmd_holds_edit_selection_depth.setAttribute('disabled','true');
188                         obj.controller.view.cmd_holds_edit_expire_time.setAttribute('disabled','true');
189                         obj.controller.view.cmd_holds_edit_shelf_expire_time.setAttribute('disabled','true');
190                         obj.controller.view.cmd_holds_edit_thaw_date.setAttribute('disabled','true');
191                         obj.controller.view.cmd_holds_edit_request_date.setAttribute('disabled','true');
192                         obj.controller.view.cmd_holds_activate.setAttribute('disabled','true');
193                         obj.controller.view.cmd_holds_suspend.setAttribute('disabled','true');
194                         obj.controller.view.cmd_alt_view.setAttribute('disabled','true');
195                         obj.controller.view.cmd_alt_view.setAttribute('rendering_rows','true');
196                         obj.controller.view.cmd_holds_retarget.setAttribute('disabled','true');
197                         obj.controller.view.cmd_holds_cancel.setAttribute('disabled','true');
198                         obj.controller.view.cmd_holds_uncancel.setAttribute('disabled','true');
199                         obj.controller.view.cmd_show_catalog.setAttribute('disabled','true');
200                     }
201                 }
202             }
203         );
204
205         JSAN.use('util.controller'); obj.controller = new util.controller();
206         obj.controller.init(
207             {
208                 'control_map' : {
209                     'save_columns' : [ [ 'command' ], function() { obj.list.save_columns(); } ],
210                     'sel_clip' : [
211                         ['command'],
212                         function() { obj.list.clipboard(); }
213                     ],
214                     'cmd_broken' : [
215                         ['command'],
216                         function() { alert($("commonStrings").getString('common.unimplemented')); }
217                     ],
218                     'sel_patron' : [
219                         ['command'],
220                         function() {
221                             JSAN.use('circ.util');
222                             circ.util.show_last_few_circs(obj.retrieve_ids);
223                         }
224                     ],
225                     'alt_view_btn' : [
226                         ['render'],
227                         function(e) {
228                             e.setAttribute('label', document.getElementById("circStrings").getString('staff.circ.holds.alt_view.label'));
229                             e.setAttribute('accesskey', document.getElementById("circStrings").getString('staff.circ.holds.alt_view.accesskey'));
230                         }
231                     ],
232                     'cmd_alt_view' : [
233                         ['command'],
234                         function(ev) {
235                             try {
236                                 var n = obj.controller.view.alt_view_btn;
237                                 if (n.getAttribute('toggle') == '1') {
238                                     document.getElementById('deck').selectedIndex = 0;
239                                     n.setAttribute('toggle','0');
240                                     n.setAttribute('label', document.getElementById("circStrings").getString('staff.circ.holds.alt_view.label'));
241                                     n.setAttribute('accesskey', document.getElementById("circStrings").getString('staff.circ.holds.alt_view.accesskey'));
242                                     obj.controller.view.save_columns.setAttribute('disabled','false');
243                                 } else {
244                                     document.getElementById('deck').selectedIndex = 1;
245                                     n.setAttribute('toggle','1');
246                                     n.setAttribute('label', document.getElementById("circStrings").getString('staff.circ.holds.list_view.label'));
247                                     n.setAttribute('accesskey', document.getElementById("circStrings").getString('staff.circ.holds.list_view.accesskey'));
248                                     netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
249                                     if (obj.retrieve_ids.length == 0) return;
250                                     var f = obj.browser.get_content();
251                                     xulG.ahr_id = obj.retrieve_ids[0].id;
252                                     xulG.blob = obj.holds_map[ xulG.ahr_id ];
253                                     xulG.patron_rendered_elsewhere = (obj.hold_interface_type == 'patron');
254                                     xulG.bib_rendered_elsewhere = (obj.hold_interface_type == 'record');
255                                     f.xulG = xulG;
256                                     f.xulG.clear_and_retrieve = function() { obj.clear_and_retrieve(); };
257                                     f.fetch_and_render_all(true);
258                                     obj.controller.view.save_columns.setAttribute('disabled','true');
259                                 }
260                             } catch(E) {
261                                 alert('Error in holds.js, cmd_alt_view handler: ' + E);
262                             }
263                         },
264                     ],
265                     'cmd_cancelled_holds_view' : [
266                         ['command'],
267                         function(ev) {
268                             document.getElementById('show_cancelled_deck').selectedIndex = 1;
269                             /* For some reason attribute propogation on the <command> element isn't working with hidden */
270                             document.getElementById('holds_cancel_btn').setAttribute('hidden','true');
271                             document.getElementById('holds_uncancel_btn').setAttribute('hidden','false');
272                             document.getElementById('holds_cancel_btn2').setAttribute('hidden','true');
273                             document.getElementById('holds_uncancel_btn2').setAttribute('hidden','false');
274                             obj.clear_and_retrieve();
275                         }
276                     ],
277                     'cmd_uncancelled_holds_view' : [
278                         ['command'],
279                         function(ev) {
280                             document.getElementById('show_cancelled_deck').selectedIndex = 0;
281                             /* For some reason attribute propogation on the <command> element isn't working with hidden */
282                             document.getElementById('holds_cancel_btn').setAttribute('hidden','false');
283                             document.getElementById('holds_uncancel_btn').setAttribute('hidden','true');
284                             document.getElementById('holds_cancel_btn2').setAttribute('hidden','false');
285                             document.getElementById('holds_uncancel_btn2').setAttribute('hidden','true');
286                             obj.clear_and_retrieve();
287                         }
288                     ],
289                     'sel_mark_items_damaged' : [
290                         ['command'],
291                         function() {
292                             JSAN.use('cat.util'); JSAN.use('util.functional');
293                             cat.util.mark_item_damaged( util.functional.map_list( obj.retrieve_ids, function(o) { return o.copy_id; } ) );
294                         }
295                     ],
296                     'sel_mark_items_missing' : [
297                         ['command'],
298                         function() {
299                             JSAN.use('cat.util'); JSAN.use('util.functional');
300                             cat.util.mark_item_missing( util.functional.map_list( obj.retrieve_ids, function(o) { return o.copy_id; } ) );
301                         }
302                     ],
303                     'sel_copy_details' : [
304                         ['command'],
305                         function() {
306                             JSAN.use('circ.util');
307                             circ.util.item_details_new(
308                                 util.functional.map_list(
309                                     obj.retrieve_ids,
310                                     function(o) { return o.barcode; }
311                                 )
312                             );
313                         }
314                     ],
315                     'cmd_holds_print_full' : [
316                         ['command'],
317                         function() {
318                             var x_print_full_pull_list = document.getElementById('print_full_btn');
319                             try {
320                                 if (progressmeter) {
321                                     progressmeter.mode = 'undetermined';
322                                     progressmeter.hidden = false;
323                                     x_print_full_pull_list.disabled = true;
324                                 }
325                                 JSAN.use('util.print');
326                                 var print = new util.print('default');
327                                 var robj = fieldmapper.standardRequest(
328                                     [ api.HTML_HOLD_PULL_LIST.app, api.HTML_HOLD_PULL_LIST.method ],
329                                     {   async: false,
330                                         timeout: 180,
331                                         params: [ses()],
332                                     }
333                                 );
334                                 if (robj != null) {
335                                     if (typeof robj.ilsevent != 'undefined') { throw(robj); }
336                                     print.simple( robj.template_output().data() );
337                                 }
338                             } catch(E) {
339                                 obj.error.standard_unexpected_error_alert('cmd_holds_print_full',E);
340                             }
341                             if (progressmeter) {
342                                 progressmeter.mode = 'determined';
343                                 progressmeter.hidden = true;
344                                 x_print_full_pull_list.disabled = false;
345                             }
346                         }
347                     ],
348                     'cmd_holds_print_alt' : [
349                         ['command'],
350                         function() {
351                             try {
352                                 var content_params = {
353                                     "session": ses(),
354                                     "authtime": ses("authtime"),
355                                     "no_xulG": false,
356                                     "show_nav_buttons": true,
357                                     "show_print_button": true
358                                 };
359                                 ["url_prefix", "new_tab", "set_tab",
360                                     "close_tab", "new_patron_tab",
361                                     "set_patron_tab", "volume_item_creator",
362                                     "get_new_session",
363                                     "holdings_maintenance_tab", "set_tab_name",
364                                     "open_chrome_window", "url_prefix",
365                                     "network_meter", "page_meter",
366                                     "set_statusbar", "set_help_context"
367                                 ].forEach(function(k) {
368                                     content_params[k] = xulG[k];
369                                 });
370
371                                 var loc = urls.XUL_BROWSER + "?url=" + window.escape(
372                                     xulG.url_prefix("/opac/extras/circ/alt_holds_print.html").replace("http:","https:")
373                                 );
374                                 xulG.new_tab(
375                                     loc, {
376                                         "tab_name": "Printable Pull List", /* XXX i18n */
377                                         "browser": false
378                                     }, content_params
379                                 );
380                             } catch (E) {
381                                 g.error.sdump("D_ERROR", E);
382                             }
383                         }
384                     ],
385                     'cmd_holds_print' : [
386                         ['command'],
387                         function() {
388                             try {
389                                 JSAN.use('patron.util');
390                                 var params = {
391                                     'patron' : patron.util.retrieve_au_via_id(ses(),obj.patron_id),
392                                     'template' : 'holds'
393                                 };
394                                 obj.list.print(params);
395                             } catch(E) {
396                                 obj.error.standard_unexpected_error_alert('print 1',E);
397                             }
398                         }
399                     ],
400                     'cmd_csv_to_clipboard' : [ ['command'], function() { obj.list.dump_csv_to_clipboard(); } ],
401                     'cmd_csv_to_printer' : [ ['command'], function() { obj.list.dump_csv_to_printer(); } ],
402                     'cmd_csv_to_file' : [ ['command'], function() { obj.list.dump_csv_to_file( { 'defaultFileName' : 'holds.txt' } ); } ],
403
404                     'cmd_holds_edit_selection_depth' : [
405                         ['command'],
406                         function() {
407                             try {
408                                 JSAN.use('util.widgets'); JSAN.use('util.functional');
409                                 var ws_type = obj.data.hash.aout[ obj.data.hash.aou[ obj.data.list.au[0].ws_ou() ].ou_type() ];
410                                 var list = util.functional.map_list(
411                                     util.functional.filter_list(
412                                         obj.data.list.aout,
413                                         function(o) {
414                                             if (o.depth() > ws_type.depth()) return false;
415                                             if (o.depth() < ws_type.depth()) return true;
416                                             return (o.id() == ws_type.id());
417                                         }
418                                     ),
419                                     function(o) {
420                                         return [
421                                             o.opac_label(),
422                                             o.id(),
423                                             false,
424                                             ( o.depth() * 2),
425                                         ];
426                                     }
427                                 );
428                                 ml = util.widgets.make_menulist( list, obj.data.list.au[0].ws_ou() );
429                                 ml.setAttribute('id','selection');
430                                 ml.setAttribute('name','fancy_data');
431                                 var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
432                                 xml += '<description>' + $("patronStrings").getString('staff.patron.holds.holds_edit_selection_depth.choose_hold_range') + '</description>';
433                                 xml += util.widgets.serialize_node(ml);
434                                 xml += '</vbox>';
435                                 var bot_xml = '<hbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
436                                 bot_xml += '<spacer flex="1"/><button label="'+ $("patronStrings").getString('staff.patron.holds.holds_edit_selection_depth.done.label') +'"';
437                                 bot_xml += 'accesskey="'+ $("patronStrings").getString('staff.patron.holds.holds_edit_selection_depth.done.accesskey') +'" name="fancy_submit"/>';
438                                 bot_xml += '<button label="'+ $("patronStrings").getString('staff.patron.holds.holds_edit_selection_depth.cancel.label') +'"';
439                                 bot_xml += 'accesskey="'+ $("patronStrings").getString('staff.patron.holds.holds_edit_selection_depth.cancel.accesskey') +'" name="fancy_cancel"/></hbox>';
440                                 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
441                                 //obj.data.temp_mid = xml; obj.data.stash('temp_mid');
442                                 //obj.data.temp_bot = bot_xml; obj.data.stash('temp_bot');
443                                 JSAN.use('util.window'); var win = new util.window();
444                                 var fancy_prompt_data = win.open(
445                                     urls.XUL_FANCY_PROMPT,
446                                     //+ '?xml_in_stash=temp_mid'
447                                     //+ '&bottom_xml_in_stash=temp_bot'
448                                     //+ '&title=' + window.escape('Choose a Pick Up Library'),
449                                     'fancy_prompt', 'chrome,resizable,modal',
450                                     { 'xml' : xml, 'bottom_xml' : bot_xml, 'title' : $("patronStrings").getString('staff.patron.holds.holds_edit_selection_depth.choose_library') }
451                                 );
452                                 if (fancy_prompt_data.fancy_status == 'incomplete') { return; }
453                                 var selection = fancy_prompt_data.selection;
454
455                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
456                                 var msg = '';
457                                 if(obj.retrieve_ids.length > 1) {
458                                     msg = $("patronStrings").getformattedString('staff.patron.holds.holds_edit_selection_depth.modify_holds_message.plural', [hold_list.join(', '), obj.data.hash.aout[selection].opac_label()])
459                                 } else {
460                                     msg = $("patronStrings").getformattedString('staff.patron.holds.holds_edit_selection_depth.modify_holds_message.singular', [hold_list.join(', '), obj.data.hash.aout[selection].opac_label()])
461                                 }
462
463                                 var r = obj.error.yns_alert(msg,
464                                         $("patronStrings").getString('staff.patron.holds.holds_edit_selection_depth.modify_holds_title'),
465                                         $("commonStrings").getString('common.yes'),
466                                         $("commonStrings").getString('common.no'),
467                                         null,
468                                         $("commonStrings").getString('common.check_to_confirm')
469                                 );
470                                 if (r == 0) {
471                                     circ.util.batch_hold_update(hold_list, { 'selection_depth' : obj.data.hash.aout[selection].depth() }, { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } });
472                                 }
473                             } catch(E) {
474                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_not_modified'),E);
475                             }
476                         }
477                     ],
478
479                     'cmd_holds_edit_pickup_lib' : [
480                         ['command'],
481                         function() {
482                             try {
483                                 JSAN.use('util.widgets'); JSAN.use('util.functional');
484
485                                 var list = util.functional.map_list(
486                                     obj.data.list.aou,
487                                     function(o) {
488                                         var sname = o.shortname(); for (i = sname.length; i < 20; i++) sname += ' ';
489                                         return [
490                                             o.name() ? sname + ' ' + o.name() : o.shortname(),
491                                             o.id(),
492                                             ( !isTrue(obj.data.hash.aout[ o.ou_type() ].can_have_users()) ),
493                                             ( obj.data.hash.aout[ o.ou_type() ].depth() * 2),
494                                         ];
495                                     }
496                                 );
497                                 ml = util.widgets.make_menulist( list, obj.data.list.au[0].ws_ou() );
498                                 ml.setAttribute('id','lib');
499                                 ml.setAttribute('name','fancy_data');
500                                 var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
501                                 xml += '<description>'+$("patronStrings").getString('staff.patron.holds.holds_edit_pickup_lib.new_pickup_lib.description')+'</description>';
502                                 xml += util.widgets.serialize_node(ml);
503                                 xml += '</vbox>';
504                                 var bot_xml = '<hbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
505                                 bot_xml += '<spacer flex="1"/><button label="'+ $("patronStrings").getString('staff.patron.holds.holds_edit_pickup_lib.done.label') +'"';
506                                 bot_xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_edit_pickup_lib.done.accesskey')+'" name="fancy_submit"/>';
507                                 bot_xml += '<button label="'+$("patronStrings").getString('staff.patron.holds.holds_edit_pickup_lib.cancel.label')+'"';
508                                 bot_xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_edit_pickup_lib.cancel.accesskey')+'" name="fancy_cancel"/></hbox>';
509                                 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
510                                 //obj.data.temp_mid = xml; obj.data.stash('temp_mid');
511                                 //obj.data.temp_bot = bot_xml; obj.data.stash('temp_bot');
512                                 JSAN.use('util.window'); var win = new util.window();
513                                 var fancy_prompt_data = win.open(
514                                     urls.XUL_FANCY_PROMPT,
515                                     //+ '?xml_in_stash=temp_mid'
516                                     //+ '&bottom_xml_in_stash=temp_bot'
517                                     //+ '&title=' + window.escape('Choose a Pick Up Library'),
518                                     'fancy_prompt', 'chrome,resizable,modal',
519                                     { 'xml' : xml, 'bottom_xml' : bot_xml, 'title' : $("patronStrings").getString('staff.patron.holds.holds_edit_pickup_lib.choose_lib') }
520                                 );
521                                 if (fancy_prompt_data.fancy_status == 'incomplete') { return; }
522                                 var pickup_lib = fancy_prompt_data.lib;
523
524                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
525                                 var msg = '';
526                                 if(obj.retrieve_ids.length > 1) {
527                                     msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_edit_pickup_lib.change_pickup_lib_message.plural',[hold_list.join(', '), obj.data.hash.aou[pickup_lib].shortname()]);
528                                 } else {
529                                     msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_edit_pickup_lib.change_pickup_lib_message.singular',[hold_list.join(', '), obj.data.hash.aou[pickup_lib].shortname()]);
530                                 }
531                                 var r = obj.error.yns_alert(msg,
532                                         $("patronStrings").getString('staff.patron.holds.holds_edit_pickup_lib.change_pickup_lib_title'),
533                                         $("commonStrings").getString('common.yes'),
534                                         $("commonStrings").getString('common.no'),
535                                         null,
536                                         $("commonStrings").getString('common.check_to_confirm')
537                                 );
538                                 if (r == 0) {
539                                     circ.util.batch_hold_update(hold_list, { 'pickup_lib' : pickup_lib }, { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } });
540                                 }
541                             } catch(E) {
542                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_not_modified'),E);
543                             }
544                         }
545                     ],
546                     'cmd_holds_edit_phone_notify' : [
547                         ['command'],
548                         function() {
549                             try {
550                                 var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
551                                 xml += '<description>'+$("patronStrings").getString('staff.patron.holds.holds_edit_phone_notify.new_phone_number')+'</description>';
552                                 xml += '<textbox id="phone" name="fancy_data" context="clipboard"/>';
553                                 xml += '</vbox>';
554                                 var bot_xml = '<hbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
555                                 bot_xml += '<spacer flex="1"/><button label="'+$("patronStrings").getString('staff.patron.holds.holds_edit_phone_notify.btn_done.label')+'"';
556                                 bot_xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_edit_phone_notify.btn_done.accesskey')+'" name="fancy_submit"/>';
557                                 bot_xml += '<button label="'+$("patronStrings").getString('staff.patron.holds.holds_edit_phone_notify.btn_cancel.label')+'"';
558                                 bot_xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_edit_phone_notify.btn_cancel.accesskey')+'" name="fancy_cancel"/></hbox>';
559                                 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
560                                 //obj.data.temp_mid = xml; obj.data.stash('temp_mid');
561                                 //obj.data.temp_bot = bot_xml; obj.data.stash('temp_bot');
562                                 JSAN.use('util.window'); var win = new util.window();
563                                 var fancy_prompt_data = win.open(
564                                     urls.XUL_FANCY_PROMPT,
565                                     //+ '?xml_in_stash=temp_mid'
566                                     //+ '&bottom_xml_in_stash=temp_bot'
567                                     //+ '&title=' + window.escape('Choose a Hold Notification Phone Number')
568                                     //+ '&focus=phone',
569                                     'fancy_prompt', 'chrome,resizable,modal',
570                                     { 'xml' : xml, 'bottom_xml' : bot_xml, 'title' : $("patronStrings").getString('staff.patron.holds.holds_edit_phone_notify.choose_phone_number'), 'focus' : 'phone' }
571                                 );
572                                 if (fancy_prompt_data.fancy_status == 'incomplete') { return; }
573                                 var phone = fancy_prompt_data.phone;
574
575                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
576                                 var msg = '';
577                                 if(obj.retrieve_ids.length > 1) {
578                                     msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_edit_phone_notify.confirm_phone_number_change.plural',[hold_list.join(', '), phone]);
579                                 } else {
580                                     msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_edit_phone_notify.confirm_phone_number_change.singular',[hold_list.join(', '), phone]);
581                                 }
582                                 var r = obj.error.yns_alert(msg,
583                                         $("patronStrings").getString('staff.patron.holds.holds_edit_phone_notify.modifying_holds_title'),
584                                         $("commonStrings").getString('common.yes'),
585                                         $("commonStrings").getString('common.no'),
586                                         null,
587                                         $("commonStrings").getString('common.check_to_confirm')
588                                 );
589                                 if (r == 0) {
590                                     circ.util.batch_hold_update(hold_list, { 'phone_notify' : phone }, { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } });
591                                 }
592                             } catch(E) {
593                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_not_modified'),E);
594                             }
595                         }
596                     ],
597                     'cmd_holds_edit_email_notify' : [
598                         ['command'],
599                         function() {
600                             try {
601                                 var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
602                                 xml += '<description>'+$("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.description')+'</description>';
603                                 xml += '<hbox><button value="email" label="'+$("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.btn_email.label')+'"';
604                                 xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.btn_email.accesskey')+'" name="fancy_submit"/>';
605                                 xml += '<button value="noemail" label="'+$("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.btn_no_email.label')+'"';
606                                 xml += '  accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.btn_no_email.accesskey')+'" name="fancy_submit"/></hbox>';
607                                 xml += '</vbox>';
608                                 var bot_xml = '<hbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
609                                 bot_xml += '<spacer flex="1"/><button label="'+$("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.btn_cancel.label')+'"';
610                                 bot_xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.btn_cancel.accesskey')+'" name="fancy_cancel"/></hbox>';
611                                 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
612                                 //obj.data.temp_mid = xml; obj.data.stash('temp_mid');
613                                 //obj.data.temp_bot = bot_xml; obj.data.stash('temp_bot');
614                                 JSAN.use('util.window'); var win = new util.window();
615                                 var fancy_prompt_data = win.open(
616                                     urls.XUL_FANCY_PROMPT,
617                                     //+ '?xml_in_stash=temp_mid'
618                                     //+ '&bottom_xml_in_stash=temp_bot'
619                                     //+ '&title=' + window.escape('Set Email Notification for Holds'),
620                                     'fancy_prompt', 'chrome,resizable,modal',
621                                     { 'xml' : xml, 'bottom_xml' : bot_xml, 'title' : $("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.set_notifs') }
622                                 );
623                                 if (fancy_prompt_data.fancy_status == 'incomplete') { return; }
624                                 var email = fancy_prompt_data.fancy_submit == 'email' ? get_db_true() : get_db_false();
625
626                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
627                                 var msg = '';
628                                 if(get_bool(email)) {
629                                     if(obj.retrieve_ids.length > 1) {
630                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_edit_email_notify.enable_email.plural', [hold_list.join(', ')]);
631                                     } else {
632                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_edit_email_notify.enable_email.singular', [hold_list.join(', ')]);
633                                     }
634                                 } else {
635                                     if(obj.retrieve_ids.length > 1) {
636                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_edit_email_notify.disable_email.plural', [hold_list.join(', ')]);
637                                     } else {
638                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_edit_email_notify.disable_email.singular', [hold_list.join(', ')]);
639                                     }
640                                 }
641
642                                 var r = obj.error.yns_alert(msg,
643                                         $("patronStrings").getString('staff.patron.holds.holds_edit_email_notify.mod_holds_title'),
644                                         $("commonStrings").getString('common.yes'),
645                                         $("commonStrings").getString('common.no'),
646                                         null,
647                                         $("commonStrings").getString('common.check_to_confirm')
648                                 );
649                                 if (r == 0) {
650                                     circ.util.batch_hold_update(hold_list, { 'email_notify' : email }, { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } });
651                                 }
652                             } catch(E) {
653                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_not_modified'),E);
654                             }
655                         }
656                     ],
657                     'cmd_holds_cut_in_line' : [
658                         ['command'],
659                         function() {
660                             try {
661                                 var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
662                                 xml += '<description>'+$("patronStrings").getString('staff.patron.holds.holds_cut_in_line.description')+'</description>';
663                                 xml += '<hbox><button value="cut" label="'+$("patronStrings").getString('staff.patron.holds.holds_cut_in_line.btn_cut.label')+'"';
664                                 xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_cut_in_line.btn_cut.accesskey')+'" name="fancy_submit"/>';
665                                 xml += '<button value="nocut" label="'+$("patronStrings").getString('staff.patron.holds.holds_cut_in_line.btn_no_cut.label')+'"';
666                                 xml += '  accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_cut_in_line.btn_no_cut.accesskey')+'" name="fancy_submit"/></hbox>';
667                                 xml += '</vbox>';
668                                 var bot_xml = '<hbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
669                                 bot_xml += '<spacer flex="1"/><button label="'+$("patronStrings").getString('staff.patron.holds.holds_cut_in_line.btn_cancel.label')+'"';
670                                 bot_xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_cut_in_line.btn_cancel.accesskey')+'" name="fancy_cancel"/></hbox>';
671                                 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
672                                 JSAN.use('util.window'); var win = new util.window();
673                                 var fancy_prompt_data = win.open(
674                                     urls.XUL_FANCY_PROMPT,
675                                     'fancy_prompt', 'chrome,resizable,modal',
676                                     { 'xml' : xml, 'bottom_xml' : bot_xml, 'title' : $("patronStrings").getString('staff.patron.holds.holds_cut_in_line.set_notifs') }
677                                 );
678                                 if (fancy_prompt_data.fancy_status == 'incomplete') { return; }
679                                 var cut = fancy_prompt_data.fancy_submit == 'cut' ? get_db_true() : get_db_false();
680
681                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
682                                 var msg = '';
683                                 if(get_bool(cut)) {
684                                     if(obj.retrieve_ids.length > 1) {
685                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_cut_in_line.enable_cut.plural', [hold_list.join(', ')]);
686                                     } else {
687                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_cut_in_line.enable_cut.singular', [hold_list.join(', ')]);
688                                     }
689                                 } else {
690                                     if(obj.retrieve_ids.length > 1) {
691                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_cut_in_line.disable_cut.plural', [hold_list.join(', ')]);
692                                     } else {
693                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_cut_in_line.disable_cut.singular', [hold_list.join(', ')]);
694                                     }
695                                 }
696
697                                 var r = obj.error.yns_alert(msg,
698                                         $("patronStrings").getString('staff.patron.holds.holds_cut_in_line.mod_holds_title'),
699                                         $("commonStrings").getString('common.yes'),
700                                         $("commonStrings").getString('common.no'),
701                                         null,
702                                         $("commonStrings").getString('common.check_to_confirm')
703                                 );
704                                 if (r == 0) {
705                                     circ.util.batch_hold_update(hold_list, { 'cut_in_line' : cut }, { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } });
706                                 }
707                             } catch(E) {
708                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_not_modified'),E);
709                             }
710                         }
711                     ],
712                     'cmd_holds_edit_desire_mint_condition' : [
713                         ['command'],
714                         function() {
715                             try {
716                                 var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
717                                 xml += '<description>'+$("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.description')+'</description>';
718                                 xml += '<hbox><button value="good" label="'+$("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.btn_good.label')+'"';
719                                 xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.btn_good.accesskey')+'" name="fancy_submit"/>';
720                                 xml += '<button value="nogood" label="'+$("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.btn_mediocre.label')+'"';
721                                 xml += '  accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.btn_mediocre.accesskey')+'" name="fancy_submit"/></hbox>';
722                                 xml += '</vbox>';
723                                 var bot_xml = '<hbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: vertical">';
724                                 bot_xml += '<spacer flex="1"/><button label="'+$("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.btn_cancel.label')+'"';
725                                 bot_xml += ' accesskey="'+$("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.btn_cancel.accesskey')+'" name="fancy_cancel"/></hbox>';
726                                 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
727                                 JSAN.use('util.window'); var win = new util.window();
728                                 var fancy_prompt_data = win.open(
729                                     urls.XUL_FANCY_PROMPT,
730                                     'fancy_prompt', 'chrome,resizable,modal',
731                                     { 'xml' : xml, 'bottom_xml' : bot_xml, 'title' : $("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.set_notifs') }
732                                 );
733                                 if (fancy_prompt_data.fancy_status == 'incomplete') { return; }
734                                 var good = fancy_prompt_data.fancy_submit == 'good' ? get_db_true() : get_db_false();
735
736                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
737                                 var msg = '';
738                                 if(get_bool(good)) {
739                                     if(obj.retrieve_ids.length > 1) {
740                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_desire_mint_condition.enable_good.plural', [hold_list.join(', ')]);
741                                     } else {
742                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_desire_mint_condition.enable_good.singular', [hold_list.join(', ')]);
743                                     }
744                                 } else {
745                                     if(obj.retrieve_ids.length > 1) {
746                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_desire_mint_condition.disable_good.plural', [hold_list.join(', ')]);
747                                     } else {
748                                         msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_desire_mint_condition.disable_good.singular', [hold_list.join(', ')]);
749                                     }
750                                 }
751
752                                 var r = obj.error.yns_alert(msg,
753                                         $("patronStrings").getString('staff.patron.holds.holds_desire_mint_condition.mod_holds_title'),
754                                         $("commonStrings").getString('common.yes'),
755                                         $("commonStrings").getString('common.no'),
756                                         null,
757                                         $("commonStrings").getString('common.check_to_confirm')
758                                 );
759                                 if (r == 0) {
760                                     circ.util.batch_hold_update(hold_list, { 'mint_condition' : good }, { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } });
761                                 }
762                             } catch(E) {
763                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_not_modified'),E);
764                             }
765                         }
766                     ],
767
768
769                     'cmd_holds_suspend' : [
770                         ['command'],
771                         function() {
772                             try {
773                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
774                                 var r = obj.error.yns_alert(
775                                     obj.retrieve_ids.length > 1 ?
776                                     document.getElementById('circStrings').getFormattedString('staff.circ.holds.suspend.prompt.plural',[hold_list.join(', ')]) :
777                                     document.getElementById('circStrings').getFormattedString('staff.circ.holds.suspend.prompt',[hold_list.join(', ')]),
778                                     document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds'),
779                                     document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds.yes'),
780                                     document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds.no'),
781                                     null,
782                                     document.getElementById('commonStrings').getString('common.confirm')
783                                 );
784                                 if (r == 0) {
785                                     var already_suspended = []; var filtered_hold_list = [];
786                                     for (var i = 0; i < obj.retrieve_ids.length; i++) {
787                                         var hold = obj.holds_map[ obj.retrieve_ids[i].id ].hold;
788                                         if ( get_bool( hold.frozen() ) ) {
789                                             already_suspended.push( hold.id() );
790                                             continue;
791                                         }
792                                         filtered_hold_list.push( hold.id() );
793                                     }
794                                     circ.util.batch_hold_update(filtered_hold_list, { 'frozen' : 't', 'thaw_date' : null }, { 'progressmeter' : progressmeter, 'oncomplete' :  function() { 
795                                         if (already_suspended.length == 1) {
796                                             alert( document.getElementById('circStrings').getFormattedString('staff.circ.holds.already_suspended',[already_suspended[0]]) );
797                                         } else if (already_suspended.length > 1) {
798                                             alert( document.getElementById('circStrings').getFormattedString('staff.circ.holds.already_suspended.plural',[already_suspended.join(', ')]) );
799                                         }
800                                         obj.clear_and_retrieve(true); 
801                                     } });
802                                 }
803                             } catch(E) {
804                                 obj.error.standard_unexpected_error_alert(document.getElementById('circStrings').getString('staff.circ.holds.unexpected_error.not_likely_suspended'),E);
805                             }
806                         }
807                     ],
808                     'cmd_holds_activate' : [
809                         ['command'],
810                         function() {
811                             try {
812                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
813                                 var r = obj.error.yns_alert(
814                                     obj.retrieve_ids.length > 1 ?
815                                     document.getElementById('circStrings').getFormattedString('staff.circ.holds.activate.prompt.plural',[hold_list.join(', ')]) :
816                                     document.getElementById('circStrings').getFormattedString('staff.circ.holds.activate.prompt',[hold_list.join(', ')]),
817                                     document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds'),
818                                     document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds.yes'),
819                                     document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds.no'),
820                                     null,
821                                     document.getElementById('commonStrings').getString('common.confirm')
822                                 );
823                                 if (r == 0) {
824                                     var already_activated = []; var filtered_hold_list = [];
825                                     for (var i = 0; i < obj.retrieve_ids.length; i++) {
826                                         var hold = obj.holds_map[ obj.retrieve_ids[i].id ].hold;
827                                         if ( ! get_bool( hold.frozen() ) ) {
828                                             already_activated.push( hold.id() );
829                                             continue;
830                                         }
831                                         filtered_hold_list.push( hold.id() );
832                                     }
833                                     circ.util.batch_hold_update(filtered_hold_list, { 'frozen' : 'f', 'thaw_date' : null }, { 'progressmeter' : progressmeter, 'oncomplete' :  function() { 
834                                         if (already_activated.length == 1) {
835                                             alert( document.getElementById('circStrings').getFormattedString('staff.circ.holds.already_activated',[already_activated[0]]) );
836                                         } else if (already_activated.length > 1) {
837                                             alert( document.getElementById('circStrings').getFormattedString('staff.circ.holds.already_activated.plural',[already_activated.join(', ')]) );
838                                         }
839                                         obj.clear_and_retrieve(true); 
840                                     } });
841                                 }
842                             } catch(E) {
843                                 obj.error.standard_unexpected_error_alert(document.getElementById('circStrings').getString('staff.circ.holds.unexpected_error.not_likely_activated'),E);
844                             }
845                         }
846                     ],
847                     'cmd_holds_edit_thaw_date' : [
848                         ['command'],
849                         function() {
850                             try {
851                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
852                                 var msg_singular = document.getElementById('circStrings').getFormattedString('staff.circ.holds.activation_date.prompt',[hold_list.join(', ')]);
853                                 var msg_plural = document.getElementById('circStrings').getFormattedString('staff.circ.holds.activation_date.prompt.plural',[hold_list.join(', ')]);
854                                 var msg = obj.retrieve_ids.length > 1 ? msg_plural : msg_singular;
855                                 var title = document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds');
856                                 var desc = document.getElementById('circStrings').getString('staff.circ.holds.activation_date.dialog.description');
857
858                                 JSAN.use('util.window'); var win = new util.window();
859                                 var my_xulG = win.open( 
860                                     urls.XUL_TIMESTAMP_DIALOG, 'edit_thaw_date', 'chrome,resizable,modal', 
861                                     { 
862                                         'title' : title, 
863                                         'description' : desc, 
864                                         'msg' : msg, 
865                                         'allow_unset' : true,
866                                         'disallow_future_dates' : false,
867                                         'disallow_past_dates' : true,
868                                         'disallow_today' : true,
869                                         'default_time' : '00:00:00',
870                                         'time_readonly' : false
871                                     }
872                                 );
873                                 if (my_xulG.complete) {
874                                     circ.util.batch_hold_update(
875                                         hold_list, 
876                                         { 'frozen' : 't', 'thaw_date' : my_xulG.timestamp }, 
877                                         { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } }
878                                     );
879                                 }
880                             } catch(E) {
881                                 obj.error.standard_unexpected_error_alert(document.getElementById('circStrings').getString('staff.circ.holds.unexpected_error.not_likely_modified'),E);
882                             }
883                         }
884                     ],
885                     'cmd_holds_edit_expire_time' : [
886                         ['command'],
887                         function() {
888                             try {
889                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
890                                 var msg_singular = document.getElementById('circStrings').getFormattedString('staff.circ.holds.expire_time.prompt',[hold_list.join(', ')]);
891                                 var msg_plural = document.getElementById('circStrings').getFormattedString('staff.circ.holds.expire_time.prompt.plural',[hold_list.join(', ')]);
892                                 var msg = obj.retrieve_ids.length > 1 ? msg_plural : msg_singular;
893                                 var value = 'YYYY-MM-DD';
894                                 var title = document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds');
895                                 var desc = document.getElementById('circStrings').getString('staff.circ.holds.expire_time.dialog.description');
896
897                                 JSAN.use('util.window'); var win = new util.window();
898                                 var my_xulG = win.open( 
899                                     urls.XUL_TIMESTAMP_DIALOG, 'edit_expire_time', 'chrome,resizable,modal', 
900                                     { 
901                                         'title' : title, 
902                                         'description' : desc, 
903                                         'msg' : msg, 
904                                         'allow_unset' : true,
905                                         'disallow_future_dates' : false,
906                                         'disallow_past_dates' : true,
907                                         'disallow_today' : true,
908                                         'default_time' : '00:00:00',
909                                         'time_readonly' : false
910                                     }
911                                 );
912                                 if (my_xulG.complete) {
913                                     circ.util.batch_hold_update(
914                                         hold_list, 
915                                         { 'expire_time' : my_xulG.timestamp }, 
916                                         { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } }
917                                     );
918                                 }
919                             } catch(E) {
920                                 obj.error.standard_unexpected_error_alert(document.getElementById('circStrings').getString('staff.circ.holds.unexpected_error.not_likely_modified'),E);
921                             }
922                         }
923                     ],
924                     'cmd_holds_edit_shelf_expire_time' : [
925                         ['command'],
926                         function() {
927                             try {
928                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
929                                 var msg_singular = document.getElementById('circStrings').getFormattedString('staff.circ.holds.shelf_expire_time.prompt',[hold_list.join(', ')]);
930                                 var msg_plural = document.getElementById('circStrings').getFormattedString('staff.circ.holds.shelf_expire_time.prompt.plural',[hold_list.join(', ')]);
931                                 var msg = obj.retrieve_ids.length > 1 ? msg_plural : msg_singular;
932                                 var title = document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds');
933                                 var desc = document.getElementById('circStrings').getString('staff.circ.holds.shelf_expire_time.dialog.description');
934
935                                 JSAN.use('util.window'); var win = new util.window();
936                                 var my_xulG = win.open( 
937                                     urls.XUL_TIMESTAMP_DIALOG, 'edit_shelf_expire_time', 'chrome,resizable,modal', 
938                                     { 
939                                         'title' : title, 
940                                         'description' : desc, 
941                                         'msg' : msg, 
942                                         'allow_unset' : false,
943                                         'disallow_future_dates' : false,
944                                         'disallow_past_dates' : false,
945                                         'disallow_today' : false
946                                     }
947                                 );
948                                 if (my_xulG.complete) {
949                                     circ.util.batch_hold_update(
950                                         hold_list, 
951                                         { 'shelf_expire_time' : my_xulG.timestamp }, 
952                                         { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } }
953                                     );
954                                 }
955                             } catch(E) {
956                                 obj.error.standard_unexpected_error_alert(document.getElementById('circStrings').getString('staff.circ.holds.unexpected_error.not_likely_modified'),E);
957                             }
958                         }
959                     ],
960                     'cmd_holds_edit_request_date' : [
961                         ['command'],
962                         function() {
963                             try {
964                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
965                                 var msg_singular = document.getElementById('circStrings').getFormattedString('staff.circ.holds.request_date.prompt',[hold_list.join(', ')]);
966                                 var msg_plural = document.getElementById('circStrings').getFormattedString('staff.circ.holds.request_date.prompt.plural',[hold_list.join(', ')]);
967                                 var msg = obj.retrieve_ids.length > 1 ? msg_plural : msg_singular;
968                                 var title = document.getElementById('circStrings').getString('staff.circ.holds.modifying_holds');
969                                 var desc = document.getElementById('circStrings').getString('staff.circ.holds.request_date.dialog.description');
970
971                                 JSAN.use('util.window'); var win = new util.window();
972                                 var my_xulG = win.open( 
973                                     urls.XUL_TIMESTAMP_DIALOG, 'edit_request_date', 'chrome,resizable,modal', 
974                                     { 
975                                         'title' : title, 
976                                         'description' : desc, 
977                                         'msg' : msg, 
978                                         'allow_unset' : false,
979                                         'disallow_future_dates' : true,
980                                         'disallow_past_dates' : false,
981                                         'disallow_today' : false
982                                     }
983                                 );
984                                 if (my_xulG.complete) {
985                                     circ.util.batch_hold_update(
986                                         hold_list, 
987                                         { 'request_time' : my_xulG.timestamp }, 
988                                         { 'progressmeter' : progressmeter, 'oncomplete' :  function() { obj.clear_and_retrieve(true); } }
989                                     );
990                                 }
991                             } catch(E) {
992                                 obj.error.standard_unexpected_error_alert(document.getElementById('circStrings').getString('staff.circ.holds.unexpected_error.not_likely_modified'),E);
993                             }
994                         }
995                     ],
996                     'cmd_holds_retarget' : [
997                         ['command'],
998                         function() {
999                             try {
1000                                 JSAN.use('util.functional');
1001
1002                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
1003                                 var msg = '';
1004                                 if(obj.retrieve_ids.length > 1) {
1005                                     msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_retarget.reset_hold_message.plural',[hold_list.join(', ')]);
1006                                 } else {
1007                                     msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_retarget.reset_hold_message.singular',[hold_list.join(', ')]);
1008                                 }
1009                                 var r = obj.error.yns_alert(msg,
1010                                         $("patronStrings").getString('staff.patron.holds.holds_retarget.reset_hold_title'),
1011                                         $("commonStrings").getString('common.yes'),
1012                                         $("commonStrings").getString('common.no'),
1013                                         null,
1014                                         $("commonStrings").getString('common.check_to_confirm')
1015                                 );
1016                                 if (r == 0) {
1017                                     for (var i = 0; i < obj.retrieve_ids.length; i++) {
1018                                         var robj = obj.network.simple_request('FM_AHR_RESET',[ ses(), obj.retrieve_ids[i].id]);
1019                                         if (typeof robj.ilsevent != 'undefined') throw(robj);
1020                                     }
1021                                     obj.clear_and_retrieve();
1022                                 }
1023                             } catch(E) {
1024                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_retarget.holds_not_reset'),E);
1025                             }
1026
1027                         }
1028                     ],
1029
1030                     'cmd_holds_cancel' : [
1031                         ['command'],
1032                         function() {
1033                             try {
1034                                 JSAN.use('util.functional');
1035
1036                                 var hold_list = util.functional.map_list(obj.retrieve_ids, function(o){return o.id;});
1037                                 var msg = '';
1038                                 if(obj.retrieve_ids.length > 1 ) {
1039                                     msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_cancel.cancel_hold_message.plural', [hold_list.join(', ')]);
1040                                 } else {
1041                                     msg = $("patronStrings").getFormattedString('staff.patron.holds.holds_cancel.cancel_hold_message.singular', [hold_list.join(', ')]);
1042                                 }
1043
1044                                 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
1045                                 JSAN.use('util.window');
1046                                 var win = new util.window();
1047                                 var my_xulG = win.open(
1048                                     urls.XUL_HOLD_CANCEL,
1049                                     'hold_cancel',
1050                                     'chrome,resizable,modal',
1051                                     {}
1052                                 );
1053                                 /*var r = obj.error.yns_alert(msg,
1054                                         $("patronStrings").getString('staff.patron.holds.holds_cancel.cancel_hold_title'),
1055                                         $("commonStrings").getString('common.yes'),
1056                                         $("commonStrings").getString('common.no'),
1057                                         null,
1058                                         $("commonStrings").getString('common.check_to_confirm')
1059                                 );*/
1060
1061                                 if (my_xulG.proceed) { 
1062                                     var transits = [];
1063                                     for (var i = 0; i < obj.retrieve_ids.length; i++) {
1064                                         var transit = obj.holds_map[ obj.retrieve_ids[i].id ].hold.transit();
1065                                         if (transit && ! transit.dest_recv_time() ) {
1066                                             transits.push( obj.retrieve_ids[i].barcode );
1067                                         }
1068                                         var robj = obj.network.simple_request('FM_AHR_CANCEL',[ ses(), obj.retrieve_ids[i].id, my_xulG.cancel_reason, my_xulG.note]);
1069                                         if (typeof robj.ilsevent != 'undefined') throw(robj);
1070                                     }
1071                                     if (transits.length > 0) {
1072                                         var msg2 = $("patronStrings").getFormattedString('staff.patron.holds.holds_cancel.cancel_for_barcodes', [transits.join(', ')]);
1073                                         var r2 = obj.error.yns_alert(msg2,
1074                                             $("patronStrings").getString('staff.patron.holds.holds_cancel.cancel_for_barcodes.title'),
1075                                             $("commonStrings").getString('common.yes'),
1076                                             $("commonStrings").getString('common.no'),
1077                                             null,
1078                                             $("commonStrings").getString('common.check_to_confirm'));
1079                                         if (r2 == 0) {
1080                                             try {
1081                                                 for (var i = 0; i < transits.length; i++) {
1082                                                     var robj = obj.network.simple_request('FM_ATC_VOID',[ ses(), { 'barcode' : transits[i] } ]);
1083                                                     if (typeof robj.ilsevent != 'undefined') {
1084                                                         switch(Number(robj.ilsevent)) {
1085                                                             case 1225 /* TRANSIT_ABORT_NOT_ALLOWED */ :
1086                                                                 alert(robj.desc);
1087                                                             break;
1088                                                             case 5000 /* PERM_FAILURE */ :
1089                                                             break;
1090                                                             default:
1091                                                                 throw(robj);
1092                                                             break;
1093                                                         }
1094                                                     }
1095                                                 }
1096                                             } catch(E) {
1097                                                obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_cancel.hold_transits_not_cancelled'),E);
1098                                             }
1099                                         }
1100                                     }
1101                                     obj.clear_and_retrieve();
1102                                 }
1103                             } catch(E) {
1104                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_cancel.hold_not_cancelled'),E);
1105                             }
1106                         }
1107                     ],
1108                     'cmd_holds_uncancel' : [
1109                         ['command'],
1110                         function() {
1111                             try {
1112                                 JSAN.use('util.functional');
1113                                 for (var i = 0; i < obj.retrieve_ids.length; i++) {
1114                                     var robj = obj.network.simple_request('FM_AHR_UNCANCEL',[ ses(), obj.retrieve_ids[i].id]);
1115                                     if (typeof robj.ilsevent != 'undefined') throw(robj);
1116                                 }
1117                                 obj.clear_and_retrieve();
1118                             } catch(E) {
1119                                 obj.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.holds.holds_uncancel.hold_not_uncancelled'),E);
1120                             }
1121                         }
1122                     ],
1123
1124                     'cmd_retrieve_patron' : [
1125                         ['command'],
1126                         function() {
1127                             try {
1128                                 var seen = {};
1129                                 for (var i = 0; i < obj.retrieve_ids.length; i++) {
1130                                     var patron_id = obj.retrieve_ids[i].usr;
1131                                     if (seen[patron_id]) continue; seen[patron_id] = true;
1132                                     xulG.new_patron_tab(
1133                                         {},
1134                                         { 'id' : patron_id }
1135                                     );
1136                                 }
1137                             } catch(E) {
1138                                 obj.error.standard_unexpected_error_alert('',E);
1139                             }
1140                         }
1141                     ],
1142                     'cmd_show_catalog' : [
1143                         ['command'],
1144                         function() {
1145                             try {
1146                                 for (var i = 0; i < obj.retrieve_ids.length; i++) {
1147                                     var htarget = obj.retrieve_ids[i].target;
1148                                     var htype = obj.retrieve_ids[i].type;
1149                                     var opac_url;
1150                                     switch(htype) {
1151                                         case 'M' :
1152                                             opac_url = xulG.url_prefix( urls.opac_rresult_metarecord ) + htarget;
1153                                         break;
1154                                         case 'T' :
1155                                         case 'P' :
1156                                             opac_url = xulG.url_prefix( urls.opac_rdetail ) + htarget;
1157                                         break;
1158                                         case 'I' :
1159                                             opac_url = xulG.url_prefix( urls.opac_rdetail )
1160                                             + obj.hold_subscription_map[ obj.retrieve_ids[i].id ].record_entry();
1161                                         break;
1162                                         case 'V' :
1163                                             var my_acn = obj.network.simple_request( 'FM_ACN_RETRIEVE.authoritative', [ htarget ]);
1164                                             opac_url = xulG.url_prefix( urls.opac_rdetail) + my_acn.record();
1165                                         break;
1166                                         case 'C' :
1167                                         case 'R' :
1168                                         case 'F' :
1169                                             var my_acp = obj.network.simple_request( 'FM_ACP_RETRIEVE', [ htarget ]);
1170                                             var my_acn;
1171                                             if (typeof my_acp.call_number() == 'object') {
1172                                                 my_acn = my.acp.call_number();
1173                                             } else {
1174                                                 my_acn = obj.network.simple_request( 'FM_ACN_RETRIEVE.authoritative',
1175                                                     [ my_acp.call_number() ]);
1176                                             }
1177                                             opac_url = xulG.url_prefix( urls.opac_rdetail) + my_acn.record();
1178                                         break;
1179                                         default:
1180                                             obj.error.standard_unexpected_error_alert($("patronStrings").getFormattedString('staff.patron.holds.show_catalog.unknown_htype', [htype]), obj.retrieve_ids[i]);
1181                                             continue;
1182                                         break;
1183                                     }
1184                                     var content_params = {
1185                                         'session' : ses(),
1186                                         'authtime' : ses('authtime'),
1187                                         'opac_url' : opac_url
1188                                     };
1189                                     xulG.new_tab(
1190                                         xulG.url_prefix(urls.XUL_OPAC_WRAPPER),
1191                                         {'tab_name': htype == 'M' ? 'Catalog' : $("patronStrings").getString('staff.patron.holds.show_catalog.retrieving_title') },
1192                                         content_params
1193                                     );
1194                                 }
1195                             } catch(E) {
1196                                 obj.error.standard_unexpected_error_alert('',E);
1197                             }
1198                         }
1199                     ],
1200                     'cmd_holds_title_transfer' : [
1201                         ['command'],
1202                         function() {
1203                             try {
1204                                 var hids = [];
1205                                 var unique_targets = [];
1206                                 var seen_target = {};
1207                                 for (var i = 0; i < obj.retrieve_ids.length; i++) {
1208                                     var hid = obj.retrieve_ids[i].id;
1209                                     var htarget = obj.retrieve_ids[i].id;
1210                                     var htype = obj.retrieve_ids[i].type;
1211                                     switch(htype) {
1212                                         case 'M' :
1213                                             continue; // not supported
1214                                         break;
1215                                         case 'T' :
1216                                             hids.push( hid );
1217                                             if (! seen_target[htarget]) {
1218                                                 unique_targets.push( htarget );
1219                                                 seen_target[htarget] = 1;
1220                                             }
1221                                         break;
1222                                         case 'V' :
1223                                             continue; // not supported
1224                                         break;
1225                                         case 'C' :
1226                                             continue; // not supported
1227                                         break;
1228                                         default:
1229                                             continue; // not supported
1230                                         break;
1231                                     }
1232                                 }
1233                                 JSAN.use('cat.util');
1234                                 cat.util.transfer_specific_title_holds(hids,unique_targets);
1235                                 obj.clear_and_retrieve();
1236                             } catch(E) {
1237                                 obj.error.standard_unexpected_error_alert('',E);
1238                             }
1239                         }
1240                     ],
1241
1242                     'fetch_more' : [
1243                         ['command'],
1244                         function() {
1245                             obj.pull_from_shelf_interface.current.offset += obj.pull_from_shelf_interface.current.limit;
1246                             obj.retrieve(true);
1247                         }
1248                     ],
1249                     'lib_filter_checkbox' : [
1250                         ['command'],
1251                         function(ev) {
1252                             var x_lib_type_menu = document.getElementById('lib_type_menu');
1253                             if (x_lib_type_menu) x_lib_type_menu.disabled = ! ev.target.checked;
1254                             if (obj.controller.view.lib_menu) obj.controller.view.lib_menu.disabled = ! ev.target.checked;
1255                             obj.clear_and_retrieve();
1256                             ev.target.setAttribute('checked',ev.target.checked);
1257                         }
1258                     ],
1259                     'cmd_view_expired_onshelf_holds' : [
1260                         ['command'],
1261                         function(ev) {
1262                             var x = document.getElementById('expired_checkbox'); // can't trust ev.explicitOriginalTarget, sometimes gives a "button"
1263                             obj.expired = x.checked;
1264                             obj.controller.view.cmd_clear_expired_onshelf_holds.setAttribute('disabled', !obj.expired);
1265                             obj.clear_and_retrieve();
1266                         }
1267                     ],
1268                     'cmd_clear_expired_onshelf_holds' : [
1269                         ['command'],
1270                         function(ev) {
1271                             obj.cmd_clear_expired_onshelf_holds();
1272                         }
1273                     ],
1274                     'cmd_search_opac' : [
1275                         ['command'],
1276                         function(ev) {
1277                             try {
1278                                 var use_url = urls.browser;
1279                                 use_url += use_url.match(/\?/) ? "&" : "?";
1280                                 use_url += "patron_barcode=" + obj.patron_barcode;
1281                                 var content_params = {
1282                                     'show_nav_buttons' : false,
1283                                     'show_print_button' : true,
1284                                     'passthru_content_params' : {
1285                                         'authtoken' : ses(),
1286                                         'authtime' : ses('authtime'),
1287                                         'window_open' : function(a,b,c) {
1288                                             try {
1289                                                 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
1290                                                 return window.open(a,b,c);
1291                                             } catch(E) {
1292                                                 obj.error.standard_unexpected_error_alert('window_open',E);
1293                                             }
1294                                         },
1295                                         'opac_hold_placed' : function(hold) {
1296                                             try {
1297                                                 obj.list.append(
1298                                                     {
1299                                                         'row' : {
1300                                                             'my' : {
1301                                                                 'hold_id' : typeof hold == 'object' ? hold.id() : hold
1302                                                             }
1303                                                         }
1304                                                     }
1305                                                 );
1306                                                 if (window.xulG && typeof window.xulG.on_list_change == 'function') {
1307                                                     window.xulG.on_list_change(); 
1308                                                 }
1309                                             } catch(E) {
1310                                                 obj.error.standard_unexpected_error_alert('holds.js, opac_hold_placed(): ',E);
1311                                             }
1312                                         },
1313                                         'patron_barcode' : obj.patron_barcode
1314                                     },
1315                                     'url_prefix' : xulG.url_prefix,
1316                                     'url' : xulG.url_prefix(use_url)
1317                                 };
1318                                 xulG.display_window.g.patron.right_deck.set_iframe( urls.XUL_REMOTE_BROWSER + '?patron_hold=1', {}, content_params);
1319                             } catch(E) {
1320                                 obj.error.sdump('D_ERROR','cmd_search_opac: ' + E);
1321                             }
1322
1323                         }
1324                     ]
1325                 }
1326             }
1327         );
1328
1329         obj.determine_hold_interface_type();
1330         var x_fetch_more = document.getElementById('fetch_more');
1331         var x_lib_type_menu = document.getElementById('lib_type_menu');
1332         var x_lib_menu_placeholder = document.getElementById('lib_menu_placeholder');
1333         var x_lib_filter_checkbox = document.getElementById('lib_filter_checkbox');
1334         var x_show_cancelled_deck = document.getElementById('show_cancelled_deck');
1335         var x_clear_shelf_widgets = document.getElementById('clear_shelf_widgets');
1336         var x_expired_checkbox = document.getElementById('expired_checkbox');
1337         var x_print_full_pull_list = document.getElementById('print_full_btn');
1338         var x_print_full_pull_list_alt = document.getElementById('print_alt_btn');
1339         switch(obj.hold_interface_type) {
1340             case 'shelf':
1341                 obj.render_lib_menus({'pickup_lib':true});
1342                 if (x_lib_filter_checkbox) x_lib_filter_checkbox.checked = true;
1343                 if (x_lib_type_menu) x_lib_type_menu.hidden = false;
1344                 if (x_lib_menu_placeholder) x_lib_menu_placeholder.hidden = false;
1345                 if (x_clear_shelf_widgets) x_clear_shelf_widgets.hidden = false;
1346                 if (x_print_full_pull_list_alt) x_print_full_pull_list_alt.hidden = true;
1347             break;
1348             case 'pull' :
1349                 if (x_fetch_more) x_fetch_more.hidden = false;
1350                 if (x_print_full_pull_list) x_print_full_pull_list.hidden = false;
1351                 if (x_print_full_pull_list_alt) x_print_full_pull_list_alt.hidden = false;
1352                 if (x_lib_type_menu) x_lib_type_menu.hidden = true;
1353                 if (x_lib_menu_placeholder) x_lib_menu_placeholder.hidden = true;
1354             break;
1355             case 'record' :
1356                 obj.render_lib_menus({'pickup_lib':true,'request_lib':true});
1357                 if (x_lib_filter_checkbox) x_lib_filter_checkbox.hidden = false;
1358                 if (x_lib_type_menu) x_lib_type_menu.hidden = false;
1359                 if (x_print_full_pull_list_alt) x_print_full_pull_list_alt.hidden = true;
1360                 if (x_lib_menu_placeholder) x_lib_menu_placeholder.hidden = false;
1361             break;
1362             default:
1363                 if (obj.controller.view.cmd_search_opac) obj.controller.view.cmd_search_opac.setAttribute('hidden', false);
1364                 if (x_fetch_more) x_fetch_more.hidden = true;
1365                 if (x_lib_type_menu) x_lib_type_menu.hidden = true;
1366                 if (x_lib_menu_placeholder) x_lib_menu_placeholder.hidden = true;
1367                 if (x_show_cancelled_deck) x_show_cancelled_deck.hidden = false;
1368                 if (x_print_full_pull_list_alt) x_print_full_pull_list_alt.hidden = true;
1369             break;
1370         }
1371         setTimeout( // We do this because render_lib_menus above creates and appends a DOM node, but until this thread exits, it doesn't really happen
1372             function() {
1373                 if (x_lib_filter_checkbox) if (!x_lib_filter_checkbox.checked) {
1374                     if (x_lib_type_menu) x_lib_type_menu.disabled = true;
1375                     if (obj.controller.view.lib_menu) obj.controller.view.lib_menu.disabled = true;
1376                 }
1377                 obj.controller.render();
1378                 obj.retrieve(true);
1379
1380                 obj.controller.view.cmd_retrieve_patron.setAttribute('disabled','true');
1381                 obj.controller.view.cmd_holds_edit_pickup_lib.setAttribute('disabled','true');
1382                 obj.controller.view.cmd_holds_edit_phone_notify.setAttribute('disabled','true');
1383                 obj.controller.view.cmd_holds_edit_email_notify.setAttribute('disabled','true');
1384                 obj.controller.view.cmd_holds_edit_thaw_date.setAttribute('disabled','true');
1385                 obj.controller.view.cmd_holds_activate.setAttribute('disabled','true');
1386                 obj.controller.view.cmd_holds_suspend.setAttribute('disabled','true');
1387                 obj.controller.view.cmd_holds_edit_selection_depth.setAttribute('disabled','true');
1388                 obj.controller.view.cmd_alt_view.setAttribute('disabled','true');
1389                 obj.controller.view.cmd_holds_retarget.setAttribute('disabled','true');
1390                 obj.controller.view.cmd_holds_cancel.setAttribute('disabled','true');
1391                 obj.controller.view.cmd_holds_uncancel.setAttribute('disabled','true');
1392                 obj.controller.view.cmd_show_catalog.setAttribute('disabled','true');
1393             }, 0
1394         );
1395
1396         $('cmd_alt_view').setAttribute('disabled','true');
1397         xulG.when_done = function() {
1398             $('cmd_alt_view').setAttribute('ready','true');
1399             if ($('cmd_alt_view').getAttribute('rendering_rows') != 'true') {
1400                 $('cmd_alt_view').setAttribute('disabled','false');
1401             }
1402             dump('hold details UI ready\n');
1403         }
1404         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
1405         JSAN.use('util.browser');
1406         obj.browser = new util.browser();
1407         obj.browser.init(
1408             {
1409                 'url' : urls.XUL_HOLD_DETAILS,
1410                 'push_xulG' : true,
1411                 'alt_print' : false,
1412                 'browser_id' : 'hold_detail_frame',
1413                 'passthru_content_params' : xulG
1414             }
1415         );
1416
1417     },
1418
1419     'determine_hold_interface_type' : function() {
1420         var obj = this;
1421         if (obj.patron_id) { /*************************************************** PATRON ******************************/
1422             obj.hold_interface_type = 'patron';
1423         } else if (obj.docid) { /*************************************************** RECORD ******************************/
1424             obj.hold_interface_type = 'record';
1425         } else if (obj.pull) { /*************************************************** PULL ******************************/
1426             obj.hold_interface_type = 'pull';
1427         } else if (obj.shelf) { /*************************************************** HOLD SHELF ******************************/
1428             obj.hold_interface_type = 'shelf';
1429         } else { /*************************************************** PULL ******************************/
1430             obj.hold_interface_type = 'pull';
1431         }
1432     },
1433
1434     'clear_and_retrieve' : function() {
1435         try {
1436             this.list.clear();
1437             this.pull_from_shelf_interface.current.offset = this.pull_from_shelf_interface._default.offset;
1438             this.retrieve();
1439             if (window.xulG && typeof window.xulG.on_list_change == 'function') {
1440                 window.xulG.on_list_change(); 
1441             }
1442         } catch(E) {
1443             this.error.standard_unexpected_error_alert('holds.js, clear_and_retrieve(): ',E);
1444         }
1445     },
1446
1447     'retrieve' : function() {
1448         var obj = this; var holds = [];
1449         if (window.xulG && window.xulG.holds) {
1450             holds = window.xulG.holds;
1451         } else {
1452             var method; var params = [ ses() ];
1453             switch(obj.hold_interface_type) {
1454                 case 'patron' :
1455                     if (document.getElementById('show_cancelled_deck').selectedIndex == 0) {
1456                         method = 'FM_AHR_ID_LIST_RETRIEVE_VIA_AU.authoritative';
1457                     } else {
1458                         method = 'FM_AHR_CANCELLED_ID_LIST_RETRIEVE_VIA_AU.authoritative';
1459                     }
1460                     params.push( obj.patron_id );
1461                     obj.controller.view.cmd_retrieve_patron.setAttribute('hidden','true');
1462                 break;
1463                 case 'record' :
1464                     method = 'FM_AHR_RETRIEVE_ALL_VIA_BRE';
1465                     params.push( obj.docid );
1466                     var x_lib_filter = document.getElementById('lib_filter_checkbox');
1467                     var x_lib_type_menu = document.getElementById('lib_type_menu');
1468                     if (x_lib_filter) {
1469                         if (x_lib_filter.checked) {
1470                             if (x_lib_type_menu && obj.controller.view.lib_menu) {
1471                                 var x = {};
1472                                 x[ x_lib_type_menu.value ] = obj.controller.view.lib_menu.value;
1473                                 params.push( x );
1474                             }
1475                         }
1476                     }
1477                     obj.controller.view.cmd_retrieve_patron.setAttribute('hidden','false');
1478                 break;
1479                 case 'shelf' :
1480                     if (obj.expired) {
1481                         method = 'FM_AHR_ID_LIST_EXPIRED_ONSHELF_RETRIEVE';
1482                     } else {
1483                         method = 'FM_AHR_ID_LIST_ONSHELF_RETRIEVE';
1484                     }
1485                     params.push( obj.filter_lib || obj.data.list.au[0].ws_ou() );
1486                     obj.controller.view.cmd_retrieve_patron.setAttribute('hidden','false');
1487                 break;
1488                 case 'pull' :
1489                 default:
1490                     method = 'FM_AHR_ID_LIST_PULL_LIST';
1491                     params.push( obj.pull_from_shelf_interface.current.limit ); params.push( obj.pull_from_shelf_interface.current.offset );
1492                     var x = document.getElementById('hold_count');
1493                     if (x) {
1494                         obj.network.simple_request('FM_AHR_PULL_LIST_COUNT',[ses()],function(req) {
1495                             var count = req.getResultObject();
1496                             if (typeof count.ilsevent == 'undefined' && count != null) {
1497                                 x.setAttribute('value', document.getElementById('patronStrings').getFormattedString(
1498                                     'staff.patron.holds.total_count',
1499                                     [ count ]
1500                                 ));
1501                                 x.hidden = false;
1502                             }
1503                         });
1504                     }
1505                 break;
1506             }
1507             var robj = obj.network.simple_request( method, params );
1508             if (robj != null && typeof robj.ilsevent != 'undefined') throw(robj);
1509             if (method == 'FM_AHR_RETRIEVE_ALL_VIA_BRE') {
1510                 holds = [];
1511                 if (robj != null) {
1512                     holds = holds.concat( robj.copy_holds );
1513                     holds = holds.concat( robj.recall_holds );
1514                     holds = holds.concat( robj.force_holds );
1515                     holds = holds.concat( robj.volume_holds );
1516                     holds = holds.concat( robj.title_holds );
1517                     holds = holds.concat( robj.part_holds );
1518                     holds = holds.concat( robj.issuance_holds );
1519                     holds = holds.concat( robj.metarecord_holds );
1520                     holds = holds.sort();
1521                 }
1522             } else {
1523                 if (robj == null ) {
1524                     holds = [];
1525                 } else {
1526                     if (typeof robj.length == 'undefined') {
1527                         holds = [ robj ];
1528                     } else {
1529                         holds = robj;
1530                     }
1531                 }
1532             }
1533             holds.reverse();
1534             //alert('method = ' + method + ' params = ' + js2JSON(params));
1535         }
1536
1537         var x_fetch_more = document.getElementById('fetch_more');
1538         if (holds.length == 0) {
1539             if (x_fetch_more) x_fetch_more.disabled = true;
1540         } else {
1541             if (x_fetch_more) x_fetch_more.disabled = false;
1542             obj.render(holds);
1543         }
1544
1545     },
1546
1547     'render' : function(holds) {
1548         try {
1549             var obj = this;
1550
1551             function list_append(hold_id) {
1552                 obj.list.append(
1553                     {
1554                         'row' : {
1555                             'my' : {
1556                                 'hold_id' : hold_id,
1557                                 'post_clear_shelf_action' : obj.post_clear_shelf_hold_action_map[ hold_id ]
1558                             }
1559                         },
1560                         'to_bottom' : true
1561                     }
1562                 );
1563             }
1564
1565             function gen_list_append(hold) {
1566                 return function() {
1567                     if (typeof obj.controller.view.lib_menu == 'undefined') {
1568                         list_append(typeof hold == 'object' ? hold.id() : hold);
1569                     } else {
1570                         list_append(typeof hold == 'object' ? hold.id() : hold);
1571                     }
1572                 };
1573             }
1574
1575             //obj.list.clear();
1576
1577             JSAN.use('util.exec'); var exec = new util.exec(2);
1578             var rows = [];
1579             for (var i in holds) {
1580                 rows.push( gen_list_append(holds[i]) );
1581             }
1582             exec.chain( rows );
1583
1584         } catch(E) {
1585             this.error.standard_unexpected_error_alert('holds.js, render():',E);
1586         }
1587     },
1588
1589     'render_lib_menus' : function(types) {
1590         try {
1591             var obj = this;
1592             JSAN.use('util.widgets'); JSAN.use('util.functional'); JSAN.use('util.fm_utils');
1593
1594             var x = document.getElementById('lib_type_menu');
1595             if (types) {
1596                 var nodes = x.firstChild.childNodes;
1597                 for (var i = 0; i < nodes.length; i++) nodes[i].hidden = true;
1598                 for (var i in types) document.getElementById(i).hidden = false;
1599             }
1600             x.setAttribute('oncommand','g.holds.clear_and_retrieve()');
1601
1602             x = document.getElementById('lib_menu_placeholder');
1603             util.widgets.remove_children( x );
1604
1605             JSAN.use('util.file');
1606             var file = new util.file('offline_ou_list');
1607             if (file._file.exists()) {
1608                 var list_data = file.get_object(); file.close();
1609                 var ml = util.widgets.make_menulist( list_data[0], obj.data.list.au[0].ws_ou() );
1610                 ml.setAttribute('id','lib_menu');
1611                 x.appendChild( ml );
1612                 ml.addEventListener(
1613                     'command',
1614                     function(ev) {
1615                         obj.filter_lib = ev.target.value;
1616                         obj.clear_and_retrieve();
1617                     },
1618                     false
1619                 );
1620                 obj.controller.view.lib_menu = ml;
1621             } else {
1622                 throw($("patronStrings").getString('staff.patron.holds.lib_menus.missing_library_list'));
1623             }
1624
1625         } catch(E) {
1626             this.error.standard_unexpected_error_alert('rendering lib menu',E);
1627         }
1628     },
1629
1630     'cmd_clear_expired_onshelf_holds' : function() {
1631         var obj = this;
1632         try {
1633             // Disable anything such as filters that can have us accidentally
1634             // lose these non-repeatable results.  Well, now that they're cached
1635             // it's less of an issue.
1636             if ($('lib_filter_checkbox')) {
1637                 $('lib_filter_checkbox').checked = false;
1638             }
1639             if ($('lib_type_menu')) {
1640                 $('lib_type_menu').disabled = true;
1641             }
1642             if ($('lib_menu_placeholder')) {
1643                 $('lib_menu_placeholder').firstChild.disabled = true;
1644             }
1645             obj.controller.view.cmd_view_expired_onshelf_holds.setAttribute(
1646                 'disabled', 'true');
1647             obj.controller.view.cmd_clear_expired_onshelf_holds.setAttribute(
1648                 'disabled', 'true');
1649
1650             // I could put this with the "retrieval" methods, but since it has
1651             // side effects, seems cleaner to invoke it here
1652             var robj = obj.network.simple_request(
1653                 'CLEAR_HOLD_SHELF',
1654                 [
1655                     ses(),
1656                     obj.filter_lib || obj.data.list.au[0].ws_ou()
1657                 ]
1658             );
1659             if (typeof robj.ilsevent != 'undefined') { throw(robj); }
1660             if (typeof robj.cache_key == 'undefined') { throw(robj); }
1661
1662             var cache_key = robj.cache_key;
1663
1664             // id's in xulG.holds will prevent the normal retrieval method from
1665             // firing.  Let's put our affected hold.id's in here:
1666             xulG.holds = [];
1667
1668             // Start the progress meter
1669             $('progress').value = 0;
1670             $('progress').hidden = false;
1671
1672             // Fetch the affected holds
1673             fieldmapper.standardRequest(
1674                 [ 'open-ils.circ', 'open-ils.circ.hold.clear_shelf.get_cache' ],
1675                 {
1676                     'async' : true,
1677                     'params' : [ ses(), cache_key ],
1678                     'onresponse' : function(r) {
1679                         dojo.forEach(
1680                             openils.Util.readResponse(r),
1681                             function(resp) {
1682                                 if (resp.maximum) {
1683                                     $('progress').value = Number(resp.progress)
1684                                         * 100/resp.maximum;
1685                                     return;
1686                                 }
1687                                 obj.post_clear_shelf_hold_action_map[
1688                                     resp.hold_details.id
1689                                 ] = resp.action;
1690                                 xulG.holds.push( resp.hold_details.id );
1691                             }
1692                         )
1693                     },
1694                     'oncomplete' : function() {
1695                         obj.clear_and_retrieve();
1696                         $('progress').hidden = true;
1697                     }
1698                 }
1699             );
1700
1701         } catch(E) {
1702             if (E.ilsevent == 5000 /* PERM_FAILURE */ ) {
1703                 return; /* handled by network.js */
1704             }
1705             obj.error.standard_unexpected_error_alert(
1706                 'Error in holds.js, cmd_clear_expired_onshelf_holds', E);
1707         }
1708     }
1709 }
1710
1711 dump('exiting patron.holds.js\n');