my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
my $query = {
- "select" => {"acqlia" => ["lineitem"]},
+ "select" => {"acqlia" =>
+ [{"column" => "lineitem", "transform" => "distinct"}]
+ },
"from" => {
"acqlia" => {
"acqliad" => {"field" => "id", "fkey" => "definition"},
label.oils-acq-li-search { margin: 0 12px; }
span.oils-acq-li-search { margin: 0 12px; }
span#records-up { font-weight: bold; }
+label[for="attr_search_type_scalar"] { vertical-align: top; }
+.oils-acq-li-search-scalar { margin: 8px 0; }
#acq-lit-table {width:100%}
#acq-lit-table th {padding:5px; font-weight: bold; text-align:left;}
"iface": Components.interfaces.nsIScriptableInputStream,
"cls": "@mozilla.org/scriptableinputstream;1"
},
+ "FOS": {
+ "iface": Components.interfaces.nsIFileOutputStream,
+ "cls": "@mozilla.org/network/file-output-stream;1"
+ },
"create": function(key) {
return Components.classes[this[key].cls].
createInstance(this[key].iface);
}
};
- openils.XUL.contentFromFileOpenDialog = function(windowTitle) {
- try {
- var api = new openils.XUL.SimpleXPCOM();
+ openils.XUL.contentFromFileOpenDialog = function(windowTitle, sizeLimit) {
+ var api = new openils.XUL.SimpleXPCOM();
- /* The following enablePrivilege() call must happen at this exact
- * level of scope -- not wrapped in another function -- otherwise
- * it doesn't work. */
- api.getPrivilegeManager().enablePrivilege("UniversalXPConnect");
+ /* The following enablePrivilege() call must happen at this exact
+ * level of scope -- not wrapped in another function -- otherwise
+ * it doesn't work. */
+ api.getPrivilegeManager().enablePrivilege("UniversalXPConnect");
- var picker = api.create("FP");
- picker.init(
- window, windowTitle || "Upload File", api.FP.iface.modeOpen
- );
- if (picker.show() == api.FP.iface.returnOK && picker.file) {
- var fis = api.create("FIS");
- var sis = api.create("SIS");
+ var picker = api.create("FP");
+ picker.init(
+ window, windowTitle || "Upload File", api.FP.iface.modeOpen
+ );
+ if (picker.show() == api.FP.iface.returnOK && picker.file) {
+ var fis = api.create("FIS");
+ var sis = api.create("SIS");
- fis.init(picker.file, 1 /* MODE_RDONLY */, 0, 0);
- sis.init(fis);
+ fis.init(picker.file, 1 /* MODE_RDONLY */, 0, 0);
+ sis.init(fis);
- return sis.read(-1);
- } else {
- return null;
- }
- } catch(E) {
- alert(E);
+ return sis.read(sizeLimit || -1);
+ } else {
return null;
}
};
+
+ openils.XUL.contentToFileSaveDialog = function(content, windowTitle) {
+ var api = new openils.XUL.SimpleXPCOM();
+ api.getPrivilegeManager().enablePrivilege("UniversalXPConnect");
+
+ var picker = api.create("FP");
+ picker.init(
+ window, windowTitle || "Save File", api.FP.iface.modeSave
+ );
+ var result = picker.show();
+ if (picker.file &&
+ (result == api.FP.iface.returnOK ||
+ result == api.FP.iface.returnReplace)) {
+ if (!picker.file.exists())
+ picker.file.create(0, 0644); /* XXX hardcoded = bad */
+ var fos = api.create("FOS");
+ fos.init(picker.file, 42 /* WRONLY | CREAT | TRUNCATE */, 0644, 0);
+ return fos.write(content, content.length);
+ } else {
+ return 0;
+ }
+ };
}
'LI_ATTR_SEARCH_CHOOSE_FILE': "Select file with search terms",
'LI_ATTR_SEARCH_TOO_LARGE': "That file is too large for this operation.",
'SELECT_AN_LI_ATTRIBUTE': "You must select an LI attribute.",
- 'NO_RESULTS': "No results."
+ 'NO_RESULTS': "No results.",
+ 'ISBN_SAVE_DIALOG_TITLE': "Save ISBNs to a file",
+ 'ISBN_SHORT_LIST': "Not all of the selected items had ISBNs.\nChoose OK to save the ISBNs that could be found.",
+ 'ISBN_EMPTY_LIST': "No ISBNs found."
}
this.createAssets();
break;
+ case 'export_isbn_list':
+ this.exportISBNList();
+ break;
+
case 'add_brief_record':
if(this.isPO)
location.href = oilsBasePath + '/acq/picklist/brief_record?po=' + this.isPO;
);
}
+ /* Should really think about generalizing this to do more than ISBN #s */
+ this.exportISBNList = function() {
+ var selected = this.getSelected();
+ var isbn_list = selected.map(
+ function(li) {
+ return (new openils.acq.Lineitem({"lineitem": li})).findAttr(
+ "isbn", "lineitem_marc_attr_definition"
+ );
+ }
+ ).filter(function(attr) { return Boolean(attr); });
+
+ if (isbn_list.length > 0) {
+ if (isbn_list.length < selected.length) {
+ if (!confirm(localeStrings.ISBN_SHORT_LIST)) {
+ return;
+ }
+ }
+ try {
+ openils.XUL.contentToFileSaveDialog(
+ isbn_list.join("\n"),
+ localeStrings.ISBN_SAVE_DIALOG_TITLE
+ );
+ } catch (E) {
+ alert(E);
+ }
+ } else {
+ alert(localeStrings.ISBN_EMPTY_LIST);
+ }
+ };
+
this.printPO = function() {
if(!this.isPO) return;
progressDialog.show(true);
var _searchable_by_array = ["issn", "isbn", "upc"];
var combinedAttrValueArray = [];
+var scalarAttrSearchManager;
var liTable;
function prepareStateStore(pcrud) {
}
function prepareScalarSearchStore(pcrud) {
- attrScalarDefSelector.store = new dojo.data.ItemFileReadStore({
- "data": acqliad.toStoreData(
- pcrud.search("acqliad", {"id": {"!=": null}})
- )
- });
}
function prepareArraySearchStore(pcrud) {
}).build();
}
-function load() {
- var pcrud = new openils.PermaCrud();
-
- prepareStateStore(pcrud);
- prepareScalarSearchStore(pcrud);
- prepareArraySearchStore(pcrud);
-
- prepareAgencySelector();
-
- liTable = new AcqLiTable();
- openils.Util.show("oils-acq-li-search-form-holder");
-}
-
function toggleAttrSearchType(which, checked) {
/* This would be cooler with a slick dispatch table instead of branchy
* logic, but whatever... */
if (checked) {
if (which == "scalar") {
- openils.Util.show("oils-acq-li-search-attr-scalar", "inline");
+ if (scalarAttrSearchManager.index < 1)
+ scalarAttrSearchManager.add();
+ openils.Util.show("oils-acq-li-search-attr-scalar", "inline-block");
openils.Util.hide("oils-acq-li-search-attr-array");
} else if (which == "array") {
openils.Util.hide("oils-acq-li-search-attr-scalar");
};
},
"scalar": function(v) {
- if (!v.scalar_def) {
+ var r = scalarAttrSearchManager.buildSearchClause();
+ if (r.attr_value_pairs.length < 1) {
throw new Error(localeStrings.SELECT_AN_LI_ATTRIBUTE);
+ } else {
+ return r;
}
- return {
- "attr_value_pairs":
- [[Number(v.scalar_def), v.scalar_value]] /* [[sic]] */
- };
},
"none": function(v) {
- //return {"attr_value_pairs": [[1, ""]]};
return {};
}
};
}
function loadTermsFromFile() {
- var rawdata = openils.XUL.contentFromFileOpenDialog(
- localeStrings.LI_ATTR_SEARCH_CHOOSE_FILE
- );
- if (!rawdata) {
- return;
- } else if (rawdata.length > 1024 * 128) {
+ var rawdata;
+
+ try {
/* FIXME 128k is completely arbitrary; needs researched for
- * a sane limit and should also be made configurable. Further, if
- * there's going to be a size limit, it'd be much better to apply
- * it before reading in the file at all, not now. */
- alert(localeStrings.LI_ATTR_SEARCH_TOO_LARGE);
- } else {
+ * a sane limit and should also be made configurable. */
+ rawdata = openils.XUL.contentFromFileOpenDialog(
+ localeStrings.LI_ATTR_SEARCH_CHOOSE_FILE, 1024 * 128
+ );
+ } catch (E) {
+ alert(E);
+ }
+
+ if (rawdata) {
try {
combinedAttrValueArray =
combinedAttrValueArray.concat(naivelyParse(rawdata));
}
}
+function myScalarAttrSearchManager(template_id, pcrud) {
+ this.template = dojo.byId(template_id);
+ this.store = new dojo.data.ItemFileReadStore({
+ "data": acqliad.toStoreData(
+ pcrud.search("acqliad", {"id": {"!=": null}})
+ )
+ });
+ this.rows = {};
+ this.index = 0;
+};
+myScalarAttrSearchManager.prototype.remove = function(n) {
+ dojo.destroy("scalar_attr_holder_" + n);
+ delete this.rows[n];
+};
+myScalarAttrSearchManager.prototype.add = function() {
+ var self = this;
+ var n = this.index;
+ var clone = dojo.clone(this.template);
+ var def = dojo.query('input[name="def"]', clone)[0];
+ var value = dojo.query('input[name="value"]', clone)[0];
+ var a = dojo.query('a', clone)[0];
+
+ clone.id = "scalar_attr_holder_" + n;
+ a.onclick = function() { self.remove(n); };
+
+ this.rows[n] = [
+ new dijit.form.FilteringSelect({
+ "id": "scalar_def_" + n,
+ "name": "scalar_def_" + n,
+ "store": this.store,
+ "labelAttr": "description",
+ "searchAttr": "description"
+ }, def),
+ new dijit.form.TextBox({
+ "id": "scalar_value_" + n,
+ "name": "scalar_value_" + n
+ }, value)
+ ];
+
+ this.index++;
+
+ dojo.place(clone, "oils-acq-li-search-scalar-adder", "before");
+ openils.Util.show(clone);
+};
+myScalarAttrSearchManager.prototype.buildSearchClause = function() {
+ var list = [];
+ for (var k in this.rows) {
+ var def = this.rows[k][0].attr("value");
+ var val = this.rows[k][1].attr("value");
+ if (def != "" && val != "")
+ list.push([Number(def), val]);
+ }
+ return {"attr_value_pairs": list};
+};
+myScalarAttrSearchManager.prototype.simplifiedPairs = function() {
+ var result = {};
+ for (var k in this.rows) {
+ result[this.rows[k][0].attr("value")] = this.rows[k][1].attr("value");
+ }
+ return result;
+};
+myScalarAttrSearchManager.prototype.newBrief = function() {
+ location.href = oilsBasePath + "/acq/picklist/brief_record?prepop=" +
+ encodeURIComponent(js2JSON(this.simplifiedPairs()));
+};
+
+
+function load() {
+ var pcrud = new openils.PermaCrud();
+
+ prepareStateStore(pcrud);
+ prepareArraySearchStore(pcrud);
+
+ prepareAgencySelector();
+
+ liTable = new AcqLiTable();
+ scalarAttrSearchManager = new myScalarAttrSearchManager(
+ "oils-acq-li-search-scalar-template", pcrud
+ );
+
+ openils.Util.show("oils-acq-li-search-form-holder");
+}
+
openils.Util.addOnLoad(load);
var cgi = new openils.CGI();
paramPL = cgi.param('pl');
paramPO = cgi.param('po');
+ prepop = JSON2js(cgi.param('prepop'));
if(paramPL) {
}
+ /*
marcEditButton.onClick = function(fields) {
saveBriefRecord(fields, true);
}
+ */
fieldmapper.standardRequest(
['open-ils.acq', 'open-ils.acq.lineitem_attr_definition.retrieve.all'],
attrDefs[def.code()] = xpathParser.parse(def.xpath());
var row = rowTmpl.cloneNode(true);
dojo.query('[name=name]', row)[0].innerHTML = def.description();
- new dijit.form.TextBox({name : def.code()}, dojo.query('[name=widget]', row)[0]);
+ var textbox = new dijit.form.TextBox(
+ {"name": def.code()},
+ dojo.query('[name=widget]', row)[0]
+ );
+ if (prepop && prepop[def.id()])
+ textbox.attr("value", prepop[def.id()]);
tbody.appendChild(row);
}
);
<option mask='pl' value='order_ready'>Mark Ready for Order</option>
<option mask='*' value='delete_selected'>Delete Selected Items</option>
<option mask='*' value='add_brief_record'>Add Brief Record</option>
+ <option mask='*' value='export_isbn_list'>Export ISBN List</option>
<option mask='po' value='' disabled='disabled'>----PO----</option>
<option mask='sr|pl' value='create_order'>Create Purchase Order</option>
<option mask='po' value='create_assets'>Load Bibs and Items</option>
</label>
</div>
<div class="oils-acq-li-search-form-row">
+ <!-- the "style" attribute on this input seems to be necessary as
+ I can't get the same effect from CSS for some reason -->
<input class="oils-acq-li-search" dojoType="dijit.form.RadioButton"
name="attr_search_type" jsId="attrSearchTypeScalar"
id="attr_search_type_scalar" value="scalar"
+ style="vertical-align: top;"
onChange="toggleAttrSearchType(this.value, this.checked);" />
<label for="attr_search_type_scalar" class="oils-acq-li-search">
- Search by one attribute value
+ Search by attribute values
</label>
<div id="oils-acq-li-search-attr-scalar" class="hidden">
- <input class="oils-acq-li-search"
- name="scalar_def" dojoType="dijit.form.FilteringSelect"
- jsId="attrScalarDefSelector"
- labelAttr="description" searchAttr="description" />
- <input class="oils-acq-li-search" name="scalar_value"
- dojoType="dijit.form.TextBox"/>
+<!-- <div class="oils-acq-li-search-conjunction">
+ <em>Show results for which:</em><br />
+ <input dojoType="dijit.form.RadioButton"
+ id="scalar_search_conjuction_or"
+ name="scalar_search_conjunction" value="or"
+ checked="checked" class="oils-acq-li-search" />
+ <label for="scalar_search_conjuction_or"
+ class="oils-acq-li-search">ANY of the following terms match</label>
+ <br />
+ <input dojoType="dijit.form.RadioButton"
+ id="scalar_search_conjuction_and"
+ name="scalar_search_conjunction" value="and"
+ class="oils-acq-li-search" />
+ <label for="scalar_search_conjuction_and"
+ class="oils-acq-li-search">ALL of the following terms match</label>
+ </div> -->
+ <div class="oils-acq-li-search-scalar hidden"
+ id="oils-acq-li-search-scalar-template">
+ <input class="oils-acq-li-search" name="def" />
+ <input class="oils-acq-li-search" name="value" />
+ <a class="oils-acq-li-search" title="Remove this row"
+ href="javascript:void(0);" />(X)</a>
+ </div>
+ <div id="oils-acq-li-search-scalar-adder">
+ <span dojoType="dijit.form.Button"
+ class="oils-acq-li-search"
+ onclick="scalarAttrSearchManager.add();">
+ Add more search terms
+ </span>
+ <span dojoType="dijit.form.Button"
+ class="oils-acq-li-search"
+ onclick="scalarAttrSearchManager.newBrief();">
+ New brief record like this
+ </span>
+ </div>
</div>
</div>
<div class="oils-acq-li-search-form-row">