From: senator Date: Tue, 13 Apr 2010 20:17:55 +0000 (+0000) Subject: Acq: add search-by-file-of-terms to unified search X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=f714b9a6afe913f9d4d42cd69b604d0fe57c1a09;p=evergreen%2Fbjwebb.git Acq: add search-by-file-of-terms to unified search This feature was present in the now deprecated lineitem search interface. It works, but it is severely limited at the moment in the number of search terms you can use, because search queries are made into URIs before the search actually happens (in order to make backing up to old search results possible), and at a certain point, very large URIs become infeasible. Some adjustments to how search history is made naviagable may be in order. git-svn-id: svn://svn.open-ils.org/ILS/trunk@16230 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- diff --git a/Open-ILS/web/css/skin/default/acq.css b/Open-ILS/web/css/skin/default/acq.css index 6cbc1fa3d..96eaeaad2 100644 --- a/Open-ILS/web/css/skin/default/acq.css +++ b/Open-ILS/web/css/skin/default/acq.css @@ -202,6 +202,12 @@ span[name="notes_alert_flag"] {color: #c00;font-weight: bold;font-size: 110%;mar #acq-invoice-new-msg { font-weight: bold; margin: 10px;} #acq-invoice-li-details { padding: 10px; font-weight: bold; border: 1px solid #888; margin: 10px; } #acq-invoice-create { margin: 10px; } +.acq-inoice-item-extra-info { padding-left: 10px; } +.acq-inoice-item-info { font-weight: bold; } +.acq-invoice-row td { border-bottom: 1px solid #e0e0e0; } +.acq-invoice-invalid-amount input { color: red; font-weight: bold; } +.acq-link-invoice-dialog td,.acq-link-invoice-dialog th {padding-top: 10px;} + #acq-unified-heading { margin-bottom: 10px; } #acq-unified-heading-actual { float: left; width: 50%; font-size: 120%; font-weight: bold; } #acq-unified-heading-controls { float: right; width: 50%; text-align: right; } @@ -218,8 +224,3 @@ option[disabled="disabled"] { font-style: italic; } .acq-unified-terms-match { width: 15%; } .acq-unified-terms-remove { width: 5%; text-align: right; } .acq-unified-remover { color: #c00; } -.acq-inoice-item-extra-info { padding-left: 10px; } -.acq-inoice-item-info { font-weight: bold; } -.acq-invoice-row td { border-bottom: 1px solid #e0e0e0; } -.acq-invoice-invalid-amount input { color: red; font-weight: bold; } -.acq-link-invoice-dialog td,.acq-link-invoice-dialog th {padding-top: 10px;} diff --git a/Open-ILS/web/js/dojo/openils/widget/XULTermLoader.js b/Open-ILS/web/js/dojo/openils/widget/XULTermLoader.js new file mode 100644 index 000000000..fb4770d4e --- /dev/null +++ b/Open-ILS/web/js/dojo/openils/widget/XULTermLoader.js @@ -0,0 +1,96 @@ +if (!dojo._hasResource["openils.widget.XULTermLoader"]) { + dojo._hasResource["openils.widget.XULTermLoader"] = true; + + dojo.provide("openils.widget.XULTermLoader"); + dojo.require("openils.XUL"); + dojo.requireLocalization("openils.widget", "XULTermLoader"); + + dojo.declare( + "openils.widget.XULTermLoader", [dijit.layout.ContentPane], { + "constructor": function(args) { + this.args = args; + this.terms = []; + this._ = openils.widget.XULTermLoader.localeStrings; + + /* XXX Totally arbitrary defaults. Keeping them low for now + * since all search terms have to be turned into a URL. + * There will need to be a better long term solution. + */ + if (!this.args.fileSizeLimit) + this.args.fileSizeLimit = 2048; + if (!this.args.termLimit) + this.args.termLimit = 100; + }, + "build": function(callback) { + var self = this; + + this.domNode = dojo.create("span"); + this.labelNode = dojo.create( + "span", { + "innerHTML": this._.LABEL_TEXT, + "style": "padding-right: 8px;" + }, this.domNode, "last" + ); + this.countNode = dojo.create( + "span", {"innerHTML": this.terms.length}, + this.labelNode, "first" + ); + this.buttonNode = dojo.create( + "button", { + "innerHTML": this._.BUTTON_TEXT, + "onclick": function() { self.loadTerms(); } + }, + this.domNode, "last" + ); + + if (this.args.parentNode) + dojo.place(this.domNode, this.args.parentNode, "last"); + + callback(this); + }, + "updateCount": function() { + var value = this.attr("value"); + if (dojo.isArray(value)) + this.terms = this.attr("value"); + this.countNode.innerHTML = this.terms.length; + }, + "focus": function() { + this.buttonNode.focus(); + }, + "loadTerms": function() { + try { + if (this.terms.length >= this.args.termLimit) { + alert(this._.TERM_LIMIT); + return; + } + var data = this.parseUnimaginatively( + openils.XUL.contentFromFileOpenDialog( + this._.CHOOSE_FILE, this.args.fileSizeLimit + ) + ); + if (data.length + this.terms.length >= + this.args.termLimit) { + alert(this._.TERM_LIMIT_SOME); + var can = this.args.termLimit - this.terms.length; + if (can > 0) + this.terms = this.terms.concat(data.slice(0, can)); + } else { + this.terms = this.terms.concat(data); + } + this.attr("value", this.terms); + this.updateCount(); + } catch(E) { + alert(E); + } + }, + "parseUnimaginatively": function(data) { + return data.split(/[\n, ]/).filter( + function(o) { return o.length > 0; } + ); + } + } + ); + + openils.widget.XULTermLoader.localeStrings = + dojo.i18n.getLocalization("openils.widget", "XULTermLoader"); +} diff --git a/Open-ILS/web/js/dojo/openils/widget/nls/XULTermLoader.js b/Open-ILS/web/js/dojo/openils/widget/nls/XULTermLoader.js new file mode 100644 index 000000000..71881a382 --- /dev/null +++ b/Open-ILS/web/js/dojo/openils/widget/nls/XULTermLoader.js @@ -0,0 +1,7 @@ +{ + 'LABEL_TEXT': " term(s) loaded", + 'BUTTON_TEXT': "Load more terms", + 'TERM_LIMIT': "You have already loaded the maximum number of terms.", + 'TERM_LIMIT_SOME': "Could not load all terms from the file without exceeding maximum number of terms. Some data not included.", + 'CHOOSE_FILE': "Choose a file from which to read search terms." +} diff --git a/Open-ILS/web/js/ui/default/acq/search/unified.js b/Open-ILS/web/js/ui/default/acq/search/unified.js index 141323812..67114c1c7 100644 --- a/Open-ILS/web/js/ui/default/acq/search/unified.js +++ b/Open-ILS/web/js/ui/default/acq/search/unified.js @@ -2,6 +2,7 @@ dojo.require("dojo.date.stamp"); dojo.require("dojox.encoding.base64"); dojo.require("openils.widget.AutoGrid"); dojo.require("openils.widget.AutoWidget"); +dojo.require("openils.widget.XULTermLoader"); dojo.require("openils.PermaCrud"); var termSelectorFactory; @@ -19,7 +20,7 @@ HTMLSelectElement.prototype.getValue = function() { /* only sets the selected value if such an option is actually available */ HTMLSelectElement.prototype.setValue = function(s) { for (var i = 0; i < this.options.length; i++) { - if (s == this.options[i].value && !this.options[i].disabled) { + if (s == this.options[i].value) { this.selectedIndex = i; break; } @@ -88,26 +89,47 @@ function TermSelectorFactory(terms) { "datatype": self.terms[parts[0]][parts[1]].datatype }; }, - "makeWidget": function(parentNode, wStore, callback) { + "makeWidget": function(parentNode, wStore, matchHow, value, callback) { var term = this.getTerm(); var widgetKey = this.uniq; - if (term.hint == "acqlia") { + if (matchHow.getValue() == "__in") { + new openils.widget.XULTermLoader({ + "parentNode": parentNode + }).build( + function(w) { + wStore[widgetKey] = w; + if (typeof(callback) == "function") + callback(term, widgetKey); + if (typeof(value) != "undefined") + w.attr("value", value); + /* I would love for the following call not to be + * necessary, so that updating the value of the dijit + * would lead to this automatically, but I can't yet + * figure out the correct way to do this in Dojo. + */ + w.updateCount(); + } + ); + } else if (term.hint == "acqlia") { wStore[widgetKey] = dojo.create( "input", {"type": "text"}, parentNode, "only" ); + if (typeof(value) != "undefined") + wStore[widgetKey].attr("value", value); wStore[widgetKey].focus(); if (typeof(callback) == "function") callback(term, widgetKey); } else { - var widget = new openils.widget.AutoFieldWidget({ + new openils.widget.AutoFieldWidget({ "fmClass": term.hint, "fmField": term.field, "noDisablePkey": true, "parentNode": dojo.create("span", null, parentNode, "only") - }); - widget.build( + }).build( function(w) { wStore[widgetKey] = w; + if (typeof(value) != "undefined") + w.attr("value", value); w.focus(); if (typeof(callback) == "function") callback(term, widgetKey); @@ -199,6 +221,40 @@ function TermManager() { this._selector = function(id) { return dojo.byId("term-" + id); }; this._match_how = function(id) { return dojo.byId("term-match-" + id); }; + this._updateMatchHowForField = function(term, key) { + /* NOTE important to use self, not this, in this function. + * + * Based on the selected field (its datatype and the kind of widget + * that AutoFieldWidget provides for it) we update the possible + * choices in the mach_how selector. + */ + var w = self.widgets[key]; + var can_do_fuzzy, can_do_in; + if (term.datatype == "id") { + can_do_fuzzy = false; + can_do_in = true; + } else if (term.datatype == "link") { + can_do_fuzzy = (self.getLinkTarget(term) == "au"); + can_do_in = false; /* XXX might revise later */ + } else if (typeof(w.declaredClass) != "undefined") { + can_do_fuzzy = can_do_in = + Boolean(w.declaredClass.match(/form\.Text/)); + } else { + var type = dojo.attr(w, "type"); + if (type) + can_do_fuzzy = can_do_in = (type == "text"); + else + can_do_fuzzy = can_do_in = false; + } + + self.matchHowAllow(key, "__fuzzy", can_do_fuzzy); + self.matchHowAllow(key, "__in", can_do_in); + + var inequalities = (term.datatype == "timestamp"); + self.matchHowAllow(key, "__gte", inequalities); + self.matchHowAllow(key, "__lte", inequalities); + }; + this.removerButton = function(n) { return dojo.create("button", { "innerHTML": "X", @@ -225,36 +281,8 @@ function TermManager() { dojo.empty(where); this._selector(id).makeWidget( - where, this.widgets, - function(term, key) { - var w = self.widgets[key]; - var can_do_fuzzy; - if (term.datatype == "id") { - can_do_fuzzy = false; - } else if (term.datatype == "link") { - can_do_fuzzy = (self.getLinkTarget(term) == "au"); - } else if (typeof(w.declaredClass) != "undefined") { - can_do_fuzzy = Boolean(w.declaredClass.match(/form\.Text/)); - } else { - var type = dojo.attr(w, "type"); - if (type) - can_do_fuzzy = (type == "text"); - else - can_do_fuzzy = false; - } - self.matchHowAllow(id, "__fuzzy", can_do_fuzzy); - - var inequalities = (term.datatype == "timestamp"); - self.matchHowAllow(id, "__gte", inequalities); - self.matchHowAllow(id, "__lte", inequalities); - - if (value) { - if (typeof(w.attr) == "function") - w.attr("value", value); - else - w.value = value; - } - } + where, this.widgets, this._match_how(id), value, + this._updateMatchHowForField ); }; @@ -308,6 +336,13 @@ function TermManager() { dojo.attr( match_how, "onchange", function() { + if (this.getValue() == "__in") { + self.updateRowWidget(uniq); + this.was_in = true; + } else if (this.was_in) { + self.updateRowWidget(uniq); + this.was_in = false; + } if (self.widgets[uniq]) self.widgets[uniq].focus(); } ); @@ -320,11 +355,13 @@ function TermManager() { if (term && hint) { var field = hint + ":" + this._term_reverse_selector_field(term); selector.setValue(field); - this.updateRowWidget(uniq, this._term_reverse_selector_value(term)); var match_how_value = this._term_reverse_match_how(term); if (match_how_value) match_how.setValue(match_how_value); + + this.updateRowWidget(uniq, this._term_reverse_selector_value(term)); + } } diff --git a/Open-ILS/web/templates/default/acq/search/unified.tt2 b/Open-ILS/web/templates/default/acq/search/unified.tt2 index dcc14fc7c..f5722e28f 100644 --- a/Open-ILS/web/templates/default/acq/search/unified.tt2 +++ b/Open-ILS/web/templates/default/acq/search/unified.tt2 @@ -106,16 +106,22 @@