Patron Display/Summary Revamp
authorJason Etheridge <jason@esilibrary.com>
Thu, 18 Apr 2013 18:17:10 +0000 (14:17 -0400)
committerJason Etheridge <jason@esilibrary.com>
Thu, 25 Sep 2014 18:03:03 +0000 (14:03 -0400)
This is a proof of concept for speeding up the Patron Display and Summary. It
does this by

1) producing the summary entirely server-side via Template Toolkit and perl
2) disintegrating all of the sub-interfaces like Check Out, Items Out, etc.
   These open in new tabs (with their own summary panes), which should help
   break the expectation that these interfaces should be dynamically
   synchronized, but on the downside will annoy those who are used to
   dedicating specific tab positions to specific interfaces.

The summary is less information dense than before, and completely
non-interactive.  The idea is that identifying information is found in the first
column, and the second column is reserved just for showing information like
holds available, alert message, barred status, and standing penalties--i.e.
things that should prompt the staff to dig deeper.  The third and fourth columns
have some other useful information, and though there's no unifying concept for
those at the moment, there is some of the only-show-what's-useful mindset. For
example, if the user has no DOB on record, then we just don't show the DOB at
all, not even a label and a placeholder.

Some caveats/notes:

There are a lot of hard-coded strings.  I will go back and I18N-ize them. :-)

I wanted to have two separate XUL files for search and display, but for now I
have them combined into a single file so that others can test using stock staff
clients. For the same reason, I've also symlinked (yay, git) display_horiz.xul
to the new display.xul.  As a consequence of this, sticky settings are unique
for each filename.

I put PatronSummary.pm under EGCatLoader for expediency, but it should really
live somewhere else, and in particular, make use of oils auth proxy, and not
the TPAC login page when its session cookie expires. :-)

18 files changed:
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/PatronSummary.pm [new file with mode: 0644]
Open-ILS/src/templates/base_nodojo.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/PatronSummary.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/css/PatronSummary.css.tt2 [new file with mode: 0644]
Open-ILS/xul/staff_client/chrome/content/main/constants.js
Open-ILS/xul/staff_client/chrome/content/main/menu.js
Open-ILS/xul/staff_client/chrome/content/util/list.js
Open-ILS/xul/staff_client/server/main/data.xul
Open-ILS/xul/staff_client/server/patron/display.js [deleted file]
Open-ILS/xul/staff_client/server/patron/display.xul
Open-ILS/xul/staff_client/server/patron/display_horiz_overlay.xul [deleted file]
Open-ILS/xul/staff_client/server/patron/display_overlay.xul [deleted file]
Open-ILS/xul/staff_client/server/patron/holds.js
Open-ILS/xul/staff_client/server/patron/patron.js [new file with mode: 0644]
Open-ILS/xul/staff_client/server/patron/search.js [new file with mode: 0644]
Open-ILS/xul/staff_client/server/patron/search_result.js
Open-ILS/xul/staff_client/server/patron/standing_penalties.js

index 7fe805b..936c21d 100644 (file)
@@ -26,6 +26,7 @@ use OpenILS::WWW::EGCatLoader::Record;
 use OpenILS::WWW::EGCatLoader::Container;
 use OpenILS::WWW::EGCatLoader::SMS;
 use OpenILS::WWW::EGCatLoader::Register;
+use OpenILS::WWW::EGCatLoader::PatronSummary;
 
 my $U = 'OpenILS::Application::AppUtils';
 
@@ -205,6 +206,7 @@ sub load {
     return $self->load_myopac_prefs_my_lists if $path =~ m|opac/myopac/prefs_my_lists|;
     return $self->load_myopac_prefs if $path =~ m|opac/myopac/prefs|;
     return $self->load_sms_cn if $path =~ m|opac/sms_cn|;
+    return $self->load_patron_summary if $path =~ m|opac/PatronSummary|;
 
     return Apache2::Const::OK;
 }
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/PatronSummary.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/PatronSummary.pm
new file mode 100644 (file)
index 0000000..06c4e2a
--- /dev/null
@@ -0,0 +1,184 @@
+package OpenILS::WWW::EGCatLoader;
+use strict; use warnings;
+use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_INTERNAL_SERVER_ERROR REDIRECT HTTP_BAD_REQUEST);
+use OpenSRF::Utils::Logger qw/$logger/;
+use OpenILS::Utils::CStoreEditor qw/:funcs/;
+use OpenILS::Utils::Fieldmapper;
+use OpenILS::Application::AppUtils;
+use OpenILS::Event;
+use OpenSRF::Utils::JSON;
+use Data::Dumper;
+$Data::Dumper::Indent = 0;
+use DateTime;
+my $U = 'OpenILS::Application::AppUtils';
+
+sub isTrue {
+    my $v = shift;
+    return 1 if ($v eq 't');
+    return 0;
+}
+
+sub load_patron_summary {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    #my $gos = $ctx->{get_org_setting};
+    my $e = $self->editor;
+    my $cgi = $self->cgi;
+
+    $self->_load_user_with_prefs() if($e->checkauth);
+
+    $ctx->{page} = 'patron_summary';
+    $ctx->{au_id} = $cgi->param('au_id');
+    my @classnames = ();
+
+    # open-ils.actor.user.fleshed.retrieve.authoritative
+    my $au_resp = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.user.fleshed.retrieve.authoritative',
+        $e->authtoken,
+        $ctx->{au_id},
+        [
+            'card',
+            'profile',
+            'mailing_address',
+            'billing_address',
+            'open_billable_transactions_summary',
+            'standing_penalties',
+            'notes',
+            'usr_activity',
+            'ident_type'
+        ]
+    );
+
+    if (ref $au_resp eq 'HASH' && defined $au_resp->{textcode}) {
+        $ctx->{error} = $au_resp;
+        return Apache2::Const::OK;
+    }
+
+    $au_resp->standing_penalties(
+        grep {
+            isTrue($_->isdeleted) || $_->stop_date
+        } @{ $au_resp->standing_penalties }
+    );
+    $ctx->{user} = $au_resp;
+
+    $ctx->{addr} = $au_resp->mailing_address && $au_resp->mailing_address->valid
+        ? $au_resp->mailing_address
+        : $au_resp->billing_address && $au_resp->billing_address->valid
+            ? $au_resp->billing_address
+            : undef;
+
+    my $classhash = {};
+    my $block_list;
+    foreach my $p ( @{ $au_resp->standing_penalties } ) {
+        $classhash->{ $p->standing_penalty->name } = 1;
+        if ($p->standing_penalty->id >= 100) {
+            $classhash->{'PATRON_HAS_CUSTOM_PENALTY'} = 1;
+        }
+        if (isTrue($p->standing_penalty->staff_alert)) {
+            $classhash->{'PATRON_HAS_STAFF_ALERT'} = 1;
+        }
+        $block_list = $p->standing_penalty->block_list;
+        if ($block_list) {
+            $classhash->{'PATRON_HAS_BLOCK'} = 1;
+            if ($block_list =~ 'CIRC') {
+                $classhash->{'PATRON_HAS_CIRC_BLOCK'} = 1;
+            }
+            if ($block_list =~ 'RENEW') {
+                $classhash->{'PATRON_HAS_RENEW_BLOCK'} = 1;
+            }
+            if ($block_list =~ 'HOLD') {
+                $classhash->{'PATRON_HAS_HOLD_BLOCK'} = 1;
+            }
+            if ($block_list =~ 'CAPTURE') {
+                $classhash->{'PATRON_HAS_CAPTURE_BLOCK'} = 1;
+            }
+            if ($block_list =~ 'FULFILL') {
+                $classhash->{'PATRON_HAS_FULFILL_BLOCK'} = 1;
+            }
+        }
+    }
+    foreach my $c ( keys %{ $classhash } ) {
+        push @classnames, $c;
+    }
+    if (scalar @{ $au_resp->standing_penalties } == 0) {
+        push @classnames, 'NO_PENALTIES';
+    }
+    if (scalar @{ $au_resp->standing_penalties } == 1) {
+        push @classnames, 'ONE_PENALTY';
+    }
+    if (scalar @{ $au_resp->standing_penalties } > 1) {
+        push @classnames, 'MULTIPLE_PENALTIES';
+    }
+    if ($au_resp->alert_message) {
+        push @classnames, 'PATRON_HAS_ALERT';
+    }
+    if (isTrue($au_resp->barred)) {
+        $ctx->{barred} = 1;
+        push @classnames, 'PATRON_BARRED';
+    }
+    if (isTrue($au_resp->juvenile)) {
+        push @classnames, 'PATRON_JUVENILE';
+    }
+    if (!isTrue($au_resp->active)) {
+        push @classnames, 'PATRON_INACTIVE';
+    }
+    if (scalar( @{ $au_resp->notes }) > 0) {
+        push @classnames, 'PATRON_HAS_NOTES';
+    }
+    push @classnames, 'PATRON_NET_ACCESS_' . $au_resp->net_access_level;
+    if (
+        ($au_resp->mailing_address
+        && !isTrue($au_resp->mailing_address->valid))
+    || ($au_resp->billing_address
+        && !isTrue($au_resp->billing_address->valid))
+    ) {
+        push @classnames, 'PATRON_HAS_INVALID_ADDRESS';
+    }
+
+    # TODO: PATRON_EXPIRED
+    # TODO: PATRON_AGE_IS_
+    # TODO: PATRON_AGE_LT_
+    # TODO: PATRON_AGE_GE_
+
+    my $mous_resp = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.user.fines.summary.authoritative',
+        $e->authtoken,
+        $ctx->{au_id}
+    );
+    $ctx->{money_open_user_summary} = $mous_resp;
+
+    if ($mous_resp && $mous_resp->balance_owed > 0) {
+        push @classnames, 'PATRON_HAS_BILLS';
+    }
+
+    my $checked_out_count_resp = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.user.checked_out.count.authoritative',
+        $e->authtoken,
+        $ctx->{au_id}
+    );
+    $ctx->{checked_out_count} = $checked_out_count_resp;
+    if ($checked_out_count_resp
+    && ($checked_out_count_resp->{overdue}
+    + $checked_out_count_resp->{long_overdue}
+    > 0)) {
+        push @classnames, 'PATRON_HAS_OVERDUES';
+    }
+
+    my $holds_count_resp = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.user.hold_requests.count.authoritative',
+        $e->authtoken,
+        $ctx->{au_id}
+    );
+    $ctx->{holds_count} = $holds_count_resp;
+
+    $ctx->{css_classnames} = join ' ', @classnames;
+    $ctx->{orig_params} = $cgi->Vars;
+
+    return Apache2::Const::OK;
+}
+
+
diff --git a/Open-ILS/src/templates/base_nodojo.tt2 b/Open-ILS/src/templates/base_nodojo.tt2
new file mode 100644 (file)
index 0000000..dc2197d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns='http://www.w3.org/1999/xhtml' lang='[% ctx.locale %]' xml:lang='[% ctx.locale %]'>
+    <head>
+        <title>[% ctx.page_title %]</title>
+        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+        <style type="text/css">
+            @import "[% extracss %]";
+        </style>
+    </head>
+    <body class="[% class %]">
+        [% content %]
+    </body>
+</html>
diff --git a/Open-ILS/src/templates/opac/PatronSummary.tt2 b/Open-ILS/src/templates/opac/PatronSummary.tt2
new file mode 100644 (file)
index 0000000..a831ff7
--- /dev/null
@@ -0,0 +1,167 @@
+[%  PROCESS "opac/parts/header.tt2";
+    WRAPPER "base_nodojo.tt2"
+        extracss="/eg/opac/css/PatronSummary.css";
+    ctx.page_title = l("Patron Summary") %]
+    <div id="content-wrapper">
+        <div id="main-content" class="[% ctx.css_classnames %]">
+            <div class="common-full-pad" style="float:none"></div>
+            [% IF NOT ctx.error %]
+            <div class="table patronSummaryDiv">
+                <div class="row"><div class="cell">
+                    <div class="textBackground">
+                        <span class="patronNameLarge">
+                            [% l(
+                                HUMAN_NAME_FORMAT,
+                                ctx.user.prefix, ctx.user.first_given_name,
+                                ctx.user.second_given_name, ctx.user.family_name,
+                                ctx.user.suffix
+                            ) | html %]
+                        </span><br/>
+                        [% IF ctx.addr %]
+                        <span>
+                            [% ctx.addr.street1 | html %]<br/>
+                            [% ctx.addr.street2 | html %]<br/>
+                            [% ctx.addr.city | html %],
+                            [% ctx.addr.state | html %]
+                            [% ctx.post_code | html %]
+                        </span><br/>
+                        [% END %]
+                        <span>
+                        [% IF ctx.user.day_phone %]
+                            [% l('D: [_1] ', ctx.user.day_phone) | html %]
+                        [% ELSIF ctx.user.evening_phone %]
+                            [% l('E: [_1] ', ctx.user.evening_phone) | html %]
+                        [% ELSIF ctx.user.other_phone %]
+                            [% l('O: [_1] ', ctx.user.other_phone) | html %]
+                        [% END %]
+                        </span><br/>
+                        [% IF ctx.user.email %]
+                        <span>
+                            [% ctx.user.email | html %]
+                        </span>
+                        [% END %]
+                    </div>
+                </div><div class="cell">
+                    <div class="textBackground alerts">
+                        [% IF ctx.barred %]
+                        <span>
+                            [% l('Patron is BARRED') %]
+                        </span><br/>
+                        [% END %]
+                        [% IF ctx.holds_count.ready > 0 %]
+                        <span>
+                            [% l('[_1] holds Ready for Pickup', ctx.holds_count.ready) %]
+                        </span><br/>
+                        [% END %]
+                        [% IF ctx.user.alert_message %]
+                        <span>
+                            [% ctx.user.alert_message | html %]
+                        </span><br/>
+                        [% END %]
+                        [% FOREACH p IN ctx.user.standing_penalties %]
+                        <span>
+                            [% p.standing_penalty.label | html %]
+                            [% IF p.note %]
+                                : [% p.note | html %]
+                            [% END %]
+                        </span><br/>
+                        [% END %]
+                    </div>
+                </div><div class="cell">
+                    <div class="textBackground">
+                        <span>[% ctx.user.profile.name | html %]</span><br/>
+                        [% IF ctx.user.card AND ctx.user.card.active %]
+                        <span>
+                            [% l(
+                                'Card: [_1]',
+                                ctx.user.card.barcode
+                            ) | html %]
+                        </span><br/>
+                        [% END %]
+                        <span>
+                            [% l(
+                                'OPAC: [_1]',
+                                ctx.user.usrname
+                            ) | html %]
+                        </span><br/>
+                        [% IF ctx.user.ident_value %]
+                        <span>
+                            [% l(
+                                '[_1]: [_2]',
+                                ctx.user.ident_type.name,
+                                ctx.user.ident_value
+                            ) | html %]
+                        </span><br/>
+                        [% END %]
+                        <span>
+                            [% l(
+                                'Last Updated: [_1]',
+                                date.format(ctx.user.last_update_time, DATE_FORMAT)
+                            ) | html %]
+                        </span><br/>
+                    </div>
+                </div><div class="cell">
+                    <div class="textBackground">
+                        [% IF ctx.user.dob %]
+                        <span>
+                            [% l(
+                                'DOB: [_1]',
+                                date.format(ctx.user.dob, DATE_FORMAT)
+                            ) | html %]
+                        </span><br/>
+                        [% END %]
+                        <span>
+                            [% l(
+                                'Exp: [_1]',
+                                date.format(ctx.user.expire_date, DATE_FORMAT)
+                            ) | html %]
+                        </span><br/>
+                        [% IF ctx.user.usr_activity AND ctx.user.usr_activity.0 %]
+                        <span>
+                            [% l(
+                                'Last Activity: [_1]',
+                                date.format(
+                                    ctx.user.usr_activity.0.event_time,
+                                    DATE_FORMAT
+                                )
+                            ) | html %]
+                        </span><br/>
+                        [% END %]
+                        [% IF ctx.user.credit_forward_balance %]
+                        <span>
+                            [% l(
+                                'Credit: [_1]',
+                                ctx.user.credit_forward_balance
+                            ) | html %]
+                        </span><br/>
+                        [% END %]
+                        [% IF ctx.money_open_user_summary %]
+                        <span>
+                            [% l(
+                                'Balance: [_1]',
+                                ctx.money_open_user_summary.balance_owed
+                            ) | html %]
+                        </span><br/>
+                        [% END %]
+                    </div>
+                </div></div>
+            </div>
+            [% ELSE %]
+            <div>
+                <span style="font-weight: bold; font-size: xx-large">
+                    Error loading user with database id = [% ctx.au_id %]
+                </span><br/>
+                <span style="font-weight: bold;">
+                    Description: [% ctx.error.desc %]
+                </span><br/>
+                <span>Server Time: [% ctx.error.servertime %]</span><br/>
+                <span>Text Code: [% ctx.error.textcode %]</span><br/>
+                <span>ILS Event: [% ctx.error.ilsevent %]</span><br/>
+                <span>PID: [% ctx.error.pid %]</span><br/>
+                <span>Stack Trace: [% ctx.error.stacktrace %]</span><br/>
+            </div>
+            [% END %]
+            <div class="common-full-pad" style="float:none"></div>
+        </div>
+    </div>
+[% END %]
diff --git a/Open-ILS/src/templates/opac/css/PatronSummary.css.tt2 b/Open-ILS/src/templates/opac/css/PatronSummary.css.tt2
new file mode 100644 (file)
index 0000000..7d4f98a
--- /dev/null
@@ -0,0 +1,47 @@
+body {
+    font-family: Arial, Helvetica, sans-serif;
+}
+.textBackground {
+}
+.table {
+    display: table;
+    width: 90%;
+}
+.row { display: table-row; }
+.cell {
+    display: table-cell;
+    padding-left: 10px;
+    padding-right: 10px;
+    width: 25%;
+}
+.fLeft {
+    float: left;
+    padding-left: 10px;
+    padding-right: 10px;
+}
+.fRight {
+    float: right;
+    padding-left: 10px;
+    padding-right: 10px;
+}
+.fNone {
+    float: none;
+    padding-left: 10px;
+    padding-right: 10px;
+}
+.alerts { font-weight: bold; }
+.patronNameLarge { font-weight: bold; }
+.patronSummaryDiv { border: solid thick transparent; padding: 10px; }
+.NO_PENALTIES .patronSummaryDiv { border-color: lime; }
+.ONE_PENALTY .patronSummaryDiv { border-color: #66FFFF; }
+.MULTIPLE_PENALTIES .patronSummaryDiv { border-color: #FF6633; }
+.PATRON_HAS_STAFF_ALERT .patronSummaryDiv { border-color: blue; }
+.PATRON_HAS_BILLS .patronSummaryDiv { border-color: #FFC266; }
+.PATRON_HAS_OVERDUES .patronSummaryDiv { border-color: #FFC266; }
+.PATRON_EXCEEDS_CHECKOUT_COUNT .patronSummaryDiv { border-color: #C99DFF; }
+.PATRON_EXCEEDS_OVERDUE_COUNT .patronSummaryDiv { border-color: #C99DFF; }
+.PATRON_EXCEEDS_FINES .patronSummaryDiv { border-color: #C99DFF; }
+.PATRON_HAS_ALERT .patronSummaryDiv { border-color: yellow; }
+.PATRON_INACTIVE .patronSummaryDiv { border-color: #333333; }
+.PATRON_EXPIRED .patronSummaryDiv { border-color: #666666; }
+.PATRON_BARRED .patronSummaryDiv { border-color: #CC3300; }
index 189d1a4..7b4d4d8 100644 (file)
@@ -520,5 +520,6 @@ var urls = {
     'XUL_SERIAL_BATCH_RECEIVE': 'oils://remote/xul/server/serial/batch_receive.xul',
     'EG_TRIGGER_EVENTS' : 'oils://remote/eg/actor/user/event_log',
     'XUL_SEARCH_PREFS' : 'chrome://open_ils_staff_client/content/main/search_prefs.xul',
-    'XUL_SERVER_ADDONS' : 'oils://remote/xul/server/addon/addons.xul'
+    'XUL_SERVER_ADDONS' : 'oils://remote/xul/server/addon/addons.xul',
+    'EG_PATRON_SUMMARY' : 'oils://remote/eg/opac/PatronSummary',
 }
index 3addc9c..0df205d 100644 (file)
@@ -2439,6 +2439,10 @@ commands:
             var id = tab.getAttribute('id');
             return 'id = ' + id + ' semaphore = ' + obj.tab_semaphores[id];
         }
+        content_params.get_idx = function() {
+            var idx = obj.controller.view.tabs.selectedIndex;
+            return idx;
+        }
         content_params.new_tab = function(a,b,c) { return obj.new_tab(a,b,c); };
         content_params.set_tab = function(a,b,c) { return obj.set_tab(a,b,c); };
         content_params.open_external = function(a) { return obj.open_external(a); };
index 0eba98b..335fdb0 100644 (file)
@@ -1348,6 +1348,16 @@ util.list.prototype = {
         this.node.view.selection.selectAll();
     },
 
+    'retrieve_selection_retrieval_data' : function(params) {
+        var obj = this;
+        return util.functional.map_list(
+            obj.retrieve_selection(params),
+            function(el,idx) {
+                return JSON2js( el.getAttribute('retrieve_id') );
+            }
+        );
+    },
+
     'retrieve_selection' : function(params) {
         var obj = this;
         switch(this.node.nodeName) {
index f18146b..7f86c14 100644 (file)
@@ -95,6 +95,8 @@
             //cache_me('/xul/server/util/browser.xul','http');
             //cache_me('/xul/server/util/rbrowser.xul','http');
 
+            cache_me('/xul/server//patron/search.js','http');
+            cache_me('/xul/server//patron/patron.js','http');
             //cache_me('/xul/server//patron/display.js','http');  
             //cache_me('/xul/server//patron/holds.js','http');  
             //cache_me('/xul/server//patron/items.js','http'); 
             //cache_me('/xul/server//patron/summary.js','http'); 
             //cache_me('/xul/server//patron/util.js','http'); 
 
-            //cache_me('/xul/server/patron/display.xul','http');  
+            cache_me('/xul/server/patron/display.xul','http');
+            cache_me('/xul/server/patron/display_horiz.xul','http');
             //cache_me('/xul/server/patron/display_overlay.xul','http');  
             //cache_me('/xul/server/patron/holds.xul','http');  
             //cache_me('/xul/server/patron/holds_overlay.xul','http');  
             //cache_me('/xul/server/patron/search_result_overlay.xul','http');  
             //cache_me('/xul/server/patron/summary.xul','http'); 
             //cache_me('/xul/server/patron/summary_overlay.xul','http'); 
-            //cache_me('/xul/server/patron/barcode_entry.xul','http');
+            cache_me('/xul/server/patron/barcode_entry.xul','http');
 
             //cache_me('/xul/server/admin/adminlib.js','http');
             //cache_me('/xul/server/admin/admin.css','http');
diff --git a/Open-ILS/xul/staff_client/server/patron/display.js b/Open-ILS/xul/staff_client/server/patron/display.js
deleted file mode 100644 (file)
index 87b50e2..0000000
+++ /dev/null
@@ -1,1075 +0,0 @@
-dump('entering patron/display.js\n');
-dojo.require("openils.User");
-dojo.require("openils.XUL");
-
-function $(id) { return document.getElementById(id); }
-
-if (typeof patron == 'undefined') patron = {};
-patron.display = function (params) {
-
-    JSAN.use('util.error'); this.error = new util.error();
-    JSAN.use('util.window'); this.window = new util.window();
-    JSAN.use('util.network'); this.network = new util.network();
-    JSAN.use('util.widgets'); 
-    this.w = window;
-}
-
-patron.display.prototype = {
-
-    'retrieve_ids' : [],
-    'stop_checkouts' : false,
-    'check_stop_checkouts' : function() { return this.stop_checkouts; },
-
-    'init' : function( params ) {
-
-        var obj = this;
-
-        obj.event_listeners = new EventListenerList();
-        obj.barcode = params['barcode'];
-        obj.id = params['id'];
-
-        JSAN.use('OpenILS.data'); this.OpenILS = {}; 
-        obj.OpenILS.data = new OpenILS.data(); obj.OpenILS.data.init({'via':'stash'});
-        
-        //var horizontal_interface = String( obj.OpenILS.data.hash.aous['ui.circ.patron_summary.horizontal'] ) == 'true';
-        //document.getElementById('ui.circ.patron_summary.horizontal').setAttribute('orient', horizontal_interface ? 'vertical' : 'horizontal');
-        //document.getElementById('pdms1').setAttribute('orient', horizontal_interface ? 'vertical' : 'horizontal');
-        
-        JSAN.use('util.deck'); 
-        obj.right_deck = new util.deck('patron_right_deck');
-        obj.left_deck = new util.deck('patron_left_deck');
-
-        JSAN.use('util.controller'); obj.controller = new util.controller();
-        obj.controller.init(
-            {
-                control_map : {
-                    'cmd_broken' : [
-                        ['command'],
-                        function() { alert($("commonStrings").getString('common.unimplemented')); }
-                    ],
-                    'cmd_patron_retrieve' : [
-                        ['command'],
-                        function(ev) {
-                            if (typeof window.xulG == 'object' && typeof window.xulG.new_tab == 'function') {
-                                for (var i = 0; i < obj.retrieve_ids.length; i++) {    
-                                    try {
-                                        window.xulG.new_patron_tab(
-                                            {}, { 'id' : obj.retrieve_ids[i] }
-                                        );
-                                    } catch(E) {
-                                        alert(E);
-                                    }
-                                }
-                            }
-                        }
-                    ],
-                    'cmd_patron_merge' : [
-                        ['command'],
-                        function(ev) {
-                            JSAN.use('patron.util');
-                            if (patron.util.merge( obj.retrieve_ids )) {
-                                obj.controller.view.cmd_patron_retrieve.setAttribute('disabled','true');
-                                obj.controller.view.cmd_patron_merge.setAttribute('disabled','true');
-                                var sobj = obj.search_result.g.search_result;
-                                if ( sobj.query ) { sobj.search( sobj.query ); }
-                            }
-                        }
-                    ],
-                    'cmd_patron_toggle_summary' : [
-                        ['command'],
-                        function(ev) {
-                            document.getElementById('splitter_grippy').doCommand();
-                        }
-                    ],
-                    'cmd_patron_delete' : [
-                        ['command'],
-                        function(ev) {
-                            try {
-                                if (get_bool( obj.patron.super_user() )) {
-                                    alert($("patronStrings").getString('staff.patron.display.cmd_patron_delete.deny_deletion_of_super_user'));
-                                    return;
-                                }
-                                if (obj.patron.id() == obj.OpenILS.data.list.au[0].id()) {
-                                    alert($("patronStrings").getString('staff.patron.display.cmd_patron_delete.deny_deletion_of_self'));
-                                    return;
-                                }
-                                var rv = obj.error.yns_alert_original(
-                                    $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dialog.message'),
-                                    $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dialog.title'),
-                                    $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dialog.okay'),
-                                    $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dialog.cancel'),
-                                    null,
-                                    $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dialog.confirmation')
-                                );
-                                //alert('rv = ' + rv + ' (' + typeof rv + ')');
-                                if (rv == 0) {
-                                    var params = [ ses(), obj.patron.id() ];
-                                    var staff_check = obj.network.simple_request('PERM_RETRIEVE_WORK_OU',[ ses(), 'STAFF_LOGIN', obj.patron.id() ]);
-                                    if (staff_check.length > 0) {
-                                        var dest_barcode = window.prompt(
-                                            $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dest_user.prompt'),
-                                            $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dest_user.default_value'),
-                                            $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dest_user.title')
-                                        );
-                                        if (!dest_barcode) return;
-                                        JSAN.use('patron.util');
-                                        var dest_usr = patron.util.retrieve_fleshed_au_via_barcode( ses(), dest_barcode );
-                                        if (typeof dest_usr.ilsevent != 'undefined') {
-                                            alert( $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dest_user.failure') );
-                                            return;
-                                        }
-                                        if (dest_usr.id() == obj.patron.id()) {
-                                            alert( $("patronStrings").getString('staff.patron.display.cmd_patron_delete.dest_user.self_reference_failure') );
-                                            return;
-                                        }
-                                        params.push( dest_usr.id() );
-                                    }
-                                    var robj = obj.network.simple_request(
-                                        'FM_AU_DELETE',
-                                        params,
-                                        null,
-                                        {
-                                            'title' : document.getElementById('patronStrings').getString('staff.patron.display.cmd_patron_delete.override_prompt'),
-                                            'overridable_events' : [
-                                                2004 /* ACTOR_USER_DELETE_OPEN_XACTS */
-                                            ]
-                                        }
-                                    );
-                                    if (typeof robj.ilsevent != 'undefined') {
-                                        switch(Number(robj.ilsevent)) {
-                                            /* already informed via override prompt */
-                                            case 2004 /* ACTOR_USER_DELETE_OPEN_XACTS */ :
-                                                return;
-                                            break;
-                                        }
-                                    }
-                                    obj.refresh_all();
-                                }
-                            } catch(E) {
-                                obj.error.standard_unexpected_error_alert('Error in server/patron/display.js -> cmd_patron_delete: ',E);
-                            }
-                        }
-                    ],
-                    'cmd_search_form' : [
-                        ['command'],
-                        function(ev) {
-                            obj.controller.view.cmd_search_form.setAttribute('disabled','true');
-                            obj.left_deck.node.selectedIndex = 0;
-                            obj.controller.view.patron_name.setAttribute('value', $("patronStrings").getString('staff.patron.display.cmd_search_form.no_patron'));
-                            obj.controller.view.patron_name.setAttribute('tooltiptext', '');
-                            obj.controller.view.patron_name.setAttribute('onclick', '');
-                            removeCSSClass(document.documentElement,'PATRON_HAS_BILLS');
-                            removeCSSClass(document.documentElement,'PATRON_HAS_OVERDUES');
-                            removeCSSClass(document.documentElement,'PATRON_HAS_NOTES');
-                            removeCSSClass(document.documentElement,'PATRON_HAS_LOST');
-                            removeCSSClass(document.documentElement,'PATRON_HAS_LOST_AND_COUNTED');
-                            removeCSSClass(document.documentElement,'PATRON_EXCEEDS_CHECKOUT_COUNT');
-                            removeCSSClass(document.documentElement,'PATRON_EXCEEDS_OVERDUE_COUNT');
-                            removeCSSClass(document.documentElement,'PATRON_EXCEEDS_LOST_COUNT');
-                            removeCSSClass(document.documentElement,'PATRON_EXCEEDS_FINES');
-                            removeCSSClass(document.documentElement,'NO_PENALTIES');
-                            removeCSSClass(document.documentElement,'ONE_PENALTY');
-                            removeCSSClass(document.documentElement,'MULTIPLE_PENALTIES');
-                            removeCSSClass(document.documentElement,'PATRON_HAS_ALERT');
-                            removeCSSClass(document.documentElement,'PATRON_BARRED');
-                            removeCSSClass(document.documentElement,'PATRON_INACTIVE');
-                            removeCSSClass(document.documentElement,'PATRON_EXPIRED');
-                            removeCSSClass(document.documentElement,'PATRON_HAS_INVALID_DOB');
-                            removeCSSClass(document.documentElement,'PATRON_JUVENILE');
-                            removeCSSClass(document.documentElement,'PATRON_HAS_INVALID_ADDRESS');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_GE_65');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_LT_65');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_GE_24');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_LT_24');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_GE_21');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_LT_21');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_GE_18');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_LT_18');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_GE_13');
-                            removeCSSClass(document.documentElement,'PATRON_AGE_LT_13');
-                            removeCSSClass(document.documentElement,'PATRON_NET_ACCESS_1');
-                            removeCSSClass(document.documentElement,'PATRON_NET_ACCESS_2');
-                            removeCSSClass(document.documentElement,'PATRON_NET_ACCESS_3');
-                        }
-                    ],
-                    'cmd_patron_refresh' : [
-                        ['command'],
-                        function(ev) {
-                            try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible( document.getElementById("PatronNavBar_refresh" ) ); } catch(E) {};
-                            obj.refresh_all();
-                        }
-                    ],
-                    'cmd_patron_checkout' : [
-                        ['command'],
-                        function(ev) {
-                            obj.reset_nav_styling('cmd_patron_checkout');
-                            obj.spawn_checkout_interface();
-                        }
-                    ],
-                    'cmd_patron_items' : [
-                        ['command'],
-                        function(ev) {
-                            try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible( document.getElementById("PatronNavBar_items" ) ); } catch(E) {};
-                            obj.reset_nav_styling('cmd_patron_items');
-                            var frame = obj.right_deck.set_iframe(
-                                urls.XUL_PATRON_ITEMS,
-                                {},
-                                {
-                                    'patron_id' : obj.patron.id(),
-                                    'on_list_change' : function(b) {
-                                        obj.summary_window.g.summary.controller.render('patron_checkouts');
-                                        obj.summary_window.g.summary.controller.render('patron_standing_penalties');
-                                        obj.summary_window.g.summary.controller.render('patron_bill');
-                                        if (obj.bill_window) {
-                                            obj.bill_window.refresh(true);
-                                        }
-                                    },
-                                    'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                                    'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                                    'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                    'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); }
-                                }
-                            );
-                            obj.items_window = get_contentWindow(frame);
-                        }
-                    ],
-                    'cmd_patron_edit' : [
-                        ['command'],
-                        function(ev) {
-                                try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible( document.getElementById("PatronNavBar_edit" ) ); } catch(E) {};
-                                obj.reset_nav_styling('cmd_patron_edit');
-
-                                function spawn_search(s) {
-                                    obj.error.sdump('D_TRACE', 'Editor would like to search for: ' + js2JSON(s)); 
-                                    obj.OpenILS.data.stash_retrieve();
-                                    xulG.new_patron_tab( {}, { 'doit' : 1, 'query' : js2JSON(s) } );
-                                }
-
-                                function spawn_editor(p) {
-                                    var url = urls.XUL_PATRON_EDIT;
-                                    var loc = xulG.url_prefix('XUL_REMOTE_BROWSER');
-                                    xulG.new_tab(
-                                        loc, 
-                                        {}, 
-                                        { 
-                                            'url' : url,
-                                            'show_print_button' : true , 
-                                            'tab_name' : $("patronStrings").getString('staff.patron.display.spawn_editor.editing_related_patron'),
-                                            'passthru_content_params' : {
-                                                'spawn_search' : spawn_search,
-                                                'spawn_editor' : spawn_editor,
-                                                'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                                                'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                                                'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                                'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); },
-                                                'params' : p,
-                                                'on_save' : function(p_obj) {
-                                                    JSAN.use('patron.util');
-                                                    patron.util.work_log_patron_edit(p_obj);
-                                                }
-                                            },
-                                            'lock_tab' : function() { return xulG.lock_tab(); },
-                                            'unlock_tab' : function() { return xulG.unlock_tab(); }
-                                        }
-                                    );
-                                }
-
-                            obj.right_deck.set_iframe(
-                                urls.XUL_REMOTE_BROWSER + '?patron_edit=1',
-                                {}, {
-                                    'url' : urls.XUL_PATRON_EDIT,
-                                    'show_print_button' : true,
-                                    'passthru_content_params' : {
-                                        'params' : {
-                                            'ses' : ses(),
-                                            'usr' : obj.patron.id()
-                                        },
-                                        'on_save' : function(p) {
-                                            try {
-                                                JSAN.use('patron.util'); 
-                                                patron.util.work_log_patron_edit(p);
-                                                if (obj.barcode) obj.barcode = p.card().barcode();
-                                                //obj.summary_window.g.summary.retrieve();
-                                                obj.refresh_all();
-                                            } catch(E) {
-                                                alert(E);
-                                            }
-                                        },
-                                        'spawn_search' : spawn_search,
-                                        'spawn_editor' : spawn_editor,
-                                        'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                                        'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                                        'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                        'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); }
-                                    },
-                                    'lock_tab' : function() { return xulG.lock_tab(); },
-                                    'unlock_tab' : function() { return xulG.unlock_tab(); }
-                                }
-                            );
-                        }
-                    ],
-                    'cmd_patron_other' : [
-                        ['command'],
-                        function(ev) {
-                            try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible( document.getElementById("PatronNavBar_other" ) ); } catch(E) {};
-                            obj.reset_nav_styling('cmd_patron_other');
-                            try { document.getElementById('PatronNavBar_other').firstChild.showPopup(); } catch(E) {};
-                        }
-                    ],
-                    'cmd_patron_info_notes' : [
-                        ['command'],
-                        function(ev) {
-                            obj.right_deck.set_iframe(
-                                urls.XUL_PATRON_INFO_NOTES,
-                                {},
-                                {
-                                    'patron_id' : obj.patron.id(),
-                                    'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                                    'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                                    'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                    'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); }
-                                }
-                            );
-                        }
-                    ],
-                    'cmd_patron_info_triggered_events' : [
-                        ['command'],
-                        function(ev) {
-                            obj.right_deck.set_iframe(
-                                xulG.url_prefix(urls.XUL_REMOTE_BROWSER),
-                                {},
-                                {
-                                    'url': urls.EG_TRIGGER_EVENTS + "?patron_id=" + obj.patron.id(),
-                                    'show_print_button': false,
-                                    'show_nav_buttons': false
-                                }
-                            );
-                        }
-                    ],
-                    'cmd_patron_info_stats' : [
-                        ['command'],
-                        function(ev) {
-                            obj.right_deck.set_iframe(
-                                urls.XUL_PATRON_INFO_STAT_CATS,
-                                {},
-                                {
-                                    'patron_id' : obj.patron.id(),
-                                    'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                                    'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                                    'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                    'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); }
-                                }
-                            );
-                        }
-                    ],
-                    'cmd_patron_info_surveys' : [
-                        ['command'],
-                        function(ev) {
-                            obj.right_deck.set_iframe(
-                                urls.XUL_PATRON_INFO_SURVEYS,
-                                {},
-                                {
-                                    'patron_id' : obj.patron.id(),
-                                    'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                                    'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                                    'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                    'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); }
-                                }
-                            );
-                        }
-                    ],
-                    'cmd_patron_info_acq_requests' : [
-                        ['command'],
-                        function(ev) {
-                            obj.right_deck.set_iframe(
-                                urls.EG_ACQ_USER_REQUESTS + '?usr=' + obj.patron.id(),
-                                {},
-                                {
-                                    'get_barcode' : function(a,b,c) { return xulG.get_barcode(a,b,c); },
-                                    'get_barcode_and_settings' : function(a,b,c) { return xulG.get_barcode_and_settings(a,b,c); }
-                                }
-                            );
-                        }
-                    ],
-
-                    'cmd_patron_info_groups' : [
-                        ['command'],
-                        function(ev) {
-                            obj.spawn_group_interface();
-                        }
-                    ],
-                    'cmd_patron_alert' : [
-                        ['command'],
-                        function(ev) {
-                            if (obj.msg_url) {
-                                obj.right_deck.set_iframe('data:text/html;charset=UTF-8,'+obj.msg_url,{},{});
-                            } else {
-                                obj.right_deck.set_iframe('data:text/html;charset=UTF-8,<h1>' + $("patronStrings").getString('staff.patron.display.no_alerts_or_messages') + '</h1>',{},{});
-                            }
-                        }
-                    ],
-                    'cmd_patron_reservation' : [
-                        ['command'],
-                        function(ev) {
-                            openils.XUL.newTabEasy(
-                                "BOOKING_RESERVATION",
-                                $("offlineStrings").getString(
-                                    "menu.cmd_booking_reservation.tab"
-                                ), {
-                                    "bresv_interface_opts": {
-                                        "patron_barcode":
-                                            obj.patron.card().barcode()
-                                    }
-                                },
-                                true
-                            );
-                        }
-                    ],
-                    'cmd_patron_reservation_pickup' : [
-                        ['command'],
-                        function(ev) {
-                            openils.XUL.newTabEasy(
-                                "BOOKING_PICKUP",
-                                $("offlineStrings").getString(
-                                    "menu.cmd_booking_reservation_pickup.tab"
-                                ), {
-                                    "bresv_interface_opts": {
-                                        "patron_barcode":
-                                            obj.patron.card().barcode()
-                                    }
-                                },
-                                true
-                            );
-                        }
-                    ],
-                    'cmd_patron_reservation_return' : [
-                        ['command'],
-                        function(ev) {
-                            openils.XUL.newTabEasy(
-                                "BOOKING_RETURN",
-                                $("offlineStrings").getString(
-                                    "menu.cmd_booking_reservation_return.tab"
-                                ), {
-                                    "bresv_interface_opts": {
-                                        "patron_barcode":
-                                            obj.patron.card().barcode()
-                                    }
-                                },
-                                true
-                            );
-                        }
-                    ],
-                    'cmd_patron_exit' : [
-                        ['command'],
-                        function(ev) {
-                            xulG.set_tab(urls.XUL_PATRON_BARCODE_ENTRY,{},{});
-                        }
-                    ],
-                    'cmd_patron_holds' : [
-                        ['command'],
-                        function(ev) {
-                            try {
-                                try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible( document.getElementById("PatronNavBar_holds" ) ); } catch(E) {};
-                                obj.reset_nav_styling('cmd_patron_holds');
-                                obj.right_deck.set_iframe(
-                                    urls.XUL_PATRON_HOLDS,    
-                                    {},
-                                    {
-                                        'display_window' : window,
-                                        'patron_id' : obj.patron.id(),
-                                        'patron_barcode' : obj.patron.card().barcode(),
-                                        'on_list_change' : function(h) {
-                                            try {
-                                                obj.summary_window.g.summary.controller.render('patron_holds');
-                                            } catch(E) {
-                                                alert(E);
-                                            }
-                                        },
-                                        'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                                        'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                                        'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                        'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); },
-                                        'get_barcode' : function(a,b,c) { return xulG.get_barcode(a,b,c); },
-                                        'get_barcode_and_settings' : function(a,b,c) { return xulG.get_barcode_and_settings(a,b,c); }
-                                    }
-                                );
-                            } catch(E) {
-                                alert(E);
-                            }
-                        }
-                    ],
-                    'cmd_patron_bills' : [
-                        ['command'],
-                        function(ev) {
-                            try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible( document.getElementById("PatronNavBar_bills" ) ); } catch(E) {};
-                            obj.reset_nav_styling('cmd_patron_bills');
-                            var f = obj.right_deck.set_iframe(
-                                urls.XUL_PATRON_BILLS,
-                                {},
-                                {
-                                    'display_window' : window,
-                                    'patron_id' : obj.patron.id(),
-                                    'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                                    'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                                    'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                    'on_money_change' : function(b) {
-                                        obj.summary_window.g.summary.controller.render('patron_standing_penalties');
-                                        obj.summary_window.g.summary.controller.render('patron_bill');
-                                        obj.summary_window.refresh();
-                                    }
-                                }
-                            );
-                            obj.bill_window = get_contentWindow(f);
-                        }
-                    ],
-                    'patron_name' : [
-                        ['render'],
-                        function(e) {
-                            return function() { 
-                                JSAN.use('patron.util'); 
-                                e.setAttribute('value',
-                                    patron.util.format_name( obj.patron )
-                                );
-                                patron.util.set_penalty_css(obj.patron);
-                                var tooltiptext = $("patronStrings").getFormattedString(
-                                    'staff.patron.display.db_data',
-                                    [
-                                        obj.patron.id(),
-                                        obj.patron.create_date(),
-                                        obj.patron.last_update_time()
-                                            ? obj.patron.last_update_time()
-                                            : ''
-                                    ]
-                                );
-                                e.setAttribute('tooltiptext',tooltiptext);
-                                e.setAttribute('onclick','try { copy_to_clipboard(event); } catch(E) { alert(E); }');
-                            };
-                        }
-                    ],
-                    'PatronNavBar' : [
-                        ['render'],
-                        function(e) {
-                            return function() {}
-                        }
-                    ],
-                    'cmd_verify_credentials' : [
-                        ['command'],
-                        function() {
-                            var vframe = obj.right_deck.reset_iframe(
-                                urls.XUL_VERIFY_CREDENTIALS,
-                                {},
-                                {
-                                    'barcode' : obj.patron.card().barcode(),
-                                    'usrname' : obj.patron.usrname()
-                                }
-                            );
-                        } 
-                    ],
-                    'cmd_perm_editor' : [
-                        ['command'],
-                        function() {
-                             var frame = obj.right_deck.reset_iframe( urls.XUL_USER_PERM_EDITOR + '?ses=' + window.encodeURIComponent(ses()) + '&usr=' + obj.patron.id(), {}, {});
-                        }
-                    ],
-                    'cmd_standing_penalties' : [
-                        ['command'],
-                        function() {
-                            function penalty_interface() {
-                                try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible( document.getElementById("PatronNavBar_messages" ) ); } catch(E) {};
-                                obj.reset_nav_styling('cmd_standing_penalties');
-                                return obj.right_deck.set_iframe(
-                                    urls.XUL_STANDING_PENALTIES,
-                                    {},
-                                    {
-                                        'patron' : obj.patron,
-                                        'refresh' : function() { 
-                                            obj.refresh_all(); 
-                                        }
-                                    }
-                                );
-                            }
-                            penalty_interface();
-                        } 
-                    ]
-                }
-            }
-        );
-
-        var make_listener = function(xx) {
-            return function() { 
-                try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible(xx); } catch(E) {}; 
-            }
-        };
-
-        
-        var need_focus_listeners = [
-            'PatronNavBar_checkout', 'PatronNavBar_refresh', 'PatronNavBar_items', 'PatronNavBar_holds',
-            'PatronNavBar_other', 'PatronNavBar_edit', 'PatronNavBar_bills', 'PatronNavBar_messages'
-        ];
-        for (var i = 0; i < need_focus_listeners.length; i++) {
-            var elementID = need_focus_listeners[i];
-            var x = document.getElementById(elementID);
-            obj.event_listeners.add(x, 'focus', make_listener(x), false);
-        }
-
-        if (obj.barcode || obj.id) {
-            if (typeof window.xulG == 'object' && typeof window.xulG.set_tab_name == 'function') {
-                try { window.xulG.set_tab_name($("patronStrings").getString('staff.patron.display.init.retrieving_patron')); } catch(E) { alert(E); }
-            }
-
-            var displayClickies = document.getElementById("pdm2hb1a").getElementsByTagName("label");
-            for (var i = 0; i < displayClickies.length; i++) {
-                if (displayClickies[i].getAttribute('command')) {
-                    displayClickies[i].setAttribute('onclick', 'this.doCommand();');
-                }
-            }
-
-            obj.controller.view.PatronNavBar.selectedIndex = 1;
-            JSAN.use('util.widgets'); 
-            util.widgets.enable_accesskeys_in_node_and_children(
-                obj.controller.view.PatronNavBar.lastChild
-            );
-            util.widgets.disable_accesskeys_in_node_and_children(
-                obj.controller.view.PatronNavBar.firstChild
-            );
-            obj.controller.view.cmd_patron_refresh.setAttribute('disabled','true');
-            obj.controller.view.cmd_patron_checkout.setAttribute('disabled','true');
-            obj.controller.view.cmd_patron_items.setAttribute('disabled','true');
-            obj.controller.view.cmd_patron_holds.setAttribute('disabled','true');
-            obj.controller.view.cmd_patron_bills.setAttribute('disabled','true');
-            obj.controller.view.cmd_patron_edit.setAttribute('disabled','true');
-            obj.controller.view.patron_name.setAttribute('value', $("patronStrings").getString('staff.patron.display.init.retrieving'));
-            document.documentElement.setAttribute('class','');
-            var frame = obj.left_deck.set_iframe(
-                urls.XUL_PATRON_SUMMARY,
-                {},
-                {
-                    'display_window' : window,
-                    'barcode' : obj.barcode,
-                    'id' : obj.id,
-                    'refresh' : function() { obj.refresh_all(); },
-                    'on_finished' : obj.gen_patron_summary_finish_func(params),
-                    'stop_sign_page' : obj.gen_patron_stop_sign_page_func(),
-                    'spawn_group_interface' : function() { obj.spawn_group_interface(); },
-                    'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); },
-                    'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                    'set_tab' : function(a,b,c) { return xulG.set_tab(a,b,c); },
-                    'on_error' : function(E) {
-                        try {
-                            var error;
-                            if (typeof E.ilsevent != 'undefined') {
-                                error = E.textcode;
-                            } else {
-                                error = js2JSON(E).substr(0,100);
-                            }
-                            xulG.set_tab(urls.XUL_PATRON_BARCODE_ENTRY + '?error=' + window.encodeURIComponent(error),{},{});
-                        } catch(F) {
-                            alert(F);
-                        }
-                    }
-                }
-            );
-            obj.summary_window = get_contentWindow(frame);
-
-        } else {
-            obj.render_search_form(params);
-        }
-    },
-
-    'cleanup' : function( params ) {
-        var obj = this;
-        delete obj.search_result;
-        delete obj.search_window;
-        delete obj.patron;
-        delete obj.items_window;
-        delete obj.summary_window;
-        delete obj.checkout_window;
-        obj.controller.cleanup();
-        obj.event_listeners.removeAll();
-    },
-
-    'reset_nav_styling' : function(btn,dont_hide_summary) {
-        try {
-            if (!dont_hide_summary) { dont_hide_summary = false; }
-            if (this.skip_hide_summary) {
-                this.skip_hide_summary = false;
-                dont_hide_summary = true;
-            }
-            var buttons = document.getElementsByTagName('button');
-            for(var i = 0; i < buttons.length; i++) {
-                var command = buttons[i].getAttribute('command');
-                if(command == btn) buttons[i].setAttribute('style','background: blue; color: white;');
-                else buttons[i].setAttribute('style','');
-            }
-            var auto_hide_patron_sidebar = String( this.OpenILS.data.hash.aous['circ.auto_hide_patron_summary'] ) == 'true';
-            var x = document.getElementById('splitter_grippy'); 
-            if (x && auto_hide_patron_sidebar && ! dont_hide_summary) {
-                if (! this.summary_hidden_once_already ) {
-                    var first_deck = x.parentNode.previousSibling;
-                    if (! first_deck.collapsed) x.doCommand();
-                    this.summary_hidden_once_already = true;
-                }
-            }
-        } catch(E) {
-            alert(E);
-        }
-    },
-
-    'render_search_form' : function(params) {
-        var obj = this;
-            if (typeof window.xulG == 'object' && typeof window.xulG.set_tab_name == 'function') {
-                try { window.xulG.set_tab_name($("patronStrings").getString('staff.patron.display.render_search_form.patron_search')); } catch(E) { alert(E); }
-            }
-
-            obj.controller.view.PatronNavBar.selectedIndex = 0;
-            obj.controller.view.cmd_patron_retrieve.setAttribute('disabled','true');
-            obj.controller.view.cmd_patron_merge.setAttribute('disabled','true');
-            obj.controller.view.cmd_search_form.setAttribute('disabled','true');
-
-            var horizontal_interface = String( obj.OpenILS.data.hash.aous['ui.circ.patron_summary.horizontal'] ) == 'true';
-            var loc = horizontal_interface ? urls.XUL_PATRON_HORIZONTAL_SEARCH_FORM : urls.XUL_PATRON_SEARCH_FORM; 
-            var my_xulG = {
-                'clear_left_deck' : function() {
-                    setTimeout( function() {
-                        obj.left_deck.clear_all_except(loc);
-                        obj.render_search_form(params);
-                    }, 0);
-                },
-                'on_submit' : function(query,search_limit,search_sort) {
-                    obj.controller.view.cmd_patron_retrieve.setAttribute('disabled','true');
-                    obj.controller.view.cmd_patron_merge.setAttribute('disabled','true');
-                    var list_frame = obj.right_deck.reset_iframe(
-                        urls.XUL_PATRON_SEARCH_RESULT, // + '?' + query,
-                        {},
-                        {
-                            'query' : query,
-                            'search_limit' : search_limit,
-                            'search_sort' : search_sort,
-                            'on_dblclick' : function(list) {
-                                JSAN.use('util.widgets');
-                                util.widgets.dispatch('command','cmd_patron_retrieve')
-                            },
-                            'on_select' : function(list) {
-                                if (!list) return;
-                                if (list.length < 1) return;
-                                obj.controller.view.cmd_patron_retrieve.setAttribute('disabled','false');
-                                if (list.length > 1) obj.controller.view.cmd_patron_merge.setAttribute('disabled','false');
-                                obj.controller.view.cmd_search_form.setAttribute('disabled','false');
-                                obj.retrieve_ids = list;
-                                obj.controller.view.patron_name.setAttribute('value',$("patronStrings").getString('staff.patron.display.init.retrieving'));
-                                document.documentElement.setAttribute('class','');
-                                setTimeout(
-                                    function() {
-                                        var frame = obj.left_deck.set_iframe(
-                                            urls.XUL_PATRON_SUMMARY + '?id=' + window.encodeURIComponent(list[0]),
-                                            {},
-                                            {
-                                                //'id' : list[0],
-                                                'spawn_group_interface' : function() { obj.spawn_group_interface(); },
-                                                'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); },
-                                                'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                                                'set_tab' : function(a,b,c) { return xulG.set_tab(a,b,c); },
-                                                'on_finished' : function(patron) {
-                                                    obj.patron = patron;
-                                                    obj.controller.render();
-                                                }
-                                            }
-                                        );
-                                        obj.summary_window = get_contentWindow(frame);
-                                        obj.patron = obj.summary_window.g.summary.patron;
-                                        obj.controller.render('patron_name');
-                                    }, 0
-                                );
-                            }
-                        }
-                    );
-                    obj.search_result = get_contentWindow(list_frame);
-                }
-            };
-
-            if (params['query']) {
-                my_xulG.query = JSON2js(params['query']);
-                if (params.doit) my_xulG.doit = 1;
-            }
-
-            var form_frame = obj.left_deck.set_iframe(
-                loc,
-                {},
-                my_xulG
-            );
-            obj.search_window = get_contentWindow(form_frame);
-            obj._already_defaulted_once = true;
-    },
-
-    '_already_defaulted_once' : false,
-
-    'refresh_deck' : function(url) {
-        var obj = this;
-        for (var i = 0; i < obj.right_deck.node.childNodes.length; i++) {
-            try {
-                var f = obj.right_deck.node.childNodes[i];
-                var w = get_contentWindow(f);
-                if (url) {
-                    if (w.location.href == url) w.refresh(true);
-                } else {
-                    if (typeof w.refresh == 'function') {
-                        w.refresh(true);
-                    }
-                }
-
-            } catch(E) {
-                obj.error.sdump('D_ERROR','refresh_deck: ' + E + '\n');
-            }
-        }
-    },
-    
-    'refresh_all' : function() {
-        var obj = this;
-        obj.controller.view.patron_name.setAttribute('value', $("patronStrings").getString('staff.patron.display.init.retrieving'));
-        document.documentElement.setAttribute('class','');
-        obj.network.simple_request(
-            'RECALCULATE_STANDING_PENALTIES',
-            [ ses(), obj.patron.id() ]
-        );
-        try { obj.summary_window.refresh(); } catch(E) { obj.error.sdump('D_ERROR', E + '\n'); }
-        try { obj.refresh_deck(); } catch(E) { obj.error.sdump('D_ERROR', E + '\n'); }
-    },
-
-    'spawn_checkout_interface' : function() {
-        var obj = this;
-        try {
-            try { document.getElementById("PatronNavBarScrollbox").ensureElementIsVisible( document.getElementById("PatronNavBar_checkout" ) ); } catch(E) {};
-            obj.reset_nav_styling('cmd_patron_checkout',true);
-            var frame = obj.right_deck.set_iframe(
-                urls.XUL_CHECKOUT,
-                {},
-                { 
-                    'set_tab' : function(a,b,c) { return xulG.set_tab(a,b,c); },
-                    'patron_id' : obj.patron.id(),
-                    'patron' : obj.patron,
-                    'check_stop_checkouts' : function() { return obj.check_stop_checkouts(); },
-                    'on_list_change_old' : function(checkout) {
-                        var x = obj.summary_window.g.summary.controller.view.patron_checkouts;
-                        var n = Number(x.getAttribute('value'));
-                        x.setAttribute('value',n+1);
-                    },
-                    'on_list_change' : function(checkout,is_renewal) {
-                        // Downside here: an extra network call, open-ils.actor.user.checked_out.count.authoritative
-                        obj.summary_window.g.summary.controller.render('patron_checkouts');
-                        obj.summary_window.g.summary.controller.render('patron_standing_penalties');
-
-                        /* this stops noncats from getting pushed into Items Out */
-                        if (!checkout.circ.id()) return;
-
-                        if (obj.items_window) {
-                            if (is_renewal) {
-                                var original_circ_id = obj.items_window.g.items.list_circ_map_by_copy[ checkout.circ.target_copy() ];
-                                obj.items_window.g.items.list_circ_map[ original_circ_id ].row.my.circ = checkout.circ;
-                                obj.items_window.g.items.list_circ_map[ checkout.circ.id() ] =
-                                    obj.items_window.g.items.list_circ_map[ original_circ_id ];
-                                obj.items_window.g.items.refresh( checkout.circ.id() );
-                            } else {
-                                var nparams = obj.items_window.g.items.list.append(
-                                    {
-                                        'row' : {
-                                            'my' : {
-                                                'circ_id' : checkout.circ.id()
-                                            }
-                                        },
-                                        'to_bottom' : true
-                                    }
-                                )
-                                obj.items_window.g.items.list_circ_map[ checkout.circ.id() ] = nparams;
-                                obj.items_window.g.items.list_circ_map_by_copy[ checkout.circ.target_copy() ] = checkout.circ.id();
-                            }
-                        }
-                    },
-                    'get_barcode' : xulG.get_barcode,
-                    'get_barcode_and_settings' : xulG.get_barcode_and_settings,
-                    'url_prefix' : xulG.url_prefix,
-                    'set_statusbar' : xulG.set_statusbar
-                }
-            );
-            obj.checkout_window = get_contentWindow(frame);
-        } catch(E) {
-            alert('Error in spawn_checkout_interface(): ' + E);
-        }
-    },
-
-    'gen_patron_summary_finish_func' : function(display_params) {
-        var obj = this;
-
-        return function(patron,params) {
-            try {
-                obj.patron = patron; obj.controller.render();
-
-                obj.controller.view.cmd_patron_refresh.setAttribute('disabled','false');
-                obj.controller.view.cmd_patron_checkout.setAttribute('disabled','false');
-                obj.controller.view.cmd_patron_items.setAttribute('disabled','false');
-                obj.controller.view.cmd_patron_holds.setAttribute('disabled','false');
-                obj.controller.view.cmd_patron_bills.setAttribute('disabled','false');
-                obj.controller.view.cmd_patron_edit.setAttribute('disabled','false');
-
-                if (typeof window.xulG == 'object' && typeof window.xulG.set_tab_name == 'function') {
-                    try { 
-                        window.xulG.set_tab_name(
-                            $("patronStrings").getString('staff.patron.display.tab_name')
-                                + ' ' + patron.family_name() + ', ' + patron.first_given_name() + ' ' 
-                                + (patron.second_given_name() ? patron.second_given_name() : '' ) 
-                        ); 
-                    } catch(E) { 
-                        obj.error.sdump('D_ERROR',E);
-                    }
-                }
-
-                if (!obj._already_defaulted_once) {
-                    obj._already_defaulted_once = true;
-                    if (display_params['show']) {
-                        setTimeout(
-                            function() {
-                                switch(display_params['show']) {
-                                    case 'bills' : util.widgets.dispatch('command','cmd_patron_bills'); break;
-                                }
-                            },
-                            0
-                        );
-                    } else {
-                        obj.spawn_checkout_interface();
-                    }
-                }
-
-                if (obj.stop_checkouts && obj.checkout_window) {
-                    setTimeout( function() {
-                        try {
-                            obj.checkout_window.g.checkout.check_disable();
-                        } catch(E) { }
-                    }, 1000);
-                }
-                            
-            } catch(E) {
-                alert('Error in patron_summary_finish_func(): ' + E);
-            }
-        };
-    },
-
-    'gen_patron_stop_sign_page_func' : function() {
-        var obj = this;
-        // FIXME - replace this generated "stop sign" page with a dedicated XUL file or template
-        return function(patron,params) {
-            try {
-                obj._already_defaulted_once = true;
-                var msg = ''; obj.stop_checkouts = false;
-                if (patron.alert_message())
-                    msg += $("patronStrings").getFormattedString('staff.patron.display.init.network_request.alert_message', [patron.alert_message()]) + '<br/><br/>';
-                //alert('obj.barcode = ' + obj.barcode);
-                if (obj.barcode) {
-                    if (patron.cards()) for (var i = 0; i < patron.cards().length; i++) {
-                        //alert('card #'+i+' == ' + js2JSON(patron.cards()[i]));
-                        if ( (patron.cards()[i].barcode()==obj.barcode) && ( ! get_bool(patron.cards()[i].active()) ) ) {
-                            msg += $("patronStrings").getString('staff.patron.display.init.network_request.inactive_card') + '<br/><br/>';
-                            obj.stop_checkouts = true;
-                        }
-                    }
-                }
-                if (get_bool(patron.barred())) {
-                    msg += $("patronStrings").getString('staff.patron.display.init.network_request.account_barred') + '<br/><br/>';
-                    obj.stop_checkouts = true;
-                }
-                if (!get_bool(patron.active())) {
-                    msg += $("patronStrings").getString('staff.patron.display.init.network_request.account_inactive') + '<br/><br/>';
-                    obj.stop_checkouts = true;
-                }
-                if (patron.expire_date()) {
-                    var now = new Date();
-                    now = now.getTime()/1000;
-
-                    var expire_parts = patron.expire_date().substr(0,10).split('-');
-                    expire_parts[1] = expire_parts[1] - 1;
-
-                    var expire = new Date();
-                    expire.setFullYear(expire_parts[0], expire_parts[1], expire_parts[2]);
-                    expire = expire.getTime()/1000
-
-                    var preexpire = new Date();
-                    var preexpire_value;
-                    var preexpire_setting = obj.OpenILS.data.hash.aous['circ.patron_expires_soon_warning'];
-                    if (preexpire_setting) {
-                        if (typeof preexpire_setting == "string") { 
-                            preexpire_value = parseInt(preexpire_setting);  
-                        } else {
-                            preexpire_value = preexpire_setting;
-                        }
-                        preexpire.setDate(preexpire.getDate() + preexpire_value);
-                    }
-                    preexpire = preexpire.getTime()/1000;
-
-                    if (expire < now) {
-                        msg += $("patronStrings").getString('staff.patron.display.init.network_request.account_expired') + '<br/><br/>';
-                        obj.stop_checkouts = true;
-                    } else if (expire < preexpire && preexpire_setting) {
-                        msg += $("patronStrings").getString('staff.patron.display.init.network_request.account_expire_soon') + '<br/><br/>';
-                    }
-                }
-                var penalties = patron.standing_penalties();
-                if (!penalties) { penalties = []; }
-                var dl_flag_opened = false;
-                for (var i = 0; i < penalties.length; i++) {
-                    if (get_bool(penalties[i].standing_penalty().staff_alert())) {
-                        if (!dl_flag_opened) {
-                            msg += '<dl>';
-                            dl_flag_opened = true;
-                        }
-                        msg += '<dt>';
-                        msg += obj.OpenILS.data.hash.aou[ penalties[i].org_unit() ].shortname() + ' : ' + penalties[i].standing_penalty().label() + '<br/>';
-                        msg += '</dt><dd>';
-                        msg += (penalties[i].note())?penalties[i].note():'';
-                        msg += '</dd>';
-                    }
-                }
-                if (dl_flag_opened) { msg += '</dl>'; }
-                var holds = params.holds_summary;
-                if (holds.ready && holds.ready > 0) {
-                    msg += $("patronStrings").getFormattedString('staff.patron.display.init.holds_ready', [holds.ready]);
-                }
-                if (msg) {
-                    if (msg != obj.old_msg) {
-                        //obj.error.yns_alert(msg,'Alert Message','OK',null,null,'Check here to confirm this message.');
-                        document.documentElement.firstChild.focus();
-                        var data_url = window.encodeURIComponent("<img src='" + xulG.url_prefix('/xul/server/skin/media/images/stop_sign.png') + "'/>" + '<h1>'
-                            + $("patronStrings").getString('staff.patron.display.init.network_request.window_title') + '</h1><blockquote><p>' + msg + '</p>\r\n\r\n<pre>'
-                            + $("patronStrings").getString('staff.patron.display.init.network_request.window_message') + '</pre></blockquote>');
-                        obj.right_deck.set_iframe('data:text/html;charset=UTF-8,'+data_url,{},{});
-                        obj.old_msg = msg;
-                        obj.msg_url = data_url;
-                    } else {
-                        obj.error.sdump('D_TRACE',$("patronStrings").getFormattedString('staff.patron.display.init.network_request.dump_error_message', [msg]));
-                    }
-                }
-            } catch(E) {
-                alert('Error in patron_stop_sign_page_func(): ' + E);
-            }
-        };
-    },
-
-    'spawn_group_interface' : function() {
-        var obj = this;
-        try {
-            obj.right_deck.set_iframe(
-                urls.XUL_PATRON_INFO_GROUP,
-                {},
-                {
-                    'patron_id' : obj.patron.id(),
-                    'url_prefix' : function(url,secure) { return xulG.url_prefix(url,secure); },
-                    'get_new_session' : function(a) { return xulG.get_new_session(a); },
-                    'new_tab' : function(a,b,c) { return xulG.new_tab(a,b,c); },
-                    'new_patron_tab' : function(a,b) { return xulG.new_patron_tab(a,b); }
-                }
-            );
-        } catch(E) {
-            alert('Error in display.js, spawn_group_interface(): ' + E);
-        }
-    }
-
-}
-
-dump('exiting patron/display.js\n');
index 65a1a74..915e0b8 100644 (file)
 <?xml version="1.0"?>
-<!-- Application: Evergreen Staff Client -->
-<!-- Screen: Patron Display -->
-
-<!-- ///////////////////////////////////////////////////////////////////////////////////////////////////////////// -->
-<!-- STYLESHEETS -->
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="/xul/server/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="/xul/server/skin/patron_display.css" type="text/css"?>
-
-<!-- ///////////////////////////////////////////////////////////////////////////////////////////////////////////// -->
-<!-- LOCALIZATION -->
+<?xml-stylesheet href="oils://remote/xul/server/skin/global.css" type="text/css"?>
 <!DOCTYPE window PUBLIC "" ""[
     <!--#include virtual="/opac/locale/${locale}/lang.dtd"-->
 ]>
+<?xul-overlay href="oils://remote/xul/server/OpenILS/util_overlay.xul"?>
 
-<!-- ///////////////////////////////////////////////////////////////////////////////////////////////////////////// -->
-<!-- OVERLAYS -->
-<?xul-overlay href="/xul/server/OpenILS/util_overlay.xul"?>
-<?xul-overlay href="/xul/server/patron/display_overlay.xul"?>
-
-<window id="patron_display_win" 
-    onload="try { my_init(); font_helper(); persist_helper(); } catch(E) { alert(E); }"
-    onunload="try { my_cleanup(); persist_helper_cleanup(); } catch(E) { alert(E); }"
+<window id="search_win"
+    onload="try { persist_helper(); my_init(); font_helper(); } catch(E) { alert(E); }"
     xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
-    <!-- ///////////////////////////////////////////////////////////////////////////////////////////////////////////// -->
-    <!-- BEHAVIOR -->
     <script type="text/javascript">
         var myPackageDir = 'open_ils_staff_client'; var IAMXUL = true; var g = {};
     </script>
     <scripts id="openils_util_scripts"/>
+    <script type="text/javascript" src="chrome://open_ils_staff_client/content/main/JSAN.js"/>
+    <script type="text/javascript" src="oils://remote/xul/server/patron/search.js"/>
+    <script type="text/javascript" src="oils://remote/xul/server/patron/patron.js"/>
 
-    <script type="text/javascript" src="/xul/server/main/JSAN.js"/>
-    <script type="text/javascript" src="/xul/server/patron/display.js"/>
-    <script>
-    <![CDATA[
-        function $(id) { return document.getElementById(id); }
-    
-        function my_init() {
-            try {
-                if (typeof JSAN == 'undefined') { throw( $("commonStrings").getString('common.jsan.missing') ); }
-                JSAN.errorLevel = "die"; // none, warn, or die
-                JSAN.addRepository('/xul/server/');
-                JSAN.use('util.error'); g.error = new util.error();
-                g.error.sdump('D_TRACE','my_init() for patron_display.xul');
-
-                JSAN.use('patron.display'); g.patron = new patron.display();
-                g.patron.init( { 
-                    'barcode' : xul_param('barcode'),
-                    'id' : xul_param('id'),
-                    'query' : xul_param('query'),
-                    'doit' : xul_param('doit'),
-                    'show' : xul_param('show')
-                } );
-
-            //document.documentElement.style.setProperty('font-size-adjust','1','important');
-
-            } catch(E) {
-                var err_msg = $("commonStrings").getFormattedString('common.exception', ['patron/display.xul', E]);
-                try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); }
-                alert(err_msg);
-            }
-        }
-
-        function my_cleanup() {
-            try {
-                g.patron.cleanup();
-            } catch(E) {
-                var err_msg = $("commonStrings").getFormattedString('common.exception', ['patron/display.xul', E]);
-                try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); }
-                alert(err_msg);
-            }
-        }
-
-        function default_focus() {
-            setTimeout(
-                function() {
-                    try {
-                        var node = g.patron.right_deck.node.selectedPanel;
-                        if (node && get_contentWindow(node) && typeof get_contentWindow(node).default_focus == 'function') {
-                            get_contentWindow(node).default_focus();
-                        } else {
-                            var node = g.patron.left_deck.node.selectedPanel;
-                            if (node && get_contentWindow(node) && typeof get_contentWindow(node).default_focus == 'function') {
-                                get_contentWindow(node).default_focus();
-                            }
-                        }
-                    } catch(E) {
-                        g.error.sdump('D_ERROR','default_focus(): ' + js2JSON(E));
-                    }
-                }, 0
-            );
-        }
-
-    ]]>
-    </script>
+    <messagecatalog id="patronStrings"
+        src="/xul/server/locale/<!--#echo var='locale'-->/patron.properties"/>
+
+    <commandset id="patron_cmds">
+
+        <command id="cmd_swap_view" />
+        <command id="cmd_submit" />
+        <command id="cmd_merge" />
+        <command id="cmd_retrieve" />
+        <command id="cmd_sel_clip" />
+        <command id="cmd_save_columns" />
+        <command id="cmd_search_print" />
+
+        <command id="cmd_reload" />
+        <command id="cmd_bills" />
+        <command id="cmd_checkout" />
+        <command id="cmd_edit" />
+        <command id="cmd_events" />
+        <command id="cmd_group" />
+        <command id="cmd_holds" />
+        <command id="cmd_items_out" />
+        <command id="cmd_messages" />
+        <command id="cmd_notes" />
+        <command id="cmd_perms" />
+        <command id="cmd_reservation" />
+        <command id="cmd_reservation_pickup" />
+        <command id="cmd_reservation_return" />
+        <command id="cmd_requests" />
+        <command id="cmd_statcats" />
+        <command id="cmd_surveys" />
+        <command id="cmd_test_password" />
+        <command id="cmd_delete" />
 
-    <messagecatalog id="patronStrings" src="/xul/server/locale/<!--#echo var='locale'-->/patron.properties"/>
-
-    <commandset id="patron_display_cmds">
-        <command id="cmd_patron_refresh" />
-        <command id="cmd_patron_checkout" />
-        <command id="cmd_patron_items" />
-        <command id="cmd_patron_holds" />
-        <command id="cmd_patron_bills" />
-        <command id="cmd_patron_edit" />
-        <command id="cmd_patron_info_notes" />
-        <command id="cmd_patron_info_triggered_events" />
-        <command id="cmd_patron_info_stats" />
-        <command id="cmd_patron_info_surveys" />
-        <command id="cmd_patron_info_acq_requests" />
-        <command id="cmd_patron_info_groups" />
-        <command id="cmd_patron_other" />
-        <command id="cmd_patron_alert" />
-        <command id="cmd_patron_reservation" />
-        <command id="cmd_patron_reservation_pickup" />
-        <command id="cmd_patron_reservation_return" />
-        <command id="cmd_patron_exit" />
-        <command id="cmd_patron_retrieve" />
-        <command id="cmd_patron_merge" />
-        <command id="cmd_patron_toggle_summary" />
-        <command id="cmd_patron_delete" />
-        <command id="cmd_search_form" />
-        <command id="cmd_verify_credentials" />
-        <command id="cmd_perm_editor" />
-        <command id="cmd_standing_penalties" />
     </commandset>
 
-    <box id="patron_display_main" class="my_overflow" />
+    <deck id="uber_deck" flex="1">
+    <!-- FIXME: this should really be two different XUL files, but for now,
+        to allow testing with stock staff clients, I'm squishing them together
+    -->
+
+    <label value="Loading..."/>
+
+    <vbox flex="1">
+
+    <groupbox id="psgf_gb">
+        <caption id="psgf_gbc" label='&staff.patron_search_form.caption;' />
+        <hbox>
+            <hbox>
+                <label control="inactive"
+                    accesskey="&staff.patron.search_form_overlay.inactive.accesskey;"
+                    value="&staff.patron.search_form_overlay.inactive.value;"/>
+                <checkbox id="inactive" group="_" tabindex="40" oils_persist="checked"/>
+            </hbox>
+            <hbox>
+                <label control="search_ou_menu"
+                    value="&staff.patron.search_form_overlay.search_range_menu.value;"/>
+                <hbox id="search_ou" group="_" tabindex="41" oils_persist="value"/>
+            </hbox>
+            <hbox>
+                <label control="search_profile_menu"
+                    value="&staff.patron_search_form.profile.label;"/>
+                <hbox id="profile" group="_" tabindex="42" oils_persist="value"/>
+            </hbox>
+        </hbox>
+        <hbox>
+            <!-- group 0 = user  group 1 = address  group 2 = phone, ident -->
+            <grid id="psg">
+                <columns id="psc">
+                    <column id="psc1"/>
+                    <column id="psc2" flex="1"/>
+                    <column id="psc3"/>
+                    <column id="psc4" flex="1"/>
+                    <column id="psc5"/>
+                    <column id="psc6" flex="1"/>
+                    <column id="psc7"/>
+                    <column id="psc8" flex="1"/>
+                </columns>
+                <rows id="psr">
+                    <row id="psr1">
+                        <label id="psl6c" control="card" style="font-weight: bold"
+                            value="&staff.patron_search_form.card.label;"
+                            accesskey="&staff.patron_search_form.card.accesskey;"/>
+                        <textbox id="card" group="0" context="clipboard" tabindex="10"/>
+                        <label id="psl1" control="family_name"
+                            value="&staff.patron_search_form.family_name.label;"
+                            accesskey="a"
+                            oldaccesskey="&staff.patron_search_form.family_name.accesskey;"/>
+                        <textbox id="family_name" group="0" context="clipboard" tabindex="14"/>
+                        <label id="psl7" control="street1"
+                            value="&staff.patron_search_form.street1.label;"
+                            accesskey="&staff.patron_search_form.street1.accesskey;"/>
+                        <textbox id="street1" group="1" context="clipboard" tabindex="18"/>
+                        <label id="psl5" control="phone"
+                            value="&staff.patron_search_form.phone.label;"
+                            accesskey="&staff.patron_search_form.phone.accesskey;"/>
+                        <textbox id="phone" group="2" context="clipboard" tabindex="22"/>
+                    </row>
+                    <row id="psr2">
+                        <label id="psl6b" control="usrname"
+                            value="&staff.patron_search_form.usrname.label;"
+                            accesskey="&staff.patron_search_form.usrname.accesskey;"/>
+                        <textbox id="usrname" group="0" context="clipboard" tabindex="11"/>
+                        <label id="psl2" control="first_given_name"
+                            value="&staff.patron_search_form.first_given_name.label;"
+                            accesskey="&staff.patron_search_form.first_given_name.accesskey;"/>
+                        <textbox id="first_given_name" group="0" context="clipboard" tabindex="15"/>
+                        <label id="psl8" control="street2"
+                            value="&staff.patron_search_form.street2.label;"
+                            accesskey="&staff.patron_search_form.street2.accesskey;"/>
+                        <textbox id="street2" group="1" context="clipboard" tabindex="19"/>
+                        <label id="psl4" control="email"
+                            value="&staff.patron_search_form.email.label;"
+                            accesskey="&staff.patron_search_form.email.accesskey;"/>
+                        <textbox id="email" group="0" context="clipboard" tabindex="23"/>
+                    </row>
+                    <row id="psr3">
+                        <label id="psl6" control="ident"
+                            value="&staff.patron_search_form.ident.label;"
+                            accesskey="&staff.patron_search_form.ident.accesskey;"/>
+                        <textbox id="ident" group="2" context="clipboard" tabindex="12"/>
+                        <label id="psl3" control="second_given_name"
+                            value="&staff.patron_search_form.second_given_name.label;"
+                            accesskey="&staff.patron_search_form.second_given_name.accesskey;"/>
+                        <textbox id="second_given_name" group="0" context="clipboard" tabindex="16"/>
+                        <label id="psl9" control="city"
+                            value="&staff.patron_search_form.city.label;"
+                            accesskey="&staff.patron_search_form.city.accesskey;"/>
+                        <textbox id="city" group="1" context="clipboard" tabindex="20"/>
+                        <label id="psl10" control="state"
+                            value="&staff.patron_search_form.state.label;"
+                            accesskey="&staff.patron_search_form.state.accesskey;"/>
+                        <textbox id="state" group="1" context="clipboard" tabindex="24"/>
+                    </row>
+                    <row id="psr14">
+                        <spacer/>
+                        <spacer/>
+                        <label id="psl14" control="alias"
+                            value="&staff.patron_search_form.alias.label;"
+                            accesskey="&staff.patron_search_form.alias.accesskey;"/>
+                        <textbox id="alias" group="0" context="clipboard" tabindex="17"/>
+                        <label id="psl11" control="post_code"
+                            value="&staff.patron_search_form.post_code.label;"
+                            accesskey="&staff.patron_search_form.post_code.accesskey;"/>
+                        <textbox id="post_code" group="1" context="clipboard" tabindex="21"/>
+                    </row>
+                </rows>
+            </grid>
+            <vbox>
+                <button id="search" flex="1" label="&staff.patron_search_form.search.label;"
+                    accesskey="&staff.patron_search_form.search.accesskey;"
+                    command="cmd_submit" tabindex="30"/>
+                <button id="clear" label="&staff.patron_search_form.clear.label;"
+                    accesskey="&staff.patron_search_form.clear.accesskey;"
+                    command="cmd_clear" tabindex="31"/>
+            </vbox>
+        </hbox>
+    </groupbox>
+    <groupbox flex="1">
+        <caption label="Patrons"/>
+        <deck id="deck" flex="1">
+            <tree id="patron_list" flex="1" enableColumnDrag="true" seltype="multiple"/>
+            <iframe id="iframe" flex="1"/>
+        </deck>
+        <hbox>
+            <hbox id="patron_list_actions"/>
+            <hbox id="retrieve_settings">
+                <button type="menu"
+                    label="Retrieve Settings"
+                    accesskey="t">
+                    <menupopup>
+                        <menuitem type="checkbox" id="auto"
+                            oils_persist="checked"
+                            accesskey="M"
+                            label="Auto-Retrieve Single Match"/>
+                        <menuitem type="checkbox" id="replace_tab"
+                            oils_persist="checked"
+                            accesskey="T"
+                            label="Replace Tab on Retrieve"/>
+                        <menuitem type="checkbox" id="retrieve_library_card"
+                            oils_persist="checked"
+                            accesskey="C"
+                            label="Retrieve Library Card with search results"/>
+                        <menuitem type="checkbox" id="retrieve_mailing_address"
+                            oils_persist="checked"
+                            accesskey="M"
+                            label="Retrieve Mailing Address with search results"/>
+                        <menuitem type="checkbox" id="retrieve_billing_address"
+                            oils_persist="checked"
+                            accesskey="B"
+                            label="Retrieve Billing Address with search results"/>
+                    </menupopup>
+                </button>
+            </hbox>
+            <spacer flex="1"/>
+            <button id="swap_btn"
+                label="Toggle View"
+                accesskey="V"
+                command="cmd_swap_view"/>
+            <button id="pnb1b2"
+                label="&staff.patron.display_overlay.merge_patrons.label;"
+                accesskey="&staff.patron.display_overlay.merge_patrons.accesskey;"
+                command="cmd_merge"/>
+            <button id="pnb1b1"
+                label="&staff.patron.display_overlay.retrieve_patron.label;"
+                accesskey="&staff.patron.display_overlay.retrieve_patron.accesskey;"
+                command="cmd_retrieve"/>
+        </hbox>
+    </groupbox>
+
+    </vbox>
+
+    <vbox flex="1">
+        <hbox id="top_pane" flex="1" oils_persist="height">
+            <iframe id="iframe1" flex="1" src="data:,Loading..." oils_persist="height"/>
+        </hbox>
+        <splitter collapse="before" resizebefore="flex" resizeafter="flex" oils_persist="state hidden" oils_persist_peers="top_pane bottom_pane"><grippy/></splitter>
+        <hbox id="bottom_pane" flex="1" oils_persist="height">
+            <vbox id="button_box" oils_persist="height width" class="my_overflow">
+                <button id="reload"
+                    label="Reload"
+                    accesskey="R"
+                    command="cmd_reload"/>
+                <description>New tab for...</description>
+                <vbox id="main_button_group">
+                    <button id="bills"
+                        label="Bills"
+                        accesskey="B"
+                        command="cmd_bills"/>
+                    <button id="booking" type="menu"
+                        label="Booking"
+                        accesskey="k">
+                        <menupopup>
+                            <menuitem command="cmd_reservation"
+                                label="&staff.main.menu.booking.reservation.label_alt;"
+                                acceskey="&staff.main.menu.booking.reservation.accesskey;"/>
+                            <menuitem command="cmd_reservation_pickup"
+                                label="&staff.main.menu.booking.reservation_pickup.label;"
+                                acceskey="&staff.main.menu.booking.reservation_pickup.accesskey;"/>
+                            <menuitem command="cmd_reservation_return"
+                                label="&staff.main.menu.booking.reservation_return.label;"
+                                acceskey="&staff.main.menu.booking.reservation_return.accesskey;"/>
+                        </menupopup>
+                    </button>
+                    <button id="checkout"
+                        label="Check Out"
+                        accesskey="C"
+                        command="cmd_checkout"/>
+                    <button id="edit"
+                        label="Edit"
+                        accesskey="E"
+                        command="cmd_edit"/>
+                    <button id="events"
+                        label="Events"
+                        accesskey="v"
+                        command="cmd_events"/>
+                    <button id="group"
+                        label="Group"
+                        accesskey="G"
+                        command="cmd_group"/>
+                    <button id="holds"
+                        label="Holds"
+                        accesskey="H"
+                        command="cmd_holds"/>
+                    <button id="items_out"
+                        label="Items Out"
+                        accesskey="I"
+                        command="cmd_items_out"/>
+                    <button id="messages"
+                        label="Messages"
+                        accesskey="M"
+                        command="cmd_messages"/>
+                    <button id="notes"
+                        label="Notes"
+                        accesskey="N"
+                        command="cmd_notes"/>
+                    <button id="perms"
+                        label="Permissions"
+                        accesskey="P"
+                        command="cmd_perms"/>
+                    <button id="requests"
+                        label="Requests"
+                        accesskey="q"
+                        command="cmd_requests"/>
+                    <button id="statcats"
+                        label="StatCats"
+                        accesskey="S"
+                        command="cmd_statcats"/>
+                    <button id="surveys"
+                        label="Surveys"
+                        accesskey="y"
+                        command="cmd_surveys"/>
+                    <button id="test_password"
+                        label="Test Password"
+                        accesskey="T"
+                        command="cmd_test_password"/>
+                </vbox>
+                <label value=" "/>
+                <button id="delete"
+                    label="Delete"
+                    accesskey=""
+                    command="cmd_delete"/>
+            </vbox>
+            <splitter collapse="before"
+                oils_persist="state hidden"
+                oils_persist_peers="button_box iframe2">
+                <grippy/>
+            </splitter>
+        </hbox>
+    </vbox>
+
+    </deck>
 
 </window>
 
diff --git a/Open-ILS/xul/staff_client/server/patron/display_horiz_overlay.xul b/Open-ILS/xul/staff_client/server/patron/display_horiz_overlay.xul
deleted file mode 100644 (file)
index a73aa46..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE overlay PUBLIC "" ""[
-    <!--#include virtual="/opac/locale/${locale}/lang.dtd"-->
-]>
-<overlay id="patron_display_overlay" 
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
-<script>dump('loading patron/display_overlay.xul\n');</script>
-
-<commandset id="patron_display_cmds" />
-
-<box id="patron_display_main" flex="1" orient="vertical">
-<vbox id="pdm2" flex="1">
-    <hbox id="pdm2hb1">
-        <hbox>
-            <label id="patron_name" class="patronNameLarge" value="&staff.patron.display_overlay.none_selected.value;" flex="1"/>
-        </hbox>
-        <deck id="PatronNavBar" flex="1" class="my_overflow" />
-    </hbox>
-    <hbox id="pdm2hb1a">
-        <label class="hideme barred_indicator" value="&staff.patron.display_overlay.barred.value;" command="cmd_patron_edit"/>
-        <label class="hideme expired_indicator" value="&staff.patron.display_overlay.expired.value;" command="cmd_patron_edit"/>
-        <label class="hideme inactive_indicator" value="&staff.patron.display_overlay.inactive.value;" command="cmd_patron_edit"/>
-        <label class="hideme juvenile_indicator" value="&staff.patron.display_overlay.juvenile.value;" command="cmd_patron_edit"/>
-        <label class="hideme alert_indicator" value="&staff.patron.display_overlay.alert.value;" command="cmd_patron_edit"/>
-        <label class="hideme note_indicator" value="&staff.patron.display_overlay.see_notes.value;" command="cmd_patron_info_notes"/>
-        <label class="hideme max_bills_indicator" value="&staff.patron.display_overlay.max_bills.value;" command="cmd_patron_bills"/>
-        <label class="hideme max_overdues_indicator" value="&staff.patron.display_overlay.max_overdues.value;" command="cmd_patron_items"/>
-        <label class="hideme max_out_indicator" value="&staff.patron.display_overlay.max_checked_out.value;" command="cmd_patron_items"/>
-        <label class="hideme bills_indicator" value="&staff.patron.display_overlay.has_bills.value;" command="cmd_patron_bills"/>
-        <label class="hideme overdues_indicator" value="&staff.patron.display_overlay.has_overdues.value;" command="cmd_patron_items"/>
-        <label class="hideme max_lost_indicator" value="&staff.patron.display_overlay.max_lost.value;" command="cmd_patron_items"/>
-        <label class="hideme lost_indicator" value="&staff.patron.display_overlay.has_lost.value;" command="cmd_patron_items"/>
-        <label class="hideme invalid_dob_indicator" value="&staff.patron.display_overlay.invalid_dob.value;" command="cmd_patron_edit"/>
-        <label class="hideme invalid_address_indicator" value="&staff.patron.display_overlay.invalid_address.value;" command="cmd_patron_edit"/>
-        <label class="hideme invalid_email_indicator" value="&staff.patron.display_overlay.invalid_email.value;" command="cmd_patron_edit"/>
-        <label class="hideme invalid_phone_indicator" value="&staff.patron.display_overlay.invalid_phone.value;" command="cmd_patron_edit"/>
-    </hbox>
-    <vbox id="PatronNotNavBar" flex="1" class="my_bg">
-        <hbox id="left_deck_vbox" flex="1" oils_persist="height"> 
-            <deck id="patron_left_deck" oils_persist="height"/>
-        </hbox>
-        <splitter id="deck_splitter" collapse="before" oils_persist="state hidden" oils_persist_peers="left_deck_vbox right_deck_vbox"><grippy id="splitter_grippy"/></splitter>
-        <hbox id="right_deck_vbox" flex="3" oils_persist="height">
-            <deck id="patron_right_deck" oils_persist="height"/>
-        </hbox>
-    </vbox>
-</vbox>
-</box>
-
-<deck id="patron_right_deck" flex="1">
-</deck>
-
-<deck id="patron_left_deck" flex="1">
-</deck>
-
-<deck id="PatronNavBar">
-    <hbox id="PatronNavBar0" flex="1"/>
-    <hbox id="PatronNavBar1" flex="1"/>
-</deck>
-
-<hbox id="PatronNavBar1" flex="1">
-    <vbox flex="1">
-        <hbox flex="1">
-            <spacer flex="1"/>
-            <arrowscrollbox id="PatronNavBarScrollbox" orient="horizontal" flex="1">
-                <spacer flex="1"/>
-                <grid>
-                    <columns>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                    </columns>
-                    <rows>
-                        <row>
-                            <button id="PatronNavBar_refresh" command="cmd_patron_refresh" class="nav"
-                                label="&staff.patron_navbar.refresh;" accesskey="&staff.patron_navbar.refresh.accesskey;"/>
-                            <button id="PatronNavBar_checkout" command="cmd_patron_checkout" class="nav"
-                                label="&staff.patron_navbar.checkout;" accesskey="&staff.patron_navbar.checkout.accesskey;"/>
-                            <button id="PatronNavBar_items" command="cmd_patron_items" class="nav"
-                                label="&staff.patron_navbar.items;" accesskey="&staff.patron_navbar.items.accesskey;"/>
-                            <button id="PatronNavBar_holds" command="cmd_patron_holds" class="nav"
-                                label="&staff.patron_navbar.holds;" accesskey="&staff.patron_navbar.holds.accesskey;"/>
-                            <button id="PatronNavBar_bills" command="cmd_patron_bills" class="nav"
-                                label="&staff.patron_navbar.bills;" accesskey="&staff.patron_navbar.bills.accesskey;"/>
-                            <button id="PatronNavBar_edit" command="cmd_patron_edit" class="nav"
-                                label="&staff.patron_navbar.edit;" accesskey="&staff.patron_navbar.edit.accesskey;"/>
-                            <button id="PatronNavBar_messages" label="&staff.patron_navbar.actions.menu.standing_penalties.label;" accesskey="&staff.patron_navbar.actions.menu.standing_penalties.accesskey;" command="cmd_standing_penalties" class="nav"/>
-                            <button id="PatronNavBar_other" command="cmd_patron_other" class="nav" label="&staff.patron_navbar.other;" accesskey="&staff.patron_navbar.other.accesskey;" type="menu">
-                                <menupopup>
-                                    <menuitem label="&staff.patron_navbar.alert;" accesskey="&staff.patron_navbar.alert.accesskey;" command="cmd_patron_alert"/>
-                                    <menuitem label="&staff.patron.info.notes.label;" accesskey="&staff.patron.info.notes.accesskey;" command="cmd_patron_info_notes"/>
-                                    <menuitem label="&staff.patron.info.triggered_events.label;" accesskey="&staff.patron.info.triggered_events.accesskey;" command="cmd_patron_info_triggered_events"/>
-                                    <menuitem label="&staff.patron.info.stat_cats.label;" accesskey="&staff.patron.info.stat_cats.accesskey;" command="cmd_patron_info_stats"/>
-                                    <menu id="PatronNavBar_other_booking" label="&staff.main.menu.booking.label;" accesskey="&staff.main.menu.booking.accesskey;">
-                                        <menupopup id="PatronNavBar_other_booking_popup">
-                                            <menuitem label="&staff.main.menu.booking.reservation.label_alt;" accesskey="&staff.main.menu.booking.reservation.accesskey;" command="cmd_patron_reservation" />
-                                            <menuitem label="&staff.main.menu.booking.reservation_pickup.label;" accesskey="&staff.main.menu.booking.reservation_pickup.accesskey;" command="cmd_patron_reservation_pickup" />
-                                            <menuitem label="&staff.main.menu.booking.reservation_return.label;" accesskey="&staff.main.menu.booking.reservation_return.accesskey;" command="cmd_patron_reservation_return" />
-                                        </menupopup>
-                                    </menu>
-                                    <menuitem label="&staff.patron.info.surveys.label;" accesskey="&staff.patron.info.surveys.accesskey;" command="cmd_patron_info_surveys"/>
-                                    <menuitem label="&staff.patron.info.acq_requests.label;" accesskey="&staff.patron.info.acq_requests.accesskey;" command="cmd_patron_info_acq_requests"/>
-                                    <menuitem label="&staff.patron.info.group.label;" accesskey="&staff.patron.info.group.accesskey;" command="cmd_patron_info_groups"/>
-                                    <menuitem label="&staff.patron_display.verify_password.label;" accesskey="&staff.patron_display.verify_password.accesskey;" command="cmd_verify_credentials"/>
-                                    <menuitem label="&staff.main.menu.admin.user_edit.label;" accesskey="&staff.main.menu.admin.user_edit.accesskey;" command="cmd_perm_editor"/>
-                                    <menuitem label="&staff.patron_display.toggle_summary.label;" accesskey="&staff.patron_display.toggle_summary.accesskey;" command="cmd_patron_toggle_summary"/>
-                                    <menuitem label="&staff.patron_display.delete_patron.label;" accesskey="&staff.patron_display.delete_patron.accesskey;" command="cmd_patron_delete"/>
-                                    <menuitem label="&staff.patron.display_overlay.exit.label;" accesskey="&staff.patron.display_overlay.exit.accesskey;" command="cmd_patron_exit"/>
-                                </menupopup>
-                            </button>
-                        </row>
-                        <row>
-                            <label id="under_refresh"/>
-                            <label id="under_checkout"/>
-                            <label id="under_items"/>
-                            <label id="under_holds"/>
-                            <label id="under_bills"/>
-                            <label id="under_edit"/>
-                            <label id="under_info"/>
-                            <label id="under_edit"/>
-                        </row>
-                    </rows>
-                </grid>
-            </arrowscrollbox>
-        </hbox>
-    </vbox>
-</hbox>
-
-<hbox id="PatronNavBar0" flex="1">
-    <vbox flex="1">
-        <hbox flex="1">
-            <spacer flex="1"/>
-            <button id="pnb1b2" label="&staff.patron.display_overlay.merge_patrons.label;" accesskey="&staff.patron.display_overlay.merge_patrons.accesskey;" command="cmd_patron_merge"/>
-            <button id="pnb1b0" label="&staff.patron.display_overlay.search_form.label;" accesskey="&staff.patron.display_overlay.search_form.accesskey;" command="cmd_search_form"/>
-            <button id="pnb1b1" label="&staff.patron.display_overlay.retrieve_patron.label;" accesskey="&staff.patron.display_overlay.retrieve_patron.accesskey;" command="cmd_patron_retrieve"/>
-        </hbox>
-        <label value=" "/>
-    </vbox>
-</hbox>
-
-</overlay>
diff --git a/Open-ILS/xul/staff_client/server/patron/display_overlay.xul b/Open-ILS/xul/staff_client/server/patron/display_overlay.xul
deleted file mode 100644 (file)
index 7437b76..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE overlay PUBLIC "" ""[
-    <!--#include virtual="/opac/locale/${locale}/lang.dtd"-->
-]>
-<overlay id="patron_display_overlay" 
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
-<script>dump('loading patron/display_overlay.xul\n');</script>
-
-<commandset id="patron_display_cmds" />
-
-<box id="patron_display_main" flex="1" orient="vertical">
-<vbox id="pdm2" flex="1">
-    <hbox id="pdm2hb1">
-        <hbox>
-            <label id="patron_name" class="patronNameLarge" value="&staff.patron.display_overlay.none_selected.value;" flex="1"/>
-        </hbox>
-        <deck id="PatronNavBar" flex="1" class="my_overflow" />
-    </hbox>
-    <hbox id="pdm2hb1a">
-        <label class="hideme barred_indicator" value="&staff.patron.display_overlay.barred.value;" command="cmd_patron_edit"/>
-        <label class="hideme expired_indicator" value="&staff.patron.display_overlay.expired.value;" command="cmd_patron_edit"/>
-        <label class="hideme inactive_indicator" value="&staff.patron.display_overlay.inactive.value;" command="cmd_patron_edit"/>
-        <label class="hideme juvenile_indicator" value="&staff.patron.display_overlay.juvenile.value;" command="cmd_patron_edit"/>
-        <label class="hideme alert_indicator" value="&staff.patron.display_overlay.alert.value;" command="cmd_patron_edit"/>
-        <label class="hideme note_indicator" value="&staff.patron.display_overlay.see_notes.value;" command="cmd_patron_info_notes"/>
-        <label class="hideme max_bills_indicator" value="&staff.patron.display_overlay.max_bills.value;" command="cmd_patron_bills"/>
-        <label class="hideme max_overdues_indicator" value="&staff.patron.display_overlay.max_overdues.value;" command="cmd_patron_items"/>
-        <label class="hideme max_out_indicator" value="&staff.patron.display_overlay.max_checked_out.value;" command="cmd_patron_items"/>
-        <label class="hideme bills_indicator" value="&staff.patron.display_overlay.has_bills.value;" command="cmd_patron_bills"/>
-        <label class="hideme overdues_indicator" value="&staff.patron.display_overlay.has_overdues.value;" command="cmd_patron_items"/>
-        <label class="hideme max_lost_indicator" value="&staff.patron.display_overlay.max_lost.value;" command="cmd_patron_items"/>
-        <label class="hideme lost_indicator" value="&staff.patron.display_overlay.has_lost.value;" command="cmd_patron_items"/>
-        <label class="hideme invalid_dob_indicator" value="&staff.patron.display_overlay.invalid_dob.value;" command="cmd_patron_edit"/>
-        <label class="hideme invalid_address_indicator" value="&staff.patron.display_overlay.invalid_address.value;" command="cmd_patron_edit"/>
-        <label class="hideme invalid_email_indicator" value="&staff.patron.display_overlay.invalid_email.value;" command="cmd_patron_edit"/>
-        <label class="hideme invalid_phone_indicator" value="&staff.patron.display_overlay.invalid_phone.value;" command="cmd_patron_edit"/>
-    </hbox>
-    <hbox id="PatronNotNavBar" flex="1" class="my_bg">
-        <vbox id="left_deck_vbox" flex="1" oils_persist="width"> 
-            <deck id="patron_left_deck" oils_persist="width"/>
-        </vbox>
-        <splitter id="deck_splitter" collapse="before" oils_persist="state hidden" oils_persist_peers="left_deck_vbox right_deck_vbox"><grippy id="splitter_grippy"/></splitter>
-        <vbox id="right_deck_vbox" flex="3" oils_persist="width">
-            <deck id="patron_right_deck" oils_persist="width"/>
-        </vbox>
-    </hbox>
-</vbox>
-</box>
-
-<deck id="patron_right_deck" flex="1">
-</deck>
-
-<deck id="patron_left_deck" flex="1">
-</deck>
-
-<deck id="PatronNavBar">
-    <hbox id="PatronNavBar0" flex="1"/>
-    <hbox id="PatronNavBar1" flex="1"/>
-</deck>
-
-<hbox id="PatronNavBar1" flex="1">
-    <vbox flex="1">
-        <hbox flex="1">
-            <spacer flex="1"/>
-            <arrowscrollbox id="PatronNavBarScrollbox" orient="horizontal" flex="1">
-                <spacer flex="1"/>
-                <grid>
-                    <columns>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                        <column/>
-                    </columns>
-                    <rows>
-                        <row>
-                            <button id="PatronNavBar_refresh" command="cmd_patron_refresh" class="nav"
-                                label="&staff.patron_navbar.refresh;" accesskey="&staff.patron_navbar.refresh.accesskey;"/>
-                            <button id="PatronNavBar_checkout" command="cmd_patron_checkout" class="nav"
-                                label="&staff.patron_navbar.checkout;" accesskey="&staff.patron_navbar.checkout.accesskey;"/>
-                            <button id="PatronNavBar_items" command="cmd_patron_items" class="nav"
-                                label="&staff.patron_navbar.items;" accesskey="&staff.patron_navbar.items.accesskey;"/>
-                            <button id="PatronNavBar_holds" command="cmd_patron_holds" class="nav"
-                                label="&staff.patron_navbar.holds;" accesskey="&staff.patron_navbar.holds.accesskey;"/>
-                            <button id="PatronNavBar_bills" command="cmd_patron_bills" class="nav"
-                                label="&staff.patron_navbar.bills;" accesskey="&staff.patron_navbar.bills.accesskey;"/>
-                            <button id="PatronNavBar_edit" command="cmd_patron_edit" class="nav"
-                                label="&staff.patron_navbar.edit;" accesskey="&staff.patron_navbar.edit.accesskey;"/>
-                            <button id="PatronNavBar_messages" label="&staff.patron_navbar.actions.menu.standing_penalties.label;" accesskey="&staff.patron_navbar.actions.menu.standing_penalties.accesskey;" command="cmd_standing_penalties" class="nav"/>
-                            <button id="PatronNavBar_other" command="cmd_patron_other" class="nav" label="&staff.patron_navbar.other;" accesskey="&staff.patron_navbar.other.accesskey;" type="menu">
-                                <menupopup>
-                                    <menuitem label="&staff.patron_navbar.alert;" accesskey="&staff.patron_navbar.alert.accesskey;" command="cmd_patron_alert"/>
-                                    <menuitem label="&staff.patron.info.notes.label;" accesskey="&staff.patron.info.notes.accesskey;" command="cmd_patron_info_notes"/>
-                                    <menuitem label="&staff.patron.info.triggered_events.label;" accesskey="&staff.patron.info.triggered_events.accesskey;" command="cmd_patron_info_triggered_events"/>
-                                    <menuitem label="&staff.patron.info.stat_cats.label;" accesskey="&staff.patron.info.stat_cats.accesskey;" command="cmd_patron_info_stats"/>
-                                    <menu id="PatronNavBar_other_booking" label="&staff.main.menu.booking.label;" accesskey="&staff.main.menu.booking.accesskey;">
-                                        <menupopup id="PatronNavBar_other_booking_popup">
-                                            <menuitem label="&staff.main.menu.booking.reservation.label_alt;" accesskey="&staff.main.menu.booking.reservation.accesskey;" command="cmd_patron_reservation" />
-                                            <menuitem label="&staff.main.menu.booking.reservation_pickup.label;" accesskey="&staff.main.menu.booking.reservation_pickup.accesskey;" command="cmd_patron_reservation_pickup" />
-                                            <menuitem label="&staff.main.menu.booking.reservation_return.label;" accesskey="&staff.main.menu.booking.reservation_return.accesskey;" command="cmd_patron_reservation_return" />
-                                        </menupopup>
-                                    </menu>
-                                    <menuitem label="&staff.patron.info.surveys.label;" accesskey="&staff.patron.info.surveys.accesskey;" command="cmd_patron_info_surveys"/>
-                                    <menuitem label="&staff.patron.info.acq_requests.label;" accesskey="&staff.patron.info.acq_requests.accesskey;" command="cmd_patron_info_acq_requests"/>
-                                    <menuitem label="&staff.patron.info.group.label;" accesskey="&staff.patron.info.group.accesskey;" command="cmd_patron_info_groups"/>
-                                    <menuitem label="&staff.patron_display.verify_password.label;" accesskey="&staff.patron_display.verify_password.accesskey;" command="cmd_verify_credentials"/>
-                                    <menuitem label="&staff.main.menu.admin.user_edit.label;" accesskey="&staff.main.menu.admin.user_edit.accesskey;" command="cmd_perm_editor"/>
-                                    <menuitem label="&staff.patron_display.toggle_summary.label;" accesskey="&staff.patron_display.toggle_summary.accesskey;" command="cmd_patron_toggle_summary"/>
-                                    <menuitem label="&staff.patron_display.delete_patron.label;" accesskey="&staff.patron_display.delete_patron.accesskey;" command="cmd_patron_delete"/>
-                                    <menuitem label="&staff.patron.display_overlay.exit.label;" accesskey="&staff.patron.display_overlay.exit.accesskey;" command="cmd_patron_exit"/>
-                                </menupopup>
-                            </button>
-                        </row>
-                        <row>
-                            <label id="under_refresh"/>
-                            <label id="under_checkout"/>
-                            <label id="under_items"/>
-                            <label id="under_holds"/>
-                            <label id="under_bills"/>
-                            <label id="under_edit"/>
-                            <label id="under_info"/>
-                            <label id="under_edit"/>
-                        </row>
-                    </rows>
-                </grid>
-            </arrowscrollbox>
-        </hbox>
-    </vbox>
-</hbox>
-
-<hbox id="PatronNavBar0" flex="1">
-    <vbox flex="1">
-        <hbox flex="1">
-            <spacer flex="1"/>
-            <button id="pnb1b2" label="&staff.patron.display_overlay.merge_patrons.label;" accesskey="&staff.patron.display_overlay.merge_patrons.accesskey;" command="cmd_patron_merge"/>
-            <button id="pnb1b0" label="&staff.patron.display_overlay.search_form.label;" accesskey="&staff.patron.display_overlay.search_form.accesskey;" command="cmd_search_form"/>
-            <button id="pnb1b1" label="&staff.patron.display_overlay.retrieve_patron.label;" accesskey="&staff.patron.display_overlay.retrieve_patron.accesskey;" command="cmd_patron_retrieve"/>
-        </hbox>
-        <label value=" "/>
-    </vbox>
-</hbox>
-
-</overlay>
index fdc6095..928d659 100644 (file)
@@ -1453,7 +1453,17 @@ patron.holds.prototype = {
                                     'url_prefix' : xulG.url_prefix,
                                     'url' : xulG.url_prefix('browser')
                                 };
-                                xulG.display_window.g.patron.right_deck.set_iframe( urls.XUL_REMOTE_BROWSER + '?patron_hold=1', {}, content_params);
+                                if (typeof xulG.display_window != 'undefined') {
+                                    xulG.display_window.g.patron.right_deck.set_iframe( urls.XUL_REMOTE_BROWSER + '?patron_hold=1', {}, content_params);
+                                } else {
+                                    xulG.new_tab(
+                                        urls.XUL_REMOTE_BROWSER + '?patron_hold=1',
+                                        {
+                                            'tab_name' : 'Place Hold Patron #'+xulG.patron_id
+                                        },
+                                        content_params
+                                    );
+                                }
                             } catch(E) {
                                 obj.error.sdump('D_ERROR','cmd_search_opac: ' + E);
                             }
diff --git a/Open-ILS/xul/staff_client/server/patron/patron.js b/Open-ILS/xul/staff_client/server/patron/patron.js
new file mode 100644 (file)
index 0000000..b1bfa35
--- /dev/null
@@ -0,0 +1,662 @@
+var patron_id;
+var main_interface;
+
+function patron_init() {
+    try {
+        if (typeof JSAN == 'undefined') {
+            throw( "The JSAN library object is missing.");
+        }
+        JSAN.errorLevel = "die"; // none, warn, or die
+        JSAN.addRepository('oils://remote/xul/server/');
+        JSAN.use('util.error'); g.error = new util.error();
+        g.error.sdump('D_TRACE','my_init() for patron.xul');
+
+        JSAN.use('OpenILS.data');
+        g.data = new OpenILS.data();
+        g.data.stash_retrieve();
+
+        patron_id = xul_param('id');
+        if (!patron_id && xul_param('barcode')) {
+            // FIXME - not ideal; these come from the Offline XACT Mgr
+            var p_obj = patron.util.retrieve_fleshed_au_via_barcode(
+                ses(),
+                xul_param('barcode')
+            );
+            if (typeof p_obj.ilsevent != 'undefined') { throw(p_obj); }
+            patron_id = p_obj.id();
+        }
+
+        main_interface = xul_param('interface')
+            || xul_param('show') || 'checkout';
+
+        g.data.last_patron = patron_id;
+        g.data.stash('last_patron');
+
+        JSAN.use('util.file');
+        JSAN.use('util.widgets');
+        JSAN.use('util.functional');
+
+        try {
+            xulG.set_tab_name(get_tab_name(main_interface));
+        } catch(E) {}
+
+        patron_ui_setup();
+        patron_default_focus();
+
+    } catch(E) {
+        alert('Error in patron.xul, my_init(): ' + E);
+    }
+}
+
+function spawn_search(s) {
+    try {
+        xulG.new_patron_tab(
+            { 'tab_name' : 'Patron Search' },
+            {
+                'run_query' : 1,
+                'query' : s
+            }
+        );
+    } catch(E) {
+        dump('Error in patron.xul, spawn_search('+s+'): ' + E + '\n');
+    }
+}
+
+function spawn_editor(p) {
+    var url = urls.XUL_PATRON_EDIT;
+    var loc = xulG.url_prefix('XUL_REMOTE_BROWSER');
+    xulG.new_tab(
+        loc,
+        {},
+        {
+            'url' : url,
+            'show_print_button' : true ,
+            'tab_name' : $("patronStrings").getString(
+                'staff.patron.display.spawn_editor.editing_related_patron'
+            ),
+            'passthru_content_params' : {
+                'spawn_search' : spawn_search,
+                'spawn_editor' : spawn_editor,
+                'url_prefix' : xulG.url_prefix,
+                'get_new_session' : xulG.get_new_session,
+                'new_tab' : xulG.new_tab,
+                'new_patron_tab' : xulG.new_patron_tab,
+                'params' : p,
+                'on_save' : function(p_obj) {
+                    JSAN.use('patron.util');
+                    patron.util.work_log_patron_edit(p_obj);
+                    new_patron_tab('edit',true);
+                }
+            },
+            'lock_tab' : xulG.lock_tab,
+            'unlock_tab' : xulG.unlock_tab
+        }
+    );
+}
+
+function get_tab_name(p_interface) {
+    try {
+        var tab_name = p_interface + ' Patron#' + patron_id;
+        switch(p_interface) {
+            case 'checkout':
+                tab_name = 'Check Out Patron#' + patron_id;
+            break;
+            case 'items_out':
+                tab_name = 'Items Out Patron#' + patron_id;
+            break;
+            case 'holds':
+                tab_name = 'Holds Patron#' + patron_id;
+            break;
+            case 'messages':
+                tab_name = 'Messages Patron#' + patron_id;
+            break;
+            case 'notes':
+                tab_name = 'Notes Patron#' + patron_id;
+            break;
+            case 'group':
+                tab_name = 'Group Patron#' + patron_id;
+            break;
+            case 'bills':
+                tab_name = 'Bills Patron#' + patron_id;
+            break;
+            case 'edit':
+                tab_name = 'Edit Patron#' + patron_id;
+            break;
+            case 'perms':
+                tab_name = 'Permissions Patron#' + patron_id;
+            break;
+            case 'events':
+                tab_name = 'Events Patron#' + patron_id;
+            break;
+            case 'requests':
+                tab_name = 'Requests Patron#' + patron_id;
+            break;
+            case 'statcats':
+                tab_name = 'StatCats Patron#' + patron_id;
+            break;
+            case 'surveys':
+                tab_name = 'Surveys Patron#' + patron_id;
+            break;
+            case 'test_password':
+                tab_name = 'Verify Credentials Patron#' + patron_id;
+            break;
+        }
+        return tab_name;
+    } catch(E) {
+        dump('Error in patron.xul, get_tab_name('+p_interface+'): ' + E + '\n');
+    }
+}
+
+function new_patron_tab(p_interface,replace_tab) {
+    try {
+        xulG[
+            replace_tab
+            ? 'set_tab'
+            : 'new_tab'
+        ](
+            urls.XUL_PATRON_DISPLAY,{
+                'tab_name' : get_tab_name(p_interface)
+            },{
+                'id':patron_id,
+                'interface' : p_interface
+            }
+        );
+    } catch(E) {
+        dump('Error in patron.xul, new_patron_tab('+p_interface+'): ' + E + '\n');
+    }
+}
+
+function reset_summary() {
+    try {
+        $('iframe1').setAttribute(
+            'src',
+            'about:blank'
+        );
+        setTimeout(
+            function() {
+                $('iframe1').setAttribute(
+                    'src',
+                    urls.EG_PATRON_SUMMARY + '?au_id=' + patron_id
+                );
+            }, 0
+        );
+    } catch(E) {
+        dump('Error in patron.xul, reset_summary(): ' + E + '\n');
+    }
+}
+
+function sort_button_box(box, recurse) {
+    try {
+        var curgroup = new Array();
+        var curstart = 1;
+        var curordinal = 0;
+        for (var itemid = 0; itemid < box.children.length; itemid++) {
+            var item = box.children[itemid];
+            curordinal++;
+            if (item.getAttribute('forceFirst')) {
+                item.setAttribute('ordinal', curstart);
+                curstart++;
+                continue;
+            }
+            if (item.nodeName == 'description'
+                || item.nodeName == 'label'
+                || item.nodeName == 'spacer'
+            ) {
+                sort_button_box_items(curgroup, curstart);
+                item.setAttribute('ordinal', curordinal);
+                curstart = curordinal + 1;
+                curgroup = new Array();
+                continue;
+            }
+            if ((item.nodeName == 'hbox'
+                    || item.nodeName == 'vbox'
+                ) && recurse
+            ) {
+                sort_menu_box(item, recurse);
+            }
+            curgroup.push(item);
+        }
+        sort_button_box_items(curgroup, curstart);
+    } catch(E) {
+        dump('Error in patron.xul, sort_button_box(): ' + E + '\n');
+    }
+}
+
+function sort_button_box_items(itemgroup, start) {
+    try {
+        var curpos = start;
+        var sorted = itemgroup.sort(function(a,b) {
+            var labelA = a.getAttribute('label').toUpperCase();
+            var labelB = b.getAttribute('label').toUpperCase();
+            return labelA.localeCompare(labelB);
+        });
+        for(var item = 0; item < sorted.length; item++) {
+            sorted[item].setAttribute('ordinal', curpos++);
+        }
+    } catch(E) {
+        dump('Error in patron.xul, sort_button_box_items(): ' + E + '\n');
+    }
+}
+
+function handle_reservation(ev) {
+    try {
+        JSAN.use('patron.util');
+        dojo.require("openils.User");
+        dojo.require("openils.XUL");
+        openils.XUL.newTabEasy(
+            "BOOKING_RESERVATION",
+            $("offlineStrings").getString(
+                "menu.cmd_booking_reservation.tab"
+            ), {
+                "bresv_interface_opts": {
+                    "patron_barcode":
+                        xul_param('barcode')
+                        || patron.util.retrieve_fleshed_au_via_id(
+                                ses(),
+                                patron_id
+                            ).card().barcode()
+                }
+            },
+            true
+        );
+    } catch(E) {
+        dump('Error in patron.xul, handle_reservation(): ' + E + '\n');
+    }
+}
+
+function handle_reservation_pickup(ev) {
+    try {
+        JSAN.use('patron.util');
+        dojo.require("openils.User");
+        dojo.require("openils.XUL");
+        openils.XUL.newTabEasy(
+            "BOOKING_PICKUP",
+            $("offlineStrings").getString(
+                "menu.cmd_booking_reservation_pickup.tab"
+            ), {
+                "bresv_interface_opts": {
+                    "patron_barcode":
+                        xul_param('barcode')
+                        || patron.util.retrieve_fleshed_au_via_id(
+                                ses(),
+                                patron_id
+                            ).card().barcode()
+                }
+            },
+            true
+        );
+    } catch(E) {
+        dump('Error in patron.xul, handle_reservation_pickup(): ' + E + '\n');
+    }
+}
+
+function handle_reservation_return(ev) {
+    try {
+        JSAN.use('patron.util');
+        dojo.require("openils.User");
+        dojo.require("openils.XUL");
+        openils.XUL.newTabEasy(
+            "BOOKING_RETURN",
+            $("offlineStrings").getString(
+                "menu.cmd_booking_reservation_return.tab"
+            ), {
+                "bresv_interface_opts": {
+                    "patron_barcode":
+                        xul_param('barcode')
+                        || patron.util.retrieve_fleshed_au_via_id(
+                                ses(),
+                                patron_id
+                            ).card().barcode()
+                }
+            },
+            true
+        );
+    } catch(E) {
+        dump('Error in patron.xul, handle_reservation_pickup(): ' + E + '\n');
+    }
+}
+
+function handle_delete(ev) {
+    try {
+        $('delete').disabled;
+        JSAN.use('patron.util');
+        var p_obj = patron.util.retrieve_fleshed_au_via_id(
+            ses(),
+            patron_id
+        );
+        JSAN.use('util.network');
+        var net = new util.network();
+        if (get_bool( p_obj.super_user() )) {
+            alert($("patronStrings").getString(
+                'staff.patron.display.cmd_patron_delete.deny_deletion_of_super_user'));
+            return;
+        }
+        if (patron_id == g.data.list.au[0].id()) {
+            alert($("patronStrings").getString(
+                'staff.patron.display.cmd_patron_delete.deny_deletion_of_self'));
+            return;
+        }
+        var rv = g.error.yns_alert_original(
+            $("patronStrings").getString(
+                'staff.patron.display.cmd_patron_delete.dialog.message'),
+            $("patronStrings").getString(
+                'staff.patron.display.cmd_patron_delete.dialog.title'),
+            $("patronStrings").getString(
+                'staff.patron.display.cmd_patron_delete.dialog.okay'),
+            $("patronStrings").getString(
+                'staff.patron.display.cmd_patron_delete.dialog.cancel'),
+            null,
+            $("patronStrings").getString(
+                'staff.patron.display.cmd_patron_delete.dialog.confirmation')
+        );
+        if (rv == 0) {
+            var params = [ ses(), patron_id ];
+            var staff_check = net.simple_request(
+                'PERM_RETRIEVE_WORK_OU',[
+                    ses(),
+                    'STAFF_LOGIN',
+                    patron_id
+                ]
+            );
+            if (staff_check.length > 0) {
+                var dest_barcode = window.prompt(
+                    $("patronStrings").getString(
+                        'staff.patron.display.cmd_patron_delete.dest_user.prompt'),
+                    $("patronStrings").getString(
+                        'staff.patron.display.cmd_patron_delete.dest_user.default_value'),
+                    $("patronStrings").getString(
+                        'staff.patron.display.cmd_patron_delete.dest_user.title')
+                );
+                if (!dest_barcode) return;
+                var dest_usr = patron.util.retrieve_fleshed_au_via_barcode(
+                    ses(), dest_barcode );
+                if (typeof dest_usr.ilsevent != 'undefined') {
+                    alert($("patronStrings").getString(
+                        'staff.patron.display.cmd_patron_delete.dest_user.failure'));
+                    return;
+                }
+                if (dest_usr.id() == patron_id) {
+                    alert($("patronStrings").getString(
+                        'staff.patron.display.cmd_patron_delete.dest_user.self_reference_failure'));
+                    return;
+                }
+                params.push( dest_usr.id() );
+            }
+            var robj = net.simple_request(
+                'FM_AU_DELETE',
+                params,
+                null,
+                {
+                    'title' : $("patronStrings").getString(
+                        'staff.patron.display.cmd_patron_delete.override_prompt'),
+                    'overridable_events' : [
+                        2004 /* ACTOR_USER_DELETE_OPEN_XACTS */
+                    ]
+                }
+            );
+            if (typeof robj.ilsevent != 'undefined') {
+                switch(Number(robj.ilsevent)) {
+                    /* already informed via override prompt */
+                    case 2004 /* ACTOR_USER_DELETE_OPEN_XACTS */ :
+                        return;
+                    break;
+                }
+            }
+            util.widgets.dispatch('command','cmd_reload');
+        }
+        $('delete').disabled = false;
+    } catch(E) {
+        dump('Error in patron.xul, handle_delete(): ' + E + '\n');
+    }
+}
+
+function patron_ui_setup() {
+    try {
+        dump('entering patron.xul, ui_setup()\n');
+
+        sort_button_box( $('main_button_group'), false );
+
+        $('cmd_reload').addEventListener(
+            'command',
+            function(ev){ new_patron_tab(main_interface,true); },
+            false
+        );
+
+        $('cmd_reservation').addEventListener(
+            'command',
+            handle_reservation,
+            false
+        );
+
+        $('cmd_reservation_pickup').addEventListener(
+            'command',
+            handle_reservation_pickup,
+            false
+        );
+
+        $('cmd_reservation_return').addEventListener(
+            'command',
+            handle_reservation_return,
+            false
+        );
+
+        $('cmd_delete').addEventListener(
+            'command',
+            handle_delete,
+            false
+        );
+
+        [
+            "bills",
+            "checkout",
+            "edit",
+            "events",
+            "group",
+            "holds",
+            "items_out",
+            "messages",
+            "notes",
+            "perms",
+            "requests",
+            "statcats",
+            "surveys",
+            "test_password"
+        ].forEach(
+            function(cmd) {
+                $('cmd_'+cmd).addEventListener(
+                    'command',
+                    function(c_interface) {
+                        return function(ev) {
+                            new_patron_tab(c_interface);
+                        }
+                    }(cmd),
+                    false
+                );
+            }
+        );
+
+        $('iframe1').setAttribute(
+            'src',
+            urls.EG_PATRON_SUMMARY + '?au_id=' + patron_id
+        );
+
+        $(main_interface).disabled = true;
+
+        var barcode_for_some_interfaces = xul_param('barcode');
+        var patron_object_for_some_interfaces;
+
+        var bottom_pane = $('bottom_pane');
+        if ($('iframe2')) { bottom_pane.removeChild($('iframe2')); }
+        var iframe = document.createElement('iframe');
+        iframe.setAttribute('id','iframe2');
+        iframe.setAttribute('flex','1');
+        var src = 'data:text/plain,Missing interface';
+        switch(main_interface) {
+            case 'checkout':
+                src = urls.XUL_CHECKOUT;
+            break;
+            case 'items_out':
+                src = urls.XUL_PATRON_ITEMS;
+            break;
+            case 'holds':
+                src = urls.XUL_PATRON_HOLDS;
+                // FIXME - not ideal; but OPAC Place Hold needs this
+                if (!barcode_for_some_interfaces) {
+                    JSAN.use('patron.util');
+                    var p_obj = patron.util.retrieve_fleshed_au_via_id(
+                        ses(),
+                        patron_id
+                    );
+                    barcode_for_some_interfaces = p_obj.card().barcode();
+                }
+            break;
+            case 'messages':
+                src = urls.XUL_STANDING_PENALTIES;
+                JSAN.use('patron.util');
+                patron_object_for_some_interfaces = patron.util.retrieve_fleshed_au_via_id(
+                    ses(),
+                    patron_id
+                );
+            break;
+            case 'group':
+                src = urls.XUL_PATRON_INFO_GROUP;
+            break;
+            case 'bills':
+                src = urls.XUL_PATRON_BILLS;
+            break;
+            case 'edit':
+                src = urls.XUL_REMOTE_BROWSER; /* XUL_PATRON_EDIT */
+            break;
+            case 'events':
+                src = urls.XUL_REMOTE_BROWSER; /* EG_TRIGGER_EVENTS */
+            break;
+            case 'statcats':
+                src = urls.XUL_PATRON_INFO_STAT_CATS;
+            break;
+            case 'notes':
+                src = urls.XUL_PATRON_INFO_NOTES;
+            break;
+            case 'requests':
+                src = urls.EG_ACQ_USER_REQUESTS + '?usr=' + patron_id;
+            break;
+            case 'surveys':
+                src = urls.XUL_PATRON_INFO_SURVEYS;
+            break;
+            case 'test_password':
+                src = urls.XUL_VERIFY_CREDENTIALS;
+                var p_obj = patron.util.retrieve_fleshed_au_via_id(
+                    ses(),
+                    patron_id
+                );
+                patron_object_for_some_interfaces = p_obj;
+                barcode_for_some_interfaces = p_obj.card().barcode();
+            break;
+            case 'perms':
+                src = urls.XUL_USER_PERM_EDITOR
+                    + '?ses=' + window.escape(ses())
+                    + '&usr=' + patron_id;
+            break;
+        }
+        iframe.setAttribute('src',src);
+        bottom_pane.appendChild(iframe);
+        var cw = get_contentWindow(iframe);
+        cw.IAMXUL = true;
+        cw.xulG = {
+            'set_tab' : function(a,b,c) { return xulG.set_tab(a,b,c); },
+            'patron_id' : patron_id,
+            'get_barcode' : xulG.get_barcode,
+            'get_barcode_and_settings' : xulG.get_barcode_and_settings,
+            'get_new_session' : xulG.get_new_session,
+            'new_tab' : xulG.new_tab,
+            'new_patron_tab' : xulG.new_patron_tab,
+            'url_prefix' : xulG.url_prefix,
+            'on_list_change' : function(x) {},
+            'lock_tab' : xulG.lock_tab,
+            'unlock_tab' : xulG.unlock_tab
+        }
+        switch(main_interface) {
+            case 'checkout':
+                cw.xulG.check_stop_checkouts = function() { return false; };
+            break;
+            case 'items_out':
+            break;
+            case 'holds':
+                cw.xulG.patron_barcode = barcode_for_some_interfaces;
+            break;
+            case 'messages':
+                cw.xulG.patron = patron_object_for_some_interfaces;
+                cw.xulG.reset_summary = reset_summary;
+            break;
+            case 'group':
+            break;
+            case 'bills':
+                cw.xulG.on_money_change = function(b) {
+                    reset_summary();
+                }
+            break;
+            case 'edit':
+                cw.xulG.url = urls.XUL_PATRON_EDIT;
+                cw.xulG.show_print_button = urls.XUL_PATRON_EDIT;
+                cw.xulG.passthru_content_params = {
+                    'params' : {
+                        'ses' : ses(),
+                        'usr' : patron_id
+                    },
+                    'on_save' : function(p) {
+                        JSAN.use('patron.util');
+                        patron.util.work_log_patron_edit(p);
+                        new_patron_tab('edit',true);
+                    },
+                    'spawn_search' : spawn_search,
+                    'spawn_editor' : spawn_editor,
+                    'url_prefix' : xulG.url_prefix,
+                    'get_new_session' : xulG.get_new_session,
+                    'new_tab' : xulG.new_tab,
+                    'new_patron_tab' : xulG.new_patron_tab
+                }
+            break;
+            case 'events':
+                cw.xulG.url = urls.EG_TRIGGER_EVENTS + '?patron_id=' + patron_id;
+                cw.xulG.show_print_button = false;
+                cw.xulG.show_nav_buttons = false;
+            break;
+            case 'statcats':
+            break;
+            case 'notes':
+            break;
+            case 'requests':
+            break;
+            case 'surveys':
+            break;
+            case 'test_password':
+                cw.xulG.barcode = barcode_for_some_interfaces;
+                cw.xulG.usrname = patron_object_for_some_interfaces.usrname();
+            break;
+            case 'perms':
+            break;
+        }
+
+    } catch(E) {
+        alert('Error in patron.xul, ui_setup(): ' + E + '\n');
+    }
+}
+
+function patron_default_focus() {
+    setTimeout(
+        function() {
+            try {
+                dump('entering patron.xul, default_focus()\n');
+                if ($('iframe2')) {
+                    $('iframe2').focus();
+                    var cw = get_contentWindow($('iframe2'));
+                    if (cw && typeof cw.default_focus == 'function') {
+                        cw.default_focus();
+                    }
+                }
+            } catch(E) {
+                dump('Error in patron.xul, default_focus(): ' + E + '\n');
+            }
+        }, 0
+    );
+}
+
diff --git a/Open-ILS/xul/staff_client/server/patron/search.js b/Open-ILS/xul/staff_client/server/patron/search.js
new file mode 100644 (file)
index 0000000..7fd6af5
--- /dev/null
@@ -0,0 +1,368 @@
+/** FIXME: kludge to allow for testing with stock clients **/
+
+function my_init() {
+    try {
+        if (xul_param('id')||xul_param('barcode')) {
+            $('uber_deck').selectedIndex = 2;
+            patron_init();
+        } else {
+            $('uber_deck').selectedIndex = 1;
+            search_init();
+        }
+    } catch(E) {
+        alert('Error in my_init(): ' + E);
+    }
+}
+
+function default_focus() {
+    if (xul_param('id')||xul_param('barcode')) {
+        patron_default_focus();
+    } else {
+        search_default_focus();
+    }
+}
+
+/******/
+
+function search_init() {
+    try {
+        if (typeof JSAN == 'undefined') {
+            throw( "The JSAN library object is missing.");
+        }
+        JSAN.errorLevel = "die"; // none, warn, or die
+        JSAN.addRepository('oils://remote/xul/server/');
+        JSAN.use('util.error'); g.error = new util.error();
+        g.error.sdump('D_TRACE','my_init() for patron/search.xul');
+
+        JSAN.use('OpenILS.data');
+        g.data = new OpenILS.data();
+        g.data.stash_retrieve();
+
+        JSAN.use('util.file');
+        JSAN.use('util.widgets');
+        JSAN.use('util.functional');
+        JSAN.use('patron.search_result');
+
+        try {
+            window.xulG.set_tab_name(
+                xul_param('perm_editor')
+                ? 'Patron Search (for Perm Editor)'
+                : 'Patron Search (for Check Out)'
+            );
+        } catch(E) {}
+
+        search_ui_setup();
+        g.search = new patron.search_result();
+        g.search.init({});
+        $('patron_list_actions').appendChild(
+            g.search.list.render_list_actions()
+        );
+        g.search.list.set_list_actions();
+        search_default_focus();
+
+    } catch(E) {
+        alert('Error in patron/search.xul: ' + E);
+    }
+}
+
+function handle_enter(ev) {
+    try {
+        if (ev.target.tagName != 'textbox') {
+            return;
+        }
+        if (ev.keyCode == 13 /* enter */
+        || ev.keyCode == 77 /* enter on a mac */) {
+            submit();
+        }
+    } catch(E) {
+        dump('Error in patron/search.xul, handle_enter(): ' + E + '\n');
+    }
+}
+
+function swap_view(ev) {
+    try {
+        var idx = $('deck').selectedIndex;
+        if (idx == 0) {
+            $('deck').selectedIndex = 1;
+            var patrons = g.search.list.retrieve_selection_retrieval_data();
+            if (patrons.length > 0) {
+                $('iframe').setAttribute(
+                    'src',
+                    urls.EG_PATRON_SUMMARY+'?au_id='+patrons[0]
+                );
+            }
+        } else {
+            $('deck').selectedIndex = 0;
+            $('patron_list').focus();
+            $('iframe').setAttribute('src','data:,Loading...');
+        }
+    } catch(E) {
+        dump('Error in patron/search.xul, swap_view(): ' + E + '\n');
+    }
+}
+
+function handle_merge(ev) {
+    try {
+        JSAN.use('patron.util');
+        if (
+            patron.util.merge(
+                g.search.list.retrieve_selection_retrieval_data()
+            )
+        ) {
+            util.widgets.dispatch('command','cmd_submit');
+        }
+    } catch(E) {
+        dump('Error in patron/search.xul, handle_merge: ' + E + '\n');
+    }
+}
+
+function search_ui_setup() {
+    try {
+        dump('entering patron/search.xul, ui_setup()\n');
+
+        $('cmd_swap_view').addEventListener(
+            'command',
+            swap_view,
+            false
+        );
+        $('iframe').setAttribute('src','data:,Loading...');
+
+        $('cmd_submit').addEventListener(
+            'command',
+            submit,
+            false
+        );
+
+        $('cmd_retrieve').addEventListener(
+            'command',
+            function(ev) { retrieve_patrons(); },
+            false
+        );
+
+        $('cmd_merge').addEventListener(
+            'command',
+            handle_merge,
+            false
+        );
+
+        var nl = document.getElementsByTagName('textbox');
+        for (var i = 0; i < nl.length; i++) {
+            nl[i].addEventListener(
+                'keypress',
+                handle_enter,
+                false
+            );
+        }
+
+        util.widgets.remove_children('search_ou');
+        if (! $('search_ou').hasAttribute('value')) {
+            $('search_ou').setAttribute('value',g.data.tree.aou.id());
+        }
+
+        var search_ou_ml = util.widgets.make_menulist(
+            util.functional.map_list( g.data.list.my_aou,
+                function(el,idx) {
+                    return [ el.name(), el.id() ]
+                }
+            ).sort(
+                function(a,b) {
+                    if (a[1] < b[1]) return -1;
+                    if (a[1] > b[1]) return 1;
+                    return 0;
+                }
+            ),
+            $('search_ou').getAttribute('value')
+        );
+        search_ou_ml.addEventListener(
+            'command',
+            function(ev) {
+                search_ou_ml.parentNode.setAttribute(
+                    'value',
+                    ev.target.value
+                );
+                oils_persist(search_ou_ml.parentNode);
+            },
+            false
+        );
+        search_ou_ml.setAttribute('id','search_ou_ml');
+        $('search_ou').appendChild(search_ou_ml);
+
+        util.widgets.remove_children('profile');
+        var profile_ml = util.widgets.make_menulist(
+            [
+                ['','']
+            ].concat(
+                util.functional.map_list(
+                    g.data.list.pgt,
+                    function(el,idx) {
+                        return [ el.name(), el.id() ]
+                    }
+                ).sort(
+                    function(a,b) {
+                        if (a[0] < b[0]) return -1;
+                        if (a[0] > b[0]) return 1;
+                        return 0;
+                    }
+                )
+            ),
+            $('profile').getAttribute('value')
+        );
+        profile_ml.addEventListener(
+                'command',
+                function(ev) {
+                    profile_ml.parentNode.setAttribute(
+                        'value',
+                        ev.target.value
+                    );
+                    oils_persist(profile_ml.parentNode);
+                },
+                false
+        );
+        profile_ml.setAttribute('id','profile_ml');
+        $('profile').appendChild(profile_ml);
+
+    } catch(E) {
+        dump('Error in patron/search.xul, ui_setup(): ' + E + '\n');
+    }
+}
+
+function search_default_focus() {
+    setTimeout(
+        function() {
+            try {
+                dump('entering patron/search.xul, default_focus()\n');
+                var field = xul_param('focus')||'card';
+                // HACK for while we're symlinking barcode_entry.xul
+                // to allow testing with stock clients
+                if (! location.href.match(/barcode_entry/)) {
+                    field = 'family_name';
+                }
+                $(field).select();
+                $(field).focus();
+            } catch(E) {
+                dump('Error in patron/search.xul, default_focus(): ' + E + '\n');
+            }
+        }, 0
+    );
+}
+
+var _submitting = false;
+function submit(ev) {
+    if (_submitting) {
+        dump('submit() in patron/search.xul while already submitting\n');
+        return;
+    }
+    _submitting = true;
+    try {
+        var query = {};
+        var render_list = document.getElementsByAttribute('group','*');
+        for (var i = 0; i < render_list.length; i++) {
+            var node = render_list[i];
+            var id = node.id;
+            var value;
+            if (id == 'inactive') {
+                value = node.getAttribute('checked');
+            } else if (id == 'profile'
+            || id == 'search_ou') {
+                value  = node.getAttribute('value');
+            } else {
+                value = node.value.replace(/^\s+/,'').replace(/[\\\s]+$/,'');
+                switch(id) {
+                    case 'family_name' :
+                    case 'first_given_name' :
+                    case 'second_given_name' :
+                        value = value.replace(/^[\d\s]+/g,'').replace(/[\d\s]+$/g,'')
+                    break;
+                }
+            }
+            if (value != '') {
+                query[id] = value;
+            }
+        }
+        search(query,undefined,undefined);
+    } catch(E) {
+        dump('Error in patron/search.xul, submit(): ' + E + '\n');
+    }
+    _submitting = false;
+}
+
+function search(query,limit,sort) {
+    try {
+        g.search.search_limit = limit;
+        g.search.search_sort = sort;
+        g.search.on_select = function(ev){dump('on_select\n');};
+        g.search.on_dblclick = function(ev) { retrieve_patrons() };
+        var patron_parts = [];
+        if ($('retrieve_library_card').getAttribute('checked') == 'true') {
+            patron_parts.push('card');
+        }
+        if ($('retrieve_mailing_address').getAttribute('checked') == 'true') {
+            patron_parts.push('mailing_address');
+        }
+        if ($('retrieve_billing_address').getAttribute('checked') == 'true') {
+            patron_parts.push('billing_address');
+        }
+        g.search.patron_parts = patron_parts;
+        g.search.skip_render_of_single_result =
+            $('replace_tab').getAttribute('checked') == 'true';
+        if ($('auto').getAttribute('checked') == 'true') {
+            g.search.single_result_callback =
+                function(id) { retrieve_patrons([id]); }
+        } else {
+            g.search.single_result_callback = null;
+        }
+        $('deck').selectedIndex = 0;
+        $('iframe').setAttribute('src','data:,Loading...');
+        $('patron_list').focus();
+        g.search.search(query);
+    } catch(E) {
+        dump('Error in patron/search.xul, search(): ' + E + '\n');
+    }
+}
+
+function retrieve_patrons(patrons) {
+    if (!patrons) {
+        patrons = g.search.list.retrieve_selection_retrieval_data();
+    }
+    var current_tab_index = typeof xulG.get_idx == 'function'
+        ? xulG.get_idx()
+        : -1; // Just want to test this code without requiring a
+              // local staff client upgrade
+    for (
+        var i = $('replace_tab').getAttribute('checked') == 'true'
+        ? 1 // open new tabs before replacing current tab
+        : 0;
+        i < patrons.length;
+        i++
+    ) {
+        xulG.new_tab(
+            urls.XUL_PATRON_DISPLAY,{
+                'nofocus' : current_tab_index == -1
+            },{
+                'id':patrons[i],
+                'interface' : xul_param('perm_editor')
+                ? 'perms'
+                : 'checkout'
+            }
+        );
+    }
+    if ($('replace_tab').getAttribute('checked') == 'true') {
+        var tab_params = {};
+        if (current_tab_index != -1) {
+            tab_params.index = current_tab_index;
+        }
+        xulG.set_tab(
+            urls.XUL_PATRON_DISPLAY,
+            tab_params,{
+                'id':patrons[0],
+                'interface' : xul_param('perm_editor')
+                ? 'perms'
+                : 'checkout'
+            }
+        );
+    } else {
+        if (current_tab_index == -1) {
+            search_default_focus();
+        }
+    }
+}
index 49c4522..15ac3ff 100644 (file)
@@ -21,7 +21,8 @@ patron.search_result.prototype = {
         obj.query = params['query'];
         obj.search_limit = params['search_limit'];
         obj.search_sort = params['search_sort'];
-
+        obj.patron_parts = params['patron_parts']
+            || ["card","billing_address","mailing_address"];
         JSAN.use('OpenILS.data'); this.OpenILS = {}; 
         obj.OpenILS.data = new OpenILS.data(); obj.OpenILS.data.init({'via':'stash'});
         var obscure_dob = String( obj.OpenILS.data.hash.aous['circ.obscure_dob'] ) == 'true';
@@ -100,7 +101,7 @@ patron.search_result.prototype = {
                     var au_obj = patron.util.retrieve_fleshed_au_via_id(
                         ses(),
                         id,
-                        ["card","billing_address","mailing_address"],
+                        obj.patron_parts,
                         function(req) {
                             try {
                                 var row = params.row;
@@ -198,7 +199,7 @@ patron.search_result.prototype = {
         var search_hash = {};
         obj.search_term_count = 0;
         var inactive = false;
-        var search_depth = 0;
+        var search_ou = 0;
         for (var i in query) {
             switch( i ) {
                 case 'card':
@@ -236,8 +237,9 @@ patron.search_result.prototype = {
                     if (query[i] == 'checked' || query[i] == 'true') inactive = true;
                 break;
 
-                case 'search_depth':
-                    search_depth = function(a){return a;}(query[i]);
+                case 'search_depth' /* bad name, but keeping for the moment */:
+                case 'search_ou' /* truthful name */:
+                    search_ou = function(a){return a;}(query[i]);
                 break;
             }
         }
@@ -263,7 +265,7 @@ patron.search_result.prototype = {
             } else {
                 params.push(0);
             }
-            params.push(search_depth);
+            params.push(search_ou);
             if (obj.search_term_count > 0) {
                 //alert('search params = ' + obj.error.pretty_print( js2JSON( params ) ) );
                 results = this.network.simple_request( 'FM_AU_IDS_RETRIEVE_VIA_HASH', params );
@@ -282,21 +284,33 @@ patron.search_result.prototype = {
                 return;
             }
 
-            obj.list.clear();
-            //this.list.append( { 'retrieve_id' : results[i], 'row' : {} } );
-            var funcs = [];
+            if (results.length == 1 && obj.skip_render_of_single_result) {
+                // no-op
+            } else {
+                obj.list.clear();
+                var funcs = [];
 
                 function gen_func(r) {
                     return function() {
-                        obj.list.append( { 'retrieve_id' : r, 'row' : {}, 'to_bottom' : true, 'no_auto_select' : true } );
+                        obj.list.append({
+                            'retrieve_id' : r,
+                            'row' : {},
+                            'to_bottom' : true,
+                            'no_auto_select' : true
+                        });
                     }
                 }
 
-            for (var i = 0; i < results.length; i++) {
-                funcs.push( gen_func(results[i]) );
+                for (var i = 0; i < results.length; i++) {
+                    funcs.push( gen_func(results[i]) );
+                }
+                JSAN.use('util.exec'); var exec = new util.exec(4);
+                exec.chain( funcs );
+            }
+
+            if (results.length == 1 && typeof obj.single_result_callback == 'function') {
+                obj.single_result_callback(results[0]);
             }
-            JSAN.use('util.exec'); var exec = new util.exec(4);
-            exec.chain( funcs );
 
         } catch(E) {
             this.error.standard_unexpected_error_alert('patron.search_result.search',E);
index 7a1786f..4f1317c 100644 (file)
@@ -211,6 +211,9 @@ function generate_request_handler_for_penalty_apply(penalty,id) {
                 xulG.refresh();
             }
             */
+            if (xulG && typeof xulG.reset_summary == 'function') {
+                xulG.reset_summary();
+            }
             document.getElementById('progress').hidden = true;
 
         } catch(E) {
@@ -238,6 +241,9 @@ function handle_remove_penalty(ev) {
                     xulG.refresh();
                 }
                 */
+                if (xulG && typeof xulG.reset_summary == 'function') {
+                    xulG.reset_summary();
+                }
                 document.getElementById('progress').hidden = true;
 
                 //patron.util.set_penalty_css(xulG.patron);
@@ -340,6 +346,9 @@ function handle_edit_penalty(ev) {
                 xulG.refresh();
             }
             */
+            if (xulG && typeof xulG.reset_summary == 'function') {
+                xulG.reset_summary();
+            }
         }
 
     } catch(E) {
@@ -400,6 +409,9 @@ function handle_archive_penalty(ev) {
                 xulG.refresh();
             }
             */
+            if (xulG && typeof xulG.reset_summary == 'function') {
+                xulG.reset_summary();
+            }
         }
 
     } catch(E) {