web staff autogrid; sorting
authorBill Erickson <berick@esilibrary.com>
Mon, 24 Mar 2014 14:53:42 +0000 (10:53 -0400)
committerBill Erickson <berick@esilibrary.com>
Mon, 24 Mar 2014 14:53:42 +0000 (10:53 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/parts/t_autogrid.tt2
Open-ILS/src/templates/staff/test/t_autogrid.tt2
Open-ILS/web/js/ui/default/staff/services/autogrid.js
Open-ILS/web/js/ui/default/staff/test/app.js

index 9379c4b..4091ab4 100644 (file)
 <style>
   /* TODO: move me */
-  .eg-grid > div:nth-child(odd) {background-color: rgb(248, 248, 248);}
-  /*.eg-grid-row:hover > .eg-grid-cell {background-color: rgb(248, 248, 248)}*/
-  .eg-grid-scroll {overflow-y:scroll; height: 600px}
 
-  .eg-grid-header-row { 
-    font-weight: bold; 
+  /* odd/even row styling */
+  .eg-grid > div:nth-child(odd):not(.eg-grid-header-row):not(.eg-grid-row-selected) {
+    background-color: rgb(248, 248, 248);
   }
+
+  .eg-grid-scroll {overflow-y:scroll; height: 600px}
+
   .eg-grid-row {
-    display: flex;
     width: 100%;
-    border-left: 1px solid #ccc;
-    border-right: 1px solid #ccc;
+    display: flex;
+    border: 1px solid #ccc;
   }
 
-  .eg-grid-header-row > .eg-grid-cell {
+  .eg-grid-action-row {
+    border: none;
+    justify-content:flex-end; /* i.e. float right */
+  }
+
+  .eg-grid-header-row { 
+    font-weight: bold; 
     border-top: 1px solid #ccc;
   }
 
-  .eg-grid-action-row {
-    display:flex;
-    justify-content:flex-end;
-    width:100%;
+  .eg-grid-header-row > .eg-grid-cell {
+    border-right: 1px solid #CCC;
+    text-align: center;
   }
+
   .eg-grid-cell {
-    border-bottom: 1px solid #ccc;
-    /*border-right: 1px solid #DDD;*/
-    padding: 2px;
+    /* avoid text flowing into adjacent cells */
     overflow: hidden;
   }
 
+  /* in config display, make cells more obvious */
+  .eg-grid-as-conf .eg-grid-cell {
+    border-right: 1px solid #777;
+  }
 
   /* stock columns need fixed-width controls */
   .eg-grid-cell-1 {flex: 1}
   .eg-grid-cell-2 {flex: 2}
-  .eg-grid-row-selected > .eg-grid-cell { 
+
+  .eg-grid-row-selected {
     color: rgb(51, 51, 51);
-    /*background-color: rgb(248, 248, 248);*/
     background-color: rgb(201, 221, 225);
     border-bottom: 1px solid #888;
   }
+
+  .eg-grid-conf-cell-entry {
+    width:95%;
+    text-align:center;
+  }
+  .eg-grid-conf-cell-entry:not(:first-child) {
+    border-top:1px solid #ccc;
+  }
+
 </style>
 
 <div ng-if="showGridConf">
-  <style>
-  .eg-grid-cell {
-    border-right: 1px solid #DDD;
-  }
-  </style>
+  <!-- when the grid conf row is visible, give all cells a 
+      border so that vertical alignment is easier to visualize 
+      TODO: move this into an .eg-grid-cell-bordered class and
+      apply use ng-class on each cell instead -->
+  <style>.eg-grid-cell {border-right: 1px solid #888}</style>
 </div>
 
-<div class="eg-grid">
+<div class="eg-grid" ng-class="{'eg-grid-as-conf' : showGridConf}">
   <!-- import embedded eg-grid-field defs via no-op transclude -->
   <div ng-transclude></div>
 
-  <div class="eg-grid-action-row">
-    [% INCLUDE 'staff/parts/column_picker.tt2' listname='dataList' %]
+  <div class="eg-grid-row eg-grid-action-row">
+    [% INCLUDE 'staff/parts/column_picker.tt2' listname='list' %]
   </div>
 
+  <!-- ================== -->
+  <!-- column headers row -->
   <div class="eg-grid-row eg-grid-header-row">
     <div class="eg-grid-cell eg-grid-cell-1">[% l('#') %]</div>
     <div class="eg-grid-cell eg-grid-cell-1">
-      <input type='checkbox' ng-click="dataList.toggleSelectAll()"/>
+      <input type='checkbox' ng-click="list.toggleSelectAll()"/>
     </div>
     <div class="eg-grid-cell"
-        ng-repeat="column in dataList.allColumns"
+        ng-repeat="column in list.allColumns"
         style="flex:{{column.flexWidth}}"
-        ng-show="dataList.displayColumns[column.name]">
+        ng-show="list.displayColumns[column.name]">
       <a href="javascript:;" ng-click="sortOn(column.name)">{{column.label}}</a>
     </div>
   </div>
 
-  <div class="eg-grid-row eg-grid-header-row" ng-show="showGridConf">
+  <!-- ====================== -->
+  <!-- grid configuration row -->
+  <div class="eg-grid-row" ng-show="showGridConf">
     <div class="eg-grid-cell eg-grid-cell-2">
-      <div style="width:100%;text-align:right">[% l('Wider') %]</div>
-      <div style="width:100%;text-align:right;border-top:1px solid #ccc">
-        [% l('Narrower') %]</div>
-      <div style="width:100%;text-align:right;border-top:1px solid #ccc">
-        [% l('Sort') %]</div>
+      <div class="eg-grid-conf-cell-entry">[% l('Wider') %]</div>
+      <div class="eg-grid-conf-cell-entry">[% l('Narrower') %]</div>
+      <div class="eg-grid-conf-cell-entry">[% l('Sort') %]</div>
     </div>
     <div class="eg-grid-cell"
-      ng-repeat="column in dataList.allColumns"
+      ng-repeat="column in list.allColumns"
       style="flex:{{column.flexWidth}}"
-      ng-show="dataList.displayColumns[column.name]">
-      <div style="width:100%;text-align:center">
+      ng-show="list.displayColumns[column.name]">
+      <div class="eg-grid-conf-cell-entry">
         <a href="" title="[% l('Make column wider') %]"
           ng-click="column.flexWidth = column.flexWidth + 1">
           <span class="glyphicon glyphicon-fast-forward"></span>
         </a>
       </div>
-      <div style="width:100%;text-align:center;border-top:1px solid #ccc">
+      <div class="eg-grid-conf-cell-entry">
         <a href="" title="[% l('Make column narrower') %]"
           ng-click="column.flexWidth = column.flexWidth - 1">
           <span class="glyphicon glyphicon-fast-backward"></span>
         </a>
       </div>
-      <div style="width:100%;text-align:center;border-top:1px solid #ccc">
+      <div class="eg-grid-conf-cell-entry">
         <input type='number' ng-model="column.sortPriority" 
           title="[% l('Sort Priority') %]" style='width:2.3em'/>
       </div>
     </div>
   </div>
 
+  <!-- ============== -->
+  <!-- grid data rows -->
   <div class="eg-grid-row" 
-      ng-repeat="item in dataList.items"
+      ng-repeat="item in list.items"
       ng-class="{'eg-grid-row-selected' : itemIsSelected(item)}">
     <div class="eg-grid-cell eg-grid-cell-1" 
       ng-click="handleRowClick($event, item)">
-      {{$index + 1 + dataList.pageOffset}}
+      {{$index + 1 + list.pageOffset}}
     </div>
     <div class="eg-grid-cell eg-grid-cell-1">
       <!-- ng-click=handleRowClick here has unintended 
            consequences and is unnecessary, avoid it -->
       <input type='checkbox'  
-        ng-model="dataList.selected[dataList.indexValue(item)]"/>
+        ng-model="list.selected[list.indexValue(item)]"/>
     </div>
     <div class="eg-grid-cell"
         ng-click="handleRowClick($event, item)"
-        ng-repeat="column in dataList.allColumns"
+        ng-repeat="column in list.allColumns"
         style="flex:{{column.flexWidth}}"
-        ng-show="dataList.displayColumns[column.name]">
-      {{dataList.fieldValue(item, column.name) | egGridvalueFilter:column}}
+        ng-show="list.displayColumns[column.name]">
+      {{list.fieldValue(item, column.name) | egGridvalueFilter:column}}
     </div>
   </div>
 </div>
index d4102ec..1a8aa84 100644 (file)
@@ -4,8 +4,10 @@
   idl-class="aou"
   sort="testGridSort"
   query="testGridQuery"
+  persist-key="eg.staff.test.grid.explicit-fields"
   id-field="id">
   <!-- 
+  eg-list="testEgList"
     eg-grid-field's require closing tags; not sure why 
     you can also do <div eg-grid-tag attrs..></div>
   -->
@@ -30,7 +32,7 @@
 <h1>AutoGrid w/ Auto Fields</h1>
 
 <eg-grid
-  persist-key="staff.test.grid.auto-fields"
+  persist-key="eg.staff.test.grid.auto-fields"
   idl-class="rmsr"
   is-scroll="true"
   sort="testGridSort"
index 47db665..36d4b97 100644 (file)
@@ -16,9 +16,6 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
             // fields on the base idlClass
             autoFields : '=',
 
-            // optional, custom data retrieval function
-            dataFetcher : '=',
-
             // grid preferences will be stored / retrieved with this key
             persistKey : '@',
 
@@ -28,9 +25,20 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
 
             // field whose value is unique and may be used for item
             // reference / lookup.  This will usually be someting like
-            // "id".  This is not needed when using autoFields, since
-            // we can determine the primary key directly from the IDL.
-            idField : '@'
+            // "id".  This is not needed when using autoFields, since we
+            // can determine the primary key directly from the IDL.
+            idField : '@',
+
+            // egList is provided for us.
+            dataSource : '=',
+
+            egList : '=',
+            
+            // if true, hide the sortPriority options in the
+            // grid configuration UI.  This is primarily used by
+            // UIs where the data is ephemeral and can only be
+            // single-display-column sorted.
+            disableSortPriority : '='
         },
 
         link : function(scope, element, attrs) {     
@@ -42,20 +50,15 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
 
         templateUrl : '/eg/staff/parts/t_autogrid', // TODO: avoid abs url
 
-        controller : function($scope, $timeout, $modal, egIDL, egAuth, egNet, egList) { // TODO: reqs list
+        controller : // TODO: reqs list
+            function($scope, $timeout, $modal, egIDL, egAuth, egNet, egList) { 
             var self = this;
 
-            // If we stick w/ Bootstrap grids for display, we're 
-            // limited to (currently) 12 visible columns at a time.
-            // One of those is occupied by the shared ow count / 
-            // selector column
-            this.maxFieldCount = 24; 
-
-            // TODO
+            // TODO: dynamic
             this.limit = 20; 
             this.ofset = 0;
 
-            $scope.dataList = egList.create();
+            $scope.list = $scope.egList || egList.create();
 
             // column-header click quick sort
             $scope.sortOn = function(col_name) {
@@ -77,7 +80,7 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
             // [{name : "asc"}, {code : "desc"}, {type : "asc"}]
             this.compileSort = function() {
 
-                var sortList = $scope.dataList.allColumns.filter(
+                var sortList = $scope.list.allColumns.filter(
                     function(col) { return Number(col.sortPriority) != 0 }
                 ).sort( 
                     function(a, b) { 
@@ -113,11 +116,6 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
              */
             this.addColumn = function(fieldSpec) {
 
-                if (Object.keys($scope.dataList.displayColumns).length
-                        >= self.maxFieldCount) {
-                    fieldSpec.display = false;
-                }
-
                 var field = {
                     name : fieldSpec.name,
                     label : fieldSpec.label,
@@ -127,7 +125,7 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
                 };
                 if (!field.path) field.path = field.name;
                 field = self.absorbField(field);
-                $scope.dataList.addColumn(field);
+                $scope.list.addColumn(field);
                 field.flexWidth = 2; // TODO:
             }
 
@@ -137,7 +135,7 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
              * from the "selector" field as well.
              */
             this.compileAutoFields = function() {
-                if ($scope.dataList.allColumns.length) return;
+                if ($scope.list.allColumns.length) return;
 
                 $scope.idField = $scope.idField || 
                     egIDL.classes[$scope.idlClass].pkey;
@@ -250,10 +248,12 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
              * For non-stock grids, calls the external data fetcher
              */
             $scope.fetchData = function() {
-                $scope.dataList.resetPageData();
 
-                if (self.dataFetcher) 
-                    return self.dataFetcher();
+                // when a list is provided, data management is 
+                // handled externally.
+                if ($scope.egList) return;
+
+                $scope.list.resetPageData();
 
                 if (!$scope.query) {
                     console.error("egGrid requires a query");
@@ -268,11 +268,11 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
                 if ($scope.autoFields)
                     self.compileAutoFields();
 
-                $scope.dataList.indexField = $scope.idField;
+                $scope.list.indexField = $scope.idField;
 
                 var queryFields = {}
-                angular.forEach($scope.dataList.allColumns, function(field) {
-                    if ($scope.dataList.displayColumns[field.name])
+                angular.forEach($scope.list.allColumns, function(field) {
+                    if ($scope.list.displayColumns[field.name])
                         queryFields[field.name] = field.path || field.name;
                 });
 
@@ -286,22 +286,22 @@ angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'
                         offset : self.offset
                     }
                 ).then(null, null, function(item) {
-                    $scope.dataList.items.push(item);
+                    $scope.list.items.push(item);
                 });
             }
 
             $scope.handleRowClick = function($event, item) {
-                var index = $scope.dataList.indexValue(item);
+                var index = $scope.list.indexValue(item);
                 if ($event.ctrlKey || $event.metaKey /* mac command */) {
-                    $scope.dataList.toggleOneSelection(index);
+                    $scope.list.toggleOneSelection(index);
                 } else {
-                    $scope.dataList.selectOne(index);
+                    $scope.list.selectOne(index);
                 }
             }
 
             $scope.itemIsSelected = function(item) {
-                return $scope.dataList.selected[
-                    $scope.dataList.indexValue(item)
+                return $scope.list.selected[
+                    $scope.list.indexValue(item)
                 ];
             }
         }
index b9917c8..7e73a45 100644 (file)
@@ -19,15 +19,25 @@ angular.module('egTestApp', ['ngRoute', 'ui.bootstrap',
     function($scope, $rootScope, $timeout) {
 }])
 
-.controller('TestGridCtrl', 
-       ['$scope', 
-function($scope) {
+.controller('TestGridCtrl', function($scope, $timeout, egList) {
     var self = this;
-
     console.log('TestGridCtrl');
+
     $scope.testGridQuery = {id : {'<>' : null}};
     $scope.testGridSort = ['depth', 'parent_ou_id', 'name']
-}]);
+    $scope.testEgList = egList.create();
+    $timeout(function() { 
+        $scope.testEgList.items.push({
+            name : 'foo',
+            id : '1'
+        })
+        $scope.testEgList.items.push({
+            name : 'bar',
+            id : '2'
+        })
+
+    });
+});