]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/share/grid/grid-body.component.ts
LP1803787 Grid toolbar actions menu component; cleanup
[Evergreen.git] / Open-ILS / src / eg2 / src / app / share / grid / grid-body.component.ts
1 import {Component, Input, OnInit, Host} from '@angular/core';
2 import {GridContext, GridColumn, GridRowSelector,
3     GridToolbarAction, GridColumnSet, GridDataSource} from './grid';
4 import {GridComponent} from './grid.component';
5 import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';
6
7 @Component({
8   selector: 'eg-grid-body',
9   templateUrl: './grid-body.component.html'
10 })
11
12 export class GridBodyComponent implements OnInit {
13
14     @Input() context: GridContext;
15
16     // Track the context menus so we can manually close them
17     // when another popover is opened.
18     contextMenus: NgbPopover[];
19
20     constructor(@Host() private grid: GridComponent) {
21         this.contextMenus = [];
22     }
23
24     ngOnInit() {}
25
26     // Not using @HostListener because it only works globally.
27     onGridKeyDown(evt: KeyboardEvent) {
28         switch (evt.key) {
29             case 'ArrowUp':
30                 if (evt.shiftKey) {
31                     // Extend selection up one row
32                     this.context.selectMultiRowsPrevious();
33                 } else {
34                     this.context.selectPreviousRow();
35                 }
36                 evt.stopPropagation();
37                 break;
38             case 'ArrowDown':
39                 if (evt.shiftKey) {
40                     // Extend selection down one row
41                     this.context.selectMultiRowsNext();
42                 } else {
43                     this.context.selectNextRow();
44                 }
45                 evt.stopPropagation();
46                 break;
47             case 'ArrowLeft':
48             case 'PageUp':
49                 this.context.toPrevPage()
50                 .then(ok => this.context.selectFirstRow(), err => {});
51                 evt.stopPropagation();
52                 break;
53             case 'ArrowRight':
54             case 'PageDown':
55                 this.context.toNextPage()
56                 .then(ok => this.context.selectFirstRow(), err => {});
57                 evt.stopPropagation();
58                 break;
59             case 'a':
60                 // control-a means select all visible rows.
61                 // For consistency, select all rows in the current page only.
62                 if (evt.ctrlKey) {
63                     this.context.rowSelector.clear();
64                     this.context.selectRowsInPage();
65                     evt.preventDefault();
66                 }
67                 break;
68
69             case 'Enter':
70                 if (this.context.lastSelectedIndex) {
71                     this.grid.onRowActivate.emit(
72                         this.context.getRowByIndex(
73                             this.context.lastSelectedIndex)
74                     );
75                 }
76                 evt.stopPropagation();
77                 break;
78         }
79     }
80
81     handleRowClick($event: any, row: any) {
82
83         if (this.context.disableSelect) {
84             // Avoid any appearance or click behavior when row
85             // selection is disabled.
86             return;
87         }
88
89         const index = this.context.getRowIndex(row);
90
91         if (this.context.disableMultiSelect) {
92             this.context.selectOneRow(index);
93         } else if ($event.ctrlKey || $event.metaKey /* mac command */) {
94             this.context.toggleSelectOneRow(index);
95
96         } else if ($event.shiftKey) {
97             // TODO shift range click
98
99         } else {
100             this.context.selectOneRow(index);
101         }
102     }
103
104     onRowClick($event: any, row: any, idx: number) {
105         this.handleRowClick($event, row);
106         this.grid.onRowClick.emit(row);
107     }
108
109     onRowDblClick(row: any) {
110         this.grid.onRowActivate.emit(row);
111     }
112
113     // Apply row selection, track the new menu if needed,
114     // manually close any existing open menus, open selected menu.
115     onRowContextClick($event, row: any, contextMenu: NgbPopover) {
116         $event.preventDefault(); // prevent browser context menu
117
118         if (this.context.toolbarActions.length === 0) {
119             // No actions to render.
120             return;
121         }
122
123         if (!this.context.rowIsSelected(row)) {
124             // If the focused row is not selected, select it.
125             // Otherwise, avoid modifying the row selection.
126             this.context.selectOneRow(this.context.getRowIndex(row));
127         }
128
129         const existing = this.contextMenus.filter(m => m === contextMenu)[0];
130         if (!existing) {
131             this.contextMenus.push(contextMenu);
132         }
133
134         // Force any previously opened menus to close, which does
135         // not naturally occur via context-click.
136         this.contextMenus.forEach(m => m.close());
137
138         contextMenu.open({gridContext: this.context});
139     }
140 }
141