[open-ils-commits] [GIT] Evergreen ILS branch master updated. 67e85c40d41c46fd123eed51729f966d9336549f

Evergreen Git git at git.evergreen-ils.org
Fri May 24 14:01:15 EDT 2019


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  67e85c40d41c46fd123eed51729f966d9336549f (commit)
      from  fdb1b355d501c9e3043cab23d45e920fb51e42dd (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 67e85c40d41c46fd123eed51729f966d9336549f
Author: Bill Erickson <berickxx at gmail.com>
Date:   Tue Mar 5 17:07:21 2019 -0500

    LP1816480 Angular grid ARIA improvements
    
    Various navigation and "role" improvements to the Angular grid:
    
    * Apply "grid", "row", "columnheader", and "gridcell" role attributes.
    * Page-Down goes to next page
    * Page-Up goes to previous page
    * Shift-UpArrow extends selection one row up (spanning pages).
    * Shift-DownArrow extends selection one row down (spanning pages).
    * Shift-Arrow controls support reverse navigation for back-tracking to
      de-select certain rows.
    ** E.g. shift-up 3 rows then shift-down 1 will leave 2 rows selected.
    * Control-A now selects all rows in the page.
    ** For consistency with the select-all checkbox, only rows in the
       current page are selected.
    ** Note we could add an option to extend the selection to all rows,
       but it would require pre-fetching all of the data, simimar to
       how grid printing pre-fetches.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Jane Sandberg <sandbej at linnbenton.edu>

diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-body.component.html b/Open-ILS/src/eg2/src/app/share/grid/grid-body.component.html
index 8d495aa84d..a9f35aaaa5 100644
--- a/Open-ILS/src/eg2/src/app/share/grid/grid-body.component.html
+++ b/Open-ILS/src/eg2/src/app/share/grid/grid-body.component.html
@@ -2,7 +2,7 @@
   tabindex=1 so the grid body can capture keyboard events.
 -->
 <div class="eg-grid-body" tabindex="1" (keydown)="onGridKeyDown($event)">
-  <div class="eg-grid-row eg-grid-body-row {{context.rowClassCallback(row)}}"
+  <div role="row" class="eg-grid-row eg-grid-body-row {{context.rowClassCallback(row)}}"
     [ngClass]="{'selected': context.rowSelector.contains(context.getRowIndex(row))}"
     *ngFor="let row of context.dataSource.getPageOfRows(context.pager); let idx = index">
 
@@ -27,7 +27,8 @@
         </ng-container>
       </ng-container>
     </div>
-    <div class="eg-grid-cell eg-grid-body-cell" [ngStyle]="{flex:col.flex}"
+    <div role="gridcell" class="eg-grid-cell eg-grid-body-cell"
+      [ngStyle]="{flex:col.flex}"
       [ngClass]="{'eg-grid-cell-overflow': context.overflowCells}"
       (dblclick)="onRowDblClick(row)"
       (click)="onRowClick($event, row, idx)"
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-body.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid-body.component.ts
index 15aa2b7038..9c9b19041c 100644
--- a/Open-ILS/src/eg2/src/app/share/grid/grid-body.component.ts
+++ b/Open-ILS/src/eg2/src/app/share/grid/grid-body.component.ts
@@ -20,23 +20,45 @@ export class GridBodyComponent implements OnInit {
     onGridKeyDown(evt: KeyboardEvent) {
         switch (evt.key) {
             case 'ArrowUp':
-                this.context.selectPreviousRow();
+                if (evt.shiftKey) {
+                    // Extend selection up one row
+                    this.context.selectMultiRowsPrevious();
+                } else {
+                    this.context.selectPreviousRow();
+                }
                 evt.stopPropagation();
                 break;
             case 'ArrowDown':
-                this.context.selectNextRow();
+                if (evt.shiftKey) {
+                    // Extend selection down one row
+                    this.context.selectMultiRowsNext();
+                } else {
+                    this.context.selectNextRow();
+                }
                 evt.stopPropagation();
                 break;
             case 'ArrowLeft':
+            case 'PageUp':
                 this.context.toPrevPage()
                 .then(ok => this.context.selectFirstRow(), err => {});
                 evt.stopPropagation();
                 break;
             case 'ArrowRight':
+            case 'PageDown':
                 this.context.toNextPage()
                 .then(ok => this.context.selectFirstRow(), err => {});
                 evt.stopPropagation();
                 break;
+            case 'a':
+                // control-a means select all visible rows.
+                // For consistency, select all rows in the current page only.
+                if (evt.ctrlKey) {
+                    this.context.rowSelector.clear();
+                    this.context.selectRowsInPage();
+                    evt.preventDefault();
+                }
+                break;
+
             case 'Enter':
                 if (this.context.lastSelectedIndex) {
                     this.grid.onRowActivate.emit(
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html b/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html
index 98a6fbf365..96811a32aa 100644
--- a/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html
+++ b/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html
@@ -1,26 +1,31 @@
 
-<div class="eg-grid-row eg-grid-header-row">
+<div row="row" class="eg-grid-row eg-grid-header-row">
   <ng-container *ngIf="!context.disableSelect">
-    <div class="eg-grid-cell eg-grid-header-cell eg-grid-checkbox-cell eg-grid-cell-skinny">
-      <input type='checkbox' (click)="handleBatchSelect($event)">
+    <div role="columnheader"
+      class="eg-grid-cell eg-grid-header-cell eg-grid-checkbox-cell eg-grid-cell-skinny">
+      <input type='checkbox' (click)="handleBatchSelect($event)"
+        [(ngModel)]="batchRowCheckbox">
     </div>
   </ng-container>
-  <div class="eg-grid-cell eg-grid-header-cell eg-grid-number-cell eg-grid-cell-skinny">
+  <div role="columnheader"
+    class="eg-grid-cell eg-grid-header-cell eg-grid-number-cell eg-grid-cell-skinny">
     <span i18n="number|Row Number Header">#</span>
   </div>
-  <div *ngIf="context.rowFlairIsEnabled" 
+  <div *ngIf="context.rowFlairIsEnabled"
+    role="columnheader"
     class="eg-grid-cell eg-grid-header-cell eg-grid-flair-cell">
     <span class="material-icons">notifications</span>
   </div>
-  <div *ngFor="let col of context.columnSet.displayColumns()" 
-    draggable="true" 
+  <div role="columnheader"
+    *ngFor="let col of context.columnSet.displayColumns()"
+    draggable="true"
     (dragstart)="dragColumn = col"
     (drop)="onColumnDrop(col)"
     (dragover)="onColumnDragEnter($event, col)"
     (dragleave)="onColumnDragLeave($event, col)"
     [ngClass]="{'dragover' : col.isDragTarget}"
     class="eg-grid-cell eg-grid-header-cell" [ngStyle]="{flex:col.flex}">
-    <a class="sortable label-with-material-icon" *ngIf="col.isSortable" 
+    <a class="sortable label-with-material-icon" *ngIf="col.isSortable"
       (click)="sortOneColumn(col)">
       <span class="eg-grid-header-cell-sort-label">{{col.label}}</span>
       <span class="material-icons eg-grid-header-cell-sort-arrow"
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts
index 0010a45f38..591fc66c2b 100644
--- a/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts
+++ b/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts
@@ -13,9 +13,15 @@ export class GridHeaderComponent implements OnInit {
 
     dragColumn: GridColumn;
 
+    batchRowCheckbox: boolean;
+
     constructor() {}
 
-    ngOnInit() {}
+    ngOnInit() {
+        this.context.selectRowsInPageEmitter.subscribe(
+            () => this.batchRowCheckbox = true
+        );
+    }
 
     onColumnDragEnter($event: any, col: any) {
         if (this.dragColumn && this.dragColumn.name !== col.name) {
@@ -71,9 +77,7 @@ export class GridHeaderComponent implements OnInit {
     }
 
     selectAll() {
-        const rows = this.context.dataSource.getPageOfRows(this.context.pager);
-        const indexes = rows.map(r => this.context.getRowIndex(r));
-        this.context.rowSelector.select(indexes);
+        this.context.selectRowsInPage();
     }
 
     allRowsAreSelected(): boolean {
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html
index 5dd307f4f9..af223fefdf 100644
--- a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html
+++ b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html
@@ -19,7 +19,7 @@
         <label class="form-check-label">
           <input class="form-check-input" type="checkbox"
             [(ngModel)]="cb.isChecked"
-            (click)="cb.onChange.emit($event.target.checked)"/>
+            (click)="cb.onChange($event.target.checked)"/>
             {{cb.label}}
         </label>
       </ng-container>
@@ -29,6 +29,9 @@
   <!-- push everything else to the right -->
   <div class="flex-1"></div>
 
+  <div class="font-sm font-italic d-flex flex-column-reverse mr-2">
+    {{gridContext.rowSelector.selected().length}} selected
+  </div>
   <div ngbDropdown class="mr-1" placement="bottom-right">
     <button ngbDropdownToggle [disabled]="!gridContext.toolbarActions.length"
         class="btn btn-outline-dark no-dropdown-caret">
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.component.html b/Open-ILS/src/eg2/src/app/share/grid/grid.component.html
index a98e17afaf..77ea0e6fb1 100644
--- a/Open-ILS/src/eg2/src/app/share/grid/grid.component.html
+++ b/Open-ILS/src/eg2/src/app/share/grid/grid.component.html
@@ -1,8 +1,8 @@
 
-<div class="eg-grid">
+<div class="eg-grid" role="grid">
 
   <eg-grid-toolbar
-    [gridContext]="context" 
+    [gridContext]="context"
     [gridPrinter]="gridPrinter"
     [colWidthConfig]="colWidthConfig">
   </eg-grid-toolbar>
@@ -11,7 +11,7 @@
 
   <eg-grid-column-width #colWidthConfig [gridContext]="context">
   </eg-grid-column-width>
-  
+
   <eg-grid-print #gridPrinter [gridContext]="context">
   </eg-grid-print>
 
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.ts b/Open-ILS/src/eg2/src/app/share/grid/grid.ts
index 7c30438ccc..fbc020895d 100644
--- a/Open-ILS/src/eg2/src/app/share/grid/grid.ts
+++ b/Open-ILS/src/eg2/src/app/share/grid/grid.ts
@@ -442,6 +442,10 @@ export class GridContext {
     overflowCells: boolean;
     showLinkSelectors: boolean;
 
+    // Allow calling code to know when the select-all-rows-in-page
+    // action has occurred.
+    selectRowsInPageEmitter: EventEmitter<void>;
+
     // Services injected by our grid component
     idl: IdlService;
     org: OrgService;
@@ -467,6 +471,7 @@ export class GridContext {
     }
 
     init() {
+        this.selectRowsInPageEmitter = new EventEmitter<void>();
         this.columnSet = new GridColumnSet(this.idl, this.idlClass);
         this.columnSet.isSortable = this.isSortable === true;
         this.columnSet.isMultiSortable = this.isMultiSortable === true;
@@ -731,6 +736,12 @@ export class GridContext {
         this.lastSelectedIndex = index;
     }
 
+    selectMultipleRows(indexes: any[]) {
+        this.rowSelector.clear();
+        this.rowSelector.select(indexes);
+        this.lastSelectedIndex = indexes[indexes.length - 1];
+    }
+
     // selects or deselects an item, without affecting the others.
     // returns true if the item is selected; false if de-selected.
     toggleSelectOneRow(index: any) {
@@ -770,12 +781,84 @@ export class GridContext {
         }
     }
 
+    // shift-up-arrow
+    // Select the previous row in addition to any currently selected row.
+    // However, if the previous row is already selected, assume the user
+    // has reversed direction and now wants to de-select the last selected row.
+    selectMultiRowsPrevious() {
+        if (!this.lastSelectedIndex) { return; }
+        const pos = this.getRowPosition(this.lastSelectedIndex);
+        const selectedIndexes = this.rowSelector.selected();
+
+        const promise = // load the previous page of data if needed
+            (pos === this.pager.offset) ? this.toPrevPage() : Promise.resolve();
+
+        promise.then(
+            ok => {
+                const row = this.dataSource.data[pos - 1];
+                const newIndex = this.getRowIndex(row);
+                if (selectedIndexes.filter(i => i === newIndex).length > 0) {
+                    // Prev row is already selected.  User is reversing direction.
+                    this.rowSelector.deselect(this.lastSelectedIndex);
+                    this.lastSelectedIndex = newIndex;
+                } else {
+                    this.selectMultipleRows(selectedIndexes.concat(newIndex));
+                }
+            },
+            err => {}
+        );
+    }
+
+    // shift-down-arrow
+    // Select the next row in addition to any currently selected row.
+    // However, if the next row is already selected, assume the user
+    // has reversed direction and wants to de-select the last selected row.
+    selectMultiRowsNext() {
+        if (!this.lastSelectedIndex) { return; }
+        const pos = this.getRowPosition(this.lastSelectedIndex);
+        const selectedIndexes = this.rowSelector.selected();
+
+        const promise = // load the next page of data if needed
+            (pos === (this.pager.offset + this.pager.limit - 1)) ?
+            this.toNextPage() : Promise.resolve();
+
+        promise.then(
+            ok => {
+                const row = this.dataSource.data[pos + 1];
+                const newIndex = this.getRowIndex(row);
+                if (selectedIndexes.filter(i => i === newIndex).length > 0) {
+                    // Next row is already selected.  User is reversing direction.
+                    this.rowSelector.deselect(this.lastSelectedIndex);
+                    this.lastSelectedIndex = newIndex;
+                } else {
+                    this.selectMultipleRows(selectedIndexes.concat(newIndex));
+                }
+            },
+            err => {}
+        );
+    }
+
+    getFirstRowInPage(): any {
+        return this.dataSource.data[this.pager.offset];
+    }
+
+    getLastRowInPage(): any {
+        return this.dataSource.data[this.pager.offset + this.pager.limit - 1];
+    }
+
     selectFirstRow() {
-        this.selectRowByPos(this.pager.offset);
+        this.selectOneRow(this.getRowIndex(this.getFirstRowInPage()));
     }
 
     selectLastRow() {
-        this.selectRowByPos(this.pager.offset + this.pager.limit - 1);
+        this.selectOneRow(this.getRowIndex(this.getLastRowInPage()));
+    }
+
+    selectRowsInPage() {
+        const rows = this.dataSource.getPageOfRows(this.pager);
+        const indexes = rows.map(r => this.getRowIndex(r));
+        this.rowSelector.select(indexes);
+        this.selectRowsInPageEmitter.emit();
     }
 
     toPrevPage(): Promise<any> {

-----------------------------------------------------------------------

Summary of changes:
 .../src/app/share/grid/grid-body.component.html    |  5 +-
 .../eg2/src/app/share/grid/grid-body.component.ts  | 26 ++++++-
 .../src/app/share/grid/grid-header.component.html  | 21 ++++--
 .../src/app/share/grid/grid-header.component.ts    | 12 ++-
 .../src/app/share/grid/grid-toolbar.component.html |  5 +-
 .../src/eg2/src/app/share/grid/grid.component.html |  6 +-
 Open-ILS/src/eg2/src/app/share/grid/grid.ts        | 87 +++++++++++++++++++++-
 7 files changed, 140 insertions(+), 22 deletions(-)


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list