fb3cb742cc6daceff84b747e2c3bf88caf789006
[working/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             if (this.context.toggleSelectOneRow(index)) {
95                 this.context.lastSelectedIndex = index;
96             }
97
98         } else if ($event.shiftKey) {
99             // TODO shift range click
100
101         } else {
102             this.context.selectOneRow(index);
103         }
104     }
105
106     onRowClick($event: any, row: any, idx: number) {
107         this.handleRowClick($event, row);
108         this.grid.onRowClick.emit(row);
109     }
110
111     onRowDblClick(row: any) {
112         this.grid.onRowActivate.emit(row);
113     }
114
115     performAction(action: GridToolbarAction) {
116         action.action(this.context.getSelectedRows());
117     }
118
119     // Apply row selection, track the new menu if needed, 
120     // manually close any existing open menus, open selected menu.
121     onRowContextClick($event, row: any, contextMenu: NgbPopover) {
122         $event.preventDefault(); // prevent browser context menu
123
124         if (this.context.toolbarActions.length === 0) {
125             // No actions to render.
126             return;
127         }
128
129         this.handleRowClick($event, row);
130
131         const existing = this.contextMenus.filter(m => m === contextMenu)[0];
132         if (!existing) {
133             this.contextMenus.push(contextMenu);
134         }
135
136         // Force any previously opened menus to close, which does 
137         // not naturally occur via context-click.
138         this.contextMenus.forEach(m => m.close());
139
140         contextMenu.open({gridContext: this.context});
141     }
142 }
143