sorting bug fixed, FlattenerGrid's API stabilized
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Tue, 27 Mar 2012 13:36:33 +0000 (09:36 -0400)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Tue, 27 Mar 2012 13:36:33 +0000 (09:36 -0400)
when I say its API is stablized I mean how you build the map, using the
<th> elements and the mapExtras attribute on the <table> element.

Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/src/templates/conify/flattener_test.tt2
Open-ILS/web/js/dojo/openils/FlattenerStore.js
Open-ILS/web/js/dojo/openils/widget/FlattenerGrid.js

index e3f5a5f..bde5fdd 100644 (file)
     dojoType="openils.widget.FlattenerGrid"
     fmClass="'acp'"
     autoHeight="10"
-    query="{'tcn': {'>': '100' },'circ_lib': 'BR1'}">
+    mapExtras="{copy_status: {path: 'status.name', filter: true}}"
+    query="{'copy_status': ['Available','Reshelving','In process'],'circ_lib': 'BR1'}">
     <thead>
         <tr>
             <th field="barcode" fpath="barcode">Barcode</th>
             <th field="circ_lib_name" fpath="circ_lib.name">Circulation Library Name</th>
-            <th field="circ_lib" fpath="circ_lib.shortname">Circulation Library</th>
-            <th field="call_number" fpath="call_number.label" fdisplay="true" fsort="true">Call Number</th>
-            <th field="tcn" fpath="call_number.record.tcn_value" fdisplay="true" ffilter="true">TCN</th>
+            <th field="circ_lib" fpath="circ_lib.shortname" ffilter="true">Circulation Library</th>
+            <th field="call_number" fpath="call_number.label">Call Number</th>
+            <th field="shelving_loc" fpath="location.name" ffilter="true">Shelving Location</th>
         </tr>
     </thead>
 </table>
index f5c0fc1..f1eaa2f 100644 (file)
@@ -109,7 +109,7 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
         },
 
         "getValues": function(/* object */ item, /* string */ attribute) {
-            console.log("getValues(" + item + ", " + attribute + ")");
+            //console.log("getValues(" + item + ", " + attribute + ")");
             if (!this.isItem(item) || typeof attribute != "string")
                 throw new FlattenerStoreError("bad arguments");
 
@@ -118,7 +118,7 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
         },
 
         "getAttributes": function(/* object */ item) {
-            console.log("getAttributes(" + item + ")");
+            //console.log("getAttributes(" + item + ")");
             if (!this.isItem(item))
                 throw new FlattenerStoreError("getAttributes(): bad args");
             else
@@ -126,7 +126,7 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
         },
 
         "hasAttribute": function(/* object */ item, /* string */ attribute) {
-            console.log("hasAttribute(" + item + ", " + attribute + ")");
+            //console.log("hasAttribute(" + item + ", " + attribute + ")");
             if (!this.isItem(item) || typeof attribute != "string") {
                 throw new FlattenerStoreError("hasAttribute(): bad args");
             } else {
@@ -138,7 +138,7 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
             /* object */ item,
             /* string */ attribute,
             /* anything */ value) {
-            console.log("containsValue(" + item + ", " + attribute + ", " + value + ")");
+            //console.log("containsValue(" + item + ", " + attribute + ", " + value + ")");
             if (!this.isItem(item) || typeof attribute != "string")
                 throw new FlattenerStoreError("bad data");
             else
@@ -163,24 +163,25 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
         },
 
         "isItemLoaded": function(/* anything */ something) {
-            console.log("isItemLoaded(" + something + ")");
-            return this.isItem(something);  /* for this store,
-                                               items are always loaded */
+            console.warning("[unfinished] isItemLoaded(" + something + ")");
+
+            /* This is assuming items are always loaded, which is probably not right for this particular store.*/
+            return this.isItem(something);
         },
 
         "close": function(/* object */ request) { /* no-op */ return; },
 
         "getLabel": function(/* object */ item) {
-            console.log("getLabel(" + item + ")");
+            //console.log("getLabel(" + item + ")");
             return "XXX TODO";
         },
         "getLabelAttributes": function(/* object */ item) {
-            console.log("getLabelAttributes(" + item + ")");
+            //console.log("getLabelAttributes(" + item + ")");
             return ["XXX TODO"];
         },
 
         "loadItem": function(/* object */ keywordArgs) {
-            console.log("loadItem(" + dojo.toJson(keywordArgs) + ")");
+            //console.log("loadItem(" + dojo.toJson(keywordArgs) + ")");
 
             if (!this.isItem(keywordArgs.item))
                 throw new FlattenerStoreError("not an item; can't load it");
@@ -210,14 +211,10 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
             //  callback to the *req* object for the caller's use, but
             //  the one we provide does nothing but issue an alert().
 
-            console.log("fetch(" + dojo.toJson(req) + ")");
-            /* if-not-ready-then-act-as-if-empty. this is how you do that. */
+            console.info("fetch(" + dojo.toJson(req) + ")");
 
-//            if (!this.cm_cache.is_done) {
-//                if (typeof req.onComplete == "function")
-//                    req.onComplete.call(callback_scope, [], req);
-//                return;
-//            }
+            /* XXX We're clearing this cache upon every fetch? Do we need/want
+             * to do that?  Not sure. */
             this._current_items = {};
 
             var callback_scope = req.scope || dojo.global;
@@ -235,33 +232,32 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
                     return;
 
                 if (typeof req.onBegin == "function") {
-
+                    /* We lie to onBegin like this because we don't know how
+                     * many more rows we might be able to fetch if the
+                     * user keeps scrolling.  Once we get a number of
+                     * results that is less than the limit we asked for,
+                     * the grid is smart enough to know we're at the end and
+                     * it does the right thing. */
                     var might_be_a_lie = obj.length;
                     if (obj.length >= req.count)
                         might_be_a_lie += req.count;
 
-                    console.debug("onBegin(" + might_be_a_lie + ", ...)");
                     req.onBegin.call(callback_scope, might_be_a_lie, req);
                 }
 
                 dojo.forEach(
                     obj,
                     function(item) {
+                        /* Cache items internally. */
                         self._current_items[item[self.fmIdentifier]] = item;
 
-                        if (typeof req.onItem == "function") {
+                        if (typeof req.onItem == "function")
                             req.onItem.call(callback_scope, item, req);
-                        }
                     }
                 );
 
-                if (typeof req.onComplete == "function") {
-                    req.onComplete.call(
-                        callback_scope,
-                        openils.Util.objectValues(self._current_items),
-                        req
-                    );
-                }
+                if (typeof req.onComplete == "function")
+                    req.onComplete.call(callback_scope, obj, req);
             };
 
             req.abort = function() {
@@ -270,7 +266,6 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
 
             var fetch_time = this._last_fetch = (new Date().getTime());
 
-            console.log(dojo.toJson(post_params));
             dojo.xhrPost({
                 "url": "/opac/extras/flattener",
                 "content": post_params,
@@ -289,7 +284,7 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
         /* *** Begin dojo.data.api.Identity methods *** */
 
         "getIdentity": function(/* object */ item) {
-            console.log("getIdentity(" + item + ")");
+            //console.log("getIdentity(" + item + ")");
             if (!this.isItem(item))
                 throw new FlattenerStoreError("not an item");
 
@@ -297,17 +292,20 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
         },
 
         "getIdentityAttributes": function(/* object */ item) {
-            console.log("getIdentityAttributes(" + item + ")");
+            // console.log("getIdentityAttributes(" + item + ")");
             return [this.fmIdentifier];
         },
 
         "fetchItemByIdentity": function(/* object */ keywordArgs) {
 
-            /* XXX This almost certainly needs attention, and/or
-             * needs to be able to call fetch() or to talk to the
-             * web service directly. */
+            /* XXX This almost certainly needs attention (unless DataGrid
+             * doesn't use it (or loadItem)?), and needs to be able to call
+             * fetch() or to talk to the web service directly. */
 
-            console.log("fetchItemByIdentity(" + dojo.toJson(keywordArgs)+ ")");
+            console.warning(
+                "[unfinished] fetchItemByIdentity(" +
+                dojo.toJson(keywordArgs) + ")"
+            );
             if (keywordArgs.identity == undefined)
                 return null; // Identity API spec unclear whether error callback
                              // would need to be run, so we won't.
@@ -331,7 +329,6 @@ if (!dojo._hasResource["openils.FlattenerStore"]) {
          *     APIs they're implementing. *** */
 
         "getFeatures": function() {
-            console.log("getFeatures()");
             return {
                 "dojo.data.api.Read": true,
                 "dojo.data.api.Identity": true
index a5621ae..8e07821 100644 (file)
@@ -11,33 +11,39 @@ if (!dojo._hasResource["openils.widget.FlattenerGrid"]) {
             "columnReordering": true,
             "fmClass": null,
             "fmIdentifier": null,
+            "mapExtras": null,
 
+            /* _generate_map() lives to interpret the attributes of the
+             * FlattenerGrid dijit itself plus those definined in
+             * <table>
+             *  <thead>
+             *   <tr>
+             *    <th field="foo" ...>
+             * to build the map to hand to the FlattenerStore, which in turn
+             * uses it to query the flattener service.
+             */
             "_generate_map": function() {
                 var map = this.mapClause = {};
                 var fields = this.structure[0].cells[0];
-                /* XXX TODO remove column from grid (or hide? or what?)
-                 * when display is false */
+
+                /* These are the fields defined in thead -> tr -> [th,th,...].
+                 * For purposes of building the map, where each field has
+                 * three boolean attributes "display", "sort" and "filter",
+                 * assume "display" and "sort" are always true for these.
+                 * That doesn't mean that at the UI level we can't hide a
+                 * column later.
+                 *
+                 * If you need extra fields in the map for which display
+                 * or sort should *not* be true, use mapExtras.
+                 */
                 dojo.forEach(
-                    fields,
-                    function(field) {
-                        if (field.fpath) {
-                            if ("fdisplay" in field ||
-                                "fsort" in field ||
-                                "ffilter" in field) {
-                                map[field.field] = {
-                                    "display": (field.fdisplay || false),
-                                    "filter": (field.ffilter || false),
-                                    "sort": (field.fsort || false)
-                                };
-                            } else {
-                                map[field.field] = {
-                                    "sort": true,
-                                    "filter": true,
-                                    "display": true
-                                };
-                            }
-                            map[field.field].path = field.fpath;
-                        }
+                    fields, function(field) {
+                        map[field.field] = {
+                            "display": true,
+                            "filter": (field.ffilter || false),
+                            "sort": true,
+                            "path": field.fpath || field.field
+                        };
                     }
                 );
 
@@ -51,6 +57,27 @@ if (!dojo._hasResource["openils.widget.FlattenerGrid"]) {
                     };
                 }
 
+                if (this.mapExtras) {
+                    /* It's not particularly useful to add simple fields, i.e.
+                     *  circ_lib: "circ_lib.name"
+                     * to mapExtras, because by convention used elsewhere in
+                     * Flattener, that gives all attributes, including
+                     * display, a true value. Still, be consistent to avoid
+                     * stumping users.
+                     */
+                    for (var key in this.mapExtras) {
+                        if (typeof this.mapExtras[key] != "object") {
+                            this.mapExtras[key] = {
+                                "path": this.mapExtras[key],
+                                "sort": true,
+                                "filter": true,
+                                "display": true
+                            };
+                        }
+                    }
+                    dojo.mixin(map, this.mapExtras);
+                }
+
                 return map;
             },
 
@@ -85,8 +112,7 @@ if (!dojo._hasResource["openils.widget.FlattenerGrid"]) {
             orig_mf(node, cellDef);
 
             dojo.forEach(
-                ["fpath", "fdisplay", "fsort", "ffilter"],
-                function(a) {
+                ["fpath", "ffilter"], function(a) {
                     var value = dojo.attr(node, a);
                     if (value)
                         cellDef[a] = value;