[open-ils-commits] r17057 - in trunk/Open-ILS: examples src/perlmods/OpenILS/Application src/perlmods/OpenILS/Application/Storage/Publisher src/perlmods/OpenILS/WWW web/js/dojo/fieldmapper web/js/dojo/openils/widget web/js/dojo/openils/widget/nls web/opac/common/js web/opac/locale/en-US web/opac/skin/default/js web/opac/skin/default/xml/common web/opac/skin/default/xml/rdetail web/opac/theme/default/css (miker)

svn at svn.open-ils.org svn at svn.open-ils.org
Thu Jul 29 17:08:42 EDT 2010


Author: miker
Date: 2010-07-29 17:08:36 -0400 (Thu, 29 Jul 2010)
New Revision: 17057

Added:
   trunk/Open-ILS/web/js/dojo/openils/widget/FacetSidebar.js
   trunk/Open-ILS/web/js/dojo/openils/widget/Searcher.js
   trunk/Open-ILS/web/js/dojo/openils/widget/nls/Searcher.js
Modified:
   trunk/Open-ILS/examples/fm_IDL.xml
   trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/metabib.pm
   trunk/Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm
   trunk/Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm
   trunk/Open-ILS/web/js/dojo/fieldmapper/Fieldmapper.js
   trunk/Open-ILS/web/opac/common/js/config.js
   trunk/Open-ILS/web/opac/common/js/opac_utils.js
   trunk/Open-ILS/web/opac/locale/en-US/opac.dtd
   trunk/Open-ILS/web/opac/skin/default/js/rdetail.js
   trunk/Open-ILS/web/opac/skin/default/js/result_common.js
   trunk/Open-ILS/web/opac/skin/default/js/search_bar.js
   trunk/Open-ILS/web/opac/skin/default/js/sidebar.js
   trunk/Open-ILS/web/opac/skin/default/xml/common/js_common.xml
   trunk/Open-ILS/web/opac/skin/default/xml/common/searchbar.xml
   trunk/Open-ILS/web/opac/skin/default/xml/common/sidebar.xml
   trunk/Open-ILS/web/opac/skin/default/xml/rdetail/rdetail_summary.xml
   trunk/Open-ILS/web/opac/theme/default/css/colors.css
Log:
This patch replaces the result page sidebar new-search trees
(implemented before "faceting" became a thing, and designed for
new-search, not drill-down) with and implementation of what has become
the generally accepted "way to do faceting".  This is implemented as a
Dojo Dijit, and the markup and code footprints within the OPAC proper
are small, just  a couple <div>s and a little bit of glue code to help
the facet rendering engine find the data it needs.  The set and order
of facet classes to display in a given facet bar (title, author,
subject, etc) is configurable in the markup, as are the number of
values displayed for each facet when collapsed (before the [More...]
button is pushed).

Also included is a Searcher Dijit which implements an embeddable
advanced search interface.  This is mainly useful for constructing
boolean-chained searches (we support AND and OR now, though they're
spelled && and || in the query string), and has the beginnings of
support for filters and modifiers.



Modified: trunk/Open-ILS/examples/fm_IDL.xml
===================================================================
--- trunk/Open-ILS/examples/fm_IDL.xml	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/examples/fm_IDL.xml	2010-07-29 21:08:36 UTC (rev 17057)
@@ -1510,7 +1510,7 @@
         </permacrud>
 	</class>
 
-	<class id="cmsa" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_search_alias" oils_persist:tablename="config.metabib_search_alias" reporter:label="Metabib Search Alias">
+	<class id="cmsa" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_search_alias" oils_persist:tablename="config.metabib_search_alias" reporter:label="Metabib Search Alias" oils_persist:field_safe="true">
 		<fields oils_persist:primary="alias">
 			<field reporter:label="Alias (RegExp)" name="alias" reporter:datatype="text"/>
 			<field reporter:label="Class" name="field_class" reporter:datatype="link"/>
@@ -1530,7 +1530,7 @@
         </permacrud>
 	</class>
 
-	<class id="cmc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_class" oils_persist:tablename="config.metabib_class" reporter:label="Metabib Class">
+	<class id="cmc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_class" oils_persist:tablename="config.metabib_class" reporter:label="Metabib Class" oils_persist:field_safe="true">
 		<fields oils_persist:primary="name">
 			<field reporter:label="Name" name="name" reporter:datatype="text"/>
 			<field reporter:label="Label" name="label" reporter:datatype="text"/>
@@ -1549,7 +1549,7 @@
         </permacrud>
 	</class>
 
-	<class id="cmf" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_field" oils_persist:tablename="config.metabib_field" reporter:label="Metabib Field">
+	<class id="cmf" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_field" oils_persist:tablename="config.metabib_field" reporter:label="Metabib Field" oils_persist:field_safe="true">
 		<fields oils_persist:primary="id" oils_persist:sequence="config.metabib_field_id_seq">
 			<field reporter:label="Class" name="field_class" reporter:datatype="link"/>
 			<field reporter:label="ID" name="id" reporter:datatype="id" />

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/metabib.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/metabib.pm	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/metabib.pm	2010-07-29 21:08:36 UTC (rev 17057)
@@ -3092,6 +3092,8 @@
     my $query = $base_query;
     $log->debug("Full base query: $base_query", DEBUG);
 
+    $query = "$args{facets} $query" if  ($args{facets});
+
     if (!$locale_map{COMPLETE}) {
 
         my @locales = config::i18n_locale->search_where({ code => { '<>' => '' } });

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm	2010-07-29 21:08:36 UTC (rev 17057)
@@ -1862,6 +1862,9 @@
 				{ name => 'orgUnit',
 				  desc => 'An OpenILS actor::org_unit short name that limits the scope of returned holdings',
 				  type => 'text' },
+				{ name => 'depth',
+				  desc => 'An OpenILS actor::org_unit_type depththat limits the scope of returned holdings',
+				  type => 'number' },
 				{ name => 'hideCopies',
 				  desc => 'Flag that prevents the inclusion of copies in the returned holdings',
 				  type => 'boolean' },

Modified: trunk/Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm	2010-07-29 21:08:36 UTC (rev 17057)
@@ -367,7 +367,7 @@
 		if ($uri =~ m{^tag:[^:]+:([^\/]+)/([^\/[]+)(?:\[([0-9,]+)\])?(?:/(.+))?}o) {
 			$id = $2;
 			$paging = $3;
-			$lib = uc($4);
+			($lib,$depth) = split('/', $4);
 			$type = 'record';
 			$type = 'metarecord' if ($1 =~ /^m/o);
 			$type = 'authority' if ($1 =~ /^authority/o);

Modified: trunk/Open-ILS/web/js/dojo/fieldmapper/Fieldmapper.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/fieldmapper/Fieldmapper.js	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/js/dojo/fieldmapper/Fieldmapper.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -182,7 +182,7 @@
 			if (dojo.isObject(params)) {
 				args = params;
 			} else {
-                args.params = [].splice.call(arguments, 1, arguments.length - 1);
+                args.params = [].splice.call(arguments, 2, arguments.length - 2);
 			}
 
 		}

Added: trunk/Open-ILS/web/js/dojo/openils/widget/FacetSidebar.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/openils/widget/FacetSidebar.js	                        (rev 0)
+++ trunk/Open-ILS/web/js/dojo/openils/widget/FacetSidebar.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -0,0 +1,223 @@
+/* ---------------------------------------------------------------------------
+ * Copyright (C) 2010  Equinox Software, Inc
+ * Mike Rylander <miker at esilibrary.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * ---------------------------------------------------------------------------
+ */
+
+if(!dojo._hasResource["openils.widget.FacetSidebar"]) {
+
+    dojo._hasResource["openils.widget.FacetSidebar"] = true;
+    dojo.provide("openils.widget.FacetSidebar");
+    dojo.require("openils.widget.Searcher");
+
+    dojo.declare(
+        'openils.widget.FacetSidebar',
+        [dijit._Widget, dijit._Templated],
+        {   
+
+            templateString : '<div dojoAttachPoint="myTop"><div dojoAttachPoint="containerNode"></div><div class="facetClassContainer" dojoAttachPoint="facetClasses"></div></div>',
+            widgetsInTemplate: false,
+
+            facetData : {},
+            facetCacheKey : '',
+            searchBox : '',
+            classOrder : null,
+            searchSubmit : '',
+            facetLimit : 10,
+
+            startup : function () {
+                this.populate();
+                this.inherited(arguments)
+            },
+
+            populate : function () {},
+
+            render : function () {
+                if (!this.facetCacheKey) return;
+
+                if (openils.widget.Searcher._cache.facetData) {
+                    this.facetData = openils.widget.Searcher._cache.facetData;
+                } else {
+                    var facetData = fieldmapper.standardRequest( [ 'open-ils.search', 'open-ils.search.facet_cache.retrieve'], this.facetCacheKey );
+                    if (!facetData) return;
+                    this.facetData = openils.widget.Searcher._cache.facetData = facetData;
+                }
+
+                var classes = openils.widget.Searcher._cache.arr.cmc;
+                if (this.classOrder && this.classOrder.length > 0) {
+                    classes = [];
+                    dojo.forEach(
+                        this.classOrder,
+                        function(x) { classes.push({name:x}); }
+                    );
+                }
+
+                var me = this;
+                dojo.forEach(
+                    classes,
+                    function (x) {
+                        var possible_facets = dojo.filter(
+                            openils.widget.Searcher._cache.arr.cmf,
+                            function (y) {
+                                if (y.field_class == x.name && facetData[y.id]) return 1;
+                                return 0;
+                            }
+                        );
+                        if (possible_facets.length > 0) me.addClass( x.name, possible_facets );
+                    }
+                );
+            },
+
+            addClass : function (thisclass, facets) {
+                return new openils.widget.FacetSidebar.facetClass(
+                    { facetLimit: this.facetLimit, searchBox : this.searchBox, searchSubmit : this.searchSubmit, facetClass : thisclass, facetData : this.facetData, facetList : facets }
+                ).placeAt(this.facetClasses, 'last');
+            }
+        }
+    );
+
+    dojo._hasResource["openils.widget.FacetSidebar.facetClass"] = true;
+    dojo.provide("openils.widget.FacetSidebar.facetClass");
+
+    dojo.declare(
+        'openils.widget.FacetSidebar.facetClass',
+        [dijit._Widget, dijit._Templated],
+        {   
+
+            templateString :
+'<div class="facetClassLabelContainer">' +
+'  <div class="facetClassLabel" dojoAttachPoint="facetClassLabel"></div>' +
+'  <div class="facetFieldContainer" dojoAttachPoint="facetFields"></div>' +
+'</div>',
+            widgetsInTemplate: false,
+
+            facetLimit : 10,
+            facetClass : '',
+            facetData : null,
+            facetList : null,
+            searchBox : '',
+            searchSubmit : '',
+
+            postCreate : function () {
+                if (!this.facetClass) return;
+                if (!this.facetData) return;
+
+                var myclass = this.facetClass;
+
+                var fclass = dojo.filter(openils.widget.Searcher._cache.arr.cmc, function (x) { if (x.name == myclass) return 1; return 0; })[0];
+                this.facetClassLabel.innerHTML = fclass.label;
+
+                var me = this;
+                dojo.forEach(
+                    this.facetList,
+                    function (f) { me.addFacets(f); }
+                );
+            },
+
+            addFacets : function (f) {
+                return new openils.widget.FacetSidebar.facetField(
+                    { facetLimit: this.facetLimit, searchBox : this.searchBox, searchSubmit : this.searchSubmit, facet : f, facetData : this.facetData[f.id] }
+                ).placeAt( this.facetFields, 'last' );
+            }
+        }
+    );
+
+    dojo._hasResource["openils.widget.FacetSidebar.facetField"] = true;
+    dojo.provide("openils.widget.FacetSidebar.facetField");
+
+    dojo.declare(
+        'openils.widget.FacetSidebar.facetField',
+        [dijit._Widget, dijit._Templated],
+        {   
+
+            templateString : 
+'<div class="facetField" dojoAttachPoint="myTop">' +
+'  <div class="extraFacetFieldsWrapper" dojoAttachPoint="toggleExtraFacetFieldsWrapper"><button class="toggleExtraFacetFieldsButton" dojoType="dijit.form.Button" dojoAttachPoint="toggleExtraFacetFields" dojoAttachEvent="onClick:toggleExtraFacets"></button></div>' +
+'  <div class="facetFieldLabel" dojoAttachPoint="facetLabel"></div>' +
+'  <div class="facetFields" dojoAttachPoint="facetFields"></div>' +
+'  <div class="facetFields hide_me" dojoAttachPoint="extraFacetFields"></div>' +
+'</div>',
+
+            widgetsInTemplate: true,
+            facet : null,
+            facetData : null,
+            facetLimit : 10,
+            searchBox : '',
+            searchSubmit : '',
+            extraHidden : true,
+
+            postCreate : function () {
+                this.nls = dojo.i18n.getLocalization("openils.widget", "Searcher");
+                var me = this;
+                var keylist = []; for (var i in this.facetData) { keylist.push(i); }
+
+                keylist = keylist.sort(function(a,b){
+                    if (me.facetData[a] < me.facetData[b]) return 1;
+                    if (me.facetData[a] > me.facetData[b]) return -1;
+                    if (a < b) return -1;
+                    if (a > b) return 1;
+                    return 0;
+                });
+
+                this.facetLabel.innerHTML = this.facet.label;
+                this.toggleExtraFacetFields.setLabel(this.nls.more);
+
+                var pos = 0;
+                dojo.forEach(
+                    keylist,
+                    function(value){
+
+                        var have_it = dojo.byId(me.searchBox).value.indexOf(me.facet.field_class + '|' + me.facet.name + '[' + value + ']') > -1;
+
+                        var container = dojo.create('div',{'class':'facetFieldLine'});
+                        dojo.create('span',{'class':'facetFieldLineCount', innerHTML: me.facetData[value]},container);
+
+                        if (have_it) {
+                            dojo.create('a',{href : '#', 'class':'facetFieldLineValue', onclick : function(){ me.undoSearch(value); return false;}, innerHTML: '<b>(' + value + ')</b>'},container);
+                        } else {
+                            dojo.create('a',{href : '#', 'class':'facetFieldLineValue', onclick : function(){ me.doSearch(value); return false;}, innerHTML: value},container);
+                        }
+
+                        if (pos >= me.facetLimit) dojo.place(container,me.extraFacetFields,'last');
+                        else dojo.place(container,me.facetFields,'last');
+
+                        pos++;
+                    }
+                );
+
+                if (pos < me.facetLimit + 1) dojo.query(this.toggleExtraFacetFieldsWrapper).toggleClass('hide_me');
+
+            },
+
+            toggleExtraFacets : function () {
+                dojo.query(this.extraFacetFields).toggleClass('hide_me');
+                this.extraHidden = !this.extraHidden;
+                this.extraHidden ? this.toggleExtraFacetFields.setLabel(this.nls.more) : this.toggleExtraFacetFields.setLabel(this.nls.less);
+            },
+
+            undoSearch : function (value) {
+                var sb = dojo.byId(this.searchBox);
+                sb.value = sb.value.replace(this.facet.field_class + '|' + this.facet.name + '[' + value + ']','');
+                dojo.byId(this.searchSubmit).click();
+            },
+
+            doSearch : function (value) {
+                dojo.byId(this.searchBox).value += ' ' + this.facet.field_class + '|' + this.facet.name + '[' + value + ']';
+                dojo.byId(this.searchSubmit).click();
+            }
+        }
+    );
+
+
+}
+

Added: trunk/Open-ILS/web/js/dojo/openils/widget/Searcher.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/openils/widget/Searcher.js	                        (rev 0)
+++ trunk/Open-ILS/web/js/dojo/openils/widget/Searcher.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -0,0 +1,543 @@
+/* ---------------------------------------------------------------------------
+ * Copyright (C) 2010  Equinox Software, Inc
+ * Mike Rylander <miker at esilibrary.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * ---------------------------------------------------------------------------
+ */
+
+if(!dojo._hasResource["openils.widget.Searcher"]) {
+
+    dojo._hasResource["openils.widget.Searcher"] = true;
+    dojo.provide("openils.widget.Searcher");
+
+    dojo.require("fieldmapper.AutoIDL");
+    dojo.require("openils.I18N");
+    dojo.require("fieldmapper.dojoData");
+    dojo.require("DojoSRF");
+    dojo.require("dojo.data.ItemFileReadStore");
+    dojo.require("dijit._Widget");
+    dojo.require("dijit._Templated");
+    dojo.require("dijit.form.Button");
+    dojo.require("dijit.form.TextBox");
+    dojo.require("dijit.form.FilteringSelect");
+    dojo.requireLocalization("openils.widget", "Searcher");
+
+    fieldmapper.IDL.load(['cmf','cmc','cmsa']);
+
+//------ searching wrapper, uses dijits below -----------------------------------------------
+
+    dojo.declare(
+        'openils.widget.Searcher',
+        [dijit._Widget, dijit._Templated],
+        {
+
+            templateString : 
+"<div dojoAttachPoint='searcherTopNode'>" +
+
+"  <div dojoAttachPoint='deck'>" +
+"    <div dojoAttachPoint='basicSearch'>" +
+"      <span dojoAttachPoint='containerNode' class='searcherSimpleSearchWrapper'></span>" +
+"    </div>" +
+
+"    <div dojoAttachPoint='advSearch' class='hide_me searcherAdvancedSearchWrapper'>" +
+"      <div dojoAttachPoint='searcherClassedSearchesContainer' class='searcherClassedSearchesContainer hide_me'>" +
+"        <div dojoAttachPoint='classedSearches' class='searcherClassedSearches'>" +
+"          <span dojoAttachPoint='searcherClassedSearchesLabel' class='searcherClassedSearchesLabel'></span>" +
+"        </div>" +
+"        <div class='searcherClassedSearchesAddContainer'>" +
+"          <button dojoType='dijit.form.Button' dojoAttachPoint='andClassedSearch' dojoAttachEvent='onClick:addClassAnd'></button>" +
+"          <button dojoType='dijit.form.Button' dojoAttachPoint='orClassedSearch' dojoAttachEvent='onClick:addClassOr'></button>" +
+"        </div>" +
+"      </div>" +
+
+"      <div dojoAttachPoint='searcherFacetedSearchesContainer' class='searcherFacetedSearchesContainer hide_me'>" +
+"        <div class='searcherFacetedSearches' dojoAttachPoint='facetedSearches'>" +
+"          <span dojoAttachPoint='searcherFacetedSearchesLabel' class='searcherFacetedSearchesLabel'></span>" +
+"        </div>" +
+"        <span>" +
+"          <button dojoType='dijit.form.Button' dojoAttachPoint='addFacetedSearch' dojoAttachEvent='onClick:addFacet'></button>" +
+"        </span>" +
+"      </div>" +
+
+"      <div dojoAttachPoint='searcherFilterModifierContainer' class='searcherFilterModifierContainer hide_me'>" +
+"        <table width='100%'><tbody><tr>" +
+"          <td dojoAttachPoint='searcherFilterContainer' class='searcherFilterContainer hide_me' valign='top' width='50%'>" +
+"            <div dojoAttachPoint='filters'>" +
+"              <span dojoAttachPoint='searcherFiltersLabel' class='searcherFiltersLabel'></span>" +
+"            </div>" +
+"            <button dojoType='dijit.form.Button' dojoAttachPoint='addFilterButton' dojoAttachEvent='onClick:addFilter'></button>" +
+"          </td>" +
+"          <td dojoAttachPoint='searcherModifierContainer' class='searcherModifierContainer hide_me' valign='top' width='50%'>" +
+"            <div dojoAttachPoint='modifiers'>" +
+"              <span dojoAttachPoint='searcherModifiersLabel' class='searcherModifiersLabel'></span>" +
+"            </div>" +
+"            <button dojoType='dijit.form.Button' dojoAttachPoint='addModifierButton' dojoAttachEvent='onClick:addModifier'></button>" +
+"          </td>" +
+"        </tr></tbody></table>" +
+"      </div>" +
+
+"      <div class='searcherGoContainer'>" +
+"        <span dojoType='dijit.form.Button' dojoAttachPoint='goButton' dojoAttachEvent='onClick:performSearch'></span>" +
+"      </div>" +
+"    </div>" +
+"  </div>" +
+
+"  <div class='searcherDeckSwapContainer'>" +
+"    <span dojoType='dijit.form.Button' dojoAttachPoint='advToggle' dojoAttachEvent='onClick:swapDeck'></span>" +
+"  </div>" +
+"</div>",
+            widgetsInTemplate: true,
+            advanced : false,
+            basicTextBox : '',
+            facetTextBox : '',
+            withClassedSearches : true,
+            withFacetedSearches : false,
+            withFiltersModifiers : false,
+            withFilters : false,
+            withModifiers : false,
+            basic_query : '',
+            facet_query : '',
+
+            compileFullSearch : function () {
+                if (!this.advanced) return dojo.byId( this.basicTextBox ).attr('value');
+
+                var query = '';
+
+                var first_cs = true;
+
+                // First, classed searches
+                dojo.query( '.classedSearch', this.classedSearches ).forEach(
+                    function (csearch) {
+                        csearch = dijit.byNode(csearch);
+                        var part = csearch.searchValue.attr('value');
+                        if (!part || part.match(/^\s+$/)) return;
+
+                        if (first_cs) first_cs = false;
+                        else query += csearch.anded ? '' : ' ||';
+
+                        query += ' ' + csearch.matchIndex.attr('value') + ':';
+                        if (csearch.matchType.attr('value') == 'exact') {
+                            query += '"';
+                        } else if (csearch.matchType.attr('value') == 'notcontains') {
+                            part = '-' + part.replace(/\s+/g, ' -');
+                        }
+
+                        query += part;
+
+                        if (csearch.matchType.attr('value') == 'exact') query += '"';
+                    }
+                );
+
+                var fquery = '';
+                // Now facets
+                dojo.query( '.facetedSearch', this.facetedSearches ).forEach(
+                    function (facet) {
+                        facet = dijit.byNode(facet);
+                        var part = facet.searchValue.attr('value');
+                        if (!part || part.match(/^\s+$/)) return;
+                        fquery += ' ' + facet.matchIndex.attr('value') + '[' + part + ']';
+                    }
+                );
+
+                // and filters...
+                dojo.query( '.filter', this.filters ).forEach(
+                    function (filt) {
+                        filt = dijit.byNode(filt);
+                        var part = filt.valueList.attr('value');
+                        if (!part || part.match(/^\s+$/) || filt.filterSelect.attr('value') == '-') return;
+                        query += ' ' + filt.filterSelect.attr('value') + '(' + part + ')';
+                    }
+                );
+
+                // finally, modifiers
+                dojo.query( '.modifier', this.modifiers ).forEach(
+                    function (modifier) {
+                        modifier = dijit.byNode(modifier);
+                        var part = modifier.modifierSelect.attr('value')
+                        if (!part || part == '-') return;
+                        query += ' #' + part;
+                    }
+                );
+
+
+                this.basic_query = query;
+                this.facet_query = fquery;
+
+                return query;
+            },
+
+            addFilter : function () {
+                return new openils.widget.Searcher.filter({}, dojo.create('div',null,this.filters));
+            },
+
+            addModifier : function () {
+                return new openils.widget.Searcher.modifier({}, dojo.create('div',null,this.modifiers));
+            },
+
+            addClassAnd : function () {
+                return new openils.widget.Searcher.classedSearch({}, dojo.create('div',null,this.classedSearches));
+            },
+
+            addClassOr  : function () {
+                return new openils.widget.Searcher.classedSearch({anded:false}, dojo.create('div',null,this.classedSearches));
+            },
+
+            addFacet : function () {
+                return new openils.widget.Searcher.facetedSearch({}, dojo.create('div',null,this.facetedSearches));
+            },
+
+            performSearch  : function () {},
+            populate  : function () {},
+
+            startup : function () {
+                if (this.advanced) {
+                    dojo.query(this.basicSearch).toggleClass('hide_me');
+                    dojo.query(this.advSearch).toggleClass('hide_me');
+                }
+
+                if (!this.facetTextBox) this.facetTextBox = this.basicTextBox;
+
+                if (this.withFiltersModifiers) {
+                    this.withFilters = true;
+                    this.withModifiers = true;
+                } else if (this.withFilters || this.withModifiers) {
+                    this.withFiltersModifiers = true;
+                }
+
+                if (this.withFiltersModifiers) dojo.query(this.searcherFilterModifierContainer).toggleClass('hide_me');
+                if (this.withFilters) dojo.query(this.searcherFilterContainer).toggleClass('hide_me');
+                if (this.withModifiers) dojo.query(this.searcherModifierContainer).toggleClass('hide_me');
+                if (this.withFacetedSearches) dojo.query(this.searcherFacetedSearchesContainer).toggleClass('hide_me');
+                if (this.withClassedSearches) dojo.query(this.searcherClassedSearchesContainer).toggleClass('hide_me');
+
+                this.populate();
+                this.inherited(arguments)
+            },
+    
+            swapDeck : function () {
+                if (this.advanced) this.advanced = false;
+                else this.advanced = true;
+
+                dojo.query(this.basicSearch).toggleClass('hide_me');
+                dojo.query(this.advSearch).toggleClass('hide_me');
+
+                if (this.advanced) this.advToggle.setLabel(this.nls.basic);
+                else this.advToggle.setLabel(this.nls.advanced);
+            },
+
+            postCreate : function () {
+                this.nls = dojo.i18n.getLocalization("openils.widget", "Searcher");
+
+                this.searcherClassedSearchesLabel.innerHTML = this.nls.classed_searches;
+                this.searcherFacetedSearchesLabel.innerHTML = this.nls.faceted_searches;
+                this.searcherFiltersLabel.innerHTML = this.nls.filters;
+                this.searcherModifiersLabel.innerHTML = this.nls.modifiers;
+                this.addFacetedSearch.setLabel(this.nls.new_facet);
+
+                this.andClassedSearch.setLabel(this.nls.and);
+                this.orClassedSearch.setLabel(this.nls.or);
+
+                this.addFilterButton.setLabel(this.nls.new_filter);
+                this.addModifierButton.setLabel(this.nls.new_modifier);
+
+                this.goButton.setLabel(this.nls.perform_search);
+
+                if (this.advanced) this.advToggle.setLabel(this.nls.basic);
+                else this.advToggle.setLabel(this.nls.advanced);
+                
+                new openils.widget.Searcher.classedSearch(
+                    { noRemove : true },
+                    dojo.create('div',null,this.classedSearches)
+                );
+            }
+
+        } 
+    );
+
+    openils.widget.Searcher._cache = {arr : {}, obj : {}, store : {}};
+
+    dojo.forEach(
+        [ {ident:'name',classname:'cmc',label:'label'}, {ident:'id',classname:'cmf',label:'label'}, {ident:'alias',classname:'cmsa',label:'alias'} ],
+        function (c) {
+
+            var q = {};
+            q[c.ident] = { '!=' :  null };
+
+            var fielder_result = fieldmapper.standardRequest(
+                [ 'open-ils.fielder', 'open-ils.fielder.'+c.classname+'.atomic'],
+                [ { query : q } ]
+            );
+
+            var sorted_fielder_result = fielder_result.sort( function(a,b) {
+                if(a[c.label] > b[c.label]) return 1;
+                if(a[c.label] < b[c.label]) return -1;
+                return 0;
+            });
+
+            openils.widget.Searcher._cache.arr[c.classname] = sorted_fielder_result;
+
+            var list = [];
+            openils.widget.Searcher._cache.obj[c.classname] = {};
+
+            dojo.forEach(
+                openils.widget.Searcher._cache.arr[c.classname],
+                function (x) {
+                    openils.widget.Searcher._cache.obj[c.classname][x[c.ident]] = x;
+                    list.push(x);
+                }
+            );
+
+            openils.widget.Searcher._cache.store[c.classname] = new dojo.data.ItemFileReadStore( { data : {identifier : c.ident, label : c.label, items : list } } );
+        }
+    );
+
+    var facet_list = [];
+    var search_list = [];
+
+    dojo.forEach(
+        openils.widget.Searcher._cache.arr.cmc,
+        function (cmc_obj) {
+            search_list.push({
+                name    : cmc_obj.name,
+                label   : cmc_obj.label
+            });
+            dojo.forEach(
+                dojo.filter(
+                    openils.widget.Searcher._cache.arr.cmf,
+                    function (x) {
+                        if (x.field_class == cmc_obj.name) return 1;
+                        return 0;
+                    }
+                ),
+                function (cmf_obj) {
+                    if (cmf_obj.search_field == 't') {
+                        search_list.push({
+                            name : cmc_obj.name + '|' + cmf_obj.name,
+                            label : ' -- ' + cmf_obj.label
+                        });
+                    }
+                    if (cmf_obj.facet_field == 't') {
+                        facet_list.push({
+                            name : cmc_obj.name + '|' + cmf_obj.name,
+                            label : cmc_obj.label + ' : '  + cmf_obj.label
+                        });
+                    }
+                }
+            )
+        }
+    );
+
+    openils.widget.Searcher.facetStore = new dojo.data.ItemFileReadStore( { data : {identifier : 'name', label : 'label', items : facet_list} } );
+    openils.widget.Searcher.searchStore = new dojo.data.ItemFileReadStore( { data : {identifier : 'name', label : 'label', items : search_list} } );
+
+//------ modifiers template -----------------------------------------------
+
+    dojo._hasResource["openils.widget.Searcher.modifier"] = true;
+    dojo.provide("openils.widget.Searcher.modifier");
+
+    dojo.declare(
+        'openils.widget.Searcher.modifier',
+        [dijit._Widget, dijit._Templated],
+        {
+
+            templateString :
+'<table dojoAttachPoint="myTop" class="modifier"><tbody><tr>' +
+'   <td>' +
+'     <select value="-" name="modifierSelect" dojoAttachPoint="modifierSelect" dojoType="dijit.form.FilteringSelect" >' +
+'       <option dojoAttachPoint="modifierDefault" value="-">-- Select a Modifier --</option>' +
+'       <option dojoAttachPoint="modifierAvailable" value="available"></option>' +
+'       <option dojoAttachPoint="modifierDescending" value="descending"></option>' +
+'       <option dojoAttachPoint="modifierAscending" value="ascending"></option>' +
+'       <option dojoAttachPoint="modifierMetabib" value="metabib"></option>' +
+'       <option dojoAttachPoint="modifierStaff" value="staff"></option>' +
+'     </select>' +
+'   </td> ' +
+'   <td dojoAttachPoint="removeWrapper"><span dojoType="dijit.form.Button" dojoAttachPoint="removeButton" dojoAttachEvent="onClick:killMe"></span></td> ' +
+'</tr></tbody></table>',
+            widgetsInTemplate: true,
+
+            postCreate : function () {
+                this.nls = dojo.i18n.getLocalization("openils.widget", "Searcher");
+
+                this.modifierDefault.innerHTML = this.nls.modifier_default;
+                this.modifierAvailable.innerHTML = this.nls.available;
+                this.modifierDescending.innerHTML = this.nls.descending;
+                this.modifierAscending.innerHTML = this.nls.ascending;
+                this.modifierMetabib.innerHTML = this.nls.metabib;
+                this.modifierStaff.innerHTML = this.nls.staff;
+
+                this.removeButton.setLabel(this.nls.remove);
+            },
+    
+            killMe : function () {
+                dijit.byNode(this.myTop).destroyRecursive();
+                this.destroy();
+            }
+        }
+    );
+
+//------ filters template -----------------------------------------------
+
+    dojo._hasResource["openils.widget.Searcher.filter"] = true;
+    dojo.provide("openils.widget.Searcher.filter");
+
+    dojo.declare(
+        'openils.widget.Searcher.filter',
+        [dijit._Widget, dijit._Templated],
+        {
+
+            templateString :
+'<table dojoAttachPoint="myTop" class="filter"><tbody><tr>' +
+'   <td>' +
+'     <select value="-" name="filterSelect" dojoAttachPoint="filterSelect" dojoType="dijit.form.FilteringSelect">' +
+'       <option dojoAttachPoint="filterDefault" value="-">-- Select a Filter --</option>' +
+'       <option dojoAttachPoint="filterSite" value="site">Site</option>' +
+'       <option dojoAttachPoint="filterDepth" value="depth">Search Depth</option>' +
+'       <option dojoAttachPoint="filterSort" value="sort">Sort Axis</option>' +
+'       <option dojoAttachPoint="filterStatuses" value="statuses">Statuses</option>' +
+'       <option dojoAttachPoint="filterAudience" value="audience">Audience</option>' +
+'       <option dojoAttachPoint="filterBefore" value="before">Published Before</option>' +
+'       <option dojoAttachPoint="filterAfter" value="after">Published After</option>' +
+'       <option dojoAttachPoint="filterBetween" value="between">Published Between</option>' +
+'       <option dojoAttachPoint="filterDuring" value="during">In Publication</option>' +
+'       <option dojoAttachPoint="filterForm" value="item_form">Form</option>' +
+'       <option dojoAttachPoint="filterType" value="item_type">Type</option>' +
+'       <option dojoAttachPoint="filterTypeForm" value="format">Type and Form</option>' +
+'       <option dojoAttachPoint="filterVRFormat" value="vr_format">Videorecording Format</option>' +
+'       <option dojoAttachPoint="filterLitForm" value="lit_form">Literary Form</option>' +
+'       <option dojoAttachPoint="filterBibLevel" value="bib_level">Bibliographic Level</option>' +
+'     </select>' +
+'   </td> ' +
+'   <td><div dojoAttachPoint="valueList" dojoType="dijit.form.TextBox"></div></td> ' +
+'   <td dojoAttachPoint="removeWrapper"><span dojoType="dijit.form.Button" dojoAttachPoint="removeButton" dojoAttachEvent="onClick:killMe"></span></td> ' +
+'</tr></tbody></table>',
+            widgetsInTemplate: true,
+
+            postCreate : function () {
+                this.nls = dojo.i18n.getLocalization("openils.widget", "Searcher");
+
+                this.filterDefault.innerHTML = this.nls.filter_default;
+                this.filterSite.innerHTML = this.nls.site;
+                this.filterDepth.innerHTML = this.nls.depth;
+                this.filterSort.innerHTML = this.nls.sort;
+                this.filterStatuses.innerHTML = this.nls.statuses;
+                this.filterAudience.innerHTML = this.nls.audience;
+                this.filterBefore.innerHTML = this.nls.before;
+                this.filterAfter.innerHTML = this.nls.after;
+                this.filterBetween.innerHTML = this.nls.between;
+                this.filterDuring.innerHTML = this.nls.during;
+                this.filterForm.innerHTML = this.nls.item_form;
+                this.filterType.innerHTML = this.nls.item_type;
+                this.filterTypeForm.innerHTML = this.nls.format;
+                this.filterVRFormat.innerHTML = this.nls.vr_format;
+                this.filterLitForm.innerHTML = this.nls.lit_form;
+                this.filterBibLevel.innerHTML = this.nls.bib_level;
+
+                this.removeButton.setLabel(this.nls.remove);
+            },
+    
+            killMe : function () {
+                dijit.byNode(this.myTop).destroyRecursive();
+                this.destroy();
+            }
+        }
+    );
+
+//------ facet search template -----------------------------------------------
+
+    dojo._hasResource["openils.widget.Searcher.facetedSearch"] = true;
+    dojo.provide("openils.widget.Searcher.facetedSearch");
+
+    dojo.declare(
+        'openils.widget.Searcher.facetedSearch',
+        [dijit._Widget, dijit._Templated],
+        {
+
+            templateString :
+'<table dojoAttachPoint="myTop" class="facetedSearch"><tbody><tr>' +
+'   <td><div dojoAttachPoint="matchIndex" searchAttr="label" dojoType="dijit.form.FilteringSelect" store="openils.widget.Searcher.facetStore"></div></td> ' +
+'   <td><span style="margin-left:10px; margin-right:10px;" dojoAttachPoint="exactOption"></span></td> ' +
+'   <td><div dojoAttachPoint="searchValue" dojoType="dijit.form.TextBox"></div></td> ' +
+'   <td dojoAttachPoint="removeWrapper"><span dojoType="dijit.form.Button" dojoAttachPoint="removeButton" dojoAttachEvent="onClick:killMe"></span></td> ' +
+'</tr></tbody></table>',
+            widgetsInTemplate: true,
+
+            noRemove : false,
+
+            postCreate : function () {
+                this.nls = dojo.i18n.getLocalization("openils.widget", "Searcher");
+
+                this.exactOption.innerHTML = this.nls.exact;
+                this.removeButton.setLabel(this.nls.remove);
+
+                if (this.noRemove) dojo.destroy(this.removeWrapper);
+            },
+    
+            killMe : function () {
+                dijit.byNode(this.myTop).destroyRecursive();
+                this.destroy();
+            }
+        }
+    );
+
+//------ classed search template -----------------------------------------------
+
+    dojo._hasResource["openils.widget.Searcher.classedSearch"] = true;
+    dojo.provide("openils.widget.Searcher.classedSearch");
+
+    dojo.declare(
+        'openils.widget.Searcher.classedSearch',
+        [dijit._Widget, dijit._Templated],
+        {
+
+            templateString :
+'<table dojoAttachPoint="myTop" class="classedSearch"><tbody><tr>' +
+'   <td colspan="4" align="center"><span dojoAttachPoint="joinerSpan"></span></td></tr><tr> ' +
+'   <td><div dojoAttachPoint="matchIndex" value="keyword" searchAttr="label" dojoType="dijit.form.FilteringSelect" store="openils.widget.Searcher.searchStore"></div></td> ' +
+'   <td>' +
+'     <select dojoAttachPoint="matchType" dojoType="dijit.form.FilteringSelect" name="matchType">' +
+'       <option dojoAttachPoint="containsOption" value="contains">Contains</option>' +
+'       <option dojoAttachPoint="notContainsOption" value="notcontains">Does Not Contain</option>' +
+'       <option dojoAttachPoint="exactOption" value="exact"> Matches Exactly</option>' +
+'     </select>' +
+'   </td> ' +
+'   <td><div dojoAttachPoint="searchValue" dojoType="dijit.form.TextBox"></div></td> ' +
+'   <td dojoAttachPoint="removeWrapper"><span dojoType="dijit.form.Button" dojoAttachPoint="removeButton" dojoAttachEvent="onClick:killMe"></span></td> ' +
+'</tr></tbody></table>',
+            widgetsInTemplate: true,
+
+            anded : true,
+            noRemove : false,
+
+            postCreate : function () {
+                this.nls = dojo.i18n.getLocalization("openils.widget", "Searcher");
+
+                this.containsOption.innerHTML = this.nls.contains;
+                this.notContainsOption.innerHTML = this.nls.notcontains;
+                this.exactOption.innerHTML = this.nls.exact;
+
+                this.removeButton.setLabel(this.nls.remove);
+
+                if (this.noRemove) dojo.destroy(this.removeWrapper);
+                if (!this.noRemove && this.anded) this.joinerSpan.innerHTML = this.nls.and;
+                if (!this.noRemove && !this.anded) this.joinerSpan.innerHTML = this.nls.or;
+            },
+    
+            killMe : function () {
+                dojo.destroy(this.myTop);
+                this.destroy();
+            }
+        }
+    );
+
+
+}

Added: trunk/Open-ILS/web/js/dojo/openils/widget/nls/Searcher.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/openils/widget/nls/Searcher.js	                        (rev 0)
+++ trunk/Open-ILS/web/js/dojo/openils/widget/nls/Searcher.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -0,0 +1,42 @@
+{
+    and : '&&',
+    or  : '||',
+    more  : 'More...',
+    less  : '...Less',
+    classed_searches  : 'Classed Searches',
+    faceted_searches  : 'Facets',
+    filters  : 'Filters',
+    modifiers  : 'Modifiers',
+    new_facet  : 'New Facet',
+    new_filter  : 'New Filter',
+    new_modifier  : 'New Modifier',
+    remove  : 'Remove',
+    advanced  : 'Advanced',
+    basic  : 'Basic',
+    perform_search  : 'Go!',
+    contains : 'Contains',
+    notcontains : 'Does Not Contain',
+    exact : 'Exactly Matches',
+    modifier_default : '-- Select a Modifier --',
+    available : 'Available',
+    descending : 'Sort Descending',
+    ascending : 'Sort Ascending',
+    metabib : 'Metarecord Search',
+    staff : 'Staff Search',
+    filter_default : '-- Select a Filter --',
+    site : 'Site',
+    depth : 'Search Depth',
+    sort : 'Sort Axis',
+    statuses : 'Statuses',
+    audience : 'Audience',
+    before : 'Published Before',
+    after : 'Published After',
+    between : 'Published Between',
+    during : 'In Publication',
+    item_form : 'Form',
+    item_type : 'Type',
+    format : 'Type and Form',
+    vr_format : 'Videorecording Format',
+    lit_form : 'Literary Form',
+    bib_level : 'Bibliographic Level'
+}

Modified: trunk/Open-ILS/web/opac/common/js/config.js
===================================================================
--- trunk/Open-ILS/web/opac/common/js/config.js	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/common/js/config.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -9,6 +9,7 @@
 
 /* URL param names */
 var PARAM_TERM			= "t";			/* search term */
+var PARAM_FACET			= "ft";			/* facet term */
 var PARAM_STYPE		= "tp";			/* search type */
 var PARAM_LOCATION	= "l";			/* current location */
 var PARAM_LASSO	= "sg";			/* current location */
@@ -49,6 +50,7 @@
 
 /* URL param values (see comments above) */
 var TERM;  
+var FACET;  
 var STYPE;  
 var LOCATION;  
 var LASSO;  

Modified: trunk/Open-ILS/web/opac/common/js/opac_utils.js
===================================================================
--- trunk/Open-ILS/web/opac/common/js/opac_utils.js	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/common/js/opac_utils.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -140,6 +140,7 @@
 	if(isNaN(DEPTH)) DEPTH = null;
 
 
+	FACET		= cgi.param(PARAM_FACET);
 	TERM		= cgi.param(PARAM_TERM);
 	STYPE		= cgi.param(PARAM_STYPE);
 	FORM		= cgi.param(PARAM_FORM);
@@ -232,6 +233,7 @@
 
 /* URL param accessors */
 function getTerm(){return TERM;}
+function getFacet(){return FACET;}
 function getStype(){return STYPE;}
 function getLocation(){return LOCATION;}
 function getLasso(){return LASSO;}
@@ -376,6 +378,8 @@
 		string += _appendParam(ORIGLOC,	PARAM_ORIGLOC, args, getOrigLocation, string);
 	if(getTerm()) 
 		string += _appendParam(TERM,		PARAM_TERM, args, getTerm, string);
+	if(getFacet()) 
+		string += _appendParam(FACET,		PARAM_FACET, args, getFacet, string);
 	if(getStype()) 
 		string += _appendParam(STYPE,		PARAM_STYPE, args, getStype, string);
 	if(getLocation() != 1) 
@@ -504,7 +508,7 @@
 function buildSearchLink(type, string, linknode, trunc) {
 	if(!trunc) trunc = 65;
 	var args = {};
-	if( SHOW_MR_DEFAULT) {
+	if( SHOW_MR_DEFAULT || findCurrentPage() == MRESULT ) {
 		args.page = MRESULT;
 	} else {
 		args.page = RRESULT;

Modified: trunk/Open-ILS/web/opac/locale/en-US/opac.dtd
===================================================================
--- trunk/Open-ILS/web/opac/locale/en-US/opac.dtd	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/locale/en-US/opac.dtd	2010-07-29 21:08:36 UTC (rev 17057)
@@ -373,6 +373,7 @@
 <!ENTITY navigate.loggedinas.title "Logged in as...">
 <!ENTITY navigate.titleGroupResults "My Search Results">
 <!ENTITY navigate.titleResults "My Title Results">
+<!ENTITY navigate.facetRefine "Refine your search">
 <!ENTITY navigate.title.details "My Title Details">
 <!ENTITY navigate.record.details "Record Details">
 

Modified: trunk/Open-ILS/web/opac/skin/default/js/rdetail.js
===================================================================
--- trunk/Open-ILS/web/opac/skin/default/js/rdetail.js	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/skin/default/js/rdetail.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -464,9 +464,9 @@
 	breq.callback( rdetailCheckDeleted );
 	breq.send();
 
-	resultBuildCaches( [ record ] );
-	resultDrawSubjects();
-	resultDrawSeries();
+	//resultBuildCaches( [ record ] );
+	//resultDrawSubjects();
+	//resultDrawSeries();
 
 	// grab added content 
 

Modified: trunk/Open-ILS/web/opac/skin/default/js/result_common.js
===================================================================
--- trunk/Open-ILS/web/opac/skin/default/js/result_common.js	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/skin/default/js/result_common.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -13,9 +13,7 @@
 	G.evt.result.hitCountReceived.push(resultSetHitInfo);
 	G.evt.result.recordReceived.push(resultDisplayRecord, resultAddCopyCounts);
 	G.evt.result.copyCountsReceived.push(resultDisplayCopyCounts);
-	G.evt.result.allRecordsReceived.push(resultBuildCaches, resultDrawSubjects, 
-      resultDrawAuthors, resultDrawSeries, function(){unHideMe($('result_info_2'))},
-	  fetchGoogleBooksLink,fetchChiliFreshReviews);
+	G.evt.result.allRecordsReceived.push( function(){unHideMe($('result_info_2'))}, fetchGoogleBooksLink, fetchChiliFreshReviews);
 
 	attachEvt('result','lowHits',resultLowHits);
 	attachEvt('result','zeroHits',resultZeroHits);
@@ -81,6 +79,8 @@
     if(getAvail()) args.available = 1;
 
 
+	if(getFacet()) args.facets  = getFacet();
+
 	if(getAudience()) args.audience  = getAudience().split(/,/);
 	if(getLitForm()) args.lit_form	= getLitForm().split(/,/);
 	if(getLanguage()) args.language	= getLanguage().split(/,/);

Modified: trunk/Open-ILS/web/opac/skin/default/js/search_bar.js
===================================================================
--- trunk/Open-ILS/web/opac/skin/default/js/search_bar.js	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/skin/default/js/search_bar.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -31,6 +31,7 @@
 
 	/* set up the selector objects, etc */
 	G.ui.searchbar.text.value = (getTerm() != null) ? getTerm() : "";
+	if (!isFrontPage) G.ui.searchbar.facets.value = (getFacet() != null) ? getFacet() : "";
 	setSelector(_ts,	getStype());
 	setSelector(_fs,	getForm());
 
@@ -51,6 +52,7 @@
 function searchBarSubmit(isFilterSort) {
 
 	var text = G.ui.searchbar.text.value;
+	var facet_text = isFrontPage ? '' : G.ui.searchbar.facets.value;
 
 	clearSearchParams();
 
@@ -61,7 +63,7 @@
 
 	var args = {};
 
-	if(SHOW_MR_DEFAULT || (isFilterSort && findCurrentPage() == MRESULT)) {
+	if(SHOW_MR_DEFAULT || findCurrentPage() == MRESULT) {
 		args.page				= MRESULT;
 	} else {
 		args.page				= RRESULT;
@@ -70,6 +72,7 @@
 
 	args[PARAM_STYPE]		= _ts.options[_ts.selectedIndex].value;
 	args[PARAM_TERM]		= text;
+	args[PARAM_FACET]		= facet_text;
 	args[PARAM_LOCATION] = depthSelGetNewLoc();
 	args[PARAM_DEPTH]		= d;
 	args[PARAM_FORM]		= _fs.options[_fs.selectedIndex].value;

Modified: trunk/Open-ILS/web/opac/skin/default/js/sidebar.js
===================================================================
--- trunk/Open-ILS/web/opac/skin/default/js/sidebar.js	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/skin/default/js/sidebar.js	2010-07-29 21:08:36 UTC (rev 17057)
@@ -183,12 +183,14 @@
 }
 
 function sidebarTreesFree() {
+/*
 	removeChildren($(subjectSidebarTree.rootid));
 	removeChildren($(authorSidebarTree.rootid));
 	removeChildren($(seriesSidebarTree.rootid));
 	subjectSidebarTree = null;
 	authorSidebarTree = null;
 	seriesSidebarTree = null;
+*/
 }
 
 

Modified: trunk/Open-ILS/web/opac/skin/default/xml/common/js_common.xml
===================================================================
--- trunk/Open-ILS/web/opac/skin/default/xml/common/js_common.xml	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/skin/default/xml/common/js_common.xml	2010-07-29 21:08:36 UTC (rev 17057)
@@ -71,5 +71,5 @@
 		dojo.require("dojo.date.locale");
 		dojo.require("dojo.date.stamp");
 		dojo.require("dojo.parser");
-		dojo.require("openils.I18N");
+		dojo.require("openils.widget.FacetSidebar"); // pulls in Searcher and I18N
 	</script>

Modified: trunk/Open-ILS/web/opac/skin/default/xml/common/searchbar.xml
===================================================================
--- trunk/Open-ILS/web/opac/skin/default/xml/common/searchbar.xml	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/skin/default/xml/common/searchbar.xml	2010-07-29 21:08:36 UTC (rev 17057)
@@ -1,13 +1,44 @@
 
 <!-- Searchbar for doing metarecord searches -->
 
-<div id='searchbar'>
+<div id='searchbar' dojoType="openils.widget.Searcher" basicTextBox='search_box'>
+    <script type='dojo/method' event='performSearch'>
+        this.compileFullSearch();
+        dojo.byId(this.basicTextBox).value = this.basic_query;
+        dojo.byId(this.facetTextBox).value += this.facet_query;
+        dojo.byId('search_submit').click();
+    </script>
+    <script type='dojo/method' event='populate'><![CDATA[
+        var searcher = this;
+        attachEvt("result", "allRecordsReceived", function () {
+            if(!resultCompiledSearch) {
+                return;
+            }
+        
+            var all_search = dojo.query( '.classedSearch', searcher.classedSearches );
+            if (all_search.length > 1) {
+                for (var i = 1; i < all_search.length; i++) {
+                    dojo.destroy(all_search[i]);
+                }
+            }
 
+            var csearch = dijit.byNode(dojo.query( '.classedSearch', searcher.classedSearches )[0]);
+        
+            for (var type in resultCompiledSearch.searches) {
+                csearch.matchIndex.attr('value',type);
+                csearch.searchValue.attr('value',resultCompiledSearch.searches[type].term);
+                csearch = searcher.addClassAnd();
+            }
+        });
+    ]]></script>
+
+
 	<!-- load my js -->
 	<script language='javascript' type='text/javascript'>
 		config.ids.searchbar = {};
 		config.css.searchbar = {};
 		config.ids.searchbar.text				= 'search_box';	
+		config.ids.searchbar.facets				= 'facet_box';	
 		config.ids.searchbar.submit			= 'search_submit';	
 		config.ids.searchbar.type_selector	= 'search_type_selector';
 		config.ids.searchbar.depth_selector	= 'depth_selector';
@@ -28,7 +59,8 @@
 
 				<td nowrap='nowrap' align='center'  class='search_box_container color_2'>
 
-					<input id='search_box' type='text' />
+					<input id='search_box' type='text' onkeyup='dojo.byId("facet_box").value = "";'/>
+					<input id='facet_box' type='hidden' />
 					<span style='padding-left: 6px;'>
 						<input type='button' style='width: 40px;' id='search_submit' value='&button.go;' />
 					</span>

Modified: trunk/Open-ILS/web/opac/skin/default/xml/common/sidebar.xml
===================================================================
--- trunk/Open-ILS/web/opac/skin/default/xml/common/sidebar.xml	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/skin/default/xml/common/sidebar.xml	2010-07-29 21:08:36 UTC (rev 17057)
@@ -55,49 +55,26 @@
 		</div>
 	</div>
 
-	<div id='subject_tree_sidebar' class='sidebar_chunk hide_me' style='margin-top: 12px;'> 
-		<div id='subject_sidebar_tree_div'> </div>
-		<script language='javascript' type='text/javascript'>
-			removeChildren($('subject_sidebar_tree_div'));
-			var subjectSidebarTree = new SlimTree(
-				document.getElementById('subject_sidebar_tree_div'),
-				'subjectSidebarTree', '../../../../images/slimtree/related.jpg');
-			subjectSidebarTree.addNode( 'subjectSidebarTreeRoot', -1, 
-				"&sidebar.relevantSubjects.headerLabel;", 
-				'javascript:subjectSidebarTree.toggle(' +
-					'"subjectSidebarTreeRoot");');
-		</script>
-	</div>
+    <div id='facetSidebarContainer' class='hide_me'>
 
-	<div id='author_tree_sidebar' class='sidebar_chunk hide_me'> 
-		<hr/>
-		<div id='author_sidebar_tree_div'> </div>
-		<script language='javascript' type='text/javascript'>
-			removeChildren($('author_sidebar_tree_div'));
-			var authorSidebarTree = new SlimTree(
-				document.getElementById('author_sidebar_tree_div'),
-				'authorSidebarTree','../../../../images/slimtree/people.jpg');
-			authorSidebarTree.addNode( 'authorSidebarTreeRoot', -1, 
-				"&sidebar.relevantAuthors.headerLabel;", 
-				'javascript:authorSidebarTree.toggle(' +
-					'"authorSidebarTreeRoot");');
-		</script>
+   	 <div class="side_bar_item" style="margin-top: 10px; font-weight: bold;">
+      <span>&navigate.facetRefine;</span>
 	</div>
 
-	<div id='series_tree_sidebar' class='sidebar_chunk hide_me'> 
-		<hr/>
-		<div id='series_sidebar_tree_div'> </div>
-		<script language='javascript' type='text/javascript'>
-			removeChildren($('series_sidebar_tree_div'));
-			var seriesSidebarTree = new SlimTree(
-				document.getElementById('series_sidebar_tree_div'),
-				'seriesSidebarTree',
-				'../../../../images/slimtree/houses.jpg');
-			seriesSidebarTree.addNode( 'seriesSidebarTreeRoot', -1, 
-				"&sidebar.relevantSeries.headerLabel;", 
-				'javascript:seriesSidebarTree.toggle(' +
-					'"seriesSidebarTreeRoot");');
-		</script>
+     <div dojoType='openils.widget.FacetSidebar' searchBox='facet_box' searchSubmit='search_submit' facetLimit='5' classOrder='["author","subject","series","title","keyword"]'>
+            <script type='dojo/method' event='populate'><![CDATA[
+                var fblob = this;
+                attachEvt("result", "allRecordsReceived", function () {
+                    if(!resultFacetKey) return;
+                    if (fblob.facetCacheKey) return; // already rendered it
+
+                    dojo.removeClass('facetSidebarContainer','hide_me');
+
+                    fblob.facetCacheKey = resultFacetKey;
+                    fblob.render();
+                });
+            ]]></script>
+        </div>
 	</div>
 
 	<div id='adv_quick_search_sidebar' class='sidebar_chunk hide_me' 
@@ -188,21 +165,11 @@
 		config.ids.sidebar.loginbox		= 'login_link_div';
 		config.ids.sidebar.logged_in_as	= 'logged_in_as_div';
 		config.ids.sidebar.username_dest	= 'username_dest';
-		config.ids.sidebar.subject			= 'subject_sidebar';
-		config.ids.sidebar.subject_item	= 'subject_item';
-		config.ids.sidebar.author			= 'author_sidebar';
-		config.ids.sidebar.author_item	= 'author_item';
-		config.ids.sidebar.series			= 'series_sidebar';
-		config.ids.sidebar.series_item	= 'series_item';
 		
 		config.ids.sidebar.home_link		= 'home_link'
 		config.ids.sidebar.advanced_link	= 'advanced_link'
 		config.ids.sidebar.myopac_link	= 'myopac_link'
 		
-		config.names.sidebar.subject_item	= 'subject_item';
-		config.names.sidebar.author_item		= 'author_item';
-		config.names.sidebar.series_item		= 'series_item';
-
 		config.css.encircled				= 'encircled';
 	</script>
 

Modified: trunk/Open-ILS/web/opac/skin/default/xml/rdetail/rdetail_summary.xml
===================================================================
--- trunk/Open-ILS/web/opac/skin/default/xml/rdetail/rdetail_summary.xml	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/skin/default/xml/rdetail/rdetail_summary.xml	2010-07-29 21:08:36 UTC (rev 17057)
@@ -28,7 +28,7 @@
                         var out = '';
                         var list = dojo.query( 'subfield', item );
                         for (var i = 0; i < list.length; i++) {
-                            out += dojox.data.dom.textContent(list[i]) + ' ';
+                            out += BT.textContent(list[i]) + ' ';
                         }
                         return out;
                     ]]></script>
@@ -93,13 +93,13 @@
                         var output = [];
                         var list = dojo.query( 'subfield', item );
                         for (var i =0; i < list.length; i++) {
-                            total += dojox.data.dom.textContent(list[i]) + ' ';
+                            total += BT.textContent(list[i]) + ' ';
                             var current = '<a href="rresult.xml?rt=subject&tp=subject&t=' + total;
                             for (var p in other_params) {
                                 if (cgi.param(other_params[p]))
                                     current += '&' + other_params[p] + '=' + cgi.param(other_params[p]);
                             }
-                            current += '">' + dojox.data.dom.textContent(list[i]) + '</a>'
+                            current += '">' + BT.textContent(list[i]) + '</a>'
                             output.push(current);
                         }
                         return '<span>' + output.join(' &#x2d;&#x2d; ') + '</span><br/>';

Modified: trunk/Open-ILS/web/opac/theme/default/css/colors.css
===================================================================
--- trunk/Open-ILS/web/opac/theme/default/css/colors.css	2010-07-29 20:10:34 UTC (rev 17056)
+++ trunk/Open-ILS/web/opac/theme/default/css/colors.css	2010-07-29 21:08:36 UTC (rev 17057)
@@ -30,9 +30,43 @@
 .border_3_3 { border: 3px solid #E0F6E0; }
 .border_4_3 { border: 3px solid #E0F0E0; }
 
+/* some facet styling */
+.facetClassContainer { margin: 2px; border: 1px solid #64EA4F; }
+.facetClassLabelContainer { background: #A7EA9D; border: 1px solid #A7EA9D; }
+.facetClassLabel { font-weight: bold; text-align: center; }
+.facetFieldContainer { background: #E0F6E0; }
+.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 #A7EA9D; color: gray; width: 3em; margin-right: 3px }
+.facetField { border-top: 1px solid #A7EA9D; }
+.facetFields { padding-left: 5px; }
+.facetFieldLineValue { overflow: hidden; text-overflow: ellipsis; }
 
+.searcherSimpleSearchWrapper {} 
+.searcherAdvancedSearchWrapper { margin: 2px; border: 1px solid #64EA4F; } 
 
+.searcherClassedSearchesContainer { margin: 5px; } 
+.searcherClassedSearches {} 
+.searcherClassedSearchesLabel { font-weight: bold; } 
 
+.searcherClassedSearchesAddContainer { width: 50%; text-align: center; }
+
+.searcherFacetedSearchesContainer { margin: 5px; border-top: 1px solid black; } 
+.searcherFacetedSearches {} 
+.searcherFacetedSearchesLabel { font-weight: bold; } 
+
+.searcherFilterModifierContainer { margin: 5px; border-top: 1px solid black; } 
+
+.searcherFiltersLabel { font-weight: bold; } 
+.searcherFilterContainer {} 
+
+.searcherModifiersLabel { font-weight: bold; } 
+.searcherModifierContainer {} 
+
+.searcherGoContainer { width: 50%; text-align: right; }
+.searcherDeckSwapContainer {}
+
 /* general purpose light borders */
 .border_5 { border: 1px solid #D0D0D0; }
 .border_6 { border: 1px solid #808080; }



More information about the open-ils-commits mailing list