ms-data-grid 0.0.16 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/DOCUMENTATION.md +243 -0
  3. package/ng-package.json +10 -0
  4. package/package.json +33 -45
  5. package/src/lib/css/bootstrap.css +12043 -0
  6. package/src/lib/data-grid/data-grid.component.html +4806 -0
  7. package/src/lib/data-grid/data-grid.component.scss +1502 -0
  8. package/src/lib/data-grid/data-grid.component.spec.ts +28 -0
  9. package/src/lib/data-grid/data-grid.component.ts +4216 -0
  10. package/src/lib/data-grid/statuses.ts +47 -0
  11. package/src/lib/data-grid.module.ts +20 -0
  12. package/src/lib/data-grid.service.spec.ts +16 -0
  13. package/src/lib/data-grid.service.ts +9 -0
  14. package/src/lib/directives/draggable-header.directive.spec.ts +11 -0
  15. package/src/lib/directives/draggable-header.directive.ts +172 -0
  16. package/src/lib/pipes/filter.pipe.spec.ts +11 -0
  17. package/src/lib/pipes/filter.pipe.ts +16 -0
  18. package/src/lib/services/cell-selection.service.spec.ts +16 -0
  19. package/src/lib/services/cell-selection.service.ts +234 -0
  20. package/src/lib/services/common.service.spec.ts +16 -0
  21. package/src/lib/services/common.service.ts +239 -0
  22. package/src/lib/services/copy-service.service.spec.ts +16 -0
  23. package/src/lib/services/copy-service.service.ts +251 -0
  24. package/src/lib/services/drag-drp.service.spec.ts +16 -0
  25. package/src/lib/services/drag-drp.service.ts +58 -0
  26. package/src/lib/services/split-columns.service.spec.ts +16 -0
  27. package/src/lib/services/split-columns.service.ts +148 -0
  28. package/src/lib/services/swap-columns.service.spec.ts +16 -0
  29. package/src/lib/services/swap-columns.service.ts +162 -0
  30. package/{public-api.d.ts → src/public-api.ts} +8 -4
  31. package/tsconfig.lib.json +16 -0
  32. package/tsconfig.lib.prod.json +10 -0
  33. package/tsconfig.spec.json +14 -0
  34. package/esm2022/lib/data-grid/data-grid.component.mjs +0 -3623
  35. package/esm2022/lib/data-grid/statuses.mjs +0 -44
  36. package/esm2022/lib/data-grid.module.mjs +0 -26
  37. package/esm2022/lib/data-grid.service.mjs +0 -14
  38. package/esm2022/lib/directives/draggable-header.directive.mjs +0 -145
  39. package/esm2022/lib/pipes/filter.pipe.mjs +0 -22
  40. package/esm2022/lib/services/common.service.mjs +0 -206
  41. package/esm2022/lib/services/copy-service.service.mjs +0 -221
  42. package/esm2022/lib/services/split-columns.service.mjs +0 -143
  43. package/esm2022/lib/services/swap-columns.service.mjs +0 -118
  44. package/esm2022/ms-data-grid.mjs +0 -5
  45. package/esm2022/public-api.mjs +0 -8
  46. package/fesm2022/ms-data-grid.mjs +0 -4546
  47. package/fesm2022/ms-data-grid.mjs.map +0 -1
  48. package/index.d.ts +0 -5
  49. package/lib/data-grid/data-grid.component.d.ts +0 -468
  50. package/lib/data-grid/statuses.d.ts +0 -3
  51. package/lib/data-grid.module.d.ts +0 -14
  52. package/lib/data-grid.service.d.ts +0 -6
  53. package/lib/directives/draggable-header.directive.d.ts +0 -31
  54. package/lib/pipes/filter.pipe.d.ts +0 -7
  55. package/lib/services/common.service.d.ts +0 -17
  56. package/lib/services/copy-service.service.d.ts +0 -14
  57. package/lib/services/split-columns.service.d.ts +0 -9
  58. package/lib/services/swap-columns.service.d.ts +0 -19
@@ -0,0 +1,47 @@
1
+ export const STATUSES_BADGE_MAP: { [key: string]: string } = {
2
+ // Success – Green
3
+ 'active': 'badge badge-success',
4
+ 'approved': 'badge badge-success',
5
+ 'accepted': 'badge badge-success',
6
+ 'completed': 'badge badge-success',
7
+ 'evaluated': 'badge badge-success',
8
+ 'assigned': 'badge badge-success',
9
+ 'scrap': 'badge badge-success',
10
+ 'move-available': 'badge badge-success',
11
+ 'move-assigned': 'badge badge-success',
12
+
13
+ // Warning – Yellow/Amber
14
+ 'contract': 'badge badge-warning',
15
+ 'warranty': 'badge badge-warning',
16
+ 'scheduled': 'badge badge-warning',
17
+ 'leased': 'badge badge-warning',
18
+ 'disposed': 'badge badge-warning',
19
+ 'maintenance': 'badge badge-warning',
20
+ 'assigning start': 'badge badge-warning',
21
+ 'evaluation start': 'badge badge-warning',
22
+ 'to be start assigning': 'badge badge-warning',
23
+ 'pending': 'badge badge-warning',
24
+ 'leave': 'badge badge-warning',
25
+
26
+ // Danger – Red
27
+ 'inactive': 'badge badge-danger',
28
+ 'rejected': 'badge badge-danger',
29
+ 'unassigned': 'badge badge-danger',
30
+ 'trashed': 'badge badge-danger',
31
+ 'onhold': 'badge badge-danger',
32
+ 'assigning stop': 'badge badge-danger',
33
+ 'evaluation stop': 'badge badge-danger',
34
+ 'unavailable': 'badge badge-danger',
35
+ 'move-error': 'badge badge-danger',
36
+ 'failed': 'badge badge-danger',
37
+ 'absent': 'badge badge-danger',
38
+
39
+ // Info – Blue
40
+ 'insurance': 'badge badge-info',
41
+ 'pastdue': 'badge badge-info',
42
+
43
+ // Dark – Neutral/Other
44
+ 'expired': 'badge badge-dark',
45
+ 'draft': 'badge badge-dark',
46
+ 'present': 'badge badge-success'
47
+ };
@@ -0,0 +1,20 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { DataGridComponent } from './data-grid/data-grid.component';
3
+ import { CommonModule } from '@angular/common';
4
+ import { FormsModule } from '@angular/forms';
5
+ import { FilterPipe } from './pipes/filter.pipe';
6
+ import { DraggableHeaderDirective } from './directives/draggable-header.directive';
7
+ import { DragDropModule } from '@angular/cdk/drag-drop';
8
+ import { InlineSVGModule } from 'ng-inline-svg';
9
+ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
10
+ import { ScrollingModule } from '@angular/cdk/scrolling';
11
+
12
+
13
+
14
+ @NgModule({
15
+ declarations: [DataGridComponent, FilterPipe, DraggableHeaderDirective],
16
+ imports: [CommonModule, FormsModule, DragDropModule, InlineSVGModule.forRoot(), ScrollingModule],
17
+ exports: [DataGridComponent, DraggableHeaderDirective],
18
+ providers: [],
19
+ })
20
+ export class DataGridModule {}
@@ -0,0 +1,16 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+
3
+ import { DataGridService } from './data-grid.service';
4
+
5
+ describe('DataGridService', () => {
6
+ let service: DataGridService;
7
+
8
+ beforeEach(() => {
9
+ TestBed.configureTestingModule({});
10
+ service = TestBed.inject(DataGridService);
11
+ });
12
+
13
+ it('should be created', () => {
14
+ expect(service).toBeTruthy();
15
+ });
16
+ });
@@ -0,0 +1,9 @@
1
+ import { Injectable } from '@angular/core';
2
+
3
+ @Injectable({
4
+ providedIn: 'root'
5
+ })
6
+ export class DataGridService {
7
+
8
+ constructor() { }
9
+ }
@@ -0,0 +1,11 @@
1
+ /* tslint:disable:no-unused-variable */
2
+
3
+ import { TestBed, async } from '@angular/core/testing';
4
+ import { DraggableHeaderDirective } from './draggable-header.directive';
5
+
6
+ describe('Directive: DraggableHeader', () => {
7
+ it('should create an instance', () => {
8
+ const directive = new DraggableHeaderDirective();
9
+ expect(directive).toBeTruthy();
10
+ });
11
+ });
@@ -0,0 +1,172 @@
1
+ import {
2
+ Directive,
3
+ ElementRef,
4
+ EventEmitter,
5
+ HostListener,
6
+ Input,
7
+ Output,
8
+ Renderer2,
9
+ } from '@angular/core';
10
+
11
+ export interface DragMoveEvent {
12
+ event: MouseEvent;
13
+ data: any;
14
+ }
15
+
16
+ @Directive({
17
+ selector: '[appDraggableHeader]',
18
+ })
19
+ export class DraggableHeaderDirective {
20
+ @Input() column: any;
21
+ @Input() headerName: string = '';
22
+
23
+ @Output() dragStart = new EventEmitter<any>();
24
+ @Output() dragMove = new EventEmitter<any>();
25
+ @Output() dragEnd = new EventEmitter<any>();
26
+
27
+ private isDragging = false;
28
+ private placeholderEl: HTMLElement | null = null;
29
+ private previewEl: HTMLElement | null = null;
30
+
31
+ constructor(private el: ElementRef, private renderer: Renderer2) {}
32
+
33
+ startX = 0;
34
+ startY = 0;
35
+
36
+ @HostListener('mousedown', ['$event'])
37
+ onMouseDown(event: MouseEvent) {
38
+ if (event.button !== 0) return;
39
+ let target = event.target as HTMLElement;
40
+ const classes = target.classList;
41
+ debugger
42
+ if ((event.target as HTMLElement).classList.contains('three-dots')) return;
43
+ this.startX = event.clientX;
44
+ this.startY = event.clientY;
45
+ this.isDragging = false;
46
+
47
+ document.addEventListener('mousemove', this.onMouseMove);
48
+ document.addEventListener('mouseup', this.onMouseUp);
49
+ }
50
+
51
+ onMouseMove = (event: MouseEvent) => {
52
+ debugger
53
+ const moveX = Math.abs(event.clientX - this.startX - 10);
54
+ const moveY = Math.abs(event.clientY - this.startY - 10);
55
+ if (!this.isDragging && (moveX > 1 || moveY > 1)) {
56
+ this.startDragging(event);
57
+ }
58
+
59
+ if (this.isDragging && this.previewEl) {
60
+ this.renderer.setStyle(this.previewEl, 'top', `${event.pageY + 10}px`);
61
+ this.renderer.setStyle(this.previewEl, 'left', `${event.pageX + 10}px`);
62
+
63
+ // Find the element under cursor (hovered element)
64
+ const hoveredElement = document.elementFromPoint(
65
+ event.clientX,
66
+ event.clientY
67
+ );
68
+
69
+ this.dragMove.emit({
70
+ event,
71
+ column: this.column,
72
+ hoveredElement,
73
+ });
74
+ }
75
+ };
76
+
77
+ onMouseUp = (event: MouseEvent) => {
78
+ if (!this.isDragging) return;
79
+ this.isDragging = false;
80
+
81
+ this.dragEnd.emit({ column: this.column, event });
82
+
83
+ if (this.previewEl) {
84
+ this.renderer.removeChild(document.body, this.previewEl);
85
+ this.previewEl = null;
86
+ }
87
+
88
+ if (this.placeholderEl) {
89
+ const parent = this.placeholderEl.parentNode;
90
+ if (parent) {
91
+ parent.replaceChild(this.el.nativeElement, this.placeholderEl);
92
+ }
93
+ this.placeholderEl = null;
94
+ }
95
+
96
+ // Reset the cursor
97
+ this.resetCursor();
98
+
99
+ document.removeEventListener('mousemove', this.onMouseMove);
100
+ document.removeEventListener('mouseup', this.onMouseUp);
101
+ };
102
+
103
+ private originalCursor: string | null = null;
104
+
105
+ private setCursor(cursorStyle: string) {
106
+ this.renderer.setStyle(document.body, 'cursor', cursorStyle);
107
+ }
108
+
109
+ private resetCursor() {
110
+ this.renderer.setStyle(document.body, 'cursor', this.originalCursor || '');
111
+ }
112
+
113
+ private startDragging(event: MouseEvent) {
114
+ this.isDragging = true;
115
+
116
+ // Store original cursor (optional fallback)
117
+ this.originalCursor = getComputedStyle(document.body).cursor;
118
+
119
+ // Set cursor to grabbing
120
+ this.setCursor('move');
121
+
122
+ // --- Clone the element as a placeholder ---
123
+ this.placeholderEl = this.el.nativeElement.cloneNode(true) as HTMLElement;
124
+ this.renderer.setStyle(this.placeholderEl, 'opacity', '0.5');
125
+ this.renderer.setStyle(this.placeholderEl, 'pointer-events', 'none');
126
+ this.renderer.addClass(this.placeholderEl, 'drag-placeholder');
127
+
128
+ const parent = this.el.nativeElement.parentNode;
129
+ parent.replaceChild(this.placeholderEl, this.el.nativeElement);
130
+
131
+ // --- Create floating preview ---
132
+ this.previewEl = this.renderer.createElement('div');
133
+ this.renderer.setStyle(this.previewEl, 'position', 'absolute');
134
+ this.renderer.setStyle(this.previewEl, 'top', `${event.pageY + 10}px`);
135
+ this.renderer.setStyle(this.previewEl, 'left', `${event.pageX + 10}px`);
136
+ this.renderer.setStyle(this.previewEl, 'pointer-events', 'none');
137
+ this.renderer.setStyle(this.previewEl, 'z-index', '1000');
138
+ this.renderer.setStyle(this.previewEl, 'max-width', '200px');
139
+ this.renderer.setStyle(this.previewEl, 'padding', '8px');
140
+ this.renderer.setStyle(this.previewEl, 'border', '1px solid #ccc');
141
+ this.renderer.setStyle(this.previewEl, 'background-color', '#fff');
142
+ this.renderer.setStyle(
143
+ this.previewEl,
144
+ 'box-shadow',
145
+ '0 2px 6px rgba(0,0,0,0.2)'
146
+ );
147
+ this.renderer.setStyle(this.previewEl, 'border-radius', '4px');
148
+ this.renderer.setStyle(this.previewEl, 'display', 'flex');
149
+ this.renderer.setStyle(this.previewEl, 'align-items', 'center');
150
+ this.renderer.setStyle(this.previewEl, 'gap', '8px');
151
+ this.renderer.setStyle(this.previewEl, 'font-weight', '500');
152
+ this.renderer.setStyle(this.previewEl, 'white-space', 'nowrap');
153
+
154
+ const icon = this.renderer.createElement('span');
155
+ this.renderer.setStyle(icon, 'font-size', '16px');
156
+ this.renderer.setStyle(icon, 'user-select', 'none');
157
+ this.renderer.setProperty(icon, 'innerText', '≡');
158
+
159
+ const text = this.renderer.createElement('span');
160
+ this.renderer.setProperty(text, 'innerText', this.headerName || 'Dragging');
161
+
162
+ this.renderer.appendChild(this.previewEl, icon);
163
+ this.renderer.appendChild(this.previewEl, text);
164
+ this.renderer.appendChild(document.body, this.previewEl);
165
+
166
+ this.dragStart.emit({ column: this.column, event });
167
+ }
168
+
169
+ public overrideCursor(style: string) {
170
+ this.setCursor(style);
171
+ }
172
+ }
@@ -0,0 +1,11 @@
1
+ /* tslint:disable:no-unused-variable */
2
+
3
+ import { TestBed, async } from '@angular/core/testing';
4
+ import { FilterPipe } from './filter.pipe';
5
+
6
+ describe('Pipe: Filtere', () => {
7
+ it('create an instance', () => {
8
+ let pipe = new FilterPipe();
9
+ expect(pipe).toBeTruthy();
10
+ });
11
+ });
@@ -0,0 +1,16 @@
1
+ import { Pipe, PipeTransform } from '@angular/core';
2
+
3
+ @Pipe({
4
+ name: 'filter',
5
+ })
6
+ export class FilterPipe implements PipeTransform {
7
+ transform(items: any[], searchText: string, key?: string): any[] {
8
+ if (!items || !searchText) return items;
9
+
10
+ searchText = searchText.toLowerCase();
11
+
12
+ return items.filter(item => {
13
+ const value = key ? item?.[key] : item;
14
+ return value?.toString().toLowerCase().includes(searchText);
15
+ });
16
+ }}
@@ -0,0 +1,16 @@
1
+ /* tslint:disable:no-unused-variable */
2
+
3
+ import { TestBed, async, inject } from '@angular/core/testing';
4
+ import { CellSelectionService } from './cell-selection.service';
5
+
6
+ describe('Service: CellSelection', () => {
7
+ beforeEach(() => {
8
+ TestBed.configureTestingModule({
9
+ providers: [CellSelectionService]
10
+ });
11
+ });
12
+
13
+ it('should ...', inject([CellSelectionService], (service: CellSelectionService) => {
14
+ expect(service).toBeTruthy();
15
+ }));
16
+ });
@@ -0,0 +1,234 @@
1
+ // selection.service.ts
2
+ import { Injectable } from '@angular/core';
3
+
4
+ export interface SelectionRange {
5
+ startRow: number;
6
+ startGroupIndex: number;
7
+ startSubColIndex: number;
8
+ startField: string;
9
+ endRow: number;
10
+ endGroupIndex: number;
11
+ endSubColIndex: number;
12
+ endField: string;
13
+ }
14
+
15
+ export interface ActiveCell {
16
+ row: number;
17
+ groupIndex: number;
18
+ subColIndex: number;
19
+ field: string;
20
+ }
21
+
22
+ @Injectable({
23
+ providedIn: 'root'
24
+ })
25
+ export class CellSelectionService {
26
+ private selectionRange: SelectionRange | null = null;
27
+ private activeCell: ActiveCell | null = null;
28
+ private isSelecting = false;
29
+
30
+ // Get the current selection range
31
+ getSelection(): SelectionRange | null {
32
+ return this.selectionRange;
33
+ }
34
+
35
+ // Get the active cell
36
+ getActiveCell(): ActiveCell | null {
37
+ return this.activeCell;
38
+ }
39
+
40
+ // Check if a cell is selected
41
+ isSelected(row: number, groupIndex: number, subColIndex: number, field: string): boolean {
42
+ if (!this.selectionRange) return false;
43
+
44
+ const {
45
+ startRow,
46
+ startGroupIndex,
47
+ startSubColIndex,
48
+ startField,
49
+ endRow,
50
+ endGroupIndex,
51
+ endSubColIndex,
52
+ endField
53
+ } = this.selectionRange;
54
+
55
+ // Normalize the selection range
56
+ const minRow = Math.min(startRow, endRow);
57
+ const maxRow = Math.max(startRow, endRow);
58
+
59
+ // For group and subcolumn, we need to compare both indices AND field names
60
+ const isSameGroup = startGroupIndex === endGroupIndex;
61
+ const isSameField = startField === endField;
62
+
63
+ if (isSameGroup && isSameField) {
64
+ // Selection is within the same group and same field
65
+ const minSubCol = Math.min(startSubColIndex, endSubColIndex);
66
+ const maxSubCol = Math.max(startSubColIndex, endSubColIndex);
67
+
68
+ return row >= minRow &&
69
+ row <= maxRow &&
70
+ groupIndex === startGroupIndex &&
71
+ field === startField &&
72
+ subColIndex >= minSubCol &&
73
+ subColIndex <= maxSubCol;
74
+ } else if (isSameGroup) {
75
+ // Selection spans multiple fields within the same group
76
+ // We need to check if this field is between start and end fields
77
+ const fieldsInGroup = this.getFieldsInGroup(groupIndex); // You'll need to implement this
78
+ const startFieldIndex = fieldsInGroup.indexOf(startField);
79
+ const endFieldIndex = fieldsInGroup.indexOf(endField);
80
+ const minFieldIndex = Math.min(startFieldIndex, endFieldIndex);
81
+ const maxFieldIndex = Math.max(startFieldIndex, endFieldIndex);
82
+ const currentFieldIndex = fieldsInGroup.indexOf(field);
83
+
84
+ return row >= minRow &&
85
+ row <= maxRow &&
86
+ groupIndex === startGroupIndex &&
87
+ currentFieldIndex >= minFieldIndex &&
88
+ currentFieldIndex <= maxFieldIndex;
89
+ } else {
90
+ // Selection spans multiple groups
91
+ const minGroup = Math.min(startGroupIndex, endGroupIndex);
92
+ const maxGroup = Math.max(startGroupIndex, endGroupIndex);
93
+
94
+ // For cells in the starting group
95
+ if (groupIndex === startGroupIndex) {
96
+ const fieldsInGroup = this.getFieldsInGroup(groupIndex);
97
+ const startFieldIndex = fieldsInGroup.indexOf(startField);
98
+ const currentFieldIndex = fieldsInGroup.indexOf(field);
99
+
100
+ return row >= minRow &&
101
+ row <= maxRow &&
102
+ currentFieldIndex >= (startGroupIndex === minGroup ? startFieldIndex : 0) &&
103
+ currentFieldIndex <= (startGroupIndex === maxGroup ? startFieldIndex : fieldsInGroup.length - 1);
104
+ }
105
+
106
+ // For cells in the ending group
107
+ if (groupIndex === endGroupIndex) {
108
+ const fieldsInGroup = this.getFieldsInGroup(groupIndex);
109
+ const endFieldIndex = fieldsInGroup.indexOf(endField);
110
+ const currentFieldIndex = fieldsInGroup.indexOf(field);
111
+
112
+ return row >= minRow &&
113
+ row <= maxRow &&
114
+ currentFieldIndex >= (endGroupIndex === minGroup ? endFieldIndex : 0) &&
115
+ currentFieldIndex <= (endGroupIndex === maxGroup ? endFieldIndex : fieldsInGroup.length - 1);
116
+ }
117
+
118
+ // For cells in between groups
119
+ return row >= minRow &&
120
+ row <= maxRow &&
121
+ groupIndex > minGroup &&
122
+ groupIndex < maxGroup;
123
+ }
124
+ }
125
+
126
+ // Check if a cell is the active cell
127
+ isActiveCell(row: number, groupIndex: number, subColIndex: number, field: string): boolean {
128
+ return this.activeCell?.row === row &&
129
+ this.activeCell?.groupIndex === groupIndex &&
130
+ this.activeCell?.subColIndex === subColIndex &&
131
+ this.activeCell?.field === field;
132
+ }
133
+
134
+ // Start selection
135
+ startSelection(row: number, groupIndex: number, subColIndex: number, field: string): void {
136
+ this.isSelecting = true;
137
+ this.selectionRange = {
138
+ startRow: row,
139
+ startGroupIndex: groupIndex,
140
+ startSubColIndex: subColIndex,
141
+ startField: field,
142
+ endRow: row,
143
+ endGroupIndex: groupIndex,
144
+ endSubColIndex: subColIndex,
145
+ endField: field
146
+ };
147
+ this.activeCell = { row, groupIndex, subColIndex, field };
148
+ }
149
+
150
+ // Extend selection
151
+ extendSelection(row: number, groupIndex: number, subColIndex: number, field: string): void {
152
+ if (this.isSelecting && this.selectionRange) {
153
+ this.selectionRange.endRow = row;
154
+ this.selectionRange.endGroupIndex = groupIndex;
155
+ this.selectionRange.endSubColIndex = subColIndex;
156
+ this.selectionRange.endField = field;
157
+ }
158
+ }
159
+
160
+ // End selection
161
+ endSelection(): void {
162
+ this.isSelecting = false;
163
+ }
164
+
165
+ // Clear selection
166
+ clearSelection(): void {
167
+ this.selectionRange = null;
168
+ this.activeCell = null;
169
+ }
170
+
171
+ // Move selection with keyboard
172
+ moveSelection(direction: 'up' | 'down' | 'left' | 'right', columnStructure: any[]): void {
173
+ if (!this.activeCell) return;
174
+
175
+ let { row, groupIndex, subColIndex, field } = this.activeCell;
176
+
177
+ switch (direction) {
178
+ case 'up':
179
+ row--;
180
+ break;
181
+ case 'down':
182
+ row++;
183
+ break;
184
+ case 'left':
185
+ if (subColIndex > 0) {
186
+ // Move left within the same group
187
+ subColIndex--;
188
+ field = this.getFieldFromIndices(groupIndex, subColIndex, columnStructure);
189
+ } else if (groupIndex > 0) {
190
+ // Move to previous group
191
+ groupIndex--;
192
+ subColIndex = columnStructure[groupIndex].children.length - 1;
193
+ field = this.getFieldFromIndices(groupIndex, subColIndex, columnStructure);
194
+ }
195
+ break;
196
+ case 'right':
197
+ if (subColIndex < columnStructure[groupIndex].children.length - 1) {
198
+ // Move right within the same group
199
+ subColIndex++;
200
+ field = this.getFieldFromIndices(groupIndex, subColIndex, columnStructure);
201
+ } else if (groupIndex < columnStructure.length - 1) {
202
+ // Move to next group
203
+ groupIndex++;
204
+ subColIndex = 0;
205
+ field = this.getFieldFromIndices(groupIndex, subColIndex, columnStructure);
206
+ }
207
+ break;
208
+ }
209
+
210
+ // Boundary checks for rows (you'll need to implement based on your data)
211
+ // if (row >= 0 && row < maxRows) {
212
+ this.startSelection(row, groupIndex, subColIndex, field);
213
+ this.endSelection();
214
+ // }
215
+ }
216
+
217
+ // Helper method to get field from indices
218
+ private getFieldFromIndices(groupIndex: number, subColIndex: number, columnStructure: any[]): string {
219
+ if (groupIndex >= 0 &&
220
+ groupIndex < columnStructure.length &&
221
+ subColIndex >= 0 &&
222
+ subColIndex < columnStructure[groupIndex].children.length) {
223
+ return columnStructure[groupIndex].children[subColIndex].field;
224
+ }
225
+ return '';
226
+ }
227
+
228
+ // Helper method to get all fields in a group
229
+ private getFieldsInGroup(groupIndex: number): string[] {
230
+ // You'll need to implement this based on your data structure
231
+ // This should return an array of field names for the specified group
232
+ return [];
233
+ }
234
+ }
@@ -0,0 +1,16 @@
1
+ /* tslint:disable:no-unused-variable */
2
+
3
+ import { TestBed, async, inject } from '@angular/core/testing';
4
+ import { CommonService } from './common.service';
5
+
6
+ describe('Service: Common', () => {
7
+ beforeEach(() => {
8
+ TestBed.configureTestingModule({
9
+ providers: [CommonService]
10
+ });
11
+ });
12
+
13
+ it('should ...', inject([CommonService], (service: CommonService) => {
14
+ expect(service).toBeTruthy();
15
+ }));
16
+ });