Copy location filter selector for the TPAC advanced search interface.
The behavior is the same as the analogous JSPAC feature. The interface
components are hidden by default, so non-JS browsers will be none the
wiser.
A number of small tweaks to related code were needed and are included in
this commit:
1. Make copy locations field_safe in the IDL so they can be retrieved
and parsed without the IDL
2. Insert a (full) hash-based org unit tree as inline JS at the bottom
of js.tt2 so JS will have access to the whole tree without having to
load the IDL to understand it.
3. Fix a bug in openils.CGI : decodeURIComponent parameter names
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Signed-off-by: Ben Shum <bshum@biblio.org>
<link field="notify_staff" reltype="has_a" key="id" map="" class="au"/>
</links>
</class>
- <class id="acpl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::copy_location" oils_persist:tablename="asset.copy_location" reporter:label="Copy/Shelving Location">
+ <class id="acpl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::copy_location" oils_persist:tablename="asset.copy_location" reporter:label="Copy/Shelving Location" oils_persist:field_safe="true">
<fields oils_persist:primary="id" oils_persist:sequence="asset.copy_location_id_seq">
<field reporter:label="Can Circulate?" name="circulate" reporter:datatype="bool"/>
<field reporter:label="Is Holdable?" name="holdable" reporter:datatype="bool"/>
<tr>
[%
END; %]
- <td valign='top'>
+ <td valign='top'[% IF adv_chunk.js_only %]
+ id='adv_chunk_[% adv_chunk.adv_special %]'
+ class='hidden'[% END %]>
<strong>[% adv_chunk.adv_label %]</strong><br />
[%
IF adv_chunk.adv_special;
SWITCH adv_chunk.adv_special;
CASE "lib_selector";
PROCESS "opac/parts/org_selector.tt2";
- INCLUDE build_org_selector show_loc_groups=1; %]
+ INCLUDE build_org_selector show_loc_groups=1 id="adv_org_selector" %]
<div style="position:relative;top:7px;">
<input type='checkbox' name="modifier"
value="available"[% CGI.param('modifier').grep('available').size ? ' checked="checked"' : '' %]
CASE "sort_selector";
INCLUDE "opac/parts/filtersort.tt2"
value=CGI.param('sort') class='results_header_sel';
+
+ CASE "copy_location" %]
+ <select id="adv_copy_location_selector"
+ aria-label="[% l('Select Shelving Location') %]"
+ name="fi:locations" size="3" multiple="multiple">
+ </select>
+ [%
END;
ELSIF adv_chunk.adv_attr;
INCLUDE "opac/parts/coded_value_selector.tt2"
{adv_label => l("Audience"), adv_attr => ["audience_group", "audience"], adv_break => 1},
{adv_label => l("Video Format"), adv_attr => "vr_format"},
{adv_label => l("Bib Level"), adv_attr => "bib_level"},
- {adv_label => l("Literary Form"), adv_attr => "lit_form", adv_break => 1},
+ {adv_label => l("Literary Form"), adv_attr => "lit_form"},
+ {adv_label => l("Shelving Location"), adv_special => "copy_location", js_only => 1, adv_break => 1},
{adv_label => l("Search Library"), adv_special => "lib_selector"},
{adv_label => l("Publication Year"), adv_special => "pub_year"},
{adv_label => l("Sort Results"), adv_special => "sort_selector"},
[% INCLUDE "opac/parts/acjs.tt2" IF ctx.page == 'record' %]
[% INCLUDE "opac/parts/ac_google_books.tt2" IF ctx.page == 'record' AND ctx.google_books_preview %]
+[% IF ctx.page == 'advanced' %]
+<script type="text/javascript"
+ src="[% ctx.media_prefix %]/js/ui/default/opac/copyloc.js"></script>
+[% END %]
+
+<!-- provide a JS friendly org unit hash -->
+<script type="text/javascript">
+var aou_hash = {
+[% FOR org_unit IN ctx.aou_list %]
+ [% org_unit.id %] : {
+ id : "[% org_unit.id %]",
+ name : "[% org_unit.name | replace('"', '\"') %]",
+ parent_ou : "[% org_unit.parent_ou %]",
+ depth : "[% org_unit.ou_type.depth %]",
+ can_have_vols : "[% org_unit.ou_type.can_have_vols %]"
+ }[%- ',' UNLESS loop.last -%]
+[% END %]
+};
+</script>
[%- END; # want_dojo -%]
if(c == "&" || c == ";") {
inkey = 1;
invalue = 0;
+ key = decodeURIComponent(key);
if( ! this.data[key] ) this.data[key] = [];
this.data[key].push(decodeURIComponent(value));
this._keys.push(key);
--- /dev/null
+dojo.require("DojoSRF");
+dojo.require("openils.CGI");
+
+// called on initial page load and when the advance search org unit
+// selector is changed.
+function apply_adv_copy_locations() {
+
+ // patron selected org
+ var sel = dojo.byId('adv_org_selector');
+ var selected_id = sel.options[sel.selectedIndex].getAttribute('value');
+ var org_unit = aou_hash[selected_id];
+
+ if (org_unit.can_have_vols != 't') {
+ dojo.addClass('adv_chunk_copy_location', 'hidden');
+ return;
+ }
+
+ var display_orgs = [];
+
+ // we want to display copy locations at the selected org,
+ // all parent orgs, and all child orgs.
+
+ function collect_child_orgs(org_id) {
+ display_orgs.push(org_id);
+ for (var id in aou_hash) { // for key in
+ if (aou_hash[id].parent_ou == org_id)
+ collect_child_orgs(id);
+ }
+ }
+
+ function collect_parent_orgs(org_id) {
+ if (!org_id) return;
+ display_orgs.push(org_id);
+ collect_parent_orgs(aou_hash[org_id].parent_ou);
+ }
+
+ collect_child_orgs(org_unit.id);
+ collect_parent_orgs(org_unit.parent_ou);
+ fetch_adv_copy_locations(display_orgs);
+}
+
+function fetch_adv_copy_locations(org_ids) {
+
+ var params = [{
+ cache : 1,
+ fields : ['name', 'id', 'owning_lib'],
+ query : {owning_lib : org_ids, opac_visible : 't'}
+ }];
+
+ new OpenSRF.ClientSession('open-ils.fielder').request({
+ method: 'open-ils.fielder.acpl.atomic',
+ params: params,
+ async: true,
+ oncomplete: function(r) {
+ var resp = r.recv();
+ if (resp) {
+ var list = resp.content();
+ if (list && list.length) {
+ render_adv_copy_locations(list);
+ } else {
+ dojo.addClass('adv_chunk_copy_location', 'hidden');
+ }
+ } else {
+ dojo.addClass('adv_chunk_copy_location', 'hidden');
+ }
+ }
+ }).send();
+}
+
+function render_adv_copy_locations(locations) {
+ var sel = dojo.byId('adv_copy_location_selector');
+ var cgi = new openils.CGI();
+
+ // collect any location values from the URL to re-populate the list
+ var url_selected = cgi.param('fi:locations');
+ if (url_selected) {
+ if (!dojo.isArray(url_selected))
+ url_selected = [url_selected];
+ }
+
+ dojo.removeClass('adv_chunk_copy_location', 'hidden');
+
+ // sort by name
+ locations = locations.sort(
+ function(a, b) {return a.name < b.name ? -1 : 1}
+ );
+
+ // remove the previous list of locations
+ dojo.empty(sel);
+
+ // append the new list of locations
+ dojo.forEach(locations, function(loc) {
+ var attrs = {value : loc.id, innerHTML : loc.name};
+ if (url_selected && url_selected.indexOf(''+loc.id) > -1) {
+ attrs.selected = true;
+ }
+ sel.appendChild(dojo.create('option', attrs));
+ });
+}
+
+// load the locations on page load
+dojo.addOnLoad(function() {
+ apply_adv_copy_locations();
+ dojo.connect(dojo.byId('adv_org_selector'),
+ 'onchange', apply_adv_copy_locations);
+});
+