From 5dde64b78ff7d52f603910e37412739101a6bd9d Mon Sep 17 00:00:00 2001 From: Lebbeous Fogle-Weekley Date: Thu, 19 Jan 2012 14:14:00 -0500 Subject: [PATCH] ui and other improvements. since last time: * ditched standalone html test and integrated widget with the homesearch page * adjustments to ordering at db-stored-proc level courtesy of miker (this MAY have solved a problem mentioned in the previous commit msg where when the filteringselect's onBlur is called, the value selected could change) * the mod_perl module now returns JSON instead of XML if it's asked to by an "Accept" HTTP header, and the AutoSuggestStore takes advantage of this * AutoSuggestStore actually uses the value in the search type selector now * the mod_perl module actually respects the limit parameter now more still to come, including: * use openils.Searcher or similar to display class and field in the form "Topic (Subject)" * tie in selected org unit to request visibility searching from the UI layer * still investigate and fix numerical range problem * still overload validator to make it always return true * OU setting or some other such flag to enable/disable autosuggest UI bits in general Signed-off-by: Lebbeous Fogle-Weekley --- .../src/perlmods/lib/OpenILS/WWW/AutoSuggest.pm | 71 +++++++++++++++++++--- .../sql/Pg/upgrade/YYYY.schema.bib_autosuggest.sql | 3 +- Open-ILS/web/dijittest.2.html | 54 ---------------- Open-ILS/web/js/dojo/openils/AutoSuggestStore.js | 66 ++++++++++---------- Open-ILS/web/opac/skin/default/css/layout.css | 7 +++ Open-ILS/web/opac/skin/default/js/search_bar.js | 39 ++++++------ .../web/opac/skin/default/xml/home/homesearch.xml | 28 +++------ 7 files changed, 132 insertions(+), 136 deletions(-) delete mode 100644 Open-ILS/web/dijittest.2.html diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/AutoSuggest.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/AutoSuggest.pm index 79fff884bc..441025ffca 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/AutoSuggest.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/AutoSuggest.pm @@ -5,11 +5,13 @@ use warnings; use Apache2::Log; use Apache2::Const -compile => qw( - OK REDIRECT DECLINED NOT_FOUND HTTP_INTERNAL_SERVER_ERROR :log + OK HTTP_NOT_ACCEPTABLE HTTP_INTERNAL_SERVER_ERROR :log ); use XML::LibXML; +use Text::Glob; use CGI qw(:all -utf8); +use OpenSRF::Utils::JSON; use OpenILS::Utils::CStoreEditor qw/:funcs/; sub prepare_for_tsquery { @@ -60,7 +62,8 @@ sub get_suggestions { $search_class, $headline_opts, $org_unit - ] + ], + "limit" => $limit }); } @@ -84,13 +87,68 @@ sub suggestions_to_xml { return $dom->toString(); } +sub suggestions_to_json { + my ($suggestions) = @_; + + return OpenSRF::Utils::JSON->perl2JSON({ + "val" => [ + map { + +{ term => $_->{value}, field => $_->{field}, + match => $_->{match} } + } @$suggestions + ] + }); +} + +sub output_handler { + my ($r, $data) = @_; + + # We'll probably never need this fanciness for autosuggest, but + # you can add handlers for different requested content-types here, and + # you can weight them to control what matches requests for things like + # 'application/*' + + my $dispatch = { + "application/xml" => { + "prio" => 0, + "code" => sub { + $r->content_type("application/xml; charset=utf-8"); + print suggestions_to_xml($data); + return Apache2::Const::OK; + } + }, + "application/json" => { + "prio" => 1, + "code" => sub { + $r->content_type("application/json; charset=utf-8"); + print suggestions_to_json($data); + return Apache2::Const::OK; + } + } + }; + + foreach my $media_range (split /,/, $r->headers_in->{Accept}) { + $media_range =~ s/;.+$//; # keep type, subtype. lose parameters. + + my ($match) = grep { Text::Glob::match_glob($media_range, $_) } ( + sort { + $dispatch->{$a}->{prio} <=> $dispatch->{$b}->{prio} + } keys %$dispatch + ); + + if ($match) { + return $dispatch->{$match}{code}->($data); + } + } + + return Apache2::Const::HTTP_NOT_ACCEPTABLE; +} + sub handler { my $r = shift; my $cgi = new CGI; my $editor = new_editor; - $r->content_type("application/xml; charset=utf-8"); - my $suggestions = get_suggestions( $editor, map { scalar($cgi->param($_)) } qw( @@ -112,9 +170,8 @@ sub handler { } $editor->disconnect; - print suggestions_to_xml($suggestions); - - return Apache2::Const::OK; + + return output_handler($r, $suggestions); } 1; diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.bib_autosuggest.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.bib_autosuggest.sql index 5f9a7c2428..e64f39ffbd 100644 --- a/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.bib_autosuggest.sql +++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.schema.bib_autosuggest.sql @@ -432,7 +432,7 @@ BEGIN JOIN config.metabib_class cmc ON (cmf.field_class = cmc.name) ' || search_class_join || opac_visibility_join || ' WHERE $1 @@ mbe.index_vector - ORDER BY 4 DESC, 5 DESC NULLS LAST, 6 DESC, 7 DESC, 8 DESC + ORDER BY 4 DESC, 5 DESC NULLS LAST, 6 DESC, 7 DESC, 8 DESC, 1 ASC ' USING query, search_class, headline_opts, visibility_org; -- sort order: @@ -441,6 +441,7 @@ BEGIN -- field weight -- rank -- bouyancy + -- value itself END; $func$ LANGUAGE PLPGSQL; diff --git a/Open-ILS/web/dijittest.2.html b/Open-ILS/web/dijittest.2.html deleted file mode 100644 index d98f137187..0000000000 --- a/Open-ILS/web/dijittest.2.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - -

autosuggest dijit.form.FilteringSelect test

-
- - diff --git a/Open-ILS/web/js/dojo/openils/AutoSuggestStore.js b/Open-ILS/web/js/dojo/openils/AutoSuggestStore.js index a296adf3bb..99599023b3 100644 --- a/Open-ILS/web/js/dojo/openils/AutoSuggestStore.js +++ b/Open-ILS/web/js/dojo/openils/AutoSuggestStore.js @@ -1,7 +1,6 @@ if (!dojo._hasResource["openils.AutoSuggestStore"]) { dojo._hasResource["openils.AutoSuggestStore"] = true; dojo.provide("openils.AutoSuggestStore"); - dojo.require("dojox.html"); dojo.require("openils.Util"); /* an exception class specific to openils.AutoSuggestStore */ @@ -17,9 +16,18 @@ if (!dojo._hasResource["openils.AutoSuggestStore"]) { "openils.AutoSuggestStore", null, { "constructor": function(/* object */ args) { + dojo.mixin(this, args); /* XXX very sloppy */ this._current_items = {}; }, + "_prepare_match_for_display": function(match, field) { + return ( + "
" + + match + "
" + field + + "
" + ); + }, + /* req will have attribute 'query' and possibly 'limit', for now */ "_prepare_autosuggest_url": function(req) { var term = req.query.term; @@ -31,11 +39,11 @@ if (!dojo._hasResource["openils.AutoSuggestStore"]) { term += " "; term = term.replace(/\*$/, ""); -// console.log("transformed query: '" + term + "'"); - - /* XXX limit! org_unit! */ - return "/opac/extras/autosuggest?query=" + - encodeURI(term) + "&search_class=title"; + /* XXX support limit here? the mod_perl interface does */ + return "/opac/extras/autosuggest?" + [ + "query=" + encodeURI(term), + "search_class=" + this.type_selector.value + ].join("&"); }, /* *** Begin dojo.data.api.Read methods *** */ @@ -179,7 +187,7 @@ if (!dojo._hasResource["openils.AutoSuggestStore"]) { // // description: // Translate the *query* into a call we make to the - // autosuggest webserver module, which yields XML for us, + // autosuggest webserver module, which yields JSON for us, // and translate those results into items, storing them // in our internal cache. // @@ -200,20 +208,19 @@ if (!dojo._hasResource["openils.AutoSuggestStore"]) { // The Read API also charges this method with adding an abort // callback to the *req* object for the caller's use, but // the one we provide does nothing but issue an alert(). -// console.log("fetch(" + dojo.toJson(openils.Util.objectProperties(req)) + ")"); + console.log("fetch(" + dojo.toJson(openils.Util.objectProperties(req)) + ")"); var callback_scope = req.scope || dojo.global; var url = this._prepare_autosuggest_url(req); if (!url) { -// console.log("what happens if we do nothing?"); if (typeof req.onComplete == "function") { -// console.log(" except calling onComplete!"); - var results = openils.Util.objectValues(this._current_items); -// console.log(" results are " + results.length + " item(s)"); - req.onComplete.call(callback_scope, results, req); + req.onComplete.call( + callback_scope, + openils.Util.objectValues(this._current_items), + req + ); } - return; } @@ -222,24 +229,16 @@ if (!dojo._hasResource["openils.AutoSuggestStore"]) { /* set up some closures... */ var self = this; - var process_fetch = function(xmldoc) { -// console.log("inside process_fetch"); - dojo.query("as val", xmldoc).forEach( - function(val) { - var item = {}; - item.field = val.getAttribute("field"); - item.term = val.getAttribute("term"); - - /* XXX obv this next bit needs improvement, but it - * shows that what we want to do is plenty possible */ - item.match = - val.textContent.replace(/>/, ">"). - replace(/</, "<"). - replace(/&/, "&"); - item.match = "
" + item.match + - "
" + item.field + "
"; + var process_fetch = function(obj) { + obj.val.forEach( + function(item) { + /* XXX May not need this id field ultimately; still + * trying to use it to solve misc problems. */ item.id = item.field + "_" + item.term; + item.match = self._prepare_match_for_display( + item.match, item.field + ); self._current_items[item.id] = item; if (typeof req.onItem == "function") @@ -268,9 +267,10 @@ if (!dojo._hasResource["openils.AutoSuggestStore"]) { dojo.xhrGet( { "url": url, - "handleAs": "xml", + "handleAs": "json", "sync": false, - "preventCache": false, + "preventCache": false, /* XXX is this what we want? */ + "headers": {"Accept": "application/json"}, "load": process_fetch } ); @@ -296,7 +296,7 @@ if (!dojo._hasResource["openils.AutoSuggestStore"]) { "getIdentityAttributes": function(/* object */ item) { // summary: // Given an *item* return the list of the name of the fields - // that constitute the item's unique identifier. + // that constitute the item's unique identifier. // console.log("getIdentityAttributes()"); return ["id"]; }, diff --git a/Open-ILS/web/opac/skin/default/css/layout.css b/Open-ILS/web/opac/skin/default/css/layout.css index 8a4ca89efc..b977d0bb8c 100644 --- a/Open-ILS/web/opac/skin/default/css/layout.css +++ b/Open-ILS/web/opac/skin/default/css/layout.css @@ -263,3 +263,10 @@ tr[name="myopac_invalid_addr_row"] td { td.toc_label { text-align: right; } td.toc_title { text-align: left; padding-left: 1em; padding-right: 2em; } td.toc_page { text-align: right; } + +.oils_AS { font-weight: bold; color: #c00; } +.oils_AS_match_term { text-align: left; color: #000; } +.oils_AS_match_field { + font-size: 75%; padding: 0.65em 0; + text-align: right; color: #666; +} diff --git a/Open-ILS/web/opac/skin/default/js/search_bar.js b/Open-ILS/web/opac/skin/default/js/search_bar.js index c77caa8351..fbff91a01f 100644 --- a/Open-ILS/web/opac/skin/default/js/search_bar.js +++ b/Open-ILS/web/opac/skin/default/js/search_bar.js @@ -13,27 +13,22 @@ G.evt.common.init.push(searchBarInit); var newSearchLocation; var newSearchDepth = null; -dojo.require("openils.BibTemplate"); - - -var autosuggest_ft; - -function autosuggestTest() { - if (!autosuggest_ft) { - autosuggest_ft = new openils.FeedTemplate({ - "place": dojo.byId("test1"), - "root": dojo.byId("template_root"), - "empty": true, - "query": "as", - "preventCache": true /* XXX do we want this permanently? */ - }); - } - - autosuggest_ft.feed_uri = "http://dev-vm1/opac/extras/autosuggest?query=" + - dojo.byId("search_box").value; - console.log(autosuggest_ft.feed_uri); - - autosuggest_ft.render(); +dojo.require("dijit.form.FilteringSelect"); +dojo.require("openils.AutoSuggestStore"); + +function autoSuggestInit() { + var as_store = new openils.AutoSuggestStore( + {"type_selector": G.ui.searchbar.type_selector} + ); + new dijit.form.FilteringSelect({ + "store": as_store, + "labelAttr": "match", + "labelType": "html", + "searchAttr": "term", + "hasDownArrow": false, + "autoComplete": false, + "style": dojo.attr("search_box", "style") + }, "search_box"); } function searchBarInit() { @@ -69,6 +64,8 @@ function searchBarInit() { if(getSort() && getSortDir()) setSelector($('opac.result.sort'), getSort()+'.'+getSortDir()); } + + autoSuggestInit(); /* XXX TODO make this conditional. OU setting? */ } function searchBarSubmit(isFilterSort) { diff --git a/Open-ILS/web/opac/skin/default/xml/home/homesearch.xml b/Open-ILS/web/opac/skin/default/xml/home/homesearch.xml index 1db0f336a7..30ca9a3481 100644 --- a/Open-ILS/web/opac/skin/default/xml/home/homesearch.xml +++ b/Open-ILS/web/opac/skin/default/xml/home/homesearch.xml @@ -55,14 +55,10 @@ -
- - - unhidesearch - -
- -
+ + + + @@ -132,16 +128,8 @@ -
-
- - - -
-
+ + + + -- 2.11.0