item status UI continued
authorBill Erickson <berick@esilibrary.com>
Thu, 15 May 2014 17:29:07 +0000 (13:29 -0400)
committerBill Erickson <berick@esilibrary.com>
Thu, 15 May 2014 17:29:07 +0000 (13:29 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/cat/item/index.tt2
Open-ILS/src/templates/staff/cat/item/t_list.tt2
Open-ILS/src/templates/staff/share/t_autogrid.tt2
Open-ILS/web/js/ui/default/staff/cat/item/app.js
Open-ILS/web/js/ui/default/staff/services/grid.js

index 7a774df..aee8eaf 100644 (file)
 
 <h1>[% l('Scan Item') %]</h1>
 
-<form id="item-status-form" ng-submit="fetchCopy(args)" role="form">
+<form id="item-status-form" ng-submit="context.search(args)" role="form">
   <div class="row">
     <div class="col-md-6">
       <div class="input-group">
-        <input type="text" id="item-status-barcode" focus-me="focusBarcode"
-          class="form-control" ng-model="args.barcode">
+
+        <!-- barcode input -->
+        <input type="text" id="item-status-barcode" 
+          focus-me="focusBarcode" class="form-control" ng-model="args.barcode">
+
+        <!-- submit -->
         <input class="btn btn-default" 
           type="submit" value="[% l('Submit') %]"/>
+
+        <!-- toggle detail view -->
+        <button class="btn btn-default" style="margin-left:10px" ng-click="toggleView($event)">
+            <span ng-show="context.page == 'list'">[% l('Detail View') %]</span>
+            <span ng-show="context.page == 'detail'">[% l('List View') %]</span>
+        </button>
+
       </div><!-- input group -->
     </div><!-- col -->
   </div><!-- row -->
index 316a9f0..8823659 100644 (file)
@@ -1,10 +1,11 @@
 <eg-grid
-  id-field="id"
+  id-field="index"
   idl-class="acp"
   features="-display,-sort,-multisort"
   main-label="[% l('Item Status') %]"
   items-provider="gridDataProvider"
   persist-key="cat.items">
+
   <eg-grid-field label="[% l('Barcode') %]"     path='barcode' visible></eg-grid-field>
   <eg-grid-field label="[% l('Call Number') %]" path="call_number.label" visible></eg-grid-field>
   <eg-grid-field label="[% l('Location') %]"    path="location.name" visible></eg-grid-field>
index ccfc46e..27439e9 100644 (file)
     <ul class="dropdown-menu">
       <li ng-repeat="item in menuItems" ng-class="{divider: item.divider}">
         <a ng-if="!item.divider" href
-          ng-click="item.handler(item, item.handlerData)">{{item.label}}</a>
+          ng-click="item.handler()">{{item.label}}</a>
       </li>
     </ul>
   </div>
 
+  <!-- if we have a single menu item, present it as a single button -->
+  <button class="btn btn-default" style="margin-right: 10px"
+    ng-if="!menuLabel && menuItems.length == 1"
+    ng-click="menuItems[0].handler(menuItems[0], menuItems[0].handlerData)">
+    {{menuItems[0].label}}
+  </button>
+
   <!-- column picker, pager, etc. -->
   <div class="btn-group column-picker">
 
index c36e621..1fcdf16 100644 (file)
@@ -28,77 +28,119 @@ angular.module('egItemStatus',
     $routeProvider.otherwise({redirectTo : '/cat/item/search'});
 })
 
+.factory('itemSvc', 
+       ['egCore',
+function(egCore) {
+
+    var service = {
+        copies : [], // copy barcode search results
+        index : 0 // search grid index
+    };
+
+    service.flesh = {   
+        flesh : 3, 
+        flesh_fields : {
+            acp : ['call_number','location','status','location'],
+            acn : ['record'],
+            bre : ['simple_record','creator','editor']
+        },
+        select : { 
+            // avoid fleshing MARC on the bre
+            // note: don't add simple_record.. not sure why
+            bre : ['id','tcn_value','creator','editor'],
+        } 
+    }
+
+    service.fetch = function(barcode, id) {
+        var promise;
+
+        if (barcode) {
+            promise = egCore.pcrud.search('acp', 
+                {barcode : barcode, deleted : 'f'}, service.flesh);
+        } else {
+            promise = egCore.pcrud.retrieve('acp', id, service.flesh);
+        }
+
+        return promise.then(function(copy) {
+            if (!copy) return null;
+
+            var flatCopy = egCore.idl.toHash(copy, true);
+            flatCopy.index = service.index++;
+            service.copies.unshift(flatCopy);
+
+            return {
+                copy : copy, 
+                index : flatCopy.index
+            };
+        });
+    }
+
+    return service;
+}])
+
 /**
  * Search bar along the top of the page.
  * Parent scope for list and detail views
  */
 .controller('SearchCtrl', 
-       ['$scope','$location','egCore','egGridDataProvider',
-function($scope , $location , egCore , egGridDataProvider) {
-    
+       ['$scope','$location','egCore','egGridDataProvider','itemSvc',
+function($scope , $location , egCore , egGridDataProvider , itemSvc) {
     $scope.focusBarcode = true;
-    var copies = [];
 
-    var provider = egGridDataProvider.instance({});
+    // sub-scopes (search / detail-view) apply their version 
+    // of retrieval function to $scope.context.search
+    // and display toggling via $scope.context.toggleDisplay
+    $scope.context = {};
+
+    $scope.toggleView = function($event) {
+        $scope.context.toggleDisplay();
+        $event.preventDefault(); // avoid form submission
+    }
+
+    $scope.args = {};
+}])
+
+/**
+ * List view - grid stuff
+ */
+.controller('ListCtrl', 
+       ['$scope','$location','$timeout','egCore','egGridDataProvider','itemSvc',
+function($scope , $location , $timeout , egCore , egGridDataProvider , itemSvc) {
+    $scope.context.page = 'list';
+
+    var provider = egGridDataProvider.instance();
     provider.get = function(offset, count) {
-        return provider.arrayNotifier(copies, offset, count);
+        return provider.arrayNotifier(itemSvc.copies, offset, count);
     }
+
     provider.itemFieldValue = provider.flatItemFieldValue;
     $scope.gridDataProvider = provider;
 
-    $scope.searchCopy = function(args) {
-        $scope.fetchCopy(args.barcode)
-        .then(function(copy) {
-            if (copy) {
-                copies.unshift(egCore.idl.toHash(copy, true));
+    $scope.context.search = function(args) {
+        itemSvc.fetch(args.barcode).then(function(res) {
+            if (res) {
                 provider.increment();
-            } else {
-                $scope.copyNotFound = true;
+                provider.selectOneItem(res.index);
             }
-        });
+        })
     }
 
-    $scope.fetchCopy(barcode, id) {
-        var flesh = {   
-            flesh : 3, 
-            flesh_fields : {
-                acp : ['call_number','location','status','location'],
-                acn : ['record'],
-                bre : ['simple_record','creator','editor']
-            },
-            select : { 
-                // avoid fleshing MARC on the bre
-                // note: don't add simple_record.. not sure why
-                bre : ['id','tcn_value','creator','editor'],
-            } 
-        };
-
-        var promise;
-        
-        if (barcode) {
-            promise = egCore.pcrud.search('acp', 
-                {barcode : barcode, deleted : 'f'}, flesh);
-        } else {
-            promise = egCore.pcrud.retrieve('acp', id, flesh);
-        }
-
-        promise.then(function(copy) { 
-            if (!copy) {
-                $scope.copyNotFound = true;
-                return;
-            }
-            return egCore.idl.toHash(copy, true) 
+    if (itemSvc.copy) {
+        // If a copy was just displayed in the detail view, ensure it's
+        // focused in the list view.  However, give the grid a chance to
+        // instantiate before attempting to select any items.
+        $timeout(function() {
+            var flatCopy = itemSvc.copies.filter(
+                function(c) { return c.id == itemSvc.copy.id() })[0];
+            provider.selectOneItem(flatCopy.index);
         });
     }
-}])
 
-/**
- * List view - grid stuff
- */
-.controller('ListCtrl', 
-       ['$scope','$location','egCore',
-function($scope , $location , egCore) {
-    // grid stuff
+    $scope.context.toggleDisplay = function() {
+        var item = provider.getSelectedItems()[0];
+        if (item) 
+            $location.path('/cat/item/view/' + item.id + '/summary');
+    }
 
 }])
 
@@ -106,20 +148,22 @@ function($scope , $location , egCore) {
  * Detail view -- shows one copy
  */
 .controller('ViewCtrl', 
-       ['$scope','$location','$routeParams','egCore',
-function($scope , $location , $routeParams , egCore) {
+       ['$scope','$location','$routeParams','egCore','itemSvc',
+function($scope , $location , $routeParams , egCore , itemSvc) {
     var copyId = $routeParams.id;
     $scope.tab = $routeParams.tab;
+    $scope.context.page = 'detail';
 
-    // TODO: cache data per copy
-
-    function loadCopy() {
-        $scope.fetchCopy(null, copyId)
-
-        }).then(function(copy) {
-            if (!copy) return;
+    function loadCopy(barcode) {
+        delete $scope.copy;
+        delete itemSvc.copy;
 
-            // TODO: FLATTEN EVERYTHING
+        return itemSvc.fetch(barcode, copyId).then(function(res) {
+            if (!res) return;
+            var copy = res.copy;
+            copyId = copy.id();
+            $scope.args.barcode = copy.barcode();
+            itemSvc.copy = copy;
 
             // locally flesh org units
             copy.circ_lib(egCore.org.get(copy.circ_lib()));
@@ -140,7 +184,9 @@ function($scope , $location , $routeParams , egCore) {
     }
 
     function loadCurrentCirc() {
-
+        delete $scope.circ;
+        delete $scope.circ_summary;
+        
         egCore.pcrud.search('circ', 
             {target_copy : copyId},
             {   flesh : 1,
@@ -176,12 +222,16 @@ function($scope , $location , $routeParams , egCore) {
 
     function loadCircCounts() {
 
+        delete $scope.circ_counts;
+        $scope.total_circs = 0;
+        $scope.total_circs_this_year = 0;
+        $scope.total_circs_prev_year = 0;
+
         egCore.pcrud.search('circbyyr', 
             {copy : copyId}, null, {atomic : true})
 
         .then(function(counts) {
             $scope.circ_counts = counts;
-            $scope.total_circs = 0;
 
             angular.forEach(counts, function(count) {
                 $scope.total_circs += Number(count.count());
@@ -207,20 +257,35 @@ function($scope , $location , $routeParams , egCore) {
     function loadPrevCirc() {
     }
 
-    loadCopy();
 
-    switch($scope.tab) {
-        case 'summary':
-            loadCurrentCirc();
-            loadCircCounts();
-            break;
+    // we don't need all data on all tabs, so fetch what's needed when needed.
+    function loadTabData() {
+        switch($scope.tab) {
+            case 'summary':
+                loadCurrentCirc();
+                loadCircCounts();
+                break;
+
+            case 'circs':
+                loadCurrentCirc();
+                loadPrevCirc();
+                break;
+        }
+    }
 
-        case 'circs':
-            loadCurrentCirc();
-            loadPrevCirc();
-            break;
+    // handle the barcode scan box, which will replace our current copy
+    $scope.context.search = function(args) {
+        // when searching by barcode, we have to wait for the 
+        // copy to arrive (to collect the copyID) before
+        // fetching the remaining tab data.
+        loadCopy(args.barcode).then(loadTabData);
+    }
 
+    $scope.context.toggleDisplay = function() {
+        $location.path('/cat/item/search');
     }
 
+    loadCopy();
+    loadTabData();
 }])
 
index e1cfd2b..1c870f0 100644 (file)
@@ -108,6 +108,13 @@ angular.module('egGridMod',
                 $scope.menuItems = [];
                 grid.addMenuItem = function(item) {
                     $scope.menuItems.push(item);
+                    var handler = item.handler;
+                    if (handler) {
+                        item.handler = function() {
+                            handler(item, item.handlerData, 
+                                grid.getSelectedItems());
+                        }
+                    }
                 }
 
                 // items needed only by the grid; remove from scope
@@ -177,6 +184,14 @@ angular.module('egGridMod',
                     if (reset) grid.offset = 0;
                     grid.collect();
                 }
+                
+                grid.dataProvider.getSelectedItems = function() {
+                    return grid.getSelectedItems();
+                }
+
+                grid.dataProvider.selectOneItem = function(index) {
+                    return grid.selectOneItem(index);
+                }
 
                 $scope.itemFieldValue = grid.dataProvider.itemFieldValue;
                 $scope.indexValue = function(item) {
@@ -908,6 +923,7 @@ angular.module('egGridMod',
 
         function GridDataProvider(args) {
             var gridData = this;
+            if (!args) args = {};
 
             gridData.sort = [];
             gridData.query = args.query;
@@ -939,7 +955,9 @@ angular.module('egGridMod',
             // redraw itself.  If reset is true, it resets the grid paging
             // to page 0.
             gridData.increment = function(reset) {
-                gridData.load(reset);
+                // if called before the grid is instantiated, 
+                // load() may not yet be defined.
+                if (gridData.load) gridData.load(reset);
             }
 
             // returns a promise whose notify() delivers items