From 5dcc20c16017b682f80a30f8042d8dbff2e50ed9 Mon Sep 17 00:00:00 2001 From: gmc Date: Fri, 6 Aug 2010 00:54:52 +0000 Subject: [PATCH] Patch from Bill Erickson backporting various autogrid fixes * includes autogrid caching and paging * purpose is to more gracefully handle large circ and hold policy matrixes in the 1.6.0.x branch Signed-off-by: Galen Charlton git-svn-id: svn://svn.open-ils.org/ILS/branches/rel_1_6_0@17109 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/web/js/dojo/openils/Event.js | 3 + .../web/js/dojo/openils/widget/AutoFieldWidget.js | 261 +++++++++++++++++---- Open-ILS/web/js/dojo/openils/widget/AutoGrid.js | 167 +++++++++++-- Open-ILS/web/js/dojo/openils/widget/AutoWidget.js | 2 +- Open-ILS/web/js/dojo/openils/widget/EditDialog.js | 4 +- Open-ILS/web/js/dojo/openils/widget/EditPane.js | 107 +++++++-- .../js/dojo/openils/widget/nls/AutoFieldWidget.js | 5 +- .../js/ui/default/conify/global/action/survey.js | 4 +- .../ui/default/conify/global/action/survey/edit.js | 4 +- .../conify/global/config/circ_matrix_matchpoint.js | 13 +- 10 files changed, 466 insertions(+), 104 deletions(-) diff --git a/Open-ILS/web/js/dojo/openils/Event.js b/Open-ILS/web/js/dojo/openils/Event.js index a37f6ff066..b2bf745682 100644 --- a/Open-ILS/web/js/dojo/openils/Event.js +++ b/Open-ILS/web/js/dojo/openils/Event.js @@ -29,12 +29,15 @@ if(!dojo._hasResource["openils.Event"]) { this.servertime = kwargs.servertime; this.ilsperm = kwargs.ilsperm; this.ilspermloc = kwargs.ilspermloc; + this.note = kwargs.note; }, toString : function() { var s = 'Event: ' + (this.code || '') + ':' + this.textcode + ' -> ' + new String(this.desc); if(this.ilsperm) s += ' ' + this.ilsperm + '@' + this.ilspermloc; + if(this.note) + s += '\n' + this.note; return s; } }); diff --git a/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js b/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js index 3d8ee68f9d..5c0ee8765c 100644 --- a/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js +++ b/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js @@ -9,8 +9,6 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { dojo.declare('openils.widget.AutoFieldWidget', null, { async : false, - cache : {}, - cacheSingle : {}, /** * args: @@ -24,6 +22,28 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { * orgLimitPerms -- If this field defines a set of org units and an orgLimitPerms * is defined, the code will limit the org units in the set to those * allowed by the permission + * orgDefaultsToWs -- If this is an org unit field and the widget has no value, + * set the value equal to the users's workstation org unit. Othwerwise, leave it null + * selfReference -- The primary purpose of an AutoFieldWidget is to render the value + * or widget for a field on an object (that may or may not link to another object). + * selfReference allows you to sidestep the indirection and create a selector widget + * based purely on an fmClass. To get a dropdown of all of the 'abc' + * objects, pass in {selfReference : true, fmClass : 'abc'}. + * labelFormat -- For widgets that are displayed as remote object filtering selects, + * this provides a mechanism for overriding the label format in the filtering select. + * It must be an array, whose first value is a format string, compliant with + * dojo.string.substitute. The remaining array items are the arguments to the format + * represented as field names on the remote linked object. + * E.g. + * labelFormat : [ '${0} (${1})', 'obj_field_1', 'obj_field_2' ] + * Note: this does not control the final display value. Only values in the drop-down. + * See searchFormat for controlling the display value + * searchFormat -- This format controls the structure of the search attribute which + * controls the text used during type-ahead searching and the displayed value in + * the filtering select. See labelFormat for the structure. + * dataLoader : Bypass the default PermaCrud linked data fetcher and use this function instead. + * Function arguments are (link class name, search filter, callback) + * The fetched objects should be passed to the callback as an array */ constructor : function(args) { for(var k in args) @@ -33,23 +53,41 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { if(this.fmObject) this.fmClass = this.fmObject.classname; this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass]; + this.suppressLinkedFields = args.suppressLinkedFields || []; + + if(this.selfReference) { + this.fmField = fieldmapper.IDL.fmclasses[this.fmClass].pkey; + + // create a mock-up of the idlField object. + this.idlField = { + datatype : 'link', + 'class' : this.fmClass, + reltype : 'has_a', + key : this.fmField, + name : this.fmField + }; - if(!this.idlField) { - this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass]; - var fields = this.fmIDL.fields; - for(var f in fields) - if(fields[f].name == this.fmField) - this.idlField = fields[f]; + } else { + + if(!this.idlField) { + this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass]; + var fields = this.fmIDL.fields; + for(var f in fields) + if(fields[f].name == this.fmField) + this.idlField = fields[f]; + } } if(!this.idlField) - throw new Error("AutoFieldWidget could not determine which field to render. We need more information. fmClass=" + + throw new Error("AutoFieldWidget could not determine which " + + "field to render. We need more information. fmClass=" + this.fmClass + ' fmField=' + this.fmField + ' fmObject=' + js2JSON(this.fmObject)); this.auth = openils.User.authtoken; - if(!this.cache[this.auth]) { - this.cache[this.auth] = {}; - } + this.cache = openils.widget.AutoFieldWidget.cache; + this.cache[this.auth] = this.cache[this.auth] || {}; + this.cache[this.auth].single = this.cache[this.auth].single || {}; + this.cache[this.auth].list = this.cache[this.auth].list || {}; }, /** @@ -59,14 +97,21 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { var value = this.baseWidgetValue(); switch(this.idlField.datatype) { case 'bool': - return (value) ? 't' : 'f' + switch(value) { + case 'true': return 't'; + case 'on': return 't'; + case 'false' : return 'f'; + case 'unset' : return null; + case true : return 't'; + default: return 'f'; + } case 'timestamp': if(!value) return null; return dojo.date.stamp.toISOString(value); case 'int': case 'float': case 'money': - if(isNaN(value)) value = 0; + if(isNaN(value)) value = null; default: return (value === '') ? null : value; } @@ -85,9 +130,18 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { var value = this.widgetValue; switch(this.idlField.datatype) { case 'bool': - return (openils.Util.isTrue(value)) ? - openils.widget.AutoFieldWidget.localeStrings.TRUE : - openils.widget.AutoFieldWidget.localeStrings.FALSE; + switch(value) { + case 't': + case 'true': + return openils.widget.AutoFieldWidget.localeStrings.TRUE; + case 'f' : + case 'false' : + return openils.widget.AutoFieldWidget.localeStrings.FALSE; + case null : + case 'unset' : return openils.widget.AutoFieldWidget.localeStrings.UNSET; + case true : return openils.widget.AutoFieldWidget.localeStrings.TRUE; + default: return openils.widget.AutoFieldWidget.localeStrings.FALSE; + } case 'timestamp': if (!value) return ''; dojo.require('dojo.date.locale'); @@ -109,10 +163,15 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { build : function(onload) { + if(this.widgetValue == null) + this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null; + if(this.widget) { // core widget provided for us, attach and move on if(this.parentNode) // may already be in the "right" place this.parentNode.appendChild(this.widget.domNode); + if(this.widget.attr('value') == null) + this._widgetLoaded(); return; } @@ -120,8 +179,6 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { this.parentNode = dojo.create('div'); this.onload = onload; - if(this.widgetValue == null) - this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null; if(this.readOnly) { dojo.require('dijit.layout.ContentPane'); @@ -171,9 +228,30 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { break; case 'bool': - dojo.require('dijit.form.CheckBox'); - this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode); - this.widgetValue = openils.Util.isTrue(this.widgetValue); + if(this.ternary) { + dojo.require('dijit.form.FilteringSelect'); + var store = new dojo.data.ItemFileReadStore({ + data:{ + identifier : 'value', + items:[ + {label : openils.widget.AutoFieldWidget.localeStrings.UNSET, value : 'unset'}, + {label : openils.widget.AutoFieldWidget.localeStrings.TRUE, value : 'true'}, + {label : openils.widget.AutoFieldWidget.localeStrings.FALSE, value : 'false'} + ] + } + }); + this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode); + this.widget.searchAttr = this.widget.labelAttr = 'label'; + this.widget.valueAttr = 'value'; + this.widget.store = store; + this.widget.startup(); + this.widgetValue = (this.widgetValue === null) ? 'unset' : + (openils.Util.isTrue(this.widgetValue)) ? 'true' : 'false'; + } else { + dojo.require('dijit.form.CheckBox'); + this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode); + this.widgetValue = openils.Util.isTrue(this.widgetValue); + } break; case 'link': @@ -202,36 +280,45 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { if(this.idlField.datatype == 'org_unit') return false; // we already handle org_units, no need to re-fetch + // user opted to bypass fetching this linked data + if(this.suppressLinkedFields.indexOf(this.idlField.name) > -1) + return false; + var linkInfo = this._getLinkSelector(); if(!(linkInfo && linkInfo.vfield && linkInfo.vfield.selector)) return false; var lclass = linkInfo.linkClass; - if(lclass == 'aou') { - this.widgetValue = fieldmapper.aou.findOrgUnit(this.widgetValue).shortname(); - return; - } + if(lclass == 'aou') + return false; // first try the store cache var self = this; - if(this.cache[this.auth][lclass]) { - var store = this.cache[this.auth][lclass]; + if(this.cache[this.auth].list[lclass]) { + var store = this.cache[this.auth].list[lclass]; var query = {}; query[linkInfo.vfield.name] = ''+this.widgetValue; + var found = false; store.fetch({query:query, onComplete: function(list) { - self.widgetValue = store.getValue(list[0], linkInfo.vfield.selector); + if(list[0]) { + self.widgetValue = store.getValue(list[0], linkInfo.vfield.selector); + found = true; + } } }); - return; + + if(found) return; } // then try the single object cache - if(this.cacheSingle[lclass] && this.cacheSingle[lclass][this.widgetValue]) { - this.widgetValue = this.cacheSingle[lclass][this.widgetValue]; + if(this.cache[this.auth].single[lclass] && this.cache[this.auth].single[lclass][this.widgetValue]) { + this.widgetValue = this.cache[this.auth].single[lclass][this.widgetValue]; return; } + console.log("Fetching sync object " + lclass + " : " + this.widgetValue); + // if those fail, fetch the linked object this.async = true; var self = this; @@ -239,10 +326,13 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { async : !this.forceSync, oncomplete : function(r) { var item = openils.Util.readResponse(r); - if(!self.cacheSingle[lclass]) - self.cacheSingle[lclass] = {}; - self.widgetValue = item[linkInfo.vfield.selector](); - self.cacheSingle[lclass][self.widgetValue] = item; + var newvalue = item[linkInfo.vfield.selector](); + + if(!self.cache[self.auth].single[lclass]) + self.cache[self.auth].single[lclass] = {}; + self.cache[self.auth].single[lclass][self.widgetValue] = newvalue; + + self.widgetValue = newvalue; self.widget.startup(); self._widgetLoaded(); } @@ -275,6 +365,7 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { }, _buildLinkSelector : function() { + var self = this; var selectorInfo = this._getLinkSelector(); if(!selectorInfo) return false; @@ -298,30 +389,90 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name; this.widget.valueAttr = vfield.name; - var self = this; var oncomplete = function(list) { + + if(self.labelFormat) + self.widget.labelAttr = '_label'; + + if(self.searchFormat) + self.widget.searchAttr = '_search'; + + function formatString(item, formatList) { + + try { + + // formatList[1..*] are names of fields. Pull the field + // values from each object to determine the values for string substitution + var values = []; + var format = formatList[0]; + for(var i = 1; i< formatList.length; i++) + values.push(item[formatList[i]]); + + return dojo.string.substitute(format, values); + + } catch(E) { + throw new Error( + "openils.widget.AutoFieldWidget: Invalid formatList ["+formatList+"] : "+E); + } + + } + if(list) { - self.widget.store = - new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)}); - self.cache[self.auth][linkClass] = self.widget.store; + var storeData = {data:fieldmapper[linkClass].toStoreData(list)}; + + if(self.labelFormat) { + dojo.forEach(storeData.data.items, + function(item) { + item._label = formatString(item, self.labelFormat); + } + ); + } + + if(self.searchFormat) { + dojo.forEach(storeData.data.items, + function(item) { + item._search = formatString(item, self.searchFormat); + } + ); + } + + self.widget.store = new dojo.data.ItemFileReadStore(storeData); + self.cache[self.auth].list[linkClass] = self.widget.store; + } else { - self.widget.store = self.cache[self.auth][linkClass]; + self.widget.store = self.cache[self.auth].list[linkClass]; } + self.widget.startup(); self._widgetLoaded(); }; - if(this.cache[self.auth][linkClass]) { + if(!this.noCache && this.cache[self.auth].list[linkClass]) { oncomplete(); } else { - new openils.PermaCrud().retrieveAll(linkClass, { - async : !this.forceSync, - oncomplete : function(r) { - var list = openils.Util.readResponse(r, false, true); - oncomplete(list); + + if(this.dataLoader) { + + // caller provided an external function for retrieving the data + this.dataLoader(linkClass, this.searchFilter, oncomplete); + + } else { + + var _cb = function(r) { + oncomplete(openils.Util.readResponse(r, false, true)); + }; + + if (this.searchFilter) { + new openils.PermaCrud().search(linkClass, this.searchFilter, { + async : !this.forceSync, oncomplete : _cb + }); + } else { + new openils.PermaCrud().retrieveAll(linkClass, { + async : !this.forceSync, oncomplete : _cb + }); } - }); + } } return true; @@ -347,13 +498,22 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { } else { this.baseWidgetValue(this.widgetValue); - if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence) + if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence && (!this.selfReference && !this.noDisablePkey)) this.widget.attr('disabled', true); if(this.disableWidgetTest && this.disableWidgetTest(this.idlField.name, this.fmObject)) this.widget.attr('disabled', true); } if(this.onload) this.onload(this.widget, this); + + if(!this.readOnly && this.dijitArgs && this.dijitArgs.required) { + // a required dijit is not given any styling to indicate the value + // is invalid until the user has focused the widget then left it with + // invalid data. This change tells dojo to pretend this focusing has + // already happened so we can style required widgets during page render. + this.widget._hasBeenBlurred = true; + this.widget.validate(); + } }, _buildOrgSelector : function() { @@ -365,7 +525,7 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { this.widget.parentField = 'parent_ou'; var user = new openils.User(); - if(this.widgetValue == null) + if(this.widgetValue == null && this.orgDefaultsToWs) this.widgetValue = user.user.ws_ou(); // if we have a limit perm, find the relevent orgs (async) @@ -463,5 +623,6 @@ if(!dojo._hasResource['openils.widget.AutoFieldWidget']) { }); openils.widget.AutoFieldWidget.localeStrings = dojo.i18n.getLocalization("openils.widget", "AutoFieldWidget"); + openils.widget.AutoFieldWidget.cache = {}; } diff --git a/Open-ILS/web/js/dojo/openils/widget/AutoGrid.js b/Open-ILS/web/js/dojo/openils/widget/AutoGrid.js index 9666dc89d3..8f70175b23 100644 --- a/Open-ILS/web/js/dojo/openils/widget/AutoGrid.js +++ b/Open-ILS/web/js/dojo/openils/widget/AutoGrid.js @@ -1,6 +1,7 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { dojo.provide('openils.widget.AutoGrid'); dojo.require('dojox.grid.DataGrid'); + dojo.require('dijit.layout.ContentPane'); dojo.require('openils.widget.AutoWidget'); dojo.require('openils.widget.AutoFieldWidget'); dojo.require('openils.widget.EditPane'); @@ -17,11 +18,18 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { editOnEnter : false, defaultCellWidth : null, editStyle : 'dialog', + editReadOnly : false, suppressFields : null, hideSelector : false, selectorWidth : '1.5', showColumnPicker : false, columnPickerPrefix : null, + displayLimit : 15, + displayOffset : 0, + requiredFields : null, + hidePaginator : false, + showLoadFilter : false, + suppressLinkedFields : null, // list of fields whose linked display data should not be fetched from the server /* by default, don't show auto-generated (sequence) fields */ showSequenceFields : false, @@ -34,6 +42,7 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { this.initAutoEnv(); this.attr('structure', this._compileStructure()); this.setStore(this.buildAutoStore()); + this.cachedQueryOpts = {}; if(this.showColumnPicker) { if(!this.columnPickerPrefix) { @@ -51,6 +60,7 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { this.overrideEditWidgets = {}; this.overrideEditWidgetClass = {}; + this.overrideWidgetArgs = {}; if(this.editOnEnter) this._applyEditOnEnter(); @@ -65,6 +75,82 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { } ); } + + if(!this.hidePaginator) { + var self = this; + this.paginator = new dijit.layout.ContentPane(); + + + var back = dojo.create('a', { + innerHTML : 'Back', // TODO i18n + style : 'padding-right:6px;', + href : 'javascript:void(0);', + onclick : function() { + self.resetStore(); + self.cachedQueryOpts.offset = self.displayOffset -= self.displayLimit; + if(self.displayOffset < 0) + self.cachedQueryOpts.offset = self.displayOffset = 0; + if(self.dataLoader) + self.dataLoader() + else + self.loadAll(self.cachedQueryOpts, self.cachedQuerySearch); + } + }); + + var forw = dojo.create('a', { + innerHTML : 'Next', // TODO i18n + style : 'padding-right:6px;', + href : 'javascript:void(0);', + onclick : function() { + self.resetStore(); + self.cachedQueryOpts.offset = self.displayOffset += self.displayLimit; + if(self.dataLoader) + self.dataLoader() + else + self.loadAll(self.cachedQueryOpts, self.cachedQuerySearch); + } + }); + + dojo.place(this.paginator.domNode, this.domNode, 'before'); + dojo.place(back, this.paginator.domNode); + dojo.place(forw, this.paginator.domNode); + + if(this.showLoadFilter) { + dojo.require('openils.widget.PCrudFilterDialog'); + dojo.place( + dojo.create('a', { + innerHTML : 'Filter', // TODO i18n + style : 'padding-right:6px;', + href : 'javascript:void(0);', + onclick : function() { + var dialog = new openils.widget.PCrudFilterDialog({fmClass:self.fmClass}) + dialog.onApply = function(filter) { + self.resetStore(); + self.loadAll(self.cachedQueryOpts, filter); + }; + dialog.startup(); + dialog.show(); + } + }), + this.paginator.domNode + ); + } + + // progress image + this.loadProgressIndicator = dojo.create('img', { + src:'/opac/images/progressbar_green.gif', // TODO configured path + style:'height:16px;width:16px;' + }); + dojo.place(this.loadProgressIndicator, this.paginator.domNode); + } + }, + + hideLoadProgressIndicator : function() { + dojo.style(this.loadProgressIndicator, 'visibility', 'hidden'); + }, + + showLoadProgressIndicator : function() { + dojo.style(this.loadProgressIndicator, 'visibility', 'visible'); }, /* Don't allow sorting on the selector column */ @@ -205,6 +291,9 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { } }, + /** + * @return {Array} List of every fieldmapper object in the data store + */ getAllObjects : function() { var objs = []; var self = this; @@ -220,16 +309,18 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { return objs; }, + /** + * Deletes the underlying object for all selected rows + */ deleteSelected : function() { var items = this.getSelectedItems(); var total = items.length; var self = this; dojo.require('openils.PermaCrud'); - var pcrud = new openils.PermaCrud(); dojo.forEach(items, function(item) { var fmObject = new fieldmapper[self.fmClass]().fromStoreItem(item); - pcrud['delete'](fmObject, {oncomplete : function(r) { self.store.deleteItem(item) }}); + new openils.PermaCrud()['eliminate'](fmObject, {oncomplete : function(r) { self.store.deleteItem(item) }}); } ); }, @@ -282,12 +373,17 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { var grid = this; var fmObject = new fieldmapper[this.fmClass]().fromStoreItem(storeItem); var idents = grid.store.getIdentityAttributes(); + var self = this; var pane = new openils.widget.EditPane({ fmObject:fmObject, + hideSaveButton : this.editReadOnly, + readOnly : this.editReadOnly, overrideWidgets : this.overrideEditWidgets, overrideWidgetClass : this.overrideEditWidgetClass, + overrideWidgetArgs : this.overrideWidgetArgs, disableWidgetTest : this.disableWidgetTest, + requiredFields : this.requiredFields, onPostSubmit : function() { for(var i in fmObject._fields) { var field = fmObject._fields[i]; @@ -304,7 +400,8 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { } catch (E) {} },200 ); - if(onPostSubmit) onPostSubmit(); + if(onPostSubmit) + onPostSubmit(); }, onCancel : function() { setTimeout(function(){ @@ -324,9 +421,11 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { fmClass : this.fmClass, overrideWidgets : this.overrideEditWidgets, overrideWidgetClass : this.overrideEditWidgetClass, + overrideWidgetArgs : this.overrideWidgetArgs, disableWidgetTest : this.disableWidgetTest, - onPostSubmit : function(r) { - var fmObject = openils.Util.readResponse(r); + requiredFields : this.requiredFields, + onPostSubmit : function(req, cudResults) { + var fmObject = cudResults[0]; if(grid.onPostCreate) grid.onPostCreate(fmObject); if(fmObject) @@ -338,7 +437,7 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { } catch (E) {} },200); if(onPostSubmit) - onPostSubmit(); + onPostSubmit(fmObject); }, onCancel : function() { if(onCancel) onCancel(); @@ -349,7 +448,15 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { return pane; }, - // .startup() is called within + /** + * Creates an EditPane with a copy of the data from the provided store + * item for cloning said item + * @param {Object} storeItem Dojo data item + * @param {Number} rowIndex The Grid row index of the item to be cloned + * @param {Function} onPostSubmit Optional callback for post-submit behavior + * @param {Function} onCancel Optional callback for clone cancelation + * @return {Object} The clone EditPane + */ _makeClonePane : function(storeItem, rowIndex, onPostSubmit, onCancel) { var clonePane = this._makeCreatePane(onPostSubmit, onCancel); var origPane = this._makeEditPane(storeItem, rowIndex); @@ -378,6 +485,9 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { this.editDialog.show(); }, + /** + * Generates an EditDialog for object creation and displays it to the user + */ showCreateDialog : function() { var self = this; var done = function() { self.hideDialog(); }; @@ -397,13 +507,20 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { if(this.onEditPane) this.onEditPane(this.editPane); }, - showClonePane : function() { + showClonePane : function(onPostSubmit) { var self = this; var done = function() { self.hidePane(); }; + + var row = this.getFirstSelectedRow(); if(!row) return; + + var postSubmit = (onPostSubmit) ? + function(result) { onPostSubmit(self.getItem(row), result); self.hidePane(); } : + done; + dojo.style(this.domNode, 'display', 'none'); - this.editPane = this._makeClonePane(this.getItem(row), row, done, done); + this.editPane = this._makeClonePane(this.getItem(row), row, postSubmit, done); this.domNode.parentNode.insertBefore(this.editPane.domNode, this.domNode); if(this.onEditPane) this.onEditPane(this.editPane); }, @@ -439,16 +556,28 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { loadAll : function(opts, search) { dojo.require('openils.PermaCrud'); - if(!opts) opts = {}; + if(this.loadProgressIndicator) + dojo.style(this.loadProgressIndicator, 'visibility', 'visible'); var self = this; + opts = dojo.mixin( + {limit : this.displayLimit, offset : this.displayOffset}, + opts || {} + ); opts = dojo.mixin(opts, { async : true, streaming : true, onresponse : function(r) { var item = openils.Util.readResponse(r); self.store.newItem(item.toStoreItem()); + }, + oncomplete : function() { + if(self.loadProgressIndicator) + dojo.style(self.loadProgressIndicator, 'visibility', 'hidden'); } }); + + this.cachedQuerySearch = search; + this.cachedQueryOpts = opts; if(search) new openils.PermaCrud().search(this.fmClass, search, opts); else @@ -470,18 +599,26 @@ if(!dojo._hasResource['openils.widget.AutoGrid']) { fmClass: this.grid.fmClass, fmField: this.field, widgetValue : val, - readOnly : true + readOnly : true, + forceSync : true, // prevents many simultaneous requests for the same data + suppressLinkedFields : this.grid.suppressLinkedFields }); + autoWidget.build(); + + /* + // With proper caching, this should not be necessary to prevent grid render flickering var _this = this; autoWidget.build( function(w, ww) { - var node = _this.grid.getCell(_this.index).view.getCellNode(rowIndex, _this.index); - if(node) { - node.innerHTML = ww.getDisplayString(); - } + try { + var node = _this.grid.getCell(_this.index).view.getCellNode(rowIndex, _this.index); + if(node) + node.innerHTML = ww.getDisplayString(); + } catch(E) {} } ); + */ return autoWidget.getDisplayString(); } diff --git a/Open-ILS/web/js/dojo/openils/widget/AutoWidget.js b/Open-ILS/web/js/dojo/openils/widget/AutoWidget.js index f8bb0984fd..e4f11ab20c 100644 --- a/Open-ILS/web/js/dojo/openils/widget/AutoWidget.js +++ b/Open-ILS/web/js/dojo/openils/widget/AutoWidget.js @@ -48,7 +48,7 @@ if(!dojo._hasResource['openils.widget.AutoWidget']) { self.sortedFieldList.push(field) } else { // non-IDL field - self.sortedFieldList.push({name : name, virtual:true}); + self.sortedFieldList.push({name : name, nonIdl:true}); } } ); diff --git a/Open-ILS/web/js/dojo/openils/widget/EditDialog.js b/Open-ILS/web/js/dojo/openils/widget/EditDialog.js index 6bb66bdfed..08a22dece5 100644 --- a/Open-ILS/web/js/dojo/openils/widget/EditDialog.js +++ b/Open-ILS/web/js/dojo/openils/widget/EditDialog.js @@ -38,9 +38,9 @@ if(!dojo._hasResource['openils.widget.EditDialog']) { self.hide(); } - this.editPane.onPostSubmit = function(r) { + this.editPane.onPostSubmit = function(r, cudResults) { self.hide(); - if(onSubmit) onSubmit(r); + if(onSubmit) onSubmit(r, cudResults); } }, diff --git a/Open-ILS/web/js/dojo/openils/widget/EditPane.js b/Open-ILS/web/js/dojo/openils/widget/EditPane.js index 48e5ecfcc9..69b005b383 100644 --- a/Open-ILS/web/js/dojo/openils/widget/EditPane.js +++ b/Open-ILS/web/js/dojo/openils/widget/EditPane.js @@ -16,6 +16,11 @@ if(!dojo._hasResource['openils.widget.EditPane']) { onPostSubmit : null, // apply callback onCancel : null, // cancel callback hideActionButtons : false, + fieldDocs : null, + existingTable : null, + suppressFields : null, + requiredFields : null, + paneStackCount : 1, // how many fields to add to each row, for compressing display constructor : function(args) { this.fieldList = []; @@ -31,11 +36,20 @@ if(!dojo._hasResource['openils.widget.EditPane']) { this.inherited(arguments); this.initAutoEnv(); if(this.readOnly) - this.hideActionButtons = true; + this.hideSaveButton = true; - var table = this.table = document.createElement('table'); + // grab any field-level docs + /* + var pcrud = new openils.PermaCrud(); + this.fieldDocs = pcrud.search('fdoc', {fm_class:this.fmClass}); + */ + + var table = this.existingTable; + if(!table) { + var table = this.table = document.createElement('table'); + this.domNode.appendChild(table); + } var tbody = document.createElement('tbody'); - this.domNode.appendChild(table); table.appendChild(tbody); this.limitPerms = []; @@ -48,37 +62,80 @@ if(!dojo._hasResource['openils.widget.EditPane']) { if(!this.overrideWidgetClass) this.overrideWidgetClass = {}; + if(!this.overrideWidgetArgs) + this.overrideWidgetArgs = {}; + + var idx = 0; + var currentRow; for(var f in this.sortedFieldList) { var field = this.sortedFieldList[f]; - if(!field || field.virtual) continue; + if(!field || field.virtual || field.nonIdl) continue; + + if(this.suppressFields && this.suppressFields.indexOf(field.name) > -1) + continue; if(field.name == this.fmIDL.pkey && this.mode == 'create' && this.fmIDL.pkey_sequence) continue; /* don't show auto-generated fields on create */ - var row = document.createElement('tr'); + if((idx++ % this.paneStackCount) == 0 || !currentRow) { + // time to start a new row + currentRow = document.createElement('tr'); + tbody.appendChild(currentRow); + } + + //var docTd = document.createElement('td'); var nameTd = document.createElement('td'); var valTd = document.createElement('td'); var valSpan = document.createElement('span'); valTd.appendChild(valSpan); - + dojo.addClass(nameTd, 'openils-widget-editpane-name-cell'); + dojo.addClass(valTd, 'openils-widget-editpane-value-cell'); + + /* + if(this.fieldDocs[field]) { + var helpLink = dojo.create('a'); + var helpImg = dojo.create('img', {src:'/opac/images/advancedsearch-icon.png'}); // TODO Config + helpLink.appendChild(helpImg); + docTd.appendChild(helpLink); + } + */ nameTd.appendChild(document.createTextNode(field.label)); - row.setAttribute('fmfield', field.name); - row.appendChild(nameTd); - row.appendChild(valTd); - tbody.appendChild(row); - - var widget = new openils.widget.AutoFieldWidget({ - idlField : field, - fmObject : this.fmObject, - fmClass : this.fmClass, - parentNode : valSpan, - orgLimitPerms : this.limitPerms, - readOnly : this.readOnly, - widget : this.overrideWidgets[field.name], - widgetClass : this.overrideWidgetClass[field.name], - disableWidgetTest : this.disableWidgetTest - }); + currentRow.setAttribute('fmfield', field.name); + //currentRow.appendChild(docTd); + currentRow.appendChild(nameTd); + currentRow.appendChild(valTd); + //dojo.addClass(docTd, 'oils-fm-edit-pane-help'); + + if(!this.overrideWidgetArgs[field.name]) + this.overrideWidgetArgs[field.name] = {}; + + var args = dojo.mixin( + { // defaults + idlField : field, + fmObject : this.fmObject, + fmClass : this.fmClass, + parentNode : valSpan, + orgLimitPerms : this.limitPerms, + readOnly : this.readOnly, + widget : this.overrideWidgets[field.name], + widgetClass : this.overrideWidgetClass[field.name], + disableWidgetTest : this.disableWidgetTest + }, + this.overrideWidgetArgs[field.name] // per-field overrides + ); + + if(args.readOnly) { + dojo.addClass(nameTd, 'openils-widget-editpane-ro-name-cell'); + dojo.addClass(valTd, 'openils-widget-editpane-ro-value-cell'); + } + + if(this.requiredFields && this.requiredFields.indexOf(field.name) >= 0) { + if(!args.dijitArgs) args.dijitArgs = {}; + args.dijitArgs.required = true; + } + + var widget = new openils.widget.AutoFieldWidget(args); widget.build(); this.fieldList.push({name:field.name, widget:widget}); @@ -117,6 +174,8 @@ if(!dojo._hasResource['openils.widget.EditPane']) { onClick : this.onCancel }, cancelSpan); + if(this.hideSaveButton) return; + new dijit.form.Button({ label:'Save', // XXX onClick: function() {self.performAutoEditAction();} @@ -137,9 +196,9 @@ if(!dojo._hasResource['openils.widget.EditPane']) { performAutoEditAction : function() { var self = this; self.performEditAction({ - oncomplete:function(r) { + oncomplete:function(req, cudResults) { if(self.onPostSubmit) - self.onPostSubmit(r); + self.onPostSubmit(req, cudResults); } }); }, diff --git a/Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js b/Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js index a948eee61c..4d19f3419d 100644 --- a/Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js +++ b/Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js @@ -1,4 +1,5 @@ { - 'TRUE' : 'True', - 'FALSE' : 'False' + "TRUE" : "True", + "FALSE" : "False", + "UNSET" : "Unset" } diff --git a/Open-ILS/web/js/ui/default/conify/global/action/survey.js b/Open-ILS/web/js/ui/default/conify/global/action/survey.js index 5fb779bc2e..c9809653d4 100644 --- a/Open-ILS/web/js/ui/default/conify/global/action/survey.js +++ b/Open-ILS/web/js/ui/default/conify/global/action/survey.js @@ -145,8 +145,8 @@ function svCreate(args) { var pcrud = new openils.PermaCrud(); pcrud.create(sv, { - oncomplete: function(r) { - var obj = openils.Util.readResponse(r); + oncomplete: function(r, objs) { + var obj = objs[0]; if(!obj) return ''; svGrid.store.newItem(asv.toStoreItem(obj)); svSurveyDialog.hide(); diff --git a/Open-ILS/web/js/ui/default/conify/global/action/survey/edit.js b/Open-ILS/web/js/ui/default/conify/global/action/survey/edit.js index 2c2b8ed67b..132c3fcfdf 100644 --- a/Open-ILS/web/js/ui/default/conify/global/action/survey/edit.js +++ b/Open-ILS/web/js/ui/default/conify/global/action/survey/edit.js @@ -123,8 +123,8 @@ function newQuestion(svyId, questionText, questionRow) { question.question(questionText); question.isnew(true); pcrud.create(question, - {oncomplete: function(r) - { var q = openils.Util.readResponse(r); + {oncomplete: function(r, qs) + { var q = qs[0]; questionRow.parentNode.removeChild(questionRow); drawQuestionBody(q, null); newQuestionBody(svyId); diff --git a/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js b/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js index 3004406519..7fdae7b166 100644 --- a/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js +++ b/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js @@ -12,6 +12,7 @@ var circModEntryCache = {}; var matchPoint; function load(){ + cmGrid.overrideWidgetArgs.is_renewal = {ternary : true}; cmGrid.loadAll({order_by:{ccmm:'circ_modifier'}}); cmGrid.onEditPane = buildEditPaneAdditions; circModEditor = dojo.byId('circ-mod-editor').parentNode.removeChild(dojo.byId('circ-mod-editor')); @@ -22,6 +23,7 @@ function byName(name, ctxt) { } function buildEditPaneAdditions(editPane) { + if(!editPane.fmObject) return; var node = circModEditor.cloneNode(true); var tableTmpl = node.removeChild(byName('circ-mod-group-table', node)); circModGroupTables = []; @@ -143,8 +145,8 @@ function applyCircModChanges() { if(group.isnew()) { pcrud.create(group, { - oncomplete : function(r) { - var group = openils.Util.readResponse(r); + oncomplete : function(r, cudResults) { + var group = cudResults[0]; dojo.forEach(entries, function(e) { e.circ_mod_test(group.id()) } ); pcrud.create(entries, { oncomplete : function() { @@ -157,8 +159,7 @@ function applyCircModChanges() { } else { pcrud.update(group, { - oncomplete : function(r) { - openils.Util.readResponse(r); + oncomplete : function(r, cudResults) { var newOnes = entries.filter(function(e) { return e.isnew() }); var delOnes = entries.filter(function(e) { return e.isdeleted() }); if(!delOnes.length && !newOnes.length) { @@ -169,7 +170,7 @@ function applyCircModChanges() { pcrud.create(newOnes, { oncomplete : function() { if(delOnes.length) { - pcrud.delete(delOnes, { + pcrud.eliminate(delOnes, { oncomplete : function() { progressDialog.hide(); } @@ -180,7 +181,7 @@ function applyCircModChanges() { } }); } else { - pcrud.delete(delOnes, { + pcrud.eliminate(delOnes, { oncomplete : function() { progressDialog.hide(); } -- 2.11.0