From 35cabbf30859c70842675131d694927fc7722427 Mon Sep 17 00:00:00 2001 From: miker Date: Wed, 30 Dec 2009 15:43:32 +0000 Subject: [PATCH] Patch from Lebbeous Fogle-Weekley adding a pull list interface for booking reservations git-svn-id: svn://svn.open-ils.org/ILS/trunk@15247 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- .../perlmods/OpenILS/Application/Booking.pm | 171 +++++++++++++--- Open-ILS/web/css/skin/default/booking.css | 21 +- .../js/dojo/openils/booking/nls/pull_list.js | 19 ++ .../dojo/openils/booking/nls/reservation.js | 11 +- Open-ILS/web/js/ui/default/booking/common.js | 64 ++++++ .../web/js/ui/default/booking/pull_list.js | 190 ++++++++++++++++++ .../web/js/ui/default/booking/reservation.js | 137 +++++-------- Open-ILS/web/opac/locale/en-US/lang.dtd | 2 + .../templates/default/booking/pull_list.tt2 | 49 +++++ .../templates/default/booking/reservation.tt2 | 89 ++++---- .../staff_client/chrome/content/main/menu.js | 19 +- .../chrome/content/main/menu_frame_menus.xul | 2 + .../chrome/locale/en-US/offline.properties | 3 + .../server/patron/display_horiz_overlay.xul | 8 +- .../server/patron/display_overlay.xul | 8 +- 15 files changed, 616 insertions(+), 177 deletions(-) create mode 100644 Open-ILS/web/js/dojo/openils/booking/nls/pull_list.js create mode 100644 Open-ILS/web/js/ui/default/booking/common.js create mode 100644 Open-ILS/web/js/ui/default/booking/pull_list.js create mode 100644 Open-ILS/web/templates/default/booking/pull_list.tt2 diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm b/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm index 436d51fe82..b603a606c6 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Booking.pm @@ -3,6 +3,7 @@ package OpenILS::Application::Booking; use strict; use warnings; +use POSIX qw/strftime/; use OpenILS::Application; use base qw/OpenILS::Application/; @@ -478,7 +479,10 @@ sub reservation_list_by_filters { } ]; $cstore->disconnect; - return $ids if not $whole_obj; + if (not $whole_obj) { + $e->disconnect; + return $ids; + } my $bresv_list = $e->search_booking_reservation([ {"id" => $ids}, @@ -489,6 +493,7 @@ sub reservation_list_by_filters { } }] ); + $e->disconnect; return $bresv_list ? $bresv_list : []; } __PACKAGE__->register_method( @@ -522,27 +527,48 @@ NOTES ); +sub naive_ts_string { strftime("%F %T", localtime(shift)); } + sub get_pull_list { - my ($self, $client, $auth, $range, $pickup_lib) = @_; + my ($self, $client, $auth, $range, $interval_secs, $pickup_lib) = @_; my $e = new_editor(xact => 1, authtoken => $auth); return $e->die_event unless $e->checkauth; return $e->die_event unless $e->allowed('RETRIEVE_RESERVATION_PULL_LIST'); - return $e->die_event unless ref($range) eq 'ARRAY'; + return $e->die_event unless ( + ref($range) eq 'ARRAY' or + ($interval_secs = int($interval_secs)) > 0 + ); + + $range = [ naive_ts_string(time), naive_ts_string(time + $interval_secs) ] + if not $range; + + my @fundamental_constraints = ( + {"current_resource" => {"!=" => undef}}, + {"capture_time" => undef}, + {"cancel_time" => undef}, + {"return_time" => undef}, + {"pickup_time" => undef} + ); my $query = { - "select" => {"bresv" => ["id"]}, + "select" => { + "bresv" => [ + "current_resource", + { + "column" => "start_time", + "transform" => "min", + "aggregate" => 1 + } + ] + }, "from" => "bresv", "where" => { "-and" => [ json_query_ranges_overlap( $range->[0], $range->[1], "start_time", "end_time" ), - {"current_resource" => {"!=" => undef}}, - {"capture_time" => undef}, - {"cancel_time" => undef}, - {"return_time" => undef}, - {"pickup_time" => undef} + @fundamental_constraints ], } }; @@ -550,33 +576,128 @@ sub get_pull_list { push @{$query->{"where"}->{"-and"}}, {"pickup_lib" => $pickup_lib}; } - my $ids = [ map { $_->{id} } @{$e->json_query($query)} ]; - if (@$ids) { - my $bresv_list = $e->search_booking_reservation([ - {"id" => $ids}, { - flesh => 1, - flesh_fields => { - bresv => [qw/usr target_resource_type current_resource/] - } + my $rows = $e->json_query($query); + my %resource_id_map = (); + my @all_ids = (); + if (@$rows) { + my $id_query = { + "select" => {"bresv" => ["id"]}, + "from" => "bresv", + "where" => { + "-and" => [ + {"current_resource" => "PLACEHOLDER"}, + {"start_time" => "PLACEHOLDER"}, + ] + } + }; + if ($pickup_lib) { + push @{$id_query->{"where"}->{"-and"}}, + {"pickup_lib" => $pickup_lib}; + } + + foreach (@$rows) { + $id_query->{"where"}->{"-and"}->[0]->{"current_resource"} = + $_->{"current_resource"}; + $id_query->{"where"}->{"-and"}->[1]->{"start_time"} = + $_->{"start_time"}; + + my $results = $e->json_query($id_query); + if (@$results) { + my @these_ids = map { $_->{"id"} } @$results; + push @all_ids, @these_ids; + + $resource_id_map{$_->{"current_resource"}} = [@these_ids]; + } + } + } + if (@all_ids) { + my %bresv_lookup = ( + map { $_->id => $_ } @{ + $e->search_booking_reservation([{"id" => [@all_ids]}, { + flesh => 1, + flesh_fields => { bresv => [ + "usr", + "target_resource_type", + "current_resource" + ]} + }]) + } + ); + $e->disconnect; + return [ map { + my $key = $_; + my $one = $bresv_lookup{$resource_id_map{$key}->[0]}; + my $result = { + "current_resource" => $one->current_resource, + "target_resource_type" => $one->target_resource_type, + "reservations" => [ + map { $bresv_lookup{$_} } @{$resource_id_map{$key}} + ] + }; + foreach (@{$result->{"reservations"}}) { # deflesh + $_->current_resource($_->current_resource->id); + $_->target_resource_type($_->target_resource_type->id); } - ]); - return $bresv_list ? $bresv_list : []; + $result; + } keys %resource_id_map ]; } else { - return $ids; # empty list + $e->disconnect; + return []; } } __PACKAGE__->register_method( method => "get_pull_list", api_name => "open-ils.booking.reservations.get_pull_list", + argc => 4, + signature=> { + params => [ + {type => "string", desc => "Authentication token"}, + {type => "array", desc => + "range: Date/time range for reservations (opt)"}, + {type => "int", desc => + "interval: Seconds from now (instead of range)"}, + {type => "number", desc => "(Optional) Pickup library"} + ], + return => { desc => "An array of hashes, each containing key/value " . + "pairs describing resource, resource type, and a list of " . + "reservations that claim the given resource." } + } +); + + +sub get_copy_fleshed_just_right { + my ($self, $client, $auth, $barcode) = @_; + + my $e = new_editor(authtoken => $auth); + my $results = $e->search_asset_copy([ + {"barcode" => $barcode}, + { + "flesh" => 1, + "flesh_fields" => {"acp" => [qw/call_number location/]} + } + ]); + + if (ref($results) eq 'ARRAY') { + $e->disconnect; + return $results->[0] unless ref $barcode; + return +{ map { $_->barcode => $_ } @$results }; + } else { + return $e->die_event; + } +} +__PACKAGE__->register_method( + method => "get_copy_fleshed_just_right", + api_name => "open-ils.booking.asset.get_copy_fleshed_just_right", argc => 2, signature=> { params => [ - {type => 'string', desc => 'Authentication token'}, - {type => 'array', desc => 'Date/time range for reservations'}, - {type => 'number', desc => '(Optional) Pickup library'} + {type => "string", desc => "Authentication token"}, + {type => "mixed", desc => "One barcode or an array of them"}, ], - return => { desc => "An array of reservations, fleshed with usr, " . - "current_resource, and target_resource_type" } + return => { desc => + "A copy, or a hash of copies keyed by barcode if an array of " . + "barcodes was given" + } } ); diff --git a/Open-ILS/web/css/skin/default/booking.css b/Open-ILS/web/css/skin/default/booking.css index 07a73e25ee..11871f3630 100644 --- a/Open-ILS/web/css/skin/default/booking.css +++ b/Open-ILS/web/css/skin/default/booking.css @@ -52,6 +52,23 @@ option.forced_unavailable { font-weight: bold; font-style: italic; } -div#preselected_patron { - font-size: 12pt; +input#arbitrary_resource { margin-left: 8px; margin-right: 8px; } +div#or { font-size: 12pt; font-weight: bold; } +input#interval_in_days { width: 75px; } +table#the_table thead tr th { + vertical-align: top; + background-color: #dddddd; + color: #000000; + font-weight: bold; + padding: 0 6px 0 6px; + border-left: 1px #333333 solid; + border-right: 1px #333333 solid; +} +tbody#the_table_body td { + vertical-align: top; + padding: 2px; + border-top: 1px #cccccc solid; + border-left: 1px #cccccc solid; + border-bottom: 1px #333333 solid; + border-right: 1px #333333 solid; } diff --git a/Open-ILS/web/js/dojo/openils/booking/nls/pull_list.js b/Open-ILS/web/js/dojo/openils/booking/nls/pull_list.js new file mode 100644 index 0000000000..1bb998752c --- /dev/null +++ b/Open-ILS/web/js/dojo/openils/booking/nls/pull_list.js @@ -0,0 +1,19 @@ +{ + 'PULL_LIST_NO_RESPONSE': "No response from server trying to get pull list!", + 'PULL_LIST_ERROR': "Error trying to fetch pull list: ", + 'COPY_LOOKUP_NO_RESPONSE': "No response looking up copies by barcode", + 'COPY_LOOKUP_ERROR': "Error looking up copies by barcode: ", + 'COPY_MISSING': "Unexpected error: No information for copy: ", + + 'AUTO_pickup_lib_selector': "Select a location for pickup:", + 'AUTO_pull_list_title': "Booking Pull List", + 'AUTO_interval_in_days': "Generate list for this many days hence: ", + 'AUTO_ATTR_VALUE_fetch': "Fetch", + 'AUTO_th_title_or_name': "Title or name", + 'AUTO_th_barcode': "Barcode", + 'AUTO_th_call_number': "Call number", + 'AUTO_th_copy_location': "Copy location", + 'AUTO_th_copy_number': "Copy number", + 'AUTO_th_resv_details': "Reservation details", + 'AUTO_ATTR_VALUE_print': "Print", +} diff --git a/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js b/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js index b2aeae8a41..2939d0f3f1 100644 --- a/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js +++ b/Open-ILS/web/js/dojo/openils/booking/nls/reservation.js @@ -45,6 +45,8 @@ "Error retrieving booking resource type", 'INVALID_TS_RANGE': "You must choose a valid start and end time for the reservation.", + 'BRSRC_NOT_FOUND': "Could not locate that resource.", + 'BRSRC_RETRIVE_ERROR': "Error retrieving resource: ", 'ANY': "ANY", 'AUTO_choose_a_brt': "Choose a Bookable Resource Type", @@ -62,5 +64,12 @@ 'AUTO_bresv_grid_resource': "Resource", 'AUTO_bresv_grid_start_time': "Start time", 'AUTO_bresv_grid_end_time': "End time", - 'AUTO_brt_noncat_only': "Show only non-cataloged bookable resource types" + 'AUTO_brt_noncat_only': "Show only non-cataloged bookable resource types", + 'AUTO_arbitrary_resource': + "Enter the barcode of a cataloged, bookable resource:", + 'AUTO_explain_bookable': + "To reserve an item that is not yet registered as a bookable " + + "resource, find it in the catalog or under Display Item, and "+ + "select Make Item Bookable or Book Item Now there.", + 'AUTO_or': '- Or -' } diff --git a/Open-ILS/web/js/ui/default/booking/common.js b/Open-ILS/web/js/ui/default/booking/common.js new file mode 100644 index 0000000000..4351166ad4 --- /dev/null +++ b/Open-ILS/web/js/ui/default/booking/common.js @@ -0,0 +1,64 @@ +/* Quick and dirty way to localize some strings; not recommended for reuse. + * I'm sure dojo provides a better mechanism for this, but at the moment + * this is faster to implement anew than figuring out the Right way to do + * the same thing w/ dojo. + */ +function init_auto_l10n(el) { + function do_it(myel, cls) { + if (cls) { + var clss = cls.split(" "); + for (var k in clss) { + var parts = clss[k].match(/^AUTO_ATTR_([A-Z]+)_.+$/); + if (parts && localeStrings[clss[k]]) { + myel.setAttribute( + parts[1].toLowerCase(), localeStrings[clss[k]] + ); + } else if (clss[k].match(/^AUTO_/) && localeStrings[clss[k]]) { + myel.innerHTML = localeStrings[clss[k]]; + } + } + } + } + + for (var i in el.attributes) { + if (el.attributes[i].nodeName == "class") { + do_it(el, el.attributes[i].value); + break; + } + } + for (var i in el.childNodes) { + if (el.childNodes[i].nodeType == 1) { // element node? + init_auto_l10n(el.childNodes[i]); // recurse! + } + } +} + +function get_keys(L) { var K = []; for (var k in L) K.push(k); return K; } +function hide_dom_element(e) { e.style.display = "none"; }; +function reveal_dom_element(e) { e.style.display = ""; }; +function formal_name(u) { + var name = u.family_name() + ", " + u.first_given_name(); + if (u.second_given_name()) + name += (" " + u.second_given_name()); + return name; +} +function humanize_timestamp_string(ts) { + /* For now, this discards time zones. */ + var parts = ts.split("T"); + var timeparts = parts[1].split("-")[0].split(":"); + return parts[0] + " " + timeparts[0] + ":" + timeparts[1]; +} +function is_ils_error(e) { return (e.ilsevent != undefined); } +function is_ils_actor_card_error(e) { + return (e.textcode == "ACTOR_CARD_NOT_FOUND"); +} +function my_ils_error(leader, e) { + var s = leader + "\n"; + var keys = [ + "ilsevent", "desc", "textcode", "servertime", "pid", "stacktrace" + ]; + for (var i in keys) { + if (e[keys[i]]) s += ("\t" + keys[i] + ": " + e[keys[i]] + "\n"); + } + return s; +} diff --git a/Open-ILS/web/js/ui/default/booking/pull_list.js b/Open-ILS/web/js/ui/default/booking/pull_list.js new file mode 100644 index 0000000000..f295cc720b --- /dev/null +++ b/Open-ILS/web/js/ui/default/booking/pull_list.js @@ -0,0 +1,190 @@ +dojo.require("openils.User"); +dojo.require("openils.PermaCrud"); +dojo.require("fieldmapper.OrgUtils"); +dojo.require("openils.widget.OrgUnitFilteringSelect"); +dojo.requireLocalization("openils.booking", "pull_list"); + +var localeStrings = dojo.i18n.getLocalization("openils.booking", "pull_list"); +var pcrud = new openils.PermaCrud(); + +var pickup_lib_selected; +var acp_cache = {}; + +function init_pickup_lib_selector() { + var User = new openils.User(); + User.buildPermOrgSelector( + "RETRIEVE_RESERVATION_PULL_LIST", pickup_lib_selector, null, + function() { + pickup_lib_selected = pickup_lib_selector.getValue(); + dojo.connect(pickup_lib_selector, "onChange", + function() { pickup_lib_selected = this.getValue(); } + ) + } + ); +} + +function retrieve_pull_list(ivl_in_days) { + var secs = Number(ivl_in_days) * 86400; + + if (isNaN(secs) || secs < 1) + throw new Error("Invalid interval"); + + return fieldmapper.standardRequest( + ["open-ils.booking", "open-ils.booking.reservations.get_pull_list"], + [xulG.auth.session.key, null, secs, pickup_lib_selected] + ); +} + +function dom_table_rowid(resource_id) { + return "pull_list_resource_" + resource_id; +} + +function generate_result_row(one) { + function cell(id, content) { + var td = document.createElement("td"); + if (id != undefined) td.setAttribute("id", id); + td.appendChild(document.createTextNode(content)); + return td; + } + + function reservation_info_cell(one) { + var td = document.createElement("td"); + for (var i in one.reservations) { + var one_resv = one.reservations[i]; + var div = document.createElement("div"); + var s = humanize_timestamp_string(one_resv.start_time()) + " - " + + humanize_timestamp_string(one_resv.end_time()) + " " + + formal_name(one_resv.usr()); + /* FIXME: The above need patron barcode instead of name, but + * that requires a fix in the middle layer to flesh on the + * right stuff. */ + div.appendChild(document.createTextNode(s)); + td.appendChild(div); + } + return td; + } + + var baseid = dom_table_rowid(one.current_resource.id()); + + var cells = []; + cells.push(cell(undefined, one.target_resource_type.name())); + cells.push(cell(undefined, one.current_resource.barcode())); + cells.push(cell(baseid + "_call_number", "-")); + cells.push(cell(baseid + "_copy_location", "-")); + cells.push(cell(baseid + "_copy_number", "-")); + cells.push(reservation_info_cell(one)); + + var row = document.createElement("tr"); + row.setAttribute("id", baseid); + + for (var i in cells) row.appendChild(cells[i]); + return row; +} + +function render_pull_list_fundamentals(list) { + var rows = []; + + for (var i in list) + rows.push(generate_result_row(list[i])); + + document.getElementById("the_table_body").innerHTML = ""; + + for (var i in rows) + document.getElementById("the_table_body").appendChild(rows[i]); +} + +function get_all_relevant_acp(list) { + var barcodes = []; + for (var i in list) { + if (list[i].target_resource_type.catalog_item()) { + /* There shouldn't be any duplicates. No need to worry bout that */ + barcodes.push(list[i].current_resource.barcode()); + } + } + var results = fieldmapper.standardRequest( + [ + "open-ils.booking", + "open-ils.booking.asset.get_copy_fleshed_just_right" + ], + [xulG.auth.session.key, barcodes] + ); + + if (!results) { + alert(localeStrings.COPY_LOOKUP_NO_RESPONSE); + return null; + } else if (is_ils_error(results)) { + alert(my_ils_error(localeStrings.COPY_LOOKUP_ERROR, results)); + return null; + } else { + return results; + } +} + +function fill_in_pull_list_details(list, acp_cache) { + for (var i in list) { + var one = list[i]; + if (one.target_resource_type.catalog_item() == "t") { + /* FIXME: This block could stand to be a lot more elegant. */ + var call_number_el = document.getElementById( + dom_table_rowid(one.current_resource.id()) + "_call_number" + ); + var copy_location_el = document.getElementById( + dom_table_rowid(one.current_resource.id()) + "_copy_location" + ); + var copy_number_el = document.getElementById( + dom_table_rowid(one.current_resource.id()) + "_copy_number" + ); + + var bc = one.current_resource.barcode(); + + if (acp_cache[bc]) { + if (call_number_el && acp_cache[bc].call_number()) { + var value = acp_cache[bc].call_number().label(); + if (value) call_number_el.innerHTML = value; + } + if (copy_location_el && acp_cache[bc].location()) { + var value = acp_cache[bc].location().name(); + if (value) copy_location_el.innerHTML = value; + } + if (copy_number_el) { + var value = acp_cache[bc].copy_number(); + if (value) copy_number_el.innerHTML = value; + } + } else { + alert(localeStrings.COPY_MISSING + bc); + } + } + } +} + +function populate_pull_list(form) { + /* Step 1: get the pull list from the server. */ + try { + var results = retrieve_pull_list(form.interval_in_days.value); + } catch (E) { + alert(localeStrings.PULL_LIST_ERROR + E); + return; + } + if (results == null) { + alert(localeStrings.PULL_LIST_NO_RESPONSE); + return; + } else if (is_ils_error(results)) { + alert(my_ils_error(localeStrings.PULL_LIST_ERROR, results)); + return; + } + + /* Step 2: render the table with the pull list */ + render_pull_list_fundamentals(results); + + /* Step 3: asynchronously fill in the copy details we're missing */ + setTimeout(function() { + var acp_cache = {}; + if ((acp_cache = get_all_relevant_acp(results))) + fill_in_pull_list_details(results, acp_cache); + }, 0); +} + +function my_init() { + init_pickup_lib_selector(); + init_auto_l10n(document.getElementById("auto_l10n_start_here")); +} diff --git a/Open-ILS/web/js/ui/default/booking/reservation.js b/Open-ILS/web/js/ui/default/booking/reservation.js index 94cdd9c964..662d4cf5ea 100644 --- a/Open-ILS/web/js/ui/default/booking/reservation.js +++ b/Open-ILS/web/js/ui/default/booking/reservation.js @@ -15,6 +15,7 @@ var localeStrings = dojo.i18n.getLocalization("openils.booking", "reservation"); var pcrud = new openils.PermaCrud(); var opts; var our_brt; +var brt_list = []; var brsrc_index = {}; var bresv_index = {}; var just_reserved_now = {}; @@ -184,21 +185,6 @@ SelectorMemory.prototype.restore = function() { /* * Misc helper functions */ -function hide_dom_element(e) { e.style.display = "none"; }; -function reveal_dom_element(e) { e.style.display = ""; }; -function get_keys(L) { var K = []; for (var k in L) K.push(k); return K; } -function formal_name(u) { - var name = u.family_name() + ", " + u.first_given_name(); - if (u.second_given_name()) - name += (" " + u.second_given_name()); - return name; -} -function humanize_timestamp_string(ts) { - /* For now, this discards time zones. */ - var parts = ts.split("T"); - var timeparts = parts[1].split("-")[0].split(":"); - return parts[0] + " " + timeparts[0] + ":" + timeparts[1]; -} function set_datagrid_empty_store(grid) { grid.setStore( new dojo.data.ItemFileReadStore( @@ -206,20 +192,6 @@ function set_datagrid_empty_store(grid) { ) ); } -function is_ils_error(e) { return (e.ilsevent != undefined); } -function is_ils_actor_card_error(e) { - return (e.textcode == "ACTOR_CARD_NOT_FOUND"); -} -function my_ils_error(header, e) { - var s = header + "\n"; - var keys = [ - "ilsevent", "desc", "textcode", "servertime", "pid", "stacktrace" - ]; - for (var i in keys) { - if (e[keys[i]]) s += ("\t" + keys[i] + ": " + e[keys[i]] + "\n"); - } - return s; -} /* * These functions communicate with the middle layer. @@ -484,6 +456,27 @@ function cancel_reservations(bresv_list) { ); } +function munge_specific_resource(barcode) { + try { + var brsrc_list = pcrud.search('brsrc', {'barcode': barcode}); + if (brsrc_list && brsrc_list.length > 0) { + opts.booking_results = { + "brt": [[brsrc_list[0].type(), 0, 1]], + "brsrc": [[brsrc_list[0].id(), 0, 1]], + }; + if (!(our_brt = get_brt_by_id(opts.booking_results.brt[0][0]))) { + alert(localeStrings.COULD_NOT_RETRIEVE_BRT_PASSED_IN); + } else { + init_reservation_interface(); + } + } else { + alert(localeStrings.BRSRC_NOT_FOUND); + } + } catch (E) { + alert(localeStrings.BRSRC_RETRIEVE_ERROR + E); + } +} + /* * These functions deal with interface tricks (populating widgets, * changing the page, etc.). @@ -492,14 +485,10 @@ function provide_brt_selector(targ_div) { if (!targ_div) { alert(localeStrings.NO_TARG_DIV); } else { - var brt_list = xulG.brt_list = get_all_noncat_brt(); + brt_list = get_all_noncat_brt(); if (!brt_list || brt_list.length < 1) { - targ_div.appendChild( - document.createTextNode(localeStrings.NO_BRT_RESULTS) - ); - document.getElementById( - "brt_select_other_controls" - ).style.display = "none"; + document.getElementById("select_noncat_brt_block"). + style.display = "none"; } else { var selector = document.createElement("select"); selector.setAttribute("id", "brt_selector"); @@ -520,17 +509,29 @@ function provide_brt_selector(targ_div) { } } -function init_reservation_interface(f) { +function init_resv_iface_arb() { + init_reservation_interface(document.getElementById("arbitrary_resource")); +} + +function init_resv_iface_sel() { + init_reservation_interface(document.getElementById("brt_selector")); +} + +function init_reservation_interface(widget) { + /* Save a global reference to the brt we're going to reserve */ + if (widget && (widget.selectedIndex != undefined)) { + our_brt = brt_list[widget.selectedIndex]; + } else if (widget != undefined) { + if (!munge_specific_resource(widget.value)) + return; + } + /* Hide and reveal relevant divs. */ var search_block = document.getElementById("brt_search_block"); var reserve_block = document.getElementById("brt_reserve_block"); hide_dom_element(search_block); reveal_dom_element(reserve_block); - /* Save a global reference to the brt we're going to reserve */ - if (f) - our_brt = xulG.brt_list[f.brt_selector.selectedIndex]; - /* Get a list of attributes that can apply to that brt. */ var bra_list = pcrud.search("bra", {"resource_type": our_brt.id()}); if (!bra_list) { @@ -587,12 +588,6 @@ function init_reservation_interface(f) { /* Add a prominent label reminding the user what resource type they're * asking about. */ document.getElementById("brsrc_list_header").innerHTML = our_brt.name(); - - if (opts.patron_barcode) { - document.getElementById("holds_patron_barcode").style.display = "none"; - document.getElementById("patron_barcode").value = opts.patron_barcode; - document.getElementById("patron_barcode").onchange(); - } update_brsrc_list(); } @@ -702,41 +697,6 @@ function cancel_selected_bresv(bresv_dojo_items) { } } -/* Quick and dirty way to localize some strings; not recommended for reuse. - * I'm sure dojo provides a better mechanism for this, but at the moment - * this is faster to implement anew than figuring out the Right way to do - * the same thing w/ dojo. - */ -function init_auto_l10n(el) { - function do_it(myel, cls) { - if (cls) { - var clss = cls.split(" "); - for (var k in clss) { - var parts = clss[k].match(/^AUTO_ATTR_([A-Z]+)_.+$/); - if (parts && localeStrings[clss[k]]) { - myel.setAttribute( - parts[1].toLowerCase(), localeStrings[clss[k]] - ); - } else if (clss[k].match(/^AUTO_/) && localeStrings[clss[k]]) { - myel.innerHTML = localeStrings[clss[k]]; - } - } - } - } - - for (var i in el.attributes) { - if (el.attributes[i].nodeName == "class") { - do_it(el, el.attributes[i].value); - break; - } - } - for (var i in el.childNodes) { - if (el.childNodes[i].nodeType == 1) { // element node? - init_auto_l10n(el.childNodes[i]); // recurse! - } - } -} - /* The following function should return true if the reservation interface * should start normally (show a list of brt to choose from) or false if * it should not (because we've "started" it some other way by setting up @@ -757,16 +717,9 @@ function early_action_passthru() { } if (opts.patron_barcode) { - try { - var patron = get_actor_by_barcode(opts.patron_barcode); - if (patron) { - document.getElementById("preselected_patron").innerHTML = - "Patron targeted for reservation: " + - formal_name(patron) + ""; - } - } catch (E) { - ; /* XXX ignorable? perhaps. */ - } + document.getElementById("contain_patron_barcode").style.display="none"; + document.getElementById("patron_barcode").value = opts.patron_barcode; + update_bresv_grid(); } return true; diff --git a/Open-ILS/web/opac/locale/en-US/lang.dtd b/Open-ILS/web/opac/locale/en-US/lang.dtd index 713d946ef9..dcaa36e067 100644 --- a/Open-ILS/web/opac/locale/en-US/lang.dtd +++ b/Open-ILS/web/opac/locale/en-US/lang.dtd @@ -765,6 +765,8 @@ + + diff --git a/Open-ILS/web/templates/default/booking/pull_list.tt2 b/Open-ILS/web/templates/default/booking/pull_list.tt2 new file mode 100644 index 0000000000..cbaf29ffc4 --- /dev/null +++ b/Open-ILS/web/templates/default/booking/pull_list.tt2 @@ -0,0 +1,49 @@ +[% WRAPPER "default/base.tt2" %] + + + + +
+

+
+
+ + +
+
+ + + + + +
+ +
+
+
+ + + + + + + + + + + + + +
+
+ +
+[% END %] diff --git a/Open-ILS/web/templates/default/booking/reservation.tt2 b/Open-ILS/web/templates/default/booking/reservation.tt2 index ae80b33e65..8ed092327f 100644 --- a/Open-ILS/web/templates/default/booking/reservation.tt2 +++ b/Open-ILS/web/templates/default/booking/reservation.tt2 @@ -1,4 +1,5 @@ [% WRAPPER "default/base.tt2" %] +