[open-ils-commits] r17109 - in branches/rel_1_6_0/Open-ILS/web/js: dojo/openils dojo/openils/widget dojo/openils/widget/nls ui/default/conify/global/action ui/default/conify/global/action/survey ui/default/conify/global/config (gmc)

svn at svn.open-ils.org svn at svn.open-ils.org
Thu Aug 5 20:54:54 EDT 2010


Author: gmc
Date: 2010-08-05 20:54:52 -0400 (Thu, 05 Aug 2010)
New Revision: 17109

Modified:
   branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/Event.js
   branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js
   branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoGrid.js
   branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoWidget.js
   branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/EditDialog.js
   branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/EditPane.js
   branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js
   branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/action/survey.js
   branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/action/survey/edit.js
   branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js
Log:
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 <gmc at esilibrary.com>


Modified: branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/Event.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/Event.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/Event.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -29,12 +29,15 @@
             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;
         }
     });

Modified: branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -9,8 +9,6 @@
     dojo.declare('openils.widget.AutoFieldWidget', null, {
 
         async : false,
-        cache : {},
-        cacheSingle : {},
 
         /**
          * args:
@@ -24,6 +22,28 @@
          *  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(this.fmObject) 
                 this.fmClass = this.fmObject.classname;
             this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
+            this.suppressLinkedFields = args.suppressLinkedFields || [];
 
-            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.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
+                };
+
+            } 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 @@
             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 @@
             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 @@
 
         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 @@
                 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 @@
                         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(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 @@
                 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 @@
         },
 
         _buildLinkSelector : function() {
+            var self = this;
             var selectorInfo = this._getLinkSelector();
             if(!selectorInfo) return false;
 
@@ -298,30 +389,90 @@
             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 @@
             } 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 @@
             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 @@
     });
 
     openils.widget.AutoFieldWidget.localeStrings = dojo.i18n.getLocalization("openils.widget", "AutoFieldWidget");
+    openils.widget.AutoFieldWidget.cache = {};
 }
 

Modified: branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoGrid.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoGrid.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoGrid.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -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 @@
             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 @@
                 this.initAutoEnv();
                 this.attr('structure', this._compileStructure());
                 this.setStore(this.buildAutoStore());
+                this.cachedQueryOpts = {};
 
                 if(this.showColumnPicker) {
                     if(!this.columnPickerPrefix) {
@@ -51,6 +60,7 @@
 
                 this.overrideEditWidgets = {};
                 this.overrideEditWidgetClass = {};
+                this.overrideWidgetArgs = {};
 
                 if(this.editOnEnter) 
                     this._applyEditOnEnter();
@@ -65,8 +75,84 @@
                         }
                     );
                 }
+
+                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 */
             canSort : function(rowIdx) {
                 if(rowIdx == 1 && !this.hideSelector)
@@ -205,6 +291,9 @@
                 }
             },
 
+            /**
+             * @return {Array} List of every fieldmapper object in the data store
+             */
             getAllObjects : function() {
                 var objs = [];
                 var self = this;
@@ -220,16 +309,18 @@
                 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 @@
                 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 @@
                                 } catch (E) {}
                             },200
                         );
-                        if(onPostSubmit) onPostSubmit();
+                        if(onPostSubmit) 
+                            onPostSubmit();
                     },
                     onCancel : function() {
                         setTimeout(function(){
@@ -324,9 +421,11 @@
                     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 @@
                             } catch (E) {}
                         },200);
                         if(onPostSubmit)
-                            onPostSubmit();
+                            onPostSubmit(fmObject);
                     },
                     onCancel : function() {
                         if(onCancel) onCancel();
@@ -349,7 +448,15 @@
                 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 @@
                 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(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 @@
 
             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 @@
             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();
     }

Modified: branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoWidget.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoWidget.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/AutoWidget.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -48,7 +48,7 @@
                             self.sortedFieldList.push(field)
                         } else {
                             // non-IDL field
-                            self.sortedFieldList.push({name : name, virtual:true});
+                            self.sortedFieldList.push({name : name, nonIdl:true});
                         }
                     }
                 );

Modified: branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/EditDialog.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/EditDialog.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/EditDialog.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -38,9 +38,9 @@
                     self.hide(); 
                 }
 
-                this.editPane.onPostSubmit = function(r) { 
+                this.editPane.onPostSubmit = function(r, cudResults) { 
                     self.hide(); 
-                    if(onSubmit) onSubmit(r);
+                    if(onSubmit) onSubmit(r, cudResults);
                 }
             },
 

Modified: branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/EditPane.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/EditPane.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/EditPane.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -16,6 +16,11 @@
             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 @@
                 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,38 +62,81 @@
                 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);
+                    currentRow.setAttribute('fmfield', field.name);
+                    //currentRow.appendChild(docTd);
+                    currentRow.appendChild(nameTd);
+                    currentRow.appendChild(valTd);
+                    //dojo.addClass(docTd, 'oils-fm-edit-pane-help');
 
-                    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
-                    });
+                    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 @@
                     onClick : this.onCancel
                 }, cancelSpan);
 
+                if(this.hideSaveButton) return;
+
                 new dijit.form.Button({
                     label:'Save',  // XXX
                     onClick: function() {self.performAutoEditAction();}
@@ -137,9 +196,9 @@
             performAutoEditAction : function() {
                 var self = this;
                 self.performEditAction({
-                    oncomplete:function(r) {
+                    oncomplete:function(req, cudResults) {
                         if(self.onPostSubmit)
-                            self.onPostSubmit(r);
+                            self.onPostSubmit(req, cudResults);
                     }
                 });
             },

Modified: branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/dojo/openils/widget/nls/AutoFieldWidget.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -1,4 +1,5 @@
 {
-    'TRUE' : 'True',
-    'FALSE' : 'False'
+    "TRUE" : "True",
+    "FALSE" : "False",
+    "UNSET" : "Unset"
 }

Modified: branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/action/survey/edit.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/action/survey/edit.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/action/survey/edit.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -123,8 +123,8 @@
     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);

Modified: branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/action/survey.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/action/survey.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/action/survey.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -145,8 +145,8 @@
     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();

Modified: branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js
===================================================================
--- branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js	2010-08-06 00:49:37 UTC (rev 17108)
+++ branches/rel_1_6_0/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js	2010-08-06 00:54:52 UTC (rev 17109)
@@ -12,6 +12,7 @@
 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 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 @@
         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 @@
         } 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 @@
                         pcrud.create(newOnes, {
                             oncomplete : function() {
                                 if(delOnes.length) {
-                                    pcrud.delete(delOnes, {
+                                    pcrud.eliminate(delOnes, {
                                         oncomplete : function() {
                                             progressDialog.hide();
                                         }
@@ -180,7 +181,7 @@
                             }
                         });
                     } else {
-                        pcrud.delete(delOnes, {
+                        pcrud.eliminate(delOnes, {
                             oncomplete : function() {
                                 progressDialog.hide();
                             }



More information about the open-ils-commits mailing list