[% BLOCK APP_JS %]
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/list.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/app.js"></script>
-[%
-COLUMNS = [
-{label => l('Circ ID'), name => 'id', display => 1},
-{label => l('Barcode'), name => 'target_copy.barcode' display => 1},
-{label => l('Due Date'), name => 'due_date' display => 1},
-{label => l('Checkout/Renewal Library'),
- name => 'circ_lib.shortname' display => 1},
-{label => l('Renewals Remaining'), name => 'renewal_remaining' display => 1},
-{label => l('Fines Stopped'), name => 'stop_fines' display => 1},
-{label => l('Title'),
- name => 'target_copy.call_number.record.simple_record.title', display => 1},
-]
-%]
-<!-- tell JS about our columns so they can be dynamically managed -->
-<div ng-init="
-items_out.setColumns([
-[%- FOR col IN COLUMNS %]
-{label:'[% col.label %]',name:'[% col.name %]'[% IF col.display %],display:true[% END %]}[% IF !loop.last; ','; END -%]
-[% END %]
-]);
-">
-</div>
+<eg-grid
+ idl-class="circ"
+ persist-key="eg.staff.circ.patron.items_out"
+ eg-list="items_out"
+ id-field="id">
+ <eg-grid-field name="id"></eg-grid-field>
+ <eg-grid-field
+ name="target_copy.barcode"
+ path="target_copy.barcode"
+ flex="3"
+ label="[% l('Barcode') %]">
+ </eg-grid-field>
+ <eg-grid-field
+ name="due_date"
+ label="[% l('Due Date') %]">
+ </eg-grid-field>
+ <eg-grid-field
+ name="circ_lib.shortname"
+ path="circ_lib.shortname"
+ label="[% l('Circ Lib') %]">
+ </eg-grid-field>
+ <eg-grid-field name="renewal_remaining"></eg-grid-field>
+ <eg-grid-field name="stop_fines"></eg-grid-field>
+ <eg-grid-field
+ name="title"
+ flex="5"
+ label="[% l('Title') %]"
+ path="target_copy.call_number.record.simple_record.title">
+ </eg-grid-field>
+</eg-grid>
-<div class="row" ng-show="!loading && !items_out.count()">
- <div class="col-md-10 col-md-offset-1">
- <div class="alert alert-info">[% l('No Items To Display') %]</div>
- </div>
-</div>
+<!-- TODO: row-level styling, alerts, etc. (e.g. overdue) -->
+
+<!--
+<tr ng-repeat="circ in items_out.items | reverse track by $index"
+ ng-click="onRowClick($event, circ)"
+ ng-class="{
+ selected : items_out.selected[circ.id()],
+ 'patron-summary-alert' : circIsOverdue(circ)
+ }">
+-->
-<div class="row" ng-show="items_out.count()">
- <div class="col-md-12">
- <table class="list table table-hover table-condensed">
- <thead>
- <tr>
- <th>#</th>
- <th><a href='' ng-click="items_out.toggleSelectAll()">✓</a></th>
- <th ng-repeat="col in items_out.allColumns"
- ng-show="items_out.displayColumns[col.name]">
- {{col.label}}
- </th>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="circ in items_out.items | reverse track by $index"
- ng-click="onRowClick($event, circ)"
- ng-class="{
- selected : items_out.selected[circ.id()],
- 'patron-summary-alert' : circIsOverdue(circ)
- }">
- <td>{{$index + 1}}</td>
- <td><span ng-if="items_out.selected[circ.id()]">✓</span>
- <td ng-repeat="col in items_out.allColumns"
- ng-show="items_out.displayColumns[col.name]">
- {{items_out.fieldValue(circ, col.name)}}
- </td>
- </tr>
- </tbody>
- </table>
- </div>
-</div>
<!--
Actions row.
- This sits right above the grid and contains the column picker, etc.
+ This sits above the grid and contains the column picker, etc.
-->
<div class="eg-grid-row eg-grid-action-row">
</div>
</div>
+<div ng-show="list.items.length == 0"
+ class="alert alert-info">[% l('No Items To Display') %]</div>
+
<!-- Grid -->
-<div class="eg-grid"
- ng-class="{'eg-grid-as-conf' : showGridConf,'eg-grid-scroll' : isScroll}">
+<div class="eg-grid" ng-show="list.items.length > 0"
+ ng-class="{'eg-grid-as-conf' : showGridConf, 'eg-grid-scroll' : isScroll}">
<!-- import embedded eg-grid-field defs via no-op transclude -->
<div ng-transclude></div>
ng-repeat="column in list.allColumns"
style="flex:{{column.flex}}"
ng-show="list.displayColumns[column.name]">
- {{list.fieldValue(item, column.name) | egGridvalueFilter:column}}
+ {{list.fieldValue(item, column.path) | egGridvalueFilter:column}}
</div>
</div>
</div>
[% BLOCK APP_JS %]
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/list.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/autogrid.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/test/app.js"></script>
[% END %]
*/
angular.module('egPatronApp', ['ngRoute', 'ui.bootstrap',
- 'egCoreMod', 'egUiMod', 'egListMod', 'egUserMod'])
+ 'egCoreMod', 'egUiMod', 'egListMod', 'egGridMod', 'egUserMod'])
.config(function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
+++ /dev/null
-
-angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'])
-
-.directive('egGrid', function() {
- return {
- restrict : 'AE',
- transclude : true,
- scope : {
- // IDL class hint (e.g. "aou")
- idlClass : '@',
-
- // points to a structure in the calling scope which defines
- // a PCRUD-compliant query.
- query : '=',
-
- // if true, grid columns are derived from all non-virtual
- // fields on the base idlClass
- autoFields : '@',
-
- // grid preferences will be stored / retrieved with this key
- persistKey : '@',
-
- // if true, use the scroll CSS to force a vertical height
- // and scroll bar
- isScroll : '@',
-
- // 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 : '@',
-
- // egList containting our tabular data is provided for us
- // and managed externally.
- 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) {
- // link() is called after page compilation, which means our
- // eg-grid-field's have been parsed and loaded. Now it's
- // safe to perform our initial page load.
- scope.fetchData();
- },
-
- templateUrl : '/eg/staff/parts/t_autogrid', // TODO: avoid abs url
-
- controller : // TODO: reqs list
- function($scope, $timeout, $modal, egIDL, egAuth, egNet, egList) {
- var self = this;
-
- // TODO: dynamic
- this.limit = 20;
- this.ofset = 0;
-
- $scope.list = $scope.egList || egList.create();
-
- $scope.$watch('isScroll', function(newValue, oldValue) {
- console.log('isScroll changed to ' + newValue) });
-
- // column-header click quick sort
- $scope.sortOn = function(col_name) {
- if ($scope.sort && $scope.sort.length &&
- $scope.sort[0] == col_name) {
- var blob = {};
- blob[col_name] = 'desc';
- $scope.sort = [blob];
- } else {
- $scope.sort = [col_name];
- }
- $scope.fetchData();
- }
-
- // maps numeric sort priority to flattener sort blob
- // e.g.
- // name = 1; code = -2; type = 3
- // compiles to:
- // [{name : "asc"}, {code : "desc"}, {type : "asc"}]
- this.compileSort = function() {
-
- var sortList = $scope.list.allColumns.filter(
- function(col) { return Number(col.sortPriority) != 0 }
- ).sort(
- function(a, b) {
- if (Math.abs(a.sortPriority) < Math.abs(b.sortPriority))
- return -1;
- return 1;
- }
- );
-
- $scope.sort = sortList.map(function(col) {
- var blob = {};
- blob[col.name] = col.sortPriority < 0 ? 'desc' : 'asc';
- return blob;
- });
- },
-
- $scope.modifyColumnFlex = function(column, val) {
- column.flex += val;
- // prevent flex:0; use hiding instead
- if (column.flex < 1)
- column.flex = 1;
- }
-
- $scope.toggleGridConf = function() {
- if ($scope.showGridConf) {
- $scope.showGridConf = false;
- self.compileSort();
-
- // config done;
- // reload data in case sort priorities changed.
- $scope.fetchData();
- } else {
- $scope.showGridConf = true;
- }
- }
-
- /**
- * Adds a column from an eg-grid-field or directly from
- * an IDL field via compileAutoFields.
- */
- this.addColumn = function(fieldSpec) {
-
- var field = {
- name : fieldSpec.name,
- label : fieldSpec.label,
- path : fieldSpec.path,
- flex : fieldSpec.flex,
- datatype : fieldSpec.datatype,
- display : (fieldSpec.display !== false)
- };
- if (!field.path) field.path = field.name;
- field = self.absorbField(field);
- $scope.list.addColumn(field);
- }
-
- /**
- * Caller wants to display all fields for the selected IDL class
- * Find the fields and, when a field is a link, fetch the label
- * from the "selector" field as well.
- */
- this.compileAutoFields = function() {
- if ($scope.list.allColumns.length) return;
-
- $scope.idField = $scope.idField ||
- egIDL.classes[$scope.idlClass].pkey;
-
- angular.forEach(
- egIDL.classes[$scope.idlClass].fields.sort(
- function(a, b) { return a.name < b.name ? -1 : 1 }),
- function(field) {
- if (field.virtual) return;
- if (field.datatype == 'link' || field.datatype == 'org_unit') {
- // if the field is a link and the linked class has a
- // "selector" field specified, use the selector field
- // as the display field for the grid.
- // flattener will take care of the fleshing.
- if (field['class']) {
- var selectorField = egIDL.classes[field['class']].fields
- .filter(function(f) { return Boolean(f.selector) })[0];
- if (selectorField) {
- field.path = field.name + '.' + selectorField.selector;
- }
- }
- }
- self.addColumn(field);
- }
- );
- }
-
- // given a base class and a dotpath, find the IDL field
- this.getIDLFieldFromPath = function(idlClass, path) {
- var class_obj = egIDL.classes[idlClass];
- var path_parts = path.split(/\./);
-
- // note: use of for() is intentional for early exit
- var idl_field;
- for (var path_idx in path_parts) {
- var part = path_parts[path_idx];
-
- // find the field object matching the path component
- for (var field_idx in class_obj.fields) {
- if (class_obj.fields[field_idx].name == part) {
- idl_field = class_obj.fields[field_idx];
- break;
- }
- }
-
- // unless we're at the end of the list, this field should
- // link to another class.
-
- if (idl_field && idl_field['class'] && (
- idl_field.datatype == 'link' ||
- idl_field.datatype == 'org_unit')) {
- class_obj = egIDL.classes[idl_field['class']];
- } else {
- if (path_idx < (path_parts.length - 1)) {
- // we ran out of classes to hop through before
- // we ran out of path components
- console.error("egGrid: invalid IDL path: " + path);
- }
- }
- }
-
- return idl_field;
- }
-
- /**
- * Looks for the matching IDL field to extract the label
- * and datattype as needed.
- * Creates a local copy of the field for our internal
- * machinations.
- */
- this.absorbField = function(field) {
-
- // start by cloning the field so we can flesh it out.
- // note: aungular.copy won't work, because 'field' may
- // be a $scope object.
- var new_field = {
- name : field.name,
- label : field.label,
- path : field.path || field.name,
- flex : Number(field.flex) || 2,
- display : (field.display === false) ? false : true
- };
-
- // lookup the matching IDL field
- var idl_field = field.datatype ? field :
- self.getIDLFieldFromPath($scope.idlClass, field.path);
-
- // No matching IDL field. Caller has gone commando.
- // Nothing left to do.
- if (!idl_field) return new_field;
-
- new_field.datatype = idl_field.datatype;
-
- if (field.label) {
- // caller-provided label
- new_field.label = field.label;
- } else {
- if (idl_field.label) {
- new_field.label = idl_field.label;
- } else {
- new_field.label = new_field.name;
- }
- }
-
- return new_field;
- }
-
- /**
- * For stock grids, makes a flattened_search call to retrieve
- * the requested values.
- * For non-stock grids, calls the external data fetcher
- */
- $scope.fetchData = function() {
-
- // 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");
- return;
- }
-
- if (!$scope.idlClass) {
- console.error("egGrid requires an idlClass");
- return;
- }
-
- if ($scope.autoFields)
- self.compileAutoFields();
-
- $scope.list.indexField = $scope.idField;
-
- var queryFields = {}
- angular.forEach($scope.list.allColumns, function(field) {
- if ($scope.list.displayColumns[field.name])
- queryFields[field.name] = field.path || field.name;
- });
-
- egNet.request(
- 'open-ils.fielder',
- 'open-ils.fielder.flattened_search',
- egAuth.token(), $scope.idlClass, queryFields,
- $scope.query,
- { sort : $scope.sort,
- limit : self.limit,
- offset : self.offset
- }
- ).then(null, null, function(item) {
- $scope.list.items.push(item);
- });
- }
-
- $scope.handleRowClick = function($event, item) {
- var index = $scope.list.indexValue(item);
- if ($event.ctrlKey || $event.metaKey /* mac command */) {
- $scope.list.toggleOneSelection(index);
- } else {
- $scope.list.selectOne(index);
- }
- }
-
- $scope.itemIsSelected = function(item) {
- return $scope.list.selected[
- $scope.list.indexValue(item)
- ];
- }
- }
- };
-})
-
-/**
- * eg-grid-field : used for collecting custom field data from the templates.
- * This directive does not direct display, it just passes data up to the
- * parent grid.
- */
-.directive('egGridField', function() {
- return {
- require : '^egGrid',
- restrict : 'AE',
- transclude : true,
- scope : {
- name : '@', // required; unique name
- path : '@', // optional; flesh path
- label : '@', // optional; display label
- flex : '@', // optoinal; default flex width
- },
- template : '<div></div>', // NOOP template
- link : function(scope, element, attrs, egGridCtrl) {
- egGridCtrl.addColumn(scope);
- }
- };
-})
-
-/**
- * Translates bare IDL object values into display values.
- * 1. Passes dates through the angular date filter
- * 2. Translates bools to Booleans so the browser can display translated
- * value. (Though we could manually translate instead..)
- * Others likely to follow...
- */
-.filter('egGridvalueFilter', ['$filter', function($filter) {
- return function(value, item) {
- switch(item.datatype) {
- case 'bool':
- // Browser will translate true/false for us
- return Boolean(value == 't');
- case 'timestamp':
- // canned angular date filter FTW
- return $filter('date')(value);
- default:
- return value;
- }
- }
-}]);
-
-
--- /dev/null
+
+angular.module('egGridMod', ['egCoreMod', 'egListMod', 'egUiMod', 'ui.bootstrap'])
+
+.directive('egGrid', function() {
+ return {
+ restrict : 'AE',
+ transclude : true,
+ scope : {
+ // IDL class hint (e.g. "aou")
+ idlClass : '@',
+
+ // points to a structure in the calling scope which defines
+ // a PCRUD-compliant query.
+ query : '=',
+
+ // if true, grid columns are derived from all non-virtual
+ // fields on the base idlClass
+ autoFields : '@',
+
+ // grid preferences will be stored / retrieved with this key
+ persistKey : '@',
+
+ // if true, use the scroll CSS to force a vertical height
+ // and scroll bar
+ isScroll : '@',
+
+ // 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 : '@',
+
+ // egList containting our tabular data is provided for us
+ // and managed externally.
+ 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) {
+ // link() is called after page compilation, which means our
+ // eg-grid-field's have been parsed and loaded. Now it's
+ // safe to perform our initial page load.
+ scope.fetchData();
+ },
+
+ templateUrl : '/eg/staff/parts/t_autogrid', // TODO: avoid abs url
+
+ controller : // TODO: reqs list
+ function($scope, $timeout, $modal, egIDL, egAuth, egNet, egList) {
+ var self = this;
+
+ // TODO: dynamic
+ this.limit = 20;
+ this.ofset = 0;
+
+ $scope.list = $scope.egList || egList.create();
+
+ $scope.$watch('isScroll', function(newValue, oldValue) {
+ console.log('isScroll changed to ' + newValue) });
+
+ // column-header click quick sort
+ $scope.sortOn = function(col_name) {
+ if ($scope.sort && $scope.sort.length &&
+ $scope.sort[0] == col_name) {
+ var blob = {};
+ blob[col_name] = 'desc';
+ $scope.sort = [blob];
+ } else {
+ $scope.sort = [col_name];
+ }
+ $scope.fetchData();
+ }
+
+ // maps numeric sort priority to flattener sort blob
+ // e.g.
+ // name = 1; code = -2; type = 3
+ // compiles to:
+ // [{name : "asc"}, {code : "desc"}, {type : "asc"}]
+ this.compileSort = function() {
+
+ var sortList = $scope.list.allColumns.filter(
+ function(col) { return Number(col.sortPriority) != 0 }
+ ).sort(
+ function(a, b) {
+ if (Math.abs(a.sortPriority) < Math.abs(b.sortPriority))
+ return -1;
+ return 1;
+ }
+ );
+
+ $scope.sort = sortList.map(function(col) {
+ var blob = {};
+ blob[col.name] = col.sortPriority < 0 ? 'desc' : 'asc';
+ return blob;
+ });
+ },
+
+ $scope.modifyColumnFlex = function(column, val) {
+ column.flex += val;
+ // prevent flex:0; use hiding instead
+ if (column.flex < 1)
+ column.flex = 1;
+ }
+
+ $scope.toggleGridConf = function() {
+ if ($scope.showGridConf) {
+ $scope.showGridConf = false;
+ self.compileSort();
+
+ // config done;
+ // reload data in case sort priorities changed.
+ $scope.fetchData();
+ } else {
+ $scope.showGridConf = true;
+ }
+ }
+
+ /**
+ * Adds a column from an eg-grid-field or directly from
+ * an IDL field via compileAutoFields.
+ */
+ this.addColumn = function(fieldSpec) {
+
+ var field = {
+ name : fieldSpec.name,
+ label : fieldSpec.label,
+ path : fieldSpec.path,
+ flex : fieldSpec.flex,
+ datatype : fieldSpec.datatype,
+ display : (fieldSpec.display !== false)
+ };
+ if (!field.path) field.path = field.name;
+ if (!field.name) field.name = field.path;
+ field = self.absorbField(field);
+ $scope.list.addColumn(field);
+ }
+
+ /**
+ * Caller wants to display all fields for the selected IDL class
+ * Find the fields and, when a field is a link, fetch the label
+ * from the "selector" field as well.
+ */
+ this.compileAutoFields = function() {
+ if ($scope.list.allColumns.length) return;
+
+ $scope.idField = $scope.idField ||
+ egIDL.classes[$scope.idlClass].pkey;
+
+ angular.forEach(
+ egIDL.classes[$scope.idlClass].fields.sort(
+ function(a, b) { return a.name < b.name ? -1 : 1 }),
+ function(field) {
+ if (field.virtual) return;
+ if (field.datatype == 'link' || field.datatype == 'org_unit') {
+ // if the field is a link and the linked class has a
+ // "selector" field specified, use the selector field
+ // as the display field for the grid.
+ // flattener will take care of the fleshing.
+ if (field['class']) {
+ var selectorField = egIDL.classes[field['class']].fields
+ .filter(function(f) { return Boolean(f.selector) })[0];
+ if (selectorField) {
+ field.path = field.name + '.' + selectorField.selector;
+ }
+ }
+ }
+ self.addColumn(field);
+ }
+ );
+ }
+
+ // given a base class and a dotpath, find the IDL field
+ this.getIDLFieldFromPath = function(idlClass, path) {
+ var class_obj = egIDL.classes[idlClass];
+ var path_parts = path.split(/\./);
+
+ // note: use of for() is intentional for early exit
+ var idl_field;
+ for (var path_idx in path_parts) {
+ var part = path_parts[path_idx];
+
+ // find the field object matching the path component
+ for (var field_idx in class_obj.fields) {
+ if (class_obj.fields[field_idx].name == part) {
+ idl_field = class_obj.fields[field_idx];
+ break;
+ }
+ }
+
+ // unless we're at the end of the list, this field should
+ // link to another class.
+
+ if (idl_field && idl_field['class'] && (
+ idl_field.datatype == 'link' ||
+ idl_field.datatype == 'org_unit')) {
+ class_obj = egIDL.classes[idl_field['class']];
+ } else {
+ if (path_idx < (path_parts.length - 1)) {
+ // we ran out of classes to hop through before
+ // we ran out of path components
+ console.error("egGrid: invalid IDL path: " + path);
+ }
+ }
+ }
+
+ return idl_field;
+ }
+
+ /**
+ * Looks for the matching IDL field to extract the label
+ * and datattype as needed.
+ * Creates a local copy of the field for our internal
+ * machinations.
+ */
+ this.absorbField = function(field) {
+
+ // start by cloning the field so we can flesh it out.
+ // note: aungular.copy won't work, because 'field' may
+ // be a $scope object.
+ var new_field = {
+ name : field.name,
+ label : field.label,
+ path : field.path || field.name,
+ flex : Number(field.flex) || 2,
+ display : (field.display === false) ? false : true
+ };
+
+ // lookup the matching IDL field
+ var idl_field = field.datatype ? field :
+ self.getIDLFieldFromPath($scope.idlClass, field.path);
+
+ // No matching IDL field. Caller has gone commando.
+ // Nothing left to do.
+ if (!idl_field) return new_field;
+
+ new_field.datatype = idl_field.datatype;
+
+ if (field.label) {
+ // caller-provided label
+ new_field.label = field.label;
+ } else {
+ if (idl_field.label) {
+ new_field.label = idl_field.label;
+ } else {
+ new_field.label = new_field.name;
+ }
+ }
+
+ return new_field;
+ }
+
+ /**
+ * For stock grids, makes a flattened_search call to retrieve
+ * the requested values.
+ * For non-stock grids, calls the external data fetcher
+ */
+ $scope.fetchData = function() {
+
+ // 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");
+ return;
+ }
+
+ if (!$scope.idlClass) {
+ console.error("egGrid requires an idlClass");
+ return;
+ }
+
+ if ($scope.autoFields)
+ self.compileAutoFields();
+
+ $scope.list.indexField = $scope.idField;
+
+ var queryFields = {}
+ angular.forEach($scope.list.allColumns, function(field) {
+ if ($scope.list.displayColumns[field.name])
+ queryFields[field.name] = field.path || field.name;
+ });
+
+ egNet.request(
+ 'open-ils.fielder',
+ 'open-ils.fielder.flattened_search',
+ egAuth.token(), $scope.idlClass, queryFields,
+ $scope.query,
+ { sort : $scope.sort,
+ limit : self.limit,
+ offset : self.offset
+ }
+ ).then(null, null, function(item) {
+ $scope.list.items.push(item);
+ });
+ }
+
+ $scope.handleRowClick = function($event, item) {
+ var index = $scope.list.indexValue(item);
+ if ($event.ctrlKey || $event.metaKey /* mac command */) {
+ $scope.list.toggleOneSelection(index);
+ } else {
+ $scope.list.selectOne(index);
+ }
+ }
+
+ $scope.itemIsSelected = function(item) {
+ return $scope.list.selected[
+ $scope.list.indexValue(item)
+ ];
+ }
+ }
+ };
+})
+
+/**
+ * eg-grid-field : used for collecting custom field data from the templates.
+ * This directive does not direct display, it just passes data up to the
+ * parent grid.
+ */
+.directive('egGridField', function() {
+ return {
+ require : '^egGrid',
+ restrict : 'AE',
+ transclude : true,
+ scope : {
+ name : '@', // required; unique name
+ path : '@', // optional; flesh path
+ label : '@', // optional; display label
+ flex : '@', // optoinal; default flex width
+ },
+ template : '<div></div>', // NOOP template
+ link : function(scope, element, attrs, egGridCtrl) {
+ egGridCtrl.addColumn(scope);
+ }
+ };
+})
+
+/**
+ * Translates bare IDL object values into display values.
+ * 1. Passes dates through the angular date filter
+ * 2. Translates bools to Booleans so the browser can display translated
+ * value. (Though we could manually translate instead..)
+ * Others likely to follow...
+ */
+.filter('egGridvalueFilter', ['$filter', function($filter) {
+ return function(value, item) {
+ switch(item.datatype) {
+ case 'bool':
+ // Browser will translate true/false for us
+ return Boolean(value == 't');
+ case 'timestamp':
+ // canned angular date filter FTW
+ return $filter('date')(value);
+ default:
+ return value;
+ }
+ }
+}]);
+
+
this.selected = {};
this.indexValue = function(item) {
+ if (!item) return null;
if (this.indexFieldAsFunction) {
return item[this.indexField]();
} else {