Merge branch 'master' of git://git.evergreen-ils.org/Evergreen into ttopac
authorevergreen <evergreen@squeeze.debian>
Tue, 28 Jun 2011 15:08:51 +0000 (11:08 -0400)
committerevergreen <evergreen@squeeze.debian>
Tue, 28 Jun 2011 15:08:51 +0000 (11:08 -0400)
293 files changed:
Open-ILS/examples/apache/eg_vhost.conf
Open-ILS/examples/fm_IDL.xml
Open-ILS/examples/oils_web.xml.example
Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Container.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb/CGI_utf8.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb/I18NFilter.pm [new file with mode: 0644]
Open-ILS/src/support-scripts/test-scripts/unapi_bench.pl [new file with mode: 0755]
Open-ILS/web/css/skin/default/opac/contentslider.css [new file with mode: 0644]
Open-ILS/web/css/skin/default/opac/semiauto.css [new file with mode: 0644]
Open-ILS/web/css/skin/default/opac/style.css [new file with mode: 0644]
Open-ILS/web/images/KCLS_logo_horiz.gif [new file with mode: 0644]
Open-ILS/web/images/acct-btn-hover.png [new file with mode: 0644]
Open-ILS/web/images/acct-btn.png [new file with mode: 0644]
Open-ILS/web/images/acct_checked_out_off.gif [new file with mode: 0644]
Open-ILS/web/images/acct_checked_out_on.gif [new file with mode: 0644]
Open-ILS/web/images/acct_favs_off.gif [new file with mode: 0644]
Open-ILS/web/images/acct_favs_on.gif [new file with mode: 0644]
Open-ILS/web/images/acct_fines_off.jpg [new file with mode: 0644]
Open-ILS/web/images/acct_fines_on.jpg [new file with mode: 0644]
Open-ILS/web/images/acct_holds_off.gif [new file with mode: 0644]
Open-ILS/web/images/acct_holds_on.gif [new file with mode: 0644]
Open-ILS/web/images/acct_lists_off.gif [new file with mode: 0644]
Open-ILS/web/images/acct_lists_on.gif [new file with mode: 0644]
Open-ILS/web/images/acct_payments_off.jpg [new file with mode: 0644]
Open-ILS/web/images/acct_payments_on.jpg [new file with mode: 0644]
Open-ILS/web/images/acct_prefs_off.gif [new file with mode: 0644]
Open-ILS/web/images/acct_prefs_on.gif [new file with mode: 0644]
Open-ILS/web/images/acct_sum_fines_bl.png [new file with mode: 0644]
Open-ILS/web/images/acct_sum_fines_br.png [new file with mode: 0644]
Open-ILS/web/images/acct_sum_fines_tl.png [new file with mode: 0644]
Open-ILS/web/images/acct_sum_fines_tr.png [new file with mode: 0644]
Open-ILS/web/images/acct_summary_off.gif [new file with mode: 0644]
Open-ILS/web/images/acct_summary_on.gif [new file with mode: 0644]
Open-ILS/web/images/add_mylist.gif [new file with mode: 0644]
Open-ILS/web/images/add_mylist_sel.gif [new file with mode: 0644]
Open-ILS/web/images/add_mylist_sel.kcls.gif [new file with mode: 0644]
Open-ILS/web/images/add_search_row_btn.gif [new file with mode: 0644]
Open-ILS/web/images/adv_row_close_btn.png [new file with mode: 0644]
Open-ILS/web/images/adv_search.png [new file with mode: 0644]
Open-ILS/web/images/adv_search_hover.png [new file with mode: 0644]
Open-ILS/web/images/adv_search_off.gif [new file with mode: 0644]
Open-ILS/web/images/adv_search_on.gif [new file with mode: 0644]
Open-ILS/web/images/another_search.png [new file with mode: 0644]
Open-ILS/web/images/another_search_hover.png [new file with mode: 0644]
Open-ILS/web/images/arrow-down.gif [new file with mode: 0644]
Open-ILS/web/images/arrow-right.gif [new file with mode: 0644]
Open-ILS/web/images/arrow-right.png [new file with mode: 0644]
Open-ILS/web/images/asknow_available.gif [new file with mode: 0644]
Open-ILS/web/images/banner-bg.png [new file with mode: 0644]
Open-ILS/web/images/banner1.jpg [new file with mode: 0644]
Open-ILS/web/images/btnCancel.png [new file with mode: 0644]
Open-ILS/web/images/btnSubmit.png [new file with mode: 0644]
Open-ILS/web/images/button-bg.png [new file with mode: 0644]
Open-ILS/web/images/cancel_btn.gif [new file with mode: 0644]
Open-ILS/web/images/cd-small.png [new file with mode: 0644]
Open-ILS/web/images/clipboard.png [new file with mode: 0644]
Open-ILS/web/images/dash-corner-left1.png [new file with mode: 0644]
Open-ILS/web/images/dash-corner-left2.png [new file with mode: 0644]
Open-ILS/web/images/dash-corner-mid1.png [new file with mode: 0644]
Open-ILS/web/images/dash-corner-mid2.png [new file with mode: 0644]
Open-ILS/web/images/dash-corner-right1.png [new file with mode: 0644]
Open-ILS/web/images/dash-corner-right2.png [new file with mode: 0644]
Open-ILS/web/images/dash-divider.jpg [new file with mode: 0644]
Open-ILS/web/images/dropdown-hover.gif [new file with mode: 0644]
Open-ILS/web/images/dropdown.gif [new file with mode: 0644]
Open-ILS/web/images/expert_search_off.gif [new file with mode: 0644]
Open-ILS/web/images/expert_search_on.gif [new file with mode: 0644]
Open-ILS/web/images/faqs-btn.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/a.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/c.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/d.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/e.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/f.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/g.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/i.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/j.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/k.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/m.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/o.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/p.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/r.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/item_type/t.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/2.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/5.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/a.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/b.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/c.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/d.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/e.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/f.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/h.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/i.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/j.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/k.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/l.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/m.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_downloadableebook.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_electronicgames.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_evideo.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_onlinejournal.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_player.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_podcasts.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_streamingaudio.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_streamingvideo.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/media_vhs.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/n.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/o.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/p.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/q.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/r.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/s.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/t.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/v.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/w.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/x.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/y.png [new file with mode: 0644]
Open-ILS/web/images/format_icons/mattype/z.png [new file with mode: 0644]
Open-ILS/web/images/go-btn-hover.png [new file with mode: 0644]
Open-ILS/web/images/go-btn.png [new file with mode: 0644]
Open-ILS/web/images/go_but_long.gif [new file with mode: 0644]
Open-ILS/web/images/golive.jpg [new file with mode: 0644]
Open-ILS/web/images/gray-arrow.png [new file with mode: 0644]
Open-ILS/web/images/green_check.png [new file with mode: 0644]
Open-ILS/web/images/header_left.gif [new file with mode: 0644]
Open-ILS/web/images/header_right.gif [new file with mode: 0644]
Open-ILS/web/images/hp-links-left.jpg [new file with mode: 0644]
Open-ILS/web/images/hp-links-mid.jpg [new file with mode: 0644]
Open-ILS/web/images/hp-links-right.jpg [new file with mode: 0644]
Open-ILS/web/images/locations.jpg [new file with mode: 0644]
Open-ILS/web/images/login-bg.jpg [new file with mode: 0644]
Open-ILS/web/images/login-bg2.jpg [new file with mode: 0644]
Open-ILS/web/images/login-box-bg.jpg [new file with mode: 0644]
Open-ILS/web/images/login-btn-hover.png [new file with mode: 0644]
Open-ILS/web/images/login-btn.gif [new file with mode: 0644]
Open-ILS/web/images/login-btn.png [new file with mode: 0644]
Open-ILS/web/images/login-btn2.png [new file with mode: 0644]
Open-ILS/web/images/logout-btn-hover.png [new file with mode: 0644]
Open-ILS/web/images/logout-btn.png [new file with mode: 0644]
Open-ILS/web/images/num_search_off.gif [new file with mode: 0644]
Open-ILS/web/images/num_search_on.gif [new file with mode: 0644]
Open-ILS/web/images/one_land.gif [new file with mode: 0644]
Open-ILS/web/images/pay-fines-btn-hover.png [new file with mode: 0644]
Open-ILS/web/images/pay-fines-btn.png [new file with mode: 0644]
Open-ILS/web/images/pay_fines_btn.gif [new file with mode: 0644]
Open-ILS/web/images/place_hold.gif [new file with mode: 0644]
Open-ILS/web/images/plus_sign.png [new file with mode: 0644]
Open-ILS/web/images/projectedmedia.jpg [new file with mode: 0644]
Open-ILS/web/images/question-mark.png [new file with mode: 0644]
Open-ILS/web/images/questions.png [new file with mode: 0644]
Open-ILS/web/images/rdetail_arrow.png [new file with mode: 0644]
Open-ILS/web/images/reset_form_btn.gif [new file with mode: 0644]
Open-ILS/web/images/reviews.gif [new file with mode: 0644]
Open-ILS/web/images/save-btn.png [new file with mode: 0644]
Open-ILS/web/images/save_btn.gif [new file with mode: 0644]
Open-ILS/web/images/search_btn.gif [new file with mode: 0644]
Open-ILS/web/images/small-rss.png [new file with mode: 0644]
Open-ILS/web/images/starz.png [new file with mode: 0644]
Open-ILS/web/images/sub_checked_hist_off.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_checked_hist_on.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_checked_out_off.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_checked_out_on.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_holds_hist_off.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_holds_hist_on.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_holds_off.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_holds_on.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_prefs_info_off.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_prefs_info_on.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_prefs_notify_off.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_prefs_notify_on.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_prefs_search_off.jpg [new file with mode: 0644]
Open-ILS/web/images/sub_prefs_search_on.jpg [new file with mode: 0644]
Open-ILS/web/images/submit_btn.gif [new file with mode: 0644]
Open-ILS/web/images/tool_back.gif [new file with mode: 0644]
Open-ILS/web/images/tool_back.png [new file with mode: 0644]
Open-ILS/web/images/tool_font.gif [new file with mode: 0644]
Open-ILS/web/images/tool_forward.gif [new file with mode: 0644]
Open-ILS/web/images/tool_forward.png [new file with mode: 0644]
Open-ILS/web/images/tool_help.gif [new file with mode: 0644]
Open-ILS/web/images/tool_help.png [new file with mode: 0644]
Open-ILS/web/images/tool_home.gif [new file with mode: 0644]
Open-ILS/web/images/tool_home.png [new file with mode: 0644]
Open-ILS/web/images/tool_mail.gif [new file with mode: 0644]
Open-ILS/web/images/tool_print.gif [new file with mode: 0644]
Open-ILS/web/images/tool_print.png [new file with mode: 0644]
Open-ILS/web/images/utils-corner-left.png [new file with mode: 0644]
Open-ILS/web/images/utils-corner-mid.png [new file with mode: 0644]
Open-ILS/web/images/utils-corner-right.jpg [new file with mode: 0644]
Open-ILS/web/images/utils-corner-right.png [new file with mode: 0644]
Open-ILS/web/images/utils-corner.jpg [new file with mode: 0644]
Open-ILS/web/images/view_my_list.png [new file with mode: 0644]
Open-ILS/web/images/view_my_list_hover.png [new file with mode: 0644]
Open-ILS/web/js/ui/default/opac/simple.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/opac/staff.js [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/base.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/common.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/home.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/login.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/marc_attrs.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/myopac/_links.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/myopac/bookbags.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/myopac/circs.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/myopac/fines.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/myopac/holds.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/myopac/main.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/myopac/prefs.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/myopac/update_email.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/place_hold.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/record.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac-poc/results.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/advanced.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/home.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/login.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/mylist.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/circ_history.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/circs.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/hold_history.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/holds.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/holds/edit.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/lists.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/main.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/main_pay.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/main_payment_form.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/main_payments.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/prefs.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/prefs_notify.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/prefs_settings.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/receipt_email.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/receipt_print.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/update_email.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/update_password.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/myopac/update_username.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/advanced/global_row.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/advanced/search.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/anon_list.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/base.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/chilifresh.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/cn_browse.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/coded_value_selector.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/filtersort.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/footer.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/header.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/homesearch.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/js.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/login/form.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/login/help.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/login/password_hint.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/misc_util.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/myopac/base.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/myopac/main_base.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/myopac/main_refund_policy.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/myopac/prefs_base.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/myopac/prefs_hints.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/org_selector.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/place_hold.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/printnav.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/qtype_selector.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/authors.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/awards.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/body.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/cn_details.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/copyinfo.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/extras.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/issues.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/subjects.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/record/summary.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/result/lowhits.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/result/lowhits_purchase.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/result/table.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/searchbar.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/tips.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/topnav.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/topnav_links.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/parts/topnav_logo.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/place_hold.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/record.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/opac/results.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/myopac/main_refund_policy.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/parts/footer.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/parts/homesearch.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/parts/login/help.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/parts/myopac/prefs_hints.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/parts/printnav.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/parts/result/lowhits_purchase.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/parts/topnav_links.tt2 [new file with mode: 0644]
Open-ILS/web/templates_kcls/default/opac/parts/topnav_logo.tt2 [new file with mode: 0644]

index 7fea97c..e8ca3ec 100644 (file)
@@ -114,6 +114,7 @@ RewriteRule . - [E=locale:%1]
     #SetEnv OILS_CHILIFRESH_ACCOUNT
     #SetEnv OILS_CHILIFRESH_PROFILE
     #SetEnv OILS_CHILIFRESH_URL http://chilifresh.com/on-site/js/evergreen.js
+    #SetEnv OILS_CHILIFRESH_HTTPS_URL https://secure.chilifresh.com/on-site/js/evergreen.js
 
     # Specify the initial script URL for Novelist (containing account credentials, etc.)
     #SetEnv OILS_NOVELIST_URL
@@ -169,26 +170,6 @@ RewriteRule . - [E=locale:%1]
 
 </Location>
 
-<Location /js/>
-    # ----------------------------------------------------------------------------------
-    # Some mod_deflate fun
-    # ----------------------------------------------------------------------------------
-    <IfModule mod_deflate.c>
-        SetOutputFilter DEFLATE
-
-        BrowserMatch ^Mozilla/4 gzip-only-text/html
-        BrowserMatch ^Mozilla/4\.0[678] no-gzip
-        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
-
-        SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
-
-        <IfModule mod_headers.c>
-            Header append Vary User-Agent env=!dont-vary
-        </IfModule>
-    </IfModule>
-
-</Location>
-
 # ----------------------------------------------------------------------------------
 # Force SSL on the OPAC's "My Account" page
 # ----------------------------------------------------------------------------------
@@ -554,7 +535,40 @@ RewriteRule ^/openurl$ ${openurl:%1} [NE,PT]
     Options +ExecCGI
     PerlSendHeader On
     allow from all
+    <IfModule mod_deflate.c>
+        SetOutputFilter DEFLATE
+        BrowserMatch ^Mozilla/4 gzip-only-text/html
+        BrowserMatch ^Mozilla/4\.0[678] no-gzip
+        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
+        SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
+        <IfModule mod_headers.c>
+            Header append Cache-Control "public"
+            Header append Vary User-Agent env=!dont-vary
+        </IfModule>
+    </IfModule>
 </Location>
+<LocationMatch ^/(images|css|js)/>
+    # should pick up the default expire time from eg.conf...
+    <IfModule mod_deflate.c>
+        SetOutputFilter DEFLATE
+        BrowserMatch ^Mozilla/4 gzip-only-text/html
+        BrowserMatch ^Mozilla/4\.0[678] no-gzip
+        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
+        SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
+        <IfModule mod_headers.c>
+            Header append Cache-Control "public"
+            Header append Vary User-Agent env=!dont-vary
+        </IfModule>
+    </IfModule>
+</LocationMatch>
+<Location /eg/opac>
+    PerlSetVar OILSWebContextLoader "OpenILS::WWW::EGCatLoader"
+    # Expire the HTML quickly since we're loading dynamic data for each page
+    ExpiresActive On
+    ExpiresByType text/html "access plus 5 seconds"
+</Location>
+
+
 # Note: the template processor will decline handling anything it does not
 # have an explicit configuration for, which means it will fall back to 
 # Apache to serve the file.  However, in the interest of speed, go ahead 
index ce42aa3..f9b824b 100644 (file)
@@ -2266,6 +2266,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <field name="xact" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field name="grocery" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field name="circulation" oils_persist:virtual="true" reporter:datatype="link"/>
+                       <field name="reservation" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field name="billing_location" reporter:datatype="link"/>
                </fields>
                <links>
@@ -2273,6 +2274,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="xact" reltype="might_have" key="id" map="" class="mbt"/>
                        <link field="circulation" reltype="might_have" key="id" map="" class="circ"/>
                        <link field="grocery" reltype="might_have" key="id" map="" class="mg"/>
+                       <link field="reservation" reltype="might_have" key="id" map="" class="bresv"/>
                        <link field="billing_location" reltype="has_a" key="id" map="" class="aou"/>
                </links>
        </class>
index 60f1573..0728082 100644 (file)
@@ -9,8 +9,24 @@
         files have the following filename extension -->
     <default_template_extension>tt2</default_template_extension>
 
-    <!-- media_prefix can be a remote server.  
-         E.g. <media_prefix>http://static.example.com/media</media_prefix> -->
+    <!-- Media Prefix.  Allows static files to be served from an alternate domain/server
+
+            Examples:
+
+                # local URL path
+                <media_prefix>/media</media_prefix> 
+
+                # server w/ path.  
+                <media_prefix>static.example.com/media</media_prefix> 
+
+                ===
+                In the first 2 examples, the request protocol (http vs https) will
+                match the protocol of the current page
+                ===
+
+                # full-qualified with static protocol
+                <media_prefix>http://static.example.com/media</media_prefix> 
+     -->
     <media_prefix/>
 
     <!-- If set to true, all output will be parsed as XML before delivery to the client.  
         XML parsing adds overhead, so this should only be used for debugging -->
     <force_valid_xml>false</force_valid_xml>
 
+    <!-- Turn on template-toolkit debugging, which reports on undefined blocks, macros, etc. -->
+    <debug_template>false</debug_template>
+
+    <!-- 
+        Supported locales.  Locales with no message catalog will use the native template strings.
+        All locales will fall back to native strings when a given string is not in the catalog
+    -->
+    <locales>
+        <en_US/>
+        <en_CA>/openils/var/data/locale/messages.en_CA.po</en_CA>
+        <fr_CA>/openils/var/data/locale/messages.fr_CA.po</fr_CA>
+    </locales>
+
     <!-- Where templates can be found.  Paths will be checked in the order entered here.
          It's possible to override individual or sets of templates by putting them into
          a path in front of the default template path -->
index 5e704b4..25334fa 100644 (file)
@@ -1820,39 +1820,31 @@ __PACKAGE__->register_method(
 );
        
 sub hold_request_count {
-       my( $self, $client, $login_session, $userid ) = @_;
-
-       my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
-               $login_session, $userid, 'VIEW_HOLD' );
-       return $evt if $evt;
-       
-
-       my $holds = $apputils->simple_scalar_request(
-                       "open-ils.cstore",
-                       "open-ils.cstore.direct.action.hold_request.search.atomic",
-                       { 
-                               usr => $userid,
-                               fulfillment_time => {"=" => undef },
-                               cancel_time => undef,
-                       }
-       );
+       my( $self, $client, $authtoken, $user_id ) = @_;
+    my $e = new_editor(authtoken => $authtoken);
+    return $e->event unless $e->checkauth;
 
-       my @ready;
-       for my $h (@$holds) {
-               next unless $h->capture_time and $h->current_copy;
+    $user_id = $e->requestor->id unless defined $user_id;
 
-               my $copy = $apputils->simple_scalar_request(
-                       "open-ils.cstore",
-                       "open-ils.cstore.direct.asset.copy.retrieve",
-                       $h->current_copy
-               );
+    if($e->requestor->id ne $user_id) {
+        my $user = $e->retrieve_actor_user($user_id);
+        return $e->event unless $e->allowed('VIEW_HOLD', $user->home_ou);
+    }
 
-               if ($copy and $copy->status == 8) {
-                       push @ready, $h;
-               }
-       }
+    my $holds = $e->json_query({
+        select => {ahr => ['shelf_time']},
+        from => 'ahr',
+        where => {
+            usr => $user_id,
+            fulfillment_time => {"=" => undef },
+            cancel_time => undef,
+        }
+    });
 
-       return { total => scalar(@$holds), ready => scalar(@ready) };
+       return { 
+        total => scalar(@$holds), 
+        ready => scalar(grep { $_->{shelf_time} } @$holds) 
+    };
 }
 
 __PACKAGE__->register_method(
index 8b29701..d21a8cc 100644 (file)
@@ -1818,5 +1818,61 @@ sub create_circ_chain_summary {
     return $obj;
 }
 
+
+# Returns "mra" attribute key/value pairs for a set of bre's
+# Takes a list of bre IDs, returns a hash of hashes,
+# {bre_id1 => {key1 => {code => value1, label => label1}, ...}...}
+my $ccvm_cache;
+sub get_bre_attrs {
+    my ($class, $bre_ids, $e) = @_;
+    $e = $e || OpenILS::Utils::CStoreEditor->new;
+
+    my $attrs = {};
+    return $attrs unless defined $bre_ids;
+    $bre_ids = [$bre_ids] unless ref $bre_ids;
+
+    my $mra = $e->json_query({
+        select => {
+            mra => [
+                {
+                    column => 'id',
+                    alias => 'bre'
+                }, {
+                    column => 'attrs',
+                    transform => 'each',
+                    result_field => 'key',
+                    alias => 'key'
+                },{
+                    column => 'attrs',
+                    transform => 'each',
+                    result_field => 'value',
+                    alias => 'value'
+                }
+            ]
+        },
+        from => 'mra',
+        where => {id => $bre_ids}
+    });
+
+    return $attrs unless $mra;
+
+    $ccvm_cache = $ccvm_cache || $e->search_config_coded_value_map({id => {'!=' => undef}});
+
+    for my $id (@$bre_ids) {
+        $attrs->{$id} = {};
+        for my $mra (grep { $_->{bre} eq $id } @$mra) {
+            my $ctype = $mra->{key};
+            my $code = $mra->{value};
+            $attrs->{$id}->{$ctype} = {code => $code};
+            if($code) {
+                my ($ccvm) = grep { $_->ctype eq $ctype and $_->code eq $code } @$ccvm_cache;
+                $attrs->{$id}->{$ctype}->{label} = $ccvm->value if $ccvm;
+            }
+        }
+    }
+
+    return $attrs;
+}
+
 1;
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
new file mode 100644 (file)
index 0000000..72fbf59
--- /dev/null
@@ -0,0 +1,302 @@
+package OpenILS::WWW::EGCatLoader;
+use strict; use warnings;
+use XML::LibXML;
+use URI::Escape;
+use Digest::MD5 qw(md5_hex);
+use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_INTERNAL_SERVER_ERROR REDIRECT HTTP_BAD_REQUEST);
+use OpenSRF::AppSession;
+use OpenSRF::EX qw/:try/;
+use OpenSRF::Utils qw/:datetime/;
+use OpenSRF::Utils::JSON;
+use OpenSRF::Utils::Logger qw/$logger/;
+use OpenILS::Application::AppUtils;
+use OpenILS::Utils::CStoreEditor qw/:funcs/;
+use OpenILS::Utils::Fieldmapper;
+use DateTime::Format::ISO8601;
+use CGI qw(:all -utf8);
+
+# EGCatLoader sub-modules 
+use OpenILS::WWW::EGCatLoader::Util;
+use OpenILS::WWW::EGCatLoader::Account;
+use OpenILS::WWW::EGCatLoader::Search;
+use OpenILS::WWW::EGCatLoader::Record;
+use OpenILS::WWW::EGCatLoader::Container;
+
+my $U = 'OpenILS::Application::AppUtils';
+
+use constant COOKIE_SES => 'ses';
+
+sub new {
+    my($class, $apache, $ctx) = @_;
+
+    my $self = bless({}, ref($class) || $class);
+
+    $self->apache($apache);
+    $self->ctx($ctx);
+    $self->cgi(new CGI);
+
+    OpenILS::Utils::CStoreEditor->init; # just in case
+    $self->editor(new_editor());
+
+    return $self;
+}
+
+
+# current Apache2::RequestRec;
+sub apache {
+    my($self, $apache) = @_;
+    $self->{apache} = $apache if $apache;
+    return $self->{apache};
+}
+
+# runtime / template context
+sub ctx {
+    my($self, $ctx) = @_;
+    $self->{ctx} = $ctx if $ctx;
+    return $self->{ctx};
+}
+
+# cstore editor
+sub editor {
+    my($self, $editor) = @_;
+    $self->{editor} = $editor if $editor;
+    return $self->{editor};
+}
+
+# CGI handle
+sub cgi {
+    my($self, $cgi) = @_;
+    $self->{cgi} = $cgi if $cgi;
+    return $self->{cgi};
+}
+
+
+# -----------------------------------------------------------------------------
+# Perform initial setup, load common data, then load page data
+# -----------------------------------------------------------------------------
+sub load {
+    my $self = shift;
+
+    $self->init_ro_object_cache;
+
+    my $stat = $self->load_common;
+    return $stat unless $stat == Apache2::Const::OK;
+
+    my $path = $self->apache->path_info;
+
+    (undef, $self->ctx->{mylist}) = $self->fetch_mylist unless
+        $path =~ /opac\/my(opac\/lists|list)/;
+
+    return $self->load_simple("home") if $path =~ m|opac/home|;
+    return $self->load_simple("advanced") if $path =~ m|opac/advanced|;
+    return $self->load_rresults if $path =~ m|opac/results|;
+    return $self->load_record if $path =~ m|opac/record|;
+
+    return $self->load_mylist_add if $path =~ m|opac/mylist/add|;
+    return $self->load_mylist_move if $path =~ m|opac/mylist/move|;
+    return $self->load_mylist if $path =~ m|opac/mylist|;
+    return $self->load_cache_clear if $path =~ m|opac/cache/clear|;
+
+    # ----------------------------------------------------------------
+    # Logout and login require SSL
+    # ----------------------------------------------------------------
+    if($path =~ m|opac/login|) {
+        return $self->redirect_ssl unless $self->cgi->https;
+        return $self->load_login;
+    }
+
+    if($path =~ m|opac/logout|) {
+        #return Apache2::Const::FORBIDDEN unless $self->cgi->https; 
+        $self->apache->log->warn("catloader: logout called in non-secure context from " . 
+            ($self->ctx->{referer} || '<no referer>')) unless $self->cgi->https;
+        return $self->load_logout;
+    }
+
+    # ----------------------------------------------------------------
+    #  Everything below here requires SSL + authentication
+    # ----------------------------------------------------------------
+    return $self->redirect_auth
+        unless $self->cgi->https and $self->editor->requestor;
+
+    return $self->load_place_hold if $path =~ m|opac/place_hold|;
+    return $self->load_myopac_holds if $path =~ m|opac/myopac/holds|;
+    return $self->load_myopac_circs if $path =~ m|opac/myopac/circs|;
+    return $self->load_myopac_payment_form if $path =~ m|opac/myopac/main_payment_form|;
+    return $self->load_myopac_payments if $path =~ m|opac/myopac/main_payments|;
+    return $self->load_myopac_pay if $path =~ m|opac/myopac/main_pay|;
+    return $self->load_myopac_main if $path =~ m|opac/myopac/main|;
+    return $self->load_myopac_receipt_email if $path =~ m|opac/myopac/receipt_email|;
+    return $self->load_myopac_receipt_print if $path =~ m|opac/myopac/receipt_print|;
+    return $self->load_myopac_update_email if $path =~ m|opac/myopac/update_email|;
+    return $self->load_myopac_update_password if $path =~ m|opac/myopac/update_password|;
+    return $self->load_myopac_update_username if $path =~ m|opac/myopac/update_username|;
+    return $self->load_myopac_bookbags if $path =~ m|opac/myopac/lists|;
+    return $self->load_myopac_bookbag_update if $path =~ m|opac/myopac/list/update|;
+    return $self->load_myopac_circ_history if $path =~ m|opac/myopac/circ_history|;
+    return $self->load_myopac_hold_history if $path =~ m|opac/myopac/hold_history|;
+    return $self->load_myopac_prefs_notify if $path =~ m|opac/myopac/prefs_notify|;
+    return $self->load_myopac_prefs_settings if $path =~ m|opac/myopac/prefs_settings|;
+    return $self->load_myopac_prefs if $path =~ m|opac/myopac/prefs|;
+
+    return Apache2::Const::OK;
+}
+
+
+# -----------------------------------------------------------------------------
+# Redirect to SSL equivalent of a given page
+# -----------------------------------------------------------------------------
+sub redirect_ssl {
+    my $self = shift;
+    my $new_page = sprintf('https://%s%s', $self->apache->hostname, $self->apache->unparsed_uri);
+    return $self->generic_redirect($new_page);
+}
+
+# -----------------------------------------------------------------------------
+# If an authnticated resource is requested w/o auth, redirect to the login page,
+# then return to the originally requrested resource upon successful login.
+# -----------------------------------------------------------------------------
+sub redirect_auth {
+    my $self = shift;
+    my $login_page = sprintf('https://%s%s/login', $self->apache->hostname, $self->ctx->{opac_root});
+    my $redirect_to = uri_escape($self->apache->unparsed_uri);
+    return $self->generic_redirect("$login_page?redirect_to=$redirect_to");
+}
+
+# -----------------------------------------------------------------------------
+# Fall-through for loading a basic page
+# -----------------------------------------------------------------------------
+sub load_simple {
+    my ($self, $page) = @_;
+    $self->ctx->{page} = $page;
+    return Apache2::Const::OK;
+}
+
+# -----------------------------------------------------------------------------
+# Tests to see if the user is authenticated and sets some common context values
+# -----------------------------------------------------------------------------
+sub load_common {
+    my $self = shift;
+
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+
+    $ctx->{referer} = $self->cgi->referer;
+    $ctx->{path_info} = $self->cgi->path_info;
+    $ctx->{full_path} = $ctx->{base_path} . $self->cgi->path_info;
+    $ctx->{unparsed_uri} = $self->apache->unparsed_uri;
+    $ctx->{opac_root} = $ctx->{base_path} . "/opac"; # absolute base url
+    $ctx->{is_staff} = ($self->apache->headers_in->get('User-Agent') =~ /oils_xulrunner/);
+
+    # capture some commonly accessed pages
+    $ctx->{home_page} = 'http://' . $self->apache->hostname . $self->ctx->{opac_root} . "/home";
+    $ctx->{logout_page} = 'https://' . $self->apache->hostname . $self->ctx->{opac_root} . "/logout";
+
+    if($e->authtoken($self->cgi->cookie(COOKIE_SES))) {
+
+        if($e->checkauth) {
+
+            $ctx->{authtoken} = $e->authtoken;
+            $ctx->{authtime} = $e->authtime;
+            $ctx->{user} = $e->requestor;
+
+            $ctx->{user_stats} = $U->simplereq(
+                'open-ils.actor', 
+                'open-ils.actor.user.opac.vital_stats', 
+                $e->authtoken, $e->requestor->id);
+
+        } else {
+
+            # if we encounter a stale authtoken, call load_logout 
+            # to clean up the cookie, then redirect the user to the
+            # originally requested page
+            return $self->load_logout($self->apache->unparsed_uri);
+        }
+    }
+
+    return Apache2::Const::OK;
+}
+
+
+# -----------------------------------------------------------------------------
+# Log in and redirect to the redirect_to URL (or home)
+# -----------------------------------------------------------------------------
+sub load_login {
+    my $self = shift;
+    my $cgi = $self->cgi;
+    my $ctx = $self->ctx;
+
+    $ctx->{page} = 'login';
+
+    my $username = $cgi->param('username');
+    my $password = $cgi->param('password');
+    my $org_unit = $cgi->param('loc') || $ctx->{aou_tree}->()->id;
+    my $persist = $cgi->param('persist');
+
+    # initial log form only
+    return Apache2::Const::OK unless $username and $password;
+
+       my $seed = $U->simplereq(
+        'open-ils.auth', 
+               'open-ils.auth.authenticate.init', $username);
+
+    my $args = {       
+        barcode => $username, 
+        password => md5_hex($seed . md5_hex($password)), 
+        type => ($persist) ? 'persist' : 'opac' 
+    };
+
+    my $bc_regex = $ctx->{get_org_setting}->($org_unit, 'opac.barcode_regex');
+
+    $args->{username} = delete $args->{barcode} 
+        if $bc_regex and !($username =~ /$bc_regex/);
+
+       my $response = $U->simplereq(
+        'open-ils.auth', 'open-ils.auth.authenticate.complete', $args);
+
+    if($U->event_code($response)) { 
+        # login failed, report the reason to the template
+        $ctx->{login_failed_event} = $response;
+        return Apache2::Const::OK;
+    }
+
+    # login succeeded, redirect as necessary
+
+    my $acct = $self->apache->unparsed_uri;
+    $acct =~ s|/login|/myopac/main|;
+
+    return $self->generic_redirect(
+        $cgi->param('redirect_to') || $acct,
+        $cgi->cookie(
+            -name => COOKIE_SES,
+            -path => '/',
+            -secure => 1,
+            -value => $response->{payload}->{authtoken},
+            -expires => ($persist) ? CORE::time + $response->{payload}->{authtime} : undef
+        )
+    );
+}
+
+# -----------------------------------------------------------------------------
+# Log out and redirect to the home page
+# -----------------------------------------------------------------------------
+sub load_logout {
+    my $self = shift;
+    my $redirect_to = shift;
+
+    # If the user was adding anyting to an anonymous cache 
+    # while logged in, go ahead and clear it out.
+    $self->clear_anon_cache;
+
+    return $self->generic_redirect(
+        $redirect_to || $self->ctx->{home_page},
+        $self->cgi->cookie(
+            -name => COOKIE_SES,
+            -path => '/',
+            -value => '',
+            -expires => '-1h'
+        )
+    );
+}
+
+1;
+
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
new file mode 100644 (file)
index 0000000..efaeb28
--- /dev/null
@@ -0,0 +1,1070 @@
+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 DateTime;
+my $U = 'OpenILS::Application::AppUtils';
+
+sub prepare_extended_user_info {
+    my $self = shift;
+    my @extra_flesh = @_;
+
+    $self->ctx->{user} = $self->editor->retrieve_actor_user([
+        $self->ctx->{user}->id,
+        {
+            flesh => 1,
+            flesh_fields => {
+                au => [qw/card home_ou addresses ident_type billing_address/, @extra_flesh]
+                # ...
+            }
+        }
+    ]) or return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
+
+    return;
+}
+
+# context additions: 
+#   user : au object, fleshed
+sub load_myopac_prefs {
+    my $self = shift;
+    return $self->prepare_extended_user_info || Apache2::Const::OK;
+}
+
+sub load_myopac_prefs_notify {
+    my $self = shift;
+    my $e = $self->editor;
+
+    my $user_prefs = $self->fetch_optin_prefs;
+    $user_prefs = $self->update_optin_prefs($user_prefs)
+        if $self->cgi->request_method eq 'POST';
+
+    $self->ctx->{opt_in_settings} = $user_prefs; 
+
+    return Apache2::Const::OK;
+}
+
+sub fetch_optin_prefs {
+    my $self = shift;
+    my $e = $self->editor;
+
+    # fetch all of the opt-in settings the user has access to
+    # XXX: user's should in theory have options to opt-in to notices
+    # for remote locations, but that opens the door for a large
+    # set of generally un-used opt-ins.. needs discussion
+    my $opt_ins =  $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.event_def.opt_in.settings.atomic',
+        $e->authtoken, $e->requestor->home_ou);
+
+    # fetch user setting values for each of the opt-in settings
+    my $user_set = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.patron.settings.retrieve',
+        $e->authtoken, 
+        $e->requestor->id, 
+        [map {$_->name} @$opt_ins]
+    );
+
+    return [map { {cust => $_, value => $user_set->{$_->name} } } @$opt_ins];
+}
+
+sub update_optin_prefs {
+    my $self = shift;
+    my $user_prefs = shift;
+    my $e = $self->editor;
+    my @settings = $self->cgi->param('setting');
+    my %newsets;
+
+    # apply now-true settings
+    for my $applied (@settings) {
+        # see if setting is already applied to this user
+        next if grep { $_->{cust}->name eq $applied and $_->{value} } @$user_prefs;
+        $newsets{$applied} = OpenSRF::Utils::JSON->true;
+    }
+
+    # remove now-false settings
+    for my $pref (grep { $_->{value} } @$user_prefs) {
+        $newsets{$pref->{cust}->name} = undef 
+            unless grep { $_ eq $pref->{cust}->name } @settings;
+    }
+
+    $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.patron.settings.update',
+        $e->authtoken, $e->requestor->id, \%newsets);
+
+    # update the local prefs to match reality
+    for my $pref (@$user_prefs) {
+        $pref->{value} = $newsets{$pref->{cust}->name} 
+            if exists $newsets{$pref->{cust}->name};
+    }
+
+    return $user_prefs;
+}
+
+sub _load_user_with_prefs {
+    my $self = shift;
+    my $stat = $self->prepare_extended_user_info('settings');
+    return $stat if $stat; # not-OK
+
+    $self->ctx->{user_setting_map} = {
+        map { $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) } 
+            @{$self->ctx->{user}->settings}
+    };
+
+    return undef;
+}
+
+sub load_myopac_prefs_settings {
+    my $self = shift;
+
+    my $stat = $self->_load_user_with_prefs;
+    return $stat if $stat;
+
+    return Apache2::Const::OK
+        unless $self->cgi->request_method eq 'POST';
+
+    # some setting values from the form don't match the 
+    # required value/format for the db, so they have to be 
+    # individually translated.
+
+    my %settings;
+    my $set_map = $self->ctx->{user_setting_map};
+
+    my $key = 'opac.hits_per_page';
+    my $val = $self->cgi->param($key);
+    $settings{$key}= $val unless $$set_map{$key} eq $val;
+
+    my $now = DateTime->now->strftime('%F');
+    for $key (qw/history.circ.retention_start history.hold.retention_start/) {
+        $val = $self->cgi->param($key);
+        if($val and $val eq 'on') {
+            # Set the start time to 'now' unless a start time already exists for the user
+            $settings{$key} = $now unless $$set_map{$key};
+        } else {
+            # clear the start time if one previously existed for the user
+            $settings{$key} = undef if $$set_map{$key};
+        }
+    }
+    
+    # Send the modified settings off to be saved
+    $U->simplereq(
+        'open-ils.actor', 
+        'open-ils.actor.patron.settings.update',
+        $self->editor->authtoken, undef, \%settings);
+
+    # re-fetch user prefs 
+    $self->ctx->{updated_user_settings} = \%settings;
+    return $self->_load_user_with_prefs || Apache2::Const::OK;
+}
+
+sub fetch_user_holds {
+    my $self = shift;
+    my $hold_ids = shift;
+    my $ids_only = shift;
+    my $flesh = shift;
+    my $available = shift;
+    my $limit = shift;
+    my $offset = shift;
+
+    my $e = $self->editor;
+
+    my $circ = OpenSRF::AppSession->create('open-ils.circ');
+
+    if(!$hold_ids) {
+
+        $hold_ids = $circ->request(
+            'open-ils.circ.holds.id_list.retrieve.authoritative', 
+            $e->authtoken, 
+            $e->requestor->id
+        )->gather(1);
+    
+        $hold_ids = [ grep { defined $_ } @$hold_ids[$offset..($offset + $limit - 1)] ] if $limit or $offset;
+    }
+
+
+    return $hold_ids if $ids_only or @$hold_ids == 0;
+
+    my $args = {
+        suppress_notices => 1,
+        suppress_transits => 1,
+        suppress_mvr => 1,
+        suppress_patron_details => 1,
+        include_bre => $flesh ? 1 : 0
+    };
+
+    # ----------------------------------------------------------------
+    # Collect holds in batches of $batch_size for faster retrieval
+
+    my $batch_size = 8;
+    my $batch_idx = 0;
+    my $mk_req_batch = sub {
+        my @ses;
+        my $top_idx = $batch_idx + $batch_size;
+        while($batch_idx < $top_idx) {
+            my $hold_id = $hold_ids->[$batch_idx++];
+            last unless $hold_id;
+            my $ses = OpenSRF::AppSession->create('open-ils.circ');
+            my $req = $ses->request(
+                'open-ils.circ.hold.details.retrieve', 
+                $e->authtoken, $hold_id, $args);
+            push(@ses, {ses => $ses, req => $req});
+        }
+        return @ses;
+    };
+
+    my $first = 1;
+    my(@collected, @holds, @ses);
+
+    while(1) {
+        @ses = $mk_req_batch->() if $first;
+        last if $first and not @ses;
+
+        if(@collected) {
+            # If desired by the caller, filter any holds that are not available.
+            if ($available) {
+                @collected = grep { $_->{hold}->{status} == 4 } @collected;
+            }
+            while(my $blob = pop(@collected)) {
+                $blob->{marc_xml} = XML::LibXML->new->parse_string($blob->{hold}->{bre}->marc) if $flesh;
+                push(@holds, $blob);
+            }
+        }
+
+        for my $req_data (@ses) {
+            push(@collected, {hold => $req_data->{req}->gather(1)});
+            $req_data->{ses}->kill_me;
+        }
+
+        @ses = $mk_req_batch->();
+        last unless @collected or @ses;
+        $first = 0;
+    }
+
+    # put the holds back into the original server sort order
+    my @sorted;
+    for my $id (@$hold_ids) {
+        push @sorted, grep { $_->{hold}->{hold}->id == $id } @holds;
+    }
+
+    return \@sorted;
+}
+
+sub handle_hold_update {
+    my $self = shift;
+    my $action = shift;
+    my $e = $self->editor;
+    my $url;
+
+    my @hold_ids = $self->cgi->param('hold_id'); # for non-_all actions
+    @hold_ids = @{$self->fetch_user_holds(undef, 1)} if $action =~ /_all/;
+
+    my $circ = OpenSRF::AppSession->create('open-ils.circ');
+
+    if($action =~ /cancel/) {
+
+        for my $hold_id (@hold_ids) {
+            my $resp = $circ->request(
+                'open-ils.circ.hold.cancel', $e->authtoken, $hold_id, 6 )->gather(1); # 6 == patron-cancelled-via-opac
+        }
+
+    } elsif ($action =~ /activate|suspend/) {
+        
+        my $vlist = [];
+        for my $hold_id (@hold_ids) {
+            my $vals = {id => $hold_id};
+
+            if($action =~ /activate/) {
+                $vals->{frozen} = 'f';
+                $vals->{thaw_date} = undef;
+
+            } elsif($action =~ /suspend/) {
+                $vals->{frozen} = 't';
+                # $vals->{thaw_date} = TODO;
+            }
+            push(@$vlist, $vals);
+        }
+
+        $circ->request('open-ils.circ.hold.update.batch.atomic', $e->authtoken, undef, $vlist)->gather(1);
+    } elsif ($action eq 'edit') {
+
+        my @vals = map {
+            my $val = {"id" => $_};
+            $val->{"frozen"} = $self->cgi->param("frozen");
+            $val->{"pickup_lib"} = $self->cgi->param("pickup_lib");
+
+            for my $field (qw/expire_time thaw_date/) {
+                # XXX TODO make this support other date formats, not just
+                # MM/DD/YYYY.
+                next unless $self->cgi->param($field) =~
+                    m:^(\d{2})/(\d{2})/(\d{4})$:;
+                $val->{$field} = "$3-$1-$2";
+            }
+            $val;
+        } @hold_ids;
+
+        $circ->request(
+            'open-ils.circ.hold.update.batch.atomic',
+            $e->authtoken, undef, \@vals
+        )->gather(1);   # LFW XXX test for failure
+        $url = 'https://' . $self->apache->hostname . $self->ctx->{opac_root} . '/myopac/holds';
+    }
+
+    $circ->kill_me;
+    return defined($url) ? $self->generic_redirect($url) : undef;
+}
+
+sub load_myopac_holds {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+    
+
+    my $limit = $self->cgi->param('limit') || 0;
+    my $offset = $self->cgi->param('offset') || 0;
+    my $action = $self->cgi->param('action') || '';
+    my $available = int($self->cgi->param('available') || 0);
+
+    my $hold_handle_result;
+    $hold_handle_result = $self->handle_hold_update($action) if $action;
+
+    $ctx->{holds} = $self->fetch_user_holds(undef, 0, 1, $available, $limit, $offset);
+
+    return defined($hold_handle_result) ? $hold_handle_result : Apache2::Const::OK;
+}
+
+sub load_place_hold {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    my $e = $self->editor;
+    my $cgi = $self->cgi;
+    $self->ctx->{page} = 'place_hold';
+
+    $ctx->{hold_target} = $cgi->param('hold_target');
+    $ctx->{hold_type} = $cgi->param('hold_type');
+    $ctx->{default_pickup_lib} = $e->requestor->home_ou; # XXX staff
+
+    if ($ctx->{hold_type} eq 'T') {
+        $ctx->{record} = $e->retrieve_biblio_record_entry($ctx->{hold_target});
+    } elsif ($ctx->{hold_type} eq 'I') {
+        my $iss = $e->retrieve_serial_issuance([
+            $ctx->{hold_target}, {
+                "flesh" => 2,
+                "flesh_fields" => {
+                    "siss" => ["subscription"], "ssub" => ["record_entry"]
+                }
+            }
+        ]);
+        $ctx->{record} = $iss->subscription->record_entry;
+    }
+    # ...
+
+    $ctx->{marc_xml} = XML::LibXML->new->parse_string($ctx->{record}->marc);
+
+    if(my $pickup_lib = $cgi->param('pickup_lib')) {
+
+        my $args = {
+            patronid => $e->requestor->id,
+            titleid => $ctx->{hold_target}, # XXX
+            pickup_lib => $pickup_lib,
+            depth => 0, # XXX
+        };
+
+        my $allowed = $U->simplereq(
+            'open-ils.circ',
+            'open-ils.circ.title_hold.is_possible',
+            $e->authtoken, $args
+        );
+
+        if($allowed->{success} == 1) {
+            my $hold = Fieldmapper::action::hold_request->new;
+
+            $hold->pickup_lib($pickup_lib);
+            $hold->requestor($e->requestor->id);
+            $hold->usr($e->requestor->id); # XXX staff
+            $hold->target($ctx->{hold_target});
+            $hold->hold_type($ctx->{hold_type});
+            # frozen, expired, etc..
+
+            my $stat = $U->simplereq(
+                'open-ils.circ',
+                'open-ils.circ.holds.create',
+                $e->authtoken, $hold
+            );
+
+            if($stat and $stat > 0) {
+                # if successful, return the user to the requesting page
+                $self->apache->log->info("Redirecting back to " . $cgi->param('redirect_to'));
+                return $self->generic_redirect;
+
+            } else {
+                $ctx->{hold_failed} = 1;
+            }
+        } else { # hold *check* failed
+            $ctx->{hold_failed} = 1; # XXX process the events, etc
+            $ctx->{hold_failed_event} = $allowed->{last_event};
+        }
+
+        # hold permit failed
+        $logger->info('hold permit result ' . OpenSRF::Utils::JSON->perl2JSON($allowed));
+    }
+
+    return Apache2::Const::OK;
+}
+
+
+sub fetch_user_circs {
+    my $self = shift;
+    my $flesh = shift; # flesh bib data, etc.
+    my $circ_ids = shift;
+    my $limit = shift;
+    my $offset = shift;
+
+    my $e = $self->editor;
+
+    my @circ_ids;
+
+    if($circ_ids) {
+        @circ_ids = @$circ_ids;
+
+    } else {
+
+        my $circ_data = $U->simplereq(
+            'open-ils.actor', 
+            'open-ils.actor.user.checked_out',
+            $e->authtoken, 
+            $e->requestor->id
+        );
+
+        @circ_ids =  ( @{$circ_data->{overdue}}, @{$circ_data->{out}} );
+
+        if($limit or $offset) {
+            @circ_ids = grep { defined $_ } @circ_ids[0..($offset + $limit - 1)];
+        }
+    }
+
+    return [] unless @circ_ids;
+
+    my $cstore = OpenSRF::AppSession->create('open-ils.cstore');
+
+    my $qflesh = {
+        flesh => 3,
+        flesh_fields => {
+            circ => ['target_copy'],
+            acp => ['call_number'],
+            acn => ['record']
+        }
+    };
+
+    $e->xact_begin;
+    my $circs = $e->search_action_circulation(
+        [{id => \@circ_ids}, ($flesh) ? $qflesh : {}], {substream => 1});
+
+    my @circs;
+    for my $circ (@$circs) {
+        push(@circs, {
+            circ => $circ, 
+            marc_xml => ($flesh and $circ->target_copy->call_number->id != -1) ? 
+                XML::LibXML->new->parse_string($circ->target_copy->call_number->record->marc) : 
+                undef  # pre-cat copy, use the dummy title/author instead
+        });
+    }
+    $e->xact_rollback;
+
+    # make sure the final list is in the correct order
+    my @sorted_circs;
+    for my $id (@circ_ids) {
+        push(
+            @sorted_circs,
+            (grep { $_->{circ}->id == $id } @circs)
+        );
+    }
+
+    return \@sorted_circs;
+}
+
+
+sub handle_circ_renew {
+    my $self = shift;
+    my $action = shift;
+    my $ctx = $self->ctx;
+
+    my @renew_ids = $self->cgi->param('circ');
+
+    my $circs = $self->fetch_user_circs(0, ($action eq 'renew') ? [@renew_ids] : undef);
+
+    # TODO: fire off renewal calls in batches to speed things up
+    my @responses;
+    for my $circ (@$circs) {
+
+        my $evt = $U->simplereq(
+            'open-ils.circ', 
+            'open-ils.circ.renew',
+            $self->editor->authtoken,
+            {
+                patron_id => $self->editor->requestor->id,
+                copy_id => $circ->{circ}->target_copy,
+                opac_renewal => 1
+            }
+        );
+
+        # TODO return these, then insert them into the circ data 
+        # blob that is shoved into the template for each circ
+        # so the template won't have to match them
+        push(@responses, {copy => $circ->{circ}->target_copy, evt => $evt});
+    }
+
+    return @responses;
+}
+
+
+sub load_myopac_circs {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+
+    $ctx->{circs} = [];
+    my $limit = $self->cgi->param('limit') || 0; # 0 == unlimited
+    my $offset = $self->cgi->param('offset') || 0;
+    my $action = $self->cgi->param('action') || '';
+
+    # perform the renewal first if necessary
+    my @results = $self->handle_circ_renew($action) if $action =~ /renew/;
+
+    $ctx->{circs} = $self->fetch_user_circs(1, undef, $limit, $offset);
+
+    my $success_renewals = 0;
+    my $failed_renewals = 0;
+    for my $data (@{$ctx->{circs}}) {
+        my ($resp) = grep { $_->{copy} == $data->{circ}->target_copy->id } @results;
+
+        if($resp) {
+            my $evt = ref($resp->{evt}) eq 'ARRAY' ? $resp->{evt}->[0] : $resp->{evt};
+            $data->{renewal_response} = $evt;
+            $success_renewals++ if $evt->{textcode} eq 'SUCCESS';
+            $failed_renewals++ if $evt->{textcode} ne 'SUCCESS';
+        }
+    }
+
+    $ctx->{success_renewals} = $success_renewals;
+    $ctx->{failed_renewals} = $failed_renewals;
+
+    return Apache2::Const::OK;
+}
+
+sub load_myopac_circ_history {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+    my $limit = $self->cgi->param('limit') || 15;
+    my $offset = $self->cgi->param('offset') || 0;
+
+    $ctx->{circ_history_limit} = $limit;
+    $ctx->{circ_history_offset} = $offset;
+
+    my $circs = $e->json_query({
+        from => ['action.usr_visible_circs', $e->requestor->id],
+        #limit => $limit || 25,
+        #offset => $offset || 0,
+    });
+
+    # XXX: order-by in the json_query above appears to do nothing, so in-query 
+    # paging is not reallly an option.  do the sorting/paging here
+
+    # sort newest to oldest
+    $circs = [ sort { $b->{xact_start} cmp $a->{xact_start} } @$circs ];
+    my @ids = map { $_->{id} } @$circs;
+
+    # find the selected page and trim cruft
+    @ids = @ids[$offset..($offset + $limit - 1)] if $limit;
+    @ids = grep { defined $_ } @ids;
+
+    $ctx->{circs} = $self->fetch_user_circs(1, \@ids);
+    #$ctx->{circs} = $self->fetch_user_circs(1, [map { $_->{id} } @$circs], $limit, $offset);
+
+    return Apache2::Const::OK;
+}
+
+# TODO: action.usr_visible_holds does not return cancelled holds.  Should it?
+sub load_myopac_hold_history {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+    my $limit = $self->cgi->param('limit') || 15;
+    my $offset = $self->cgi->param('offset') || 0;
+    $ctx->{hold_history_limit} = $limit;
+    $ctx->{hold_history_offset} = $offset;
+
+
+    my $holds = $e->json_query({
+        from => ['action.usr_visible_holds', $e->requestor->id],
+        limit => $limit || 25,
+        offset => $offset || 0
+    });
+
+    $ctx->{holds} = $self->fetch_user_holds([map { $_->{id} } @$holds], 0, 1, 0, $limit, $offset);
+
+    return Apache2::Const::OK;
+}
+
+sub load_myopac_payment_form {
+    my $self = shift;
+    my $r;
+
+    $r = $self->prepare_fines(undef, undef, [$self->cgi->param('xact')]) and return $r;
+    $r = $self->prepare_extended_user_info and return $r;
+
+    return Apache2::Const::OK;
+}
+
+# TODO: add other filter options as params/configs/etc.
+sub load_myopac_payments {
+    my $self = shift;
+    my $limit = $self->cgi->param('limit') || 20;
+    my $offset = $self->cgi->param('offset') || 0;
+    my $e = $self->editor;
+
+    $self->ctx->{payment_history_limit} = $limit;
+    $self->ctx->{payment_history_offset} = $offset;
+
+    my $args = {};
+    $args->{limit} = $limit if $limit;
+    $args->{offset} = $offset if $offset;
+
+    $self->ctx->{payments} = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.user.payments.retrieve.atomic',
+        $e->authtoken, $e->requestor->id, $args);
+
+    return Apache2::Const::OK;
+}
+
+sub load_myopac_pay {
+    my $self = shift;
+    my $r;
+
+    $r = $self->prepare_fines(undef, undef, [$self->cgi->param('xact')]) and
+        return $r;
+
+    # balance_owed is computed specifically from the fines we're trying
+    # to pay in this case.
+    if ($self->ctx->{fines}->{balance_owed} <= 0) {
+        $self->apache->log->info(
+            sprintf("Can't pay non-positive balance. xacts selected: (%s)",
+                join(", ", map(int, $self->cgi->param("xact"))))
+        );
+        return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    my $cc_args = {"where_process" => 1};
+
+    $cc_args->{$_} = $self->cgi->param($_) for (qw/
+        number cvv2 expire_year expire_month billing_first
+        billing_last billing_address billing_city billing_state
+        billing_zip
+    /);
+
+    my $args = {
+        "cc_args" => $cc_args,
+        "userid" => $self->ctx->{user}->id,
+        "payment_type" => "credit_card_payment",
+        "payments" => $self->prepare_fines_for_payment   # should be safe after self->prepare_fines
+    };
+
+    my $resp = $U->simplereq("open-ils.circ", "open-ils.circ.money.payment",
+        $self->editor->authtoken, $args, $self->ctx->{user}->last_xact_id
+    );
+
+    $self->ctx->{"payment_response"} = $resp;
+
+    unless ($resp->{"textcode"}) {
+        $self->ctx->{printable_receipt} = $U->simplereq(
+           "open-ils.circ", "open-ils.circ.money.payment_receipt.print",
+           $self->editor->authtoken, $resp->{payments}
+        );
+    }
+
+    return Apache2::Const::OK;
+}
+
+sub load_myopac_receipt_print {
+    my $self = shift;
+
+    $self->ctx->{printable_receipt} = $U->simplereq(
+       "open-ils.circ", "open-ils.circ.money.payment_receipt.print",
+       $self->editor->authtoken, [$self->cgi->param("payment")]
+    );
+
+    return Apache2::Const::OK;
+}
+
+sub load_myopac_receipt_email {
+    my $self = shift;
+
+    # The following ML method doesn't actually check whether the user in
+    # question has an email address, so we do.
+    if ($self->ctx->{user}->email) {
+        $self->ctx->{email_receipt_result} = $U->simplereq(
+           "open-ils.circ", "open-ils.circ.money.payment_receipt.email",
+           $self->editor->authtoken, [$self->cgi->param("payment")]
+        );
+    } else {
+        $self->ctx->{email_receipt_result} =
+            new OpenILS::Event("PATRON_NO_EMAIL_ADDRESS");
+    }
+
+    return Apache2::Const::OK;
+}
+
+sub prepare_fines {
+    my ($self, $limit, $offset, $id_list) = @_;
+
+    # XXX TODO: check for failure after various network calls
+
+    # It may be unclear, but this result structure lumps circulation and
+    # reservation fines together, and keeps grocery fines separate.
+    $self->ctx->{"fines"} = {
+        "circulation" => [],
+        "grocery" => [],
+        "total_paid" => 0,
+        "total_owed" => 0,
+        "balance_owed" => 0
+    };
+
+    my $cstore = OpenSRF::AppSession->create('open-ils.cstore');
+
+    # TODO: This should really be a ML call, but the existing calls 
+    # return an excessive amount of data and don't offer streaming
+
+    my %paging = ($limit or $offset) ? (limit => $limit, offset => $offset) : ();
+
+    my $req = $cstore->request(
+        'open-ils.cstore.direct.money.open_billable_transaction_summary.search',
+        {
+            usr => $self->editor->requestor->id,
+            balance_owed => {'!=' => 0},
+            ($id_list && @$id_list ? ("id" => $id_list) : ()),
+        },
+        {
+            flesh => 4,
+            flesh_fields => {
+                mobts => [qw/grocery circulation reservation/],
+                bresv => ['target_resource_type'],
+                brt => ['record'],
+                mg => ['billings'],
+                mb => ['btype'],
+                circ => ['target_copy'],
+                acp => ['call_number'],
+                acn => ['record']
+            },
+            order_by => { mobts => 'xact_start' },
+            %paging
+        }
+    );
+
+    my @total_keys = qw/total_paid total_owed balance_owed/;
+    $self->ctx->{"fines"}->{@total_keys} = (0, 0, 0);
+
+    while(my $resp = $req->recv) {
+        my $mobts = $resp->content;
+        my $circ = $mobts->circulation;
+
+        my $last_billing;
+        if($mobts->grocery) {
+            my @billings = sort { $a->billing_ts cmp $b->billing_ts } @{$mobts->grocery->billings};
+            $last_billing = pop(@billings);
+        }
+
+        # XXX TODO confirm that the following, and the later division by 100.0
+        # to get a floating point representation once again, is sufficiently
+        # "money-safe" math.
+        $self->ctx->{"fines"}->{$_} += int($mobts->$_ * 100) for (@total_keys);
+
+        my $marc_xml = undef;
+        if ($mobts->xact_type eq 'reservation' and
+            $mobts->reservation->target_resource_type->record) {
+            $marc_xml = XML::LibXML->new->parse_string(
+                $mobts->reservation->target_resource_type->record->marc
+            );
+        } elsif ($mobts->xact_type eq 'circulation' and
+            $circ->target_copy->call_number->id != -1) {
+            $marc_xml = XML::LibXML->new->parse_string(
+                $circ->target_copy->call_number->record->marc
+            );
+        }
+
+        push(
+            @{$self->ctx->{"fines"}->{$mobts->grocery ? "grocery" : "circulation"}},
+            {
+                xact => $mobts,
+                last_grocery_billing => $last_billing,
+                marc_xml => $marc_xml
+            } 
+        );
+    }
+
+    $self->ctx->{"fines"}->{$_} /= 100.0 for (@total_keys);
+    return;
+}
+
+sub prepare_fines_for_payment {
+    # This assumes $self->prepare_fines has already been run
+    my ($self) = @_;
+
+    my @results = ();
+    if ($self->ctx->{fines}) {
+        push @results, [$_->{xact}->id, $_->{xact}->balance_owed] foreach (
+            @{$self->ctx->{fines}->{circulation}},
+            @{$self->ctx->{fines}->{grocery}}
+        );
+    }
+
+    return \@results;
+}
+
+sub load_myopac_main {
+    my $self = shift;
+    my $limit = $self->cgi->param('limit') || 0;
+    my $offset = $self->cgi->param('offset') || 0;
+
+    return $self->prepare_fines($limit, $offset) || Apache2::Const::OK;
+}
+
+sub load_myopac_update_email {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+    my $email = $self->cgi->param('email') || '';
+
+    return Apache2::Const::OK 
+        unless $self->cgi->request_method eq 'POST';
+
+    unless($email =~ /.+\@.+\..+/) { # TODO better regex?
+        $ctx->{invalid_email} = $email;
+        return Apache2::Const::OK;
+    }
+
+    my $stat = $U->simplereq(
+        'open-ils.actor', 
+        'open-ils.actor.user.email.update', 
+        $e->authtoken, $email);
+
+    my $url = $self->apache->unparsed_uri;
+    $url =~ s/update_email/prefs/;
+
+    return $self->generic_redirect($url);
+}
+
+sub load_myopac_update_username {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+    my $username = $self->cgi->param('username') || '';
+
+    return Apache2::Const::OK 
+        unless $self->cgi->request_method eq 'POST';
+
+    unless($username and $username !~ /\s/) { # any other username restrictions?
+        $ctx->{invalid_username} = $username;
+        return Apache2::Const::OK;
+    }
+
+    if($username ne $e->requestor->usrname) {
+
+        my $evt = $U->simplereq(
+            'open-ils.actor', 
+            'open-ils.actor.user.username.update', 
+            $e->authtoken, $username);
+
+        if($U->event_equals($evt, 'USERNAME_EXISTS')) {
+            $ctx->{username_exists} = $username;
+            return Apache2::Const::OK;
+        }
+    }
+
+    my $url = $self->apache->unparsed_uri;
+    $url =~ s/update_username/prefs/;
+
+    return $self->generic_redirect($url);
+}
+
+sub load_myopac_update_password {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+
+    return Apache2::Const::OK 
+        unless $self->cgi->request_method eq 'POST';
+
+    my $current_pw = $self->cgi->param('current_pw') || '';
+    my $new_pw = $self->cgi->param('new_pw') || '';
+    my $new_pw2 = $self->cgi->param('new_pw2') || '';
+
+    unless($new_pw eq $new_pw2) {
+        $ctx->{password_nomatch} = 1;
+        return Apache2::Const::OK;
+    }
+
+    my $pw_regex = $ctx->{get_org_setting}->($e->requestor->home_ou, 'global.password_regex');
+
+    if($pw_regex and $new_pw !~ /$pw_regex/) {
+        $ctx->{password_invalid} = 1;
+        return Apache2::Const::OK;
+    }
+
+    my $evt = $U->simplereq(
+        'open-ils.actor', 
+        'open-ils.actor.user.password.update', 
+        $e->authtoken, $new_pw, $current_pw);
+
+
+    if($U->event_equals($evt, 'INCORRECT_PASSWORD')) {
+        $ctx->{password_incorrect} = 1;
+        return Apache2::Const::OK;
+    }
+
+    my $url = $self->apache->unparsed_uri;
+    $url =~ s/update_password/prefs/;
+
+    return $self->generic_redirect($url);
+}
+
+sub load_myopac_bookbags {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+
+    $e->xact_begin; # replication...
+
+    my $rv = $self->load_mylist;
+    unless($rv eq Apache2::Const::OK) {
+        $e->rollback;
+        return $rv;
+    }
+
+    my $args = {
+        order_by => {cbreb => 'name'},
+        limit => $self->cgi->param('limit') || 10,
+        offset => $self->cgi->param('offset') || 0
+    };
+
+    $ctx->{bookbags} = $e->search_container_biblio_record_entry_bucket([
+        {owner => $self->editor->requestor->id, btype => 'bookbag'},
+        # XXX what to do about the possibility of really large bookbags here?
+        {"flesh" => 1, "flesh_fields" => {"cbreb" => ["items"]}, %$args}
+    ]);
+
+    if(!$ctx->{bookbags}) {
+        $e->rollback;
+        return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
+    }
+    
+    # get unique record IDs
+    my %rec_ids = ();
+    foreach my $bbag (@{$ctx->{bookbags}}) {
+        foreach my $rec_id (
+            map { $_->target_biblio_record_entry } @{$bbag->items}
+        ) {
+            $rec_ids{$rec_id} = 1;
+        }
+    }
+
+    $ctx->{bookbags_marc_xml} = $self->fetch_marc_xml_by_id([keys %rec_ids]);
+
+    $e->rollback;
+    return Apache2::Const::OK;
+}
+
+
+# actions are create, delete, show, hide, rename, add_rec, delete_item
+# CGI is action, list=list_id, add_rec/record=bre_id, del_item=bucket_item_id, name=new_bucket_name
+sub load_myopac_bookbag_update {
+    my ($self, $action, $list_id) = @_;
+    my $e = $self->editor;
+    my $cgi = $self->cgi;
+
+    $action ||= $cgi->param('action');
+    $list_id ||= $cgi->param('list');
+
+    my @add_rec = $cgi->param('add_rec') || $cgi->param('record');
+    my @del_item = $cgi->param('del_item');
+    my $shared = $cgi->param('shared');
+    my $name = $cgi->param('name');
+    my $success = 0;
+    my $list;
+
+    if($action eq 'create') {
+        $list = Fieldmapper::container::biblio_record_entry_bucket->new;
+        $list->name($name);
+        $list->owner($e->requestor->id);
+        $list->btype('bookbag');
+        $list->pub($shared ? 't' : 'f');
+        $success = $U->simplereq('open-ils.actor', 
+            'open-ils.actor.container.create', $e->authtoken, 'biblio', $list)
+
+    } else {
+
+        $list = $e->retrieve_container_biblio_record_entry_bucket($list_id);
+
+        return Apache2::Const::HTTP_BAD_REQUEST unless 
+            $list and $list->owner == $e->requestor->id;
+    }
+
+    if($action eq 'delete') {
+        $success = $U->simplereq('open-ils.actor', 
+            'open-ils.actor.container.full_delete', $e->authtoken, 'biblio', $list_id);
+
+    } elsif($action eq 'show') {
+        unless($U->is_true($list->pub)) {
+            $list->pub('t');
+            $success = $U->simplereq('open-ils.actor', 
+                'open-ils.actor.container.update', $e->authtoken, 'biblio', $list);
+        }
+
+    } elsif($action eq 'hide') {
+        if($U->is_true($list->pub)) {
+            $list->pub('f');
+            $success = $U->simplereq('open-ils.actor', 
+                'open-ils.actor.container.update', $e->authtoken, 'biblio', $list);
+        }
+
+    } elsif($action eq 'rename') {
+        if($name) {
+            $list->name($name);
+            $success = $U->simplereq('open-ils.actor', 
+                'open-ils.actor.container.update', $e->authtoken, 'biblio', $list);
+        }
+
+    } elsif($action eq 'add_rec') {
+        foreach my $add_rec (@add_rec) {
+            my $item = Fieldmapper::container::biblio_record_entry_bucket_item->new;
+            $item->bucket($list_id);
+            $item->target_biblio_record_entry($add_rec);
+            $success = $U->simplereq('open-ils.actor', 
+                'open-ils.actor.container.item.create', $e->authtoken, 'biblio', $item);
+            last unless $success;
+        }
+
+    } elsif($action eq 'del_item') {
+        foreach (@del_item) {
+            $success = $U->simplereq(
+                'open-ils.actor',
+                'open-ils.actor.container.item.delete', $e->authtoken, 'biblio', $_
+            );
+            last unless $success;
+        }
+    }
+
+    return $self->generic_redirect if $success;
+
+    $self->ctx->{bucket_action} = $action;
+    $self->ctx->{bucket_action_failed} = 1;
+    return Apache2::Const::OK;
+}
+
+1
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Container.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Container.pm
new file mode 100644 (file)
index 0000000..7f87104
--- /dev/null
@@ -0,0 +1,130 @@
+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;
+my $U = 'OpenILS::Application::AppUtils';
+
+use constant COOKIE_ANON_CACHE => 'anoncache';
+use constant ANON_CACHE_MYLIST => 'mylist';
+
+# Retrieve the users cached records AKA 'My List'
+# Returns an empty list if there are no cached records
+sub fetch_mylist {
+    my ($self, $with_marc_xml) = @_;
+
+    my $list = [];
+    my $cache_key = $self->cgi->cookie(COOKIE_ANON_CACHE);
+
+    if($cache_key) {
+
+        $list = $U->simplereq(
+            'open-ils.actor',
+            'open-ils.actor.anon_cache.get_value', 
+            $cache_key, ANON_CACHE_MYLIST);
+
+        if(!$list) {
+            $cache_key = undef;
+            $list = [];
+        }
+    }
+
+    my $marc_xml;
+    if ($with_marc_xml) {
+        $marc_xml = $self->fetch_marc_xml_by_id($list);
+    }
+
+    return ($cache_key, $list, $marc_xml);
+}
+
+
+# Adds a record (by id) to My List, creating a new anon cache + list if necessary.
+sub load_mylist_add {
+    my $self = shift;
+    my $rec_id = $self->cgi->param('record');
+
+    my ($cache_key, $list) = $self->fetch_mylist;
+    push(@$list, $rec_id);
+
+    $cache_key = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.anon_cache.set_value', 
+        $cache_key, ANON_CACHE_MYLIST, $list);
+
+    return $self->mylist_action_redirect($cache_key);
+}
+
+# Removes a record ID from My List, or moves to an actual bookbag
+sub load_mylist_move {
+    my $self = shift;
+    my @rec_ids = $self->cgi->param('record');
+
+    my ($cache_key, $list) = $self->fetch_mylist;
+    return $self->mylist_action_redirect unless $cache_key;
+
+    my @keep;
+    foreach my $id (@$list) { push(@keep, $id) unless grep { $id eq $_ } @rec_ids; }
+
+    $cache_key = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.anon_cache.set_value', 
+        $cache_key, ANON_CACHE_MYLIST, \@keep
+    );
+
+    if ($self->ctx->{user} and $self->cgi->param('action') =~ /^\d+$/) {
+        # in this case, action becomes list_id
+        $self->load_myopac_bookbag_update('add_rec', $self->cgi->param('action'));
+        # XXX TODO: test for failure of above
+    }
+
+    return $self->mylist_action_redirect($cache_key);
+}
+
+sub load_cache_clear {
+    my $self = shift;
+    $self->clear_anon_cache;
+    return $self->mylist_action_redirect;
+}
+
+# Wipes the entire anonymous cache, including My List
+sub clear_anon_cache {
+    my $self = shift;
+    my $field = shift;
+
+    my $cache_key = $self->cgi->cookie(COOKIE_ANON_CACHE) or return;
+
+    $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.anon_cache.delete_session', $cache_key)
+        if $cache_key;
+
+}
+
+# Called after an anon-cache / My List action occurs.  Redirect
+# to the redirect_url (cgi param) or referrer or home.
+sub mylist_action_redirect {
+    my $self = shift;
+    my $cache_key = shift;
+
+    return $self->generic_redirect(
+        undef, 
+        $self->cgi->cookie(
+            -name => COOKIE_ANON_CACHE,
+            -path => '/',
+            -value => ($cache_key) ? $cache_key : '',
+            -expires => ($cache_key) ? undef : '-1h'
+        )
+    );
+}
+
+sub load_mylist {
+    my ($self) = shift;
+    (undef, $self->ctx->{mylist}, $self->ctx->{mylist_marc_xml}) =
+        $self->fetch_mylist(1);
+
+    return Apache2::Const::OK;
+}
+
+1;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm
new file mode 100644 (file)
index 0000000..02fd651
--- /dev/null
@@ -0,0 +1,201 @@
+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;
+my $U = 'OpenILS::Application::AppUtils';
+
+# context additions: 
+#   record : bre object
+sub load_record {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    $ctx->{page} = 'record';
+
+    my $org = $self->cgi->param('loc') || $ctx->{aou_tree}->()->id;
+    my $depth = $self->cgi->param('depth') || 0;
+    my $copy_limit = int($self->cgi->param('copy_limit') || 10);
+    my $copy_offset = int($self->cgi->param('copy_offset') || 0);
+
+    my $rec_id = $ctx->{page_args}->[0]
+        or return Apache2::Const::HTTP_BAD_REQUEST;
+
+    # run copy retrieval in parallel to bib retrieval
+    # XXX unapi
+    my $copy_rec = OpenSRF::AppSession->create('open-ils.cstore')->request(
+        'open-ils.cstore.json_query.atomic', 
+        $self->mk_copy_query($rec_id, $org, $depth, $copy_limit, $copy_offset));
+
+    my (undef, @rec_data) = $self->get_records_and_facets([$rec_id], undef, {flesh => '{holdings_xml,mra}'});
+    $ctx->{bre_id} = $rec_data[0]->{id};
+    $ctx->{marc_xml} = $rec_data[0]->{marc_xml};
+
+    $ctx->{copies} = $copy_rec->gather(1);
+    $ctx->{copy_limit} = $copy_limit;
+    $ctx->{copy_offset} = $copy_offset;
+
+    $ctx->{have_holdings_to_show} = 0;
+    $self->get_hold_copy_summary($rec_id, $org);
+
+    # XXX TODO we'll also need conditional logic to show MFHD-based holdings
+    if (
+        $ctx->{get_org_setting}->
+            ($org, "opac.fully_compressed_serial_holdings")
+    ) {
+        $ctx->{holding_summaries} =
+            $self->get_holding_summaries($rec_id, $org, $depth);
+
+        $ctx->{have_holdings_to_show} =
+            scalar(@{$ctx->{holding_summaries}->{basic}}) ||
+            scalar(@{$ctx->{holding_summaries}->{index}}) ||
+            scalar(@{$ctx->{holding_summaries}->{supplement}});
+    }
+
+    for my $expand ($self->cgi->param('expand')) {
+        $ctx->{"expand_$expand"} = 1;
+        if ($expand eq 'marchtml') {
+            $ctx->{marchtml} = $self->mk_marc_html($rec_id);
+        } elsif ($expand eq 'issues' and $ctx->{have_holdings_to_show}) {
+            $ctx->{expanded_holdings} =
+                $self->get_expanded_holdings($rec_id, $org, $depth);
+        }
+    }
+
+    return Apache2::Const::OK;
+}
+
+sub mk_copy_query {
+    my $self = shift;
+    my $rec_id = shift;
+    my $org = shift;
+    my $depth = shift;
+    my $copy_limit = shift;
+    my $copy_offset = shift;
+
+    my $query = {
+        select => {
+            acp => ['id', 'barcode', 'circ_lib', 'create_date', 'age_protect', 'holdable'],
+            acpl => [
+                {column => 'name', alias => 'copy_location'},
+                {column => 'holdable', alias => 'location_holdable'}
+            ],
+            ccs => [
+                {column => 'name', alias => 'copy_status'},
+                {column => 'holdable', alias => 'status_holdable'}
+            ],
+            acn => [
+                {column => 'label', alias => 'call_number_label'},
+                {column => 'id', alias => 'call_number'}
+            ],
+            circ => ['due_date'],
+        },
+        from => {
+            acp => {
+                acn => {},
+                acpl => {},
+                ccs => {},
+                circ => {type => 'left'},
+                aou => {}
+            }
+        },
+        where => {
+            '+acp' => {
+                deleted => 'f',
+                call_number => {
+                    in => {
+                        select => {acn => ['id']},
+                        from => 'acn',
+                        where => {record => $rec_id}
+                    }
+                },
+                circ_lib => {
+                    in => {
+                        select => {aou => [{
+                            column => 'id', 
+                            transform => 'actor.org_unit_descendants', 
+                            result_field => 'id', 
+                            params => [$depth]
+                        }]},
+                        from => 'aou',
+                        where => {id => $org}
+                    }
+                }
+            },
+            '+acn' => {deleted => 'f'},
+            '+circ' => {checkin_time => undef}
+        },
+
+        # Order is: copies with circ_lib=org, followed by circ_lib name, followed by call_number label
+        order_by => [
+            {class => 'aou', field => 'name'}, 
+            {class => 'acn', field => 'label'}
+        ],
+
+        limit => $copy_limit,
+        offset => $copy_offset
+    };
+
+    # Filter hidden items if this is the public catalog
+    unless($self->ctx->{is_staff}) { 
+        $query->{where}->{'+acp'}->{opac_visible} = 't';
+        $query->{where}->{'+acpl'}->{opac_visible} = 't';
+        $query->{where}->{'+ccs'}->{opac_visible} = 't';
+    }
+
+    return $query;
+    #return $self->editor->json_query($query);
+}
+
+sub mk_marc_html {
+    my($self, $rec_id) = @_;
+
+    # could be optimized considerably by performing the xslt on the already fetched record
+    return $U->simplereq(
+        'open-ils.search', 
+        'open-ils.search.biblio.record.html', $rec_id, 1);
+}
+
+sub get_holding_summaries {
+    my ($self, $rec_id, $org, $depth) = @_;
+
+    return (
+        create OpenSRF::AppSession("open-ils.serial")->request(
+            "open-ils.serial.bib.summary_statements",
+            $rec_id, {"org_id" => $org, "depth" => $depth}
+        )->gather(1)
+    );
+}
+
+sub get_expanded_holdings {
+    my ($self, $rec_id, $org, $depth) = @_;
+
+    my $holding_limit = int($self->cgi->param("holding_limit") || 10);
+    my $holding_offset = int($self->cgi->param("holding_offset") || 0);
+    my $type = $self->cgi->param("expand_holding_type");
+
+    return create OpenSRF::AppSession("open-ils.serial")->request(
+        "open-ils.serial.received_siss.retrieve.by_bib.atomic",
+        $rec_id, {
+            "ou" => $org, "depth" => $depth,
+            "limit" => $holding_limit, "offset" => $holding_offset,
+            "type" => $type
+        }
+    )->gather(1);
+}
+
+
+sub get_hold_copy_summary {
+    my ($self, $rec_id, $org) = @_;
+    
+    my $req1 = OpenSRF::AppSession->create('open-ils.search')->request(
+        'open-ils.search.biblio.record.copy_count', $org, $rec_id); 
+
+    $self->ctx->{record_hold_count} = $U->simplereq(
+        'open-ils.circ', 'open-ils.circ.bre.holds.count', $rec_id);
+
+    $self->ctx->{copy_summary} = $req1->recv->content;
+}
+
+1;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
new file mode 100644 (file)
index 0000000..787228c
--- /dev/null
@@ -0,0 +1,201 @@
+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 OpenSRF::Utils::JSON;
+my $U = 'OpenILS::Application::AppUtils';
+
+
+sub _prepare_biblio_search_basics {
+    my ($cgi) = @_;
+
+    return $cgi->param('query') unless $cgi->param('qtype');
+
+    my %parts;
+    my @part_names = qw/qtype contains query/;
+    $parts{$_} = [ $cgi->param($_) ] for (@part_names);
+
+    my @chunks = ();
+    for (my $i = 0; $i < scalar @{$parts{'qtype'}}; $i++) {
+        my ($qtype, $contains, $query) = map { $parts{$_}->[$i] } @part_names;
+
+        next unless $query =~ /\S/;
+        push(@chunks, $qtype . ':') unless $qtype eq 'keyword' and $i == 0;
+
+        # This stuff probably will need refined or rethought to better handle
+        # the weird things Real Users will surely type in.
+        $contains = "" unless defined $contains; # silence warning
+        if ($contains eq 'nocontains') {
+            $query =~ s/"//g;
+            $query = ('"' . $query . '"') if index $query, ' ';
+            $query = '-' . $query;
+        } elsif ($contains eq 'phrase') {
+            $query =~ s/"//g;
+            $query = ('"' . $query . '"') if index $query, ' ';
+        } elsif ($contains eq 'exact') {
+            $query =~ s/[\^\$]//g;
+            $query = '^' . $query . '$';
+        }
+        push @chunks, $query;
+    }
+
+    return join(' ', @chunks);
+}
+
+sub _prepare_biblio_search {
+    my ($cgi, $ctx) = @_;
+
+    my $query = _prepare_biblio_search_basics($cgi);
+
+    $query = ('#' . $_ . ' ' . $query) foreach ($cgi->param('modifier'));
+
+    # filters
+    foreach (grep /^fi:/, $cgi->param) {
+        /:(-?\w+)$/ or next;
+        my $term = join(",", $cgi->param($_));
+        $query .= " $1($term)" if length $term;
+    }
+
+    if ($cgi->param('sort')) {
+        my ($axis, $desc) = split /\./, $cgi->param('sort');
+        $query .= " sort($axis)";
+        $query .= '#descending' if $desc;
+    }
+
+    if ($cgi->param('pubdate') && $cgi->param('date1')) {
+        if ($cgi->param('pubdate') eq 'between') {
+            $query .= ' between(' . $cgi->param('date1');
+            $query .= ',' .  $cgi->param('date2') if $cgi->param('date2');
+            $query .= ')';
+        } elsif ($cgi->param('pubdate') eq 'is') {
+            $query .= ' between(' . $cgi->param('date1') .
+                ',' .  $cgi->param('date1') . ')';  # sic, date1 twice
+        } else {
+            $query .= ' ' . $cgi->param('pubdate') .
+                '(' . $cgi->param('date1') . ')';
+        }
+    }
+
+    my $site;
+    my $org = $cgi->param('loc');
+    if (defined($org) and $org ne '' and ($org ne $ctx->{aou_tree}->()->id) and not $query =~ /site\(\S+\)/) {
+        $site = $ctx->{get_aou}->($org)->shortname;
+        $query .= " site($site)";
+    }
+
+    if(!$site) {
+        ($site) = ($query =~ /site\(([^\)]+)\)/);
+        $site ||= $ctx->{aou_tree}->()->shortname;
+    }
+
+
+    my $depth;
+    if (defined($cgi->param('depth')) and not $query =~ /depth\(\d+\)/) {
+        $depth = defined $cgi->param('depth') ?
+            $cgi->param('depth') : $ctx->{get_aou}->($site)->ou_type->depth;
+        $query .= " depth($depth)";
+    }
+
+    return ($query, $site, $depth);
+}
+
+sub _get_search_limit {
+    my $self = shift;
+
+    # param takes precedence
+    my $limit = $self->cgi->param('limit');
+    return $limit if $limit;
+
+    if($self->editor->requestor) {
+        # See if the user has a hit count preference
+        my $lset = $self->editor->search_actor_user_setting({
+            usr => $self->editor->requestor->id, 
+            name => 'opac.hits_per_page'
+        })->[0];
+        return OpenSRF::Utils::JSON->JSON2perl($lset->value) if $lset;
+    }
+
+    return 10; # default
+}
+
+# context additions: 
+#   page_size
+#   hit_count
+#   records : list of bre's and copy-count objects
+sub load_rresults {
+    my $self = shift;
+    my $cgi = $self->cgi;
+    my $ctx = $self->ctx;
+    my $e = $self->editor;
+
+    $ctx->{page} = 'rresult';
+    my $page = $cgi->param('page') || 0;
+    my $facet = $cgi->param('facet');
+    my $limit = $self->_get_search_limit;
+    my $loc = $cgi->param('loc');
+    my $offset = $page * $limit;
+
+    my ($query, $site, $depth) = _prepare_biblio_search($cgi, $ctx);
+
+    return $self->generic_redirect unless $query;
+
+    # Limit and offset will stay here. Everything else should be part of
+    # the query string, not special args.
+    my $args = {'limit' => $limit, 'offset' => $offset};
+
+    # Stuff these into the TT context so that templates can use them in redrawing forms
+    $ctx->{processed_search_query} = $query;
+
+    $query = "$query $facet" if $facet; # TODO
+
+    $logger->activity("EGWeb: [search] $query");
+
+    my $results;
+
+    try {
+
+        my $method = 'open-ils.search.biblio.multiclass.query';
+        $method .= '.staff' if $ctx->{is_staff};
+        $results = $U->simplereq('open-ils.search', $method, $args, $query, 1);
+
+    } catch Error with {
+        my $err = shift;
+        $logger->error("multiclass search error: $err");
+        $results = {count => 0, ids => []};
+    };
+
+    my $rec_ids = [map { $_->[0] } @{$results->{ids}}];
+
+    $ctx->{records} = [];
+    $ctx->{search_facets} = {};
+    $ctx->{page_size} = $limit;
+    $ctx->{hit_count} = $results->{count};
+
+    return Apache2::Const::OK if @$rec_ids == 0;
+
+    my ($facets, @data) = $self->get_records_and_facets(
+        $rec_ids, $results->{facet_key}, 
+        {
+            flesh => '{holdings_xml,mra}',
+            site => $site,
+            depth => $depth
+        }
+    );
+
+    # shove recs into context in search results order
+    for my $rec_id (@$rec_ids) {
+        push(
+            @{$ctx->{records}},
+            grep { $_->{id} == $rec_id } @data
+        );
+    }
+
+    $ctx->{search_facets} = $facets;
+
+    return Apache2::Const::OK;
+}
+
+1;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
new file mode 100644 (file)
index 0000000..8b12453
--- /dev/null
@@ -0,0 +1,247 @@
+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 OpenSRF::MultiSession;
+my $U = 'OpenILS::Application::AppUtils';
+
+my $ro_object_subs; # cached subs
+our %cache = ( # cached data
+    map => {aou => {}}, # others added dynamically as needed
+    list => {},
+    search => {},
+    org_settings => {}
+);
+
+sub init_ro_object_cache {
+    my $self = shift;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+
+    if($ro_object_subs) {
+        # subs have been built.  insert into the context then move along.
+        $ctx->{$_} = $ro_object_subs->{$_} for keys %$ro_object_subs;
+        return;
+    }
+
+    # make all "field_safe" classes accesible by default in the template context
+    my @classes = grep {
+        ($Fieldmapper::fieldmap->{$_}->{field_safe} || '') =~ /true/i
+    } keys %{ $Fieldmapper::fieldmap };
+
+    for my $class (@classes) {
+
+        my $hint = $Fieldmapper::fieldmap->{$class}->{hint};
+        next if $hint eq 'aou'; # handled separately
+
+        my $ident_field =  $Fieldmapper::fieldmap->{$class}->{identity};
+        (my $eclass = $class) =~ s/Fieldmapper:://o;
+        $eclass =~ s/::/_/g;
+
+        my $list_key = "${hint}_list";
+        my $get_key = "get_$hint";
+        my $search_key = "search_$hint";
+
+        # Retrieve the full set of objects with class $hint
+        $ro_object_subs->{$list_key} = sub {
+            my $method = "retrieve_all_$eclass";
+            $cache{list}{$hint} = $e->$method() unless $cache{list}{$hint};
+            return $cache{list}{$hint};
+        };
+    
+        # locate object of class $hint with Ident field $id
+        $cache{map}{$hint} = {};
+        $ro_object_subs->{$get_key} = sub {
+            my $id = shift;
+            return $cache{map}{$hint}{$id} if $cache{map}{$hint}{$id}; 
+            ($cache{map}{$hint}{$id}) = grep { $_->$ident_field eq $id } @{$ro_object_subs->{$list_key}->()};
+            return $cache{map}{$hint}{$id};
+        };
+
+        # search for objects of class $hint where field=value
+        $cache{search}{$hint} = {};
+        $ro_object_subs->{$search_key} = sub {
+            my ($field, $val) = @_;
+            my $method = "search_$eclass";
+            $cache{search}{$hint}{$field} = {} unless $cache{search}{$hint}{$field};
+            $cache{search}{$hint}{$field}{$val} = $e->$method({$field => $val}) 
+                unless $cache{search}{$hint}{$field}{$val};
+            return $cache{search}{$hint}{$field}{$val};
+        };
+    }
+
+    $ro_object_subs->{aou_tree} = sub {
+
+        # fetch the org unit tree
+        unless($cache{aou_tree}) {
+            my $tree = $e->search_actor_org_unit([
+                           {   parent_ou => undef},
+                           {   flesh            => -1,
+                                   flesh_fields    => {aou =>  ['children']},
+                                   order_by        => {aou => 'name'}
+                           }
+                   ])->[0];
+
+            # flesh the org unit type for each org unit
+            # and simultaneously set the id => aou map cache
+            sub flesh_aout {
+                my $node = shift;
+                my $ro_object_subs = shift;
+                $node->ou_type( $ro_object_subs->{get_aout}->($node->ou_type) );
+                $cache{map}{aou}{$node->id} = $node;
+                flesh_aout($_, $ro_object_subs) foreach @{$node->children};
+            };
+            flesh_aout($tree, $ro_object_subs);
+
+            $cache{aou_tree} = $tree;
+        }
+
+        return $cache{aou_tree};
+    };
+
+    # Add a special handler for the tree-shaped org unit cache
+    $ro_object_subs->{get_aou} = sub {
+        my $org_id = shift;
+        $ro_object_subs->{aou_tree}->(); # force the org tree to load
+        return $cache{map}{aou}{$org_id};
+    };
+
+    # turns an ISO date into something TT can understand
+    $ro_object_subs->{parse_datetime} = sub {
+        my $date = shift;
+        $date = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($date));
+        return sprintf(
+            "%0.2d:%0.2d:%0.2d %0.2d-%0.2d-%0.4d",
+            $date->hour,
+            $date->minute,
+            $date->second,
+            $date->day,
+            $date->month,
+            $date->year
+        );
+    };
+
+    # retrieve and cache org unit setting values
+    $ro_object_subs->{get_org_setting} = sub {
+        my($org_id, $setting) = @_;
+
+        $cache{org_settings}{$org_id} = {} 
+            unless $cache{org_settings}{$org_id};
+
+        $cache{org_settings}{$org_id}{$setting} = 
+            $U->ou_ancestor_setting_value($org_id, $setting)
+                unless exists $cache{org_settings}{$org_id}{$setting};
+
+        return $cache{org_settings}{$org_id}{$setting};
+    };
+
+    $ctx->{$_} = $ro_object_subs->{$_} for keys %$ro_object_subs;
+}
+
+sub generic_redirect {
+    my $self = shift;
+    my $url = shift;
+    my $cookie = shift; # can be an array of cgi.cookie's
+
+    $self->apache->print(
+        $self->cgi->redirect(
+            -url => $url || 
+                $self->cgi->param('redirect_to') || 
+                $self->ctx->{referer} || 
+                $self->ctx->{home_page},
+            -cookie => $cookie
+        )
+    );
+
+    return Apache2::Const::REDIRECT;
+}
+
+sub get_records_and_facets {
+    my ($self, $rec_ids, $facet_key, $unapi_args) = @_;
+
+    $unapi_args ||= {};
+    $unapi_args->{site} ||= $self->ctx->{aou_tree}->()->shortname;
+    $unapi_args->{depth} ||= $self->ctx->{aou_tree}->()->ou_type->depth;
+    $unapi_args->{flesh_depth} ||= 5;
+
+    my @data;
+    my $ses = OpenSRF::MultiSession->new(
+        app => 'open-ils.cstore',
+        cap => 10, # XXX config
+        success_handler => sub {
+            my($self, $req) = @_;
+            my $data = $req->{response}->[0]->content;
+            my $xml = XML::LibXML->new->parse_string($data->{'unapi.bre'})->documentElement;
+            my $bre_id =  $xml->find('*[@tag="901"]/*[@code="c"]')->[0]->textContent;
+            push(@data, {id => $bre_id, marc_xml => $xml});
+        }
+    );
+
+    $ses->request(
+        'open-ils.cstore.json_query',
+         {from => [
+            'unapi.bre', $_, 'marcxml','record', 
+            $unapi_args->{flesh}, 
+            $unapi_args->{site}, 
+            $unapi_args->{depth}, 
+            $unapi_args->{flesh_depth}, 
+        ]}
+    ) for @$rec_ids;
+
+    # collect the facet data
+    my $search = OpenSRF::AppSession->create('open-ils.search');
+    my $facet_req = $search->request(
+        'open-ils.search.facet_cache.retrieve', $facet_key, 10
+    ) if $facet_key;
+
+    # gather up the unapi recs
+    $ses->session_wait(1);
+
+    my $facets;
+    if ($facet_key) {
+        $facets = $facet_req->gather(1);
+        $facets->{$_} = {
+            cmf => $self->ctx->{get_cmf}->($_),
+            data => $facets->{$_}
+        } for keys %$facets;    # quick-n-dirty
+    } else {
+        $facets = undef;
+    }
+
+    return ($facets, @data);
+}
+
+# TODO: blend this code w/ ^-- get_records_and_facets
+sub fetch_marc_xml_by_id {
+    my ($self, $id_list) = @_;
+    $id_list = [$id_list] unless ref($id_list);
+
+    {
+        no warnings qw/numeric/;
+        $id_list = [map { int $_ } @$id_list];
+        $id_list = [grep { $_ > 0} @$id_list];
+    };
+
+    return {} if scalar(@$id_list) < 1;
+
+    # I'm just sure there needs to be some more efficient way to get all of
+    # this.
+    my $results = $self->editor->json_query({
+        "select" => {"bre" => ["id", "marc"]},
+        "from" => {"bre" => {}},
+        "where" => {"id" => $id_list}
+    }) or return $self->editor->die_event;
+
+    my $marc_xml = {};
+    for my $r (@$results) {
+        $marc_xml->{$r->{"id"}} =
+            (new XML::LibXML)->parse_string($r->{"marc"});
+    }
+
+    return $marc_xml;
+}
+
+1;
index ec765af..b6b4ed2 100644 (file)
@@ -7,6 +7,7 @@ use File::stat;
 use Apache2::Const -compile => qw(OK DECLINED HTTP_INTERNAL_SERVER_ERROR);
 use Apache2::Log;
 use OpenSRF::EX qw(:try);
+use OpenILS::Utils::CStoreEditor;
 
 use constant OILS_HTTP_COOKIE_SKIN => 'oils:skin';
 use constant OILS_HTTP_COOKIE_THEME => 'oils:theme';
@@ -15,12 +16,13 @@ use constant OILS_HTTP_COOKIE_LOCALE => 'oils:locale';
 my $web_config;
 my $web_config_file;
 my $web_config_edit_time;
+my %lh_cache; # locale handlers
 
 sub import {
     my $self = shift;
     $web_config_file = shift || '';
     unless(-r $web_config_file) {
-        warn "Invalid web config $web_config_file";
+        warn "Invalid web config $web_config_file\n";
         return;
     }
     check_web_config();
@@ -32,26 +34,80 @@ sub handler {
     check_web_config($r); # option to disable this
     my $ctx = load_context($r);
     my $base = $ctx->{base_path};
+
+    $r->content_type('text/html; encoding=utf8');
+
     my($template, $page_args, $as_xml) = find_template($r, $base, $ctx);
+    $ctx->{page_args} = $page_args;
+
+    my $stat = run_context_loader($r, $ctx);
+
+    return $stat unless $stat == Apache2::Const::OK;
     return Apache2::Const::DECLINED unless $template;
 
     $template = $ctx->{skin} . "/$template";
-    $ctx->{page_args} = $page_args;
-    $r->content_type('text/html; encoding=utf8');
 
     my $tt = Template->new({
         OUTPUT => ($as_xml) ?  sub { parse_as_xml($r, $ctx, @_); } : $r,
         INCLUDE_PATH => $ctx->{template_paths},
+        DEBUG => $ctx->{debug_template},
+        PLUGINS => {
+            EGI18N => 'OpenILS::WWW::EGWeb::I18NFilter',
+            CGI_utf8 => 'OpenILS::WWW::EGWeb::CGI_utf8'
+        }
     });
 
-    unless($tt->process($template, {ctx => $ctx})) {
-        $r->log->warn('Template error: ' . $tt->error);
+    unless($tt->process($template, {ctx => $ctx, ENV => \%ENV, l => set_text_handler($ctx, $r)})) {
+        $r->log->warn('egweb: template error: ' . $tt->error);
         return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
     }
 
     return Apache2::Const::OK;
 }
 
+sub set_text_handler {
+    my $ctx = shift;
+    my $r = shift;
+
+    my $locale = $ctx->{locale};
+    $locale =~ s/-/_/g;
+
+    $r->log->debug("egweb: messages locale = $locale");
+
+    unless($lh_cache{$locale}) {
+        $r->log->info("egweb: Unsupported locale: $locale");
+        $lh_cache{$locale} = $lh_cache{'en_US'};
+    }
+
+    return $OpenILS::WWW::EGWeb::I18NFilter::maketext = 
+        sub { return $lh_cache{$locale}->maketext(@_); };
+}
+
+
+
+sub run_context_loader {
+    my $r = shift;
+    my $ctx = shift;
+
+    my $stat = Apache2::Const::OK;
+
+    my $loader = $r->dir_config('OILSWebContextLoader');
+    return $stat unless $loader;
+
+    eval {
+        $loader->use;
+        $stat = $loader->new($r, $ctx)->load;
+    };
+
+    if($@) {
+        $r->log->error("egweb: Context Loader error: $@");
+        return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    $r->log->debug("egweb: context loader resulted in status $stat");
+    return $stat;
+}
+
 sub parse_as_xml {
     my $r = shift;
     my $ctx = shift;
@@ -65,9 +121,9 @@ sub parse_as_xml {
         $data = $ctx->{final_dtd} . "\n" . $data;
         $success = 1;
     } otherwise {
-       my $e = shift;
+           my $e = shift;
         my $err = "Invalid XML: $e";
-        $r->log->error($err);
+        $r->log->error("egweb: $err");
         $r->content_type('text/plain; encoding=utf8');
         $r->print("\n$err\n\n$data");
     };
@@ -79,16 +135,23 @@ sub parse_as_xml {
 sub load_context {
     my $r = shift;
     my $cgi = CGI->new;
-    my $ctx = $web_config->{ctx};
+    my $ctx = {}; # new context for each page load
+    $ctx->{$_} = $web_config->{base_ctx}->{$_} for keys %{$web_config->{base_ctx}};
     $ctx->{hostname} = $r->hostname;
     $ctx->{base_url} = $cgi->url(-base => 1);
     $ctx->{skin} = $cgi->cookie(OILS_HTTP_COOKIE_SKIN) || 'default';
     $ctx->{theme} = $cgi->cookie(OILS_HTTP_COOKIE_THEME) || 'default';
+
     $ctx->{locale} = 
         $cgi->cookie(OILS_HTTP_COOKIE_LOCALE) || 
         parse_accept_lang($r->headers_in->get('Accept-Language')) || 'en-US';
-    $r->log->debug('skin = ' . $ctx->{skin} . ' : theme = ' . 
-        $ctx->{theme} . ' : locale = ' . $ctx->{locale});
+
+    my $mprefix = $ctx->{media_prefix};
+    if($mprefix and $mprefix !~ /^http/ and $mprefix !~ /^\//) {
+        # if a hostname is provided /w no protocol, match the protocol to the current page
+        $ctx->{media_prefix} = ($cgi->https) ? "https://$mprefix" : "http://$mprefix";
+    }
+
     return $ctx;
 }
 
@@ -146,7 +209,7 @@ sub find_template {
             last unless $localpath;
             for my $tpath (@{$ctx->{template_paths}}) {
                 my $fpath = "$tpath/$skin/$localpath.$ext";
-                $r->log->debug("looking at possible template $fpath");
+                $r->log->debug("egweb: looking at possible template $fpath");
                 if(-r $fpath) {
                     $template = "$localpath.$ext";
                     last;
@@ -161,12 +224,12 @@ sub find_template {
 
         # no template configured or found
         unless($template) {
-            $r->log->warn("No template configured for path $path");
+            $r->log->debug("egweb: No template configured for path $path");
             return ();
         }
     }
 
-    $r->log->debug("template = $template : page args = @$page_args");
+    $r->log->debug("egweb: template = $template : page args = @$page_args");
     return ($template, $page_args, $as_xml);
 }
 
@@ -176,12 +239,46 @@ sub check_web_config {
     my $r = shift;
     my $epoch = stat($web_config_file)->mtime;
     unless($web_config_edit_time and $web_config_edit_time == $epoch) {
-        $r->log->debug("Reloading web config after edit...") if $r;
+        $r->log->debug("egweb: Reloading web config after edit...") if $r;
         $web_config_edit_time = $epoch;
         $web_config = parse_config($web_config_file);
     }
 }
 
+# Create an I18N sub-module for each supported locale
+# Each module creates its own MakeText lexicon by parsing .po/.mo files
+sub load_locale_handlers {
+    my $ctx = shift;
+    my $locales = $ctx->{locales};
+
+    $locales->{en_US} = {} unless exists $locales->{en_US};
+
+    for my $lang (keys %$locales) {
+        my $messages = $locales->{$lang};
+        $messages = '' if ref $messages; # empty {}
+
+        # TODO Can we do this without eval?
+        my $eval = <<EVAL;
+            package OpenILS::WWW::EGWeb::I18N::$lang;
+            use base 'OpenILS::WWW::EGWeb::I18N';
+            if(\$messages) {
+                use Locale::Maketext::Lexicon::Gettext;
+                if(open F, '$messages') {
+                    our %Lexicon = (%Lexicon, %{ Locale::Maketext::Lexicon::Gettext->parse(<F>) });
+                    close F;
+                } else {
+                    warn "EGWeb: unable to open messages file: $messages"; 
+                }
+            }
+EVAL
+        eval $eval;
+        warn "$@\n" if $@; # TODO better logging
+        $lh_cache{$lang} = "OpenILS::WWW::EGWeb::I18N::$lang"->new;
+    }
+}
+
+
+
 sub parse_config {
     my $cfg_file = shift;
     my $data = XML::Simple->new->XMLin($cfg_file);
@@ -191,9 +288,12 @@ sub parse_config {
     $ctx->{media_prefix} = (ref $data->{media_prefix}) ? '' : $data->{media_prefix};
     $ctx->{base_path} = (ref $data->{base_path}) ? '' : $data->{base_path};
     $ctx->{template_paths} = [];
-    $ctx->{force_valid_xml} = ($data->{force_valid_xml} =~ /true/io) ? 1 : 0;
+    $ctx->{force_valid_xml} = ( ($data->{force_valid_xml}||'') =~ /true/io) ? 1 : 0;
+    $ctx->{debug_template} = ( ($data->{debug_template}||'')  =~ /true/io) ? 1 : 0;
     $ctx->{default_template_extension} = $data->{default_template_extension} || 'tt2';
     $ctx->{web_dir} = $data->{web_dir};
+    $ctx->{locales} = $data->{locales};
+    load_locale_handlers($ctx);
 
     my $tpaths = $data->{template_paths}->{path};
     $tpaths = [$tpaths] unless ref $tpaths;
@@ -217,7 +317,7 @@ sub parse_config {
         }
     }
 
-    return {ctx => $ctx, handlers => $handlers};
+    return {base_ctx => $ctx, handlers => $handlers};
 }
 
 package PathConfig;
@@ -226,5 +326,9 @@ sub new {
     return bless(\%args, $class);
 }
 
+# base class for all supported locales
+package OpenILS::WWW::EGWeb::I18N;
+use base 'Locale::Maketext';
+our %Lexicon = (_AUTO => 1);
 
 1;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb/CGI_utf8.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb/CGI_utf8.pm
new file mode 100644 (file)
index 0000000..0239e1b
--- /dev/null
@@ -0,0 +1,44 @@
+package OpenILS::WWW::EGWeb::CGI_utf8;
+
+# The code in this module is copied from (except for a tiny modification)
+# Template::Plugin::CGI, which is written by:
+#
+# Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
+#
+# Copyright (C) 1996-2007 Andy Wardley.  All Rights Reserved.
+#
+# This module is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+
+use strict;
+use warnings;
+use base 'Template::Plugin';
+use CGI qw(:all -utf8);
+
+sub new {
+    my $class   = shift;
+    my $context = shift;
+    new CGI(@_);
+}
+
+# monkeypatch CGI::params() method to Do The Right Thing in TT land
+
+sub CGI::params {
+    my $self = shift;
+    local $" = ', ';
+
+    return $self->{ _TT_PARAMS } ||= do {
+        # must call Vars() in a list context to receive
+        # plain list of key/vals rather than a tied hash
+        my $params = { $self->Vars() };
+
+        # convert any null separated values into lists
+        @$params{ keys %$params } = map { 
+            /\0/ ? [ split /\0/ ] : $_ 
+        } values %$params;
+
+        $params;
+    };
+}
+
+1;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb/I18NFilter.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb/I18NFilter.pm
new file mode 100644 (file)
index 0000000..cc931fa
--- /dev/null
@@ -0,0 +1,19 @@
+package OpenILS::WWW::EGWeb::I18NFilter;
+use Template::Plugin::Filter;
+use base qw(Template::Plugin::Filter);
+our $DYNAMIC = 1;
+our $maketext;
+
+sub filter {
+    my ($self, $text, $args) = @_;
+    return $maketext->($text, @$args);
+}
+
+sub init {
+    my $self = shift;
+    $self->install_filter('l');
+    return $self;
+}
+
+1;
+
diff --git a/Open-ILS/src/support-scripts/test-scripts/unapi_bench.pl b/Open-ILS/src/support-scripts/test-scripts/unapi_bench.pl
new file mode 100755 (executable)
index 0000000..5b38b28
--- /dev/null
@@ -0,0 +1,336 @@
+#!/usr/bin/perl
+require '../oils_header.pl';
+use strict; use warnings;
+use Time::HiRes qw/time usleep/;
+use Data::Dumper;
+use OpenSRF::Utils::JSON;
+use OpenILS::Utils::CStoreEditor;
+use XML::LibXML;
+
+#-----------------------------------------------------------------------------
+# Does a checkout, renew, and checkin 
+#-----------------------------------------------------------------------------
+
+my @recs = (1,2,3,4,5,6,7,8,9,10);
+
+osrf_connect(shift() || '/openils/conf/opensrf_core.xml');
+
+my $e = OpenILS::Utils::CStoreEditor->new;
+
+sub xptext {
+    my($node, $path) = @_;
+    #my $res = $node->findnodes($path);
+    my $res = $node->find($path);
+    return '' unless $res and $res->[0];
+    return $res->[0]->textContent;
+}
+
+sub get_bib_attrs {
+    my $xml = shift;
+    return {
+        isbn => xptext($xml, '*[@tag="020"]/*[@code="a"]'),
+        upc => xptext($xml,'*[@tag="024"]/*[@code="a"]'),
+        issn => xptext($xml,'*[@tag="022"]/*[@code="a"]'),
+        title => xptext($xml,'*[@tag="245"]/*[@code="a"]'),
+        author => xptext($xml,'*[@tag="100"]/*[@code="a"]'),
+        publisher => xptext($xml,'*[@tag="260"]/*[@code="b"]'),
+        pubdate => xptext($xml,'*[@tag="260"]/*[@code="c"]'),
+        edition => xptext($xml,'*[@tag="250"]/*[@code="a"]'),
+    };
+}
+
+sub unapi {
+    my @recs = @_;
+    my $start = time();
+
+    my $ses1 = OpenSRF::AppSession->create('open-ils.cstore');
+    my $ses2 = OpenSRF::AppSession->create('open-ils.cstore');
+    my $ses3 = OpenSRF::AppSession->create('open-ils.cstore');
+    my ($req1, $req2, $req3);
+
+    my %records;
+    while(@recs) {
+        my ($id1, $id2, $id3) = (pop @recs, pop @recs, pop @recs);
+
+        for my $r ($req1, $req2, $req3) {
+            if($r) {
+                my $data = $r->gather(1);
+                my $xml = XML::LibXML->new->parse_string($data->{'unapi.bre'});
+                $xml = $xml->documentElement;
+                my $attrs = get_bib_attrs($xml);
+                my $rec_id =  xptext($xml,'*[@tag="901"]/*[@code="c"]');
+                $records{$rec_id}{$_} = $attrs->{$_} for keys %$attrs;
+
+                my $rvols = [];
+                for my $volnode ($xml->findnodes('//*[local-name()="volumes"]/*[local-name()="volume"]')) {
+                    my $vol = {}; 
+                    $vol->{copies} = [];
+                    $vol->{label} = $volnode->getAttribute('label');
+                    for my $copynode ($volnode->getElementsByLocalName('copy')) {
+                        my $copy = {};   
+                        $copy->{barcode} = $copynode->getAttribute('barcode');
+                        push(@{$vol->{copies}}, $copy);
+                    }
+                    push(@{$records{$rec_id}->{volumes}}, $vol);
+                }
+
+            }
+        }
+
+        $req1 = ($id1) ? $ses1->request('open-ils.cstore.json_query', {from => ['unapi.bre', $id1, 'marcxml', 'record', '{holdings_xml,acp}', 'CONS']}) : undef;
+        $req2 = ($id2) ? $ses1->request('open-ils.cstore.json_query', {from => ['unapi.bre', $id2, 'marcxml', 'record', '{holdings_xml,acp}', 'CONS']}) : undef;
+        $req3 = ($id3) ? $ses1->request('open-ils.cstore.json_query', {from => ['unapi.bre', $id3, 'marcxml', 'record', '{holdings_xml,acp}', 'CONS']}) : undef;
+    }
+
+
+    for my $r ($req1, $req2, $req3) {
+        if($r) {
+            my $data = $r->gather(1);
+            my $xml = XML::LibXML->new->parse_string($data->{'unapi.bre'});
+            $xml = $xml->documentElement;
+            my $attrs = get_bib_attrs($xml);
+            my $rec_id =  xptext($xml,'*[@tag="901"]/*[@code="c"]');
+            $records{$rec_id}{$_} = $attrs->{$_} for keys %$attrs;
+
+            my $rvols = [];
+            for my $volnode ($xml->findnodes('//*[local-name()="volumes"]/*[local-name()="volume"]')) {
+                my $vol = {}; 
+                $vol->{copies} = [];
+                $vol->{label} = $volnode->getAttribute('label');
+                for my $copynode ($volnode->getElementsByLocalName('copy')) {
+                    my $copy = {};   
+                    $copy->{barcode} = $copynode->getAttribute('barcode');
+                    push(@{$vol->{copies}}, $copy);
+                }
+                push(@{$records{$rec_id}->{volumes}}, $vol);
+            }
+
+        }
+    }
+
+    my $duration = time() - $start;
+
+    for my $rec_id (keys %records) {
+        my $rec = $records{$rec_id};
+        print sprintf("%d [%s] has %d volumes and %d copies\n",
+            $rec_id, $rec->{title}, 
+            scalar(@{$rec->{volumes}}),
+            scalar(map { @{$_->{copies}} } @{$rec->{volumes}}));
+    }
+
+    #note, unapi.biblio_record_entry_feed per record performs the same as unapi.bre pre record
+    print "\nunapi 'unapi.bre' duration is $duration\n\n";
+}
+
+sub unapi_spread {
+    my @recs = @_;
+    my %records;
+    my $start = time();
+
+    my @reqs;
+    for my $rec_id (@recs) {
+
+        my $ses = OpenSRF::AppSession->create('open-ils.cstore');
+        my $req = $ses->request(
+            'open-ils.cstore.json_query', 
+            {from => ['unapi.bre', $rec_id, 'marcxml', 'record', '{holdings_xml,acp}', 'CONS']});
+
+        push(@reqs, $req);
+    }
+
+    for my $req (@reqs) {
+
+        my $data = $req->gather(1);
+        my $xml = XML::LibXML->new->parse_string($data->{'unapi.bre'});
+        $xml = $xml->documentElement;
+        my $attrs = get_bib_attrs($xml);
+        my $rec_id =  xptext($xml,'*[@tag="901"]/*[@code="c"]');
+        $records{$rec_id}{$_} = $attrs->{$_} for keys %$attrs;
+
+        my $rvols = [];
+        for my $volnode ($xml->findnodes('//*[local-name()="volumes"]/*[local-name()="volume"]')) {
+            my $vol = {}; 
+            $vol->{copies} = [];
+            $vol->{label} = $volnode->getAttribute('label');
+            for my $copynode ($volnode->getElementsByLocalName('copy')) {
+                my $copy = {};   
+                $copy->{barcode} = $copynode->getAttribute('barcode');
+                push(@{$vol->{copies}}, $copy);
+            }
+            push(@{$records{$rec_id}->{volumes}}, $vol);
+        }
+    }
+
+    my $duration = time() - $start;
+
+    for my $rec_id (keys %records) {
+        my $rec = $records{$rec_id};
+        print sprintf("%d [%s] has %d volumes and %d copies\n",
+            $rec_id, $rec->{title}, 
+            scalar(@{$rec->{volumes}}),
+            scalar(map { @{$_->{copies}} } @{$rec->{volumes}}));
+    }
+
+    #note, unapi.biblio_record_entry_feed per record performs the same as unapi.bre pre record
+    print "\nunapi 'unapi.bre' spread duration is $duration\n\n";
+}
+
+
+
+sub unapi_batch {
+    my @recs = @_;
+    my $start = time();
+
+    my $data = $e->json_query({from => ['unapi.biblio_record_entry_feed', "{".join(',',@recs)."}", 'marcxml', '{holdings_xml,acp}', 'CONS']})->[0];
+    my $xml = XML::LibXML->new->parse_string($data->{'unapi.biblio_record_entry_feed'});
+
+    my %records;
+    for my $rec_xml ($xml->documentElement->getElementsByLocalName('record')) { 
+
+        my $attrs = get_bib_attrs($rec_xml);
+        my $rec_id =  xptext($rec_xml,'*[@tag="901"]/*[@code="c"]');
+        #print "REC = $rec_xml : $rec_id : " . $attrs->{title} . "\n" . $rec_xml->toString . "\n";
+        $records{$rec_id}{$_} = $attrs->{$_} for keys %$attrs;
+
+        my $rvols = [];
+        for my $volnode ($rec_xml->findnodes('//*[local-name()="volumes"]/*[local-name()="volume"]')) {
+            my $vol = {}; 
+            $vol->{copies} = [];
+            $vol->{label} = $volnode->getAttribute('label');
+            for my $copynode ($volnode->getElementsByLocalName('copy')) {
+                my $copy = {};   
+                $copy->{barcode} = $copynode->getAttribute('barcode');
+                push(@{$vol->{copies}}, $copy);
+            }
+            push(@{$records{$rec_id}->{volumes}}, $vol);
+        }
+    }
+
+    my $duration = time() - $start;
+
+    for my $rec_id (keys %records) {
+        my $rec = $records{$rec_id};
+        print sprintf("%d [%s] has %d volumes and %d copies\n",
+            $rec_id, $rec->{title}, 
+            scalar(@{$rec->{volumes}}),
+            scalar(map { @{$_->{copies}} } @{$rec->{volumes}}));
+    }
+    print "\nunapi 'batch feed' duration is $duration\n\n";
+}
+
+sub direct_spread {
+    my @recs = @_;
+    my %records;
+    my $start = time();
+
+    my $query = {
+        flesh => 4, 
+        flesh_fields => {
+            bre => ['call_numbers'], 
+            acn => ['copies', 'uris'], 
+            acp => ['location', 'stat_cat_entries', 'parts'],
+            ascecm => ['stat_cat', 'stat_cat_entry'],
+            acpm => ['part']
+        }
+    };
+
+    my @reqs;
+    for my $rec_id (@recs) {
+        my $ses = OpenSRF::AppSession->create('open-ils.cstore');
+        my $req = $ses->request(
+            'open-ils.cstore.direct.biblio.record_entry.search', {id => $rec_id}, $query);
+        push(@reqs, $req);
+    }
+
+    $records{$_}{counts} = $e->json_query({from => ['asset.record_copy_count', 1, $_, 0]})->[0] for @recs;
+    for my $req (@reqs) {
+        my $bre = $req->gather(1);
+        my $xml = XML::LibXML->new->parse_string($bre->marc)->documentElement;
+        my $attrs = get_bib_attrs($xml);
+        $records{$bre->id}{record} = $bre;
+        $records{$bre->id}{$_} = $attrs->{$_} for keys %$attrs;
+    }
+
+    my $duration = time() - $start;
+
+    for my $rec_id (keys %records) {
+        my $rec = $records{$rec_id};
+        print sprintf("%d [%s] has %d volumes and %d copies\n",
+            $rec_id, $rec->{title}, 
+            scalar(@{$rec->{record}->call_numbers}), 
+            scalar(map { @{$_->copies} } @{$rec->{record}->call_numbers}));
+    }
+
+    print "\n'direct' spread calls processing duration is $duration\n\n";
+}
+
+
+sub direct {
+    my @recs = @_;
+    my %records;
+
+    my $start = time();
+
+    my $ses1 = OpenSRF::AppSession->create('open-ils.cstore');
+    my $ses2 = OpenSRF::AppSession->create('open-ils.cstore');
+    my $ses3 = OpenSRF::AppSession->create('open-ils.cstore');
+    my ($req1, $req2, $req3);
+
+    my $query = {
+        flesh => 5, 
+        flesh_fields => {
+            bre => ['call_numbers'], 
+            acn => ['copies', 'uris'], 
+            acp => ['location', 'stat_cat_entries', 'parts'],
+            ascecm => ['stat_cat', 'stat_cat_entry'],
+            acpm => ['part']
+        }
+    };
+
+    my $first = 1;
+    while(@recs) {
+        my ($id1, $id2, $id3) = (pop @recs, pop @recs, pop @recs);
+
+        for my $r ($req1, $req2, $req3) {
+            last unless $r;
+            my $bre = $r->gather(1);
+            my $xml = XML::LibXML->new->parse_string($bre->marc)->documentElement;
+            my $attrs = get_bib_attrs($xml);
+            $records{$bre->id}{record} = $bre;
+            $records{$bre->id}{$_} = $attrs->{$_} for keys %$attrs;
+        }
+
+        $req1 = ($id1) ? $ses1->request('open-ils.cstore.direct.biblio.record_entry.search', {id => $id1}, $query) : undef;
+        $req2 = ($id2) ? $ses1->request('open-ils.cstore.direct.biblio.record_entry.search', {id => $id2}, $query) : undef;
+        $req3 = ($id3) ? $ses1->request('open-ils.cstore.direct.biblio.record_entry.search', {id => $id3}, $query) : undef;
+        
+        if($first) {
+            $records{$_}{counts} = $e->json_query({from => ['asset.record_copy_count', 1, $_, 0]})->[0] for @recs;
+            $first = 0;
+        }
+    }
+
+    for my $r ($req1, $req2, $req3) {
+        last unless $r;
+        my $bre = $r->gather(1);
+        my $xml = XML::LibXML->new->parse_string($bre->marc)->documentElement;
+        my $attrs = get_bib_attrs($xml);
+        $records{$bre->id}{record} = $bre;
+        $records{$bre->id}{$_} = $attrs->{$_} for keys %$attrs;
+    }
+
+
+    my $duration = time() - $start;
+
+    for my $rec_id (keys %records) {
+        my $rec = $records{$rec_id};
+        print sprintf("%d [%s] has %d volumes and %d copies\n",
+            $rec_id, $rec->{title}, 
+            scalar(@{$rec->{record}->call_numbers}), 
+            scalar(map { @{$_->copies} } @{$rec->{record}->call_numbers}));
+    }
+
+    print "\n'direct' calls processing duration is $duration\n\n";
+}
+
+for (0..1) { direct(@recs); unapi(@recs); unapi_batch(@recs); unapi_spread(@recs); direct_spread(@recs); }
diff --git a/Open-ILS/web/css/skin/default/opac/contentslider.css b/Open-ILS/web/css/skin/default/opac/contentslider.css
new file mode 100644 (file)
index 0000000..64a6d25
--- /dev/null
@@ -0,0 +1,39 @@
+.sliderwrapper{
+position: relative; /*leave as is*/
+overflow: hidden; /*leave as is*/
+width: 675px; /*width of featured content slider*/
+height: 213px;
+}
+
+
+
+.sliderwrapper .contentdiv{
+visibility: hidden; /*leave as is*/
+position: absolute; /*leave as is*/ 
+left: 0;  /*leave as is*/
+top: 0;  /*leave as is*/
+width: 675px; /*width of content DIVs within slider. Total width should equal slider's inner width (390+5+5=400) */
+height: 100%;
+filter:progid:DXImageTransform.Microsoft.alpha(opacity=100);
+-moz-opacity: 1;
+opacity: 1;
+}
+
+.pagination{
+width: 400px; /*Width of pagination DIV. Total width should equal slider's outer width (400+10+10=420)*/
+text-align: right;
+background-color: navy;
+padding: 5px 10px;
+}
+
+.pagination a{
+padding: 0 5px;
+text-decoration: none; 
+color: #00007D;
+background: white;
+}
+
+.pagination a:hover, .pagination a.selected{
+color: #000;
+background-color: #FEE496;
+}
\ No newline at end of file
diff --git a/Open-ILS/web/css/skin/default/opac/semiauto.css b/Open-ILS/web/css/skin/default/opac/semiauto.css
new file mode 100644 (file)
index 0000000..e4e9eb7
--- /dev/null
@@ -0,0 +1,183 @@
+/* once done renaming and everything, combine with style.css */
+
+/* Verfied in-use classes --------------------------- */
+.opac-auto-004 { background: #E0F0E0; }
+.opac-auto-009 { border: 3px solid #E0E0E0; }
+.opac-auto-010 { border-bottom: 1px dotted #ccc; padding-top: 10px; }
+.opac-auto-011 { border-bottom: 1px dotted #ccc; padding-top: 6px; }
+.opac-auto-012 { border-bottom: none; }
+.opac-auto-013 { border-bottom: none; *height: 0px; }
+.opac-auto-015 { border-left: 1px solid #e9ebf3; padding-right: 27px; }
+.opac-auto-017 { border: none; width: 100%; }
+.opac-auto-018 { border-top: 1px dotted #ccc; padding-top: 17px; }
+.clear-both { clear: both; }
+.common-no-pad { clear: both; height: 0px; margin: 0px; padding: 0px; }
+.common-full-pad { clear: both; height: 15px; }
+.opac-auto-029 { color: #333; font-weight: bold; font-size: 13px; }
+.opac-auto-030 { color: #545454; }
+.opac-auto-031 { color: #9999FF; padding-left: 10px; font-size: 7pt; font-weight: 300; }
+.red { color: red; }
+.bold-red { color: red; font-weight: bold }
+.pointer { cursor: pointer; }
+/* ------------------------------------------- */
+
+
+#lib_selector_span { display: none }
+.float-left { float: left; }
+.bookbag-share { float: left; padding: 5px 0; }
+.bookbag-controls { float: left; padding: 5px 0px 0px 10px; }
+.left-corner { float: left; width: 163px; height: 30px; background: url('/images/utils-corner-mid.png') repeat-x top; }
+.float-right { float: right; }
+.opac-auto-045 { float: right; margin-right: 17px; }
+.opac-auto-046 { float: right; width: 214px; }
+.opac-auto-047 { float: right; width: 353px; background: #ccc; padding: 10px; margin-top: 7px; }
+.opac-auto-048 { float: right; width: 65px; }
+#they_said_dont_touch { float: right; width: 675px; height: 213px; color: green; overflow: hidden; }
+.opac-auto-050 { float: right; width: 85px; }
+.ten-px { font-size: 10px; }
+.eleven-px { font-size: 11px; }
+.eight-pt { font-size: 8pt; }
+.opac-auto-054 { font-size: 8pt; padding-left: 20px; }
+.bold { font-weight: bold; }
+.opac-auto-057 { font-weight: bold; padding: 5px; margin: 5px; width: 100%; }
+.opac-auto-058 { font-weight: bold; padding-left: 10px; }
+#anon_list_name { font-weight: bold; padding-right: 10px; }
+.opac-auto-060 { font-weight: normal; }
+.opac-auto-061 { height: 0px; border-top: 1px solid #b7b7b7; border-bottom: 1px solid #d4d4d4; margin: 15px 0px; }
+.small-height { height: 10px; }
+.normal-height { height: 15px; }
+.big-height { height: 20px; }
+.very-big-height { height: 30px; }
+#gold-links-holder { height: 24px; background: #252525; }
+.opac-auto-067 { margin: 3px; width: 100%; }
+.big-block { margin: auto; width: 974px; height: 0px; }
+.opac-auto-069 { margin-bottom: 10px; }
+.opac-auto-070 { margin-bottom: 20px; }
+.opac-auto-071 { margin-bottom: 5px; }
+.opac-auto-072 { margin-left: 20px; }
+.bookbag-list { margin-left: 5px; margin-top: 5px; width: 91%; border: 0;}
+#cn_browse_where { margin-left: 6px; }
+.opac-auto-075 { margin-right: 20px; }
+.opac-auto-076 { margin-right: 3px; }
+.opac-auto-077 { margin-right: 4px; position: relative; top: -10px; }
+.opac-auto-078 { margin-right: 7px; }
+.opac-auto-079 { margin-top: 10px; }
+.opac-auto-080 { margin-top: 10px; margin-bottom: 10px; }
+.opac-auto-081 { margin-top: 13px; }
+.opac-auto-082 { margin-top: 29px; }
+.opac-auto-083 { margin-top: 2px; }
+.opac-auto-084 { margin-top: 5px; }
+.opac-auto-085 { margin-top: 6px; margin-left: 20px; width: 250px; padding: 5px; }
+.opac-auto-086 { margin-top: 8px; }
+.opac-auto-087 { max-width: 11em; }
+.opac-auto-088 { padding: 0px; }
+.opac-auto-089 { padding: 0px 10px; }
+.opac-auto-090 { padding: 10px; }
+.opac-auto-091 { padding: 10px 0px; }
+.opac-auto-092 { padding: 4px; text-align: center; }
+.pad-bottom-five { padding: 5px; }
+.opac-auto-094 { padding: 5px 7px 0px 0px; }
+.opac-auto-095 { padding: 5px 7px 0px 0px; white-space: nowrap; }
+.opac-auto-096 { padding: 6px }
+.opac-auto-097 { padding: 8px 0px 6px 0px; width: 100%; border: 0; }
+.opac-auto-097b { padding: 8px 0px 6px 0px; border: 0; }
+.opac-auto-098 { padding-bottom: 10px; }
+.opac-auto-099 { padding-bottom: 12px; color: #666; }
+.opac-auto-100 { padding-bottom: 16px; }
+.opac-auto-101 { padding-bottom: 1px; }
+.opac-auto-102 { padding-bottom: 7px; }
+.opac-auto-103 { padding-left: 10px; }
+.opac-auto-104 { padding-left: 11px; padding-right: 11px; }
+.opac-auto-105 { padding-left: 11px; padding-right: 13px; }
+.opac-auto-106 { padding-left: 15px; }
+.opac-auto-107 { padding-left: 15px; padding-bottom: 10px; }
+.opac-auto-108 { padding-left: 5px; }
+.opac-auto-109 { padding-left: 5px; padding-bottom: 10px; }
+.opac-auto-110 { padding-left: 6px; }
+.opac-auto-111 { padding-left: 8px; }
+.opac-auto-112 { padding-left: 9px; }
+.opac-auto-113 { padding-right: 10px; }
+.opac-auto-114 { padding-right: 15px; padding-left: 15px; }
+.opac-auto-115 { padding-right: 20px; }
+.opac-auto-116 { padding-right: 5px; }
+.opac-auto-117 { padding-right: 7px; }
+.pad-top-ten { padding-top: 10px; }
+.opac-auto-119 { padding-top: 14px; }
+.opac-auto-120 { padding-top: 5px; }
+.opac-auto-121 { padding-top: 6px; }
+.opac-auto-122 { padding-top: 7px; }
+.opac-auto-123 { padding-top: 8px; }
+.pos-abs { position: absolute; }
+#new_cat_link_holder { position: absolute; z-index: 101; }
+#new_cat_link_holder a { display: block; width: 675px; height: 213px; }
+.pos-rel { position: relative; }
+#search-box table { position: relative; left: -10px; }
+.opac-auto-129 { position: relative; left: -19px; }
+.opac-auto-130 { position: relative; left: 80px; }
+.opac-auto-131 { position: relative; top: 0px; left: 55px; }
+.opac-auto-132 { position: relative; top: 13px; }
+.opac-auto-133 { position: relative; top: -13px; left: 2px; font-size: 10px; }
+.opac-auto-134 { position: relative; top: -15px; left: 172px; }
+.opac-auto-135 { position: relative; top: -15px; left: -23px; }
+.opac-auto-136 { position: relative; top: 161px; left: 172px; }
+.opac-auto-137 { position: relative; top: 161px; left: -23px; }
+#home_adv_search_link { position: relative; top: -1px; left: 10px; }
+#util_back_btn { position: relative; top: 1px; left: 10px; }
+.opac-auto-140 { position: relative; top: -2px; }
+#util_help_btn { position: relative; top: 2px; left: 40px; }
+#util_forw_btn { position: relative; top: 2px; left: 50px; }
+.opac-auto-143 { position: relative; top: -3px; }
+#util_home_btn { position: relative; top: 3px; left: 20px; }
+.opac-auto-145 { position: relative; top: -3px; left: 3px; }
+.opac-auto-146 { position: relative; top: -3px; left: -5px; }
+.opac-auto-147 { position: relative; top: -5px; }
+.pos-rel-top-5 { position: relative; top: 5px; }
+.opac-auto-149 { position: relative; top: 5px; left: 25px; }
+#util_print_btn { position: relative; top: 5px; left: 30px; }
+.opac-auto-151 { position: relative; top: 75px; }
+#adv_reset { position: relative; top: -9px; }
+.opac-auto-153 { position: relative; z-index: 100; }
+.text-center { text-align: center; }
+.opac-auto-156 { text-align: center; font-weight: bold; }
+#adv_quick_search_sidebar { text-align: center; margin-top: 20px; width: 400px; }
+.opac-auto-158 { text-align: center; margin-top: 6px; margin-bottom: 6px }
+.opac-auto-159 { text-align: center; padding: 20px; width: 100% }
+.opac-auto-160 { text-align: center; padding-bottom: 8px; }
+.opac-auto-161 { text-align: right; padding-right: 7px; width: 62px; }
+.opac-auto-162 { vertical-align: top; }
+.nowrap { white-space: nowrap; }
+.opac-auto-164 { white-space: nowrap; padding-left: 5px; }
+.full-width { width: 100%; }
+.opac-auto-167 { width: 100%; border: 1px solid black; padding: 6px; margin-top: 5px; }
+.opac-auto-168 { width: 100%; border: 2px solid #E0F0E0; margin-bottom: 20px; }
+.opac-auto-169 { width: 100%; height: 100%; }
+.opac-auto-170 { width: 100%; margin-top: 20px; border-top: 1px dotted #ccc; padding-top: 8px; }
+.opac-auto-171 { font-size: 120%; text-align: center; font-style: italic; }
+.opac-auto-172 { width: 100%; text-align: center; padding-bottom: 5px; }
+.opac-auto-173 { width: 10px; }
+.opac-auto-174 { width: 111px; height: 25px; }
+.opac-auto-175 { width: 125px; height: 21px; }
+.opac-auto-176 { width: 129px; }
+#search_box { width: 162px; }
+.opac-auto-178 { width: 174px; }
+.opac-auto-179 { width: 175px; margin-right: 11px; }
+.opac-auto-179 optgroup { margin-left: 1em; font-weight: normal; font-style: italic; }
+.opac-auto-179-inner-option { margin-left: 2em; } /* XXX ".opac-auto-179 optgroup option" doesn't work!? */
+.opac-auto-180 { width: 182px; color: black; padding: 5px 25px; }
+.opac-auto-181 { width: 195px; }
+.opac-auto-182 { width: 230px; text-align: left; margin-top: 3px; }
+.opac-auto-183 { width: 250px; text-align: left; }
+.opac-auto-184 { width: 26px; height: 23px; margin-top: 6px; margin-bottom: 6px; }
+.opac-auto-185 { width: 324px; }
+.opac-auto-186 { width: 400px; margin-top: 20px; }
+.opac-auto-187 { width: 662px; }
+.opac-auto-188 { width: 700px; height: 30px; border: 1px solid red; }
+.opac-auto-189 { width: 742px; float: left; }
+.opac-auto-190 { width: 88px; }
+.opac-auto-191 { width: 90px; }
+#cn_browse_div > div { width: 90%; text-align: center; margin: 10px; }
+.opac-auto-193 { width: 91px; }
+#cn_browse { width: 95%; text-align: center; padding: 15px; }
+.opac-auto-195 { width: 99%; text-align: center }
+#homesearch_thing { width: 664px; height: 117px; background: #bda964; }
+#mystery_thing { width: 664px; height: 35px; background: #ffffff; }
diff --git a/Open-ILS/web/css/skin/default/opac/style.css b/Open-ILS/web/css/skin/default/opac/style.css
new file mode 100644 (file)
index 0000000..caba3e0
--- /dev/null
@@ -0,0 +1,1003 @@
+body {
+       margin:0;
+       font-family: Arial, Helvetica, sans-serif;
+       font-size: 12px;
+       background:#333;
+}
+
+img {
+       border: none;
+}
+
+a {
+       color: #003399;
+       text-decoration: none;
+}
+
+a:hover {
+       text-decoration: underline;
+}
+
+#search-wrapper input[type=text] {
+       border:none;
+       margin:0;
+       padding:0;
+}
+
+#search-wrapper select {
+       border:1px solid #e9ebf3;
+       margin:0;
+       padding:0;
+       width:168px;
+}
+
+/*
+#search-wrapper select {
+       border:0px solid black;
+       filter:alpha(opacity=0);
+       -moz-opacity:0;
+       -khtml-opacity:0;
+       opacity:0;
+       padding:0;
+       margin:0;
+       height:18px;
+       font-size: 12px;
+}
+*/
+h1 {
+       margin:0;
+       margin-bottom: 5px;
+       font-size: 20px;
+       font-weight:normal;
+}
+
+h2 {
+       margin:0;
+       margin-bottom: 5px;
+       font-size: 14px;
+       font-weight:bold;
+}
+
+.hide_me, .hidden {
+       display: none;
+       visibility: hidden;
+}
+
+div.select-box-wrapper {
+       position:absolute;
+       padding-top:2px;
+       padding-left:3px;
+       overflow:hidden;
+       text-align:left;
+}
+
+div.select-wrapper {
+       border:1px solid #4C8AB0;
+       display:inline-block;
+       position:relative;
+       z-index:2;
+       background:url('/images/dropdown.gif') no-repeat right center;
+}
+
+div.select-wrapper:hover {
+       background:url('/images/dropdown-hover.gif') no-repeat right center;
+}
+
+#dash_wrapper {
+       width:500px;
+       position:relative;
+       top:-26px;
+}
+
+#dashboard {
+       clear:both;
+       float:right;
+       width:384px;
+}
+
+#dashboard span {
+       font-weight:bold;
+       position:relative;
+       left:-1px;
+}
+
+#dash_user {
+       font-weight: bold;
+       text-transform: capitalize;
+    position: relative;
+    top: 10px;
+}
+
+#dash_corner_mid1a {
+    vertical-align: top;
+    background: url('/images/dash-corner-mid1.png') repeat-x;
+    padding-left: 8px;
+}
+#dash_corner_mid1b {
+    background: url('/images/dash-corner-mid1.png') repeat-x;
+    padding: 0px 8px 0px 10px;
+}
+#dash_corner_mid1b img { position: relative; top: -1px; }
+#dash_corner_mid1c {
+    background: url('/images/dash-corner-mid1.png') repeat-x;
+    vertical-align: top;
+}
+#dash_corner_mid2a {
+    vertical-align: top;
+    width: 372px;
+    background: url('/images/dash-corner-mid2.png') repeat-x;
+}
+.dash-pos-out { position: relative; left: 3px; }
+.dash-pos-holds { position: relative; left: 100px; }
+.dash-align-out { text-align: right; width: 86px; }
+.dash-align-holds { text-align: right; width: 62px; }
+.dash-pos-pickup { position: relative; left: 170px; }
+.dash-align-pickup { text-align: right; width: 111px; }
+.dash-pos-fines { position: relative; left: 284px; }
+.dash-align-fines { text-align: right; width: 76px; }
+.pos-rel-top4 { position: relative; top: 4px; }
+#dash_number_row { position: relative; top: 6px; }
+#logout_link { left: 1px; }
+
+#dash_checked { color: #ffcc33; }
+#dash_holds { color: #ffcc33; }
+#dash_pickup { color: #1dd93c; }
+#dash_fines { color: #f41d36; }
+#header {
+       color: #fff;
+       padding: 26px 0px 26px 0px;
+       width: 974px;
+       margin: auto;
+       font-size:11px;
+}
+
+#header a {
+       color: #fff;
+}
+
+#header a:hover {
+       color: white;
+       text-decoration: none;
+}
+
+#header-links {
+       color: #afafaf;
+       font-size: 11px;
+       font-weight: bold;
+       position: relative;
+       top:4px;
+       
+}
+
+#header-links a {
+       color: #afafaf;
+       display: block;
+       float:left;
+       margin-right:22px;
+}
+
+#header-links a:hover {
+       color: white;
+       text-decoration: none;
+}
+
+#header #header-links2 {
+       position:relative;
+       top:-8px;
+       color: white;
+       padding-bottom: 15px;
+}
+
+#header #header-links2 a {
+       color: white;
+}
+
+#header #header-links2 a:hover {
+       text-decoration: underline;
+}
+
+#header #your-acct-login {
+       padding-top:10px;
+}
+
+#gold-links {
+       margin:auto;
+       width:974px;
+       padding-left:0px;
+}
+
+#gold-links-home {
+       margin:auto;
+       width:694px;
+       padding-left:0px;
+}
+
+#util-bar {
+       margin:auto;
+       width:974px;
+       padding-left:0px;
+       height:0px;
+}
+
+#search-wrapper {
+       border-bottom: 1px solid #e9ebf3;
+       padding-bottom: 5px;
+       background: white;
+}
+
+#search_box_wrapper {
+       border:1px solid #e9ebf3;
+       padding: 1px;
+    padding-left: 3px;
+}
+
+#search-wrapper #breadcrumb {
+       margin-top:0px;
+       font-size: 10px;
+       float:left;
+}
+
+#search-wrapper #search-within {
+       margin-top:10px;
+       float:right;
+       position:relative;
+       left:-173px;
+}
+
+#search-wrapper #breadcrumb a {
+       color: black;
+}
+
+#search-wrapper #search_frm label {
+       font-size: 10px;
+}
+
+#search-wrapper #search-box {
+       width:974px;
+       margin:auto;
+       padding-left: 0px;
+}
+
+#utils {
+       float:right;
+       z-index:1;
+       width:150px;
+       height:30px;
+       background:url('/images/utils-corner-left.png') no-repeat left top;
+       padding-left: 3px;
+       color: white;
+       position:relative;
+}
+
+#utils a {
+       color: white;
+       font-size: 10px;
+}
+#adv_search_tabs {
+       height:33px;
+       width:974px;
+       margin:auto;
+}
+
+#adv_search_tabs a {
+       float: left;
+       display: block;
+       height:33px;
+       margin-right:7px;
+}
+
+#adv_search {
+       width:156px;
+       background:url('/images/adv_search_on.gif') no-repeat bottom;
+}
+
+#num_search {
+       width:156px;
+       background:url('/images/num_search_off.gif') no-repeat bottom;
+}
+
+#expert_search {
+       width:156px;
+       background:url('/images/expert_search_off.gif') no-repeat bottom;
+}
+
+#acct_tabs, #acct_fines_tabs {
+       height:33px;
+       width:974px;
+       margin:auto;
+}
+
+#acct_tabs a, #acct_fines_tabs a {
+       float: left;
+       display: block;
+       height:33px;
+       margin-right:7px;
+}
+
+.acct-tab {
+    background-repeat: no-repeat;
+    background-position: bottom;
+    width:156px;
+}
+
+.acct-main-off {
+       background-image:url('/images/acct_summary_off.gif');
+}
+.acct-main-on {
+       background-image:url('/images/acct_summary_on.gif');
+}
+
+.acct-circs-off {
+       background-image:url('/images/acct_checked_out_off.gif');
+}
+.acct-circs-on {
+       background-image:url('/images/acct_checked_out_on.gif');
+}
+
+.acct-holds-off {
+       background-image:url('/images/acct_holds_off.gif');
+}
+.acct-holds-on {
+       background-image:url('/images/acct_holds_on.gif');
+}
+
+.acct-prefs-off {
+       background-image:url('/images/acct_prefs_off.gif');
+}
+.acct-prefs-on {
+       background-image:url('/images/acct_prefs_on.gif');
+}
+
+.acct-lists-off {
+       background-image:url('/images/acct_lists_off.gif');
+}
+.acct-lists-on {
+       background-image:url('/images/acct_lists_on.gif');
+}
+
+#rdetail_header {
+       font-size:14px;
+       font-weight:bold;
+       color:#074079;
+       padding: 5px 7px 6px 0px;
+       border-bottom: 1px dotted #ccc;
+}
+
+#rdetail_result_count {
+       color: black;
+       font-size: 11px;
+       font-weight: normal;
+}
+
+#rdetail_result_nav {
+       float:right;
+       font-size: 11px;
+       font-weight:normal;
+}
+
+#rdetail_details_table {
+       margin-top: 15px;
+}
+
+#rdetail_title {
+       font-size: 18px;
+}
+
+#rdetail_image { border: none; }
+#rdetail_image_cell {
+       padding-top: 3px;
+       padding-right: 10px;
+}
+
+.rdetail_aux_utils {
+       border-left:1px dotted #ccc;
+       padding-left: 17px;
+       padding-bottom: 6px;
+       padding-right: 70px;
+}
+
+.results_aux_utils {
+       border-left:1px dotted #ccc;
+       padding-left: 17px;
+       padding-bottom: 6px;
+       padding-right: 50px;
+}
+
+#rdetails_status td, #rdetails_status2 td {
+       white-space:nowrap !important;
+       padding: 7px 0px 3px 13px;
+}
+
+#rdetails_status thead td {
+       background-color: #d8d8d8;
+       padding: 13px 0px 13px 13px;
+       font-size: 10px;
+       text-transform: uppercase;
+       font-weight: bold;
+}
+
+#rdetails_status tbody td {
+       padding-left: 13px;;
+}
+
+.rdetail_extras {
+       height: 29px;
+       background: #9ad0f1;
+       padding-top:1px;
+       margin-bottom: 10px;
+       margin-top: 10px;
+       clear:both;
+}
+
+.rdetail_extras_hr {
+       height: 1px;
+       background: #b7def5;
+       margin-left: 1px;
+       margin-right: 1px;
+}
+
+.rdetail_extras_link {
+       padding-top: 4px;
+       padding-left: 12px;
+       font-size: 10px;
+       text-transform: uppercase;
+       font-weight: bold;
+}
+
+.rdetail_extras_lbl {
+       position: relative;
+       top: -4px;
+       left: 7px;
+}
+
+#paginate-homebanner a.toc {
+       display:block;
+       width:20px;
+       height:20px;
+       background:gray;
+       float:left;
+       margin-left:2px;
+       margin-right:2px;
+       margin-top:2px;
+}
+
+#rdetail_extras_expand, #rdetail_extras_collapse, #rdetail_locs_collapse {
+       margin-left: 13px;
+}
+
+#rdetail_locs_expand, #rdetail_locs_collapse {
+       padding-bottom:3px;
+       margin-top:15px;
+       margin-left:13px;
+}
+
+#rdetail_anotes_div .biography {
+       margin:0;
+}
+
+#paginate-homebanner a.selected {
+       border: 2px solid black;
+       margin-top:0px;
+       margin-left:0px;
+       margin-right:0px;
+}
+
+#hp-buttons {
+       margin: auto;
+       margin-top: 6px;
+       width: 694px; /* 974px; */
+}
+
+#hp-welcome {
+       position:absolute;
+       width:295px;
+       height:192px;
+       background: url('/images/banner-bg.png') no-repeat;
+       color: #fff;
+       padding-left: 33px;
+       padding-top: 21px;
+       z-index:9999999999;
+}
+
+#hp-welcome h1 {
+       font-size: 25px;
+       margin-bottom:15px;
+}
+
+#hp-welcome a {
+       color: #fff;
+       text-decoration: underline;
+}
+
+#hp-banner {
+       margin: auto;
+       width: 694px; /* formerly 974px */
+       height: 213px;
+}
+
+#hp-ql-table {
+       margin-left: 2px;
+       padding-top: 3px;
+}
+
+#hp-ql-table a {
+       color: #333;
+       font-weight: bold;
+       font-size: 13px;
+       text-transform: uppercase;
+       text-decoration: none;
+       display: block;
+       width: 144px;
+       height: 25px;
+       padding-top: 9px;
+       padding-left: 15px;
+       background: url('/images/button-bg.png') no-repeat;
+}
+
+#hp-ql-bottom {
+       width: 640px;
+       height: 31px;
+       padding-left: 24px;
+       padding-top: 13px;
+       background: url('/images/hp-links-mid.jpg') repeat-x;
+}
+
+#hp-ql-bottom a {
+       display: inline-block;
+       text-decoration: none;
+       color: white;
+       font-size: 15px;
+       font-weight: bold;
+}
+
+#hp-ql-bottom img {
+    position:relative;
+    top:-1px;
+    left:2px;
+}
+
+.almost-content-wrapper {
+       background: white;
+}
+
+#content-wrapper {
+       background: white;
+       min-height: 260px;
+       border-bottom: 1px solid black;
+}
+
+.content-wrapper-record-page { top: -15px; position: relative; }
+
+#main-content-home { width: 694px; margin: auto; padding-left: 17px; }
+#main-content { width: 974px; margin:auto; padding-left: 0px; }
+
+#main-content .login_boxes {
+       border: 1px solid #dedede;
+       background:url('/images/login-bg.jpg') top repeat-x;
+       color: #333;
+}
+
+#main-content .login_boxes h1 {
+       font-weight: normal;
+       font-size: 25px;
+       margin:0;
+}
+
+#main-content .left_brain {
+       padding-left:28px;
+       padding-top:25px;
+}
+
+#main-content .left_brain input[type=text], #main-content .left_brain input[type=password] {
+       width:167px;
+       height:18px;
+       margin:0;
+       padding:0;
+       border:none;
+       background: none;
+       font-size: 15px;
+       color: #666;
+}
+
+#main-content .left_brain .input_bg {
+       padding:10px 10px 0px 13px;
+       background: url('/images/login-box-bg.jpg') no-repeat;
+       width:167px;
+       height:29px;
+}
+
+#home-buttons-inner {
+       width:664px;
+       height:117px;
+       background:#bda964;
+}
+
+#holds_temp_parent td {
+       border-bottom:1px solid #dcdbdb;
+}
+
+#holds_temp_parent input, #holds_temp_parent select {
+       margin:0;
+}
+
+
+
+
+#results_header_bar {
+       background: #929292;
+       border-top:1px solid #8b8b8b;
+}
+
+#results_header_inner {
+       height:32px;
+       width:974px;
+       margin:auto;
+       padding-top:6px;
+}
+
+.results_header_btns {
+       float:left;
+       margin-right: 6px;
+}
+
+.cached_list_div { width: 111px; height: 25px; }
+
+.results_header_div {
+       float: left;
+       width: 0px;
+       height: 25px;
+       border-left: 1px solid #7c7c7c;
+       border-right: 1px solid #9c9c9c;
+       margin: 0px 13px;
+}
+
+.results_header_lbl {
+       font-weight: bold;
+       float: left;
+       font-size: 11px;
+       color: #191919;
+       position: relative;
+       top: 5px;
+       margin-right: 6px;
+}
+
+.results_header_sel {
+    /* width: 88px; */
+       float:left;
+       position: relative;
+       top: 2px;
+       margin:0;
+}
+
+.results_header_nav1 {
+       padding: 5px 7px 6px 0px;
+       border-bottom: 1px dotted #ccc;
+}
+
+.results_header_nav1 .h1 {
+       font-size:14px;
+       font-weight:bold;
+       color:#074079;
+}
+
+.start_end_links_span {
+       font-size: 11px;
+}
+
+.nav_arrow_fix {
+       font-size:8px;
+       position:relative;
+       top:-1px;
+}
+
+#result_table_div {
+       margin-top: 20px;
+}
+
+.result_numbers {
+       font-size: 11px; padding-left:15px; white-space: nowrap; width: 320px;
+}
+
+.result_table_subtable { width: 100%; border-collapse: collapse; border: 0; }
+
+
+
+
+.icon_text {
+       text-transform:capitalize;
+}
+
+.result_table_title_cell {
+       padding-left: 7px;
+}
+
+#myopac_summary_div p {
+       margin:0;
+       margin-bottom: 10px;
+}
+
+#acct_sum_checked_table td {
+       padding-bottom:5px;
+}
+
+#zero_search_hits div { float:left;width:300px;margin-top:20px; }
+
+#zero_search_hits p {
+       margin-top:0;
+}
+
+#zero_hits_term {
+       text-transform: uppercase;
+    font-weight: bold;
+}
+
+#zero_search_hits #spell_check_link {
+       text-transform: uppercase;
+}
+
+#zero_search_hits #zero_hits_suggestions {
+       text-transform: uppercase;
+}
+
+.results_info_table td {
+       padding-right: 10px;
+}
+
+#myopac_holds_main_table {
+       border-collapse: collapse;
+}
+
+#myopac_holds_main_table td {
+       border: 1px solid black;
+       
+}
+
+#myopac_prefs_div .data_grid {
+       border-collapse:collapse;
+}
+
+#myopac_prefs_div .data_grid td {
+       background:#f0f0f0;
+       border-bottom:3px solid white;
+       padding:6px 0px 7px 17px;
+}
+
+.header_middle {
+       height:22px;
+       font-size:14px;
+       font-weight:bold;
+       color:#074079;
+       padding: 0px 7px 0px 0px;
+       border-bottom: 1px dotted #ccc;
+}
+
+.header_middle a {
+       font-size: 12px;
+       font-weight: normal;
+}
+
+.acct_sum_row {
+       padding: 7px 15px;
+       width: 712px;
+       background: #f0f0f0;
+       margin-bottom: 2px;
+       font-size: 10px;
+       font-weight: bold;
+       text-transform: uppercase;
+}
+
+.acct_sum_row a {
+       text-transform: none;
+       font-size: 12px;
+       position:relative;
+       top:-1px;
+}
+
+.acct_sum_row .view_link {
+       font-weight: normal;
+       font-size:12px;
+}
+
+#myopac_sum_fines {
+       float:right;
+       padding: 15px 0px 0px 23px;
+       background: #f0f0f0;
+       width: 177px;
+       height: 166px;
+}
+
+#myopac_sum_fines_placehold { float: right; width: 177px; height: 166px; }
+
+.acct_holds_temp td {
+       text-align: left;
+}
+
+#acct_checked_tabs .align, #acct_holds_tabs .align, #acct_prefs_tabs .align {
+       float:left;
+       /*padding-left:10px;*/
+}
+
+#acct_checked_tabs .selected, #acct_holds_tabs .selected, #acct_prefs_tabs .selected {
+       /*background:url('/images/gray-arrow.png') left 3px no-repeat;*/
+}
+
+#acct_checked_main_header, #acct_holds_main_header, #acct_checked_hist_header, #acct_list_header, #acct_list_header_anon, #temp_list_holds {
+       font-weight:bold;
+       text-transform:uppercase;
+       font-size: 10px;
+}
+
+#acct_checked_main_header td, #acct_holds_main_header td, #acct_checked_hist_header td, #acct_list_header td, #acct_list_header_anon td, #temp_list_holds td {
+       background: #d8d8d8;
+       padding: 8px 0px 7px 0px;
+}
+
+#acct_list_header select, #acct_list_header_anon select {
+       font-weight:normal;
+       text-transform:none;
+}
+
+#acct_holds_activates_table label {
+       font-weight: bold;
+       font-size: 11px;
+       text-transform:uppercase;
+       padding-right: 5px;
+}
+
+.adv_search_font {
+       font-size: 10px;
+}
+
+.search_catalog_lbl {
+       font-size: 14px;
+}
+
+.lbl1 {
+       font-size:14px;
+       font-weight:bold;
+}
+
+.lbl2 {
+       font-size:10px;
+       font-weight:normal;
+       position:relative;
+       top:3px;
+}
+
+#myopac_tabs, #adv_search_parent, #fines_payments_wrapper {
+       background: #929292;
+       border-top:1px solid #8b8b8b;
+       padding-top:5px;
+       margin-bottom:20px;
+}
+
+#fines_payments_wrapper {
+    padding-left: 5px; 
+    padding-right: 5px;
+}
+
+#myopac_payments_table th { text-align: left; }
+#myopac_payments_table tbody tr:nth-child(odd) { background-color: #ddd; }
+#myopac_payments_table form { display: inline; }
+#myopac_payments_table input[type="submit"] { padding: 1px; }
+
+.payment-error {
+    font-weight: bold; color: red;
+    padding: 10px; border: 1px solid #888;
+}
+
+#adv_search_parent {
+       margin-bottom:0px;
+}
+
+#myopac_loading {
+       width:100%;
+       text-align:center;
+       padding-top:20px;
+       font-size:16px;
+       font-weight:bold;
+}
+
+.chili_link {
+       width:100px !important;
+       text-align: center !important;
+}
+
+.chili_review div.chili_link div {
+       margin: auto;
+}
+
+/* some facet styling */
+.facetClassContainer { margin: 2px; border: 1px solid #CCC; }
+.facetClassLabelContainer { border: 1px solid #CCC; }
+.facetClassLabel { font-weight: bold; text-align: center; }
+.facetFieldContainer {  }
+.facetFieldLabel { padding-left: 2px; margin-top: 5px; margin-bottom: 5px; font-weight: bold; text-align: left; }
+.extraFacetFieldsWrapper { }
+.toggleExtraFacetFieldsButton { float: right; margin: 0px; padding: 0px; }
+.facetFieldLineCount { display: inline-block; border-right: 1px solid #CCC; color: gray; width: 3em; margin-right: 3px }
+.facetField { border-top: 1px solid #CCC; }
+.facetFields { padding-left: 5px; }
+.facetFieldLineValue { overflow: hidden; text-overflow: ellipsis; }
+
+#footer {
+       padding-top:5px;
+       padding-bottom: 10px;
+       color: white;
+       margin: auto;
+       width: 974px;
+       color: #afafaf;
+       font-size: 11px;
+}
+
+#footer a {
+       color: white;
+       color: #afafaf;
+}
+
+.color_4 {
+       text-transform: uppercase;
+       font-weight: bold;
+       font-size: 10px;
+}
+
+.advanced_div { padding-top: 15px; }
+#adv_global_search select { width: 13em; }
+#adv_global_input_table select { width: 7em; }
+.adv_adv_link { font-size: 8pt; color: red; }
+#acct_prefs_header { float: left; }
+#limit_to_available {
+    float: left; position: relative; top: 2px;
+    left: -2px; margin-right: 4px;
+}
+#rdetail_copy_info_table { font-size: 8pt; }
+#rdetail_copy_info_table td { padding: 3px; }
+.search_page_nav_link { cursor: pointer; }
+#opac.result.sort { width: 160px; }
+.renew-summary { font-size: 125%; font-style: italic; margin: 0.5ex 0; }
+.failure-text { margin-left: 4em; font-style: italic; color: #ff0000; }
+.refine-controls { font-size: 125%; padding: 0.5ex 0; }
+#adv_search_refine input[type=text] { border: 1px inset #ccc !important; }
+#adv_search_refine select { border: 1px inset #ccc !important; }
+#adv_search_refine {
+    padding-left: 5em; background-color: #d7d7d7; margin: 2ex 0;
+}
+.row-remover { position: relative; top: 1px; vertical-align: middle; }
+.subtle-button {
+    background-color: #ffffff;
+    color: #003399; text-decoration: none;
+    font-size: 12px;
+    padding: 0; border: 0; margin: 0;
+    vertical-align: middle;
+}
+.subtle-button:hover { text-decoration: underline; cursor: pointer; }
+.no-dec:hover { text-decoration: none; }
+.pending-addr td { background-color: #ffcccc !important; border: 0 !important; }
+
+#account-update-email table { text-align: center; padding: 20px; margin-top: 30px; border-collapse: collapse; }
+#account-update-email table td { padding: 5px 15px 5px 15px; border-bottom: 1px solid #ddd; text-align: left;}
+#account-update-email-error { font-size: 1.5em; padding: 10px; border:1px solid #e9ebf3;}
+a.dash-link:hover { text-decoration: underline !important; }
+#list_create_table td { vertical-align: middle; padding: 0 8px; }
+#list_create_table {
+    background-color: #ccc;
+    padding-bottom: 4px;
+    margin-bottom: 10px;
+    border-bottom: 1px dotted #666;
+}
+.list-create-table-buttons input[type=image] { margin-top: 2px; }
+.result_table_format_cell { padding: 0px 10px; text-align: center; }
+#hold_editor h1 { font-size: 120%; font-weight: bold; }
+#hold_editor h2 { font-size: 111%; font-weight: normal; text-indent: 2em; font-style: italic; }
+#hold_editor h1, #hold_editor h2 { margin: 2px 0; }
+#hold_editor_table { background-color: #ddd; padding: 0.5em; }
+#hold_editor_table th { text-align: right; padding-right: 1em; }
+#hold_editor_table td { padding: 0.25em 0; }
+.fmt-note { vertical-align: middle; padding-left: 1em !important; }
+.hold-editor-controls { text-align: center; padding-top: 1em !important; }
+.hold-editor-controls a { padding-left: 2em; }
+
+.text-right { text-align: right; }
+.rdetail-author-div { padding-bottom: 10px; }
+
+.invisible { visibility: hidden; }
diff --git a/Open-ILS/web/images/KCLS_logo_horiz.gif b/Open-ILS/web/images/KCLS_logo_horiz.gif
new file mode 100644 (file)
index 0000000..8e1d56e
Binary files /dev/null and b/Open-ILS/web/images/KCLS_logo_horiz.gif differ
diff --git a/Open-ILS/web/images/acct-btn-hover.png b/Open-ILS/web/images/acct-btn-hover.png
new file mode 100644 (file)
index 0000000..1e6e20a
Binary files /dev/null and b/Open-ILS/web/images/acct-btn-hover.png differ
diff --git a/Open-ILS/web/images/acct-btn.png b/Open-ILS/web/images/acct-btn.png
new file mode 100644 (file)
index 0000000..c9b92cd
Binary files /dev/null and b/Open-ILS/web/images/acct-btn.png differ
diff --git a/Open-ILS/web/images/acct_checked_out_off.gif b/Open-ILS/web/images/acct_checked_out_off.gif
new file mode 100644 (file)
index 0000000..dcfcfcb
Binary files /dev/null and b/Open-ILS/web/images/acct_checked_out_off.gif differ
diff --git a/Open-ILS/web/images/acct_checked_out_on.gif b/Open-ILS/web/images/acct_checked_out_on.gif
new file mode 100644 (file)
index 0000000..f364d38
Binary files /dev/null and b/Open-ILS/web/images/acct_checked_out_on.gif differ
diff --git a/Open-ILS/web/images/acct_favs_off.gif b/Open-ILS/web/images/acct_favs_off.gif
new file mode 100644 (file)
index 0000000..5ffc024
Binary files /dev/null and b/Open-ILS/web/images/acct_favs_off.gif differ
diff --git a/Open-ILS/web/images/acct_favs_on.gif b/Open-ILS/web/images/acct_favs_on.gif
new file mode 100644 (file)
index 0000000..f96342a
Binary files /dev/null and b/Open-ILS/web/images/acct_favs_on.gif differ
diff --git a/Open-ILS/web/images/acct_fines_off.jpg b/Open-ILS/web/images/acct_fines_off.jpg
new file mode 100644 (file)
index 0000000..b73b61d
Binary files /dev/null and b/Open-ILS/web/images/acct_fines_off.jpg differ
diff --git a/Open-ILS/web/images/acct_fines_on.jpg b/Open-ILS/web/images/acct_fines_on.jpg
new file mode 100644 (file)
index 0000000..4ea7e89
Binary files /dev/null and b/Open-ILS/web/images/acct_fines_on.jpg differ
diff --git a/Open-ILS/web/images/acct_holds_off.gif b/Open-ILS/web/images/acct_holds_off.gif
new file mode 100644 (file)
index 0000000..6179396
Binary files /dev/null and b/Open-ILS/web/images/acct_holds_off.gif differ
diff --git a/Open-ILS/web/images/acct_holds_on.gif b/Open-ILS/web/images/acct_holds_on.gif
new file mode 100644 (file)
index 0000000..d1c75bb
Binary files /dev/null and b/Open-ILS/web/images/acct_holds_on.gif differ
diff --git a/Open-ILS/web/images/acct_lists_off.gif b/Open-ILS/web/images/acct_lists_off.gif
new file mode 100644 (file)
index 0000000..9a5b2a2
Binary files /dev/null and b/Open-ILS/web/images/acct_lists_off.gif differ
diff --git a/Open-ILS/web/images/acct_lists_on.gif b/Open-ILS/web/images/acct_lists_on.gif
new file mode 100644 (file)
index 0000000..668b0c9
Binary files /dev/null and b/Open-ILS/web/images/acct_lists_on.gif differ
diff --git a/Open-ILS/web/images/acct_payments_off.jpg b/Open-ILS/web/images/acct_payments_off.jpg
new file mode 100644 (file)
index 0000000..c8a50f5
Binary files /dev/null and b/Open-ILS/web/images/acct_payments_off.jpg differ
diff --git a/Open-ILS/web/images/acct_payments_on.jpg b/Open-ILS/web/images/acct_payments_on.jpg
new file mode 100644 (file)
index 0000000..c571398
Binary files /dev/null and b/Open-ILS/web/images/acct_payments_on.jpg differ
diff --git a/Open-ILS/web/images/acct_prefs_off.gif b/Open-ILS/web/images/acct_prefs_off.gif
new file mode 100644 (file)
index 0000000..c357add
Binary files /dev/null and b/Open-ILS/web/images/acct_prefs_off.gif differ
diff --git a/Open-ILS/web/images/acct_prefs_on.gif b/Open-ILS/web/images/acct_prefs_on.gif
new file mode 100644 (file)
index 0000000..67d1f47
Binary files /dev/null and b/Open-ILS/web/images/acct_prefs_on.gif differ
diff --git a/Open-ILS/web/images/acct_sum_fines_bl.png b/Open-ILS/web/images/acct_sum_fines_bl.png
new file mode 100644 (file)
index 0000000..d750579
Binary files /dev/null and b/Open-ILS/web/images/acct_sum_fines_bl.png differ
diff --git a/Open-ILS/web/images/acct_sum_fines_br.png b/Open-ILS/web/images/acct_sum_fines_br.png
new file mode 100644 (file)
index 0000000..8aa81f0
Binary files /dev/null and b/Open-ILS/web/images/acct_sum_fines_br.png differ
diff --git a/Open-ILS/web/images/acct_sum_fines_tl.png b/Open-ILS/web/images/acct_sum_fines_tl.png
new file mode 100644 (file)
index 0000000..17051c9
Binary files /dev/null and b/Open-ILS/web/images/acct_sum_fines_tl.png differ
diff --git a/Open-ILS/web/images/acct_sum_fines_tr.png b/Open-ILS/web/images/acct_sum_fines_tr.png
new file mode 100644 (file)
index 0000000..fb9dac3
Binary files /dev/null and b/Open-ILS/web/images/acct_sum_fines_tr.png differ
diff --git a/Open-ILS/web/images/acct_summary_off.gif b/Open-ILS/web/images/acct_summary_off.gif
new file mode 100644 (file)
index 0000000..63456c1
Binary files /dev/null and b/Open-ILS/web/images/acct_summary_off.gif differ
diff --git a/Open-ILS/web/images/acct_summary_on.gif b/Open-ILS/web/images/acct_summary_on.gif
new file mode 100644 (file)
index 0000000..99d4990
Binary files /dev/null and b/Open-ILS/web/images/acct_summary_on.gif differ
diff --git a/Open-ILS/web/images/add_mylist.gif b/Open-ILS/web/images/add_mylist.gif
new file mode 100644 (file)
index 0000000..a30b32d
Binary files /dev/null and b/Open-ILS/web/images/add_mylist.gif differ
diff --git a/Open-ILS/web/images/add_mylist_sel.gif b/Open-ILS/web/images/add_mylist_sel.gif
new file mode 100644 (file)
index 0000000..0448d21
Binary files /dev/null and b/Open-ILS/web/images/add_mylist_sel.gif differ
diff --git a/Open-ILS/web/images/add_mylist_sel.kcls.gif b/Open-ILS/web/images/add_mylist_sel.kcls.gif
new file mode 100644 (file)
index 0000000..45bd8b6
Binary files /dev/null and b/Open-ILS/web/images/add_mylist_sel.kcls.gif differ
diff --git a/Open-ILS/web/images/add_search_row_btn.gif b/Open-ILS/web/images/add_search_row_btn.gif
new file mode 100644 (file)
index 0000000..a48e68c
Binary files /dev/null and b/Open-ILS/web/images/add_search_row_btn.gif differ
diff --git a/Open-ILS/web/images/adv_row_close_btn.png b/Open-ILS/web/images/adv_row_close_btn.png
new file mode 100644 (file)
index 0000000..edccf37
Binary files /dev/null and b/Open-ILS/web/images/adv_row_close_btn.png differ
diff --git a/Open-ILS/web/images/adv_search.png b/Open-ILS/web/images/adv_search.png
new file mode 100644 (file)
index 0000000..79fb08a
Binary files /dev/null and b/Open-ILS/web/images/adv_search.png differ
diff --git a/Open-ILS/web/images/adv_search_hover.png b/Open-ILS/web/images/adv_search_hover.png
new file mode 100644 (file)
index 0000000..0cb3fe1
Binary files /dev/null and b/Open-ILS/web/images/adv_search_hover.png differ
diff --git a/Open-ILS/web/images/adv_search_off.gif b/Open-ILS/web/images/adv_search_off.gif
new file mode 100644 (file)
index 0000000..a129b93
Binary files /dev/null and b/Open-ILS/web/images/adv_search_off.gif differ
diff --git a/Open-ILS/web/images/adv_search_on.gif b/Open-ILS/web/images/adv_search_on.gif
new file mode 100644 (file)
index 0000000..d0faa4f
Binary files /dev/null and b/Open-ILS/web/images/adv_search_on.gif differ
diff --git a/Open-ILS/web/images/another_search.png b/Open-ILS/web/images/another_search.png
new file mode 100644 (file)
index 0000000..4bcd214
Binary files /dev/null and b/Open-ILS/web/images/another_search.png differ
diff --git a/Open-ILS/web/images/another_search_hover.png b/Open-ILS/web/images/another_search_hover.png
new file mode 100644 (file)
index 0000000..08efaf5
Binary files /dev/null and b/Open-ILS/web/images/another_search_hover.png differ
diff --git a/Open-ILS/web/images/arrow-down.gif b/Open-ILS/web/images/arrow-down.gif
new file mode 100644 (file)
index 0000000..ebf64c4
Binary files /dev/null and b/Open-ILS/web/images/arrow-down.gif differ
diff --git a/Open-ILS/web/images/arrow-right.gif b/Open-ILS/web/images/arrow-right.gif
new file mode 100644 (file)
index 0000000..6c82655
Binary files /dev/null and b/Open-ILS/web/images/arrow-right.gif differ
diff --git a/Open-ILS/web/images/arrow-right.png b/Open-ILS/web/images/arrow-right.png
new file mode 100644 (file)
index 0000000..232a5e4
Binary files /dev/null and b/Open-ILS/web/images/arrow-right.png differ
diff --git a/Open-ILS/web/images/asknow_available.gif b/Open-ILS/web/images/asknow_available.gif
new file mode 100644 (file)
index 0000000..326c8d1
Binary files /dev/null and b/Open-ILS/web/images/asknow_available.gif differ
diff --git a/Open-ILS/web/images/banner-bg.png b/Open-ILS/web/images/banner-bg.png
new file mode 100644 (file)
index 0000000..6d990c5
Binary files /dev/null and b/Open-ILS/web/images/banner-bg.png differ
diff --git a/Open-ILS/web/images/banner1.jpg b/Open-ILS/web/images/banner1.jpg
new file mode 100644 (file)
index 0000000..28eaafc
Binary files /dev/null and b/Open-ILS/web/images/banner1.jpg differ
diff --git a/Open-ILS/web/images/btnCancel.png b/Open-ILS/web/images/btnCancel.png
new file mode 100644 (file)
index 0000000..4cfacaf
Binary files /dev/null and b/Open-ILS/web/images/btnCancel.png differ
diff --git a/Open-ILS/web/images/btnSubmit.png b/Open-ILS/web/images/btnSubmit.png
new file mode 100644 (file)
index 0000000..7a67408
Binary files /dev/null and b/Open-ILS/web/images/btnSubmit.png differ
diff --git a/Open-ILS/web/images/button-bg.png b/Open-ILS/web/images/button-bg.png
new file mode 100644 (file)
index 0000000..38390aa
Binary files /dev/null and b/Open-ILS/web/images/button-bg.png differ
diff --git a/Open-ILS/web/images/cancel_btn.gif b/Open-ILS/web/images/cancel_btn.gif
new file mode 100644 (file)
index 0000000..1cebf59
Binary files /dev/null and b/Open-ILS/web/images/cancel_btn.gif differ
diff --git a/Open-ILS/web/images/cd-small.png b/Open-ILS/web/images/cd-small.png
new file mode 100644 (file)
index 0000000..d2f8fb4
Binary files /dev/null and b/Open-ILS/web/images/cd-small.png differ
diff --git a/Open-ILS/web/images/clipboard.png b/Open-ILS/web/images/clipboard.png
new file mode 100644 (file)
index 0000000..b4bf071
Binary files /dev/null and b/Open-ILS/web/images/clipboard.png differ
diff --git a/Open-ILS/web/images/dash-corner-left1.png b/Open-ILS/web/images/dash-corner-left1.png
new file mode 100644 (file)
index 0000000..9559e8b
Binary files /dev/null and b/Open-ILS/web/images/dash-corner-left1.png differ
diff --git a/Open-ILS/web/images/dash-corner-left2.png b/Open-ILS/web/images/dash-corner-left2.png
new file mode 100644 (file)
index 0000000..5bc8112
Binary files /dev/null and b/Open-ILS/web/images/dash-corner-left2.png differ
diff --git a/Open-ILS/web/images/dash-corner-mid1.png b/Open-ILS/web/images/dash-corner-mid1.png
new file mode 100644 (file)
index 0000000..546b8a8
Binary files /dev/null and b/Open-ILS/web/images/dash-corner-mid1.png differ
diff --git a/Open-ILS/web/images/dash-corner-mid2.png b/Open-ILS/web/images/dash-corner-mid2.png
new file mode 100644 (file)
index 0000000..15af112
Binary files /dev/null and b/Open-ILS/web/images/dash-corner-mid2.png differ
diff --git a/Open-ILS/web/images/dash-corner-right1.png b/Open-ILS/web/images/dash-corner-right1.png
new file mode 100644 (file)
index 0000000..061afc9
Binary files /dev/null and b/Open-ILS/web/images/dash-corner-right1.png differ
diff --git a/Open-ILS/web/images/dash-corner-right2.png b/Open-ILS/web/images/dash-corner-right2.png
new file mode 100644 (file)
index 0000000..8663e0c
Binary files /dev/null and b/Open-ILS/web/images/dash-corner-right2.png differ
diff --git a/Open-ILS/web/images/dash-divider.jpg b/Open-ILS/web/images/dash-divider.jpg
new file mode 100644 (file)
index 0000000..19dda7d
Binary files /dev/null and b/Open-ILS/web/images/dash-divider.jpg differ
diff --git a/Open-ILS/web/images/dropdown-hover.gif b/Open-ILS/web/images/dropdown-hover.gif
new file mode 100644 (file)
index 0000000..1ac62ae
Binary files /dev/null and b/Open-ILS/web/images/dropdown-hover.gif differ
diff --git a/Open-ILS/web/images/dropdown.gif b/Open-ILS/web/images/dropdown.gif
new file mode 100644 (file)
index 0000000..3aab6fe
Binary files /dev/null and b/Open-ILS/web/images/dropdown.gif differ
diff --git a/Open-ILS/web/images/expert_search_off.gif b/Open-ILS/web/images/expert_search_off.gif
new file mode 100644 (file)
index 0000000..96b4f51
Binary files /dev/null and b/Open-ILS/web/images/expert_search_off.gif differ
diff --git a/Open-ILS/web/images/expert_search_on.gif b/Open-ILS/web/images/expert_search_on.gif
new file mode 100644 (file)
index 0000000..6a41861
Binary files /dev/null and b/Open-ILS/web/images/expert_search_on.gif differ
diff --git a/Open-ILS/web/images/faqs-btn.png b/Open-ILS/web/images/faqs-btn.png
new file mode 100644 (file)
index 0000000..38134ec
Binary files /dev/null and b/Open-ILS/web/images/faqs-btn.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/a.png b/Open-ILS/web/images/format_icons/item_type/a.png
new file mode 100644 (file)
index 0000000..2800684
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/a.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/c.png b/Open-ILS/web/images/format_icons/item_type/c.png
new file mode 100644 (file)
index 0000000..132ca40
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/c.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/d.png b/Open-ILS/web/images/format_icons/item_type/d.png
new file mode 100644 (file)
index 0000000..132ca40
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/d.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/e.png b/Open-ILS/web/images/format_icons/item_type/e.png
new file mode 100644 (file)
index 0000000..f9f8047
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/e.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/f.png b/Open-ILS/web/images/format_icons/item_type/f.png
new file mode 100644 (file)
index 0000000..f9f8047
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/f.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/g.png b/Open-ILS/web/images/format_icons/item_type/g.png
new file mode 100644 (file)
index 0000000..dd0a56f
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/g.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/i.png b/Open-ILS/web/images/format_icons/item_type/i.png
new file mode 100644 (file)
index 0000000..b6ddf3e
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/i.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/j.png b/Open-ILS/web/images/format_icons/item_type/j.png
new file mode 100644 (file)
index 0000000..5ada234
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/j.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/k.png b/Open-ILS/web/images/format_icons/item_type/k.png
new file mode 100644 (file)
index 0000000..e523300
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/k.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/m.png b/Open-ILS/web/images/format_icons/item_type/m.png
new file mode 100644 (file)
index 0000000..a347513
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/m.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/o.png b/Open-ILS/web/images/format_icons/item_type/o.png
new file mode 100644 (file)
index 0000000..f7b5c7b
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/o.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/p.png b/Open-ILS/web/images/format_icons/item_type/p.png
new file mode 100644 (file)
index 0000000..f7b5c7b
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/p.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/r.png b/Open-ILS/web/images/format_icons/item_type/r.png
new file mode 100644 (file)
index 0000000..7b76d03
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/r.png differ
diff --git a/Open-ILS/web/images/format_icons/item_type/t.png b/Open-ILS/web/images/format_icons/item_type/t.png
new file mode 100644 (file)
index 0000000..2800684
Binary files /dev/null and b/Open-ILS/web/images/format_icons/item_type/t.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/2.png b/Open-ILS/web/images/format_icons/mattype/2.png
new file mode 100644 (file)
index 0000000..b874f44
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/2.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/5.png b/Open-ILS/web/images/format_icons/mattype/5.png
new file mode 100644 (file)
index 0000000..dba509d
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/5.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/a.png b/Open-ILS/web/images/format_icons/mattype/a.png
new file mode 100644 (file)
index 0000000..57ee12c
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/a.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/b.png b/Open-ILS/web/images/format_icons/mattype/b.png
new file mode 100644 (file)
index 0000000..c227660
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/b.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/c.png b/Open-ILS/web/images/format_icons/mattype/c.png
new file mode 100644 (file)
index 0000000..26f4818
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/c.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/d.png b/Open-ILS/web/images/format_icons/mattype/d.png
new file mode 100644 (file)
index 0000000..9f4b0f9
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/d.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/e.png b/Open-ILS/web/images/format_icons/mattype/e.png
new file mode 100644 (file)
index 0000000..96d0eed
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/e.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/f.png b/Open-ILS/web/images/format_icons/mattype/f.png
new file mode 100644 (file)
index 0000000..dcfd893
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/f.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/h.png b/Open-ILS/web/images/format_icons/mattype/h.png
new file mode 100644 (file)
index 0000000..8afcef9
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/h.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/i.png b/Open-ILS/web/images/format_icons/mattype/i.png
new file mode 100644 (file)
index 0000000..f36fe75
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/i.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/j.png b/Open-ILS/web/images/format_icons/mattype/j.png
new file mode 100644 (file)
index 0000000..84cc188
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/j.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/k.png b/Open-ILS/web/images/format_icons/mattype/k.png
new file mode 100644 (file)
index 0000000..96a9f35
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/k.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/l.png b/Open-ILS/web/images/format_icons/mattype/l.png
new file mode 100644 (file)
index 0000000..4ba36f1
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/l.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/m.png b/Open-ILS/web/images/format_icons/mattype/m.png
new file mode 100644 (file)
index 0000000..95e6652
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/m.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_downloadableebook.png b/Open-ILS/web/images/format_icons/mattype/media_downloadableebook.png
new file mode 100644 (file)
index 0000000..82f66ba
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_downloadableebook.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_electronicgames.png b/Open-ILS/web/images/format_icons/mattype/media_electronicgames.png
new file mode 100644 (file)
index 0000000..b696a7a
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_electronicgames.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_evideo.png b/Open-ILS/web/images/format_icons/mattype/media_evideo.png
new file mode 100644 (file)
index 0000000..09a7ea6
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_evideo.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_onlinejournal.png b/Open-ILS/web/images/format_icons/mattype/media_onlinejournal.png
new file mode 100644 (file)
index 0000000..65cac4c
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_onlinejournal.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_player.png b/Open-ILS/web/images/format_icons/mattype/media_player.png
new file mode 100644 (file)
index 0000000..64197e1
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_player.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_podcasts.png b/Open-ILS/web/images/format_icons/mattype/media_podcasts.png
new file mode 100644 (file)
index 0000000..d563fbb
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_podcasts.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_streamingaudio.png b/Open-ILS/web/images/format_icons/mattype/media_streamingaudio.png
new file mode 100644 (file)
index 0000000..51c31c3
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_streamingaudio.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_streamingvideo.png b/Open-ILS/web/images/format_icons/mattype/media_streamingvideo.png
new file mode 100644 (file)
index 0000000..3fe2cbe
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_streamingvideo.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/media_vhs.png b/Open-ILS/web/images/format_icons/mattype/media_vhs.png
new file mode 100644 (file)
index 0000000..11c1e42
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/media_vhs.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/n.png b/Open-ILS/web/images/format_icons/mattype/n.png
new file mode 100644 (file)
index 0000000..62b1af2
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/n.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/o.png b/Open-ILS/web/images/format_icons/mattype/o.png
new file mode 100644 (file)
index 0000000..c60d039
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/o.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/p.png b/Open-ILS/web/images/format_icons/mattype/p.png
new file mode 100644 (file)
index 0000000..009d292
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/p.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/q.png b/Open-ILS/web/images/format_icons/mattype/q.png
new file mode 100644 (file)
index 0000000..0949630
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/q.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/r.png b/Open-ILS/web/images/format_icons/mattype/r.png
new file mode 100644 (file)
index 0000000..65a2de2
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/r.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/s.png b/Open-ILS/web/images/format_icons/mattype/s.png
new file mode 100644 (file)
index 0000000..94cebfb
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/s.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/t.png b/Open-ILS/web/images/format_icons/mattype/t.png
new file mode 100644 (file)
index 0000000..437f91f
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/t.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/v.png b/Open-ILS/web/images/format_icons/mattype/v.png
new file mode 100644 (file)
index 0000000..53a192e
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/v.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/w.png b/Open-ILS/web/images/format_icons/mattype/w.png
new file mode 100644 (file)
index 0000000..1270685
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/w.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/x.png b/Open-ILS/web/images/format_icons/mattype/x.png
new file mode 100644 (file)
index 0000000..bcd621c
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/x.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/y.png b/Open-ILS/web/images/format_icons/mattype/y.png
new file mode 100644 (file)
index 0000000..a5db067
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/y.png differ
diff --git a/Open-ILS/web/images/format_icons/mattype/z.png b/Open-ILS/web/images/format_icons/mattype/z.png
new file mode 100644 (file)
index 0000000..ccf1fed
Binary files /dev/null and b/Open-ILS/web/images/format_icons/mattype/z.png differ
diff --git a/Open-ILS/web/images/go-btn-hover.png b/Open-ILS/web/images/go-btn-hover.png
new file mode 100644 (file)
index 0000000..9b878b2
Binary files /dev/null and b/Open-ILS/web/images/go-btn-hover.png differ
diff --git a/Open-ILS/web/images/go-btn.png b/Open-ILS/web/images/go-btn.png
new file mode 100644 (file)
index 0000000..24091c9
Binary files /dev/null and b/Open-ILS/web/images/go-btn.png differ
diff --git a/Open-ILS/web/images/go_but_long.gif b/Open-ILS/web/images/go_but_long.gif
new file mode 100644 (file)
index 0000000..79d2f9a
Binary files /dev/null and b/Open-ILS/web/images/go_but_long.gif differ
diff --git a/Open-ILS/web/images/golive.jpg b/Open-ILS/web/images/golive.jpg
new file mode 100644 (file)
index 0000000..8b34912
Binary files /dev/null and b/Open-ILS/web/images/golive.jpg differ
diff --git a/Open-ILS/web/images/gray-arrow.png b/Open-ILS/web/images/gray-arrow.png
new file mode 100644 (file)
index 0000000..bf56b6e
Binary files /dev/null and b/Open-ILS/web/images/gray-arrow.png differ
diff --git a/Open-ILS/web/images/green_check.png b/Open-ILS/web/images/green_check.png
new file mode 100644 (file)
index 0000000..9738bd8
Binary files /dev/null and b/Open-ILS/web/images/green_check.png differ
diff --git a/Open-ILS/web/images/header_left.gif b/Open-ILS/web/images/header_left.gif
new file mode 100644 (file)
index 0000000..9543795
Binary files /dev/null and b/Open-ILS/web/images/header_left.gif differ
diff --git a/Open-ILS/web/images/header_right.gif b/Open-ILS/web/images/header_right.gif
new file mode 100644 (file)
index 0000000..f00ff76
Binary files /dev/null and b/Open-ILS/web/images/header_right.gif differ
diff --git a/Open-ILS/web/images/hp-links-left.jpg b/Open-ILS/web/images/hp-links-left.jpg
new file mode 100644 (file)
index 0000000..0b8c9cf
Binary files /dev/null and b/Open-ILS/web/images/hp-links-left.jpg differ
diff --git a/Open-ILS/web/images/hp-links-mid.jpg b/Open-ILS/web/images/hp-links-mid.jpg
new file mode 100644 (file)
index 0000000..c9cdabf
Binary files /dev/null and b/Open-ILS/web/images/hp-links-mid.jpg differ
diff --git a/Open-ILS/web/images/hp-links-right.jpg b/Open-ILS/web/images/hp-links-right.jpg
new file mode 100644 (file)
index 0000000..63812f9
Binary files /dev/null and b/Open-ILS/web/images/hp-links-right.jpg differ
diff --git a/Open-ILS/web/images/locations.jpg b/Open-ILS/web/images/locations.jpg
new file mode 100644 (file)
index 0000000..56e7785
Binary files /dev/null and b/Open-ILS/web/images/locations.jpg differ
diff --git a/Open-ILS/web/images/login-bg.jpg b/Open-ILS/web/images/login-bg.jpg
new file mode 100644 (file)
index 0000000..46fc85f
Binary files /dev/null and b/Open-ILS/web/images/login-bg.jpg differ
diff --git a/Open-ILS/web/images/login-bg2.jpg b/Open-ILS/web/images/login-bg2.jpg
new file mode 100644 (file)
index 0000000..2c38853
Binary files /dev/null and b/Open-ILS/web/images/login-bg2.jpg differ
diff --git a/Open-ILS/web/images/login-box-bg.jpg b/Open-ILS/web/images/login-box-bg.jpg
new file mode 100644 (file)
index 0000000..caf036d
Binary files /dev/null and b/Open-ILS/web/images/login-box-bg.jpg differ
diff --git a/Open-ILS/web/images/login-btn-hover.png b/Open-ILS/web/images/login-btn-hover.png
new file mode 100644 (file)
index 0000000..442f33f
Binary files /dev/null and b/Open-ILS/web/images/login-btn-hover.png differ
diff --git a/Open-ILS/web/images/login-btn.gif b/Open-ILS/web/images/login-btn.gif
new file mode 100644 (file)
index 0000000..69d6a56
Binary files /dev/null and b/Open-ILS/web/images/login-btn.gif differ
diff --git a/Open-ILS/web/images/login-btn.png b/Open-ILS/web/images/login-btn.png
new file mode 100644 (file)
index 0000000..5548b99
Binary files /dev/null and b/Open-ILS/web/images/login-btn.png differ
diff --git a/Open-ILS/web/images/login-btn2.png b/Open-ILS/web/images/login-btn2.png
new file mode 100644 (file)
index 0000000..ff4af14
Binary files /dev/null and b/Open-ILS/web/images/login-btn2.png differ
diff --git a/Open-ILS/web/images/logout-btn-hover.png b/Open-ILS/web/images/logout-btn-hover.png
new file mode 100644 (file)
index 0000000..411fc01
Binary files /dev/null and b/Open-ILS/web/images/logout-btn-hover.png differ
diff --git a/Open-ILS/web/images/logout-btn.png b/Open-ILS/web/images/logout-btn.png
new file mode 100644 (file)
index 0000000..bd31a47
Binary files /dev/null and b/Open-ILS/web/images/logout-btn.png differ
diff --git a/Open-ILS/web/images/num_search_off.gif b/Open-ILS/web/images/num_search_off.gif
new file mode 100644 (file)
index 0000000..1062802
Binary files /dev/null and b/Open-ILS/web/images/num_search_off.gif differ
diff --git a/Open-ILS/web/images/num_search_on.gif b/Open-ILS/web/images/num_search_on.gif
new file mode 100644 (file)
index 0000000..f7d7829
Binary files /dev/null and b/Open-ILS/web/images/num_search_on.gif differ
diff --git a/Open-ILS/web/images/one_land.gif b/Open-ILS/web/images/one_land.gif
new file mode 100644 (file)
index 0000000..082b996
Binary files /dev/null and b/Open-ILS/web/images/one_land.gif differ
diff --git a/Open-ILS/web/images/pay-fines-btn-hover.png b/Open-ILS/web/images/pay-fines-btn-hover.png
new file mode 100644 (file)
index 0000000..b7708da
Binary files /dev/null and b/Open-ILS/web/images/pay-fines-btn-hover.png differ
diff --git a/Open-ILS/web/images/pay-fines-btn.png b/Open-ILS/web/images/pay-fines-btn.png
new file mode 100644 (file)
index 0000000..356433b
Binary files /dev/null and b/Open-ILS/web/images/pay-fines-btn.png differ
diff --git a/Open-ILS/web/images/pay_fines_btn.gif b/Open-ILS/web/images/pay_fines_btn.gif
new file mode 100644 (file)
index 0000000..eb4816f
Binary files /dev/null and b/Open-ILS/web/images/pay_fines_btn.gif differ
diff --git a/Open-ILS/web/images/place_hold.gif b/Open-ILS/web/images/place_hold.gif
new file mode 100644 (file)
index 0000000..3f72215
Binary files /dev/null and b/Open-ILS/web/images/place_hold.gif differ
diff --git a/Open-ILS/web/images/plus_sign.png b/Open-ILS/web/images/plus_sign.png
new file mode 100644 (file)
index 0000000..a17d58a
Binary files /dev/null and b/Open-ILS/web/images/plus_sign.png differ
diff --git a/Open-ILS/web/images/projectedmedia.jpg b/Open-ILS/web/images/projectedmedia.jpg
new file mode 100644 (file)
index 0000000..ba0e6d2
Binary files /dev/null and b/Open-ILS/web/images/projectedmedia.jpg differ
diff --git a/Open-ILS/web/images/question-mark.png b/Open-ILS/web/images/question-mark.png
new file mode 100644 (file)
index 0000000..b5f0f87
Binary files /dev/null and b/Open-ILS/web/images/question-mark.png differ
diff --git a/Open-ILS/web/images/questions.png b/Open-ILS/web/images/questions.png
new file mode 100644 (file)
index 0000000..9be69b2
Binary files /dev/null and b/Open-ILS/web/images/questions.png differ
diff --git a/Open-ILS/web/images/rdetail_arrow.png b/Open-ILS/web/images/rdetail_arrow.png
new file mode 100644 (file)
index 0000000..e464bf2
Binary files /dev/null and b/Open-ILS/web/images/rdetail_arrow.png differ
diff --git a/Open-ILS/web/images/reset_form_btn.gif b/Open-ILS/web/images/reset_form_btn.gif
new file mode 100644 (file)
index 0000000..6b70964
Binary files /dev/null and b/Open-ILS/web/images/reset_form_btn.gif differ
diff --git a/Open-ILS/web/images/reviews.gif b/Open-ILS/web/images/reviews.gif
new file mode 100644 (file)
index 0000000..b78fa25
Binary files /dev/null and b/Open-ILS/web/images/reviews.gif differ
diff --git a/Open-ILS/web/images/save-btn.png b/Open-ILS/web/images/save-btn.png
new file mode 100644 (file)
index 0000000..4565850
Binary files /dev/null and b/Open-ILS/web/images/save-btn.png differ
diff --git a/Open-ILS/web/images/save_btn.gif b/Open-ILS/web/images/save_btn.gif
new file mode 100644 (file)
index 0000000..f87282a
Binary files /dev/null and b/Open-ILS/web/images/save_btn.gif differ
diff --git a/Open-ILS/web/images/search_btn.gif b/Open-ILS/web/images/search_btn.gif
new file mode 100644 (file)
index 0000000..f2fdc9b
Binary files /dev/null and b/Open-ILS/web/images/search_btn.gif differ
diff --git a/Open-ILS/web/images/small-rss.png b/Open-ILS/web/images/small-rss.png
new file mode 100644 (file)
index 0000000..67d0f37
Binary files /dev/null and b/Open-ILS/web/images/small-rss.png differ
diff --git a/Open-ILS/web/images/starz.png b/Open-ILS/web/images/starz.png
new file mode 100644 (file)
index 0000000..4a79dd4
Binary files /dev/null and b/Open-ILS/web/images/starz.png differ
diff --git a/Open-ILS/web/images/sub_checked_hist_off.jpg b/Open-ILS/web/images/sub_checked_hist_off.jpg
new file mode 100644 (file)
index 0000000..7fda1c3
Binary files /dev/null and b/Open-ILS/web/images/sub_checked_hist_off.jpg differ
diff --git a/Open-ILS/web/images/sub_checked_hist_on.jpg b/Open-ILS/web/images/sub_checked_hist_on.jpg
new file mode 100644 (file)
index 0000000..703aac1
Binary files /dev/null and b/Open-ILS/web/images/sub_checked_hist_on.jpg differ
diff --git a/Open-ILS/web/images/sub_checked_out_off.jpg b/Open-ILS/web/images/sub_checked_out_off.jpg
new file mode 100644 (file)
index 0000000..0573fbd
Binary files /dev/null and b/Open-ILS/web/images/sub_checked_out_off.jpg differ
diff --git a/Open-ILS/web/images/sub_checked_out_on.jpg b/Open-ILS/web/images/sub_checked_out_on.jpg
new file mode 100644 (file)
index 0000000..97bb178
Binary files /dev/null and b/Open-ILS/web/images/sub_checked_out_on.jpg differ
diff --git a/Open-ILS/web/images/sub_holds_hist_off.jpg b/Open-ILS/web/images/sub_holds_hist_off.jpg
new file mode 100644 (file)
index 0000000..020abe9
Binary files /dev/null and b/Open-ILS/web/images/sub_holds_hist_off.jpg differ
diff --git a/Open-ILS/web/images/sub_holds_hist_on.jpg b/Open-ILS/web/images/sub_holds_hist_on.jpg
new file mode 100644 (file)
index 0000000..020abe9
Binary files /dev/null and b/Open-ILS/web/images/sub_holds_hist_on.jpg differ
diff --git a/Open-ILS/web/images/sub_holds_off.jpg b/Open-ILS/web/images/sub_holds_off.jpg
new file mode 100644 (file)
index 0000000..b888359
Binary files /dev/null and b/Open-ILS/web/images/sub_holds_off.jpg differ
diff --git a/Open-ILS/web/images/sub_holds_on.jpg b/Open-ILS/web/images/sub_holds_on.jpg
new file mode 100644 (file)
index 0000000..9505638
Binary files /dev/null and b/Open-ILS/web/images/sub_holds_on.jpg differ
diff --git a/Open-ILS/web/images/sub_prefs_info_off.jpg b/Open-ILS/web/images/sub_prefs_info_off.jpg
new file mode 100644 (file)
index 0000000..896e227
Binary files /dev/null and b/Open-ILS/web/images/sub_prefs_info_off.jpg differ
diff --git a/Open-ILS/web/images/sub_prefs_info_on.jpg b/Open-ILS/web/images/sub_prefs_info_on.jpg
new file mode 100644 (file)
index 0000000..0895969
Binary files /dev/null and b/Open-ILS/web/images/sub_prefs_info_on.jpg differ
diff --git a/Open-ILS/web/images/sub_prefs_notify_off.jpg b/Open-ILS/web/images/sub_prefs_notify_off.jpg
new file mode 100644 (file)
index 0000000..55df9da
Binary files /dev/null and b/Open-ILS/web/images/sub_prefs_notify_off.jpg differ
diff --git a/Open-ILS/web/images/sub_prefs_notify_on.jpg b/Open-ILS/web/images/sub_prefs_notify_on.jpg
new file mode 100644 (file)
index 0000000..fd536a8
Binary files /dev/null and b/Open-ILS/web/images/sub_prefs_notify_on.jpg differ
diff --git a/Open-ILS/web/images/sub_prefs_search_off.jpg b/Open-ILS/web/images/sub_prefs_search_off.jpg
new file mode 100644 (file)
index 0000000..89115f6
Binary files /dev/null and b/Open-ILS/web/images/sub_prefs_search_off.jpg differ
diff --git a/Open-ILS/web/images/sub_prefs_search_on.jpg b/Open-ILS/web/images/sub_prefs_search_on.jpg
new file mode 100644 (file)
index 0000000..3eab9fa
Binary files /dev/null and b/Open-ILS/web/images/sub_prefs_search_on.jpg differ
diff --git a/Open-ILS/web/images/submit_btn.gif b/Open-ILS/web/images/submit_btn.gif
new file mode 100644 (file)
index 0000000..5286943
Binary files /dev/null and b/Open-ILS/web/images/submit_btn.gif differ
diff --git a/Open-ILS/web/images/tool_back.gif b/Open-ILS/web/images/tool_back.gif
new file mode 100644 (file)
index 0000000..37d1278
Binary files /dev/null and b/Open-ILS/web/images/tool_back.gif differ
diff --git a/Open-ILS/web/images/tool_back.png b/Open-ILS/web/images/tool_back.png
new file mode 100644 (file)
index 0000000..41a13e2
Binary files /dev/null and b/Open-ILS/web/images/tool_back.png differ
diff --git a/Open-ILS/web/images/tool_font.gif b/Open-ILS/web/images/tool_font.gif
new file mode 100644 (file)
index 0000000..9dc10a9
Binary files /dev/null and b/Open-ILS/web/images/tool_font.gif differ
diff --git a/Open-ILS/web/images/tool_forward.gif b/Open-ILS/web/images/tool_forward.gif
new file mode 100644 (file)
index 0000000..db0d800
Binary files /dev/null and b/Open-ILS/web/images/tool_forward.gif differ
diff --git a/Open-ILS/web/images/tool_forward.png b/Open-ILS/web/images/tool_forward.png
new file mode 100644 (file)
index 0000000..582a6b9
Binary files /dev/null and b/Open-ILS/web/images/tool_forward.png differ
diff --git a/Open-ILS/web/images/tool_help.gif b/Open-ILS/web/images/tool_help.gif
new file mode 100644 (file)
index 0000000..2a3de86
Binary files /dev/null and b/Open-ILS/web/images/tool_help.gif differ
diff --git a/Open-ILS/web/images/tool_help.png b/Open-ILS/web/images/tool_help.png
new file mode 100644 (file)
index 0000000..3007c20
Binary files /dev/null and b/Open-ILS/web/images/tool_help.png differ
diff --git a/Open-ILS/web/images/tool_home.gif b/Open-ILS/web/images/tool_home.gif
new file mode 100644 (file)
index 0000000..9b83ccf
Binary files /dev/null and b/Open-ILS/web/images/tool_home.gif differ
diff --git a/Open-ILS/web/images/tool_home.png b/Open-ILS/web/images/tool_home.png
new file mode 100644 (file)
index 0000000..0620200
Binary files /dev/null and b/Open-ILS/web/images/tool_home.png differ
diff --git a/Open-ILS/web/images/tool_mail.gif b/Open-ILS/web/images/tool_mail.gif
new file mode 100644 (file)
index 0000000..83c3573
Binary files /dev/null and b/Open-ILS/web/images/tool_mail.gif differ
diff --git a/Open-ILS/web/images/tool_print.gif b/Open-ILS/web/images/tool_print.gif
new file mode 100644 (file)
index 0000000..d3d7ee3
Binary files /dev/null and b/Open-ILS/web/images/tool_print.gif differ
diff --git a/Open-ILS/web/images/tool_print.png b/Open-ILS/web/images/tool_print.png
new file mode 100644 (file)
index 0000000..2c0dc0b
Binary files /dev/null and b/Open-ILS/web/images/tool_print.png differ
diff --git a/Open-ILS/web/images/utils-corner-left.png b/Open-ILS/web/images/utils-corner-left.png
new file mode 100644 (file)
index 0000000..db70a75
Binary files /dev/null and b/Open-ILS/web/images/utils-corner-left.png differ
diff --git a/Open-ILS/web/images/utils-corner-mid.png b/Open-ILS/web/images/utils-corner-mid.png
new file mode 100644 (file)
index 0000000..80d4857
Binary files /dev/null and b/Open-ILS/web/images/utils-corner-mid.png differ
diff --git a/Open-ILS/web/images/utils-corner-right.jpg b/Open-ILS/web/images/utils-corner-right.jpg
new file mode 100644 (file)
index 0000000..1559897
Binary files /dev/null and b/Open-ILS/web/images/utils-corner-right.jpg differ
diff --git a/Open-ILS/web/images/utils-corner-right.png b/Open-ILS/web/images/utils-corner-right.png
new file mode 100644 (file)
index 0000000..303ab75
Binary files /dev/null and b/Open-ILS/web/images/utils-corner-right.png differ
diff --git a/Open-ILS/web/images/utils-corner.jpg b/Open-ILS/web/images/utils-corner.jpg
new file mode 100644 (file)
index 0000000..4932a28
Binary files /dev/null and b/Open-ILS/web/images/utils-corner.jpg differ
diff --git a/Open-ILS/web/images/view_my_list.png b/Open-ILS/web/images/view_my_list.png
new file mode 100644 (file)
index 0000000..d5f1b83
Binary files /dev/null and b/Open-ILS/web/images/view_my_list.png differ
diff --git a/Open-ILS/web/images/view_my_list_hover.png b/Open-ILS/web/images/view_my_list_hover.png
new file mode 100644 (file)
index 0000000..369cb1a
Binary files /dev/null and b/Open-ILS/web/images/view_my_list_hover.png differ
diff --git a/Open-ILS/web/js/ui/default/opac/simple.js b/Open-ILS/web/js/ui/default/opac/simple.js
new file mode 100644 (file)
index 0000000..d71c98a
--- /dev/null
@@ -0,0 +1,50 @@
+/* Keep this dead simple. No dojo. */
+function $(s) { return document.getElementById(s); }
+function removeClass(node, cls) {
+    if (!node || !node.className) return;
+    node.className =
+        node.className.replace(new RegExp("\\b" + cls + "\\b", "g"), "");
+}
+function addClass(node, cls) {
+    if (!node) return;
+    removeClass(node, cls);
+    if (!node.className) node.className = cls;
+    else node.className += ' ' + cls;
+}
+function unHideMe(node) { removeClass(node, "hide_me"); }
+function hideMe(node) { addClass(node, "hide_me"); }
+
+var _search_row_template;
+function addSearchRow() {
+    if (!_search_row_template) {
+        t = $("adv_global_row").cloneNode(true);
+        t.id = null;
+        _search_row_template = t;
+    }
+
+    $("adv_global_tbody").insertBefore(
+        _search_row_template.cloneNode(true),
+        $("adv_global_addrow")
+    );
+}
+function print_node(node_id) {
+    var iframe = document.createElement("iframe");
+    var source_node = document.getElementById(node_id);
+    source_node.parentNode.appendChild(iframe);
+
+    var iwin = iframe.contentWindow;
+
+    /* These next three statements are only needed by IE, but they don't
+     * hurt FF/Chrome. */
+    iwin.document.open();
+    iwin.document.write(    /* XXX make better/customizable? */
+        "<html><head><title>Recipt</title></head><body></body></html>"
+    );
+    iwin.document.close();
+
+    iwin.document.body.innerHTML = source_node.innerHTML;
+    iframe.focus();
+
+    try { iframe.print(); } catch (e) { iwin.print(); }
+    setTimeout(function() { iframe.style.display = "none"; }, 3500);
+}
diff --git a/Open-ILS/web/js/ui/default/opac/staff.js b/Open-ILS/web/js/ui/default/opac/staff.js
new file mode 100644 (file)
index 0000000..abb8ce8
--- /dev/null
@@ -0,0 +1,22 @@
+/* staff client integration functions */
+function debug(msg){dump(msg+'\n')}
+var eventCache={};
+function attachEvt(scope, name, action) {
+    if(!eventCache[scope]) eventCache[scope] = {};
+    if(!eventCache[scope][name]) eventCache[scope][name] = [];
+    eventCache[scope][name].push(action);
+}
+function runEvt(scope, name) {
+    debug('running event '+scope+':'+name);
+    var args = Array.prototype.slice.call(arguments).slice(2);
+    if(eventCache[scope]) {
+        var evt = eventCache[scope][name];
+        for(var i in evt) {evt[i].apply(evt[i], args);}
+    } 
+}
+window.onload = function() {
+    // record details page events
+    var rec = location.href.match(/\/opac\/record\/(\d+)/);
+    if(rec && rec[1]) { runEvt('rdetail', 'recordRetrieved', rec[1]); }
+    // fire other events the staff client is expecting...
+}
diff --git a/Open-ILS/web/templates/default/opac-poc/base.tt2 b/Open-ILS/web/templates/default/opac-poc/base.tt2
new file mode 100644 (file)
index 0000000..6d54607
--- /dev/null
@@ -0,0 +1,12 @@
+<!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" />
+        [% BLOCK html_head; END; # provide a default that can be overridden %]
+        [% PROCESS html_head %]
+    </head>
+    <body>
+        [% content %] 
+    </body>
+</html>
diff --git a/Open-ILS/web/templates/default/opac-poc/common.tt2 b/Open-ILS/web/templates/default/opac-poc/common.tt2
new file mode 100644 (file)
index 0000000..c4caa0e
--- /dev/null
@@ -0,0 +1,58 @@
+[% 
+    # Org Unit Selector Widget : 
+    #   PROCESS build_org_selector id='selector-id' name='selector-name'
+    BLOCK build_org_selector;
+        first_run = 0;
+        IF !org_unit;
+            org_unit = ctx.aou_tree;
+            first_run = 1;
+%]
+    <select id='[% id %]' name='[% name %]'>
+    [% END %]
+        <option value='[% org_unit.id %]' [% IF org_unit.id == value %] selected='selected' [% END %]>
+            [% 
+                pad = org_unit.ou_type.depth * 2;
+                FOR idx IN [0..pad]; '&nbsp;'; END;
+                org_unit.name;
+            %]
+        </option>
+        [% FOR child IN org_unit.children; PROCESS build_org_selector org_unit = child; END %]
+    [% IF first_run %]
+    </select>
+    [% END %]
+[% END %]
+
+[% PROCESS 'default/opac/marc_attrs.tt2' %]
+[%  USE date;
+    USE money = format('$%.2f');
+    icon_by_mattype = {     # XXX KCLS-specific
+        "a" => "media_book.jpg",
+        "b" => "media_magazines.jpg",
+        "c" => "media_printedmusic.jpg",
+        "d" => "media_microform.jpg",
+        "e" => "media_equipment.jpg",
+        "f" => "media_films.jpg",
+        "g" => "",
+        "h" => "media_dvd.jpg",
+        "i" => "media_bookoncassette.jpg",
+        "j" => "media_musiccd.jpg",
+        "k" => "media_musiccassette.jpg",
+        "l" => "media_musicrecord.jpg",
+        "m" => "media_software.jpg",
+        "n" => "media_bookoncd.jpg",
+        "o" => "media_kit.jpg",
+        "p" => "media_newspaper.jpg",
+        "q" => "media_largeprint.jpg",
+        "r" => "media_3dobject.jpg",
+        "s" => "media_slide.jpg",
+        "t" => "media_online.jpg",
+        "u" => "media_eaudio.jpg",
+        "v" => "media_ebooktext.jpg",
+        "w" => "media_eaudio.jpg",
+        "x" => "media_downloadmusic.jpg",
+        "y" => "media_downloadvideo.jpg",
+        "z" => "media_map.jpg",
+        "2" => "media_cassettewithbook.jpg",
+        "5" => "media_cdwithbook.jpg"
+    };
+%]
diff --git a/Open-ILS/web/templates/default/opac-poc/home.tt2 b/Open-ILS/web/templates/default/opac-poc/home.tt2
new file mode 100644 (file)
index 0000000..03b2ad1
--- /dev/null
@@ -0,0 +1,24 @@
+[% ctx.page_title = "Home" %]
+
+[% BLOCK html_head %]
+<style>
+    #home_div { text-align: center; width: 100%; margin-top: 30px;}
+</style>
+[% END %]
+
+[% WRAPPER "default/opac/base.tt2" %]
+[% PROCESS "default/opac/common.tt2" %]
+
+<div id='home_div'>
+    <img src='/images/eg_logo.jpg'/>
+    <br/><br/>
+    <form action='./results' method='GET'>
+        <input type='text' name='query' size='50' value='[% query %]'/>
+        [% PROCESS build_org_selector name='loc' %]
+        <input type='submit' value='[% l('Go!') %]'/>
+        <input type='hidden' name='page' value='0'/>
+    </form>
+</div>
+
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/login.tt2 b/Open-ILS/web/templates/default/opac-poc/login.tt2
new file mode 100644 (file)
index 0000000..1bae958
--- /dev/null
@@ -0,0 +1,32 @@
+[% BLOCK html_head %]
+<style>
+</style>
+[% END %]
+
+[% 
+    USE CGI;
+    WRAPPER "default/opac/base.tt2"; 
+    ctx.page_title = "Login";
+%]
+
+<div style='width:400px; text-align:center; border: 1px solid #888'>
+    <form method='POST'>
+        <table>
+            <tr>
+                <td>Username or Barcode</td>
+                <td><input name='username' type='text'/></td>
+            </tr>
+            <tr>
+                <td>Password</td>
+                <td><input name='password' type='password'/></td>
+            </tr>
+            <tr>
+                <td colspan='2' style='text-align:center'>
+                    <input type='submit'/>
+                </td>
+            </tr>
+        </table>
+        <input type='hidden' name='redirect_to' value='[% CGI.param('redirect_to') || ctx.referer | replace('^http:', 'https:') %]'/>
+    </form>
+</div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/marc_attrs.tt2 b/Open-ILS/web/templates/default/opac-poc/marc_attrs.tt2
new file mode 100644 (file)
index 0000000..73f12c3
--- /dev/null
@@ -0,0 +1,18 @@
+[% 
+    # Extract MARC fields from XML
+    #   get_marc_attrs( { marc_xml => doc } )
+    BLOCK get_marc_attrs;
+        xml = args.marc_xml;
+        args.isbn = xml.findnodes('//*[@tag="020"]/*[@code="a"]').textContent;
+        args.upc = xml.findnodes('//*[@tag="024"]/*[@code="a"]').textContent;
+        args.issn = xml.findnodes('//*[@tag="022"]/*[@code="a"]').textContent;
+        args.title = xml.findnodes('//*[@tag="245"]/*[@code="a"]').textContent;
+        args.author = xml.findnodes('//*[@tag="100"]/*[@code="a"]').textContent;
+        args.publisher = xml.findnodes('//*[@tag="260"]/*[@code="b"]').textContent;
+        args.pubdate = xml.findnodes('//*[@tag="260"]/*[@code="c"]').textContent;
+        args.mattype = xml.findnodes('//*[@tag="998"]/*[@code="d"]').textContent; # XXX this is KCLS-specific and will need to change
+
+        # clean up the ISBN
+        args.isbn_clean = args.isbn.replace('\ .*', '');
+    END;
+%]
diff --git a/Open-ILS/web/templates/default/opac-poc/myopac/_links.tt2 b/Open-ILS/web/templates/default/opac-poc/myopac/_links.tt2
new file mode 100644 (file)
index 0000000..b034198
--- /dev/null
@@ -0,0 +1,20 @@
+<div>[%
+pages = [
+    {url => "main", name => "My Account"},
+    {url => "circs", name => "Items Out"},
+    {url => "holds", name => "Items on Hold"},
+    {url => "fines", name => "Fines"},
+    {url => "prefs", name => "Account Preferences"},
+    {url => "bookbags", name => "My Bookbags"}
+];
+FOREACH page IN pages %]
+    <span style="margin: 0 0.5em;">
+    [% IF page.url != myopac_page %]<a href="[% page.url %]">[% END;
+        page.name;
+        IF page.url != myopac_page %]</a>
+    [% ELSE; ctx.page_title = page.name; END %]</span>
+[% END %]</div>
+<ul>
+    <li><a href="../home">Home</a></li>
+    <li><a href="../logout">Logout</a></li>
+</ul>
diff --git a/Open-ILS/web/templates/default/opac-poc/myopac/bookbags.tt2 b/Open-ILS/web/templates/default/opac-poc/myopac/bookbags.tt2
new file mode 100644 (file)
index 0000000..0ac2dc0
--- /dev/null
@@ -0,0 +1,52 @@
+[% BLOCK html_head %]
+<style>
+    table { width: 100%; text-align: center; padding: 20px; margin-top: 30px; }
+    table { border-collapse: collapse; }
+    table { padding: 3px; border-bottom: 1px solid #ddd; text-align: left;}
+    table tr:nth-child(odd) { background-color:#ded; }
+    #action_div { width: 95%; }
+    #action-buttons { float:right; }
+</style>
+[% END %]
+
+[% WRAPPER "default/opac/base.tt2" %]
+[% INCLUDE "default/opac/myopac/_links.tt2" myopac_page = "bookbags" %]
+
+[% IF ctx.bookbags.size == 0 %]
+<b>No Bookbags</b>
+[% STOP; END %]
+
+<form method='POST' id='bbag-form'>
+    <div id='action_div'>
+        <div id='action-buttons'>
+            <select name='action'>
+                <option value='delete'>Delete Selected</option>
+                <option value='delete_all'>Delete All</option>
+            </select>
+            <input type='submit' value='Go'/>
+        </div>
+    </div>
+    <table>
+        <thead>
+            <tr>
+                <th>Name</th>
+                <th>Public</th>
+                <th>Created On</th>
+                <th>Items</th>
+            </tr>
+        </thead>
+        <tbody>
+            [% FOR bbag IN ctx.bookbags %]
+                <tr [% IF loop.count % 2 == 1 %] class='bbag-table-odd' [% END %]>
+                    <td>[% bbag.name %]</td>
+                    <td>[% bbag.pub == 't' ? 'Yes' : 'No' %]</td>
+                    <td>[% date.format(ctx.parse_datetime(bbag.create_time),'%Y-%m-%d') %]</td>
+                    <td>XXX</td>
+                </tr>
+            [% END %]
+        </tbody>
+    </table>
+</form>
+
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/myopac/circs.tt2 b/Open-ILS/web/templates/default/opac-poc/myopac/circs.tt2
new file mode 100644 (file)
index 0000000..5f08d2e
--- /dev/null
@@ -0,0 +1,77 @@
+[% BLOCK html_head %]
+<style>
+    table { width: 100%; text-align: center; padding: 20px; margin-top: 30px; }
+    table { border-collapse: collapse; }
+    table { padding: 3px; border-bottom: 1px solid #ddd; text-align: left;}
+    #action_div { width: 95%; }
+    .renew-summary { float:left; padding-right: 10px;}
+    #action-buttons { float:right; }
+    .circ-table-odd { background-color:#ded; }
+    .failure-text { font-weight: bold; color: red; }
+    #circ-form { margin-top: 20px; }
+</style>
+[% END %]
+
+[% PROCESS "default/opac/common.tt2" %]
+[% WRAPPER "default/opac/base.tt2" %]
+[% INCLUDE "default/opac/myopac/_links.tt2" myopac_page = "circs" %]
+
+[% IF ctx.circs.size == 0 %]
+<b>No Items Checked Out</b>
+[% STOP; END %]
+
+<form method='POST' id='circ-form'>
+    <div id='action_div'>
+        [% IF ctx.success_renewals > 0 %]
+            <div class='renew-summary'><b>Successfully renewed [% ctx.success_renewals %] items.</b></div>
+        [% END %]
+        [% IF ctx.failed_renewals > 0 %]
+            <div class='renew-summary'><b>Failed to renew [% ctx.failed_renewals %] items.</b></div>
+        [% END %]
+        <div id='action-buttons'>
+            <button type='submit' value='renew' name='action'>Renew Selected</button>
+            <button type='submit' value='renew_all' name='action'>Renew All</button>
+        </div>
+    </div>
+    <table>
+        <thead>
+            <tr>
+                <th>Title</th>
+                <th>Author</th>
+                <th>Due Date</th>
+                <th>Renewals Remaining</th>
+                <th>Select</th>
+            </tr>
+        </thead>
+        <tbody>
+            [% FOR circ IN ctx.circs %]
+                [% attrs = {marc_xml => circ.marc_xml}; %]
+                [% PROCESS get_marc_attrs args=attrs; %]
+
+                <tr [% IF loop.count % 2 == 1 %] class='circ-table-odd' [% END %]>
+                    <td><a href='../record/[% circ.circ.target_copy.call_number.record.id %]'>[% attrs.title %]</a></td>
+                    <td><a href='../results?query=au:[% attrs.author | url %]'>[% attrs.author %]</a></td>
+                    <td>[% date.format(ctx.parse_datetime(circ.circ.due_date),'%Y-%m-%d') %]</td>
+                    <td><em>[% circ.circ.renewal_remaining %]</em></td>
+                    <td><input name='circ' value='[% circ.circ.id %]' type='checkbox' 
+                        [% IF circ.circ.renewal_remaining < 1 %] disabled='disabled' [% END %]/></td>
+                </tr>
+
+                [% IF circ.renewal_response and circ.renewal_response.textcode != 'SUCCESS' %]
+                <tr [% IF loop.count % 2 == 1 %] class='circ-table-odd' [% END %]>
+                    <td colspan='0'>
+                        <div class='failure-text'>
+                            [% circ.renewal_response.textcode %] 
+                            [% IF circ.renewal_response.payload.fail_part and circ.renewal_response.payload.fail_part != circ.renewal_response.textcode %]
+                                [% circ.renewal_response.payload.fail_part %]
+                            [% END %]
+                        </div>
+                    </td>
+                </tr>
+                [% END %]
+            [% END %]
+        </tbody>
+    </table>
+</form>
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/myopac/fines.tt2 b/Open-ILS/web/templates/default/opac-poc/myopac/fines.tt2
new file mode 100644 (file)
index 0000000..727322f
--- /dev/null
@@ -0,0 +1,107 @@
+[% BLOCK html_head %]
+<style>
+    table { width: 100%; text-align: center; padding: 20px; margin-top: 30px; }
+    table { border-collapse: collapse; }
+    table { padding: 3px; border-bottom: 1px solid #ddd; text-align: left;}
+    table tr:nth-child(odd) { background-color:#ded; }
+    h2 { margin-bottom: 0; }
+</style>
+[% END %]
+
+[% PROCESS "default/opac/common.tt2" %]
+[% WRAPPER "default/opac/base.tt2" %]
+[% INCLUDE "default/opac/myopac/_links.tt2" myopac_page = "fines" %]
+<h2>Summary</h2>
+<table>
+    <thead>
+        <tr>
+            <th>Total Owed</th>
+            <th>Total Paid</th>
+            <th>Balance Owed</th>
+        </tr>
+    </thead>
+    <tbody>
+        <tr>
+            <td>[% money(ctx.fines.total_owed) %]</td>
+            <td>[% money(ctx.fines.total_paid) %]</td>
+            <td>[% money(ctx.fines.balance_owed) %]</td>
+        </tr>
+    </tbody>
+</table>
+
+[% IF ctx.fines.circulation.size > 0 %]
+<h2>Overdue materials</h2>
+<table>
+    <thead>
+        <tr>
+            <th>Title</th>
+            <th>Author</th>
+            <th>Checkout Date</th>
+            <th>Due Date</th>
+            <th>Date Returned</th>
+            <th>Balance Owed</th>
+        </tr>
+    </thead>
+    <tbody>
+    [% FOR f IN ctx.fines.circulation %]
+        [% attrs = {marc_xml => f.marc_xml}; %]
+        [% PROCESS get_marc_attrs args=attrs; %]
+        <tr>
+            <td>[% attrs.title %]</td>
+            <td>[% attrs.author %]</td>
+            <td>[% date.format(
+                ctx.parse_datetime(f.xact.circulation.xact_start), "%Y-%m-%d"
+            ) %]</td>
+            <td>[% date.format(
+                ctx.parse_datetime(f.xact.circulation.due_date), "%Y-%m-%d"
+            ) %]</td>
+            <td>[%
+                IF f.xact.circulation.checkin_time;
+                    date.format(
+                        ctx.parse_datetime(f.xact.circulation.checkin_time),
+                        "%Y-%m-%d"
+                    );
+                END %]</td><!-- XXX TODO display stop_fines_time if set? Display something instead of blank like "fines accruing" ? -->
+            <td>[% money(f.xact.balance_owed) %]</td>
+        </tr>
+    [% END %]
+    </tbody>
+</table>
+[% END %]
+
+[% IF ctx.fines.grocery.size > 0 %]
+<h2>Other Fees</h2>
+<table>
+    <thead>
+        <tr>
+            <th>Transaction Start Time</th>
+            <th>Last Payment Time</th>
+            <th>Initial Amount Owed</th>
+            <th>Total Amount Paid</th>
+            <th>Balance Owed</th>
+            <th>Billing Type</th>
+        </tr>
+    </thead>
+    <tbody>
+    [% FOR f IN ctx.fines.grocery %]
+        <tr>
+            <td>[%
+                date.format(
+                    ctx.parse_datetime(f.xact.xact_start), "%Y-%m-%d"
+                ) %]</td>
+            <td>[% IF f.xact.last_payment_ts;
+                    date.format(
+                        ctx.parse_datetime(f.xact.last_payment_ts), "%Y-%m-%d"
+                        );
+                    END %]</td>
+            <td>[% money(f.xact.total_owed) %]</td>
+            <td>[% money(f.xact.total_paid) %]</td>
+            <td>[% money(f.xact.balance_owed) %]</td>
+            <td>[% f.xact.last_billing_type %]</td>
+        </tr>
+    [% END %]
+    </tbody>
+</table>
+[% END %]
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/myopac/holds.tt2 b/Open-ILS/web/templates/default/opac-poc/myopac/holds.tt2
new file mode 100644 (file)
index 0000000..ce09725
--- /dev/null
@@ -0,0 +1,94 @@
+[% BLOCK html_head %]
+<style>
+    table { width: 100%; text-align: center; padding: 20px; margin-top: 30px; }
+    table { border-collapse: collapse; }
+    table { padding: 3px; border-bottom: 1px solid #ddd; text-align: left;}
+    table tr:nth-child(odd) { background-color:#ded; }
+    #action_div { width: 95%; }
+    #action-buttons { float:right; }
+</style>
+[% END %]
+
+[%  PROCESS "default/opac/common.tt2";
+    WRAPPER "default/opac/base.tt2";
+    INCLUDE "default/opac/myopac/_links.tt2" myopac_page = "holds" %]
+
+[% IF ctx.holds.size == 0 %]
+<b>No Items On Hold</b>
+[% STOP; END %]
+
+<form method='POST'>
+
+    <div id='action_div'>
+        <div id='action-buttons'>
+            <select name='action'>
+                <option value='cancel'>Cancel Selected</option>
+                <option value='cancel_all'>Cancel All</option>
+                <option value='suspend'>Suspend Selected</option>
+                <option value='suspend_all'>Suspend All</option>
+                <option value='activate'>Activate Selected</option>
+                <option value='activate_all'>Activate All</option>
+            </select>
+            <input type='Submit' value='Go'/>
+        </div>
+    </div>
+    <table>
+        <thead>
+            <tr>
+                <th>Title</th>
+                <th>Author</th>
+                <th>Formats</th>
+                <th>Pickup Location</th>
+                <th>Status</th>
+                <th>Active</th>
+                <th>Activate on...</th>
+                <th>Expiration Date</th>
+                <th>Select</th>
+            </tr>
+        </thead>
+        <tbody>
+            [% FOR hold IN ctx.holds %]
+                [% attrs = {marc_xml => hold.marc_xml}; %]
+                [% PROCESS get_marc_attrs args=attrs; %]
+            <tr>
+                <td><a href='../record/[% hold.hold.bre.id %]'>[% attrs.title %]</a></td>
+                <td><a href='../results?query=au:[% attrs.author | url %]'>[% attrs.author %]</a></td>
+                <td>
+                    [%
+                        key = attrs.mattype;
+                        format_desc = ctx.find_citm(key).value;
+                        icon_filename = icon_by_mattype.$key;
+                        IF icon_filename;
+                    %]<!-- XXX in situations where we might show M-type holds, this won't be good enough -->
+                    <img alt="[% format_desc %]" title="[% format_desc %]"
+                        src="/images/mattype/[% icon_filename %]" />
+                    [%  END %]
+                </td>
+                <td>[% ctx.find_aou(hold.hold.hold.pickup_lib).name %]</td>
+                <td>[%
+                    IF hold.hold.status == 4;
+                        "Available";
+                    ELSIF hold.hold.estimated_wait;
+                        "Estimated wait (days): "; hold.hold.estimated_wait;
+                    ELSIF hold.hold.status == 3;
+                        "In Transit";
+                    ELSIF hold.hold.status < 3;
+                        "Waiting for copy";
+                    END;
+                %]</td>
+                <td>[% IF hold.hold.hold.frozen == 't' %] No [% ELSE %] Yes [% END %]</td>
+                <td>[% 
+                    IF hold.hold.hold.frozen == 't' AND hold.hold.hold.thaw_date;
+                        date.format(ctx.parse_datetime(hold.hold.hold.thaw_date),'%Y-%m-%d'); 
+                    ELSE;
+                        '-';
+                    END 
+                %]</td>
+                <td>[% hold.hold.hold.expire_time ? hold.hold.hold.expire_time : '-' %]</td>
+                <td><input type='checkbox' name='hold_id' value='[% hold.hold.hold.id %]'/></td>
+            </tr>
+            [% END %]
+        </tbody>
+    </table>
+</form> 
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/myopac/main.tt2 b/Open-ILS/web/templates/default/opac-poc/myopac/main.tt2
new file mode 100644 (file)
index 0000000..33a533e
--- /dev/null
@@ -0,0 +1,39 @@
+[% BLOCK html_head %]
+<style>
+    table { text-align: center; padding: 20px; margin-top: 30px; border-collapse: collapse; }
+    table td { padding: 5px 15px 5px 15px; border-bottom: 1px solid #ddd; text-align: left;}
+    table tr:nth-child(odd) { background-color:#ded; }
+</style>
+[% END %]
+
+[% WRAPPER "default/opac/base.tt2" %]
+[% INCLUDE "default/opac/myopac/_links.tt2" myopac_page = "main" %]
+<table>
+    <tr>
+        <td>First Name</td>
+        <td>[% ctx.user.first_given_name %]</td>
+    </tr>
+    <tr>
+        <td>Middle Name</td>
+        <td>[% ctx.user.second_given_name %]</td>
+    </tr>
+    <tr>
+        <td>Last Name</td>
+        <td>[% ctx.user.family_name %]</td>
+    </tr>
+    <tr>
+        <td>Library Card</td>
+        <td>[% ctx.user.card.barcode %]</td>
+    </tr>
+    <tr>
+        <td>Email Address</td>
+        <td>[% ctx.user.email %]</td>
+        <td><a href='update_email'>Change</a></td>
+    </tr>
+    <tr>
+        <td>Phone</td>
+        <td>[% ctx.user.day_phone %]</td>
+    </tr>
+</table>
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/myopac/prefs.tt2 b/Open-ILS/web/templates/default/opac-poc/myopac/prefs.tt2
new file mode 100644 (file)
index 0000000..d9a60ba
--- /dev/null
@@ -0,0 +1,15 @@
+[% BLOCK html_head %]
+<style>
+    table { width: 100%; text-align: center; padding: 20px; margin-top: 30px; }
+    table { border-collapse: collapse; }
+    table { padding: 3px; border-bottom: 1px solid #ddd; text-align: left;}
+    table tr:nth-child(odd) { background-color:#ded; }
+</style>
+[% END %]
+
+[% WRAPPER "default/opac/base.tt2" %]
+[% INCLUDE "default/opac/myopac/_links.tt2" myopac_page = "prefs" %]
+<p><em>XXX TODO Need to find out whether the list of pref fields can/should be generated
+    from db entries or something.</em></p>
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/myopac/update_email.tt2 b/Open-ILS/web/templates/default/opac-poc/myopac/update_email.tt2
new file mode 100644 (file)
index 0000000..7666c8f
--- /dev/null
@@ -0,0 +1,20 @@
+[% BLOCK html_head %]
+<style>
+    table { text-align: center; padding: 20px; margin-top: 30px; border-collapse: collapse; }
+    table td { padding: 5px 15px 5px 15px; border-bottom: 1px solid #ddd; text-align: left;}
+    table tr:nth-child(odd) { background-color:#ded; }
+</style>
+[% END %]
+
+[% WRAPPER "default/opac/base.tt2" %]
+[% INCLUDE "default/opac/myopac/_links.tt2" %]
+
+<form method='POST'>
+    <table> 
+        <tr><td>Current Email</td><td>[% ctx.user.email %]</td></tr>
+        <tr><td>New Email</td><td><input type='text' name='email'/></td></tr>
+    </table>
+    <input type='submit'/>
+</form>
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/place_hold.tt2 b/Open-ILS/web/templates/default/opac-poc/place_hold.tt2
new file mode 100644 (file)
index 0000000..bfbee07
--- /dev/null
@@ -0,0 +1,33 @@
+[% BLOCK html_head %]
+<style>
+</style>
+[% END %]
+
+[% 
+    USE CGI;
+    PROCESS "default/opac/common.tt2";
+    WRAPPER "default/opac/base.tt2"; 
+    ctx.page_title = "Place Hold";
+    attrs = {marc_xml => ctx.marc_xml};
+    PROCESS get_marc_attrs args=attrs;
+%]
+
+
+<div>
+    <div>Placing hold on [% attrs.title %], by [% attrs.author %]</div>
+    [% IF ctx.hold_success %] 
+        <div>Succeeded</div>
+    [% ELSIF ctx.hold_failed %]
+        <div>Failed...</div>
+    [% ELSE %]
+    <form action='place_hold' method='POST'>
+        Choose a pickup Library [% PROCESS build_org_selector name='pickup_lib' value=ctx.default_pickup_lib %]
+        <input type='Submit'/>
+        <input type='hidden' name='hold_target' value='[% CGI.param('hold_target') | html %]'/>
+        <input type='hidden' name='hold_type' value='[% CGI.param('hold_type') | html %]'/>
+        <input type='hidden' name='redirect_to' value='[% ctx.referer | html %]'/>
+    </form>
+    [% END %]
+</div>
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/record.tt2 b/Open-ILS/web/templates/default/opac-poc/record.tt2
new file mode 100644 (file)
index 0000000..24f1203
--- /dev/null
@@ -0,0 +1,82 @@
+[% BLOCK html_head %]
+<style>
+    table { width: 100%; padding: 20px; margin-top: 30px; }
+    table { border-collapse: collapse; }
+    table td { padding: 3px; border-bottom: 1px solid #ddd; text-align: left;}
+    table th { padding: 3px; border-bottom: 1px solid #ddd; text-align: left;}
+    table tr:nth-child(even) { background-color:#ded; }
+    #record_table td { padding-left: 15px; padding-right: 15px; }
+</style>
+[% END %]
+
+[% 
+    WRAPPER "default/opac/base.tt2"; 
+    PROCESS "default/opac/common.tt2";
+    ctx.page_title = "Details";
+    record = ctx.record;
+    attrs = {marc_xml => ctx.marc_xml};
+    PROCESS get_marc_attrs args=attrs;
+%]
+
+<div id='detail_div'>
+    <table id='record_table' style='width:auto'>
+        <tr>
+            <td rowspan='10' style='width:55px; vertical-align:top; padding-right:4px;'>
+                [% IF attrs.isbn_clean || attrs.upc %]
+                <img width='50' height='70' src='[% ctx.media_prefix %]/opac/extras/ac/jacket/small/[% attrs.isbn_clean || attrs.upc %]'/>
+                [% END %]
+            </td>
+        </tr>
+        [% IF attrs.title %]<tr><td>Title</td><td>[% attrs.title %]</td></tr>[% END %]
+        [% IF attrs.author %]<tr><td>Author</td><td><a href='../results?query=au:[% attrs.author | uri %]'>[% attrs.author %]</a></td></tr>[% END %]
+        [% IF attrs.isbn %]<tr><td>ISBN</td><td>[% attrs.isbn %]</td></tr>[% END %]
+        [% IF attrs.issn %]<tr><td>ISSN</td><td>[% attrs.issn %]</td></tr>[% END %]
+        [% IF attrs.upc %]<tr><td>UPC</td><td>[% attrs.upc %]</td></tr>[% END %]
+        [% IF attrs.pubdate %]<tr><td>Publication Date</td><td>[% attrs.pubdate %]</td></tr>[% END %]
+        [% IF attrs.publisher %]<tr><td>Publishere</td><td>[% attrs.publisher %]</td></tr>[% END %]
+        <tr>
+            <td>Subjects</td>
+            <td>
+            [% FOR node IN ctx.marc_xml.findnodes('//*[@tag="650"]') %]
+                [% 
+                    s0 = node.childNodes.0.textContent;
+                    s1 = node.childNodes.1.textContent;
+                %]
+                [% IF s0 %]
+                    <a href='../results?query=su:[% s0 | url %]'>[% s0 %]</a>
+                    [% IF s1 %]
+                    <span>--</span>
+                    <a href='../results?query=su:[% s1 | url %]'>[% s1 %]</a>
+                    [% END %]
+                    <br/>
+                [% END %]
+            [% END %]
+            </td>
+        </tr>
+    </table>
+    <table id='copy_table'>
+        <thead>
+            <tr>
+                <th>Owning Lib</th>
+                <th>Call Number</th>
+                <th>Barcode</th>
+                <th>Status</th>
+            </tr>
+        </thead>
+        <tbody>
+        [% FOR acn IN record.call_numbers %]
+            [% FOR acp IN acn.copies %]
+                <tr>
+                    <td>[% ctx.find_aou(acn.owning_lib).shortname %]</td>
+                    <td>[% acn.label %]</td>
+                    <td>[% acp.barcode %]</td>
+                    <td>[% ctx.find_ccs(acp.status).name %]</td>
+                </tr>
+            [% END %]
+        [% END %]
+        </tbody>
+    </table>
+</div>
+
+
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac-poc/results.tt2 b/Open-ILS/web/templates/default/opac-poc/results.tt2
new file mode 100644 (file)
index 0000000..9ecead4
--- /dev/null
@@ -0,0 +1,117 @@
+[% BLOCK html_head %]
+<style>
+    #body_table { width: 100%; margin-top: 20px; }
+    #left_block { width: 15%; vertical-align: top; }
+    #right_block { width: auto; vertical-align: top;}
+    #record_table { border-collapse: collapse; width:100%; }
+    #record_table td { padding: 3px; border-bottom: 1px solid #ddd; }
+    #record_table tr:nth-child(odd) { background-color:#ded; }
+    .record-table-odd { background-color:#ded; }
+    #form_div { text-align: center; width: 100%; margin-top: 10px;}
+    #links_div { margin-bottom: 10px; padding: 5px;}
+</style>
+[% END %]
+
+[% 
+    USE CGI;
+    USE POSIX;
+    WRAPPER "default/opac/base.tt2"; 
+    PROCESS "default/opac/common.tt2";
+    ctx.page_title = "Results";
+    page = CGI.param('page') || 0; 
+    query = CGI.param('query');
+    page_count = POSIX.ceil(ctx.hit_count / ctx.page_size);
+    loc = CGI.param('loc');
+%]
+
+<div id='form_div'>
+    <form action='./results' method='GET'>
+        <input type='text' name='query' size='50' value='[% query %]'/>
+        [% PROCESS build_org_selector name='loc' value=loc %]
+        <input type='submit'/>
+        <input type='hidden' name='page' value='0'/>
+    </form>
+</div>
+
+<table id='body_table'>
+    <tr>
+        <td id='left_block'>
+                [% IF ctx.user; %]
+                    <div id='links_div'>
+                        <div><a href='home'>Home</a></div>
+                        <div><a href='myopac/main'>Account</a></div>
+                        <div><a href='logout'>Logout</a></div>
+                    </div>
+                    <hr/>
+                    <table>
+                        <tr><td colspan='2' style='border-bottom:1px solid #9A9'>Signed in as [% ctx.user.usrname %]</td></tr>
+                        <tr><td>Total Holds</td><td>[% ctx.user_stats.holds.total %]</td></tr>
+                        <tr><td>Ready Holds</td><td>[% ctx.user_stats.holds.ready %]</td></tr>
+                        <tr><td>Items Out</td><td>[% ctx.user_stats.checkouts.out %]</td></tr>
+                        <tr><td>Fines</td><td>$[% ctx.user_stats.fines.balance_owed %]</td></tr>
+                    </table>
+                [% ELSE %]
+                    [% 
+                        login = CGI.url("-path" => 1).replace('^http:', 'https:').replace('/results','/login');
+                    %]
+                    <a href='[% login %]'>Login</a>
+                [% END %]
+            </div>
+            <div>
+                [% FOR facet_type IN ctx.search_facets.keys %]
+                    [% cmf = ctx.search_facets.$facet_type.cmf %]
+                    <b>[% cmf.label %]</b>
+                    <ul>
+                        [% FOR facet IN ctx.search_facets.$facet_type.data.keys %]
+                            [% facet_count = ctx.search_facets.$facet_type.data.$facet %]
+                            <li><a href='results?query=[% query | url %]&facet=[% cmf.field_class %]|[% cmf.name %][[% facet | url %]]'>[% facet_count %] / [% facet %]</a></li>
+                        [% END %]
+                    </ul>
+                [% END %]
+            </div>
+        </td>
+        <td id='right_block'>
+            <div>
+                <span>[% l('Hits: [_1] / Page [_2] of [_3]', ctx.hit_count, page + 1, page_count) %]</span>
+                [% 
+                    q = query | url;
+                    np_link = '?query=' _ q;
+                    IF loc; np_link = np_link _ "&loc=" _ loc; END;
+                    IF depth or depth == 0; np_link = np_link _ "&depth=" _ depth; END;
+                %]
+                <a [% IF page > 0 %] href='[% np_link %]&page=[% page - 1 %]' [% END %]>Prev</a>  
+                <a [% IF (page + 1) < page_count %] href='[% np_link %]&page=[% page + 1 %]' [% END %]>Next</a>
+            </div>
+            <table id='record_table'>
+                [%
+                FOR rec IN ctx.records;
+                    attrs = {marc_xml => rec.marc_xml};
+                    PROCESS get_marc_attrs args=attrs;
+                %]
+                <tr [% IF loop.count % 2 == 1 %] class='record-table-odd' [% END %]>
+                    <td style='width:52px;height:72px'>
+                        [% IF attrs.isbn %]
+                        <img width='50' height='70' src='[% ctx.media_prefix %]/opac/extras/ac/jacket/small/[% attrs.isbn_clean || attrs.upc %]'/>
+                        [% END %]
+                    </td>
+                    <td width='auto'>
+                        <div width='99%'>
+                            <div style='float:left'>
+                                <a href='record/[% rec.bre.id %]'>[% attrs.title %]</a>
+                            </div>
+                            <div style='float:right'>
+                                <span>[% rec.copy_counts.available %] / [% rec.copy_counts.visible %]</span>
+                                <span style='padding-left:10px;'><a href='place_hold?hold_target=[% rec.bre.id %]&hold_type=T'>Hold</a></span>
+                            </div>
+                        </div><br/>
+                        <div>[% attrs.author %]</div>
+                        <div>[% attrs.isbn || attrs.issn || attrs.upc %] [% attrs.publisher %] [% attrs.pubdate %]</div>
+                    </td>
+                </tr>
+                [% END %]
+            </table>
+        </td>
+    </tr>
+
+</table>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac/advanced.tt2 b/Open-ILS/web/templates/default/opac/advanced.tt2
new file mode 100644 (file)
index 0000000..5c953a3
--- /dev/null
@@ -0,0 +1,23 @@
+[%  PROCESS "default/opac/parts/header.tt2";
+    WRAPPER "default/opac/parts/base.tt2";
+    INCLUDE "default/opac/parts/topnav.tt2";
+    ctx.page_title = l("Advanced Search") %]
+    <div id="search-wrapper">
+        [% INCLUDE "default/opac/parts/printnav.tt2" %]
+        <div id="adv_search_parent">
+            <div id="adv_search_tabs">
+                <a href="#" alt="[% l('Advanced Search') %]" id="adv_search"></a>
+<!--                <a href="#" alt="[% l('Numeric Search') %]" id="num_search"></a>
+                    <a href="#" alt="[% l('Expert Search') %]" id="expert_search"></a> -->
+            </div>
+        </div>
+    </div>
+    <div id="content-wrapper">
+        <div id="main-content">
+            <div class="advanced_div">
+            [% INCLUDE "default/opac/parts/advanced/search.tt2" %]
+            </div>
+            <div class="common-full-pad"></div>        
+        </div>
+    </div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac/home.tt2 b/Open-ILS/web/templates/default/opac/home.tt2
new file mode 100644 (file)
index 0000000..5e1fe41
--- /dev/null
@@ -0,0 +1,16 @@
+[%  PROCESS "default/opac/parts/header.tt2";
+    WRAPPER "default/opac/parts/base.tt2";
+    INCLUDE "default/opac/parts/topnav.tt2";
+    ctx.page_title = l("Home") %]
+    <div id="search-wrapper">
+        [% INCLUDE "default/opac/parts/printnav.tt2" %]
+        [% INCLUDE "default/opac/parts/searchbar.tt2" %]
+    </div>
+    <div id="content-wrapper">
+        <div id="main-content-home">
+            <div class="common-full-pad"></div>
+            [% INCLUDE "default/opac/parts/homesearch.tt2" %]
+            <div class="common-full-pad"></div>        
+        </div>
+    </div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac/login.tt2 b/Open-ILS/web/templates/default/opac/login.tt2
new file mode 100644 (file)
index 0000000..5f4d03f
--- /dev/null
@@ -0,0 +1,27 @@
+[%  PROCESS "default/opac/parts/header.tt2";
+    WRAPPER "default/opac/parts/base.tt2";
+    INCLUDE "default/opac/parts/topnav.tt2";
+    ctx.page_title = l("Account Login") %]
+    <div id="search-wrapper">
+        [% INCLUDE "default/opac/parts/printnav.tt2" %]
+        [% INCLUDE "default/opac/parts/searchbar.tt2" %]
+    </div>
+    <div id="content-wrapper">
+        <div id="main-content">
+            [% INCLUDE "default/opac/parts/login/form.tt2" %]
+            <div class="clear-both very-big-height"></div>     
+            <script type="text/javascript">
+                /* Note: when common browsers suppor HTML5 "autofocus", we can remove this */
+                var _onload = window.onload;
+                window.onload = function() {
+                    try {
+                        document.getElementById("username_field").focus();
+                        if (_onload) _onload();
+                    } catch (E) {
+                        void(0);
+                    }
+                };
+            </script>
+        </div>
+    </div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac/mylist.tt2 b/Open-ILS/web/templates/default/opac/mylist.tt2
new file mode 100644 (file)
index 0000000..2ec8a5d
--- /dev/null
@@ -0,0 +1,20 @@
+[%  PROCESS "default/opac/parts/header.tt2";
+    PROCESS "default/opac/parts/misc_util.tt2";
+    WRAPPER "default/opac/parts/base.tt2";
+    INCLUDE "default/opac/parts/topnav.tt2";
+    ctx.page_title = l("Record Detail") %]
+    <div id="search-wrapper">
+        [% INCLUDE "default/opac/parts/printnav.tt2" %]
+        [% INCLUDE "default/opac/parts/searchbar.tt2" %]
+    </div>
+    <div id="content-wrapper">
+        <div id="main-content">
+            [%  IF ctx.mylist.size;
+                    INCLUDE "default/opac/parts/anon_list.tt2";
+                ELSE %]
+                <div class="opac-auto-171 opac-auto-097">[% l("You have not created a list yet."); %]</div>
+                [% END %]
+            <div class="common-full-pad"></div>        
+        </div>
+    </div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac/myopac/circ_history.tt2 b/Open-ILS/web/templates/default/opac/myopac/circ_history.tt2
new file mode 100644 (file)
index 0000000..a095558
--- /dev/null
@@ -0,0 +1,102 @@
+[%  PROCESS "default/opac/parts/header.tt2";
+    PROCESS "default/opac/parts/misc_util.tt2";
+    WRAPPER "default/opac/parts/myopac/base.tt2";
+    myopac_page = "circs"
+    limit = ctx.circ_history_limit;
+    offset = ctx.circ_history_offset;
+%]
+
+<div style="padding:0px;">
+    
+    <div id="acct_checked_tabs" style="padding-bottom: 12px;color:#666;">
+        <div class="align selected">
+            <a href='circs'><img src="[% ctx.media_prefix %]/images/sub_checked_out_off.jpg"/></a>
+        </div>
+        <div class="align">
+            <img src="[% ctx.media_prefix %]/images/sub_checked_hist_on.jpg"/>
+        </div>
+        <div class="clear-both"></div>
+    </div>
+
+    <div class="header_middle">
+        <span class="float-left">[% l('Previously Checked Out Items') %]</span>
+        <span class='float-left' style='padding-left: 10px;'>
+            <a href='circ_history?limit=[% limit %]&amp;offset=[% offset - limit %]'
+                [% IF offset == 0 %] class='invisible' [% END %]><span class="nav_arrow_fix">&#9668;</span>[% l('Previous') %]</a>
+            [%# TODO: get total to prevent paging off then end of the list.. %]
+            <a href='circ_history?limit=[% limit %]&amp;offset=[% offset + limit %]'
+               [% IF ctx.circs.size < limit %] class='invisible' [% END %] >[% l('Next') %]<span class="nav_arrow_fix">&#9658;</span></a>
+        </span>
+        <span class="float-right">
+            <a class="hide_me" href="#">[% l('Export List') %]</a>
+        </span>
+    </div>
+    <div class="clear-both"></div>
+
+    [% IF ctx.circs.size < 1 %]
+    <div class="opac-auto-079">
+        <big><strong>[% l('There are no items in your circulation history.') %]</strong></big>
+    </div>
+    [% ELSE %]
+
+    <div id='checked_main'>
+        <table style='border-collapse:collapse;'>
+            <thead id="acct_checked_main_header">
+                <tr>
+                    <td width="32%" style="padding-left:5px;">
+                        <span title="Click to sort" class='pointer'>[% l('Title') %]</span> /
+                        <span title="Click to sort" class='pointer'>[% l('Author') %]</span>
+                    </td>
+                    <td width="10%" style="padding-left:5px;">
+                        <span title="Click to sort" class='pointer'>[% l('Checkout Date') %]</span>
+                    </td>
+                    <td width="10%" style="padding-left:5px;">
+                        <span title="Click to sort" class='pointer'>[% l('Due Date') %]</span>
+                    </td>
+                    <td width="10%" style="padding-left:5px;">
+                        <span title="Click to sort" class='pointer'>[% l('Date Returned') %]</span>
+                    </td>
+                    <td width="16%">
+                        <span title="Click to sort" class='pointer'>[% l('Barcode') %]</span>
+                    </td>
+                    <td width="22%">
+                        <span title="Click to sort" class='pointer'>[% l('Call Number') %]</span>
+                    </td>
+                </tr>
+            </thead>
+            <tbody>
+                [% FOR circ IN ctx.circs;
+                    attrs = {marc_xml => circ.marc_xml};
+                    PROCESS get_marc_attrs args=attrs; %]
+                    <tr>
+                        <td style="padding-left:5px;padding-bottom:10px;">
+                            <a href="[% ctx.opac_root %]/record/[% circ.circ.target_copy.call_number.record.id %]" 
+                                name="[% l('Catalog record') %]">[% attrs.title %]</a>
+                            [% IF attrs.author %] /
+                            <a href="[% ctx.opac_root %]/results?qtype=author&amp;query=[% attrs.author | replace('[,\.:;]', '') | url %]">[% attrs.author %]</a>
+                            [% END %]
+                        </td>
+                        <td style="padding-left:5px;">
+                            [% date.format(ctx.parse_datetime(circ.circ.xact_start),DATE_FORMAT); %]
+                        </td>
+                        <td style="padding-left:5px;">
+                            [% date.format(ctx.parse_datetime(circ.circ.due_date),DATE_FORMAT); %]
+                        </td>
+                        <td style="padding-left:5px;">
+                            [% 
+                                IF circ.circ.checkin_time; 
+                                    date.format(ctx.parse_datetime(circ.circ.checkin_time),DATE_FORMAT); 
+                                ELSE; %]
+                                <span style='color:blue;'>*</span><!-- meh -->
+                            [% END; %]
+                        </td>
+                        <td>[% circ.circ.target_copy.barcode %]</td>
+                        <td>[% circ.circ.target_copy.call_number.label %]</td>
+                    </tr>
+                [% END %]
+            </tbody>
+        </table>
+    </div>
+    [% END %]
+</div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac/myopac/circs.tt2 b/Open-ILS/web/templates/default/opac/myopac/circs.tt2
new file mode 100644 (file)
index 0000000..67f94b8
--- /dev/null
@@ -0,0 +1,166 @@
+[%  PROCESS "default/opac/parts/header.tt2";
+    PROCESS "default/opac/parts/misc_util.tt2";
+    WRAPPER "default/opac/parts/myopac/base.tt2";
+    myopac_page = "circs"  %]
+<div id='myopac_checked_div' style="padding:0px;">
+
+    <div id="acct_checked_tabs" style="padding-bottom: 12px;color:#666;">
+        <div class="align selected">
+            <img src="[% ctx.media_prefix %]/images/sub_checked_out_on.jpg" />
+        </div>
+        <div class="align">
+            <a href="circ_history"><img
+                src="[% ctx.media_prefix %]/images/sub_checked_hist_off.jpg" /></a>
+        </div>
+        <div class="clear-both"></div>
+    </div>
+
+    <div class="header_middle">
+        <span class="float-left">[% l('Current Items Checked Out') %]</span>
+        <span class="float-right">
+            <a class="hide_me" href="#">[% l('Export List') %]</a>
+        </span>
+    </div>
+    <div class="clear-both"></div>
+    [% IF ctx.circs.size < 1 %]
+    <div class="opac-auto-079">
+        <big><strong>[% l('You have no items checked out.') %]</strong></big>
+    </div>
+    [% ELSE %]
+    [% IF ctx.success_renewals %]
+    <div class="renew-summary">
+        [% l("Successfully renewed [_1] item(s)", ctx.success_renewals) %]
+    </div>
+    [% END %]
+    [% IF ctx.failed_renewals %]
+    <div class="renew-summary red">
+        [% l("Failed to renew [_1] item(s)", ctx.failed_renewals) %]
+    </div>
+    [% END %]
+    <div id='checked_main'>
+        <form method="POST" id="circ-form"
+            onsubmit="return confirm('[% l("Are you sure you wish to renew the selected item(s)?") %]');">
+        <table cellpadding='0' cellspacing='0' class="opac-auto-097b">
+            <tr>
+                <td>
+                    <select name="action">
+                        <option value="renew">[% l('Renew Selected Titles') %]</option>
+                    </select>
+                </td>
+                <td style="padding-left:9px;">
+                    <input type="image"
+                        alt="[% l('Go') %]" title="[% l('Go') %]"
+                        src="[% ctx.media_prefix %]/images/go-btn.png" /></a>
+                </td>
+                <td style="padding-left:5px;">
+                    <a href="#"><img alt="Renewing Help"
+                        src="[% ctx.media_prefix %]/images/question-mark.png" /></a>
+                </td>
+            </tr>
+        </table>
+        <table id="acct_checked_main_header" cellpadding='0' cellspacing='0'
+            border='0'>
+            <tr>
+                <td width="1%" style="padding-left:10px;">
+                    <input type="checkbox" id="check_all_checked"
+                        onclick="var inputs=document.getElementsByTagName('input'); for (i = 0; i < inputs.length; i++) { if (inputs[i].name == 'circ' && !inputs[i].disabled) inputs[i].checked = this.checked;}"
+                    />
+                </td>
+                <td width="40%" style="padding-left:5px;">
+                    <span title="Click to sort" class='pointer'>
+                        Title
+                    </span> /
+                    <span title="Click to sort" class='pointer'>
+                        Author
+                    </span>
+                </td>
+                <td width="8%" style="padding-right:5px;" align="center">
+                    <span title="Click to sort" class='pointer'>Renews<br />Left
+                    </span>
+                </td>
+                <td width="13%" style="padding-left:5px;">
+                    <span title="Click to sort" class='pointer'>Due Date</span>
+                </td>
+                <td width="16%">
+                    <span title="Click to sort" class='pointer'>barcode</span>
+                </td>
+                <td width="22%">
+                    <span title="Click to sort" class='pointer'>call number</span>
+                </td>
+            </tr>
+        </table>
+   
+        <div id="checked_temp_parent">
+            <div id="acct_checked_temp">
+                <table cellpadding='0' cellspacing='0' border='0'
+                    style="margin-top:5px;">
+                    [% FOR circ IN ctx.circs;
+                        attrs = {marc_xml => circ.marc_xml};
+                        PROCESS get_marc_attrs args=attrs; %]
+                    <tr>
+                        <td width="1%" style="padding-left:10px;" valign="top">
+                            <input type="checkbox" name="circ"
+                                [% IF circ.circ.renewal_remaining < 1; l('disabled="disabled"'); END %]
+                                value="[% circ.circ.id %]" />
+                        </td>
+                        <td width="40%"
+                            style="padding-left:5px;padding-bottom:10px;"
+                            name="author">
+                            <a href="[% ctx.opac_root %]/record/[% circ.circ.target_copy.call_number.record.id %]" name="[% l('Catalog record') %]">[% attrs.title %]</a>
+                            [% IF attrs.author %] /
+                            <a href="[% ctx.opac_root %]/results?qtype=author&amp;query=[% attrs.author | replace('[,\.:;]', '') | url %]">[% attrs.author %]</a>
+                            [% END %]
+                        </td>
+                        <td width="8%" name="renewals" align="center">
+                            [% circ.circ.renewal_remaining %]
+                        </td>
+                        <td width="13%" style="padding-left:5px;"
+                            name="due_date">
+                            [% date.format(ctx.parse_datetime(circ.circ.due_date),DATE_FORMAT) %]
+                        </td>
+                        <td width="16%" name="barcode">
+                            [% circ.circ.target_copy.barcode %]
+                        </td>
+                        <td width="22%" name="call_number">
+                            [% circ.circ.target_copy.call_number.label %]
+                        </td>
+                    </tr>
+                    [%  IF circ.renewal_response AND
+                            circ.renewal_response.textcode != 'SUCCESS' %]
+                    <tr>
+                        <td colspan="6">[%# XXX colspan="0" does not work in IE %]
+                            <span class="failure-text" title="[% circ.renewal_response.textcode %] / [% circ.renewal_response.payload.fail_part %]">
+                                [% circ.renewal_response.desc || circ.renewal_response.payload.fail_part || circ.renewal_response.textcode %]
+                            </span>
+                        </td>
+                    </tr>
+                    [%  END;
+                    END %]
+                </table>
+            </div>
+        </div>
+        </form>
+    </div>
+    [% END %]
+    <div id='non_cat_circs_div' class='hide_me'>
+        <br/>
+        <div style='text-align: center'><b>[% l("Other Circulations") %]</b></div>
+        <table class='data_grid' width='100%'>
+            <thead>
+                <tr>
+                    <td>[% l("Circulating Library") %]</td>
+                    <td>[% l("Circulation Type") %]</td>
+                    <td>[% l("Please return by ...") %]</td>
+                </tr>
+            </thead>
+            <tbody id='non_cat_circs_tbody'>
+                <tr id='non_cat_circs_row'>
+                    <td name='circ_lib'/>
+                    <td name='item_type'/>
+                    <td name='circ_time'/>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac/myopac/hold_history.tt2 b/Open-ILS/web/templates/default/opac/myopac/hold_history.tt2
new file mode 100644 (file)
index 0000000..43f3256
--- /dev/null
@@ -0,0 +1,127 @@
+[%  PROCESS "default/opac/parts/header.tt2";
+    PROCESS "default/opac/parts/misc_util.tt2";
+    WRAPPER "default/opac/parts/myopac/base.tt2";
+    myopac_page = "holds"  
+    limit = ctx.hold_history_limit;
+    offset = ctx.hold_history_offset;
+%]
+
+<div id='myopac_holds_div'>
+
+    <div id="acct_holds_tabs" style="padding-bottom: 12px;color:#666;">
+        <div class="align selected">
+            <a href='holds'><img src="[% ctx.media_prefix %]/images/sub_holds_off.jpg"/></a>
+        </div>
+        <div class="align">
+            <img src="[% ctx.media_prefix %]/images/sub_holds_hist_on.jpg"/>
+        </div>
+        <div class="clear-both"></div>
+    </div>
+
+    <div class="header_middle">
+        <span style="float:left;">[% l("Previously Held Items") %]</span>
+        <span class='float-left' style='padding-left: 10px;'>
+            <a href='hold_history?limit=[% limit %]&amp;offset=[% offset - limit %]'
+                [% IF offset == 0 %] class='invisible' [% END %]><span class="nav_arrow_fix">&#9668;</span>[% l('Previous') %]</a>
+            [%# TODO: get total to prevent paging off then end of the list.. %]
+            <a href='hold_history?limit=[% limit %]&amp;offset=[% offset + limit %]'
+               [% IF ctx.holds.size < limit %] class='invisible' [% END %] >[% l('Next') %]<span class="nav_arrow_fix">&#9658;</span></a>
+        </span>
+        <span style="float:right;">
+            <a class="hide_me" href="#">Export List</a>
+        </span>
+    </div>
+    <div class="clear-both"></div>
+
+    <div id='holds_main'>
+        [% IF ctx.holds.size < 1 %]
+        <div class="opac-auto-079">
+            <big><strong>[% l('No holds found.') %]</strong></big>
+        </div>
+        [% ELSE %]
+        <table style='border-collapse:collapse; width: 100%;'>
+            <thead id='acct_holds_main_header'>
+                <tr>
+                    <td width="138"><span>[% l('Title') %]</span></td>
+                    <td width="123"><span>[% l('Author') %]</span></td>
+                    <td width="64"> <span>[% l('Format') %]</span></td>
+                    <td width="136"><span>[% l('Pickup Location') %]</span> </td>
+                    <td width="104">[% l('Active On') %]</td>
+                    <td width="95">[% l('Active') %]</td>
+                    <td width="106">[% l('Date Fulfilled') %]</td>
+                    <td width="172"><span>[% l('Status') %]</span></td>
+                </tr>
+            </thead>
+            <tbody>
+                [% FOR hold IN ctx.holds;
+                    attrs = {marc_xml => hold.marc_xml};
+                    PROCESS get_marc_attrs args=attrs;
+                    ahr = hold.hold.hold %]
+
+                <tr id="acct_holds_temp" name="acct_holds_temp" class="acct_holds_temp">
+
+                    <td width="138">
+                        <div style="margin-top:10px;margin-bottom:10px;">
+                            <a href="[% ctx.opac_root %]/record/[% hold.hold.bre.id %]">[% attrs.title | html %]</a>
+                        </div>
+                    </td>
+                    <td width="123">
+                        <div style="margin-top:10px;margin-bottom:10px;">
+                            <a href="[% ctx.opac_root %]/results?qtype=author&amp;query=[% attrs.author | replace('[,\.:;]', '') | url %]">[% attrs.author | html %]</a>
+                        </div>
+                    </td>
+                    <td width="64">
+                        <div style="width:26px;height:23px;margin-top:6px;margin-bottom:6px;">
+                            [% IF attrs.format_icon %]
+                            <img src="[% ctx.media_prefix %]/images/[% attrs.form_icon %]"
+                                title="[% attrs.format %]" alt="[% attrs.format %]" />
+                            [% ELSE;
+                                attrs.format;
+                               END %]
+                        </div>
+                    </td>
+                    <td width="136">
+                        [% ctx.get_aou(ahr.pickup_lib).name %]
+                    </td>
+                    <td width="104">
+                        [% IF ahr.frozen == 't' AND ahr.thaw_date;
+                            date.format(ctx.parse_datetime(ahr.thaw_date), DATE_FORMAT);
+                        END %]
+                    </td>
+                    <td width="95">
+                        [% l(ahr.frozen == 'f' ? 'Active' : 'Suspended') %]
+                    </td>
+                    <td width="106">
+                        [% IF ahr.fulfillment_time;
+                            date.format(ctx.parse_datetime(ahr.fulfillment_time), DATE_FORMAT);
+                        END %]
+                    </td>
+                    <td width="110">
+                        <div name="acct_holds_status"
+                            style="margin-top:10px;margin-bottom:10px;">
+                            [%
+                                IF hold.hold.status == 4;
+                                    l("Available");
+                                    IF ahr.shelf_expire_time;
+                                        l('<br/>Expires [_1]', 
+                                            date.format(ctx.parse_datetime(ahr.shelf_expire_time), DATE_FORMAT));
+                                    END;
+                                ELSIF hold.hold.estimated_wait AND hold.hold.estimated_wait > 0;
+                                    # estimated wait is delivered as seconds.
+                                    SET hwait = POSIX.ceil(hold.hold.estimated_wait / 86400);
+                                    l("Estimated wait: [quant,_1,day,days]", hwait);
+                                ELSIF hold.hold.status == 3;
+                                    l("In Transit");
+                                ELSIF hold.hold.status < 3;
+                                    l("Waiting for copy");
+                                END;
+                            %]
+                        </div>
+                    </td>
+                </tr>
+                [% END %]
+            </tbody>
+        </table>
+        [% END %]
+    </div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/opac/myopac/holds.tt2 b/Open-ILS/web/templates/default/opac/myopac/holds.tt2
new file mode 100644 (file)
index 0000000..a6bb670
--- /dev/null
@@ -0,0 +1,228 @@
+[%  PROCESS "default/opac/parts/header.tt2";
+    PROCESS "default/opac/parts/misc_util.tt2";
+    WRAPPER "default/opac/parts/myopac/base.tt2";
+    myopac_page = "holds"  %]
+<div id='myopac_holds_div'>
+
+    <div id="acct_holds_tabs" style="padding-bottom: 12px;color:#666;">
+        <div class="align selected">
+            <img src="[% ctx.media_prefix %]/images/sub_holds_on.jpg"/>
+        </div>
+        <div class="align">
+            <a href='hold_history'><img src="[% ctx.media_prefix %]/images/sub_holds_hist_off.jpg"/></a>
+        </div>
+        <div class="clear-both"></div>
+    </div>
+
+    <div class="header_middle">
+        <span id="acct_holds_header" style="float:left;">
+            [%  IF CGI.param("available");
+                    l("Items Ready for Pickup");
+                ELSE;
+                    l("Current Items on Hold");
+                END
+            %]
+        </span>
+        <span style="float:right;">
+            <a class="hide_me" href="#">Export List</a>
+        </span>
+    </div>
+    <div class="clear-both"></div>
+    <div id='holds_main'>
+        <form method="POST">
+        <table cellpadding='0' cellspacing='0' class="opac-auto-097">
+            <tr>
+                <td width="1">
+                    <select name="action" id="acct_holds_actions">
+                        <option id='myopac_holds_actions_none' value=''>
+                        -- [% l("Actions for selected holds") %] --
+                        </option>
+                        <option value='suspend'>
+                            [% l("Suspend") %]
+                        </option>
+                        <option value='activate'>
+                            [% l("Activate") %]
+                        </option>
+                        <!-- XXX maybe later <option value='thaw_date'>
+                            [% l("Set Active Date") %]
+                        </option> -->
+                        <option value='cancel'>
+                            [% l("Cancel") %]
+                        </option>
+                    </select>
+                </td>
+                <td width="1" style="padding-left:9px;">
+                    <input type="image"
+                        alt="[% l('Go') %]" title="[% l('Go') %]"
+                        src="[% ctx.media_prefix %]/images/go-btn.png" />
+                </td>
+                <td width="1" style="padding-left:5px;">
+                    <a href="#"><img
+                        alt="Holds Help"
+                        src="[% ctx.media_prefix %]/images/question-mark.png" /></a>
+                </td>
+                <td align="right">
+                    [% l("Show") %] &nbsp; &nbsp;
+                    [% IF CGI.param("available") %]
+                    <a href="holds">[% l('all') %]</a> |
+                    <strong>[% l("only available") %]</strong>
+                    [% ELSE %]
+                    <strong>[% l("all") %]</strong> |
+                    <a href="holds?available=1">[% l("only available") %]</a>
+                    [% END %] &nbsp; &nbsp;
+                    [% l("holds") %]
+                    <select class="hide_me" id="holds_sort">
+                        <option value="">-- Sort By --</option>
+                        <option value="title">Title</option>
+                        <option value="pickup">PickUp Location</option>
+                        <option value="status">Status</option>
+                    </select>
+                </td>
+            </tr>
+        </table>
+        [% IF ctx.holds.size < 1 %]
+        <div class="opac-auto-079">
+            <big><strong>[% l('No holds found.') %]</strong></big>
+        </div>
+        [% ELSE %]
+        <table id="acct_holds_main_header" cellpadding='0' cellspacing='0'
+            border='0' width="100%">
+            <tr>
+                <td width="36" align="center">
+                    <input type="checkbox" id="check_all_holds" />
+                </td>
+                <td width="138">
+                    <span title="Click to sort"
+                        style="cursor:pointer;">
+                        Title
+                    </span>
+                </td>
+                <td width="123">
+                    <span title="Click to sort" style="cursor:pointer;">Author</span>
+                </td>
+                <td width="64">
+                    <span title="Click to sort"
+                        style="cursor:pointer;">Format</span>
+                </td>
+                <td width="136">
+                    <span title="Click to sort"
+                        style="cursor:pointer;">Pickup Location</span>
+                </td>
+                <td width="104">Activate</td>
+                <td