LP1821382 Angular grid optoin to disable paging
[evergreen-equinox.git] / Open-ILS / src / eg2 / src / app / share / grid / grid.ts
index 92591a7..64f3321 100644 (file)
@@ -32,6 +32,7 @@ export class GridColumn {
     isDragTarget: boolean;
     isSortable: boolean;
     isMultiSortable: boolean;
+    disableTooltip: boolean;
     comparator: (valueA: any, valueB: any) => number;
 
     // True if the column was automatically generated.
@@ -441,6 +442,11 @@ export class GridContext {
     defaultHiddenFields: string[];
     overflowCells: boolean;
     showLinkSelectors: boolean;
+    disablePaging: 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;
@@ -459,7 +465,6 @@ export class GridContext {
         this.store = store;
         this.format = format;
         this.pager = new Pager();
-        this.pager.limit = 10;
         this.rowSelector = new GridRowSelector();
         this.toolbarButtons = [];
         this.toolbarCheckboxes = [];
@@ -467,11 +472,15 @@ 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;
         this.columnSet.defaultHiddenFields = this.defaultHiddenFields;
         this.columnSet.defaultVisibleFields = this.defaultVisibleFields;
+        if (!this.pager.limit) {
+            this.pager.limit = this.disablePaging ? MAX_ALL_ROW_COUNT : 10;
+        }
         this.generateColumns();
     }
 
@@ -542,18 +551,34 @@ export class GridContext {
     sortLocalData() {
 
         const sortDefs = this.dataSource.sort.map(sort => {
+            const column = this.columnSet.getColByName(sort.name);
+
             const def = {
                 name: sort.name,
                 dir: sort.dir,
-                col: this.columnSet.getColByName(sort.name)
+                col: column
             };
 
             if (!def.col.comparator) {
-                def.col.comparator = (a, b) => {
-                    if (a < b) { return -1; }
-                    if (a > b) { return 1; }
-                    return 0;
-                };
+                switch (def.col.datatype) {
+                    case 'id':
+                    case 'money':
+                    case 'int':
+                        def.col.comparator = (a, b) => {
+                            a = Number(a);
+                            b = Number(b);
+                            if (a < b) { return -1; }
+                            if (a > b) { return 1; }
+                            return 0;
+                        };
+                        break;
+                    default:
+                        def.col.comparator = (a, b) => {
+                            if (a < b) { return -1; }
+                            if (a > b) { return 1; }
+                            return 0;
+                        };
+                }
             }
 
             return def;
@@ -574,8 +599,6 @@ export class GridContext {
                 const diff = sortDef.col.comparator(valueA, valueB);
                 if (diff === 0) { continue; }
 
-                console.log(valueA, valueB, diff);
-
                 return sortDef.dir === 'DESC' ? -diff : diff;
             }
 
@@ -717,6 +740,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) {
@@ -756,12 +785,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> {
@@ -927,7 +1028,8 @@ export class GridToolbarButton {
 
 export class GridToolbarCheckbox {
     label: string;
-    onChange: (checked: boolean) => void;
+    isChecked: boolean;
+    onChange: EventEmitter<boolean>;
 }
 
 export class GridDataSource {
@@ -935,6 +1037,7 @@ export class GridDataSource {
     data: any[];
     sort: any[];
     allRowsRetrieved: boolean;
+    requestingData: boolean;
     getRows: (pager: Pager, sort: any[]) => Observable<any>;
 
     constructor() {
@@ -970,16 +1073,23 @@ export class GridDataSource {
             return Promise.resolve();
         }
 
+        // If we have to call out for data, set inFetch
+        this.requestingData = true;
+
         return new Promise((resolve, reject) => {
             let idx = pager.offset;
             return this.getRows(pager, this.sort).subscribe(
-                row => this.data[idx++] = row,
+                row => {
+                    this.data[idx++] = row;
+                    this.requestingData = false;
+                },
                 err => {
                     console.error(`grid getRows() error ${err}`);
                     reject(err);
                 },
                 ()  => {
                     this.checkAllRetrieved(pager, idx);
+                    this.requestingData = false;
                     resolve();
                 }
             );